marcattacks 2.5.0 → 2.7.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 (100) hide show
  1. package/README.md +82 -2
  2. package/dist/attacker.d.ts.map +1 -1
  3. package/dist/attacker.js +10 -0
  4. package/dist/attacker.js.map +1 -1
  5. package/dist/command.js +1 -0
  6. package/dist/command.js.map +1 -1
  7. package/dist/fix/binds.d.ts +5 -0
  8. package/dist/fix/binds.d.ts.map +1 -0
  9. package/dist/fix/binds.js +82 -0
  10. package/dist/fix/binds.js.map +1 -0
  11. package/dist/fix/conditions.d.ts +5 -0
  12. package/dist/fix/conditions.d.ts.map +1 -0
  13. package/dist/fix/conditions.js +111 -0
  14. package/dist/fix/conditions.js.map +1 -0
  15. package/dist/fix/fixes.d.ts +7 -0
  16. package/dist/fix/fixes.d.ts.map +1 -0
  17. package/dist/fix/fixes.js +478 -0
  18. package/dist/fix/fixes.js.map +1 -0
  19. package/dist/fix/index.d.ts +12 -0
  20. package/dist/fix/index.d.ts.map +1 -0
  21. package/dist/fix/index.js +40 -0
  22. package/dist/fix/index.js.map +1 -0
  23. package/dist/fix/parser.d.ts +25 -0
  24. package/dist/fix/parser.d.ts.map +1 -0
  25. package/dist/fix/parser.js +156 -0
  26. package/dist/fix/parser.js.map +1 -0
  27. package/dist/fix/path.d.ts +23 -0
  28. package/dist/fix/path.d.ts.map +1 -0
  29. package/dist/fix/path.js +351 -0
  30. package/dist/fix/path.js.map +1 -0
  31. package/dist/fix/signal.d.ts +2 -0
  32. package/dist/fix/signal.d.ts.map +1 -0
  33. package/dist/fix/signal.js +5 -0
  34. package/dist/fix/signal.js.map +1 -0
  35. package/dist/fix/util.d.ts +6 -0
  36. package/dist/fix/util.d.ts.map +1 -0
  37. package/dist/fix/util.js +133 -0
  38. package/dist/fix/util.js.map +1 -0
  39. package/dist/input/alephseq.d.ts.map +1 -1
  40. package/dist/input/alephseq.js +18 -5
  41. package/dist/input/alephseq.js.map +1 -1
  42. package/dist/input/fastxml.d.ts +3 -0
  43. package/dist/input/fastxml.d.ts.map +1 -0
  44. package/dist/input/fastxml.js +134 -0
  45. package/dist/input/fastxml.js.map +1 -0
  46. package/dist/input/xml.d.ts.map +1 -1
  47. package/dist/input/xml.js +4 -2
  48. package/dist/input/xml.js.map +1 -1
  49. package/dist/marcmap.d.ts.map +1 -1
  50. package/dist/marcmap.js +15 -3
  51. package/dist/marcmap.js.map +1 -1
  52. package/dist/output/alephseq.d.ts.map +1 -1
  53. package/dist/output/alephseq.js +29 -5
  54. package/dist/output/alephseq.js.map +1 -1
  55. package/dist/output/null.d.ts +3 -0
  56. package/dist/output/null.d.ts.map +1 -0
  57. package/dist/output/null.js +13 -0
  58. package/dist/output/null.js.map +1 -0
  59. package/dist/output/xml.d.ts.map +1 -1
  60. package/dist/output/xml.js +27 -0
  61. package/dist/output/xml.js.map +1 -1
  62. package/dist/stream/framer.d.ts.map +1 -0
  63. package/dist/stream/framer.js.map +1 -0
  64. package/dist/stream/worker-pool-str.d.ts.map +1 -0
  65. package/dist/stream/worker-pool-str.js.map +1 -0
  66. package/dist/stream/worker-pool.d.ts +10 -0
  67. package/dist/stream/worker-pool.d.ts.map +1 -0
  68. package/dist/stream/worker-pool.js +206 -0
  69. package/dist/stream/worker-pool.js.map +1 -0
  70. package/dist/transform/fix.d.ts +16 -0
  71. package/dist/transform/fix.d.ts.map +1 -0
  72. package/dist/transform/fix.js +46 -0
  73. package/dist/transform/fix.js.map +1 -0
  74. package/dist/transform/jsonata.d.ts +4 -0
  75. package/dist/transform/jsonata.d.ts.map +1 -1
  76. package/dist/transform/jsonata.js +40 -44
  77. package/dist/transform/jsonata.js.map +1 -1
  78. package/dist/transform/marcinrdf.d.ts +1 -1
  79. package/dist/transform/marcinrdf.d.ts.map +1 -1
  80. package/dist/transform/marcinrdf.js +16 -3
  81. package/dist/transform/marcinrdf.js.map +1 -1
  82. package/dist/util/marc_record.d.ts +19 -0
  83. package/dist/util/marc_record.d.ts.map +1 -0
  84. package/dist/util/marc_record.js +16 -0
  85. package/dist/util/marc_record.js.map +1 -0
  86. package/dist/worker-str.d.ts.map +1 -0
  87. package/dist/worker-str.js.map +1 -0
  88. package/dist/worker.d.ts +2 -0
  89. package/dist/worker.d.ts.map +1 -0
  90. package/dist/worker.js +33 -0
  91. package/dist/worker.js.map +1 -0
  92. package/package.json +4 -1
  93. package/dist/output/mulitipart.d.ts +0 -7
  94. package/dist/output/mulitipart.d.ts.map +0 -1
  95. package/dist/output/mulitipart.js +0 -53
  96. package/dist/output/mulitipart.js.map +0 -1
  97. package/dist/output/text.d.ts +0 -6
  98. package/dist/output/text.d.ts.map +0 -1
  99. package/dist/output/text.js +0 -34
  100. package/dist/output/text.js.map +0 -1
