hadsync 0.2.2__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.
- hadsync-0.2.2/.claude/settings.local.json +13 -0
- hadsync-0.2.2/.github/ISSUE_TEMPLATE/bug_report.md +34 -0
- hadsync-0.2.2/.github/ISSUE_TEMPLATE/feature_request.md +17 -0
- hadsync-0.2.2/.gitignore +32 -0
- hadsync-0.2.2/.hadsync.yaml +12 -0
- hadsync-0.2.2/CHANGELOG.md +103 -0
- hadsync-0.2.2/CONTRIBUTING.md +42 -0
- hadsync-0.2.2/LICENSE +21 -0
- hadsync-0.2.2/PKG-INFO +403 -0
- hadsync-0.2.2/README.md +346 -0
- hadsync-0.2.2/docs/diff-conflict-summary.jpg +0 -0
- hadsync-0.2.2/docs/diff-show-flag.jpg +0 -0
- hadsync-0.2.2/docs/vscode-autocomplete.jpg +0 -0
- hadsync-0.2.2/docs/vscode-command-palette.jpg +0 -0
- hadsync-0.2.2/docs/vscode-entities-screenshot.jpg +0 -0
- hadsync-0.2.2/docs/vscode-problems-panel.jpg +0 -0
- hadsync-0.2.2/docs/vscode-screenshot.jpg +0 -0
- hadsync-0.2.2/hadsync/__init__.py +1 -0
- hadsync-0.2.2/hadsync/cli.py +979 -0
- hadsync-0.2.2/hadsync/config.py +123 -0
- hadsync-0.2.2/hadsync/converter.py +73 -0
- hadsync-0.2.2/hadsync/entities.py +134 -0
- hadsync-0.2.2/hadsync/ha_rest.py +41 -0
- hadsync-0.2.2/hadsync/ha_ws.py +144 -0
- hadsync-0.2.2/hadsync/output.py +20 -0
- hadsync-0.2.2/hadsync/schema.py +138 -0
- hadsync-0.2.2/hadsync/state.py +57 -0
- hadsync-0.2.2/hadsync/validator.py +168 -0
- hadsync-0.2.2/hadsync/watcher.py +119 -0
- hadsync-0.2.2/hadsync_design.docx +0 -0
- hadsync-0.2.2/pyproject.toml +71 -0
- hadsync-0.2.2/tests/__init__.py +0 -0
- hadsync-0.2.2/tests/unit/__init__.py +0 -0
- hadsync-0.2.2/tests/unit/test_config.py +146 -0
- hadsync-0.2.2/tests/unit/test_converter.py +120 -0
- hadsync-0.2.2/tests/unit/test_entities.py +218 -0
- hadsync-0.2.2/tests/unit/test_schema.py +112 -0
- hadsync-0.2.2/tests/unit/test_state.py +64 -0
- hadsync-0.2.2/tests/unit/test_validator.py +103 -0
- hadsync-0.2.2/vscode-hadsync/.vscodeignore +8 -0
- hadsync-0.2.2/vscode-hadsync/LICENSE +21 -0
- hadsync-0.2.2/vscode-hadsync/README.md +100 -0
- hadsync-0.2.2/vscode-hadsync/package-lock.json +59 -0
- hadsync-0.2.2/vscode-hadsync/package.json +119 -0
- hadsync-0.2.2/vscode-hadsync/src/commands.ts +270 -0
- hadsync-0.2.2/vscode-hadsync/src/completion.ts +54 -0
- hadsync-0.2.2/vscode-hadsync/src/diagnostics.ts +115 -0
- hadsync-0.2.2/vscode-hadsync/src/extension.ts +130 -0
- hadsync-0.2.2/vscode-hadsync/src/runner.ts +106 -0
- hadsync-0.2.2/vscode-hadsync/src/statusBar.ts +107 -0
- hadsync-0.2.2/vscode-hadsync/tsconfig.json +12 -0
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
{
|
|
2
|
+
"permissions": {
|
|
3
|
+
"allow": [
|
|
4
|
+
"Bash(python3 -c ' *)",
|
|
5
|
+
"Bash(HA_TOKEN=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiI1MWNjNTg4MzY0NzA0ODk0YThjOWMwMDg2ZGEwYTc2MCIsImlhdCI6MTc3ODE3NjgyNiwiZXhwIjoyMDkzNTM2ODI2fQ.BFWPnJp6Zxm0TIw5kGn2hImfEk51LOHnqQ_Zm5Dr09I hadsync init)",
|
|
6
|
+
"Bash(HA_TOKEN=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiI1MWNjNTg4MzY0NzA0ODk0YThjOWMwMDg2ZGEwYTc2MCIsImlhdCI6MTc3ODE3NjgyNiwiZXhwIjoyMDkzNTM2ODI2fQ.BFWPnJp6Zxm0TIw5kGn2hImfEk51LOHnqQ_Zm5Dr09I hadsync config *)",
|
|
7
|
+
"Bash(python3 -c \"import websockets; print\\(dir\\(websockets\\)\\)\")",
|
|
8
|
+
"Bash(git init *)",
|
|
9
|
+
"Bash(HA_TOKEN=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiI1MWNjNTg4MzY0NzA0ODk0YThjOWMwMDg2ZGEwYTc2MCIsImlhdCI6MTc3ODE3NjgyNiwiZXhwIjoyMDkzNTM2ODI2fQ.BFWPnJp6Zxm0TIw5kGn2hImfEk51LOHnqQ_Zm5Dr09I hadsync *)",
|
|
10
|
+
"Read(//Users/ggevorgyan/git/esp32/esp-tool/**)"
|
|
11
|
+
]
|
|
12
|
+
}
|
|
13
|
+
}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: Bug report
|
|
3
|
+
about: Something isn't working as expected
|
|
4
|
+
labels: bug
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
**hadsync version**
|
|
8
|
+
<!-- run: hadsync --version -->
|
|
9
|
+
|
|
10
|
+
**Home Assistant version**
|
|
11
|
+
<!-- run: hadsync list (shows HA version on connect), or check HA → Settings → About -->
|
|
12
|
+
|
|
13
|
+
**Command that failed**
|
|
14
|
+
```
|
|
15
|
+
hadsync ...
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
**What happened**
|
|
19
|
+
<!-- Clear description of the bug -->
|
|
20
|
+
|
|
21
|
+
**Steps to reproduce**
|
|
22
|
+
1.
|
|
23
|
+
2.
|
|
24
|
+
3.
|
|
25
|
+
|
|
26
|
+
**Expected behaviour**
|
|
27
|
+
|
|
28
|
+
**Actual behaviour / error output**
|
|
29
|
+
```
|
|
30
|
+
paste output here
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
**Additional context**
|
|
34
|
+
<!-- Dashboard type (storage-mode vs strategy), network setup, etc. -->
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: Feature request
|
|
3
|
+
about: Suggest an improvement or new command
|
|
4
|
+
labels: enhancement
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
**What problem does this solve?**
|
|
8
|
+
<!-- Describe the workflow gap or pain point -->
|
|
9
|
+
|
|
10
|
+
**Proposed solution**
|
|
11
|
+
<!-- How you'd like it to work. CLI examples are helpful. -->
|
|
12
|
+
|
|
13
|
+
**Alternatives considered**
|
|
14
|
+
<!-- Other approaches you've thought of -->
|
|
15
|
+
|
|
16
|
+
**Additional context**
|
|
17
|
+
<!-- Screenshots, HA version, dashboard structure, etc. -->
|
hadsync-0.2.2/.gitignore
ADDED
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
# Python
|
|
2
|
+
.venv/
|
|
3
|
+
uv.lock
|
|
4
|
+
.python-version
|
|
5
|
+
__pycache__/
|
|
6
|
+
*.py[cod]
|
|
7
|
+
*.egg-info/
|
|
8
|
+
dist/
|
|
9
|
+
build/
|
|
10
|
+
.eggs/
|
|
11
|
+
|
|
12
|
+
# Testing / coverage
|
|
13
|
+
.pytest_cache/
|
|
14
|
+
.coverage
|
|
15
|
+
htmlcov/
|
|
16
|
+
|
|
17
|
+
# Editors
|
|
18
|
+
.vscode/
|
|
19
|
+
.idea/
|
|
20
|
+
*.swp
|
|
21
|
+
|
|
22
|
+
# hadsync runtime files
|
|
23
|
+
.hadsync-state.json
|
|
24
|
+
.ha-entities.json
|
|
25
|
+
|
|
26
|
+
# dashboard workspace — lives in its own repo
|
|
27
|
+
ha-dashboards/
|
|
28
|
+
|
|
29
|
+
# VS Code extension build artifacts
|
|
30
|
+
vscode-hadsync/out/
|
|
31
|
+
vscode-hadsync/node_modules/
|
|
32
|
+
vscode-hadsync/*.vsix
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
ha_url: http://192.168.68.103:8123
|
|
2
|
+
ha_token: ${HA_TOKEN}
|
|
3
|
+
workspace: /Users/ggevorgyan/git/esp32/esphome/home-assistant-dashboards
|
|
4
|
+
pull:
|
|
5
|
+
refresh_entities: true
|
|
6
|
+
dashboards: all
|
|
7
|
+
push:
|
|
8
|
+
require_validation: true
|
|
9
|
+
confirm: true
|
|
10
|
+
validation:
|
|
11
|
+
warn_on_unknown_entities: true
|
|
12
|
+
entity_cache_max_age_days: 7
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
## [v0.2.2] — 2026-05-10
|
|
4
|
+
|
|
5
|
+
### Fixed — VS Code Extension
|
|
6
|
+
|
|
7
|
+
- **Stale diagnostics after external pull** — Problems panel no longer retains old errors after `hadsync pull` is run from the terminal. A `FileSystemWatcher` on `**/lovelace.yaml` now re-validates automatically when any file changes on disk, regardless of whether the change came from VS Code or an external process.
|
|
8
|
+
- **Incorrect "N modified" in status bar** — The status bar was counting every dashboard that had never been pushed as "modified", showing e.g. `13 modified` immediately after a clean pull. Fixed to use the same mtime-vs-last_pull comparison as `hadsync status` in the CLI — "modified" now means the local file was actually edited since the last pull.
|
|
9
|
+
|
|
10
|
+
[v0.2.2]: https://github.com/gevgev/hadsync/releases/tag/v0.2.2
|
|
11
|
+
|
|
12
|
+
---
|
|
13
|
+
|
|
14
|
+
## [v0.2.1] — 2026-05-10
|
|
15
|
+
|
|
16
|
+
### Added — Phase 1b (Conflict Detection)
|
|
17
|
+
|
|
18
|
+
- **`hadsync diff` conflict detection** — stores a hash of the HA config at every pull; diff now classifies each divergence into one of four verdicts:
|
|
19
|
+
- **CONFLICT** — both local and HA changed since last pull (shown in red with explicit next-step options)
|
|
20
|
+
- **HA changed only** — warns and suggests `hadsync pull <id>`
|
|
21
|
+
- **Local changed only** — warns and suggests `hadsync push <id>`
|
|
22
|
+
- **No baseline** — generic message when dashboard was never pulled with the new hash tracking
|
|
23
|
+
- **Pull timestamp in diff output** — `Last pull: 2026-05-10 18:19 (2h ago)` shown for each dashboard
|
|
24
|
+
- **Annotated change summary** — HA and local card counts now show `← changed since pull` or `(unchanged since pull)` tags
|
|
25
|
+
- **`ha_config_hash`** field in `.hadsync-state.json` — 16-char SHA-256 prefix of the normalized HA config stored on every pull; enables HA-side change detection without keeping a full config snapshot
|
|
26
|
+
|
|
27
|
+
### Fixed
|
|
28
|
+
|
|
29
|
+
- **Error handling gaps (community review)** — VS Code extension now shows `showErrorMessage()` popups on command failure; detects `hadsync not found` at activation with an Open Settings link; `onDidSaveTextDocument` wrapped in try/catch; 60-second subprocess timeout prevents VS Code freeze
|
|
30
|
+
- **Python error messages** — `ha_ws.py` now distinguishes connection refused, DNS failure, timeout, and auth_invalid with targeted, actionable messages including next-step hints (e.g. where to generate a long-lived token in HA)
|
|
31
|
+
- **Watch mode resilience** — `watcher.py` event handler wrapped in try/catch so an unexpected crash no longer silently kills the watchdog observer thread
|
|
32
|
+
|
|
33
|
+
[v0.2.1]: https://github.com/gevgev/hadsync/releases/tag/v0.2.1
|
|
34
|
+
|
|
35
|
+
---
|
|
36
|
+
|
|
37
|
+
## [v0.2.0] — 2026-05-09
|
|
38
|
+
|
|
39
|
+
Phases 2, 3, and 4 complete. All four design phases are now implemented.
|
|
40
|
+
|
|
41
|
+
### Added — Phase 2 (Entity Validation)
|
|
42
|
+
|
|
43
|
+
- **`hadsync entities refresh`** — fetches all entity states from HA `/api/states` and writes `.ha-entities.json`
|
|
44
|
+
- **`hadsync entities list [filter]`** — lists cached entities with domain and friendly name, filtered by substring
|
|
45
|
+
- **Entity ID extraction** — recursive walk of any Lovelace config depth; handles `entity:`, `entities:` (strings and dicts), conditional conditions, stack nesting, picture-elements, and any other nesting pattern
|
|
46
|
+
- **Phase 2 validation** — unknown entity IDs reported with line numbers; silently skipped if cache is absent (no friction before first `entities refresh`)
|
|
47
|
+
- **Cache age warning** — warns when entity cache exceeds `validation.entity_cache_max_age_days` (default: 7)
|
|
48
|
+
- **`validation.warn_on_unknown_entities`** config flag — controls whether unknown IDs are warnings (default) or errors that block push
|
|
49
|
+
|
|
50
|
+
### Added — Phase 3 (Schema Validation & Watch)
|
|
51
|
+
|
|
52
|
+
- **`hadsync watch [ID] [--auto-push]`** — watches workspace for `lovelace.yaml` saves; runs Phase 1+2+3 validation on every change; pushes to HA automatically when validation passes if `--auto-push` is set
|
|
53
|
+
- **Phase 3 card schema validation** — 35 standard Lovelace card types with required-field checks; `custom:*` always passes; unknown non-custom types warn rather than block; extra prefixes configurable via `validation.custom_card_types`
|
|
54
|
+
- **Enhanced `hadsync diff`** — view-by-view change summary (`+ added`, `- removed`, `~ N cards changed`) shown before the optional unified diff
|
|
55
|
+
- **`validation.custom_card_types`** config field — list of additional type prefixes treated as valid alongside `custom:*`
|
|
56
|
+
|
|
57
|
+
### Added — Phase 4 (VS Code Extension)
|
|
58
|
+
|
|
59
|
+
- **`vscode-hadsync/`** — VS Code extension written in TypeScript; activates on any workspace containing `.hadsync.yaml`
|
|
60
|
+
- **11 palette commands** (`Cmd+Shift+P`): pull (all / active), push (all / active, with confirmation dialog), validate (all / active), diff, status, list, entities refresh, entities search
|
|
61
|
+
- **Inline diagnostics** — on `lovelace.yaml` save, runs `hadsync --json-output validate`; errors and warnings appear in the Problems panel and as editor squiggles with correct line numbers
|
|
62
|
+
- **Status bar** — bottom-left item shows last pull time or modified-dashboard count; reads `.hadsync-state.json` directly; click opens status table
|
|
63
|
+
- **Entity ID autocomplete** — completion items from `.ha-entities.json` triggered by `entity: ` and list item patterns; includes friendly name and domain in detail
|
|
64
|
+
- **Context menu** — validate / push / diff available on right-click in any `lovelace.yaml` editor
|
|
65
|
+
- **Settings**: `hadsync.executablePath`, `hadsync.validateOnSave` (default: true), `hadsync.autoPushOnSave` (default: false)
|
|
66
|
+
|
|
67
|
+
### Changed
|
|
68
|
+
|
|
69
|
+
- **`hadsync validate --json-output`** — emits structured JSON (per-dashboard file path, passed flag, issue list with severity/message/line); used by the VS Code extension for diagnostics; human output unchanged when flag is absent
|
|
70
|
+
- **Validation pipeline** — `hadsync validate` and `hadsync push` pre-push validation now run Phase 1 + Phase 2 + Phase 3 in sequence
|
|
71
|
+
- **`hadsync diff`** — now includes view-level summary before optional unified diff
|
|
72
|
+
|
|
73
|
+
### Notes
|
|
74
|
+
|
|
75
|
+
- Tested against **Home Assistant 2026.5.0**
|
|
76
|
+
- VS Code extension requires `hadsync` on PATH or `hadsync.executablePath` setting; `HA_TOKEN` must be in the environment VS Code inherits
|
|
77
|
+
|
|
78
|
+
---
|
|
79
|
+
|
|
80
|
+
## [v0.1.0] — 2026-05-08
|
|
81
|
+
|
|
82
|
+
Initial release. Phase 1 (Core CLI) complete.
|
|
83
|
+
|
|
84
|
+
### Added
|
|
85
|
+
|
|
86
|
+
- **`hadsync init`** — interactive setup: HA URL, token env var (with validation to catch pasted token values), workspace directory. Tests live HA connection.
|
|
87
|
+
- **`hadsync list`** — discovers all storage-mode Lovelace dashboards on the HA instance.
|
|
88
|
+
- **`hadsync pull [ID]`** — downloads one or all dashboards from HA as local YAML; auto-refreshes entity cache (`.ha-entities.json`); skips strategy-based dashboards with a warning.
|
|
89
|
+
- **`hadsync push [ID]`** — uploads local YAML to HA with layered safety: pre-push validation, no-op guard (skips if already in sync), change summary (view/card counts), destructive-change warnings, explicit per-dashboard confirmation, and `--dry-run` mode.
|
|
90
|
+
- **`hadsync validate [ID]`** — standalone YAML validation (syntax + structure) with PASS / WARN / FAIL per dashboard and line numbers on errors. Safe for CI pipelines — no HA connection required.
|
|
91
|
+
- **`hadsync status`** — sync status table: last pull time, last push time, local state (clean / modified / never pulled). No HA connection required.
|
|
92
|
+
- **`hadsync diff [ID] [--show]`** — compares local YAML against live HA state. `--show` renders a coloured unified diff (red = HA, green = local).
|
|
93
|
+
- **`hadsync config show`** — displays resolved config with masked token and workspace source.
|
|
94
|
+
- **`HADSYNC_WORKSPACE` env var** — overrides the workspace directory at runtime without editing config.
|
|
95
|
+
|
|
96
|
+
### Notes
|
|
97
|
+
|
|
98
|
+
- Tested against **Home Assistant 2026.5.0**.
|
|
99
|
+
- The HA WebSocket commands referenced in common documentation (`lovelace/dashboards`, `lovelace/save_config`) do not exist in HA 2026.5. This release uses the correct equivalents: `get_panels` (filtered by `component_name=lovelace`) and `lovelace/config/save`.
|
|
100
|
+
- Strategy-based dashboards (auto-generated by HA, e.g. the default Overview using `original-states` strategy) are detected during pull and skipped — they cannot be meaningfully round-tripped as static YAML.
|
|
101
|
+
|
|
102
|
+
[v0.2.0]: https://github.com/gevgev/hadsync/releases/tag/v0.2.0
|
|
103
|
+
[v0.1.0]: https://github.com/gevgev/hadsync/releases/tag/v0.1.0
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
# Contributing to hadsync
|
|
2
|
+
|
|
3
|
+
Contributions are welcome — bug reports, feature requests, and pull requests.
|
|
4
|
+
|
|
5
|
+
## Before you open a PR
|
|
6
|
+
|
|
7
|
+
- Check [open issues](https://github.com/gevgev/hadsync/issues) to avoid duplicate work
|
|
8
|
+
- For anything beyond a small fix, open an issue first to discuss the approach
|
|
9
|
+
|
|
10
|
+
## Development setup
|
|
11
|
+
|
|
12
|
+
```bash
|
|
13
|
+
git clone https://github.com/gevgev/hadsync.git
|
|
14
|
+
cd hadsync
|
|
15
|
+
uv tool install --editable . # or: pip install -e ".[dev]"
|
|
16
|
+
pytest tests/
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
## Running tests
|
|
20
|
+
|
|
21
|
+
```bash
|
|
22
|
+
pytest tests/ # 43 unit tests, no HA connection required
|
|
23
|
+
pytest tests/unit/ # unit tests only
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
Unit tests use no live HA instance. If you change `ha_ws.py`, please also test manually against a real HA instance — the WebSocket API has version-specific behavior that mocks cannot fully capture.
|
|
27
|
+
|
|
28
|
+
## HA version compatibility
|
|
29
|
+
|
|
30
|
+
hadsync is tested against **Home Assistant 2026.5**. Please note the HA version you tested against in your PR description.
|
|
31
|
+
|
|
32
|
+
> **Note:** The WS commands used differ from common documentation. See [HA API Notes](README.md#ha-api-notes) in the README before touching the WebSocket client.
|
|
33
|
+
|
|
34
|
+
## Code style
|
|
35
|
+
|
|
36
|
+
- Python 3.11+, type annotations throughout
|
|
37
|
+
- No comments describing *what* the code does — only *why* when non-obvious
|
|
38
|
+
- Keep modules focused: CLI routing lives in `cli.py`, HA communication in `ha_ws.py` / `ha_rest.py`, etc.
|
|
39
|
+
|
|
40
|
+
## Reporting bugs
|
|
41
|
+
|
|
42
|
+
Please use the [bug report template](.github/ISSUE_TEMPLATE/bug_report.md) and include your HA version — it matters for reproducing WS API issues.
|
hadsync-0.2.2/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Gevorg Gevorgyan
|
|
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.
|