@super_studio/ecforce-ai-agent-server 0.2.0-canary.4 → 1.0.0-canary.7

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 (67) hide show
  1. package/dist/_virtual/_@oxc-project_runtime@0.103.0/helpers/defineProperty.cjs +14 -0
  2. package/dist/_virtual/_@oxc-project_runtime@0.103.0/helpers/defineProperty.mjs +14 -0
  3. package/dist/_virtual/_@oxc-project_runtime@0.103.0/helpers/objectSpread2.cjs +27 -0
  4. package/dist/_virtual/_@oxc-project_runtime@0.103.0/helpers/objectSpread2.mjs +27 -0
  5. package/dist/_virtual/_@oxc-project_runtime@0.103.0/helpers/objectWithoutProperties.cjs +15 -0
  6. package/dist/_virtual/_@oxc-project_runtime@0.103.0/helpers/objectWithoutProperties.mjs +15 -0
  7. package/dist/_virtual/_@oxc-project_runtime@0.103.0/helpers/objectWithoutPropertiesLoose.cjs +14 -0
  8. package/dist/_virtual/_@oxc-project_runtime@0.103.0/helpers/objectWithoutPropertiesLoose.mjs +13 -0
  9. package/dist/_virtual/_@oxc-project_runtime@0.103.0/helpers/toPrimitive.cjs +16 -0
  10. package/dist/_virtual/_@oxc-project_runtime@0.103.0/helpers/toPrimitive.mjs +16 -0
  11. package/dist/_virtual/_@oxc-project_runtime@0.103.0/helpers/toPropertyKey.cjs +11 -0
  12. package/dist/_virtual/_@oxc-project_runtime@0.103.0/helpers/toPropertyKey.mjs +11 -0
  13. package/dist/_virtual/_@oxc-project_runtime@0.103.0/helpers/typeof.cjs +18 -0
  14. package/dist/_virtual/_@oxc-project_runtime@0.103.0/helpers/typeof.mjs +12 -0
  15. package/dist/index.cjs +7 -0
  16. package/dist/index.d.cts +3 -0
  17. package/dist/index.d.mts +3 -0
  18. package/dist/index.mjs +3 -531
  19. package/dist/lib/constants.cjs +6 -0
  20. package/dist/lib/constants.mjs +6 -0
  21. package/dist/lib/constants.mjs.map +1 -0
  22. package/dist/lib/jwt.cjs +64 -0
  23. package/dist/lib/jwt.mjs +64 -0
  24. package/dist/lib/jwt.mjs.map +1 -0
  25. package/dist/mcp-auth.cjs +52 -0
  26. package/dist/mcp-auth.d.cts +38 -0
  27. package/dist/mcp-auth.d.cts.map +1 -0
  28. package/dist/mcp-auth.d.mts +38 -0
  29. package/dist/mcp-auth.d.mts.map +1 -0
  30. package/dist/mcp-auth.mjs +44 -129
  31. package/dist/mcp-auth.mjs.map +1 -0
  32. package/dist/sdk/__generated__/index.cjs +524 -0
  33. package/dist/sdk/__generated__/index.d.cts +1648 -0
  34. package/dist/sdk/__generated__/index.d.cts.map +1 -0
  35. package/dist/sdk/__generated__/index.d.mts +1648 -0
  36. package/dist/sdk/__generated__/index.d.mts.map +1 -0
  37. package/dist/sdk/__generated__/index.mjs +523 -0
  38. package/dist/sdk/__generated__/index.mjs.map +1 -0
  39. package/dist/sdk/index.cjs +21 -0
  40. package/dist/sdk/index.d.cts +22 -0
  41. package/dist/sdk/index.d.cts.map +1 -0
  42. package/dist/sdk/index.d.mts +22 -0
  43. package/dist/sdk/index.d.mts.map +1 -0
  44. package/dist/sdk/index.mjs +22 -0
  45. package/dist/sdk/index.mjs.map +1 -0
  46. package/package.json +14 -20
  47. package/src/sdk/__generated__/index.ts +2194 -532
  48. package/src/sdk/generate.ts +21 -1
  49. package/dist/chunk-FWCSY2DS.mjs +0 -37
  50. package/dist/chunk-ORMEWXMH.js +0 -37
  51. package/dist/index.d.ts +0 -2
  52. package/dist/index.d.ts.map +0 -1
  53. package/dist/index.js +0 -532
  54. package/dist/lib/constants.d.ts +0 -2
  55. package/dist/lib/constants.d.ts.map +0 -1
  56. package/dist/lib/jwt.d.ts +0 -37
  57. package/dist/lib/jwt.d.ts.map +0 -1
  58. package/dist/mcp-auth.d.ts +0 -35
  59. package/dist/mcp-auth.d.ts.map +0 -1
  60. package/dist/mcp-auth.js +0 -136
  61. package/dist/sdk/__generated__/index.d.ts +0 -637
  62. package/dist/sdk/__generated__/index.d.ts.map +0 -1
  63. package/dist/sdk/generate.d.ts +0 -2
  64. package/dist/sdk/generate.d.ts.map +0 -1
  65. package/dist/sdk/index.d.ts +0 -19
  66. package/dist/sdk/index.d.ts.map +0 -1
  67. package/src/.tmp/test-script.ts +0 -18
