poundpay 0.2.9 → 0.3
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/.gitignore +3 -0
- data/README.rdoc +50 -3
- data/examples/simple_application/.rvmrc +1 -1
- data/examples/simple_application/application.rb +152 -48
- data/examples/simple_application/config.rb +14 -5
- data/examples/simple_application/config.ru +16 -2
- data/examples/simple_application/index.html.erb +125 -14
- data/examples/simple_application/static/css/simplemp.css +13 -0
- data/examples/simple_application/static/css/ui-lightness/images/ui-bg_diagonals-thick_18_b81900_40x40.png +0 -0
- data/examples/simple_application/static/css/ui-lightness/images/ui-bg_diagonals-thick_20_666666_40x40.png +0 -0
- data/examples/simple_application/static/css/ui-lightness/images/ui-bg_flat_10_000000_40x100.png +0 -0
- data/examples/simple_application/static/css/ui-lightness/images/ui-bg_glass_100_f6f6f6_1x400.png +0 -0
- data/examples/simple_application/static/css/ui-lightness/images/ui-bg_glass_100_fdf5ce_1x400.png +0 -0
- data/examples/simple_application/static/css/ui-lightness/images/ui-bg_glass_65_ffffff_1x400.png +0 -0
- data/examples/simple_application/static/css/ui-lightness/images/ui-bg_gloss-wave_35_f6a828_500x100.png +0 -0
- data/examples/simple_application/static/css/ui-lightness/images/ui-bg_highlight-soft_100_eeeeee_1x100.png +0 -0
- data/examples/simple_application/static/css/ui-lightness/images/ui-bg_highlight-soft_75_ffe45c_1x100.png +0 -0
- data/examples/simple_application/static/css/ui-lightness/images/ui-icons_222222_256x240.png +0 -0
- data/examples/simple_application/static/css/ui-lightness/images/ui-icons_228ef1_256x240.png +0 -0
- data/examples/simple_application/static/css/ui-lightness/images/ui-icons_ef8c08_256x240.png +0 -0
- data/examples/simple_application/static/css/ui-lightness/images/ui-icons_ffd27a_256x240.png +0 -0
- data/examples/simple_application/static/css/ui-lightness/images/ui-icons_ffffff_256x240.png +0 -0
- data/examples/simple_application/static/css/ui-lightness/jquery-ui-1.8.13.custom.css +578 -0
- data/examples/simple_application/static/favicon.ico +0 -0
- data/examples/simple_application/static/js/jquery-1.6.1.js +8936 -0
- data/examples/simple_application/static/js/jquery-ui-1.8.13.custom.min.js +784 -0
- data/examples/simple_application/static/js/simplemp.js +177 -0
- data/lib/poundpay.rb +2 -1
- data/lib/poundpay/elements.rb +38 -18
- data/lib/poundpay/exceptions.rb +10 -0
- data/lib/poundpay/version.rb +1 -1
- data/spec/fixtures/charge_permissions.rb +24 -0
- data/spec/fixtures/payments.rb +0 -6
- data/spec/poundpay/elements_spec.rb +34 -43
- data/spec/poundpay/exceptions_spec.rb +11 -0
- metadata +29 -21
data/.gitignore
CHANGED
data/README.rdoc
CHANGED
@@ -7,7 +7,7 @@ Poundpay is a payments platform for marketplaces
|
|
7
7
|
|
8
8
|
1. Add the following to your Gemfile
|
9
9
|
|
10
|
-
gem 'poundpay', '~> 0.2.
|
10
|
+
gem 'poundpay', '~> 0.2.9'
|
11
11
|
|
12
12
|
2. At the command prompt, install the gem with bundler
|
13
13
|
|
@@ -35,6 +35,13 @@ Poundpay is a payments platform for marketplaces
|
|
35
35
|
|
36
36
|
before_filter :verify_poundpay_callback
|
37
37
|
|
38
|
+
== Creating a user
|
39
|
+
|
40
|
+
@user = Poundpay::User.create(
|
41
|
+
:first_name => "Dart",
|
42
|
+
:last_name => "Master",
|
43
|
+
:email_address => "dart-master@example.com")
|
44
|
+
|
38
45
|
|
39
46
|
== Creating a payment
|
40
47
|
|
@@ -47,7 +54,7 @@ Poundpay is a payments platform for marketplaces
|
|
47
54
|
:description => "Beats by Dr. Dre")
|
48
55
|
|
49
56
|
|
50
|
-
== Serving IFRAME
|
57
|
+
== Serving the payment IFRAME
|
51
58
|
|
52
59
|
<script src="https://www.poundpay.com/js/poundpay.js"></script>
|
53
60
|
|
@@ -80,6 +87,46 @@ Poundpay is a payments platform for marketplaces
|
|
80
87
|
|
81
88
|
payment = Poundpay::Payment.find(payment_sid)
|
82
89
|
payment.escrow # AUTHORIZED -> ESCROWED. Credit card is charged
|
83
|
-
payment.partially_release(amount) # ESCROWED or PARTIALLY_RELEASED -> PARTIALLY_RELEASED or PARTIALLY_RELEASED. Recipieint recieves a portion of funds.
|
84
90
|
payment.release # ESCROWED or PARTIALLY_RELEASED -> RELEASED. Recipient receives money
|
85
91
|
payment.cancel # ESCROWED or PARTIALLY_RELEASED -> CANCELED. Payer receives refund
|
92
|
+
|
93
|
+
|
94
|
+
== Creating a charge permission
|
95
|
+
|
96
|
+
@charge_permission = Poundpay::ChargePermission.create(
|
97
|
+
:email_address => "fred@example.com")
|
98
|
+
|
99
|
+
|
100
|
+
== Serving the charge permission IFRAME
|
101
|
+
|
102
|
+
<script src="https://www.poundpay.com/js/poundpay.js"></script>
|
103
|
+
|
104
|
+
<div id="pound-root"></div>
|
105
|
+
|
106
|
+
<script>
|
107
|
+
function handleChargePermissionSuccess() {
|
108
|
+
// do something
|
109
|
+
}
|
110
|
+
|
111
|
+
function handleChargePermissionError() {
|
112
|
+
// handle error
|
113
|
+
}
|
114
|
+
|
115
|
+
PoundPay.init({
|
116
|
+
charge_permission_sid: "<%= @charge_permission.sid %>",
|
117
|
+
success: handleChargePermissionSuccess,
|
118
|
+
error: handleChargePermissionError,
|
119
|
+
name: "Fred Nietzsche", // Optional
|
120
|
+
address_street: "330 Townsend St", // Optional
|
121
|
+
address_city: "San Francisco", // Optional
|
122
|
+
address_state: "California", // Optional
|
123
|
+
address_zip: "94107", // Optional
|
124
|
+
server: "<%= Poundpay.www_url %>"
|
125
|
+
});
|
126
|
+
</script>
|
127
|
+
|
128
|
+
|
129
|
+
== Charge permission methods
|
130
|
+
|
131
|
+
charge_permission = Poundpay::ChargePermission.find(charge_permission_sid)
|
132
|
+
charge_permission.deactivate # CREATED or ACTIVE -> INACTIVE. Charge permission is deactivated and can no longer be used to authorize payments for the associated payer.
|
@@ -1,65 +1,169 @@
|
|
1
|
-
require '
|
2
|
-
require '
|
3
|
-
require 'net/https'
|
4
|
-
require 'json'
|
5
|
-
require 'erb'
|
1
|
+
require 'pp'
|
2
|
+
require 'poundpay'
|
6
3
|
|
7
|
-
require 'config'
|
4
|
+
require './config'
|
8
5
|
|
6
|
+
class SimpleController
|
7
|
+
attr_reader :poundpay_client
|
9
8
|
|
10
|
-
|
11
|
-
|
9
|
+
def initialize
|
10
|
+
if Poundpay.configured?
|
11
|
+
return
|
12
|
+
end
|
13
|
+
config = SimpleApplication::CONFIG[:poundpay]
|
14
|
+
puts config
|
15
|
+
Poundpay.configure_from_hash(config)
|
16
|
+
end
|
12
17
|
|
13
|
-
def
|
14
|
-
|
15
|
-
|
16
|
-
@sid = sid
|
17
|
-
@token = token
|
18
|
+
def return_404
|
19
|
+
response = Rack::Response.new(["Page Not Found"], 404, {"Content-Type" => "text/plain"})
|
20
|
+
response.finish
|
18
21
|
end
|
19
22
|
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
23
|
+
end
|
24
|
+
|
25
|
+
class Index < SimpleController
|
26
|
+
|
27
|
+
def call env
|
28
|
+
request = Rack::Request.new(env)
|
29
|
+
unless request.path == '/' and request.get?
|
30
|
+
return return_404
|
31
|
+
end
|
32
|
+
# Create payment request
|
33
|
+
payment = SimpleApplication::CONFIG[:default_payment]
|
34
|
+
# Render and return page
|
35
|
+
www_poundpay_url = Poundpay.www_url
|
36
|
+
template = ERB.new(open("index.html.erb").read)
|
37
|
+
page = template.result(binding)
|
38
|
+
response = Rack::Response.new([page], 200, {"Content-Type" => "text/html"})
|
39
|
+
response.finish
|
31
40
|
end
|
41
|
+
|
32
42
|
end
|
33
43
|
|
44
|
+
class Payment < SimpleController
|
34
45
|
|
35
|
-
|
36
|
-
|
46
|
+
def call env
|
47
|
+
request = Rack::Request.new(env)
|
48
|
+
return_value = case request.path.gsub(/\/$/, '') # trim trailing /
|
49
|
+
when '/payment' then request.post? ? create(request) : nil
|
50
|
+
when '/payment/release' then request.post? ? release(request) : nil
|
51
|
+
when '/payment/authorize' then request.post? ? authorize(request) : nil
|
52
|
+
when '/payment/cancel' then request.post? ? cancel(request) : nil
|
53
|
+
when '/payment/escrow' then request.post? ? escrow(request) : nil
|
54
|
+
else nil
|
55
|
+
end
|
37
56
|
|
38
|
-
|
39
|
-
|
40
|
-
|
57
|
+
if return_value
|
58
|
+
response = Rack::Response.new([return_value], 201, {"Content-Type" => "text/html"})
|
59
|
+
response.finish
|
60
|
+
else
|
61
|
+
return_404
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
def create request
|
66
|
+
payment = Poundpay::Payment.create(request.POST)
|
67
|
+
payment.sid
|
41
68
|
end
|
42
69
|
|
43
|
-
def
|
44
|
-
|
45
|
-
|
70
|
+
def authorize request
|
71
|
+
payment = Poundpay::Payment.find(request.POST['sid'])
|
72
|
+
payment.authorize
|
73
|
+
payment.save
|
74
|
+
PP.pp(payment.schema, '')
|
75
|
+
end
|
76
|
+
|
77
|
+
def release request
|
78
|
+
payment = Poundpay::Payment.find(request.POST['sid'])
|
79
|
+
payment.release
|
80
|
+
payment.save
|
81
|
+
PP.pp(payment.schema, '')
|
82
|
+
end
|
83
|
+
|
84
|
+
def cancel request
|
85
|
+
payment = Poundpay::Payment.find(request.POST['sid'])
|
86
|
+
payment.cancel
|
87
|
+
payment.save
|
88
|
+
PP.pp(payment.schema, '')
|
89
|
+
end
|
90
|
+
|
91
|
+
def escrow request
|
92
|
+
payment = Poundpay::Payment.find(request.POST['sid'])
|
93
|
+
payment.escrow
|
94
|
+
payment.save
|
95
|
+
PP.pp(payment.schema, '')
|
96
|
+
end
|
97
|
+
|
98
|
+
end
|
99
|
+
|
100
|
+
|
101
|
+
class User < SimpleController
|
102
|
+
|
103
|
+
def call env
|
104
|
+
request = Rack::Request.new(env)
|
105
|
+
return_value = case request.path.gsub(/\/$/, '') # trim trailing /
|
106
|
+
when '/user' then request.post? ? create(request) : nil
|
107
|
+
else nil
|
108
|
+
end
|
109
|
+
|
110
|
+
if return_value
|
111
|
+
response = Rack::Response.new([return_value], 201, {"Content-Type" => "text/html"})
|
112
|
+
response.finish
|
113
|
+
else
|
114
|
+
return_404
|
46
115
|
end
|
47
|
-
|
48
|
-
params = {
|
49
|
-
'amount' => 20000, # In USD cents
|
50
|
-
'payer_fee_amount' => 0,
|
51
|
-
'payer_email_address' => 'goliath@example.com',
|
52
|
-
'recipient_fee_amount' => 500,
|
53
|
-
'recipient_email_address' => 'david@example.com',
|
54
|
-
'description' => 'Beats by Dr. Dre',
|
55
|
-
}
|
56
|
-
payment = @poundpay_client.post 'payments', params
|
57
|
-
puts payment
|
116
|
+
end
|
58
117
|
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
118
|
+
def create request
|
119
|
+
user = Poundpay::User.create({
|
120
|
+
:first_name => request.POST['user_first_name'],
|
121
|
+
:last_name => request.POST['user_last_name'],
|
122
|
+
:email_address => request.POST['user_email_address']
|
123
|
+
})
|
124
|
+
PP.pp(user.schema, '')
|
64
125
|
end
|
126
|
+
|
127
|
+
end
|
128
|
+
|
129
|
+
|
130
|
+
class ChargePermission < SimpleController
|
131
|
+
|
132
|
+
def call env
|
133
|
+
request = Rack::Request.new(env)
|
134
|
+
return_value = case request.path.gsub(/\/$/, '') # trim trailing /
|
135
|
+
when '/charge_permission' then request.post? ? create(request) : nil
|
136
|
+
when '/charge_permission/find' then request.post? ? show(request) : nil
|
137
|
+
when '/charge_permission/deactivate' then request.post? ? deactivate(request) : nil
|
138
|
+
else nil
|
139
|
+
end
|
140
|
+
|
141
|
+
if return_value
|
142
|
+
response = Rack::Response.new([return_value], 201, {"Content-Type" => "text/html"})
|
143
|
+
response.finish
|
144
|
+
else
|
145
|
+
return_404
|
146
|
+
end
|
147
|
+
end
|
148
|
+
|
149
|
+
def create request
|
150
|
+
charge_permission = Poundpay::ChargePermission.create(request.POST)
|
151
|
+
PP.pp(charge_permission.schema, '')
|
152
|
+
end
|
153
|
+
|
154
|
+
def show request
|
155
|
+
charge_permissions = Poundpay::ChargePermission.all(:email_address => request.POST['email_address'])
|
156
|
+
if charge_permissions
|
157
|
+
PP.pp(charge_permissions.map {|cp| cp.schema}, '')
|
158
|
+
else
|
159
|
+
nil
|
160
|
+
end
|
161
|
+
end
|
162
|
+
|
163
|
+
def deactivate request
|
164
|
+
charge_permission = Poundpay::ChargePermission.find(request.POST['sid'])
|
165
|
+
charge_permission.deactivate
|
166
|
+
PP.pp(charge_permission.schema, '')
|
167
|
+
end
|
168
|
+
|
65
169
|
end
|
@@ -1,11 +1,20 @@
|
|
1
1
|
class SimpleApplication
|
2
2
|
CONFIG = {
|
3
3
|
poundpay: {
|
4
|
-
api_url
|
5
|
-
www_url
|
6
|
-
version
|
7
|
-
|
8
|
-
|
4
|
+
"api_url" => "https://api-sandbox.poundpay.com",
|
5
|
+
"www_url" => "https://www-sandbox.poundpay.com",
|
6
|
+
"version" => "silver",
|
7
|
+
"developer_sid" => "DV2f8a5168710c11e0aab3123140005921",
|
8
|
+
"auth_token" => "f309a5f600a630f7293c64783eaebc8b67a34428cfcd96e82599657a12769924",
|
9
|
+
"callback_url" => '',
|
10
|
+
},
|
11
|
+
default_payment: {
|
12
|
+
"amount" => "67890",
|
13
|
+
"payer_fee_amount" => "100",
|
14
|
+
"recipient_fee_amount" => "200",
|
15
|
+
"payer_email_address" => "sam@example.com",
|
16
|
+
"recipient_email_address" => "jacob@example.net",
|
17
|
+
"description" => "this is a simple description that just loves developers, developers",
|
9
18
|
}
|
10
19
|
}
|
11
20
|
end
|
@@ -1,6 +1,20 @@
|
|
1
|
-
|
1
|
+
# http://stackoverflow.com/questions/2900370/
|
2
|
+
# why-does-ruby-1-9-2-remove-from-load-path-and-whats-the-alternative
|
3
|
+
|
4
|
+
require 'rack'
|
5
|
+
require 'rack/urlmap'
|
2
6
|
|
3
7
|
use Rack::ShowExceptions
|
4
8
|
use Rack::Lint
|
9
|
+
use Rack::Static, :urls => ["/static"]
|
10
|
+
|
11
|
+
require './application'
|
12
|
+
|
13
|
+
app = Rack::URLMap.new(
|
14
|
+
'/' => Index.new,
|
15
|
+
'/payment' => Payment.new,
|
16
|
+
'/charge_permission'=> ChargePermission.new,
|
17
|
+
'/user' => User.new,
|
18
|
+
)
|
5
19
|
|
6
|
-
run
|
20
|
+
run app
|
@@ -1,18 +1,129 @@
|
|
1
|
+
<!DOCTYPE html>
|
1
2
|
<html>
|
2
|
-
<
|
3
|
-
|
3
|
+
<head>
|
4
|
+
<meta charset="utf-8">
|
5
|
+
<meta name="description" content="Simple Marketplace">
|
6
|
+
<title>Simple MarketPlace</title>
|
7
|
+
<link rel="icon" href="static/favicon.ico" type="image/x-icon">
|
8
|
+
<link rel="stylesheet" href="static/css/simplemp.css">
|
9
|
+
<script src="static/js/jquery-1.6.1.js"></script>
|
10
|
+
<script src="static/js/jquery-ui-1.8.13.custom.min.js"></script>
|
11
|
+
<script src="<%= www_poundpay_url %>/js/poundpay.js"></script>
|
12
|
+
<script src="static/js/simplemp.js"></script>
|
13
|
+
</head>
|
4
14
|
<body>
|
5
|
-
|
6
|
-
|
7
|
-
<
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
15
|
+
<h1>Create charge permission</h1>
|
16
|
+
<table id="chargePermissionTable">
|
17
|
+
<tr>
|
18
|
+
<td>Email
|
19
|
+
<td><input type="text" class="text" id="email_address" value="<%= payment['payer_email_address'] %>">
|
20
|
+
</tr>
|
21
|
+
</table>
|
22
|
+
<a href="javascript:;" onclick="createChargePermission();">Create Charge Permission</a><br>
|
23
|
+
<a href="javascript:;" onclick="findChargePermission();">Find Charge Permission</a><br>
|
24
|
+
<pre id="find_charge_permission_results"></pre>
|
25
|
+
|
26
|
+
<h1>Display charge permission iframe</h1>
|
27
|
+
<table>
|
28
|
+
<tr>
|
29
|
+
<td>Charge permission id
|
30
|
+
<td><input type="text" class="text" id="charge_permission_id">
|
31
|
+
</tr>
|
32
|
+
<tr>
|
33
|
+
<td>Card holder name</td>
|
34
|
+
<td><input type="text" class="text" id="charge_permission_cardholder_name">
|
35
|
+
</tr>
|
36
|
+
<tr>
|
37
|
+
<td>server
|
38
|
+
<td><input type="text" class="text" id="charge_permission_server" value="<%= www_poundpay_url %>">
|
39
|
+
</tr>
|
40
|
+
</table>
|
41
|
+
<a href="javascript:;" onclick="deactivateChargePermission();">Deactivate Charge Permission</a><br>
|
42
|
+
<a href="javascript:;" onclick="startChargePermissionIFrame();">Start Charge Permission IFrame</a><br>
|
43
|
+
<div id="pound-pcp"></div>
|
44
|
+
|
45
|
+
<h1>Create payment</h1>
|
46
|
+
<table id="paymentsTable">
|
47
|
+
<tr>
|
48
|
+
<td>Payment Amount
|
49
|
+
<td><input type="text" class="text" id="amount" value="<%= payment['amount'] %>">
|
50
|
+
</tr>
|
51
|
+
<tr>
|
52
|
+
<td>Payer Fee</td>
|
53
|
+
<td><input type="text" class="text" id="payer_fee_amount" value="<%= payment['payer_fee_amount'] %>">
|
54
|
+
</tr>
|
55
|
+
<tr>
|
56
|
+
<td>Recipient Fee</td>
|
57
|
+
<td><input type="text" class="text" id="recipient_fee_amount" value="<%= payment['recipient_fee_amount'] %>">
|
58
|
+
</tr>
|
59
|
+
<tr>
|
60
|
+
<td>Payer Email</td>
|
61
|
+
<td><input type="text" class="text" id="payer_email_address" value="<%= payment['payer_email_address'] %>">
|
62
|
+
</tr>
|
63
|
+
<tr>
|
64
|
+
<td>Recipient Email</td>
|
65
|
+
<td><input type="text" class="text" id="recipient_email_address" value="<%= payment['recipient_email_address'] %>">
|
66
|
+
</tr>
|
67
|
+
<tr>
|
68
|
+
<td>Description</td>
|
69
|
+
<td><input type="text" class="text" id="description" value="<%= payment['description'] %>">
|
70
|
+
</tr>
|
71
|
+
</table>
|
72
|
+
|
73
|
+
<a href="javascript:;" onclick="createPayment();">Create Payment</a>
|
74
|
+
|
75
|
+
<h1>Display payment iframe</h1>
|
76
|
+
<table>
|
77
|
+
<tr>
|
78
|
+
<td>Payment request id</td>
|
79
|
+
<td><input type="text" class="text" id="payment_id">
|
80
|
+
</tr>
|
81
|
+
<tr>
|
82
|
+
<td>Card holder name</td>
|
83
|
+
<td><input type="text" class="text" id="cardholder_name">
|
84
|
+
</tr>
|
85
|
+
<tr>
|
86
|
+
<td>server</td>
|
87
|
+
<td><input type="text" class="text" id="server" value="<%= www_poundpay_url %>">
|
88
|
+
</tr>
|
89
|
+
</table>
|
90
|
+
<a href="javascript:;" onclick="startIFrame();">Start Payment IFrame</a>
|
91
|
+
<div id="pound-root"></div>
|
92
|
+
<h1 id="paymentComplete" style="display:none;color:green;">
|
93
|
+
Payment Complete
|
94
|
+
</h1>
|
95
|
+
<h1>Create User</h1>
|
96
|
+
<table id="create_user_table">
|
97
|
+
<tr>
|
98
|
+
<td>First Name</td>
|
99
|
+
<td><input type="text" class="text" id="user_first_name">
|
100
|
+
</tr>
|
101
|
+
<tr>
|
102
|
+
<td>Last Name</td>
|
103
|
+
<td><input type="text" class="text" id="user_last_name">
|
104
|
+
</tr>
|
105
|
+
<tr>
|
106
|
+
<td>Email Address</td>
|
107
|
+
<td><input type="text" class="text" id="user_email_address">
|
108
|
+
</tr>
|
109
|
+
</table>
|
110
|
+
<a href="javascript:;" onclick="createUser();">Create User</a>
|
111
|
+
|
112
|
+
<pre id="created_user_results"></pre>
|
113
|
+
|
114
|
+
|
115
|
+
<h1>Payment Operations</h1>
|
116
|
+
<table>
|
117
|
+
<tr>
|
118
|
+
<td>Payment SID
|
119
|
+
<td><input type="text" class="text" id="operating_payment_sid">
|
120
|
+
</tr>
|
121
|
+
</table>
|
122
|
+
<a href="javascript:;" onclick="authorizePayment();">Authorize Payment</a><br>
|
123
|
+
<a href="javascript:;" onclick="escrowPayment();">Escrow Payment</a><br>
|
124
|
+
<a href="javascript:;" onclick="releasePayment();">Release Payment</a><br>
|
125
|
+
<a href="javascript:;" onclick="cancelPayment();">Cancel Payment</a><br>
|
126
|
+
|
127
|
+
<pre id="operation_results"></pre>
|
17
128
|
</body>
|
18
129
|
</html>
|