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

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

Revert "Merge remote-tracking branch 'origin' into tp30"

This reverts commit e21f283e02d0bfe6678e479d562d70df8fb28ca4, reversing
changes made to 25063bb61ef2849749d0a8be287687ce7b3794be.


Project: http://git-wip-us.apache.org/repos/asf/incubator-tinkerpop/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-tinkerpop/commit/6902e68a
Tree: http://git-wip-us.apache.org/repos/asf/incubator-tinkerpop/tree/6902e68a
Diff: http://git-wip-us.apache.org/repos/asf/incubator-tinkerpop/diff/6902e68a

Branch: refs/heads/tp30
Commit: 6902e68a0a334e44ce881ca0917b9b4d08f344f4
Parents: e21f283
Author: Stephen Mallette <sp...@genoprime.com>
Authored: Tue Aug 25 08:52:12 2015 -0400
Committer: Stephen Mallette <sp...@genoprime.com>
Committed: Tue Aug 25 08:52:12 2015 -0400

----------------------------------------------------------------------
 CHANGELOG.asciidoc                              |   28 +-
 README.asciidoc                                 |    2 +-
 docs/src/gremlin-applications.asciidoc          |   50 +-
 docs/static/images/gremlin-gangster.png         |  Bin 142316 -> 0 bytes
 docs/static/images/tinkerpop3.graffle           | 2023 +-----------------
 gremlin-console/conf/remote-objects.yaml        |   23 +-
 gremlin-console/conf/remote-secure.yaml         |    9 -
 gremlin-console/conf/remote.yaml                |   12 -
 gremlin-console/pom.xml                         |    2 +-
 .../console/plugin/GephiRemoteAcceptor.groovy   |  320 +--
 .../GephiTraversalVisualizationStrategy.groovy  |  127 --
 .../plugin/UtilitiesGremlinPluginScript.groovy  |    2 +-
 .../GephiRemoteAcceptorIntegrateTest.java       |  105 +-
 gremlin-core/pom.xml                            |    2 +-
 .../gremlin/process/traversal/Path.java         |   35 +-
 .../process/traversal/TraversalStrategies.java  |    4 +-
 .../gremlin/process/traversal/Traverser.java    |    3 -
 .../traversal/dsl/graph/GraphTraversal.java     |  147 +-
 .../gremlin/process/traversal/dsl/graph/__.java |   27 +-
 .../process/traversal/lambda/LoopTraversal.java |   33 +-
 .../gremlin/process/traversal/step/Scoping.java |    4 +-
 .../traversal/step/branch/BranchStep.java       |    2 -
 .../traversal/step/branch/RepeatStep.java       |    9 +-
 .../traversal/step/filter/DedupGlobalStep.java  |    2 +-
 .../step/filter/WherePredicateStep.java         |   13 +-
 .../process/traversal/step/map/LoopsStep.java   |   37 -
 .../process/traversal/step/map/MapKeysStep.java |   14 +-
 .../traversal/step/map/MapValuesStep.java       |   14 +-
 .../process/traversal/step/map/MatchStep.java   |   23 +-
 .../traversal/step/map/RangeLocalStep.java      |   18 +-
 .../traversal/step/map/TailLocalStep.java       |    6 +-
 .../traversal/step/sideEffect/GraphStep.java    |   12 +-
 .../traversal/step/util/AbstractStep.java       |   16 +-
 .../traversal/step/util/ComputerAwareStep.java  |   12 +-
 .../process/traversal/step/util/EmptyPath.java  |   10 +-
 .../traversal/step/util/ImmutablePath.java      |   70 +-
 .../traversal/step/util/MutablePath.java        |   46 +-
 .../optimization/DedupBijectionStrategy.java    |   90 +
 .../optimization/FilterRankingStrategy.java     |  176 --
 .../traverser/B_LP_O_P_S_SE_SL_Traverser.java   |   99 -
 .../B_LP_O_P_S_SE_SL_TraverserGenerator.java    |   59 -
 .../traverser/B_LP_O_S_SE_SL_Traverser.java     |  106 -
 .../B_LP_O_S_SE_SL_TraverserGenerator.java      |   61 -
 .../traverser/B_O_P_S_SE_SL_Traverser.java      |  100 +
 .../B_O_P_S_SE_SL_TraverserGenerator.java       |   58 +
 .../traverser/TraverserRequirement.java         |    1 -
 .../traverser/util/AbstractTraverser.java       |    6 -
 .../util/DefaultTraverserGeneratorFactory.java  |   12 +-
 .../traverser/util/EmptyTraverser.java          |    6 -
 .../process/traversal/util/TraversalHelper.java |   25 +-
 .../gremlin/structure/Transaction.java          |    1 +
 .../structure/io/graphml/GraphMLReader.java     |   43 +-
 .../gremlin/structure/io/gryo/GryoMapper.java   |   22 +-
 .../util/AbstractThreadLocalTransaction.java    |   75 -
 .../util/AbstractThreadedTransaction.java       |   70 -
 .../structure/util/AbstractTransaction.java     |   83 +-
 .../gremlin/process/traversal/PathTest.java     |   85 +-
 .../traversal/step/filter/WhereStepTest.java    |    2 +-
 .../traversal/step/map/LoopsStepTest.java       |   40 -
 .../traversal/step/map/SelectOneStepTest.java   |    2 +-
 .../traversal/step/map/SelectStepTest.java      |    2 +-
 .../DedupBijectionStrategyTest.java             |  128 ++
 .../optimization/FilterRankingStrategyTest.java |  133 --
 .../LambdaRestrictionStrategyTest.java          |    3 +
 gremlin-driver/pom.xml                          |    2 +-
 gremlin-groovy-test/pom.xml                     |    2 +-
 .../step/branch/GroovyRepeatTest.groovy         |    7 +-
 .../traversal/step/map/GroovyCountTest.groovy   |   11 +-
 .../traversal/step/map/GroovyLoopsTest.groovy   |   56 -
 .../traversal/step/map/GroovyMapKeysTest.groovy |    5 -
 .../step/map/GroovyMapValuesTest.groovy         |    5 -
 .../traversal/step/map/GroovyMatchTest.groovy   |    5 -
 .../traversal/step/map/GroovyUnfoldTest.groovy  |    9 +-
 .../traversal/step/map/GroovyVertexTest.groovy  |   12 +-
 .../step/sideEffect/GroovyProfileTest.groovy    |    2 +-
 .../process/GroovyProcessComputerSuite.java     |    1 -
 .../process/GroovyProcessStandardSuite.java     |    1 -
 gremlin-groovy/pom.xml                          |    2 +-
 .../gremlin/groovy/engine/GremlinExecutor.java  |   32 +-
 .../groovy/engine/GremlinExecutorTest.java      |   11 +-
 .../groovy/engine/GremlinExecutorInit.groovy    |    3 +-
 gremlin-server/conf/gremlin-server-classic.yaml |    2 +-
 .../conf/gremlin-server-modern-readonly.yaml    |    2 +-
 gremlin-server/conf/gremlin-server-modern.yaml  |    2 +-
 gremlin-server/conf/gremlin-server-secure.yaml  |    2 +-
 gremlin-server/conf/gremlin-server.yaml         |    2 +-
 gremlin-server/pom.xml                          |    2 +-
 .../gremlin/server/op/session/Session.java      |    2 +
 .../server/util/ServerGremlinExecutor.java      |    4 +
 .../server/GremlinDriverIntegrateTest.java      |    2 +-
 .../server/GremlinResultSetIntegrateTest.java   |    2 +-
 .../server/gremlin-server-integration.yaml      |    2 +-
 .../server/gremlin-server-performance.yaml      |    2 +-
 gremlin-shaded/pom.xml                          |    2 +-
 gremlin-test/pom.xml                            |    2 +-
 .../tinkerpop/gremlin/AbstractGremlinTest.java  |   38 +-
 .../apache/tinkerpop/gremlin/GraphProvider.java |   10 +-
 .../gremlin/process/ProcessComputerSuite.java   |   23 +-
 .../gremlin/process/ProcessStandardSuite.java   |    2 -
 .../traversal/step/branch/RepeatTest.java       |   28 +-
 .../process/traversal/step/map/CountTest.java   |   17 -
 .../process/traversal/step/map/LoopsTest.java   |  152 --
 .../process/traversal/step/map/MapKeysTest.java |   18 +-
 .../traversal/step/map/MapValuesTest.java       |   18 +-
 .../process/traversal/step/map/MatchTest.java   |   31 +-
 .../process/traversal/step/map/UnfoldTest.java  |   24 +-
 .../process/traversal/step/map/VertexTest.java  |   29 +-
 .../traversal/step/sideEffect/ProfileTest.java  |    6 +-
 .../gremlin/structure/TransactionTest.java      |   13 +-
 .../tinkerpop/gremlin/structure/io/IoTest.java  |   46 +-
 .../structure/io/graphml/graph-types-bad.xml    |   42 -
 hadoop-gremlin/pom.xml                          |    2 +-
 .../gremlin/hadoop/structure/HadoopGraph.java   |    8 -
 neo4j-gremlin/pom.xml                           |    2 +-
 .../step/sideEffect/Neo4jGraphStep.java         |    2 +-
 .../gremlin/neo4j/structure/Neo4jGraph.java     |    8 +-
 pom.xml                                         |    2 +-
 tinkergraph-gremlin/pom.xml                     |    2 +-
 .../step/sideEffect/TinkerGraphStep.java        |    2 +-
 .../tinkergraph/structure/TinkerGraph.java      |    6 -
 .../tinkergraph/structure/TinkerIoRegistry.java |   88 -
 .../tinkergraph/structure/TinkerGraphTest.java  |   44 +-
 122 files changed, 1108 insertions(+), 4501 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-tinkerpop/blob/6902e68a/CHANGELOG.asciidoc