@@ -0,0 +1,52 @@
1
+ const require_jwt = require('./lib/jwt.cjs');
2
+
3
+ //#region src/mcp-auth.ts
4
+ const DEFAULT_MAX_AGE = 600;
5
+ const DEFAULT_SALT = process.env.STAGE === "local" ? "dev" : process.env.STAGE;
6
+ /**
7
+ * Uses Auth.js JWT encoding/decoding.
8
+ * @see https://github.com/nextauthjs/next-auth/blob/main/packages/core/src/jwt.ts
9
+ */
10
+ async function createMCPToken(payload, options) {
11
+ var _options$maxAge, _options$secret, _options$salt;
12
+ const maxAge = (_options$maxAge = options === null || options === void 0 ? void 0 : options.maxAge) !== null && _options$maxAge !== void 0 ? _options$maxAge : DEFAULT_MAX_AGE;
13
+ const secret = (_options$secret = options === null || options === void 0 ? void 0 : options.secret) !== null && _options$secret !== void 0 ? _options$secret : process.env.MCP_TOKEN_SECRET;
14
+ const salt = (_options$salt = options === null || options === void 0 ? void 0 : options.salt) !== null && _options$salt !== void 0 ? _options$salt : DEFAULT_SALT;
15
+ if (!secret || !salt) throw new Error("Secret or salt is not set");
16
+ return {
17
+ token: await require_jwt.encode({
18
+ token: payload,
19
+ secret,
20
+ salt,
21
+ maxAge
22
+ }),
23
+ expiresAt: new Date(Date.now() + maxAge * 1e3)
24
+ };
25
+ }
26
+ /**
27
+ * Uses Auth.js JWT encoding/decoding.
28
+ * @see https://github.com/nextauthjs/next-auth/blob/main/packages/core/src/jwt.ts
29
+ */
30
+ async function decodeMCPToken(token, options) {
31
+ var _options$secret2, _options$salt2;
32
+ const secret = (_options$secret2 = options === null || options === void 0 ? void 0 : options.secret) !== null && _options$secret2 !== void 0 ? _options$secret2 : process.env.MCP_TOKEN_SECRET;
33
+ const salt = (_options$salt2 = options === null || options === void 0 ? void 0 : options.salt) !== null && _options$salt2 !== void 0 ? _options$salt2 : DEFAULT_SALT;
34
+ if (!secret || !salt) throw new Error("Secret or salt is not set");
35
+ const decoded = await require_jwt.decode({
36
+ token,
37
+ secret,
38
+ salt
39
+ });
40
+ if (!decoded) throw new Error("Invalid token");
41
+ return decoded;
42
+ }
43
+ function getMcpToken(req) {
44
+ const mcpToken = req.headers.get("X-MCP-Token");
45
+ if (!mcpToken || typeof mcpToken !== "string") throw new Error("Unauthorized");
46
+ return mcpToken;
47
+ }
48
+
49
+ //#endregion
50
+ exports.createMCPToken = createMCPToken;
51
+ exports.decodeMCPToken = decodeMCPToken;
52
+ exports.getMcpToken = getMcpToken;
@@ -0,0 +1,38 @@
1
+ //#region src/mcp-auth.d.ts
2
+ /**
3
+ * 共通のMCPトークンのペイロード。
4
+ * すべてのapps(cdp, ma, bi)はこのトークンの形になります。
5
+ */
6
+ type MCPTokenPayload = {
7
+ source: string;
8
+ user: {
9
+ id: string;
10
+ name: string;
11
+ email: string;
12
+ projectId: string;
13
+ };
14
+ };
15
+ /**
16
+ * Uses Auth.js JWT encoding/decoding.
17
+ * @see https://github.com/nextauthjs/next-auth/blob/main/packages/core/src/jwt.ts
18
+ */
19
+ declare function createMCPToken(payload: MCPTokenPayload, options?: {
20
+ secret?: string;
21
+ salt?: string;
22
+ maxAge?: number;
23
+ }): Promise<{
24
+ token: string;
25
+ expiresAt: Date;
26
+ }>;
27
+ /**
28
+ * Uses Auth.js JWT encoding/decoding.
29
+ * @see https://github.com/nextauthjs/next-auth/blob/main/packages/core/src/jwt.ts
30
+ */
31
+ declare function decodeMCPToken(token: string, options?: {
32
+ secret?: string;
33
+ salt?: string;
34
+ }): Promise<MCPTokenPayload>;
35
+ declare function getMcpToken(req: Request): string;
36
+ //#endregion
37
+ export { MCPTokenPayload, createMCPToken, decodeMCPToken, getMcpToken };
38
+ //# sourceMappingURL=mcp-auth.d.cts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mcp-auth.d.cts","names":[],"sources":["../src/mcp-auth.ts"],"sourcesContent":[],"mappings":";;AAMA;AAiBA;;KAjBY,eAAA;EAuBT,MAAA,EAAA,MAAA;EAAA,IAAA,EAAA;IAwBmB,EAAA,EAAA,MAAA;IAuBN,IAAA,EAAA,MAAW;;;;;;;;;iBArDL,cAAA,UACX;;;;IAKR;;;;;;;;iBAwBmB,cAAA;;;IAMnB,QAAQ;iBAiBK,WAAA,MAAiB"}
@@ -0,0 +1,38 @@
1
+ //#region src/mcp-auth.d.ts
2
+ /**
3
+ * 共通のMCPトークンのペイロード。
4
+ * すべてのapps(cdp, ma, bi)はこのトークンの形になります。
5
+ */
6
+ type MCPTokenPayload = {
7
+ source: string;
8
+ user: {
9
+ id: string;
10
+ name: string;
11
+ email: string;
12
+ projectId: string;
13
+ };
14
+ };
15
+ /**
16
+ * Uses Auth.js JWT encoding/decoding.
17
+ * @see https://github.com/nextauthjs/next-auth/blob/main/packages/core/src/jwt.ts
18
+ */
19
+ declare function createMCPToken(payload: MCPTokenPayload, options?: {
20
+ secret?: string;
21
+ salt?: string;
22
+ maxAge?: number;
23
+ }): Promise<{
24
+ token: string;
25
+ expiresAt: Date;
26
+ }>;
27
+ /**
28
+ * Uses Auth.js JWT encoding/decoding.
29
+ * @see https://github.com/nextauthjs/next-auth/blob/main/packages/core/src/jwt.ts
30
+ */
31
+ declare function decodeMCPToken(token: string, options?: {
32
+ secret?: string;
33
+ salt?: string;
34
+ }): Promise<MCPTokenPayload>;
35
+ declare function getMcpToken(req: Request): string;
36
+ //#endregion
37
+ export { MCPTokenPayload, createMCPToken, decodeMCPToken, getMcpToken };
38
+ //# sourceMappingURL=mcp-auth.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mcp-auth.d.mts","names":[],"sources":["../src/mcp-auth.ts"],"sourcesContent":[],"mappings":";;AAMA;AAiBA;;KAjBY,eAAA;EAuBT,MAAA,EAAA,MAAA;EAAA,IAAA,EAAA;IAwBmB,EAAA,EAAA,MAAA;IAuBN,IAAA,EAAA,MAAW;;;;;;;;;iBArDL,cAAA,UACX;;;;IAKR;;;;;;;;iBAwBmB,cAAA;;;IAMnB,QAAQ;iBAiBK,WAAA,MAAiB"}
package/dist/mcp-auth.mjs CHANGED
@@ -1,136 +1,51 @@
1
- import "./chunk-FWCSY2DS.mjs";
1
+ import { decode, encode } from "./lib/jwt.mjs";
2
2
 
