qbo_api 1.8.2 → 1.8.3

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 706590c1ebea65c87b5bd12452dca43fa3746bbc
4
- data.tar.gz: 7d815c391cca1e6f11ff95d804bc6f17692be548
3
+ metadata.gz: 1a14e9e5e66c903adfe8068876926ab4a7cb1a6a
4
+ data.tar.gz: 81dea94865459c92b103ae0b6804b85f2287e23c
5
5
  SHA512:
6
- metadata.gz: 10c69ee5b8e677a9dc58bb1c6c5e9b24e806bd76bf9e5070cd2f99614446c9d5ba5a5f9fca44a4ab50199e20b8f047e1c246bce9f2180e8029df036809ad6c74
7
- data.tar.gz: 9352623cd9286a26149cfbb8cb5bbdeeb77f95882b938d7bd5774957bae1cdcbe51e766212bae4f13335c1664ac64fe4dec91114091b1465f72502b57ce78397
6
+ metadata.gz: 5c7a3e681f058684ccec7da9db94da92ce20f010f6762b91eb7e87cf10b83a320897a8fcd84f882d841544ec17b08ab3e90711c3674ef0662669861e3108ed58
7
+ data.tar.gz: 5ffdd016f2ef8f8d83b9b700d76a835cdb86fd39a85621976fc0fef99a69c9dff30b5c4b0a40bbf2624a5fd163bfe71753aebc2058ca03f55a6f76b90e8615f2
data/Gemfile CHANGED
@@ -1,4 +1,3 @@
1
1
  source 'https://rubygems.org'
2
2
 
3
- # Specify your gem's dependencies in qbo_api.gemspec
4
3
  gemspec
