activemerchant 1.36.0 → 1.37.0

Sign up to get free protection for your applications and to get access to all the features.
data.tar.gz.sig CHANGED
Binary file
data/CHANGELOG CHANGED
@@ -1,5 +1,14 @@
1
1
  = ActiveMerchant CHANGELOG
2
2
 
3
+ * MerchantWarrior: Fix handling of amounts [duff]
4
+ * Ipay88: New gateway [kamal, siong1987, jduff]
5
+ * IATS: New gateway [unkown, jduff]
6
+ * MerchantWarrior: Send the CVV to the gateway [duff]
7
+ * PayU: Fix a major bug with status types [melari]
8
+ * SecureNet: Allow production transactions [duff]
9
+ * Stripe: Allow a card_not_present_fee to be specified [melari]
10
+
11
+
3
12
  == Version 1.36.0 (August 2, 2013)
4
13
 
5
14
  * Fat Zebra: More consistent handling of tokens [adrianmacneil]
@@ -10,6 +19,8 @@
10
19
  * Mercury: Proper refund and void support [opendining]
11
20
  * PaymentExpress: Return token in authorization [ntalbott]
12
21
  * Stripe: Support for partial application fee refunds [melari, odorcicd]
22
+ * NMI: Support for recurring flag [duff]
23
+ * SecureNet: Use working live url [duff]
13
24
 
14
25
  == Version 1.35.1 (July 22, 2013)
15
26
 
@@ -31,7 +31,8 @@ module ActiveMerchant #:nodoc:
31
31
  #
32
32
  # ActiveMerchant::Billing::Base.gateway('moneris').new
33
33
  def self.gateway(name)
34
- Billing.const_get("#{name.to_s.downcase}_gateway".camelize)
34
+ raise NameError if (name_str = name.to_s.downcase).blank?
35
+ Billing.const_get("#{name_str}_gateway".camelize)
35
36
  end
36
37
 
37
38
  # Return the matching integration module
@@ -342,7 +342,7 @@ module ActiveMerchant #:nodoc:
342
342
  post[:description] = options[:description]
343
343
  end
344
344
 
345
- def add_creditcard(post, creditcard)
345
+ def add_creditcard(post, creditcard, options={})
346
346
  post[:card_num] = creditcard.number
347
347
  post[:card_code] = creditcard.verification_value if creditcard.verification_value?
348
348
  post[:exp_date] = expdate(creditcard)
@@ -354,7 +354,7 @@ module ActiveMerchant #:nodoc:
354
354
  if card_brand(source) == "check"
355
355
  add_check(params, source, options)
356
356
  else
357
- add_creditcard(params, source)
357
+ add_creditcard(params, source, options)
358
358
  end
359
359
  end
360
360
 
@@ -0,0 +1,35 @@
1
+ module ActiveMerchant #:nodoc:
2
+ module Billing #:nodoc:
3
+ class IatsPaymentsGateway < AuthorizeNetGateway
4
+ self.live_url = self.test_url = 'https://www.iatspayments.com/netgate/AEGateway.aspx'
5
+
6
+ self.homepage_url = 'http://www.iatspayments.com/'
7
+ self.display_name = 'IATSPayments'
8
+
9
+ def authorize(money, paysource, options = {})
10
+ raise NotImplementedError
11
+ end
12
+
13
+ def capture(money, authorization, options = {})
14
+ raise NotImplementedError
15
+ end
16
+
17
+ def void(authorization, options = {})
18
+ raise NotImplementedError
19
+ end
20
+
21
+ def refund(money, identification, options = {})
22
+ raise NotImplementedError
23
+ end
24
+
25
+ def credit(money, identification, options = {})
26
+ raise NotImplementedError
27
+ end
28
+
29
+ private
30
+ def split(response)
31
+ response.split(',')
32
+ end
33
+ end
34
+ end
35
+ end
@@ -46,7 +46,7 @@ module ActiveMerchant #:nodoc:
46
46
  post = {}
47
47
  add_amount(post, money, options)
48
48
  add_transaction(post, identification)
49
- post.merge!('captureAmount' => money.to_s)
49
+ post.merge!('captureAmount' => amount(money))
50
50
  commit('processCapture', post)
51
51
  end
52
52
 
