mongoid 8.0.3 → 8.0.4
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- checksums.yaml.gz.sig +0 -0
- data/lib/mongoid/association/embedded/embeds_many/proxy.rb +17 -15
- data/lib/mongoid/association/referenced/has_and_belongs_to_many/proxy.rb +4 -0
- data/lib/mongoid/association/referenced/has_many/proxy.rb +4 -0
- data/lib/mongoid/criteria/queryable/extensions/array.rb +1 -1
- data/lib/mongoid/criteria/queryable/extensions/hash.rb +1 -1
- data/lib/mongoid/criteria/queryable/extensions/numeric.rb +0 -8
- data/lib/mongoid/criteria/queryable/extensions/string.rb +1 -11
- data/lib/mongoid/criteria/queryable/extensions/symbol.rb +0 -10
- data/lib/mongoid/criteria/translator.rb +45 -0
- data/lib/mongoid/criteria.rb +1 -0
- data/lib/mongoid/document.rb +50 -13
- data/lib/mongoid/factory.rb +21 -8
- data/lib/mongoid/matcher.rb +21 -6
- data/lib/mongoid/shardable.rb +35 -11
- data/lib/mongoid/threaded.rb +30 -0
- data/lib/mongoid/traversable.rb +1 -1
- data/lib/mongoid/version.rb +1 -1
- data/spec/mongoid/association/embedded/embeds_many/proxy_spec.rb +37 -32
- data/spec/mongoid/association/referenced/has_and_belongs_to_many/proxy_spec.rb +143 -197
- data/spec/mongoid/association/referenced/has_many/proxy_spec.rb +102 -114
- data/spec/mongoid/attributes_spec.rb +2 -2
- data/spec/mongoid/criteria/queryable/extensions/string_spec.rb +0 -59
- data/spec/mongoid/criteria/queryable/extensions/symbol_spec.rb +0 -59
- data/spec/mongoid/criteria/queryable/optional_spec.rb +15 -0
- data/spec/mongoid/criteria/translator_spec.rb +132 -0
- data/spec/mongoid/shardable_models.rb +14 -0
- data/spec/mongoid/shardable_spec.rb +153 -61
- data.tar.gz.sig +0 -0
- metadata +656 -648
- metadata.gz.sig +0 -0
@@ -2,6 +2,26 @@
|
|
2
2
|
|
3
3
|
require "spec_helper"
|
4
4
|
|
5
|
+
module RefHasManySpec
|
6
|
+
module OverrideInitialize
|
7
|
+
class Parent
|
8
|
+
include Mongoid::Document
|
9
|
+
has_many :children, inverse_of: :parent
|
10
|
+
end
|
11
|
+
|
12
|
+
class Child
|
13
|
+
include Mongoid::Document
|
14
|
+
belongs_to :parent
|
15
|
+
field :name, type: String
|
16
|
+
|
17
|
+
def initialize(*args)
|
18
|
+
super
|
19
|
+
self.name ||= "default"
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
5
25
|
describe Mongoid::Association::Referenced::HasMany::Proxy do
|
6
26
|
|
7
27
|
before :all do
|
@@ -877,6 +897,14 @@ describe Mongoid::Association::Referenced::HasMany::Proxy do
|
|
877
897
|
[ :build, :new ].each do |method|
|
878
898
|
|
879
899
|
describe "##{method}" do
|
900
|
+
context 'when model has #initialize' do
|
901
|
+
let(:parent) { RefHasManySpec::OverrideInitialize::Parent.create }
|
902
|
+
let(:child) { parent.children.send(method) }
|
903
|
+
|
904
|
+
it 'should call #initialize' do
|
905
|
+
expect(child.name).to be == "default"
|
906
|
+
end
|
907
|
+
end
|
880
908
|
|
881
909
|
context "when the association is not polymorphic" do
|
882
910
|
|
@@ -2077,154 +2105,114 @@ describe Mongoid::Association::Referenced::HasMany::Proxy do
|
|
2077
2105
|
end
|
2078
2106
|
end
|
2079
2107
|
|
2080
|
-
|
2081
|
-
|
2082
|
-
|
2083
|
-
Person.create!(username: 'arthurnn')
|
2084
|
-
end
|
2108
|
+
%i[ delete delete_one ].each do |method|
|
2109
|
+
describe "##{method}" do
|
2110
|
+
let!(:person) { Person.create!(username: 'arthurnn') }
|
2085
2111
|
|
2086
|
-
|
2112
|
+
context 'when the document is found' do
|
2113
|
+
context 'when no dependent option is set' do
|
2114
|
+
context 'when we are assigning attributes' do
|
2115
|
+
let!(:drug) { person.drugs.create! }
|
2116
|
+
let(:deleted) { person.drugs.send(method, drug) }
|
2087
2117
|
|
2088
|
-
|
2118
|
+
before do
|
2119
|
+
Mongoid::Threaded.begin_execution(:assign)
|
2120
|
+
end
|
2089
2121
|
|
2090
|
-
|
2122
|
+
after do
|
2123
|
+
Mongoid::Threaded.exit_execution(:assign)
|
2124
|
+
end
|
2091
2125
|
|
2092
|
-
|
2093
|
-
|
2126
|
+
it 'does not cascade' do
|
2127
|
+
expect(deleted.changes.keys).to eq([ 'person_id' ])
|
2128
|
+
end
|
2094
2129
|
end
|
2095
2130
|
|
2096
|
-
|
2097
|
-
|
2098
|
-
|
2131
|
+
context 'when the document is loaded' do
|
2132
|
+
let!(:drug) { person.drugs.create! }
|
2133
|
+
let!(:deleted) { person.drugs.send(method, drug) }
|
2099
2134
|
|
2100
|
-
|
2101
|
-
|
2102
|
-
|
2135
|
+
it 'returns the document' do
|
2136
|
+
expect(deleted).to eq(drug)
|
2137
|
+
end
|
2103
2138
|
|
2104
|
-
|
2105
|
-
|
2106
|
-
|
2139
|
+
it 'deletes the foreign key' do
|
2140
|
+
expect(drug.person_id).to be_nil
|
2141
|
+
end
|
2107
2142
|
|
2108
|
-
|
2109
|
-
|
2143
|
+
it 'removes the document from the association' do
|
2144
|
+
expect(person.drugs).not_to include(drug)
|
2145
|
+
end
|
2110
2146
|
end
|
2111
|
-
end
|
2112
2147
|
|
2113
|
-
|
2148
|
+
context 'when the document is not loaded' do
|
2149
|
+
let!(:drug) { Drug.create!(person_id: person.username) }
|
2150
|
+
let!(:deleted) { person.drugs.send(method, drug) }
|
2114
2151
|
|
2115
|
-
|
2116
|
-
|
2117
|
-
|
2152
|
+
it 'returns the document' do
|
2153
|
+
expect(deleted).to eq(drug)
|
2154
|
+
end
|
2118
2155
|
|
2119
|
-
|
2120
|
-
|
2121
|
-
|
2156
|
+
it 'deletes the foreign key' do
|
2157
|
+
expect(drug.person_id).to be_nil
|
2158
|
+
end
|
2122
2159
|
|
2123
|
-
|
2124
|
-
|
2160
|
+
it 'removes the document from the association' do
|
2161
|
+
expect(person.drugs).not_to include(drug)
|
2162
|
+
end
|
2125
2163
|
end
|
2164
|
+
end
|
2126
2165
|
|
2127
|
-
|
2128
|
-
|
2129
|
-
|
2166
|
+
context 'when dependent is delete' do
|
2167
|
+
context 'when the document is loaded' do
|
2168
|
+
let!(:post) { person.posts.create!(title: 'test') }
|
2169
|
+
let!(:deleted) { person.posts.send(method, post) }
|
2130
2170
|
|
2131
|
-
|
2132
|
-
|
2133
|
-
|
2134
|
-
end
|
2171
|
+
it 'returns the document' do
|
2172
|
+
expect(deleted).to eq(post)
|
2173
|
+
end
|
2135
2174
|
|
2136
|
-
|
2175
|
+
it 'deletes the document' do
|
2176
|
+
expect(post).to be_destroyed
|
2177
|
+
end
|
2137
2178
|
|
2138
|
-
|
2139
|
-
|
2179
|
+
it 'removes the document from the association' do
|
2180
|
+
expect(person.posts).not_to include(post)
|
2181
|
+
end
|
2140
2182
|
end
|
2141
2183
|
|
2142
|
-
|
2143
|
-
person.
|
2144
|
-
|
2184
|
+
context 'when the document is not loaded' do
|
2185
|
+
let!(:post) { Post.create!(title: 'foo', person_id: person.id) }
|
2186
|
+
let!(:deleted) { person.posts.send(method, post) }
|
2145
2187
|
|
2146
|
-
|
2147
|
-
|
2148
|
-
|
2188
|
+
it 'returns the document' do
|
2189
|
+
expect(deleted).to eq(post)
|
2190
|
+
end
|
2149
2191
|
|
2150
|
-
|
2151
|
-
|
2152
|
-
|
2192
|
+
it 'deletes the document' do
|
2193
|
+
expect(post).to be_destroyed
|
2194
|
+
end
|
2153
2195
|
|
2154
|
-
|
2155
|
-
|
2196
|
+
it 'removes the document from the association' do
|
2197
|
+
expect(person.posts).not_to include(post)
|
2198
|
+
end
|
2156
2199
|
end
|
2157
2200
|
end
|
2158
2201
|
end
|
2159
2202
|
|
2160
|
-
context
|
2203
|
+
context 'when the document is not found' do
|
2204
|
+
let!(:post) { Post.create!(title: 'foo') }
|
2205
|
+
let!(:deleted) { person.posts.send(method, post) }
|
2161
2206
|
|
2162
|
-
|
2163
|
-
|
2164
|
-
let!(:post) do
|
2165
|
-
person.posts.create!(title: "test")
|
2166
|
-
end
|
2167
|
-
|
2168
|
-
let!(:deleted) do
|
2169
|
-
person.posts.delete(post)
|
2170
|
-
end
|
2171
|
-
|
2172
|
-
it "returns the document" do
|
2173
|
-
expect(deleted).to eq(post)
|
2174
|
-
end
|
2175
|
-
|
2176
|
-
it "deletes the document" do
|
2177
|
-
expect(post).to be_destroyed
|
2178
|
-
end
|
2179
|
-
|
2180
|
-
it "removes the document from the association" do
|
2181
|
-
expect(person.posts).to_not include(post)
|
2182
|
-
end
|
2207
|
+
it 'returns nil' do
|
2208
|
+
expect(deleted).to be_nil
|
2183
2209
|
end
|
2184
2210
|
|
2185
|
-
|
2186
|
-
|
2187
|
-
let!(:post) do
|
2188
|
-
Post.create!(title: "foo", person_id: person.id)
|
2189
|
-
end
|
2190
|
-
|
2191
|
-
let!(:deleted) do
|
2192
|
-
person.posts.delete(post)
|
2193
|
-
end
|
2194
|
-
|
2195
|
-
it "returns the document" do
|
2196
|
-
expect(deleted).to eq(post)
|
2197
|
-
end
|
2198
|
-
|
2199
|
-
it "deletes the document" do
|
2200
|
-
expect(post).to be_destroyed
|
2201
|
-
end
|
2202
|
-
|
2203
|
-
it "removes the document from the association" do
|
2204
|
-
expect(person.posts).to_not include(post)
|
2205
|
-
end
|
2211
|
+
it 'does not delete the document' do
|
2212
|
+
expect(post).to be_persisted
|
2206
2213
|
end
|
2207
2214
|
end
|
2208
2215
|
end
|
2209
|
-
|
2210
|
-
context "when the document is not found" do
|
2211
|
-
|
2212
|
-
let!(:post) do
|
2213
|
-
Post.create!(title: "foo")
|
2214
|
-
end
|
2215
|
-
|
2216
|
-
let!(:deleted) do
|
2217
|
-
person.posts.delete(post)
|
2218
|
-
end
|
2219
|
-
|
2220
|
-
it "returns nil" do
|
2221
|
-
expect(deleted).to be_nil
|
2222
|
-
end
|
2223
|
-
|
2224
|
-
it "does not delete the document" do
|
2225
|
-
expect(post).to be_persisted
|
2226
|
-
end
|
2227
|
-
end
|
2228
2216
|
end
|
2229
2217
|
|
2230
2218
|
[ :delete_all, :destroy_all ].each do |method|
|
@@ -2499,7 +2499,7 @@ describe Mongoid::Attributes do
|
|
2499
2499
|
end
|
2500
2500
|
end
|
2501
2501
|
|
2502
|
-
context "when doing
|
2502
|
+
context "when doing _remove" do
|
2503
2503
|
let(:doc) { NestedBook.create! }
|
2504
2504
|
let(:page) { NestedPage.new }
|
2505
2505
|
before do
|
@@ -2507,7 +2507,7 @@ describe Mongoid::Attributes do
|
|
2507
2507
|
doc.pages << NestedPage.new
|
2508
2508
|
doc.pages << NestedPage.new
|
2509
2509
|
|
2510
|
-
doc.pages.
|
2510
|
+
doc.pages._remove(page)
|
2511
2511
|
end
|
2512
2512
|
|
2513
2513
|
it "updates the attributes" do
|
@@ -253,65 +253,6 @@ describe String do
|
|
253
253
|
end
|
254
254
|
end
|
255
255
|
|
256
|
-
describe "#to_direction" do
|
257
|
-
|
258
|
-
context "when ascending" do
|
259
|
-
|
260
|
-
it "returns 1" do
|
261
|
-
expect("ascending".to_direction).to eq(1)
|
262
|
-
end
|
263
|
-
end
|
264
|
-
|
265
|
-
context "when asc" do
|
266
|
-
|
267
|
-
it "returns 1" do
|
268
|
-
expect("asc".to_direction).to eq(1)
|
269
|
-
end
|
270
|
-
end
|
271
|
-
|
272
|
-
context "when ASCENDING" do
|
273
|
-
|
274
|
-
it "returns 1" do
|
275
|
-
expect("ASCENDING".to_direction).to eq(1)
|
276
|
-
end
|
277
|
-
end
|
278
|
-
|
279
|
-
context "when ASC" do
|
280
|
-
|
281
|
-
it "returns 1" do
|
282
|
-
expect("ASC".to_direction).to eq(1)
|
283
|
-
end
|
284
|
-
end
|
285
|
-
|
286
|
-
context "when descending" do
|
287
|
-
|
288
|
-
it "returns -1" do
|
289
|
-
expect("descending".to_direction).to eq(-1)
|
290
|
-
end
|
291
|
-
end
|
292
|
-
|
293
|
-
context "when desc" do
|
294
|
-
|
295
|
-
it "returns -1" do
|
296
|
-
expect("desc".to_direction).to eq(-1)
|
297
|
-
end
|
298
|
-
end
|
299
|
-
|
300
|
-
context "when DESCENDING" do
|
301
|
-
|
302
|
-
it "returns -1" do
|
303
|
-
expect("DESCENDING".to_direction).to eq(-1)
|
304
|
-
end
|
305
|
-
end
|
306
|
-
|
307
|
-
context "when DESC" do
|
308
|
-
|
309
|
-
it "returns -1" do
|
310
|
-
expect("DESC".to_direction).to eq(-1)
|
311
|
-
end
|
312
|
-
end
|
313
|
-
end
|
314
|
-
|
315
256
|
describe ".evolve" do
|
316
257
|
|
317
258
|
context "when provided a regex" do
|
@@ -107,63 +107,4 @@ describe Symbol do
|
|
107
107
|
end
|
108
108
|
end
|
109
109
|
end
|
110
|
-
|
111
|
-
describe "#to_direction" do
|
112
|
-
|
113
|
-
context "when ascending" do
|
114
|
-
|
115
|
-
it "returns 1" do
|
116
|
-
expect(:ascending.to_direction).to eq(1)
|
117
|
-
end
|
118
|
-
end
|
119
|
-
|
120
|
-
context "when asc" do
|
121
|
-
|
122
|
-
it "returns 1" do
|
123
|
-
expect(:asc.to_direction).to eq(1)
|
124
|
-
end
|
125
|
-
end
|
126
|
-
|
127
|
-
context "when ASCENDING" do
|
128
|
-
|
129
|
-
it "returns 1" do
|
130
|
-
expect(:ASCENDING.to_direction).to eq(1)
|
131
|
-
end
|
132
|
-
end
|
133
|
-
|
134
|
-
context "when ASC" do
|
135
|
-
|
136
|
-
it "returns 1" do
|
137
|
-
expect(:ASC.to_direction).to eq(1)
|
138
|
-
end
|
139
|
-
end
|
140
|
-
|
141
|
-
context "when descending" do
|
142
|
-
|
143
|
-
it "returns -1" do
|
144
|
-
expect(:descending.to_direction).to eq(-1)
|
145
|
-
end
|
146
|
-
end
|
147
|
-
|
148
|
-
context "when desc" do
|
149
|
-
|
150
|
-
it "returns -1" do
|
151
|
-
expect(:desc.to_direction).to eq(-1)
|
152
|
-
end
|
153
|
-
end
|
154
|
-
|
155
|
-
context "when DESCENDING" do
|
156
|
-
|
157
|
-
it "returns -1" do
|
158
|
-
expect(:DESCENDING.to_direction).to eq(-1)
|
159
|
-
end
|
160
|
-
end
|
161
|
-
|
162
|
-
context "when DESC" do
|
163
|
-
|
164
|
-
it "returns -1" do
|
165
|
-
expect(:DESC.to_direction).to eq(-1)
|
166
|
-
end
|
167
|
-
end
|
168
|
-
end
|
169
110
|
end
|
@@ -741,6 +741,21 @@ describe Mongoid::Criteria::Queryable::Optional do
|
|
741
741
|
|
742
742
|
it_behaves_like "a cloning option"
|
743
743
|
end
|
744
|
+
|
745
|
+
context "when the hash has hash values" do
|
746
|
+
|
747
|
+
let(:selection) do
|
748
|
+
query.send("#{method}", score: { "$meta" => "textScore"})
|
749
|
+
end
|
750
|
+
|
751
|
+
it "adds the sorting criteria" do
|
752
|
+
expect(selection.options).to eq(
|
753
|
+
{ sort: { "score" => { "$meta" => "textScore" } }}
|
754
|
+
)
|
755
|
+
end
|
756
|
+
|
757
|
+
it_behaves_like "a cloning option"
|
758
|
+
end
|
744
759
|
end
|
745
760
|
|
746
761
|
context "when provided an array" do
|
@@ -0,0 +1,132 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "spec_helper"
|
4
|
+
|
5
|
+
describe Mongoid::Criteria::Translator do
|
6
|
+
describe "#to_direction" do
|
7
|
+
context "when the value is a string" do
|
8
|
+
context "when ascending" do
|
9
|
+
it "returns 1" do
|
10
|
+
expect(described_class.to_direction("ascending")).to eq(1)
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
context "when asc" do
|
15
|
+
it "returns 1" do
|
16
|
+
expect(described_class.to_direction("asc")).to eq(1)
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
context "when ASCENDING" do
|
21
|
+
it "returns 1" do
|
22
|
+
expect(described_class.to_direction("ASCENDING")).to eq(1)
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
context "when ASC" do
|
27
|
+
it "returns 1" do
|
28
|
+
expect(described_class.to_direction("ASC")).to eq(1)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
context "when descending" do
|
33
|
+
it "returns -1" do
|
34
|
+
expect(described_class.to_direction("descending")).to eq(-1)
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
context "when desc" do
|
39
|
+
it "returns -1" do
|
40
|
+
expect(described_class.to_direction("desc")).to eq(-1)
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
context "when DESCENDING" do
|
45
|
+
it "returns -1" do
|
46
|
+
expect(described_class.to_direction("DESCENDING")).to eq(-1)
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
context "when DESC" do
|
51
|
+
it "returns -1" do
|
52
|
+
expect(described_class.to_direction("DESC")).to eq(-1)
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
context "when the value is a symbol" do
|
58
|
+
context "when ascending" do
|
59
|
+
it "returns 1" do
|
60
|
+
expect(described_class.to_direction(:ascending)).to eq(1)
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
context "when asc" do
|
65
|
+
it "returns 1" do
|
66
|
+
expect(described_class.to_direction(:asc)).to eq(1)
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
context "when ASCENDING" do
|
71
|
+
it "returns 1" do
|
72
|
+
expect(described_class.to_direction(:ASCENDING)).to eq(1)
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
context "when ASC" do
|
77
|
+
it "returns 1" do
|
78
|
+
expect(described_class.to_direction(:ASC)).to eq(1)
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
context "when descending" do
|
83
|
+
it "returns -1" do
|
84
|
+
expect(described_class.to_direction(:descending)).to eq(-1)
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
context "when desc" do
|
89
|
+
it "returns -1" do
|
90
|
+
expect(described_class.to_direction(:desc)).to eq(-1)
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
context "when DESCENDING" do
|
95
|
+
it "returns -1" do
|
96
|
+
expect(described_class.to_direction(:DESCENDING)).to eq(-1)
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
context "when DESC" do
|
101
|
+
it "returns -1" do
|
102
|
+
expect(described_class.to_direction(:DESC)).to eq(-1)
|
103
|
+
end
|
104
|
+
end
|
105
|
+
end
|
106
|
+
|
107
|
+
context "when the value is numeric" do
|
108
|
+
it "should pass the value through unchanged" do
|
109
|
+
expect(described_class.to_direction(1)).to eq(1)
|
110
|
+
expect(described_class.to_direction(-1)).to eq(-1)
|
111
|
+
expect(described_class.to_direction(Math::PI)).to eq(Math::PI)
|
112
|
+
end
|
113
|
+
end
|
114
|
+
|
115
|
+
context "when the value is a hash" do
|
116
|
+
it "should pass the value through unchanged" do
|
117
|
+
expect(described_class.to_direction({})).to eq({})
|
118
|
+
expect(described_class.to_direction(scope: { "$meta" => "textScore" }))
|
119
|
+
.to eq(scope: { "$meta" => "textScore" })
|
120
|
+
expect(described_class.to_direction(a: 1, b: 2)).to eq(a: 1, b: 2)
|
121
|
+
end
|
122
|
+
end
|
123
|
+
|
124
|
+
context "when the value is an unrecognized type" do
|
125
|
+
it "should raise ArgumentError" do
|
126
|
+
expect { described_class.to_direction([]) }.to raise_error(ArgumentError)
|
127
|
+
expect { described_class.to_direction(/a/) }.to raise_error(ArgumentError)
|
128
|
+
expect { described_class.to_direction(Object.new) }.to raise_error(ArgumentError)
|
129
|
+
end
|
130
|
+
end
|
131
|
+
end
|
132
|
+
end
|
@@ -59,3 +59,17 @@ end
|
|
59
59
|
class SmNotSharded
|
60
60
|
include Mongoid::Document
|
61
61
|
end
|
62
|
+
|
63
|
+
class SmReviewAuthor
|
64
|
+
include Mongoid::Document
|
65
|
+
embedded_in :review, class_name: "SmReview", touch: false
|
66
|
+
field :name, type: String
|
67
|
+
end
|
68
|
+
|
69
|
+
class SmReview
|
70
|
+
include Mongoid::Document
|
71
|
+
|
72
|
+
embeds_one :author, class_name: "SmReviewAuthor"
|
73
|
+
|
74
|
+
shard_key "author.name" => 1
|
75
|
+
end
|