net_tcp_client 2.0.1 → 2.2.1

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.
metadata CHANGED
@@ -1,19 +1,18 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: net_tcp_client
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.0.1
4
+ version: 2.2.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Reid Morrison
8
- autorequire:
8
+ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2016-06-04 00:00:00.000000000 Z
11
+ date: 2023-03-25 00:00:00.000000000 Z
12
12
  dependencies: []
13
13
  description: Net::TCPClient implements resilience features that many developers wish
14
14
  was already included in the standard Ruby libraries.
15
15
  email:
16
- - reidmo@gmail.com
17
16
  executables: []
18
17
  extensions: []
19
18
  extra_rdoc_files: []
@@ -31,21 +30,12 @@ files:
31
30
  - lib/net/tcp_client/tcp_client.rb
32
31
  - lib/net/tcp_client/version.rb
33
32
  - lib/net_tcp_client.rb
34
- - test/address_test.rb
35
- - test/policy/custom_policy_test.rb
36
- - test/policy/ordered_policy_test.rb
37
- - test/policy/random_policy_test.rb
38
- - test/simple_tcp_server.rb
39
- - test/ssl_files/ca.pem
40
- - test/ssl_files/localhost-server-key.pem
41
- - test/ssl_files/localhost-server.pem
42
- - test/tcp_client_test.rb
43
- - test/test_helper.rb
44
- homepage: https://github.com/rocketjob/net_tcp_client
33
+ homepage: https://github.com/reidmorrison/net_tcp_client
45
34
  licenses:
46
35
  - Apache-2.0
47
- metadata: {}
48
- post_install_message:
36
+ metadata:
37
+ rubygems_mfa_required: 'true'
38
+ post_install_message:
49
39
  rdoc_options: []
50
40
  require_paths:
51
41
  - lib
@@ -53,27 +43,16 @@ required_ruby_version: !ruby/object:Gem::Requirement
53
43
  requirements:
54
44
  - - ">="
55
45
  - !ruby/object:Gem::Version
56
- version: '0'
46
+ version: '2.3'
57
47
  required_rubygems_version: !ruby/object:Gem::Requirement
58
48
  requirements:
59
49
  - - ">="
60
50
  - !ruby/object:Gem::Version
61
51
  version: '0'
62
52
  requirements: []
63
- rubyforge_project:
64
- rubygems_version: 2.5.1
65
- signing_key:
53
+ rubygems_version: 3.3.7
54
+ signing_key:
66
55
  specification_version: 4
67
56
  summary: Net::TCPClient is a TCP Socket Client with built-in timeouts, retries, and
68
57
  logging