@@ -54,7 +54,7 @@ module ActiveMerchant #:nodoc:
54
54
  post = {}
55
55
  add_amount(post, money, options)
56
56
  add_transaction(post, identification)
57
- post['refundAmount'] = money
57
+ post['refundAmount'] = amount(money)
58
58
  commit('refundCard', post)
59
59
  end
60
60
 
@@ -105,14 +105,15 @@ module ActiveMerchant #:nodoc:
105
105
  post['paymentCardNumber'] = creditcard.number
106
106
  post['paymentCardName'] = creditcard.name
107
107
  post['paymentCardExpiry'] = creditcard.expiry_date.expiration.strftime("%m%y")
108
+ post['paymentCardCSC'] = creditcard.verification_value if creditcard.verification_value?
108
109
  end
109
110
 
110
111
  def add_amount(post, money, options)
111
112
  currency = (options[:currency] || currency(money))
112
113
 
113
- post['transactionAmount'] = money.to_s
114
+ post['transactionAmount'] = amount(money)
114
115
  post['transactionCurrency'] = currency
115
- post['hash'] = verification_hash(money, currency)
116
+ post['hash'] = verification_hash(amount(money), currency)
116
117
  end
117
118
 
118
119
  def verification_hash(money, currency)
@@ -67,15 +67,15 @@ module ActiveMerchant #:nodoc:
67
67
  end
68
68
 
69
69
  def refund(money, authorization, options = {})
70
- commit :refund, build_reference_request(money, authorization)
70
+ commit :refund, build_reference_request(money, authorization, options)
71
71
  end
72
72
 
73
73
  def authorize(money, credit_card, options = {})
74
74
  commit :authorization, build_purchase_request(money, credit_card, options)
75
75
  end
76
76
 
77
- def capture(money, authorization)
78
- commit :capture, build_reference_request(money, authorization)
77
+ def capture(money, authorization, options = {})
78
+ commit :capture, build_reference_request(money, authorization, options)
79
79
  end
80
80
 
81
81
  def store(creditcard, options = {})
@@ -116,7 +116,7 @@ module ActiveMerchant #:nodoc:
116
116
  xml.target!
117
117
  end
118
118
 
119
- def build_reference_request(money, reference)
119
+ def build_reference_request(money, reference, options)
120
120
  xml = Builder::XmlMarkup.new
121
121
 
122
122
  transaction_id, order_id, preauth_id, original_amount = reference.split('*')
@@ -7,7 +7,14 @@ module ActiveMerchant #:nodoc:
7
7
  self.display_name = 'NMI'
8
8
  self.supported_countries = ['US']
9
9
  self.supported_cardtypes = [:visa, :master, :american_express, :discover]
10
+
11
+ private
12
+ def add_creditcard(post, creditcard, options={})
13
+ super
14
+ post[:recurring_billing] = "TRUE" if options[:recurring]
15
+ end
10
16
  end
17
+
11
18
  end
12
19
  end
13
20
 
@@ -24,7 +24,7 @@ module ActiveMerchant #:nodoc:
24
24
  self.display_name = 'SecureNet'
25
25
 
26
26
  self.test_url = 'https://certify.securenet.com/API/gateway.svc/webHttp/ProcessTransaction'
27
- self.live_url = 'https://gateway.securenet.com/api/Gateway.svc'
27
+ self.live_url = 'https://gateway.securenet.com/api/Gateway.svc/webHttp/ProcessTransaction'
28
28
 
29
29
  APPROVED, DECLINED = 1, 2
30
30
 
@@ -65,12 +65,12 @@ module ActiveMerchant #:nodoc:
65
65
  private
66
66
  def commit(request)
67
67
  xml = build_request(request)
68
- data = ssl_post(self.test_url, xml, "Content-Type" => "text/xml")
68
+ url = test? ? self.test_url : self.live_url
69
+ data = ssl_post(url, xml, "Content-Type" => "text/xml")
69
70
  response = parse(data)
70
71
 
