devklean 1.0.0__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.
Files changed (49) hide show
  1. devklean/__init__.py +6 -0
  2. devklean/__main__.py +4 -0
  3. devklean/_version.py +8 -0
  4. devklean/cli/__init__.py +3 -0
  5. devklean/cli/commands/__init__.py +4 -0
  6. devklean/cli/commands/clean.py +106 -0
  7. devklean/cli/commands/common.py +38 -0
  8. devklean/cli/commands/doctor.py +43 -0
  9. devklean/cli/commands/history.py +14 -0
  10. devklean/cli/commands/restore.py +20 -0
  11. devklean/cli/commands/scan.py +16 -0
  12. devklean/cli/confirmation.py +51 -0
  13. devklean/cli/dispatcher.py +45 -0
  14. devklean/cli/main.py +61 -0
  15. devklean/cli/parser.py +164 -0
  16. devklean/config/__init__.py +15 -0
  17. devklean/config/defaults.py +14 -0
  18. devklean/config/manager.py +226 -0
  19. devklean/config/models.py +48 -0
  20. devklean/config/paths.py +24 -0
  21. devklean/config/targets.py +23 -0
  22. devklean/deletion/__init__.py +17 -0
  23. devklean/deletion/history.py +66 -0
  24. devklean/deletion/integrity.py +39 -0
  25. devklean/deletion/metadata.py +198 -0
  26. devklean/deletion/paths.py +24 -0
  27. devklean/deletion/safety.py +176 -0
  28. devklean/deletion/trash.py +89 -0
  29. devklean/formatting.py +31 -0
  30. devklean/logging_setup.py +74 -0
  31. devklean/models.py +34 -0
  32. devklean/output/__init__.py +5 -0
  33. devklean/output/base.py +38 -0
  34. devklean/output/console.py +94 -0
  35. devklean/output/history_payload.py +34 -0
  36. devklean/output/json.py +75 -0
  37. devklean/output/scan_payload.py +51 -0
  38. devklean/output/sorting.py +12 -0
  39. devklean/output/text.py +183 -0
  40. devklean/output/theme.py +46 -0
  41. devklean/scanner/__init__.py +17 -0
  42. devklean/scanner/filters.py +32 -0
  43. devklean/scanner/scanner.py +170 -0
  44. devklean/tui.py +126 -0
  45. devklean-1.0.0.dist-info/METADATA +257 -0
  46. devklean-1.0.0.dist-info/RECORD +49 -0
  47. devklean-1.0.0.dist-info/WHEEL +4 -0
  48. devklean-1.0.0.dist-info/entry_points.txt +2 -0
  49. devklean-1.0.0.dist-info/licenses/LICENSE +21 -0
