rbraspag 0.0.2

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/rbraspag.gemspec ADDED
@@ -0,0 +1,30 @@
1
+ # -*- encoding: utf-8 -*-
2
+ $:.push File.expand_path("../lib", __FILE__)
3
+ require "rbraspag/version"
4
+
5
+ Gem::Specification.new do |s|
6
+ s.name = "rbraspag"
7
+ s.version = Braspag::VERSION
8
+ s.authors = ["Celestino Gomes", "Renato Elias", "Luca Bastos", "Lenon Marcel", "Madson Cardoso"]
9
+ s.email = %w[tinorj@gmail.com renato.elias@gmail.com lucabastos@gmail.com lenon.marcel@gmail.com madsonmac@gmail.com]
10
+ s.homepage = "http://github.com/concretesolutions/rbraspag"
11
+ s.summary = "rbraspag gem to use Braspag gateway"
12
+ s.description = "rbraspag gem to use Braspag gateway"
13
+
14
+ s.rubyforge_project = "rbraspag"
15
+
16
+ s.files = `git ls-files`.split("\n")
17
+ s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
18
+ s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
19
+ s.require_paths = ["lib"]
20
+
21
+ s.add_dependency 'cs-httpi', '>= 0.9.5.2'
22
+ s.add_dependency 'json'
23
+ s.add_dependency 'nokogiri'
24
+
25
+ s.add_development_dependency "rspec"
26
+ s.add_development_dependency "fakeweb"
27
+ s.add_development_dependency "shoulda-matchers"
28
+ s.add_development_dependency "guard-rspec"
29
+ s.add_development_dependency "ruby-debug19"
30
+ end
data/spec/bill_spec.rb ADDED
@@ -0,0 +1,394 @@
1
+ #encoding: utf-8
2
+ require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
3
+
4
+ describe Braspag::Bill do
5
+
6
+ #TODO Transformar numeros magicos em symbols, por exemplo metodo de pagamento pode ser :real ao inves de 10
7
+
8
+ let!(:merchant_id) {"{84BE7E7F-698A-6C74-F820-AE359C2A07C2}"}
9
+ let!(:connection) {Braspag::Connection.new(merchant_id, :test)}
10
+
11
+ describe ".new" do
12
+
13
+ it "should raise an error when no connection is given" do
14
+ expect {
15
+ Braspag::Bill.new("", {})
16
+ }.to raise_error(Braspag::InvalidConnection)
17
+ end
18
+
19
+ it "should raise an error when :order_id is not present" do
20
+ expect {
21
+ Braspag::Bill.new(connection, {
22
+ :amount => "10000",
23
+ :payment_method => "06"
24
+ })
25
+ }.to raise_error(Braspag::IncompleteParams)
26
+ end
27
+
28
+ it "should raise an error when :amount is not present" do
29
+ expect {
30
+ Braspag::Bill.new(connection, {
31
+ :order_id => "12",
32
+ :payment_method => "06"
33
+ })
34
+ }.to raise_error(Braspag::IncompleteParams)
35
+ end
36
+
37
+ it "should raise an error when :payment_method is not present" do
38
+ expect {
39
+ Braspag::Bill.new(connection, {
40
+ :order_id => "13",
41
+ :amount => "12000"
42
+ })
43
+ }.to raise_error(Braspag::IncompleteParams)
44
+ end
45
+
46
+ it "should raise an error when :order_id is less than 1 character" do
47
+ expect {
48
+ Braspag::Bill.new(connection, {
49
+ :order_id => "",
50
+ :amount => "12300",
51
+ :payment_method => "06"
52
+ })
53
+ }.to raise_error(Braspag::InvalidOrderId)
54
+ end
55
+
56
+ it "should raise an error when :order_id is more than 50 characters" do
57
+ expect {
58
+ Braspag::Bill.new(connection, {
59
+ :order_id => "1" * 51,
60
+ :amount => "1200",
61
+ :payment_method => "06"
62
+ })
63
+ }.to raise_error(Braspag::InvalidOrderId)
64
+ end
65
+
66
+ it "should raise an error when :customer_name is less than 1 character" do
67
+ expect {
68
+ Braspag::Bill.new(connection, {
69
+ :order_id => "102",
70
+ :amount => "4200",
71
+ :payment_method => "06",
72
+ :customer_name => ""
73
+ })
74
+ }.to raise_error(Braspag::InvalidCustomerName)
75
+ end
76
+
77
+ it "should raise an error when :customer_name is more than 255 characters" do
78
+ expect {
79
+ Braspag::Bill.new(connection, {
80
+ :order_id => "112",
81
+ :amount => "12100",
82
+ :payment_method => "06",
83
+ :customer_name => "A" * 256
84
+ })
85
+ }.to raise_error(Braspag::InvalidCustomerName)
86
+ end
87
+
88
+ it "should raise an error when :customer_id is less than 11 characters" do
89
+ expect {
90
+ Braspag::Bill.new(connection, {
91
+ :order_id => "23",
92
+ :amount => "25100",
93
+ :payment_method => "06",
94
+ :customer_id => "2" * 10
95
+ })
96
+ }.to raise_error(Braspag::InvalidCustomerId)
97
+ end
98
+
99
+ it "should raise an error when :customer_id is more than 18 characters" do
100
+ expect {
101
+ Braspag::Bill.new(connection, {
102
+ :order_id => "90",
103
+ :amount => "9000",
104
+ :payment_method => "06",
105
+ :customer_id => "3" * 19
106
+ })
107
+ }.to raise_error(Braspag::InvalidCustomerId)
108
+ end
109
+
110
+ it "should raise an error when :number is less than 1 character" do
111
+ expect {
112
+ Braspag::Bill.new(connection, {
113
+ :order_id => "900",
114
+ :amount => "9200",
115
+ :payment_method => "06",
116
+ :number => ""
117
+ })
118
+ }.to raise_error(Braspag::InvalidNumber)
119
+ end
120
+
121
+ it "should raise an error when :number is more than 255 characters" do
122
+ expect {
123
+ Braspag::Bill.new(connection, {
124
+ :order_id => "91",
125
+ :amount => "8000",
126
+ :payment_method => "06",
127
+ :number => "5" * 256
128
+ })
129
+ }.to raise_error(Braspag::InvalidNumber)
130
+ end
131
+
132
+ it "should raise an error when :instructions is less than 1 character" do
133
+ expect {
134
+ Braspag::Bill.new(connection, {
135
+ :order_id => "76",
136
+ :amount => "5000",
137
+ :payment_method => "06",
138
+ :instructions => ""
139
+ })
140
+ }.to raise_error(Braspag::InvalidInstructions)
141
+ end
142
+
143
+ it "should raise an error when :instructions is more than 512 characters" do
144
+ expect {
145
+ Braspag::Bill.new(connection, {
146
+ :order_id => "65",
147
+ :amount => "21000",
148
+ :payment_method => "06",
149
+ :instructions => "O" * 513
150
+ })
151
+ }.to raise_error(Braspag::InvalidInstructions)
152
+ end
153
+
154
+ it "should raise an error when :expiration_date is more or less than 8 characters" do
155
+ expect {
156
+ Braspag::Bill.new(connection, {
157
+ :order_id => "34",
158
+ :amount => "24500",
159
+ :payment_method => "06",
160
+ :expiration_date => "1" * 7
161
+ })
162
+ }.to raise_error(Braspag::InvalidExpirationDate)
163
+
164
+ expect {
165
+ Braspag::Bill.new(connection, {
166
+ :order_id => "67",
167
+ :amount => "32100",
168
+ :payment_method => "06",
169
+ :expiration_date => "2" * 9
170
+ })
171
+ }.to raise_error(Braspag::InvalidExpirationDate)
172
+ end
173
+
174
+ it "should accept :expiration_date with Date Object" do
175
+ Braspag::Bill.new(connection, {
176
+ :order_id => "67",
177
+ :amount => "32100",
178
+ :payment_method => "06",
179
+ :expiration_date => Date.today + 2
180
+ }).should be_ok
181
+ end
182
+
183
+ end
184
+
185
+ describe ".generate" do
186
+
187
+ context "with correct data" do
188
+
189
+ before do
190
+ xml = <<-EOXML
191
+ <?xml version="1.0" encoding="utf-8"?>
192
+ <PagadorBoletoReturn xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
193
+ xmlns:xsd="http://www.w3.org/2001/XMLSchema"
194
+ xmlns="https://www.pagador.com.br/webservice/pagador">
195
+ <amount>3</amount>
196
+ <boletoNumber>70031</boletoNumber>
197
+ <expirationDate>2011-06-27T00:00:00-03:00</expirationDate>
198
+ <url>https://homologacao.pagador.com.br/pagador/reenvia.asp?Id_Transacao=34ae7d96-aa65-425a-b893-55791cb6a4df</url>
199
+ <returnCode>0</returnCode>)
200
+ <status>0</status>
201
+ </PagadorBoletoReturn>
202
+ EOXML
203
+
204
+ FakeWeb.register_uri(:post, "#{Braspag::Test::BASE_URL}/webservices/pagador/Boleto.asmx/CreateBoleto", :body => xml)
205
+
206
+ @bill = Braspag::Bill.new(connection , {
207
+ :order_id => 1,
208
+ :amount => 3,
209
+ :payment_method => 10
210
+ })
211
+ @response = @bill.generate
212
+ end
213
+
214
+ after do
215
+ FakeWeb.clean_registry
216
+ end
217
+
218
+ it "should return a public url" do
219
+ @response[:url].should == "https://homologacao.pagador.com.br/pagador/reenvia.asp?Id_Transacao=34ae7d96-aa65-425a-b893-55791cb6a4df"
220
+ end
221
+
222
+ it "should return 0 (waiting payment) as the status" do
223
+ @response[:status].should == "0"
224
+ end
225
+
226
+ it "should return 0 (success) as the return_code" do
227
+ @response[:return_code].should == "0"
228
+ end
229
+
230
+ it "should return 3 as the amount" do
231
+ @response[:amount].should == "3"
232
+ end
233
+
234
+ it "should return the bill number" do
235
+ @response[:number].should == "70031"
236
+ end
237
+
238
+ it "should return the expiration date" do
239
+ @response[:expiration_date].should be_kind_of Date
240
+ @response[:expiration_date].to_s.should == "2011-06-27"
241
+ end
242
+
243
+ end
244
+
245
+ context "with incorrect data" do
246
+
247
+ it "should raise an error for invalid :merchantId" do
248
+ xml = <<-EOXML
249
+ <?xml version="1.0" encoding="utf-8"?>
250
+ <PagadorBoletoReturn xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
251
+ xmlns:xsd="http://www.w3.org/2001/XMLSchema"
252
+ xmlns="https://www.pagador.com.br/webservice/pagador">
253
+ <amount xsi:nil="true" />
254
+ <expirationDate xsi:nil="true" />
255
+ <returnCode>1</returnCode>
256
+ <message>Invalid merchantId</message>
257
+ <status xsi:nil="true" />
258
+ </PagadorBoletoReturn>
259
+ EOXML
260
+
261
+ FakeWeb.register_uri(:post, "#{Braspag::Test::BASE_URL}/webservices/pagador/Boleto.asmx/CreateBoleto", :body => xml)
262
+
263
+ connection = Braspag::Connection.new("{12345678-1234-1234-1234-123456789000}", :test)
264
+
265
+ expect {
266
+ bill = Braspag::Bill.new(connection, {
267
+ :order_id => 1,
268
+ :amount => 3,
269
+ :payment_method => 10
270
+ })
271
+ bill.generate
272
+ }.to raise_error(Braspag::InvalidMerchantId)
273
+
274
+ FakeWeb.clean_registry
275
+ end
276
+
277
+ it "should raise an error for invalid :number" do
278
+ xml = <<-EOXML
279
+ <?xml version="1.0" encoding="utf-8"?>
280
+ <PagadorBoletoReturn xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
281
+ xmlns:xsd="http://www.w3.org/2001/XMLSchema"
282
+ xmlns="https://www.pagador.com.br/webservice/pagador">
283
+ <amount xsi:nil="true" />
284
+ <expirationDate xsi:nil="true" />
285
+ <returnCode>1</returnCode>
286
+ <message>Input string was not in a correct format.</message>
287
+ <status xsi:nil="true" />
288
+ </PagadorBoletoReturn>
289
+ EOXML
290
+
291
+ FakeWeb.register_uri(:post, "#{Braspag::Test::BASE_URL}/webservices/pagador/Boleto.asmx/CreateBoleto", :body => xml)
292
+
293
+ expect {
294
+ bill = Braspag::Bill.new(connection, {
295
+ :number => "A" * 50,
296
+ :order_id => "x",
297
+ :amount => 3,
298
+ :payment_method => 10
299
+ })
300
+ bill.generate
301
+ }.to raise_error(Braspag::InvalidStringFormat)
302
+
303
+ FakeWeb.clean_registry
304
+ end
305
+
306
+ it "should raise an error for invalid :payment_method" do
307
+ xml = <<-EOXML
308
+ <?xml version="1.0" encoding="utf-8"?>
309
+ <PagadorBoletoReturn xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
310
+ xmlns:xsd="http://www.w3.org/2001/XMLSchema"
311
+ xmlns="https://www.pagador.com.br/webservice/pagador">
312
+ <amount xsi:nil="true" />
313
+ <expirationDate xsi:nil="true" />
314
+ <returnCode>3</returnCode>
315
+ <message>Invalid payment method</message>
316
+ <status xsi:nil="true" />
317
+ </PagadorBoletoReturn>
318
+ EOXML
319
+
320
+ FakeWeb.register_uri(:post, "#{Braspag::Test::BASE_URL}/webservices/pagador/Boleto.asmx/CreateBoleto", :body => xml)
321
+
322
+ expect {
323
+ bill = Braspag::Bill.new(connection, {
324
+ :order_id => 1,
325
+ :amount => "0000",
326
+ :payment_method => 10
327
+ })
328
+ bill.generate
329
+ }.to raise_error(Braspag::InvalidPaymentMethod)
330
+
331
+ FakeWeb.clean_registry
332
+ end
333
+
334
+ it "should raise an error for invalid :amount" do
335
+ xml = <<-EOXML
336
+ <?xml version="1.0" encoding="utf-8"?>
337
+ <PagadorBoletoReturn xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
338
+ xmlns:xsd="http://www.w3.org/2001/XMLSchema"
339
+ xmlns="https://www.pagador.com.br/webservice/pagador">
340
+ <amount xsi:nil="true" />
341
+ <expirationDate xsi:nil="true" />
342
+ <returnCode>1</returnCode>
343
+ <message>Invalid purchase amount</message>
344
+ <status xsi:nil="true" />
345
+ </PagadorBoletoReturn>
346
+ EOXML
347
+
348
+ FakeWeb.register_uri(:post, "#{Braspag::Test::BASE_URL}/webservices/pagador/Boleto.asmx/CreateBoleto", :body => xml)
349
+
350
+ expect {
351
+ bill = Braspag::Bill.new(connection, {
352
+ :order_id => 1,
353
+ :amount => -33,
354
+ :payment_method => 10
355
+ })
356
+ bill.generate
357
+ }.to raise_error(Braspag::InvalidAmount)
358
+
359
+ FakeWeb.clean_registry
360
+ end
361
+
362
+ it "should raise an error for unknown problems" do
363
+ xml = <<-EOXML
364
+ <?xml version="1.0" encoding="utf-8"?>
365
+ <PagadorBoletoReturn xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
366
+ xmlns:xsd="http://www.w3.org/2001/XMLSchema"
367
+ xmlns="https://www.pagador.com.br/webservice/pagador">
368
+ <amount xsi:nil="true" />
369
+ <expirationDate xsi:nil="true" />
370
+ <returnCode>1</returnCode>
371
+ <message>Invalid server</message>
372
+ <status xsi:nil="true" />
373
+ </PagadorBoletoReturn>
374
+ EOXML
375
+
376
+ FakeWeb.register_uri(:post, "#{Braspag::Test::BASE_URL}/webservices/pagador/Boleto.asmx/CreateBoleto", :body => xml)
377
+
378
+ expect {
379
+ bill = Braspag::Bill.new(connection, {
380
+ :order_id => 1,
381
+ :amount => 3,
382
+ :payment_method => "10"
383
+ })
384
+ bill.generate
385
+ }.to raise_error(Braspag::UnknownError)
386
+
387
+ FakeWeb.clean_registry
388
+ end
389
+
390
+ end
391
+
392
+ end
393
+
394
+ end
@@ -0,0 +1,54 @@
1
+ #encoding: utf-8
2
+ require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
3
+
4
+ describe Braspag::Connection do
5
+ let!(:connection) { Braspag::Connection }
6
+ let!(:merchant_id) { "{12345678-1234-1234-1234-123456789000}" }
7
+
8
+ it "deve gerar uma exceção quando :merchantId for maior que 38 caracteres" do
9
+ merchant_id = (1..100).collect{"A"}.join
10
+ expect { connection.new(merchant_id) }.should raise_error(Braspag::Connection::InvalidMerchantId)
11
+ end
12
+
13
+ it "deve gerar uma exceção quando :merchantId for menor que 38 caracteres" do
14
+ merchant_id = (1..37).collect{"B"}.join
15
+ expect { connection.new(merchant_id) }.should raise_error(Braspag::Connection::InvalidMerchantId)
16
+ end
17
+
18
+ it "deve gerar uma exceção quando :merchantId não seguir o formato {00000000-0000-0000-0000-000000000000}" do
19
+ expect { connection.new("0000000-0000-0000-0000-000000000000") }.should raise_error(Braspag::Connection::InvalidMerchantId)
20
+ expect { connection.new("{000000000000000000000000000000000000}") }.should raise_error(Braspag::Connection::InvalidMerchantId)
21
+
22
+ expect { connection.new(merchant_id) }.should_not raise_error
23
+ end
24
+
25
+ it "deve inicializar dado um ambiente e o id da loja" do
26
+ expect { connection.new(merchant_id, :test) }.should_not raise_error
27
+ end
28
+
29
+ it "deve inicializar dado um id da loja" do
30
+ expect { connection.new(merchant_id) }.should_not raise_error
31
+ end
32
+
33
+ it "deve entender que o ambiente é produção quando nehum for especificado" do
34
+ connection.new(merchant_id).environment.should eql(Braspag::Production)
35
+ end
36
+
37
+ it "deve entender que o ambiente é teste quando for especificado staging" do
38
+ connection.new(merchant_id, 'staging').environment.should eql(Braspag::Test)
39
+ end
40
+
41
+ it "deve reconhecer a url do ambiente de teste" do
42
+ connection.new(merchant_id, :test).base_url.should eql(Braspag::Test::BASE_URL)
43
+ end
44
+
45
+ it "deve reconhecer a url do ambiente de produção" do
46
+ connection.new(merchant_id, :production).base_url.should eql(Braspag::Production::BASE_URL)
47
+ end
48
+
49
+ it "deve devolver o merchant id utilizado na conexão" do
50
+ connection.new(merchant_id).merchant_id.should eql(merchant_id)
51
+ end
52
+
53
+
54
+ end
@@ -0,0 +1,68 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
2
+
3
+ describe Braspag::CreditCard do
4
+ before do
5
+ @merchant_id = "{84BE7E7F-698A-6C74-F820-AE359C2A07C2}"
6
+ @connection = Braspag::Connection.new(@merchant_id, :test)
7
+ @gateway = Braspag::CreditCard.new(@connection)
8
+ # respond_with "<?xml version='1.0' encoding='utf-8'?><soap:Envelope xmlns:soap='http://www.w3.org/2003/05/soap-envelope' xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance' xmlns:xsd='http://www.w3.org/2001/XMLSchema'><soap:Body><AuthorizeResponse xmlns='https://www.pagador.com.br/webservice/pagador'><AuthorizeResult><amount>1</amount><authorisationNumber>418270</authorisationNumber><message>Transaction Successful</message><returnCode>0</returnCode><status>1</status><transactionId>128199</transactionId></AuthorizeResult></AuthorizeResponse></soap:Body></soap:Envelope>"
9
+ end
10
+
11
+ context "on authorize!" do
12
+ before :each do
13
+ #respond_with "<?xml version='1.0' encoding='utf-8'?><soap:Envelope xmlns:soap='http://www.w3.org/2003/05/soap-envelope' xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance' xmlns:xsd='http://www.w3.org/2001/XMLSchema'><soap:Body><AuthorizeResponse xmlns='https://www.pagador.com.br/webservice/pagador'><AuthorizeResult><amount>1</amount><authorisationNumber>418270</authorisationNumber><message>Transaction Successful</message><returnCode>0</returnCode><status>1</status><transactionId>128199</transactionId></AuthorizeResult></AuthorizeResponse></soap:Body></soap:Envelope>"
14
+ end
15
+
16
+ pending "deve enviar dados para webservice de autorizacao" do
17
+ expected = <<STRING
18
+ <?xml version='1.0' ?>
19
+ <env:Envelope xmlns:env="http://www.w3.org/2003/05/soap-envelope">
20
+ <env:Header />
21
+ <env:Body>
22
+ <tns:Authorize xmlns:tns="https://www.pagador.com.br/webservice/pagador">
23
+ <tns:merchantId>#{@merchant_id}</tns:merchantId>
24
+ <tns:orderId>teste564</tns:orderId>
25
+ <tns:customerName>comprador de teste</tns:customerName>
26
+ <tns:amount>1,00</tns:amount>
27
+ </tns:Authorize>
28
+ </env:Body>
29
+ </env:Envelope>
30
+ STRING
31
+ # request_should_contain(expected)
32
+ # @gateway.authorize! :orderId => "teste564", :customerName => "comprador de teste", :amount => "1,00"
33
+ end
34
+
35
+ pending "deve devolver o resultado em um mapa" do
36
+ # map = {"amount" =>"1", "authorisationNumber" => "418270", "message" => "Transaction Successful", "returnCode" => "0", "status" => "1", "transactionId" => "128199"}
37
+ # @gateway.authorize!(:orderId => "teste564", :customerName => "comprador de teste", :amount => "1,00").should == map
38
+ end
39
+ end
40
+
41
+ context "on capture!" do
42
+ before :each do
43
+ # respond_with "<?xml version='1.0' encoding='utf-8'?><soap:Envelope xmlns:soap='http://www.w3.org/2003/05/soap-envelope' xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance' xmlns:xsd='http://www.w3.org/2001/XMLSchema'><soap:Body><CaptureResponse xmlns='https://www.pagador.com.br/webservice/pagador'><CaptureResult><amount>1</amount><authorisationNumber>418270</authorisationNumber><message>Transaction Successful</message><returnCode>0</returnCode><status>1</status><transactionId>128199</transactionId></CaptureResult></CaptureResponse></soap:Body></soap:Envelope>"
44
+ end
45
+
46
+ pending "deve enviar dados para webservice de captura" do
47
+ expected = <<STRING
48
+ <?xml version='1.0' ?>
49
+ <env:Envelope xmlns:env="http://www.w3.org/2003/05/soap-envelope">
50
+ <env:Header />
51
+ <env:Body>
52
+ <tns:Capture xmlns:tns="https://www.pagador.com.br/webservice/pagador">
53
+ <tns:merchantId>#{@merchant_id}</tns:merchantId>
54
+ <tns:orderId>teste564</tns:orderId>
55
+ </tns:Capture>
56
+ </env:Body>
57
+ </env:Envelope>
58
+ STRING
59
+ # request_should_contain(expected)
60
+ # @gateway.capture! :orderId => "teste564"
61
+ end
62
+
63
+ pending "deve devolver o resultado em um mapa" do
64
+ # map = {"amount" =>"1", "authorisationNumber" => "418270", "message" => "Transaction Successful", "returnCode" => "0", "status" => "1", "transactionId" => "128199"}
65
+ # @gateway.capture!(:orderId => "teste564").should == map
66
+ end
67
+ end
68
+ end