edge-proc 0.1.5__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 (80) hide show
  1. edge_proc-0.1.5/.gitignore +35 -0
  2. edge_proc-0.1.5/CHANGELOG.md +220 -0
  3. edge_proc-0.1.5/LICENSE +21 -0
  4. edge_proc-0.1.5/PKG-INFO +512 -0
  5. edge_proc-0.1.5/README.md +477 -0
  6. edge_proc-0.1.5/edgeproc/__init__.py +47 -0
  7. edge_proc-0.1.5/edgeproc/_version.py +3 -0
  8. edge_proc-0.1.5/edgeproc/bundles/__init__.py +0 -0
  9. edge_proc-0.1.5/edgeproc/bundles/adapters.py +101 -0
  10. edge_proc-0.1.5/edgeproc/bundles/cas.py +346 -0
  11. edge_proc-0.1.5/edgeproc/bundles/chunking.py +99 -0
  12. edge_proc-0.1.5/edgeproc/bundles/containment.py +56 -0
  13. edge_proc-0.1.5/edgeproc/bundles/manifest.py +147 -0
  14. edge_proc-0.1.5/edgeproc/bundles/publish.py +174 -0
  15. edge_proc-0.1.5/edgeproc/bundles/signing.py +102 -0
  16. edge_proc-0.1.5/edgeproc/bundles/sync.py +263 -0
  17. edge_proc-0.1.5/edgeproc/cli/__init__.py +7 -0
  18. edge_proc-0.1.5/edgeproc/cli/app.py +551 -0
  19. edge_proc-0.1.5/edgeproc/core/__init__.py +0 -0
  20. edge_proc-0.1.5/edgeproc/core/facade.py +119 -0
  21. edge_proc-0.1.5/edgeproc/core/memory.py +70 -0
  22. edge_proc-0.1.5/edgeproc/core/models.py +113 -0
  23. edge_proc-0.1.5/edgeproc/core/protocols.py +53 -0
  24. edge_proc-0.1.5/edgeproc/core/registry.py +23 -0
  25. edge_proc-0.1.5/edgeproc/core/router.py +24 -0
  26. edge_proc-0.1.5/edgeproc/core/settings.py +73 -0
  27. edge_proc-0.1.5/edgeproc/core/telemetry.py +40 -0
  28. edge_proc-0.1.5/edgeproc/errors.py +82 -0
  29. edge_proc-0.1.5/edgeproc/localvec/__init__.py +0 -0
  30. edge_proc-0.1.5/edgeproc/localvec/encoder.py +82 -0
  31. edge_proc-0.1.5/edgeproc/localvec/faiss_index.py +232 -0
  32. edge_proc-0.1.5/edgeproc/localvec/fusion.py +33 -0
  33. edge_proc-0.1.5/edgeproc/localvec/loader.py +33 -0
  34. edge_proc-0.1.5/edgeproc/localvec/runtime.py +171 -0
  35. edge_proc-0.1.5/edgeproc/localvec/searcher.py +43 -0
  36. edge_proc-0.1.5/edgeproc/py.typed +0 -0
  37. edge_proc-0.1.5/examples/README.md +14 -0
  38. edge_proc-0.1.5/examples/catalog.json +17 -0
  39. edge_proc-0.1.5/examples/quickstart.py +62 -0
  40. edge_proc-0.1.5/examples/run_loop.sh +58 -0
  41. edge_proc-0.1.5/pyproject.toml +167 -0
  42. edge_proc-0.1.5/tests/__init__.py +0 -0
  43. edge_proc-0.1.5/tests/bundles/__init__.py +0 -0
  44. edge_proc-0.1.5/tests/bundles/_producer.py +39 -0
  45. edge_proc-0.1.5/tests/bundles/test_adapters.py +46 -0
  46. edge_proc-0.1.5/tests/bundles/test_cas.py +340 -0
  47. edge_proc-0.1.5/tests/bundles/test_chunking.py +104 -0
  48. edge_proc-0.1.5/tests/bundles/test_concurrency.py +114 -0
  49. edge_proc-0.1.5/tests/bundles/test_containment.py +78 -0
  50. edge_proc-0.1.5/tests/bundles/test_manifest_v2.py +173 -0
  51. edge_proc-0.1.5/tests/bundles/test_pointer_hardening.py +283 -0
  52. edge_proc-0.1.5/tests/bundles/test_publish.py +417 -0
  53. edge_proc-0.1.5/tests/bundles/test_signing.py +84 -0
  54. edge_proc-0.1.5/tests/bundles/test_sync_caps.py +92 -0
  55. edge_proc-0.1.5/tests/bundles/test_sync_index.py +237 -0
  56. edge_proc-0.1.5/tests/bundles/test_sync_integration.py +198 -0
  57. edge_proc-0.1.5/tests/cli/__init__.py +0 -0
  58. edge_proc-0.1.5/tests/cli/test_cli.py +463 -0
  59. edge_proc-0.1.5/tests/core/__init__.py +0 -0
  60. edge_proc-0.1.5/tests/core/test_facade.py +131 -0
  61. edge_proc-0.1.5/tests/core/test_memory.py +51 -0
  62. edge_proc-0.1.5/tests/core/test_models.py +125 -0
  63. edge_proc-0.1.5/tests/core/test_protocols.py +72 -0
  64. edge_proc-0.1.5/tests/core/test_registry.py +37 -0
  65. edge_proc-0.1.5/tests/core/test_router.py +57 -0
  66. edge_proc-0.1.5/tests/core/test_settings.py +94 -0
  67. edge_proc-0.1.5/tests/core/test_telemetry.py +43 -0
  68. edge_proc-0.1.5/tests/localvec/__init__.py +0 -0
  69. edge_proc-0.1.5/tests/localvec/_fakes.py +33 -0
  70. edge_proc-0.1.5/tests/localvec/test_encoder.py +86 -0
  71. edge_proc-0.1.5/tests/localvec/test_faiss_index.py +241 -0
  72. edge_proc-0.1.5/tests/localvec/test_fusion.py +40 -0
  73. edge_proc-0.1.5/tests/localvec/test_loader.py +78 -0
  74. edge_proc-0.1.5/tests/localvec/test_runtime.py +134 -0
  75. edge_proc-0.1.5/tests/localvec/test_searcher.py +35 -0
  76. edge_proc-0.1.5/tests/test_errors.py +134 -0
  77. edge_proc-0.1.5/tests/test_integration.py +99 -0
  78. edge_proc-0.1.5/tests/test_public_surface.py +71 -0
  79. edge_proc-0.1.5/tests/test_release_contract_docs.py +186 -0
  80. edge_proc-0.1.5/tests/test_workflow_security.py +46 -0
