Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Is there any workaround to run cypher "path" #959

Open
ministat opened this issue Sep 16, 2023 · 9 comments
Open

Is there any workaround to run cypher "path" #959

ministat opened this issue Sep 16, 2023 · 9 comments

Comments

@ministat
Copy link

ministat commented Sep 16, 2023

Morpheus does not support "path" (https://github.com/opencypher/morpheus/blob/master/documentation/asciidoc/cypher-cypher9-features.adoc), but I encountered a problem which requires "path", I'd like to know is there any workaround.

MATCH path = (start:Application {alias: "r1shsummaryv2"})-[:DependsOn*]->(end:Application {alias: "r1appmetasvccont"})
UNWIND nodes(path) AS node
RETURN node {.alias, .properties} AS valueMap
@Mats-SX
Copy link
Member

Mats-SX commented Sep 25, 2023

Hello @ministat

It was a long time ago since I (or anyone, really) worked on this library, so I do not recall exactly if we implemented support for variable-length relationship variables. If we did, you could try:

MATCH (start:Application {alias: "r1shsummaryv2"})-[r:DependsOn*]->(end:Application {alias: "r1appmetasvccont"})
UNWIND r AS relationship
WITH startNode(relationship) AS source
RETURN source {.alias, .properties} AS valueMap

@ministat
Copy link
Author

ministat commented Sep 25, 2023

@Mats-SX Thanks for your reply. Unfortunately, I got exception when I run the cyper you suggested. It looks like the pattern is unsupported.

Exception in thread "main" org.opencypher.okapi.impl.exception.NotImplementedException: Support for pattern conversion of RelationshipChain(NodePattern(Some(Variable(start)),ArrayBuffer(LabelName(Application)),None,None),RelationshipPattern(Some(Variable(r)),List(RelTypeName(DependsOn)),Some(None),None,OUTGOING,false,None),NodePattern(Some(Variable(end)),ArrayBuffer(LabelName(Application)),None,None)) not yet implemented
	at org.opencypher.okapi.ir.impl.PatternConverter$$anonfun$org$opencypher$okapi$ir$impl$PatternConverter$$convertElement$2$$anonfun$apply$3$$anonfun$apply$4$$anonfun$apply$5.apply(PatternConverter.scala:175)
	at org.opencypher.okapi.ir.impl.PatternConverter$$anonfun$org$opencypher$okapi$ir$impl$PatternConverter$$convertElement$2$$anonfun$apply$3$$anonfun$apply$4$$anonfun$apply$5.apply(PatternConverter.scala:127)
	at cats.data.StateFunctions$$anonfun$modify$4.apply(IndexedStateT.scala:299)
	at cats.data.StateFunctions$$anonfun$modify$4.apply(IndexedStateT.scala:299)
	at cats.data.StateFunctions$$anonfun$apply$19.apply(IndexedStateT.scala:289)
	at cats.data.StateFunctions$$anonfun$apply$19.apply(IndexedStateT.scala:289)
	at scala.Function1$$anonfun$andThen$1.apply(Function1.scala:52)
	at cats.data.IndexedStateT$$anonfun$run$1.apply(IndexedStateT.scala:66)
	at cats.data.IndexedStateT$$anonfun$run$1.apply(IndexedStateT.scala:66)
	at cats.Eval$.loop$1(Eval.scala:351)
	at cats.Eval$.cats$Eval$$evaluate(Eval.scala:372)
	at cats.Eval$FlatMap.value(Eval.scala:308)
	at org.opencypher.okapi.ir.impl.PatternConverter.convert(PatternConverter.scala:58)
	at org.opencypher.okapi.ir.impl.IRBuilderContext.convertPattern(IRBuilderContext.scala:64)
	at org.opencypher.okapi.ir.impl.IRBuilder$$anonfun$org$opencypher$okapi$ir$impl$IRBuilder$$convertPattern$1.apply(IRBuilder.scala:546)
	at org.opencypher.okapi.ir.impl.IRBuilder$$anonfun$org$opencypher$okapi$ir$impl$IRBuilder$$convertPattern$1.apply(IRBuilder.scala:544)
	at org.atnos.eff.Continuation.go$1(Continuation.scala:54)
	at org.atnos.eff.Continuation.apply(Continuation.scala:72)
	at org.atnos.eff.Interpret$$anonfun$interpretContinuation$1$1.apply(Interpret.scala:43)
	at org.atnos.eff.Interpret$$anonfun$interpretContinuation$1$1.apply(Interpret.scala:43)
	at org.atnos.eff.Continuation.go$1(Continuation.scala:54)
	at org.atnos.eff.Continuation.apply(Continuation.scala:72)
	at org.atnos.eff.Interpret$$anonfun$interpretContinuation$1$1.apply(Interpret.scala:43)
	at org.atnos.eff.Interpret$$anonfun$interpretContinuation$1$1.apply(Interpret.scala:43)
	at org.atnos.eff.Continuation.go$1(Continuation.scala:54)
	at org.atnos.eff.Continuation.apply(Continuation.scala:72)
	at org.atnos.eff.EffInterpretation$$anonfun$runEval$1$1.apply(Eff.scala:361)
	at org.atnos.eff.EffInterpretation$$anonfun$runEval$1$1.apply(Eff.scala:361)
	at cats.Later.value$lzycompute(Eval.scala:151)
	at cats.Later.value(Eval.scala:150)
	at cats.Eval$.loop$1(Eval.scala:351)
	at cats.Eval$.cats$Eval$$evaluate(Eval.scala:372)
	at cats.Eval$FlatMap.value(Eval.scala:308)
	at org.atnos.eff.EffInterpretation$class.run(Eff.scala:369)
	at org.atnos.eff.Eff$.run(Eff.scala:149)
	at org.atnos.eff.syntax.EffNoEffectOps$.run$extension(eff.scala:59)
	at org.opencypher.okapi.ir.impl.package$RichIRBuilderStack.run(package.scala:52)
	at org.opencypher.okapi.ir.impl.IRBuilder$.process(IRBuilder.scala:56)
	at org.opencypher.okapi.relational.api.graph.RelationalCypherSession$$anonfun$6.apply(RelationalCypherSession.scala:169)
	at org.opencypher.okapi.relational.api.graph.RelationalCypherSession$$anonfun$6.apply(RelationalCypherSession.scala:169)
	at org.opencypher.okapi.relational.api.graph.RelationalCypherSession.time(RelationalCypherSession.scala:119)
	at org.opencypher.okapi.relational.api.graph.RelationalCypherSession.cypherOnGraph(RelationalCypherSession.scala:169)
	at org.opencypher.okapi.relational.api.graph.RelationalCypherGraph$class.cypher(RelationalCypherGraph.scala:106)
	at org.opencypher.okapi.relational.impl.graph.ScanGraph.cypher(ScanGraph.scala:43)
	at org.opencypher.okapi.relational.impl.graph.ScanGraph.cypher(ScanGraph.scala:43)

@Mats-SX
Copy link
Member

Mats-SX commented Sep 26, 2023

As a last attempt, try adding an upper bound to the variable-length pattern. I noted that we declared unbounded var-length patterns as not implemented here.

MATCH (start:Application {alias: "r1shsummaryv2"})-[r:DependsOn*..100]->(end:Application {alias: "r1appmetasvccont"})
UNWIND r AS relationship
WITH startNode(relationship) AS source
RETURN source {.alias, .properties} AS valueMap

@ministat
Copy link
Author

The exception changed, but unfortunately, it still failed for something not implemented.

23/09/27 10:25:12 WARN SparkSession$Builder: Using an existing SparkSession; some configuration may not take effect.
Exception in thread "main" org.opencypher.okapi.impl.exception.NotImplementedException: The expression DesugaredMapProjection(Variable(source),List(LiteralEntry(PropertyKeyName(alias),Property(Variable(source),PropertyKeyName(alias))), LiteralEntry(PropertyKeyName(properties),Property(Variable(source),PropertyKeyName(properties)))),false) [line 4, column 8 (offset: 189)] is not supported by the system
	at org.opencypher.okapi.ir.impl.IRBuilderContext.infer(IRBuilderContext.scala:84)
	at org.opencypher.okapi.ir.impl.IRBuilderContext.convertExpression(IRBuilderContext.scala:68)
	at org.opencypher.okapi.ir.impl.IRBuilder$$anonfun$org$opencypher$okapi$ir$impl$IRBuilder$$convertExpr$2.apply(IRBuilder.scala:567)
	at org.opencypher.okapi.ir.impl.IRBuilder$$anonfun$org$opencypher$okapi$ir$impl$IRBuilder$$convertExpr$2.apply(IRBuilder.scala:566)
	at org.atnos.eff.Continuation$$anonfun$map$1.apply(Continuation.scala:39)
	at org.atnos.eff.Continuation$$anonfun$map$1.apply(Continuation.scala:39)
	at org.atnos.eff.Continuation.go$1(Continuation.scala:54)
	at org.atnos.eff.Continuation.apply(Continuation.scala:72)
	at org.atnos.eff.Interpret$$anonfun$interpretContinuation$1$1.apply(Interpret.scala:43)
	at org.atnos.eff.Interpret$$anonfun$interpretContinuation$1$1.apply(Interpret.scala:43)
	at org.atnos.eff.Continuation.go$1(Continuation.scala:54)
	at org.atnos.eff.Continuation.apply(Continuation.scala:72)
	at org.atnos.eff.Interpret$$anonfun$interpretContinuation$1$1.apply(Interpret.scala:43)
	at org.atnos.eff.Interpret$$anonfun$interpretContinuation$1$1.apply(Interpret.scala:43)
	at org.atnos.eff.Continuation.go$1(Continuation.scala:54)
	at org.atnos.eff.Continuation.apply(Continuation.scala:72)
	at org.atnos.eff.EffInterpretation$$anonfun$runEval$1$1.apply(Eff.scala:361)
	at org.atnos.eff.EffInterpretation$$anonfun$runEval$1$1.apply(Eff.scala:361)
	at cats.Later.value$lzycompute(Eval.scala:151)
	at cats.Later.value(Eval.scala:150)
	at cats.Eval$.loop$1(Eval.scala:351)
	at cats.Eval$.cats$Eval$$evaluate(Eval.scala:372)
	at cats.Eval$FlatMap.value(Eval.scala:308)
	at org.atnos.eff.EffInterpretation$class.run(Eff.scala:369)
	at org.atnos.eff.Eff$.run(Eff.scala:149)
	at org.atnos.eff.syntax.EffNoEffectOps$.run$extension(eff.scala:59)
	at org.opencypher.okapi.ir.impl.package$RichIRBuilderStack.run(package.scala:52)
	at org.opencypher.okapi.ir.impl.IRBuilder$.process(IRBuilder.scala:56)
	at org.opencypher.okapi.relational.api.graph.RelationalCypherSession$$anonfun$6.apply(RelationalCypherSession.scala:169)
	at org.opencypher.okapi.relational.api.graph.RelationalCypherSession$$anonfun$6.apply(RelationalCypherSession.scala:169)
	at org.opencypher.okapi.relational.api.graph.RelationalCypherSession.time(RelationalCypherSession.scala:119)
	at org.opencypher.okapi.relational.api.graph.RelationalCypherSession.cypherOnGraph(RelationalCypherSession.scala:169)
	at org.opencypher.okapi.relational.api.graph.RelationalCypherGraph$class.cypher(RelationalCypherGraph.scala:106)
	at org.opencypher.okapi.relational.impl.graph.ScanGraph.cypher(ScanGraph.scala:43)
	at org.opencypher.okapi.relational.impl.graph.ScanGraph.cypher(ScanGraph.scala:43)
	at com.ebay.nugraph.gremlintomorpheus.Sherlock$.executeCypher(Sherlock.scala:260)
	at com.ebay.nugraph.gremlintomorpheus.MainEntry$.main(MainEntry.scala:16)
	at com.ebay.nugraph.gremlintomorpheus.MainEntry.main(MainEntry.scala)

@ministat
Copy link
Author

@Mats-SX Do you have any document introducing the design and implementation? I'd like to evaluate the effort to support this feature. That will be great if you or your colleagues can provide some help and guide.

@DarthMax
Copy link
Contributor

I think you are quite close, this should work:

MATCH (start:Application {alias: "r1shsummaryv2"})-[r:DependsOn*..100]->(end:Application {alias: "r1appmetasvccont"})
UNWIND r AS relationship
WITH startNode(relationship) AS source
RETURN source.alias, source.properties

There is one caveat though. IIRC the Variable Path Expand will always try to do as many expands as you specify, because we basically unroll this into optional joins in spark. So you might want to play around with that upper bound to get faster query results

@ministat
Copy link
Author

Yes. It looks quite close to be working. However, there is an exception. Can I ignore this?

Exception in thread "main" org.opencypher.okapi.impl.exception.IllegalArgumentException: 

Expected:
	Header does not contain a column for r :: LIST(RELATIONSHIP(:DependsOn) @ session.tmp1).
	[`end._label_`, `end.alias`, `end.label`, `end.lcmstate`, `end.name`, `end.type`, `end:Application`, `end`, `explode(r)`, `r(1).edgelabel`, `r(1):DependsOn`, `r(1)`, `r(2).edgelabel`, `r(2):DependsOn`, `r(2)`, `relationship`, `source(r(1))`, `source(r(2))`, `start._label_`, `start.alias`, `start.label`, `start.lcmstate`, `start.name`, `start.type`, `start:Application`, `start`, `target(r(1))`, `target(r(2))`]
Found:
	none
	at org.opencypher.okapi.relational.impl.table.RecordHeader$$anonfun$column$1.apply(RecordHeader.scala:88)
	at org.opencypher.okapi.relational.impl.table.RecordHeader$$anonfun$column$1.apply(RecordHeader.scala:88)
	at scala.collection.MapLike$class.getOrElse(MapLike.scala:128)
	at scala.collection.AbstractMap.getOrElse(Map.scala:59)
	at org.opencypher.okapi.relational.impl.table.RecordHeader.column(RecordHeader.scala:88)
	at org.opencypher.spark.impl.SparkSQLExprMapper$RichExpression.asSparkSQLExpr(SparkSQLExprMapper.scala:133)
	at org.opencypher.spark.impl.SparkSQLExprMapper$RichExpression.asSparkSQLExpr(SparkSQLExprMapper.scala:371)
	at org.opencypher.spark.impl.SparkSQLExprMapper$RichExpression.asSparkSQLExpr(SparkSQLExprMapper.scala:141)
	at org.opencypher.spark.impl.table.SparkTable$DataFrameTable$$anonfun$4.apply(SparkTable.scala:85)
	at org.opencypher.spark.impl.table.SparkTable$DataFrameTable$$anonfun$4.apply(SparkTable.scala:84)
	at scala.collection.LinearSeqOptimized$class.foldLeft(LinearSeqOptimized.scala:124)
	at scala.collection.immutable.List.foldLeft(List.scala:84)
	at org.opencypher.spark.impl.table.SparkTable$DataFrameTable.withColumns(SparkTable.scala:84)
	at org.opencypher.spark.impl.table.SparkTable$DataFrameTable.withColumns(SparkTable.scala:53)
	at org.opencypher.okapi.relational.impl.operators.Add._table$lzycompute(RelationalOperator.scala:246)
	at org.opencypher.okapi.relational.impl.operators.Add._table(RelationalOperator.scala:240)
	at org.opencypher.okapi.relational.impl.operators.RelationalOperator.table(RelationalOperator.scala:77)
	at org.opencypher.okapi.relational.impl.operators.Add._table$lzycompute(RelationalOperator.scala:246)
	at org.opencypher.okapi.relational.impl.operators.Add._table(RelationalOperator.scala:240)
	at org.opencypher.okapi.relational.impl.operators.RelationalOperator.table(RelationalOperator.scala:77)
	at org.opencypher.okapi.relational.impl.operators.Add._table$lzycompute(RelationalOperator.scala:246)
	at org.opencypher.okapi.relational.impl.operators.Add._table(RelationalOperator.scala:240)
	at org.opencypher.okapi.relational.impl.operators.RelationalOperator.table(RelationalOperator.scala:77)
	at org.opencypher.okapi.relational.impl.operators.Add._table$lzycompute(RelationalOperator.scala:246)
	at org.opencypher.okapi.relational.impl.operators.Add._table(RelationalOperator.scala:240)
	at org.opencypher.okapi.relational.impl.operators.RelationalOperator.table(RelationalOperator.scala:77)
	at org.opencypher.okapi.relational.impl.operators.Select._table$lzycompute(RelationalOperator.scala:330)
	at org.opencypher.okapi.relational.impl.operators.Select._table(RelationalOperator.scala:328)
	at org.opencypher.okapi.relational.impl.operators.RelationalOperator.table(RelationalOperator.scala:77)
	at org.opencypher.okapi.relational.impl.operators.AlignColumnsWithReturnItems._table$lzycompute(RelationalOperator.scala:355)
	at org.opencypher.okapi.relational.impl.operators.AlignColumnsWithReturnItems._table(RelationalOperator.scala:353)
	at org.opencypher.okapi.relational.impl.operators.RelationalOperator.table(RelationalOperator.scala:77)
	at org.opencypher.okapi.relational.api.planning.RelationalCypherResult$$anonfun$getRecords$1.apply(RelationalCypherResult.scala:70)
	at org.opencypher.okapi.relational.api.planning.RelationalCypherResult$$anonfun$getRecords$1.apply(RelationalCypherResult.scala:64)
	at scala.Option.flatMap(Option.scala:171)
	at org.opencypher.okapi.relational.api.planning.RelationalCypherResult.getRecords(RelationalCypherResult.scala:64)
	at org.opencypher.okapi.api.graph.CypherResult$class.records(CypherResult.scala:71)
	at org.opencypher.okapi.relational.api.planning.RelationalCypherResult.records(RelationalCypherResult.scala:38)
	at com.ebay.nugraph.gremlintomorpheus.Sherlock$.executeCypher(Sherlock.scala:270)
	at com.ebay.nugraph.gremlintomorpheus.MainEntry$.main(MainEntry.scala:16)
	at com.ebay.nugraph.gremlintomorpheus.MainEntry.main(MainEntry.scala)

Source code in SparkSQLExprMapper.scala:

        case _: Var | _: Param | _: HasLabel | _: HasType | _: StartNode | _: EndNode =>
          verify

          val colName = header.column(expr) // <- throw exception
          if (df.columns.contains(colName)) {
            df.col(colName)
          } else {
            NULL_LIT
          }

@Mats-SX
Copy link
Member

Mats-SX commented Oct 3, 2023

I really don't recall how this works. It looks like we're expanding the relationship variable r into multiple variables r(x) where x denotes the distance from the source node. So with an upper bound of 10 you would get 10 such r variables. But we're not renaming things well enough, because explode(r) references just r not r(x) which cannot be found.

I couldn't say what is wrong -- my best advice is to try some more alternatives, maybe this one:

MATCH (start:Application {alias: "r1shsummaryv2"})-[r:DependsOn*..2]->(end:Application {alias: "r1appmetasvccont"})
RETURN r

But it could also be the case that what you're trying to do is not properly implemented. In case you want to implement more support feel free to go ahead. At Neo4j we are not pursuing anything with this project currently. We do have another project https://github.com/neo4j-contrib/neo4j-spark-connector which is actively maintained. I've contacted the people who work on that to see if it can help your use case.

@ministat
Copy link
Author

ministat commented Oct 4, 2023

Thanks for your patient response. The following cypher does not throw exception nor give the expected result.

MATCH (start:Application {alias: "r1shsummaryv2"})-[r:DependsOn*..2]->(end:Application {alias: "r1appmetasvccont"})
RETURN r
╔══════╤══════╤══════════════════════════════════════════════════════════════════════════════════════════╗
║ r(1) │ r(2) │ r                                                                                        ║
╠══════╪══════╪══════════════════════════════════════════════════════════════════════════════════════════╣
║ null │ null │ [[[:`DependsOn` {`edgelabel`: 'DependsOn'}]]]                                            ║
║ null │ null │ [[[:`DependsOn` {`edgelabel`: 'DependsOn'}], [:`DependsOn` {`edgelabel`: 'DependsOn'}]]] ║
║ null │ null │ [[[:`DependsOn` {`edgelabel`: 'DependsOn'}], [:`DependsOn` {`edgelabel`: 'DependsOn'}]]] ║
║ null │ null │ [[[:`DependsOn` {`edgelabel`: 'DependsOn'}], [:`DependsOn` {`edgelabel`: 'DependsOn'}]]] ║
║ null │ null │ [[[:`DependsOn` {`edgelabel`: 'DependsOn'}], [:`DependsOn` {`edgelabel`: 'DependsOn'}]]] ║
║ null │ null │ [[[:`DependsOn` {`edgelabel`: 'DependsOn'}], [:`DependsOn` {`edgelabel`: 'DependsOn'}]]] ║
║ null │ null │ [[[:`DependsOn` {`edgelabel`: 'DependsOn'}], [:`DependsOn` {`edgelabel`: 'DependsOn'}]]] ║
║ null │ null │ [[[:`DependsOn` {`edgelabel`: 'DependsOn'}], [:`DependsOn` {`edgelabel`: 'DependsOn'}]]] ║
║ null │ null │ [[[:`DependsOn` {`edgelabel`: 'DependsOn'}], [:`DependsOn` {`edgelabel`: 'DependsOn'}]]] ║
║ null │ null │ [[[:`DependsOn` {`edgelabel`: 'DependsOn'}], [:`DependsOn` {`edgelabel`: 'DependsOn'}]]] ║
║ null │ null │ [[[:`DependsOn` {`edgelabel`: 'DependsOn'}], [:`DependsOn` {`edgelabel`: 'DependsOn'}]]] ║
║ null │ null │ [[[:`DependsOn` {`edgelabel`: 'DependsOn'}], [:`DependsOn` {`edgelabel`: 'DependsOn'}]]] ║
║ null │ null │ [[[:`DependsOn` {`edgelabel`: 'DependsOn'}], [:`DependsOn` {`edgelabel`: 'DependsOn'}]]] ║
║ null │ null │ [[[:`DependsOn` {`edgelabel`: 'DependsOn'}], [:`DependsOn` {`edgelabel`: 'DependsOn'}]]] ║
║ null │ null │ [[[:`DependsOn` {`edgelabel`: 'DependsOn'}], [:`DependsOn` {`edgelabel`: 'DependsOn'}]]] ║
║ null │ null │ [[[:`DependsOn` {`edgelabel`: 'DependsOn'}], [:`DependsOn` {`edgelabel`: 'DependsOn'}]]] ║
║ null │ null │ [[[:`DependsOn` {`edgelabel`: 'DependsOn'}], [:`DependsOn` {`edgelabel`: 'DependsOn'}]]] ║
║ null │ null │ [[[:`DependsOn` {`edgelabel`: 'DependsOn'}], [:`DependsOn` {`edgelabel`: 'DependsOn'}]]] ║
║ null │ null │ [[[:`DependsOn` {`edgelabel`: 'DependsOn'}], [:`DependsOn` {`edgelabel`: 'DependsOn'}]]] ║
║ null │ null │ [[[:`DependsOn` {`edgelabel`: 'DependsOn'}], [:`DependsOn` {`edgelabel`: 'DependsOn'}]]] ║
║ null │ null │ [[[:`DependsOn` {`edgelabel`: 'DependsOn'}], [:`DependsOn` {`edgelabel`: 'DependsOn'}]]] ║
║ null │ null │ [[[:`DependsOn` {`edgelabel`: 'DependsOn'}], [:`DependsOn` {`edgelabel`: 'DependsOn'}]]] ║
║ null │ null │ [[[:`DependsOn` {`edgelabel`: 'DependsOn'}], [:`DependsOn` {`edgelabel`: 'DependsOn'}]]] ║
║ null │ null │ [[[:`DependsOn` {`edgelabel`: 'DependsOn'}], [:`DependsOn` {`edgelabel`: 'DependsOn'}]]] ║
║ null │ null │ [[[:`DependsOn` {`edgelabel`: 'DependsOn'}], [:`DependsOn` {`edgelabel`: 'DependsOn'}]]] ║
║ null │ null │ [[[:`DependsOn` {`edgelabel`: 'DependsOn'}], [:`DependsOn` {`edgelabel`: 'DependsOn'}]]] ║
║ null │ null │ [[[:`DependsOn` {`edgelabel`: 'DependsOn'}], [:`DependsOn` {`edgelabel`: 'DependsOn'}]]] ║
║ null │ null │ [[[:`DependsOn` {`edgelabel`: 'DependsOn'}], [:`DependsOn` {`edgelabel`: 'DependsOn'}]]] ║
║ null │ null │ [[[:`DependsOn` {`edgelabel`: 'DependsOn'}], [:`DependsOn` {`edgelabel`: 'DependsOn'}]]] ║
║ null │ null │ [[[:`DependsOn` {`edgelabel`: 'DependsOn'}], [:`DependsOn` {`edgelabel`: 'DependsOn'}]]] ║
║ null │ null │ [[[:`DependsOn` {`edgelabel`: 'DependsOn'}], [:`DependsOn` {`edgelabel`: 'DependsOn'}]]] ║
║ null │ null │ [[[:`DependsOn` {`edgelabel`: 'DependsOn'}], [:`DependsOn` {`edgelabel`: 'DependsOn'}]]] ║
║ null │ null │ [[[:`DependsOn` {`edgelabel`: 'DependsOn'}], [:`DependsOn` {`edgelabel`: 'DependsOn'}]]] ║
║ null │ null │ [[[:`DependsOn` {`edgelabel`: 'DependsOn'}], [:`DependsOn` {`edgelabel`: 'DependsOn'}]]] ║
║ null │ null │ [[[:`DependsOn` {`edgelabel`: 'DependsOn'}], [:`DependsOn` {`edgelabel`: 'DependsOn'}]]] ║
║ null │ null │ [[[:`DependsOn` {`edgelabel`: 'DependsOn'}], [:`DependsOn` {`edgelabel`: 'DependsOn'}]]] ║
║ null │ null │ [[[:`DependsOn` {`edgelabel`: 'DependsOn'}], [:`DependsOn` {`edgelabel`: 'DependsOn'}]]] ║
║ null │ null │ [[[:`DependsOn` {`edgelabel`: 'DependsOn'}], [:`DependsOn` {`edgelabel`: 'DependsOn'}]]] ║
║ null │ null │ [[[:`DependsOn` {`edgelabel`: 'DependsOn'}], [:`DependsOn` {`edgelabel`: 'DependsOn'}]]] ║
║ null │ null │ [[[:`DependsOn` {`edgelabel`: 'DependsOn'}], [:`DependsOn` {`edgelabel`: 'DependsOn'}]]] ║
║ null │ null │ [[[:`DependsOn` {`edgelabel`: 'DependsOn'}], [:`DependsOn` {`edgelabel`: 'DependsOn'}]]] ║
║ null │ null │ [[[:`DependsOn` {`edgelabel`: 'DependsOn'}], [:`DependsOn` {`edgelabel`: 'DependsOn'}]]] ║
║ null │ null │ [[[:`DependsOn` {`edgelabel`: 'DependsOn'}], [:`DependsOn` {`edgelabel`: 'DependsOn'}]]] ║
║ null │ null │ [[[:`DependsOn` {`edgelabel`: 'DependsOn'}], [:`DependsOn` {`edgelabel`: 'DependsOn'}]]] ║
║ null │ null │ [[[:`DependsOn` {`edgelabel`: 'DependsOn'}], [:`DependsOn` {`edgelabel`: 'DependsOn'}]]] ║
║ null │ null │ [[[:`DependsOn` {`edgelabel`: 'DependsOn'}], [:`DependsOn` {`edgelabel`: 'DependsOn'}]]] ║
║ null │ null │ [[[:`DependsOn` {`edgelabel`: 'DependsOn'}], [:`DependsOn` {`edgelabel`: 'DependsOn'}]]] ║
║ null │ null │ [[[:`DependsOn` {`edgelabel`: 'DependsOn'}], [:`DependsOn` {`edgelabel`: 'DependsOn'}]]] ║
║ null │ null │ [[[:`DependsOn` {`edgelabel`: 'DependsOn'}], [:`DependsOn` {`edgelabel`: 'DependsOn'}]]] ║
║ null │ null │ [[[:`DependsOn` {`edgelabel`: 'DependsOn'}], [:`DependsOn` {`edgelabel`: 'DependsOn'}]]] ║
║ null │ null │ [[[:`DependsOn` {`edgelabel`: 'DependsOn'}], [:`DependsOn` {`edgelabel`: 'DependsOn'}]]] ║
║ null │ null │ [[[:`DependsOn` {`edgelabel`: 'DependsOn'}], [:`DependsOn` {`edgelabel`: 'DependsOn'}]]] ║
║ null │ null │ [[[:`DependsOn` {`edgelabel`: 'DependsOn'}], [:`DependsOn` {`edgelabel`: 'DependsOn'}]]] ║
║ null │ null │ [[[:`DependsOn` {`edgelabel`: 'DependsOn'}], [:`DependsOn` {`edgelabel`: 'DependsOn'}]]] ║
║ null │ null │ [[[:`DependsOn` {`edgelabel`: 'DependsOn'}], [:`DependsOn` {`edgelabel`: 'DependsOn'}]]] ║
║ null │ null │ [[[:`DependsOn` {`edgelabel`: 'DependsOn'}], [:`DependsOn` {`edgelabel`: 'DependsOn'}]]] ║
║ null │ null │ [[[:`DependsOn` {`edgelabel`: 'DependsOn'}], [:`DependsOn` {`edgelabel`: 'DependsOn'}]]] ║
║ null │ null │ [[[:`DependsOn` {`edgelabel`: 'DependsOn'}], [:`DependsOn` {`edgelabel`: 'DependsOn'}]]] ║
║ null │ null │ [[[:`DependsOn` {`edgelabel`: 'DependsOn'}], [:`DependsOn` {`edgelabel`: 'DependsOn'}]]] ║
║ null │ null │ [[[:`DependsOn` {`edgelabel`: 'DependsOn'}], [:`DependsOn` {`edgelabel`: 'DependsOn'}]]] ║
║ null │ null │ [[[:`DependsOn` {`edgelabel`: 'DependsOn'}], [:`DependsOn` {`edgelabel`: 'DependsOn'}]]] ║
║ null │ null │ [[[:`DependsOn` {`edgelabel`: 'DependsOn'}], [:`DependsOn` {`edgelabel`: 'DependsOn'}]]] ║
║ null │ null │ [[[:`DependsOn` {`edgelabel`: 'DependsOn'}], [:`DependsOn` {`edgelabel`: 'DependsOn'}]]] ║
║ null │ null │ [[[:`DependsOn` {`edgelabel`: 'DependsOn'}], [:`DependsOn` {`edgelabel`: 'DependsOn'}]]] ║
║ null │ null │ [[[:`DependsOn` {`edgelabel`: 'DependsOn'}], [:`DependsOn` {`edgelabel`: 'DependsOn'}]]] ║
║ null │ null │ [[[:`DependsOn` {`edgelabel`: 'DependsOn'}], [:`DependsOn` {`edgelabel`: 'DependsOn'}]]] ║
║ null │ null │ [[[:`DependsOn` {`edgelabel`: 'DependsOn'}], [:`DependsOn` {`edgelabel`: 'DependsOn'}]]] ║
║ null │ null │ [[[:`DependsOn` {`edgelabel`: 'DependsOn'}], [:`DependsOn` {`edgelabel`: 'DependsOn'}]]] ║
║ null │ null │ [[[:`DependsOn` {`edgelabel`: 'DependsOn'}], [:`DependsOn` {`edgelabel`: 'DependsOn'}]]] ║
╚══════╧══════╧══════════════════════════════════════════════════════════════════════════════════════════╝

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants