pin_up 0.9.5 → 0.10.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 569c2387bbe572f2e680d34ccc7319d663fd2941
4
- data.tar.gz: 2e4ff4fc878584bf9938d2d7dd0bdd4b20b248e7
3
+ metadata.gz: 6462e443b565fb449f179d8dc607a6dd17026639
4
+ data.tar.gz: 65efb2532459059fb87f5842d3db3440ff93fd40
5
5
  SHA512:
6
- metadata.gz: 429922018edf82e1cd70f9982961a43f2a335937655463af14640c821bfb6cdad01cb51ffcbe5ec34f0201ce0454e19bc12a48c8ba758f5edbeab86f8be9860a
7
- data.tar.gz: 1a65fd45399e990c5730c166b91d5f88155323cd66aa9604c3f1ef1d3d75e95eb340c204d398e5cff4b7c96879ce51e73ad50a3b55c883282ae0bf0fcf9c742b
6
+ metadata.gz: 93a17f92904c15f4226d1f2d2b26fb535ef6d0fef66d44362e587bef735cc8273ec15c8b10dfbc69d2233cc152b5db9a176f59a858d0da99b9f815611092f161
7
+ data.tar.gz: e3a6b2d5644ac32fb3a470d272b8275286796c6b37e5e1dfacdef7b49ffda869bfc2768c24fd1279da19867763f5a9cf5b8075b6508efccb49c965c85cff0a71
data/.DS_Store ADDED
Binary file
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.9.5
1
+ 0.10.0
data/lib/pin_up.rb CHANGED
@@ -1,11 +1,12 @@
1
1
  require 'httparty'
2
2
  require 'json'
3
- require 'erb'
4
3
 
5
4
  require 'pin_up/base'
6
5
  require 'pin_up/card'
7
6
  require 'pin_up/charge'
7
+ require 'pin_up/client'
8
8
  require 'pin_up/customer'
9
9
  require 'pin_up/refund'
10
+ require 'pin_up/retrying_client'
10
11
 
11
12
  require 'pin_up/pin_errors'
data/lib/pin_up/base.rb CHANGED
@@ -18,12 +18,12 @@ module Pin
18
18
  env = env.to_sym
19
19
  @@auth = { username: @key, password: '' }
20
20
  @@base_url = if env == :live
21
- 'https://api.pin.net.au/1/'
22
- elsif env == :test
23
- 'https://test-api.pin.net.au/1/'
24
- else
25
- fail "'env' option must be :live or :test. Leave blank for live payments"
26
- end
21
+ 'https://api.pin.net.au/1/'
22
+ elsif env == :test
23
+ 'https://test-api.pin.net.au/1/'
24
+ else
25
+ fail "'env' option must be :live or :test. Leave blank for live payments"
26
+ end
27
27
  end
28
28
 
29
29
  ##
@@ -32,25 +32,14 @@ module Pin
32
32
  @@base_url
33
33
  end
34
34
 
35
- # protected
36
-
37
- ##
38
- # Sends an authorised GET request to pins server
39
- # args: url (eg: 'charges' or 'charges/token')
40
- def self.auth_get(url, token = nil)
41
- HTTParty.get("#{@@base_url}#{url}", basic_auth: @@auth)
42
- end
43
-
44
- ##
45
- # Sends an authorised POST request to pins server
46
- def self.auth_post(url, options = {})
47
- HTTParty.post("#{@@base_url}#{url}", body: options, basic_auth: @@auth)
48
- end
49
-
50
35
  ##
51
- # Sends an authorised PUT request to pins server
52
- def self.auth_put(url, options = {})
53
- HTTParty.put("#{@@base_url}#{url}", body: options, basic_auth: @@auth)
36
+ # Sends an authenticated request to pin's server
37
+ # args: method (Symbol), args (Hash)
38
+ # eg. args => { url: 'cards', options: { ... } }
39
+ def self.make_request(method, args)
40
+ client = Pin::Client.new(method, args, @@base_url, @@auth)
41
+ retrying_client = Pin::RetryingClient.new(client)
42
+ retrying_client.make_request
54
43
  end
55
44
 
56
45
  ##
data/lib/pin_up/card.rb CHANGED
@@ -11,7 +11,7 @@ module Pin
11
11
  # args: card_details (Hash)
