foundry-design-protocol 0.2.0-beta.21 → 0.2.0-beta.23
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 +6 -4
- package/dist/engineering-verification.d.ts +11 -0
- package/dist/engineering-verification.d.ts.map +1 -0
- package/dist/engineering-verification.js +111 -0
- package/dist/engineering-verification.js.map +1 -0
- package/dist/index.d.ts +432 -174
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +30 -1
- package/dist/index.js.map +1 -1
- package/dist/readiness.d.ts +123 -0
- package/dist/readiness.d.ts.map +1 -0
- package/dist/readiness.js +63 -0
- package/dist/readiness.js.map +1 -0
- package/dist/visual-check.d.ts +289 -0
- package/dist/visual-check.d.ts.map +1 -0
- package/dist/visual-check.js +82 -0
- package/dist/visual-check.js.map +1 -0
- package/package.json +5 -1
package/README.md
CHANGED
|
@@ -10,7 +10,9 @@ Design Branches keeps parallel visual directions isolated inside one local sessi
|
|
|
10
10
|
|
|
11
11
|
Foundry is distributed through npm, so testers do not need GitHub access.
|
|
12
12
|
|
|
13
|
-
> **Current beta release:** `0.2.0-beta.
|
|
13
|
+
> **Current beta release:** `0.2.0-beta.23`. For an exact-version install, use `foundry-design@0.2.0-beta.23`.
|
|
14
|
+
|
|
15
|
+
The redesigned workspace now opens by default. Existing `ui=next` links continue to work; append `ui=legacy` to the workspace URL only when you need the previous interface for compatibility.
|
|
14
16
|
|
|
15
17
|
Full documentation is available at [withfoundry.ai](https://withfoundry.ai).
|
|
16
18
|
|
|
@@ -141,10 +143,10 @@ If an npm mirror or existing `npx` cache reports an old tag, bypass it with a te
|
|
|
141
143
|
|
|
142
144
|
```bash
|
|
143
145
|
FOUNDRY_NPX_CACHE="$(mktemp -d)"
|
|
144
|
-
npx --yes --prefer-online --registry=https://registry.npmjs.org --cache "$FOUNDRY_NPX_CACHE" --package=foundry-design@0.2.0-beta.
|
|
146
|
+
npx --yes --prefer-online --registry=https://registry.npmjs.org --cache "$FOUNDRY_NPX_CACHE" --package=foundry-design@0.2.0-beta.23 foundry-design
|
|
145
147
|
```
|
|
146
148
|
|
|
147
|
-
The
|
|
149
|
+
The CLI supports Node.js 20.9 or newer. Repository development and the framework compatibility fixtures require Node.js 20.19 or newer. Read the [local-first safety model](https://withfoundry.ai/#safety) before using it with sensitive work.
|
|
148
150
|
|
|
149
151
|
## Agent plugin
|
|
150
152
|
|
|
@@ -158,7 +160,7 @@ Foundry remains local-first. Installing the plugin does not create an account, e
|
|
|
158
160
|
|
|
159
161
|
### Cursor one-click connection
|
|
160
162
|
|
|
161
|
-
[Add the Foundry MCP bridge to Cursor](cursor://anysphere.cursor-deeplink/mcp/install?name=foundry-design-control&config=
|
|
163
|
+
[Add the Foundry MCP bridge to Cursor](cursor://anysphere.cursor-deeplink/mcp/install?name=foundry-design-control&config=eyJjb21tYW5kIjoibnB4IiwiYXJncyI6WyIteSIsIi0tcHJlZmVyLW9ubGluZSIsImZvdW5kcnktZGVzaWduLW1jcC1zZXJ2ZXJAMC4yLjAtYmV0YS4yMyJdLCJlbnYiOnsiRk9VTkRSWV9ERVNJR05fUlVOVElNRV9VUkwiOiJodHRwOi8vMTI3LjAuMC4xOjQzODcifX0%3D), then run `npx foundry-design` inside the project. The repository's Cursor plugin additionally bundles the Foundry skill and session-start hook for marketplace distribution.
|
|
162
164
|
|
|
163
165
|
## Current capabilities
|
|
164
166
|
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { ApplyRun, ChangeContext, DeliveryRecord, DesignChange, VerificationResult } from './index.js';
|
|
2
|
+
export declare function matchingDeliveryCaptures(record: DeliveryRecord): {
|
|
3
|
+
before: DeliveryRecord["evidence"][number];
|
|
4
|
+
after: DeliveryRecord["evidence"][number];
|
|
5
|
+
}[];
|
|
6
|
+
export declare function engineeringVerification(record: DeliveryRecord, run: ApplyRun | undefined, change: DesignChange, context: ChangeContext): {
|
|
7
|
+
status: 'passed' | 'failed' | 'untested';
|
|
8
|
+
result?: VerificationResult;
|
|
9
|
+
reason?: string;
|
|
10
|
+
};
|
|
11
|
+
//# sourceMappingURL=engineering-verification.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"engineering-verification.d.ts","sourceRoot":"","sources":["../src/engineering-verification.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,QAAQ,EACR,aAAa,EACb,cAAc,EACd,YAAY,EACZ,kBAAkB,EACnB,MAAM,YAAY,CAAC;AAGpB,wBAAgB,wBAAwB,CAAC,MAAM,EAAE,cAAc;YAEnD,cAAc,CAAC,UAAU,CAAC,CAAC,MAAM,CAAC;WACnC,cAAc,CAAC,UAAU,CAAC,CAAC,MAAM,CAAC;IAmC5C;AAwBD,wBAAgB,uBAAuB,CACrC,MAAM,EAAE,cAAc,EACtB,GAAG,EAAE,QAAQ,GAAG,SAAS,EACzB,MAAM,EAAE,YAAY,EACpB,OAAO,EAAE,aAAa,GACrB;IAAE,MAAM,EAAE,QAAQ,GAAG,QAAQ,GAAG,UAAU,CAAC;IAAC,MAAM,CAAC,EAAE,kBAAkB,CAAC;IAAC,MAAM,CAAC,EAAE,MAAM,CAAA;CAAE,CAoE5F"}
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
import { verificationValueMatches } from './verification-value.js';
|
|
2
|
+
export function matchingDeliveryCaptures(record) {
|
|
3
|
+
const pairs = [];
|
|
4
|
+
for (const after of record.evidence) {
|
|
5
|
+
const proof = after.capture;
|
|
6
|
+
if (!proof ||
|
|
7
|
+
!proof.conditions ||
|
|
8
|
+
proof.phase !== 'rebuilt' ||
|
|
9
|
+
proof.applyRunId !== record.applyRunId ||
|
|
10
|
+
!record.appliedRevision ||
|
|
11
|
+
proof.sourceRevision !== record.appliedRevision)
|
|
12
|
+
continue;
|
|
13
|
+
const before = record.evidence.find((item) => {
|
|
14
|
+
const baseline = item.capture;
|
|
15
|
+
return (baseline?.phase === 'before' &&
|
|
16
|
+
baseline.conditions &&
|
|
17
|
+
baseline.conditions.motion === proof.conditions.motion &&
|
|
18
|
+
baseline.conditions.browser === proof.conditions.browser &&
|
|
19
|
+
baseline.conditions.platform === proof.conditions.platform &&
|
|
20
|
+
baseline.conditions.deviceScaleFactor === proof.conditions.deviceScaleFactor &&
|
|
21
|
+
baseline.targetId === proof.targetId &&
|
|
22
|
+
baseline.sourceRevision === record.baselineRevision &&
|
|
23
|
+
Boolean(record.baselineRevision) &&
|
|
24
|
+
baseline.viewport.width === proof.viewport.width &&
|
|
25
|
+
baseline.viewport.height === proof.viewport.height &&
|
|
26
|
+
baseline.context.breakpoint === proof.context.breakpoint &&
|
|
27
|
+
baseline.context.theme === proof.context.theme &&
|
|
28
|
+
baseline.context.state === proof.context.state);
|
|
29
|
+
});
|
|
30
|
+
if (before)
|
|
31
|
+
pairs.push({ before, after });
|
|
32
|
+
}
|
|
33
|
+
return pairs;
|
|
34
|
+
}
|
|
35
|
+
function exactValue(left, right) {
|
|
36
|
+
if (Object.is(left, right))
|
|
37
|
+
return true;
|
|
38
|
+
if (!left || !right || typeof left !== 'object' || typeof right !== 'object')
|
|
39
|
+
return false;
|
|
40
|
+
if (Array.isArray(left) || Array.isArray(right))
|
|
41
|
+
return (Array.isArray(left) &&
|
|
42
|
+
Array.isArray(right) &&
|
|
43
|
+
left.length === right.length &&
|
|
44
|
+
left.every((value, index) => exactValue(value, right[index])));
|
|
45
|
+
const a = Object.keys(left).sort();
|
|
46
|
+
const b = Object.keys(right).sort();
|
|
47
|
+
return (a.length === b.length &&
|
|
48
|
+
a.every((key, index) => key === b[index] &&
|
|
49
|
+
exactValue(left[key], right[key])));
|
|
50
|
+
}
|
|
51
|
+
export function engineeringVerification(record, run, change, context) {
|
|
52
|
+
if (!run ||
|
|
53
|
+
run.id !== record.applyRunId ||
|
|
54
|
+
!run.changeIds.includes(change.id) ||
|
|
55
|
+
!record.changeIds.includes(change.id))
|
|
56
|
+
return { status: 'untested', reason: 'No matching frozen Apply contract.' };
|
|
57
|
+
// Completion deliberately releases the active lease. Its acknowledged attempt
|
|
58
|
+
// remains frozen on the run and is the authority for historical evidence.
|
|
59
|
+
const completedAttempt = ['passed', 'needs_attention'].includes(run.state) &&
|
|
60
|
+
run.completedAt &&
|
|
61
|
+
Number.isFinite(Date.parse(run.completedAt))
|
|
62
|
+
? run.applyResultClaimAttemptId
|
|
63
|
+
: undefined;
|
|
64
|
+
const claimAttempt = run.claimAttemptId ?? completedAttempt;
|
|
65
|
+
if (!claimAttempt ||
|
|
66
|
+
run.applyResultClaimAttemptId !== claimAttempt ||
|
|
67
|
+
!run.applyResultAcknowledgedAt ||
|
|
68
|
+
!['verifying', 'passed', 'needs_attention'].includes(run.state))
|
|
69
|
+
return {
|
|
70
|
+
status: 'untested',
|
|
71
|
+
reason: 'The current Apply attempt has no acknowledged verification lifecycle.',
|
|
72
|
+
};
|
|
73
|
+
const acknowledgedAt = Date.parse(run.applyResultAcknowledgedAt);
|
|
74
|
+
const results = record.verificationResults.filter((item) => item.changeId === change.id &&
|
|
75
|
+
item.property === change.property &&
|
|
76
|
+
item.applyRunId === run.id &&
|
|
77
|
+
item.claimAttemptId === claimAttempt &&
|
|
78
|
+
item.context &&
|
|
79
|
+
item.context.breakpoint === context.breakpoint &&
|
|
80
|
+
item.context.theme === context.theme &&
|
|
81
|
+
item.context.state === context.state &&
|
|
82
|
+
exactValue(item.requested, change.after) &&
|
|
83
|
+
Number.isFinite(Date.parse(item.verifiedAt)) &&
|
|
84
|
+
Date.parse(item.verifiedAt) >= acknowledgedAt);
|
|
85
|
+
const result = results.sort((a, b) => Date.parse(b.verifiedAt) - Date.parse(a.verifiedAt))[0];
|
|
86
|
+
if (!result)
|
|
87
|
+
return {
|
|
88
|
+
status: 'untested',
|
|
89
|
+
reason: 'No matching rendered evidence for this request and attempt.',
|
|
90
|
+
};
|
|
91
|
+
if (!result.passed)
|
|
92
|
+
return { status: 'failed', result };
|
|
93
|
+
if (!verificationValueMatches(change.property, result.rendered, change.after, change.unit))
|
|
94
|
+
return { status: 'failed', result, reason: 'Recorded pass contradicts the reviewed value.' };
|
|
95
|
+
if (!run.validationResults.length || run.validationResults.some((item) => !item.passed))
|
|
96
|
+
return { status: 'untested', result, reason: 'Source validation is missing or failed.' };
|
|
97
|
+
if (record.appliedRevision && run.appliedRevision !== record.appliedRevision)
|
|
98
|
+
return { status: 'untested', result, reason: 'Delivery and Apply source revisions differ.' };
|
|
99
|
+
if (change.target?.platform === 'web' &&
|
|
100
|
+
(!result.geometry ||
|
|
101
|
+
result.geometry.width <= 0 ||
|
|
102
|
+
result.geometry.height <= 0 ||
|
|
103
|
+
!result.evidence.length))
|
|
104
|
+
return {
|
|
105
|
+
status: 'untested',
|
|
106
|
+
result,
|
|
107
|
+
reason: 'Visible browser geometry and evidence are missing.',
|
|
108
|
+
};
|
|
109
|
+
return { status: 'passed', result };
|
|
110
|
+
}
|
|
111
|
+
//# sourceMappingURL=engineering-verification.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"engineering-verification.js","sourceRoot":"","sources":["../src/engineering-verification.ts"],"names":[],"mappings":"AAOA,OAAO,EAAE,wBAAwB,EAAE,MAAM,yBAAyB,CAAC;AAEnE,MAAM,UAAU,wBAAwB,CAAC,MAAsB;IAC7D,MAAM,KAAK,GAGN,EAAE,CAAC;IACR,KAAK,MAAM,KAAK,IAAI,MAAM,CAAC,QAAQ,EAAE,CAAC;QACpC,MAAM,KAAK,GAAG,KAAK,CAAC,OAAO,CAAC;QAC5B,IACE,CAAC,KAAK;YACN,CAAC,KAAK,CAAC,UAAU;YACjB,KAAK,CAAC,KAAK,KAAK,SAAS;YACzB,KAAK,CAAC,UAAU,KAAK,MAAM,CAAC,UAAU;YACtC,CAAC,MAAM,CAAC,eAAe;YACvB,KAAK,CAAC,cAAc,KAAK,MAAM,CAAC,eAAe;YAE/C,SAAS;QACX,MAAM,MAAM,GAAG,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,EAAE;YAC3C,MAAM,QAAQ,GAAG,IAAI,CAAC,OAAO,CAAC;YAC9B,OAAO,CACL,QAAQ,EAAE,KAAK,KAAK,QAAQ;gBAC5B,QAAQ,CAAC,UAAU;gBACnB,QAAQ,CAAC,UAAU,CAAC,MAAM,KAAK,KAAK,CAAC,UAAW,CAAC,MAAM;gBACvD,QAAQ,CAAC,UAAU,CAAC,OAAO,KAAK,KAAK,CAAC,UAAW,CAAC,OAAO;gBACzD,QAAQ,CAAC,UAAU,CAAC,QAAQ,KAAK,KAAK,CAAC,UAAW,CAAC,QAAQ;gBAC3D,QAAQ,CAAC,UAAU,CAAC,iBAAiB,KAAK,KAAK,CAAC,UAAW,CAAC,iBAAiB;gBAC7E,QAAQ,CAAC,QAAQ,KAAK,KAAK,CAAC,QAAQ;gBACpC,QAAQ,CAAC,cAAc,KAAK,MAAM,CAAC,gBAAgB;gBACnD,OAAO,CAAC,MAAM,CAAC,gBAAgB,CAAC;gBAChC,QAAQ,CAAC,QAAQ,CAAC,KAAK,KAAK,KAAK,CAAC,QAAQ,CAAC,KAAK;gBAChD,QAAQ,CAAC,QAAQ,CAAC,MAAM,KAAK,KAAK,CAAC,QAAQ,CAAC,MAAM;gBAClD,QAAQ,CAAC,OAAO,CAAC,UAAU,KAAK,KAAK,CAAC,OAAO,CAAC,UAAU;gBACxD,QAAQ,CAAC,OAAO,CAAC,KAAK,KAAK,KAAK,CAAC,OAAO,CAAC,KAAK;gBAC9C,QAAQ,CAAC,OAAO,CAAC,KAAK,KAAK,KAAK,CAAC,OAAO,CAAC,KAAK,CAC/C,CAAC;QACJ,CAAC,CAAC,CAAC;QACH,IAAI,MAAM;YAAE,KAAK,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC,CAAC;IAC5C,CAAC;IACD,OAAO,KAAK,CAAC;AACf,CAAC;AAED,SAAS,UAAU,CAAC,IAAa,EAAE,KAAc;IAC/C,IAAI,MAAM,CAAC,EAAE,CAAC,IAAI,EAAE,KAAK,CAAC;QAAE,OAAO,IAAI,CAAC;IACxC,IAAI,CAAC,IAAI,IAAI,CAAC,KAAK,IAAI,OAAO,IAAI,KAAK,QAAQ,IAAI,OAAO,KAAK,KAAK,QAAQ;QAAE,OAAO,KAAK,CAAC;IAC3F,IAAI,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,IAAI,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC;QAC7C,OAAO,CACL,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC;YACnB,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC;YACpB,IAAI,CAAC,MAAM,KAAK,KAAK,CAAC,MAAM;YAC5B,IAAI,CAAC,KAAK,CAAC,CAAC,KAAK,EAAE,KAAK,EAAE,EAAE,CAAC,UAAU,CAAC,KAAK,EAAE,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,CAC9D,CAAC;IACJ,MAAM,CAAC,GAAG,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,CAAC;IACnC,MAAM,CAAC,GAAG,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,IAAI,EAAE,CAAC;IACpC,OAAO,CACL,CAAC,CAAC,MAAM,KAAK,CAAC,CAAC,MAAM;QACrB,CAAC,CAAC,KAAK,CACL,CAAC,GAAG,EAAE,KAAK,EAAE,EAAE,CACb,GAAG,KAAK,CAAC,CAAC,KAAK,CAAC;YAChB,UAAU,CAAE,IAAgC,CAAC,GAAG,CAAC,EAAG,KAAiC,CAAC,GAAG,CAAC,CAAC,CAC9F,CACF,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,uBAAuB,CACrC,MAAsB,EACtB,GAAyB,EACzB,MAAoB,EACpB,OAAsB;IAEtB,IACE,CAAC,GAAG;QACJ,GAAG,CAAC,EAAE,KAAK,MAAM,CAAC,UAAU;QAC5B,CAAC,GAAG,CAAC,SAAS,CAAC,QAAQ,CAAC,MAAM,CAAC,EAAE,CAAC;QAClC,CAAC,MAAM,CAAC,SAAS,CAAC,QAAQ,CAAC,MAAM,CAAC,EAAE,CAAC;QAErC,OAAO,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,EAAE,oCAAoC,EAAE,CAAC;IAC9E,8EAA8E;IAC9E,0EAA0E;IAC1E,MAAM,gBAAgB,GACpB,CAAC,QAAQ,EAAE,iBAAiB,CAAC,CAAC,QAAQ,CAAC,GAAG,CAAC,KAAK,CAAC;QACjD,GAAG,CAAC,WAAW;QACf,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,WAAW,CAAC,CAAC;QAC1C,CAAC,CAAC,GAAG,CAAC,yBAAyB;QAC/B,CAAC,CAAC,SAAS,CAAC;IAChB,MAAM,YAAY,GAAG,GAAG,CAAC,cAAc,IAAI,gBAAgB,CAAC;IAC5D,IACE,CAAC,YAAY;QACb,GAAG,CAAC,yBAAyB,KAAK,YAAY;QAC9C,CAAC,GAAG,CAAC,yBAAyB;QAC9B,CAAC,CAAC,WAAW,EAAE,QAAQ,EAAE,iBAAiB,CAAC,CAAC,QAAQ,CAAC,GAAG,CAAC,KAAK,CAAC;QAE/D,OAAO;YACL,MAAM,EAAE,UAAU;YAClB,MAAM,EAAE,uEAAuE;SAChF,CAAC;IACJ,MAAM,cAAc,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,yBAAyB,CAAC,CAAC;IACjE,MAAM,OAAO,GAAG,MAAM,CAAC,mBAAmB,CAAC,MAAM,CAC/C,CAAC,IAAI,EAAE,EAAE,CACP,IAAI,CAAC,QAAQ,KAAK,MAAM,CAAC,EAAE;QAC3B,IAAI,CAAC,QAAQ,KAAK,MAAM,CAAC,QAAQ;QACjC,IAAI,CAAC,UAAU,KAAK,GAAG,CAAC,EAAE;QAC1B,IAAI,CAAC,cAAc,KAAK,YAAY;QACpC,IAAI,CAAC,OAAO;QACZ,IAAI,CAAC,OAAO,CAAC,UAAU,KAAK,OAAO,CAAC,UAAU;QAC9C,IAAI,CAAC,OAAO,CAAC,KAAK,KAAK,OAAO,CAAC,KAAK;QACpC,IAAI,CAAC,OAAO,CAAC,KAAK,KAAK,OAAO,CAAC,KAAK;QACpC,UAAU,CAAC,IAAI,CAAC,SAAS,EAAE,MAAM,CAAC,KAAK,CAAC;QACxC,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;QAC5C,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,UAAU,CAAC,IAAI,cAAc,CAChD,CAAC;IACF,MAAM,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,UAAU,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;IAC9F,IAAI,CAAC,MAAM;QACT,OAAO;YACL,MAAM,EAAE,UAAU;YAClB,MAAM,EAAE,6DAA6D;SACtE,CAAC;IACJ,IAAI,CAAC,MAAM,CAAC,MAAM;QAAE,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,CAAC;IACxD,IAAI,CAAC,wBAAwB,CAAC,MAAM,CAAC,QAAQ,EAAE,MAAM,CAAC,QAAQ,EAAE,MAAM,CAAC,KAAK,EAAE,MAAM,CAAC,IAAI,CAAC;QACxF,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,+CAA+C,EAAE,CAAC;IAC/F,IAAI,CAAC,GAAG,CAAC,iBAAiB,CAAC,MAAM,IAAI,GAAG,CAAC,iBAAiB,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC;QACrF,OAAO,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,EAAE,MAAM,EAAE,yCAAyC,EAAE,CAAC;IAC3F,IAAI,MAAM,CAAC,eAAe,IAAI,GAAG,CAAC,eAAe,KAAK,MAAM,CAAC,eAAe;QAC1E,OAAO,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,EAAE,MAAM,EAAE,6CAA6C,EAAE,CAAC;IAC/F,IACE,MAAM,CAAC,MAAM,EAAE,QAAQ,KAAK,KAAK;QACjC,CAAC,CAAC,MAAM,CAAC,QAAQ;YACf,MAAM,CAAC,QAAQ,CAAC,KAAK,IAAI,CAAC;YAC1B,MAAM,CAAC,QAAQ,CAAC,MAAM,IAAI,CAAC;YAC3B,CAAC,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC;QAE1B,OAAO;YACL,MAAM,EAAE,UAAU;YAClB,MAAM;YACN,MAAM,EAAE,oDAAoD;SAC7D,CAAC;IACJ,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,CAAC;AACtC,CAAC"}
|