emarsys 0.1.0
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/.gitignore +18 -0
- data/.rspec +1 -0
- data/Gemfile +11 -0
- data/LICENSE.txt +22 -0
- data/README.md +171 -0
- data/Rakefile +7 -0
- data/emarsys.gemspec +25 -0
- data/lib/emarsys.rb +60 -0
- data/lib/emarsys/client.rb +40 -0
- data/lib/emarsys/data_object.rb +78 -0
- data/lib/emarsys/data_objects/condition.rb +20 -0
- data/lib/emarsys/data_objects/contact.rb +121 -0
- data/lib/emarsys/data_objects/contact_list.rb +47 -0
- data/lib/emarsys/data_objects/email.rb +133 -0
- data/lib/emarsys/data_objects/email_category.rb +20 -0
- data/lib/emarsys/data_objects/email_launch_status.rb +38 -0
- data/lib/emarsys/data_objects/email_status_code.rb +39 -0
- data/lib/emarsys/data_objects/event.rb +44 -0
- data/lib/emarsys/data_objects/export.rb +22 -0
- data/lib/emarsys/data_objects/field.rb +39 -0
- data/lib/emarsys/data_objects/file.rb +39 -0
- data/lib/emarsys/data_objects/folder.rb +24 -0
- data/lib/emarsys/data_objects/form.rb +21 -0
- data/lib/emarsys/data_objects/language.rb +20 -0
- data/lib/emarsys/data_objects/segment.rb +21 -0
- data/lib/emarsys/data_objects/source.rb +40 -0
- data/lib/emarsys/error.rb +24 -0
- data/lib/emarsys/extensions.rb +8 -0
- data/lib/emarsys/field_mapping.rb +55 -0
- data/lib/emarsys/params_converter.rb +29 -0
- data/lib/emarsys/request.rb +46 -0
- data/lib/emarsys/response.rb +24 -0
- data/lib/emarsys/version.rb +3 -0
- data/spec/emarsys/client_spec.rb +85 -0
- data/spec/emarsys/data_object_spec.rb +55 -0
- data/spec/emarsys/data_objects/condition_spec.rb +9 -0
- data/spec/emarsys/data_objects/contact_list_spec.rb +9 -0
- data/spec/emarsys/data_objects/contact_spec.rb +79 -0
- data/spec/emarsys/data_objects/email_category_spec.rb +9 -0
- data/spec/emarsys/data_objects/email_launch_status_spec.rb +25 -0
- data/spec/emarsys/data_objects/email_spec.rb +84 -0
- data/spec/emarsys/data_objects/email_status_code_spec.rb +25 -0
- data/spec/emarsys/data_objects/event_spec.rb +23 -0
- data/spec/emarsys/data_objects/export_spec.rb +9 -0
- data/spec/emarsys/data_objects/field_spec.rb +19 -0
- data/spec/emarsys/data_objects/file_spec.rb +29 -0
- data/spec/emarsys/data_objects/folder_spec.rb +13 -0
- data/spec/emarsys/data_objects/form_spec.rb +9 -0
- data/spec/emarsys/data_objects/language_spec.rb +9 -0
- data/spec/emarsys/data_objects/segment_spec.rb +9 -0
- data/spec/emarsys/data_objects/source_spec.rb +25 -0
- data/spec/emarsys/extensions_spec.rb +24 -0
- data/spec/emarsys/field_mapping_spec.rb +14 -0
- data/spec/emarsys/params_converter_spec.rb +52 -0
- data/spec/emarsys/request_spec.rb +27 -0
- data/spec/emarsys/response_spec.rb +35 -0
- data/spec/emarsys_spec.rb +22 -0
- data/spec/spec_helper.rb +28 -0
- metadata +178 -0
@@ -0,0 +1,55 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Emarsys::DataObject do
|
4
|
+
context "as a class" do
|
5
|
+
|
6
|
+
describe '.get' do
|
7
|
+
it "delegates to the instance request method" do
|
8
|
+
Emarsys::DataObject.any_instance.should_receive(:request).with('get', 'test_method', {}).and_return(nil)
|
9
|
+
Emarsys::DataObject.get('test_method', {})
|
10
|
+
end
|
11
|
+
|
12
|
+
it "transfers params to specific emarsys params format" do
|
13
|
+
Emarsys::DataObject.any_instance.should_receive(:request).with('get', 'test_method/a=1&b=2', {}).and_return(nil)
|
14
|
+
Emarsys::DataObject.get('test_method', {'a' => 1, 'b' => 2})
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
describe '.post' do
|
19
|
+
it "delegates to the instance request method" do
|
20
|
+
Emarsys::DataObject.any_instance.should_receive(:request).with('post', 'test_method', {}).and_return(nil)
|
21
|
+
Emarsys::DataObject.post('test_method', {})
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
describe '.put' do
|
26
|
+
it "delegates to the instance request method" do
|
27
|
+
Emarsys::DataObject.any_instance.should_receive(:request).with('put', 'test_method', {}).and_return(nil)
|
28
|
+
Emarsys::DataObject.put('test_method', {})
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
describe '.delete' do
|
33
|
+
it "delegates to the instance request method" do
|
34
|
+
Emarsys::DataObject.any_instance.should_receive(:request).with('delete', 'test_method', {}).and_return(nil)
|
35
|
+
Emarsys::DataObject.delete('test_method', {})
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
describe '.parameterize_params' do
|
40
|
+
it "converts hash to params string" do
|
41
|
+
params = {"a" => 1, "b" => 2, "c" => 3}
|
42
|
+
expect(Emarsys::DataObject.parameterize_params(params)).to eq("a=1&b=2&c=3")
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
context "as an instance" do
|
48
|
+
let(:data_object) { Emarsys::DataObject.new }
|
49
|
+
|
50
|
+
it "provides a simpel #request that delegates to Emarsys::Request" do
|
51
|
+
Emarsys::Request.any_instance.should_receive(:send_request).and_return(nil)
|
52
|
+
data_object.request('get', 'test_method', {})
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
@@ -0,0 +1,79 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Emarsys::Contact do
|
4
|
+
describe ".create" do
|
5
|
+
it "requests contact creation with parameters" do
|
6
|
+
stub_params = {1 => 'John', 2 => "Doe"}
|
7
|
+
stub = stub_request(:post, "https://suite5.emarsys.net/api/v2/contact").with(:body => stub_params.merge!({'key_id' => 3, 3 => 'john.doe@example.com'}).to_json).to_return(standard_return_body)
|
8
|
+
Emarsys::Contact.create(3, "john.doe@example.com", stub_params)
|
9
|
+
stub.should have_been_requested.once
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
describe ".emarsys_id" do
|
14
|
+
it "requests emarsys_id of a contact" do
|
15
|
+
stub = stub_request(:get, "https://suite5.emarsys.net/api/v2/contact/3=jane.doe@example.com").to_return(standard_return_body)
|
16
|
+
Emarsys::Contact.emarsys_id(3, 'jane.doe@example.com')
|
17
|
+
stub.should have_been_requested.once
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
describe ".update" do
|
22
|
+
it "requests contact update with parameters" do
|
23
|
+
stub_params = {1 => 'Jane', 2 => "Doe"}
|
24
|
+
stub = stub_request(:put, "https://suite5.emarsys.net/api/v2/contact").with(:body => stub_params.merge!({'key_id' => 3, 3 => 'jane.doe@example.com'}).to_json).to_return(standard_return_body)
|
25
|
+
Emarsys::Contact.update(3, 'jane.doe@example.com', stub_params)
|
26
|
+
stub.should have_been_requested.once
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
describe ".create_batch" do
|
31
|
+
it "requests contact batch creation with parameters" do
|
32
|
+
stub_params = [{1 => 'Jane', 2 => "Doe"}, {1 => 'Paul', 2 => 'Tester'}]
|
33
|
+
stub = stub_request(:post, "https://suite5.emarsys.net/api/v2/contact").with(:body => {'key_id' => 3, 'contacts' => stub_params}.to_json).to_return(standard_return_body)
|
34
|
+
Emarsys::Contact.create_batch(3, stub_params)
|
35
|
+
stub.should have_been_requested.once
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
describe ".update_batch" do
|
40
|
+
it "requests contact batch update with parameters" do
|
41
|
+
stub_params = [{1 => 'Jane', 2 => "Doe"}, {1 => 'Paul', 2 => 'Tester'}]
|
42
|
+
stub = stub_request(:put, "https://suite5.emarsys.net/api/v2/contact").with(:body => {'key_id' => 3, 'contacts' => stub_params}.to_json).to_return(standard_return_body)
|
43
|
+
Emarsys::Contact.update_batch(3, stub_params)
|
44
|
+
stub.should have_been_requested.once
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
describe ".contact_history" do
|
49
|
+
it "requests contact histories" do
|
50
|
+
stub_params = [1,2,3]
|
51
|
+
stub = stub_request(:post, "https://suite5.emarsys.net/api/v2/contact/getcontacthistory").with(:body => {'contacts' => stub_params}.to_json).to_return(standard_return_body)
|
52
|
+
Emarsys::Contact.contact_history(stub_params)
|
53
|
+
stub.should have_been_requested.once
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
describe ".search" do
|
58
|
+
it "requests contact data based on search params" do
|
59
|
+
stub = stub_request(:post, "https://suite5.emarsys.net/api/v2/contact/getdata").with(:body => {'keyId' => '3', 'keyValues' => ['jane.doe@example.com'], 'fields' => []}.to_json).to_return(standard_return_body)
|
60
|
+
Emarsys::Contact.search('3', ['jane.doe@example.com'])
|
61
|
+
stub.should have_been_requested.once
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
describe ".export_registrations" do
|
66
|
+
it "requests contact data export based on parameters" do
|
67
|
+
stub_params = {distribution_method: 'local', time_range: ["2013-01-01","2013-12-31"], contact_fields: [1,2,3]}
|
68
|
+
stub = stub_request(:post, "https://suite5.emarsys.net/api/v2/contact/getregistrations").with(:body => stub_params.to_json).to_return(standard_return_body)
|
69
|
+
Emarsys::Contact.export_registrations(stub_params)
|
70
|
+
stub.should have_been_requested.once
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
|
75
|
+
|
76
|
+
def contact_history(contact_ids_array)
|
77
|
+
post "contact/getcontacthistory", {'contacts' => contact_ids_array}
|
78
|
+
end
|
79
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Emarsys::EmailLaunchStatus do
|
4
|
+
describe "CODES constant" do
|
5
|
+
it "is an array of size 4" do
|
6
|
+
expect(Emarsys::EmailLaunchStatus::CODES.size).to eq(4)
|
7
|
+
end
|
8
|
+
end
|
9
|
+
|
10
|
+
describe ".collection" do
|
11
|
+
it "requests all email_launch_status" do
|
12
|
+
expect(Emarsys::EmailLaunchStatus.collection).to eq(Emarsys::EmailLaunchStatus::CODES)
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
describe ".resource" do
|
17
|
+
it "requests a single email launch status" do
|
18
|
+
expect(Emarsys::EmailLaunchStatus.resource(0)).to eq({'0' => 'Not launched'})
|
19
|
+
end
|
20
|
+
|
21
|
+
it "returns nil if it cannot find a launch code" do
|
22
|
+
expect(Emarsys::EmailLaunchStatus.resource(100)).to eq(nil)
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,84 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Emarsys::Email do
|
4
|
+
describe ".collection" do
|
5
|
+
it "requests all emails" do
|
6
|
+
stub_get('email') { Emarsys::Email.collection }.should have_been_requested.once
|
7
|
+
end
|
8
|
+
|
9
|
+
it "requests all emails to the given status parameter" do
|
10
|
+
stub_get('email/status=3') { Emarsys::Email.collection({:status => 3}) }.should have_been_requested.once
|
11
|
+
end
|
12
|
+
|
13
|
+
it "requests all emails to the given contactlist parameter" do
|
14
|
+
stub_get('email/contactlist=123') { Emarsys::Email.collection({:contactlist => 123}) }.should have_been_requested.once
|
15
|
+
end
|
16
|
+
|
17
|
+
it "requests all emails - even with combined parameters" do
|
18
|
+
stub_get('email/status=3&contactlist=123') { Emarsys::Email.collection({:status => 3, :contactlist => 123}) }.should have_been_requested.once
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
describe ".resource" do
|
23
|
+
it "requests a single email" do
|
24
|
+
stub_get('email/123') { Emarsys::Email.resource(123) }.should have_been_requested.once
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
describe ".create" do
|
29
|
+
it "requests email creation" do
|
30
|
+
stub = stub_request(:post, "https://suite5.emarsys.net/api/v2/email").to_return(standard_return_body)
|
31
|
+
Emarsys::Email.create
|
32
|
+
stub.should have_been_requested.once
|
33
|
+
end
|
34
|
+
|
35
|
+
it "requests email creation with parameters" do
|
36
|
+
stub_params = {:language => 'de', :name => "Something"}
|
37
|
+
stub = stub_request(:post, "https://suite5.emarsys.net/api/v2/email").with(:body => stub_params.to_json).to_return(standard_return_body)
|
38
|
+
Emarsys::Email.create(stub_params)
|
39
|
+
stub.should have_been_requested.once
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
describe ".launch" do
|
44
|
+
it "requests an email launch" do
|
45
|
+
stub = stub_request(:post, "https://suite5.emarsys.net/api/v2/email/123/launch").to_return(standard_return_body)
|
46
|
+
Emarsys::Email.launch(123)
|
47
|
+
stub.should have_been_requested.once
|
48
|
+
end
|
49
|
+
|
50
|
+
it "requests an email launch with parameters" do
|
51
|
+
stub_params = {:schedule => "2013-12-01 23:00:00", :time_zone => "Europe/Berlin"}
|
52
|
+
stub = stub_request(:post, "https://suite5.emarsys.net/api/v2/email/123/launch").with(:body => stub_params.to_json).to_return(standard_return_body)
|
53
|
+
Emarsys::Email.launch(123, stub_params)
|
54
|
+
stub.should have_been_requested.once
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
describe ".preview" do
|
59
|
+
it "requests an email preview" do
|
60
|
+
stub_params = {:version => 'html'}
|
61
|
+
stub = stub_request(:post, "https://suite5.emarsys.net/api/v2/email/123/preview").with(:body => stub_params.to_json).to_return(standard_return_body)
|
62
|
+
Emarsys::Email.preview(123, 'html')
|
63
|
+
stub.should have_been_requested.once
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
describe ".send_test_mail" do
|
68
|
+
it "requests an email test sending with custom recipient list" do
|
69
|
+
stub_params = {:recipientlist => 'john.doe@example.com;jane.doe@example.com'}
|
70
|
+
stub = stub_request(:post, "https://suite5.emarsys.net/api/v2/email/123/sendtestmail").with(:body => stub_params.to_json).to_return(standard_return_body)
|
71
|
+
Emarsys::Email.send_test_mail(123, stub_params)
|
72
|
+
stub.should have_been_requested.once
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
describe ".response_summary" do
|
77
|
+
it "requests a single email" do
|
78
|
+
stub_get('email/123/responsesummary') { Emarsys::Email.response_summary(123) }.should have_been_requested.once
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
|
83
|
+
|
84
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Emarsys::EmailStatusCode do
|
4
|
+
describe "CODES constant" do
|
5
|
+
it "is an array of size 5" do
|
6
|
+
expect(Emarsys::EmailStatusCode::CODES.size).to eq(5)
|
7
|
+
end
|
8
|
+
end
|
9
|
+
|
10
|
+
describe ".collection" do
|
11
|
+
it "requests all email_status_codes" do
|
12
|
+
expect(Emarsys::EmailStatusCode.collection).to eq(Emarsys::EmailStatusCode::CODES)
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
describe ".resource" do
|
17
|
+
it "requests a single email status code hash" do
|
18
|
+
expect(Emarsys::EmailStatusCode.resource(1)).to eq({'1' => 'In design'})
|
19
|
+
end
|
20
|
+
|
21
|
+
it "returns nil if it cannot find a status code" do
|
22
|
+
expect(Emarsys::EmailStatusCode.resource(100)).to eq(nil)
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Emarsys::Event do
|
4
|
+
describe ".collection" do
|
5
|
+
it "requests all events" do
|
6
|
+
stub_get("event") { Emarsys::Event.collection }.should have_been_requested.once
|
7
|
+
end
|
8
|
+
end
|
9
|
+
|
10
|
+
describe ".trigger" do
|
11
|
+
it "requests event trigger with parameters" do
|
12
|
+
stub = stub_request(:post, "https://suite5.emarsys.net/api/v2/event/123/trigger").with(:body => {'key_id' => 3, 'external_id' => "jane.doe@example.com"}.to_json).to_return(standard_return_body)
|
13
|
+
Emarsys::Event.trigger(123, 3, 'jane.doe@example.com')
|
14
|
+
stub.should have_been_requested.once
|
15
|
+
end
|
16
|
+
|
17
|
+
it "requests event trigger with additional data parameters" do
|
18
|
+
stub = stub_request(:post, "https://suite5.emarsys.net/api/v2/event/123/trigger").with(:body => {'key_id' => 3, 'external_id' => "jane.doe@example.com", :data => {'global' => {'my_placeholder' => 'Something'}}}.to_json).to_return(standard_return_body)
|
19
|
+
Emarsys::Event.trigger(123, 3, 'jane.doe@example.com', {'global' => {'my_placeholder' => 'Something'}})
|
20
|
+
stub.should have_been_requested.once
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Emarsys::Field do
|
4
|
+
describe ".collection" do
|
5
|
+
it "requests all fields" do
|
6
|
+
stub_get("field") { Emarsys::Field.collection }.should have_been_requested.once
|
7
|
+
end
|
8
|
+
|
9
|
+
it "requests all fields with translate parameter" do
|
10
|
+
stub_get("field/translate/en") { Emarsys::Field.collection('translate' => 'en') }.should have_been_requested.once
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
describe ".choice" do
|
15
|
+
it "requests the choice options of a field" do
|
16
|
+
stub_get("field/1/choice") { Emarsys::Field.choice(1) }.should have_been_requested.once
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Emarsys::File do
|
4
|
+
describe ".collection" do
|
5
|
+
it "requests all files" do
|
6
|
+
stub_get("file") { Emarsys::File.collection }.should have_been_requested.once
|
7
|
+
end
|
8
|
+
|
9
|
+
it "requests all files with parameter" do
|
10
|
+
stub_get("file/folder=3") { Emarsys::File.collection(:folder => 3) }.should have_been_requested.once
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
describe ".create" do
|
15
|
+
it "requests file creation with parameters" do
|
16
|
+
stub_params = {:filename => 'my_file.jpg', :file => 'base_64_encoded_string'}
|
17
|
+
stub = stub_request(:post, "https://suite5.emarsys.net/api/v2/file").with(:body => stub_params.to_json).to_return(standard_return_body)
|
18
|
+
Emarsys::File.create('my_file.jpg', 'base_64_encoded_string')
|
19
|
+
stub.should have_been_requested.once
|
20
|
+
end
|
21
|
+
|
22
|
+
it "requests file creation with optional folder parameter" do
|
23
|
+
stub_params = {:filename => 'my_file.jpg', :file => 'base_64_encoded_string', :folder => 3}
|
24
|
+
stub = stub_request(:post, "https://suite5.emarsys.net/api/v2/file").with(:body => stub_params.to_json).to_return(standard_return_body)
|
25
|
+
Emarsys::File.create('my_file.jpg', 'base_64_encoded_string', 3)
|
26
|
+
stub.should have_been_requested.once
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Emarsys::Folder do
|
4
|
+
describe ".collection" do
|
5
|
+
it "requests all folders" do
|
6
|
+
stub_get("folder") { Emarsys::Folder.collection }.should have_been_requested.once
|
7
|
+
end
|
8
|
+
|
9
|
+
it "requests all folders with parameters" do
|
10
|
+
stub_get("folder/folder=3") { Emarsys::Folder.collection(:folder => 3) }.should have_been_requested.once
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Emarsys::Source do
|
4
|
+
describe ".collection" do
|
5
|
+
it "requests all sources" do
|
6
|
+
stub_get("source") { Emarsys::Source.collection }.should have_been_requested.once
|
7
|
+
end
|
8
|
+
end
|
9
|
+
|
10
|
+
describe ".create" do
|
11
|
+
it "requests source creation with parameters" do
|
12
|
+
stub = stub_request(:post, "https://suite5.emarsys.net/api/v2/source/create").with(:body => {:name => 'test_source'}.to_json).to_return(standard_return_body)
|
13
|
+
Emarsys::Source.create('test_source')
|
14
|
+
stub.should have_been_requested.once
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
describe ".delete" do
|
19
|
+
it "requests source deletion" do
|
20
|
+
stub = stub_request(:delete, "https://suite5.emarsys.net/api/v2/source/123").to_return(standard_return_body)
|
21
|
+
Emarsys::Source.destroy(123)
|
22
|
+
stub.should have_been_requested.once
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|