12
12
  # returns: card object
13
13
  def self.create(options)
14
- build_response(auth_post('cards', options))
14
+ build_response(make_request(:post, { url: 'cards', options: options }))
15
15
  end
16
16
  end
17
17
  end
data/lib/pin_up/charge.rb CHANGED
@@ -12,7 +12,7 @@ module Pin
12
12
  #
13
13
  # https://pin.net.au/docs/api/charges#get-charges
14
14
  def self.all(page = nil, pagination = false)
15
- build_collection_response(auth_get("charges?page=#{page}"), pagination)
15
+ build_collection_response(make_request(:get, { url: "charges?page=#{page}" }), pagination)
16
16
  end
17
17
 
18
18
  ##
@@ -21,7 +21,7 @@ module Pin
21
21
  # returns: a charge object
22
22
  # https://pin.net.au/docs/api/charges#get-charge
23
23
  def self.find(token)
24
- build_response(auth_get("charges/#{token}"))
24
+ build_response(make_request(:get, {url: "charges/#{token}" } ))
25
25
  end
26
26
 
27
27
  # Find a charge(s) for your account given a search term or set of terms
@@ -33,7 +33,7 @@ module Pin
33
33
  options.each do |key, option|
34
34
  term += "#{key.to_s}=#{URI.encode(option)}&"
35
35
  end
36
- build_response(auth_get("charges/search?#{term}"))
36
+ build_response(make_request(:get, {url: "charges/search?#{term}" } ))
37
37
  end
38
38
 
39
39
  # Create a charge given charge details and a card,
@@ -42,7 +42,7 @@ module Pin
42
42
  # returns: a charge object
43
43
  # https://pin.net.au/docs/api/charges#post-charges
44
44
  def self.create(options = {})
45
- build_response(auth_post('charges', options))
45
+ build_response(make_request(:post, {url: 'charges', options: options} ))
46
46
  end
47
47
 
48
48
  # Captures a previously authorised charge and returns its details.
@@ -50,7 +50,7 @@ module Pin
50
50
  # returns: charge object
51
51
  # https://pin.net.au/docs/api/charges#put-charges
52
52
  def self.capture(token)
53
- build_response(auth_put("/charges/#{token}/capture"))
53
+ build_response(make_request(:put, { url: "/charges/#{token}/capture" } ))
54
54
  end
55
55
  end
56
56
  end
@@ -0,0 +1,22 @@
1
+ module Pin
2
+ class Client
3
+ def initialize(method, args, base_url, auth)
4
+ @method = method
5
+ @args = args
6
+ @base_url = base_url
7
+ @auth = auth
8
+ end
9
+
10
+ ##
11
+ # Sends an authenticated request to pin's server
12
+ # args: method (Symbol), args (Hash)
13
+ # eg. args => { url: 'cards', options: { ... } }
14
+ def make_request(times)
15
+ if %i(get post put patch delete).include? @method
16
+ HTTParty.send(@method, "#{@base_url}#{@args[:url]}", body: @args[:options], basic_auth: @auth)
17
+ else
18
+ Pin::PinError.handle_bad_request
19
+ end
20
+ end
21
+ end
22
+ end
@@ -12,7 +12,7 @@ module Pin
12
12
  #
13
13
  # https://pin.net.au/docs/api/customers#get-customers
14
14
  def self.all(page = nil, pagination = false)
15
- build_collection_response(auth_get("customers?page=#{page}"), pagination)
15
+ build_collection_response(make_request(:get, {url: "customers?page=#{page}" } ), pagination)
16
16
  end
17
17
 
18
18
  ##
@@ -27,7 +27,7 @@ module Pin
27
27
  { card_token: card }
28
28
  end.merge(email: email)
29
29
 
30
- build_response(auth_post('customers', options))
30
+ build_response(make_request(:post, { url: 'customers', options: options }))
31
31
  end
32
32
 
33
33
  ##
@@ -36,7 +36,7 @@ module Pin
36
36
  # returns: a customer object
37
37
  # https://pin.net.au/docs/api/customers#get-customers
38
38
  def self.find(token)
39
- build_response(auth_get("customers/#{token}"))
39
+ build_response(make_request(:get, {url: "customers/#{token}" } ))
40
40
  end