@@ -0,0 +1,257 @@
1
+ Metadata-Version: 2.4
2
+ Name: devklean
3
+ Version: 1.0.0
4
+ Summary: Clean up common development artifacts (node_modules, .venv, caches) to reclaim disk space
5
+ Project-URL: Homepage, https://github.com/smurftyy/devklean
6
+ Project-URL: Repository, https://github.com/smurftyy/devklean
7
+ Project-URL: Issues, https://github.com/smurftyy/devklean/issues
8
+ Project-URL: Changelog, https://github.com/smurftyy/devklean/blob/main/CHANGELOG.md
9
+ Author-email: smurftyy <oladapooloyede185@gmail.com>
10
+ License-Expression: MIT
11
+ License-File: LICENSE
12
+ Keywords: cleanup,cli,development,disk-space,node_modules,venv
13
+ Classifier: Development Status :: 5 - Production/Stable
14
+ Classifier: Environment :: Console
15
+ Classifier: Intended Audience :: Developers
16
+ Classifier: Intended Audience :: End Users/Desktop
17
+ Classifier: Operating System :: OS Independent
18
+ Classifier: Programming Language :: Python :: 3
19
+ Classifier: Programming Language :: Python :: 3.8
20
+ Classifier: Programming Language :: Python :: 3.9
21
+ Classifier: Programming Language :: Python :: 3.10
22
+ Classifier: Programming Language :: Python :: 3.11
23
+ Classifier: Programming Language :: Python :: 3.12
24
+ Classifier: Topic :: System :: Filesystems
25
+ Classifier: Topic :: Utilities
26
+ Requires-Python: >=3.8
27
+ Requires-Dist: send2trash>=1.8.2
28
+ Requires-Dist: tomli>=2.0.0; python_version < '3.11'
29
+ Provides-Extra: dev
30
+ Requires-Dist: build>=1.0; extra == 'dev'
31
+ Requires-Dist: mypy>=1.8; extra == 'dev'
32
+ Requires-Dist: pytest-cov>=4.0; extra == 'dev'
33
+ Requires-Dist: pytest>=7.0; extra == 'dev'
34
+ Requires-Dist: ruff>=0.6; extra == 'dev'
35
+ Description-Content-Type: text/markdown
36
+
37
+ # devklean
38
+
39
+ [![CI](https://github.com/smurftyy/devklean/actions/workflows/ci.yml/badge.svg)](https://github.com/smurftyy/devklean/actions/workflows/ci.yml)
40
+ [![PyPI version](https://img.shields.io/pypi/v/devklean.svg)](https://pypi.org/project/devklean/)
41
+ [![Python versions](https://img.shields.io/pypi/pyversions/devklean.svg)](https://pypi.org/project/devklean/)
42
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://github.com/smurftyy/devklean/blob/main/LICENSE)
43
+
44
+ **Reclaim disk space by safely cleaning up development artifacts** — `node_modules`, `.venv`, build caches, and other regenerable directories — with a trash-backed safety net so nothing is ever lost to a typo.
45
+
46
+ <!-- TODO: insert terminal recording GIF of `devklean clean` here -->
47
+
48
+ ## Why
49
+
50
+ Development trees accumulate gigabytes of regenerable junk. `devklean` finds it, shows you exactly what it found and how big it is, and removes it **to your native system trash** — the Recycle Bin on Windows, Trash on macOS, the freedesktop trash on Linux — not `rm -rf`, so a mistaken delete is recoverable from your trash. It refuses to touch dangerous paths, makes large deletions require an explicit typed confirmation, and keeps a history of what it removed.
51
+
52
+ ## Installation
53
+
54
+ ```bash
55
+ # Recommended: isolated install as a standalone CLI tool
56
+ pipx install devklean
57
+
58
+ # Or into the current environment
59
+ pip install devklean
60
+ ```
61
+
62
+ Requires Python 3.8+. Runtime dependencies are `send2trash` (used for all deletions) and `tomli` (only on Python < 3.11).
63
+
64
+ ## Quick start
65
+
66
+ ```bash
67
+ # See what could be cleaned under the current directory — no changes made
68
+ devklean scan
69
+
70
+ # Scan and delete (with confirmation), moving items to the trash
71
+ devklean clean
72
+
73
+ # Preview a clean without deleting anything
74
+ devklean clean --dry-run
75
+ ```
76
+
77
+ ## Commands
78
+
79
+ | Command | What it does |
80
+ | --- | --- |
81
+ | `devklean scan [PATH]` | Find cleanable directories and report sizes. Never deletes. |
82
+ | `devklean clean [PATH]` | Scan, then delete (to trash) after confirmation. |
83
+ | `devklean restore` | Explain how to recover deleted items from your system trash. |
84
+ | `devklean history` | Show previous cleanup operations (timestamp, size, strategy, item count). |
85
+ | `devklean doctor` | Inspect and repair the deletion metadata store. |
86
+ | `devklean --version` | Print the version. |
87
+
88
+ **Default command:** running `devklean` with no subcommand defaults to `clean` — so `devklean` is `devklean clean`, and `devklean ~/code` is `devklean clean ~/code`. As a convenience, a bare `devklean --dry-run` (without `-i`) is treated as a `scan` preview.
89
+
90
+ ### `scan`
91
+
92
+ ```bash
93
+ devklean scan # scan current directory
94
+ devklean scan ~/projects # scan a specific path
95
+ devklean scan --json # machine-readable output for tooling
96
+ ```
97
+
98
+ ### `clean`
99
+
100
+ ```bash
101
+ devklean clean # scan + delete with a y/N confirmation
102
+ devklean clean ~/projects # clean a specific path
103
+ devklean clean --dry-run # show what *would* be deleted; delete nothing
104
+ devklean clean -i # interactive: pick items in a TUI (Linux/macOS only)
105
+ devklean clean --allow-symlinks # permit deleting symlinked targets (blocked by default)
106
+ devklean clean -y # skip the y/N prompt (large deletions still require typing DELETE)
107
+ ```
108
+
109
+ | Flag | Meaning |
110
+ | --- | --- |
111
+ | `--dry-run` | Report what would be deleted; make no changes. Output says "would delete". |
112
+ | `-i`, `--interactive` | Choose items in a terminal UI (SPACE select, A all, D none, ENTER confirm, Q quit). **Linux/macOS only** — see [Platform support](#platform-support). |
113
+ | `--allow-symlinks` | Allow deleting symbolic links. Off by default (symlinks are blocked). |
114
+ | `-y`, `--yes` | Skip the standard confirmation. Deletions over the size threshold still require typing `DELETE`. |
115
+
116
+ ### `restore`
117
+
118
+ devklean moves items to your operating system's own trash, which the OS owns —
119
+ so recovery is done through your file manager's trash, not through devklean.
120
+ This command just shows you how:
121
+
122
+ ```bash
123
+ devklean restore # explains how to recover from the Recycle Bin / Trash
124
+ ```
125
+
126
+ - **Windows** — open the Recycle Bin and restore the item.
127
+ - **macOS** — open Trash in Finder and "Put Back".
128
+ - **Linux** — open Trash in your file manager and restore.
129
+
130
+ Run `devklean history` to see what was removed and when.
131
+
132
+ ### `history`
133
+
134
+ ```bash
135
+ devklean history # human-readable table of past cleanups
136
+ devklean history --json # machine-readable
137
+ ```
138
+
139
+ ### `doctor`
140
+
141
+ ```bash
142
+ devklean doctor # report corrupt metadata; prompt before removing it
143
+ devklean doctor --yes # remove corrupt records without prompting
144
+ ```
145
+
146
+ ## Usage example
147
+
148
+ ```text
149
+ $ devklean clean ~/code/my-app
150
+ devklean scanning /home/me/code/my-app...
151
+
152
+ TYPE SIZE PATH
153
+ ──────────────────────────────────────────────────────────────────────
154
+ Node.js 612.0 MB /home/me/code/my-app/node_modules
155
+ Python venv 188.0 MB /home/me/code/my-app/.venv
156
+ Build output 34.0 MB /home/me/code/my-app/dist
157
+ ──────────────────────────────────────────────────────────────────────
158
+ TOTAL 834.0 MB
159
+
160
+ Delete 3 directories (~834.0 MB)? (y/N) y
161
+
162
+ ✓ /home/me/code/my-app/node_modules
163
+ ✓ /home/me/code/my-app/.venv
164
+ ✓ /home/me/code/my-app/dist
165
+
166
+ ✓ Cleaned 3 directories, freed ~834.0 MB.
167
+ ```
168
+
169
+ <!-- TODO: insert terminal recording GIF of interactive mode (`devklean clean -i`) here -->
170
+
171
+ ## Platform support
172
+
173
+ `devklean` runs on **Linux, macOS, and Windows**. All core commands — `scan`,
174
+ `clean`, `history`, `doctor`, and `restore` — work on every platform.
175
+
176
+ **Known limitation:** interactive mode (`-i` / `--interactive`) is **Linux/macOS
177
+ only** for now. It is built on Python's `curses` module, which is not available
178
+ on Windows. Running `devklean clean -i` on Windows prints a clear message and
179
+ exits without making changes, rather than crashing — use `devklean clean`
180
+ (non-interactive) instead. Windows support for interactive mode may come in a
181
+ future release.
182
+
183
+ ## Configuration
184
+
185
+ `devklean` reads TOML config with the precedence **project > global > built-in defaults**:
186
+
187
+ 1. A project file `.devklean.toml`, discovered by walking up from the current directory.
188
+ 2. The global file `~/.config/devklean/config.toml` (or `$XDG_CONFIG_HOME/devklean/config.toml`).
189
+
190
+ ```toml
191
+ # ~/.config/devklean/config.toml or ./.devklean.toml
192
+
193
+ # Directory names to never touch (merged into the ignore list)
194
+ exclude = ["node_modules", ".git"]
195
+
196
+ [defaults]
197
+ dry_run = false
198
+ interactive = false
199
+ default_yes = false # skip the y/N prompt (the large-deletion DELETE gate still applies)
200
+ theme = "default" # "default" or "mono"
201
+ confirm_threshold = 1073741824 # bytes; deletions >= this require typing DELETE (default 1 GiB)
202
+ path = "."
203
+
204
+ [targets]
205
+ exclude = ["dist"] # remove built-in target *types*
206
+ [targets.custom]
207
+ ".turbo" = "Turborepo cache" # add custom target directory types
208
+
209
+ [ignore]
210
+ paths = ["/keep/this/node_modules"] # absolute paths to skip
211
+ directories = ["vendor"] # directory names to skip
212
+ ```
213
+
214
+ Scalar keys from the project file override the global file; list keys (`exclude`, `ignore.*`) are unioned. Unknown keys and malformed TOML produce a warning rather than a crash.
215
+
216
+ Color follows the `theme` setting and is automatically disabled when output is piped or `NO_COLOR` is set.
217
+
218
+ ## Logs
219
+
220
+ `devklean` writes detailed structured logs (commands, scanned/deleted paths, sizes, errors) to:
221
+
222
+ ```
223
+ ~/.cache/devklean/logs/latest.log # or $XDG_CACHE_HOME/devklean/logs/latest.log
224
+ ```
225
+
226
+ Logs rotate (5 backups) and are kept entirely separate from terminal output.
227
+
228
+ ## FAQ
229
+
230
+ **Why didn't it delete something?**
231
+ `devklean` refuses to delete paths that should never be removed: the filesystem root, your home directory, mounted drive roots, protected system directories (`/etc`, `/usr`, …), and symbolic links. Symlinks can be allowed with `--allow-symlinks`. Each refusal prints the specific reason.
232
+
233
+ **It asked me to type `DELETE` — why?**
234
+ Deletions whose total size meets the `confirm_threshold` (default 1 GiB) require an explicit typed confirmation as an extra guard against large accidental deletes. This gate is intentionally **not** bypassed by `--yes` or `default_yes`; only `--dry-run` skips it.
235
+
236
+ **Where do deleted files go? Can I get them back?**
237
+ Items are moved to your operating system's native trash (Recycle Bin on Windows, Trash on macOS, the freedesktop trash on Linux), not permanently deleted. Recover them through your file manager's trash UI — devklean does not own that trash and can't move items back. Run `devklean history` to see what was removed, or `devklean restore` for recovery instructions.
238
+
239
+ **How do I exclude a folder?**
240
+ Add its name to `exclude` (global or project `.devklean.toml`), or an absolute path to `[ignore].paths`. See [Configuration](#configuration).
241
+
242
+ **Where are the logs?**
243
+ `~/.cache/devklean/logs/latest.log` (see [Logs](#logs)).
244
+
245
+ **How do I turn off colors?**
246
+ Set `NO_COLOR=1`, pipe the output, or set `theme = "mono"` in config.
247
+
248
+ **Something looks wrong with my history data.**
249
+ Run `devklean doctor` to detect and remove corrupt metadata records.
250
+
251
+ ## Contributing
252
+
253
+ See [CONTRIBUTING.md](CONTRIBUTING.md). Bug reports and PRs are welcome.
254
+
255
+ ## License
256
+
257
+ MIT — see [LICENSE](LICENSE).
@@ -0,0 +1,49 @@
1
+ devklean/__init__.py,sha256=ZGl68XBGj7V-2xjqilodvXiE_hn298QPRkgzR0VefsA,270
2
+ devklean/__main__.py,sha256=kqUyX7bo1E6P8gwEAkb5E5K1CFyUPZoaEobocmSGFaI,69
3
+ devklean/_version.py,sha256=3ntxAdhBWQkOtQ61NwSW-mQEEp4lHPrJOUeo8JZSAow,260
4
+ devklean/formatting.py,sha256=GkzW0jot-WA2Y_mpv0R94LBH8bVxQnuJYAn8hK6k3cs,817
5
+ devklean/logging_setup.py,sha256=MirR0UfG5NYhs9-Yq91wdB3zWXf6UF5bo_eOOb3PtC8,2433
6
+ devklean/models.py,sha256=73QtNKOVOqp4oNP2Qcs1zvn_XqpxLo7zep0LN5fPi78,617
7
+ devklean/tui.py,sha256=-UNRK0I36QXaCsUZEbty5Rx0K3o5exilXYwL3B6NpVQ,4164
8
+ devklean/cli/__init__.py,sha256=g69W-cFS7OA24QUKcP5m3hSnaW86BUHExdwP01peLvg,55
9
+ devklean/cli/confirmation.py,sha256=ldd_aaeiT0cEl6acRmHuB_UVz63zNLbxFfQ8jztU-t4,1905
10
+ devklean/cli/dispatcher.py,sha256=jA3STlpE7YK-bKpbASflBPhG3UFzHrQvjiIQ1wicpaE,1504
11
+ devklean/cli/main.py,sha256=in54Xq-vGJedKHjvOn6HpCIQbLLFTICb_6hgsMnTWM8,2184
12
+ devklean/cli/parser.py,sha256=tBppyIBAFrU04tANctK-J6YTbakL7CQi05yC1w2A0YU,5086
13
+ devklean/cli/commands/__init__.py,sha256=_cD7RwBtn3JGsJuL9T78jseExPlZvXhqmPinFc2dj9U,135
14
+ devklean/cli/commands/clean.py,sha256=kUVUznlfW1-QwxMUv_hEg9RyT1FzZcpoOYSGC5kil6U,3321
15
+ devklean/cli/commands/common.py,sha256=T5hVXFiXn7Jau9C5lLqHsLtoDslJW3GYyBle4pVKJO4,1064
16
+ devklean/cli/commands/doctor.py,sha256=rHwBRV3_iInuPaBfNpG-GCNJYhQaQU9u-kIvfo1eX_g,1242
17
+ devklean/cli/commands/history.py,sha256=DJenCPVZOUCNtUER6x9vxAna4Pet5FF9JPXYdBahvM4,539
18
+ devklean/cli/commands/restore.py,sha256=YbOX3V9tarILxno0_bZCUwoayIggwE7plLq2M3QtLxI,670
19
+ devklean/cli/commands/scan.py,sha256=X19cmAOA9-dALxcl_nDt_-ofnMvZrrW_nX8khoOy6Xg,539
20
+ devklean/config/__init__.py,sha256=pCuU0p-6uksmnygP3fkoYXcVhwEx1fKedXqKb0SxMqI,440
21
+ devklean/config/defaults.py,sha256=KrmYjMEgfLCFhkiLgi62e9piNP2YWSWz_Dzbb-4FegU,345
22
+ devklean/config/manager.py,sha256=MDdOgdY4FtAUAxAIlK2Jw5cnf0C6cNA-v6hGLSoQxCM,7626
23
+ devklean/config/models.py,sha256=5Z1ATDfC-M-c0cAhQhUWjG2BWNsXHLfzWVASAz1hDKA,1451
24
+ devklean/config/paths.py,sha256=Fk3bIF4FXhAEKl0xx2fNtMaAWgYVwxapgg04AzUcWiI,765
25
+ devklean/config/targets.py,sha256=-B2zqSt3GyKGdy-1lvbcwprTLoCC_4LsEjtT9Y_qle0,560
26
+ devklean/deletion/__init__.py,sha256=71GdPX5t6YL5NtlfDuourQ9OqmPdEav_Vb21RcvFdh0,528
27
+ devklean/deletion/history.py,sha256=tflDTVlEW9xvQtdrWfKTq42pJsdw9PjPkJfKR8I1Erk,1953
28
+ devklean/deletion/integrity.py,sha256=nwavIjqz_eoG_OvrrrBwrwtAkhrCdexo9sT9p9mG9yI,1117
29
+ devklean/deletion/metadata.py,sha256=HT5ApjDUB4hm1lHRZSOYtQpM1HyavWGSt152lM2nyh4,6278
30
+ devklean/deletion/paths.py,sha256=eVOXIixkxTgsGehxtKIl9v9Xy2X4yBQAZG2X9W3CuNs,772
31
+ devklean/deletion/safety.py,sha256=VPJynVy0id478nGDb6T0bEnhsG2Tm5bE9jrINAl2x4I,5621
32
+ devklean/deletion/trash.py,sha256=fYafOvLYZisLvwoxbRE3s5X_0lhsxRPLu9D206CfKtc,3270
33
+ devklean/output/__init__.py,sha256=qv0VEHgaRqYRq9R9p7wiv8luji-0qEsXv6Oiaky-C7w,190
34
+ devklean/output/base.py,sha256=gzylNsCyv8WgIsAPTpnry4VvaaZpBWQEnzBB1ygA_Vg,1037
35
+ devklean/output/console.py,sha256=CErmuXPmxXx-lotW_2Yzk5JcUWsk5G_JW-yXXDghKXc,2767
36
+ devklean/output/history_payload.py,sha256=nKWs9lldXU1uW6CDPQGCrXgmUosFMcbnjKJ4jlehG5g,1156
37
+ devklean/output/json.py,sha256=B7hvYFfDLhTFuuiw1_9KSAhIjN_lquABbSmTPk-I7-s,2273
38
+ devklean/output/scan_payload.py,sha256=-DislAeiqFz8VzmjP9p5MNZwsmNLnEo_8pbGSKYdAFw,1381
39
+ devklean/output/sorting.py,sha256=-3Y4xZNScFPznCIOUYMRBwTZ5NnZPZS_JTHgnetcmW4,434
40
+ devklean/output/text.py,sha256=RXbNFEvVPKTAoo9PRurCbZ2pMqyiYShku61p2ssNXDw,7032
41
+ devklean/output/theme.py,sha256=ryv0GjlKFD2STiUcjSo9z-pXvK6diZvShVwEnO6BfNY,922
42
+ devklean/scanner/__init__.py,sha256=FY3fddVXtbawnn00a1XIGZiG_v6fH4S9OuGW7pcjYgI,414
43
+ devklean/scanner/filters.py,sha256=LJnc-NiHFuqfwSZODxNuY63f8asbPYCmx3stlKx5fGg,1124
44
+ devklean/scanner/scanner.py,sha256=5ZPze62Ush0eOZDKIcCrnwG-nGeNmQvqH2qXAtxrQL0,6784
45
+ devklean-1.0.0.dist-info/METADATA,sha256=qcn7_7GzMeNduE9zHyEY_4XgyGCPppA4qsStBwRFnXg,11177
46
+ devklean-1.0.0.dist-info/WHEEL,sha256=mffPy8wBnZQn2VnJUU5jE99KsxaSfiyMHV9Yt0aLVxs,87
47
+ devklean-1.0.0.dist-info/entry_points.txt,sha256=2sfmv0MdTQjlDndGdj5h9w2f-YTAHeL91Ibc8L-T_58,52
48
+ devklean-1.0.0.dist-info/licenses/LICENSE,sha256=n1AGmToEZdT_uH_-ALQxahLbYSQKyURxtzAAm6GL8Mk,1065
49
+ devklean-1.0.0.dist-info/RECORD,,
@@ -0,0 +1,4 @@
1
+ Wheel-Version: 1.0
2
+ Generator: hatchling 1.30.1
3
+ Root-Is-Purelib: true
4
+ Tag: py3-none-any
@@ -0,0 +1,2 @@
1
+ [console_scripts]
2
+ devklean = devklean.cli.main:main
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 smurftyy
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.