@agentskit/doc-bridge 1.7.45 → 1.9.0

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 (213) hide show
  1. package/CHANGELOG.md +465 -0
  2. package/CONTRIBUTING.md +23 -0
  3. package/README.md +87 -40
  4. package/SECURITY.md +7 -0
  5. package/action.yml +1 -1
  6. package/bin/ak-docs.js +2 -2
  7. package/bin/ak-verify.js +13 -7
  8. package/dist/cli/program.d.ts +3 -1
  9. package/dist/cli/program.js +15861 -6223
  10. package/dist/cli/program.js.map +1 -1
  11. package/dist/config/index.d.ts +1 -1
  12. package/dist/config/index.js +86 -6
  13. package/dist/config/index.js.map +1 -1
  14. package/dist/{index-BUL0q7s8.d.ts → index-Beor6Yhi.d.ts} +133 -1
  15. package/dist/index.d.ts +9871 -1062
  16. package/dist/index.js +16126 -6125
  17. package/dist/index.js.map +1 -1
  18. package/docs/MARKETPLACE.md +1 -1
  19. package/docs/PRD-documentation-efficiency-study.md +406 -0
  20. package/docs/PRD-knowledge-retrieval-and-enrichment.md +466 -0
  21. package/docs/adr/0002-documentation-audit-boundary.md +22 -0
  22. package/docs/adr/0003-study-protocol-and-historical-evidence.md +40 -0
  23. package/docs/adr/0004-controlled-study-runner.md +25 -0
  24. package/docs/adr/0005-documentation-quality-and-criticality.md +20 -0
  25. package/docs/adr/0006-registry-semantic-grounding.md +20 -0
  26. package/docs/adr/0007-longitudinal-study-metrics.md +21 -0
  27. package/docs/adr/0008-study-verification-boundary.md +21 -0
  28. package/docs/adr/0009-study-provider-cli-adapter.md +25 -0
  29. package/docs/agent-corpus/INDEX.md +12 -1
  30. package/docs/agent-corpus/OVERVIEW.md +25 -0
  31. package/docs/agent-corpus/chat.md +5 -1
  32. package/docs/agent-corpus/cli.md +16 -0
  33. package/docs/agent-corpus/conformance.md +12 -0
  34. package/docs/agent-corpus/doc-bridge.md +47 -0
  35. package/docs/agent-corpus/doctor.md +8 -0
  36. package/docs/agent-corpus/gates.md +4 -0
  37. package/docs/agent-corpus/mcp.md +13 -0
  38. package/docs/agent-corpus/memory.md +4 -0
  39. package/docs/agent-corpus/query.md +33 -0
  40. package/docs/bench/README.md +122 -0
  41. package/docs/bench/retrieval-baseline-v1.json +28 -0
  42. package/docs/bench/retrieval-suite-v1.json +1033 -0
  43. package/docs/chat-and-rag.md +3 -2
  44. package/docs/for-agents.md +9 -1
  45. package/docs/getting-started.md +4 -11
  46. package/docs/guides/gate-ci.md +11 -1
  47. package/docs/guides/install-and-run.md +9 -65
  48. package/docs/index.md +22 -1
  49. package/docs/knowledge-engine-runbook.md +38 -3
  50. package/docs/landing/assets/context-payload-reduction.svg +21 -0
  51. package/docs/landing/assets/controlled-ab-comparison.svg +30 -0
  52. package/docs/landing/index.html +119 -5
  53. package/docs/loop-workflow.md +117 -0
  54. package/docs/mcp.md +6 -1
  55. package/docs/parity/public-claims-v1.json +145 -0
  56. package/docs/playbook/doc-bridge-pattern.md +1 -1
  57. package/docs/query.md +90 -2
  58. package/docs/recipes/index-pipeline.md +1 -1
  59. package/docs/schemas/agent-handoff-v1.md +15 -0
  60. package/docs/schemas/doc-bridge-index-v1.md +65 -0
  61. package/docs/spec/benchmark-v1.md +33 -1
  62. package/docs/spec/cli.md +30 -10
  63. package/docs/spec/config-v1.md +147 -8
  64. package/docs/spec/documentation-audit-v1.md +61 -0
  65. package/docs/spec/enrichment-overlay-v1.md +241 -0
  66. package/docs/spec/graph-signals-v1.md +92 -0
  67. package/docs/spec/incremental-scan-v1.md +102 -0
  68. package/docs/spec/markdown-analyzer-v1.md +73 -0
  69. package/docs/spec/mcp-knowledge-tools-v1.md +147 -0
  70. package/docs/spec/measured-enrichment-v1.md +229 -0
  71. package/docs/spec/public-parity-v1.md +119 -0
  72. package/docs/spec/registry-agents.md +6 -0
  73. package/docs/spec/render-v1.md +122 -0
  74. package/docs/spec/retrieval-index-v1.md +164 -0
  75. package/docs/spec/study-metrics-v1.md +58 -0
  76. package/docs/spec/study-protocol-v1.md +46 -0
  77. package/docs/spec/study-provider-cli-v1.md +116 -0
  78. package/docs/spec/study-runner-v1.md +35 -0
  79. package/docs/spec/study-task-suite-v1.md +41 -0
  80. package/docs/spec/study-verification-v1.md +40 -0
  81. package/docs/study/README.md +84 -0
  82. package/docs/study/ab-adjudicated-cost-analysis-v1.md +29 -0
  83. package/docs/study/ab-adjudicated-cost-plan-v1.json +33 -0
  84. package/docs/study/ab-adjudicated-cost-plan-v2-v1.json +33 -0
  85. package/docs/study/ab-adjudicated-cost-result-v1.json +80 -0
  86. package/docs/study/ab-baseline-analysis-v1.md +21 -0
  87. package/docs/study/ab-baseline-plan-v1.json +33 -0
  88. package/docs/study/ab-baseline-recovery-plan-v1.json +33 -0
  89. package/docs/study/ab-baseline-result-v1.json +79 -0
  90. package/docs/study/documentation-audit-round-2026-08-31.json +183 -0
  91. package/docs/study/historical-evidence-v1.json +252 -0
  92. package/docs/study/observation-ledger-v1.json +30632 -0
  93. package/docs/study/phase3-task-coverage-v1.json +34 -0
  94. package/docs/study/phase4-public-pilot-ledger-v1.json +1344 -0
  95. package/docs/study/phase4-public-pilot-result-v1.json +52 -0
  96. package/docs/study/phase4-public-pilot-run-plan-v1.json +26 -0
  97. package/docs/study/phase4-public-pilot-task-suite-v1.json +71 -0
  98. package/docs/study/pilot-round-2026-08-31.json +46 -0
  99. package/docs/study/protocol-v1.json +90 -0
  100. package/docs/study/publication-gate-v1.md +45 -0
  101. package/docs/study/quality-scorecard-cycle-plan.md +545 -0
  102. package/docs/study/quality-scorecard-v1.json +38 -0
  103. package/docs/study/round-1-adjudicated-smoke-v1.json +30642 -0
  104. package/docs/study/round-1-instrumentation-plan-v1.md +39 -0
  105. package/docs/study/round-2-expanded-adjudication-v1.json +91 -0
  106. package/docs/study/round-2-expanded-validation-v1.md +58 -0
  107. package/docs/study/round-3-evidence-contract-v1.json +75 -0
  108. package/docs/study/round-3-evidence-contract-v1.md +57 -0
  109. package/docs/study/round-4-confirmation-v1.json +75 -0
  110. package/docs/study/round-4-confirmation-v1.md +55 -0
  111. package/docs/study/run-plan-v1.json +33 -0
  112. package/docs/study/semantic-adjudication-cycle-8.md +20 -0
  113. package/docs/study/task-suite-v1.json +96 -0
  114. package/docs/study/token-efficiency-plan-v1.md +337 -0
  115. package/docs/study/token-efficiency-protocol-v2.json +62 -0
  116. package/docs/study/verification-binding-v1.json +27 -0
  117. package/docs/validation-cycle-plan.md +14 -0
  118. package/docs/verification-harness.md +11 -6
  119. package/ecosystem-claims.json +2 -2
  120. package/ecosystem-upstream.json +2 -2
  121. package/ecosystem.json +4 -4
  122. package/mcpb/manifest.json +9 -1
  123. package/package.json +25 -6
  124. package/scripts/check-ecosystem-upstream.mjs +34 -6
  125. package/skills/doc-bridge-handoff/fixtures/synthetic-repo/docs/for-agents/packages/payments.md +7 -0
  126. package/skills/doc-bridge-handoff/scripts/resolve-handoff.mjs +1 -1
  127. package/src/agents/registry-adapter.ts +192 -24
  128. package/src/audit/documentation.ts +513 -0
  129. package/src/bench/baseline.ts +198 -0
  130. package/src/bench/overlay-delta.ts +139 -0
  131. package/src/bench/retrieval.ts +319 -0
  132. package/src/budget/compile.ts +91 -0
  133. package/src/budget/sections.ts +70 -0
  134. package/src/cli/program.ts +684 -74
  135. package/src/cli/usage.ts +71 -0
  136. package/src/config/defaults.ts +1 -0
  137. package/src/config/index.ts +4 -0
  138. package/src/config/schema.ts +117 -2
  139. package/src/conformance/documentation-standard-v1.ts +8 -6
  140. package/src/discovery/areas.ts +182 -0
  141. package/src/discovery/documentation.ts +211 -5
  142. package/src/discovery/identity.ts +24 -0
  143. package/src/discovery/incremental.ts +314 -0
  144. package/src/discovery/inputs.ts +110 -0
  145. package/src/discovery/markdown.ts +481 -0
  146. package/src/discovery/repository.ts +484 -101
  147. package/src/doctor/run-doctor.ts +244 -12
  148. package/src/enrich/approvals.ts +190 -0
  149. package/src/enrich/cache.ts +93 -0
  150. package/src/enrich/context-pack.ts +272 -0
  151. package/src/enrich/overlay.ts +255 -0
  152. package/src/enrich/review.ts +106 -0
  153. package/src/enrich/stage.ts +374 -0
  154. package/src/enrich/stats.ts +100 -0
  155. package/src/enrich/validate.ts +410 -0
  156. package/src/federation/llms.ts +2 -4
  157. package/src/findings/report.ts +103 -0
  158. package/src/graph/build.ts +356 -0
  159. package/src/graph/memory.ts +208 -0
  160. package/src/index-builder/build-handoffs.ts +22 -11
  161. package/src/index-builder/build-index.ts +132 -3
  162. package/src/index-builder/llms-txt.ts +48 -8
  163. package/src/index-builder/project-corpus.ts +111 -0
  164. package/src/index.ts +630 -2
  165. package/src/lib/fuzzy-match.ts +235 -0
  166. package/src/mcp/knowledge.ts +554 -0
  167. package/src/mcp/server.ts +113 -18
  168. package/src/metrics/benchmark.ts +21 -0
  169. package/src/parity/check.ts +309 -0
  170. package/src/parity/claims.ts +259 -0
  171. package/src/parity/resolve.ts +160 -0
  172. package/src/query/handoff.ts +326 -0
  173. package/src/query/load-index.ts +53 -1
  174. package/src/query/query.ts +92 -59
  175. package/src/query/search.ts +289 -92
  176. package/src/query/text.ts +155 -0
  177. package/src/reconciliation/reconcile.ts +101 -10
  178. package/src/render/data.ts +356 -0
  179. package/src/render/engine.ts +398 -0
  180. package/src/render/generated.ts +77 -0
  181. package/src/render/render.ts +209 -0
  182. package/src/render/template-source.ts +52 -0
  183. package/src/render/templates.ts +289 -0
  184. package/src/report/html.ts +2 -2
  185. package/src/retrieval/bm25.ts +161 -0
  186. package/src/retrieval/project.ts +495 -0
  187. package/src/retrieval/rank.ts +383 -0
  188. package/src/retrieval/weights.ts +39 -0
  189. package/src/retriever/doc-bridge-retriever.ts +100 -15
  190. package/src/rules/engine.ts +30 -10
  191. package/src/schemas/agent-handoff.ts +56 -0
  192. package/src/schemas/budget.ts +37 -0
  193. package/src/schemas/doc-bridge-index.ts +53 -2
  194. package/src/schemas/enrichment.ts +369 -0
  195. package/src/schemas/json-schemas.ts +39 -2
  196. package/src/schemas/knowledge.ts +14 -1
  197. package/src/schemas/retrieval-index.ts +152 -0
  198. package/src/shims/graphology.d.ts +91 -0
  199. package/src/study/adjudication.ts +196 -0
  200. package/src/study/execution.ts +350 -0
  201. package/src/study/expectations.ts +219 -0
  202. package/src/study/metrics.ts +467 -0
  203. package/src/study/protocol.ts +271 -0
  204. package/src/study/provider-cli.ts +115 -0
  205. package/src/study/provider-telemetry.ts +47 -0
  206. package/src/study/quality-scorecard.ts +164 -0
  207. package/src/study/runner.ts +461 -0
  208. package/src/study/task-suite.ts +321 -0
  209. package/src/study/verification.ts +134 -0
  210. package/src/validate.ts +1 -4
  211. package/src/version.ts +1 -1
  212. package/src/workflow/engine.ts +36 -11
  213. package/scripts/verification-harness.mjs +0 -482
