softgnn-advisor 0.1.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. softgnn_advisor-0.1.0/CHANGELOG.md +44 -0
  2. softgnn_advisor-0.1.0/LICENSE +21 -0
  3. softgnn_advisor-0.1.0/MANIFEST.in +5 -0
  4. softgnn_advisor-0.1.0/PKG-INFO +430 -0
  5. softgnn_advisor-0.1.0/README.md +382 -0
  6. softgnn_advisor-0.1.0/ROADMAP.md +194 -0
  7. softgnn_advisor-0.1.0/pyproject.toml +70 -0
  8. softgnn_advisor-0.1.0/setup.cfg +4 -0
  9. softgnn_advisor-0.1.0/softgnn_advisor/__init__.py +2 -0
  10. softgnn_advisor-0.1.0/softgnn_advisor/__main__.py +4 -0
  11. softgnn_advisor-0.1.0/softgnn_advisor/cli.py +1254 -0
  12. softgnn_advisor-0.1.0/softgnn_advisor/config/__init__.py +0 -0
  13. softgnn_advisor-0.1.0/softgnn_advisor/config/settings.py +60 -0
  14. softgnn_advisor-0.1.0/softgnn_advisor/core/ai/__init__.py +4 -0
  15. softgnn_advisor-0.1.0/softgnn_advisor/core/ai/gnn_architecture.py +97 -0
  16. softgnn_advisor-0.1.0/softgnn_advisor/core/ai/predicter.py +264 -0
  17. softgnn_advisor-0.1.0/softgnn_advisor/core/change_provider.py +290 -0
  18. softgnn_advisor-0.1.0/softgnn_advisor/core/developer_aliases.py +31 -0
  19. softgnn_advisor-0.1.0/softgnn_advisor/core/file_filters.py +83 -0
  20. softgnn_advisor-0.1.0/softgnn_advisor/core/impact_engine.py +355 -0
  21. softgnn_advisor-0.1.0/softgnn_advisor/core/interfaces.py +45 -0
  22. softgnn_advisor-0.1.0/softgnn_advisor/core/llm_provider.py +163 -0
  23. softgnn_advisor-0.1.0/softgnn_advisor/core/llm_test_schema.py +94 -0
  24. softgnn_advisor-0.1.0/softgnn_advisor/core/metadata_utils.py +65 -0
  25. softgnn_advisor-0.1.0/softgnn_advisor/core/plan_cache.py +192 -0
  26. softgnn_advisor-0.1.0/softgnn_advisor/core/pr_scanner.py +468 -0
  27. softgnn_advisor-0.1.0/softgnn_advisor/core/test_generation_agent.py +861 -0
  28. softgnn_advisor-0.1.0/softgnn_advisor/infrastructure/pipelines/__init__.py +4 -0
  29. softgnn_advisor-0.1.0/softgnn_advisor/infrastructure/pipelines/ast_parser.py +306 -0
  30. softgnn_advisor-0.1.0/softgnn_advisor/infrastructure/pipelines/contract_extractor.py +210 -0
  31. softgnn_advisor-0.1.0/softgnn_advisor/infrastructure/pipelines/feature_encoder.py +106 -0
  32. softgnn_advisor-0.1.0/softgnn_advisor/infrastructure/pipelines/git_parser.py +92 -0
  33. softgnn_advisor-0.1.0/softgnn_advisor/infrastructure/pipelines/runtime_coverage_mapper.py +348 -0
  34. softgnn_advisor-0.1.0/softgnn_advisor/infrastructure/pipelines/test_parser.py +210 -0
  35. softgnn_advisor-0.1.0/softgnn_advisor/infrastructure/repositories/__init__.py +5 -0
  36. softgnn_advisor-0.1.0/softgnn_advisor/infrastructure/repositories/feature_repo.py +64 -0
  37. softgnn_advisor-0.1.0/softgnn_advisor/infrastructure/repositories/graph_repo.py +63 -0
  38. softgnn_advisor-0.1.0/softgnn_advisor/infrastructure/repositories/model_repo.py +68 -0
  39. softgnn_advisor-0.1.0/softgnn_advisor/scripts/etl_run.py +160 -0
  40. softgnn_advisor-0.1.0/softgnn_advisor/scripts/train_model.py +186 -0
  41. softgnn_advisor-0.1.0/softgnn_advisor.egg-info/PKG-INFO +430 -0
  42. softgnn_advisor-0.1.0/softgnn_advisor.egg-info/SOURCES.txt +48 -0
  43. softgnn_advisor-0.1.0/softgnn_advisor.egg-info/dependency_links.txt +1 -0
  44. softgnn_advisor-0.1.0/softgnn_advisor.egg-info/entry_points.txt +2 -0
  45. softgnn_advisor-0.1.0/softgnn_advisor.egg-info/requires.txt +27 -0
  46. softgnn_advisor-0.1.0/softgnn_advisor.egg-info/top_level.txt +1 -0
  47. softgnn_advisor-0.1.0/tests/test_change_provider.py +47 -0
  48. softgnn_advisor-0.1.0/tests/test_llm_provider.py +48 -0
  49. softgnn_advisor-0.1.0/tests/test_llm_test_schema.py +71 -0
  50. softgnn_advisor-0.1.0/tests/test_plan_cache.py +55 -0