----------------------------------------------------------------------
diff --git a/CHANGELOG.asciidoc b/CHANGELOG.asciidoc
index be25cf3..ec39683 100644
--- a/CHANGELOG.asciidoc
+++ b/CHANGELOG.asciidoc
@@ -17,38 +17,14 @@ limitations under the License.
 TinkerPop3 CHANGELOG
 =====================
 
-
-TinkerPop 3.1.0 (A 187 On The Undercover Gremlinz)
---------------------------------------------------
-
-image::https://raw.githubusercontent.com/apache/incubator-tinkerpop/master/docs/static/images/gremlin-gangster.png[width=185]
-
-TinkerPop 3.1.0 (NOT OFFICIALLY RELEASED YET)
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-* `GraphStep` can now take a single argument `Collection` which is either elements or element ids (i.e. `g.V([1,2,3])` is supported now).
-* Added `LoopsStep` to make the loop counter accessible within `repeat()`, `until()` and `emit()`.
-* Gephi Plugin no longer requires manual insert of `store` steps to visualize a traversal.
-* Gephi Plugin visualizes `Path` objects.
-* Added a `TinkerIoRegistry` that registers a custom serializer for Gryo that will serialize an entire `TinkerGraph` instance.
-* Added configuration options to Gephi Plugin for setting the size of nodes visualized.
-* Replaced `DedupBijectionStrategy` with the more effective `FilterRankingStrategy`.
-* `ComputerAwareSteps` must not only handle step ids, but also step labels.
-* Renamed `B_O_P_SE_SL_Traverser` to `B_LP_O_P_SE_SL_Traverser` as it now supports `TraverserRequirement.LABELED_PATH`.
-* Added `B_LP_O_S_SE_SL_Traverser` in support of `TraverserRequirement.LABELED_PATH`.
-* Added `TraverserRequirement.LABELED_PATH` which only generates path data for steps that are labeled (greatly increases the likelihood of bulking).
-* Fixed a bug in `Path` usage that required an API update: `Path.addLabel()` is now `Path.extend(Set<String>)` and `Traverser.addLabels(Set<String>)`.
-* Made `Path` iterable, so that it can be `unfold()`'ed and used by local steps like `min(local)`, `max(local)`, etc.
-
 TinkerPop 3.0.0 (A Gremlin Rāga in 7/16 Time)
 ---------------------------------------------
 