41
41
 
42
42
  ##
@@ -48,7 +48,7 @@ module Pin
48
48
  # NB: When providing a card (hash), you need to specify
49
49
  # the full list of details.
50
50
  def self.update(token, options = {})
51
- build_response(auth_put("customers/#{token}", options))
51
+ build_response(make_request(:put, { url: "customers/#{token}", options: options }))
52
52
  end
53
53
 
54
54
  ##
@@ -62,7 +62,7 @@ module Pin
62
62
  # https://pin.net.au/docs/api/customers#get-customers-charges
63
63
  def self.charges(token, page = nil, pagination = false)
64
64
  build_collection_response(
65
- auth_get("customers/#{token}/charges?page=#{page}"), pagination
65
+ make_request(:get, {url: "customers/#{token}/charges?page=#{page}" }), pagination
66
66
  )
67
67
  end
68
68
  end
@@ -30,17 +30,21 @@ module Pin
30
30
  message = ''
31
31
  begin
32
32
  response['messages'].each do |m|
33
- message += "#{m['code']}: #{m['message']}"
33
+ message += "#{m['code']}: #{m['message']} "
34
34
  end
35
35
  rescue
36
36
  begin response['messages']['amount'][0]
37
- message = "#{response['error']}: #{response['error_description']}. Amount: #{response['messages']['amount'][0]}"
37
+ message = "#{response['error']}: #{response['error_description']}. Amount: #{response['messages']['amount'][0]} "
38
38
  rescue
39
39
  message = "#{response['error']}: #{response['error_description']}"
40
40
  end
41
41
  end
42
42
  message
43
43
  end
44
+
45
+ def self.handle_bad_request
46
+ fail(Pin::ClientError, 'request :method must be one of get, post, put, patch or delete')
47
+ end
44
48
  end
45
49
 
46
50
  class ResourceNotFound < PinError
@@ -54,4 +58,7 @@ module Pin
54
58
 
55
59
  class InsufficientPinBalance < PinError
56
60
  end
61
+
62
+ class ClientError < PinError
63
+ end
57
64
  end
data/lib/pin_up/refund.rb CHANGED
@@ -12,7 +12,7 @@ module Pin
12
12
  #
13
13
  # https://pin.net.au/docs/api/refunds#get-refunds
14
14
  def self.find(token, page = nil, pagination = false)
15
- build_collection_response(auth_get("charges/#{token}/refunds?page=#{page}"), pagination)
15
+ build_collection_response(make_request(:get, { url: "charges/#{token}/refunds?page=#{page}" } ), pagination)
16
16
  end
17
17
 
18
18
  ##
@@ -23,7 +23,7 @@ module Pin
23
23
  # https://pin.net.au/docs/api/refunds#post-refunds
24
24
  def self.create(token, amount = nil)
25
25
  options = { amount: amount }
26
- build_response(auth_post("charges/#{token}/refunds", options))
26
+ build_response(make_request(:post, { url: "charges/#{token}/refunds", options: options } ))
27
27
  end
28
28
  end
29
29
  end
@@ -0,0 +1,12 @@
1
+ module Pin
2
+ require 'delegate'
3
+
4
+ class RetryingClient < DelegateClass(Pin::Client)
5
+ def make_request(*, times: 3)
6
+ super
7
+ rescue
8
+ retry if (times -= 1) > 0
9
+ raise
10
+ end
11
+ end
12
+ end
data/pin_up.gemspec CHANGED
@@ -2,16 +2,16 @@
2
2
  # DO NOT EDIT THIS FILE DIRECTLY
3
3
  # Instead, edit Jeweler::Tasks in Rakefile, and run 'rake gemspec'
4
4
  # -*- encoding: utf-8 -*-
5
- # stub: pin_up 0.9.5 ruby lib
5
+ # stub: pin_up 0.10.0 ruby lib
6
6
 
7
7
  Gem::Specification.new do |s|
8
8
  s.name = "pin_up"
9
- s.version = "0.9.5"
9
+ s.version = "0.10.0"
10
10
 
11
11
  s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
12
12
  s.require_paths = ["lib"]
13
13
  s.authors = ["Daniel Nitsikopoulos"]
