@invarn/cibuild 1.9.8 → 2.0.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.
@@ -10,7 +10,7 @@ export class PlatformDetectionError extends Error {
10
10
  }
11
11
  }
12
12
  // Platform-specific step names
13
- const MACOS_STEPS = new Set(['xcodebuild', 'xcode-test']);
13
+ const MACOS_STEPS = new Set(['xcodebuild', 'xcode-test', 'ui-fidelity-render']);
14
14
  const LINUX_STEPS = new Set(['gradle-build', 'android-lint', 'android-unit-test', 'set-java-version']);
15
15
  /**
16
16
  * PlatformDetector analyzes a YAML workflow and determines the target platform
@@ -207,6 +207,25 @@ describe('PlatformDetector', () => {
207
207
  const detector = new PlatformDetector(pipeline, pipeline.workflows.primary, 'primary');
208
208
  expect(detector.getPlatform()).toBe('macos');
209
209
  });
210
+ test('should detect macOS from ui-fidelity-render step', () => {
211
+ const pipeline = {
212
+ format_version: '4',
213
+ workflows: {
214
+ primary: {
215
+ steps: [
216
+ { 'git-clone@4.0.17': { inputs: {} } },
217
+ {
218
+ 'ui-fidelity-render@1.0.0': {
219
+ inputs: { package_path: './MyPackage', target: 'MyViews' },
220
+ },
221
+ },
222
+ ],
223
+ },
224
+ },
225
+ };
226
+ const detector = new PlatformDetector(pipeline, pipeline.workflows.primary, 'primary');
227
+ expect(detector.getPlatform()).toBe('macos');
228
+ });
210
229
  test('should detect macOS from xcode-test step', () => {
211
230
  const pipeline = {
212
231
  format_version: '4',
@@ -1 +1 @@
1
- {"version":3,"file":"cache.d.ts","sourceRoot":"","sources":["../../../../src/yaml/steps/cache.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,gBAAgB,EAAE,MAAM,WAAW,CAAC;AAC7C,OAAO,KAAK,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAC;AAkBxD;;;;;;GAMG;AACH,MAAM,WAAW,WAAW;IAC1B,4HAA4H;IAC5H,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,sHAAsH;IACtH,WAAW,CAAC,EAAE,MAAM,EAAE,CAAC;IACvB,SAAS,EAAE,MAAM,CAAC;IAClB,KAAK,EAAE,MAAM,EAAE,CAAC;IAChB,yGAAyG;IACzG,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED,eAAO,MAAM,aAAa,EAAE,MAAM,CAAC,MAAM,EAAE,WAAW,CAUrD,CAAC;AAmFF;;GAEG;AACH,MAAM,WAAW,eAAe;IAC9B,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,WAAW,CAAC,EAAE,MAAM,EAAE,CAAC;IACvB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,aAAa,CAAC,EAAE,OAAO,CAAC;CACzB;AAED;;GAEG;AACH,MAAM,WAAW,eAAe;IAC9B,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,WAAW,CAAC,EAAE,MAAM,EAAE,CAAC;IACvB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,qBAAqB,CAAC,EAAE,OAAO,CAAC;CACjC;AAED;;;GAGG;AACH,qBAAa,qBAAsB,SAAQ,gBAAgB;IACnD,OAAO,CAAC,MAAM,EAAE,eAAe,EAAE,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,EAAE,QAAQ,GAAG,OAAO,CAAC,OAAO,CAAC;YA0GzF,iBAAiB;CAqMhC;AAED;;;GAGG;AACH,qBAAa,qBAAsB,SAAQ,gBAAgB;IACnD,OAAO,CAAC,MAAM,EAAE,eAAe,EAAE,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,EAAE,QAAQ,GAAG,OAAO,CAAC,OAAO,CAAC;YAgKzF,iBAAiB;CAmIhC"}
1
+ {"version":3,"file":"cache.d.ts","sourceRoot":"","sources":["../../../../src/yaml/steps/cache.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,gBAAgB,EAAE,MAAM,WAAW,CAAC;AAC7C,OAAO,KAAK,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAC;AAkBxD;;;;;;GAMG;AACH,MAAM,WAAW,WAAW;IAC1B,4HAA4H;IAC5H,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,sHAAsH;IACtH,WAAW,CAAC,EAAE,MAAM,EAAE,CAAC;IACvB,SAAS,EAAE,MAAM,CAAC;IAClB,KAAK,EAAE,MAAM,EAAE,CAAC;IAChB,yGAAyG;IACzG,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED,eAAO,MAAM,aAAa,EAAE,MAAM,CAAC,MAAM,EAAE,WAAW,CAUrD,CAAC;AAwFF;;GAEG;AACH,MAAM,WAAW,eAAe;IAC9B,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,WAAW,CAAC,EAAE,MAAM,EAAE,CAAC;IACvB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,aAAa,CAAC,EAAE,OAAO,CAAC;CACzB;AAED;;GAEG;AACH,MAAM,WAAW,eAAe;IAC9B,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,WAAW,CAAC,EAAE,MAAM,EAAE,CAAC;IACvB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,qBAAqB,CAAC,EAAE,OAAO,CAAC;CACjC;AAED;;;GAGG;AACH,qBAAa,qBAAsB,SAAQ,gBAAgB;IACnD,OAAO,CAAC,MAAM,EAAE,eAAe,EAAE,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,EAAE,QAAQ,GAAG,OAAO,CAAC,OAAO,CAAC;YA0GzF,iBAAiB;CAqMhC;AAED;;;GAGG;AACH,qBAAa,qBAAsB,SAAQ,gBAAgB;IACnD,OAAO,CAAC,MAAM,EAAE,eAAe,EAAE,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,EAAE,QAAQ,GAAG,OAAO,CAAC,OAAO,CAAC;YAgKzF,iBAAiB;CAmIhC"}
@@ -97,7 +97,12 @@ function resolvePresetChain(technology) {
97
97
  */