-image::https://raw.githubusercontent.com/apache/incubator-tinkerpop/master/docs/static/images/gremlin-hindu.png[width=225]
+image::http://www.tinkerpop.com/docs/current/images/gremlin-hindu.png[width=225]
 
 TinkerPop 3.0.1 (NOT OFFICIALLY RELEASED YET)
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
-* `WhereTraversalStep` and `WherePredicateStep` are now the only "special" `Scoping` steps after `MatchStartStep` in `match()`.
 * Clarified semantics of `Transaction.close()` in unit tests - now refers only to closing the current transaction in the current thread.
 * `Neo4jGraph` no longer uses `OptOut` on `TransactionTest.shouldRollbackOnCloseWhenConfigured` (formerly `shouldRollbackOnShutdownWhenConfigured`)
 * Gremlin Server initialization scripts can now return a `Map` of values that will become global bindings for the server.
@@ -743,4 +719,4 @@ TinkerPop 3.0.0.M2 (Release Date: September 23, 2014)
 TinkerPop 3.0.0.M1 (Release Date: August 12, 2014)
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
-* First official release of TinkerPop3 and thus, no changes.
+* First official release of TinkerPop3 and thus, no changes.
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-tinkerpop/blob/6902e68a/README.asciidoc
----------------------------------------------------------------------
diff --git a/README.asciidoc b/README.asciidoc
index 5a403ad..934d5af 100644
--- a/README.asciidoc
+++ b/README.asciidoc
@@ -63,4 +63,4 @@ gremlin> g = graph.traversal()
 ==>graphtraversalsource[tinkergraph[vertices:6 edges:6], standard]
 gremlin> g.V().has('name','vadas').valueMap()
 ==>[name:[vadas], age:[27]]
