mongoid 1.1.3 → 1.1.4
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/.watchr +20 -2
- data/VERSION +1 -1
- data/caliper.yml +4 -0
- data/lib/mongoid.rb +0 -1
- data/lib/mongoid/associations.rb +25 -13
- data/lib/mongoid/associations/belongs_to.rb +15 -17
- data/lib/mongoid/associations/belongs_to_related.rb +12 -14
- data/lib/mongoid/associations/has_many.rb +53 -35
- data/lib/mongoid/associations/has_many_related.rb +10 -15
- data/lib/mongoid/associations/has_one.rb +31 -30
- data/lib/mongoid/associations/has_one_related.rb +18 -20
- data/lib/mongoid/associations/options.rb +10 -0
- data/lib/mongoid/associations/proxy.rb +18 -1
- data/lib/mongoid/criteria.rb +9 -233
- data/lib/mongoid/criterion/complex.rb +21 -0
- data/lib/mongoid/criterion/exclusion.rb +63 -0
- data/lib/mongoid/criterion/inclusion.rb +91 -0
- data/lib/mongoid/criterion/optional.rb +96 -0
- data/lib/mongoid/document.rb +2 -2
- data/lib/mongoid/extensions/hash/accessors.rb +6 -0
- data/lib/mongoid/extensions/hash/criteria_helpers.rb +2 -2
- data/lib/mongoid/extensions/symbol/inflections.rb +1 -1
- data/mongoid.gemspec +53 -3
- data/spec/integration/mongoid/associations_spec.rb +41 -0
- data/spec/models/address.rb +39 -0
- data/spec/models/animal.rb +6 -0
- data/spec/models/comment.rb +8 -0
- data/spec/models/country_code.rb +6 -0
- data/spec/models/employer.rb +5 -0
- data/spec/models/game.rb +6 -0
- data/spec/models/inheritance.rb +56 -0
- data/spec/models/location.rb +5 -0
- data/spec/models/mixed_drink.rb +4 -0
- data/spec/models/name.rb +13 -0
- data/spec/models/namespacing.rb +11 -0
- data/spec/models/patient.rb +4 -0
- data/spec/models/person.rb +97 -0
- data/spec/models/pet.rb +7 -0
- data/spec/models/pet_owner.rb +6 -0
- data/spec/models/phone.rb +7 -0
- data/spec/models/post.rb +15 -0
- data/spec/models/translation.rb +5 -0
- data/spec/models/vet_visit.rb +5 -0
- data/spec/spec_helper.rb +9 -326
- data/spec/unit/mongoid/associations/belongs_to_related_spec.rb +26 -5
- data/spec/unit/mongoid/associations/belongs_to_spec.rb +96 -30
- data/spec/unit/mongoid/associations/has_many_related_spec.rb +32 -12
- data/spec/unit/mongoid/associations/has_many_spec.rb +48 -12
- data/spec/unit/mongoid/associations/has_one_related_spec.rb +29 -4
- data/spec/unit/mongoid/associations/has_one_spec.rb +46 -1
- data/spec/unit/mongoid/associations/options_spec.rb +58 -0
- data/spec/unit/mongoid/associations_spec.rb +58 -1
- data/spec/unit/mongoid/criteria_spec.rb +71 -735
- data/spec/unit/mongoid/criterion/complex_spec.rb +19 -0
- data/spec/unit/mongoid/criterion/exclusion_spec.rb +75 -0
- data/spec/unit/mongoid/criterion/inclusion_spec.rb +213 -0
- data/spec/unit/mongoid/criterion/optional_spec.rb +244 -0
- data/spec/unit/mongoid/extensions/hash/accessors_spec.rb +20 -0
- metadata +53 -3
- data/lib/mongoid/complex_criterion.rb +0 -10
data/.watchr
CHANGED
@@ -1,3 +1,14 @@
|
|
1
|
+
# Watchr is the preferred method to run specs automatically over rspactor for
|
2
|
+
# Mongoid. If you are using vim, you can add the file:
|
3
|
+
#
|
4
|
+
# ~/.vim/ftdetect/watchr.vim
|
5
|
+
#
|
6
|
+
# This should have only the following line in it:
|
7
|
+
#
|
8
|
+
# autocmd BufNewFile,BufRead *.watchr setf ruby
|
9
|
+
#
|
10
|
+
# This will enable vim to recognize this file as ruby code should you wish to
|
11
|
+
# edit it.
|
1
12
|
def run(cmd)
|
2
13
|
puts cmd
|
3
14
|
system cmd
|
@@ -7,5 +18,12 @@ def spec(file)
|
|
7
18
|
run "spec -O spec/spec.opts #{file}"
|
8
19
|
end
|
9
20
|
|
10
|
-
watch("spec/.*/*_spec\.rb")
|
11
|
-
|
21
|
+
watch("spec/.*/*_spec\.rb") do |match|
|
22
|
+
p match[0]
|
23
|
+
spec(match[0])
|
24
|
+
end
|
25
|
+
|
26
|
+
watch('lib/(.*/.*)\.rb') do |match|
|
27
|
+
p match[1]
|
28
|
+
spec("spec/unit/#{match[1]}_spec.rb")
|
29
|
+
end
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
1.1.
|
1
|
+
1.1.4
|
data/caliper.yml
ADDED
data/lib/mongoid.rb
CHANGED
data/lib/mongoid/associations.rb
CHANGED
@@ -59,14 +59,16 @@ module Mongoid # :nodoc:
|
|
59
59
|
# include Mongoid::Document
|
60
60
|
# belongs_to :person, :inverse_of => :addresses
|
61
61
|
# end
|
62
|
-
def belongs_to(name, options = {})
|
62
|
+
def belongs_to(name, options = {}, &block)
|
63
63
|
unless options.has_key?(:inverse_of)
|
64
64
|
raise Errors::InvalidOptions.new("Options for belongs_to association must include :inverse_of")
|
65
65
|
end
|
66
66
|
self.embedded = true
|
67
67
|
add_association(
|
68
68
|
Associations::BelongsTo,
|
69
|
-
Associations::Options.new(
|
69
|
+
Associations::Options.new(
|
70
|
+
options.merge(:name => name, :extend => block)
|
71
|
+
)
|
70
72
|
)
|
71
73
|
end
|
72
74
|
|
@@ -84,11 +86,13 @@ module Mongoid # :nodoc:
|
|
84
86
|
# belongs_to_related :person
|
85
87
|
# end
|
86
88
|
#
|
87
|
-
def belongs_to_related(name, options = {})
|
89
|
+
def belongs_to_related(name, options = {}, &block)
|
88
90
|
field "#{name.to_s}_id"
|
89
91
|
add_association(
|
90
92
|
Associations::BelongsToRelated,
|
91
|
-
Associations::Options.new(
|
93
|
+
Associations::Options.new(
|
94
|
+
options.merge(:name => name, :extend => block)
|
95
|
+
)
|
92
96
|
)
|
93
97
|
end
|
94
98
|
|
@@ -111,10 +115,12 @@ module Mongoid # :nodoc:
|
|
111
115
|
# include Mongoid::Document
|
112
116
|
# belongs_to :person, :inverse_of => :addresses
|
113
117
|
# end
|
114
|
-
def has_many(name, options = {})
|
118
|
+
def has_many(name, options = {}, &block)
|
115
119
|
add_association(
|
116
120
|
Associations::HasMany,
|
117
|
-
Associations::Options.new(
|
121
|
+
Associations::Options.new(
|
122
|
+
options.merge(:name => name, :extend => block)
|
123
|
+
)
|
118
124
|
)
|
119
125
|
end
|
120
126
|
|
@@ -132,10 +138,12 @@ module Mongoid # :nodoc:
|
|
132
138
|
# has_many_related :posts
|
133
139
|
# end
|
134
140
|
#
|
135
|
-
def has_many_related(name, options = {})
|
141
|
+
def has_many_related(name, options = {}, &block)
|
136
142
|
add_association(
|
137
143
|
Associations::HasManyRelated,
|
138
|
-
Associations::Options.new(
|
144
|
+
Associations::Options.new(
|
145
|
+
options.merge(:name => name, :parent_key => self.name.foreign_key, :extend => block)
|
146
|
+
)
|
139
147
|
)
|
140
148
|
before_save do |document|
|
141
149
|
document.update_associations(name)
|
@@ -161,8 +169,10 @@ module Mongoid # :nodoc:
|
|
161
169
|
# include Mongoid::Document
|
162
170
|
# belongs_to :person
|
163
171
|
# end
|
164
|
-
def has_one(name, options = {})
|
165
|
-
opts = Associations::Options.new(
|
172
|
+
def has_one(name, options = {}, &block)
|
173
|
+
opts = Associations::Options.new(
|
174
|
+
options.merge(:name => name, :extend => block)
|
175
|
+
)
|
166
176
|
type = Associations::HasOne
|
167
177
|
add_association(type, opts)
|
168
178
|
add_builder(type, opts)
|
@@ -182,10 +192,12 @@ module Mongoid # :nodoc:
|
|
182
192
|
# include Mongoid::Document
|
183
193
|
# has_one_related :game
|
184
194
|
# end
|
185
|
-
def has_one_related(name, options = {})
|
195
|
+
def has_one_related(name, options = {}, &block)
|
186
196
|
add_association(
|
187
197
|
Associations::HasOneRelated,
|
188
|
-
Associations::Options.new(
|
198
|
+
Associations::Options.new(
|
199
|
+
options.merge(:name => name, :parent_key => self.name.foreign_key, :extend => block)
|
200
|
+
)
|
189
201
|
)
|
190
202
|
before_save do |document|
|
191
203
|
document.update_association(name)
|
@@ -227,7 +239,7 @@ module Mongoid # :nodoc:
|
|
227
239
|
def add_builder(type, options)
|
228
240
|
name = options.name.to_s
|
229
241
|
define_method("build_#{name}") do |attrs|
|
230
|
-
reset(name) { type.new(self, attrs, options) }
|
242
|
+
reset(name) { type.new(self, attrs.stringify_keys, options) }
|
231
243
|
end
|
232
244
|
end
|
233
245
|
|
@@ -4,10 +4,8 @@ module Mongoid #:nodoc:
|
|
4
4
|
class BelongsTo #:nodoc:
|
5
5
|
include Proxy
|
6
6
|
|
7
|
-
attr_reader :document, :options
|
8
|
-
|
9
7
|
# Creates the new association by setting the internal
|
10
|
-
#
|
8
|
+
# target as the passed in Document. This should be the
|
11
9
|
# parent.
|
12
10
|
#
|
13
11
|
# All method calls on this object will then be delegated
|
@@ -15,22 +13,18 @@ module Mongoid #:nodoc:
|
|
15
13
|
#
|
16
14
|
# Options:
|
17
15
|
#
|
18
|
-
#
|
16
|
+
# target: The parent +Document+
|
19
17
|
# options: The association options
|
20
|
-
def initialize(
|
21
|
-
@
|
18
|
+
def initialize(target, options)
|
19
|
+
@target, @options = target, options
|
20
|
+
extends(options)
|
22
21
|
end
|
23
22
|
|
24
23
|
# Returns the parent document. The id param is present for
|
25
24
|
# compatibility with rails, however this could be overwritten
|
26
25
|
# in the future.
|
27
26
|
def find(id)
|
28
|
-
@
|
29
|
-
end
|
30
|
-
|
31
|
-
# Delegate all missing methods over to the parent +Document+.
|
32
|
-
def method_missing(name, *args, &block)
|
33
|
-
@document.send(name, *args, &block)
|
27
|
+
@target
|
34
28
|
end
|
35
29
|
|
36
30
|
class << self
|
@@ -43,8 +37,8 @@ module Mongoid #:nodoc:
|
|
43
37
|
# document: The parent +Document+
|
44
38
|
# options: The association options
|
45
39
|
def instantiate(document, options)
|
46
|
-
|
47
|
-
|
40
|
+
target = document._parent
|
41
|
+
target.nil? ? nil : new(target, options)
|
48
42
|
end
|
49
43
|
|
50
44
|
# Returns the macro used to create the association.
|
@@ -55,10 +49,14 @@ module Mongoid #:nodoc:
|
|
55
49
|
# Perform an update of the relationship of the parent and child. This
|
56
50
|
# is initialized by setting a parent object as the association on the
|
57
51
|
# +Document+. Will properly set a has_one or a has_many.
|
58
|
-
|
59
|
-
|
52
|
+
#
|
53
|
+
# Returns:
|
54
|
+
#
|
55
|
+
# A new +BelongsTo+ association proxy.
|
56
|
+
def update(target, child, options)
|
57
|
+
child.parentize(target, options.inverse_of)
|
60
58
|
child.notify
|
61
|
-
|
59
|
+
instantiate(child, options)
|
62
60
|
end
|
63
61
|
end
|
64
62
|
end
|
@@ -4,8 +4,6 @@ module Mongoid #:nodoc:
|
|
4
4
|
class BelongsToRelated #:nodoc:
|
5
5
|
include Proxy
|
6
6
|
|
7
|
-
attr_reader :document, :options
|
8
|
-
|
9
7
|
# Initializing a related association only requires looking up the object
|
10
8
|
# by its id.
|
11
9
|
#
|
@@ -13,13 +11,10 @@ module Mongoid #:nodoc:
|
|
13
11
|
#
|
14
12
|
# document: The +Document+ that contains the relationship.
|
15
13
|
# options: The association +Options+.
|
16
|
-
def initialize(document, foreign_key, options)
|
17
|
-
@
|
18
|
-
|
19
|
-
|
20
|
-
# Delegate all missing methods over to the +Document+.
|
21
|
-
def method_missing(name, *args)
|
22
|
-
@document.send(name, *args)
|
14
|
+
def initialize(document, foreign_key, options, target = nil)
|
15
|
+
@options = options
|
16
|
+
@target = target || options.klass.find(foreign_key)
|
17
|
+
extends(options)
|
23
18
|
end
|
24
19
|
|
25
20
|
class << self
|
@@ -31,9 +26,9 @@ module Mongoid #:nodoc:
|
|
31
26
|
#
|
32
27
|
# document: The +Document+ that contains the relationship.
|
33
28
|
# options: The association +Options+.
|
34
|
-
def instantiate(document, options)
|
29
|
+
def instantiate(document, options, target = nil)
|
35
30
|
foreign_key = document.send(options.foreign_key)
|
36
|
-
foreign_key.blank? ? nil : new(document, foreign_key, options)
|
31
|
+
foreign_key.blank? ? nil : new(document, foreign_key, options, target)
|
37
32
|
end
|
38
33
|
|
39
34
|
# Returns the macro used to create the association.
|
@@ -53,9 +48,12 @@ module Mongoid #:nodoc:
|
|
53
48
|
# Example:
|
54
49
|
#
|
55
50
|
# <tt>BelongsToRelated.update(game, person, options)</tt>
|
56
|
-
def update(
|
57
|
-
|
58
|
-
|
51
|
+
def update(target, parent, options)
|
52
|
+
if target
|
53
|
+
parent.send("#{options.foreign_key}=", target.id)
|
54
|
+
return instantiate(parent, options, target)
|
55
|
+
end
|
56
|
+
target
|
59
57
|
end
|
60
58
|
end
|
61
59
|
|
@@ -4,44 +4,43 @@ module Mongoid #:nodoc:
|
|
4
4
|
class HasMany
|
5
5
|
include Proxy
|
6
6
|
|
7
|
-
attr_accessor :association_name, :klass
|
7
|
+
attr_accessor :association_name, :klass
|
8
8
|
|
9
9
|
# Appends the object to the +Array+, setting its parent in
|
10
10
|
# the process.
|
11
11
|
def <<(*objects)
|
12
12
|
objects.flatten.each do |object|
|
13
13
|
object.parentize(@parent, @association_name)
|
14
|
-
@
|
14
|
+
@target << object
|
15
15
|
object.notify
|
16
16
|
end
|
17
17
|
end
|
18
18
|
|
19
|
+
alias :concat :<<
|
20
|
+
alias :push :<<
|
21
|
+
|
19
22
|
# Clears the association, and notifies the parents of the removal.
|
20
23
|
def clear
|
21
|
-
unless @
|
22
|
-
object = @
|
24
|
+
unless @target.empty?
|
25
|
+
object = @target.first
|
23
26
|
object.changed(true)
|
24
27
|
object.notify_observers(object, true)
|
25
|
-
@
|
28
|
+
@target.clear
|
26
29
|
end
|
27
30
|
end
|
28
31
|
|
29
|
-
# Appends the object to the +Array+, setting its parent in
|
30
|
-
# the process.
|
31
|
-
def concat(*objects)
|
32
|
-
self << objects
|
33
|
-
end
|
34
|
-
|
35
32
|
# Builds a new Document and adds it to the association collection. The
|
36
33
|
# document created will be of the same class as the others in the
|
37
34
|
# association, and the attributes will be passed into the constructor.
|
38
35
|
#
|
39
|
-
# Returns
|
36
|
+
# Returns:
|
37
|
+
#
|
38
|
+
# The newly created Document.
|
40
39
|
def build(attrs = {}, type = nil)
|
41
40
|
object = type ? type.instantiate : @klass.instantiate
|
42
41
|
object.parentize(@parent, @association_name)
|
43
42
|
object.write_attributes(attrs)
|
44
|
-
@
|
43
|
+
@target << object
|
45
44
|
object
|
46
45
|
end
|
47
46
|
|
@@ -50,7 +49,9 @@ module Mongoid #:nodoc:
|
|
50
49
|
# association, and the attributes will be passed into the constructor and
|
51
50
|
# the new object will then be saved.
|
52
51
|
#
|
53
|
-
# Returns
|
52
|
+
# Returns:
|
53
|
+
#
|
54
|
+
# Rhe newly created Document.
|
54
55
|
def create(attrs = {}, type = nil)
|
55
56
|
object = build(attrs, type)
|
56
57
|
object.save
|
@@ -58,10 +59,16 @@ module Mongoid #:nodoc:
|
|
58
59
|
end
|
59
60
|
|
60
61
|
# Finds a document in this association.
|
62
|
+
#
|
61
63
|
# If :all is passed, returns all the documents
|
64
|
+
#
|
62
65
|
# If an id is passed, will return the document for that id.
|
66
|
+
#
|
67
|
+
# Returns:
|
68
|
+
#
|
69
|
+
# Array or single Document.
|
63
70
|
def find(param)
|
64
|
-
return @
|
71
|
+
return @target if param == :all
|
65
72
|
return detect { |document| document.id == param }
|
66
73
|
end
|
67
74
|
|
@@ -72,27 +79,29 @@ module Mongoid #:nodoc:
|
|
72
79
|
#
|
73
80
|
# This then delegated all methods to the array class since this is
|
74
81
|
# essentially a proxy to an array itself.
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
82
|
+
#
|
83
|
+
# Options:
|
84
|
+
#
|
85
|
+
# parent: The parent document to the association.
|
86
|
+
# options: The association options.
|
87
|
+
def initialize(parent, options)
|
88
|
+
@parent, @association_name = parent, options.name
|
89
|
+
@klass, @options = options.klass, options
|
90
|
+
initialize_each(parent.raw_attributes[@association_name])
|
91
|
+
extends(options)
|
84
92
|
end
|
85
93
|
|
86
|
-
#
|
87
|
-
#
|
88
|
-
#
|
94
|
+
# If the target array does not respond to the supplied method then try to
|
95
|
+
# find a named scope or criteria on the class and send the call there.
|
96
|
+
#
|
97
|
+
# If the method exists on the array, use the default proxy behavior.
|
89
98
|
def method_missing(name, *args, &block)
|
90
|
-
unless @
|
99
|
+
unless @target.respond_to?(name)
|
91
100
|
criteria = @klass.send(name, *args)
|
92
|
-
criteria.documents = @
|
101
|
+
criteria.documents = @target
|
93
102
|
return criteria
|
94
103
|
end
|
95
|
-
|
104
|
+
super
|
96
105
|
end
|
97
106
|
|
98
107
|
# Used for setting associations via a nested attributes setter from the
|
@@ -101,16 +110,25 @@ module Mongoid #:nodoc:
|
|
101
110
|
# Options:
|
102
111
|
#
|
103
112
|
# attributes: A +Hash+ of integer keys and +Hash+ values.
|
113
|
+
#
|
114
|
+
# Returns:
|
115
|
+
#
|
116
|
+
# The newly build target Document.
|
104
117
|
def nested_build(attributes)
|
105
118
|
attributes.values.each do |attrs|
|
106
119
|
build(attrs)
|
107
120
|
end
|
108
121
|
end
|
109
122
|
|
110
|
-
|
111
|
-
# the
|
112
|
-
def
|
113
|
-
|
123
|
+
protected
|
124
|
+
# Initializes each of the attributes in the hash.
|
125
|
+
def initialize_each(attributes)
|
126
|
+
@target = attributes ? attributes.collect do |attrs|
|
127
|
+
klass = attrs.klass
|
128
|
+
child = klass ? klass.instantiate(attrs) : @klass.instantiate(attrs)
|
129
|
+
child.parentize(@parent, @association_name)
|
130
|
+
child
|
131
|
+
end : []
|
114
132
|
end
|
115
133
|
|
116
134
|
class << self
|
@@ -137,7 +155,7 @@ module Mongoid #:nodoc:
|
|
137
155
|
def update(children, parent, options)
|
138
156
|
parent.remove_attribute(options.name)
|
139
157
|
children.assimilate(parent, options)
|
140
|
-
|
158
|
+
instantiate(parent, options)
|
141
159
|
end
|
142
160
|
end
|
143
161
|
|
@@ -4,14 +4,12 @@ module Mongoid #:nodoc:
|
|
4
4
|
class HasManyRelated #:nodoc:
|
5
5
|
include Proxy
|
6
6
|
|
7
|
-
attr_reader :klass
|
8
|
-
|
9
7
|
# Appends the object to the +Array+, setting its parent in
|
10
8
|
# the process.
|
11
9
|
def <<(*objects)
|
12
10
|
objects.flatten.each do |object|
|
13
11
|
object.send("#{@foreign_key}=", @parent.id)
|
14
|
-
@
|
12
|
+
@target << object
|
15
13
|
object.save unless @parent.new_record?
|
16
14
|
end
|
17
15
|
end
|
@@ -24,7 +22,7 @@ module Mongoid #:nodoc:
|
|
24
22
|
def build(attributes = {})
|
25
23
|
name = @parent.class.to_s.underscore
|
26
24
|
object = @klass.instantiate(attributes.merge(name => @parent))
|
27
|
-
@
|
25
|
+
@target << object
|
28
26
|
object
|
29
27
|
end
|
30
28
|
|
@@ -59,15 +57,11 @@ module Mongoid #:nodoc:
|
|
59
57
|
#
|
60
58
|
# document: The +Document+ that contains the relationship.
|
61
59
|
# options: The association +Options+.
|
62
|
-
def initialize(document, options)
|
60
|
+
def initialize(document, options, target = nil)
|
63
61
|
@parent, @klass = document, options.klass
|
64
62
|
@foreign_key = document.class.to_s.foreign_key
|
65
|
-
@
|
66
|
-
|
67
|
-
|
68
|
-
# Delegate all missing methods over to the documents array.
|
69
|
-
def method_missing(name, *args, &block)
|
70
|
-
@documents.send(name, *args, &block)
|
63
|
+
@target = target || @klass.all(:conditions => { @foreign_key => document.id })
|
64
|
+
extends(options)
|
71
65
|
end
|
72
66
|
|
73
67
|
# Delegates to <<
|
@@ -82,8 +76,8 @@ module Mongoid #:nodoc:
|
|
82
76
|
#
|
83
77
|
# document: The +Document+ that contains the relationship.
|
84
78
|
# options: The association +Options+.
|
85
|
-
def instantiate(document, options)
|
86
|
-
new(document, options)
|
79
|
+
def instantiate(document, options, target = nil)
|
80
|
+
new(document, options, target)
|
87
81
|
end
|
88
82
|
|
89
83
|
# Returns the macro used to create the association.
|
@@ -103,9 +97,10 @@ module Mongoid #:nodoc:
|
|
103
97
|
# Example:
|
104
98
|
#
|
105
99
|
# <tt>RelatesToOne.update(game, person, options)</tt>
|
106
|
-
def update(
|
100
|
+
def update(target, document, options)
|
107
101
|
name = document.class.to_s.underscore
|
108
|
-
|
102
|
+
target.each { |child| child.send("#{name}=", document) }
|
103
|
+
instantiate(document, options, target)
|
109
104
|
end
|
110
105
|
end
|
111
106
|
|