handover 0.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.
Files changed (50) hide show
  1. handover-0.2.0/.github/ISSUE_TEMPLATE/bug_report.md +37 -0
  2. handover-0.2.0/.github/ISSUE_TEMPLATE/feature_request.md +34 -0
  3. handover-0.2.0/.github/PULL_REQUEST_TEMPLATE.md +19 -0
  4. handover-0.2.0/.github/dependabot.yml +13 -0
  5. handover-0.2.0/.github/workflows/ci.yml +40 -0
  6. handover-0.2.0/.github/workflows/release.yml +89 -0
  7. handover-0.2.0/.gitignore +102 -0
  8. handover-0.2.0/.pre-commit-config.yaml +19 -0
  9. handover-0.2.0/CHANGELOG.md +25 -0
  10. handover-0.2.0/CLAUDE.md +39 -0
  11. handover-0.2.0/CODE_OF_CONDUCT.md +65 -0
  12. handover-0.2.0/CONTRIBUTING.md +62 -0
  13. handover-0.2.0/LICENSE +21 -0
  14. handover-0.2.0/PKG-INFO +144 -0
  15. handover-0.2.0/README.md +116 -0
  16. handover-0.2.0/SECURITY.md +24 -0
  17. handover-0.2.0/docs/adding-an-adapter.md +137 -0
  18. handover-0.2.0/docs/getting-started.md +79 -0
  19. handover-0.2.0/docs/output-format.md +126 -0
  20. handover-0.2.0/handover/__init__.py +7 -0
  21. handover-0.2.0/handover/cli.py +309 -0
  22. handover-0.2.0/handover/generator.py +98 -0
  23. handover-0.2.0/handover/heuristics.py +409 -0
  24. handover-0.2.0/handover/models.py +83 -0
  25. handover-0.2.0/handover/parsers/__init__.py +119 -0
  26. handover-0.2.0/handover/parsers/base.py +85 -0
  27. handover-0.2.0/handover/parsers/chatgpt.py +180 -0
  28. handover-0.2.0/handover/parsers/claude.py +283 -0
  29. handover-0.2.0/handover/parsers/gemini.py +93 -0
  30. handover-0.2.0/handover/parsers/perplexity.py +143 -0
  31. handover-0.2.0/handover/summarizer.py +155 -0
  32. handover-0.2.0/handover/templates/claude_md.j2 +46 -0
  33. handover-0.2.0/handover/templates/plan_md.j2 +19 -0
  34. handover-0.2.0/pyproject.toml +54 -0
  35. handover-0.2.0/scripts/install-hooks.sh +9 -0
  36. handover-0.2.0/scripts/pre-push +10 -0
  37. handover-0.2.0/tests/__init__.py +1 -0
  38. handover-0.2.0/tests/fixtures/chatgpt_single.json +108 -0
  39. handover-0.2.0/tests/fixtures/claude_bulk.jsonl +3 -0
  40. handover-0.2.0/tests/fixtures/claude_single.json +38 -0
  41. handover-0.2.0/tests/fixtures/claude_single.md +25 -0
  42. handover-0.2.0/tests/fixtures/gemini_single.json +41 -0
  43. handover-0.2.0/tests/fixtures/perplexity_bulk.json +39 -0
  44. handover-0.2.0/tests/fixtures/perplexity_single.json +34 -0
  45. handover-0.2.0/tests/test_cli.py +326 -0
  46. handover-0.2.0/tests/test_generator.py +141 -0
  47. handover-0.2.0/tests/test_heuristics.py +244 -0
  48. handover-0.2.0/tests/test_models.py +76 -0
  49. handover-0.2.0/tests/test_parser.py +360 -0
  50. handover-0.2.0/tests/test_summarizer.py +164 -0