3
- // src/lib/jwt.ts
4
- import { hkdf } from "@panva/hkdf";
5
- import {
6
- base64url,
7
- calculateJwkThumbprint,
8
- EncryptJWT,
9
- jwtDecrypt
10
- } from "jose";
11
- var DEFAULT_MAX_AGE = 30 * 24 * 60 * 60;
12
- var now = () => Date.now() / 1e3 | 0;
13
- var alg = "dir";
14
- var enc = "A256CBC-HS512";
15
- async function encode(params) {
16
- const { token = {}, secret, maxAge = DEFAULT_MAX_AGE, salt } = params;
17
- const secrets = Array.isArray(secret) ? secret : [secret];
18
- const encryptionSecret = await getDerivedEncryptionKey(
19
- enc,
20
- secrets[0],
21
- salt
22
- );
23
- const thumbprint = await calculateJwkThumbprint(
24
- { kty: "oct", k: base64url.encode(encryptionSecret) },
25
- `sha${encryptionSecret.byteLength << 3}`
26
- );
27
- return await new EncryptJWT(token).setProtectedHeader({ alg, enc, kid: thumbprint }).setIssuedAt().setExpirationTime(now() + maxAge).setJti(crypto.randomUUID()).encrypt(encryptionSecret);
28
- }
29
- async function decode(params) {
30
- const { token, secret, salt } = params;
31
- const secrets = Array.isArray(secret) ? secret : [secret];
32
- if (!token) {
33
- return null;
34
- }
35
- const { payload } = await jwtDecrypt(
36
- token,
37
- async ({ kid, enc: enc2 }) => {
38
- for (const secret2 of secrets) {
39
- const encryptionSecret = await getDerivedEncryptionKey(
40
- enc2,
41
- secret2,
42
- salt
43
- );
44
- if (kid === void 0) {
45
- return encryptionSecret;
46
- }
47
- const thumbprint = await calculateJwkThumbprint(
48
- { kty: "oct", k: base64url.encode(encryptionSecret) },
49
- `sha${encryptionSecret.byteLength << 3}`
50
- );
51
- if (kid === thumbprint) {
52
- return encryptionSecret;
53
- }
54
- }
55
- throw new Error("no matching decryption secret");
56
- },
57
- {
58
- clockTolerance: 15,
59
- keyManagementAlgorithms: [alg],
60
- contentEncryptionAlgorithms: [enc, "A256GCM"]
61
- }
62
- );
63
- return payload;
64
- }
65
- async function getDerivedEncryptionKey(enc2, keyMaterial, salt) {
66
- let length;
67
- switch (enc2) {
68
- case "A256CBC-HS512":
69
- length = 64;
70
- break;
71
- case "A256GCM":
72
- length = 32;
73
- break;
74
- default:
75
- throw new Error("Unsupported JWT Content Encryption Algorithm");
76
- }
77
- return await hkdf(
78
- "sha256",
79
- keyMaterial,
80
- salt,
81
- `Auth.js Generated Encryption Key (${salt})`,
82
- length
83
- );
84
- }
85
-
86
- // src/mcp-auth.ts
87
- var DEFAULT_MAX_AGE2 = 60 * 10;
88
- var DEFAULT_SALT = process.env.STAGE === "local" ? "dev" : process.env.STAGE;
3
+ //#region src/mcp-auth.ts
4
+ const DEFAULT_MAX_AGE = 600;
5
+ const DEFAULT_SALT = process.env.STAGE === "local" ? "dev" : process.env.STAGE;
6
+ /**
7
+ * Uses Auth.js JWT encoding/decoding.
8
+ * @see https://github.com/nextauthjs/next-auth/blob/main/packages/core/src/jwt.ts
9
+ */
89
10
  async function createMCPToken(payload, options) {
90
- var _a, _b, _c;
91
- const maxAge = (_a = options == null ? void 0 : options.maxAge) != null ? _a : DEFAULT_MAX_AGE2;
92
- const secret = (_b = options == null ? void 0 : options.secret) != null ? _b : process.env.MCP_TOKEN_SECRET;
93
- const salt = (_c = options == null ? void 0 : options.salt) != null ? _c : DEFAULT_SALT;
94
- if (!secret || !salt) {
95
- throw new Error("Secret or salt is not set");
96
- }
97
- const token = await encode({
98
- token: payload,
99
- secret,
100
- salt,
101
- maxAge
102
- });
103
- return {
104
- token,
105
- expiresAt: new Date(Date.now() + maxAge * 1e3)
106
- };
11
+ var _options$maxAge, _options$secret, _options$salt;
12
+ const maxAge = (_options$maxAge = options === null || options === void 0 ? void 0 : options.maxAge) !== null && _options$maxAge !== void 0 ? _options$maxAge : DEFAULT_MAX_AGE;
13
+ const secret = (_options$secret = options === null || options === void 0 ? void 0 : options.secret) !== null && _options$secret !== void 0 ? _options$secret : process.env.MCP_TOKEN_SECRET;
14
+ const salt = (_options$salt = options === null || options === void 0 ? void 0 : options.salt) !== null && _options$salt !== void 0 ? _options$salt : DEFAULT_SALT;
15
+ if (!secret || !salt) throw new Error("Secret or salt is not set");
16
+ return {
17
+ token: await encode({
18
+ token: payload,
19
+ secret,
20
+ salt,
21
+ maxAge
22
+ }),
23
+ expiresAt: new Date(Date.now() + maxAge * 1e3)
24
+ };
107
25
  }