@@ -0,0 +1,35 @@
1
+ __pycache__/
2
+ *.py[cod]
3
+ .venv/
4
+ venv/
5
+ build/
6
+ dist/
7
+ *.egg-info/
8
+ .coverage
9
+ coverage.xml
10
+ coverage.json
11
+ .pytest_cache/
12
+ .ruff_cache/
13
+ .mypy_cache/
14
+ .DS_Store
15
+ .env
16
+
17
+ # Signing key material — defense-in-depth. `edgeproc keygen` writes a real
18
+ # private.key; never let one be committed. (Public verification keys, when shipped,
19
+ # live under examples/ and are added explicitly.)
20
+ private.key
21
+ *.key
22
+ *.pem
23
+ keys/
24
+
25
+ .deps/
26
+
27
+ # Generated by the security-audit workflow (`uv export`); never commit it.
28
+ requirements-audit.txt
29
+
30
+ # Serena MCP tool scratch
31
+ .serena/
32
+
33
+ # `examples/quickstart.py` defaults its --out here, so running the example
34
+ # regenerates this FAISS index. Build output, never a source artifact.
35
+ examples/catalog_idx/
@@ -0,0 +1,220 @@
1
+ # Changelog
2
+
3
+ All notable changes to **edge-proc**. Newest first; we follow [SemVer](https://semver.org).
4
+
5
+ ## [Unreleased]
6
+
7
+ ## [0.1.5] — 2026-07-21
8
+
9
+ First release published to PyPI as
10
+ [`edge-proc`](https://pypi.org/project/edge-proc/), so `pip install edge-proc`
11
+ (and its extras) now works directly.
12
+
13
+ ### Added
14
+ - **`edgeproc gc` command.** The runbook told operators to reclaim disk through
15
+ `FilesystemCacheStore.gc()`, but no CLI entry point existed — an operation documented
16
+ with no way to run it. `edgeproc gc --cache-dir <cache>` sweeps every chunk and manifest
17
+ the active pointer does not reference, behind the store's mutation lock, and is a
18
+ no-op on a store with nothing promoted.
19
+ - **Canonical codes on every operator-facing failure.** `SignatureError` and
20
+ `ResponseTooLargeError` now carry `bundle.integrity_failed` / `bundle.download_failed`,
21
+ and the CLI stamps its fail-closed config refusals with `config.missing` /
22
+ `config.invalid`. A test now fails if a declared code has no throw site.
23
+ - **Performance-claim drift guard.** A test compares the committed evidence table in
24
+ `docs/OPERATIONS.md` against the committed budgets in `benchmarks/benchmark.py` —
25
+ never against a benchmark run at test time, so it cannot flake on machine variance.
26
+
27
+ ### Changed
28
+ - **`edgeproc-core` now installs from PyPI.** The `[tool.uv.sources]` git pin
29
+ (commit `6cdf847`) is dropped; the dependency is a plain `edgeproc-core>=0.2.1`
30
+ requirement resolved from PyPI, where upstream's `0.2.1` release is the first
31
+ to ship the `edgeproc_core` import package. README and CONTRIBUTING
32
+ onboarding prose follow, and the commented local path override remains for
33
+ co-development.
34
+ - **Upstream dependency renamed `shared-libs-python` → `edgeproc-core`.** Imports move
35
+ from `shared_libs_python.*` to `edgeproc_core.*`, and the dependency spec, the
36
+ `[tool.uv.sources]` key, and the lock all follow. The upstream GitHub repository is
37
+ unchanged, so the git URL still reads `hseshadr/shared-libs-python`; only the
38
+ distribution and import names moved. The pin advances to the commit carrying the new
39
+ name — still a full immutable SHA, never a mutable tag.
40
+ - **One implementation of sequence freshness.** `cas._sequence_violation` delegates its
41
+ counter comparison to the public `is_fresh_sequence` predicate instead of keeping a
42
+ private near-duplicate, so the two can no longer drift apart. Behavior is unchanged,
43
+ including the idempotent same-sequence re-promote.
44
+ - **Performance figures have one home.** The README restated a cold-sync p95 of 55 ms
45
+ that was actually that run's p50, while `docs/OPERATIONS.md` said 111.0 ms. Measured
46
+ figures now live only in `docs/OPERATIONS.md`, with the hardware stated; the README
47
+ links to them.
48
+ - **The shared error dependency is pinned by commit SHA, not tag.** A git tag is mutable,
49
+ so a moved `v0.2.0` would have silently changed the dependency for every clone. Pinned
50
+ to `ed1c3f6414710cb27d1c01e5fc2d6cadf0214b25`, the commit that tag pointed at.
51
+ - **The workflow-pinning audit scans `*.yaml` as well as `*.yml`** and asserts a non-zero
52
+ action count, so a renamed workflow can no longer make the check pass vacuously.
53
+ - **`.env.example` documents the whole config surface.** It listed 3 of 15 settings
54
+ fields; a test now fails if any field is undocumented.
55
+ - **`CITATION.cff` version tracked into the drift test.** It had sat at `0.1.1` through
56
+ three releases; the existing version-drift test now covers it.
57
+
58
+ ### Removed
59
+ - **`EdgeProc.local_default()`** — a zero-argument constructor whose empty registry
60
+ refused every task, advertising a working default that could not work. Construct
61
+ `EdgeProc(RuntimeRegistry())` explicitly.
62
+ - **`MemoryManager.reserved_bytes`** — a counter no production code read;
63
+ `MemoryBudgetExceededError` already reports available and total capacity at the only
64
+ moment the number matters.
65
+
66
+ ### Notes
67
+ - **A `v0.1.5` tag is deliberately HELD.** `publish.yml` triggers on `v*`, and edge-proc's
68
+ PyPI publish must stay blocked until `edgeproc-core` (a `Requires-Dist`) is itself
69
+ on PyPI. Tagging is a separate, sequenced decision — not a step in finishing this work.
70
+
71
+ ## [0.1.5] — 2026-07-20
72
+
73
+ ### Added
74
+ - **Canonical, portable integrity failures.** Bundle-integrity exceptions now
75
+ carry the shared `bundle.integrity_failed` code and can be rendered as RFC
76
+ 9457 Problem Details without changing their existing Python type or message.
77
+ - **Evidence-backed operating contract and benchmark.** A single operations guide now
78
+ defines threat/privacy boundaries, recovery ownership, fixed resource limits, and a
79
+ repeatable offline p50/p95/RSS gate for vector search and signed bundle sync.
80
+
81
+ ### Changed
82
+ - **Task memory budgets fail closed at the typed boundary.** Non-positive
83
+ `budget_memory_mb` values are rejected by `Task`; forged/unvalidated task
84
+ instances receive an `invalid_memory_budget` failure envelope instead of
85
+ leaking a raw `ValueError` from admission control.
86
+ - **The shared error dependency now resolves from its released v0.2.0 tag.**
87
+ Fresh clones and CI consume the same immutable public release instead of the
88
+ temporary pre-release commit pin.
89
+ - **Filesystem mutations are cross-process serialized and bounded.** Publish, sync,
90
+ rollback-check/promote, GC, and CLI materialization share one mutation lock, closing
91
+ stale-last-writer and sync-vs-GC races. Lock waits fail retryably after 30 seconds.
92
+ - **Task budgets are documented truthfully.** The v0 fields are runtime declarations,
93
+ not facade-level preemption or whole-process memory enforcement.
94
+ - **Workflow actions are immutable.** CI, gitleaks, and scheduled dependency-audit
95
+ actions are pinned to full commit SHAs, with a regression test that rejects moving tags.
96
+ - **Security lock refresh.** `setuptools` is locked at 83.0.0, clearing
97
+ PYSEC-2026-3447 reported by the exact-branch dependency audit.
98
+
99
+ ## [0.1.4] — 2026-07-13
100
+
101
+ - **`__version__` re-synced to the released version and single-sourced.**
102
+ `edgeproc.__version__` — and with it the `edgeproc version` CLI output and the
103
+ `runtime_version` stamped into every `ResultEnvelope`'s provenance — had been stuck at
104
+ `0.1.1` while the package shipped `0.1.3`. The version now lives only in
105
+ `edgeproc/_version.py`; hatchling reads it at build time (`dynamic = ["version"]`), so the
106
+ installed metadata and `__version__` are one value by construction. A regression test pins
107
+ `importlib.metadata.version("edge-proc") == edgeproc.__version__`.
108
+ - **Single-point trust-boundary hardening.** Bundle models now reject non-canonical SHA-256
109
+ values for chunk, file, and manifest digests; direct CAS calls validate digests and resolve
110
+ every object path inside the store root, including symlinked storage directories. Monotonic
111
+ sequences must be non-negative, and reusing an active sequence for different content is
112
+ rejected while exact idempotent replay and legacy signed-pointer bytes remain unchanged.
113
+ `keygen` creates or tightens its output directory to owner-only mode `0700`.
114
+
115
+ ## [0.1.3] — 2026-07-12
116
+
117
+ Security hardening pass (#11) — **additive runtime safety only**. No persisted or signed
118
+ manifest/pointer format changed; `canonical_bytes`, signing, and verification are untouched,
119
+ so every already-signed bundle still verifies and materializes unchanged.
120
+
121
+ - **Local-FS hardening: `O_NOFOLLOW` on key writes + aggregate sync caps.** `keygen` now
122
+ writes `private.key`/`public.key` with `O_NOFOLLOW` (portable via `getattr`), so a symlink
123
+ pre-planted at a key path is refused (ELOOP → fail-closed) instead of redirecting the write
124
+ onto a victim file; materialization was already symlink-safe via the §3.1 containment gate, so
125
+ it is unchanged. `sync_index` gains a fail-closed aggregate ceiling — `max_files` (refused
126
+ before any fetch) and `max_total_bytes` (a running ceiling that aborts before writing the chunk
127
+ that would cross it) — so a hostile or runaway manifest can't enumerate unbounded chunks/files
128
+ to exhaust disk. Defaults are generous (4 GiB / 100k files) and configurable via
129
+ `EdgeProcSettings`; `sync` behavior on a legitimate bundle is unchanged.
130
+ - **Signed-pointer identity binding + monotonic sequence (opt-in, backward-compatible).**
131
+ `VersionPointer` gains three optional fields — `bundle_id`, `channel`, `sequence` — folded
132
+ into the signed bytes only when set (`pointer_signing_bytes`), so a pointer that binds none
133
+ of them hashes to the exact legacy `{manifest_hash, version}` preimage and every
134
+ already-signed pointer verifies byte-for-byte. `publish --bind-identity`/`--channel`/
135
+ `--sequence` stamp them; `sync --expected-bundle-id`/`--expected-channel` pin the consumer
136
+ so a validly-signed pointer minted for another bundle/channel (a cross-bundle replay under a
137
+ shared key + transport compromise) is refused before promote, and a pointer whose bound
138
+ `bundle_id` disagrees with its manifest is rejected. A provably-lower `sequence` is refused at
139
+ `promote` alongside the PEP 440 anti-rollback guard, and `is_fresh_sequence` gives a downstream
140
+ a strict-monotonic freshness/anti-replay predicate. All identity/freshness inputs are opt-in;
141
+ the default `publish`/`sync` behavior and the persisted pointer format are unchanged.
142
+ - **Trust-boundary path containment (§3.1 trust gate).** New `bundles/containment.py`
143
+ chokepoint refuses traversal (`../`), backslash, and absolute paths. A `FileEntry.path`
144
+ `field_validator` rejects an unsafe path at parse time, and materialization re-checks the
145
+ fully-resolved target still lies inside the output root (catches symlink/zip-slip escapes).
146
+ - **Private key written 0600.** `keygen` now writes `private.key` with owner-only
147
+ permissions instead of the umask default (world-readable 0644).
148
+ - **Decompression-bomb + oversized-body caps.** CAS decompression streams at most
149
+ `max_decompressed_bytes` (default 64 MiB) rather than trusting the zstd frame's
150
+ content-size header, and the HTTP adapter refuses a response body past `max_fetch_bytes`
151
+ (default 256 MiB) — both fail-closed and configurable via `EdgeProcSettings`.
152
+ - **Anti-rollback on promote.** `promote()` refuses a signed pointer whose version is
153
+ provably older (PEP 440) than the active one, so a replayed stale `/latest` cannot
154
+ downgrade a client. Equal/forward versions, first promote, and unparseable versions are
155
+ still allowed — a valid signed bundle is never rejected.
156
+ - **FAISS stale-row purge.** Deleting an id then re-inserting it no longer leaves the old
157
+ physical row addressable; search never returns the duplicated/stale-scored entity, and
158
+ `get_stats` counts the superseded row so a rebuild compacts it.
159
+ - **CVE lock bumps (#9).** `torch` 2.12.0→2.13.0 (CVE-2025-3000), `cryptography`
160
+ 48.0.0→49.0.0 (GHSA-537c-gmf6-5ccf), `pydantic-settings` 2.14.1→2.14.2
161
+ (GHSA-4xgf-cpjx-pc3j) — all in-range lock bumps, no `pyproject` floor changes.
162
+
163
+ ## [0.1.2] — 2026-07-11
164
+
165
+ Propagation-chain release: re-pins the upstream dependency so downstream consumers can bump
166
+ in one hop (`shared-libs-python v0.1.3 → edge-proc v0.1.2 → edge-reco`). No library
167
+ code changes.
168
+
169
+ - **Deps.** `shared-libs-python` git-tag pin bumped v0.1.2 → **v0.1.3** (upstream
170
+ release is gate/CI/docs-only — zero runtime change).
171
+
172
+ Also ships the house engineering-standard alignment — CI and docs only:
173
+
174
+ - **CI.** The workflow now literally runs `uv run poe gate`, so the local gate and CI
175
+ can never drift one-sidedly; minimal token permissions; `uv sync --frozen`;
176
+ `astral-sh/setup-uv` full-pinned to v8.3.2 (no floating major tag exists); new
177
+ full-history gitleaks secret-scan job.
178
+ - **Security.** Weekly `security-audit.yml` (pip-audit over the exported lock) and
179
+ `dependabot.yml` (weekly, grouped: github-actions + uv ecosystems).
180
+ - **Docs.** New `CLAUDE.md` (agent guide: invariants, commands, scarred quality gates);
181
+ the roadmap's WASM entry upgraded to the named "First-party WASM kernel v0" item with
182
+ a gradeable definition of done (README + ROADMAP.md).
183
+
184
+ ## 0.1.1 — 2026-06-19
185
+
186
+ Public open-source release (MIT). Part of the `edge-reco → edge-proc →
187
+ shared-libs-python` stack going public together; live demo at https://edge-reco.com.
188
+
189
+ - **Clone-and-go onboarding.** `shared-libs-python` is now pulled from public GitHub
190
+ via a git source pinned to a tag (`[tool.uv.sources]`), so `git clone … && uv sync`
191
+ works with no sibling checkout. A commented path-source override remains for local
192
+ co-development.
193
+ - **CI simplified.** Dropped the private-sibling checkout + path-patch steps and the
194
+ `PORTFOLIO_PAT` secret — CI now builds exactly as an external cloner does.
195
+ - **Docs.** README sharpened to lead with the substrate value proposition (edge compute
196
+ cost, CDN-scale, offline resilience) and cross-link the three-repo stack.
197
+
198
+ ## 0.1.0 — 2026-05-28
199
+
200
+ First public release: the AI-native local execution substrate as a library + CLI.
201
+
202
+ - **Core seam.** `EdgeProc` facade, `Runtime`/`Router`/`TelemetrySink` Protocols,
203
+ pure-deterministic `DefaultRouter`, `RuntimeRegistry`, fail-closed
204
+ `no_runtime_accepted` envelope. No LLM in the routing path.
205
+ - **LocalVec runtime.** FAISS-backed `EMBED` / `SEARCH` / `RANK` with hybrid BM25 +
206
+ vector RRF fusion. `LocalVecRuntime.from_texts(catalog, encoder=...)` is the
207
+ one-call wiring for the README quickstart.
208
+ - **Signed bundle/sync substrate** (`[bundles]` extra). Content-defined chunking
209
+ (GearCDC), content-addressed CAS with zstd compression + atomic promote + GC,
210
+ ed25519-signed `VersionPointer` (the only signed object), fail-closed
211
+ signature/integrity/decompress checks, hardlink-deduped origin layout so
212
+ re-publishing an unchanged catalog touches zero chunks.
213
+ - **CLI** (`edgeproc`). `version`, `list-runtimes`, `keygen`, `publish`, `sync`,
214
+ `route` — every fetch path verifies against a pinned trust-root pubkey or
215
+ refuses to run.
216
+ - **End-to-end example.** `examples/quickstart.py` + `examples/run_loop.sh`
217
+ exercise keygen → publish → sync → route over a tiny realistic catalog.
218
+
219
+ The Wasmtime deterministic kernel, Biscuit capability tokens, and Sigstore-keyless
220
+ bundles are kept as Protocol seams for future drop-in — not in 0.1.0.
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Harish Seshadri
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.