71
- test_mode = test?
72
72
  Response.new(success?(response), message_from(response), response,
73
- :test => test_mode,
73
+ :test => test?,
74
74
  :authorization => build_authorization(response),
75
75
  :avs_result => { :code => response[:avs_result_code] },
76
76
  :cvv_result => response[:card_code_response_code]
@@ -207,7 +207,7 @@ module ActiveMerchant #:nodoc:
207
207
 
208
208
  def add_more_required_params(xml, options)
209
209
  xml.tag! 'RETAIL_LANENUM', '0'
210
- xml.tag! 'TEST', 'TRUE'
210
+ xml.tag! 'TEST', 'TRUE' if test?
211
211
  xml.tag! 'TOTAL_INSTALLMENTCOUNT', 0
212
212
  xml.tag! 'TRANSACTION_SERVICE', 0
213
213
  end
@@ -40,7 +40,7 @@ module ActiveMerchant #:nodoc:
40
40
  post = create_post_for_auth_or_purchase(money, creditcard, options)
41
41
  post[:capture] = "false"
42
42
 
43
- commit(:post, 'charges', post, generate_meta(options))
43
+ commit(:post, 'charges', post, generate_meta(options), creditcard)
44
44
  end
45
45
 
46
46
  # To create a charge on a card or a token, call
@@ -53,12 +53,12 @@ module ActiveMerchant #:nodoc:
53
53
  def purchase(money, creditcard, options = {})
54
54
  post = create_post_for_auth_or_purchase(money, creditcard, options)
55
55
 
56
- commit(:post, 'charges', post, generate_meta(options))
56
+ commit(:post, 'charges', post, generate_meta(options), creditcard)
57
57
  end
58
58
 
59
59
  def capture(money, authorization, options = {})
60
60
  post = {:amount => amount(money)}
61
- add_application_fee(post, options)
61
+ add_application_fee(post, nil, options)
62
62
 
63
63
  commit(:post, "charges/#{CGI.escape(authorization)}/capture", post)
64
64
  end
@@ -131,7 +131,7 @@ module ActiveMerchant #:nodoc:
131
131
  add_customer_data(post,options)
132
132
  post[:description] = options[:description] || options[:email]
133
133
  add_flags(post, options)
134
- add_application_fee(post, options)
134
+ add_application_fee(post, creditcard, options)
135
135
  post
136
136
  end
137
137
 
@@ -140,8 +140,25 @@ module ActiveMerchant #:nodoc:
140
140
  post[:currency] = (options[:currency] || currency(money)).downcase
141
141
  end
142
142
 
143
- def add_application_fee(post, options)
144
- post[:application_fee] = options[:application_fee] if options[:application_fee]
143
+ def add_application_fee(post, creditcard, options)
144
+ return unless options[:application_fee]
145
+ if use_card_not_present_fee?(creditcard, options)
146
+ post[:application_fee] = options[:card_not_present_fee]
147
+ else
148
+ post[:application_fee] = options[:application_fee]
149
+ end
150
+ end
151
+
152
+ def use_card_not_present_fee?(creditcard, options)
153
+ options[:card_not_present_fee].present? && !includes_track_data?(creditcard, options)
154
+ end
155
+
156
+ def includes_track_data?(creditcard, options)
157
+ if creditcard.respond_to?(:track_data)
158
+ creditcard.track_data.present?
159
+ else
160
+ options[:track_data].present?
161
+ end
145
162
  end
146
163
 
147
164
  def add_customer_data(post, options)
@@ -248,7 +265,7 @@ module ActiveMerchant #:nodoc:
248
265
  }
249
266
  end
250
267
 
251
- def commit(method, url, parameters=nil, options = {})
268
+ def commit(method, url, parameters=nil, options = {}, creditcard = nil)
252
269
  raw_response = response = nil
253
270
  success = false
254
271
  begin
@@ -262,6 +279,8 @@ module ActiveMerchant #:nodoc:
262
279
  response = json_error(raw_response)
263
280
  end
264
281
 
282
+ response[:card_present] = includes_track_data?(creditcard, options)
283
+
265
284
  card = response["card"] || response["active_card"] || {}
266
285
  avs_code = AVS_CODE_TRANSLATOR["line1: #{card["address_line1_check"]}, zip: #{card["address_zip_check"]}"]
267
286
  cvc_code = CVC_CODE_TRANSLATOR[card["cvc_check"]]