26
+ /**
27
+ * Uses Auth.js JWT encoding/decoding.
28
+ * @see https://github.com/nextauthjs/next-auth/blob/main/packages/core/src/jwt.ts
29
+ */
108
30
  async function decodeMCPToken(token, options) {
109
- var _a, _b;
110
- const secret = (_a = options == null ? void 0 : options.secret) != null ? _a : process.env.MCP_TOKEN_SECRET;
111
- const salt = (_b = options == null ? void 0 : options.salt) != null ? _b : DEFAULT_SALT;
112
- if (!secret || !salt) {
113
- throw new Error("Secret or salt is not set");
114
- }
115
- const decoded = await decode({
116
- token,
117
- secret,
118
- salt
119
- });
120
- if (!decoded) {
121
- throw new Error("Invalid token");
122
- }
123
- return decoded;
31
+ var _options$secret2, _options$salt2;
32
+ const secret = (_options$secret2 = options === null || options === void 0 ? void 0 : options.secret) !== null && _options$secret2 !== void 0 ? _options$secret2 : process.env.MCP_TOKEN_SECRET;
33
+ const salt = (_options$salt2 = options === null || options === void 0 ? void 0 : options.salt) !== null && _options$salt2 !== void 0 ? _options$salt2 : DEFAULT_SALT;
34
+ if (!secret || !salt) throw new Error("Secret or salt is not set");
35
+ const decoded = await decode({
36
+ token,
37
+ secret,
38
+ salt
39
+ });
40
+ if (!decoded) throw new Error("Invalid token");
41
+ return decoded;
124
42
  }
