@webiny/api-audit-logs-ddb 6.6.0-alpha.0 → 6.6.0-alpha.2

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.
@@ -48,10 +48,14 @@ class BaseAccessPattern {
48
48
  reverse: "DESC" === params.sort,
49
49
  index: this.index
50
50
  };
51
- if (params.createdOn_lte || params.createdOn_gte) options.between = [
52
- toGteTime(params.createdOn_gte),
53
- toLteTime(params.createdOn_lte)
54
- ];
51
+ if (params.createdOn_lte || params.createdOn_gte) {
52
+ const lower = toGteTime(params.createdOn_gte);
53
+ const upper = toLteTime(params.createdOn_lte);
54
+ options.between = [
55
+ lower,
56
+ Math.max(lower, upper)
57
+ ];
58
+ }
55
59
  return options;
56
60
  }
57
61
  }
@@ -1 +1 @@
1
- {"version":3,"file":"accessPatterns/BaseAccessPattern.js","sources":["../../src/accessPatterns/BaseAccessPattern.ts"],"sourcesContent":["import type { IAuditLog } from \"@webiny/api-audit-logs/storage/types.js\";\nimport type { IIndexStorageItem, IStorageItem } from \"~/types.js\";\nimport { createStartKey } from \"~/startKey.js\";\nimport type { IStorageListParams } from \"@webiny/api-audit-logs/storage/abstractions/Storage.js\";\nimport type {\n IAccessPattern,\n IAccessPatternCreateKeysResult,\n IAccessPatternHandles,\n IAccessPatternListResult\n} from \"~/abstractions/AccessPattern.js\";\nimport type { AuditLogsEntity } from \"~/entity.js\";\nimport type { IEntityQueryAllParams, IEntityQueryPerPageResult } from \"@webiny/db-dynamodb\";\n\nconst toGteTime = (date?: Date): number => {\n if (!date) {\n return 0;\n }\n return date.getTime();\n};\nconst toLteTime = (date?: Date): number => {\n if (!date) {\n return Date.now();\n }\n return date.getTime();\n};\n\nexport interface ICreateOptionsParams {\n limit?: number;\n sort?: \"ASC\" | \"DESC\";\n after?: string;\n createdOn_gte?: Date;\n createdOn_lte?: Date;\n}\n\nexport interface IBaseAccessPatternParams {\n index: string | undefined;\n entity: AuditLogsEntity;\n}\n\nexport interface IAccessPatternQueryParams {\n partitionKey: string;\n options: IEntityQueryAllParams[\"options\"];\n}\n\nexport abstract class BaseAccessPattern<T> implements IAccessPattern<T> {\n public readonly index;\n protected readonly entity;\n\n public constructor(params: IBaseAccessPatternParams) {\n this.index = params.index;\n this.entity = params.entity;\n }\n\n public abstract handles(): IAccessPatternHandles;\n\n public canHandle(params: IStorageListParams): boolean {\n const handles = this.handles();\n for (const key of handles.mustInclude) {\n if (!params[key]) {\n return false;\n }\n }\n for (const key of handles.mustNotInclude) {\n if (!!params[key]) {\n return false;\n }\n }\n if (!handles.shouldInclude?.length) {\n return true;\n }\n\n for (const key of handles.shouldInclude) {\n if (!!params[key]) {\n return true;\n }\n }\n return false;\n }\n\n protected async query<T extends IStorageItem = IStorageItem>(\n params: IAccessPatternQueryParams\n ) {\n return this.entity.queryPerPage<T>({\n partitionKey: params.partitionKey,\n options: params.options\n });\n }\n\n protected async populateResult(\n input: Awaited<IEntityQueryPerPageResult<IIndexStorageItem>>\n ): Promise<IEntityQueryPerPageResult<IStorageItem>> {\n const reader = this.entity.createEntityReader({\n read: input.items.map(item => {\n return {\n PK: item.PK,\n SK: item.SK\n };\n })\n });\n const result = await reader.execute();\n\n return {\n ...input,\n items: input.items\n .map(item => {\n return result.find(i => {\n return i.PK === item.PK && i.SK === item.SK;\n });\n })\n .filter((item): item is IStorageItem => !!item)\n };\n }\n\n public abstract list(params: T): Promise<IAccessPatternListResult>;\n public abstract createKeys(item: IAuditLog): IAccessPatternCreateKeysResult;\n\n protected createOptions(params: ICreateOptionsParams): IEntityQueryAllParams[\"options\"] {\n const options: IEntityQueryAllParams[\"options\"] = {\n limit: params.limit || 25,\n // @ts-expect-error\n startKey: createStartKey({\n after: params.after\n }),\n reverse: params.sort === \"DESC\",\n index: this.index\n };\n\n if (params.createdOn_lte || params.createdOn_gte) {\n options!.between = [toGteTime(params.createdOn_gte), toLteTime(params.createdOn_lte)];\n }\n\n return options;\n }\n}\n"],"names":["toGteTime","date","toLteTime","Date","BaseAccessPattern","params","handles","key","input","reader","item","result","i","options","createStartKey"],"mappings":";AAaA,MAAMA,YAAY,CAACC;IACf,IAAI,CAACA,MACD,OAAO;IAEX,OAAOA,KAAK,OAAO;AACvB;AACA,MAAMC,YAAY,CAACD;IACf,IAAI,CAACA,MACD,OAAOE,KAAK,GAAG;IAEnB,OAAOF,KAAK,OAAO;AACvB;AAoBO,MAAeG;IAIlB,YAAmBC,MAAgC,CAAE;QACjD,IAAI,CAAC,KAAK,GAAGA,OAAO,KAAK;QACzB,IAAI,CAAC,MAAM,GAAGA,OAAO,MAAM;IAC/B;IAIO,UAAUA,MAA0B,EAAW;QAClD,MAAMC,UAAU,IAAI,CAAC,OAAO;QAC5B,KAAK,MAAMC,OAAOD,QAAQ,WAAW,CACjC,IAAI,CAACD,MAAM,CAACE,IAAI,EACZ,OAAO;QAGf,KAAK,MAAMA,OAAOD,QAAQ,cAAc,CACpC,IAAI,CAAC,CAACD,MAAM,CAACE,IAAI,EACb,OAAO;QAGf,IAAI,CAACD,QAAQ,aAAa,EAAE,QACxB,OAAO;QAGX,KAAK,MAAMC,OAAOD,QAAQ,aAAa,CACnC,IAAI,CAAC,CAACD,MAAM,CAACE,IAAI,EACb,OAAO;QAGf,OAAO;IACX;IAEA,MAAgB,MACZF,MAAiC,EACnC;QACE,OAAO,IAAI,CAAC,MAAM,CAAC,YAAY,CAAI;YAC/B,cAAcA,OAAO,YAAY;YACjC,SAASA,OAAO,OAAO;QAC3B;IACJ;IAEA,MAAgB,eACZG,KAA4D,EACZ;QAChD,MAAMC,SAAS,IAAI,CAAC,MAAM,CAAC,kBAAkB,CAAC;YAC1C,MAAMD,MAAM,KAAK,CAAC,GAAG,CAACE,CAAAA,OACX;oBACH,IAAIA,KAAK,EAAE;oBACX,IAAIA,KAAK,EAAE;gBACf;QAER;QACA,MAAMC,SAAS,MAAMF,OAAO,OAAO;QAEnC,OAAO;YACH,GAAGD,KAAK;YACR,OAAOA,MAAM,KAAK,CACb,GAAG,CAACE,CAAAA,OACMC,OAAO,IAAI,CAACC,CAAAA,IACRA,EAAE,EAAE,KAAKF,KAAK,EAAE,IAAIE,EAAE,EAAE,KAAKF,KAAK,EAAE,GAGlD,MAAM,CAAC,CAACA,OAA+B,CAAC,CAACA;QAClD;IACJ;IAKU,cAAcL,MAA4B,EAAoC;QACpF,MAAMQ,UAA4C;YAC9C,OAAOR,OAAO,KAAK,IAAI;YAEvB,UAAUS,eAAe;gBACrB,OAAOT,OAAO,KAAK;YACvB;YACA,SAASA,AAAgB,WAAhBA,OAAO,IAAI;YACpB,OAAO,IAAI,CAAC,KAAK;QACrB;QAEA,IAAIA,OAAO,aAAa,IAAIA,OAAO,aAAa,EAC5CQ,QAAS,OAAO,GAAG;YAACb,UAAUK,OAAO,aAAa;YAAGH,UAAUG,OAAO,aAAa;SAAE;QAGzF,OAAOQ;IACX;AACJ"}
1
+ {"version":3,"file":"accessPatterns/BaseAccessPattern.js","sources":["../../src/accessPatterns/BaseAccessPattern.ts"],"sourcesContent":["import type { IAuditLog } from \"@webiny/api-audit-logs/storage/types.js\";\nimport type { IIndexStorageItem, IStorageItem } from \"~/types.js\";\nimport { createStartKey } from \"~/startKey.js\";\nimport type { IStorageListParams } from \"@webiny/api-audit-logs/storage/abstractions/Storage.js\";\nimport type {\n IAccessPattern,\n IAccessPatternCreateKeysResult,\n IAccessPatternHandles,\n IAccessPatternListResult\n} from \"~/abstractions/AccessPattern.js\";\nimport type { AuditLogsEntity } from \"~/entity.js\";\nimport type { IEntityQueryAllParams, IEntityQueryPerPageResult } from \"@webiny/db-dynamodb\";\n\nconst toGteTime = (date?: Date): number => {\n if (!date) {\n return 0;\n }\n return date.getTime();\n};\nconst toLteTime = (date?: Date): number => {\n if (!date) {\n return Date.now();\n }\n return date.getTime();\n};\n\nexport interface ICreateOptionsParams {\n limit?: number;\n sort?: \"ASC\" | \"DESC\";\n after?: string;\n createdOn_gte?: Date;\n createdOn_lte?: Date;\n}\n\nexport interface IBaseAccessPatternParams {\n index: string | undefined;\n entity: AuditLogsEntity;\n}\n\nexport interface IAccessPatternQueryParams {\n partitionKey: string;\n options: IEntityQueryAllParams[\"options\"];\n}\n\nexport abstract class BaseAccessPattern<T> implements IAccessPattern<T> {\n public readonly index;\n protected readonly entity;\n\n public constructor(params: IBaseAccessPatternParams) {\n this.index = params.index;\n this.entity = params.entity;\n }\n\n public abstract handles(): IAccessPatternHandles;\n\n public canHandle(params: IStorageListParams): boolean {\n const handles = this.handles();\n for (const key of handles.mustInclude) {\n if (!params[key]) {\n return false;\n }\n }\n for (const key of handles.mustNotInclude) {\n if (!!params[key]) {\n return false;\n }\n }\n if (!handles.shouldInclude?.length) {\n return true;\n }\n\n for (const key of handles.shouldInclude) {\n if (!!params[key]) {\n return true;\n }\n }\n return false;\n }\n\n protected async query<T extends IStorageItem = IStorageItem>(\n params: IAccessPatternQueryParams\n ) {\n return this.entity.queryPerPage<T>({\n partitionKey: params.partitionKey,\n options: params.options\n });\n }\n\n protected async populateResult(\n input: Awaited<IEntityQueryPerPageResult<IIndexStorageItem>>\n ): Promise<IEntityQueryPerPageResult<IStorageItem>> {\n const reader = this.entity.createEntityReader({\n read: input.items.map(item => {\n return {\n PK: item.PK,\n SK: item.SK\n };\n })\n });\n const result = await reader.execute();\n\n return {\n ...input,\n items: input.items\n .map(item => {\n return result.find(i => {\n return i.PK === item.PK && i.SK === item.SK;\n });\n })\n .filter((item): item is IStorageItem => !!item)\n };\n }\n\n public abstract list(params: T): Promise<IAccessPatternListResult>;\n public abstract createKeys(item: IAuditLog): IAccessPatternCreateKeysResult;\n\n protected createOptions(params: ICreateOptionsParams): IEntityQueryAllParams[\"options\"] {\n const options: IEntityQueryAllParams[\"options\"] = {\n limit: params.limit || 25,\n startKey: createStartKey({\n after: params.after\n }),\n reverse: params.sort === \"DESC\",\n index: this.index\n };\n\n if (params.createdOn_lte || params.createdOn_gte) {\n const lower = toGteTime(params.createdOn_gte);\n const upper = toLteTime(params.createdOn_lte);\n options!.between = [lower, Math.max(lower, upper)];\n }\n\n return options;\n }\n}\n"],"names":["toGteTime","date","toLteTime","Date","BaseAccessPattern","params","handles","key","input","reader","item","result","i","options","createStartKey","lower","upper","Math"],"mappings":";AAaA,MAAMA,YAAY,CAACC;IACf,IAAI,CAACA,MACD,OAAO;IAEX,OAAOA,KAAK,OAAO;AACvB;AACA,MAAMC,YAAY,CAACD;IACf,IAAI,CAACA,MACD,OAAOE,KAAK,GAAG;IAEnB,OAAOF,KAAK,OAAO;AACvB;AAoBO,MAAeG;IAIlB,YAAmBC,MAAgC,CAAE;QACjD,IAAI,CAAC,KAAK,GAAGA,OAAO,KAAK;QACzB,IAAI,CAAC,MAAM,GAAGA,OAAO,MAAM;IAC/B;IAIO,UAAUA,MAA0B,EAAW;QAClD,MAAMC,UAAU,IAAI,CAAC,OAAO;QAC5B,KAAK,MAAMC,OAAOD,QAAQ,WAAW,CACjC,IAAI,CAACD,MAAM,CAACE,IAAI,EACZ,OAAO;QAGf,KAAK,MAAMA,OAAOD,QAAQ,cAAc,CACpC,IAAI,CAAC,CAACD,MAAM,CAACE,IAAI,EACb,OAAO;QAGf,IAAI,CAACD,QAAQ,aAAa,EAAE,QACxB,OAAO;QAGX,KAAK,MAAMC,OAAOD,QAAQ,aAAa,CACnC,IAAI,CAAC,CAACD,MAAM,CAACE,IAAI,EACb,OAAO;QAGf,OAAO;IACX;IAEA,MAAgB,MACZF,MAAiC,EACnC;QACE,OAAO,IAAI,CAAC,MAAM,CAAC,YAAY,CAAI;YAC/B,cAAcA,OAAO,YAAY;YACjC,SAASA,OAAO,OAAO;QAC3B;IACJ;IAEA,MAAgB,eACZG,KAA4D,EACZ;QAChD,MAAMC,SAAS,IAAI,CAAC,MAAM,CAAC,kBAAkB,CAAC;YAC1C,MAAMD,MAAM,KAAK,CAAC,GAAG,CAACE,CAAAA,OACX;oBACH,IAAIA,KAAK,EAAE;oBACX,IAAIA,KAAK,EAAE;gBACf;QAER;QACA,MAAMC,SAAS,MAAMF,OAAO,OAAO;QAEnC,OAAO;YACH,GAAGD,KAAK;YACR,OAAOA,MAAM,KAAK,CACb,GAAG,CAACE,CAAAA,OACMC,OAAO,IAAI,CAACC,CAAAA,IACRA,EAAE,EAAE,KAAKF,KAAK,EAAE,IAAIE,EAAE,EAAE,KAAKF,KAAK,EAAE,GAGlD,MAAM,CAAC,CAACA,OAA+B,CAAC,CAACA;QAClD;IACJ;IAKU,cAAcL,MAA4B,EAAoC;QACpF,MAAMQ,UAA4C;YAC9C,OAAOR,OAAO,KAAK,IAAI;YACvB,UAAUS,eAAe;gBACrB,OAAOT,OAAO,KAAK;YACvB;YACA,SAASA,AAAgB,WAAhBA,OAAO,IAAI;YACpB,OAAO,IAAI,CAAC,KAAK;QACrB;QAEA,IAAIA,OAAO,aAAa,IAAIA,OAAO,aAAa,EAAE;YAC9C,MAAMU,QAAQf,UAAUK,OAAO,aAAa;YAC5C,MAAMW,QAAQd,UAAUG,OAAO,aAAa;YAC5CQ,QAAS,OAAO,GAAG;gBAACE;gBAAOE,KAAK,GAAG,CAACF,OAAOC;aAAO;QACtD;QAEA,OAAOH;IACX;AACJ"}
package/cursorSchema.d.ts CHANGED
@@ -1,4 +1,5 @@
1
1
  export declare const fetchCursor: (input: unknown) => {
2
+ [x: string]: unknown;
2
3
  PK: string;
3
4
  SK: string;
4
5
  } | undefined;
