cribo 0.0.0.dev118__py3-none-win_amd64.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.
cribo/__init__.py ADDED
@@ -0,0 +1,11 @@
1
+ """
2
+ Cribo: Python Source Bundler
3
+
4
+ A tool that produces a single .py file from a multi-module Python project
5
+ by inlining all first-party source files.
6
+
7
+ This package provides the `cribo` command-line tool.
8
+ The main interface is the CLI binary, not Python imports.
9
+ """
10
+
11
+ __version__ = "0.1.0"
cribo/__main__.py ADDED
@@ -0,0 +1,27 @@
1
+ """
2
+ Command-line interface for cribo.
3
+
4
+ This module provides access to the cribo CLI when called as `python -m cribo`.
5
+ The main interface is the binary `cribo` command.
6
+ """
7
+
8
+ import subprocess
9
+ import sys
10
+
11
+
12
+ def main() -> None:
13
+ """Main entry point that delegates to the cribo binary."""
14
+ try:
15
+ # Call the cribo binary with the same arguments
16
+ result = subprocess.run(["cribo"] + sys.argv[1:], check=False)
17
+ sys.exit(result.returncode)
18
+ except FileNotFoundError:
19
+ print(
20
+ "cribo binary not found. Please ensure cribo is properly installed.",
21
+ file=sys.stderr,
22
+ )
23
+ sys.exit(1)
24
+
25
+
26
+ if __name__ == "__main__":
27
+ main()
cribo/py.typed ADDED
@@ -0,0 +1,22 @@
1
+ """Type stubs for serpen"""
2
+
3
+ class Bundler:
4
+ """Python source bundler that produces a single .py file from multi-module projects."""
5
+
6
+ def __init__(self) -> None:
7
+ """Initialize a new bundler with default configuration."""
8
+ ...
9
+
10
+ def bundle(self, entry_path: str, output_path: str, emit_requirements: bool = False) -> None:
11
+ """
12
+ Bundle a Python project into a single file.
13
+
14
+ Args:
15
+ entry_path: Path to the entry point Python script
16
+ output_path: Path where the bundled output will be written
17
+ emit_requirements: Whether to generate a requirements.txt file
18
+
19
+ Raises:
20
+ RuntimeError: If bundling fails
21
+ """
22
+ ...
@@ -0,0 +1,475 @@
1
+ Metadata-Version: 2.4
2
+ Name: cribo
3
+ Version: 0.0.0.dev118
4
+ Classifier: Development Status :: 3 - Alpha
5
+ Classifier: Intended Audience :: Developers
6
+ Classifier: License :: OSI Approved :: MIT License
7
+ Classifier: Programming Language :: Python :: 3
8
+ Classifier: Programming Language :: Python :: 3.10
9
+ Classifier: Programming Language :: Python :: 3.11
10
+ Classifier: Programming Language :: Python :: 3.12
11
+ Classifier: Programming Language :: Rust
12
+ Classifier: Topic :: Software Development :: Build Tools
13
+ Classifier: Topic :: Software Development :: Libraries :: Python Modules
14
+ License-File: LICENSE
15
+ Summary: Python source bundler that produces a single .py file from multi-module projects
16
+ Keywords: bundler,python,deployment,pyspark,lambda
17
+ Author-email: Konstantin Vyatkin <tino@vtkn.io>
18
+ Requires-Python: >=3.8
19
+ Description-Content-Type: text/markdown; charset=UTF-8; variant=GFM
20
+ Project-URL: Homepage, https://github.com/ophidiarium/cribo
21
+ Project-URL: Repository, https://github.com/ophidiarium/cribo
22
+ Project-URL: Documentation, https://github.com/ophidiarium/cribo#readme
23
+ Project-URL: Issues, https://github.com/ophidiarium/cribo/issues
24
+
25
+ # Cribo: Python Source Bundler
26
+
27
+ [![PyPI](https://img.shields.io/pypi/v/cribo.svg)](https://pypi.org/project/cribo/)
28
+ [![npm](https://img.shields.io/npm/v/cribo.svg)](https://www.npmjs.com/package/cribo)
29
+ [![codecov](https://codecov.io/gh/ophidiarium/cribo/graph/badge.svg?token=Lt1VqlIEqV)](https://codecov.io/gh/ophidiarium/cribo)
30
+ [![Maintainability Rating](https://sonarcloud.io/api/project_badges/measure?project=ophidiarium_cribo&metric=sqale_rating)](https://sonarcloud.io/summary/new_code?id=ophidiarium_cribo)
31
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
32
+
33
+ **Cribo** is a Rust-based CLI tool that, via fast, heuristically proven bundling, consolidates a scattered Python codebaseβ€”from a single entry point or monorepoβ€”into one idiomatic `.py` file. This not only streamlines deployment in environments like PySpark, AWS Lambda, and notebooks but also makes ingesting Python codebases into AI models easier and more cost-effective while preserving full functional insights.
34
+
35
+ ## What is "Cribo"?
36
+
37
+ *Cribo* is named after the [Mussurana snake](https://a-z-animals.com/animals/mussurana-snake/) (*Clelia clelia*), nicknamed "Cribo" in Latin America. Just like the real Cribo specializes in hunting and neutralizing venomous snakes (with a diet that's 70-80% other snakes!), our tool wrangles Python dependencies and circular imports with ease. Brazilian farmers even keep Cribos around for natural pest controlβ€”think of this as the Python ecosystem's answer to dependency chaos. In short:*Cribo eats tricky imports for breakfast, so your code doesn't have to*!
38
+
39
+ ## Features
40
+
41
+ - πŸ¦€ **Rust-based CLI** based on Ruff's Python AST parser
42
+ - 🐍 Can be installed via `pip install cribo` or `npm install cribo`
43
+ - 😎 Contemporary minds can also use `uvx cribo` or `bunx cribo`
44
+ - 🌲 **Tree-shaking** (enabled by default) to inline only the modules that are actually used
45
+ - πŸ”„ **Circular dependency resolution** using Tarjan's strongly connected components (SCC) analysis and function-level lazy import transformations, with detailed diagnostics
46
+ - 🧹 **Unused import trimming** to clean up Python files standalone
47
+ - πŸ“¦ **Requirements generation** with optional `requirements.txt` output
48
+ - πŸ”§ **Configurable** import classification and source directories
49
+ - πŸš€ **Fast** and memory-efficient
50
+
51
+ ## Reliability and Production Readiness
52
+
53
+ Cribo is built with production use cases in mind and is rigorously tested to ensure reliability and performance. You can confidently use it for production-grade code, backed by the following guarantees:
54
+
55
+ - **Comprehensive Test Suite**: Cribo is continuously validated against a set of approximately 100 test fixtures that cover the full spectrum of Python's import systemβ€”from simple relative imports to complex scenarios involving circular dependencies and `importlib` constructs.
56
+
57
+ - **Real-World Ecosystem Testing**: As part of every pull request, we run an "ecosystem" test suite. This involves bundling several popular open-source libraries (such as `requests`, `httpx`, `pyyaml`, `idna`, and `rich`) and executing test code against the resulting bundle to ensure real-world compatibility.
58
+
59
+ - **Performance Monitoring**: We monitor microbenchmark regressions and ecosystem build time/size performance with every change. This ensures that Cribo's performance and efficiency are maintained and improved over time, preventing regressions from making their way into releases.
60
+
61
+ ## Installation
62
+
63
+ > **πŸ” Supply Chain Security**: All npm and pypi packages include provenance attestations for enhanced security and verification.
64
+
65
+ ### From PyPI (Python Package)
66
+
67
+ ```bash
68
+ pip install cribo
69
+ ```
70
+
71
+ ### From npm (Node.js CLI)
72
+
73
+ ```bash
74
+ # Global installation
75
+ npm install -g cribo
76
+
77
+ # One-time use
78
+ bunx cribo --help
79
+ ```
80
+
81
+ ### Binary Downloads
82
+
83
+ Download pre-built binaries for your platform from the [latest release](https://github.com/ophidiarium/cribo/releases/latest):
84
+
85
+ - **Linux x86_64**: `cribo_<version>_linux_x86_64.tar.gz`
86
+ - **Linux ARM64**: `cribo_<version>_linux_arm64.tar.gz`
87
+ - **macOS x86_64**: `cribo_<version>_darwin_x86_64.tar.gz`
88
+ - **macOS ARM64**: `cribo_<version>_darwin_arm64.tar.gz`
89
+ - **Windows x86_64**: `cribo_<version>_windows_x86_64.zip`
90
+ - **Windows ARM64**: `cribo_<version>_windows_arm64.zip`
91
+
92
+ Each binary includes a SHA256 checksum file for verification.
93
+
94
+ ### Package Manager Installation
95
+
96
+ #### Aqua
97
+
98
+ If you use [Aqua](https://aquaproj.github.io/), add to your `aqua.yaml`:
99
+
100
+ ```yaml
101
+ registries:
102
+ - type: standard
103
+ ref: latest
104
+ packages:
105
+ - name: ophidiarium/cribo@latest
106
+ ```
107
+
108
+ Then run:
109
+
110
+ ```bash
111
+ aqua install
112
+ ```
113
+
114
+ #### UBI (Universal Binary Installer)
115
+
116
+ Using [UBI](https://github.com/houseabsolute/ubi):
117
+
118
+ ```bash
119
+ # Install latest version
120
+ ubi --project ophidiarium/cribo
121
+
122
+ # Install specific version
123
+ ubi --project ophidiarium/cribo --tag v0.4.1
124
+
125
+ # Install to specific directory
126
+ ubi --project ophidiarium/cribo --in /usr/local/bin
127
+ ```
128
+
129
+ ### From Source
130
+
131
+ ```bash
132
+ git clone https://github.com/ophidiarium/cribo.git
133
+ cd cribo
134
+ cargo build --release
135
+ ```
136
+
137
+ ## Quick Start
138
+
139
+ ### Command Line Usage
140
+
141
+ ```bash
142
+ # Basic bundling
143
+ cribo --entry src/main.py --output bundle.py
144
+
145
+ # Bundle a package directory (looks for __main__.py or __init__.py)
146
+ cribo --entry mypackage/ --output bundle.py
147
+
148
+ # Generate requirements.txt
149
+ cribo --entry src/main.py --output bundle.py --emit-requirements
150
+
151
+ # Verbose output (can be repeated for more detail: -v, -vv, -vvv)
152
+ cribo --entry src/main.py --output bundle.py -v
153
+ cribo --entry src/main.py --output bundle.py -vv # debug level
154
+ cribo --entry src/main.py --output bundle.py -vvv # trace level
155
+
156
+ # Custom config file
157
+ cribo --entry src/main.py --output bundle.py --config my-cribo.toml
158
+ ```
159
+
160
+ ### CLI Options
161
+
162
+ - `-e, --entry <PATH>`: Entry point Python script or package directory (required). When pointing to a directory, Cribo will look for `__main__.py` first, then `__init__.py`
163
+ - `-o, --output <PATH>`: Output bundled Python file (required)
164
+ - `-v, --verbose...`: Increase verbosity level. Can be repeated for more detail:
165
+ - No flag: warnings and errors only
166
+ - `-v`: informational messages
167
+ - `-vv`: debug messages
168
+ - `-vvv` or more: trace messages
169
+ - `-c, --config <PATH>`: Custom configuration file path
170
+ - `--emit-requirements`: Generate requirements.txt with third-party dependencies
171
+ - `--no-tree-shake`: Disable tree-shaking optimization (tree-shaking is enabled by default)
172
+ - `--target-version <VERSION>`: Target Python version (e.g., py38, py39, py310, py311, py312, py313)
173
+ - `-h, --help`: Print help information
174
+ - `-V, --version`: Print version information
175
+
176
+ The verbose flag is particularly useful for debugging bundling issues. Each level provides progressively more detail:
177
+
178
+ ```bash
179
+ # Default: only warnings and errors
180
+ cribo --entry main.py --output bundle.py
181
+
182
+ # Info level: shows progress messages
183
+ cribo --entry main.py --output bundle.py -v
184
+
185
+ # Debug level: shows detailed processing steps
186
+ cribo --entry main.py --output bundle.py -vv
187
+
188
+ # Trace level: shows all internal operations
189
+ cribo --entry main.py --output bundle.py -vvv
190
+ ```
191
+
192
+ The verbose levels map directly to Rust's log levels and can also be controlled via the `RUST_LOG` environment variable for more fine-grained control:
193
+
194
+ ```bash
195
+ # Equivalent to -vv
196
+ RUST_LOG=debug cribo --entry main.py --output bundle.py
197
+
198
+ # Module-specific logging
199
+ RUST_LOG=cribo::bundler=trace,cribo::resolver=debug cribo --entry main.py --output bundle.py
200
+ ```
201
+
202
+ ### Tree-Shaking
203
+
204
+ Tree-shaking is enabled by default to reduce bundle size by removing unused code:
205
+
206
+ ```bash
207
+ # Bundle with tree-shaking (default behavior)
208
+ cribo --entry main.py --output bundle.py
209
+
210
+ # Disable tree-shaking to include all code
211
+ cribo --entry main.py --output bundle.py --no-tree-shake
212
+ ```
213
+
214
+ **How it works:**
215
+
216
+ - Analyzes your code starting from the entry point
217
+ - Tracks which functions, classes, and variables are actually used
218
+ - Removes unused symbols while preserving functionality
219
+ - Respects `__all__` declarations and module side effects
220
+ - Preserves all symbols from directly imported modules (`import module`)
221
+
222
+ **When to disable tree-shaking:**
223
+
224
+ - If you encounter undefined symbol errors with complex circular dependencies
225
+ - When you need to preserve all code for dynamic imports or reflection
226
+ - For debugging purposes to see the complete bundled output
227
+
228
+ ## Configuration
229
+
230
+ Cribo supports hierarchical configuration with the following precedence (highest to lowest):
231
+
232
+ 1. **CLI-provided config** (`--config` flag)
233
+ 2. **Environment variables** (with `CRIBO_` prefix)
234
+ 3. **Project config** (`cribo.toml` in current directory)
235
+ 4. **User config** (`~/.config/cribo/cribo.toml`)
236
+ 5. **System config** (`/etc/cribo/cribo.toml` on Unix, `%SYSTEMDRIVE%\ProgramData\cribo\cribo.toml` on Windows)
237
+ 6. **Default values**
238
+
239
+ ### Configuration File Format
240
+
241
+ Create a `cribo.toml` file:
242
+
243
+ ```toml
244
+ # Source directories to scan for first-party modules
245
+ src = ["src", ".", "lib"]
246
+
247
+ # Known first-party module names
248
+ known_first_party = [
249
+ "my_internal_package",
250
+ ]
251
+
252
+ # Known third-party module names
253
+ known_third_party = [
254
+ "requests",
255
+ "numpy",
256
+ "pandas",
257
+ ]
258
+
259
+ # Whether to preserve comments in the bundled output
260
+ preserve_comments = true
261
+
262
+ # Whether to preserve type hints in the bundled output
263
+ preserve_type_hints = true
264
+
265
+ # Target Python version for standard library checks
266
+ # Supported: "py38", "py39", "py310", "py311", "py312", "py313"
267
+ target-version = "py310"
268
+ ```
269
+
270
+ ### Environment Variables
271
+
272
+ All configuration options can be overridden using environment variables with the `CRIBO_` prefix:
273
+
274
+ ```bash
275
+ # Comma-separated lists
276
+ export CRIBO_SRC="src,lib,custom_dir"
277
+ export CRIBO_KNOWN_FIRST_PARTY="mypackage,myotherpackage"
278
+ export CRIBO_KNOWN_THIRD_PARTY="requests,numpy"
279
+
280
+ # Boolean values (true/false, 1/0, yes/no, on/off)
281
+ export CRIBO_PRESERVE_COMMENTS="false"
282
+ export CRIBO_PRESERVE_TYPE_HINTS="true"
283
+
284
+ # String values
285
+ export CRIBO_TARGET_VERSION="py312"
286
+ ```
287
+
288
+ ### Configuration Locations
289
+
290
+ - **Project**: `./cribo.toml`
291
+ - **User**:
292
+ - Linux/macOS: `~/.config/cribo/cribo.toml`
293
+ - Windows: `%APPDATA%\cribo\cribo.toml`
294
+ - **System**:
295
+ - Linux/macOS: `/etc/cribo/cribo.toml` or `/etc/xdg/cribo/cribo.toml`
296
+ - Windows: `%SYSTEMDRIVE%\ProgramData\cribo\cribo.toml`
297
+
298
+ ## How It Works
299
+
300
+ 1. **Module Discovery**: Scans configured source directories to discover first-party Python modules
301
+ 2. **Import Classification**: Classifies imports as first-party, third-party, or standard library
302
+ 3. **Dependency Graph**: Builds a dependency graph and performs topological sorting
303
+ 4. **Circular Dependency Resolution**: Detects and intelligently resolves function-level circular imports
304
+ 5. **Tree Shaking**: Removes unused code by analyzing which symbols are actually used (enabled by default)
305
+ 6. **Code Generation**: Generates a single Python file with proper module separation
306
+ 7. **Requirements**: Optionally generates `requirements.txt` with third-party dependencies
307
+
308
+ ## Output Structure
309
+
310
+ The bundled output follows this structure:
311
+
312
+ ```python
313
+ #!/usr/bin/env python3
314
+ # Generated by Cribo - Python Source Bundler
315
+
316
+ # Preserved imports (stdlib and third-party)
317
+ import os
318
+ import sys
319
+ import requests
320
+
321
+ # ─ Module: utils/helpers.py ─
322
+ def greet(name: str) -> str:
323
+ return f"Hello, {name}!"
324
+
325
+ # ─ Module: models/user.py ─
326
+ class User:
327
+ def **init**(self, name: str):
328
+ self.name = name
329
+
330
+ # ─ Entry Module: main.py ─
331
+ from utils.helpers import greet
332
+ from models.user import User
333
+
334
+ def main():
335
+ user = User("Alice")
336
+ print(greet(user.name))
337
+
338
+ if **name** == "**main**":
339
+ main()
340
+ ```
341
+
342
+ ## Use Cases
343
+
344
+ ### PySpark Jobs
345
+
346
+ Deploy complex PySpark applications as a single file:
347
+
348
+ ```bash
349
+ cribo --entry spark_job.py --output dist/spark_job_bundle.py --emit-requirements
350
+ spark-submit dist/spark_job_bundle.py
351
+ ```
352
+
353
+ ### AWS Lambda
354
+
355
+ Package Python Lambda functions with all dependencies:
356
+
357
+ ```bash
358
+ cribo --entry lambda_handler.py --output deployment/handler.py
359
+ # Upload handler.py + requirements.txt to Lambda
360
+ ```
361
+
362
+ ## Special Considerations
363
+
364
+ ### Pydantic Compatibility
365
+
366
+ Cribo preserves class identity and module structure to ensure Pydantic models work correctly:
367
+
368
+ ```python
369
+ # Original: models/user.py
370
+ class User(BaseModel):
371
+ name: str
372
+
373
+
374
+ # Bundled output preserves **module** and class structure
375
+ ```
376
+
377
+ ### Pandera Decorators
378
+
379
+ Function and class decorators are preserved with their original module context:
380
+
381
+ ```python
382
+ # Original: validators/schemas.py
383
+ @pa.check_types
384
+ def validate_dataframe(df: DataFrame[UserSchema]) -> DataFrame[UserSchema]:
385
+ return df
386
+
387
+
388
+ # Bundled output maintains decorator functionality
389
+ ```
390
+
391
+ ### Circular Dependencies
392
+
393
+ Cribo intelligently handles circular dependencies with advanced detection and resolution:
394
+
395
+ #### Resolvable Cycles (Function-Level)
396
+
397
+ Function-level circular imports are automatically resolved and bundled successfully:
398
+
399
+ ```python
400
+ # module_a.py
401
+ from module_b import process_b
402
+
403
+
404
+ def process_a():
405
+ return process_b() + "->A"
406
+
407
+
408
+ # module_b.py
409
+ from module_a import get_value_a
410
+
411
+
412
+ def process_b():
413
+ return f"B(using_{get_value_a()})"
414
+ ```
415
+
416
+ **Result**: βœ… Bundles successfully with warning log
417
+
418
+ #### Unresolvable Cycles (Module Constants)
419
+
420
+ Temporal paradox patterns are detected and reported with detailed diagnostics:
421
+
422
+ ```python
423
+ # constants_a.py
424
+ from constants_b import B_VALUE
425
+
426
+ A_VALUE = B_VALUE + 1 # ❌ Unresolvable
427
+
428
+ # constants_b.py
429
+ from constants_a import A_VALUE
430
+
431
+ B_VALUE = A_VALUE * 2 # ❌ Temporal paradox
432
+ ```
433
+
434
+ **Result**: ❌ Fails with detailed error message and resolution suggestions:
435
+
436
+ ```bash
437
+ Unresolvable circular dependencies detected:
438
+
439
+ Cycle 1: constants_b β†’ constants_a
440
+ Type: ModuleConstants
441
+ Reason: Module-level constant dependencies create temporal paradox - cannot be resolved through bundling
442
+ ```
443
+
444
+ ## Comparison with Other Tools
445
+
446
+ | Tool | Language | Tree Shaking | Import Cleanup | Circular Deps | PySpark Ready | Type Hints |
447
+ | ----------- | -------- | ------------ | -------------- | ------------------- | ------------- | ---------- |
448
+ | Cribo | Rust | βœ… Default | βœ… | βœ… Smart Resolution | βœ… | βœ… |
449
+ | PyInstaller | Python | ❌ | ❌ | ❌ Fails | ❌ | βœ… |
450
+ | Nuitka | Python | ❌ | ❌ | ❌ Fails | ❌ | βœ… |
451
+ | Pex | Python | ❌ | ❌ | ❌ Fails | ❌ | βœ… |
452
+
453
+ ## Contributing
454
+
455
+ Please see our [Contributing Guidelines](CONTRIBUTING.md) for details on how to contribute to the project.
456
+
457
+ ## License
458
+
459
+ This project uses a dual licensing approach:
460
+
461
+ - **Source Code**: Licensed under the [MIT License](LICENSE)
462
+ - **Documentation**: Licensed under the [Creative Commons Attribution 4.0 International License (CC BY 4.0)](docs/LICENSE)
463
+
464
+ ### What this means
465
+
466
+ - **For the source code**: You can freely use, modify, and distribute the code for any purpose with minimal restrictions under the MIT license.
467
+ - **For the documentation**: You can share, adapt, and use the documentation for any purpose (including commercially) as long as you provide appropriate attribution under CC BY 4.0.
468
+
469
+ See the [LICENSE](LICENSE) file for the MIT license text and [docs/LICENSE](docs/LICENSE) for the CC BY 4.0 license text.
470
+
471
+ ## Acknowledgments
472
+
473
+ - **Ruff**: Python AST parsing and import resolution logic inspiration
474
+ - **Maturin**: Python-Rust integration
475
+
@@ -0,0 +1,8 @@
1
+ cribo-0.0.0.dev118.data/scripts/cribo.exe,sha256=nR3UJMZrRPEwPqNf1HRYq711bYrqJ5ncScczmuyyRjM,6669312
2
+ cribo-0.0.0.dev118.dist-info/METADATA,sha256=r6zQI8E4OTpMdR8GKuMntlrchKoKOxo1f0dkgTTGv5c,16957
3
+ cribo-0.0.0.dev118.dist-info/WHEEL,sha256=14-pPWiwFoCAtTgD4hWnxHSfZQqe6Zt0DfwcROvwlzs,94
4
+ cribo-0.0.0.dev118.dist-info/licenses/LICENSE,sha256=pX9wfFFBIUMELubeUJl6rT5fKF1iFy3AO-1DN9kgihM,1438
5
+ cribo/__init__.py,sha256=eSDXo69xAQyWo1g3pcgz6Ah4IYvjbBVuVVJFmbqfmas,300
6
+ cribo/__main__.py,sha256=c9uJf3v0MNufLQsXIkgmBdXWbUysJ7-G0Nq5dN3dZZc,712
7
+ cribo/py.typed,sha256=s3opEHDc7NDxFqsb2qu86CXIp62IC_AUX0zHwvmr018,769
8
+ cribo-0.0.0.dev118.dist-info/RECORD,,
@@ -0,0 +1,4 @@
1
+ Wheel-Version: 1.0
2
+ Generator: maturin (1.10.2)
3
+ Root-Is-Purelib: false
4
+ Tag: py3-none-win_amd64
@@ -0,0 +1,30 @@
1
+ Dual Licensing Notice
2
+
3
+ This project uses a dual licensing approach:
4
+ - Source Code / Binaries: MIT License (see below)
5
+ - Documentation: Creative Commons Attribution 4.0 International (CC BY 4.0)
6
+ See docs/LICENSE for the full CC BY 4.0 license text.
7
+
8
+ ================================================================================
9
+
10
+ MIT License
11
+
12
+ Copyright (c) 2025 Konstantin Vyatkin
13
+
14
+ Permission is hereby granted, free of charge, to any person obtaining a copy
15
+ of this software and associated documentation files (the "Software"), to deal
16
+ in the Software without restriction, including without limitation the rights
17
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
18
+ copies of the Software, and to permit persons to whom the Software is
19
+ furnished to do so, subject to the following conditions:
20
+
21
+ The above copyright notice and this permission notice shall be included in all
22
+ copies or substantial portions of the Software.
23
+
24
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
25
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
26
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
27
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
28
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
29
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
30
+ SOFTWARE.