69
- test_files:
70
- - test/address_test.rb
71
- - test/policy/custom_policy_test.rb
72
- - test/policy/ordered_policy_test.rb
73
- - test/policy/random_policy_test.rb
74
- - test/simple_tcp_server.rb
75
- - test/ssl_files/ca.pem
76
- - test/ssl_files/localhost-server-key.pem
77
- - test/ssl_files/localhost-server.pem
78
- - test/tcp_client_test.rb
79
- - test/test_helper.rb
58
+ test_files: []
data/test/address_test.rb DELETED
@@ -1,91 +0,0 @@
1
- require_relative 'test_helper'
2
- require 'ipaddr'
3
-
4
- class Net::TCPClient::AddressTest < Minitest::Test
5
- describe Net::TCPClient::Address do
6
- describe '.ip_addresses' do
7
- it 'returns the ip addresses for a known DNS' do
8
- ips = Net::TCPClient::Address.ip_addresses('google.com')
9
- assert ips.count > 0
10
- ips.each do |ip|
11
- # Validate IP Addresses
12
- IPAddr.new(ip)
13
- end
14
- end
15
-
16
- it 'returns an ip address' do
17
- ips = Net::TCPClient::Address.ip_addresses('127.0.0.1')
18
- assert_equal 1, ips.count
19
- assert_equal '127.0.0.1', ips.first
20
- end
21
- end
22
-
23
- describe '.addresses' do
24
- it 'returns one address for a known DNS' do
25
- addresses = Net::TCPClient::Address.addresses('localhost', 80)
26
- assert_equal 1, addresses.count, addresses.ai
27
- address = addresses.first
28
- assert_equal 80, address.port
29
- assert_equal '127.0.0.1', address.ip_address
30
- assert_equal 'localhost', address.host_name
31
- end
32
-
33
- it 'returns addresses for a DNS with mutiple IPs' do
34
- addresses = Net::TCPClient::Address.addresses('google.com', 80)
35
- assert addresses.count > 0
36
- addresses.each do |address|
37
- # Validate IP Addresses
38
- IPAddr.new(address.ip_address)
39
- assert_equal 80, address.port
40
- assert_equal 'google.com', address.host_name
41
- end
42
- end
43
-
44
- it 'returns an ip address' do
45
- addresses = Net::TCPClient::Address.addresses('127.0.0.1', 80)
46
- assert_equal 1, addresses.count
47
- address = addresses.first
48
- assert_equal 80, address.port
49
- assert_equal '127.0.0.1', address.ip_address
50
- assert_equal '127.0.0.1', address.host_name
51
- end
52
- end
53
-
54
- describe '.addresses_for_server_name' do
55
- it 'returns addresses for server name' do
56
- addresses = Net::TCPClient::Address.addresses_for_server_name('localhost:80')
57
- assert_equal 1, addresses.count, addresses.ai
58
- address = addresses.first
59
- assert_equal 80, address.port
60
- assert_equal '127.0.0.1', address.ip_address
61
- assert_equal 'localhost', address.host_name
62
- end
63
-
64
- it 'returns an ip address' do
65
- addresses = Net::TCPClient::Address.addresses_for_server_name('127.0.0.1:80')
66
- assert_equal 1, addresses.count
67
- address = addresses.first
68
- assert_equal 80, address.port
69
- assert_equal '127.0.0.1', address.ip_address
70
- assert_equal '127.0.0.1', address.host_name
71
- end
72
- end
73
-
74
- describe '.new' do
75
- it 'creates an address' do
76
- address = Net::TCPClient::Address.new('host_name', 'ip_address', '2000')
77
- assert_equal 'host_name', address.host_name
78
- assert_equal 'ip_address', address.ip_address
79
- assert_equal 2000, address.port
80
- end
81
- end
82
-
83
- describe '#to_s' do
84
- it 'returns a string of the address' do
85
- address = Net::TCPClient::Address.new('host_name', 'ip_address', '2000')
86
- assert_equal 'host_name[ip_address]:2000', address.to_s
87
- end
88
- end
89
-
90
- end
91
- end
@@ -1,42 +0,0 @@
1
- require_relative '../test_helper'
2
- class Net::TCPClient::Policy::CustomTest < Minitest::Test
3
- describe Net::TCPClient::Policy::Custom do
4
- describe '#each' do
5
- before do
6
- @proc = -> addresses, count do
7
- addresses[count - 1]
8
- end
9
- end
10
-
11
- it 'must return one server, once' do
12
- servers = ['localhost:80']
13
- policy = Net::TCPClient::Policy::Custom.new(servers, @proc)
14
- collected = []
15
- policy.each { |address| collected << address }
16
- assert_equal 1, collected.size
17
- address = collected.first
18
- assert_equal 80, address.port
19
- assert_equal 'localhost', address.host_name
20
- assert_equal '127.0.0.1', address.ip_address
21
- end
22
-
23
- it 'must return the servers in the supplied order' do
24
- servers = %w(localhost:80 127.0.0.1:2000 lvh.me:2100)
25
- policy = Net::TCPClient::Policy::Custom.new(servers, @proc)
26
- names = []
27
- policy.each { |address| names << address.host_name }
28
- assert_equal %w(localhost 127.0.0.1 lvh.me), names
29
- end
30
-
31
- it 'must handle an empty list of servers' do
32
- servers = []
33
- policy = Net::TCPClient::Policy::Custom.new(servers, @proc)
34
- names = []
35
- policy.each { |address| names << address.host_name }
36
- assert_equal [], names
37
- end
38
- end
39
-
40
- end
41
- end
42
-
@@ -1,36 +0,0 @@
1
- require_relative '../test_helper'
2
- class Net::TCPClient::Policy::OrderedTest < Minitest::Test
3
- describe Net::TCPClient::Policy::Ordered do
4
- describe '#each' do
5
- it 'must return one server, once' do
6
- servers = ['localhost:80']
7
- policy = Net::TCPClient::Policy::Ordered.new(servers)
8
- collected = []
9
- policy.each { |address| collected << address }
10
- assert_equal 1, collected.size
11
- address = collected.first
12
- assert_equal 80, address.port
13
- assert_equal 'localhost', address.host_name
14
- assert_equal '127.0.0.1', address.ip_address
15
- end
16
-
17
- it 'must return the servers in the supplied order' do
18
- servers = %w(localhost:80 127.0.0.1:2000 lvh.me:2100)
19
- policy = Net::TCPClient::Policy::Ordered.new(servers)
20
- names = []
21
- policy.each { |address| names << address.host_name }
22
- assert_equal %w(localhost 127.0.0.1 lvh.me), names
23
- end
24
-
25
- it 'must handle an empty list of servers' do
26
- servers = []
27
- policy = Net::TCPClient::Policy::Ordered.new(servers)
28
- names = []
29
- policy.each { |address| names << address.host_name }
30
- assert_equal [], names
31
- end
32
- end
33
-
34
- end
35
- end
36
-
@@ -1,46 +0,0 @@
1
- require_relative '../test_helper'
2
- class Net::TCPClient::Policy::RandomTest < Minitest::Test
3
- describe Net::TCPClient::Policy::Random do
4
- describe '#each' do
5
- it 'must return one server, once' do
6
- servers = ['localhost:80']
7
- policy = Net::TCPClient::Policy::Random.new(servers)
8
- collected = []
9
- policy.each { |address| collected << address }
10
- assert_equal 1, collected.size
11
- address = collected.first
12
- assert_equal 80, address.port
13
- assert_equal 'localhost', address.host_name
14
- assert_equal '127.0.0.1', address.ip_address
15
- end
16
-
17
- it 'must return the servers in random order' do
18
- servers = %w(localhost:80 127.0.0.1:2000 lvh.me:2100)
19
- policy = Net::TCPClient::Policy::Random.new(servers)
20
- count = 0
21
-
22
- names = []
23
- # It is possible the random order is the supplied order.
24
- # Keep retrying until the order is different.
25
- 3.times do
26
- policy.each { |address| names << address.host_name }
27
- break if names != %w(localhost:80 127.0.0.1:2000 lvh.me:2100)
28
- names = []
29
- end
30
-
31
- refute_equal %w(localhost 127.0.0.1 lvh.me), names
32
- assert_equal %w(localhost 127.0.0.1 lvh.me).sort, names.sort
33
- end
34
-
35
- it 'must handle an empty list of servers' do
36
- servers = []
37
- policy = Net::TCPClient::Policy::Random.new(servers)
38
- names = []
39
- policy.each { |address| names << address.host_name }
40
- assert_equal [], names
41
- end
42
- end
43
-
44
- end
45
- end
46
-
@@ -1,140 +0,0 @@
1
- require 'socket'
2
- require 'openssl'
3
- require 'bson'
4
- require 'semantic_logger'
5
-
6
- # Read the bson document, returning nil if the IO is closed
7
- # before receiving any data or a complete BSON document
8
- def read_bson_document(io)
9
- bytebuf = BSON::ByteBuffer.new
10
- # Read 4 byte size of following BSON document
11
- bytes = io.read(4)
12
- return unless bytes
13
- # Read BSON document
14
- sz = bytes.unpack("V")[0]
15
- bytebuf.append!(bytes)
16
- bytes = io.read(sz-4)
17
- return unless bytes
18
- bytebuf.append!(bytes)
19
- return BSON.deserialize(bytebuf)
20
- end
21
-
22
- def ssl_file_path(name)
23
- File.join(File.dirname(__FILE__), 'ssl_files', name)
24
- end
25
-
26
- # Simple single threaded server for testing purposes using a local socket
27
- # Sends and receives BSON Messages
28
- class SimpleTCPServer
29
- include SemanticLogger::Loggable
30
- attr_accessor :thread, :server
31
- attr_reader :port, :name, :ssl
32
-
33
- def initialize(options = {})
34
- @port = (options[:port] || 2000).to_i
35
- @name = options[:name] || 'tcp'
36
- @ssl = options[:ssl] || false
37
- start
38
- end
39
-
40
- def start
41
- tcp_server = TCPServer.open(port)
42
-
43
- if ssl
44
- context = OpenSSL::SSL::SSLContext.new
45
- context.set_params(ssl)
46
- tcp_server = OpenSSL::SSL::SSLServer.new(tcp_server, context)
47
- end
48
-
49
- self.server = tcp_server
50
- self.thread = Thread.new do
51
- loop do
52
- logger.debug 'Waiting for a client to connect'
53
-
54
- # Wait for a client to connect
55
- on_request(server.accept)
56
- end
57
- end
58
- end
59
-
60
- def stop
61
- if thread
62
- thread.kill
63
- thread.join
64
- self.thread = nil
65
- end
66
- begin
67
- server.close if server
68
- rescue IOError
69
- end
70
- end
71
-
72
- # Called for each message received from the client
73
- # Returns a Hash that is sent back to the caller
74
- def on_message(message)
75
- case message['action']
76
- when 'test1'
77
- {'result' => 'test1'}
78
- when 'servername'
79
- {'result' => @name}
80
- when 'sleep'
81
- sleep message['duration'] || 1
82
- {'result' => 'sleep'}
83
- when 'fail'
84
- if message['attempt'].to_i >= 2
85
- {'result' => 'fail'}
86
- else
87
- nil
88
- end
89
- else
90
- {'result' => "Unknown action: #{message['action']}"}
91
- end
92
- end
93
-
94
- # Called for each client connection
95
- # In a real server each request would be handled in a separate thread
96
- def on_request(client)
97
- logger.debug 'Client connected, waiting for data from client'
98
-
99
- while (request = read_bson_document(client)) do
100
- logger.debug 'Received request', request
101
- break unless request
102
-
103
- if reply = on_message(request)
104
- logger.debug 'Sending Reply'
105
- logger.trace 'Reply', reply
106
- client.print(BSON.serialize(reply))
107
- else
108
- logger.debug 'Closing client since no reply is being sent back'
109
- server.close
110
- client.close
111
- logger.debug 'Server closed'
112
- start
113
- logger.debug 'Server Restarted'
114
- break
115
- end
116
- end
117
- # Disconnect from the client
118
- client.close
119
- logger.debug 'Disconnected from the client'
120
- end
121
-
122
- end
123
-
124
- if $0 == __FILE__
125
- SemanticLogger.default_level = :trace
126
- SemanticLogger.add_appender(STDOUT)
127
- server = SimpleTCPServer.new(port: 2000)
128
-
129
- # For SSL:
130
- # server = SimpleTCPServer.new(
131
- # port: 2000,
132
- # ssl: {
133
- # cert: ssl_file_path('localhost-server.pem'),
134
- # key: ssl_file_path('localhost-server-key.pem'),
135
- # ca_file: ssl_file_path('ca.pem')
136
- # }
137
- # )
138
-
139
- server.thread.join
140
- end
@@ -1,19 +0,0 @@
1
- -----BEGIN CERTIFICATE-----
2
- MIIDCzCCAfOgAwIBAgIJANF9v1dJ6jhOMA0GCSqGSIb3DQEBBQUAMBwxGjAYBgNV
3
- BAMMEXRlc3QtdG1nYXJkbmVyLWNhMB4XDTE1MTEwNjA0NDk0NVoXDTE1MTIwNjA0
4
- NDk0NVowHDEaMBgGA1UEAwwRdGVzdC10bWdhcmRuZXItY2EwggEiMA0GCSqGSIb3
5
- DQEBAQUAA4IBDwAwggEKAoIBAQDIi3qxxegV2RYl8lEWu/iwb9tqsdEYQ1gAhdAS
6
- OJAJk8SfgvjlKnyx0rV2LXhORpp13uLMB5QKXS1B+JByCYEZrC3q9b9Cl58Nl4am
7
- ky6uI/AXvbEvzSAo2resea5JGpQDxl3UJC674QdVCGR7s7Wm7am/JEr8aami4V5O
8
- +CmLfdr030jPaNVcqVS2Bf0AqrxNa3nWoHsPh1MG2VJRVpnqIuqPVL7yRi39/cu2
9
- Kd1WjJPxpbrM8H2AClX2OY6fxa3RHUUyOaveOkX5AWYXtqoMs9Evv95m4hOVAogd
10
- KzBjdtpTiIM+bdlpxY0y2Dpc9oibRFiLFqooB9Bb8VsmE/2JAgMBAAGjUDBOMB0G
11
- A1UdDgQWBBQo+GvUH8j+YFYkWtwQl32d4fVoZTAfBgNVHSMEGDAWgBQo+GvUH8j+
12
- YFYkWtwQl32d4fVoZTAMBgNVHRMEBTADAQH/MA0GCSqGSIb3DQEBBQUAA4IBAQAH
13
- RvaXH9dN3fiRvMZ8+tXY7W57jspvYtQJjNxcVGU+Pn5fznrr0E3STPoSKy6+u9rQ
14
- L0Jzq9e0tjbMmdbMugRjSOdVUGtXaki/YaGNkbKOsMLHWSgFHVZF3gJ83KdDuuFK
15
- bMTqOmrQvCG+JECH3i/lh5GHLuZlCzOmBwhzWuorjQQy/MUxQHRkHPVk4Ik7pCXm
16
- HsNcp9l2L5oKG8I4X54ElGXHoshdIXKUS6yKcnTJlhI2nt6cQCMzKoiVA5TxNnvz
17
- jdCID4nezuHFyYI3KVxsR7PzqS2fmHcfC9qGqskn+QgJ4JcwvAhT3USj4muuu3mJ
18
- /F9cJiBN2yeRQuknI6de
19
- -----END CERTIFICATE-----
@@ -1,27 +0,0 @@
1
- -----BEGIN RSA PRIVATE KEY-----
2
- MIIEogIBAAKCAQEApAeEPJjQwT10hLgBl8550gJeBuP43R8sDO63H2Q2QsgN0sLg
3
- G0fzjR8qNjYf62XwADMsCE9PwheaVSM+sREbEGu80G3IICTFP5HPuqm6ugiuYZpD
4
- BtZgiSFM1A7ShSTR0gCWqusRaR+r/IOREftvQcjqeJP0hZxYjx4XO9jBufiQMpGq
5
- qPaUQC3cXv4aDoLYbHAP+XH4FxwAbEz9/qBTeAiNorL2ruFJeqMHlKPIDt6123LF
6
- kMZ8pxke8gqmggieKH549j8VHUSpwo2TbxSIqArM8P6wDRFrZik6ZMEIX13yuet2
7
- XaFMyHLMknyh2+0vKz9sup533rk7fKUKhTtJ/QIDAQABAoIBAAnOYTt2L1S+Jc8h
8
- aQb4UxQZDCIBUwl1KZ8ETnJT/WJ0r07gU6GN5aOUL2PaTII4L+bzKDi+9Re3bYSV
9
- fNP9H88Vgc48IfC6AgjQ4MhaCU3B4xr2q/cmrdLE6ODsme1XzCtv2ZISR5IvUIri
10
- GrQmgfo+1rWqsr2iITE9LUpopPxHJV29DIVc5EuP/c+r4TFarUFd+1JdthABE3v7
11
- xMgyejnLs59Dy084RcL60mpCahvIBXdKEMY8nzhN3APp7VHx/++yTvsvcG+aNVrr
12
- C/FixbUnQWIHCeu8lvFz6fb+mMt923ZE2mcbdmOzgZqjEQYaPxfERRDTHNz9NlPQ
13
- 2Jahz0ECgYEA2JGdlD26KsYYBvFtNCsxw78DfonLolwcWK0pwKDtXb/3h8RWjBlu
14
- vmCmhE726nVl00nt2FUoGpHwcVDPwjdxFkStaSezGxEJQHEov9ZjSYJY9IdpDOhL
15
- Q8nz2geDL8P2Ti6pOCKPqgwgbgOsIgTYwreFG1KemsHIH2HeQZxFllkCgYEAweUC
16
- k3OjR1cLa5mgABLkcl8RDEBoPAFcNZg+gGgSMneEDvP2DqZ2h8CxzdG1d2VSpTHD
17
- IC2LeF5EwNq7h6X7Har0j+e9h1/TESqvx60ph89AxecjsEqjOBKto5rBMTOaah9M
18
- IXvk+fP/bwOY+6W7F4KJQk6BYw1i2FiCzivXZEUCgYAg5YWdNf8obizKKTQgX4tQ
19
- o5xBRWckQ3+ezLbx5sAHpJhSDDXlVBupWX8Ry/jfxnNwM+OoH89WseJnJBJa+xb3
20
- ffklZv1i2CSioE3DTiqIyP8ALe18I3EDXBLphIid4dNxLs9PkphmCS+H5pDoHfpb
21
- IYtbiiJDeboPYktjhfxgCQKBgDW8dVlOPBtCaXzZp7k9gyibZksh8oFm0xpbZj8K
22
- GLj53JSUUkY/Jix7YAutqgA8CYqU3wIk/TlPzvgv5rcybgUL4xma3TEOgp2IWg0Z
23
- 1Z+49bejVoW+ObwJmSv1cMNlDM+KevvwrUYEtG8c7SIZDV/3onjI7xz3kcRpy16+
24
- UcSNAoGAe1sVhiyZczEZYgjKMedLvFoFaerw4Ik6PnGCi61nrQtsa3HpLd45M648
25
- j8/HAq7/nF+7grkPFJPFBjrx1B44k6vRZNK2hC6XexaVBgGxFktfqCfytalpL3AX
26
- QqQTsJcW63zEqaFJDhO0dv9oHJuSuYnHTERgVw7VwyLC+bEkYIk=
27
- -----END RSA PRIVATE KEY-----
@@ -1,18 +0,0 @@
1
- -----BEGIN CERTIFICATE-----
2
- MIIC+TCCAeGgAwIBAgIJANNH6Xe+/HxXMA0GCSqGSIb3DQEBBQUAMBwxGjAYBgNV
3
- BAMMEXRlc3QtdG1nYXJkbmVyLWNhMB4XDTE1MTEwNjA0NTMwMloXDTE1MTIwNjA0
4
- NTMwMlowKjEoMCYGA1UEAwwfdGVzdC10bWdhcmRuZXItbG9jYWxob3N0LXNlcnZl
5
- cjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKQHhDyY0ME9dIS4AZfO
6
- edICXgbj+N0fLAzutx9kNkLIDdLC4BtH840fKjY2H+tl8AAzLAhPT8IXmlUjPrER
7
- GxBrvNBtyCAkxT+Rz7qpuroIrmGaQwbWYIkhTNQO0oUk0dIAlqrrEWkfq/yDkRH7
8
- b0HI6niT9IWcWI8eFzvYwbn4kDKRqqj2lEAt3F7+Gg6C2GxwD/lx+BccAGxM/f6g
9
- U3gIjaKy9q7hSXqjB5SjyA7etdtyxZDGfKcZHvIKpoIInih+ePY/FR1EqcKNk28U
10
- iKgKzPD+sA0Ra2YpOmTBCF9d8rnrdl2hTMhyzJJ8odvtLys/bLqed965O3ylCoU7
11
- Sf0CAwEAAaMwMC4wCQYDVR0TBAIwADALBgNVHQ8EBAMCBeAwFAYDVR0RBA0wC4IJ
12
- bG9jYWxob3N0MA0GCSqGSIb3DQEBBQUAA4IBAQCR6ruCXgsTyeI+RtnhfVrWlsdF
13
- 69eQHxGeHLd882V7xN4XfIKtfpgMVp7UlXTS/Lgtw08x+2bPiPz8EPgXa0WoYRjg
14
- i5M/4lrK++YPMzIY4o8nJY7jRcwoWGzw3rQemrc4cjj7e9YnNLOSG/pww0ticV4F
15
- +85IjE9rRsO4m/yla+epJTZiqJ0lSnCCaeNyW4/f4bipgA6PfddmteaJFUt+c7wF
16
- N992bWpb8+x0ZXGg5+A6a0NVFMu2856WeVRwMKbNwfXObDYxCdHSOufcv9hsxL4j
17
- fiF/R2ts5QbxYSoG2gnRPYxmyn/fnNen3f1u6iY4f8PVmb+6SOu0DH4sDf49
18
- -----END CERTIFICATE-----