125
43
  function getMcpToken(req) {
126
- const mcpToken = req.headers.get("X-MCP-Token");
127
- if (!mcpToken || typeof mcpToken !== "string") {
128
- throw new Error("Unauthorized");
129
- }
130
- return mcpToken;
44
+ const mcpToken = req.headers.get("X-MCP-Token");
45
+ if (!mcpToken || typeof mcpToken !== "string") throw new Error("Unauthorized");
46
+ return mcpToken;
131
47
  }
132
- export {
133
- createMCPToken,
134
- decodeMCPToken,
135
- getMcpToken
136
- };
48
+
49
+ //#endregion
50
+ export { createMCPToken, decodeMCPToken, getMcpToken };
51
+ //# sourceMappingURL=mcp-auth.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mcp-auth.mjs","names":[],"sources":["../src/mcp-auth.ts"],"sourcesContent":["import { decode, encode } from \"./lib/jwt\";\n\n/**\n * 共通のMCPトークンのペイロード。\n * すべてのapps(cdp, ma, bi)はこのトークンの形になります。\n */\nexport type MCPTokenPayload = {\n source: string;\n user: {\n id: string;\n name: string;\n email: string;\n projectId: string;\n };\n};\n\nconst DEFAULT_MAX_AGE = 60 * 10; // 10 minutes\nconst DEFAULT_SALT = process.env.STAGE === \"local\" ? \"dev\" : process.env.STAGE;\n\n/**\n * Uses Auth.js JWT encoding/decoding.\n * @see https://github.com/nextauthjs/next-auth/blob/main/packages/core/src/jwt.ts\n */\nexport async function createMCPToken(\n payload: MCPTokenPayload,\n options?: {\n secret?: string;\n salt?: string;\n maxAge?: number;\n },\n) {\n const maxAge = options?.maxAge ?? DEFAULT_MAX_AGE;\n const secret = options?.secret ?? process.env.MCP_TOKEN_SECRET;\n const salt = options?.salt ?? DEFAULT_SALT;\n if (!secret || !salt) {\n throw new Error(\"Secret or salt is not set\");\n }\n const token = await encode<MCPTokenPayload>({\n token: payload,\n secret,\n salt,\n maxAge,\n });\n return {\n token,\n expiresAt: new Date(Date.now() + maxAge * 1000),\n };\n}\n\n/**\n * Uses Auth.js JWT encoding/decoding.\n * @see https://github.com/nextauthjs/next-auth/blob/main/packages/core/src/jwt.ts\n */\nexport async function decodeMCPToken(\n token: string,\n options?: {\n secret?: string;\n salt?: string;\n },\n): Promise<MCPTokenPayload> {\n const secret = options?.secret ?? process.env.MCP_TOKEN_SECRET;\n const salt = options?.salt ?? DEFAULT_SALT;\n if (!secret || !salt) {\n throw new Error(\"Secret or salt is not set\");\n }\n const decoded = await decode<MCPTokenPayload>({\n token,\n secret,\n salt,\n });\n if (!decoded) {\n throw new Error(\"Invalid token\");\n }\n return decoded;\n}\n\nexport function getMcpToken(req: Request) {\n const mcpToken = req.headers.get(\"X-MCP-Token\");\n if (!mcpToken || typeof mcpToken !== \"string\") {\n throw new Error(\"Unauthorized\");\n }\n return mcpToken;\n}\n"],"mappings":";;;AAgBA,MAAM,kBAAkB;AACxB,MAAM,eAAe,QAAQ,IAAI,UAAU,UAAU,QAAQ,QAAQ,IAAI;;;;;AAMzE,eAAsB,eACpB,SACA,SAKA;;CACA,MAAM,8EAAS,QAAS,mEAAU;CAClC,MAAM,8EAAS,QAAS,mEAAU,QAAQ,IAAI;CAC9C,MAAM,0EAAO,QAAS,6DAAQ;AAC9B,KAAI,CAAC,UAAU,CAAC,KACd,OAAM,IAAI,MAAM,4BAA4B;AAQ9C,QAAO;EACL,OAPY,MAAM,OAAwB;GAC1C,OAAO;GACP;GACA;GACA;GACD,CAAC;EAGA,WAAW,IAAI,KAAK,KAAK,KAAK,GAAG,SAAS,IAAK;EAChD;;;;;;AAOH,eAAsB,eACpB,OACA,SAI0B;;CAC1B,MAAM,+EAAS,QAAS,qEAAU,QAAQ,IAAI;CAC9C,MAAM,2EAAO,QAAS,+DAAQ;AAC9B,KAAI,CAAC,UAAU,CAAC,KACd,OAAM,IAAI,MAAM,4BAA4B;CAE9C,MAAM,UAAU,MAAM,OAAwB;EAC5C;EACA;EACA;EACD,CAAC;AACF,KAAI,CAAC,QACH,OAAM,IAAI,MAAM,gBAAgB;AAElC,QAAO;;AAGT,SAAgB,YAAY,KAAc;CACxC,MAAM,WAAW,IAAI,QAAQ,IAAI,cAAc;AAC/C,KAAI,CAAC,YAAY,OAAO,aAAa,SACnC,OAAM,IAAI,MAAM,eAAe;AAEjC,QAAO"}