killbill 4.0.0 → 4.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.
- checksums.yaml +4 -4
- data/Gemfile.lock +12 -3
- data/Jarfile +8 -7
- data/Jarfile.lock +9 -8
- data/README.md +131 -108
- data/gen_config/api.conf +1 -1
- data/gen_config/plugin_api.conf +7 -6
- data/generators/active_merchant/templates/Jarfile.rb +7 -7
- data/generators/active_merchant/templates/plugin.gemspec.rb +2 -3
- data/killbill.gemspec +5 -2
- data/lib/killbill.rb +26 -22
- data/lib/killbill/gen/api/admin_payment_api.rb +76 -0
- data/lib/killbill/gen/api/payment_api.rb +82 -0
- data/lib/killbill/gen/api/payment_gateway_api.rb +75 -0
- data/lib/killbill/gen/api/require_gen.rb +1 -0
- data/lib/killbill/gen/plugin-api/catalog_plugin_api.rb +76 -0
- data/lib/killbill/gen/plugin-api/on_failure_payment_routing_result.rb +65 -0
- data/lib/killbill/gen/plugin-api/on_success_payment_routing_result.rb +53 -0
- data/lib/killbill/gen/plugin-api/payment_routing_api_exception.rb +51 -0
- data/lib/killbill/gen/plugin-api/payment_routing_context.rb +246 -0
- data/lib/killbill/gen/plugin-api/payment_routing_plugin_api.rb +138 -0
- data/lib/killbill/gen/plugin-api/prior_payment_routing_result.rb +107 -0
- data/lib/killbill/gen/plugin-api/require_gen.rb +9 -0
- data/lib/killbill/gen/plugin-api/standalone_plugin_catalog.rb +174 -0
- data/lib/killbill/gen/plugin-api/versioned_plugin_catalog.rb +83 -0
- data/lib/killbill/helpers/active_merchant.rb +6 -4
- data/lib/killbill/helpers/active_merchant/active_record/models/response.rb +16 -4
- data/lib/killbill/helpers/active_merchant/configuration.rb +7 -2
- data/lib/killbill/helpers/active_merchant/gateway.rb +76 -5
- data/lib/killbill/helpers/active_merchant/payment_plugin.rb +12 -8
- data/lib/killbill/helpers/catalog.rb +15 -0
- data/lib/killbill/payment_control.rb +23 -0
- data/lib/killbill/version.rb +3 -0
- data/spec/killbill/helpers/configuration_spec.rb +18 -4
- data/spec/killbill/helpers/payment_plugin_spec.rb +140 -36
- data/spec/killbill/helpers/response_spec.rb +1 -1
- metadata +49 -5
- data/VERSION +0 -1
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: ab94851c0a209b9e30898e32f1836bdc230e4a0c
|
4
|
+
data.tar.gz: 61e64d8b6b4c8d57d6cd6563360d357667290f49
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 53b4b231ff542655d1627b24e6857f92ec4417da5a007ba3edf8303106f53acf38f9a824aee2a9698346733fce07af70082a7b066db580c171513cda4deb8ad2
|
7
|
+
data.tar.gz: eb723e04306f28c0c83a544aff56ee336e704878f9005ce32fd0f78ed40295b4c5995ee0ae40de379555060a5e3ee2abe58f43f5c7ba78f464539fc989c1b2bf
|
data/Gemfile.lock
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
killbill (4.
|
4
|
+
killbill (4.1.0)
|
5
5
|
rack (>= 1.5.2)
|
6
6
|
sinatra (~> 1.3.4)
|
7
7
|
typhoeus (~> 0.6.9)
|
@@ -48,7 +48,7 @@ GEM
|
|
48
48
|
builder (3.2.2)
|
49
49
|
diff-lcs (1.1.3)
|
50
50
|
erubis (2.7.0)
|
51
|
-
ethon (0.7.
|
51
|
+
ethon (0.7.4)
|
52
52
|
ffi (>= 1.3.0)
|
53
53
|
ffi (1.9.8-java)
|
54
54
|
i18n (0.7.0)
|
@@ -56,14 +56,18 @@ GEM
|
|
56
56
|
maven-tools (~> 0.32.1)
|
57
57
|
ruby-maven (~> 3.0.4)
|
58
58
|
jdbc-mariadb (1.1.8)
|
59
|
-
jdbc-sqlite3 (3.8.
|
59
|
+
jdbc-sqlite3 (3.8.10.1)
|
60
|
+
json (1.8.2)
|
60
61
|
json (1.8.2-java)
|
61
62
|
maven-tools (0.32.5)
|
63
|
+
mini_portile (0.6.2)
|
62
64
|
minitest (5.6.1)
|
63
65
|
monetize (1.1.0)
|
64
66
|
money (~> 6.5.0)
|
65
67
|
money (6.5.1)
|
66
68
|
i18n (>= 0.6.4, <= 0.7.0)
|
69
|
+
nokogiri (1.6.6.2)
|
70
|
+
mini_portile (~> 0.6.0)
|
67
71
|
nokogiri (1.6.6.2-java)
|
68
72
|
offsite_payments (2.1.0)
|
69
73
|
actionpack (>= 3.2.20, < 5.0.0)
|
@@ -95,6 +99,7 @@ GEM
|
|
95
99
|
rack-protection (~> 1.3)
|
96
100
|
tilt (~> 1.3, >= 1.3.3)
|
97
101
|
thor (0.19.1)
|
102
|
+
thread_safe (0.3.5)
|
98
103
|
thread_safe (0.3.5-java)
|
99
104
|
tilt (1.4.1)
|
100
105
|
typhoeus (0.6.9)
|
@@ -104,6 +109,7 @@ GEM
|
|
104
109
|
|
105
110
|
PLATFORMS
|
106
111
|
java
|
112
|
+
ruby
|
107
113
|
|
108
114
|
DEPENDENCIES
|
109
115
|
actionpack (~> 4.1.0)
|
@@ -123,3 +129,6 @@ DEPENDENCIES
|
|
123
129
|
rspec (~> 2.12.0)
|
124
130
|
thor (~> 0.19.1)
|
125
131
|
thread_safe (~> 0.3.4)
|
132
|
+
|
133
|
+
BUNDLED WITH
|
134
|
+
1.10.4
|
data/Jarfile
CHANGED
@@ -1,9 +1,10 @@
|
|
1
|
-
jar 'org.kill-bill.billing:killbill-api', '0.
|
2
|
-
jar 'org.kill-bill.billing.plugin:killbill-plugin-api-currency', '0.
|
3
|
-
jar 'org.kill-bill.billing.plugin:killbill-plugin-api-invoice', '0.
|
4
|
-
jar 'org.kill-bill.billing.plugin:killbill-plugin-api-notification', '0.
|
5
|
-
jar 'org.kill-bill.billing.plugin:killbill-plugin-api-payment', '0.
|
6
|
-
jar 'org.kill-bill.billing.plugin:killbill-plugin-api-routing', '0.
|
7
|
-
jar 'org.kill-bill.billing:killbill-
|
1
|
+
jar 'org.kill-bill.billing:killbill-api', '0.18'
|
2
|
+
jar 'org.kill-bill.billing.plugin:killbill-plugin-api-currency', '0.11'
|
3
|
+
jar 'org.kill-bill.billing.plugin:killbill-plugin-api-invoice', '0.11'
|
4
|
+
jar 'org.kill-bill.billing.plugin:killbill-plugin-api-notification', '0.11'
|
5
|
+
jar 'org.kill-bill.billing.plugin:killbill-plugin-api-payment', '0.11'
|
6
|
+
jar 'org.kill-bill.billing.plugin:killbill-plugin-api-routing', '0.11'
|
7
|
+
jar 'org.kill-bill.billing.plugin:killbill-plugin-api-catalog', '0.11'
|
8
|
+
jar 'org.kill-bill.billing:killbill-util:tests', '0.14.0'
|
8
9
|
jar 'org.mockito:mockito-all', '1.10.19'
|
9
10
|
jar 'javax.servlet:javax.servlet-api', '3.1.0'
|
data/Jarfile.lock
CHANGED
@@ -1,12 +1,13 @@
|
|
1
|
-
org.kill-bill.billing:killbill-api:jar:0.
|
1
|
+
org.kill-bill.billing:killbill-api:jar:0.18
|
2
2
|
com.fasterxml.jackson.core:jackson-annotations:jar:2.4.3
|
3
3
|
joda-time:joda-time:jar:2.3
|
4
|
-
org.kill-bill.billing.plugin:killbill-plugin-api-currency:jar:0.
|
5
|
-
org.kill-bill.billing.plugin:killbill-plugin-api-invoice:jar:0.
|
6
|
-
org.kill-bill.billing.plugin:killbill-plugin-api-notification:jar:0.
|
7
|
-
org.kill-bill.billing.plugin:killbill-plugin-api-payment:jar:0.
|
8
|
-
org.kill-bill.billing.plugin:killbill-plugin-api-routing:jar:0.
|
9
|
-
org.kill-bill.billing:killbill-
|
4
|
+
org.kill-bill.billing.plugin:killbill-plugin-api-currency:jar:0.11
|
5
|
+
org.kill-bill.billing.plugin:killbill-plugin-api-invoice:jar:0.11
|
6
|
+
org.kill-bill.billing.plugin:killbill-plugin-api-notification:jar:0.11
|
7
|
+
org.kill-bill.billing.plugin:killbill-plugin-api-payment:jar:0.11
|
8
|
+
org.kill-bill.billing.plugin:killbill-plugin-api-routing:jar:0.11
|
9
|
+
org.kill-bill.billing.plugin:killbill-plugin-api-catalog:jar:0.11
|
10
|
+
org.kill-bill.billing:killbill-util:jar:tests:0.14.0
|
10
11
|
com.fasterxml.jackson.core:jackson-databind:jar:2.4.3
|
11
12
|
com.fasterxml.jackson.core:jackson-core:jar:2.4.3
|
12
13
|
com.fasterxml.jackson.dataformat:jackson-dataformat-csv:jar:2.4.3
|
@@ -30,7 +31,7 @@ aopalliance:aopalliance:jar:1.0
|
|
30
31
|
com.google.inject.extensions:guice-multibindings:jar:3.0
|
31
32
|
org.jdbi:jdbi:jar:2.62
|
32
33
|
org.joda:joda-money:jar:0.9
|
33
|
-
org.kill-bill.billing:killbill-internal-api:jar:0.
|
34
|
+
org.kill-bill.billing:killbill-internal-api:jar:0.14.0
|
34
35
|
org.kill-bill.billing:killbill-platform-api:jar:0.2
|
35
36
|
org.kill-bill.billing:killbill-platform-base:jar:0.2
|
36
37
|
com.google.code.findbugs:annotations:jar:3.0.0
|
data/README.md
CHANGED
@@ -19,123 +19,134 @@ All plugin types can interact with Kill Bill directly via APIs and expose HTTP e
|
|
19
19
|
How to write a Notification plugin
|
20
20
|
----------------------------------
|
21
21
|
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
22
|
+
```ruby
|
23
|
+
require 'killbill'
|
24
|
+
|
25
|
+
class MyNotificationPlugin < Killbill::Plugin::Notification
|
26
|
+
# Overriding this method is optional, only if you need to do some initialization work
|
27
|
+
def start_plugin
|
28
|
+
puts "MyNotificationPlugin plugin starting"
|
29
|
+
super
|
30
|
+
puts "MyNotificationPlugin plugin started"
|
31
|
+
end
|
32
|
+
|
33
|
+
# Invoked each time an event is received
|
34
|
+
def on_event(event)
|
35
|
+
puts "Received Killbill event #{event}"
|
36
|
+
end
|
37
|
+
|
38
|
+
# Overriding this method is optional, only if you need to do some tear down work
|
39
|
+
def stop_plugin
|
40
|
+
puts "MyNotificationPlugin plugin stopping"
|
41
|
+
super
|
42
|
+
puts "MyNotificationPlugin plugin stopped"
|
43
|
+
end
|
44
|
+
end
|
45
|
+
```
|
44
46
|
|
45
47
|
Make sure to create the corresponding killbill.properties file:
|
46
48
|
|
47
|
-
|
48
|
-
|
49
|
+
```ini
|
50
|
+
mainClass=MyNotificationPlugin
|
51
|
+
pluginType=NOTIFICATION
|
52
|
+
```
|
49
53
|
|
50
54
|
How to write a Payment plugin
|
51
55
|
-----------------------------
|
52
56
|
|
53
|
-
|
57
|
+
```ruby
|
58
|
+
require 'killbill'
|
54
59
|
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
60
|
+
class MyPaymentPlugin < Killbill::Plugin::Payment
|
61
|
+
def start_plugin
|
62
|
+
puts "MyPaymentPlugin plugin starting"
|
63
|
+
super
|
64
|
+
puts "MyPaymentPlugin plugin started"
|
65
|
+
end
|
61
66
|
|
62
|
-
|
63
|
-
|
67
|
+
def authorize_payment(kb_account_id, kb_payment_id, kb_payment_transaction_id, kb_payment_method_id, amount, currency, properties, context)
|
68
|
+
end
|
64
69
|
|
65
|
-
|
66
|
-
|
70
|
+
def capture_payment(kb_account_id, kb_payment_id, kb_payment_transaction_id, kb_payment_method_id, amount, currency, properties, context)
|
71
|
+
end
|
67
72
|
|
68
|
-
|
69
|
-
|
73
|
+
def purchase_payment(kb_account_id, kb_payment_id, kb_payment_transaction_id, kb_payment_method_id, amount, currency, properties, context)
|
74
|
+
end
|
70
75
|
|
71
|
-
|
72
|
-
|
76
|
+
def void_payment(kb_account_id, kb_payment_id, kb_payment_transaction_id, kb_payment_method_id, properties, context)
|
77
|
+
end
|
73
78
|
|
74
|
-
|
75
|
-
|
79
|
+
def credit_payment(kb_account_id, kb_payment_id, kb_payment_transaction_id, kb_payment_method_id, amount, currency, properties, context)
|
80
|
+
end
|
76
81
|
|
77
|
-
|
78
|
-
|
82
|
+
def refund_payment(kb_account_id, kb_payment_id, kb_payment_transaction_id, kb_payment_method_id, amount, currency, properties, context)
|
83
|
+
end
|
79
84
|
|
80
|
-
|
81
|
-
|
85
|
+
def get_payment_info(kb_account_id, kb_payment_id, properties, context)
|
86
|
+
end
|
82
87
|
|
83
|
-
|
84
|
-
|
88
|
+
def search_payments(search_key, offset, limit, properties, context)
|
89
|
+
end
|
85
90
|
|
86
|
-
|
87
|
-
|
91
|
+
def add_payment_method(kb_account_id, kb_payment_method_id, payment_method_props, set_default, properties, context)
|
92
|
+
end
|
88
93
|
|
89
|
-
|
90
|
-
|
94
|
+
def delete_payment_method(kb_account_id, kb_payment_method_id, properties, context)
|
95
|
+
end
|
91
96
|
|
92
|
-
|
93
|
-
|
97
|
+
def get_payment_method_detail(kb_account_id, kb_payment_method_id, properties, context)
|
98
|
+
end
|
94
99
|
|
95
|
-
|
96
|
-
|
100
|
+
def set_default_payment_method(kb_account_id, kb_payment_method_id, properties, context)
|
101
|
+
end
|
97
102
|
|
98
|
-
|
99
|
-
|
103
|
+
def get_payment_methods(kb_account_id, refresh_from_gateway, properties, context)
|
104
|
+
end
|
100
105
|
|
101
|
-
|
102
|
-
|
106
|
+
def search_payment_methods(search_key, offset, limit, properties, context)
|
107
|
+
end
|
103
108
|
|
104
|
-
|
105
|
-
|
109
|
+
def reset_payment_methods(kb_account_id, payment_methods, properties, context)
|
110
|
+
end
|
106
111
|
|
107
|
-
|
108
|
-
|
112
|
+
def build_form_descriptor(kb_account_id, descriptor_fields, properties, context)
|
113
|
+
end
|
109
114
|
|
110
|
-
|
111
|
-
|
115
|
+
def process_notification(notification, properties, context)
|
116
|
+
end
|
112
117
|
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
118
|
+
# Overriding this method is optional, only if you need to do some tear down work
|
119
|
+
def stop_plugin
|
120
|
+
puts "MyPaymentPlugin plugin stopping"
|
121
|
+
super
|
122
|
+
puts "MyPaymentPlugin plugin stopped"
|
123
|
+
end
|
124
|
+
end
|
125
|
+
```
|
120
126
|
|
121
127
|
Make sure to create the corresponding killbill.properties file:
|
122
128
|
|
123
|
-
|
124
|
-
|
125
|
-
|
129
|
+
```ini
|
130
|
+
mainClass=MyPaymentPlugin
|
131
|
+
pluginType=PAYMENT
|
132
|
+
```
|
126
133
|
|
127
134
|
How to write a Payment plugin integrated with ActiveMerchant
|
128
135
|
------------------------------------------------------------
|
129
136
|
|
130
137
|
Use the plugin generator:
|
131
138
|
|
132
|
-
|
139
|
+
```bash
|
140
|
+
./script/generate active_merchant gateway_name /path/to/dir
|
141
|
+
```
|
133
142
|
|
134
143
|
Replace `gateway_name` with the snake case of your ActiveMerchant gateway (e.g. `yandex`, `stripe`, `paypal`, etc.).
|
135
144
|
|
136
145
|
This will generate a tree of files ready to be plugged into Kill Bill. To package the plugin, run:
|
137
146
|
|
138
|
-
|
147
|
+
```bash
|
148
|
+
rake killbill:clean ; rake build ; rake killbill:package
|
149
|
+
```
|
139
150
|
|
140
151
|
Most of the work consists of filling in the blank in `api.rb` (payment plugin API for ActiveMerchant gateways) and `application.rb` (sinatra application for ActiveMerchant integrations). Check the [Stripe plugin](https://github.com/killbill/killbill-stripe-plugin) for an example.
|
141
152
|
|
@@ -160,14 +171,15 @@ Killbill exports a Rack handler that interfaces directly with the container in w
|
|
160
171
|
|
161
172
|
This basically means that Killbill will understand native Rack config.ru files placed in the root of your plugin, e.g. (using Sinatra):
|
162
173
|
|
163
|
-
|
164
|
-
|
165
|
-
get "/plugins/myPlugin/ping" do
|
166
|
-
status 200
|
167
|
-
"pong"
|
168
|
-
end
|
169
|
-
run Sinatra::Application
|
174
|
+
```ruby
|
175
|
+
require 'sinatra'
|
170
176
|
|
177
|
+
get "/plugins/myPlugin/ping" do
|
178
|
+
status 200
|
179
|
+
"pong"
|
180
|
+
end
|
181
|
+
run Sinatra::Application
|
182
|
+
```
|
171
183
|
|
172
184
|
Rake tasks
|
173
185
|
----------
|
@@ -176,48 +188,59 @@ The killbill gem also ships helpful Rake tasks to package Killbill-ready plugins
|
|
176
188
|
|
177
189
|
To access these tasks, add the following to your Rakefile:
|
178
190
|
|
179
|
-
|
180
|
-
|
181
|
-
|
191
|
+
```ruby
|
192
|
+
# Install tasks to package the plugin for Killbill
|
193
|
+
require 'killbill/rake_task'
|
194
|
+
Killbill::PluginHelper.install_tasks
|
182
195
|
|
183
|
-
|
184
|
-
|
185
|
-
|
196
|
+
# (Optional) Install tasks to build and release your plugin gem
|
197
|
+
require 'bundler/setup'
|
198
|
+
Bundler::GemHelper.install_tasks
|
199
|
+
```
|
186
200
|
|
187
201
|
You can verify these tasks are available by running `rake -T`.
|
188
202
|
|
189
203
|
To build the artifacts into pkg/:
|
190
204
|
|
191
|
-
|
192
|
-
|
193
|
-
|
194
|
-
|
195
|
-
|
196
|
-
|
197
|
-
|
205
|
+
```bash
|
206
|
+
# Cleanup output directories
|
207
|
+
rake killbill:clean
|
208
|
+
# Build your plugin gem in the pkg/ directory
|
209
|
+
rake build
|
210
|
+
# Build the Killbill plugin in the pkg/ directory
|
211
|
+
# The <plugin_name>-<plugin-version>/ directory is used as a staging directory
|
212
|
+
rake killbill:package
|
213
|
+
```
|
198
214
|
|
199
215
|
For quick testing of your plugin, you can use the `deploy` task:
|
200
216
|
|
201
|
-
|
202
|
-
|
203
|
-
|
204
|
-
|
205
|
-
|
206
|
-
|
217
|
+
```bash
|
218
|
+
# Deploy the plugin in /var/tmp/bundles
|
219
|
+
rake killbill:deploy
|
220
|
+
# Deploy the plugin and clobber a previous version if needed
|
221
|
+
rake killbill:deploy[true]
|
222
|
+
# You can also specify a custom plugins directory as such
|
223
|
+
rake killbill:deploy[false,/path/to/bundles]
|
224
|
+
```
|
207
225
|
|
208
226
|
To debug packaging issues, pass `true` as the third (optional) parameter:
|
209
227
|
|
210
|
-
|
211
|
-
|
228
|
+
```bash
|
229
|
+
rake killbill:deploy[false,/path/to/bundles,true]
|
230
|
+
```
|
212
231
|
|
213
232
|
Development
|
214
233
|
-----------
|
215
234
|
|
216
235
|
To run unit and remote tests:
|
217
236
|
|
218
|
-
|
219
|
-
|
237
|
+
```bash
|
238
|
+
rake
|
239
|
+
rake test:remote:spec
|
240
|
+
```
|
220
241
|
|
221
242
|
To change the database driver:
|
222
243
|
|
223
|
-
|
244
|
+
```bash
|
245
|
+
AR_ADAPTER=mariadb AR_USERNAME=root AR_PASSWORD=root AR_DATABASE=kbtest rake
|
246
|
+
```
|
data/gen_config/api.conf
CHANGED
data/gen_config/plugin_api.conf
CHANGED
@@ -1,10 +1,11 @@
|
|
1
1
|
java -cp target/killbill-java-parser-0.0.1-SNAPSHOT.jar com.ning.killbill.KillbillParser \
|
2
2
|
-i \
|
3
|
-
file
|
4
|
-
file
|
5
|
-
file
|
6
|
-
file
|
7
|
-
file
|
3
|
+
file://$PATH_TO_REPO/killbill-plugin-api/payment/src/main/java, \
|
4
|
+
file://$PATH_TO_REPO/killbill-plugin-api/notification/src/main/java, \
|
5
|
+
file://$PATH_TO_REPO/killbill-plugin-api/invoice/src/main/java, \
|
6
|
+
file://$PATH_TO_REPO/killbill-plugin-api/currency/src/main/java, \
|
7
|
+
file://$PATH_TO_REPO/killbill-plugin-api/routing/src/main/java, \
|
8
|
+
file://$PATH_TO_REPO/killbill-api/src/main/java/ \
|
8
9
|
-o \
|
9
10
|
/tmp/output \
|
10
11
|
-t \
|
@@ -14,6 +15,6 @@ org.killbill.billing.payment.plugin.api, \
|
|
14
15
|
org.killbill.billing.notification.plugin.api, \
|
15
16
|
org.killbill.billing.invoice.plugin.api \
|
16
17
|
org.killbill.billing.currency.plugin.api \
|
18
|
+
org.killbill.billing.routing.plugin.api \
|
17
19
|
-m \
|
18
20
|
JRUBY_PLUGIN_API
|
19
|
-
|