neo4j-core 3.0.0.alpha.13 → 3.0.0.alpha.14
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +60 -49
- data/lib/mydb/active_tx_log +1 -0
- data/lib/mydb/index/lucene-store.db +0 -0
- data/lib/mydb/index/lucene.log.1 +0 -0
- data/lib/mydb/index/lucene.log.active +0 -0
- data/lib/mydb/lock +0 -0
- data/lib/mydb/messages.log +313 -0
- data/lib/mydb/neostore +0 -0
- data/lib/mydb/neostore.id +0 -0
- data/lib/mydb/neostore.labeltokenstore.db +0 -0
- data/lib/mydb/neostore.labeltokenstore.db.id +0 -0
- data/lib/mydb/neostore.labeltokenstore.db.names +0 -0
- data/lib/mydb/neostore.labeltokenstore.db.names.id +0 -0
- data/lib/mydb/neostore.nodestore.db +0 -0
- data/lib/mydb/neostore.nodestore.db.id +0 -0
- data/lib/mydb/neostore.nodestore.db.labels +0 -0
- data/lib/mydb/neostore.nodestore.db.labels.id +0 -0
- data/lib/mydb/neostore.propertystore.db +0 -0
- data/lib/mydb/neostore.propertystore.db.arrays +0 -0
- data/lib/mydb/neostore.propertystore.db.arrays.id +0 -0
- data/lib/mydb/neostore.propertystore.db.id +0 -0
- data/lib/mydb/neostore.propertystore.db.index +0 -0
- data/lib/mydb/neostore.propertystore.db.index.id +0 -0
- data/lib/mydb/neostore.propertystore.db.index.keys +0 -0
- data/lib/mydb/neostore.propertystore.db.index.keys.id +0 -0
- data/lib/mydb/neostore.propertystore.db.strings +0 -0
- data/lib/mydb/neostore.propertystore.db.strings.id +0 -0
- data/lib/mydb/neostore.relationshipstore.db +0 -0
- data/lib/mydb/neostore.relationshipstore.db.id +0 -0
- data/lib/mydb/neostore.relationshiptypestore.db +0 -0
- data/lib/mydb/neostore.relationshiptypestore.db.id +0 -0
- data/lib/mydb/neostore.relationshiptypestore.db.names +0 -0
- data/lib/mydb/neostore.relationshiptypestore.db.names.id +0 -0
- data/lib/mydb/neostore.schemastore.db +0 -0
- data/lib/mydb/neostore.schemastore.db.id +0 -0
- data/lib/mydb/nioneo_logical.log.1 +0 -0
- data/lib/mydb/nioneo_logical.log.active +0 -0
- data/lib/mydb/schema/label/lucene/write.lock +0 -0
- data/lib/mydb/store_lock +0 -0
- data/lib/mydb/tm_tx_log.1 +0 -0
- data/lib/neo4j-core.rb +1 -2
- data/lib/neo4j-core/query_builder.rb +200 -0
- data/lib/neo4j-core/version.rb +1 -1
- data/lib/neo4j-embedded.rb +1 -0
- data/lib/neo4j-embedded/cypher_response.rb +89 -0
- data/lib/neo4j-embedded/cypher_response.rb~ +85 -0
- data/lib/neo4j-embedded/embedded_node.rb +12 -0
- data/lib/neo4j-embedded/embedded_node.rb~ +201 -0
- data/lib/neo4j-embedded/embedded_relationship.rb +8 -0
- data/lib/neo4j-embedded/embedded_relationship.rb~ +62 -0
- data/lib/neo4j-embedded/embedded_session.rb +20 -12
- data/lib/neo4j-embedded/embedded_session.rb~ +145 -0
- data/lib/neo4j-server/cypher_relationship.rb +6 -11
- data/lib/neo4j-server/cypher_response.rb +43 -5
- data/lib/neo4j-server/cypher_response.rb~ +155 -0
- data/lib/neo4j-server/cypher_session.rb +54 -19
- data/lib/neo4j/label.rb +7 -51
- data/lib/neo4j/node.rb +21 -19
- data/lib/neo4j/relationship.rb +7 -7
- data/lib/neo4j/session.rb +70 -28
- data/lib/neo4j/session.rb~ +202 -0
- data/neo4j-core.gemspec +0 -1
- metadata +49 -16
@@ -25,8 +25,7 @@ module Neo4j::Server
|
|
25
25
|
def load_resource
|
26
26
|
id = neo_id
|
27
27
|
unless @resource_data
|
28
|
-
|
29
|
-
@resource_data = r.first_data
|
28
|
+
@resource_data = @session._query_or_fail("START n=relationship(#{id}) RETURN n", true) # r.first_data
|
30
29
|
end
|
31
30
|
end
|
32
31
|
|
@@ -44,21 +43,17 @@ module Neo4j::Server
|
|
44
43
|
|
45
44
|
def get_property(key)
|
46
45
|
id = neo_id
|
47
|
-
|
48
|
-
expect_response_code(r.response, 200)
|
49
|
-
r.first_data
|
46
|
+
@session._query_or_fail("START n=relationship(#{id}) RETURN n.`#{key}`", true)
|
50
47
|
end
|
51
48
|
|
52
49
|
def set_property(key,value)
|
53
50
|
id = neo_id
|
54
|
-
|
55
|
-
expect_response_code(r.response, 200)
|
51
|
+
@session._query_or_fail("START n=relationship(#{id}) SET n.`#{key}` = {value}", false, {value: value})
|
56
52
|
end
|
57
53
|
|
58
54
|
def remove_property(key)
|
59
55
|
id = neo_id
|
60
|
-
|
61
|
-
expect_response_code(r.response, 200)
|
56
|
+
@session._query_or_fail("START n=relationship(#{id}) REMOVE n.`#{key}`")
|
62
57
|
end
|
63
58
|
|
64
59
|
# (see Neo4j::Relationship#props)
|
@@ -86,12 +81,12 @@ module Neo4j::Server
|
|
86
81
|
|
87
82
|
def del
|
88
83
|
id = neo_id
|
89
|
-
@session.
|
84
|
+
@session._query("START n=relationship(#{id}) DELETE n").raise_unless_response_code(200)
|
90
85
|
end
|
91
86
|
|
92
87
|
def exist?
|
93
88
|
id = neo_id
|
94
|
-
response = @session.
|
89
|
+
response = @session._query("START n=relationship(#{id}) RETURN n")
|
95
90
|
|
96
91
|
if (!response.error?)
|
97
92
|
return true
|
@@ -22,23 +22,61 @@ module Neo4j::Server
|
|
22
22
|
def_delegator :@response, :data
|
23
23
|
def_delegator :@response, :columns
|
24
24
|
|
25
|
-
def initialize(response)
|
25
|
+
def initialize(response, map_return_procs, query)
|
26
26
|
@response = response
|
27
|
+
@map_return_procs = map_return_procs
|
28
|
+
@query = query
|
27
29
|
end
|
28
30
|
|
29
|
-
def
|
31
|
+
def to_s
|
32
|
+
@query
|
33
|
+
end
|
34
|
+
|
35
|
+
def inspect
|
36
|
+
"Enumerable query: '#{@query}'"
|
37
|
+
end
|
38
|
+
|
39
|
+
def each_no_mapping
|
30
40
|
data.each do |row|
|
31
41
|
hash = {}
|
32
42
|
row.each_with_index do |row, i|
|
33
|
-
|
43
|
+
key = columns[i].to_sym
|
44
|
+
hash[key] = row
|
34
45
|
end
|
35
46
|
yield hash
|
36
47
|
end
|
37
48
|
end
|
49
|
+
|
50
|
+
def each_multi_column_mapping
|
51
|
+
data.each do |row|
|
52
|
+
hash = {}
|
53
|
+
row.each_with_index do |row, i|
|
54
|
+
key = columns[i].to_sym
|
55
|
+
proc = @map_return_procs[key]
|
56
|
+
hash[key] = proc ? proc.call(row) : row
|
57
|
+
end
|
58
|
+
yield hash
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
def each_single_column_mapping
|
63
|
+
data.each do |row|
|
64
|
+
result = @map_return_procs.call(row.first)
|
65
|
+
yield result
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
def each(&block)
|
70
|
+
case @map_return_procs
|
71
|
+
when NilClass then each_no_mapping &block
|
72
|
+
when Hash then each_multi_column_mapping &block
|
73
|
+
else each_single_column_mapping &block
|
74
|
+
end
|
75
|
+
end
|
38
76
|
end
|
39
77
|
|
40
|
-
def to_hash_enumeration
|
41
|
-
HashEnumeration.new(self)
|
78
|
+
def to_hash_enumeration(map_return_procs={}, cypher='')
|
79
|
+
HashEnumeration.new(self, map_return_procs, cypher)
|
42
80
|
end
|
43
81
|
|
44
82
|
def initialize(response, uncommited = false)
|
@@ -0,0 +1,155 @@
|
|
1
|
+
module Neo4j::Server
|
2
|
+
class CypherResponse
|
3
|
+
attr_reader :data, :columns, :error_msg, :error_status, :error_code, :response
|
4
|
+
|
5
|
+
class ResponseError < StandardError
|
6
|
+
attr_reader :status, :code
|
7
|
+
|
8
|
+
def initialize(msg, status, code)
|
9
|
+
super(msg)
|
10
|
+
@status = status
|
11
|
+
@code = code
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
|
16
|
+
class HashEnumeration
|
17
|
+
include Enumerable
|
18
|
+
extend Forwardable
|
19
|
+
def_delegator :@response, :error_msg
|
20
|
+
def_delegator :@response, :error_status
|
21
|
+
def_delegator :@response, :error_code
|
22
|
+
def_delegator :@response, :data
|
23
|
+
def_delegator :@response, :columns
|
24
|
+
|
25
|
+
def initialize(response, map_return_procs, query)
|
26
|
+
@response = response
|
27
|
+
@map_return_procs = map_return_procs
|
28
|
+
@query = query
|
29
|
+
end
|
30
|
+
|
31
|
+
def to_s
|
32
|
+
@query
|
33
|
+
end
|
34
|
+
|
35
|
+
puts "RELOADED"
|
36
|
+
def inspect
|
37
|
+
#"Enumerable query: '#{@query}' map_return: [#{@map_return_procs.keys.join(', ')}]"
|
38
|
+
"Enumerable query: '#{@query}' map_return: [#{@map_return_procs.keys.inspect}]"
|
39
|
+
end
|
40
|
+
|
41
|
+
def each_no_mapping
|
42
|
+
data.each do |row|
|
43
|
+
hash = {}
|
44
|
+
row.each_with_index do |row, i|
|
45
|
+
key = columns[i].to_sym
|
46
|
+
hash[key] = row
|
47
|
+
end
|
48
|
+
yield hash
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
def each_multi_column_mapping
|
53
|
+
data.each do |row|
|
54
|
+
hash = {}
|
55
|
+
row.each_with_index do |row, i|
|
56
|
+
key = columns[i].to_sym
|
57
|
+
proc = @map_return_procs[key]
|
58
|
+
hash[key] = proc ? proc.call(row) : row
|
59
|
+
end
|
60
|
+
yield hash
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
def each_single_column_mapping
|
65
|
+
data.each do |row|
|
66
|
+
result = @map_return_procs.call(row.first)
|
67
|
+
yield result
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
def each(&block)
|
72
|
+
case @map_return_procs
|
73
|
+
when NilClass then each_no_mapping &block
|
74
|
+
when Hash then each_multi_column_mapping &block
|
75
|
+
else each_single_column_mapping &block
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
def to_hash_enumeration(map_return_procs={}, cypher='')
|
81
|
+
HashEnumeration.new(self, map_return_procs, cypher)
|
82
|
+
end
|
83
|
+
|
84
|
+
def initialize(response, uncommited = false)
|
85
|
+
@response = response
|
86
|
+
@uncommited = uncommited
|
87
|
+
end
|
88
|
+
|
89
|
+
|
90
|
+
def first_data
|
91
|
+
if uncommited?
|
92
|
+
@data.first['row'].first
|
93
|
+
else
|
94
|
+
@data[0][0]
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
98
|
+
def error?
|
99
|
+
!!@error
|
100
|
+
end
|
101
|
+
|
102
|
+
def uncommited?
|
103
|
+
@uncommited
|
104
|
+
end
|
105
|
+
|
106
|
+
def raise_unless_response_code(code)
|
107
|
+
raise "Response code #{response.code}, expected #{code} for #{response.request.path}, #{response.body}" unless response.code == code
|
108
|
+
end
|
109
|
+
|
110
|
+
def set_data(data, columns)
|
111
|
+
@data = data
|
112
|
+
@columns = columns
|
113
|
+
self
|
114
|
+
end
|
115
|
+
|
116
|
+
def set_error(error_msg, error_status, error_core)
|
117
|
+
@error = true
|
118
|
+
@error_msg = error_msg
|
119
|
+
@error_status = error_status
|
120
|
+
@error_code = error_core
|
121
|
+
self
|
122
|
+
end
|
123
|
+
|
124
|
+
def raise_error
|
125
|
+
raise "Tried to raise error without an error" unless @error
|
126
|
+
raise ResponseError.new(@error_msg, @error_status, @error_code)
|
127
|
+
end
|
128
|
+
|
129
|
+
def self.create_with_no_tx(response)
|
130
|
+
case response.code
|
131
|
+
when 200
|
132
|
+
CypherResponse.new(response).set_data(response['data'], response['columns'])
|
133
|
+
when 400
|
134
|
+
CypherResponse.new(response).set_error(response['message'], response['exception'], response['fullname'])
|
135
|
+
else
|
136
|
+
raise "Unknown response code #{response.code} for #{response.request.path.to_s}"
|
137
|
+
end
|
138
|
+
end
|
139
|
+
|
140
|
+
def self.create_with_tx(response)
|
141
|
+
raise "Unknown response code #{response.code} for #{response.request.path.to_s}" unless response.code == 200
|
142
|
+
|
143
|
+
first_result = response['results'][0]
|
144
|
+
cr = CypherResponse.new(response, true)
|
145
|
+
|
146
|
+
if (response['errors'].empty?)
|
147
|
+
cr.set_data(first_result['data'], first_result['columns'])
|
148
|
+
else
|
149
|
+
first_error = response['errors'].first
|
150
|
+
cr.set_error(first_error['message'], first_error['status'], first_error['code'])
|
151
|
+
end
|
152
|
+
cr
|
153
|
+
end
|
154
|
+
end
|
155
|
+
end
|
@@ -15,9 +15,8 @@ module Neo4j::Server
|
|
15
15
|
# Opens a session to the database
|
16
16
|
# @see Neo4j::Session#open
|
17
17
|
#
|
18
|
-
# @param
|
19
|
-
# @params - see https://github.com/jnunemaker/httparty/blob/master/lib/httparty.rb for supported
|
20
|
-
# HTTParty options
|
18
|
+
# @param [String] endpoint_url - the url to the neo4j server, defaults to 'http://localhost:7474'
|
19
|
+
# @param [Hash] params - see https://github.com/jnunemaker/httparty/blob/master/lib/httparty.rb for supported HTTParty options
|
21
20
|
def self.open(endpoint_url=nil, params = {})
|
22
21
|
endpoint = Neo4jServerEndpoint.new(params)
|
23
22
|
url = endpoint_url || 'http://localhost:7474'
|
@@ -36,10 +35,19 @@ module Neo4j::Server
|
|
36
35
|
Neo4j::Session.register(self)
|
37
36
|
initialize_resource(data_url)
|
38
37
|
Neo4j::Session._notify_listeners(:session_available, self)
|
38
|
+
@query_builder = Neo4j::Core::QueryBuilder.new
|
39
39
|
end
|
40
40
|
|
41
41
|
def to_s
|
42
|
-
"
|
42
|
+
"#{self.class} url: '#{@resource_url}'"
|
43
|
+
end
|
44
|
+
|
45
|
+
def inspect
|
46
|
+
"#{to_s} version: '#{version}'"
|
47
|
+
end
|
48
|
+
|
49
|
+
def version
|
50
|
+
resource_data ? resource_data['neo4j_version'] : ''
|
43
51
|
end
|
44
52
|
|
45
53
|
def initialize_resource(data_url)
|
@@ -109,7 +117,7 @@ module Neo4j::Server
|
|
109
117
|
|
110
118
|
def find_all_nodes(label_name)
|
111
119
|
response = _query_or_fail("MATCH (n:`#{label_name}`) RETURN ID(n)")
|
112
|
-
|
120
|
+
search_result_to_enumerable_first_column(response)
|
113
121
|
end
|
114
122
|
|
115
123
|
def find_nodes(label_name, key, value)
|
@@ -120,20 +128,20 @@ module Neo4j::Server
|
|
120
128
|
WHERE n.#{key} = #{value}
|
121
129
|
RETURN ID(n)
|
122
130
|
CYPHER
|
123
|
-
|
131
|
+
search_result_to_enumerable_first_column(response)
|
124
132
|
end
|
125
133
|
|
126
|
-
def query(*params
|
127
|
-
|
134
|
+
def query(*params)
|
135
|
+
query_hash = @query_builder.to_query_hash(params, :id_to_node)
|
136
|
+
cypher = @query_builder.to_cypher(query_hash)
|
137
|
+
|
138
|
+
result = _query(cypher, query_hash[:params])
|
128
139
|
if result.error?
|
129
140
|
raise Neo4j::Session::CypherError.new(result.error_msg, result.error_code, result.error_status)
|
130
141
|
end
|
131
|
-
result.to_hash_enumeration
|
132
|
-
end
|
133
142
|
|
134
|
-
|
135
|
-
|
136
|
-
super_query(*params, &query_dsl)
|
143
|
+
map_return_procs = @query_builder.to_map_return_procs(query_hash)
|
144
|
+
result.to_hash_enumeration(map_return_procs, cypher)
|
137
145
|
end
|
138
146
|
|
139
147
|
def _query_or_fail(q, single_row = false, params=nil)
|
@@ -142,10 +150,6 @@ module Neo4j::Server
|
|
142
150
|
single_row ? response.first_data : response
|
143
151
|
end
|
144
152
|
|
145
|
-
def query_default_return
|
146
|
-
" RETURN ID(n)"
|
147
|
-
end
|
148
|
-
|
149
153
|
def _query(q, params=nil)
|
150
154
|
curr_tx = Neo4j::Transaction.current
|
151
155
|
if (curr_tx)
|
@@ -158,9 +162,8 @@ module Neo4j::Server
|
|
158
162
|
end
|
159
163
|
end
|
160
164
|
|
161
|
-
def
|
165
|
+
def search_result_to_enumerable_first_column(response)
|
162
166
|
return [] unless response.data
|
163
|
-
|
164
167
|
Enumerator.new do |yielder|
|
165
168
|
response.data.each do |data|
|
166
169
|
yielder << CypherNode.new(self, data[0]).wrapper
|
@@ -169,7 +172,39 @@ module Neo4j::Server
|
|
169
172
|
end
|
170
173
|
|
171
174
|
|
175
|
+
def map_column(key, map, data)
|
176
|
+
case map[key]
|
177
|
+
when :node
|
178
|
+
CypherNode.new(self, data).wrapper
|
179
|
+
when :rel, :relationship
|
180
|
+
CypherRelationship.new(self, data)
|
181
|
+
else
|
182
|
+
data
|
183
|
+
end
|
184
|
+
end
|
185
|
+
|
172
186
|
|
187
|
+
def search_result_to_enumerable(response, ret, map)
|
188
|
+
return [] unless response.data
|
189
|
+
|
190
|
+
if (ret.size == 1)
|
191
|
+
Enumerator.new do |yielder|
|
192
|
+
response.data.each do |data|
|
193
|
+
yielder << map_column(key, map, data[0])
|
194
|
+
end
|
195
|
+
end
|
173
196
|
|
197
|
+
else
|
198
|
+
Enumerator.new do |yielder|
|
199
|
+
response.data.each do |data|
|
200
|
+
hash = {}
|
201
|
+
ret.each_with_index do |key, i|
|
202
|
+
hash[key] = map_column(key, map, data[i])
|
203
|
+
end
|
204
|
+
yielder << hash
|
205
|
+
end
|
206
|
+
end
|
207
|
+
end
|
208
|
+
end
|
174
209
|
end
|
175
210
|
end
|
data/lib/neo4j/label.rb
CHANGED
@@ -3,6 +3,7 @@ module Neo4j
|
|
3
3
|
# See Neo4j::Node how to create and delete nodes
|
4
4
|
# @see http://docs.neo4j.org/chunked/milestone/graphdb-neo4j-labels.html
|
5
5
|
class Label
|
6
|
+
class InvalidQueryError < StandardError; end
|
6
7
|
|
7
8
|
# @abstract
|
8
9
|
def name
|
@@ -61,70 +62,25 @@ module Neo4j
|
|
61
62
|
class << self
|
62
63
|
include Neo4j::Core::CypherTranslator
|
63
64
|
|
65
|
+
# Returns a label of given name that can be used to specifying constraints
|
66
|
+
# @param [Symbol,String] name the name of the label
|
64
67
|
def create(name, session = Neo4j::Session.current)
|
65
68
|
session.create_label(name)
|
66
69
|
end
|
67
70
|
|
68
|
-
def query(label_name, query, session = Neo4j::Session.current)
|
69
|
-
cypher = "MATCH (n:`#{label_name}`)"
|
70
|
-
cypher += condition_to_cypher(query) if query[:conditions] && !query[:conditions].empty?
|
71
|
-
cypher += session.query_default_return
|
72
|
-
cypher += order_to_cypher(query) if query[:order]
|
73
|
-
|
74
|
-
response = session._query_or_fail(cypher)
|
75
|
-
session.search_result_to_enumerable(response) # TODO make it work in Embedded and refactor
|
76
|
-
end
|
77
|
-
|
78
71
|
|
72
|
+
# @return [Enumerable<Neo4j::Node>] all nodes having given label. Nodes can be wrapped in your own model ruby classes.
|
79
73
|
def find_all_nodes(label_name, session = Neo4j::Session.current)
|
80
74
|
session.find_all_nodes(label_name)
|
81
75
|
end
|
82
76
|
|
77
|
+
# @return [Enumerable<Neo4j::Node>] all nodes having given label and properties. Nodes can be wrapped in your own model ruby classes.
|
83
78
|
def find_nodes(label_name, key, value, session = Neo4j::Session.current)
|
84
79
|
session.find_nodes(label_name, key, value)
|
85
80
|
end
|
86
81
|
|
87
|
-
private
|
88
|
-
|
89
|
-
def condition_to_cypher(query)
|
90
|
-
conditions = query[:conditions]
|
91
|
-
" WHERE " + conditions.keys.map do |k|
|
92
|
-
value = conditions[k]
|
93
|
-
if value.is_a? Regexp
|
94
|
-
pattern = (value.casefold? ? "(?i)" : "") + value.source
|
95
|
-
"n.#{k}=~#{escape_value(pattern.gsub(/\\/, '\\\\\\'))}"
|
96
|
-
else
|
97
|
-
"n.#{k}=#{escape_value(conditions[k])}"
|
98
|
-
end
|
99
|
-
end.join(" AND ")
|
100
|
-
end
|
101
|
-
|
102
|
-
def order_to_cypher(query)
|
103
|
-
cypher = " ORDER BY "
|
104
|
-
order = query[:order]
|
105
|
-
|
106
|
-
handleHash = Proc.new do |hash|
|
107
|
-
if (hash.is_a?(Hash))
|
108
|
-
k, v = hash.first
|
109
|
-
raise "only :asc or :desc allowed in order, got #{query.inspect}" unless [:asc, :desc].include?(v)
|
110
|
-
v.to_sym == :asc ? "n.`#{k}`" : "n.`#{k}` DESC"
|
111
|
-
else
|
112
|
-
"n.`#{hash}`" unless hash.is_a?(Hash)
|
113
|
-
end
|
114
|
-
end
|
115
|
-
|
116
|
-
case order
|
117
|
-
when Array
|
118
|
-
cypher += order.map(&handleHash).join(', ')
|
119
|
-
when Hash
|
120
|
-
cypher += handleHash.call(order)
|
121
|
-
else
|
122
|
-
cypher += "n.`#{order}`"
|
123
|
-
end
|
124
|
-
|
125
|
-
cypher
|
126
|
-
end
|
127
82
|
end
|
83
|
+
|
128
84
|
end
|
129
85
|
|
130
|
-
end
|
86
|
+
end
|