@@ -0,0 +1,44 @@
1
+ # Changelog
2
+
3
+ All notable changes to SoftGNN Advisor will be documented here.
4
+
5
+ The format loosely follows [Keep a Changelog](https://keepachangelog.com/), and this project uses alpha milestone versions during early development.
6
+
7
+ ---
8
+
9
+ ## v0.1.0-alpha — Developer Preview
10
+
11
+ ### Added
12
+
13
+ - Code/test graph foundation for PR impact analysis.
14
+ - Runtime test mapping from pytest execution to source functions.
15
+ - PR scan workflow for impacted targets and missing runtime coverage.
16
+ - Semantic pytest generation for selected targets.
17
+ - Transactional generated-test patching with rollback.
18
+ - Generated block markers for safe rewrites.
19
+ - Pytest verification loop.
20
+ - Bounded repair loop for generated tests.
21
+ - Runtime coverage refresh after successful generation.
22
+ - PR scan confirmation after runtime refresh.
23
+ - LLM provider abstraction.
24
+ - Native Gemini provider.
25
+ - OpenAI-compatible provider.
26
+ - Template fallback provider.
27
+ - Structured JSON parsing and validation for LLM-generated tests.
28
+ - Safety validation for generated code patterns and test paths.
29
+ - CLI flags for generation strategy, provider config, repair, runtime refresh, and rollback policy.
30
+ - Internal tests for provider config and LLM schema validation.
31
+
32
+ ### Verified
33
+
34
+ - Gemini generated semantic tests for `FUNC:is_edge_index_sorted`.
35
+ - Patch workflow produced `6 passed` on the demo repo.
36
+ - Runtime refresh persisted `336` runtime edges.
37
+ - PR scan confirmation completed successfully.
38
+
39
+ ### Notes
40
+
41
+ - This is an alpha/developer preview.
42
+ - Generated tests should be reviewed before commit.
43
+ - Production-code fixes are not enabled in v0.1.
44
+ - Multi-agent testing swarm is roadmap, not v0.1 scope.
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Minh Quang Nguyen
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.
@@ -0,0 +1,5 @@
1
+ include README.md
2
+ include LICENSE
3
+ include CHANGELOG.md
4
+ include ROADMAP.md
5
+ recursive-include softgnn_advisor *.py *.md *.json *.yaml *.toml
@@ -0,0 +1,430 @@
1
+ Metadata-Version: 2.4
2
+ Name: softgnn-advisor
3
+ Version: 0.1.0
4
+ Summary: Graph-guided, runtime-proven, LLM-assisted PR test generation for Python projects
5
+ License: MIT
6
+ Project-URL: Homepage, https://github.com/minhquang0407/softgnn-advisor
7
+ Project-URL: Repository, https://github.com/minhquang0407/softgnn-advisor
8
+ Project-URL: Issues, https://github.com/minhquang0407/softgnn-advisor/issues
9
+ Keywords: testing,graph,llm,code-intelligence,pytest,gnn
10
+ Classifier: Development Status :: 3 - Alpha
11
+ Classifier: Environment :: Console
12
+ Classifier: Intended Audience :: Developers
13
+ Classifier: License :: OSI Approved :: MIT License
14
+ Classifier: Programming Language :: Python :: 3
15
+ Classifier: Programming Language :: Python :: 3.10
16
+ Classifier: Programming Language :: Python :: 3.11
17
+ Classifier: Programming Language :: Python :: 3.12
18
+ Classifier: Topic :: Software Development :: Testing
19
+ Classifier: Topic :: Software Development :: Quality Assurance
20
+ Requires-Python: >=3.10
21
+ Description-Content-Type: text/markdown
22
+ License-File: LICENSE
23
+ Requires-Dist: click>=8.0
24
+ Requires-Dist: rich>=13.0
25
+ Requires-Dist: networkx>=3.0
26
+ Requires-Dist: pandas>=2.0
27
+ Requires-Dist: numpy
28
+ Requires-Dist: gitpython>=3.1
29
+ Requires-Dist: thefuzz[speedup]
30
+ Requires-Dist: unidecode
31
+ Requires-Dist: tqdm
32
+ Requires-Dist: python-igraph
33
+ Requires-Dist: requests
34
+ Requires-Dist: pytest
35
+ Requires-Dist: pytest-cov
36
+ Provides-Extra: gnn
37
+ Requires-Dist: torch>=2.0; extra == "gnn"
38
+ Requires-Dist: torch-geometric; extra == "gnn"
39
+ Requires-Dist: sentence-transformers>=2.0; extra == "gnn"
40
+ Requires-Dist: scikit-learn; extra == "gnn"
41
+ Provides-Extra: llm
42
+ Requires-Dist: google-generativeai>=0.8; extra == "llm"
43
+ Requires-Dist: openai>=1.0; extra == "llm"
44
+ Provides-Extra: all
45
+ Requires-Dist: softgnn-advisor[gnn]; extra == "all"
46
+ Requires-Dist: softgnn-advisor[llm]; extra == "all"
47
+ Dynamic: license-file
48
+
49
+ <div align="center">
50
+
51
+ # SoftGNN Advisor
52
+
53
+ ### Graph-guided, runtime-proven, LLM-assisted PR testing
54
+
55
+ **Know what changed. Know what tests hit it. Generate what is missing.**
56
+
57
+ [![Tests](https://github.com/minhquang0407/softgnn-advisor/actions/workflows/tests.yml/badge.svg)](https://github.com/minhquang0407/softgnn-advisor/actions/workflows/tests.yml)
58
+ [![Release](https://img.shields.io/github/v/tag/minhquang0407/softgnn-advisor?label=release)](https://github.com/minhquang0407/softgnn-advisor/releases)
59
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](LICENSE)
60
+ [![Python](https://img.shields.io/badge/Python-3.11%2B-3776AB?logo=python&logoColor=white)](https://www.python.org/)
61
+ [![LLM](https://img.shields.io/badge/LLM-Gemini%20%7C%20OpenAI--compatible-8A2BE2)](#configure-an-llm-provider)
62
+
63
+ </div>
64
+
65
+ ---
66
+
67
+ ## Install
68
+
69
+ Recommended for CLI use:
70
+
71
+ ```bash
72
+ pipx install softgnn-advisor
73
+ ```
74
+
75
+ Or install into your current environment:
76
+
77
+ ```bash
78
+ pip install softgnn-advisor
79
+ ```
80
+
81
+ Optional extras:
82
+
83
+ ```bash
84
+ pip install "softgnn-advisor[llm]" # Gemini / OpenAI-compatible generation
85
+ pip install "softgnn-advisor[gnn]" # PyTorch Geometric ranking
86
+ pip install "softgnn-advisor[all]" # full stack
87
+ ```
88
+
89
+ Then run:
90
+
91
+ ```bash
92
+ softgnn setup /path/to/your-repo --project my-app
93
+ softgnn apply --project my-app
94
+ ```
95
+
96
+ For local development from source:
97
+
98
+ ```bash
99
+ git clone https://github.com/minhquang0407/softgnn-advisor.git
100
+ cd softgnn-advisor
101
+ python -m venv .venv
102
+ .venv\Scripts\activate # Windows
103
+ pip install -e ".[all]"
104
+ softgnn --help
105
+ ```
106
+
107
+ ---
108
+
109
+ ## What is SoftGNN?
110
+
111
+ SoftGNN Advisor is an experimental CLI that combines a **code graph**, **runtime test graph**, and **LLM test generation** to help you understand PR impact and generate missing pytest tests.
112
+
113
+ Most AI testing tools stop at:
114
+
115
+ ```text
116
+ read changed file -> ask LLM for tests -> run pytest
117
+ ```
118
+
119
+ SoftGNN aims for a stronger loop:
120
+
121
+ ```text
122
+ scan PR -> find impacted code -> map tests that actually execute it -> generate missing tests -> verify -> refresh runtime proof
123
+ ```
124
+
125
+ > **Core thesis:** a generated test is not truly useful until it passes pytest and proves it hits the intended code.
126
+
127
+ ---
128
+
129
+ ## The pipeline
130
+
131
+ ```mermaid
132
+ flowchart LR
133
+ A[PR Diff] --> B[Code Graph]
134
+ B --> C[Impact Scan]
135
+ C --> D[Missing Runtime Coverage]
136
+ D --> E[LLM Semantic Test Generation]
137
+ E --> F[Schema + Safety Validation]
138
+ F --> G[Transactional Patch]
139
+ G --> H[Pytest Verify]
140
+ H --> I[Runtime Test Mapping]
141
+ I --> J[PR Scan Confirmation]
142
+
143
+ H -- failure --> K[LLM Repair]
144
+ K --> F
145
+ ```
146
+
147
+ ---
148
+
149
+ ## Why it is different
150
+
151
+ | Capability | Naive LLM test generation | SoftGNN Advisor |
152
+ |---|---:|---:|
153
+ | Reads changed code | ✅ | ✅ |
154
+ | Generates pytest tests | ✅ | ✅ |
155
+ | Validates structured LLM output | ❌ | ✅ |
156
+ | Patches transactionally | ❌ | ✅ |
157
+ | Rolls back failed generated tests | ❌ | ✅ |
158
+ | Maps tests to functions at runtime | ❌ | ✅ |
159
+ | Confirms PR coverage after generation | ❌ | ✅ |
160
+ | Supports Gemini/OpenAI-compatible LLMs | varies | ✅ |
161
+
162
+ ---
163
+
164
+ ## Features
165
+
166
+ - **PR impact scanning** between Git revisions.
167
+ - **Code graph extraction** from Python source files.
168
+ - **Runtime test mapping** from pytest execution to source functions.
169
+ - **Missing runtime coverage detection** for impacted functions.
170
+ - **LLM-assisted semantic pytest generation**.
171
+ - **Native Gemini provider** and **OpenAI-compatible provider**.
172
+ - **Structured JSON validation** before writing tests.
173
+ - **Safety validation** against unsafe generated code patterns.
174
+ - **Transactional patching** with generated block markers.
175
+ - **Pytest verification** and bounded generated-test repair loop.
176
+ - **Runtime refresh** after successful generation.
177
+ - **PR scan confirmation** after runtime refresh.
178
+
179
+ ---
180
+
181
+ ## Verified demo
182
+
183
+ On a local `social-link-prediction` repo, SoftGNN used Gemini to generate behavior tests for:
184
+
185
+ ```text
186
+ FUNC:is_edge_index_sorted
187
+ ```
188
+
189
+ Result:
190
+
191
+ ```text
192
+ pytest: 6 passed
193
+ runtime mode: per-test
194
+ runtime edges: 336
195
+ persisted: True
196
+ missing coverage before: 0
197
+ missing coverage after: 0
198
+ ```
199
+
200
+ Fallback without an LLM produced only a shallow smoke test:
201
+
202
+ ```python
203
+ assert callable(is_edge_index_sorted)
204
+ ```
205
+
206
+ Gemini-assisted generation produced behavior checks for sorted edges, unsorted source order, unsorted target order, single-edge input, and invalid-shape errors.
207
+
208
+ Read the full demo: [docs/examples/social-link-demo.md](docs/examples/social-link-demo.md)
209
+
210
+ ---
211
+
212
+ ## Install
213
+
214
+ ```bash
215
+ git clone https://github.com/minhquang0407/softgnn-advisor.git
216
+ cd softgnn-advisor
217
+ python -m venv .venv
218
+ ```
219
+
220
+ Windows PowerShell:
221
+
222
+ ```powershell
223
+ .\.venv\Scripts\Activate.ps1
224
+ pip install -r requirements.txt
225
+ ```
226
+
227
+ Linux/macOS:
228
+
229
+ ```bash
230
+ source .venv/bin/activate
231
+ pip install -r requirements.txt
232
+ ```
233
+
234
+ > PyTorch / PyTorch Geometric installs can be platform-specific. If installation fails, follow the official PyTorch and PyG installation guides for your environment.
235
+
236
+ ---
237
+
238
+ ## Configure an LLM provider
239
+
240
+ ### Gemini
241
+
242
+ ```powershell
243
+ $env:SOFTGNN_LLM_PROVIDER="gemini"
244
+ $env:SOFTGNN_LLM_MODEL="gemini-3-flash"
245
+ $env:SOFTGNN_LLM_API_KEY="YOUR_GEMINI_API_KEY"
246
+ ```
247
+
248
+ If your API account uses another model ID:
249
+
250
+ ```powershell
251
+ $env:SOFTGNN_LLM_MODEL="gemini-2.5-flash"
252
+ ```
253
+
254
+ ### OpenAI-compatible endpoint
255
+
256
+ ```powershell
257
+ $env:SOFTGNN_LLM_PROVIDER="openai-compatible"
258
+ $env:SOFTGNN_LLM_BASE_URL="http://localhost:11434/v1"
259
+ $env:SOFTGNN_LLM_MODEL="qwen2.5-coder:7b"
260
+ $env:SOFTGNN_LLM_API_KEY="optional-if-your-endpoint-needs-it"
261
+ ```
262
+
263
+ Generation strategies:
264
+
265
+ ```text
266
+ template -> deterministic templates only
267
+ llm -> require configured LLM unless fallback is allowed
268
+ auto -> try LLM first, fallback to templates when unavailable
269
+ ```
270
+
271
+ ---
272
+
273
+ ## Quickstart
274
+
275
+ After setup, a single command runs the full workflow:
276
+
277
+ ```powershell
278
+ python softgnn.py setup C:\repo\my-app
279
+ python softgnn.py apply --project my-app
280
+ ```
281
+
282
+ `apply` does everything automatically:
283
+
284
+ ```text
285
+ detect changes (git / filesystem snapshot / full-scan)
286
+ run pr-scan
287
+ rank missing coverage targets
288
+ generate tests (LLM or template)
289
+ patch test files
290
+ run pytest
291
+ repair if failing
292
+ rollback if still failing
293
+ run runtime map
294
+ run post-scan confirmation
295
+ ```
296
+
297
+ Nothing is modified unless pytest passes.
298
+
299
+ Want to review proposed tests before patching? Use `plan` first:
300
+
301
+ ```powershell
302
+ python softgnn.py setup C:\repo\my-app
303
+ python softgnn.py plan --project my-app # review output
304
+ python softgnn.py apply --project my-app # apply reviewed plan
305
+ ```
306
+
307
+ Template-only generation (no LLM):
308
+
309
+ ```powershell
310
+ python softgnn.py apply --project my-app --strategy template
311
+ ```
312
+
313
+ Advanced commands are still available (`prepare`, `pr-scan`, `generate-tests`, `test-map`).
314
+
315
+ Mental model:
316
+
317
+ ```text
318
+ setup/prepare need the repo path once
319
+ everyday commands use --project
320
+ ```
321
+
322
+ Daily commands after setup:
323
+
324
+ | Goal | Command |
325
+ |---|---|
326
+ | Generate + verify tests | `python softgnn.py apply --project my-app` |
327
+ | Review before patching | `python softgnn.py plan --project my-app` |
328
+ | Inspect change impact | `python softgnn.py scan --project my-app` |
329
+ | Runtime test map | `python softgnn.py map --project my-app` |
330
+ | Health check | `python softgnn.py doctor --project my-app` |
331
+ | Impact of one symbol | `python softgnn.py impact --project my-app FUNC:foo` |
332
+ | Developer triage | `python softgnn.py triage --project my-app "bug description"` |
333
+
334
+ More details: [docs/quickstart.md](docs/quickstart.md)
335
+
336
+ The full guide covers:
337
+
338
+ ```text
339
+ simple CLI workflow
340
+ plan cache and apply-from-plan
341
+ Git PR workflow
342
+ no-Git filesystem snapshot workflow
343
+ first-run full-scan workflow
344
+ explicit target workflow
345
+ runtime coverage mapping
346
+ patch/verify/repair/rollback flow
347
+ ```
348
+
349
+ ---
350
+
351
+ ## Safety model
352
+
353
+ SoftGNN is conservative by default:
354
+
355
+ ```text
356
+ writes tests/ only
357
+ wraps generated code in markers
358
+ validates LLM output before patching
359
+ runs pytest before accepting generated tests
360
+ rolls back failed generated edits by default
361
+ never requires committing API keys
362
+ ```
363
+
364
+ Generated test blocks are marked:
365
+
366
+ ```python
367
+ # <softgnn-generated target="FUNC:example" start>
368
+ ...
369
+ # <softgnn-generated target="FUNC:example" end>
370
+ ```
371
+
372
+ Recommended workflow:
373
+
374
+ ```text
375
+ run on a feature branch
376
+ start with --mode plan
377
+ use --mode patch after review
378
+ inspect git diff before commit
379
+ ```
380
+
381
+ ---
382
+
383
+ ## CLI highlights
384
+
385
+ ```powershell
386
+ python softgnn.py pr-scan --project social-link --repo-path "C:\path\to\repo" --base main --head HEAD
387
+ ```
388
+
389
+ ```powershell
390
+ python softgnn.py test-map --project social-link --repo-path "C:\path\to\repo" --mode per-test --persist
391
+ ```
392
+
393
+ ```powershell
394
+ python softgnn.py generate-tests --project social-link --repo-path "C:\path\to\repo" --mode plan --generation-strategy auto
395
+ ```
396
+
397
+ ---
398
+
399
+ ## Project status
400
+
401
+ Current release: **v0.1.0-alpha**
402
+
403
+ This is a developer preview. Generated tests should be reviewed before commit. Production-code fixes are intentionally out of scope for v0.1.
404
+
405
+ ---
406
+
407
+ ## Roadmap
408
+
409
+ Short version:
410
+
411
+ ```text
412
+ M4 Runtime-Proven Test Generation
413
+ M5 Graph Impact Report / Dashboard
414
+ M6 Learned Test Prioritization / GNN Ranking
415
+ M7 Multi-Agent Quality Swarm
416
+ M8 Large-scale repo automation
417
+ M9 Controlled production-code fixes
418
+ ```
419
+
420
+ Read more:
421
+
422
+ - [ROADMAP.md](ROADMAP.md)
423
+ - [docs/future-milestones.md](docs/future-milestones.md)
424
+
425
+ ---
426
+
427
+ ## License
428
+
429
+ MIT License. See [LICENSE](LICENSE).
430
+