reg 0.4.8 → 0.5.0a0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -0
- data/COPYING +0 -0
- data/History.txt +14 -0
- data/Makefile +59 -0
- data/README +87 -40
- data/article.txt +838 -0
- data/{assert.rb → lib/assert.rb} +3 -3
- data/{reg.rb → lib/reg.rb} +11 -4
- data/lib/reg/version.rb +21 -0
- data/lib/regarray.rb +455 -0
- data/{regarrayold.rb → lib/regarrayold.rb} +33 -7
- data/lib/regbackref.rb +73 -0
- data/lib/regbind.rb +230 -0
- data/{regcase.rb → lib/regcase.rb} +15 -5
- data/lib/regcompiler.rb +2341 -0
- data/{regcore.rb → lib/regcore.rb} +196 -85
- data/{regdeferred.rb → lib/regdeferred.rb} +35 -4
- data/{regposition.rb → lib/regevent.rb} +36 -38
- data/lib/reggraphpoint.rb +28 -0
- data/lib/reghash.rb +631 -0
- data/lib/reginstrumentation.rb +36 -0
- data/{regitem_that.rb → lib/regitem_that.rb} +32 -11
- data/{regknows.rb → lib/regknows.rb} +4 -2
- data/{reglogic.rb → lib/reglogic.rb} +76 -59
- data/{reglookab.rb → lib/reglookab.rb} +31 -21
- data/lib/regmatchset.rb +323 -0
- data/{regold.rb → lib/regold.rb} +27 -27
- data/{regpath.rb → lib/regpath.rb} +91 -1
- data/lib/regposition.rb +79 -0
- data/lib/regprogress.rb +1522 -0
- data/lib/regrepeat.rb +307 -0
- data/lib/regreplace.rb +254 -0
- data/lib/regslicing.rb +581 -0
- data/lib/regsubseq.rb +72 -0
- data/lib/regsugar.rb +361 -0
- data/lib/regvar.rb +180 -0
- data/lib/regxform.rb +212 -0
- data/{trace.rb → lib/trace_during.rb} +6 -4
- data/lib/warning.rb +37 -0
- data/parser.txt +26 -8
- data/philosophy.txt +18 -0
- data/reg.gemspec +58 -25
- data/regguide.txt +18 -0
- data/test/andtest.rb +46 -0
- data/test/regcompiler_test.rb +346 -0
- data/test/regdemo.rb +20 -0
- data/{item_thattest.rb → test/regitem_thattest.rb} +2 -2
- data/test/regtest.rb +2125 -0
- data/test/test_all.rb +32 -0
- data/test/test_reg.rb +19 -0
- metadata +108 -73
- data/calc.reg +0 -73
- data/forward_to.rb +0 -49
- data/numberset.rb +0 -200
- data/regarray.rb +0 -675
- data/regbackref.rb +0 -126
- data/regbind.rb +0 -74
- data/reggrid.csv +1 -2
- data/reghash.rb +0 -318
- data/regprogress.rb +0 -1054
- data/regreplace.rb +0 -114
- data/regsugar.rb +0 -230
- data/regtest.rb +0 -1078
- data/regvar.rb +0 -76
data/lib/regmatchset.rb
ADDED
@@ -0,0 +1,323 @@
|
|
1
|
+
=begin copyright
|
2
|
+
reg - the ruby extended grammar
|
3
|
+
Copyright (C) 2016 Caleb Clausen
|
4
|
+
|
5
|
+
This library is free software; you can redistribute it and/or
|
6
|
+
modify it under the terms of the GNU Lesser General Public
|
7
|
+
License as published by the Free Software Foundation; either
|
8
|
+
version 2.1 of the License, or (at your option) any later version.
|
9
|
+
|
10
|
+
This library is distributed in the hope that it will be useful,
|
11
|
+
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
12
|
+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
13
|
+
Lesser General Public License for more details.
|
14
|
+
|
15
|
+
You should have received a copy of the GNU Lesser General Public
|
16
|
+
License along with this library; if not, write to the Free Software
|
17
|
+
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
18
|
+
=end
|
19
|
+
module Reg
|
20
|
+
|
21
|
+
#--------------------------
|
22
|
+
class MatchSet
|
23
|
+
|
24
|
+
def next_match(ary,start)
|
25
|
+
abstract
|
26
|
+
end
|
27
|
+
|
28
|
+
def deep_copy
|
29
|
+
abstract
|
30
|
+
end
|
31
|
+
|
32
|
+
def ob_state
|
33
|
+
instance_variables.sort.map{|i| instance_variable_get i }
|
34
|
+
end
|
35
|
+
|
36
|
+
def ==(other)
|
37
|
+
self.class==other.class and ob_state==other.ob_state
|
38
|
+
end
|
39
|
+
|
40
|
+
end
|
41
|
+
|
42
|
+
#--------------------------
|
43
|
+
class SingleRepeatMatchSet < MatchSet
|
44
|
+
def initialize(startcnt,stepper,endcnt)
|
45
|
+
endcnt==startcnt and raise 'why even make it a set, then?'
|
46
|
+
(endcnt-startcnt)*stepper>0 or raise "tried to make null match set"
|
47
|
+
assert startcnt>=0
|
48
|
+
assert endcnt>=0
|
49
|
+
@matchtimes,@stepper,@endcnt=startcnt,stepper,endcnt
|
50
|
+
end
|
51
|
+
|
52
|
+
def next_match(arr,idx)
|
53
|
+
assert @stepper.abs == 1
|
54
|
+
(@endcnt-@matchtimes)*@stepper>=0 or return nil
|
55
|
+
assert @matchtimes >=0
|
56
|
+
result=[RR[arr[idx...idx+@matchtimes]], @matchtimes]
|
57
|
+
assert ::Array===result.first.first
|
58
|
+
@matchtimes+=@stepper
|
59
|
+
return result
|
60
|
+
end
|
61
|
+
|
62
|
+
def deep_copy
|
63
|
+
dup
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
|
68
|
+
#--------------------------
|
69
|
+
class OrMatchSet < MatchSet
|
70
|
+
def initialize(orreg,idx,set,firstmatchlen)
|
71
|
+
@orreg,@idx,@set,@firstmatchlen=orreg,idx,set,firstmatchlen
|
72
|
+
assert @firstmatchlen.nil? || Integer===@firstmatchlen
|
73
|
+
end
|
74
|
+
|
75
|
+
def ob_state
|
76
|
+
instance_variables.map{|i| instance_variable_get i }
|
77
|
+
end
|
78
|
+
|
79
|
+
def ==(other)
|
80
|
+
OrMatchSet===other and ob_state==other.ob_state
|
81
|
+
end
|
82
|
+
|
83
|
+
def next_match(ary,idx)
|
84
|
+
if @firstmatchlen
|
85
|
+
resultlen,@firstmatchlen=@firstmatchlen,nil
|
86
|
+
assert Integer===resultlen
|
87
|
+
return [ary[idx,resultlen],resultlen]
|
88
|
+
end
|
89
|
+
@set and result= @set.next_match(ary,idx)
|
90
|
+
while result.nil?
|
91
|
+
@idx+=1
|
92
|
+
@idx >= @orreg.regs.size and return nil
|
93
|
+
x=@orreg.regs[@idx].mmatch(ary,idx)
|
94
|
+
@set,result=*if MatchSet===x then [x,x.next_match] else [nil,x] end
|
95
|
+
end
|
96
|
+
a=RR[nil]*@orreg.regs.size
|
97
|
+
a[idx]=result[0]
|
98
|
+
result[0]=a
|
99
|
+
assert ::Array===result.first.first
|
100
|
+
return result
|
101
|
+
end
|
102
|
+
|
103
|
+
def deep_copy
|
104
|
+
result=OrMatchSet.new(@orreg,@idx,@set && @set.deep_copy,@firstmatchlen)
|
105
|
+
assert self==result
|
106
|
+
return result
|
107
|
+
end
|
108
|
+
end
|
109
|
+
|
110
|
+
class SingleMatch_MatchSet < MatchSet
|
111
|
+
#this is somewhat of a hack, and shouldn't be necessary....
|
112
|
+
#it exists because every backtracking stop has to have a
|
113
|
+
#matchset in it, even the ones that only match one way.
|
114
|
+
#this class encapsulates matchsets that match only one way.
|
115
|
+
def initialize; end
|
116
|
+
def next_match*; end
|
117
|
+
end
|
118
|
+
|
119
|
+
|
120
|
+
#--------------------------
|
121
|
+
class RepeatMatchSet < MatchSet
|
122
|
+
|
123
|
+
attr :progress
|
124
|
+
def initialize(progress,consumed)
|
125
|
+
@progress=progress
|
126
|
+
#@cnt=@startcnt-stepper
|
127
|
+
#@ary.push 1
|
128
|
+
@consumed=consumed
|
129
|
+
@firstmatch=[progress.clean_result,@consumed]
|
130
|
+
assert( progress.matcher.times===progress.regsidx)
|
131
|
+
assert progress.regsidx
|
132
|
+
#assert(@ri==@firstmatch.first.size)
|
133
|
+
end
|
134
|
+
|
135
|
+
def match_iterations;
|
136
|
+
#assert(@ri==Backtrace.clean_result(@ary).size)
|
137
|
+
progress.regsidx
|
138
|
+
end
|
139
|
+
|
140
|
+
#very nearly identical to SubseqMatchSet#next_match
|
141
|
+
def next_match(arr,idx)
|
142
|
+
#fewer assertions in twin
|
143
|
+
if @firstmatch
|
144
|
+
result,@firstmatch=@firstmatch,nil
|
145
|
+
assert result.first.empty? || ::Array===result.first.first
|
146
|
+
#print "idx=#{idx}, inc=#{result.last}, arr.size=#{arr.size}\n"
|
147
|
+
# assert idx+result.last<=arr.size
|
148
|
+
# assert(progress.regsidx==result.first.size)
|
149
|
+
return result
|
150
|
+
end
|
151
|
+
|
152
|
+
@progress or return #not in twin ... ignore it
|
153
|
+
|
154
|
+
assert progress.check_result
|
155
|
+
|
156
|
+
i=@context.position_inc
|
157
|
+
=begin extents not used
|
158
|
+
extents= if i==0
|
159
|
+
[]
|
160
|
+
else
|
161
|
+
progress.position_stack[-i..-1]
|
162
|
+
end
|
163
|
+
=end
|
164
|
+
#this part's not in twin
|
165
|
+
#'need to check for fewer matches here before rematching last matchset'
|
166
|
+
|
167
|
+
#what if the match that gets discarded was returned by a matchset
|
168
|
+
#that has more matches in it?
|
169
|
+
#in that case, i is 1 and the body of this if should not be executed...
|
170
|
+
if @context.regsidx>@context.matcher.times.begin #&& i>1
|
171
|
+
progress.backup_stacks(@context) or raise
|
172
|
+
huh #need to change progress.cursor.pos here too
|
173
|
+
#result of backup_stacks is abandoned, leaked, orphaned
|
174
|
+
#we don't want it anymore
|
175
|
+
#but what if it's nil?
|
176
|
+
|
177
|
+
#but now i need to undo all other progress state too, if
|
178
|
+
#the state was created with the match result just popped.
|
179
|
+
#in general, it's not possible to distinguish state with the
|
180
|
+
#last match from state with the matches that might have preceeded it...
|
181
|
+
#unless I create a backtracking point for each optional iteration
|
182
|
+
#of the repeat matcher.
|
183
|
+
#currently, making a backtracking point implies making a matchset
|
184
|
+
#as well. I'll need a matchset the contains only 1 match.
|
185
|
+
#ok, i think this is working now. no extra code needed here.
|
186
|
+
|
187
|
+
@consumed-=pos-progress.position_stack.last
|
188
|
+
#assert(@ri==Backtrace.clean_result(@ary).size)
|
189
|
+
assert idx+@consumed<=arr.size
|
190
|
+
assert progress.check_result
|
191
|
+
result= [progress.clean_result, @consumed]
|
192
|
+
assert progress.check_result
|
193
|
+
return result
|
194
|
+
end
|
195
|
+
|
196
|
+
|
197
|
+
assert progress.check_result
|
198
|
+
assert( (0..@progress.matcher.max_matches)===@progress.regsidx)
|
199
|
+
result,di,ri=progress.last_next_match
|
200
|
+
if result and @progress.matcher.enough_matches? ri #condition slightly different in twin
|
201
|
+
result=[progress.clean_result,di]
|
202
|
+
@consumed=di #not in twin...why?
|
203
|
+
#@progress.regsidx-=1
|
204
|
+
assert ::Array===result.first.first
|
205
|
+
assert idx+result.last<=arr.size
|
206
|
+
assert progress.check_result
|
207
|
+
#assert(@ri==result.first.size)
|
208
|
+
return result
|
209
|
+
end
|
210
|
+
|
211
|
+
assert( (0..@progress.matcher.max_matches)===@progress.regsidx)
|
212
|
+
#assert(@ri==Backtrace.clean_result(@ary).size)
|
213
|
+
assert(progress.check_result)
|
214
|
+
|
215
|
+
|
216
|
+
|
217
|
+
@progress.matchset_stack.empty? and return @progress=nil #also checking @ary in twin... ignore it
|
218
|
+
assert @progress.regsidx>0
|
219
|
+
|
220
|
+
@progress.backtrack or return @progress=nil #@progress never set to nil like this in twin... ignore it
|
221
|
+
|
222
|
+
#this is where the divergence widens. ri is a local in twin
|
223
|
+
|
224
|
+
#assert(@ri==Backtrace.clean_result(@ary).size)
|
225
|
+
assert(progress.check_result)
|
226
|
+
mat,di,@ri=@progress.bt_match #mat is @ary in twin
|
227
|
+
mat.nil? and return @progress=nil
|
228
|
+
|
229
|
+
#assert(@ri==Backtrace.clean_result(mat).size)
|
230
|
+
assert @progress.regsidx
|
231
|
+
assert( (0..@progress.matcher.max_matches)===@progress.regsidx)
|
232
|
+
|
233
|
+
result=[@progress.clean_result,di]
|
234
|
+
@consumed=di #no @consumed in twin
|
235
|
+
assert ::Array===result.first.first
|
236
|
+
assert idx+result.last<=arr.size
|
237
|
+
assert progress.check_result
|
238
|
+
#assert(@ri==result.last.size)
|
239
|
+
return result
|
240
|
+
end
|
241
|
+
|
242
|
+
end
|
243
|
+
|
244
|
+
#---------------------------------------------
|
245
|
+
class SubseqMatchSet < MatchSet
|
246
|
+
|
247
|
+
def initialize progress,di;
|
248
|
+
@reg,@progress= progress.matcher,progress
|
249
|
+
|
250
|
+
@orig_pos=progress.cursor.pos-di
|
251
|
+
@firstresult= [progress.clean_result,di]
|
252
|
+
end
|
253
|
+
|
254
|
+
#(@reg=>progress.matcher,@matchary=>progress.huh,di=>progress.cursor.pos-@orig_pos)
|
255
|
+
|
256
|
+
def next_match(ary,start)
|
257
|
+
if @firstresult
|
258
|
+
@firstresult,result=nil,@firstresult
|
259
|
+
assert ::Array===result.first.first
|
260
|
+
return result
|
261
|
+
end
|
262
|
+
|
263
|
+
|
264
|
+
result,di,ri=@progress.last_next_match
|
265
|
+
result or return @progress=nil
|
266
|
+
if result and ri==@reg.max_matches
|
267
|
+
result=[@progress.clean_result,di]
|
268
|
+
assert ::Array===result.first.first
|
269
|
+
return result
|
270
|
+
end
|
271
|
+
|
272
|
+
|
273
|
+
(@progress and !@progress.matchset_stack.empty?) or return @progress=nil
|
274
|
+
assert @progress.regsidx
|
275
|
+
@progress.backtrack or return @progress=nil
|
276
|
+
|
277
|
+
#need to adjust ri?
|
278
|
+
|
279
|
+
#is this right... dunno...
|
280
|
+
result,di,bogus=@progress.bt_match
|
281
|
+
|
282
|
+
|
283
|
+
if result
|
284
|
+
result=[@progress.clean_result,di]
|
285
|
+
assert ::Array===result.first.first
|
286
|
+
return result
|
287
|
+
end
|
288
|
+
end
|
289
|
+
|
290
|
+
def match_iterations
|
291
|
+
progress.matcher.max_matches
|
292
|
+
end
|
293
|
+
|
294
|
+
end
|
295
|
+
#--------------------------
|
296
|
+
class AndMatchSet < SubseqMatchSet
|
297
|
+
#this isn't really right...
|
298
|
+
#on next_match, we need to backtrack the longest alternative(s)
|
299
|
+
#if they're then shorter than the next longest alternative,
|
300
|
+
#then that (formerly next longest) alternative becomes
|
301
|
+
#the dominating alternative, and determines how much is consumed
|
302
|
+
|
303
|
+
end
|
304
|
+
#might need Reg::Or tooo....
|
305
|
+
|
306
|
+
|
307
|
+
#--------------------------
|
308
|
+
class ReplaceMatchSet < MatchSet
|
309
|
+
def initialize(replacer, progress, origpos, ms)
|
310
|
+
@replacer,@progress,@origpos,@ms=replacer,@progress,origpos,ms
|
311
|
+
end
|
312
|
+
|
313
|
+
def next_match(*args)
|
314
|
+
result=@ms.next_match(*args)
|
315
|
+
@replacer.replace @origpos,result.last,@progress
|
316
|
+
return result
|
317
|
+
end
|
318
|
+
|
319
|
+
end
|
320
|
+
|
321
|
+
|
322
|
+
|
323
|
+
end
|
data/{regold.rb → lib/regold.rb}
RENAMED
@@ -1,6 +1,6 @@
|
|
1
1
|
=begin copyright
|
2
2
|
reg - the ruby extended grammar
|
3
|
-
Copyright (C) 2005,
|
3
|
+
Copyright (C) 2005, 2016 Caleb Clausen
|
4
4
|
|
5
5
|
This library is free software; you can redistribute it and/or
|
6
6
|
modify it under the terms of the GNU Lesser General Public
|
@@ -20,32 +20,32 @@
|
|
20
20
|
|
21
21
|
#the names defined here are considered obsolete, and will not be supported
|
22
22
|
#anymore at some point in the future.
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
23
|
+
OBSOLETE_NAMES=["And", "Array","Equals", "Fixed", "Hash", "Literal",
|
24
|
+
"Multiple", "Not", "Object", "Or", "Repeat",
|
25
|
+
"String", "Subseq", "Symbol", "Xor"]
|
26
|
+
for name in OBSOLETE_NAMES do
|
27
|
+
|
28
|
+
if Class===::Reg.const_get(name)
|
29
|
+
eval <<-endeval
|
30
|
+
class ::Reg#{name} < Reg::#{name}
|
31
|
+
|
32
|
+
def initialize(*args,&block)
|
33
|
+
@@warned_already ||= !warn("Reg#{name} is obsolete; use Reg::#{name} instead")
|
34
|
+
super
|
35
|
+
end
|
36
|
+
end
|
37
|
+
endeval
|
38
|
+
else
|
39
|
+
eval <<-endeval
|
40
|
+
module ::Reg#{name}; include Reg::#{name}
|
41
|
+
def self.included(*args,&block)
|
42
|
+
@@warned_already ||= !warn("Reg#{name} is obsolete; use Reg::#{name} instead")
|
43
|
+
super
|
44
|
+
end
|
45
|
+
end
|
46
|
+
endeval
|
47
|
+
|
48
|
+
end
|
49
49
|
|
50
50
|
# Object.const_set "Reg"+name, (Reg.const_get name)
|
51
51
|
end
|
@@ -1,6 +1,6 @@
|
|
1
1
|
=begin copyright
|
2
2
|
reg - the ruby extended grammar
|
3
|
-
Copyright (C) 2005 Caleb Clausen
|
3
|
+
Copyright (C) 2005, 2016 Caleb Clausen
|
4
4
|
|
5
5
|
This library is free software; you can redistribute it and/or
|
6
6
|
modify it under the terms of the GNU Lesser General Public
|
@@ -72,3 +72,93 @@ others n/a single
|
|
72
72
|
|
73
73
|
|
74
74
|
=end
|
75
|
+
|
76
|
+
=begin
|
77
|
+
a Reg::Path is a list of (mostly) pairs of contained in a Reg::Path constructor.
|
78
|
+
The preferred Reg::Path constructor is the --[...] syntax.
|
79
|
+
|
80
|
+
the key (left side) of each pair represents a connector matcher, and the value represents
|
81
|
+
a value matcher. here's a list of allowed connector matchers:
|
82
|
+
|
83
|
+
type allowed connector matchers
|
84
|
+
Object Array (+[String|Symbol, __]) , Array (+[Regexp, __]) , Reg::RespondsTo (made like -:foo or -"foo" or -:@foo)
|
85
|
+
Hash Any Object, Array of 1 Array|Integer, Reg::Literal, any scalar matcher
|
86
|
+
Array Integer,Range of Integer
|
87
|
+
|
88
|
+
any reg matcher may be used as a value matcher.
|
89
|
+
|
90
|
+
If the value matcher is OB and the connector matcher is of the below, the value matcher (and ** connecting to it)
|
91
|
+
may be left off, so just the connector matcher is given:
|
92
|
+
|
93
|
+
type allowed standalone connector matchers
|
94
|
+
Object Array (+[String|Symbol, __]) , Array (+[Regexp, __]) , Reg::RespondsTo (made like -:foo or -"foo" or -:@foo)
|
95
|
+
Hash Array of 1 Array|Integer, Reg::Literal, String, Symbol, Regexp
|
96
|
+
Array Integer,Range of Integer
|
97
|
+
|
98
|
+
Reg::Paths may also contain Reg::Repeat or Reg::Subseq, provided the leaves within
|
99
|
+
these are ultimately pairs or standalone connector matchers.
|
100
|
+
|
101
|
+
=end
|
102
|
+
|
103
|
+
|
104
|
+
module Reg
|
105
|
+
class Subseq
|
106
|
+
def -@; Path.new @regs; end
|
107
|
+
end
|
108
|
+
|
109
|
+
class Path
|
110
|
+
def initialize regs
|
111
|
+
@regs=regs
|
112
|
+
expand_pairs!
|
113
|
+
end
|
114
|
+
|
115
|
+
def === other
|
116
|
+
@regs.each{|r|
|
117
|
+
case r
|
118
|
+
when Integer
|
119
|
+
when Range
|
120
|
+
when Reg::Literal
|
121
|
+
when Array
|
122
|
+
case r[0]
|
123
|
+
when String,Symbol
|
124
|
+
when Regexp
|
125
|
+
when Array
|
126
|
+
when Integer
|
127
|
+
end
|
128
|
+
when Reg::RespondsTo
|
129
|
+
when Reg::Reg
|
130
|
+
else
|
131
|
+
end
|
132
|
+
}
|
133
|
+
end
|
134
|
+
end
|
135
|
+
|
136
|
+
module Reg
|
137
|
+
def expand_pairs!
|
138
|
+
0.upto(@regs.size-1) do |i|
|
139
|
+
item=@regs[i]
|
140
|
+
@regs[i]=
|
141
|
+
case item
|
142
|
+
when Reg::Pair; item #ignore
|
143
|
+
when Reg::Repeat,Reg::Subseq; item.dup.expand_pairs!
|
144
|
+
else Reg::Pair.new(item,OB)
|
145
|
+
end
|
146
|
+
end
|
147
|
+
return self
|
148
|
+
end
|
149
|
+
end
|
150
|
+
class Repeat
|
151
|
+
def expand_pairs!
|
152
|
+
item=@reg
|
153
|
+
@reg=
|
154
|
+
case item
|
155
|
+
when Reg::Pair; item #ignore
|
156
|
+
when Reg::Repeat,Reg::Subseq; item.dup.expand_pairs!
|
157
|
+
else Reg::Pair.new(item,OB)
|
158
|
+
end
|
159
|
+
return self
|
160
|
+
end
|
161
|
+
end
|
162
|
+
|
163
|
+
end
|
164
|
+
|