@kindgi/tools 0.0.0-bootstrap.0 → 0.1.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 (55) hide show
  1. package/LICENSE +201 -0
  2. package/README.md +86 -1
  3. package/dist/define.d.ts +138 -0
  4. package/dist/define.d.ts.map +1 -0
  5. package/dist/define.js +318 -0
  6. package/dist/define.js.map +1 -0
  7. package/dist/errors.d.ts +113 -0
  8. package/dist/errors.d.ts.map +1 -0
  9. package/dist/errors.js +4 -0
  10. package/dist/errors.js.map +1 -0
  11. package/dist/http.d.ts +2 -0
  12. package/dist/http.d.ts.map +1 -0
  13. package/dist/http.js +213 -0
  14. package/dist/http.js.map +1 -0
  15. package/dist/index.d.ts +15 -0
  16. package/dist/index.d.ts.map +1 -0
  17. package/dist/index.js +14 -0
  18. package/dist/index.js.map +1 -0
  19. package/dist/invoke.d.ts +27 -0
  20. package/dist/invoke.d.ts.map +1 -0
  21. package/dist/invoke.js +127 -0
  22. package/dist/invoke.js.map +1 -0
  23. package/dist/manifest.d.ts +23 -0
  24. package/dist/manifest.d.ts.map +1 -0
  25. package/dist/manifest.js +37 -0
  26. package/dist/manifest.js.map +1 -0
  27. package/dist/precondition.d.ts +25 -0
  28. package/dist/precondition.d.ts.map +1 -0
  29. package/dist/precondition.js +34 -0
  30. package/dist/precondition.js.map +1 -0
  31. package/dist/registry.d.ts +87 -0
  32. package/dist/registry.d.ts.map +1 -0
  33. package/dist/registry.js +171 -0
  34. package/dist/registry.js.map +1 -0
  35. package/dist/spec-registry.d.ts +48 -0
  36. package/dist/spec-registry.d.ts.map +1 -0
  37. package/dist/spec-registry.js +37 -0
  38. package/dist/spec-registry.js.map +1 -0
  39. package/dist/tool.schema.json +297 -0
  40. package/dist/types.d.ts +508 -0
  41. package/dist/types.d.ts.map +1 -0
  42. package/dist/types.js +14 -0
  43. package/dist/types.js.map +1 -0
  44. package/package.json +64 -4
  45. package/src/define.ts +537 -0
  46. package/src/errors.ts +139 -0
  47. package/src/http.ts +268 -0
  48. package/src/index.ts +68 -0
  49. package/src/invoke.ts +165 -0
  50. package/src/manifest.ts +40 -0
  51. package/src/precondition.ts +40 -0
  52. package/src/registry.ts +262 -0
  53. package/src/spec-registry.ts +78 -0
  54. package/src/tool.schema.json +297 -0
  55. package/src/types.ts +538 -0