14
- s.date = "2014-03-10"
14
+ s.date = "2015-02-27"
15
15
  s.description = "A Ruby gem wrapper for the pin-payments (pin.net.au) API"
16
16
  s.email = "dnitza@gmail.com"
17
17
  s.extra_rdoc_files = [
@@ -19,18 +19,8 @@ Gem::Specification.new do |s|
19
19
  "README.md"
20
20
  ]
21
21
  s.files = [
22
+ ".DS_Store",
22
23
  ".document",
23
- ".idea/.name",
24
- ".idea/.rakeTasks",
25
- ".idea/encodings.xml",
26
- ".idea/misc.xml",
27
- ".idea/modules.xml",
28
- ".idea/pin_up.iml",
29
- ".idea/scopes/scope_settings.xml",
30
- ".idea/vcs.xml",
31
- ".idea/workspace.xml",
32
- ".rubocop.yml",
33
- ".ruby-version",
34
24
  ".travis.yml",
35
25
  "Gemfile",
36
26
  "Gemfile.lock",
@@ -44,22 +34,24 @@ Gem::Specification.new do |s|
44
34
  "lib/pin_up/base.rb",
45
35
  "lib/pin_up/card.rb",
46
36
  "lib/pin_up/charge.rb",
37
+ "lib/pin_up/client.rb",
47
38
  "lib/pin_up/customer.rb",
48
39
  "lib/pin_up/pin_errors.rb",
49
40
  "lib/pin_up/refund.rb",
41
+ "lib/pin_up/retrying_client.rb",
50
42
  "pin_up.gemspec",
51
43
  "spec/base_spec.rb",
52
44
  "spec/cards_spec.rb",
53
45
  "spec/charges_spec.rb",
46
+ "spec/client_spec.rb",
54
47
  "spec/customers_spec.rb",
55
48
  "spec/errors_spec.rb",
56
49
  "spec/refund_spec.rb",
57
- "spec/spec_helper.rb",
58
- "views/receipt.html.erb"
50
+ "spec/spec_helper.rb"
59
51
  ]
60
52
  s.homepage = "http://github.com/dNitza/pin_up"
61
53
  s.licenses = ["MIT"]
62
- s.rubygems_version = "2.2.0"
54
+ s.rubygems_version = "2.2.2"
63
55
  s.summary = "A Ruby gem wrapper for the pin-payments API"
64
56
 
65
57
  if s.respond_to? :specification_version then
data/spec/base_spec.rb CHANGED
@@ -1,6 +1,6 @@
1
1
  require 'spec_helper'
2
2
 
3
- describe 'Base', :vcr, class: Pin::Base do
3
+ RSpec.describe 'Base', :vcr, class: Pin::Base do
4
4
  before(:each) do
5
5
  @test_pin = Pin::Base.new(ENV['PIN_SECRET'], :test)
6
6
  end
@@ -25,6 +25,8 @@ describe 'Base', :vcr, class: Pin::Base do
25
25
 
26
26
  it 'should list succesfully connect to Pin' do
27
27
  stub_request(:get, "https://#{@test_pin.key}:''@test-api.pin.net.au/1/customers")
28
- expect(Pin::Base.auth_get('customers').code).to eq 200
28
+ expect(Pin::Base.make_request(:get, { url: 'customers' }).code).to eq 200
29
+ # expect(Pin::Base.auth_get('customers').code).to eq 200
29
30
  end
31
+
30
32
  end
data/spec/cards_spec.rb CHANGED
@@ -1,6 +1,6 @@
1
1
  require 'spec_helper'
2
2
 
3
- describe 'Card', :vcr, class: Pin::Card do
3
+ RSpec.describe 'Card', :vcr, class: Pin::Card do
4
4
  before(:each) do
5
5
  Pin::Base.new(ENV['PIN_SECRET'], :test)
6
6
  end