package/dist/worker.js ADDED
@@ -0,0 +1,33 @@
1
+ // Worker thread: runs a parallelizable map (e.g. jsonata, fix) on batches of
2
+ // records. The heavy per-record work (jsonata evaluate / fix chain) runs here;
3
+ // the main thread does I/O, parsing and serialization.
4
+ //
5
+ // Protocol:
6
+ // main -> worker : { seq, batch: record[] }
7
+ // worker -> main : { ready: true } (once, on startup)
8
+ // { seq, mapped: (record|null)[] } (null = rejected)
9
+ // { seq, error: string }
10
+ import { parentPort, workerData } from 'node:worker_threads';
11
+ import { loadPlugin } from './plugin-loader.js';
12
+ import { REJECT } from './fix/signal.js';
13
+ const { map, param } = workerData;
14
+ const mod = await loadPlugin(map, 'transform');
15
+ if (typeof mod.createMapper !== 'function') {
16
+ throw new Error(`map '${map}' is not parallelizable (no createMapper)`);
17
+ }
18
+ const mapper = await mod.createMapper(param ?? {});
19
+ parentPort.postMessage({ ready: true });
20
+ parentPort.on('message', async (msg) => {
21
+ try {
22
+ const mapped = [];
23
+ for (const rec of msg.batch) {
24
+ const r = await mapper(rec);
25
+ mapped.push(r === REJECT ? null : r); // null marks a dropped record
26
+ }
27
+ parentPort.postMessage({ seq: msg.seq, mapped });
28
+ }
29
+ catch (err) {
30
+ parentPort.postMessage({ seq: msg.seq, error: err?.message ?? String(err) });
31
+ }
32
+ });
33
+ //# sourceMappingURL=worker.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"worker.js","sourceRoot":"","sources":["../src/worker.ts"],"names":[],"mappings":"AAAA,6EAA6E;AAC7E,+EAA+E;AAC/E,uDAAuD;AACvD,EAAE;AACF,YAAY;AACZ,8CAA8C;AAC9C,gFAAgF;AAChF,+EAA+E;AAC/E,4CAA4C;AAC5C,OAAO,EAAE,UAAU,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAC;AAC7D,OAAO,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAC;AAChD,OAAO,EAAE,MAAM,EAAE,MAAM,iBAAiB,CAAC;AAEzC,MAAM,EAAE,GAAG,EAAE,KAAK,EAAE,GAAG,UAAyC,CAAC;AAEjE,MAAM,GAAG,GAAG,MAAM,UAAU,CAAC,GAAG,EAAE,WAAW,CAAC,CAAC;AAC/C,IAAI,OAAO,GAAG,CAAC,YAAY,KAAK,UAAU,EAAE,CAAC;IACzC,MAAM,IAAI,KAAK,CAAC,QAAQ,GAAG,2CAA2C,CAAC,CAAC;AAC5E,CAAC;AACD,MAAM,MAAM,GAAuB,MAAM,GAAG,CAAC,YAAY,CAAC,KAAK,IAAI,EAAE,CAAC,CAAC;AAEvE,UAAW,CAAC,WAAW,CAAC,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;AAEzC,UAAW,CAAC,EAAE,CAAC,SAAS,EAAE,KAAK,EAAE,GAAkC,EAAE,EAAE;IACnE,IAAI,CAAC;QACD,MAAM,MAAM,GAAU,EAAE,CAAC;QACzB,KAAK,MAAM,GAAG,IAAI,GAAG,CAAC,KAAK,EAAE,CAAC;YAC1B,MAAM,CAAC,GAAG,MAAM,MAAM,CAAC,GAAG,CAAC,CAAC;YAC5B,MAAM,CAAC,IAAI,CAAC,CAAC,KAAK,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAG,8BAA8B;QAC1E,CAAC;QACD,UAAW,CAAC,WAAW,CAAC,EAAE,GAAG,EAAE,GAAG,CAAC,GAAG,EAAE,MAAM,EAAE,CAAC,CAAC;IACtD,CAAC;IAAC,OAAO,GAAQ,EAAE,CAAC;QAChB,UAAW,CAAC,WAAW,CAAC,EAAE,GAAG,EAAE,GAAG,CAAC,GAAG,EAAE,KAAK,EAAE,GAAG,EAAE,OAAO,IAAI,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;IAClF,CAAC;AACL,CAAC,CAAC,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "marcattacks",
3
- "version": "2.5.0",
3
+ "version": "2.7.0",
4
4
  "description": "A powerful streaming MARC21 to RDF converter with JSONata transformation and S3 support.",
