opsmgr-cgfrost 0.35.9
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/LEGAL.txt +13 -0
- data/README.md +123 -0
- data/lib/opsmgr.rb +12 -0
- data/lib/opsmgr/api/client.rb +116 -0
- data/lib/opsmgr/api/http_client.rb +399 -0
- data/lib/opsmgr/api/results.rb +280 -0
- data/lib/opsmgr/api/version20/endpoints.rb +121 -0
- data/lib/opsmgr/bosh_command_runner.rb +84 -0
- data/lib/opsmgr/cmd/bosh_command.rb +189 -0
- data/lib/opsmgr/cmd/ops_manager.rb +142 -0
- data/lib/opsmgr/environments.rb +106 -0
- data/lib/opsmgr/errand_runner.rb +62 -0
- data/lib/opsmgr/log.rb +70 -0
- data/lib/opsmgr/product_upload_wrapper.rb +71 -0
- data/lib/opsmgr/renderer.rb +23 -0
- data/lib/opsmgr/renderer/aws.rb +148 -0
- data/lib/opsmgr/renderer/noop.rb +21 -0
- data/lib/opsmgr/settings/microbosh/installation_settings.rb +84 -0
- data/lib/opsmgr/settings/microbosh/job.rb +56 -0
- data/lib/opsmgr/settings/microbosh/job_list.rb +27 -0
- data/lib/opsmgr/settings/microbosh/network.rb +21 -0
- data/lib/opsmgr/settings/microbosh/product.rb +90 -0
- data/lib/opsmgr/settings/microbosh/product_list.rb +27 -0
- data/lib/opsmgr/settings/microbosh/property.rb +33 -0
- data/lib/opsmgr/settings/microbosh/property_list.rb +27 -0
- data/lib/opsmgr/tasks.rb +16 -0
- data/lib/opsmgr/tasks/bosh.rake +104 -0
- data/lib/opsmgr/tasks/destroy.rake +42 -0
- data/lib/opsmgr/tasks/info.rake +19 -0
- data/lib/opsmgr/tasks/opsmgr.rake +205 -0
- data/lib/opsmgr/tasks/product.rake +82 -0
- data/lib/opsmgr/ui_helpers/add_first_user_spec.rb +25 -0
- data/lib/opsmgr/ui_helpers/config_helper.rb +38 -0
- data/lib/opsmgr/ui_helpers/delete_installation_spec.rb +41 -0
- data/lib/opsmgr/ui_helpers/delete_product_if_present_spec.rb +37 -0
- data/lib/opsmgr/ui_helpers/delete_product_spec.rb +39 -0
- data/lib/opsmgr/ui_helpers/export_installation_spec.rb +31 -0
- data/lib/opsmgr/ui_helpers/get_latest_install_log_spec.rb +29 -0
- data/lib/opsmgr/ui_helpers/import_stemcell_spec.rb +30 -0
- data/lib/opsmgr/ui_helpers/microbosh/configure_microbosh_spec.rb +32 -0
- data/lib/opsmgr/ui_helpers/post_import_configuration_spec.rb +31 -0
- data/lib/opsmgr/ui_helpers/revert_staged_changes_spec.rb +39 -0
- data/lib/opsmgr/ui_helpers/settings_helper.rb +132 -0
- data/lib/opsmgr/ui_helpers/trigger_install_spec.rb +35 -0
- data/lib/opsmgr/ui_helpers/ui_spec_runner.rb +122 -0
- data/lib/opsmgr/ui_helpers/uncheck_errands_spec.rb +29 -0
- data/lib/opsmgr/ui_helpers/upload_and_add_product_spec.rb +27 -0
- data/lib/opsmgr/ui_helpers/upload_and_upgrade_product_spec.rb +36 -0
- data/lib/opsmgr/version.rb +11 -0
- data/sample_env_files/aws.yml +95 -0
- data/sample_env_files/vsphere.yml +87 -0
- metadata +392 -0
@@ -0,0 +1,280 @@
|
|
1
|
+
require 'opsmgr/settings/microbosh/installation_settings'
|
2
|
+
require 'opsmgr/settings/microbosh/product_list'
|
3
|
+
require 'opsmgr/settings/microbosh/job_list'
|
4
|
+
require 'opsmgr/settings/microbosh/property_list'
|
5
|
+
|
6
|
+
module Opsmgr
|
7
|
+
module Api
|
8
|
+
class Result
|
9
|
+
attr_reader :message
|
10
|
+
|
11
|
+
def success?
|
12
|
+
true
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
class InstallStatusResult < Result
|
17
|
+
attr_reader :status
|
18
|
+
|
19
|
+
def initialize(status_hash)
|
20
|
+
@status = status_hash['status']
|
21
|
+
status.freeze
|
22
|
+
|
23
|
+
fail(ArgumentError, "Unrecognized status: #{status}") unless %w(failed success running).include?(status)
|
24
|
+
end
|
25
|
+
|
26
|
+
def failed?
|
27
|
+
@status == 'failed'
|
28
|
+
end
|
29
|
+
|
30
|
+
def pending?
|
31
|
+
@status == 'running'
|
32
|
+
end
|
33
|
+
|
34
|
+
def finished_successfully?
|
35
|
+
@status == 'success'
|
36
|
+
end
|
37
|
+
|
38
|
+
def finished?
|
39
|
+
failed? || finished_successfully?
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
class InstallationDeletionStatusResult < Result
|
44
|
+
NO_INSTALLATION = 'There is no installation.'.freeze
|
45
|
+
DELETE_IN_PROGRESS = 'Delete in progress'.freeze
|
46
|
+
|
47
|
+
attr_reader :status
|
48
|
+
|
49
|
+
def initialize(status_hash)
|
50
|
+
@status = status_hash['status']
|
51
|
+
end
|
52
|
+
|
53
|
+
def in_progress?
|
54
|
+
status == DELETE_IN_PROGRESS
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
class InstallLogResult < Result
|
59
|
+
attr_reader :log
|
60
|
+
|
61
|
+
def initialize(log_hash)
|
62
|
+
@log = log_hash['logs'].dup.freeze
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
class TriggerInstallResult < Result
|
67
|
+
attr_reader :install_id
|
68
|
+
|
69
|
+
def initialize(install_hash)
|
70
|
+
@install_id = install_hash['install']['id']
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
class ListProductsResult < Result
|
75
|
+
Product = Struct.new(:name, :product_version)
|
76
|
+
|
77
|
+
attr_reader :products
|
78
|
+
|
79
|
+
def initialize(product_hash_array)
|
80
|
+
@products = product_hash_array.map { |p| Product.new(p.fetch('name'), p.fetch('product_version')) }
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
class InstalledProductsResult < Result
|
85
|
+
def initialize(installed_products)
|
86
|
+
@installed_products = installed_products
|
87
|
+
end
|
88
|
+
|
89
|
+
def guid_for(product_type)
|
90
|
+
product_result = installed_products.find { |h| h.name == product_type }
|
91
|
+
product_result ? product_result.fetch('guid') : nil
|
92
|
+
end
|
93
|
+
|
94
|
+
private
|
95
|
+
|
96
|
+
attr_reader :installed_products
|
97
|
+
end
|
98
|
+
|
99
|
+
class InstallationSettingsResult < Result
|
100
|
+
def initialize(install_hash)
|
101
|
+
@install_hash = install_hash
|
102
|
+
end
|
103
|
+
|
104
|
+
def director_ip
|
105
|
+
ips_for_job(product_name: 'p-bosh', job_name: 'director').first ||
|
106
|
+
ips_for_job(product_name: 'microbosh', job_name: 'director').first
|
107
|
+
end
|
108
|
+
|
109
|
+
def ips_for_job(product_name:, job_name:)
|
110
|
+
product = products.find { |p| p.name == product_name }
|
111
|
+
return [] if product.nil?
|
112
|
+
|
113
|
+
if install_hash['ip_assignments']
|
114
|
+
install_hash['ip_assignments']['assignments'][product['guid']].each do |job_guid, assignment|
|
115
|
+
return assignment.values.flatten if job_guid.starts_with?(job_name)
|
116
|
+
end
|
117
|
+
else
|
118
|
+
product.fetch('ips').each do |job_guid, ips|
|
119
|
+
return ips if job_guid.starts_with?(job_name)
|
120
|
+
end
|
121
|
+
end
|
122
|
+
[]
|
123
|
+
end
|
124
|
+
|
125
|
+
def director_password
|
126
|
+
microbosh_jobs = microbosh_settings.fetch('jobs')
|
127
|
+
microbosh_job_list = Opsmgr::Settings::Microbosh::JobList.new(microbosh_jobs)
|
128
|
+
director_job = microbosh_job_list.find { |job| job.name == 'director' }
|
129
|
+
properties = director_job.fetch('properties')
|
130
|
+
property_list = Opsmgr::Settings::Microbosh::PropertyList.new(properties)
|
131
|
+
credential_property = property_list.find { |property| property.name == 'director_credentials' }
|
132
|
+
credential_property.fetch('value').fetch('password')
|
133
|
+
end
|
134
|
+
|
135
|
+
def uaa_admin_password
|
136
|
+
jobs = cf_settings.fetch('jobs')
|
137
|
+
job_list = Opsmgr::Settings::Microbosh::JobList.new(jobs)
|
138
|
+
uaa_job = job_list.find { |job| job.name == 'uaa' }
|
139
|
+
properties = uaa_job.fetch('properties')
|
140
|
+
property_list = Opsmgr::Settings::Microbosh::PropertyList.new(properties)
|
141
|
+
credential_property = property_list.find { |property| property.name == 'admin_credentials' }
|
142
|
+
credential_property.fetch('value').fetch('password')
|
143
|
+
end
|
144
|
+
|
145
|
+
def system_domain
|
146
|
+
properties = cc_job.fetch('properties')
|
147
|
+
property_list = Opsmgr::Settings::Microbosh::PropertyList.new(properties)
|
148
|
+
credential_property = property_list.find { |property| property.name == 'system_domain' }
|
149
|
+
credential_property.fetch('value')
|
150
|
+
end
|
151
|
+
|
152
|
+
def apps_domain
|
153
|
+
properties = cc_job.fetch('properties')
|
154
|
+
property_list = Opsmgr::Settings::Microbosh::PropertyList.new(properties)
|
155
|
+
credential_property = property_list.find { |property| property.name == 'apps_domain' }
|
156
|
+
credential_property.fetch('value')
|
157
|
+
end
|
158
|
+
|
159
|
+
def product_version(product_guid)
|
160
|
+
product = products.find { |p| p.guid == product_guid }
|
161
|
+
return nil if product.nil?
|
162
|
+
product.fetch('product_version')
|
163
|
+
end
|
164
|
+
|
165
|
+
def product_version_by_name(product_name)
|
166
|
+
product = products.find { |p| p.name == product_name }
|
167
|
+
return nil if product.nil?
|
168
|
+
product.fetch('product_version')
|
169
|
+
end
|
170
|
+
|
171
|
+
def ops_manager_installation_settings
|
172
|
+
Opsmgr::Settings::Microbosh::InstallationSettings.from_api_result(self)
|
173
|
+
end
|
174
|
+
|
175
|
+
def as_hash
|
176
|
+
install_hash
|
177
|
+
end
|
178
|
+
|
179
|
+
private
|
180
|
+
|
181
|
+
attr_reader :install_hash
|
182
|
+
|
183
|
+
def microbosh_settings
|
184
|
+
products.find { |product| product.name == 'p-bosh' || product.name == 'microbosh' } || fail('microbosh not found')
|
185
|
+
end
|
186
|
+
|
187
|
+
def cf_settings
|
188
|
+
products.find { |product| product.name == 'cf' } || fail('cf not found')
|
189
|
+
end
|
190
|
+
|
191
|
+
def products
|
192
|
+
if install_hash.key?('products')
|
193
|
+
Opsmgr::Settings::Microbosh::ProductList.new(install_hash.fetch('products'))
|
194
|
+
elsif install_hash.key?('components')
|
195
|
+
Opsmgr::Settings::Microbosh::ProductList.new(install_hash.fetch('components'))
|
196
|
+
else
|
197
|
+
fail "Unable to find products in OpsManager response. Check installation schema: #{install_hash.inspect}."
|
198
|
+
end
|
199
|
+
end
|
200
|
+
|
201
|
+
def cc_job
|
202
|
+
cf_settings.fetch('jobs')
|
203
|
+
cf_jobs = cf_settings.fetch('jobs')
|
204
|
+
cf_job_list = Opsmgr::Settings::Microbosh::JobList.new(cf_jobs)
|
205
|
+
cf_job_list.find { |job| job.name == 'cloud_controller' }
|
206
|
+
end
|
207
|
+
end
|
208
|
+
|
209
|
+
class ProductManifestResult < Result
|
210
|
+
Product = Struct.new(:name, :version)
|
211
|
+
Stemcell = Struct.new(:name, :version)
|
212
|
+
|
213
|
+
def initialize(manifest_hash)
|
214
|
+
@manifest_hash = manifest_hash
|
215
|
+
end
|
216
|
+
|
217
|
+
def releases
|
218
|
+
manifest_hash.fetch('releases').map { |h| Product.new(h.fetch('name'), h.fetch('version')) }
|
219
|
+
end
|
220
|
+
|
221
|
+
def stemcell
|
222
|
+
stemcell_hash = manifest_hash.fetch('resource_pools').first.fetch('stemcell')
|
223
|
+
Stemcell.new(stemcell_hash.fetch('name'), stemcell_hash.fetch('version'))
|
224
|
+
end
|
225
|
+
|
226
|
+
private
|
227
|
+
|
228
|
+
attr_reader :manifest_hash
|
229
|
+
end
|
230
|
+
|
231
|
+
class CreateFirstUserResult < Result
|
232
|
+
attr_reader :user_id
|
233
|
+
|
234
|
+
def initialize(user_hash)
|
235
|
+
@user_id = user_hash['user']['id']
|
236
|
+
end
|
237
|
+
|
238
|
+
def user_already_existed?
|
239
|
+
false
|
240
|
+
end
|
241
|
+
end
|
242
|
+
|
243
|
+
class StagedManifestResult < Result
|
244
|
+
attr_reader :manifest
|
245
|
+
|
246
|
+
def initialize(manifest)
|
247
|
+
@manifest = manifest
|
248
|
+
end
|
249
|
+
end
|
250
|
+
|
251
|
+
class Error < Result
|
252
|
+
def initialize(message, response)
|
253
|
+
@message = "#{message}:\n#{response.body}"
|
254
|
+
@response = response
|
255
|
+
end
|
256
|
+
|
257
|
+
def success?
|
258
|
+
false
|
259
|
+
end
|
260
|
+
|
261
|
+
private
|
262
|
+
|
263
|
+
attr_reader :response
|
264
|
+
end
|
265
|
+
|
266
|
+
class CreateFirstUserError < Error
|
267
|
+
def user_already_existed?
|
268
|
+
response.code == '401'
|
269
|
+
end
|
270
|
+
end
|
271
|
+
end
|
272
|
+
end
|
273
|
+
# Copyright (c) 2014-2015 Pivotal Software, Inc.
|
274
|
+
# All rights reserved.
|
275
|
+
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
|
276
|
+
# INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
|
277
|
+
# PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
278
|
+
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
279
|
+
# TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
|
280
|
+
# USE OR OTHER DEALINGS IN THE SOFTWARE.
|
@@ -0,0 +1,121 @@
|
|
1
|
+
module Opsmgr
|
2
|
+
module Api
|
3
|
+
module Version20
|
4
|
+
class Endpoints
|
5
|
+
VERSION = '2.0'.freeze
|
6
|
+
|
7
|
+
def version
|
8
|
+
VERSION
|
9
|
+
end
|
10
|
+
|
11
|
+
def installation_settings_post_path
|
12
|
+
'/api/installation_settings'
|
13
|
+
end
|
14
|
+
|
15
|
+
def installation_settings_get_path
|
16
|
+
'/api/installation_settings'
|
17
|
+
end
|
18
|
+
|
19
|
+
def install_post_path
|
20
|
+
'/api/installation?ignore_warnings=1'
|
21
|
+
end
|
22
|
+
|
23
|
+
def installation_path
|
24
|
+
'/api/installation'
|
25
|
+
end
|
26
|
+
|
27
|
+
def api_user_path
|
28
|
+
'/api/user'
|
29
|
+
end
|
30
|
+
|
31
|
+
def api_setup_path
|
32
|
+
'/api/setup'
|
33
|
+
end
|
34
|
+
|
35
|
+
def show_installation_status(id)
|
36
|
+
"/api/installation/#{id}"
|
37
|
+
end
|
38
|
+
|
39
|
+
def installation_log_path(id)
|
40
|
+
"/api/installation/#{id}/logs"
|
41
|
+
end
|
42
|
+
|
43
|
+
def upload_product_path
|
44
|
+
'/api/products'
|
45
|
+
end
|
46
|
+
|
47
|
+
def add_product_path
|
48
|
+
'/api/installation_settings/products'
|
49
|
+
end
|
50
|
+
|
51
|
+
def upgrade_product_path(product_guid)
|
52
|
+
"/api/installation_settings/products/#{product_guid}"
|
53
|
+
end
|
54
|
+
|
55
|
+
def upload_product_form_key
|
56
|
+
'product'
|
57
|
+
end
|
58
|
+
|
59
|
+
def list_components_path
|
60
|
+
'/api/components'
|
61
|
+
end
|
62
|
+
|
63
|
+
def list_products_path
|
64
|
+
'/api/products'
|
65
|
+
end
|
66
|
+
|
67
|
+
def installed_products_path
|
68
|
+
'/api/installation_settings/products'
|
69
|
+
end
|
70
|
+
|
71
|
+
def product_manifest_path(product_guid)
|
72
|
+
"/api/manifests/#{product_guid}"
|
73
|
+
end
|
74
|
+
|
75
|
+
def download_staged_manifest(product_guid)
|
76
|
+
"/api/v0/staged/products/#{product_guid}/manifest"
|
77
|
+
end
|
78
|
+
|
79
|
+
def export_installation_path
|
80
|
+
'/api/installation_asset_collection'
|
81
|
+
end
|
82
|
+
|
83
|
+
def import_installation_path
|
84
|
+
'/api/installation_asset_collection'
|
85
|
+
end
|
86
|
+
|
87
|
+
def mark_for_deletion_path(product_guid)
|
88
|
+
"/api/installation_settings/products/#{product_guid}"
|
89
|
+
end
|
90
|
+
|
91
|
+
def import_stemcell_path
|
92
|
+
'/api/stemcells'
|
93
|
+
end
|
94
|
+
|
95
|
+
def root_ca_certificate_path
|
96
|
+
'/api/v0/security/root_ca_certificate'
|
97
|
+
end
|
98
|
+
|
99
|
+
def uaa_get_user_by_username_path(username)
|
100
|
+
"/uaa/Users?attributes=id&filter=userName%20eq%20'#{username}'"
|
101
|
+
end
|
102
|
+
|
103
|
+
def uaa_create_user
|
104
|
+
'/uaa/Users'
|
105
|
+
end
|
106
|
+
|
107
|
+
def login_ensure_availability
|
108
|
+
'/login/ensure_availability'
|
109
|
+
end
|
110
|
+
end
|
111
|
+
end
|
112
|
+
end
|
113
|
+
end
|
114
|
+
# Copyright (c) 2014-2015 Pivotal Software, Inc.
|
115
|
+
# All rights reserved.
|
116
|
+
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
|
117
|
+
# INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
|
118
|
+
# PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
119
|
+
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
120
|
+
# TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
|
121
|
+
# USE OR OTHER DEALINGS IN THE SOFTWARE.
|
@@ -0,0 +1,84 @@
|
|
1
|
+
module Opsmgr
|
2
|
+
class BoshCommandRunner
|
3
|
+
def initialize(bosh_command:, logger:)
|
4
|
+
@bosh_command = bosh_command
|
5
|
+
@logger = logger
|
6
|
+
end
|
7
|
+
|
8
|
+
def run(command)
|
9
|
+
system_or_fail(
|
10
|
+
"#{bosh_command_prefix} #{command}",
|
11
|
+
"bosh #{command} failed"
|
12
|
+
)
|
13
|
+
end
|
14
|
+
|
15
|
+
def run_and_capture_output(command)
|
16
|
+
capture_output_or_fail(
|
17
|
+
"#{bosh_command_prefix} #{command}",
|
18
|
+
"bosh #{command} failed"
|
19
|
+
)
|
20
|
+
end
|
21
|
+
|
22
|
+
def run_with_deployment(command, deployment)
|
23
|
+
bosh_deployment = bosh_deployments[/#{deployment}-[0-9a-f]{8,}/]
|
24
|
+
fail 'Deployment not found' unless bosh_deployment
|
25
|
+
|
26
|
+
deployment_file = "#{ENV.fetch('TMPDIR', '/tmp')}/#{deployment}.yml"
|
27
|
+
|
28
|
+
begin
|
29
|
+
run(
|
30
|
+
"-n download manifest #{bosh_deployment} #{deployment_file}"
|
31
|
+
)
|
32
|
+
rescue RuntimeError
|
33
|
+
raise 'bosh download manifest failed'
|
34
|
+
end
|
35
|
+
|
36
|
+
run("-d #{deployment_file} #{command}")
|
37
|
+
end
|
38
|
+
|
39
|
+
private
|
40
|
+
|
41
|
+
def bosh_deployments
|
42
|
+
run_and_capture_output('deployments')
|
43
|
+
rescue RuntimeError
|
44
|
+
raise 'bosh deployments failed'
|
45
|
+
end
|
46
|
+
|
47
|
+
def system_or_fail(command, failure_message)
|
48
|
+
clean_and_log(command)
|
49
|
+
Bundler.clean_system(command) || fail(failure_message)
|
50
|
+
end
|
51
|
+
|
52
|
+
def capture_output_or_fail(command, failure_message)
|
53
|
+
clean_and_log(command)
|
54
|
+
|
55
|
+
Bundler.with_clean_env do
|
56
|
+
output, status = Open3.capture2(command)
|
57
|
+
fail(failure_message) unless status.success?
|
58
|
+
output
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
def clean_and_log(command)
|
63
|
+
scrubbed_command = command.slice(command.index('bosh')..-1)
|
64
|
+
scrubbed_command.sub!(/\s\-p\s\b\w+\b/, ' -p <PASSWORD>')
|
65
|
+
scrubbed_command.sub!(/\s\-u\s\b\w+\b/, ' -u <USER>')
|
66
|
+
|
67
|
+
logger.info("Running #{scrubbed_command}")
|
68
|
+
end
|
69
|
+
|
70
|
+
def bosh_command_prefix
|
71
|
+
@bosh_command_prefix ||= bosh_command.command
|
72
|
+
end
|
73
|
+
|
74
|
+
attr_reader :bosh_command, :logger
|
75
|
+
end
|
76
|
+
end
|
77
|
+
# Copyright (c) 2014-2015 Pivotal Software, Inc.
|
78
|
+
# All rights reserved.
|
79
|
+
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
|
80
|
+
# INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
|
81
|
+
# PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
82
|
+
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
83
|
+
# TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
|
84
|
+
# USE OR OTHER DEALINGS IN THE SOFTWARE.
|