ludotastic 0.2.1__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 (76) hide show
  1. ludotastic-0.2.1/.all-contributorsrc +18 -0
  2. ludotastic-0.2.1/.cruft.json +28 -0
  3. ludotastic-0.2.1/.editorconfig +27 -0
  4. ludotastic-0.2.1/.github/ISSUE_TEMPLATE/bug_report.md +26 -0
  5. ludotastic-0.2.1/.github/ISSUE_TEMPLATE/config.yml +4 -0
  6. ludotastic-0.2.1/.github/ISSUE_TEMPLATE/feature_request.md +19 -0
  7. ludotastic-0.2.1/.github/workflows/ci.yml +43 -0
  8. ludotastic-0.2.1/.github/workflows/codecov_action.yml +43 -0
  9. ludotastic-0.2.1/.github/workflows/semantic-release.yml +87 -0
  10. ludotastic-0.2.1/.gitignore +166 -0
  11. ludotastic-0.2.1/.pre-commit-config.yaml +11 -0
  12. ludotastic-0.2.1/.python-version +1 -0
  13. ludotastic-0.2.1/.python-versions +1 -0
  14. ludotastic-0.2.1/.readthedocs.yaml +19 -0
  15. ludotastic-0.2.1/LICENSE +21 -0
  16. ludotastic-0.2.1/PKG-INFO +223 -0
  17. ludotastic-0.2.1/docs/CHANGELOG.md +75 -0
  18. ludotastic-0.2.1/docs/CODE_OF_CONDUCT.md +133 -0
  19. ludotastic-0.2.1/docs/CONTRIBUTING.md +303 -0
  20. ludotastic-0.2.1/docs/README.md +189 -0
  21. ludotastic-0.2.1/docs/SECURITY.md +5 -0
  22. ludotastic-0.2.1/docs/__init__.py +1 -0
  23. ludotastic-0.2.1/docs/api.md +19 -0
  24. ludotastic-0.2.1/docs/javascripts/extra.js +8 -0
  25. ludotastic-0.2.1/docs/notes/tictactoe-observation.md +60 -0
  26. ludotastic-0.2.1/docs/reference.md +108 -0
  27. ludotastic-0.2.1/docs/stylesheets/extra.css +11 -0
  28. ludotastic-0.2.1/docs/wordlist.txt +58 -0
  29. ludotastic-0.2.1/mkdocs.yml +145 -0
  30. ludotastic-0.2.1/noxfile.py +103 -0
  31. ludotastic-0.2.1/pyproject.toml +236 -0
  32. ludotastic-0.2.1/src/ludotastic/__init__.py +54 -0
  33. ludotastic-0.2.1/src/ludotastic/api.py +191 -0
  34. ludotastic-0.2.1/src/ludotastic/cli.py +182 -0
  35. ludotastic-0.2.1/src/ludotastic/engine/__init__.py +33 -0
  36. ludotastic-0.2.1/src/ludotastic/engine/ai.py +276 -0
  37. ludotastic-0.2.1/src/ludotastic/engine/drawing.py +52 -0
  38. ludotastic-0.2.1/src/ludotastic/engine/game.py +342 -0
  39. ludotastic-0.2.1/src/ludotastic/engine/match.py +378 -0
  40. ludotastic-0.2.1/src/ludotastic/engine/models.py +89 -0
  41. ludotastic-0.2.1/src/ludotastic/engine/players.py +159 -0
  42. ludotastic-0.2.1/src/ludotastic/engine/registry.py +100 -0
  43. ludotastic-0.2.1/src/ludotastic/engine/render.py +41 -0
  44. ludotastic-0.2.1/src/ludotastic/engine/usage.py +116 -0
  45. ludotastic-0.2.1/src/ludotastic/games/__init__.py +5 -0
  46. ludotastic-0.2.1/src/ludotastic/games/snake/__init__.py +5 -0
  47. ludotastic-0.2.1/src/ludotastic/games/snake/game.py +490 -0
  48. ludotastic-0.2.1/src/ludotastic/games/snake/ui.py +85 -0
  49. ludotastic-0.2.1/src/ludotastic/games/tictactoe/__init__.py +5 -0
  50. ludotastic-0.2.1/src/ludotastic/games/tictactoe/game.py +314 -0
  51. ludotastic-0.2.1/src/ludotastic/games/tictactoe/ui.py +63 -0
  52. ludotastic-0.2.1/src/ludotastic/games/twentyfortyeight/__init__.py +17 -0
  53. ludotastic-0.2.1/src/ludotastic/games/twentyfortyeight/game.py +450 -0
  54. ludotastic-0.2.1/src/ludotastic/games/twentyfortyeight/ui.py +90 -0
  55. ludotastic-0.2.1/src/ludotastic/py.typed +0 -0
  56. ludotastic-0.2.1/src/ludotastic/service.py +229 -0
  57. ludotastic-0.2.1/src/ludotastic/settings.py +79 -0
  58. ludotastic-0.2.1/src/ludotastic/storage.py +176 -0
  59. ludotastic-0.2.1/src/ludotastic/web/__init__.py +51 -0
  60. ludotastic-0.2.1/src/ludotastic/web/match_view.py +260 -0
  61. ludotastic-0.2.1/src/ludotastic/web/pages.py +364 -0
  62. ludotastic-0.2.1/tests/__init__.py +1 -0
  63. ludotastic-0.2.1/tests/conftest.py +53 -0
  64. ludotastic-0.2.1/tests/test_ai.py +158 -0
  65. ludotastic-0.2.1/tests/test_api.py +108 -0
  66. ludotastic-0.2.1/tests/test_changelog.py +95 -0
  67. ludotastic-0.2.1/tests/test_cli.py +116 -0
  68. ludotastic-0.2.1/tests/test_engine.py +410 -0
  69. ludotastic-0.2.1/tests/test_images.py +267 -0
  70. ludotastic-0.2.1/tests/test_service.py +190 -0
  71. ludotastic-0.2.1/tests/test_snake.py +215 -0
  72. ludotastic-0.2.1/tests/test_tictactoe.py +124 -0
  73. ludotastic-0.2.1/tests/test_twentyfortyeight.py +197 -0
  74. ludotastic-0.2.1/tests/test_usage.py +166 -0
  75. ludotastic-0.2.1/tests/test_web.py +292 -0
  76. ludotastic-0.2.1/uv.lock +3441 -0