-----
\ No newline at end of file
+----

http://git-wip-us.apache.org/repos/asf/incubator-tinkerpop/blob/6902e68a/docs/src/gremlin-applications.asciidoc
----------------------------------------------------------------------
diff --git a/docs/src/gremlin-applications.asciidoc b/docs/src/gremlin-applications.asciidoc
index db2ce9a..cf63054 100644
--- a/docs/src/gremlin-applications.asciidoc
+++ b/docs/src/gremlin-applications.asciidoc
@@ -293,6 +293,8 @@ include::{basedir}/gremlin-server/scripts/generate-modern.groovy[]
 
 The script above initializes a `Map` and assigns two key/values to it.  The first, assigned to "hook", defines a `LifeCycleHook` for Gremlin Server.  The "hook" provides a way to tie script code into the Gremlin Server startup and shutdown sequences.  The `LifeCycleHook` has two methods that can be implemented: `onStartUp` and `onShutDown`.  These events are called once at Gremlin Server start and once at Gremlin Server stop.  This is an important point because code outside of the "hook" is executed for each `ScriptEngine` creation (multiple may be created when "sessions" are enabled) and therefore the `LifeCycleHook` provides a way to ensure that a script is only executed a single time. In this case, the startup hook loads the "modern" graph into the empty TinkerGraph instance, preparing it for use.  The second key/value pair assigned to the `Map`, named "g", defines a `TraversalSource` from the `Graph` bound to the "graph" variable in the YAML configuration file.  This variable `g
 `, as well as any other variable assigned to the `Map`, will be made available as variables for future remote script executions.  In more general terms, any key/value pairs assigned to a `Map` returned from the init script will become variables that are global to all requests. In addition, any functions that are defined will be cached for future use.
 
+IMPORTANT: The approach to global bindings described above was introduced with 3.0.1.  In 3.0.0, initialization scripts that simply created `Graph` and/or `TraversalSource` objects became globally bound to the server and it was not possible to bind variables of other types. This less flexible feature is expected to be removed from Gremlin Server in 3.1.0 but remains present in the 3.0.x line of releases for backward compatibility with existing scripts.
+
 With Gremlin Server running it is now possible to issue some scripts to it for processing.  Start Gremlin Console as follows:
 
 [source,text]
