mailgun-ruby 1.2.11 → 1.2.13
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.ruby-env.yml.example +1 -0
- data/CHANGELOG.md +16 -0
- data/README.md +5 -2
- data/docs/EmailValidation.md +34 -0
- data/docs/Subaccounts.md +68 -0
- data/docs/Suppressions.md +10 -0
- data/docs/railgun/EmailValidation.md +34 -0
- data/lib/mailgun/client.rb +11 -0
- data/lib/mailgun/domains/domains.rb +1 -1
- data/lib/mailgun/events/events.rb +1 -1
- data/lib/mailgun/messages/message_builder.rb +2 -2
- data/lib/mailgun/response.rb +7 -0
- data/lib/mailgun/subaccounts/subaccounts.rb +84 -0
- data/lib/mailgun/templates/templates.rb +187 -0
- data/lib/mailgun/version.rb +1 -1
- data/lib/mailgun.rb +2 -0
- data/lib/railgun/mailer.rb +3 -1
- data/mailgun.gemspec +5 -2
- data/spec/integration/email_validation_spec.rb +7 -0
- data/spec/integration/mailgun_spec.rb +16 -0
- data/spec/integration/subaccounts_spec.rb +58 -0
- data/spec/integration/templates_spec.rb +135 -0
- data/spec/unit/messages/message_builder_spec.rb +1 -1
- data/vcr_cassettes/email_validation.yml +5 -5
- data/vcr_cassettes/subaccounts.yml +270 -0
- data/vcr_cassettes/templates.yml +1065 -0
- metadata +22 -7
@@ -192,5 +192,21 @@ Testing some Mailgun awesomness!'
|
|
192
192
|
expect(result.body).to include("message")
|
193
193
|
expect(result.body).to include("id")
|
194
194
|
end
|
195
|
+
|
196
|
+
it 'receives success response code' do
|
197
|
+
@mg_obj.enable_test_mode!
|
198
|
+
|
199
|
+
expect(@mg_obj.test_mode?).to eq(true)
|
200
|
+
|
201
|
+
data = { :from => "joe@#{@domain}",
|
202
|
+
:to => "bob@#{@domain}",
|
203
|
+
:subject => "Test",
|
204
|
+
:text => "Test Data" }
|
205
|
+
|
206
|
+
result = @mg_obj.send_message(@domain, data)
|
207
|
+
result.to_h!
|
208
|
+
|
209
|
+
expect(result.success?).to be(true)
|
210
|
+
end
|
195
211
|
end
|
196
212
|
|
@@ -0,0 +1,58 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'mailgun'
|
3
|
+
|
4
|
+
vcr_opts = { :cassette_name => "subaccounts" }
|
5
|
+
|
6
|
+
describe 'For the subaccounts endpoints', vcr: vcr_opts do
|
7
|
+
let(:name) { 'test.subaccount' }
|
8
|
+
let(:subaccount_id) { 'xxx' }
|
9
|
+
|
10
|
+
before(:all) do
|
11
|
+
mg_client = Mailgun::Client.new(APIKEY, APIHOST, 'v5')
|
12
|
+
@mg_obj = Mailgun::Subaccounts.new mg_client
|
13
|
+
end
|
14
|
+
|
15
|
+
describe '#list' do
|
16
|
+
it 'returns a list of templates' do
|
17
|
+
result = @mg_obj.list
|
18
|
+
|
19
|
+
expect(result).to eq({"subaccounts"=>[{"id"=>"xxx", "name"=>"test-ruby-lib", "status"=>"open"}], "total"=>1})
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
describe '#create' do
|
24
|
+
it 'creates the subaccount' do
|
25
|
+
result = @mg_obj.create(name)
|
26
|
+
|
27
|
+
expect(result).to eq({"subaccount"=>{"id"=>"xxx", "name"=>"test.subaccount", "status"=>"open"}})
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
|
32
|
+
describe '#info' do
|
33
|
+
it 'gets the templates info' do
|
34
|
+
result = @mg_obj.info(subaccount_id)
|
35
|
+
|
36
|
+
expect(result).to eq({"subaccount"=>{"id"=>"xxx", "name"=>"test-ruby-lib", "status"=>"open"}})
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
|
41
|
+
|
42
|
+
describe '#enable' do
|
43
|
+
it 'enables the subaccount' do
|
44
|
+
result = @mg_obj.enable(subaccount_id)
|
45
|
+
|
46
|
+
expect(result).to eq({"subaccount"=>{"id"=>"xxx", "name"=>"test-ruby-lib", "status"=>"open"}})
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
describe '#disable' do
|
51
|
+
it 'disables the subaccount' do
|
52
|
+
result = @mg_obj.disable(subaccount_id)
|
53
|
+
|
54
|
+
expect(result).to eq({"subaccount"=>{"id"=>"xxx", "name"=>"test-ruby-lib", "status"=>"disabled"}})
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
end
|
@@ -0,0 +1,135 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'mailgun'
|
3
|
+
|
4
|
+
vcr_opts = { :cassette_name => "templates" }
|
5
|
+
|
6
|
+
describe 'For the templates endpoints', vcr: vcr_opts do
|
7
|
+
let(:template_name) { 'test.template' }
|
8
|
+
let(:domain) { "integration-test.domain.invalid" }
|
9
|
+
let(:tag) { 'v2' }
|
10
|
+
|
11
|
+
before(:all) do
|
12
|
+
@mg_client = Mailgun::Client.new(APIKEY, APIHOST, APIVERSION, SSL)
|
13
|
+
@mg_obj = Mailgun::Templates.new(@mg_client)
|
14
|
+
end
|
15
|
+
|
16
|
+
describe '#create' do
|
17
|
+
it 'creates the template' do
|
18
|
+
result = @mg_obj.create(
|
19
|
+
domain,
|
20
|
+
{
|
21
|
+
name: template_name,
|
22
|
+
description: 'Test',
|
23
|
+
template: '{{fname}} {{lname}}',
|
24
|
+
comment: 'test comment',
|
25
|
+
headers: '{"Subject": "{{subject}}"}',
|
26
|
+
tag: 'V1'
|
27
|
+
}
|
28
|
+
)
|
29
|
+
|
30
|
+
expect(result['template']["name"]).to eq('test.template')
|
31
|
+
expect(result['template']["description"]).to eq("Test")
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
describe '#info' do
|
36
|
+
it 'gets the templates info' do
|
37
|
+
result = @mg_obj.info(domain, 'test.template')
|
38
|
+
|
39
|
+
expect(result).to include("template")
|
40
|
+
expect(result["template"]["name"]).to eq(template_name)
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
describe '#update' do
|
45
|
+
it 'updates the template' do
|
46
|
+
result = @mg_obj.update(domain, template_name, { description: 'Updated Description' })
|
47
|
+
|
48
|
+
expect(result['message']).to eq('template has been updated')
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
describe '#list' do
|
53
|
+
it 'returns a list of templates' do
|
54
|
+
result = @mg_obj.list(domain)
|
55
|
+
|
56
|
+
expect(result.first).to have_key('name')
|
57
|
+
expect(result.first).to have_key('description')
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
describe '#delete' do
|
62
|
+
it 'deletes a template' do
|
63
|
+
result = @mg_obj.delete(domain, template_name)
|
64
|
+
|
65
|
+
expect(result).to be_truthy
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
describe '#remove_all' do
|
70
|
+
it 'deletes all templates from domain' do
|
71
|
+
result = @mg_obj.remove_all(domain)
|
72
|
+
|
73
|
+
expect(result).to be_truthy
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
describe '#create_version' do
|
78
|
+
it 'creates the version for the template' do
|
79
|
+
result = @mg_obj.create_version(
|
80
|
+
domain,
|
81
|
+
template_name,
|
82
|
+
{
|
83
|
+
template: '{{fname}} {{lname}}',
|
84
|
+
comment: 'test comment',
|
85
|
+
headers: '{"Subject": "{{subject}}"}',
|
86
|
+
tag: tag,
|
87
|
+
active: 'yes'
|
88
|
+
}
|
89
|
+
)
|
90
|
+
|
91
|
+
expect(result['template']["version"]['tag']).to eq(tag)
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
describe '#info_version' do
|
96
|
+
it "gets the template's version info" do
|
97
|
+
result = @mg_obj.info_version(domain, template_name, tag)
|
98
|
+
|
99
|
+
expect(result["template"]["version"]['tag']).to eq(tag)
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
describe '#update_version' do
|
104
|
+
it 'updates the template' do
|
105
|
+
result = @mg_obj.update_version(
|
106
|
+
domain,
|
107
|
+
template_name,
|
108
|
+
tag,
|
109
|
+
{
|
110
|
+
template: '{{fname}} {{lname}}',
|
111
|
+
comment: 'test comment 2',
|
112
|
+
headers: '{"Subject": "{{subject}}"}'
|
113
|
+
}
|
114
|
+
)
|
115
|
+
|
116
|
+
expect(result['message']).to eq('version has been updated')
|
117
|
+
end
|
118
|
+
end
|
119
|
+
|
120
|
+
describe '#template_versions_list' do
|
121
|
+
it "returns template's versions" do
|
122
|
+
result = @mg_obj.template_versions_list(domain, template_name)
|
123
|
+
|
124
|
+
expect(result["template"]["versions"].first).to include('tag')
|
125
|
+
end
|
126
|
+
end
|
127
|
+
|
128
|
+
describe '#delete_version' do
|
129
|
+
it "deletes template's version" do
|
130
|
+
result = @mg_obj.delete_version(domain, template_name, tag)
|
131
|
+
|
132
|
+
expect(result).to be_truthy
|
133
|
+
end
|
134
|
+
end
|
135
|
+
end
|
@@ -513,7 +513,7 @@ describe 'The method track_clicks' do
|
|
513
513
|
end
|
514
514
|
|
515
515
|
context 'when unexpected value is provided' do
|
516
|
-
it 'warns about
|
516
|
+
it 'warns about preferred values' do
|
517
517
|
expect(@mb_obj).to receive :warn
|
518
518
|
@mb_obj.track_clicks('random')
|
519
519
|
end
|
@@ -48,11 +48,11 @@ http_interactions:
|
|
48
48
|
"Alice <alice@example.com>",
|
49
49
|
"bob@example.com"
|
50
50
|
],
|
51
|
-
"
|
51
|
+
"unparsable": [
|
52
52
|
"example.org"
|
53
53
|
]
|
54
54
|
}
|
55
|
-
http_version:
|
55
|
+
http_version:
|
56
56
|
recorded_at: Wed, 26 Oct 2016 22:44:50 GMT
|
57
57
|
- request:
|
58
58
|
method: get
|
@@ -107,7 +107,7 @@ http_interactions:
|
|
107
107
|
"local_part": "alice"
|
108
108
|
}
|
109
109
|
}
|
110
|
-
http_version:
|
110
|
+
http_version:
|
111
111
|
recorded_at: Wed, 26 Oct 2016 22:44:50 GMT
|
112
112
|
- request:
|
113
113
|
method: get
|
@@ -162,7 +162,7 @@ http_interactions:
|
|
162
162
|
"local_part": null
|
163
163
|
}
|
164
164
|
}
|
165
|
-
http_version:
|
165
|
+
http_version:
|
166
166
|
recorded_at: Wed, 26 Oct 2016 22:44:50 GMT
|
167
167
|
- request:
|
168
168
|
method: get
|
@@ -210,6 +210,6 @@ http_interactions:
|
|
210
210
|
false, "is_role_address": false, "is_valid": true, "mailbox_verification":
|
211
211
|
"true", "parts": {"display_name": null, "domain": "mailgun.net", "local_part":
|
212
212
|
"alice"}}'
|
213
|
-
http_version:
|
213
|
+
http_version:
|
214
214
|
recorded_at: Tue, 12 Sep 2017 16:55:09 GMT
|
215
215
|
recorded_with: VCR 3.0.3
|
@@ -0,0 +1,270 @@
|
|
1
|
+
---
|
2
|
+
http_interactions:
|
3
|
+
- request:
|
4
|
+
method: get
|
5
|
+
uri: https://api.mailgun.net/v5/accounts/subaccounts
|
6
|
+
body:
|
7
|
+
encoding: US-ASCII
|
8
|
+
string: ''
|
9
|
+
headers:
|
10
|
+
Accept:
|
11
|
+
- "*/*"
|
12
|
+
User-Agent:
|
13
|
+
- rest-client/2.1.0 (darwin22 x86_64) ruby/2.7.4p191
|
14
|
+
Accept-Encoding:
|
15
|
+
- gzip;q=1.0,deflate;q=0.6,identity;q=0.3
|
16
|
+
Host:
|
17
|
+
- api.mailgun.net
|
18
|
+
Authorization:
|
19
|
+
- Basic xxx
|
20
|
+
response:
|
21
|
+
status:
|
22
|
+
code: 200
|
23
|
+
message: OK
|
24
|
+
headers:
|
25
|
+
Access-Control-Allow-Credentials:
|
26
|
+
- 'true'
|
27
|
+
Access-Control-Allow-Origin:
|
28
|
+
- "*"
|
29
|
+
Cache-Control:
|
30
|
+
- no-store
|
31
|
+
Content-Disposition:
|
32
|
+
- inline
|
33
|
+
Content-Length:
|
34
|
+
- '706'
|
35
|
+
Content-Type:
|
36
|
+
- application/json
|
37
|
+
Date:
|
38
|
+
- Mon, 20 Nov 2023 15:30:55 GMT
|
39
|
+
Server:
|
40
|
+
- TwistedWeb/23.10.0
|
41
|
+
Strict-Transport-Security:
|
42
|
+
- max-age=63072000; includeSubDomains
|
43
|
+
X-Mailgun-Key-Id:
|
44
|
+
- 1c7e8847-e7fad6d2
|
45
|
+
X-Xss-Protection:
|
46
|
+
- 1; mode=block
|
47
|
+
body:
|
48
|
+
encoding: UTF-8
|
49
|
+
string: '{"subaccounts":[{"id":"xxx","name":"test-ruby-lib","status":"open"}],"total":1}
|
50
|
+
|
51
|
+
'
|
52
|
+
http_version:
|
53
|
+
recorded_at: Mon, 20 Nov 2023 15:30:55 GMT
|
54
|
+
- request:
|
55
|
+
method: post
|
56
|
+
uri: https://api.mailgun.net/v5/accounts/subaccounts
|
57
|
+
body:
|
58
|
+
encoding: UTF-8
|
59
|
+
string: name=test.subaccount
|
60
|
+
headers:
|
61
|
+
Accept:
|
62
|
+
- "*/*"
|
63
|
+
User-Agent:
|
64
|
+
- rest-client/2.1.0 (darwin22 x86_64) ruby/2.7.4p191
|
65
|
+
Content-Length:
|
66
|
+
- '20'
|
67
|
+
Content-Type:
|
68
|
+
- application/x-www-form-urlencoded
|
69
|
+
Accept-Encoding:
|
70
|
+
- gzip;q=1.0,deflate;q=0.6,identity;q=0.3
|
71
|
+
Host:
|
72
|
+
- api.mailgun.net
|
73
|
+
Authorization:
|
74
|
+
- Basic xxx
|
75
|
+
response:
|
76
|
+
status:
|
77
|
+
code: 200
|
78
|
+
message: OK
|
79
|
+
headers:
|
80
|
+
Access-Control-Allow-Credentials:
|
81
|
+
- 'true'
|
82
|
+
Access-Control-Allow-Origin:
|
83
|
+
- "*"
|
84
|
+
Cache-Control:
|
85
|
+
- no-store
|
86
|
+
Content-Disposition:
|
87
|
+
- inline
|
88
|
+
Content-Length:
|
89
|
+
- '90'
|
90
|
+
Content-Type:
|
91
|
+
- application/json
|
92
|
+
Date:
|
93
|
+
- Mon, 20 Nov 2023 15:33:05 GMT
|
94
|
+
Server:
|
95
|
+
- TwistedWeb/23.10.0
|
96
|
+
Strict-Transport-Security:
|
97
|
+
- max-age=63072000; includeSubDomains
|
98
|
+
X-Mailgun-Key-Id:
|
99
|
+
- 1c7e8847-e7fad6d2
|
100
|
+
X-Xss-Protection:
|
101
|
+
- 1; mode=block
|
102
|
+
body:
|
103
|
+
encoding: UTF-8
|
104
|
+
string: '{"subaccount":{"id":"xxx","name":"test.subaccount","status":"open"}}
|
105
|
+
|
106
|
+
'
|
107
|
+
http_version:
|
108
|
+
recorded_at: Mon, 20 Nov 2023 15:33:05 GMT
|
109
|
+
- request:
|
110
|
+
method: get
|
111
|
+
uri: https://api.mailgun.net/v5/accounts/subaccounts/xxx
|
112
|
+
body:
|
113
|
+
encoding: US-ASCII
|
114
|
+
string: ''
|
115
|
+
headers:
|
116
|
+
Accept:
|
117
|
+
- "*/*"
|
118
|
+
User-Agent:
|
119
|
+
- rest-client/2.1.0 (darwin22 x86_64) ruby/2.7.4p191
|
120
|
+
Accept-Encoding:
|
121
|
+
- gzip;q=1.0,deflate;q=0.6,identity;q=0.3
|
122
|
+
Host:
|
123
|
+
- api.mailgun.net
|
124
|
+
Authorization:
|
125
|
+
- Basic xxx
|
126
|
+
response:
|
127
|
+
status:
|
128
|
+
code: 200
|
129
|
+
message: OK
|
130
|
+
headers:
|
131
|
+
Access-Control-Allow-Credentials:
|
132
|
+
- 'true'
|
133
|
+
Access-Control-Allow-Origin:
|
134
|
+
- "*"
|
135
|
+
Cache-Control:
|
136
|
+
- no-store
|
137
|
+
Content-Disposition:
|
138
|
+
- inline
|
139
|
+
Content-Length:
|
140
|
+
- '88'
|
141
|
+
Content-Type:
|
142
|
+
- application/json
|
143
|
+
Date:
|
144
|
+
- Mon, 20 Nov 2023 15:33:06 GMT
|
145
|
+
Server:
|
146
|
+
- TwistedWeb/23.10.0
|
147
|
+
Strict-Transport-Security:
|
148
|
+
- max-age=63072000; includeSubDomains
|
149
|
+
X-Mailgun-Key-Id:
|
150
|
+
- 1c7e8847-e7fad6d2
|
151
|
+
X-Xss-Protection:
|
152
|
+
- 1; mode=block
|
153
|
+
body:
|
154
|
+
encoding: UTF-8
|
155
|
+
string: '{"subaccount":{"id":"xxx","name":"test-ruby-lib","status":"open"}}
|
156
|
+
|
157
|
+
'
|
158
|
+
http_version:
|
159
|
+
recorded_at: Mon, 20 Nov 2023 15:33:06 GMT
|
160
|
+
- request:
|
161
|
+
method: post
|
162
|
+
uri: https://api.mailgun.net/v5/accounts/subaccounts/xxx/enable
|
163
|
+
body:
|
164
|
+
encoding: US-ASCII
|
165
|
+
string: ''
|
166
|
+
headers:
|
167
|
+
Accept:
|
168
|
+
- "*/*"
|
169
|
+
User-Agent:
|
170
|
+
- rest-client/2.1.0 (darwin22 x86_64) ruby/2.7.4p191
|
171
|
+
Content-Length:
|
172
|
+
- '0'
|
173
|
+
Content-Type:
|
174
|
+
- application/x-www-form-urlencoded
|
175
|
+
Accept-Encoding:
|
176
|
+
- gzip;q=1.0,deflate;q=0.6,identity;q=0.3
|
177
|
+
Host:
|
178
|
+
- api.mailgun.net
|
179
|
+
Authorization:
|
180
|
+
- Basic xxx
|
181
|
+
response:
|
182
|
+
status:
|
183
|
+
code: 200
|
184
|
+
message: OK
|
185
|
+
headers:
|
186
|
+
Access-Control-Allow-Credentials:
|
187
|
+
- 'true'
|
188
|
+
Access-Control-Allow-Origin:
|
189
|
+
- "*"
|
190
|
+
Cache-Control:
|
191
|
+
- no-store
|
192
|
+
Content-Disposition:
|
193
|
+
- inline
|
194
|
+
Content-Length:
|
195
|
+
- '88'
|
196
|
+
Content-Type:
|
197
|
+
- application/json
|
198
|
+
Date:
|
199
|
+
- Mon, 20 Nov 2023 15:33:06 GMT
|
200
|
+
Server:
|
201
|
+
- TwistedWeb/23.10.0
|
202
|
+
Strict-Transport-Security:
|
203
|
+
- max-age=63072000; includeSubDomains
|
204
|
+
X-Mailgun-Key-Id:
|
205
|
+
- 1c7e8847-e7fad6d2
|
206
|
+
X-Xss-Protection:
|
207
|
+
- 1; mode=block
|
208
|
+
body:
|
209
|
+
encoding: UTF-8
|
210
|
+
string: '{"subaccount":{"id":"xxx","name":"test-ruby-lib","status":"open"}}
|
211
|
+
|
212
|
+
'
|
213
|
+
http_version:
|
214
|
+
recorded_at: Mon, 20 Nov 2023 15:33:06 GMT
|
215
|
+
- request:
|
216
|
+
method: post
|
217
|
+
uri: https://api.mailgun.net/v5/accounts/subaccounts/xxx/disable
|
218
|
+
body:
|
219
|
+
encoding: US-ASCII
|
220
|
+
string: ''
|
221
|
+
headers:
|
222
|
+
Accept:
|
223
|
+
- "*/*"
|
224
|
+
User-Agent:
|
225
|
+
- rest-client/2.1.0 (darwin22 x86_64) ruby/2.7.4p191
|
226
|
+
Content-Length:
|
227
|
+
- '0'
|
228
|
+
Content-Type:
|
229
|
+
- application/x-www-form-urlencoded
|
230
|
+
Accept-Encoding:
|
231
|
+
- gzip;q=1.0,deflate;q=0.6,identity;q=0.3
|
232
|
+
Host:
|
233
|
+
- api.mailgun.net
|
234
|
+
Authorization:
|
235
|
+
- Basic xxx
|
236
|
+
response:
|
237
|
+
status:
|
238
|
+
code: 200
|
239
|
+
message: OK
|
240
|
+
headers:
|
241
|
+
Access-Control-Allow-Credentials:
|
242
|
+
- 'true'
|
243
|
+
Access-Control-Allow-Origin:
|
244
|
+
- "*"
|
245
|
+
Cache-Control:
|
246
|
+
- no-store
|
247
|
+
Content-Disposition:
|
248
|
+
- inline
|
249
|
+
Content-Length:
|
250
|
+
- '92'
|
251
|
+
Content-Type:
|
252
|
+
- application/json
|
253
|
+
Date:
|
254
|
+
- Mon, 20 Nov 2023 15:33:07 GMT
|
255
|
+
Server:
|
256
|
+
- TwistedWeb/23.10.0
|
257
|
+
Strict-Transport-Security:
|
258
|
+
- max-age=63072000; includeSubDomains
|
259
|
+
X-Mailgun-Key-Id:
|
260
|
+
- 1c7e8847-e7fad6d2
|
261
|
+
X-Xss-Protection:
|
262
|
+
- 1; mode=block
|
263
|
+
body:
|
264
|
+
encoding: UTF-8
|
265
|
+
string: '{"subaccount":{"id":"xxx","name":"test-ruby-lib","status":"disabled"}}
|
266
|
+
|
267
|
+
'
|
268
|
+
http_version:
|
269
|
+
recorded_at: Mon, 20 Nov 2023 15:33:08 GMT
|
270
|
+
recorded_with: VCR 3.0.3
|