@@ -0,0 +1,19 @@
1
+ module ActiveMerchant #:nodoc:
2
+ module Billing #:nodoc:
3
+ module Integrations #:nodoc:
4
+ module Ipay88
5
+ autoload :Return, "active_merchant/billing/integrations/ipay88/return.rb"
6
+ autoload :Helper, "active_merchant/billing/integrations/ipay88/helper.rb"
7
+ autoload :Notification, "active_merchant/billing/integrations/ipay88/notification.rb"
8
+
9
+ def self.service_url
10
+ "https://www.mobile88.com/epayment/entry.asp"
11
+ end
12
+
13
+ def self.return(query_string, options={})
14
+ Return.new(query_string, options)
15
+ end
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,114 @@
1
+ require "digest/sha1"
2
+
3
+ module ActiveMerchant #:nodoc:
4
+ module Billing #:nodoc:
5
+ module Integrations #:nodoc:
6
+ module Ipay88
7
+ class Helper < ActiveMerchant::Billing::Integrations::Helper
8
+ include RequiresParameters
9
+
10
+ # Currencies supported
11
+ # MYR (Malaysian Ringgit - for all payment methods except China Union Pay and PayPal)
12
+ # USD (US Dollar - only for PayPal)
13
+ # CNY (Yuan Renminbi - only for China Union Pay)
14
+ SUPPORTED_CURRENCIES = %w[MYR USD CNY]
15
+
16
+ # Languages supported
17
+ # ISO-8859-1 (English)
18
+ # UTF-8 (Unicode)
19
+ # GB2312 (Chinese Simplified)
20
+ # GD18030 (Chinese Simplified)
21
+ # BIG5 (Chinese Traditional)
22
+ SUPPORTED_LANGS = %w[ISO-8859-1 UTF-8 GB2312 GD18030 BIG5]
23
+
24
+ # Payment methods supported
25
+ # 8 (Alliance Online Transfer)
26
+ # 10 (AmBank)
27
+ # 21 (China Union Pay)
28
+ # 20 (CIMB Click)
29
+ # 2 (Credit Card MYR)
30
+ # 16 (FPX)
31
+ # 15 (Hong Leong Bank Transfer)
32
+ # 6 (Maybank2u.com)
33
+ # 23 (MEPS Cash)
34
+ # 17 (Mobile Money)
35
+ # 33 (PayPal)
36
+ # 14 (RHB)
37
+ PAYMENT_METHODS = %w[8 10 21 20 2 16 15 6 23 17 33 14]
38
+
39
+ attr_reader :amount_in_cents, :merchant_key
40
+
41
+ def initialize(order, account, options = {})
42
+ requires!(options, :amount, :currency, :credential2)
43
+ @merchant_key = options[:credential2]
44
+ @amount_in_cents = options[:amount]
45
+ super
46
+ add_field mappings[:signature], signature
47
+ end
48
+
49
+ def amount=(money)
50
+ cents = money.respond_to?(:cents) ? money.cents : money
51
+ if money.is_a?(String) or cents.to_i < 0
52
+ raise ArgumentError, "money amount must be either a Money object or a positive integer in cents."
53
+ end
54
+ add_field mappings[:amount], sprintf("%.2f", cents.to_f/100)
55
+ end
56
+
57
+ def currency(symbol)
58
+ raise ArgumentError, "unsupported currency" unless SUPPORTED_CURRENCIES.include?(symbol)
59
+ add_field mappings[:currency], symbol
60
+ end
61
+
62
+ def language(lang)
63
+ raise ArgumentError, "unsupported language" unless SUPPORTED_LANGS.include?(lang)
64
+ add_field mappings[:language], lang
65
+ end
66
+
67
+ def payment(pay_method)
68
+ raise ArgumentError, "unsupported payment method" unless PAYMENT_METHODS.include?(pay_method.to_s)
69
+ add_field mappings[:payment], pay_method
70
+ end
71
+
72
+ def customer(params = {})
73
+ add_field(mappings[:customer][:name], "#{params[:first_name]} #{params[:last_name]}")
74
+ add_field(mappings[:customer][:email], params[:email])
75
+ add_field(mappings[:customer][:phone], params[:phone])
76
+ end
77
+
78
+ def self.sign(str)
79
+ [Digest::SHA1.digest(str)].pack("m").chomp
80
+ end
81
+
82
+ def signature
83
+ self.class.sign(self.sig_components)
84
+ end
85
+
86
+ mapping :account, "MerchantCode"
87
+ mapping :amount, "Amount"
88
+ mapping :currency, "Currency"
89
+ mapping :order, "RefNo"
90
+ mapping :description, "ProdDesc"
91
+ mapping :customer, :name => "UserName",
92
+ :email => "UserEmail",
93
+ :phone => "UserContact"
94
+ mapping :remark, "Remark"
95
+ mapping :language, "Lang"
96
+ mapping :payment, "PaymentId"
97
+ mapping :return_url, "ResponseURL"
98
+ mapping :signature, "Signature"
99
+
100
+ protected
101
+
102
+ def sig_components
103
+ components = [merchant_key]
104
+ components << fields[mappings[:account]]
105
+ components << fields[mappings[:order]]
106
+ components << amount_in_cents
107
+ components << fields[mappings[:currency]]
108
+ components.join
109
+ end
110
+ end
111
+ end
112
+ end
113
+ end
114
+ end
@@ -0,0 +1,95 @@
1
+ require "digest/sha1"
2
+
3
+ module ActiveMerchant #:nodoc:
4
+ module Billing #:nodoc:
5
+ module Integrations #:nodoc:
6
+ module Ipay88
7
+ class Return < ActiveMerchant::Billing::Integrations::Return
8
+ include ActiveMerchant::PostsData
9
+
10
+ def account
11
+ params["MerchantCode"]
12
+ end
13
+
14
+ def payment
15
+ params["PaymentId"].to_i
16
+ end
17
+
18
+ def order
19
+ params["RefNo"]
20
+ end
21
+
22
+ def amount
23
+ params["Amount"]
24
+ end
25
+
26
+ def currency
27
+ params["Currency"]
28
+ end
29
+
30
+ def remark
31
+ params["Remark"]
32
+ end
33
+
34
+ def transaction
35
+ params["TransId"]
36
+ end
37
+
38
+ def auth_code
39
+ params["AuthCode"]
40
+ end
41
+
42
+ def status
43
+ params["Status"]
44
+ end
45
+
46
+ def error
47
+ params["ErrDesc"]
48
+ end
49
+
50
+ def signature
51
+ params["Signature"]
52
+ end
53
+
54
+ def secure?
55
+ self.generated_signature == self.signature
56
+ end
57
+
58
+ def success?
59
+ self.secure? && self.requery == "00" && self.status == "1"
60
+ end
61
+
62
+ protected
63
+
64
+ def generated_signature
65
+ Helper.sign(self.sig_components)
66
+ end
67
+
68
+ def sig_components
69
+ components = [@options[:credential2]]
70
+ [:account, :payment, :order, :amount_in_cents, :currency, :status].each do |i|
71
+ components << self.send(i)
72
+ end
73
+ components.join
74
+ end
75
+
76
+ def requery
77
+ data = { "MerchantCode" => self.account, "RefNo" => self.order, "Amount" => self.amount }
78
+ params = parameterize(data)
79
+ ssl_post Ipay88.service_url, params, { "Content-Length" => params.size.to_s, "User-Agent" => "Active Merchant -- http://activemerchant.org" }
80
+ end
81
+
82
+ private
83
+
84
+ def parameterize(params)
85
+ params.reject { |k, v| v.blank? }.keys.sort.collect { |key| "#{key}=#{CGI.escape(params[key].to_s)}" }.join("&")
86
+ end
87
+
88
+ def amount_in_cents
89
+ @amount_in_cents ||= (self.amount || "").gsub(/[.,]/, "")
90
+ end
91
+ end
92
+ end
93
+ end
94
+ end
95
+ end
@@ -11,24 +11,22 @@ module ActiveMerchant #:nodoc:
11
11
  end