98
98
  function emitDaemonPullBranch() {
99
99
  return [
100
- 'elif [ -n "$CIBUILD_CACHE_DAEMON" ] && curl -fsS ${CIBUILD_CACHE_TOKEN:+-H "Authorization: Bearer $CIBUILD_CACHE_TOKEN"} "$CIBUILD_CACHE_DAEMON/cache/$CACHE_KEY.tar.zst" | zstd -dc | tar -xf - -C /; then',
100
+ // stderr is silenced on the probe: a cache miss is the normal case and
101
+ // makes curl emit "(22) ... 404" (and the empty body makes zstd print
102
+ // "unexpected end of file"). Those are non-actionable — the branch just
103
+ // falls through to the cold path — so they're pure log noise. Exit
104
+ // status is preserved (pipefail), so the fall-through still works.
105
+ 'elif [ -n "$CIBUILD_CACHE_DAEMON" ] && { curl -fsS ${CIBUILD_CACHE_TOKEN:+-H "Authorization: Bearer $CIBUILD_CACHE_TOKEN"} "$CIBUILD_CACHE_DAEMON/cache/$CACHE_KEY.tar.zst" | zstd -dc | tar -xf - -C /; } 2>/dev/null; then',
101
106
  ' echo "Cache found (daemon), extracting..."',
102
107
  // LRU bump the tarball the daemon just persisted to ~/cache (same dir as
103
108
  // the --dir mount); tolerate its absence in case the daemon served it
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/yaml/steps/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AA+BH;;;GAGG;AACH,wBAAgB,sBAAsB,IAAI,IAAI,CAm1C7C"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/yaml/steps/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAoCH;;;GAGG;AACH,wBAAgB,sBAAsB,IAAI,IAAI,CAi3C7C"}
@@ -24,6 +24,7 @@ import { BitriseSlackStepExecutor } from './bitrise-slack.js';
24
24
  import { BitriseApkInfoStepExecutor } from './bitrise-apk-info.js';
25
25
  import { GooglePlayDeployStepExecutor } from './google-play-deploy.js';
26
26
  import { AppStoreDeployStepExecutor } from './app-store-deploy.js';
27
+ import { UiFidelityRenderStepExecutor, DEFAULT_RENDER_SIZE, DEFAULT_SCALE, } from './ui-fidelity-render.js';
27
28
  /**
28
29
  * Initializes the step registry with all available steps
29
30
  * This function should be called once at application startup
@@ -757,6 +758,34 @@ export function initializeStepRegistry() {
757
758
  },
758
759
  },
759
760
  });
761
+ // UI fidelity — render SwiftUI screens to PNGs via ImageRenderer on macOS
762
+ registerStep('ui-fidelity-render', new UiFidelityRenderStepExecutor(), {
763
+ name: 'ui-fidelity-render',
764
+ description: 'Render parameterless SwiftUI views from a SwiftPM package to PNGs with ImageRenderer (no app build, no simulator)',
765
+ platform: 'ios',
766
+ inputs: {
767
+ package_path: {
768
+ description: "Path to the user's SwiftPM package containing the screens",
769
+ required: true,
770
+ inputType: 'path',
771
+ },
772
+ target: {
773
+ description: 'SPM library product to import in the render harness',
774
+ required: true,
775
+ inputType: 'text',
776
+ },
777
+ render_size: {
778
+ description: 'Render size in device points, "<width>x<height>"',
779
+ required: false,
780
+ default: DEFAULT_RENDER_SIZE,
781
+ },
782
+ scale: {
783
+ description: 'Display scale factor applied to the render',
784
+ required: false,
785
+ default: DEFAULT_SCALE,
786
+ },
787
+ },
788
+ });
760
789
  // Export xcarchive
761
790
  registerStep('export-xcarchive', new ExportXcarchiveStepExecutor(), {
762
791
  name: 'export-xcarchive',
@@ -175,39 +175,70 @@ describe('Step Implementations', () => {
175
175
  // Package.resolved either way). So actually execute the generated
176
176
  // key-derivation in a fixture repo and read the resolved key back.
177
177
  describe('ios fallback chain (executed in a fixture repo)', () => {
178
- async function resolveIosCacheKey(build) {
178
+ // Run the generated ios cache-pull in a fixture repo and capture
179
+ // BOTH streams (the daemon probe writes its noise to stderr).
180
+ async function runIosPull(build, env = {}) {
179
181
  const script = (await new CachePullStepExecutor().execute({ technology: 'ios' }, {}, testConfigNoPeer)).script;
180
182
  const dir = mkdtempSync(join(tmpdir(), 'cibuild-cache-'));
181
183
  try {
182
184
  build(dir);
183
185
  const scriptPath = join(dir, '__cache_pull.sh');
184
186
  writeFileSync(scriptPath, script);
185
- let out = '';
187
+ let stdout = '';
188
+ let stderr = '';
186
189
  try {
187
- out = execFileSync('bash', [scriptPath], {
190
+ stdout = execFileSync('bash', [scriptPath], {
188
191
  cwd: dir,
189
192
  encoding: 'utf-8',
190
193
  stdio: ['ignore', 'pipe', 'pipe'],
194
+ env: { ...process.env, ...env },
195
+ timeout: 20000,
191
196
  });
192
197
  }
193
198
  catch (e) {
194
199
  const err = e;
195
- out = `${err.stdout ?? ''}${err.stderr ?? ''}`;
200
+ stdout = String(err.stdout ?? '');
201
+ stderr = String(err.stderr ?? '');
196
202
  }
197
- const m = out.match(/CACHE_KEY=(\S+)/);
198
- if (!m)
199
- throw new Error(`No CACHE_KEY in output:\n${out}`);
200
- return m[1];
203
+ return { stdout, stderr, combined: stdout + stderr };
201
204
  }
202
205
  finally {
203
206
  rmSync(dir, { recursive: true, force: true });
204
207
  }
205
208
  }
209
+ async function resolveIosCacheKey(build) {
210
+ const { combined } = await runIosPull(build);
211
+ const m = combined.match(/CACHE_KEY=(\S+)/);
212
+ if (!m)
213
+ throw new Error(`No CACHE_KEY in output:\n${combined}`);
214
+ return m[1];
215
+ }
216
+ function writeSpmFixture(dir) {
217
+ const swiftpm = join(dir, 'App.xcodeproj/project.xcworkspace/xcshareddata/swiftpm');
218
+ mkdirSync(swiftpm, { recursive: true });
219
+ writeFileSync(join(swiftpm, 'Package.resolved'), '{"pins":[],"version":3}');
220
+ }
221
+ test('a cold daemon miss does not print curl/zstd noise', async () => {
222
+ // Reproduce the runner setup: a configured cache daemon whose
223
+ // probe fails for an uncached key. (We point at a closed port so
224
+ // curl errors instantly with no server handle to leak — the fix
225
+ // silences curl's stderr regardless of the failure mode, exactly
226
+ // as it does for the 404 seen in production.) The probe must fall
227
+ // through to cold quietly: no "curl:" or "unexpected end of file".
228
+ const { stdout, combined } = await runIosPull(writeSpmFixture, {
229
+ CIBUILD_CACHE_DAEMON: 'http://127.0.0.1:1',
230
+ });
231
+ expect(combined).not.toContain('curl:');
232
+ expect(combined).not.toContain('unexpected end of file');
233
+ // Still resolves the SPM key and reports a cold miss.
234
+ expect(stdout).toContain('CACHE_SOURCE=cold');
235
+ expect(stdout).toMatch(/CACHE_KEY=spm-/);
236
+ });
206
237
  test('SPM project (Package.resolved, no Podfile.lock) resolves an spm- key', async () => {
207
238
  const key = await resolveIosCacheKey((dir) => {
208
239
  // Real Xcode SPM location — Package.resolved committed under
209
240
  // the shared xcworkspace data, no Podfile.lock anywhere.
210
- const swiftpm = join(dir, 'Everli.xcodeproj/project.xcworkspace/xcshareddata/swiftpm');
241
+ const swiftpm = join(dir, 'App.xcodeproj/project.xcworkspace/xcshareddata/swiftpm');
211
242
  mkdirSync(swiftpm, { recursive: true });
212
243
  writeFileSync(join(swiftpm, 'Package.resolved'), '{"pins":[],"version":3}');
213
244
  });
@@ -0,0 +1,120 @@
1
+ /**
2
+ * ui-fidelity-render step implementation.
3
+ *
4
+ * Renders parameterless SwiftUI views from a user's SwiftPM package to PNGs
5
+ * with SwiftUI's ImageRenderer on a macOS runner — no app build, no
6
+ * simulator. The step returns a self-contained node script that, at runtime:
7
+ *
8
+ * 1. Reads `.ci/inputs/params.json`
9
+ * ({ "screens": { "<ViewTypeName>": "<referenceFileBasename>" } });
10
+ * reference images live at `.ci/inputs/<basename>`.
11
+ * 2. Synthesizes a throwaway SwiftPM harness package that depends on the
12
+ * user's package and contains ONE executable target per screen, so a
13
+ * compile failure for one screen (unknown view type, unavailable init)
14
+ * never breaks the others. A screen-free probe target distinguishes
15
+ * "this screen is broken" from "the whole package does not build for
16
+ * macOS" (RENDER_UNSUPPORTED).
17
+ * 3. Builds and runs each per-screen executable, which constructs the view
18
+ * strictly as `<ViewTypeName>()`, renders at render_size x scale on the
19
+ * MainActor, and writes a PNG via CGImage + ImageIO.
20
+ * 4. Writes, inside the artifacts dir (${CIBUILD_ARTIFACTS_DIR:-.ci/artifacts}):
21
+ * - ui-fidelity/rendered/<Screen>.png
22
+ * - ui-fidelity/references/<Screen>.png (one copy per screen, even when
23
+ * two screens share a reference basename)
24
+ * - protocol-result.json (always written, even on partial/total failure;
25
+ * when params.json is absent/malformed the screens array is empty
26
+ * because screens cannot be enumerated)
27
+ * 5. Exits non-zero iff any screen is not "rendered".
28
+ *
29
+ * protocol-result.json contains relative paths only: image paths are relative
30
+ * to the artifacts dir, and error messages are sanitized so absolute runner
31
+ * paths (resolved package_path, harness temp dir, compiler diagnostics) are
32
+ * rewritten to relative paths or placeholders before they are stored.
33
+ */
34
+ import { BaseStepExecutor } from './base.js';
35
+ import type { StepDef, CIConfig } from '../../types.js';
36
+ import type { ValidationRequirement } from '../validation-types.js';
37
+ /**
38
+ * Inputs for the ui-fidelity-render step
39
+ */
40
+ export interface UiFidelityRenderInputs {
41
+ /** Path to the user's SwiftPM package (the package that defines the screens) */
42
+ package_path: string;
43
+ /** SPM library product/target to import in the render harness */
44
+ target: string;
45
+ /** Render size in device points, formatted "<width>x<height>" (default 393x852) */
46
+ render_size?: string;
47
+ /** Display scale factor applied to the render (default 2) */
48
+ scale?: number | string;
49
+ }
50
+ /**
51
+ * Default render size in device points. 393x852 is the iPhone-class portrait
52
+ * canvas shared by the iPhone 14 Pro / 15 / 16 — the most common modern
53
+ * iPhone logical resolution, so renders line up with design references by
54
+ * default.
55
+ */
56
+ export declare const DEFAULT_RENDER_SIZE = "393x852";
57
+ /** Default display scale (@2x), matching how references are typically exported. */
58
+ export declare const DEFAULT_SCALE = 2;
59
+ export interface RenderSize {
60
+ width: number;
61
+ height: number;
62
+ }
63
+ /**
64
+ * Parses a "<width>x<height>" render size string (device points).
65
+ * @throws Error when the value is malformed or non-positive
66
+ */
67
+ export declare function parseRenderSize(value: string): RenderSize;
68
+ /**
69
+ * Parses the scale input into a positive finite number.
70
+ * @throws Error when the value is not a positive number
71
+ */
72
+ export declare function parseScale(value: number | string): number;
73
+ /**
74
+ * Configuration baked into the generated runtime script at YAML-conversion
75
+ * time. Everything else (screens, references) is read at runtime from
76
+ * .ci/inputs/params.json.
77
+ */
78
+ export interface RenderScriptConfig {
79
+ packagePath: string;
80
+ target: string;
81
+ width: number;
82
+ height: number;
83
+ scale: number;
84
+ }
85
+ /** Options consumed by the pure Swift-source generators. */
86
+ export interface HarnessGeneratorOptions {
87
+ packagePath: string;
88
+ packageRef: string;
89
+ target: string;
90
+ width: number;
91
+ height: number;
92
+ scale: number;
93
+ }
94
+ /** The generator functions embedded in (and shared with) the runtime script. */
95
+ export interface RenderScriptInternals {
96
+ swiftStringLiteral(value: string): string;
97
+ generateHarnessPackageSwift(screens: string[], options: HarnessGeneratorOptions): string;
98
+ generateProbeSwift(options: HarnessGeneratorOptions): string;
99
+ generateScreenSwift(screen: string, options: HarnessGeneratorOptions): string;
100
+ }
101
+ /**
102
+ * Evaluates the embedded generator source and returns the real functions, so
103
+ * unit tests exercise exactly the code that ships inside the runtime script.
104
+ */
105
+ export declare function getRenderScriptInternals(): RenderScriptInternals;
106
+ /**
107
+ * Generates the self-contained runtime node script for the step.
108
+ * Pure function of its config — exported so tests can execute the script.
109
+ */
110
+ export declare function generateRenderScript(config: RenderScriptConfig): string;
111
+ /**
112
+ * ui-fidelity-render step executor.
113
+ * Returns a node-kind StepDef whose script performs the render at runtime on
114
+ * the macOS runner.
115
+ */
116
+ export declare class UiFidelityRenderStepExecutor extends BaseStepExecutor {
117
+ getValidationRequirements(inputs: UiFidelityRenderInputs, _env: Record<string, string>, _config: CIConfig): ValidationRequirement[];
118
+ execute(inputs: UiFidelityRenderInputs, _env: Record<string, string>, _config: CIConfig): Promise<StepDef>;
119
+ }
120
+ //# sourceMappingURL=ui-fidelity-render.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ui-fidelity-render.d.ts","sourceRoot":"","sources":["../../../../src/yaml/steps/ui-fidelity-render.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgCG;AAEH,OAAO,EAAE,gBAAgB,EAAE,MAAM,WAAW,CAAC;AAC7C,OAAO,KAAK,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAC;AACxD,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,wBAAwB,CAAC;AAEpE;;GAEG;AACH,MAAM,WAAW,sBAAsB;IACrC,gFAAgF;IAChF,YAAY,EAAE,MAAM,CAAC;IACrB,iEAAiE;IACjE,MAAM,EAAE,MAAM,CAAC;IACf,mFAAmF;IACnF,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,6DAA6D;IAC7D,KAAK,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;CACzB;AAED;;;;;GAKG;AACH,eAAO,MAAM,mBAAmB,YAAY,CAAC;AAE7C,mFAAmF;AACnF,eAAO,MAAM,aAAa,IAAI,CAAC;AAE/B,MAAM,WAAW,UAAU;IACzB,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;CAChB;AAED;;;GAGG;AACH,wBAAgB,eAAe,CAAC,KAAK,EAAE,MAAM,GAAG,UAAU,CAWzD;AAED;;;GAGG;AACH,wBAAgB,UAAU,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,GAAG,MAAM,CAQzD;AAED;;;;GAIG;AACH,MAAM,WAAW,kBAAkB;IACjC,WAAW,EAAE,MAAM,CAAC;IACpB,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;CACf;AAED,4DAA4D;AAC5D,MAAM,WAAW,uBAAuB;IACtC,WAAW,EAAE,MAAM,CAAC;IACpB,UAAU,EAAE,MAAM,CAAC;IACnB,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;CACf;AAED,gFAAgF;AAChF,MAAM,WAAW,qBAAqB;IACpC,kBAAkB,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAAC;IAC1C,2BAA2B,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE,OAAO,EAAE,uBAAuB,GAAG,MAAM,CAAC;IACzF,kBAAkB,CAAC,OAAO,EAAE,uBAAuB,GAAG,MAAM,CAAC;IAC7D,mBAAmB,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,uBAAuB,GAAG,MAAM,CAAC;CAC/E;AA6eD;;;GAGG;AACH,wBAAgB,wBAAwB,IAAI,qBAAqB,CAShE;AAED;;;GAGG;AACH,wBAAgB,oBAAoB,CAAC,MAAM,EAAE,kBAAkB,GAAG,MAAM,CAQvE;AAED;;;;GAIG;AACH,qBAAa,4BAA6B,SAAQ,gBAAgB;IAChE,yBAAyB,CACvB,MAAM,EAAE,sBAAsB,EAC9B,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,EAC5B,OAAO,EAAE,QAAQ,GAChB,qBAAqB,EAAE;IAoBpB,OAAO,CACX,MAAM,EAAE,sBAAsB,EAC9B,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,EAC5B,OAAO,EAAE,QAAQ,GAChB,OAAO,CAAC,OAAO,CAAC;CAoBpB"}