ppqs 2.1.0__tar.gz → 2.2.0__tar.gz
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.
- ppqs-2.2.0/LICENSES/MIT.txt +18 -0
- {ppqs-2.1.0/src/ppqs.egg-info → ppqs-2.2.0}/PKG-INFO +32 -2
- {ppqs-2.1.0 → ppqs-2.2.0}/README.md +30 -0
- {ppqs-2.1.0 → ppqs-2.2.0}/pyproject.toml +13 -4
- {ppqs-2.1.0 → ppqs-2.2.0/src/ppqs.egg-info}/PKG-INFO +32 -2
- {ppqs-2.1.0 → ppqs-2.2.0}/src/ppqs.egg-info/SOURCES.txt +1 -1
- {ppqs-2.1.0 → ppqs-2.2.0}/src/py_proj_quick_scripts/__init__.py +80 -39
- {ppqs-2.1.0 → ppqs-2.2.0}/test/test_cli.py +27 -0
- {ppqs-2.1.0 → ppqs-2.2.0}/test/test_find_pyproject.py +4 -0
- {ppqs-2.1.0 → ppqs-2.2.0}/test/test_parse_scripts.py +10 -13
- ppqs-2.1.0/LICENSE +0 -18
- {ppqs-2.1.0 → ppqs-2.2.0}/setup.cfg +0 -0
- {ppqs-2.1.0 → ppqs-2.2.0}/src/ppqs.egg-info/dependency_links.txt +0 -0
- {ppqs-2.1.0 → ppqs-2.2.0}/src/ppqs.egg-info/entry_points.txt +0 -0
- {ppqs-2.1.0 → ppqs-2.2.0}/src/ppqs.egg-info/requires.txt +0 -0
- {ppqs-2.1.0 → ppqs-2.2.0}/src/ppqs.egg-info/top_level.txt +0 -0
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 Karl Wette
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and
|
|
6
|
+
associated documentation files (the "Software"), to deal in the Software without restriction, including
|
|
7
|
+
without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
8
|
+
copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the
|
|
9
|
+
following conditions:
|
|
10
|
+
|
|
11
|
+
The above copyright notice and this permission notice shall be included in all copies or substantial
|
|
12
|
+
portions of the Software.
|
|
13
|
+
|
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT
|
|
15
|
+
LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO
|
|
16
|
+
EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
|
17
|
+
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
|
|
18
|
+
USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: ppqs
|
|
3
|
-
Version: 2.
|
|
3
|
+
Version: 2.2.0
|
|
4
4
|
Summary: Python project quick scripts
|
|
5
5
|
Author-email: Karl Wette <karl.wette@anu.edu.au>
|
|
6
6
|
License-Expression: MIT
|
|
@@ -10,7 +10,7 @@ Classifier: Programming Language :: Python :: 3
|
|
|
10
10
|
Classifier: Operating System :: OS Independent
|
|
11
11
|
Requires-Python: >=3.9
|
|
12
12
|
Description-Content-Type: text/markdown
|
|
13
|
-
License-File:
|
|
13
|
+
License-File: LICENSES/MIT.txt
|
|
14
14
|
Requires-Dist: tomli>=1.1.0; python_version < "3.11"
|
|
15
15
|
Dynamic: license-file
|
|
16
16
|
|
|
@@ -100,6 +100,36 @@ $ ppqs print-something Hi
|
|
|
100
100
|
Hi
|
|
101
101
|
```
|
|
102
102
|
|
|
103
|
+
`ppqs` can recursively run its own scripts, however it will only run any script
|
|
104
|
+
once. For example, given the following script:
|
|
105
|
+
|
|
106
|
+
```toml
|
|
107
|
+
[tool.ppqs.scripts]
|
|
108
|
+
task-init = """
|
|
109
|
+
echo task init
|
|
110
|
+
"""
|
|
111
|
+
task-a = """
|
|
112
|
+
ppqs task-init
|
|
113
|
+
echo task 1
|
|
114
|
+
"""
|
|
115
|
+
task-b = """
|
|
116
|
+
ppqs task-init
|
|
117
|
+
echo task 2
|
|
118
|
+
"""
|
|
119
|
+
all-tasks = """
|
|
120
|
+
ppqs task-a
|
|
121
|
+
ppqs task-b
|
|
122
|
+
"""
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
running `ppqs all-tasks` will only run `ppqs task-init` once:
|
|
126
|
+
```
|
|
127
|
+
$ ppqs all-tasks
|
|
128
|
+
task init
|
|
129
|
+
task 1
|
|
130
|
+
task 2
|
|
131
|
+
```
|
|
132
|
+
|
|
103
133
|
The following only applies to scripts defined as lists of lists:
|
|
104
134
|
|
|
105
135
|
* If a command argument is itself a list, it is concatenated into a path
|
|
@@ -84,6 +84,36 @@ $ ppqs print-something Hi
|
|
|
84
84
|
Hi
|
|
85
85
|
```
|
|
86
86
|
|
|
87
|
+
`ppqs` can recursively run its own scripts, however it will only run any script
|
|
88
|
+
once. For example, given the following script:
|
|
89
|
+
|
|
90
|
+
```toml
|
|
91
|
+
[tool.ppqs.scripts]
|
|
92
|
+
task-init = """
|
|
93
|
+
echo task init
|
|
94
|
+
"""
|
|
95
|
+
task-a = """
|
|
96
|
+
ppqs task-init
|
|
97
|
+
echo task 1
|
|
98
|
+
"""
|
|
99
|
+
task-b = """
|
|
100
|
+
ppqs task-init
|
|
101
|
+
echo task 2
|
|
102
|
+
"""
|
|
103
|
+
all-tasks = """
|
|
104
|
+
ppqs task-a
|
|
105
|
+
ppqs task-b
|
|
106
|
+
"""
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
running `ppqs all-tasks` will only run `ppqs task-init` once:
|
|
110
|
+
```
|
|
111
|
+
$ ppqs all-tasks
|
|
112
|
+
task init
|
|
113
|
+
task 1
|
|
114
|
+
task 2
|
|
115
|
+
```
|
|
116
|
+
|
|
87
117
|
The following only applies to scripts defined as lists of lists:
|
|
88
118
|
|
|
89
119
|
* If a command argument is itself a list, it is concatenated into a path
|
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "ppqs"
|
|
7
|
-
version = "2.
|
|
7
|
+
version = "2.2.0"
|
|
8
8
|
description = "Python project quick scripts"
|
|
9
9
|
authors = [
|
|
10
10
|
{ name = "Karl Wette", email = "karl.wette@anu.edu.au" },
|
|
@@ -15,7 +15,7 @@ dependencies = [
|
|
|
15
15
|
]
|
|
16
16
|
readme = "README.md"
|
|
17
17
|
license = "MIT"
|
|
18
|
-
license-files = ["
|
|
18
|
+
license-files = ["LICENSES/MIT.txt"]
|
|
19
19
|
classifiers = [
|
|
20
20
|
"Programming Language :: Python :: 3",
|
|
21
21
|
"Operating System :: OS Independent",
|
|
@@ -28,6 +28,15 @@ Issues = "https://github.com/kwwette/ppqs/issues"
|
|
|
28
28
|
[project.scripts]
|
|
29
29
|
ppqs = "py_proj_quick_scripts:cli"
|
|
30
30
|
|
|
31
|
+
[tool.ruff.lint]
|
|
32
|
+
select = [
|
|
33
|
+
"E4",
|
|
34
|
+
"E7",
|
|
35
|
+
"E9",
|
|
36
|
+
"EM",
|
|
37
|
+
"F",
|
|
38
|
+
]
|
|
39
|
+
|
|
31
40
|
[tool.pytest.ini_options]
|
|
32
41
|
minversion = "6.0"
|
|
33
42
|
addopts = "--cov=py_proj_quick_scripts --cov-report=term-missing --cov-fail-under=100"
|
|
@@ -53,14 +62,14 @@ pre-commit run -a
|
|
|
53
62
|
[tool.ppqs.scripts.build]
|
|
54
63
|
description = "Build project"
|
|
55
64
|
script = """
|
|
56
|
-
|
|
65
|
+
ppqs clean
|
|
57
66
|
python -m build
|
|
58
67
|
"""
|
|
59
68
|
|
|
60
69
|
[tool.ppqs.scripts.test]
|
|
61
70
|
description = "Run tests"
|
|
62
71
|
script = """
|
|
63
|
-
pytest ...
|
|
72
|
+
python -m pytest ...
|
|
64
73
|
"""
|
|
65
74
|
|
|
66
75
|
[tool.ppqs.scripts.clean]
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: ppqs
|
|
3
|
-
Version: 2.
|
|
3
|
+
Version: 2.2.0
|
|
4
4
|
Summary: Python project quick scripts
|
|
5
5
|
Author-email: Karl Wette <karl.wette@anu.edu.au>
|
|
6
6
|
License-Expression: MIT
|
|
@@ -10,7 +10,7 @@ Classifier: Programming Language :: Python :: 3
|
|
|
10
10
|
Classifier: Operating System :: OS Independent
|
|
11
11
|
Requires-Python: >=3.9
|
|
12
12
|
Description-Content-Type: text/markdown
|
|
13
|
-
License-File:
|
|
13
|
+
License-File: LICENSES/MIT.txt
|
|
14
14
|
Requires-Dist: tomli>=1.1.0; python_version < "3.11"
|
|
15
15
|
Dynamic: license-file
|
|
16
16
|
|
|
@@ -100,6 +100,36 @@ $ ppqs print-something Hi
|
|
|
100
100
|
Hi
|
|
101
101
|
```
|
|
102
102
|
|
|
103
|
+
`ppqs` can recursively run its own scripts, however it will only run any script
|
|
104
|
+
once. For example, given the following script:
|
|
105
|
+
|
|
106
|
+
```toml
|
|
107
|
+
[tool.ppqs.scripts]
|
|
108
|
+
task-init = """
|
|
109
|
+
echo task init
|
|
110
|
+
"""
|
|
111
|
+
task-a = """
|
|
112
|
+
ppqs task-init
|
|
113
|
+
echo task 1
|
|
114
|
+
"""
|
|
115
|
+
task-b = """
|
|
116
|
+
ppqs task-init
|
|
117
|
+
echo task 2
|
|
118
|
+
"""
|
|
119
|
+
all-tasks = """
|
|
120
|
+
ppqs task-a
|
|
121
|
+
ppqs task-b
|
|
122
|
+
"""
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
running `ppqs all-tasks` will only run `ppqs task-init` once:
|
|
126
|
+
```
|
|
127
|
+
$ ppqs all-tasks
|
|
128
|
+
task init
|
|
129
|
+
task 1
|
|
130
|
+
task 2
|
|
131
|
+
```
|
|
132
|
+
|
|
103
133
|
The following only applies to scripts defined as lists of lists:
|
|
104
134
|
|
|
105
135
|
* If a command argument is itself a list, it is concatenated into a path
|
|
@@ -1,3 +1,7 @@
|
|
|
1
|
+
# SPDX-FileCopyrightText: 2025 Karl Wette
|
|
2
|
+
#
|
|
3
|
+
# SPDX-License-Identifier: MIT
|
|
4
|
+
|
|
1
5
|
import glob
|
|
2
6
|
import os
|
|
3
7
|
import re
|
|
@@ -13,7 +17,6 @@ else: # pragma: no cover
|
|
|
13
17
|
import tomli as tomllib
|
|
14
18
|
|
|
15
19
|
__author__ = "Karl Wette"
|
|
16
|
-
__version__ = "2.1.0"
|
|
17
20
|
|
|
18
21
|
|
|
19
22
|
class MissingPyProjectError(Exception):
|
|
@@ -175,6 +178,16 @@ def parse_scripts(pyproject_path):
|
|
|
175
178
|
"commands": script_commands,
|
|
176
179
|
}
|
|
177
180
|
|
|
181
|
+
# Check that recursively run scripts exist
|
|
182
|
+
for script in scripts.values():
|
|
183
|
+
for command in script["commands"]:
|
|
184
|
+
cmd_exec = command[0]
|
|
185
|
+
if cmd_exec == "ppqs":
|
|
186
|
+
script_name_r = command[1]
|
|
187
|
+
if script_name_r not in scripts:
|
|
188
|
+
msg = f"script {script_name_r}' does not exist"
|
|
189
|
+
raise InvalidScriptError(pyproject_path, msg)
|
|
190
|
+
|
|
178
191
|
return project_name, scripts
|
|
179
192
|
|
|
180
193
|
|
|
@@ -206,14 +219,38 @@ def print_help(project_name, scripts):
|
|
|
206
219
|
)
|
|
207
220
|
|
|
208
221
|
|
|
209
|
-
def run_script(
|
|
222
|
+
def run_script(scripts, script_name, argv, cwd, has_been_run):
|
|
210
223
|
"""
|
|
211
224
|
Run a script.
|
|
212
225
|
"""
|
|
226
|
+
|
|
213
227
|
col_width = shutil.get_terminal_size().columns
|
|
228
|
+
|
|
229
|
+
# Mark script has having been run
|
|
230
|
+
has_been_run.add(script_name)
|
|
231
|
+
|
|
232
|
+
script = scripts[script_name]
|
|
214
233
|
for command in script["commands"]:
|
|
215
234
|
cmd = []
|
|
216
235
|
|
|
236
|
+
cmd_exec = command.pop(0)
|
|
237
|
+
if cmd_exec == "ppqs":
|
|
238
|
+
|
|
239
|
+
# Recursively run script
|
|
240
|
+
# - silently ignore scripts which have already been run
|
|
241
|
+
script_name_r = command.pop(0)
|
|
242
|
+
if script_name_r not in has_been_run:
|
|
243
|
+
run_script(scripts, script_name_r, argv, cwd, has_been_run)
|
|
244
|
+
continue
|
|
245
|
+
|
|
246
|
+
elif cmd_exec == "python":
|
|
247
|
+
|
|
248
|
+
# Use same Python as ppqs to run Python scripts
|
|
249
|
+
cmd.append(sys.executable)
|
|
250
|
+
|
|
251
|
+
else:
|
|
252
|
+
cmd.append(cmd_exec)
|
|
253
|
+
|
|
217
254
|
for arg in command:
|
|
218
255
|
if isinstance(arg, Path):
|
|
219
256
|
if "*" in arg.parts[-1]:
|
|
@@ -244,25 +281,35 @@ def run_script(script_name, script, argv, cwd):
|
|
|
244
281
|
raise SystemExit(retn.returncode)
|
|
245
282
|
|
|
246
283
|
|
|
247
|
-
def
|
|
284
|
+
def bash_completion(): # pragma: no cover
|
|
248
285
|
"""
|
|
249
|
-
|
|
286
|
+
Perform Bash command-line completion.
|
|
250
287
|
"""
|
|
251
288
|
|
|
252
289
|
# Parse scripts
|
|
253
290
|
pyproject_path = find_pyproject()
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
#
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
291
|
+
_, scripts = parse_scripts(pyproject_path)
|
|
292
|
+
|
|
293
|
+
# Get current command line
|
|
294
|
+
line = os.environ["COMP_LINE"]
|
|
295
|
+
words = line.split()
|
|
296
|
+
|
|
297
|
+
if line.endswith(" ") and len(words) == 1:
|
|
298
|
+
|
|
299
|
+
# Complete full script name, e.g.:
|
|
300
|
+
# $ ppqs <TAB><TAB>
|
|
301
|
+
for script_name in scripts:
|
|
302
|
+
print(script_name)
|
|
303
|
+
return
|
|
304
|
+
|
|
305
|
+
if not line.endswith(" ") and len(words) == 2:
|
|
306
|
+
|
|
307
|
+
# Complete partial script name, e.g.:
|
|
308
|
+
# $ ppqs nam<TAB>
|
|
309
|
+
for script_name in scripts:
|
|
310
|
+
if script_name.startswith(words[-1]):
|
|
311
|
+
print(script_name)
|
|
312
|
+
return
|
|
266
313
|
|
|
267
314
|
|
|
268
315
|
def cli(*argv):
|
|
@@ -274,32 +321,26 @@ def cli(*argv):
|
|
|
274
321
|
|
|
275
322
|
if argv[0] == "--bash-completion": # pragma: no cover
|
|
276
323
|
|
|
277
|
-
# Perform Bash completion
|
|
278
|
-
# - suppress any error output
|
|
324
|
+
# Perform Bash command-line completion, suppress any errors
|
|
279
325
|
try:
|
|
280
|
-
|
|
281
|
-
_, scripts = parse_scripts(pyproject_path)
|
|
282
|
-
line = os.environ["COMP_LINE"]
|
|
283
|
-
words = line.split()
|
|
284
|
-
if line.endswith(" ") and len(words) == 1:
|
|
285
|
-
|
|
286
|
-
# Complete full script name, e.g.:
|
|
287
|
-
# $ ppqs <TAB><TAB>
|
|
288
|
-
for script_name in scripts:
|
|
289
|
-
print(script_name)
|
|
290
|
-
|
|
291
|
-
if not line.endswith(" ") and len(words) == 2:
|
|
292
|
-
|
|
293
|
-
# Complete partial script name, e.g.:
|
|
294
|
-
# $ ppqs nam<TAB>
|
|
295
|
-
for script_name in scripts:
|
|
296
|
-
if script_name.startswith(words[-1]):
|
|
297
|
-
print(script_name)
|
|
298
|
-
|
|
326
|
+
bash_completion()
|
|
299
327
|
except Exception:
|
|
300
328
|
pass
|
|
301
329
|
|
|
302
330
|
else:
|
|
303
331
|
|
|
304
|
-
# Parse
|
|
305
|
-
|
|
332
|
+
# Parse scripts
|
|
333
|
+
pyproject_path = find_pyproject()
|
|
334
|
+
project_name, scripts = parse_scripts(pyproject_path)
|
|
335
|
+
|
|
336
|
+
# Parse command line
|
|
337
|
+
if argv[0] in ("-h", "-help", "--help"):
|
|
338
|
+
print_help(project_name, scripts)
|
|
339
|
+
raise SystemExit(1)
|
|
340
|
+
elif argv[0] not in scripts:
|
|
341
|
+
msg = f"unknown script '{argv[0]}'"
|
|
342
|
+
raise InvalidScriptError(pyproject_path, msg)
|
|
343
|
+
else:
|
|
344
|
+
cwd = pyproject_path.parent
|
|
345
|
+
has_been_run = set()
|
|
346
|
+
run_script(scripts, argv[0], argv[1:], cwd, has_been_run)
|
|
@@ -1,3 +1,7 @@
|
|
|
1
|
+
# SPDX-FileCopyrightText: 2025 Karl Wette
|
|
2
|
+
#
|
|
3
|
+
# SPDX-License-Identifier: MIT
|
|
4
|
+
|
|
1
5
|
import os
|
|
2
6
|
|
|
3
7
|
import pytest
|
|
@@ -34,6 +38,14 @@ def pyproject_path(tmp_path):
|
|
|
34
38
|
script = [
|
|
35
39
|
["python", "-c", "import sys; print(*sys.argv[1:])", ["subdir", "*.txt"]],
|
|
36
40
|
]
|
|
41
|
+
[tool.ppqs.scripts.greeting]
|
|
42
|
+
script = "echo Hello"
|
|
43
|
+
[tool.ppqs.scripts.farewell]
|
|
44
|
+
script = '''
|
|
45
|
+
ppqs greeting
|
|
46
|
+
ppqs greeting
|
|
47
|
+
echo Goodbye
|
|
48
|
+
'''
|
|
37
49
|
"""
|
|
38
50
|
|
|
39
51
|
write_file(pyproject_path, pyproject_toml)
|
|
@@ -109,3 +121,18 @@ def test_echo_wildcard(pyproject_path, capfd):
|
|
|
109
121
|
captured = capfd.readouterr()
|
|
110
122
|
assert captured.out == "subdir/a.txt subdir/b.txt\n".replace("/", os.sep)
|
|
111
123
|
assert captured.err == ""
|
|
124
|
+
|
|
125
|
+
|
|
126
|
+
def test_recursion(pyproject_path, capfd):
|
|
127
|
+
"""
|
|
128
|
+
Test recursive script running.
|
|
129
|
+
"""
|
|
130
|
+
|
|
131
|
+
with in_dir(pyproject_path.parent):
|
|
132
|
+
cli("farewell")
|
|
133
|
+
captured = capfd.readouterr()
|
|
134
|
+
assert captured.out == "Hello\nGoodbye\n"
|
|
135
|
+
assert captured.err == ""
|
|
136
|
+
|
|
137
|
+
with pytest.raises(InvalidScriptError):
|
|
138
|
+
cli("no-script")
|
|
@@ -1,3 +1,7 @@
|
|
|
1
|
+
# SPDX-FileCopyrightText: 2025 Karl Wette
|
|
2
|
+
#
|
|
3
|
+
# SPDX-License-Identifier: MIT
|
|
4
|
+
|
|
1
5
|
from contextlib import nullcontext
|
|
2
6
|
from pathlib import Path
|
|
3
7
|
|
|
@@ -240,21 +244,14 @@ from . import in_dir, write_file
|
|
|
240
244
|
),
|
|
241
245
|
pytest.param(
|
|
242
246
|
"""
|
|
243
|
-
[tool.ppqs.scripts]
|
|
244
|
-
|
|
245
|
-
["echo", ["a", "*.txt"]],
|
|
246
|
-
]
|
|
247
|
+
[tool.ppqs.scripts.no-script]
|
|
248
|
+
script = "ppqs script-does-not-exist"
|
|
247
249
|
""",
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
"description": "Run paths script",
|
|
252
|
-
"print-header": False,
|
|
253
|
-
"commands": [["echo", Path("a", "*.txt")]],
|
|
254
|
-
}
|
|
255
|
-
}
|
|
250
|
+
pytest.raises(
|
|
251
|
+
InvalidScriptError,
|
|
252
|
+
match="does not exist",
|
|
256
253
|
),
|
|
257
|
-
id="
|
|
254
|
+
id="recursive script does not exist",
|
|
258
255
|
),
|
|
259
256
|
],
|
|
260
257
|
)
|
ppqs-2.1.0/LICENSE
DELETED
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
Copyright 2025 Karl Wette
|
|
2
|
-
|
|
3
|
-
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
|
4
|
-
this software and associated documentation files (the “Software”), to deal in
|
|
5
|
-
the Software without restriction, including without limitation the rights to
|
|
6
|
-
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
|
7
|
-
the Software, and to permit persons to whom the Software is furnished to do so,
|
|
8
|
-
subject to the following conditions:
|
|
9
|
-
|
|
10
|
-
The above copyright notice and this permission notice shall be included in all
|
|
11
|
-
copies or substantial portions of the Software.
|
|
12
|
-
|
|
13
|
-
THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
14
|
-
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
|
15
|
-
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
|
16
|
-
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
|
17
|
-
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
|
18
|
-
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|