12
12
 
13
13
  def complete?
14
- status == "success"
14
+ status == "Completed"
15
15
  end
16
16
 
17
- # Status of the transaction. List of possible values:
18
- # <tt>invalid</tt>:: transaction id is not present
19
- # <tt>tampered</tt>:: transaction data has been tampered
20
- # <tt>success</tt>:: transaction successful
21
- # <tt>pending</tt>:: transaction is pending for some approval
22
- # <tt>failure</tt>:: transaction failure
23
17
  def status
24
18
  @status ||= if checksum_ok?
25
19
  if transaction_id.blank?
26
- 'invalid'
20
+ 'Invalid'
27
21
  else
28
- transaction_status.downcase
22
+ case transaction_status.downcase
23
+ when 'success' then 'Completed'
24
+ when 'failure' then 'Failed'
25
+ when 'pending' then 'Pending'
26
+ end
29
27
  end
30
28
  else
31
- 'tampered'
29
+ 'Tampered'
32
30
  end
33
31
  end
34
32
 
@@ -9,37 +9,20 @@ module ActiveMerchant #:nodoc:
9
9
  @notification = Notification.new(query_string, options)
10
10
  end
11
11
 
12
- # PayU Transaction Id
13
- #
14
12
  def transaction_id
15
13
  @notification.transaction_id