@@ -0,0 +1,18 @@
1
+ {
2
+ "files": [
3
+ "docs/README.md"
4
+ ],
5
+ "imageSize": 100,
6
+ "commit": false,
7
+ "contributors": [
8
+ ],
9
+ "contributorsPerLine": 7,
10
+ "badgeTemplate": "[badge-all-contributors]: https://img.shields.io/badge/all_contributors-<%= contributors.length %>-orange.svg?style=flat-square",
11
+ "projectName": "ludotastic",
12
+ "projectOwner": "MicaelJarniac",
13
+ "repoType": "github",
14
+ "repoHost": "https://github.com",
15
+ "skipCi": true,
16
+ "commitType": "docs",
17
+ "commitConvention": "angular"
18
+ }
@@ -0,0 +1,28 @@
1
+ {
2
+ "template": "https://github.com/MicaelJarniac/crustypy",
3
+ "commit": "65a9c2e060dd71527883ab57f107859dcb5afb5a",
4
+ "checkout": null,
5
+ "context": {
6
+ "cookiecutter": {
7
+ "full_name": "Micael Jarniac",
8
+ "email": "micael@jarniac.dev",
9
+ "github_username": "MicaelJarniac",
10
+ "year": "2026",
11
+ "project_name": "Ludotastic",
12
+ "project_slug": "ludotastic",
13
+ "project_distribution_name": "ludotastic",
14
+ "project_short_description": "Where humans and AI come to play.",
15
+ "version": "0.0.0",
16
+ "main_branch": "main",
17
+ "shields_url": "https://img.shields.io",
18
+ "discord_invite": "Ye9yJtZQuN",
19
+ "report_method": "micael@jarniac.dev",
20
+ "__github_path": "MicaelJarniac/ludotastic",
21
+ "__github_url": "https://github.com/MicaelJarniac/ludotastic",
22
+ "__readthedocs_name": "ludotastic",
23
+ "_template": "https://github.com/MicaelJarniac/crustypy",
24
+ "_commit": "65a9c2e060dd71527883ab57f107859dcb5afb5a"
25
+ }
26
+ },
27
+ "directory": null
28
+ }
@@ -0,0 +1,27 @@
1
+ # EditorConfig is awesome: https://EditorConfig.org
2
+
3
+ # Top-most EditorConfig file
4
+ root = true
5
+
6
+ # Unix-style newlines with a newline ending every file
7
+ [*]
8
+ end_of_line = lf
9
+ insert_final_newline = true
10
+
11
+ [*.{py}]
12
+ charset = utf-8
13
+
14
+ [*.py]
15
+ indent_style = space
16
+ indent_size = 4
17
+
18
+ [*.md]
19
+ indent_style = space
20
+ indent_size = 2
21
+
22
+ [*.{yml, yaml}]
23
+ indent_style = space
24
+ indent_size = 2
25
+
26
+ [Makefile]
27
+ indent_style = tab
@@ -0,0 +1,26 @@
1
+ ---
2
+ name: Bug report
3
+ about: Create a report to help us improve
4
+ # title: "[BUG]"
5
+ labels: bug
6
+
7
+ ---
8
+
9
+ ### Describe the bug
10
+ A clear and concise description of what the bug is.
11
+
12
+ ### To reproduce
13
+ Steps to reproduce the behavior:
14
+ 1. Go to '...'
15
+ 2. Click on '....'
16
+ 3. Scroll down to '....'
17
+ 4. See error
18
+
19
+ ### Expected behavior
20
+ A clear and concise description of what you expected to happen.
21
+
22
+ ### Screenshots
23
+ If applicable, add screenshots to help explain your problem.
24
+
25
+ ### Additional context
26
+ Add any other context about the problem here.
@@ -0,0 +1,4 @@
1
+ contact_links:
2
+ - name: Discord
3
+ url: https://discord.gg/Ye9yJtZQuN
4
+ about: Please ask and answer questions here.
@@ -0,0 +1,19 @@
1
+ ---
2
+ name: Feature request
3
+ about: Suggest an idea for this project
4
+ # title: "[FEAT]"
5
+ labels: enhancement
6
+
7
+ ---
8
+
9
+ **Is your feature request related to a problem? Please describe.**
10
+ A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
11
+
12
+ **Describe the solution you'd like**
13
+ A clear and concise description of what you want to happen.
14
+
15
+ **Describe alternatives you've considered**
16
+ A clear and concise description of any alternative solutions or features you've considered.
17
+
18
+ **Additional context**
19
+ Add any other context or screenshots about the feature request here.
@@ -0,0 +1,43 @@
1
+ name: CI
2
+
3
+ on:
4
+ pull_request:
5
+ push:
6
+ branches:
7
+ - main
8
+ - rc
9
+
10
+ permissions:
11
+ contents: read
12
+
13
+ env:
14
+ FORCE_COLOR: 1
15
+ PRE_COMMIT_COLOR: "always" # https://github.com/pre-commit/pre-commit/issues/2918
16
+
17
+ jobs:
18
+ generate-jobs:
19
+ name: Generate Session Jobs
20
+ runs-on: ubuntu-latest
21
+ outputs:
22
+ session: ${{ steps.set-matrix.outputs.session }}
23
+ steps:
24
+ - uses: actions/checkout@v4
25
+ - uses: wntrblm/nox@main
26
+ - id: set-matrix
27
+ shell: bash
28
+ run: echo session=$(nox --json -l | jq -c '[.[].session]') | tee --append $GITHUB_OUTPUT
29
+ sessions:
30
+ name: Session ${{ matrix.session }}
31
+ needs: [generate-jobs]
32
+ runs-on: ubuntu-latest
33
+ strategy:
34
+ fail-fast: false
35
+ matrix:
36
+ session: ${{ fromJson(needs.generate-jobs.outputs.session) }}
37
+ steps:
38
+ - uses: actions/checkout@v4
39
+ - uses: astral-sh/setup-uv@v5
40
+ with:
41
+ enable-cache: true
42
+ - uses: wntrblm/nox@main
43
+ - run: nox -s "${{ matrix.session }}"
@@ -0,0 +1,43 @@
1
+ name: Codecov
2
+
3
+ on:
4
+ pull_request:
5
+ push:
6
+ branches:
7
+ - main
8
+ - rc
9
+
10
+ jobs:
11
+ run:
12
+ runs-on: ubuntu-latest
13
+
14
+ permissions:
15
+ id-token: write
16
+ contents: read
17
+
18
+ steps:
19
+ - uses: actions/checkout@v4
20
+
21
+ - name: Install uv
22
+ uses: astral-sh/setup-uv@v5
23
+ with:
24
+ enable-cache: true
25
+
26
+ - name: Set up Python
27
+ uses: actions/setup-python@v5
28
+ with:
29
+ python-version-file: ".python-version"
30
+
31
+ - name: Install project
32
+ run: uv sync --all-extras --no-default-groups --group tests
33
+
34
+ - name: Generate coverage report
35
+ run: |
36
+ uv run pytest --cov --cov-report=xml
37
+
38
+ - name: Upload coverage to Codecov
39
+ uses: codecov/codecov-action@v5
40
+ with:
41
+ use_oidc: true
42
+ files: ./coverage.xml
43
+ flags: unittests
@@ -0,0 +1,87 @@
1
+ name: Semantic Release
2
+
3
+ on:
4
+ push:
5
+ branches:
6
+ - main
7
+ - rc
8
+
9
+ jobs:
10
+ Release:
11
+ runs-on: ubuntu-latest
12
+ concurrency: release
13
+
14
+ permissions:
15
+ id-token: write
16
+ contents: write
17
+
18
+ steps:
19
+ - uses: actions/checkout@v4
20
+ with:
21
+ fetch-depth: 0
22
+ ref: ${{ github.sha }}
23
+
24
+ - run: |
25
+ git checkout -B ${{ github.ref_name }} ${{ github.sha }}
26
+
27
+ - uses: astral-sh/setup-uv@v5
28
+ with:
29
+ enable-cache: true
30
+
31
+ # Run semantic-release from the locked environment rather than the
32
+ # published action. The action builds its own image and resolves
33
+ # gitpython~=3.0 at build time, so GitPython 3.1.60 -- which removed
34
+ # Actor.name_email_regex, an attribute PSR reads on every config load --
35
+ # breaks it from the outside, at every PSR version. Upstream:
36
+ # https://github.com/python-semantic-release/python-semantic-release/issues/1476
37
+ #
38
+ # Our lockfile pins a working GitPython, so this keeps releases
39
+ # reproducible and lets Dependabot bump both in step. Revert to the
40
+ # action once the fix ships.
41
+ - name: Python Semantic Release
42
+ id: release
43
+ env:
44
+ GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
45
+ GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
46
+ run: |
47
+ git config --global user.name "github-actions[bot]"
48
+ git config --global user.email \
49
+ "41898282+github-actions[bot]@users.noreply.github.com"
50
+ uv sync --frozen --no-default-groups --only-group=release
51
+ uv run --no-sync semantic-release version
52
+
53
+ # Same reason as the release step above: publish-action is also a
54
+ # Docker action and resolves the broken GitPython at build time.
55
+ #
56
+ # continue-on-error because this only attaches build artifacts to the
57
+ # GitHub release, which is a convenience: the tag, the release notes and
58
+ # the PyPI upload are what actually constitute a release. Letting it fail
59
+ # the job aborts the PyPI step below, leaving a version tagged on GitHub
60
+ # but absent from PyPI -- e.g. when GitHub has immutable releases turned
61
+ # on, since assets cannot be added to a release after it is created. A
62
+ # failure here is reported by the follow-up step rather than silently
63
+ # swallowed.
64
+ - name: Publish package to GitHub
65
+ id: publish_github
66
+ if: steps.release.outputs.released == 'true'
67
+ continue-on-error: true
68
+ env:
69
+ GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
70
+ GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
71
+ run: uv run --no-sync semantic-release publish --tag "${{ steps.release.outputs.tag }}"
72
+
73
+ - name: Warn if release assets were not attached
74
+ if: >-
75
+ steps.release.outputs.released == 'true'
76
+ && steps.publish_github.outcome == 'failure'
77
+ run: |
78
+ echo "::warning title=Release assets not attached::Could not upload \
79
+ build artifacts to the ${{ steps.release.outputs.tag }} GitHub \
80
+ release. The tag and the PyPI upload are unaffected. If the repo has \
81
+ immutable releases enabled, assets must be attached when the release \
82
+ is created; consider setting upload_to_vcs_release = false in \
83
+ pyproject.toml."
84
+
85
+ - name: Publish to PyPI
86
+ uses: pypa/gh-action-pypi-publish@release/v1
87
+ if: steps.release.outputs.released == 'true'
@@ -0,0 +1,166 @@
1
+ # Byte-compiled / optimized / DLL files
2
+ __pycache__/
3
+ *.py[cod]
4
+ *$py.class
5
+
6
+ # C extensions
7
+ *.so
8
+
9
+ # Distribution / packaging
10
+ .Python
11
+ build/
12
+ develop-eggs/
13
+ dist/
14
+ downloads/
15
+ eggs/
16
+ .eggs/
17
+ lib/
18
+ lib64/
19
+ parts/
20
+ sdist/
21
+ var/
22
+ wheels/
23
+ share/python-wheels/
24
+ *.egg-info/
25
+ .installed.cfg
26
+ *.egg
27
+ MANIFEST
28
+
29
+ # PyInstaller
30
+ # Usually these files are written by a python script from a template
31
+ # before PyInstaller builds the exe, so as to inject date/other infos into it.
32
+ *.manifest
33
+ *.spec
34
+
35
+ # Installer logs
36
+ pip-log.txt
37
+ pip-delete-this-directory.txt
38
+
39
+ # Unit test / coverage reports
40
+ htmlcov/
41
+ .tox/
42
+ .nox/
43
+ .coverage
44
+ .coverage.*
45
+ .cache
46
+ nosetests.xml
47
+ coverage.xml
48
+ *.cover
49
+ *.py,cover
50
+ .hypothesis/
51
+ .pytest_cache/
52
+ cover/
53
+
54
+ # Translations
55
+ *.mo
56
+ *.pot
57
+
58
+ # Django stuff:
59
+ *.log
60
+ local_settings.py
61
+ db.sqlite3
62
+ db.sqlite3-journal
63
+
64
+ # Flask stuff:
65
+ instance/
66
+ .webassets-cache
67
+
68
+ # Scrapy stuff:
69
+ .scrapy
70
+
71
+ # Sphinx documentation
72
+ docs/_build/
73
+
74
+ # PyBuilder
75
+ .pybuilder/
76
+ target/
77
+
78
+ # Jupyter Notebook
79
+ .ipynb_checkpoints
80
+
81
+ # IPython
82
+ profile_default/
83
+ ipython_config.py
84
+
85
+ # pyenv
86
+ # For a library or package, you might want to ignore these files since the code is
87
+ # intended to run in multiple environments; otherwise, check them in:
88
+ # .python-version
89
+
90
+ # pipenv
91
+ # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
92
+ # However, in case of collaboration, if having platform-specific dependencies or dependencies
93
+ # having no cross-platform support, pipenv may install dependencies that don't work, or not
94
+ # install all needed dependencies.
95
+ #Pipfile.lock
96
+
97
+ # poetry
98
+ # Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control.
99
+ # This is especially recommended for binary packages to ensure reproducibility, and is more
100
+ # commonly ignored for libraries.
101
+ # https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control
102
+ #poetry.lock
103
+
104
+ # pdm
105
+ # Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control.
106
+ #pdm.lock
107
+ # pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it
108
+ # in version control.
109
+ # https://pdm.fming.dev/#use-with-ide
110
+ .pdm.toml
111
+
112
+ # PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm
113
+ __pypackages__/
114
+
115
+ # Celery stuff
116
+ celerybeat-schedule
117
+ celerybeat.pid
118
+
119
+ # SageMath parsed files
120
+ *.sage.py
121
+
122
+ # Environments
123
+ .env
124
+ .venv
125
+ env/
126
+ venv/
127
+ ENV/
128
+ env.bak/
129
+ venv.bak/
130
+
131
+ # Spyder project settings
132
+ .spyderproject
133
+ .spyproject
134
+
135
+ # Rope project settings
136
+ .ropeproject
137
+
138
+ # mkdocs documentation
139
+ /site
140
+
141
+ # mypy
142
+ .mypy_cache/
143
+ .dmypy.json
144
+ dmypy.json
145
+
146
+ # ty
147
+ .ty_cache/
148
+
149
+ # Pyre type checker
150
+ .pyre/
151
+
152
+ # pytype static type analyzer
153
+ .pytype/
154
+
155
+ # Cython debug symbols
156
+ cython_debug/
157
+
158
+ # PyCharm
159
+ # JetBrains specific template is maintained in a separate JetBrains.gitignore that can
160
+ # be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore
161
+ # and can be added to the global gitignore or merged into this file. For a more nuclear
162
+ # option (not recommended) you can uncomment the following to ignore the entire idea folder.
163
+ #.idea/
164
+
165
+ # Ruff
166
+ .ruff_cache/
@@ -0,0 +1,11 @@
1
+ repos:
2
+ - repo: https://github.com/pre-commit/pre-commit-hooks
3
+ rev: 'v5.0.0'
4
+ hooks:
5
+ - id: check-toml
6
+ - id: check-yaml
7
+ exclude: ^mkdocs\.yml$
8
+ - id: check-json
9
+ - id: end-of-file-fixer
10
+ - id: trailing-whitespace
11
+ - id: requirements-txt-fixer
@@ -0,0 +1 @@
1
+ 3.14
@@ -0,0 +1 @@
1
+ 3.14
@@ -0,0 +1,19 @@
1
+ version: 2
2
+
3
+ build:
4
+ os: "ubuntu-lts-latest"
5
+ tools:
6
+ python: "latest"
7
+ jobs:
8
+ # https://docs.readthedocs.com/platform/stable/build-customization.html#install-dependencies-with-uv
9
+ create_environment:
10
+ - asdf plugin add uv
11
+ - asdf install uv latest
12
+ - asdf global uv latest
13
+ - uv venv $READTHEDOCS_VIRTUALENV_PATH
14
+ install:
15
+ - UV_PROJECT_ENVIRONMENT=$READTHEDOCS_VIRTUALENV_PATH uv sync --all-extras --no-default-groups --group docs
16
+
17
+ # Build documentation with MkDocs
18
+ mkdocs:
19
+ configuration: mkdocs.yml
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Micael Jarniac
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.