5
5
  "keywords": [
6
6
  "marc21",
@@ -36,6 +36,9 @@
36
36
  "demo:jsonl": "npx marcattacks --to jsonl data/sample.xml",
37
37
  "demo:rdf": "npx marcattacks --to rdf --map marc2rdf data/sample.xml",
38
38
  "demo:jsonld": "npx marcattacks --to jsonl --param fix=./demo/marc2rdf.jsonata data/sample.xml",
39
+ "demo:fix": "npx marcattacks --to jsonl --map fix --param fix=./demo/example.fix data/sample.xml",
40
+ "demo:fix:rdf": "npx marcattacks --to jsonl --map fix --param fix=./demo/marc2rdf.fix data/sample.xml",
41
+ "demo:workers": "npx marcattacks --to jsonl --param fix=./demo/marc2rdf.jsonata --workers 4 --info data/sample.xml",
39
42
  "demo:biblio:one": "npx marcattacks --from json --info ./data/biblio.json",
40
43
  "demo:biblio:all": "npx marcattacks --from jsonl --info https://biblio.ugent.be/exports/publications.json",
41
44
  "demo:parquet": " npx marcattacks ./data/sample.xml --to parquet --map avram --param schema=./demo/avram.schema --info --out ./data/avram.parquet",
@@ -1,7 +0,0 @@
1
- import { Transform } from 'stream';
2
- export interface OutputMultipartOptions {
3
- header?: string;
4
- delimiter?: string;
5
- }
6
- export declare function transform(opts?: OutputMultipartOptions): Promise<Transform>;
7
- //# sourceMappingURL=mulitipart.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"mulitipart.d.ts","sourceRoot":"","sources":["../../src/output/mulitipart.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,QAAQ,CAAC;AAKnC,MAAM,WAAW,sBAAsB;IACnC,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,SAAS,CAAC,EAAE,MAAM,CAAC;CACtB;AAED,wBAAsB,SAAS,CAAC,IAAI,GAAE,sBAA2B,GAAI,OAAO,CAAC,SAAS,CAAC,CAyDtF"}
@@ -1,53 +0,0 @@
1
- import { Transform } from 'stream';
2
- import log4js from 'log4js';
3
- const logger = log4js.getLogger();
4
- export async function transform(opts = {}) {
5
- let header = opts.header ? opts.header :
6
- "Content-Type: multipart/mixed; boundary=\"marcattacks\"";
7
- let delimiter = opts.delimiter ? opts.delimiter : "--marcattacks";
8
- let isFirst = true;
9
- return new Transform({
10
- objectMode: true,
11
- transform(data, _encoding, callback) {
12
- if (Object.keys(data).length == 0) {
13
- logger.debug('skipped empty record');
14
- callback();
15
- return;
16
- }
17
- let output = "";
18
- if (isFirst) {
19
- output += header + "\n\n";
20
- isFirst = false;
21
- }
22
- else {
23
- output += delimiter + "\n";
24
- }
25
- let fields = [];
26
- let sortedKeys = Object.keys(data).sort();
27
- sortedKeys.forEach(key => {
28
- if (Array.isArray(data[key])) {
29
- fields.push(`ARRAY[${data[key].length}]`);
30
- }
31
- else if (typeof data[key] === 'object') {
32
- fields.push(`HASH[${Object.keys(data[key]).length}]`);
33
- }
34
- else {
35
- fields.push(data[key]);
36
- }
37
- });
38
- output += fields.join(" ") + "\n";
39
- logger.trace(`adding ${output.length} bytes`);
40
- callback(null, output);
41
- },
42
- flush(callback) {
43
- logger.debug('flush reached');
44
- if (!isFirst) {
45
- let output = delimiter + "--\n";
46
- logger.trace(`adding ${output.length} bytes`);
47
- this.push(output);
48
- }
49
- callback();
50
- }
51
- });
52
- }
53
- //# sourceMappingURL=mulitipart.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"mulitipart.js","sourceRoot":"","sources":["../../src/output/mulitipart.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,QAAQ,CAAC;AACnC,OAAO,MAAM,MAAM,QAAQ,CAAC;AAE5B,MAAM,MAAM,GAAG,MAAM,CAAC,SAAS,EAAE,CAAC;AAOlC,MAAM,CAAC,KAAK,UAAU,SAAS,CAAC,OAA+B,EAAE;IAC7D,IAAI,MAAM,GAAY,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;QAC7C,yDAAyD,CAAC;IAC9D,IAAI,SAAS,GAAY,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,eAAe,CAAC;IAE3E,IAAI,OAAO,GAAG,IAAI,CAAC;IAEnB,OAAO,IAAI,SAAS,CAAC;QACjB,UAAU,EAAE,IAAI;QAChB,SAAS,CAAC,IAAS,EAAE,SAAS,EAAE,QAAQ;YACpC,IAAI,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,MAAM,IAAI,CAAC,EAAE,CAAC;gBAChC,MAAM,CAAC,KAAK,CAAC,sBAAsB,CAAC,CAAC;gBACrC,QAAQ,EAAE,CAAC;gBACX,OAAO;YACX,CAAC;YAED,IAAI,MAAM,GAAG,EAAE,CAAC;YAEhB,IAAI,OAAO,EAAE,CAAC;gBACV,MAAM,IAAI,MAAM,GAAG,MAAM,CAAC;gBAC1B,OAAO,GAAG,KAAK,CAAC;YACpB,CAAC;iBACI,CAAC;gBACF,MAAM,IAAI,SAAS,GAAG,IAAI,CAAC;YAC/B,CAAC;YAED,IAAI,MAAM,GAAc,EAAE,CAAC;YAE3B,IAAI,UAAU,GAAG,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,CAAC;YAE1C,UAAU,CAAC,OAAO,CAAE,GAAG,CAAC,EAAE;gBACtB,IAAI,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC;oBAC3B,MAAM,CAAC,IAAI,CAAC,SAAS,IAAI,CAAC,GAAG,CAAC,CAAC,MAAM,GAAG,CAAC,CAAC;gBAC9C,CAAC;qBACI,IAAI,OAAO,IAAI,CAAC,GAAG,CAAC,KAAK,QAAQ,EAAE,CAAC;oBACrC,MAAM,CAAC,IAAI,CAAC,QAAQ,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,MAAM,GAAG,CAAC,CAAC;gBAC1D,CAAC;qBACI,CAAC;oBACF,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC;gBAC3B,CAAC;YACL,CAAC,CAAC,CAAC;YAEH,MAAM,IAAI,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,IAAI,CAAC;YAElC,MAAM,CAAC,KAAK,CAAC,UAAU,MAAM,CAAC,MAAM,QAAQ,CAAC,CAAC;YAC9C,QAAQ,CAAC,IAAI,EAAC,MAAM,CAAC,CAAC;QAC1B,CAAC;QACD,KAAK,CAAC,QAAQ;YACV,MAAM,CAAC,KAAK,CAAC,eAAe,CAAC,CAAC;YAC9B,IAAI,CAAC,OAAO,EAAE,CAAC;gBACX,IAAI,MAAM,GAAG,SAAS,GAAG,MAAM,CAAC;gBAChC,MAAM,CAAC,KAAK,CAAC,UAAU,MAAM,CAAC,MAAM,QAAQ,CAAC,CAAC;gBAC9C,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;YACtB,CAAC;YACD,QAAQ,EAAE,CAAC;QACf,CAAC;KACJ,CAAC,CAAC;AACP,CAAC"}
@@ -1,6 +0,0 @@
1
- import { Transform } from 'stream';
2
- export interface OutputTextOptions {
3
- newline?: "yes" | "no";
4
- }
5
- export declare function transform(opts?: OutputTextOptions): Promise<Transform>;
6
- //# sourceMappingURL=text.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"text.d.ts","sourceRoot":"","sources":["../../src/output/text.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,QAAQ,CAAC;AAKnC,MAAM,WAAW,iBAAiB;IAC9B,OAAO,CAAC,EAAE,KAAK,GAAG,IAAI,CAAC;CAC1B;AAED,wBAAsB,SAAS,CAAC,IAAI,GAAE,iBAAsB,GAAI,OAAO,CAAC,SAAS,CAAC,CAkCjF"}
@@ -1,34 +0,0 @@
1
- import { Transform } from 'stream';
2
- import log4js from 'log4js';
3
- const logger = log4js.getLogger();
4
- export async function transform(opts = {}) {
5
- let newline = opts.newline ? opts.newline : "no";
6
- return new Transform({
7
- objectMode: true,
8
- transform(data, _encoding, callback) {
9
- if (Object.keys(data).length == 0) {
10
- logger.debug('skipped empty record');
11
- callback();
12
- return;
13
- }
14
- let output = "";
15
- let fields = [];
16
- let sortedKeys = Object.keys(data).sort();
17
- sortedKeys.forEach(key => {
18
- if (Array.isArray(data[key])) {
19
- fields.push(`ARRAY[${data[key].length}]`);
20
- }
21
- else if (typeof data[key] === 'object') {
22
- fields.push(`HASH[${Object.keys(data[key]).length}]`);
23
- }
24
- else {
25
- fields.push(data[key]);
26
- }
27
- });
28
- output += fields.join(delimiter) + "\n";
29
- logger.trace(`adding ${output.length} bytes`);
30
- callback(null, output);
31
- }
32
- });
33
- }
34
- //# sourceMappingURL=text.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"text.js","sourceRoot":"","sources":["../../src/output/text.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,QAAQ,CAAC;AACnC,OAAO,MAAM,MAAM,QAAQ,CAAC;AAE5B,MAAM,MAAM,GAAG,MAAM,CAAC,SAAS,EAAE,CAAC;AAMlC,MAAM,CAAC,KAAK,UAAU,SAAS,CAAC,OAA0B,EAAE;IACxD,IAAI,OAAO,GAAY,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC;IAE1D,OAAO,IAAI,SAAS,CAAC;QACjB,UAAU,EAAE,IAAI;QAChB,SAAS,CAAC,IAAS,EAAE,SAAS,EAAE,QAAQ;YACpC,IAAI,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,MAAM,IAAI,CAAC,EAAE,CAAC;gBAChC,MAAM,CAAC,KAAK,CAAC,sBAAsB,CAAC,CAAC;gBACrC,QAAQ,EAAE,CAAC;gBACX,OAAO;YACX,CAAC;YAED,IAAI,MAAM,GAAG,EAAE,CAAC;YAChB,IAAI,MAAM,GAAc,EAAE,CAAC;YAC3B,IAAI,UAAU,GAAc,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,CAAC;YAErD,UAAU,CAAC,OAAO,CAAE,GAAG,CAAC,EAAE;gBACtB,IAAI,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC;oBAC3B,MAAM,CAAC,IAAI,CAAC,SAAS,IAAI,CAAC,GAAG,CAAC,CAAC,MAAM,GAAG,CAAC,CAAC;gBAC9C,CAAC;qBACI,IAAI,OAAO,IAAI,CAAC,GAAG,CAAC,KAAK,QAAQ,EAAE,CAAC;oBACrC,MAAM,CAAC,IAAI,CAAC,QAAQ,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,MAAM,GAAG,CAAC,CAAC;gBAC1D,CAAC;qBACI,CAAC;oBACF,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC;gBAC3B,CAAC;YACL,CAAC,CAAC,CAAC;YAEH,MAAM,IAAI,MAAM,CAAC,IAAI,CAAC,SAAS,CAAC,GAAG,IAAI,CAAC;YAExC,MAAM,CAAC,KAAK,CAAC,UAAU,MAAM,CAAC,MAAM,QAAQ,CAAC,CAAC;YAC9C,QAAQ,CAAC,IAAI,EAAC,MAAM,CAAC,CAAC;QAC1B,CAAC;KACJ,CAAC,CAAC;AACP,CAAC"}