@@ -0,0 +1,87 @@
1
+ import type { Result, TenantId, ToolId } from '@kindgi/types';
2
+ import type { ToolError } from './errors.js';
3
+ import type { AnyTool } from './types.js';
4
+ /**
5
+ * In-process registry mapping (tool id, version) → tool. Multi-version:
6
+ * a single id may carry multiple compiled implementations at different
7
+ * exact semver strings; agent bindings reference tools by (id, range)
8
+ * and dispatch resolves at run start via `resolve(id, range)` (npm-
9
+ * compatible semver grammar, backed by `semver.maxSatisfying`).
10
+ *
11
+ * Not tenant-scoped. Multi-tenant deployments hold one registry per
12
+ * tenant or encode tenancy into tool ids. Cross-tenant tool sharing goes
13
+ * through the policy engine, not through registry design.
14
+ */
15
+ export interface ToolRegistry {
16
+ /**
17
+ * Register a tool. Fails with `duplicate-tool-version` if the same
18
+ * `(id, version)` pair is already registered. Distinct versions of the
19
+ * same id may coexist — that's the whole point of the versioned model.
20
+ */
21
+ register(tool: AnyTool): Result<void, ToolError>;
22
+ /**
23
+ * Return the latest active version for an id. "Latest" is defined by
24
+ * `semver.compare` — the highest exact version present. For callers
25
+ * that have no version range to resolve. Prefer `resolve(id, range)`
26
+ * when a range is available.
27
+ */
28
+ get(id: ToolId): Result<AnyTool, ToolError>;
29
+ /** Return a specific `(id, version)` pair. */
30
+ getVersion(id: ToolId, version: string): Result<AnyTool, ToolError>;
31
+ /**
32
+ * Resolve a semver range against the versions registered under `id`.
33
+ * Uses `semver.maxSatisfying` (npm grammar). Distinct failure modes:
34
+ * - `tool-not-found` → id has no versions at all
35
+ * - `invalid-version-range` → range string is grammatically broken
36
+ * - `tool-version-unresolvable` → id is present but no version satisfies
37
+ */
38
+ resolve(id: ToolId, range: string): Result<ToolResolution, ToolError>;
39
+ has(id: ToolId): boolean;
40
+ hasVersion(id: ToolId, version: string): boolean;
41
+ /**
42
+ * Return every registered tool version, sorted by id then by version
43
+ * descending. Callers that want a per-id latest-only view use
44
+ * `.get(id)` per id.
45
+ */
46
+ list(): readonly AnyTool[];
47
+ /** Return every id with at least one registered version. */
48
+ ids(): readonly ToolId[];
49
+ /** Return every version registered under `id`, sorted descending. */
50
+ versions(id: ToolId): readonly string[];
51
+ /**
52
+ * The registry for one tenant: lookups on the returned registry
53
+ * (`get`, `getVersion`, `resolve`, `list`, …) answer for `tenantId`
54
+ * only. Multi-tenant implementations load that tenant's tools (e.g.
55
+ * from a persistent store, cached) and return a view bound to it —
56
+ * never shared per-call state, so concurrent turns of different
57
+ * tenants cannot see each other's tools. A single-tenant registry
58
+ * (like `createToolRegistry`) returns itself. Callers resolve a
59
+ * turn's tools through the returned registry.
60
+ */
61
+ forTenant(tenantId: TenantId): Promise<ToolRegistry>;
62
+ /**
63
+ * Optional cache invalidation. Storage-backed implementations call
64
+ * this from the write path (`POST /v1/tools`, unregister, reinstate)
65
+ * so the next `forTenant(tenantId)` re-reads from the persistent
66
+ * store. Without it, tools published after a tenant was loaded stay
67
+ * invisible to that tenant's cached view. In-memory implementations
68
+ * leave it undefined — there is no cache to invalidate.
69
+ */
70
+ readonly invalidate?: (tenantId: TenantId) => void;
71
+ }
72
+ /** The outcome of a successful `resolve(id, range)` lookup. */
73
+ export interface ToolResolution {
74
+ readonly tool: AnyTool;
75
+ /**
76
+ * The exact version picked by `maxSatisfying`. Callers capture this in
77
+ * provenance + telemetry so a replay can pin against the same version.
78
+ */
79
+ readonly resolvedVersion: string;
80
+ }
81
+ /**
82
+ * Create an empty tool registry. Seeds are registered in order; the seed
83
+ * throws on duplicate `(id, version)` so accidental clobbers of a
84
+ * running tool fail loud at boot.
85
+ */
86
+ export declare function createToolRegistry(seed?: readonly AnyTool[]): ToolRegistry;
87
+ //# sourceMappingURL=registry.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"registry.d.ts","sourceRoot":"","sources":["../src/registry.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,MAAM,eAAe,CAAC;AAE9D,OAAO,KAAK,EAGV,SAAS,EAIV,MAAM,aAAa,CAAC;AACrB,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,YAAY,CAAC;AAE1C;;;;;;;;;;GAUG;AACH,MAAM,WAAW,YAAY;IAC3B;;;;OAIG;IACH,QAAQ,CAAC,IAAI,EAAE,OAAO,GAAG,MAAM,CAAC,IAAI,EAAE,SAAS,CAAC,CAAC;IACjD;;;;;OAKG;IACH,GAAG,CAAC,EAAE,EAAE,MAAM,GAAG,MAAM,CAAC,OAAO,EAAE,SAAS,CAAC,CAAC;IAC5C,8CAA8C;IAC9C,UAAU,CAAC,EAAE,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,MAAM,CAAC,OAAO,EAAE,SAAS,CAAC,CAAC;IACpE;;;;;;OAMG;IACH,OAAO,CAAC,EAAE,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,CAAC,cAAc,EAAE,SAAS,CAAC,CAAC;IACtE,GAAG,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC;IACzB,UAAU,CAAC,EAAE,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC;IACjD;;;;OAIG;IACH,IAAI,IAAI,SAAS,OAAO,EAAE,CAAC;IAC3B,4DAA4D;IAC5D,GAAG,IAAI,SAAS,MAAM,EAAE,CAAC;IACzB,qEAAqE;IACrE,QAAQ,CAAC,EAAE,EAAE,MAAM,GAAG,SAAS,MAAM,EAAE,CAAC;IACxC;;;;;;;;;OASG;IACH,SAAS,CAAC,QAAQ,EAAE,QAAQ,GAAG,OAAO,CAAC,YAAY,CAAC,CAAC;IACrD;;;;;;;OAOG;IACH,QAAQ,CAAC,UAAU,CAAC,EAAE,CAAC,QAAQ,EAAE,QAAQ,KAAK,IAAI,CAAC;CACpD;AAED,+DAA+D;AAC/D,MAAM,WAAW,cAAc;IAC7B,QAAQ,CAAC,IAAI,EAAE,OAAO,CAAC;IACvB;;;OAGG;IACH,QAAQ,CAAC,eAAe,EAAE,MAAM,CAAC;CAClC;AAED;;;;GAIG;AACH,wBAAgB,kBAAkB,CAAC,IAAI,GAAE,SAAS,OAAO,EAAO,GAAG,YAAY,CAgK9E"}
@@ -0,0 +1,171 @@
1
+ // SPDX-License-Identifier: Apache-2.0
2
+ // Copyright (C) 2026 Kindgi Inc.
3
+ import semver from 'semver';
4
+ /**
5
+ * Create an empty tool registry. Seeds are registered in order; the seed
6
+ * throws on duplicate `(id, version)` so accidental clobbers of a
7
+ * running tool fail loud at boot.
8
+ */
9
+ export function createToolRegistry(seed = []) {
10
+ // id → version → tool. Nested map so we can iterate versions per id
11
+ // cheaply and cache a sorted-version list.
12
+ const tools = new Map();
13
+ function versionsDesc(id) {
14
+ const versions = tools.get(id);
15
+ if (versions === undefined)
16
+ return [];
17
+ return [...versions.keys()].sort((a, b) => semver.rcompare(a, b));
18
+ }
19
+ const registry = {
20
+ register(tool) {
21
+ let versions = tools.get(tool.id);
22
+ if (versions === undefined) {
23
+ versions = new Map();
24
+ tools.set(tool.id, versions);
25
+ }
26
+ if (versions.has(tool.version)) {
27
+ const dup = {
28
+ code: 'duplicate-tool-version',
29
+ message: `Tool "${tool.id}@${tool.version}" is already registered`,
30
+ id: tool.id,
31
+ version: tool.version,
32
+ };
33
+ return { kind: 'err', error: dup };
34
+ }
35
+ versions.set(tool.version, tool);
36
+ return { kind: 'ok', value: undefined };
37
+ },
38
+ get(id) {
39
+ const desc = versionsDesc(id);
40
+ if (desc.length === 0) {
41
+ const err = {
42
+ code: 'tool-not-found',
43
+ message: `No tool registered with id "${id}"`,
44
+ id,
45
+ };
46
+ return { kind: 'err', error: err };
47
+ }
48
+ // desc is sorted desc — desc[0] is highest.
49
+ const latest = tools.get(id)?.get(desc[0]);
50
+ if (latest === undefined) {
51
+ const err = {
52
+ code: 'tool-not-found',
53
+ message: `No tool registered with id "${id}"`,
54
+ id,
55
+ };
56
+ return { kind: 'err', error: err };
57
+ }
58
+ return { kind: 'ok', value: latest };
59
+ },
60
+ getVersion(id, version) {
61
+ const found = tools.get(id)?.get(version);
62
+ if (found === undefined) {
63
+ if (tools.get(id) === undefined) {
64
+ const err = {
65
+ code: 'tool-not-found',
66
+ message: `No tool registered with id "${id}"`,
67
+ id,
68
+ };
69
+ return { kind: 'err', error: err };
70
+ }
71
+ const err = {
72
+ code: 'tool-version-not-found',
73
+ message: `Tool "${id}" has no version "${version}" registered`,
74
+ id,
75
+ version,
76
+ };
77
+ return { kind: 'err', error: err };
78
+ }
79
+ return { kind: 'ok', value: found };
80
+ },
81
+ resolve(id, range) {
82
+ const versions = tools.get(id);
83
+ if (versions === undefined || versions.size === 0) {
84
+ const err = {
85
+ code: 'tool-not-found',
86
+ message: `No tool registered with id "${id}"`,
87
+ id,
88
+ };
89
+ return { kind: 'err', error: err };
90
+ }
91
+ if (semver.validRange(range) === null) {
92
+ const err = {
93
+ code: 'invalid-version-range',
94
+ message: `Version range "${range}" for tool "${id}" is not a valid semver range`,
95
+ id,
96
+ range,
97
+ };
98
+ return { kind: 'err', error: err };
99
+ }
100
+ const available = [...versions.keys()];
101
+ const picked = semver.maxSatisfying(available, range);
102
+ if (picked === null) {
103
+ const err = {
104
+ code: 'tool-version-unresolvable',
105
+ message: `Tool "${id}" has no version satisfying "${range}" (available: ${available
106
+ .sort((a, b) => semver.rcompare(a, b))
107
+ .join(', ')})`,
108
+ id,
109
+ range,
110
+ availableVersions: available.sort((a, b) => semver.rcompare(a, b)),
111
+ };
112
+ return { kind: 'err', error: err };
113
+ }
114
+ const tool = versions.get(picked);
115
+ // maxSatisfying returned a version we just enumerated — guaranteed
116
+ // to be in the map. The `if (tool === undefined)` branch is a
117
+ // defensive no-op for the type system.
118
+ if (tool === undefined) {
119
+ const err = {
120
+ code: 'tool-version-not-found',
121
+ message: `Tool "${id}" resolved to "${picked}" but the version is missing (internal)`,
122
+ id,
123
+ version: picked,
124
+ };
125
+ return { kind: 'err', error: err };
126
+ }
127
+ return { kind: 'ok', value: { tool, resolvedVersion: picked } };
128
+ },
129
+ has(id) {
130
+ const versions = tools.get(id);
131
+ return versions !== undefined && versions.size > 0;
132
+ },
133
+ hasVersion(id, version) {
134
+ return tools.get(id)?.has(version) ?? false;
135
+ },
136
+ list() {
137
+ const out = [];
138
+ const ids = [...tools.keys()].sort();
139
+ for (const id of ids) {
140
+ for (const v of versionsDesc(id)) {
141
+ const tool = tools.get(id)?.get(v);
142
+ if (tool !== undefined)
143
+ out.push(tool);
144
+ }
145
+ }
146
+ return out;
147
+ },
148
+ ids() {
149
+ const out = [];
150
+ for (const [id, versions] of tools) {
151
+ if (versions.size > 0)
152
+ out.push(id);
153
+ }
154
+ return out;
155
+ },
156
+ versions(id) {
157
+ return versionsDesc(id);
158
+ },
159
+ async forTenant() {
160
+ // Single-tenant: the same registry serves every tenant.
161
+ return registry;
162
+ },
163
+ };
164
+ for (const tool of seed) {
165
+ const r = registry.register(tool);
166
+ if (r.kind === 'err')
167
+ throw new Error(`seed failed: ${r.error.message}`);
168
+ }
169
+ return registry;
170
+ }
171
+ //# sourceMappingURL=registry.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"registry.js","sourceRoot":"","sources":["../src/registry.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,48 @@
1
+ import type { ToolContext, ToolSpec } from './types.js';
2
+ /**
3
+ * A synthesizer takes a declarative `ToolSpec` variant and returns
4
+ * the runtime handler that satisfies its semantics. Framework core
5
+ * ships the `'http'` synthesizer (see `./http.ts` for the impl).
6
+ * Third-party kinds (SQL, MCP, webhook, ...) register their own via
7
+ * `registerToolSpecSynthesizer(kind, fn)` at module load.
8
+ *
9
+ * The synthesizer receives the fully-validated spec (author-time
10
+ * validation has already run) and returns a handler with the
11
+ * standard `(input, ctx) => Promise<output>` signature. Any
12
+ * per-invoke correctness bits (URL substitution, abort chaining,
13
+ * secret resolution) live inside the handler the synthesizer
14
+ * returns.
15
+ */
16
+ /** What the runtime gives a synthesized handler. */
17
+ export interface ToolSpecSynthesizerOptions {
18
+ /**
19
+ * The fetch for requests to the hosts a spec names. The runtime passes
20
+ * one that refuses the hosts its deployment forbids
21
+ * (`KINDGI_TENANT_HOST_ACCESS`: the cloud metadata endpoints and the
22
+ * server's own host). Absent: the global `fetch`.
23
+ */
24
+ readonly fetch?: typeof fetch;
25
+ }
26
+ export type ToolSpecSynthesizer<TSpec extends ToolSpec = ToolSpec> = (spec: TSpec, toolId: string, options?: ToolSpecSynthesizerOptions) => (input: unknown, ctx: ToolContext) => Promise<unknown>;
27
+ /**
28
+ * Register a synthesizer for a given `spec.kind`. First-party kinds
29
+ * register at framework load; third-party kinds register when their
30
+ * package's module runs. Overwriting an existing kind throws — kind
31
+ * ownership must be explicit to avoid silent shadowing.
32
+ */
33
+ export declare function registerToolSpecSynthesizer<TSpec extends ToolSpec>(kind: TSpec['kind'], synthesizer: ToolSpecSynthesizer<TSpec>): void;
34
+ /**
35
+ * Look up the synthesizer for a `ToolSpec`. Returns `undefined` when
36
+ * no synthesizer is registered for the spec's `kind` — callers
37
+ * (typically `defineTool`) surface this as a clear "no synthesizer
38
+ * for kind X" error at define time.
39
+ */
40
+ export declare function getToolSpecSynthesizer(kind: string): ToolSpecSynthesizer | undefined;
41
+ /**
42
+ * Test-only helper. Removes a registered synthesizer so tests can
43
+ * verify the "no synthesizer registered" error path without process
44
+ * teardown. Not exported from the package barrel — call it via
45
+ * direct import in tests only.
46
+ */
47
+ export declare function _unregisterToolSpecSynthesizer(kind: string): void;
48
+ //# sourceMappingURL=spec-registry.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"spec-registry.d.ts","sourceRoot":"","sources":["../src/spec-registry.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,WAAW,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAExD;;;;;;;;;;;;;GAaG;AACH,oDAAoD;AACpD,MAAM,WAAW,0BAA0B;IACzC;;;;;OAKG;IACH,QAAQ,CAAC,KAAK,CAAC,EAAE,OAAO,KAAK,CAAC;CAC/B;AAED,MAAM,MAAM,mBAAmB,CAAC,KAAK,SAAS,QAAQ,GAAG,QAAQ,IAAI,CACnE,IAAI,EAAE,KAAK,EACX,MAAM,EAAE,MAAM,EACd,OAAO,CAAC,EAAE,0BAA0B,KACjC,CAAC,KAAK,EAAE,OAAO,EAAE,GAAG,EAAE,WAAW,KAAK,OAAO,CAAC,OAAO,CAAC,CAAC;AAO5D;;;;;GAKG;AACH,wBAAgB,2BAA2B,CAAC,KAAK,SAAS,QAAQ,EAChE,IAAI,EAAE,KAAK,CAAC,MAAM,CAAC,EACnB,WAAW,EAAE,mBAAmB,CAAC,KAAK,CAAC,GACtC,IAAI,CAON;AAED;;;;;GAKG;AACH,wBAAgB,sBAAsB,CAAC,IAAI,EAAE,MAAM,GAAG,mBAAmB,GAAG,SAAS,CAEpF;AAED;;;;;GAKG;AACH,wBAAgB,8BAA8B,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAEjE"}
@@ -0,0 +1,37 @@
1
+ // SPDX-License-Identifier: Apache-2.0
2
+ // Copyright (C) 2026 Kindgi Inc.
3
+ // Registry keyed by the spec's `kind` discriminant. Populated by
4
+ // side-effect imports of first-party synthesizer packages (`./http.js`
5
+ // registers `'http'`) or third-party equivalents.
6
+ const registry = new Map();
7
+ /**
8
+ * Register a synthesizer for a given `spec.kind`. First-party kinds
9
+ * register at framework load; third-party kinds register when their
10
+ * package's module runs. Overwriting an existing kind throws — kind
11
+ * ownership must be explicit to avoid silent shadowing.
12
+ */
13
+ export function registerToolSpecSynthesizer(kind, synthesizer) {
14
+ if (registry.has(kind)) {
15
+ throw new Error(`ToolSpec synthesizer for kind "${kind}" is already registered. Multiple registrations for the same kind indicate shadowing — unregister first if replacement is intended.`);
16
+ }
17
+ registry.set(kind, synthesizer);
18
+ }
19
+ /**
20
+ * Look up the synthesizer for a `ToolSpec`. Returns `undefined` when
21
+ * no synthesizer is registered for the spec's `kind` — callers
22
+ * (typically `defineTool`) surface this as a clear "no synthesizer
23
+ * for kind X" error at define time.
24
+ */
25
+ export function getToolSpecSynthesizer(kind) {
26
+ return registry.get(kind);
27
+ }
28
+ /**
29
+ * Test-only helper. Removes a registered synthesizer so tests can
30
+ * verify the "no synthesizer registered" error path without process
31
+ * teardown. Not exported from the package barrel — call it via
32
+ * direct import in tests only.
33
+ */
34
+ export function _unregisterToolSpecSynthesizer(kind) {
35
+ registry.delete(kind);
36
+ }
37
+ //# sourceMappingURL=spec-registry.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"spec-registry.js","sourceRoot":"","sources":["../src/spec-registry.ts"],"names":[],"mappings":"AAAA,sCAAsC;AACtC,iCAAiC;AAmCjC,iEAAiE;AACjE,uEAAuE;AACvE,kDAAkD;AAClD,MAAM,QAAQ,GAAG,IAAI,GAAG,EAA+B,CAAC;AAExD;;;;;GAKG;AACH,MAAM,UAAU,2BAA2B,CACzC,IAAmB,EACnB,WAAuC;IAEvC,IAAI,QAAQ,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC;QACvB,MAAM,IAAI,KAAK,CACb,kCAAkC,IAAI,qIAAqI,CAC5K,CAAC;IACJ,CAAC;IACD,QAAQ,CAAC,GAAG,CAAC,IAAI,EAAE,WAAkC,CAAC,CAAC;AACzD,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,sBAAsB,CAAC,IAAY;IACjD,OAAO,QAAQ,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;AAC5B,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,8BAA8B,CAAC,IAAY;IACzD,QAAQ,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;AACxB,CAAC"}