@@ -0,0 +1,37 @@
1
+ require 'spec_helper'
2
+
3
+ RSpec.describe 'Client', class: Pin::Client do
4
+ it 'delegates http requests to an inner object' do
5
+ inner = double(make_request: 'RESULT')
6
+ client = Pin::RetryingClient.new(inner)
7
+ expect(client.make_request).to eq('RESULT')
8
+ end
9
+
10
+ it 'retries if a request fails' do
11
+ inner = double
12
+ client = Pin::RetryingClient.new(inner)
13
+ times = 2
14
+ allow(inner).to receive(:make_request) do
15
+ raise "Oops" if (times -= 1) > 0
16
+ 'RESULT'
17
+ end
18
+ expect(client.make_request).to eq('RESULT')
19
+ end
20
+
21
+ it 'gives up after a few tries' do
22
+ inner = double
23
+ client = Pin::RetryingClient.new(inner)
24
+ times = 4
25
+ allow(inner).to receive(:make_request) do
26
+ raise "Ooops!" if (times -= 1) > 0
27
+ end
28
+ expect{client.make_request}.to raise_error('Ooops!')
29
+ expect(inner).to have_received(:make_request).exactly(3).times
30
+ end
31
+
32
+ it 'fails if invalid http verb is used' do
33
+ inner = Pin::Client.new(:foo, {}, '', '')
34
+ client = Pin::RetryingClient.new(inner)
35
+ expect {client.make_request}.to raise_error(Pin::ClientError, 'request :method must be one of get, post, put, patch or delete')
36
+ end
37
+ end
@@ -46,11 +46,11 @@ describe 'Customer', :vcr, class: Pin::Customer do
46
46
  end
47
47
 
48
48
  it 'should create a customer given an email and card details' do
49
- Pin::Customer.create('dNitza@gmail.com', number: '5520000000000000', expiry_month: '12', expiry_year: '2014', cvc: '123', name: 'Roland Robot', address_line1: '123 fake street', address_city: 'Melbourne', address_postcode: '1234', address_state: 'Vic', address_country: 'Australia')['token'].should match(/^[a-z]{3}[_]/)
49
+ Pin::Customer.create('dNitza@gmail.com', number: '5520000000000000', expiry_month: '12', expiry_year: '2016', cvc: '123', name: 'Roland Robot', address_line1: '123 fake street', address_city: 'Melbourne', address_postcode: '1234', address_state: 'Vic', address_country: 'Australia')['token'].should match(/^[a-z]{3}[_]/)
50
50
  end
51
51
 
52
52
  it 'should update a customer given a token and details to update' do
53
- options = { email: 'dNitza@gmail.com', card: { number: '5520000000000000', address_line1: '12345 Fake Street', expiry_month: '05', expiry_year: '2014', cvc: '123', name: 'Daniel Nitsikopoulos', address_city: 'Melbourne', address_postcode: '1234', address_state: 'VIC', address_country: 'Australia' } }
53
+ options = { email: 'dNitza@gmail.com', card: { number: '5520000000000000', address_line1: '12345 Fake Street', expiry_month: '05', expiry_year: '2016', cvc: '123', name: 'Daniel Nitsikopoulos', address_city: 'Melbourne', address_postcode: '1234', address_state: 'VIC', address_country: 'Australia' } }
54
54
  Pin::Customer.update('cus_sRtAD2Am-goZoLg1K-HVpA', options)['card']['address_line1'].should == '12345 Fake Street'
55
55
  end
56
56
 
data/spec/errors_spec.rb CHANGED
@@ -10,8 +10,8 @@ describe 'Errors', :vcr, class: Pin::PinError do
10
10
  end
11
11
 
12
12
  it 'should raise a 422 error when trying to update missing a param' do
13
- options = { email: 'dNitza@gmail.com', card: { address_line1: '12345 Fake Street', expiry_month: '05', expiry_year: '2014', cvc: '123', address_city: 'Melbourne', address_postcode: '1234', address_state: 'VIC', address_country: 'Australia' } }
14
- expect { Pin::Customer.update('cus_sRtAD2Am-goZoLg1K-HVpA', options) }.to raise_error(Pin::InvalidResource, 'invalid_resource: One or more parameters were missing or invalid')
13
+ options = { email: 'dNitza@gmail.com', card: { address_line1: '12345 Fake Street', expiry_month: '05', expiry_year: '2016', cvc: '123', address_city: 'Melbourne', address_postcode: '1234', address_state: 'VIC', address_country: 'Australia' } }
14
+ expect { Pin::Customer.update('cus_sRtAD2Am-goZoLg1K-HVpA', options) }.to raise_error(Pin::InvalidResource, "card_number_invalid: Card number can't be blank card_name_invalid: Card name can't be blank ")
15
15
  end