data/README.md CHANGED
@@ -353,16 +353,22 @@ See [docs](https://developer.intuit.com/docs/0100_quickbooks_online/0100_essenti
353
353
  - If needed create an account at [https://developer.intuit.com](https://developer.intuit.com)
354
354
  - Click `Get started coding`
355
355
  - Create an app with both the `Accounting` & `Payments` selected.
356
- - Go to the `Development` tab and copy and paste the client id and client secret into the `.env` file.
357
- - Note: the `.env` file will be automatically loaded after you run the next step.
358
- - Start up the example app
359
- - `ruby example/app.rb`
360
- - Goto `http://localhost:9393/oauth2`
356
+ - Go to the [`Development` tab](https://developer.intuit.com/v2/ui#/app/dashboard)
357
+ and copy the 'Client ID' and the 'Client 'Secret' to your .env
358
+ as QBO_API_CLIENT_ID and QBO_API_CLIENT_SECRET respectively
359
+ - Add a Redirect URI: `http://localhost:9393/oauth2-redirect` (or whatever PORT= is in your .env)
360
+ - Create a new Company ([from the manage sandboxes page](https://developer.intuit.com/v2/ui#/sandbox))
361
+ Don't use it for anything else besides testing this app.
362
+ -. Copy the 'Company ID' to your .env as QBO_API_COMPANY_ID
363
+ - Start up the example OAuth2 app
364
+ - `ruby example/oauth2.rb`
365
+ - Go to `http://localhost:9393/oauth2`
361
366
  - Use the `Connect to QuickBooks` button to connect to your QuickBooks sandbox, which you receive when signing up at [https://developer.intuit.com](https://developer.intuit.com).
362
- - After successfully connecting to your sandbox run:
367
+ - After successfully connecting to your sandbox go to :
363
368
  - `http://localhost:9393/oauth2/customer/5`
364
369
  - You should see "Dukes Basketball Camp" displayed
365
- - Checkout [`example/app.rb`](https://github.com/minimul/qbo_api/blob/master/example/app.rb) to see what is going on under the hood.
370
+ - Checkout [`example/oauth2.rb`](https://github.com/minimul/qbo_api/blob/master/example/oauth2.rb)
371
+ to see what is going on under the hood.
366
372
 
367
373
  ## OAuth1: Spin up an example
368
374
  ### OLD LEGACY - SEE OAUTH2 EXAMPLE ABOVE
@@ -374,20 +380,47 @@ See [docs](https://developer.intuit.com/docs/0100_quickbooks_online/0100_essenti
374
380
  - If needed create an account at [https://developer.intuit.com](https://developer.intuit.com)
375
381
  - Click `Get started coding`
376
382
  - Create an app with both the `Accounting` & `Payments` selected.
377
- - Go to the `Development` tab and copy and paste the consumer key and secret into the `.env` file.
378
- - Note: the `.env` file will be automatically loaded after you run the next step.
383
+ - Go to the `Development` tab and copy and paste the consumer key and secret into the `.env` file
384
+ as QBO_API_CONSUMER_KEY and QBO_API_CONSUMER_SECRET respectively.
379
385
  - Start up the example app
380
- - `ruby example/app.rb`
381
- - Goto `http://localhost:9393`
386
+ - `ruby example/oauth.rb`
387
+ - Go to `http://localhost:9393`
382
388
  - Use the `Connect to QuickBooks` button to connect to your QuickBooks sandbox, which you receive when signing up at [https://developer.intuit.com](https://developer.intuit.com).
383
389
  - After successfully connecting to your sandbox run:
384
390
  - `http://localhost:9393/customer/5`
385
391
  - You should see "Dukes Basketball Camp" displayed
386
- - Checkout [`example/app.rb`](https://github.com/minimul/qbo_api/blob/master/example/app.rb) to see what is going on under the hood.
392
+ - Checkout [`example/oauth.rb`](https://github.com/minimul/qbo_api/blob/master/example/oauth.rb)
393
+ to see what is going on under the hood.
387
394
 
388
395
  ## Webhooks
389
396
  - <a href="http://minimul.com/getting-started-with-quickbooks-online-webhooks.html" target="_blank">Check out this tutorial and screencast on handling a webhook request</a>. Also checkout [`example/app.rb`](https://github.com/minimul/qbo_api/blob/master/example/app.rb) for the request handling code.
390
397
 
398
+ See https://www.twilio.com/blog/2015/09/6-awesome-reasons-to-use-ngrok-when-testing-webhooks.html
399
+ for how to install ngrok and what it is.
400
+
401
+ - With either the oauth1 or oauth2 examples running, run:
402
+ `ngrok http 9393 -subdomain=somereasonablyuniquenamehere`
403
+
404
+ - Go to the [`Development` tab](https://developer.intuit.com/v2/ui#/app/dashboard)
405
+ - Add a webhook, Select all triggers and enter the https url from the ngrok output
406
+ `https://somereasonablyuniquenamehere/webhooks`
407
+
408
+ - After saving the webhook, click 'show token'.
409
+ Add the token to your .env as QBO_API_VERIFIER_TOKEN
410
+
411
+ - In another tab, create a customer via the (OAuth2) API:
412
+ `bundle exec ruby -rqbo_api -rdotenv -e 'Dotenv.load; p QboApi.new(access_token: ENV.fetch("QBO_API_OAUTH2_ACCESS_TOKEN"), realm_id: ENV.fetch("QBO_API_COMPANY_ID")).create(:customer, payload: { DisplayName: "TestCustomer" })'`
413
+ (You'll also need to have added the QBO_API_COMPANY_ID and QBO_API_OAUTH2_ACCESS_TOKEN to your .env)
414
+
415
+ There could be a delay of up to a minute before the webhook fires.
416
+
417
+ It'll appear in your logs like:
418
+ ```
419
+ {"eventNotifications"=>[{"realmId"=>"XXXX", "dataChangeEvent"=>{"entities"=>[{"name"=>"Customer", "id"=>"62", "operation"=>"Create", "lastUpdated"=>"2018-04-08T04:14:39.000Z"}]}}]}
420
+ Verified: true
421
+ "POST /webhooks HTTP/1.1" 200 - 0.0013
422
+ ```
423
+
391
424
  ## Contributing
392
425
 
393
426
  Bug reports and pull requests are welcome on GitHub at https://github.com/minimul/qbo_api.
@@ -408,9 +441,7 @@ Bug reports and pull requests are welcome on GitHub at https://github.com/minimu
408
441
  #### Protip: Once your .env file is completely filled out you can use the console to play around in your sandbox
409
442
  ```
410
443
  bin/console test
411
- >> q = QboApi.new(creds.to_h)
412
- >> q = QboApi.new(oauth2_creds.to_h) # FOR OAuth2
413
- >> q.get :customer, 1
444
+ >> @qbo_api.get :customer, 1
414
445
  ```
415
446
 
416
447
  ## License
@@ -6,6 +6,7 @@ require "qbo_api"
6
6
  if ARGV[0] == "test"
7
7
  require_relative '../spec/support/credentials'
8
8
  ARGV[0] = nil # needed to avoid irb error
9
+ instance_variable_set(:@qbo_api, QboApi.new(creds.to_h))
9
10
  end
10
11
 
11
12
  # You can add fixtures and/or initialization code here to make experimenting
@@ -0,0 +1,54 @@
1
+ BASE_GEMS = proc do
2
+ gem 'qbo_api', path: '.'
3
+ # This app
4
+ gem 'sinatra'
5
+ gem 'sinatra-contrib'
6
+
7
+ # Creds from ../.env
8
+ gem 'dotenv'
9
+ end
10
+
11
+ BASE_SETUP = proc do
12
+ # Webhook support
13
+ require 'json'
14
+ require 'openssl'
15
+ require 'base64'
16
+
17
+ Dotenv.load "#{__dir__}/../.env"
18
+ end
19
+
20
+ BASE_APP_CONFIG = proc do
21
+ PORT = ENV.fetch("PORT", 9393)
22
+ # WebHook verifier token
23
+ VERIFIER_TOKEN = ENV['QBO_API_VERIFIER_TOKEN']
24
+
25
+ configure do
26
+ $VERBOSE = nil # silence redefined constant warning
27
+ register Sinatra::Reloader
28
+ end
29
+
30
+ set :sessions, :true
31
+ set :port, PORT
32
+
33
+ before do
34
+ # Rewrite trailing slashes
35
+ next unless request.path_info =~ %r{/(.+)/$}
36
+ redirect(Regexp.last_match[1], 301)
37
+ end
38
+
39
+ post '/webhooks' do
40
+ request.body.rewind
41
+ data = request.body.read
42
+ puts JSON.parse data
43
+ verified = verify_webhook(data, env['HTTP_INTUIT_SIGNATURE'])
44
+ puts "Verified: #{verified}"
45
+ end
46
+
47
+ helpers do
48
+ def verify_webhook(data, hmac_header)
49
+ digest = OpenSSL::Digest.new('sha256')
50
+ calculated_hmac = Base64.encode64(OpenSSL::HMAC.digest(digest, VERIFIER_TOKEN, data)).strip
51
+ calculated_hmac == hmac_header
52
+ end
53
+ end
54
+ end
@@ -0,0 +1,62 @@
1
+ require 'bundler/inline'
2
+
3
+ require File.expand_path(File.join('..', 'base'), __FILE__)
4
+
5
+ install_gems = true
6
+ gemfile(install_gems) do
7
+ source 'https://rubygems.org'
8
+
9
+ instance_eval(&BASE_GEMS)
10
+
11
+ gem 'omniauth'
12
+ gem 'omniauth-quickbooks'
13
+ end
14
+
15
+ instance_eval(&BASE_SETUP)
16
+
17
+ class OAuthApp < Sinatra::Base
18
+ instance_eval(&BASE_APP_CONFIG)
19
+
20
+ CONSUMER_KEY = ENV['QBO_API_CONSUMER_KEY']
21
+ CONSUMER_SECRET = ENV['QBO_API_CONSUMER_SECRET']
22
+
23
+ use Rack::Session::Cookie, secret: '34233adasf/qewrq453agqr9(lasfa)'
24
+ use OmniAuth::Builder do
25
+ provider :quickbooks, CONSUMER_KEY, CONSUMER_SECRET
26
+ end
27
+
28
+ get '/' do
29
+ @app_center = QboApi::APP_CENTER_BASE
30
+ @auth_data = oauth_data
31
+ @port = PORT
32
+ erb :index
33
+ end
34
+
35
+ get '/customer/:id' do
36
+ if session[:token]
37
+ api = QboApi.new(oauth_data)
38
+ @resp = api.get :customer, params[:id]
39
+ end
40
+ erb :customer
41
+ end
42
+
43
+ get '/auth/quickbooks/callback' do
44
+ auth = env["omniauth.auth"][:credentials]
45
+ session[:token] = auth[:token]
46
+ session[:secret] = auth[:secret]
47
+ session[:realm_id] = params['realmId']
48
+ '<!DOCTYPE html><html lang="en"><head></head><body><script>window.opener.location.reload(); window.close();</script></body></html>'
49
+ end
50
+
51
+ def oauth_data
52
+ {
53
+ consumer_key: CONSUMER_KEY,
54
+ consumer_secret: CONSUMER_SECRET,
55
+ token: session[:token],
56
+ token_secret: session[:secret],
57
+ realm_id: session[:realm_id]
58
+ }
59
+ end
60
+ end
61
+
62
+ OAuthApp.run!
@@ -0,0 +1,69 @@
1
+ require 'bundler/inline'
2
+
3
+ require File.expand_path(File.join('..', 'base'), __FILE__)
4
+
5
+ install_gems = true
6
+ gemfile(install_gems) do
7
+ source 'https://rubygems.org'
8
+
9
+ instance_eval(&BASE_GEMS)
10
+
11
+ gem 'rack-oauth2'
12
+ end
13
+
14
+ instance_eval(&BASE_SETUP)
15
+
16
+ class OAuth2App < Sinatra::Base
17
+ instance_eval(&BASE_APP_CONFIG)
18
+
19
+ CLIENT_ID = ENV['QBO_API_CLIENT_ID']
20
+ CLIENT_SECRET = ENV['QBO_API_CLIENT_SECRET']
21
+
22
+ helpers do
23
+ def oauth2_client
24
+ client = Rack::OAuth2::Client.new(
25
+ identifier: CLIENT_ID,
26
+ secret: CLIENT_SECRET,
27
+ redirect_uri: "http://localhost:#{PORT}/oauth2-redirect",
28
+ authorization_endpoint: "https://appcenter.intuit.com/connect/oauth2",
29
+ token_endpoint: "https://oauth.platform.intuit.com/oauth2/v1/tokens/bearer"
30
+ )
31
+ end
32
+ end
33
+
34
+ get '/oauth2' do
35
+ session[:state] = SecureRandom.uuid
36
+ @client = oauth2_client
37
+ erb :oauth2
38
+ end
39
+
40
+ get '/oauth2-redirect' do
41
+ state = params[:state]
42
+ error = params[:error]
43
+ code = params[:code]
44
+ if state == session[:state]
45
+ client = oauth2_client
46
+ client.authorization_code = code
47
+ if resp = client.access_token!
48
+ session[:refresh_token] = resp.refresh_token
49
+ session[:access_token] = resp.access_token
50
+ session[:realm_id] = params[:realmId]
51
+ erb :oauth2_redirect
52
+ else
53
+ "Something went wrong. Try the process again"
54
+ end
55
+ else
56
+ "Error: #{error}"
57
+ end
58
+ end
59
+
60
+ get '/oauth2/customer/:id' do
61
+ if access_token = session[:access_token]
62
+ api = QboApi.new(access_token: access_token, realm_id: session[:realm_id])
63
+ @resp = api.get :customer, params[:id]
64
+ end
65
+ erb :customer
66
+ end
67
+ end
68
+
69
+ OAuth2App.run!
@@ -21,6 +21,5 @@
21
21
  <% end %>
22
22
 
23
23
  <ipp:connectToIntuit></ipp:connectToIntuit>
24
- <p><a href="/oauth2">OAuth2 Connect Page</a></p>
25
24
  </body>
26
25
  </html>
@@ -1,3 +1,3 @@
1
1
  class QboApi
2
- VERSION = "1.8.2"
2
+ VERSION = "1.8.3"
3
3
  end
@@ -22,12 +22,7 @@ Gem::Specification.new do |spec|
22
22
  spec.add_development_dependency "rake", "~> 10.0"
23
23
  spec.add_development_dependency "rspec"
24
24
  spec.add_development_dependency 'webmock'
25
- spec.add_development_dependency 'sinatra'
26
- spec.add_development_dependency 'rack-oauth2'
27
25
  spec.add_development_dependency 'simple_oauth'
28
- spec.add_development_dependency 'omniauth'
29
- spec.add_development_dependency 'omniauth-quickbooks'
30
- spec.add_development_dependency 'shotgun'
31
26
  spec.add_development_dependency 'dotenv'
32
27
  spec.add_development_dependency 'vcr'
33
28
  spec.add_development_dependency 'awesome_print'
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: qbo_api
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.8.2
4
+ version: 1.8.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Christian Pelczarski
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2018-04-03 00:00:00.000000000 Z
11
+ date: 2018-04-12 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -66,34 +66,6 @@ dependencies:
66
66
  - - ">="
67
67
  - !ruby/object:Gem::Version
68
68
  version: '0'
69
- - !ruby/object:Gem::Dependency
70
- name: sinatra
71
- requirement: !ruby/object:Gem::Requirement
72
- requirements:
73
- - - ">="
74
- - !ruby/object:Gem::Version
75
- version: '0'
76
- type: :development
77
- prerelease: false
78
- version_requirements: !ruby/object:Gem::Requirement
79
- requirements:
80
- - - ">="
81
- - !ruby/object:Gem::Version
82
- version: '0'
83
- - !ruby/object:Gem::Dependency
84
- name: rack-oauth2
85
- requirement: !ruby/object:Gem::Requirement
86
- requirements:
87
- - - ">="
88
- - !ruby/object:Gem::Version
89
- version: '0'
90
- type: :development
91
- prerelease: false
92
- version_requirements: !ruby/object:Gem::Requirement
93
- requirements:
94
- - - ">="
95
- - !ruby/object:Gem::Version
96
- version: '0'
97
69
  - !ruby/object:Gem::Dependency
98
70
  name: simple_oauth
99
71
  requirement: !ruby/object:Gem::Requirement
@@ -108,48 +80,6 @@ dependencies:
108
80
  - - ">="
109
81
  - !ruby/object:Gem::Version
110
82
  version: '0'
111
- - !ruby/object:Gem::Dependency
112
- name: omniauth
113
- requirement: !ruby/object:Gem::Requirement
114
- requirements:
115
- - - ">="
116
- - !ruby/object:Gem::Version
117
- version: '0'
118
- type: :development
119
- prerelease: false
120
- version_requirements: !ruby/object:Gem::Requirement
121
- requirements:
122
- - - ">="
123
- - !ruby/object:Gem::Version
124
- version: '0'
125
- - !ruby/object:Gem::Dependency
126
- name: omniauth-quickbooks
127
- requirement: !ruby/object:Gem::Requirement
128
- requirements:
129
- - - ">="
130
- - !ruby/object:Gem::Version
131
- version: '0'
132
- type: :development
133
- prerelease: false
134
- version_requirements: !ruby/object:Gem::Requirement
135
- requirements:
136
- - - ">="
137
- - !ruby/object:Gem::Version
138
- version: '0'
139
- - !ruby/object:Gem::Dependency
140
- name: shotgun
141
- requirement: !ruby/object:Gem::Requirement
142
- requirements:
143
- - - ">="
144
- - !ruby/object:Gem::Version
145
- version: '0'
146
- type: :development
147
- prerelease: false
148
- version_requirements: !ruby/object:Gem::Requirement
149
- requirements:
150
- - - ">="
151
- - !ruby/object:Gem::Version
152
- version: '0'
153
83
  - !ruby/object:Gem::Dependency
154
84
  name: dotenv
155
85
  requirement: !ruby/object:Gem::Requirement
@@ -266,7 +196,9 @@ files:
266
196
  - Rakefile
267
197
  - bin/console
268
198
  - bin/setup
269
- - example/app.rb
199
+ - example/base.rb
200
+ - example/oauth.rb
201
+ - example/oauth2.rb
270
202
  - example/views/customer.erb
271
203
  - example/views/index.erb
272
204
  - example/views/oauth2.erb
@@ -1,118 +0,0 @@
1
- require "bundler/setup"
2
- require 'sinatra'
3
- require 'json'
4
- require 'openssl'
5
- require 'base64'
6
- require 'omniauth'
7
- require 'omniauth-quickbooks'
8
- require 'dotenv'
9
- require 'rack/oauth2'
10
- require 'qbo_api'
11
-
12
- Dotenv.load "#{__dir__}/../.env"
13
-
14
- PORT = ENV.fetch("PORT", 9393)
15
- CONSUMER_KEY = ENV['QBO_API_CONSUMER_KEY']
16
- CONSUMER_SECRET = ENV['QBO_API_CONSUMER_SECRET']
17
- CLIENT_ID = ENV['QBO_API_CLIENT_ID']
18
- CLIENT_SECRET = ENV['QBO_API_CLIENT_SECRET']
19
- VERIFIER_TOKEN = ENV['QBO_API_VERIFIER_TOKEN']
20
-
21
- set :port, PORT
22
- use Rack::Session::Cookie, secret: '34233adasf/qewrq453agqr9(lasfa)'
23
- use OmniAuth::Builder do
24
- provider :quickbooks, CONSUMER_KEY, CONSUMER_SECRET
25
- end
26
-
27
- helpers do
28
- def verify_webhook(data, hmac_header)
29
- digest = OpenSSL::Digest.new('sha256')
30
- calculated_hmac = Base64.encode64(OpenSSL::HMAC.digest(digest, VERIFIER_TOKEN, data)).strip
31
- calculated_hmac == hmac_header
32
- end
33
-
34
- def oauth2_client
35
- client = Rack::OAuth2::Client.new(
36
- identifier: CLIENT_ID,
37
- secret: CLIENT_SECRET,
38
- redirect_uri: "http://localhost:#{PORT}/oauth2-redirect",
39
- authorization_endpoint: "https://appcenter.intuit.com/connect/oauth2",
40
- token_endpoint: "https://oauth.platform.intuit.com/oauth2/v1/tokens/bearer"
41
- )
42
- end
43
- end
44
-
45
- get '/' do
46
- @app_center = QboApi::APP_CENTER_BASE
47
- @auth_data = oauth_data
48
- @port = PORT
49
- erb :index
50
- end
51
-
52
- get '/oauth2' do
53
- session[:state] = SecureRandom.uuid
54
- @client = oauth2_client
55
- erb :oauth2
56
- end
57
-
58
- get '/oauth2-redirect' do
59
- state = params[:state]
60
- error = params[:error]
61
- code = params[:code]
62
- if state == session[:state]
63
- client = oauth2_client
64
- client.authorization_code = code
65
- if resp = client.access_token!
66
- session[:refresh_token] = resp.refresh_token
67
- session[:access_token] = resp.access_token
68
- session[:realm_id] = params[:realmId]
69
- erb :oauth2_redirect
70
- else
71
- "Something went wrong. Try the process again"
72
- end
73
- else
74
- "Error: #{error}"
75
- end
76
- end
77
-
78
- get '/oauth2/customer/:id' do
79
- if access_token = session[:access_token]
80
- api = QboApi.new(access_token: access_token, realm_id: session[:realm_id])
81
- @resp = api.get :customer, params[:id]
82
- end
83
- erb :customer
84
- end
85
-
86
- get '/customer/:id' do
87
- if session[:token]
88
- api = QboApi.new(oauth_data)
89
- @resp = api.get :customer, params[:id]
90
- end
91
- erb :customer
92
- end
93
-
94
- post '/webhooks' do
95
- request.body.rewind
96
- data = request.body.read
97
- puts JSON.parse data
98
- verified = verify_webhook(data, env['HTTP_INTUIT_SIGNATURE'])
99
- puts "Verified: #{verified}"
100
- end
101
-
102
- def oauth_data
103
- {
104
- consumer_key: CONSUMER_KEY,
105
- consumer_secret: CONSUMER_SECRET,
106
- token: session[:token],
107
- token_secret: session[:secret],
108
- realm_id: session[:realm_id]
109
- }
110
- end
111
-
112
- get '/auth/quickbooks/callback' do
113
- auth = env["omniauth.auth"][:credentials]
114
- session[:token] = auth[:token]
115
- session[:secret] = auth[:secret]
116
- session[:realm_id] = params['realmId']
117
- '<!DOCTYPE html><html lang="en"><head></head><body><script>window.opener.location.reload(); window.close();</script></body></html>'
118
- end