vidibus-inheritance 0.3.6 → 0.3.9
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.
- data/README.rdoc +3 -2
- data/TODO +4 -5
- data/VERSION +1 -1
- data/lib/vidibus/inheritance.rb +1 -7
- data/lib/vidibus/inheritance/mongoid.rb +239 -190
- data/lib/vidibus/inheritance/validators/ancestor_validator.rb +1 -1
- data/spec/models.rb +70 -0
- data/spec/spec_helper.rb +2 -1
- data/spec/vidibus/inheritance/inheritance_spec.rb +396 -0
- data/spec/vidibus/inheritance/mongoid_spec.rb +104 -397
- data/spec/vidibus/inheritance/validators/ancestor_validator_spec.rb +11 -13
- data/vidibus-inheritance.gemspec +7 -3
- metadata +8 -4
@@ -1,66 +1,10 @@
|
|
1
1
|
require "spec_helper"
|
2
2
|
|
3
|
-
class Model
|
4
|
-
include Mongoid::Document
|
5
|
-
include Mongoid::Timestamps
|
6
|
-
include Vidibus::Uuid::Mongoid
|
7
|
-
include Vidibus::Inheritance::Mongoid
|
8
|
-
field :name
|
9
|
-
field :age, :type => Integer
|
10
|
-
embeds_many :children
|
11
|
-
embeds_many :puppets
|
12
|
-
embeds_one :location
|
13
|
-
end
|
14
|
-
|
15
|
-
class Child
|
16
|
-
include Mongoid::Document
|
17
|
-
field :name
|
18
|
-
field :mutated, :type => Boolean
|
19
|
-
validates :name, :presence => true
|
20
|
-
embedded_in :model, :inverse_of => :children
|
21
|
-
embeds_many :puppets
|
22
|
-
embeds_one :location
|
23
|
-
end
|
24
|
-
|
25
|
-
class Puppet
|
26
|
-
include Mongoid::Document
|
27
|
-
field :name
|
28
|
-
validates :name, :presence => true
|
29
|
-
embedded_in :child, :inverse_of => :puppets
|
30
|
-
embedded_in :model, :inverse_of => :puppets
|
31
|
-
embedded_in :location, :inverse_of => :puppets
|
32
|
-
embeds_one :location
|
33
|
-
end
|
34
|
-
|
35
|
-
class Location
|
36
|
-
include Mongoid::Document
|
37
|
-
field :name
|
38
|
-
field :mutated, :type => Boolean
|
39
|
-
validates :name, :presence => true
|
40
|
-
embedded_in :model, :inverse_of => :location
|
41
|
-
embedded_in :child, :inverse_of => :location
|
42
|
-
embedded_in :puppet, :inverse_of => :location
|
43
|
-
embeds_many :puppets
|
44
|
-
end
|
45
|
-
|
46
|
-
class Manager
|
47
|
-
include Mongoid::Document
|
48
|
-
include Vidibus::Uuid::Mongoid
|
49
|
-
include Vidibus::Inheritance::Mongoid
|
50
|
-
field :name
|
51
|
-
validates :name, :presence => true
|
52
|
-
end
|
53
|
-
|
54
|
-
class Clerk
|
55
|
-
include Mongoid::Document
|
56
|
-
field :name
|
57
|
-
validates :name, :presence => true
|
58
|
-
end
|
59
|
-
|
60
3
|
describe "Vidibus::Inheritance::Mongoid" do
|
61
4
|
let(:ancestor) { Model.create }
|
62
|
-
let(:anna) { Model.create!(:name => "Anna", :age => 35) }
|
63
5
|
let(:inheritor) { Model.new }
|
6
|
+
let(:anna) { Model.create!(:name => "Anna", :age => 35) }
|
7
|
+
let(:jeanny) { Model.create!(:name => "Jeanny", :age => 17) }
|
64
8
|
|
65
9
|
describe "validation" do
|
66
10
|
it "should fail if ancestor does not have an UUID" do
|
@@ -114,6 +58,12 @@ describe "Vidibus::Inheritance::Mongoid" do
|
|
114
58
|
inheritor.update_attributes(:name => "Jenny")
|
115
59
|
inheritor.mutated_attributes.should eql(["name"])
|
116
60
|
end
|
61
|
+
|
62
|
+
it "should be tracked if data gets modified in a before_validation callback" do
|
63
|
+
model = Trude.create
|
64
|
+
model.name.should eql("Trude")
|
65
|
+
model.mutated_attributes.should eql(["name"])
|
66
|
+
end
|
117
67
|
end
|
118
68
|
|
119
69
|
describe "#mutated?" do
|
@@ -136,13 +86,6 @@ describe "Vidibus::Inheritance::Mongoid" do
|
|
136
86
|
end
|
137
87
|
end
|
138
88
|
|
139
|
-
describe "#ancestor" do
|
140
|
-
it "should return an ancestor object by uuid" do
|
141
|
-
inheritor.ancestor_uuid = ancestor.uuid
|
142
|
-
inheritor.ancestor.should eql(ancestor)
|
143
|
-
end
|
144
|
-
end
|
145
|
-
|
146
89
|
describe "#ancestor=" do
|
147
90
|
it "should set an ancestor object" do
|
148
91
|
inheritor.ancestor = ancestor
|
@@ -168,6 +111,21 @@ describe "Vidibus::Inheritance::Mongoid" do
|
|
168
111
|
end
|
169
112
|
end
|
170
113
|
|
114
|
+
describe "#ancestor" do
|
115
|
+
it "should return an ancestor object by uuid" do
|
116
|
+
inheritor.ancestor_uuid = ancestor.uuid
|
117
|
+
inheritor.ancestor.should eql(ancestor)
|
118
|
+
end
|
119
|
+
end
|
120
|
+
|
121
|
+
describe "#ancestors" do
|
122
|
+
it "should return a list of all ancestors" do
|
123
|
+
inheritor = Model.create!(:ancestor => ancestor)
|
124
|
+
nextgen = Model.create!(:ancestor => inheritor)
|
125
|
+
nextgen.ancestors.should eql([inheritor, ancestor])
|
126
|
+
end
|
127
|
+
end
|
128
|
+
|
171
129
|
describe "#inherit!" do
|
172
130
|
it "should call #inherit_attributes once" do
|
173
131
|
stub(inheritor)._inherited { true }
|
@@ -233,368 +191,117 @@ describe "Vidibus::Inheritance::Mongoid" do
|
|
233
191
|
it "should return all inheritors" do
|
234
192
|
inheritor1 = Model.create(:ancestor => ancestor)
|
235
193
|
inheritor2 = Model.create(:ancestor => ancestor)
|
236
|
-
ancestor.inheritors.
|
237
|
-
|
238
|
-
|
194
|
+
list = ancestor.inheritors.to_a
|
195
|
+
list.should have(2).inheritors
|
196
|
+
list.should include(inheritor1)
|
197
|
+
list.should include(inheritor2)
|
239
198
|
end
|
240
199
|
end
|
241
200
|
|
242
|
-
describe "
|
243
|
-
it "should
|
244
|
-
|
245
|
-
|
246
|
-
Model.create!(:ancestor => ancestor)
|
201
|
+
describe "#inheritable_documents" do
|
202
|
+
it "should perform .inheritable_documents with current object" do
|
203
|
+
mock(Model).inheritable_documents(anna, {})
|
204
|
+
anna.inheritable_documents
|
247
205
|
end
|
248
206
|
|
249
|
-
it "should
|
250
|
-
|
251
|
-
|
252
|
-
stub(inheritor).inherit_attributes
|
253
|
-
inheritor.save
|
254
|
-
inheritor.should have_received.inherit_attributes
|
207
|
+
it "should allow options" do
|
208
|
+
mock(Model).inheritable_documents(anna, :keys => true)
|
209
|
+
anna.inheritable_documents(:keys => true)
|
255
210
|
end
|
256
|
-
|
257
|
-
|
258
|
-
|
259
|
-
|
260
|
-
|
261
|
-
|
262
|
-
|
211
|
+
end
|
212
|
+
|
213
|
+
describe "#clone!" do
|
214
|
+
it "should create a sibling" do
|
215
|
+
twin = anna.clone!
|
216
|
+
twin.should_not eql(anna)
|
217
|
+
twin.name.should eql(anna.name)
|
218
|
+
twin.age.should eql(anna.age)
|
263
219
|
end
|
264
220
|
|
265
|
-
it "should
|
266
|
-
|
267
|
-
|
268
|
-
|
221
|
+
it "should preserve ancestor relation" do
|
222
|
+
anna.inherit_from!(ancestor)
|
223
|
+
twin = anna.clone!
|
224
|
+
twin.ancestor.should eql(ancestor)
|
269
225
|
end
|
270
226
|
|
271
|
-
it "should not
|
272
|
-
|
273
|
-
|
274
|
-
|
227
|
+
it "should not clone inheritors (should it?)" do
|
228
|
+
anna.inherit_from!(ancestor)
|
229
|
+
twin = ancestor.clone!
|
230
|
+
twin.inheritors.should be_empty
|
275
231
|
end
|
276
232
|
|
277
|
-
it "should
|
278
|
-
|
279
|
-
|
280
|
-
|
281
|
-
inheritor.age.should eql(35)
|
233
|
+
it "should clone embedded documents" do
|
234
|
+
anna.children.create(:name => "Lisa")
|
235
|
+
twin = anna.clone!
|
236
|
+
twin.children.should have(1).child
|
282
237
|
end
|
283
238
|
|
284
|
-
it "should
|
285
|
-
|
286
|
-
|
287
|
-
|
239
|
+
it "should clone a single embedded document" do
|
240
|
+
anna.create_location(:name => "Bathroom")
|
241
|
+
twin = anna.clone!
|
242
|
+
twin.location.name.should eql("Bathroom")
|
288
243
|
end
|
289
244
|
|
290
|
-
it "should
|
291
|
-
|
292
|
-
|
293
|
-
|
294
|
-
|
295
|
-
|
296
|
-
|
245
|
+
it "should clone children of embedded documents" do
|
246
|
+
lisa = anna.children.create(:name => "Lisa")
|
247
|
+
lisa.puppets.create(:name => "Gonzo")
|
248
|
+
twin = anna.clone!
|
249
|
+
lisa_twin = twin.children.first
|
250
|
+
lisa_twin.puppets.should have(1).puppet
|
251
|
+
# lisa_twin.puppets.first._id.should_not eql(lisa_twin.puppets.first._id)
|
297
252
|
end
|
298
|
-
|
299
|
-
|
300
|
-
|
301
|
-
|
302
|
-
|
303
|
-
|
304
|
-
|
253
|
+
end
|
254
|
+
|
255
|
+
describe ".inheritable_documents" do
|
256
|
+
it "should return embedded relations of a given object" do
|
257
|
+
docs = Model.inheritable_documents(anna)
|
258
|
+
docs.length.should eql(3)
|
259
|
+
docs.should have_key("location")
|
260
|
+
docs.should have_key("children")
|
261
|
+
docs.should have_key("puppets")
|
305
262
|
end
|
306
263
|
|
307
|
-
it "should
|
308
|
-
|
309
|
-
|
310
|
-
|
311
|
-
anna.update_attributes(:name => "Leah")
|
312
|
-
inheritor.reload
|
313
|
-
inheritor.name.should eql("Sara")
|
264
|
+
it "should return a collection of documents embedded by embeds_many" do
|
265
|
+
anna.children.create(:name => "Lisa")
|
266
|
+
docs = Model.inheritable_documents(anna)
|
267
|
+
docs["children"].should eql([anna.children.first])
|
314
268
|
end
|
315
269
|
|
316
|
-
it "should
|
317
|
-
|
318
|
-
Model
|
319
|
-
|
320
|
-
ancestor.update_attributes(:updated_at => Time.now)
|
270
|
+
it "should return a document embedded by embeds_one" do
|
271
|
+
anna.create_location(:name => "Beach")
|
272
|
+
docs = Model.inheritable_documents(anna)
|
273
|
+
docs["location"].should eql(anna.location)
|
321
274
|
end
|
322
275
|
|
323
|
-
it "should
|
324
|
-
|
325
|
-
|
326
|
-
anna.update_attributes(:name => "Anna")
|
276
|
+
it "should return the keys of embedded relations if option :keys is given" do
|
277
|
+
keys = Model.inheritable_documents(anna, :keys => true)
|
278
|
+
keys.should eql(%w[location puppets children])
|
327
279
|
end
|
328
|
-
|
329
|
-
|
330
|
-
|
331
|
-
|
332
|
-
|
333
|
-
|
334
|
-
valid.should be_valid
|
280
|
+
end
|
281
|
+
|
282
|
+
describe ".roots" do
|
283
|
+
before do
|
284
|
+
inheritor.inherit_from!(anna)
|
285
|
+
jeanny
|
335
286
|
end
|
336
287
|
|
337
|
-
|
338
|
-
|
339
|
-
|
340
|
-
|
341
|
-
ancestor.save
|
342
|
-
inheritor.reload
|
343
|
-
end
|
344
|
-
|
345
|
-
it "should inherit subobjects on existing relationship" do
|
346
|
-
inheritor.children.should have(1).child
|
347
|
-
end
|
348
|
-
|
349
|
-
it "should inherit subobjects when relationship gets established" do
|
350
|
-
inheritor = Model.new
|
351
|
-
inheritor.inherit_from!(ancestor)
|
352
|
-
inheritor.children.should have(1).child
|
353
|
-
inheritor.reload.children.should have(1).child
|
354
|
-
end
|
355
|
-
|
356
|
-
it "should add subobjects" do
|
357
|
-
ancestor.children << Child.new(:name => "Leah")
|
358
|
-
ancestor.save
|
359
|
-
ancestor.children.should have(2).children
|
360
|
-
inheritor.reload
|
361
|
-
inheritor.children.should have(2).children
|
362
|
-
end
|
363
|
-
|
364
|
-
it "should add subobjects with saving" do
|
365
|
-
ancestor.children << Child.new(:name => "Leah")
|
366
|
-
ancestor.save
|
367
|
-
ancestor.children.should have(2).children
|
368
|
-
inheritor.save
|
369
|
-
inheritor.reload
|
370
|
-
inheritor.children.should have(2).children
|
371
|
-
end
|
372
|
-
|
373
|
-
it "should not add existing subobjects twice" do
|
374
|
-
inheritor.inherit_from!(ancestor)
|
375
|
-
inheritor.children.should have(1).child
|
376
|
-
inheritor.reload.children.should have(1).child
|
377
|
-
end
|
378
|
-
|
379
|
-
it "should remove subobjects" do
|
380
|
-
inheritor.children.should have(1).child
|
381
|
-
ancestor.children.first.destroy
|
382
|
-
ancestor.save
|
383
|
-
inheritor.reload
|
384
|
-
ancestor.children.should have(0).children
|
385
|
-
inheritor.children.should have(0).children
|
386
|
-
end
|
387
|
-
|
388
|
-
it "should update subobjects" do
|
389
|
-
ancestor.children.first.name = "Luke"
|
390
|
-
ancestor.save
|
391
|
-
inheritor.reload
|
392
|
-
inheritor.children.first.name.should eql("Luke")
|
393
|
-
end
|
394
|
-
|
395
|
-
it "should call #update_inherited_attributes for updating subobjects, if available" do
|
396
|
-
Child.send(:define_method, :update_inherited_attributes) do
|
397
|
-
self.update_attributes(:name => "Callback")
|
398
|
-
end
|
399
|
-
Child.send(:protected, :update_inherited_attributes)
|
400
|
-
ancestor.children.first.name = "Luke"
|
401
|
-
ancestor.save
|
402
|
-
Child.send(:remove_method, :update_inherited_attributes)
|
403
|
-
inheritor.reload
|
404
|
-
inheritor.children.first.name.should eql("Callback")
|
405
|
-
end
|
406
|
-
|
407
|
-
it "should exclude acquired attributes of subobjects" do
|
408
|
-
ancestor.children.first.mutated = true
|
409
|
-
ancestor.save
|
410
|
-
ancestor.children.first.mutated.should be_true
|
411
|
-
inheritor.reload
|
412
|
-
inheritor.children.first.mutated.should be_false
|
413
|
-
end
|
414
|
-
|
415
|
-
it "should inherit embedded documents of subobjects" do
|
416
|
-
ancestor.children.first.puppets.create(:name => "Goofy")
|
417
|
-
ancestor.save
|
418
|
-
inheritor.reload
|
419
|
-
inheritor.children.first.puppets.should have(1).puppet
|
420
|
-
end
|
288
|
+
it "should return all model that have no ancestor" do
|
289
|
+
Model.all.to_a.should have(3).models
|
290
|
+
list = Model.roots.to_a
|
291
|
+
list.should have(2).models
|
421
292
|
end
|
422
293
|
|
423
|
-
|
424
|
-
|
425
|
-
|
426
|
-
|
427
|
-
|
428
|
-
|
429
|
-
end
|
430
|
-
|
431
|
-
it "should inherit subobject on existing relationship" do
|
432
|
-
inheritor.location.should_not be_nil
|
433
|
-
end
|
434
|
-
|
435
|
-
it "should inherit subobjects when relationship gets established" do
|
436
|
-
inheritor = Model.new
|
437
|
-
inheritor.inherit_from!(ancestor)
|
438
|
-
inheritor.location.should_not be_nil
|
439
|
-
end
|
440
|
-
|
441
|
-
it "should update subobject" do
|
442
|
-
ancestor.location.name = "Studio"
|
443
|
-
ancestor.save
|
444
|
-
inheritor.reload
|
445
|
-
ancestor.location.name.should eql("Studio")
|
446
|
-
inheritor.location.name.should eql("Studio")
|
447
|
-
end
|
448
|
-
|
449
|
-
it "should remove subobject" do
|
450
|
-
ancestor.location.destroy
|
451
|
-
ancestor.save
|
452
|
-
inheritor.reload
|
453
|
-
ancestor.location.should be_nil
|
454
|
-
inheritor.location.should be_nil
|
455
|
-
end
|
456
|
-
|
457
|
-
it "should exclude acquired attributes of subobject" do
|
458
|
-
ancestor.location.mutated = true
|
459
|
-
ancestor.save
|
460
|
-
ancestor.location.mutated.should be_true
|
461
|
-
inheritor.reload
|
462
|
-
inheritor.location.mutated.should be_false
|
463
|
-
end
|
464
|
-
|
465
|
-
it "should inherit embedded documents of subobject" do
|
466
|
-
ancestor.location.puppets.create(:name => "Goofy")
|
467
|
-
ancestor.save
|
468
|
-
inheritor.reload
|
469
|
-
inheritor.location.puppets.should have(1).puppet
|
470
|
-
end
|
294
|
+
it "should accept sorting criteria" do
|
295
|
+
Model.all.to_a.should have(3).models
|
296
|
+
stub_time!(1.hour.since)
|
297
|
+
anna.update_attributes(:age => 20)
|
298
|
+
list = Model.roots.desc(:updated_at).to_a
|
299
|
+
list[0].updated_at.should > list[1].updated_at
|
471
300
|
end
|
472
301
|
|
473
|
-
|
474
|
-
|
475
|
-
|
476
|
-
before do
|
477
|
-
ancestor.inherit_from!(grand_ancestor)
|
478
|
-
inheritor.inherit_from!(ancestor)
|
479
|
-
end
|
480
|
-
|
481
|
-
it "should apply changes on grand ancestor to inheritor" do
|
482
|
-
inheritor.name.should eql("Anna")
|
483
|
-
grand_ancestor.update_attributes(:name => "Leah")
|
484
|
-
inheritor.reload
|
485
|
-
inheritor.name.should eql("Leah")
|
486
|
-
end
|
487
|
-
|
488
|
-
it "should not apply changes on grand ancestor to inheritor if predecessor has mutations" do
|
489
|
-
ancestor.update_attributes(:name => "Jenny")
|
490
|
-
grand_ancestor.update_attributes(:name => "Leah")
|
491
|
-
inheritor.reload
|
492
|
-
inheritor.name.should eql("Jenny")
|
493
|
-
end
|
494
|
-
|
495
|
-
it "should allow resetting mutated attributes" do
|
496
|
-
ancestor.update_attributes(:name => "Sara")
|
497
|
-
ancestor.name.should eql("Sara")
|
498
|
-
inheritor.reload
|
499
|
-
inheritor.name.should eql("Sara")
|
500
|
-
ancestor.inherit!(:reset => :name)
|
501
|
-
ancestor.name.should eql("Anna")
|
502
|
-
inheritor.reload
|
503
|
-
inheritor.name.should eql("Anna")
|
504
|
-
end
|
505
|
-
|
506
|
-
context "with embedded collections" do
|
507
|
-
before do
|
508
|
-
grand_ancestor.children.create(:name => "Han")
|
509
|
-
grand_ancestor.save
|
510
|
-
ancestor.reload
|
511
|
-
inheritor.reload
|
512
|
-
end
|
513
|
-
|
514
|
-
it "should inherit subobjects" do
|
515
|
-
inheritor.children.should have(1).child
|
516
|
-
end
|
517
|
-
|
518
|
-
it "should add subobjects" do
|
519
|
-
grand_ancestor.children << Child.new(:name => "Leah")
|
520
|
-
grand_ancestor.save
|
521
|
-
inheritor.reload
|
522
|
-
inheritor.children.should have(2).children
|
523
|
-
end
|
524
|
-
|
525
|
-
it "should not add existing subobjects twice" do
|
526
|
-
ancestor.inherit_from!(grand_ancestor)
|
527
|
-
inheritor.reload
|
528
|
-
inheritor.children.should have(1).child
|
529
|
-
end
|
530
|
-
|
531
|
-
it "should remove subobjects" do
|
532
|
-
inheritor.children.should have(1).child
|
533
|
-
grand_ancestor.children.first.destroy
|
534
|
-
grand_ancestor.save
|
535
|
-
grand_ancestor.children.should have(0).children
|
536
|
-
inheritor.reload
|
537
|
-
inheritor.children.should have(0).children
|
538
|
-
end
|
539
|
-
|
540
|
-
it "should update subobjects" do
|
541
|
-
grand_ancestor.children.first.name = "Luke"
|
542
|
-
grand_ancestor.save
|
543
|
-
grand_ancestor.children.first.name.should eql("Luke")
|
544
|
-
inheritor.reload
|
545
|
-
inheritor.children.first.name.should eql("Luke")
|
546
|
-
end
|
547
|
-
|
548
|
-
it "should inherit embedded documents of subobjects" do
|
549
|
-
grand_ancestor.children.first.puppets.create(:name => "Goofy")
|
550
|
-
grand_ancestor.save
|
551
|
-
inheritor.reload
|
552
|
-
inheritor.children.first.puppets.should have(1).puppet
|
553
|
-
end
|
554
|
-
end
|
555
|
-
|
556
|
-
context "with embedded items" do
|
557
|
-
before do
|
558
|
-
grand_ancestor.create_location(:name => "Home")
|
559
|
-
grand_ancestor.save
|
560
|
-
ancestor.reload
|
561
|
-
inheritor.reload
|
562
|
-
end
|
563
|
-
|
564
|
-
it "should inherit subobject on existing relationship" do
|
565
|
-
inheritor.location.should_not be_nil
|
566
|
-
end
|
567
|
-
|
568
|
-
it "should inherit subobject when relationship gets established" do
|
569
|
-
ancestor = Model.new
|
570
|
-
ancestor.inherit_from!(grand_ancestor)
|
571
|
-
inheritor = Model.new
|
572
|
-
inheritor.inherit_from!(ancestor)
|
573
|
-
inheritor.location.should_not be_nil
|
574
|
-
end
|
575
|
-
|
576
|
-
it "should update subobject" do
|
577
|
-
grand_ancestor.location.name = "Studio"
|
578
|
-
grand_ancestor.save
|
579
|
-
inheritor.reload
|
580
|
-
inheritor.location.name.should eql("Studio")
|
581
|
-
end
|
582
|
-
|
583
|
-
it "should remove subobject" do
|
584
|
-
grand_ancestor.location.destroy
|
585
|
-
grand_ancestor.save
|
586
|
-
inheritor.reload
|
587
|
-
grand_ancestor.location.should be_nil
|
588
|
-
inheritor.location.should be_nil
|
589
|
-
end
|
590
|
-
|
591
|
-
it "should inherit embedded documents of subobject" do
|
592
|
-
grand_ancestor.location.puppets.create(:name => "Goofy")
|
593
|
-
grand_ancestor.save
|
594
|
-
inheritor.reload
|
595
|
-
inheritor.location.puppets.should have(1).puppet
|
596
|
-
end
|
597
|
-
end
|
302
|
+
it "should accept conditions" do
|
303
|
+
list = Model.roots.where(:name => ancestor.name).to_a
|
304
|
+
list.should have(1).models
|
598
305
|
end
|
599
306
|
end
|
600
307
|
end
|