16
14
  end
17
15
 
18
- # Returns the status of the transaction as a string
19
- # The status can be one of the following
20
- #
21
- # invalid - transaction id not present
22
- # tampered - checksum does not mismatch
23
- # mismatch - order id mismatch
24
- # success - transaction success
25
- # pending - transaction pending
26
- # failure - transaction failure
27
- #
28
- # payu does not put the discount field in the checksum
29
- # it can be easily forged by the attacker without detection
30
- #
31
16
  def status( order_id, order_amount )
32
17
  if @notification.invoice_ok?( order_id ) && @notification.amount_ok?( BigDecimal.new(order_amount) )
33
18
  @notification.status
34
19
  else
35
- 'mismatch'
20
+ 'Mismatch'
36
21
  end
37
22
  end
38
23
 
39
- # check success of the transaction
40
- # check order_id and
41
24
  def success?
42
- status( @params['txnid'], @params['amount'] ) == 'success'
25
+ status( @params['txnid'], @params['amount'] ) == 'Completed'
43
26
  end
44
27
 
45
28
  def message
@@ -1,3 +1,3 @@
1
1
  module ActiveMerchant
2
- VERSION = "1.36.0"
2
+ VERSION = "1.37.0"
3
3
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: activemerchant
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.36.0
4
+ version: 1.37.0
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -37,7 +37,7 @@ cert_chain:
37
37
  Z1BvU1BxN25rK3MyRlFVQko5VVpGSzFsZ016aG8vNGZaZ3pKd2J1K2NPOFNO
38
38
  dWFMUy9iagpoUGFTVHlWVTB5Q1Nudz09Ci0tLS0tRU5EIENFUlRJRklDQVRF
39
39
  LS0tLS0K
40
- date: 2013-08-02 00:00:00.000000000 Z
40
+ date: 2013-08-20 00:00:00.000000000 Z
41
41
  dependencies:
42
42
  - !ruby/object:Gem::Dependency
43
43
  name: activesupport
@@ -276,6 +276,7 @@ files:
276
276
  - lib/active_merchant/billing/gateways/firstdata_e4.rb
277
277
  - lib/active_merchant/billing/gateways/garanti.rb
278
278
  - lib/active_merchant/billing/gateways/hdfc.rb
279
+ - lib/active_merchant/billing/gateways/iats_payments.rb
279
280
  - lib/active_merchant/billing/gateways/ideal/ideal_base.rb
280
281
  - lib/active_merchant/billing/gateways/ideal/ideal_rabobank.pem
281
282
  - lib/active_merchant/billing/gateways/ideal/ideal_response.rb
@@ -429,6 +430,9 @@ files:
429
430
  - lib/active_merchant/billing/integrations/hi_trust/notification.rb
430
431
  - lib/active_merchant/billing/integrations/hi_trust/return.rb
431
432
  - lib/active_merchant/billing/integrations/hi_trust.rb
433
+ - lib/active_merchant/billing/integrations/ipay88/helper.rb
434
+ - lib/active_merchant/billing/integrations/ipay88/return.rb
435
+ - lib/active_merchant/billing/integrations/ipay88.rb
432
436
  - lib/active_merchant/billing/integrations/liqpay/helper.rb
433
437
  - lib/active_merchant/billing/integrations/liqpay/notification.rb
434
438
  - lib/active_merchant/billing/integrations/liqpay/return.rb
metadata.gz.sig CHANGED
Binary file