@@ -349,8 +351,6 @@ script = """
 
 TIP: In Groovy, `""" text """` is a convenient way to create a multi-line string and works well in concert with `:> @variable`. Note that this model of submitting a string variable works for all `:>` based plugins, not just Gremlin Server.
 
-WARNING: Not all values that can be returned from a Gremlin script end up being serializable.  For example, submitting `:> graph` will return a `Graph` instance and in most cases those are not serializable by Gremlin Server and will return a serialization error.  It should be noted that `TinkerGraph`, as a convenience for shipping around small sub-graphs, is serializable from Gremlin Server.
-
 Connecting via Java
 ~~~~~~~~~~~~~~~~~~~
 
@@ -1130,34 +1130,41 @@ NOTE: Issuing `:> graph` again will clear the Gephi workspace and then re-write
 
 Now that the graph is visualized in Gephi, it is possible to link:https://gephi.github.io/users/tutorial-layouts/[apply a layout algorithm], change the size and/or color of vertices and edges, and display labels/properties of interest.  Further information can be found in Gephi's tutorial on link:https://gephi.github.io/users/tutorial-visualization/[Visualization].  After applying the Fruchterman Reingold layout, increasing the node size, decreasing the edge scale, and displaying the id, name, and weight attributes the graph looks as displayed in the right image above.
 
-In addition to providing a way to pipe a `Graph` instance to Gephi, the plugin also enables methods for visualizing a `Path` and a `Traversal`.  In both cases, the `Graph` underlying the `Path` and `Traversal` must be visualized in Gephi as defined above.  To visualize a `Path`, simple get a `Path` object and `:submit` it:
-
-[source,groovy]
-gremlin> :> g.V(1).repeat(both().dedup()).until(hasId(582)).path().next()
+NOTE: It's recommended to choose a continuously running layout algorithm like Fruchterman Reingold or Force Atlas, because every update to color the visited vertices causes their positions to be reset, so these layouts will constantly adjust to account for these changes and make visualization of the traversals.  This also explains why the graph seems to rotate each store step in the screenshots below.
 
-The above line of code will visualize the "shortest path" between vertex `1` and vertex `582`, highlighting vertex `1` first then stepping through the path to `582` highlighting each vertex found as it goes.
+Consider the following traversal:
 
-WARNING: On some platforms, Gephi may not properly refresh the edges in the "Overview" panel for `Path` visualizations.  If this problem occurs, manually refreshing the "Overview" will allow the `Path` visualization to become fully realized (e.g. click the "Show Hulls" button).
+[source,groovy]
+----
+g = graph.traversal()
+g.V(2).in().out('knows').
+      has('age',gt(30)).outE('created').
+      has('weight',gt(0.5d)).inV()
+----
 
-Visualization of a `Traversal` has a different approach as the visualization occurs as the `Traversal` is executing, thus showing a real-time view of its execution.  A `Traversal` must be "configured" to operate in this format and for that it requires use of the `visualTraversal` option on the `config` function of the `:remote` command:
+To visualize it insert the appropriately named `store('n')` steps where `n` is an integer, and the vertices will be highlighted in ascending store step order.
 
 [gremlin-groovy,modern]
 ----
-:remote config visualTraversal graph                   <1>
-traversal = vg.V(2).in().out('knows').
-                    has('age',gt(30)).outE('created').
-                    has('weight',gt(0.5d)).inV()
-:> traversal                                           <2>
+g = graph.traversal()
+g.V(2).in('knows').out('knows').has('age',gt(30)).
+       outE('created').has('weight',gt(0.5d)).inV().values('name')
+traversal = g.V(2).store('1').
+       in('knows').store('2').
+       out('knows').has('age',gt(30)).store('3').
+       outE('created').has('weight',gt(0.5d)).inV().store('4')
+traversal.getSideEffects().get('1')
+traversal.getSideEffects().get('2')
+traversal.getSideEffects().get('3')
+traversal.getSideEffects().get('4')
+:> traversal
 ----
 
-<1> Configure a "visual traversal" from your "graph" - this must be a `Graph` instance.
-<2> Submit the `Traversal` to visualize to Gephi.
-
-When the `:>` line is called, each step of the `Traversal` that produces or filters vertices generates events to Gephi. The events update the color and size of the vertices at that step with `startRGBColor` and `startSize` respectively. After the first step visualization, it sleeps for the configured `stepDelay` in milliseconds. On the second step, it decays the configured `colorToFade` of all the previously visited vertices in prior steps, by multiplying the current `colorToFade` value for each vertex with the `colorFadeRate`.  Setting the `colorFadeRate` value to `1.0` will prevent the color decay.  The screenshots below show how the visualization evolves over the four steps:
+When `:> traversal` is called, it iterates through the sideEffects of the traversal accessing the vertices stored at each corresponding step. It then updates the vertices' color with `startRGBColor`, which in this case is a lime-green blue: [0.0,1.0,0.5]. After the first step visualization, it sleeps for the configured `stepDelay` in milliseconds. On the second step, it decays the configured `colorToFade` of all the previously visited vertices in prior steps, by multiplying the current `colorToFade` value for each vertex with the `colorFadeRate`.  To avoid color decay on prior steps, then provide a `colorFadeRate` value of `1.0`.  The screenshots below show how the visualization evolves over the 4 steps:
 
 image::gephi-traversal.png[width=1200]
 
-To get a sense of how the visualization configuration parameters affect the output, see the example below:
+Once a traversal visualization has executed, clear the colors in Gephi by selecting the grey square icon under the magnifying glass icon on the lower left tool bar next to the graph canvas.  Run another traversal against the same graph and it will update the appropriate vertices.  To get a sense of how the visualization configuration parameters affect the output, see the example below:
 
 [gremlin-groovy,modern]
 ----
@@ -1169,7 +1176,7 @@ To get a sense of how the visualization configuration parameters affect the outp
 
 image::gephi-traversal-config.png[width=400]
 
-The visualization configuration above starts with a blue color now (most recently visited), fading the blue color (so that dark green remains on oldest visited), and fading the blue color more quickly so that the gradient from dark green to blue across steps has higher contrast. The following table provides a more detailed description of the Gephi plugin configuration parameters as accepted via the `:remote config` command:
+The visualization configuration above starts with a blue color now (most recently visited), fading the blue color (so that dark green remains on oldest visited), and fading the blue color more quickly so that the gradient from dark green to blue across steps has higher contrast. Here is a more detailed description of Gephi plugin configuration parameters, in the order accepted on the `:remote connect gephi` command, or modified via the `:remote config` command:
 
 [width="100%",cols="3,10,^2",options="header"]
 |=========================================================
@@ -1177,13 +1184,10 @@ The visualization configuration above starts with a blue color now (most recentl
 |workspace |The name of the workspace that your Graph Streaming server is started for. |workspace0
 |host |The host URL where the Graph Streaming server is configured for. |localhost
 |port |The port number of the URL that the Graph Streaming server is listening on. |8080
-|sizeDecrementRate |The rate at which the size of an element decreases on each step of the visualization. |0.33
 |stepDelay |The amount of time in milliseconds to pause between step visualizations. |1000
 |startRGBColor |A size 3 float array of RGB color values which define the starting color to update most recently visited nodes with.  |[0.0,1.0,0.5]
-|startSize |The size an element should be when it is most recently visited. |20
 |colorToFade |A single char from the set `{r,g,b,R,G,B}` determining which color to fade for vertices visited in prior steps |g
 |colorFadeRate |A float value in the range `(0.0,1.0]` which is multiplied against the current `colorToFade` value for prior vertices; a `1.0` value effectively turns off the color fading of prior step visited vertices |0.7
-|visualTraversal |Creates a `TraversalSource` variable in the Console named `vg` which can be used for visualizing traversals. This configuration option takes two parameters.  The first is required and is the name of the `Graph` instance variable that will generate the `TraversalSource`.  The second parameter is the variable name that the `TraversalSource` should have when referenced in the Console.  If left unspecified, this value defaults to `vg`.
 |=========================================================
 
 [[server-plugin]]

http://git-wip-us.apache.org/repos/asf/incubator-tinkerpop/blob/6902e68a/docs/static/images/gremlin-gangster.png
----------------------------------------------------------------------
diff --git a/docs/static/images/gremlin-gangster.png b/docs/static/images/gremlin-gangster.png
deleted file mode 100644
index 64181db..0000000
Binary files a/docs/static/images/gremlin-gangster.png and /dev/null differ