@funkai/prompts 0.3.0 → 0.4.1
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.
- package/.turbo/turbo-build.log +13 -13
- package/CHANGELOG.md +28 -0
- package/README.md +3 -3
- package/dist/lib/cli.d.mts +2 -2
- package/dist/lib/cli.mjs +1 -1
- package/dist/lib/{engine-CQfJbVz6.d.mts → engine-BAYeiay3.d.mts} +2 -2
- package/dist/lib/{engine-CQfJbVz6.d.mts.map → engine-BAYeiay3.d.mts.map} +1 -1
- package/dist/lib/{engine-CPKs9QbX.mjs → engine-Bhv5Zxdu.mjs} +3 -1
- package/dist/lib/{engine-CPKs9QbX.mjs.map → engine-Bhv5Zxdu.mjs.map} +1 -1
- package/dist/lib/index.d.mts +59 -2
- package/dist/lib/index.d.mts.map +1 -1
- package/dist/lib/index.mjs +84 -4
- package/dist/lib/index.mjs.map +1 -1
- package/dist/lib/runtime.d.mts +1 -1
- package/dist/lib/runtime.mjs +1 -1
- package/dist/lib/{types-2PI_9h-M.d.mts → types-DmnHC99v.d.mts} +25 -3
- package/dist/lib/types-DmnHC99v.d.mts.map +1 -0
- package/docs/cli/commands.md +8 -8
- package/docs/cli/overview.md +1 -1
- package/docs/cli.md +132 -0
- package/docs/codegen.md +142 -0
- package/docs/file-format/overview.md +1 -1
- package/docs/file-format.md +306 -0
- package/docs/guides/author-prompt.md +2 -2
- package/docs/guides/setup-project.md +1 -1
- package/docs/overview.md +9 -36
- package/docs/setup.md +76 -0
- package/docs/troubleshooting.md +1 -1
- package/package.json +2 -2
- package/src/engine.ts +2 -0
- package/src/group.test.ts +89 -0
- package/src/group.ts +36 -0
- package/src/index.ts +3 -1
- package/src/prompt.test.ts +90 -0
- package/src/prompt.ts +60 -0
- package/src/registry.test.ts +10 -20
- package/src/registry.ts +11 -11
- package/src/types.ts +24 -1
- package/tsconfig.json +12 -5
- package/dist/lib/types-2PI_9h-M.d.mts.map +0 -1
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
import { describe, expect, it } from "vitest";
|
|
2
|
+
import { z } from "zod";
|
|
3
|
+
|
|
4
|
+
import { createPromptGroup } from "@/group.js";
|
|
5
|
+
import { createPrompt } from "@/prompt.js";
|
|
6
|
+
|
|
7
|
+
describe(createPromptGroup, () => {
|
|
8
|
+
it("should set the group on each prompt module", () => {
|
|
9
|
+
const greeting = createPrompt({
|
|
10
|
+
name: "greeting",
|
|
11
|
+
template: "Hello {{ name }}!",
|
|
12
|
+
schema: z.object({ name: z.string() }),
|
|
13
|
+
});
|
|
14
|
+
|
|
15
|
+
const group = createPromptGroup("agents", { greeting });
|
|
16
|
+
|
|
17
|
+
expect(group.greeting.group).toBe("agents");
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
it("should override existing group on prompt modules", () => {
|
|
21
|
+
const greeting = createPrompt({
|
|
22
|
+
name: "greeting",
|
|
23
|
+
group: "old-group",
|
|
24
|
+
template: "Hello {{ name }}!",
|
|
25
|
+
schema: z.object({ name: z.string() }),
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
const group = createPromptGroup("agents", { greeting });
|
|
29
|
+
|
|
30
|
+
expect(group.greeting.group).toBe("agents");
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
it("should not mutate the original prompt module", () => {
|
|
34
|
+
const greeting = createPrompt({
|
|
35
|
+
name: "greeting",
|
|
36
|
+
template: "Hello {{ name }}!",
|
|
37
|
+
schema: z.object({ name: z.string() }),
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
createPromptGroup("agents", { greeting });
|
|
41
|
+
|
|
42
|
+
expect(greeting.group).toBeUndefined();
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
it("should preserve render functionality", () => {
|
|
46
|
+
const greeting = createPrompt({
|
|
47
|
+
name: "greeting",
|
|
48
|
+
template: "Hello {{ name }}!",
|
|
49
|
+
schema: z.object({ name: z.string() }),
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
const group = createPromptGroup("agents", { greeting });
|
|
53
|
+
|
|
54
|
+
expect(group.greeting.render({ name: "Alice" })).toBe("Hello Alice!");
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
it("should support multiple prompts in a group", () => {
|
|
58
|
+
const greeting = createPrompt({
|
|
59
|
+
name: "greeting",
|
|
60
|
+
template: "Hello {{ name }}!",
|
|
61
|
+
schema: z.object({ name: z.string() }),
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
const farewell = createPrompt({
|
|
65
|
+
name: "farewell",
|
|
66
|
+
template: "Goodbye {{ name }}!",
|
|
67
|
+
schema: z.object({ name: z.string() }),
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
const group = createPromptGroup("agents", { greeting, farewell });
|
|
71
|
+
|
|
72
|
+
expect(group.greeting.group).toBe("agents");
|
|
73
|
+
expect(group.farewell.group).toBe("agents");
|
|
74
|
+
expect(group.greeting.render({ name: "Alice" })).toBe("Hello Alice!");
|
|
75
|
+
expect(group.farewell.render({ name: "Bob" })).toBe("Goodbye Bob!");
|
|
76
|
+
});
|
|
77
|
+
|
|
78
|
+
it("should support nested group paths", () => {
|
|
79
|
+
const system = createPrompt({
|
|
80
|
+
name: "system",
|
|
81
|
+
template: "You are a {{ role }}.",
|
|
82
|
+
schema: z.object({ role: z.string() }),
|
|
83
|
+
});
|
|
84
|
+
|
|
85
|
+
const group = createPromptGroup("agents/core", { system });
|
|
86
|
+
|
|
87
|
+
expect(group.system.group).toBe("agents/core");
|
|
88
|
+
});
|
|
89
|
+
});
|
package/src/group.ts
ADDED
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import type { PromptModule } from "./types.js";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Create a prompt group namespace from a record of prompt modules.
|
|
5
|
+
*
|
|
6
|
+
* Sets the `group` field on each module to the given group name,
|
|
7
|
+
* producing a new namespace object without mutating the originals.
|
|
8
|
+
*
|
|
9
|
+
* @param name - Group name applied to each prompt (e.g. `'agents'`, `'agents/core'`).
|
|
10
|
+
* @param prompts - Record of prompt modules to group.
|
|
11
|
+
* @returns A new {@link PromptNamespace} with group-tagged prompt modules.
|
|
12
|
+
*
|
|
13
|
+
* @example
|
|
14
|
+
* ```ts
|
|
15
|
+
* import { createPrompt, createPromptGroup } from '@funkai/prompts'
|
|
16
|
+
* import { z } from 'zod'
|
|
17
|
+
*
|
|
18
|
+
* const agents = createPromptGroup('agents', {
|
|
19
|
+
* greeting: createPrompt({
|
|
20
|
+
* name: 'greeting',
|
|
21
|
+
* template: 'Hello {{ name }}!',
|
|
22
|
+
* schema: z.object({ name: z.string() }),
|
|
23
|
+
* }),
|
|
24
|
+
* })
|
|
25
|
+
*
|
|
26
|
+
* agents.greeting.render({ name: 'Alice' })
|
|
27
|
+
* ```
|
|
28
|
+
*/
|
|
29
|
+
export function createPromptGroup<T extends Record<string, PromptModule>>(
|
|
30
|
+
name: string,
|
|
31
|
+
prompts: T,
|
|
32
|
+
): T {
|
|
33
|
+
return Object.fromEntries(
|
|
34
|
+
Object.entries(prompts).map(([key, module]) => [key, { ...module, group: name }]),
|
|
35
|
+
) as T;
|
|
36
|
+
}
|
package/src/index.ts
CHANGED
|
@@ -1,2 +1,4 @@
|
|
|
1
|
+
export { createPromptGroup } from "./group.js";
|
|
2
|
+
export { createPrompt } from "./prompt.js";
|
|
1
3
|
export { createPromptRegistry } from "./registry.js";
|
|
2
|
-
export type { PromptModule, PromptNamespace, PromptRegistry } from "./types.js";
|
|
4
|
+
export type { PromptConfig, PromptModule, PromptNamespace, PromptRegistry } from "./types.js";
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
import { describe, expect, it } from "vitest";
|
|
2
|
+
import { z } from "zod";
|
|
3
|
+
|
|
4
|
+
import { createPrompt } from "@/prompt.js";
|
|
5
|
+
|
|
6
|
+
describe(createPrompt, () => {
|
|
7
|
+
it("should create a prompt module with name and group", () => {
|
|
8
|
+
const prompt = createPrompt({
|
|
9
|
+
name: "greeting",
|
|
10
|
+
group: "agents",
|
|
11
|
+
template: "Hello {{ name }}!",
|
|
12
|
+
schema: z.object({ name: z.string() }),
|
|
13
|
+
});
|
|
14
|
+
|
|
15
|
+
expect(prompt.name).toBe("greeting");
|
|
16
|
+
expect(prompt.group).toBe("agents");
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
it("should set group to undefined when not provided", () => {
|
|
20
|
+
const prompt = createPrompt({
|
|
21
|
+
name: "greeting",
|
|
22
|
+
template: "Hello!",
|
|
23
|
+
schema: z.object({}),
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
expect(prompt.group).toBeUndefined();
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
it("should render a template with variables", () => {
|
|
30
|
+
const prompt = createPrompt({
|
|
31
|
+
name: "greeting",
|
|
32
|
+
template: "Hello {{ name }}, welcome to {{ place }}!",
|
|
33
|
+
schema: z.object({ name: z.string(), place: z.string() }),
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
const result = prompt.render({ name: "Alice", place: "Wonderland" });
|
|
37
|
+
expect(result).toBe("Hello Alice, welcome to Wonderland!");
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
it("should render a static template with no variables", () => {
|
|
41
|
+
const prompt = createPrompt({
|
|
42
|
+
name: "static",
|
|
43
|
+
template: "No variables here.",
|
|
44
|
+
schema: z.object({}),
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
expect(prompt.render({})).toBe("No variables here.");
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
it("should validate variables against the schema", () => {
|
|
51
|
+
const prompt = createPrompt({
|
|
52
|
+
name: "greeting",
|
|
53
|
+
template: "Hello {{ name }}!",
|
|
54
|
+
schema: z.object({ name: z.string() }),
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
expect(prompt.validate({ name: "Alice" })).toEqual({ name: "Alice" });
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
it("should throw on invalid variables during render", () => {
|
|
61
|
+
const prompt = createPrompt({
|
|
62
|
+
name: "greeting",
|
|
63
|
+
template: "Hello {{ name }}!",
|
|
64
|
+
schema: z.object({ name: z.string() }),
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
expect(() => prompt.render({ name: 42 } as never)).toThrow();
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
it("should throw on invalid variables during validate", () => {
|
|
71
|
+
const prompt = createPrompt({
|
|
72
|
+
name: "greeting",
|
|
73
|
+
template: "Hello {{ name }}!",
|
|
74
|
+
schema: z.object({ name: z.string() }),
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
expect(() => prompt.validate({ name: 42 })).toThrow();
|
|
78
|
+
});
|
|
79
|
+
|
|
80
|
+
it("should expose the schema for external validation", () => {
|
|
81
|
+
const schema = z.object({ name: z.string() });
|
|
82
|
+
const prompt = createPrompt({
|
|
83
|
+
name: "greeting",
|
|
84
|
+
template: "Hello {{ name }}!",
|
|
85
|
+
schema,
|
|
86
|
+
});
|
|
87
|
+
|
|
88
|
+
expect(prompt.schema).toBe(schema);
|
|
89
|
+
});
|
|
90
|
+
});
|
package/src/prompt.ts
ADDED
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import { liquidEngine } from "./engine.js";
|
|
2
|
+
import type { PromptConfig, PromptModule } from "./types.js";
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Create a prompt module from a config object.
|
|
6
|
+
*
|
|
7
|
+
* Encapsulates template rendering (via LiquidJS) and variable validation
|
|
8
|
+
* (via Zod) into a single {@link PromptModule}. Works for both codegen
|
|
9
|
+
* output and runtime on-the-fly prompt construction.
|
|
10
|
+
*
|
|
11
|
+
* @param config - Prompt configuration with name, template, schema, and optional group.
|
|
12
|
+
* @returns A {@link PromptModule} with `render` and `validate` methods.
|
|
13
|
+
*
|
|
14
|
+
* @example
|
|
15
|
+
* ```ts
|
|
16
|
+
* import { createPrompt } from '@funkai/prompts'
|
|
17
|
+
* import { z } from 'zod'
|
|
18
|
+
*
|
|
19
|
+
* const greeting = createPrompt({
|
|
20
|
+
* name: 'greeting',
|
|
21
|
+
* template: 'Hello {{ name }}, welcome to {{ place }}!',
|
|
22
|
+
* schema: z.object({ name: z.string(), place: z.string() }),
|
|
23
|
+
* })
|
|
24
|
+
*
|
|
25
|
+
* greeting.render({ name: 'Alice', place: 'Wonderland' })
|
|
26
|
+
* // => "Hello Alice, welcome to Wonderland!"
|
|
27
|
+
* ```
|
|
28
|
+
*/
|
|
29
|
+
export function createPrompt<T>(config: PromptConfig<T>): PromptModule<T> {
|
|
30
|
+
const { name, group, template, schema } = config;
|
|
31
|
+
|
|
32
|
+
return {
|
|
33
|
+
name,
|
|
34
|
+
group,
|
|
35
|
+
schema,
|
|
36
|
+
/**
|
|
37
|
+
* Render the prompt template with the given variables.
|
|
38
|
+
*
|
|
39
|
+
* @param variables - Template variables matching the prompt schema.
|
|
40
|
+
* @returns The rendered prompt string.
|
|
41
|
+
* @throws {ZodError} If variables fail schema validation.
|
|
42
|
+
*/
|
|
43
|
+
render(variables: T): string {
|
|
44
|
+
return liquidEngine.parseAndRenderSync(
|
|
45
|
+
template,
|
|
46
|
+
schema.parse(variables) as Record<string, unknown>,
|
|
47
|
+
);
|
|
48
|
+
},
|
|
49
|
+
/**
|
|
50
|
+
* Validate variables against the prompt schema.
|
|
51
|
+
*
|
|
52
|
+
* @param variables - Variables to validate.
|
|
53
|
+
* @returns The parsed and validated variables.
|
|
54
|
+
* @throws {ZodError} If variables fail schema validation.
|
|
55
|
+
*/
|
|
56
|
+
validate(variables: unknown): T {
|
|
57
|
+
return schema.parse(variables);
|
|
58
|
+
},
|
|
59
|
+
};
|
|
60
|
+
}
|
package/src/registry.test.ts
CHANGED
|
@@ -1,31 +1,21 @@
|
|
|
1
1
|
import { describe, expect, it } from "vitest";
|
|
2
2
|
import { z } from "zod";
|
|
3
3
|
|
|
4
|
+
import { createPrompt } from "@/prompt.js";
|
|
4
5
|
import { createPromptRegistry } from "@/registry.js";
|
|
5
6
|
|
|
6
|
-
const mockPrompt = {
|
|
7
|
-
name: "test-prompt"
|
|
8
|
-
group: "agents"
|
|
7
|
+
const mockPrompt = createPrompt({
|
|
8
|
+
name: "test-prompt",
|
|
9
|
+
group: "agents",
|
|
10
|
+
template: "Hello {{ name }}",
|
|
9
11
|
schema: z.object({ name: z.string() }),
|
|
10
|
-
|
|
11
|
-
return `Hello ${variables.name}`;
|
|
12
|
-
},
|
|
13
|
-
validate(variables: unknown) {
|
|
14
|
-
return z.object({ name: z.string() }).parse(variables);
|
|
15
|
-
},
|
|
16
|
-
};
|
|
12
|
+
});
|
|
17
13
|
|
|
18
|
-
const emptyPrompt = {
|
|
19
|
-
name: "empty"
|
|
20
|
-
|
|
14
|
+
const emptyPrompt = createPrompt({
|
|
15
|
+
name: "empty",
|
|
16
|
+
template: "static",
|
|
21
17
|
schema: z.object({}),
|
|
22
|
-
|
|
23
|
-
return "static";
|
|
24
|
-
},
|
|
25
|
-
validate(variables: unknown) {
|
|
26
|
-
return z.object({}).parse(variables);
|
|
27
|
-
},
|
|
28
|
-
};
|
|
18
|
+
});
|
|
29
19
|
|
|
30
20
|
describe(createPromptRegistry, () => {
|
|
31
21
|
it("should provide dot-access to a registered prompt", () => {
|
package/src/registry.ts
CHANGED
|
@@ -55,16 +55,16 @@ function isPromptModule(value: unknown): value is PromptModule {
|
|
|
55
55
|
* @private
|
|
56
56
|
*/
|
|
57
57
|
function deepFreeze<T extends PromptNamespace>(obj: T): PromptRegistry<T> {
|
|
58
|
-
Object.
|
|
59
|
-
|
|
60
|
-
if (
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
!isPromptModule(value)
|
|
65
|
-
) {
|
|
66
|
-
deepFreeze(value as PromptNamespace);
|
|
58
|
+
const copied = Object.entries(obj).reduce<Record<string, unknown>>((acc, [key, value]) => {
|
|
59
|
+
const isNamespace = typeof value === "object" && value !== null && !isPromptModule(value);
|
|
60
|
+
if (isNamespace) {
|
|
61
|
+
acc[key] = deepFreeze({ ...value } as PromptNamespace);
|
|
62
|
+
} else {
|
|
63
|
+
acc[key] = value;
|
|
67
64
|
}
|
|
68
|
-
|
|
69
|
-
|
|
65
|
+
return acc;
|
|
66
|
+
}, {});
|
|
67
|
+
|
|
68
|
+
Object.freeze(copied);
|
|
69
|
+
return copied as PromptRegistry<T>;
|
|
70
70
|
}
|
package/src/types.ts
CHANGED
|
@@ -10,7 +10,30 @@ export type CreateEngineOptions = Pick<
|
|
|
10
10
|
>;
|
|
11
11
|
|
|
12
12
|
/**
|
|
13
|
-
*
|
|
13
|
+
* Configuration for creating a prompt module via {@link createPrompt}.
|
|
14
|
+
*
|
|
15
|
+
* @example
|
|
16
|
+
* ```ts
|
|
17
|
+
* const config: PromptConfig<{ name: string }> = {
|
|
18
|
+
* name: 'greeting',
|
|
19
|
+
* template: 'Hello {{ name }}!',
|
|
20
|
+
* schema: z.object({ name: z.string() }),
|
|
21
|
+
* }
|
|
22
|
+
* ```
|
|
23
|
+
*/
|
|
24
|
+
export interface PromptConfig<T = unknown> {
|
|
25
|
+
/** Kebab-case prompt identifier (e.g. `'greeting'`, `'worker-system'`). */
|
|
26
|
+
readonly name: string;
|
|
27
|
+
/** LiquidJS template string with `{{ variable }}` expressions. */
|
|
28
|
+
readonly template: string;
|
|
29
|
+
/** Zod schema for validating template variables. */
|
|
30
|
+
readonly schema: ZodType<T>;
|
|
31
|
+
/** Optional group path (e.g. `'agents'`, `'agents/core'`). */
|
|
32
|
+
readonly group?: string;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* A single prompt module produced by {@link createPrompt} or codegen.
|
|
14
37
|
*
|
|
15
38
|
* Each `.prompt` file generates a default export conforming to this shape.
|
|
16
39
|
*/
|
package/tsconfig.json
CHANGED
|
@@ -5,21 +5,28 @@
|
|
|
5
5
|
"module": "NodeNext",
|
|
6
6
|
"moduleResolution": "NodeNext",
|
|
7
7
|
"lib": ["ES2024"],
|
|
8
|
+
"types": ["node"],
|
|
9
|
+
|
|
8
10
|
"strict": true,
|
|
9
|
-
"
|
|
11
|
+
"noUncheckedIndexedAccess": true,
|
|
12
|
+
"exactOptionalPropertyTypes": true,
|
|
13
|
+
"noFallthroughCasesInSwitch": true,
|
|
14
|
+
"noPropertyAccessFromIndexSignature": true,
|
|
15
|
+
|
|
16
|
+
"verbatimModuleSyntax": true,
|
|
17
|
+
"resolveJsonModule": true,
|
|
10
18
|
"skipLibCheck": true,
|
|
11
19
|
"forceConsistentCasingInFileNames": true,
|
|
12
|
-
|
|
13
|
-
"isolatedModules": true,
|
|
20
|
+
|
|
14
21
|
"declaration": true,
|
|
15
22
|
"declarationMap": true,
|
|
16
23
|
"sourceMap": true,
|
|
24
|
+
|
|
17
25
|
"outDir": "./dist",
|
|
18
26
|
"rootDir": ".",
|
|
19
27
|
"paths": {
|
|
20
28
|
"@/*": ["./src/*"]
|
|
21
|
-
}
|
|
22
|
-
"types": ["node"]
|
|
29
|
+
}
|
|
23
30
|
},
|
|
24
31
|
"include": ["src"],
|
|
25
32
|
"exclude": ["node_modules", "dist"]
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"types-2PI_9h-M.d.mts","names":[],"sources":["../../src/types.ts"],"mappings":";;;;;;AAMA;KAAY,mBAAA,GAAsB,IAAA,CAChC,aAAA;;;;AASF;;UAAiB,YAAA;EAAA,SACN,IAAA;EAAA,SACA,KAAA;EAAA,SACA,MAAA,EAAQ,OAAA,CAAQ,CAAA;EACzB,MAAA,CAAO,SAAA,EAAW,CAAA;EAClB,QAAA,CAAS,SAAA,YAAqB,CAAA;AAAA;;;;;UAOf,eAAA;EAAA,UACL,GAAA,WAAc,YAAA,GAAe,eAAA;AAAA;;;;;;;;AADzC;;;;;KAgBY,cAAA,WAAyB,eAAA,2BACd,CAAA,GAAI,CAAA,CAAE,CAAA,UAAW,YAAA,GAClC,CAAA,CAAE,CAAA,IACF,CAAA,CAAE,CAAA,UAAW,eAAA,GACX,cAAA,CAAe,CAAA,CAAE,CAAA,KACjB,CAAA,CAAE,CAAA"}
|