@@ -0,0 +1,37 @@
1
+ ---
2
+ name: Bug report
3
+ about: Report a bug or unexpected behavior in handover
4
+ title: '[BUG] '
5
+ labels: bug
6
+ assignees: ''
7
+ ---
8
+
9
+ ## Description
10
+
11
+ A clear and concise description of what the bug is.
12
+
13
+ ## Steps to Reproduce
14
+
15
+ 1. Run `handover ...`
16
+ 2. With input file of type: ...
17
+ 3. See error
18
+
19
+ ## Expected Behavior
20
+
21
+ What you expected to happen.
22
+
23
+ ## Actual Behavior
24
+
25
+ What actually happened. Include the full error message or output.
26
+
27
+ ## Environment
28
+
29
+ - **CLI version:** `handover --version`
30
+ - **Python version:** `python --version`
31
+ - **OS:** (e.g. macOS 14, Ubuntu 22.04, Windows 11)
32
+ - **Input format:** (e.g. single JSON, bulk JSONL, Markdown)
33
+ - **Mode:** (e.g. default / `--no-llm` / `--dry-run`)
34
+
35
+ ## Additional Context
36
+
37
+ Any other context that might help (e.g. anonymized snippet of the input file that triggers the issue).
@@ -0,0 +1,34 @@
1
+ ---
2
+ name: Feature request
3
+ about: Suggest a new feature or improvement for handover
4
+ title: '[FEATURE] '
5
+ labels: enhancement
6
+ assignees: ''
7
+ ---
8
+
9
+ ## Problem Statement
10
+
11
+ What problem does this feature solve? Who is the user experiencing it?
12
+ (e.g. "As a developer using Gemini for design and Claude Code for implementation, I have no way to...")
13
+
14
+ ## Proposed Solution
15
+
16
+ A clear description of the feature you'd like to see. How would it work from the user's perspective?
17
+
18
+ ## Alternatives Considered
19
+
20
+ What other solutions or workarounds have you considered? Why are they not sufficient?
21
+
22
+ ## Phase
23
+
24
+ Which project phase does this belong to?
25
+
26
+ - [ ] Phase 1 — Claude chat → Claude Code (current)
27
+ - [ ] Phase 2 — Universal chat sources (ChatGPT, Gemini, Perplexity adapters)
28
+ - [ ] Phase 3 — Reverse handover (terminal → chat)
29
+ - [ ] Phase 4 — Additional target agent adapters (Aider, Goose, Codex CLI)
30
+ - [ ] Other / cross-cutting
31
+
32
+ ## Additional Context
33
+
34
+ Any mockups, examples, or related issues that provide more context.
@@ -0,0 +1,19 @@
1
+ ## Summary
2
+
3
+ <!-- Briefly describe what this PR does and why. -->
4
+
5
+ ## Changes
6
+
7
+ <!-- List the key changes made. -->
8
+
9
+ ## Checklist
10
+
11
+ - [ ] Tests added (or updated) for new/changed behaviour
12
+ - [ ] Docs updated (README, docstrings, relevant docs/ page)
13
+ - [ ] If adding a new adapter: `docs/adding-an-adapter.md` guide was followed
14
+ - [ ] `PLAN.md` updated if any implementation tasks are now complete
15
+ - [ ] CI passes (no new test failures)
16
+
17
+ ## Related Issues
18
+
19
+ <!-- Closes #<issue_number> -->
@@ -0,0 +1,13 @@
1
+ version: 2
2
+ updates:
3
+ - package-ecosystem: "pip"
4
+ directory: "/"
5
+ schedule:
6
+ interval: "daily"
7
+ open-pull-requests-limit: 5
8
+
9
+ - package-ecosystem: "github-actions"
10
+ directory: "/"
11
+ schedule:
12
+ interval: "weekly"
13
+ open-pull-requests-limit: 3
@@ -0,0 +1,40 @@
1
+ name: CI
2
+
3
+ on:
4
+ push:
5
+ branches: [main, feature/**]
6
+ pull_request:
7
+ branches: [main]
8
+
9
+ jobs:
10
+ lint:
11
+ runs-on: ubuntu-latest
12
+ steps:
13
+ - uses: actions/checkout@v4
14
+ - uses: actions/setup-python@v5
15
+ with:
16
+ python-version: "3.11"
17
+ - name: Install dev dependencies
18
+ run: pip install -e ".[dev]"
19
+ - name: Ruff lint
20
+ run: ruff check handover/ tests/
21
+ - name: Ruff format check
22
+ run: ruff format --check handover/ tests/
23
+ - name: Mypy
24
+ run: mypy handover/
25
+
26
+ test:
27
+ needs: lint
28
+ runs-on: ubuntu-latest
29
+ strategy:
30
+ matrix:
31
+ python-version: ["3.11", "3.12"]
32
+ steps:
33
+ - uses: actions/checkout@v4
34
+ - uses: actions/setup-python@v5
35
+ with:
36
+ python-version: ${{ matrix.python-version }}
37
+ - name: Install dependencies
38
+ run: pip install -e ".[dev]"
39
+ - name: Run tests
40
+ run: pytest tests/ -v --cov=handover --cov-report=term-missing --cov-fail-under=80
@@ -0,0 +1,89 @@
1
+ name: Release to PyPI
2
+
3
+ on:
4
+ push:
5
+ tags:
6
+ - "v*"
7
+
8
+ jobs:
9
+ test-before-release:
10
+ name: Test before release
11
+ runs-on: ubuntu-latest
12
+ steps:
13
+ - uses: actions/checkout@v4
14
+ - uses: actions/setup-python@v5
15
+ with:
16
+ python-version: "3.11"
17
+ - name: Install dev dependencies
18
+ run: pip install -e ".[dev]"
19
+ - name: Ruff lint
20
+ run: ruff check handover/ tests/
21
+ - name: Ruff format check
22
+ run: ruff format --check handover/ tests/
23
+ - name: Mypy
24
+ run: mypy handover/
25
+ - name: Run tests with coverage gate
26
+ run: pytest tests/ -v --cov=handover --cov-fail-under=80
27
+
28
+ build:
29
+ name: Build distribution
30
+ needs: test-before-release
31
+ runs-on: ubuntu-latest
32
+ steps:
33
+ - uses: actions/checkout@v4
34
+ - uses: actions/setup-python@v5
35
+ with:
36
+ python-version: "3.11"
37
+ - name: Install build tools
38
+ run: pip install hatchling build
39
+ - name: Build package
40
+ run: python -m build
41
+ - name: Store distribution packages
42
+ uses: actions/upload-artifact@v4
43
+ with:
44
+ name: python-package-distributions
45
+ path: dist/
46
+
47
+ publish-to-testpypi:
48
+ name: Publish to TestPyPI (dry run)
49
+ needs: build
50
+ runs-on: ubuntu-latest
51
+ environment:
52
+ name: testpypi
53
+ url: https://test.pypi.org/p/handover
54
+ permissions:
55
+ id-token: write # Required for TestPyPI Trusted Publisher
56
+ steps:
57
+ - name: Download distribution packages
58
+ uses: actions/download-artifact@v4
59
+ with:
60
+ name: python-package-distributions
61
+ path: dist/
62
+ - name: Publish to TestPyPI
63
+ uses: pypa/gh-action-pypi-publish@release/v1
64
+ with:
65
+ repository-url: https://test.pypi.org/legacy/
66
+ - name: Verify install from TestPyPI
67
+ run: |
68
+ pip install --index-url https://test.pypi.org/simple/ \
69
+ --extra-index-url https://pypi.org/simple/ \
70
+ handover
71
+ handover --version
72
+
73
+ publish-to-pypi:
74
+ name: Publish to PyPI
75
+ needs: [build, publish-to-testpypi]
76
+ runs-on: ubuntu-latest
77
+ environment:
78
+ name: pypi
79
+ url: https://pypi.org/p/handover
80
+ permissions:
81
+ id-token: write # Required for PyPI Trusted Publisher
82
+ steps:
83
+ - name: Download distribution packages
84
+ uses: actions/download-artifact@v4
85
+ with:
86
+ name: python-package-distributions
87
+ path: dist/
88
+ - name: Publish to PyPI
89
+ uses: pypa/gh-action-pypi-publish@release/v1
@@ -0,0 +1,102 @@
1
+ # Python
2
+ __pycache__/
3
+ *.py[cod]
4
+ *$py.class
5
+ *.so
6
+ *.egg
7
+ *.egg-info/
8
+ dist/
9
+ build/
10
+ eggs/
11
+ parts/
12
+ var/
13
+ sdist/
14
+ develop-eggs/
15
+ .installed.cfg
16
+ lib/
17
+ lib64/
18
+ conversations.json
19
+
20
+ # Virtual environments
21
+ .env
22
+ .venv
23
+ env/
24
+ venv/
25
+ ENV/
26
+ env.bak/
27
+ venv.bak/
28
+
29
+ # Distribution / packaging
30
+ .Python
31
+ pip-log.txt
32
+ pip-delete-this-directory.txt
33
+ .tox/
34
+ .nox/
35
+ .coverage
36
+ .coverage.*
37
+ .cache
38
+ nosetests.xml
39
+ coverage.xml
40
+ *.cover
41
+ *.py,cover
42
+ .hypothesis/
43
+ .pytest_cache/
44
+ htmlcov/
45
+
46
+ # Installers
47
+ *.manifest
48
+ *.spec
49
+
50
+ # Jupyter Notebook
51
+ .ipynb_checkpoints
52
+
53
+ # pyenv
54
+ .python-version
55
+
56
+ # Celery
57
+ celerybeat-schedule
58
+ celerybeat.pid
59
+
60
+ # SageMath parsed files
61
+ *.sage.py
62
+
63
+ # Environments
64
+ .env
65
+ .env.local
66
+ .env.*.local
67
+
68
+ # mypy
69
+ .mypy_cache/
70
+ .dmypy.json
71
+ dmypy.json
72
+
73
+ # Pyre type checker
74
+ .pyre/
75
+
76
+ # macOS
77
+ .DS_Store
78
+ .AppleDouble
79
+ .LSOverride
80
+ Icon
81
+ ._*
82
+ .DocumentRevisions-V100
83
+ .fseventsd
84
+ .Spotlight-V100
85
+ .TemporaryItems
86
+ .Trashes
87
+ .VolumeIcon.icns
88
+ .com.apple.timemachine.donotpresent
89
+
90
+ # IDE
91
+ .idea/
92
+ .vscode/
93
+ *.swp
94
+ *.swo
95
+ *~
96
+
97
+ # handover-specific
98
+ .handover/
99
+ dev_docs/
100
+
101
+ # Claude Code project config (local only — machine-specific permissions)
102
+ .claude/
@@ -0,0 +1,19 @@
1
+ repos:
2
+ - repo: https://github.com/astral-sh/ruff-pre-commit
3
+ rev: v0.4.4
4
+ hooks:
5
+ - id: ruff
6
+ args: [--fix]
7
+ - id: ruff-format
8
+ - repo: https://github.com/pre-commit/mirrors-mypy
9
+ rev: v1.10.0
10
+ hooks:
11
+ - id: mypy
12
+ additional_dependencies: [click, anthropic, jinja2]
13
+ - repo: https://github.com/pre-commit/pre-commit-hooks
14
+ rev: v4.6.0
15
+ hooks:
16
+ - id: trailing-whitespace
17
+ - id: end-of-file-fixer
18
+ - id: check-yaml
19
+ - id: check-toml
@@ -0,0 +1,25 @@
1
+ # Changelog
2
+
3
+ All notable changes to this project will be documented in this file.
4
+ Format based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
5
+ Versioning follows [Semantic Versioning](https://semver.org/).
6
+
7
+ ## [Unreleased]
8
+
9
+ ## [0.2.0] - 2026-04-05
10
+
11
+ ### Added
12
+ - Claude adapter (`parsers/claude.py`) supporting both `.jsonl` (bulk export) and `.json` (single chat / browser extension) input formats
13
+ - Support for Claude bulk JSON array export format (`conversations.json`)
14
+ - Adapter pattern with `BaseParser` in `parsers/base.py` — extensible to future sources (ChatGPT, Gemini, etc.)
15
+ - Heuristic summarizer (`heuristics.py`) for keyword-based context extraction when `--no-llm` is passed
16
+ - LLM summarizer using Anthropic SDK (`claude-sonnet-4-6`) for AI-generated `CLAUDE.md` and `PLAN.md` artifacts
17
+ - Jinja2-based generator with templates for `CLAUDE.md` and `PLAN.md`
18
+ - CLI (`handover`) with subcommands: `run`, `list`, `init`
19
+ - `--no-llm` flag for offline/heuristic-only mode
20
+ - Full test suite with 80% coverage gate
21
+ - GitHub Actions CI (lint + test matrix on Python 3.11 + 3.12)
22
+ - GitHub Actions release pipeline to TestPyPI and PyPI via Trusted Publisher
23
+
24
+ [Unreleased]: https://github.com/mohankrishnaalavala/handover/compare/v0.2.0...HEAD
25
+ [0.2.0]: https://github.com/mohankrishnaalavala/handover/releases/tag/v0.2.0
@@ -0,0 +1,39 @@
1
+ # handover — Universal AI Chat to Local Agent Handover Tool
2
+
3
+ ## Project Goal
4
+ CLI tool that parses AI chat exports and generates CLAUDE.md + PLAN.md
5
+ artifacts for local terminal agents to ingest. Phase 1: Claude chat only.
6
+
7
+ ## Tech Stack
8
+ - Language: Python 3.11+
9
+ - CLI: Click (with subcommands: main, list, init)
10
+ - Templates: Jinja2
11
+ - API: Anthropic SDK (claude-sonnet-4-6 for summarization)
12
+ - Testing: pytest + pytest-cov
13
+ - Packaging: pyproject.toml / hatchling
14
+
15
+ ## Architecture Rules
16
+ - Parser uses adapter pattern: one class per source in parsers/
17
+ - BaseParser in parsers/base.py defines the interface all adapters must implement
18
+ - Summarizer calls Claude API unless --no-llm; then delegates to heuristics.py
19
+ - Heuristics are keyword-rule-based — keep them simple and documented
20
+ - Generator uses Jinja2 templates only — never hardcode output format in Python
21
+ - All data models are dataclasses in models.py with full type hints
22
+ - schema_version must be bumped in models.py when HandoverContext fields change
23
+
24
+ ## Coding Standards
25
+ - Type hints on all functions and methods
26
+ - Docstrings on all public methods
27
+ - Tests required for: parser output, heuristics rules, generator file output
28
+ - Mocked API calls in test_summarizer.py — never hit real API in tests
29
+ - No dependencies beyond: click, anthropic, jinja2, pytest, pytest-cov
30
+
31
+ ## Key Commands
32
+ - Run tests: pytest tests/ -v --cov=handover
33
+ - Install locally: pip install -e .
34
+ - Run CLI: handover --help
35
+
36
+ ## Phase 1 Focus
37
+ - Claude adapter only (parsers/claude.py)
38
+ - Do NOT build ChatGPT adapter yet — that is Phase 2
39
+ - Both input formats: .jsonl (bulk) and .json (single chat via browser extension)
@@ -0,0 +1,65 @@
1
+ # Contributor Covenant Code of Conduct
2
+
3
+ ## Our Pledge
4
+
5
+ We as members, contributors, and leaders pledge to make participation in our
6
+ community a harassment-free experience for everyone, regardless of age, body
7
+ size, visible or invisible disability, ethnicity, sex characteristics, gender
8
+ identity and expression, level of experience, education, socio-economic status,
9
+ nationality, personal appearance, race, caste, color, religion, or sexual
10
+ identity and orientation.
11
+
12
+ We pledge to act and interact in ways that contribute to an open, welcoming,
13
+ diverse, inclusive, and healthy community.
14
+
15
+ ## Our Standards
16
+
17
+ Examples of behavior that contributes to a positive environment:
18
+
19
+ * Demonstrating empathy and kindness toward other people
20
+ * Being respectful of differing opinions, viewpoints, and experiences
21
+ * Giving and gracefully accepting constructive feedback
22
+ * Accepting responsibility and apologizing to those affected by our mistakes
23
+ * Focusing on what is best not just for us as individuals, but for the overall community
24
+
25
+ Examples of unacceptable behavior:
26
+
27
+ * The use of sexualized language or imagery, and sexual attention or advances of any kind
28
+ * Trolling, insulting or derogatory comments, and personal or political attacks
29
+ * Public or private harassment
30
+ * Publishing others' private information without explicit permission
31
+ * Other conduct which could reasonably be considered inappropriate in a professional setting
32
+
33
+ ## Enforcement Responsibilities
34
+
35
+ Project maintainers are responsible for clarifying and enforcing our standards of
36
+ acceptable behavior and will take appropriate and fair corrective action in
37
+ response to any behavior that they deem inappropriate, threatening, offensive,
38
+ or harmful.
39
+
40
+ ## Scope
41
+
42
+ This Code of Conduct applies within all community spaces, and also applies when
43
+ an individual is officially representing the community in public spaces.
44
+
45
+ ## Enforcement
46
+
47
+ Instances of abusive, harassing, or otherwise unacceptable behavior may be
48
+ reported by following the instructions in [SECURITY.md](SECURITY.md) or by
49
+ contacting the maintainer via the [GitHub profile](https://github.com/mohankrishnaalavala).
50
+
51
+ All complaints will be reviewed and investigated promptly and fairly.
52
+
53
+ ## Enforcement Guidelines
54
+
55
+ **1. Correction** — Private written warning, clarity around the violation.
56
+
57
+ **2. Warning** — A warning with consequences for continued behavior.
58
+
59
+ **3. Temporary Ban** — Temporary ban from any interaction or public communication.
60
+
61
+ **4. Permanent Ban** — Permanent ban from any public interaction within the community.
62
+
63
+ ## Attribution
64
+
65
+ This Code of Conduct is adapted from the [Contributor Covenant](https://www.contributor-covenant.org/), version 2.1.
@@ -0,0 +1,62 @@
1
+ # Contributing to handover
2
+
3
+ Thank you for your interest in contributing! `handover` is an open-source project and contributions are very welcome.
4
+
5
+ ## Setup
6
+
7
+ ```bash
8
+ git clone https://github.com/mohankrishnaalavala/handover.git
9
+ cd handover
10
+ pip install -e ".[dev]"
11
+ ```
12
+
13
+ ## Running Tests
14
+
15
+ ```bash
16
+ pytest tests/ -v --cov=handover --cov-report=term-missing
17
+ ```
18
+
19
+ All tests must pass before submitting a PR. Never commit code that breaks existing tests.
20
+
21
+ ## Primary Contribution Path: Adding a New Source Adapter
22
+
23
+ Adding a new source (ChatGPT, Gemini, Perplexity, etc.) is the primary way to contribute. Each adapter is one self-contained class in `handover/parsers/`. A contributor can own an adapter end-to-end as an isolated PR.
24
+
25
+ See **[docs/adding-an-adapter.md](docs/adding-an-adapter.md)** for the complete step-by-step guide.
26
+
27
+ In brief, adding a new adapter means:
28
+ 1. Create `handover/parsers/{source_name}.py` — subclass `BaseParser`
29
+ 2. Register the adapter in `parsers/__init__.py`
30
+ 3. Add a test fixture in `tests/fixtures/`
31
+ 4. Add tests in `tests/test_parser.py`
32
+ 5. Update the supported formats table in `README.md`
33
+ 6. Add the source name to the `--source` flag in `cli.py`
34
+
35
+ ## Code Standards
36
+
37
+ The following standards are taken directly from `CLAUDE.md` and apply to all contributions:
38
+
39
+ - **Type hints** on all functions and methods
40
+ - **Docstrings** on all public methods
41
+ - **Tests required** for: parser output, heuristics rules, generator file output
42
+ - Mocked API calls in `test_summarizer.py` — never hit the real Anthropic API in tests
43
+ - No additional dependencies beyond: `click`, `anthropic`, `jinja2`, `pytest`, `pytest-cov`
44
+
45
+ ## Submitting a Pull Request
46
+
47
+ 1. Fork the repo and create a feature branch
48
+ 2. Make your changes, add tests, update docs
49
+ 3. Run `pytest tests/ -v` — all tests must pass
50
+ 4. Update `PLAN.md` if your PR completes any listed tasks
51
+ 5. Open a PR against `main` using the PR template
52
+
53
+ ## Project Phases
54
+
55
+ Before contributing, it helps to understand the roadmap:
56
+
57
+ - **Phase 1** (current): Claude chat → Claude Code. This is what we're building now.
58
+ - **Phase 2**: Universal chat sources — ChatGPT, Gemini, Perplexity adapters. **This is the main open contribution path.**
59
+ - **Phase 3**: Reverse handover — Claude Code session logs → readable handover doc.
60
+ - **Phase 4**: Additional target agents (Aider, Goose, Codex CLI).
61
+
62
+ Please check open issues and the `PLAN.md` before starting work to avoid duplicating effort.
handover-0.2.0/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Mohan Krishnaa Alavala
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.