package/cursorSchema.js CHANGED
@@ -11,7 +11,7 @@ const schema = zod.string().transform((value)=>{
11
11
  }).pipe(zod.object({
12
12
  PK: zod.string(),
13
13
  SK: zod.string()
14
- }));
14
+ }).passthrough());
15
15
  const fetchCursor = (input)=>{
16
16
  const result = schema.safeParse(input);
17
17
  if (!result.success) return;
@@ -1 +1 @@
1
- {"version":3,"file":"cursorSchema.js","sources":["../src/cursorSchema.ts"],"sourcesContent":["import zod from \"zod\";\nimport { decodeCursor } from \"@webiny/db-dynamodb\";\n\nconst schema = zod\n .string()\n .transform(value => {\n const decoded = decodeCursor(value);\n if (!decoded) {\n throw new Error(\"Invalid cursor.\");\n }\n try {\n return JSON.parse(decoded);\n } catch {\n return decoded;\n }\n })\n .pipe(\n zod.object({\n PK: zod.string(),\n SK: zod.string()\n })\n );\n\nexport const fetchCursor = (input: unknown) => {\n const result = schema.safeParse(input);\n if (!result.success) {\n return undefined;\n }\n return result.data;\n};\n"],"names":["schema","zod","value","decoded","decodeCursor","Error","JSON","fetchCursor","input","result"],"mappings":";;AAGA,MAAMA,SAASC,IAAAA,MACJ,GACN,SAAS,CAACC,CAAAA;IACP,MAAMC,UAAUC,aAAaF;IAC7B,IAAI,CAACC,SACD,MAAM,IAAIE,MAAM;IAEpB,IAAI;QACA,OAAOC,KAAK,KAAK,CAACH;IACtB,EAAE,OAAM;QACJ,OAAOA;IACX;AACJ,GACC,IAAI,CACDF,IAAI,MAAM,CAAC;IACP,IAAIA,IAAI,MAAM;IACd,IAAIA,IAAI,MAAM;AAClB;AAGD,MAAMM,cAAc,CAACC;IACxB,MAAMC,SAAST,OAAO,SAAS,CAACQ;IAChC,IAAI,CAACC,OAAO,OAAO,EACf;IAEJ,OAAOA,OAAO,IAAI;AACtB"}
1
+ {"version":3,"file":"cursorSchema.js","sources":["../src/cursorSchema.ts"],"sourcesContent":["import zod from \"zod\";\nimport { decodeCursor } from \"@webiny/db-dynamodb\";\n\nconst schema = zod\n .string()\n .transform(value => {\n const decoded = decodeCursor(value);\n if (!decoded) {\n throw new Error(\"Invalid cursor.\");\n }\n try {\n return JSON.parse(decoded);\n } catch {\n return decoded;\n }\n })\n .pipe(\n zod\n .object({\n PK: zod.string(),\n SK: zod.string()\n })\n .passthrough()\n );\n\nexport const fetchCursor = (input: unknown) => {\n const result = schema.safeParse(input);\n if (!result.success) {\n return undefined;\n }\n return result.data;\n};\n"],"names":["schema","zod","value","decoded","decodeCursor","Error","JSON","fetchCursor","input","result"],"mappings":";;AAGA,MAAMA,SAASC,IAAAA,MACJ,GACN,SAAS,CAACC,CAAAA;IACP,MAAMC,UAAUC,aAAaF;IAC7B,IAAI,CAACC,SACD,MAAM,IAAIE,MAAM;IAEpB,IAAI;QACA,OAAOC,KAAK,KAAK,CAACH;IACtB,EAAE,OAAM;QACJ,OAAOA;IACX;AACJ,GACC,IAAI,CACDF,IAAAA,MACW,CAAC;IACJ,IAAIA,IAAI,MAAM;IACd,IAAIA,IAAI,MAAM;AAClB,GACC,WAAW;AAGjB,MAAMM,cAAc,CAACC;IACxB,MAAMC,SAAST,OAAO,SAAS,CAACQ;IAChC,IAAI,CAACC,OAAO,OAAO,EACf;IAEJ,OAAOA,OAAO,IAAI;AACtB"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@webiny/api-audit-logs-ddb",
3
- "version": "6.6.0-alpha.0",
3
+ "version": "6.6.0-alpha.2",
4
4
  "type": "module",
5
5
  "keywords": [
6
6
  "@webiny/api-audit-logs",
@@ -21,19 +21,19 @@
21
21
  "./*": "./*"
22
22
  },
23
23
  "dependencies": {
24
- "@webiny/api": "6.6.0-alpha.0",
25
- "@webiny/api-audit-logs": "6.6.0-alpha.0",
26
- "@webiny/aws-sdk": "6.6.0-alpha.0",
27
- "@webiny/db-dynamodb": "6.6.0-alpha.0",
28
- "@webiny/error": "6.6.0-alpha.0",
29
- "@webiny/feature": "6.6.0-alpha.0",
30
- "@webiny/handler": "6.6.0-alpha.0",
31
- "@webiny/utils": "6.6.0-alpha.0",
24
+ "@webiny/api": "6.6.0-alpha.2",
25
+ "@webiny/api-audit-logs": "6.6.0-alpha.2",
26
+ "@webiny/aws-sdk": "6.6.0-alpha.2",
27
+ "@webiny/db-dynamodb": "6.6.0-alpha.2",
28
+ "@webiny/error": "6.6.0-alpha.2",
29
+ "@webiny/feature": "6.6.0-alpha.2",
30
+ "@webiny/handler": "6.6.0-alpha.2",
31
+ "@webiny/utils": "6.6.0-alpha.2",
32
32
  "zod": "4.4.3"
33
33
  },
34
34
  "devDependencies": {
35
- "@webiny/build-tools": "6.6.0-alpha.0",
36
- "@webiny/project-utils": "6.6.0-alpha.0",
35
+ "@webiny/api-core": "6.6.0-alpha.2",
36
+ "@webiny/build-tools": "6.6.0-alpha.2",
37
37
  "rimraf": "6.1.3",
38
38
  "typescript": "7.0.2"
39
39
  },
package/startKey.d.ts CHANGED
@@ -1,6 +1,2 @@
1
1
  import type { IStorageListParams } from "@webiny/api-audit-logs/storage/abstractions/Storage.js";
2
- export interface ICreateStartKeyResult {
3
- PK: string;
4
- SK: string;
5
- }
6
- export declare const createStartKey: (params: Pick<IStorageListParams, "after">) => ICreateStartKeyResult | undefined;
2
+ export declare const createStartKey: (params: Pick<IStorageListParams, "after">) => Record<string, unknown> | undefined;
package/startKey.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"startKey.js","sources":["../src/startKey.ts"],"sourcesContent":["import type { IStorageListParams } from \"@webiny/api-audit-logs/storage/abstractions/Storage.js\";\nimport { fetchCursor } from \"~/cursorSchema.js\";\n\nexport interface ICreateStartKeyResult {\n PK: string;\n SK: string;\n}\n\nexport const createStartKey = (\n params: Pick<IStorageListParams, \"after\">\n): ICreateStartKeyResult | undefined => {\n if (!params.after) {\n return undefined;\n }\n return fetchCursor(params.after);\n};\n"],"names":["createStartKey","params","fetchCursor"],"mappings":";AAQO,MAAMA,iBAAiB,CAC1BC;IAEA,IAAI,CAACA,OAAO,KAAK,EACb;IAEJ,OAAOC,YAAYD,OAAO,KAAK;AACnC"}
1
+ {"version":3,"file":"startKey.js","sources":["../src/startKey.ts"],"sourcesContent":["import type { IStorageListParams } from \"@webiny/api-audit-logs/storage/abstractions/Storage.js\";\nimport { fetchCursor } from \"~/cursorSchema.js\";\n\nexport const createStartKey = (\n params: Pick<IStorageListParams, \"after\">\n): Record<string, unknown> | undefined => {\n if (!params.after) {\n return undefined;\n }\n return fetchCursor(params.after);\n};\n"],"names":["createStartKey","params","fetchCursor"],"mappings":";AAGO,MAAMA,iBAAiB,CAC1BC;IAEA,IAAI,CAACA,OAAO,KAAK,EACb;IAEJ,OAAOC,YAAYD,OAAO,KAAK;AACnC"}