16
16
 
17
17
  it 'should raise a 422 error when trying to make a payment with an expired card' do
@@ -27,7 +27,7 @@ describe 'Errors', :vcr, class: Pin::PinError do
27
27
  address_state: 'WA',
28
28
  address_country: 'Australia'
29
29
  } }
30
- expect { Pin::Charges.create(options) }.to raise_error(Pin::InvalidResource, 'card_expiry_month_invalid: Card expiry month is expiredcard_expiry_year_invalid: Card expiry year is expired')
30
+ expect { Pin::Charges.create(options) }.to raise_error(Pin::InvalidResource, 'card_expiry_month_invalid: Card expiry month is expired card_expiry_year_invalid: Card expiry year is expired ')
31
31
  end
32
32
 
33
33
  it 'should raise a 400 error when trying to make a payment and a valid card gets declined' do
@@ -50,7 +50,7 @@ describe 'Errors', :vcr, class: Pin::PinError do
50
50
  options = { email: 'dNitza@gmail.com', description: 'A new charge from testing Pin gem', amount: '400', currency: 'AUD', ip_address: '127.0.0.1', card: {
51
51
  number: '5520000000000099',
52
52
  expiry_month: '05',
53
- expiry_year: '2014',
53
+ expiry_year: '2019',
54
54
  cvc: '123',
55
55
  name: 'Roland Robot',
56
56
  address_line1: '42 Sevenoaks St',
@@ -59,7 +59,7 @@ describe 'Errors', :vcr, class: Pin::PinError do
59
59
  address_state: 'WA',
60
60
  address_country: 'Australia'
61
61
  } }
62
- expect { Pin::Charges.create(options) }.to raise_error(Pin::InvalidResource, 'card_number_invalid: Card number is not a valid Visa or Mastercard number')
62
+ expect { Pin::Charges.create(options) }.to raise_error(Pin::InvalidResource, 'card_number_invalid: Card number is not a valid Visa or Mastercard number ')
63
63
  end
64
64
 
65
65
  it 'Should raise a ResourceNotFound error when can\'t find customer' do
@@ -69,13 +69,13 @@ describe 'Errors', :vcr, class: Pin::PinError do
69
69
  it 'should raise a 422 error if no 2nd argument is given' do
70
70
  options = { email: 'dNitza@gmail.com', description: 'A new charge from testing Pin gem', amount: '400', currency: 'AUD', ip_address: '127.0.0.1', customer_token: 'cus_8ImkZdEZ6BXUA6NcJDZg_g' }
71
71
  @charge = Pin::Charges.create(options)
72
- expect { Pin::Refund.create(@charge['token']) }.to raise_error(Pin::InvalidResource, 'invalid_resource: One or more parameters were missing or invalid. Amount: can\'t be blank')
72
+ expect { Pin::Refund.create(@charge['token']) }.to raise_error(Pin::InvalidResource, "amount_invalid: Amount can't be blank amount_invalid: Amount is not a number ")
73
73
  end
74
74
 
75
75
  xit 'should raise a 422 error if a value of < 100 is given' do
76
- options = { email: 'dNitza@gmail.com', description: 'A new charge from testing Pin gem', amount: '400', currency: 'AUD', ip_address: '127.0.0.1', customer_token: 'cus_8ImkZdEZ6BXUA6NcJDZg_g' }
76
+ options = { email: 'dNitza@gmail.com', description: 'A new charge from testing Pin gem', amount: '10', currency: 'AUD', ip_address: '127.0.0.1', customer_token: 'cus_8ImkZdEZ6BXUA6NcJDZg_g' }
77
77
  @charge = Pin::Charges.create(options)
78
- expect { Pin::Refund.create(@charge['token'], 90) }.to raise_error(Pin::InvalidResource, 'One or more parameters were missing or invalid')
78
+ expect { Pin::Refund.create(@charge['token'], 90) }.to raise_error(Pin::InvalidResource, 'amount_invalid: Amount must be more than 100 ($1.00 AUD) ')
79
79
  end
80
80
 
81
81
  end