@prism-d1/cli 1.0.93 → 1.0.95
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/dist/assets/github-workflows/prism-eval-gate-kiro.yml +311 -1
- package/dist/assets/gitlab-workflows/prism-eval-gate.yml +333 -116
- package/dist/assets/infra/lib/lambda/velocity-widget.ts +1 -1
- package/dist/src/commands/bedrock-protection/scan-account.d.ts +45 -0
- package/dist/src/commands/bedrock-protection/scan-account.d.ts.map +1 -0
- package/dist/src/commands/bedrock-protection/scan-account.js +105 -0
- package/dist/src/commands/bedrock-protection/scan-account.js.map +1 -0
- package/dist/src/commands/bedrock-protection/scan-repo.d.ts +16 -0
- package/dist/src/commands/bedrock-protection/scan-repo.d.ts.map +1 -0
- package/dist/src/commands/bedrock-protection/scan-repo.js +397 -0
- package/dist/src/commands/bedrock-protection/scan-repo.js.map +1 -0
- package/dist/src/commands/bootstrapper/install-eval-harness.d.ts +5 -5
- package/dist/src/commands/bootstrapper/install-eval-harness.d.ts.map +1 -1
- package/dist/src/commands/bootstrapper/install-eval-harness.js +157 -75
- package/dist/src/commands/bootstrapper/install-eval-harness.js.map +1 -1
- package/dist/src/commands/bootstrapper/install-github-workflows.d.ts +6 -2
- package/dist/src/commands/bootstrapper/install-github-workflows.d.ts.map +1 -1
- package/dist/src/commands/bootstrapper/install-github-workflows.js +36 -48
- package/dist/src/commands/bootstrapper/install-github-workflows.js.map +1 -1
- package/dist/src/commands/bootstrapper/install-gitlab-workflows.d.ts.map +1 -1
- package/dist/src/commands/bootstrapper/install-gitlab-workflows.js +10 -1
- package/dist/src/commands/bootstrapper/install-gitlab-workflows.js.map +1 -1
- package/dist/src/utils/audit-bedrock.d.ts +24 -0
- package/dist/src/utils/audit-bedrock.d.ts.map +1 -0
- package/dist/src/utils/audit-bedrock.js +331 -0
- package/dist/src/utils/audit-bedrock.js.map +1 -0
- package/dist/src/utils/audit-iam.d.ts +6 -0
- package/dist/src/utils/audit-iam.d.ts.map +1 -0
- package/dist/src/utils/audit-iam.js +239 -0
- package/dist/src/utils/audit-iam.js.map +1 -0
- package/dist/src/utils/audit.d.ts +61 -0
- package/dist/src/utils/audit.d.ts.map +1 -0
- package/dist/src/utils/audit.js +90 -0
- package/dist/src/utils/audit.js.map +1 -0
- package/dist/src/utils/aws.d.ts +38 -0
- package/dist/src/utils/aws.d.ts.map +1 -0
- package/dist/src/utils/aws.js +61 -0
- package/dist/src/utils/aws.js.map +1 -0
- package/package.json +1 -1
- package/dist/assets/github-workflows/prism-eval-gate.yml +0 -490
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared result model and reporter for the audit commands
|
|
3
|
+
* (`scan-account`, `bedrock-protection`, `scan-repo`).
|
|
4
|
+
*
|
|
5
|
+
* This lives under utils/ rather than alongside the commands because
|
|
6
|
+
* `commands/<category>/*.js` is the command auto-discovery path -- every file in
|
|
7
|
+
* a category directory is registered as a subcommand, so a shared module placed
|
|
8
|
+
* there would appear in `--help` as a bogus command.
|
|
9
|
+
*/
|
|
10
|
+
export type Severity = 'CRITICAL' | 'HIGH' | 'MEDIUM' | 'LOW' | 'INFO';
|
|
11
|
+
/**
|
|
12
|
+
* INDETERMINATE is a first-class outcome, not an error case.
|
|
13
|
+
*
|
|
14
|
+
* A check that could not run has told you nothing, and folding it into the pass
|
|
15
|
+
* count is how an audit ends up certifying an account or repo it never
|
|
16
|
+
* examined. Cost Explorer being switched off, a missing IAM permission, or an
|
|
17
|
+
* absent gitleaks binary all produce INDETERMINATE -- never PASS.
|
|
18
|
+
*/
|
|
19
|
+
export type Status = 'PASS' | 'FAIL' | 'INDETERMINATE';
|
|
20
|
+
export interface Finding {
|
|
21
|
+
id: string;
|
|
22
|
+
/** Report grouping key; each command supplies its own headings. */
|
|
23
|
+
category: string;
|
|
24
|
+
title: string;
|
|
25
|
+
status: Status;
|
|
26
|
+
severity: Severity;
|
|
27
|
+
detail: string;
|
|
28
|
+
remediation?: string;
|
|
29
|
+
}
|
|
30
|
+
export declare const SEVERITY_ORDER: Severity[];
|
|
31
|
+
export declare function severityRank(s: Severity): number;
|
|
32
|
+
export interface ReportOptions {
|
|
33
|
+
title: string;
|
|
34
|
+
/** Rendered under the title, e.g. "Account: 1234 Region: us-west-2". */
|
|
35
|
+
subtitle: string;
|
|
36
|
+
/** Ordered [categoryKey, heading] pairs. Categories not listed are omitted. */
|
|
37
|
+
groups: Array<[string, string]>;
|
|
38
|
+
json: boolean;
|
|
39
|
+
/** Extra fields merged into the JSON envelope alongside `findings`. */
|
|
40
|
+
jsonContext?: Record<string, unknown>;
|
|
41
|
+
}
|
|
42
|
+
export declare function renderReport(findings: Finding[], opts: ReportOptions): void;
|
|
43
|
+
/** Parse and validate a --fail-on value. Returns null for "none". */
|
|
44
|
+
export declare function parseFailOn(value: string | undefined): Severity | null;
|
|
45
|
+
/**
|
|
46
|
+
* Apply --fail-on to the findings, setting process.exitCode when breached.
|
|
47
|
+
* Only FAIL counts -- an INDETERMINATE check has not established a violation,
|
|
48
|
+
* and exiting non-zero on it would make a missing permission indistinguishable
|
|
49
|
+
* from a real finding.
|
|
50
|
+
*/
|
|
51
|
+
export declare function applyFailOn(findings: Finding[], failOn: Severity | null, quiet: boolean): void;
|
|
52
|
+
export declare const FAIL_ON_OPTION: {
|
|
53
|
+
flags: string;
|
|
54
|
+
description: string;
|
|
55
|
+
default: string;
|
|
56
|
+
};
|
|
57
|
+
export declare const JSON_OPTION: {
|
|
58
|
+
flags: string;
|
|
59
|
+
description: string;
|
|
60
|
+
};
|
|
61
|
+
//# sourceMappingURL=audit.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"audit.d.ts","sourceRoot":"","sources":["../../../src/utils/audit.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,MAAM,MAAM,QAAQ,GAAG,UAAU,GAAG,MAAM,GAAG,QAAQ,GAAG,KAAK,GAAG,MAAM,CAAC;AAEvE;;;;;;;GAOG;AACH,MAAM,MAAM,MAAM,GAAG,MAAM,GAAG,MAAM,GAAG,eAAe,CAAC;AAEvD,MAAM,WAAW,OAAO;IACtB,EAAE,EAAE,MAAM,CAAC;IACX,mEAAmE;IACnE,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,QAAQ,CAAC;IACnB,MAAM,EAAE,MAAM,CAAC;IACf,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED,eAAO,MAAM,cAAc,EAAE,QAAQ,EAAkD,CAAC;AAIxF,wBAAgB,YAAY,CAAC,CAAC,EAAE,QAAQ,GAAG,MAAM,CAEhD;AAED,MAAM,WAAW,aAAa;IAC5B,KAAK,EAAE,MAAM,CAAC;IACd,2EAA2E;IAC3E,QAAQ,EAAE,MAAM,CAAC;IACjB,+EAA+E;IAC/E,MAAM,EAAE,KAAK,CAAC,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC;IAChC,IAAI,EAAE,OAAO,CAAC;IACd,uEAAuE;IACvE,WAAW,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACvC;AAED,wBAAgB,YAAY,CAAC,QAAQ,EAAE,OAAO,EAAE,EAAE,IAAI,EAAE,aAAa,GAAG,IAAI,CAuC3E;AAED,qEAAqE;AACrE,wBAAgB,WAAW,CAAC,KAAK,EAAE,MAAM,GAAG,SAAS,GAAG,QAAQ,GAAG,IAAI,CAOtE;AAED;;;;;GAKG;AACH,wBAAgB,WAAW,CAAC,QAAQ,EAAE,OAAO,EAAE,EAAE,MAAM,EAAE,QAAQ,GAAG,IAAI,EAAE,KAAK,EAAE,OAAO,GAAG,IAAI,CAS9F;AAED,eAAO,MAAM,cAAc;;;;CAI1B,CAAC;AAEF,eAAO,MAAM,WAAW;;;CAGvB,CAAC"}
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared result model and reporter for the audit commands
|
|
3
|
+
* (`scan-account`, `bedrock-protection`, `scan-repo`).
|
|
4
|
+
*
|
|
5
|
+
* This lives under utils/ rather than alongside the commands because
|
|
6
|
+
* `commands/<category>/*.js` is the command auto-discovery path -- every file in
|
|
7
|
+
* a category directory is registered as a subcommand, so a shared module placed
|
|
8
|
+
* there would appear in `--help` as a bogus command.
|
|
9
|
+
*/
|
|
10
|
+
export const SEVERITY_ORDER = ['INFO', 'LOW', 'MEDIUM', 'HIGH', 'CRITICAL'];
|
|
11
|
+
const ICON = { PASS: '✅', FAIL: '❌', INDETERMINATE: '❓' };
|
|
12
|
+
export function severityRank(s) {
|
|
13
|
+
return SEVERITY_ORDER.indexOf(s);
|
|
14
|
+
}
|
|
15
|
+
export function renderReport(findings, opts) {
|
|
16
|
+
if (opts.json) {
|
|
17
|
+
console.log(JSON.stringify({
|
|
18
|
+
...(opts.jsonContext ?? {}),
|
|
19
|
+
generated_at: new Date().toISOString(),
|
|
20
|
+
findings,
|
|
21
|
+
}, null, 2));
|
|
22
|
+
return;
|
|
23
|
+
}
|
|
24
|
+
console.log(`\n${opts.title}`);
|
|
25
|
+
if (opts.subtitle)
|
|
26
|
+
console.log(` ${opts.subtitle}`);
|
|
27
|
+
console.log(` Audit only — this command makes no changes.\n`);
|
|
28
|
+
for (const [key, heading] of opts.groups) {
|
|
29
|
+
const rows = findings.filter((f) => f.category === key);
|
|
30
|
+
if (!rows.length)
|
|
31
|
+
continue;
|
|
32
|
+
console.log(`── ${heading} ──\n`);
|
|
33
|
+
rows.sort((a, b) => severityRank(b.severity) - severityRank(a.severity));
|
|
34
|
+
for (const f of rows) {
|
|
35
|
+
console.log(` ${ICON[f.status]} [${f.severity}] ${f.title}`);
|
|
36
|
+
console.log(` ${f.detail}`);
|
|
37
|
+
if (f.status !== 'PASS' && f.remediation)
|
|
38
|
+
console.log(` → ${f.remediation}`);
|
|
39
|
+
console.log('');
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
const fail = findings.filter((f) => f.status === 'FAIL');
|
|
43
|
+
const indet = findings.filter((f) => f.status === 'INDETERMINATE');
|
|
44
|
+
const bySev = (s) => fail.filter((f) => f.severity === s).length;
|
|
45
|
+
console.log('── Summary ──\n');
|
|
46
|
+
console.log(` ${findings.length} checks: ${findings.length - fail.length - indet.length} pass, ${fail.length} fail, ${indet.length} indeterminate`);
|
|
47
|
+
console.log(` Findings by severity: CRITICAL ${bySev('CRITICAL')}, HIGH ${bySev('HIGH')}, MEDIUM ${bySev('MEDIUM')}, LOW ${bySev('LOW')}\n`);
|
|
48
|
+
if (indet.length) {
|
|
49
|
+
console.log(` ❓ ${indet.length} check(s) could not run and are NOT passes: ${indet.map((f) => f.id).join(', ')}`);
|
|
50
|
+
console.log(` Treat the result as a floor, not a clean bill of health.\n`);
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
/** Parse and validate a --fail-on value. Returns null for "none". */
|
|
54
|
+
export function parseFailOn(value) {
|
|
55
|
+
const v = (value ?? 'none').toUpperCase();
|
|
56
|
+
if (v === 'NONE')
|
|
57
|
+
return null;
|
|
58
|
+
if (!SEVERITY_ORDER.includes(v)) {
|
|
59
|
+
throw new Error(`--fail-on must be one of CRITICAL, HIGH, MEDIUM, LOW, none (got "${value}")`);
|
|
60
|
+
}
|
|
61
|
+
return v;
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* Apply --fail-on to the findings, setting process.exitCode when breached.
|
|
65
|
+
* Only FAIL counts -- an INDETERMINATE check has not established a violation,
|
|
66
|
+
* and exiting non-zero on it would make a missing permission indistinguishable
|
|
67
|
+
* from a real finding.
|
|
68
|
+
*/
|
|
69
|
+
export function applyFailOn(findings, failOn, quiet) {
|
|
70
|
+
if (!failOn)
|
|
71
|
+
return;
|
|
72
|
+
const threshold = severityRank(failOn);
|
|
73
|
+
const breaching = findings.filter((f) => f.status === 'FAIL' && severityRank(f.severity) >= threshold);
|
|
74
|
+
if (!breaching.length)
|
|
75
|
+
return;
|
|
76
|
+
if (!quiet) {
|
|
77
|
+
console.error(`❌ ${breaching.length} finding(s) at or above ${failOn}: ${breaching.map((f) => f.id).join(', ')}\n`);
|
|
78
|
+
}
|
|
79
|
+
process.exitCode = 1;
|
|
80
|
+
}
|
|
81
|
+
export const FAIL_ON_OPTION = {
|
|
82
|
+
flags: '--fail-on <severity>',
|
|
83
|
+
description: 'Exit non-zero if any finding is at or above this severity (CRITICAL|HIGH|MEDIUM|LOW|none)',
|
|
84
|
+
default: 'none',
|
|
85
|
+
};
|
|
86
|
+
export const JSON_OPTION = {
|
|
87
|
+
flags: '--json',
|
|
88
|
+
description: 'Emit machine-readable JSON instead of the report',
|
|
89
|
+
};
|
|
90
|
+
//# sourceMappingURL=audit.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"audit.js","sourceRoot":"","sources":["../../../src/utils/audit.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Thin JSON wrapper over the AWS CLI for the audit commands.
|
|
3
|
+
*
|
|
4
|
+
* Uses `run()` (execFileSync with an args array, no shell), so nothing here is
|
|
5
|
+
* exposed to shell interpretation even though callers pass a user-supplied
|
|
6
|
+
* --profile and --region.
|
|
7
|
+
*/
|
|
8
|
+
export interface AwsResult {
|
|
9
|
+
ok: boolean;
|
|
10
|
+
json: any;
|
|
11
|
+
/** AWS error code parsed from stderr, e.g. NoSuchEntity, when ok === false. */
|
|
12
|
+
errorCode: string;
|
|
13
|
+
/** stderr on failure, stdout on an unparseable success. */
|
|
14
|
+
raw: string;
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Several AWS commands exit 0 with a COMPLETELY EMPTY body when the thing being
|
|
18
|
+
* described does not exist -- measured on `budgets describe-budgets` with no
|
|
19
|
+
* budgets, and on `bedrock get-model-invocation-logging-configuration` with
|
|
20
|
+
* logging disabled. `JSON.parse('')` throws, so a naive wrapper crashes on
|
|
21
|
+
* precisely the accounts that most need auditing. Empty output is normalised to
|
|
22
|
+
* {} here and interpreted by each individual check.
|
|
23
|
+
*/
|
|
24
|
+
export declare function aws(args: string[], profile?: string): AwsResult;
|
|
25
|
+
/**
|
|
26
|
+
* Resolve the caller's account id, or print guidance and return null.
|
|
27
|
+
*
|
|
28
|
+
* Not every failure is an AWS API error with a parseable code -- an unknown
|
|
29
|
+
* --profile fails in the CLI's own config layer and never reaches the service,
|
|
30
|
+
* so fall back to its stderr rather than reporting "unknown error".
|
|
31
|
+
*/
|
|
32
|
+
export declare function resolveAccount(profile?: string): string | null;
|
|
33
|
+
export declare function daysSince(iso: string): number | null;
|
|
34
|
+
export declare const PROFILE_OPTION: {
|
|
35
|
+
flags: string;
|
|
36
|
+
description: string;
|
|
37
|
+
};
|
|
38
|
+
//# sourceMappingURL=aws.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"aws.d.ts","sourceRoot":"","sources":["../../../src/utils/aws.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAIH,MAAM,WAAW,SAAS;IACxB,EAAE,EAAE,OAAO,CAAC;IACZ,IAAI,EAAE,GAAG,CAAC;IACV,+EAA+E;IAC/E,SAAS,EAAE,MAAM,CAAC;IAClB,2DAA2D;IAC3D,GAAG,EAAE,MAAM,CAAC;CACb;AAED;;;;;;;GAOG;AACH,wBAAgB,GAAG,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,OAAO,CAAC,EAAE,MAAM,GAAG,SAAS,CAe/D;AAED;;;;;;GAMG;AACH,wBAAgB,cAAc,CAAC,OAAO,CAAC,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAS9D;AAED,wBAAgB,SAAS,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAIpD;AAED,eAAO,MAAM,cAAc;;;CAG1B,CAAC"}
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Thin JSON wrapper over the AWS CLI for the audit commands.
|
|
3
|
+
*
|
|
4
|
+
* Uses `run()` (execFileSync with an args array, no shell), so nothing here is
|
|
5
|
+
* exposed to shell interpretation even though callers pass a user-supplied
|
|
6
|
+
* --profile and --region.
|
|
7
|
+
*/
|
|
8
|
+
import { run } from './exec.js';
|
|
9
|
+
/**
|
|
10
|
+
* Several AWS commands exit 0 with a COMPLETELY EMPTY body when the thing being
|
|
11
|
+
* described does not exist -- measured on `budgets describe-budgets` with no
|
|
12
|
+
* budgets, and on `bedrock get-model-invocation-logging-configuration` with
|
|
13
|
+
* logging disabled. `JSON.parse('')` throws, so a naive wrapper crashes on
|
|
14
|
+
* precisely the accounts that most need auditing. Empty output is normalised to
|
|
15
|
+
* {} here and interpreted by each individual check.
|
|
16
|
+
*/
|
|
17
|
+
export function aws(args, profile) {
|
|
18
|
+
const argv = profile ? [...args, '--profile', profile] : args;
|
|
19
|
+
const res = run('aws', [...argv, '--output', 'json']);
|
|
20
|
+
const body = (res.stdout || '').trim();
|
|
21
|
+
if (!res.ok) {
|
|
22
|
+
const m = /An error occurred \(([A-Za-z0-9.]+)\)/.exec(res.stderr || '');
|
|
23
|
+
return { ok: false, json: null, errorCode: m ? m[1] : '', raw: res.stderr || '' };
|
|
24
|
+
}
|
|
25
|
+
if (!body)
|
|
26
|
+
return { ok: true, json: {}, errorCode: '', raw: '' };
|
|
27
|
+
try {
|
|
28
|
+
return { ok: true, json: JSON.parse(body), errorCode: '', raw: body };
|
|
29
|
+
}
|
|
30
|
+
catch {
|
|
31
|
+
return { ok: false, json: null, errorCode: 'UnparseableResponse', raw: body };
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Resolve the caller's account id, or print guidance and return null.
|
|
36
|
+
*
|
|
37
|
+
* Not every failure is an AWS API error with a parseable code -- an unknown
|
|
38
|
+
* --profile fails in the CLI's own config layer and never reaches the service,
|
|
39
|
+
* so fall back to its stderr rather than reporting "unknown error".
|
|
40
|
+
*/
|
|
41
|
+
export function resolveAccount(profile) {
|
|
42
|
+
const who = aws(['sts', 'get-caller-identity'], profile);
|
|
43
|
+
if (who.ok)
|
|
44
|
+
return who.json?.Account ?? null;
|
|
45
|
+
const reason = who.errorCode
|
|
46
|
+
|| (who.raw.split('\n').map((l) => l.trim()).filter(Boolean).pop() ?? 'unknown error');
|
|
47
|
+
console.error(`\n❌ Cannot resolve AWS identity: ${reason}`);
|
|
48
|
+
console.error(` Configure credentials, or pass --profile <name>.\n`);
|
|
49
|
+
return null;
|
|
50
|
+
}
|
|
51
|
+
export function daysSince(iso) {
|
|
52
|
+
const t = Date.parse(iso);
|
|
53
|
+
if (Number.isNaN(t))
|
|
54
|
+
return null;
|
|
55
|
+
return Math.floor((Date.now() - t) / 86_400_000);
|
|
56
|
+
}
|
|
57
|
+
export const PROFILE_OPTION = {
|
|
58
|
+
flags: '--profile <name>',
|
|
59
|
+
description: 'AWS CLI profile to audit (defaults to the ambient credentials)',
|
|
60
|
+
};
|
|
61
|
+
//# sourceMappingURL=aws.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"aws.js","sourceRoot":"","sources":["../../../src/utils/aws.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EAAE,GAAG,EAAE,MAAM,WAAW,CAAC;AAWhC;;;;;;;GAOG;AACH,MAAM,UAAU,GAAG,CAAC,IAAc,EAAE,OAAgB;IAClD,MAAM,IAAI,GAAG,OAAO,CAAC,CAAC,CAAC,CAAC,GAAG,IAAI,EAAE,WAAW,EAAE,OAAO,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;IAC9D,MAAM,GAAG,GAAG,GAAG,CAAC,KAAK,EAAE,CAAC,GAAG,IAAI,EAAE,UAAU,EAAE,MAAM,CAAC,CAAC,CAAC;IACtD,MAAM,IAAI,GAAG,CAAC,GAAG,CAAC,MAAM,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC;IAEvC,IAAI,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC;QACZ,MAAM,CAAC,GAAG,uCAAuC,CAAC,IAAI,CAAC,GAAG,CAAC,MAAM,IAAI,EAAE,CAAC,CAAC;QACzE,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,IAAI,EAAE,SAAS,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,EAAE,GAAG,EAAE,GAAG,CAAC,MAAM,IAAI,EAAE,EAAE,CAAC;IACpF,CAAC;IACD,IAAI,CAAC,IAAI;QAAE,OAAO,EAAE,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,EAAE,EAAE,SAAS,EAAE,EAAE,EAAE,GAAG,EAAE,EAAE,EAAE,CAAC;IACjE,IAAI,CAAC;QACH,OAAO,EAAE,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,SAAS,EAAE,EAAE,EAAE,GAAG,EAAE,IAAI,EAAE,CAAC;IACxE,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,IAAI,EAAE,SAAS,EAAE,qBAAqB,EAAE,GAAG,EAAE,IAAI,EAAE,CAAC;IAChF,CAAC;AACH,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,cAAc,CAAC,OAAgB;IAC7C,MAAM,GAAG,GAAG,GAAG,CAAC,CAAC,KAAK,EAAE,qBAAqB,CAAC,EAAE,OAAO,CAAC,CAAC;IACzD,IAAI,GAAG,CAAC,EAAE;QAAE,OAAO,GAAG,CAAC,IAAI,EAAE,OAAO,IAAI,IAAI,CAAC;IAE7C,MAAM,MAAM,GAAG,GAAG,CAAC,SAAS;WACvB,CAAC,GAAG,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,GAAG,EAAE,IAAI,eAAe,CAAC,CAAC;IACzF,OAAO,CAAC,KAAK,CAAC,oCAAoC,MAAM,EAAE,CAAC,CAAC;IAC5D,OAAO,CAAC,KAAK,CAAC,uDAAuD,CAAC,CAAC;IACvE,OAAO,IAAI,CAAC;AACd,CAAC;AAED,MAAM,UAAU,SAAS,CAAC,GAAW;IACnC,MAAM,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;IAC1B,IAAI,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC;QAAE,OAAO,IAAI,CAAC;IACjC,OAAO,IAAI,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC,GAAG,UAAU,CAAC,CAAC;AACnD,CAAC;AAED,MAAM,CAAC,MAAM,cAAc,GAAG;IAC5B,KAAK,EAAE,kBAAkB;IACzB,WAAW,EAAE,gEAAgE;CAC9E,CAAC"}
|