postquant 0.4.0 → 0.4.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.
- package/README.md +15 -0
- package/dist/commands/scan.d.ts.map +1 -1
- package/dist/commands/scan.js +25 -3
- package/dist/commands/scan.js.map +1 -1
- package/dist/scanner/openssl.d.ts.map +1 -1
- package/dist/scanner/openssl.js +6 -0
- package/dist/scanner/openssl.js.map +1 -1
- package/dist/scanner/tls.d.ts +2 -0
- package/dist/scanner/tls.d.ts.map +1 -1
- package/dist/scanner/tls.js +55 -30
- package/dist/scanner/tls.js.map +1 -1
- package/dist/utils/validate.d.ts +10 -0
- package/dist/utils/validate.d.ts.map +1 -0
- package/dist/utils/validate.js +40 -0
- package/dist/utils/validate.js.map +1 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -47,6 +47,8 @@ We scanned popular open-source frameworks with PostQuant v0.3.0:
|
|
|
47
47
|
|
|
48
48
|
> Scanned with PostQuant v0.3.0 on March 3, 2026. Run `npx postquant analyze <path>` to scan your own projects.
|
|
49
49
|
|
|
50
|
+
> **Note:** Detection uses pattern matching, not AST analysis. Results may miss obfuscated or indirect crypto usage.
|
|
51
|
+
|
|
50
52
|
## Package Scan Results
|
|
51
53
|
|
|
52
54
|
We scanned popular npm and PyPI packages. Context-aware risk assessment separates real threats from protocol compliance:
|
|
@@ -296,6 +298,19 @@ npm run dev -- analyze ./src # Code scan from source
|
|
|
296
298
|
|
|
297
299
|
See [docs/ROADMAP.md](docs/ROADMAP.md) for details.
|
|
298
300
|
|
|
301
|
+
## Limitations
|
|
302
|
+
|
|
303
|
+
PostQuant's code scanner uses regex-based pattern matching. This is fast and works well for common crypto usage, but has known blind spots:
|
|
304
|
+
|
|
305
|
+
- **No AST parsing** — Obfuscated, aliased, or dynamically constructed crypto calls may not be detected.
|
|
306
|
+
- **No cross-function data flow** — If a key size is defined in one function and used in another, the scanner won't correlate them.
|
|
307
|
+
- **No runtime analysis** — Crypto operations triggered by configuration files, environment variables, or runtime logic are not visible.
|
|
308
|
+
- **Key size extraction is best-effort** — Some patterns detect the algorithm but not the key size, especially for indirect parameter passing.
|
|
309
|
+
|
|
310
|
+
Context-aware risk assessment (v0.3.0+) mitigates some false positives but cannot eliminate them entirely. When in doubt, PostQuant errs on the side of flagging (false positives over false negatives).
|
|
311
|
+
|
|
312
|
+
For the TLS scanner, detection accuracy depends on the server's TLS configuration and the local OpenSSL version. Hybrid PQC detection requires OpenSSL 3.5+.
|
|
313
|
+
|
|
299
314
|
## Contributing
|
|
300
315
|
|
|
301
316
|
See [CONTRIBUTING.md](CONTRIBUTING.md).
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"scan.d.ts","sourceRoot":"","sources":["../../src/commands/scan.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"scan.d.ts","sourceRoot":"","sources":["../../src/commands/scan.ts"],"names":[],"mappings":"AAQA,OAAO,KAAK,EAAgB,WAAW,EAAa,MAAM,mBAAmB,CAAC;AA4C9E,wBAAsB,WAAW,CAC/B,KAAK,EAAE,MAAM,EAAE,EACf,OAAO,EAAE,WAAW,GACnB,OAAO,CAAC,MAAM,CAAC,CAkEjB"}
|
package/dist/commands/scan.js
CHANGED
|
@@ -5,19 +5,35 @@ import { classify } from '../scanner/classifier.js';
|
|
|
5
5
|
import { grade, shouldFailForGrade } from '../scanner/grader.js';
|
|
6
6
|
import { formatTerminal } from '../output/terminal.js';
|
|
7
7
|
import { formatJson } from '../output/json.js';
|
|
8
|
+
import { validateHostname, validatePort, validateFilePath } from '../utils/validate.js';
|
|
8
9
|
function parseHost(input) {
|
|
9
10
|
const lastColon = input.lastIndexOf(':');
|
|
10
11
|
if (lastColon === -1) {
|
|
12
|
+
if (!validateHostname(input))
|
|
13
|
+
return null;
|
|
11
14
|
return { host: input, port: 443 };
|
|
12
15
|
}
|
|
13
16
|
const portStr = input.slice(lastColon + 1);
|
|
14
17
|
const port = parseInt(portStr, 10);
|
|
15
|
-
|
|
18
|
+
// If what follows the last colon doesn't look like a port number at all,
|
|
19
|
+
// treat the whole input as a hostname (e.g. IPv6 without brackets)
|
|
20
|
+
if (isNaN(port) || portStr.length === 0) {
|
|
21
|
+
if (!validateHostname(input))
|
|
22
|
+
return null;
|
|
16
23
|
return { host: input, port: 443 };
|
|
17
24
|
}
|
|
18
|
-
|
|
25
|
+
// Port was parsed as a number — validate it strictly
|
|
26
|
+
if (!validatePort(port))
|
|
27
|
+
return null;
|
|
28
|
+
const host = input.slice(0, lastColon);
|
|
29
|
+
if (!validateHostname(host))
|
|
30
|
+
return null;
|
|
31
|
+
return { host, port };
|
|
19
32
|
}
|
|
20
33
|
function readHostsFile(filePath) {
|
|
34
|
+
if (!validateFilePath(filePath)) {
|
|
35
|
+
throw new Error(`Invalid file path: contains prohibited characters`);
|
|
36
|
+
}
|
|
21
37
|
const content = readFileSync(filePath, 'utf-8');
|
|
22
38
|
return content
|
|
23
39
|
.split('\n')
|
|
@@ -43,7 +59,13 @@ export async function scanCommand(hosts, options) {
|
|
|
43
59
|
const results = [];
|
|
44
60
|
let hadErrors = false;
|
|
45
61
|
for (const input of allHostInputs) {
|
|
46
|
-
const
|
|
62
|
+
const parsed = parseHost(input);
|
|
63
|
+
if (!parsed) {
|
|
64
|
+
hadErrors = true;
|
|
65
|
+
console.error(chalk.red(`\nInvalid host: ${input} — contains prohibited characters or invalid port`));
|
|
66
|
+
continue;
|
|
67
|
+
}
|
|
68
|
+
const { host, port } = parsed;
|
|
47
69
|
try {
|
|
48
70
|
const scanResult = await scanHost(host, port, options.timeout);
|
|
49
71
|
const classified = classify(scanResult);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"scan.js","sourceRoot":"","sources":["../../src/commands/scan.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AACvC,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,EAAE,QAAQ,EAAE,MAAM,mBAAmB,CAAC;AAC7C,OAAO,EAAE,QAAQ,EAAE,MAAM,0BAA0B,CAAC;AACpD,OAAO,EAAE,KAAK,EAAE,kBAAkB,EAAE,MAAM,sBAAsB,CAAC;AACjE,OAAO,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AACvD,OAAO,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;
|
|
1
|
+
{"version":3,"file":"scan.js","sourceRoot":"","sources":["../../src/commands/scan.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"openssl.d.ts","sourceRoot":"","sources":["../../src/scanner/openssl.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"openssl.d.ts","sourceRoot":"","sources":["../../src/scanner/openssl.ts"],"names":[],"mappings":"AAIA,MAAM,WAAW,kBAAkB;IACjC,wDAAwD;IACxD,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IACrB,2EAA2E;IAC3E,WAAW,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI,CAAC;CAClE;AAUD;;;GAGG;AACH,wBAAsB,YAAY,IAAI,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAiB3D;AAED;;;GAGG;AACH,wBAAsB,gBAAgB,CACpC,IAAI,EAAE,MAAM,EACZ,IAAI,EAAE,MAAM,GACX,OAAO,CAAC,kBAAkB,CAAC,CAgC7B;AAED;;GAEG;AACH,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,MAAM,GAAG,kBAAkB,CAyBrE"}
|
package/dist/scanner/openssl.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { execFile } from 'node:child_process';
|
|
2
2
|
import { access, constants } from 'node:fs/promises';
|
|
3
|
+
import { validateHostname, validatePort } from '../utils/validate.js';
|
|
3
4
|
const OPENSSL_CANDIDATES = [
|
|
4
5
|
'openssl',
|
|
5
6
|
'/opt/homebrew/opt/openssl@3/bin/openssl',
|
|
@@ -34,6 +35,9 @@ export async function findOpenssl3() {
|
|
|
34
35
|
*/
|
|
35
36
|
export async function probeWithOpenssl(host, port) {
|
|
36
37
|
const nullResult = { group: null, peerTempKey: null };
|
|
38
|
+
if (!validateHostname(host) || !validatePort(port)) {
|
|
39
|
+
return nullResult;
|
|
40
|
+
}
|
|
37
41
|
let opensslBin;
|
|
38
42
|
try {
|
|
39
43
|
opensslBin = await findOpenssl3();
|
|
@@ -50,6 +54,8 @@ export async function probeWithOpenssl(host, port) {
|
|
|
50
54
|
's_client',
|
|
51
55
|
'-connect',
|
|
52
56
|
`${host}:${port}`,
|
|
57
|
+
'-servername',
|
|
58
|
+
host,
|
|
53
59
|
]);
|
|
54
60
|
}
|
|
55
61
|
catch {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"openssl.js","sourceRoot":"","sources":["../../src/scanner/openssl.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,oBAAoB,CAAC;AAC9C,OAAO,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;
|
|
1
|
+
{"version":3,"file":"openssl.js","sourceRoot":"","sources":["../../src/scanner/openssl.ts"],"names":[],"mappings":"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"}
|
package/dist/scanner/tls.d.ts
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
1
|
import type { TlsScanResult } from '../types/index.js';
|
|
2
|
+
/** @internal — for testing only */
|
|
3
|
+
export declare function _resetOpensslWarning(): void;
|
|
2
4
|
export declare function scanHost(host: string, port: number, timeout: number): Promise<TlsScanResult>;
|
|
3
5
|
//# sourceMappingURL=tls.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tls.d.ts","sourceRoot":"","sources":["../../src/scanner/tls.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"tls.d.ts","sourceRoot":"","sources":["../../src/scanner/tls.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAC;AAMvD,mCAAmC;AACnC,wBAAgB,oBAAoB,IAAI,IAAI,CAE3C;AAED,wBAAsB,QAAQ,CAC5B,IAAI,EAAE,MAAM,EACZ,IAAI,EAAE,MAAM,EACZ,OAAO,EAAE,MAAM,GACd,OAAO,CAAC,aAAa,CAAC,CA+DxB"}
|
package/dist/scanner/tls.js
CHANGED
|
@@ -1,44 +1,68 @@
|
|
|
1
1
|
import tls from 'node:tls';
|
|
2
|
-
import
|
|
2
|
+
import chalk from 'chalk';
|
|
3
|
+
import { probeWithOpenssl, findOpenssl3 } from './openssl.js';
|
|
4
|
+
import { validateHostname, validatePort } from '../utils/validate.js';
|
|
5
|
+
let opensslWarningShown = false;
|
|
6
|
+
/** @internal — for testing only */
|
|
7
|
+
export function _resetOpensslWarning() {
|
|
8
|
+
opensslWarningShown = false;
|
|
9
|
+
}
|
|
3
10
|
export async function scanHost(host, port, timeout) {
|
|
11
|
+
if (!validateHostname(host)) {
|
|
12
|
+
throw new Error(`Invalid hostname: "${host}" contains prohibited characters`);
|
|
13
|
+
}
|
|
14
|
+
if (!validatePort(port)) {
|
|
15
|
+
throw new Error(`Invalid port: ${port} must be an integer between 1 and 65535`);
|
|
16
|
+
}
|
|
4
17
|
const result = await connectTls(host, port, timeout);
|
|
5
|
-
//
|
|
6
|
-
|
|
18
|
+
// Check OpenSSL availability and warn if missing
|
|
19
|
+
let opensslAvailable = false;
|
|
7
20
|
try {
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
21
|
+
opensslAvailable = (await findOpenssl3()) !== null;
|
|
22
|
+
}
|
|
23
|
+
catch {
|
|
24
|
+
// findOpenssl3 failed entirely
|
|
25
|
+
}
|
|
26
|
+
if (!opensslAvailable && !opensslWarningShown) {
|
|
27
|
+
opensslWarningShown = true;
|
|
28
|
+
process.stderr.write(chalk.yellow('Warning: OpenSSL 3.5+ not found — PQC key exchange detection unavailable\n'));
|
|
29
|
+
}
|
|
30
|
+
// Enrich with openssl probe for PQC detection
|
|
31
|
+
if (opensslAvailable) {
|
|
32
|
+
try {
|
|
33
|
+
const probe = await probeWithOpenssl(host, port);
|
|
34
|
+
if (probe.group) {
|
|
35
|
+
const groupUpper = probe.group.toUpperCase();
|
|
36
|
+
const isPqc = groupUpper.includes('KYBER') ||
|
|
37
|
+
groupUpper.includes('MLKEM') ||
|
|
38
|
+
groupUpper.includes('ML-KEM');
|
|
39
|
+
if (isPqc) {
|
|
40
|
+
result.ephemeralKeyInfo = {
|
|
41
|
+
type: 'KEM',
|
|
42
|
+
name: probe.group,
|
|
43
|
+
size: 0,
|
|
44
|
+
};
|
|
45
|
+
}
|
|
46
|
+
else if (!result.ephemeralKeyInfo) {
|
|
47
|
+
result.ephemeralKeyInfo = {
|
|
48
|
+
type: 'ECDH',
|
|
49
|
+
name: probe.group,
|
|
50
|
+
size: 0,
|
|
51
|
+
};
|
|
52
|
+
}
|
|
20
53
|
}
|
|
21
|
-
else if (!result.ephemeralKeyInfo) {
|
|
22
|
-
// Classical group detected by openssl, Node.js had nothing
|
|
54
|
+
else if (!result.ephemeralKeyInfo && probe.peerTempKey) {
|
|
23
55
|
result.ephemeralKeyInfo = {
|
|
24
|
-
type:
|
|
25
|
-
name: probe.
|
|
26
|
-
size:
|
|
56
|
+
type: probe.peerTempKey.type,
|
|
57
|
+
name: probe.peerTempKey.name,
|
|
58
|
+
size: probe.peerTempKey.size,
|
|
27
59
|
};
|
|
28
60
|
}
|
|
29
61
|
}
|
|
30
|
-
|
|
31
|
-
//
|
|
32
|
-
result.ephemeralKeyInfo = {
|
|
33
|
-
type: probe.peerTempKey.type,
|
|
34
|
-
name: probe.peerTempKey.name,
|
|
35
|
-
size: probe.peerTempKey.size,
|
|
36
|
-
};
|
|
62
|
+
catch {
|
|
63
|
+
// openssl probe failed — keep Node.js data as-is
|
|
37
64
|
}
|
|
38
65
|
}
|
|
39
|
-
catch {
|
|
40
|
-
// openssl probe failed — keep Node.js data as-is
|
|
41
|
-
}
|
|
42
66
|
return result;
|
|
43
67
|
}
|
|
44
68
|
function connectTls(host, port, timeout) {
|
|
@@ -46,6 +70,7 @@ function connectTls(host, port, timeout) {
|
|
|
46
70
|
const socket = tls.connect({
|
|
47
71
|
host,
|
|
48
72
|
port,
|
|
73
|
+
servername: host,
|
|
49
74
|
rejectUnauthorized: false,
|
|
50
75
|
timeout,
|
|
51
76
|
}, () => {
|
package/dist/scanner/tls.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tls.js","sourceRoot":"","sources":["../../src/scanner/tls.ts"],"names":[],"mappings":"AAAA,OAAO,GAAG,MAAM,UAAU,CAAC;
|
|
1
|
+
{"version":3,"file":"tls.js","sourceRoot":"","sources":["../../src/scanner/tls.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Validate a hostname for safety.
|
|
3
|
+
* Not full DNS validation — rejects obviously malicious input.
|
|
4
|
+
*/
|
|
5
|
+
export declare function validateHostname(hostname: string): boolean;
|
|
6
|
+
/** Validate a port number. Must be an integer 1–65535. */
|
|
7
|
+
export declare function validatePort(port: number): boolean;
|
|
8
|
+
/** Validate a file path. Only rejects null bytes — fs errors handle the rest. */
|
|
9
|
+
export declare function validateFilePath(filePath: string): boolean;
|
|
10
|
+
//# sourceMappingURL=validate.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"validate.d.ts","sourceRoot":"","sources":["../../src/utils/validate.ts"],"names":[],"mappings":"AAQA;;;GAGG;AACH,wBAAgB,gBAAgB,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAU1D;AAED,0DAA0D;AAC1D,wBAAgB,YAAY,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAGlD;AAED,iFAAiF;AACjF,wBAAgB,gBAAgB,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAI1D"}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Characters that must never appear in a hostname.
|
|
3
|
+
* Covers shell metacharacters, whitespace, and null bytes.
|
|
4
|
+
*/
|
|
5
|
+
const HOSTNAME_DENY_RE = /[\s\0;`$|&<>(){}\[\]!#'"\\]/;
|
|
6
|
+
/** Same deny list but without brackets — used for IPv6 inner content. */
|
|
7
|
+
const IPV6_INNER_DENY_RE = /[\s\0;`$|&<>(){}!#'"\\]/;
|
|
8
|
+
/**
|
|
9
|
+
* Validate a hostname for safety.
|
|
10
|
+
* Not full DNS validation — rejects obviously malicious input.
|
|
11
|
+
*/
|
|
12
|
+
export function validateHostname(hostname) {
|
|
13
|
+
if (hostname.length === 0 || hostname.length > 253)
|
|
14
|
+
return false;
|
|
15
|
+
// Handle bracketed IPv6 before the general deny regex (which includes brackets)
|
|
16
|
+
if (hostname.startsWith('[') && hostname.endsWith(']')) {
|
|
17
|
+
const inner = hostname.slice(1, -1);
|
|
18
|
+
if (inner.length === 0)
|
|
19
|
+
return false;
|
|
20
|
+
return !IPV6_INNER_DENY_RE.test(inner);
|
|
21
|
+
}
|
|
22
|
+
if (HOSTNAME_DENY_RE.test(hostname))
|
|
23
|
+
return false;
|
|
24
|
+
return true;
|
|
25
|
+
}
|
|
26
|
+
/** Validate a port number. Must be an integer 1–65535. */
|
|
27
|
+
export function validatePort(port) {
|
|
28
|
+
if (!Number.isInteger(port))
|
|
29
|
+
return false;
|
|
30
|
+
return port >= 1 && port <= 65535;
|
|
31
|
+
}
|
|
32
|
+
/** Validate a file path. Only rejects null bytes — fs errors handle the rest. */
|
|
33
|
+
export function validateFilePath(filePath) {
|
|
34
|
+
if (filePath.length === 0)
|
|
35
|
+
return false;
|
|
36
|
+
if (filePath.includes('\0'))
|
|
37
|
+
return false;
|
|
38
|
+
return true;
|
|
39
|
+
}
|
|
40
|
+
//# sourceMappingURL=validate.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"validate.js","sourceRoot":"","sources":["../../src/utils/validate.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,MAAM,gBAAgB,GAAG,6BAA6B,CAAC;AACvD,yEAAyE;AACzE,MAAM,kBAAkB,GAAG,yBAAyB,CAAC;AAErD;;;GAGG;AACH,MAAM,UAAU,gBAAgB,CAAC,QAAgB;IAC/C,IAAI,QAAQ,CAAC,MAAM,KAAK,CAAC,IAAI,QAAQ,CAAC,MAAM,GAAG,GAAG;QAAE,OAAO,KAAK,CAAC;IACjE,gFAAgF;IAChF,IAAI,QAAQ,CAAC,UAAU,CAAC,GAAG,CAAC,IAAI,QAAQ,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAC;QACvD,MAAM,KAAK,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;QACpC,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC;YAAE,OAAO,KAAK,CAAC;QACrC,OAAO,CAAC,kBAAkB,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IACzC,CAAC;IACD,IAAI,gBAAgB,CAAC,IAAI,CAAC,QAAQ,CAAC;QAAE,OAAO,KAAK,CAAC;IAClD,OAAO,IAAI,CAAC;AACd,CAAC;AAED,0DAA0D;AAC1D,MAAM,UAAU,YAAY,CAAC,IAAY;IACvC,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,IAAI,CAAC;QAAE,OAAO,KAAK,CAAC;IAC1C,OAAO,IAAI,IAAI,CAAC,IAAI,IAAI,IAAI,KAAK,CAAC;AACpC,CAAC;AAED,iFAAiF;AACjF,MAAM,UAAU,gBAAgB,CAAC,QAAgB;IAC/C,IAAI,QAAQ,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,KAAK,CAAC;IACxC,IAAI,QAAQ,CAAC,QAAQ,CAAC,IAAI,CAAC;QAAE,OAAO,KAAK,CAAC;IAC1C,OAAO,IAAI,CAAC;AACd,CAAC"}
|