@@ -0,0 +1,235 @@
1
+ /**
2
+ * Jaro-Winkler similarity, mirroring `fuzzyMatchList` from `@agentskit/core/fuzzy-match`.
3
+ *
4
+ * The ecosystem owns this contract; it is mirrored rather than imported for the same reason the
5
+ * eval format is: `@agentskit/core` is an optional peer, loaded dynamically, and discovery is
6
+ * synchronous — an analyzer that resolved a reference only when an optional package happened to
7
+ * be installed would make the snapshot depend on the installation. A test cross-checks these
8
+ * functions against the real ones when the peer is present, so the mirror cannot drift.
9
+ */
10
+
11
+ export type FuzzyMatch = {
12
+ readonly candidate: string
13
+ readonly score: number
14
+ }
15
+
16
+ const normalize = (value: string, caseSensitive: boolean): string =>
17
+ (caseSensitive ? value : value.toLowerCase()).trim().replace(/\s+/g, ' ')
18
+
19
+ /** Jaro similarity: matching characters within a sliding window, minus half the transpositions. */
20
+ export const jaro = (a: string, b: string): number => {
21
+ if (a === b) return 1
22
+ if (a.length === 0 || b.length === 0) return 0
23
+
24
+ const window = Math.max(0, Math.floor(Math.max(a.length, b.length) / 2) - 1)
25
+ const matchedA = new Array<boolean>(a.length).fill(false)
26
+ const matchedB = new Array<boolean>(b.length).fill(false)
27
+ let matches = 0
28
+
29
+ for (let index = 0; index < a.length; index += 1) {
30
+ const from = Math.max(0, index - window)
31
+ const to = Math.min(index + window + 1, b.length)
32
+ for (let candidate = from; candidate < to; candidate += 1) {
33
+ if (matchedB[candidate] || a[index] !== b[candidate]) continue
34
+ matchedA[index] = true
35
+ matchedB[candidate] = true
36
+ matches += 1
37
+ break
38
+ }
39
+ }
40
+ if (matches === 0) return 0
41
+
42
+ let transpositions = 0
43
+ let position = 0
44
+ for (let index = 0; index < a.length; index += 1) {
45
+ if (!matchedA[index]) continue
46
+ while (!matchedB[position]) position += 1
47
+ if (a[index] !== b[position]) transpositions += 1
48
+ position += 1
49
+ }
50
+ transpositions /= 2
51
+
52
+ return (matches / a.length + matches / b.length + (matches - transpositions) / matches) / 3
53
+ }
54
+
55
+ /** Jaro, plus a bonus for up to four shared leading characters. Case-insensitive by default. */
56
+ export const jaroWinkler = (a: string, b: string, options: { readonly caseSensitive?: boolean } = {}): number => {
57
+ const caseSensitive = options.caseSensitive ?? false
58
+ const left = normalize(a, caseSensitive)
59
+ const right = normalize(b, caseSensitive)
60
+ const similarity = jaro(left, right)
61
+ if (similarity === 0) return 0
62
+
63
+ let prefix = 0
64
+ for (let index = 0; index < Math.min(4, left.length, right.length) && left[index] === right[index]; index += 1) {
65
+ prefix += 1
66
+ }
67
+ return similarity + prefix * 0.1 * (1 - similarity)
68
+ }
69
+
70
+ /**
71
+ * The lengths a candidate can have and still reach a threshold.
72
+ *
73
+ * Jaro-Winkler is bounded by the lengths of the two strings, so most candidates can be discarded
74
+ * without computing anything. With `m` matching characters, `jaro ≤ (m/|a| + m/|b| + 1) / 3`, and
75
+ * the prefix bonus can only raise the result: `jw ≤ 0.6·jaro + 0.4`. Requiring `jw ≥ t` therefore
76
+ * requires `jaro ≥ (t − 0.4) / 0.6`, hence `m/|a| + m/|b| ≥ 3·that − 1 = R`. Since `m` cannot
77
+ * exceed the shorter string, a candidate longer than the query needs `|b| ≤ |a| / (R − 1)` and a
78
+ * shorter one needs `|b| ≥ |a| · (R − 1)`.
79
+ *
80
+ * At the resolution threshold of 0.92 that is a window of 0.6× to 1.67× the query's length. When
81
+ * `R ≤ 1` the inequality constrains nothing and every length stays a candidate, so a low threshold
82
+ * still scans everything — as it must.
83
+ */
84
+ export const fuzzyLengthWindow = (queryLength: number, threshold: number): { readonly min: number; readonly max: number } => {
85
+ const jaroFloor = Math.max(0, (threshold - 0.4) / 0.6)
86
+ const ratio = 3 * jaroFloor - 1
87
+ if (ratio <= 1) return { min: 0, max: Number.POSITIVE_INFINITY }
88
+ return { min: queryLength * (ratio - 1), max: queryLength / (ratio - 1) }
89
+ }
90
+
91
+ /**
92
+ * Candidates grouped by length, so a scan only visits the lengths that can pass.
93
+ *
94
+ * Built once per universe and reused by every query. Without it, resolving references across a
95
+ * repository is quadratic: each document rebuilt the candidate list and ran the full similarity
96
+ * scan per reference, which on a four-thousand-document repository did not finish.
97
+ */
98
+ type IndexedCandidate = {
99
+ readonly value: string
100
+ /** Length after normalization, which is what the similarity compares. */
101
+ readonly length: number
102
+ readonly counts: Uint16Array
103
+ /** Position in the universe the index was built from, so a filtered scan stays in the caller's order. */
104
+ readonly order: number
105
+ }
106
+
107
+ export type FuzzyCandidateIndex = {
108
+ readonly byLength: ReadonlyMap<number, readonly IndexedCandidate[]>
109
+ }
110
+
111
+ /**
112
+ * Character counts over a fixed alphabet slot per code unit.
113
+ *
114
+ * Every code unit at or above the alphabet shares the last slot, which can only over-count the
115
+ * characters two strings share — the safe direction for a bound that decides what to skip.
116
+ */
117
+ const ALPHABET = 128
118
+ const countsOf = (value: string): Uint16Array => {
119
+ const counts = new Uint16Array(ALPHABET)
120
+ for (let index = 0; index < value.length; index += 1) {
121
+ const code = value.charCodeAt(index)
122
+ const slot = code < ALPHABET ? code : ALPHABET - 1
123
+ counts[slot] = (counts[slot] ?? 0) + 1
124
+ }
125
+ return counts
126
+ }
127
+
128
+ /**
129
+ * The form the bounds are computed over.
130
+ *
131
+ * `jaroWinkler` compares normalized strings, so the index has to measure normalized ones: a
132
+ * candidate padded with whitespace is sixteen characters on disk and ten to the similarity, and a
133
+ * window built on the wrong number would skip a candidate that matches. Case is folded even for a
134
+ * case-sensitive query — folding can only raise the shared-character count, and the bound is
135
+ * allowed to over-estimate, never to under-estimate.
136
+ */
137
+ const indexedForm = (value: string): string => normalize(value, false)
138
+
139
+ export const createFuzzyCandidateIndex = (candidates: readonly string[]): FuzzyCandidateIndex => {
140
+ const byLength = new Map<number, IndexedCandidate[]>()
141
+ for (const [order, value] of candidates.entries()) {
142
+ const form = indexedForm(value)
143
+ const entry: IndexedCandidate = { value, length: form.length, counts: countsOf(form), order }
144
+ const bucket = byLength.get(entry.length)
145
+ if (bucket) bucket.push(entry)
146
+ else byLength.set(entry.length, [entry])
147
+ }
148
+ return { byLength }
149
+ }
150
+
151
+ /**
152
+ * The characters two strings share, as an upper bound on Jaro's `m`.
153
+ *
154
+ * Jaro counts a character as matching only if it appears in both strings (within a window), so `m`
155
+ * can never exceed the multiset intersection. Comparing two count vectors costs one pass over the
156
+ * alphabet, where computing Jaro costs a pass over one string per character of the other — so this
157
+ * is the cheap half of the test, and it is exact in the direction that matters: it only ever
158
+ * over-estimates `m`, and therefore only ever keeps a candidate that might have passed.
159
+ */
160
+ const sharedCharacterBound = (a: Uint16Array, b: Uint16Array): number => {
161
+ let shared = 0
162
+ for (let slot = 0; slot < ALPHABET; slot += 1) {
163
+ const left = a[slot] ?? 0
164
+ if (left === 0) continue
165
+ const right = b[slot] ?? 0
166
+ shared += left < right ? left : right
167
+ }
168
+ return shared
169
+ }
170
+
171
+ const candidatesWithin = (
172
+ index: FuzzyCandidateIndex,
173
+ query: string,
174
+ threshold: number,
175
+ ): readonly string[] => {
176
+ const form = indexedForm(query)
177
+ const { min, max } = fuzzyLengthWindow(form.length, threshold)
178
+ const jaroFloor = Math.max(0, (threshold - 0.4) / 0.6)
179
+ const required = 3 * jaroFloor - 1
180
+ const queryCounts = countsOf(form)
181
+ const within: IndexedCandidate[] = []
182
+ for (const [length, bucket] of index.byLength) {
183
+ if (length < min || length > max) continue
184
+ for (const candidate of bucket) {
185
+ if (required > 1) {
186
+ const bound = sharedCharacterBound(queryCounts, candidate.counts)
187
+ if (bound / form.length + bound / candidate.length < required) continue
188
+ }
189
+ within.push(candidate)
190
+ }
191
+ }
192
+ /*
193
+ * Back into the universe's own order. Scores that tie are ordered by the scan that found them, so
194
+ * an index that visits candidates grouped by length would otherwise rank equal matches differently
195
+ * from a plain list — the filter is meant to be invisible, and a test asserts the two agree.
196
+ */
197
+ return within.sort((left, right) => left.order - right.order).map((candidate) => candidate.value)
198
+ }
199
+
200
+ export const fuzzyMatchList = (
201
+ query: string,
202
+ candidates: readonly string[] | FuzzyCandidateIndex,
203
+ options: { readonly threshold?: number; readonly topK?: number; readonly caseSensitive?: boolean } = {},
204
+ ): FuzzyMatch[] => {
205
+ const threshold = options.threshold ?? 0.85
206
+ const topK = options.topK ?? 10
207
+ const searched = Array.isArray(candidates)
208
+ ? candidates
209
+ : candidatesWithin(candidates as FuzzyCandidateIndex, query, threshold)
210
+ const matches: FuzzyMatch[] = []
211
+ for (const candidate of searched) {
212
+ const score = jaroWinkler(query, candidate, { caseSensitive: options.caseSensitive ?? false })
213
+ if (score >= threshold) matches.push({ candidate, score })
214
+ }
215
+ return matches.sort((left, right) => right.score - left.score).slice(0, topK)
216
+ }
217
+
218
+ /**
219
+ * Resolve a reference only when the evidence is unambiguous.
220
+ *
221
+ * A near-miss is a guess, and a guess in a knowledge graph is worse than a gap: it sends an agent
222
+ * to the wrong file with the same confidence as a fact. So a fuzzy resolution requires a high
223
+ * score *and* a single candidate at that score — two plausible targets mean the reference stays
224
+ * unresolved and is reported instead.
225
+ */
226
+ export const FUZZY_RESOLUTION_THRESHOLD = 0.92
227
+
228
+ export const resolveFuzzyReference = (
229
+ query: string,
230
+ candidates: readonly string[] | FuzzyCandidateIndex,
231
+ threshold = FUZZY_RESOLUTION_THRESHOLD,
232
+ ): { readonly candidate: string; readonly score: number } | undefined => {
233
+ const matches = fuzzyMatchList(query, candidates, { threshold, topK: 2 })
234
+ return matches.length === 1 ? matches[0] : undefined
235
+ }