constant-docs 0.4.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.
- constant_docs-0.4.0/LICENSE +15 -0
- constant_docs-0.4.0/PKG-INFO +380 -0
- constant_docs-0.4.0/README.md +351 -0
- constant_docs-0.4.0/pyproject.toml +62 -0
- constant_docs-0.4.0/pyproject.toml.orig +66 -0
- constant_docs-0.4.0/src/constant_docs/__init__.py +18 -0
- constant_docs-0.4.0/src/constant_docs/__main__.py +15 -0
- constant_docs-0.4.0/src/constant_docs/api.py +968 -0
- constant_docs-0.4.0/src/constant_docs/auto.py +239 -0
- constant_docs-0.4.0/src/constant_docs/checks.py +494 -0
- constant_docs-0.4.0/src/constant_docs/cli.py +1085 -0
- constant_docs-0.4.0/src/constant_docs/config.py +1158 -0
- constant_docs-0.4.0/src/constant_docs/coverage.py +165 -0
- constant_docs-0.4.0/src/constant_docs/decisions.py +303 -0
- constant_docs-0.4.0/src/constant_docs/document.py +438 -0
- constant_docs-0.4.0/src/constant_docs/fingerprint.py +27 -0
- constant_docs-0.4.0/src/constant_docs/globs.py +154 -0
- constant_docs-0.4.0/src/constant_docs/guides/quickstart.md +124 -0
- constant_docs-0.4.0/src/constant_docs/guides/readme.md +198 -0
- constant_docs-0.4.0/src/constant_docs/house-style.md +70 -0
- constant_docs-0.4.0/src/constant_docs/index.py +210 -0
- constant_docs-0.4.0/src/constant_docs/kinds.py +304 -0
- constant_docs-0.4.0/src/constant_docs/paths.py +246 -0
- constant_docs-0.4.0/src/constant_docs/prompts/architecture.md +61 -0
- constant_docs-0.4.0/src/constant_docs/prompts/cli-reference.md +40 -0
- constant_docs-0.4.0/src/constant_docs/prompts/config-reference.md +38 -0
- constant_docs-0.4.0/src/constant_docs/prompts/errors.md +50 -0
- constant_docs-0.4.0/src/constant_docs/prompts/log.md +22 -0
- constant_docs-0.4.0/src/constant_docs/prompts/module.md +39 -0
- constant_docs-0.4.0/src/constant_docs/prompts/spec.md +68 -0
- constant_docs-0.4.0/src/constant_docs/state.py +273 -0
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
Apache License, Version 2.0
|
|
2
|
+
|
|
3
|
+
Copyright 2026 Ashborn Systems
|
|
4
|
+
|
|
5
|
+
Licensed under the Apache License, Version 2.0 (the "License");
|
|
6
|
+
you may not use this file except in compliance with the License.
|
|
7
|
+
You may obtain a copy of the License at
|
|
8
|
+
|
|
9
|
+
http://www.apache.org/licenses/LICENSE-2.0
|
|
10
|
+
|
|
11
|
+
Unless required by applicable law or agreed to in writing, software
|
|
12
|
+
distributed under the License is distributed on an "AS IS" BASIS,
|
|
13
|
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
14
|
+
See the License for the specific language governing permissions and
|
|
15
|
+
limitations under the License.
|
|
@@ -0,0 +1,380 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: constant-docs
|
|
3
|
+
Version: 0.4.0
|
|
4
|
+
Summary: Self-maintaining documentation for agentic codebases
|
|
5
|
+
Keywords: documentation,docs,staleness,drift,ci,codegen,agents,llm
|
|
6
|
+
Author: Ashborn Systems
|
|
7
|
+
License-Expression: Apache-2.0
|
|
8
|
+
License-File: LICENSE
|
|
9
|
+
Classifier: Development Status :: 3 - Alpha
|
|
10
|
+
Classifier: Intended Audience :: Developers
|
|
11
|
+
Classifier: Topic :: Documentation
|
|
12
|
+
Classifier: Topic :: Software Development :: Documentation
|
|
13
|
+
Classifier: Topic :: Software Development :: Quality Assurance
|
|
14
|
+
Classifier: Programming Language :: Python :: 3
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
18
|
+
Classifier: Operating System :: OS Independent
|
|
19
|
+
Classifier: Typing :: Typed
|
|
20
|
+
Requires-Dist: pyyaml>=6.0.3
|
|
21
|
+
Requires-Python: >=3.11
|
|
22
|
+
Project-URL: Homepage, https://github.com/ashborn-systems/constant-docs
|
|
23
|
+
Project-URL: Repository, https://github.com/ashborn-systems/constant-docs
|
|
24
|
+
Project-URL: Documentation, https://github.com/ashborn-systems/constant-docs/blob/main/README.md
|
|
25
|
+
Project-URL: Changelog, https://github.com/ashborn-systems/constant-docs/blob/main/docs/CHANGELOG.md
|
|
26
|
+
Project-URL: Issues, https://github.com/ashborn-systems/constant-docs/issues
|
|
27
|
+
Project-URL: Specification, https://github.com/ashborn-systems/constant-docs/blob/main/docs/SPEC.md
|
|
28
|
+
Description-Content-Type: text/markdown
|
|
29
|
+
|
|
30
|
+
<!-- constant-docs
|
|
31
|
+
type: Readme
|
|
32
|
+
title: README
|
|
33
|
+
description: Self-maintaining documentation for agentic codebases.
|
|
34
|
+
tags:
|
|
35
|
+
- readme
|
|
36
|
+
created: '2026-08-26'
|
|
37
|
+
updated: '2026-08-26'
|
|
38
|
+
|
|
39
|
+
constant_docs:
|
|
40
|
+
module: README
|
|
41
|
+
kind: readme
|
|
42
|
+
source_glob:
|
|
43
|
+
- src/constant_docs/cli.py
|
|
44
|
+
- src/constant_docs/kinds.py
|
|
45
|
+
- src/constant_docs/api.py
|
|
46
|
+
- plugin/hooks/hooks.json
|
|
47
|
+
- pyproject.toml
|
|
48
|
+
source_files:
|
|
49
|
+
- plugin/hooks/hooks.json
|
|
50
|
+
- pyproject.toml
|
|
51
|
+
- src/constant_docs/api.py
|
|
52
|
+
- src/constant_docs/cli.py
|
|
53
|
+
- src/constant_docs/kinds.py
|
|
54
|
+
source_hash: sha256:fc83f9e4fa284f88138c90b174bbd6452527577e4a329b8edb68673c5e33c26a
|
|
55
|
+
hash_method: sha256-over-sorted-path-and-content
|
|
56
|
+
hash_covers: source_files
|
|
57
|
+
timestamp: '2026-08-26T15:46:02Z'
|
|
58
|
+
generator: constant-docs/0.4.0
|
|
59
|
+
generator_spec: https://github.com/ashborn-systems/constant-docs/blob/main/SPEC.md
|
|
60
|
+
-->
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
# constant-docs
|
|
67
|
+
|
|
68
|
+
**Documentation that writes and maintains itself.**
|
|
69
|
+
|
|
70
|
+
A command-line tool and a Python library. It runs in any repository, in any
|
|
71
|
+
language, driven by whatever coding agent you already use.
|
|
72
|
+
|
|
73
|
+
Agents ship code faster than anyone can keep the docs up to date.
|
|
74
|
+
|
|
75
|
+
Each document records a hash of the code behind it. Change that code and the
|
|
76
|
+
document goes stale. constant-docs names what fell behind, and your agent
|
|
77
|
+
rewrites it.
|
|
78
|
+
|
|
79
|
+
```console
|
|
80
|
+
$ constant-docs verify
|
|
81
|
+
Stale modules: src/payments
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
## How the loop works
|
|
85
|
+
|
|
86
|
+
Edit a file, and the document describing it is already behind. The loop closes
|
|
87
|
+
inside the same turn:
|
|
88
|
+
|
|
89
|
+
```console
|
|
90
|
+
$ constant-docs verify
|
|
91
|
+
All modules up to date.
|
|
92
|
+
|
|
93
|
+
$ echo 'def refund(charge_id: str) -> None: ...' >> src/payments/core.py
|
|
94
|
+
|
|
95
|
+
$ constant-docs verify
|
|
96
|
+
Stale modules: src/payments
|
|
97
|
+
|
|
98
|
+
$ # your agent reads the source, rewrites docs/src/payments.md, and:
|
|
99
|
+
|
|
100
|
+
$ constant-docs verify
|
|
101
|
+
All modules up to date.
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
Your coding agent writes every word, because it already holds the source and
|
|
105
|
+
a model connection. constant-docs names the documents that moved and takes the
|
|
106
|
+
new text back.
|
|
107
|
+
|
|
108
|
+
That one command is also the whole CI integration. It exits 1, and a change
|
|
109
|
+
that alters behaviour while leaving its documentation behind does not merge:
|
|
110
|
+
|
|
111
|
+
```yaml
|
|
112
|
+
- run: constant-docs verify
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
## Install
|
|
116
|
+
|
|
117
|
+
```bash
|
|
118
|
+
pip install constant-docs # or: uv add constant-docs
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
One dependency, PyYAML. Python 3.11 or newer.
|
|
122
|
+
|
|
123
|
+
## Try it
|
|
124
|
+
|
|
125
|
+
```bash
|
|
126
|
+
cd examples/sample-repo
|
|
127
|
+
constant-docs verify
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
```console
|
|
131
|
+
Missing documents: src/ledger, src/payments
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
Point it at your own repository with a `constant-docs.yaml` at the root:
|
|
135
|
+
|
|
136
|
+
```yaml
|
|
137
|
+
version: 1
|
|
138
|
+
docs_root: docs
|
|
139
|
+
|
|
140
|
+
modules:
|
|
141
|
+
src/payments: src/payments/**/*.py
|
|
142
|
+
src/ledger: src/ledger/**/*.py
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
`constant-docs verify` now names what is missing.
|
|
146
|
+
|
|
147
|
+
Every command and flag is in the [CLI reference](docs/CLI.md); every
|
|
148
|
+
configuration key is in the [configuration reference](docs/CONFIGURATION.md).
|
|
149
|
+
Neither is restated here, because a second copy of the thing that changes most
|
|
150
|
+
is the copy that goes stale.
|
|
151
|
+
|
|
152
|
+
## Driving it from your agent
|
|
153
|
+
|
|
154
|
+
Three commands carry the whole integration, and none of them names a particular
|
|
155
|
+
tool:
|
|
156
|
+
|
|
157
|
+
| Command | Run it | It does |
|
|
158
|
+
|---|---|---|
|
|
159
|
+
| `constant-docs mark <path>` | after your agent writes a file | notes which documents that path affects. A glob match and a dictionary insert |
|
|
160
|
+
| `constant-docs settle --json` | when your agent goes quiet | names what the marks turned up, and hands over each document's files, its previous text, and the conventions to write against |
|
|
161
|
+
| `constant-docs apply <module> "<body>"` | once your agent has written | stores the text and moves the hash |
|
|
162
|
+
|
|
163
|
+
A shell script drives that loop. So does a Makefile, a git hook, or a person:
|
|
164
|
+
|
|
165
|
+
```console
|
|
166
|
+
$ git diff --name-only | xargs constant-docs mark
|
|
167
|
+
$ constant-docs settle --json
|
|
168
|
+
```
|
|
169
|
+
|
|
170
|
+
`settle` reports what `mark` recorded, so a harness that skips the marking step
|
|
171
|
+
sees an empty list. `plan --json` considers every module, and `verify` hashes
|
|
172
|
+
everything and exits 1 on drift whatever the marks say. Keep `verify` as the
|
|
173
|
+
gate.
|
|
174
|
+
|
|
175
|
+
**Claude Code gets a plugin.** Install it from `plugin/` and two hooks run
|
|
176
|
+
those commands for you: `PostToolUse` runs `mark`, `Stop` runs `settle --hook`.
|
|
177
|
+
Edit a file, stop the turn, and its document is up to date. Nobody asked. Any
|
|
178
|
+
harness that can run a command on write and at turn end does the same job.
|
|
179
|
+
|
|
180
|
+
Regeneration happens at quiescence, never mid-edit, so the generator and the
|
|
181
|
+
coding loop never write the same file at once. The dirty set lives in
|
|
182
|
+
`.constant-docs/dirty.json` — gitignored — so a crashed session is picked up on
|
|
183
|
+
the next run.
|
|
184
|
+
|
|
185
|
+
The [harness guide](guides/harness-integration.md) walks through each route.
|
|
186
|
+
|
|
187
|
+
## Kinds
|
|
188
|
+
|
|
189
|
+
A document is not always a module explainer. Its **kind** decides which
|
|
190
|
+
sections it must carry, which prompt its generator is handed, and whether a
|
|
191
|
+
regeneration replaces the body or appends to it.
|
|
192
|
+
|
|
193
|
+
| Kind | For | Mode |
|
|
194
|
+
|---|---|---|
|
|
195
|
+
| `module` | A set of source files. The default | replace |
|
|
196
|
+
| `spec` | What a subsystem promises, and why | replace |
|
|
197
|
+
| `log` | A changelog or build log | **append** |
|
|
198
|
+
| `architecture` | The module map, with a diagram | replace |
|
|
199
|
+
| `errors` | Every message the tool can emit | replace |
|
|
200
|
+
| `config-reference` | Every configuration key | replace |
|
|
201
|
+
| `cli-reference` | Every command and flag | replace |
|
|
202
|
+
|
|
203
|
+
```yaml
|
|
204
|
+
modules:
|
|
205
|
+
src/payments: src/payments/**/*.py # kind `module`, the default
|
|
206
|
+
|
|
207
|
+
SPEC:
|
|
208
|
+
glob: ["src/**/*.py", "tests/test_*.py"]
|
|
209
|
+
kind: spec
|
|
210
|
+
|
|
211
|
+
SECURITY:
|
|
212
|
+
covers: [src/payments, src/web] # follows when either glob moves
|
|
213
|
+
kind: spec
|
|
214
|
+
```
|
|
215
|
+
|
|
216
|
+
An append never rewrites or reorders what is already there. Pass a whole body
|
|
217
|
+
to a log, or a single entry to a module document, and the tool refuses it. A
|
|
218
|
+
configuration that has never heard of kinds behaves exactly as it did.
|
|
219
|
+
|
|
220
|
+
One house style governs every generated document. It lives in a single file
|
|
221
|
+
that all seven prompts receive, so the rules cannot drift apart.
|
|
222
|
+
|
|
223
|
+
## Finding what is undocumented
|
|
224
|
+
|
|
225
|
+
```bash
|
|
226
|
+
constant-docs init # what is here, and what covers none of it
|
|
227
|
+
constant-docs coverage # source no module covers, by directory
|
|
228
|
+
```
|
|
229
|
+
|
|
230
|
+
`verify` can only check what has been declared, so a repository could otherwise
|
|
231
|
+
drift to a large fraction undocumented while every check passed. `coverage` does one thing: a set difference. Declare the directories that
|
|
232
|
+
should carry no document in configuration, **with a reason each**. An
|
|
233
|
+
exclusion nobody justified is one nobody decided.
|
|
234
|
+
|
|
235
|
+
`verify --coverage` folds it into the gate, opt-in. And `init` never removes: it
|
|
236
|
+
proposes, because dropping a module orphans its document and `prune` deletes
|
|
237
|
+
it.
|
|
238
|
+
|
|
239
|
+
**Already have a `docs/` folder? Pointing the tool at it is safe.** `prune`
|
|
240
|
+
deletes only documents carrying this tool's frontmatter. Your hand-written
|
|
241
|
+
decision record belongs to somebody else, so the tool never touches it. It
|
|
242
|
+
names those files on every run, so you never mistake silence for *"there was
|
|
243
|
+
nothing else"*. It still *reports* them, because the docs root is a bundle and
|
|
244
|
+
they do not conform to it. Refusing to check a file and refusing to delete it
|
|
245
|
+
are two different things.
|
|
246
|
+
|
|
247
|
+
## Running it on a schedule
|
|
248
|
+
|
|
249
|
+
Hooks need a live session. Changes also arrive from a timer, a chat client, or
|
|
250
|
+
somebody editing files directly, and nothing fires for those. `auto` runs a
|
|
251
|
+
command you declare, then checks what it left behind:
|
|
252
|
+
|
|
253
|
+
```yaml
|
|
254
|
+
auto:
|
|
255
|
+
command: "<your agent> -p 'Run the constant-docs settle loop'"
|
|
256
|
+
when: stale
|
|
257
|
+
budget: 5
|
|
258
|
+
```
|
|
259
|
+
|
|
260
|
+
The tool still calls no model. constant-docs splits your command with `shlex`
|
|
261
|
+
and runs it directly, so an agent CLI, a script and a Makefile target all work.
|
|
262
|
+
No credential goes in it, and **the command's success is checked**: `auto`
|
|
263
|
+
re-runs `verify` afterwards. It exits 0 when everything is clean, 1 when
|
|
264
|
+
something is still stale, and 2 when the command could not run. Three
|
|
265
|
+
outcomes, because a scheduler that confuses the last two retries the wrong
|
|
266
|
+
one.
|
|
267
|
+
|
|
268
|
+
## Three things it checks that a hash cannot
|
|
269
|
+
|
|
270
|
+
**A regeneration cannot drop a decision.** A document rewritten by a model can
|
|
271
|
+
lose the thing it existed to record. Give each recorded decision an identifier
|
|
272
|
+
and the tool refuses a rewrite that loses one, naming it. Rewording is always
|
|
273
|
+
free; only losing is not. Retiring one is deliberate and gets written into the
|
|
274
|
+
document.
|
|
275
|
+
|
|
276
|
+
**A cross-cutting document follows what it covers.** `covers: [api, cli]` takes
|
|
277
|
+
in those modules' files by name, so it goes stale when their boundary
|
|
278
|
+
moves.
|
|
279
|
+
|
|
280
|
+
**An error catalogue agrees with the source, both ways.** Every message the code
|
|
281
|
+
raises appears in the catalogue, and every entry still exists in the code.
|
|
282
|
+
Neither needs parsing beyond a string scan, so it costs nothing — and it is the
|
|
283
|
+
one document here the tool can actually guarantee. The rest are only fresh.
|
|
284
|
+
|
|
285
|
+
## What a document looks like
|
|
286
|
+
|
|
287
|
+
```markdown
|
|
288
|
+
---
|
|
289
|
+
type: Code Module
|
|
290
|
+
title: Payments
|
|
291
|
+
description: Reconciles inbound payment events against ledger entries.
|
|
292
|
+
tags: [code-module]
|
|
293
|
+
|
|
294
|
+
constant_docs:
|
|
295
|
+
module: src/payments
|
|
296
|
+
kind: module
|
|
297
|
+
source_glob: src/payments/**/*.py
|
|
298
|
+
source_files:
|
|
299
|
+
- src/payments/core.py
|
|
300
|
+
- src/payments/reconcile.py
|
|
301
|
+
source_hash: sha256:a3f1c07e…
|
|
302
|
+
hash_method: sha256-over-sorted-path-and-content
|
|
303
|
+
hash_covers: source_files
|
|
304
|
+
timestamp: '2026-08-19T09:14:00Z'
|
|
305
|
+
generator: constant-docs/0.4.0
|
|
306
|
+
generator_spec: https://github.com/ashborn-systems/constant-docs/blob/main/docs/SPEC.md
|
|
307
|
+
---
|
|
308
|
+
## Purpose
|
|
309
|
+
|
|
310
|
+
Owns the mapping between external payment events and internal ledger entries.
|
|
311
|
+
Callers submit a batch and receive a report. Matching strategy, retry policy,
|
|
312
|
+
and duplicate handling are internal.
|
|
313
|
+
|
|
314
|
+
## Correctness pillars
|
|
315
|
+
|
|
316
|
+
WHEN a batch contains a duplicate event ID, the module SHALL discard the later
|
|
317
|
+
event and record it in the report.
|
|
318
|
+
|
|
319
|
+
## Known failure modes
|
|
320
|
+
|
|
321
|
+
| Symptom | Cause | Fix |
|
|
322
|
+
|---|---|---|
|
|
323
|
+
| Report totals disagree with the ledger | Batch submitted while a ledger write was in flight | Submit batches only from the settled-state queue |
|
|
324
|
+
```
|
|
325
|
+
|
|
326
|
+
The frontmatter stands alone. An agent that has never run this tool can see
|
|
327
|
+
what the document describes, where its source lives, and how to recompute the
|
|
328
|
+
digest. The tool keeps everything it owns under one `constant_docs` key, an
|
|
329
|
+
Open Knowledge Format producer extension. `type`, `title` and `tags` stay
|
|
330
|
+
yours, and unknown keys survive a write.
|
|
331
|
+
|
|
332
|
+
## Python API
|
|
333
|
+
|
|
334
|
+
```python
|
|
335
|
+
from constant_docs import append, apply, plan, prune, settle, verify
|
|
336
|
+
|
|
337
|
+
p = plan(changed_paths=["src/payments/reconcile.py"])
|
|
338
|
+
apply("src/payments", body="## Purpose\n…") # writes only if the body differs
|
|
339
|
+
append("CHANGELOG", entry="…", title="0.3.0")
|
|
340
|
+
report = verify() # no writes, no network
|
|
341
|
+
prune() # delete orphaned documents
|
|
342
|
+
```
|
|
343
|
+
|
|
344
|
+
## What it does not do
|
|
345
|
+
|
|
346
|
+
No model client, no network call, no source parsing. No AST, no tree-sitter,
|
|
347
|
+
no import graph. Modules are globs and files are bytes, which is what makes
|
|
348
|
+
"any language" a property here.
|
|
349
|
+
|
|
350
|
+
It cannot catch writing about the world outside your files. A document saying
|
|
351
|
+
a disk is half full stays fresh for ever, because nobody edited anything. Hash
|
|
352
|
+
what lives in files. Leave live values to something that owns them.
|
|
353
|
+
|
|
354
|
+
It cannot catch two documents contradicting each other. Content hashing sees one thing: a document
|
|
355
|
+
falling behind its source. That is why the tool always moves a section and
|
|
356
|
+
never copies it.
|
|
357
|
+
|
|
358
|
+
And it cannot catch a decision reworded into something weaker. The guard draws
|
|
359
|
+
one line, between present and deleted. Degradation is left to review, and
|
|
360
|
+
said so here so that you learn it now.
|
|
361
|
+
|
|
362
|
+
It ships one ready-made integration. The Claude Code plugin installs and runs;
|
|
363
|
+
for any other agent you wire `mark` and `settle` to whatever signals it gives
|
|
364
|
+
you, which takes a few lines of shell.
|
|
365
|
+
|
|
366
|
+
**This file maintains itself.** It carries the tool's own block in an HTML
|
|
367
|
+
comment, which GitHub renders as nothing. It goes stale whenever the CLI, the
|
|
368
|
+
kinds or the Python API move.
|
|
369
|
+
|
|
370
|
+
## Reading further
|
|
371
|
+
|
|
372
|
+
- [Specification](docs/SPEC.md) — the full design and its 156 acceptance criteria
|
|
373
|
+
- [Architecture](docs/ARCHITECTURE.md) — what the parts are and how they meet
|
|
374
|
+
- [CLI reference](docs/CLI.md) and [configuration reference](docs/CONFIGURATION.md)
|
|
375
|
+
- [Error catalogue](docs/ERRORS.md) — every message, its cause, and what to do
|
|
376
|
+
- [examples/](examples/) — a worked repository with its documents committed
|
|
377
|
+
|
|
378
|
+
## Licence
|
|
379
|
+
|
|
380
|
+
Apache 2.0 — see [LICENSE](LICENSE).
|