ci-info 0.4.0__py2.py3-none-any.whl

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.
ci_info/__init__.py ADDED
@@ -0,0 +1,102 @@
1
+ from builtins import str # remove this once Py2 is dropped
2
+ import json
3
+ import os
4
+
5
+ try:
6
+ from ._version import __version__
7
+ except ImportError:
8
+ __version__ = "0+unknown"
9
+
10
+ _here = os.path.dirname(__file__)
11
+ with open(os.path.join(_here, "vendors.json")) as fp:
12
+ vendors = json.load(fp)
13
+
14
+
15
+ def _detect_env(env=None):
16
+ if env is None:
17
+ env = os.environ
18
+
19
+ for vendor in vendors:
20
+ vend = vendor.get("env")
21
+ if isinstance(vend, str) and vend in env:
22
+ return vendor
23
+ if isinstance(vend, list):
24
+ if all(ev in env for ev in vend):
25
+ return vendor
26
+ elif isinstance(vend, dict):
27
+ if "includes" in vend:
28
+ # Envvar needs to be present and include some value
29
+ if vend["env"] in env and vend["includes"] in env[vend["env"]]:
30
+ return vendor
31
+ elif "any" in vend:
32
+ if any(ev in env for ev in vend["any"]):
33
+ return vendor
34
+ else:
35
+ for ev, val in vend.items():
36
+ if ev in env and env[ev] == val:
37
+ return vendor
38
+ return {}
39
+
40
+
41
+ def name(env=None):
42
+ """
43
+ Returns a string containing name of the CI server the code is running on.
44
+ If CI server is not detected, returns None.
45
+ """
46
+ return _detect_env(env).get("name")
47
+
48
+
49
+ def is_ci(env=None):
50
+ """
51
+ Returns a boolean. Will be `True` if the code is running on a CI server,
52
+ otherwise `False`.
53
+ """
54
+ return bool(name(env))
55
+
56
+
57
+ def is_pr(env=None):
58
+ """
59
+ Returns a boolean if PR detection is supported for the current CI server.
60
+ Will be `True` if a PR is being tested, otherwise `False`. If PR detection
61
+ is not supported for the current CI server, the value will be `None`.
62
+ """
63
+ if env is None:
64
+ env = os.environ
65
+ vendor = _detect_env(env)
66
+
67
+ vpr = vendor.get("pr")
68
+ if vpr is None:
69
+ return
70
+
71
+ if isinstance(vpr, str):
72
+ return bool(env.get(vpr))
73
+ if isinstance(vpr, dict):
74
+ if "env" in vpr:
75
+ # Envvar is not equal to
76
+ if "ne" in vpr:
77
+ return bool(env.get(vpr["env"])) and env.get(vpr["env"]) != vpr["ne"]
78
+ # Envvar is one of a set of values
79
+ elif "any" in vpr:
80
+ return env.get(vpr["env"]) in vpr["any"]
81
+ # Envvar is one of a set of values
82
+ elif "any" in vpr:
83
+ for k in vpr["any"]:
84
+ if env.get(k):
85
+ return True
86
+ return False
87
+ # Specific value(s)
88
+ else:
89
+ for k, v in vpr.items():
90
+ if env.get(k) != v:
91
+ return False
92
+ return True
93
+ return None
94
+
95
+
96
+ def info(env=None):
97
+ """Return a dictionary with all info: name, is_ci, is_pr."""
98
+ return {
99
+ "name": name(env),
100
+ "is_ci": is_ci(env),
101
+ "is_pr": is_pr(env),
102
+ }
ci_info/vendors.json ADDED
@@ -0,0 +1,358 @@
1
+ [
2
+ {
3
+ "name": "Agola CI",
4
+ "constant": "AGOLA",
5
+ "env": "AGOLA_GIT_REF",
6
+ "pr": "AGOLA_PULL_REQUEST_ID"
7
+ },
8
+ {
9
+ "name": "Appcircle",
10
+ "constant": "APPCIRCLE",
11
+ "env": "AC_APPCIRCLE",
12
+ "pr": {
13
+ "env": "AC_GIT_PR",
14
+ "ne": "false"
15
+ }
16
+ },
17
+ {
18
+ "name": "AppVeyor",
19
+ "constant": "APPVEYOR",
20
+ "env": "APPVEYOR",
21
+ "pr": "APPVEYOR_PULL_REQUEST_NUMBER"
22
+ },
23
+ {
24
+ "name": "AWS CodeBuild",
25
+ "constant": "CODEBUILD",
26
+ "env": "CODEBUILD_BUILD_ARN",
27
+ "pr": {
28
+ "env": "CODEBUILD_WEBHOOK_EVENT",
29
+ "any": [
30
+ "PULL_REQUEST_CREATED",
31
+ "PULL_REQUEST_UPDATED",
32
+ "PULL_REQUEST_REOPENED"
33
+ ]
34
+ }
35
+ },
36
+ {
37
+ "name": "Azure Pipelines",
38
+ "constant": "AZURE_PIPELINES",
39
+ "env": "TF_BUILD",
40
+ "pr": {
41
+ "BUILD_REASON": "PullRequest"
42
+ }
43
+ },
44
+ {
45
+ "name": "Bamboo",
46
+ "constant": "BAMBOO",
47
+ "env": "bamboo_planKey"
48
+ },
49
+ {
50
+ "name": "Bitbucket Pipelines",
51
+ "constant": "BITBUCKET",
52
+ "env": "BITBUCKET_COMMIT",
53
+ "pr": "BITBUCKET_PR_ID"
54
+ },
55
+ {
56
+ "name": "Bitrise",
57
+ "constant": "BITRISE",
58
+ "env": "BITRISE_IO",
59
+ "pr": "BITRISE_PULL_REQUEST"
60
+ },
61
+ {
62
+ "name": "Buddy",
63
+ "constant": "BUDDY",
64
+ "env": "BUDDY_WORKSPACE_ID",
65
+ "pr": "BUDDY_EXECUTION_PULL_REQUEST_ID"
66
+ },
67
+ {
68
+ "name": "Buildkite",
69
+ "constant": "BUILDKITE",
70
+ "env": "BUILDKITE",
71
+ "pr": {
72
+ "env": "BUILDKITE_PULL_REQUEST",
73
+ "ne": "false"
74
+ }
75
+ },
76
+ {
77
+ "name": "CircleCI",
78
+ "constant": "CIRCLE",
79
+ "env": "CIRCLECI",
80
+ "pr": "CIRCLE_PULL_REQUEST"
81
+ },
82
+ {
83
+ "name": "Cirrus CI",
84
+ "constant": "CIRRUS",
85
+ "env": "CIRRUS_CI",
86
+ "pr": "CIRRUS_PR"
87
+ },
88
+ {
89
+ "name": "Cloudflare Pages",
90
+ "constant": "CLOUDFLARE_PAGES",
91
+ "env": "CF_PAGES"
92
+ },
93
+ {
94
+ "name": "Cloudflare Workers",
95
+ "constant": "CLOUDFLARE_WORKERS",
96
+ "env": "WORKERS_CI"
97
+ },
98
+ {
99
+ "name": "Codefresh",
100
+ "constant": "CODEFRESH",
101
+ "env": "CF_BUILD_ID",
102
+ "pr": {
103
+ "any": [
104
+ "CF_PULL_REQUEST_NUMBER",
105
+ "CF_PULL_REQUEST_ID"
106
+ ]
107
+ }
108
+ },
109
+ {
110
+ "name": "Codemagic",
111
+ "constant": "CODEMAGIC",
112
+ "env": "CM_BUILD_ID",
113
+ "pr": "CM_PULL_REQUEST"
114
+ },
115
+ {
116
+ "name": "Codeship",
117
+ "constant": "CODESHIP",
118
+ "env": {
119
+ "CI_NAME": "codeship"
120
+ }
121
+ },
122
+ {
123
+ "name": "Drone",
124
+ "constant": "DRONE",
125
+ "env": "DRONE",
126
+ "pr": {
127
+ "DRONE_BUILD_EVENT": "pull_request"
128
+ }
129
+ },
130
+ {
131
+ "name": "dsari",
132
+ "constant": "DSARI",
133
+ "env": "DSARI"
134
+ },
135
+ {
136
+ "name": "Earthly",
137
+ "constant": "EARTHLY",
138
+ "env": "EARTHLY_CI"
139
+ },
140
+ {
141
+ "name": "Expo Application Services",
142
+ "constant": "EAS",
143
+ "env": "EAS_BUILD"
144
+ },
145
+ {
146
+ "name": "Gerrit",
147
+ "constant": "GERRIT",
148
+ "env": "GERRIT_PROJECT"
149
+ },
150
+ {
151
+ "name": "Gitea Actions",
152
+ "constant": "GITEA_ACTIONS",
153
+ "env": "GITEA_ACTIONS"
154
+ },
155
+ {
156
+ "name": "GitHub Actions",
157
+ "constant": "GITHUB_ACTIONS",
158
+ "env": "GITHUB_ACTIONS",
159
+ "pr": {
160
+ "GITHUB_EVENT_NAME": "pull_request"
161
+ }
162
+ },
163
+ {
164
+ "name": "GitLab CI",
165
+ "constant": "GITLAB",
166
+ "env": "GITLAB_CI",
167
+ "pr": "CI_MERGE_REQUEST_ID"
168
+ },
169
+ {
170
+ "name": "GoCD",
171
+ "constant": "GOCD",
172
+ "env": "GO_PIPELINE_LABEL"
173
+ },
174
+ {
175
+ "name": "Google Cloud Build",
176
+ "constant": "GOOGLE_CLOUD_BUILD",
177
+ "env": "BUILDER_OUTPUT"
178
+ },
179
+ {
180
+ "name": "Harness CI",
181
+ "constant": "HARNESS",
182
+ "env": "HARNESS_BUILD_ID"
183
+ },
184
+ {
185
+ "name": "Heroku",
186
+ "constant": "HEROKU",
187
+ "env": {
188
+ "env": "NODE",
189
+ "includes": "/app/.heroku/node/bin/node"
190
+ }
191
+ },
192
+ {
193
+ "name": "Hudson",
194
+ "constant": "HUDSON",
195
+ "env": "HUDSON_URL"
196
+ },
197
+ {
198
+ "name": "Jenkins",
199
+ "constant": "JENKINS",
200
+ "env": [
201
+ "JENKINS_URL",
202
+ "BUILD_ID"
203
+ ],
204
+ "pr": {
205
+ "any": [
206
+ "ghprbPullId",
207
+ "CHANGE_ID"
208
+ ]
209
+ }
210
+ },
211
+ {
212
+ "name": "LayerCI",
213
+ "constant": "LAYERCI",
214
+ "env": "LAYERCI",
215
+ "pr": "LAYERCI_PULL_REQUEST"
216
+ },
217
+ {
218
+ "name": "Magnum CI",
219
+ "constant": "MAGNUM",
220
+ "env": "MAGNUM"
221
+ },
222
+ {
223
+ "name": "Netlify CI",
224
+ "constant": "NETLIFY",
225
+ "env": "NETLIFY",
226
+ "pr": {
227
+ "env": "PULL_REQUEST",
228
+ "ne": "false"
229
+ }
230
+ },
231
+ {
232
+ "name": "Nevercode",
233
+ "constant": "NEVERCODE",
234
+ "env": "NEVERCODE",
235
+ "pr": {
236
+ "env": "NEVERCODE_PULL_REQUEST",
237
+ "ne": "false"
238
+ }
239
+ },
240
+ {
241
+ "name": "Prow",
242
+ "constant": "PROW",
243
+ "env": "PROW_JOB_ID"
244
+ },
245
+ {
246
+ "name": "ReleaseHub",
247
+ "constant": "RELEASEHUB",
248
+ "env": "RELEASE_BUILD_ID"
249
+ },
250
+ {
251
+ "name": "Render",
252
+ "constant": "RENDER",
253
+ "env": "RENDER",
254
+ "pr": {
255
+ "IS_PULL_REQUEST": "true"
256
+ }
257
+ },
258
+ {
259
+ "name": "Sail CI",
260
+ "constant": "SAIL",
261
+ "env": "SAILCI",
262
+ "pr": "SAIL_PULL_REQUEST_NUMBER"
263
+ },
264
+ {
265
+ "name": "Screwdriver",
266
+ "constant": "SCREWDRIVER",
267
+ "env": "SCREWDRIVER",
268
+ "pr": {
269
+ "env": "SD_PULL_REQUEST",
270
+ "ne": "false"
271
+ }
272
+ },
273
+ {
274
+ "name": "Semaphore",
275
+ "constant": "SEMAPHORE",
276
+ "env": "SEMAPHORE",
277
+ "pr": "PULL_REQUEST_NUMBER"
278
+ },
279
+ {
280
+ "name": "Sourcehut",
281
+ "constant": "SOURCEHUT",
282
+ "env": {
283
+ "CI_NAME": "sourcehut"
284
+ }
285
+ },
286
+ {
287
+ "name": "Strider CD",
288
+ "constant": "STRIDER",
289
+ "env": "STRIDER"
290
+ },
291
+ {
292
+ "name": "TaskCluster",
293
+ "constant": "TASKCLUSTER",
294
+ "env": [
295
+ "TASK_ID",
296
+ "RUN_ID"
297
+ ]
298
+ },
299
+ {
300
+ "name": "TeamCity",
301
+ "constant": "TEAMCITY",
302
+ "env": "TEAMCITY_VERSION"
303
+ },
304
+ {
305
+ "name": "Travis CI",
306
+ "constant": "TRAVIS",
307
+ "env": "TRAVIS",
308
+ "pr": {
309
+ "env": "TRAVIS_PULL_REQUEST",
310
+ "ne": "false"
311
+ }
312
+ },
313
+ {
314
+ "name": "Vela",
315
+ "constant": "VELA",
316
+ "env": "VELA",
317
+ "pr": {
318
+ "VELA_PULL_REQUEST": "1"
319
+ }
320
+ },
321
+ {
322
+ "name": "Vercel",
323
+ "constant": "VERCEL",
324
+ "env": {
325
+ "any": [
326
+ "NOW_BUILDER",
327
+ "VERCEL"
328
+ ]
329
+ },
330
+ "pr": "VERCEL_GIT_PULL_REQUEST_ID"
331
+ },
332
+ {
333
+ "name": "Visual Studio App Center",
334
+ "constant": "APPCENTER",
335
+ "env": "APPCENTER_BUILD_ID"
336
+ },
337
+ {
338
+ "name": "Woodpecker",
339
+ "constant": "WOODPECKER",
340
+ "env": {
341
+ "CI": "woodpecker"
342
+ },
343
+ "pr": {
344
+ "CI_BUILD_EVENT": "pull_request"
345
+ }
346
+ },
347
+ {
348
+ "name": "Xcode Cloud",
349
+ "constant": "XCODE_CLOUD",
350
+ "env": "CI_XCODE_PROJECT",
351
+ "pr": "CI_PULL_REQUEST_NUMBER"
352
+ },
353
+ {
354
+ "name": "Xcode Server",
355
+ "constant": "XCODE_SERVER",
356
+ "env": "XCS"
357
+ }
358
+ ]
@@ -0,0 +1,141 @@
1
+ Metadata-Version: 2.4
2
+ Name: ci-info
3
+ Version: 0.4.0
4
+ Summary: Continuous Integration Information
5
+ Project-URL: Homepage, https://github.com/mgxd/ci-info
6
+ Author-email: Mathias Goncalves <mathiasg@stanford.edu>
7
+ License: MIT
8
+ License-File: LICENSE
9
+ Classifier: Development Status :: 5 - Production/Stable
10
+ Classifier: Intended Audience :: Developers
11
+ Classifier: License :: OSI Approved :: MIT License
12
+ Classifier: Programming Language :: Python :: 3
13
+ Provides-Extra: all
14
+ Requires-Dist: pytest; extra == 'all'
15
+ Provides-Extra: test
16
+ Requires-Dist: pytest; extra == 'test'
17
+ Provides-Extra: tests
18
+ Requires-Dist: pytest; extra == 'tests'
19
+ Description-Content-Type: text/markdown
20
+
21
+ # ci-info
22
+
23
+ [![PyPI version](https://badge.fury.io/py/ci-info.svg)](https://badge.fury.io/py/ci-info)
24
+ [![Build Status](https://travis-ci.org/mgxd/ci-info.svg?branch=master)](https://travis-ci.org/mgxd/ci-info)
25
+
26
+ A Python implementation of [watson/ci-info](https://github.com/watson/ci-info).
27
+ Get details about the current Continuous Integration environment.
28
+
29
+ Please [open an issue](https://github.com/mgxd/ci-info/issues/new)
30
+ if your CI server isn't properly detected :)
31
+
32
+
33
+ ## Supported CI tools
34
+
35
+ Officially supported CI servers:
36
+
37
+ | Name | isPR |
38
+ | ------------------------------------------------------------------------------- | ---- |
39
+ | [Agola CI](https://agola.io/) | ✅ |
40
+ | [Appcircle](https://appcircle.io/) | ✅ |
41
+ | [AppVeyor](http://www.appveyor.com) | ✅ |
42
+ | [AWS CodeBuild](https://aws.amazon.com/codebuild/) | ✅ |
43
+ | [Azure Pipelines](https://azure.microsoft.com/en-us/services/devops/pipelines/) | ✅ |
44
+ | [Bamboo](https://www.atlassian.com/software/bamboo) by Atlassian | 🚫 |
45
+ | [Bitbucket Pipelines](https://bitbucket.org/product/features/pipelines) | ✅ |
46
+ | [Bitrise](https://www.bitrise.io/) | ✅ |
47
+ | [Buddy](https://buddy.works/) | ✅ |
48
+ | [Buildkite](https://buildkite.com) | ✅ |
49
+ | [CircleCI](http://circleci.com) | ✅ |
50
+ | [Cirrus CI](https://cirrus-ci.org) | ✅ |
51
+ | [Cloudflare Pages](https://pages.cloudflare.com/) | 🚫 |
52
+ | [Cloudflare Workers](https://pages.cloudflare.com/) | 🚫 |
53
+ | [Codefresh](https://codefresh.io/) | ✅ |
54
+ | [Codeship](https://codeship.com) | 🚫 |
55
+ | [Drone](https://drone.io) | ✅ |
56
+ | [dsari](https://github.com/rfinnie/dsari) | 🚫 |
57
+ | [Earthly CI](https://earthly.dev/) | 🚫 |
58
+ | [Expo Application Services](https://expo.dev/eas) | 🚫 |
59
+ | [Gerrit CI](https://www.gerritcodereview.com) | 🚫 |
60
+ | [GitHub Actions](https://github.com/features/actions/) | ✅ |
61
+ | [GitLab CI](https://about.gitlab.com/gitlab-ci/) | ✅ |
62
+ | [Gitea Actions](https://about.gitea.com/) | 🚫 |
63
+ | [GoCD](https://www.go.cd/) | 🚫 |
64
+ | [Google Cloud Build](https://cloud.google.com/build) | 🚫 |
65
+ | [Harness CI](https://www.harness.io/products/continuous-integration) | 🚫 |
66
+ | [Heroku](https://www.heroku.com) | 🚫 |
67
+ | [Hudson](http://hudson-ci.org) | 🚫 |
68
+ | [Jenkins CI](https://jenkins-ci.org) | ✅ |
69
+ | [LayerCI](https://layerci.com/) | ✅ |
70
+ | [Magnum CI](https://magnum-ci.com) | 🚫 |
71
+ | [Netlify CI](https://www.netlify.com/) | ✅ |
72
+ | [Nevercode](http://nevercode.io/) | ✅ |
73
+ | [Prow](https://docs.prow.k8s.io/) | 🚫 |
74
+ | [ReleaseHub](https://releasehub.com/) | 🚫 |
75
+ | [Render](https://render.com/) | ✅ |
76
+ | [Sail CI](https://sail.ci/) | ✅ |
77
+ | [Screwdriver](https://screwdriver.cd/) | ✅ |
78
+ | [Semaphore](https://semaphoreci.com) | ✅ |
79
+ | [Shippable](https://www.shippable.com/) | ✅ |
80
+ | [Solano CI](https://www.solanolabs.com/) | ✅ |
81
+ | [Sourcehut](https://sourcehut.org/) | 🚫 |
82
+ | [Strider CD](https://strider-cd.github.io/) | 🚫 |
83
+ | [TaskCluster](http://docs.taskcluster.net) | 🚫 |
84
+ | [TeamCity](https://www.jetbrains.com/teamcity/) by JetBrains | 🚫 |
85
+ | [Travis CI](http://travis-ci.org) | ✅ |
86
+ | [Vela](https://go-vela.github.io/docs/) | ✅ |
87
+ | [Vercel](https://vercel.com/) | ✅ |
88
+ | [Visual Studio App Center](https://appcenter.ms/) | 🚫 |
89
+ | [Woodpecker](https://woodpecker-ci.org/) | ✅ |
90
+
91
+
92
+ ## Installation
93
+
94
+ ```
95
+ pip install ci-info
96
+ ```
97
+
98
+ ## Usage
99
+
100
+ ```python
101
+ import ci_info
102
+ if ci_info.is_ci():
103
+ print(ci_info.name())
104
+
105
+ "My CI Name"
106
+ ```
107
+
108
+
109
+ ## API
110
+
111
+ ### `ci_info.name()`
112
+
113
+ Returns a string containing name of the CI server the code is running on.
114
+ If CI server is not detected, it returns `None`.
115
+
116
+ Don't depend on the value of this string not to change for a specific
117
+ vendor.
118
+
119
+ ### `ci_info.is_ci()`
120
+
121
+ Returns a boolean. Will be `True` if the code is running on a CI server,
122
+ otherwise `False`.
123
+
124
+ Some CI servers not listed here might still trigger the `ci_info.is_ci()`
125
+ boolean to be set to `True` if they use certain vendor neutral
126
+ environment variables. In those cases `ci_info.name()` will be `None` and no
127
+ vendor specific boolean will be set to `True`.
128
+
129
+ ### `ci_info.is_pr()`
130
+
131
+ Returns a boolean if PR detection is supported for the current CI server. Will
132
+ be `True` if a PR is being tested, otherwise `False`. If PR detection is
133
+ not supported for the current CI server, the value will be `None`.
134
+
135
+ ### `ci_info.info()`
136
+
137
+ Returns a dictionary of all above values in key/value pairs.
138
+
139
+ ## License
140
+
141
+ [MIT](LICENSE)
@@ -0,0 +1,6 @@
1
+ ci_info/__init__.py,sha256=MVEmulWNwlr1-riN2BC8m0c1vKyUEkWCT1vxIoU7jnM,2913
2
+ ci_info/vendors.json,sha256=AyhjPdAKVzd3zEfB1XkK1JS-zJ80Nu1yO9Gmb2UV4AM,6424
3
+ ci_info-0.4.0.dist-info/METADATA,sha256=sfhnF7pqYKw7bfpYVy7NL_t_YdBgos8Kw91wVFlfTzg,7199
4
+ ci_info-0.4.0.dist-info/WHEEL,sha256=aha0VrrYvgDJ3Xxl3db_g_MDIW-ZexDdrc_m-Hk8YY4,105
5
+ ci_info-0.4.0.dist-info/licenses/LICENSE,sha256=cJMF2XeQUFeyljkMpbf7_VcD8asbNuI93u1MXi1dTcA,1083
6
+ ci_info-0.4.0.dist-info/RECORD,,
@@ -0,0 +1,5 @@
1
+ Wheel-Version: 1.0
2
+ Generator: hatchling 1.28.0
3
+ Root-Is-Purelib: true
4
+ Tag: py2-none-any
5
+ Tag: py3-none-any
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2019 Mathias Goncalves
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.