@mseep/dembrandt 0.19.5

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 (139) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +408 -0
  3. package/dist/index.d.ts +8 -0
  4. package/dist/index.js +532 -0
  5. package/dist/index.js.map +1 -0
  6. package/dist/lib/browser.d.ts +16 -0
  7. package/dist/lib/browser.js +27 -0
  8. package/dist/lib/browser.js.map +1 -0
  9. package/dist/lib/colors.d.ts +101 -0
  10. package/dist/lib/colors.js +405 -0
  11. package/dist/lib/colors.js.map +1 -0
  12. package/dist/lib/compare.d.ts +31 -0
  13. package/dist/lib/compare.js +46 -0
  14. package/dist/lib/compare.js.map +1 -0
  15. package/dist/lib/discovery.d.ts +31 -0
  16. package/dist/lib/discovery.js +243 -0
  17. package/dist/lib/discovery.js.map +1 -0
  18. package/dist/lib/drift.d.ts +64 -0
  19. package/dist/lib/drift.js +383 -0
  20. package/dist/lib/drift.js.map +1 -0
  21. package/dist/lib/dtcg/validate.d.ts +51 -0
  22. package/dist/lib/dtcg/validate.js +1403 -0
  23. package/dist/lib/dtcg/validate.js.map +1 -0
  24. package/dist/lib/exit-codes.d.ts +29 -0
  25. package/dist/lib/exit-codes.js +26 -0
  26. package/dist/lib/exit-codes.js.map +1 -0
  27. package/dist/lib/extractors/breakpoints.d.ts +5 -0
  28. package/dist/lib/extractors/breakpoints.js +450 -0
  29. package/dist/lib/extractors/breakpoints.js.map +1 -0
  30. package/dist/lib/extractors/colors.d.ts +2 -0
  31. package/dist/lib/extractors/colors.js +657 -0
  32. package/dist/lib/extractors/colors.js.map +1 -0
  33. package/dist/lib/extractors/components.d.ts +4 -0
  34. package/dist/lib/extractors/components.js +370 -0
  35. package/dist/lib/extractors/components.js.map +1 -0
  36. package/dist/lib/extractors/index.d.ts +9 -0
  37. package/dist/lib/extractors/index.js +1257 -0
  38. package/dist/lib/extractors/index.js.map +1 -0
  39. package/dist/lib/extractors/logo.d.ts +2 -0
  40. package/dist/lib/extractors/logo.js +626 -0
  41. package/dist/lib/extractors/logo.js.map +1 -0
  42. package/dist/lib/extractors/spacing.d.ts +4 -0
  43. package/dist/lib/extractors/spacing.js +163 -0
  44. package/dist/lib/extractors/spacing.js.map +1 -0
  45. package/dist/lib/extractors/teach.d.ts +1 -0
  46. package/dist/lib/extractors/teach.js +66 -0
  47. package/dist/lib/extractors/teach.js.map +1 -0
  48. package/dist/lib/extractors/typography.d.ts +1 -0
  49. package/dist/lib/extractors/typography.js +163 -0
  50. package/dist/lib/extractors/typography.js.map +1 -0
  51. package/dist/lib/findings.d.ts +34 -0
  52. package/dist/lib/findings.js +166 -0
  53. package/dist/lib/findings.js.map +1 -0
  54. package/dist/lib/formatters/dtcg.d.ts +10 -0
  55. package/dist/lib/formatters/dtcg.js +416 -0
  56. package/dist/lib/formatters/dtcg.js.map +1 -0
  57. package/dist/lib/formatters/html.d.ts +25 -0
  58. package/dist/lib/formatters/html.js +479 -0
  59. package/dist/lib/formatters/html.js.map +1 -0
  60. package/dist/lib/formatters/markdown.d.ts +5 -0
  61. package/dist/lib/formatters/markdown.js +568 -0
  62. package/dist/lib/formatters/markdown.js.map +1 -0
  63. package/dist/lib/formatters/pdf.d.ts +12 -0
  64. package/dist/lib/formatters/pdf.js +1121 -0
  65. package/dist/lib/formatters/pdf.js.map +1 -0
  66. package/dist/lib/formatters/terminal.d.ts +6 -0
  67. package/dist/lib/formatters/terminal.js +954 -0
  68. package/dist/lib/formatters/terminal.js.map +1 -0
  69. package/dist/lib/formatters/theme.d.ts +35 -0
  70. package/dist/lib/formatters/theme.js +37 -0
  71. package/dist/lib/formatters/theme.js.map +1 -0
  72. package/dist/lib/merger.d.ts +14 -0
  73. package/dist/lib/merger.js +362 -0
  74. package/dist/lib/merger.js.map +1 -0
  75. package/dist/lib/normalize.d.ts +29 -0
  76. package/dist/lib/normalize.js +59 -0
  77. package/dist/lib/normalize.js.map +1 -0
  78. package/dist/lib/robots.d.ts +12 -0
  79. package/dist/lib/robots.js +110 -0
  80. package/dist/lib/robots.js.map +1 -0
  81. package/dist/lib/run-summary.d.ts +40 -0
  82. package/dist/lib/run-summary.js +64 -0
  83. package/dist/lib/run-summary.js.map +1 -0
  84. package/dist/lib/types.d.ts +329 -0
  85. package/dist/lib/types.js +7 -0
  86. package/dist/lib/types.js.map +1 -0
  87. package/dist/lib/version.d.ts +134 -0
  88. package/dist/lib/version.js +153 -0
  89. package/dist/lib/version.js.map +1 -0
  90. package/dist/mcp-server.d.ts +11 -0
  91. package/dist/mcp-server.js +311 -0
  92. package/dist/mcp-server.js.map +1 -0
  93. package/dist/package.json +106 -0
  94. package/dist/test/_vitest-shim.d.ts +13 -0
  95. package/dist/test/_vitest-shim.js +23 -0
  96. package/dist/test/_vitest-shim.js.map +1 -0
  97. package/dist/test/cli.test.d.ts +1 -0
  98. package/dist/test/cli.test.js +24 -0
  99. package/dist/test/cli.test.js.map +1 -0
  100. package/dist/test/colors.test.d.ts +1 -0
  101. package/dist/test/colors.test.js +64 -0
  102. package/dist/test/colors.test.js.map +1 -0
  103. package/dist/test/compare.test.d.ts +1 -0
  104. package/dist/test/compare.test.js +57 -0
  105. package/dist/test/compare.test.js.map +1 -0
  106. package/dist/test/drift.test.d.ts +1 -0
  107. package/dist/test/drift.test.js +53 -0
  108. package/dist/test/drift.test.js.map +1 -0
  109. package/dist/test/dtcg-formatter.test.d.ts +1 -0
  110. package/dist/test/dtcg-formatter.test.js +48 -0
  111. package/dist/test/dtcg-formatter.test.js.map +1 -0
  112. package/dist/test/dtcg-validate.test.d.ts +1 -0
  113. package/dist/test/dtcg-validate.test.js +2129 -0
  114. package/dist/test/dtcg-validate.test.js.map +1 -0
  115. package/dist/test/exit-codes.test.d.ts +1 -0
  116. package/dist/test/exit-codes.test.js +53 -0
  117. package/dist/test/exit-codes.test.js.map +1 -0
  118. package/dist/test/findings.test.d.ts +1 -0
  119. package/dist/test/findings.test.js +77 -0
  120. package/dist/test/findings.test.js.map +1 -0
  121. package/dist/test/html.test.d.ts +1 -0
  122. package/dist/test/html.test.js +95 -0
  123. package/dist/test/html.test.js.map +1 -0
  124. package/dist/test/markdown.test.d.ts +1 -0
  125. package/dist/test/markdown.test.js +145 -0
  126. package/dist/test/markdown.test.js.map +1 -0
  127. package/dist/test/merger.test.d.ts +1 -0
  128. package/dist/test/merger.test.js +98 -0
  129. package/dist/test/merger.test.js.map +1 -0
  130. package/dist/test/normalize.test.d.ts +1 -0
  131. package/dist/test/normalize.test.js +47 -0
  132. package/dist/test/normalize.test.js.map +1 -0
  133. package/dist/test/run-summary.test.d.ts +1 -0
  134. package/dist/test/run-summary.test.js +45 -0
  135. package/dist/test/run-summary.test.js.map +1 -0
  136. package/dist/test/version.test.d.ts +1 -0
  137. package/dist/test/version.test.js +73 -0
  138. package/dist/test/version.test.js.map +1 -0
  139. package/package.json +106 -0
@@ -0,0 +1,134 @@
1
+ /**
2
+ * Single source of truth for dembrandt output versioning.
3
+ *
4
+ * Three independent version axes travel with every extraction. Keeping them
5
+ * separate is the whole point: a consumer (dembrandt-next, the MCP client, a
6
+ * skill, the drift engine) must be able to reason about the *output format*
7
+ * without coupling to which CLI release produced it.
8
+ *
9
+ * - toolVersion — the dembrandt CLI release (package.json version, e.g.
10
+ * "0.16.0"). Surfaced as meta.dembrandtVersion. Changes on
11
+ * every npm publish, including pure refactors.
12
+ * - schemaVersion — the dembrandt OUTPUT CONTRACT. Bumps only when the JSON
13
+ * shape changes in a way a consumer must adapt to. A tool
14
+ * release that does not change the shape leaves this alone.
15
+ * - specVersion — the W3C DTCG spec revision the `--dtcg` export targets.
16
+ *
17
+ * Version info is surfaced through the two extraction chokepoints, so every
18
+ * consumer inherits it without special-casing:
19
+ * - native JSON : meta.schemaVersion (alongside meta.dembrandtVersion),
20
+ * produced by extractBranding().
21
+ * - DTCG export : $extensions["com.dembrandt"], produced by toDtcgTokens().
22
+ * The DTCG spec mandates that tools preserve vendor extension
23
+ * data they do not understand, so this block survives a
24
+ * round-trip through any compliant tool.
25
+ *
26
+ * schemaVersion bump policy (semver over the output contract, not the tool):
27
+ * - PATCH : additive, non-semantic (a new optional field a consumer can ignore)
28
+ * - MINOR : additive but meaningful (a new field consumers will want to read)
29
+ * - MAJOR : removal, rename, or changed meaning of an existing field
30
+ * Pre-1.0 the tool used loose semver; the output contract starts clean at 1.0.0,
31
+ * baselined on the 0.16.0 shape (inline SVG logo fields, meta.degraded).
32
+ */
33
+ /**
34
+ * dembrandt output contract version. Bump per the policy documented above.
35
+ *
36
+ * 1.1.0 — added SpacingValue.display, a guaranteed "Npx" string for rendering.
37
+ * Additive: 1.0.x consumers ignore it. Read `display` instead of
38
+ * formatting `px`, whose type narrows from "16px" to a number through
39
+ * normalizeExtraction().
40
+ * 1.0.0 — baselined on the 0.16.0 shape.
41
+ */
42
+ export declare const SCHEMA_VERSION = "1.1.0";
43
+ /** W3C DTCG spec revision the `--dtcg` export targets. */
44
+ export declare const DTCG_SPEC_VERSION = "2025.10";
45
+ /**
46
+ * Reverse-domain key under which all dembrandt-specific data lives in DTCG
47
+ * output. The DTCG spec recommends reverse-domain notation for $extensions keys
48
+ * to avoid vendor clashes, and requires other tools to preserve unknown
49
+ * extension data. This is the only sanctioned channel for proprietary data;
50
+ * never invent custom `$`-prefixed keys or custom `$type` values.
51
+ */
52
+ export declare const EXTENSION_KEY = "com.dembrandt";
53
+ /** Document-level provenance block embedded in DTCG `$extensions`. */
54
+ export interface DembrandtProvenance {
55
+ /** Output contract version (SCHEMA_VERSION). */
56
+ schemaVersion: string;
57
+ /** dembrandt CLI release that produced this, or null if unknown. */
58
+ toolVersion: string | null;
59
+ /** DTCG spec revision the export targets. */
60
+ specVersion: string;
61
+ /** Constant tool identifier. */
62
+ generator: 'dembrandt';
63
+ /** Extraction source. */
64
+ source: {
65
+ url: string | null;
66
+ domain: string;
67
+ };
68
+ /** ISO timestamp of the extraction, or null. */
69
+ extractedAt: string | null;
70
+ }
71
+ /** The slice of an extraction result this module needs to assemble provenance. */
72
+ export interface ExtractionLike {
73
+ url?: string;
74
+ extractedAt?: string;
75
+ meta?: {
76
+ dembrandtVersion?: string | null;
77
+ schemaVersion?: string | null;
78
+ };
79
+ }
80
+ /**
81
+ * Build the canonical `com.dembrandt` provenance block for DTCG `$extensions`.
82
+ * Reads the tool version off the already-assembled native result so there is one
83
+ * place (extractBranding's meta) that owns toolVersion.
84
+ */
85
+ export declare function buildDembrandtProvenance(result?: ExtractionLike): DembrandtProvenance;
86
+ /**
87
+ * Verdict of comparing an extraction's output-contract version against the
88
+ * contract this build understands.
89
+ *
90
+ * - 'current' : found === SCHEMA_VERSION exactly.
91
+ * - 'compatible' : same major, different minor/patch. Safe to consume: within a
92
+ * major the contract only changes additively, so a newer
93
+ * producer just carries extra fields a consumer can ignore,
94
+ * and an older producer is missing fields a consumer tolerates.
95
+ * - 'outdated' : found major < expected major. A breaking contract change
96
+ * landed since; re-extraction recommended.
97
+ * - 'ahead' : found major > expected major. The producer is newer than
98
+ * this build; upgrade the consumer to read it reliably.
99
+ * - 'legacy' : no schemaVersion present but a toolVersion is. A pre-1.0
100
+ * extraction made before the contract existed.
101
+ * - 'unknown' : no version metadata at all.
102
+ *
103
+ * `compatible` is true only for 'current' and 'compatible'; every other status
104
+ * carries a non-null `message`. This is the single sanctioned compatibility
105
+ * check: consumers (the viewer, dembrandt-next, the drift engine) must compare
106
+ * the OUTPUT CONTRACT here, never the CLI release (`toolVersion`), which churns
107
+ * on every publish and produces false "version mismatch" warnings.
108
+ */
109
+ export type SchemaCompatibilityStatus = 'current' | 'compatible' | 'outdated' | 'ahead' | 'legacy' | 'unknown';
110
+ export interface SchemaCompatibility {
111
+ status: SchemaCompatibilityStatus;
112
+ /** True when the extraction can be consumed without caveats. */
113
+ compatible: boolean;
114
+ /** schemaVersion read off the extraction, or null when absent. */
115
+ found: string | null;
116
+ /** The contract version this build understands (SCHEMA_VERSION). */
117
+ expected: string;
118
+ /** CLI release that produced the extraction, for diagnostics only. */
119
+ toolVersion: string | null;
120
+ /** Human-readable caveat, or null when status is 'current' / 'compatible'. */
121
+ message: string | null;
122
+ }
123
+ /**
124
+ * Compare an extraction's output-contract version against this build's
125
+ * SCHEMA_VERSION. Never throws: malformed or missing version data degrades to
126
+ * 'unknown' / 'legacy'. See SchemaCompatibility for the status semantics.
127
+ */
128
+ export declare function checkSchemaCompatibility(result?: ExtractionLike): SchemaCompatibility;
129
+ /**
130
+ * One-line notice for surfacing a compatibility verdict in a UI or log. Returns
131
+ * null when there is nothing to warn about, so callers can render unconditionally:
132
+ * `const notice = formatCompatibilityNotice(checkSchemaCompatibility(result));`
133
+ */
134
+ export declare function formatCompatibilityNotice(compat: SchemaCompatibility): string | null;
@@ -0,0 +1,153 @@
1
+ /**
2
+ * Single source of truth for dembrandt output versioning.
3
+ *
4
+ * Three independent version axes travel with every extraction. Keeping them
5
+ * separate is the whole point: a consumer (dembrandt-next, the MCP client, a
6
+ * skill, the drift engine) must be able to reason about the *output format*
7
+ * without coupling to which CLI release produced it.
8
+ *
9
+ * - toolVersion — the dembrandt CLI release (package.json version, e.g.
10
+ * "0.16.0"). Surfaced as meta.dembrandtVersion. Changes on
11
+ * every npm publish, including pure refactors.
12
+ * - schemaVersion — the dembrandt OUTPUT CONTRACT. Bumps only when the JSON
13
+ * shape changes in a way a consumer must adapt to. A tool
14
+ * release that does not change the shape leaves this alone.
15
+ * - specVersion — the W3C DTCG spec revision the `--dtcg` export targets.
16
+ *
17
+ * Version info is surfaced through the two extraction chokepoints, so every
18
+ * consumer inherits it without special-casing:
19
+ * - native JSON : meta.schemaVersion (alongside meta.dembrandtVersion),
20
+ * produced by extractBranding().
21
+ * - DTCG export : $extensions["com.dembrandt"], produced by toDtcgTokens().
22
+ * The DTCG spec mandates that tools preserve vendor extension
23
+ * data they do not understand, so this block survives a
24
+ * round-trip through any compliant tool.
25
+ *
26
+ * schemaVersion bump policy (semver over the output contract, not the tool):
27
+ * - PATCH : additive, non-semantic (a new optional field a consumer can ignore)
28
+ * - MINOR : additive but meaningful (a new field consumers will want to read)
29
+ * - MAJOR : removal, rename, or changed meaning of an existing field
30
+ * Pre-1.0 the tool used loose semver; the output contract starts clean at 1.0.0,
31
+ * baselined on the 0.16.0 shape (inline SVG logo fields, meta.degraded).
32
+ */
33
+ // URL is a global in both the Node and DOM libs; no import needed.
34
+ /**
35
+ * dembrandt output contract version. Bump per the policy documented above.
36
+ *
37
+ * 1.1.0 — added SpacingValue.display, a guaranteed "Npx" string for rendering.
38
+ * Additive: 1.0.x consumers ignore it. Read `display` instead of
39
+ * formatting `px`, whose type narrows from "16px" to a number through
40
+ * normalizeExtraction().
41
+ * 1.0.0 — baselined on the 0.16.0 shape.
42
+ */
43
+ export const SCHEMA_VERSION = '1.1.0';
44
+ /** W3C DTCG spec revision the `--dtcg` export targets. */
45
+ export const DTCG_SPEC_VERSION = '2025.10';
46
+ /**
47
+ * Reverse-domain key under which all dembrandt-specific data lives in DTCG
48
+ * output. The DTCG spec recommends reverse-domain notation for $extensions keys
49
+ * to avoid vendor clashes, and requires other tools to preserve unknown
50
+ * extension data. This is the only sanctioned channel for proprietary data;
51
+ * never invent custom `$`-prefixed keys or custom `$type` values.
52
+ */
53
+ export const EXTENSION_KEY = 'com.dembrandt';
54
+ /**
55
+ * Derive a clean domain from an extraction URL. Returns 'unknown' on failure so
56
+ * the contract never throws while assembling metadata.
57
+ */
58
+ function domainOf(url) {
59
+ if (!url)
60
+ return 'unknown';
61
+ try {
62
+ return new URL(url).hostname.replace(/^www\./, '');
63
+ }
64
+ catch {
65
+ return 'unknown';
66
+ }
67
+ }
68
+ /**
69
+ * Build the canonical `com.dembrandt` provenance block for DTCG `$extensions`.
70
+ * Reads the tool version off the already-assembled native result so there is one
71
+ * place (extractBranding's meta) that owns toolVersion.
72
+ */
73
+ export function buildDembrandtProvenance(result = {}) {
74
+ return {
75
+ schemaVersion: SCHEMA_VERSION,
76
+ toolVersion: result?.meta?.dembrandtVersion ?? null,
77
+ specVersion: DTCG_SPEC_VERSION,
78
+ generator: 'dembrandt',
79
+ source: {
80
+ url: result?.url ?? null,
81
+ domain: domainOf(result?.url),
82
+ },
83
+ extractedAt: result?.extractedAt ?? null,
84
+ };
85
+ }
86
+ /** Parse a semver-ish string into its numeric parts, or null if unparseable. */
87
+ function parseSemver(v) {
88
+ if (!v)
89
+ return null;
90
+ const m = /^(\d+)\.(\d+)\.(\d+)/.exec(v.trim());
91
+ if (!m)
92
+ return null;
93
+ return { major: Number(m[1]), minor: Number(m[2]), patch: Number(m[3]) };
94
+ }
95
+ /**
96
+ * Compare an extraction's output-contract version against this build's
97
+ * SCHEMA_VERSION. Never throws: malformed or missing version data degrades to
98
+ * 'unknown' / 'legacy'. See SchemaCompatibility for the status semantics.
99
+ */
100
+ export function checkSchemaCompatibility(result = {}) {
101
+ const found = result?.meta?.schemaVersion ?? null;
102
+ const toolVersion = result?.meta?.dembrandtVersion ?? null;
103
+ const base = { found, expected: SCHEMA_VERSION, toolVersion };
104
+ const foundParts = parseSemver(found);
105
+ if (!foundParts) {
106
+ if (toolVersion) {
107
+ return {
108
+ ...base,
109
+ status: 'legacy',
110
+ compatible: false,
111
+ message: `Extraction predates the schema contract (produced by dembrandt v${toolVersion}, ` +
112
+ `no schemaVersion). Re-extract with the current release to validate against ` +
113
+ `schema ${SCHEMA_VERSION}. Reading best-effort.`,
114
+ };
115
+ }
116
+ return {
117
+ ...base,
118
+ status: 'unknown',
119
+ compatible: false,
120
+ message: 'No version metadata on this extraction. Cannot verify schema compatibility; reading best-effort.',
121
+ };
122
+ }
123
+ const expectedParts = parseSemver(SCHEMA_VERSION);
124
+ if (foundParts.major === expectedParts.major) {
125
+ const status = found === SCHEMA_VERSION ? 'current' : 'compatible';
126
+ return { ...base, status, compatible: true, message: null };
127
+ }
128
+ if (foundParts.major < expectedParts.major) {
129
+ return {
130
+ ...base,
131
+ status: 'outdated',
132
+ compatible: false,
133
+ message: `Extraction uses schema ${found}, this build expects ${SCHEMA_VERSION} ` +
134
+ `(breaking change between majors). Re-extract recommended.`,
135
+ };
136
+ }
137
+ return {
138
+ ...base,
139
+ status: 'ahead',
140
+ compatible: false,
141
+ message: `Extraction uses schema ${found}, newer than this build's ${SCHEMA_VERSION} ` +
142
+ `(breaking change between majors). Upgrade dembrandt to read it reliably.`,
143
+ };
144
+ }
145
+ /**
146
+ * One-line notice for surfacing a compatibility verdict in a UI or log. Returns
147
+ * null when there is nothing to warn about, so callers can render unconditionally:
148
+ * `const notice = formatCompatibilityNotice(checkSchemaCompatibility(result));`
149
+ */
150
+ export function formatCompatibilityNotice(compat) {
151
+ return compat.compatible ? null : compat.message;
152
+ }
153
+ //# sourceMappingURL=version.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"version.js","sourceRoot":"","sources":["../../lib/version.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AAEH,mEAAmE;AAEnE;;;;;;;;GAQG;AACH,MAAM,CAAC,MAAM,cAAc,GAAG,OAAO,CAAC;AAEtC,0DAA0D;AAC1D,MAAM,CAAC,MAAM,iBAAiB,GAAG,SAAS,CAAC;AAE3C;;;;;;GAMG;AACH,MAAM,CAAC,MAAM,aAAa,GAAG,eAAe,CAAC;AAyB7C;;;GAGG;AACH,SAAS,QAAQ,CAAC,GAA8B;IAC9C,IAAI,CAAC,GAAG;QAAE,OAAO,SAAS,CAAC;IAC3B,IAAI,CAAC;QACH,OAAO,IAAI,GAAG,CAAC,GAAG,CAAC,CAAC,QAAQ,CAAC,OAAO,CAAC,QAAQ,EAAE,EAAE,CAAC,CAAC;IACrD,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,SAAS,CAAC;IACnB,CAAC;AACH,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,wBAAwB,CAAC,SAAyB,EAAE;IAClE,OAAO;QACL,aAAa,EAAE,cAAc;QAC7B,WAAW,EAAE,MAAM,EAAE,IAAI,EAAE,gBAAgB,IAAI,IAAI;QACnD,WAAW,EAAE,iBAAiB;QAC9B,SAAS,EAAE,WAAW;QACtB,MAAM,EAAE;YACN,GAAG,EAAE,MAAM,EAAE,GAAG,IAAI,IAAI;YACxB,MAAM,EAAE,QAAQ,CAAC,MAAM,EAAE,GAAG,CAAC;SAC9B;QACD,WAAW,EAAE,MAAM,EAAE,WAAW,IAAI,IAAI;KACzC,CAAC;AACJ,CAAC;AA+CD,gFAAgF;AAChF,SAAS,WAAW,CAAC,CAA4B;IAC/C,IAAI,CAAC,CAAC;QAAE,OAAO,IAAI,CAAC;IACpB,MAAM,CAAC,GAAG,sBAAsB,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC;IAChD,IAAI,CAAC,CAAC;QAAE,OAAO,IAAI,CAAC;IACpB,OAAO,EAAE,KAAK,EAAE,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;AAC3E,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,wBAAwB,CAAC,SAAyB,EAAE;IAClE,MAAM,KAAK,GAAG,MAAM,EAAE,IAAI,EAAE,aAAa,IAAI,IAAI,CAAC;IAClD,MAAM,WAAW,GAAG,MAAM,EAAE,IAAI,EAAE,gBAAgB,IAAI,IAAI,CAAC;IAC3D,MAAM,IAAI,GAAG,EAAE,KAAK,EAAE,QAAQ,EAAE,cAAc,EAAE,WAAW,EAAE,CAAC;IAE9D,MAAM,UAAU,GAAG,WAAW,CAAC,KAAK,CAAC,CAAC;IACtC,IAAI,CAAC,UAAU,EAAE,CAAC;QAChB,IAAI,WAAW,EAAE,CAAC;YAChB,OAAO;gBACL,GAAG,IAAI;gBACP,MAAM,EAAE,QAAQ;gBAChB,UAAU,EAAE,KAAK;gBACjB,OAAO,EACL,mEAAmE,WAAW,IAAI;oBAClF,6EAA6E;oBAC7E,UAAU,cAAc,wBAAwB;aACnD,CAAC;QACJ,CAAC;QACD,OAAO;YACL,GAAG,IAAI;YACP,MAAM,EAAE,SAAS;YACjB,UAAU,EAAE,KAAK;YACjB,OAAO,EACL,kGAAkG;SACrG,CAAC;IACJ,CAAC;IAED,MAAM,aAAa,GAAG,WAAW,CAAC,cAAc,CAAE,CAAC;IAEnD,IAAI,UAAU,CAAC,KAAK,KAAK,aAAa,CAAC,KAAK,EAAE,CAAC;QAC7C,MAAM,MAAM,GACV,KAAK,KAAK,cAAc,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,YAAY,CAAC;QACtD,OAAO,EAAE,GAAG,IAAI,EAAE,MAAM,EAAE,UAAU,EAAE,IAAI,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC;IAC9D,CAAC;IAED,IAAI,UAAU,CAAC,KAAK,GAAG,aAAa,CAAC,KAAK,EAAE,CAAC;QAC3C,OAAO;YACL,GAAG,IAAI;YACP,MAAM,EAAE,UAAU;YAClB,UAAU,EAAE,KAAK;YACjB,OAAO,EACL,0BAA0B,KAAK,wBAAwB,cAAc,GAAG;gBACxE,2DAA2D;SAC9D,CAAC;IACJ,CAAC;IAED,OAAO;QACL,GAAG,IAAI;QACP,MAAM,EAAE,OAAO;QACf,UAAU,EAAE,KAAK;QACjB,OAAO,EACL,0BAA0B,KAAK,6BAA6B,cAAc,GAAG;YAC7E,0EAA0E;KAC7E,CAAC;AACJ,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,yBAAyB,CAAC,MAA2B;IACnE,OAAO,MAAM,CAAC,UAAU,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC;AACnD,CAAC"}
@@ -0,0 +1,11 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * Dembrandt MCP Server
4
+ *
5
+ * Extract design tokens from any live website. Works with Claude Code, Cursor,
6
+ * Windsurf, and any MCP-compatible client.
7
+ *
8
+ * Install:
9
+ * claude mcp add --transport stdio dembrandt -- npx -y --package dembrandt dembrandt-mcp
10
+ */
11
+ export {};
@@ -0,0 +1,311 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * Dembrandt MCP Server
4
+ *
5
+ * Extract design tokens from any live website. Works with Claude Code, Cursor,
6
+ * Windsurf, and any MCP-compatible client.
7
+ *
8
+ * Install:
9
+ * claude mcp add --transport stdio dembrandt -- npx -y --package dembrandt dembrandt-mcp
10
+ */
11
+ import { readFileSync } from "node:fs";
12
+ import { createRequire } from "node:module";
13
+ import { loadBrowserEngines, PlaywrightMissingError } from "./lib/browser.js";
14
+ import { extractBranding } from "./lib/extractors/index.js";
15
+ import { computeDrift } from "./lib/drift.js";
16
+ import { generateHtmlReport } from "./lib/formatters/html.js";
17
+ const { version } = JSON.parse(readFileSync(new URL("./package.json", import.meta.url), "utf8"));
18
+ /**
19
+ * @modelcontextprotocol/sdk and zod are optional peer dependencies: consumers
20
+ * of the pure exports (drift, types, normalize, dtcg) are not forced to install
21
+ * the MCP stack. The server entry defers their import to startup so a missing
22
+ * install surfaces a clear instruction instead of a raw ERR_MODULE_NOT_FOUND at
23
+ * module load, before any guard could run.
24
+ */
25
+ class McpDepsMissingError extends Error {
26
+ constructor() {
27
+ super("MCP server dependencies not installed, run: npm i @modelcontextprotocol/sdk zod");
28
+ this.name = "McpDepsMissingError";
29
+ }
30
+ }
31
+ async function loadMcpDeps() {
32
+ try {
33
+ const [mcp, stdio, zod] = await Promise.all([
34
+ import("@modelcontextprotocol/sdk/server/mcp.js"),
35
+ import("@modelcontextprotocol/sdk/server/stdio.js"),
36
+ import("zod"),
37
+ ]);
38
+ return { McpServer: mcp.McpServer, StdioServerTransport: stdio.StdioServerTransport, z: zod.z };
39
+ }
40
+ catch {
41
+ throw new McpDepsMissingError();
42
+ }
43
+ }
44
+ // extractBranding expects a spinner — stub it for MCP context
45
+ const nullSpinner = {
46
+ text: "",
47
+ start(msg) { this.text = msg; return this; },
48
+ stop() { return this; },
49
+ succeed(_msg) { return this; },
50
+ fail(_msg) { return this; },
51
+ warn(_msg) { return this; },
52
+ info(_msg) { return this; },
53
+ };
54
+ /**
55
+ * Run extraction with error handling suitable for MCP responses.
56
+ * Returns { ok, data?, error? } so tool handlers never throw.
57
+ */
58
+ async function runExtraction(url, options = {}) {
59
+ if (!/^https?:\/\//i.test(url))
60
+ url = "https://" + url;
61
+ let browser;
62
+ let chromium;
63
+ try {
64
+ ({ chromium } = await loadBrowserEngines());
65
+ }
66
+ catch (err) {
67
+ if (err instanceof PlaywrightMissingError)
68
+ return { ok: false, error: err.message };
69
+ throw err;
70
+ }
71
+ const pwVersion = createRequire(import.meta.url)("playwright-core/package.json").version;
72
+ try {
73
+ browser = await chromium.launch({
74
+ headless: true,
75
+ args: ["--disable-blink-features=AutomationControlled"],
76
+ });
77
+ }
78
+ catch (err) {
79
+ return {
80
+ ok: false,
81
+ error: `Browser launch failed. Install the matching browser: npx playwright@${pwVersion} install chromium\n\n${err.message}`,
82
+ };
83
+ }
84
+ // Suppress console output — extractors.js writes directly to stdout
85
+ // which would corrupt the JSON-RPC stream
86
+ const _log = console.log;
87
+ const _warn = console.warn;
88
+ const _error = console.error;
89
+ console.log = () => { };
90
+ console.warn = () => { };
91
+ console.error = () => { };
92
+ try {
93
+ const data = await extractBranding(url, nullSpinner, browser, {
94
+ navigationTimeout: 90000,
95
+ slow: options.slow || false,
96
+ darkMode: options.darkMode || false,
97
+ mobile: options.mobile || false,
98
+ });
99
+ return { ok: true, data };
100
+ }
101
+ catch (err) {
102
+ const msg = err.message || String(err);
103
+ if (msg.includes("timeout") || msg.includes("Timeout")) {
104
+ return { ok: false, error: `Extraction timed out for ${url}. Try with slow: true for heavy SPAs.` };
105
+ }
106
+ if (msg.includes("net::ERR_NAME_NOT_RESOLVED")) {
107
+ return { ok: false, error: `Could not resolve ${url}. Check the URL.` };
108
+ }
109
+ if (msg.includes("net::ERR_CONNECTION_REFUSED")) {
110
+ return { ok: false, error: `Connection refused by ${url}.` };
111
+ }
112
+ return { ok: false, error: `Extraction failed for ${url}: ${msg}` };
113
+ }
114
+ finally {
115
+ console.log = _log;
116
+ console.warn = _warn;
117
+ console.error = _error;
118
+ await browser.close().catch(() => { });
119
+ }
120
+ }
121
+ function jsonResult(data) {
122
+ return { content: [{ type: "text", text: JSON.stringify(data, null, 2) }] };
123
+ }
124
+ function errorResult(message) {
125
+ return { content: [{ type: "text", text: message }], isError: true };
126
+ }
127
+ // ── Job Queue ──────────────────────────────────────────────────────────
128
+ class JobQueue {
129
+ #jobs = new Map();
130
+ #queue = [];
131
+ #running = new Set();
132
+ #maxConcurrent = 2;
133
+ enqueue(url, opts, pick) {
134
+ const id = `job_${Date.now()}_${Math.random().toString(36).slice(2, 8)}`;
135
+ this.#jobs.set(id, {
136
+ status: "queued",
137
+ url,
138
+ opts,
139
+ pick,
140
+ createdAt: Date.now(),
141
+ startedAt: undefined,
142
+ completedAt: undefined,
143
+ result: undefined,
144
+ error: undefined,
145
+ });
146
+ this.#queue.push(id);
147
+ void this.#drain();
148
+ return id;
149
+ }
150
+ get(id) {
151
+ return this.#jobs.get(id) ?? null;
152
+ }
153
+ cancel(id) {
154
+ const job = this.#jobs.get(id);
155
+ if (!job || job.status !== "queued")
156
+ return false;
157
+ job.status = "cancelled";
158
+ job.completedAt = Date.now();
159
+ const idx = this.#queue.indexOf(id);
160
+ if (idx !== -1)
161
+ this.#queue.splice(idx, 1);
162
+ return true;
163
+ }
164
+ async #drain() {
165
+ while (this.#queue.length > 0 && this.#running.size < this.#maxConcurrent) {
166
+ const id = this.#queue.shift();
167
+ const job = this.#jobs.get(id);
168
+ if (!job || job.status === "cancelled")
169
+ continue;
170
+ job.status = "running";
171
+ job.startedAt = Date.now();
172
+ this.#running.add(id);
173
+ runExtraction(job.url, job.opts)
174
+ .then((result) => {
175
+ if (job.status === "cancelled")
176
+ return;
177
+ if (result.ok) {
178
+ job.status = "completed";
179
+ job.result = job.pick(result.data);
180
+ }
181
+ else {
182
+ job.status = "failed";
183
+ job.error = result.error;
184
+ }
185
+ })
186
+ .catch((err) => {
187
+ if (job.status !== "cancelled") {
188
+ job.status = "failed";
189
+ job.error = err.message || String(err);
190
+ }
191
+ })
192
+ .finally(() => {
193
+ job.completedAt = Date.now();
194
+ this.#running.delete(id);
195
+ void this.#drain();
196
+ });
197
+ }
198
+ }
199
+ // Remove completed/failed/cancelled jobs older than 1 hour
200
+ cleanup() {
201
+ const cutoff = Date.now() - 3_600_000;
202
+ for (const [id, job] of this.#jobs) {
203
+ if (["completed", "failed", "cancelled"].includes(job.status) &&
204
+ job.completedAt !== undefined &&
205
+ job.completedAt < cutoff) {
206
+ this.#jobs.delete(id);
207
+ }
208
+ }
209
+ }
210
+ }
211
+ const jobQueue = new JobQueue();
212
+ setInterval(() => jobQueue.cleanup(), 600_000);
213
+ // ── Helpers ────────────────────────────────────────────────────────────
214
+ /**
215
+ * Wrapper for extraction tools.
216
+ * Async by default: enqueues and returns a job_id immediately.
217
+ * Pass sync: true to block and return the result directly.
218
+ */
219
+ function toolHandler(pick, extraOptions = {}) {
220
+ return async (params) => {
221
+ const { url, slow, darkMode, sync } = params;
222
+ const opts = { slow, darkMode, ...extraOptions };
223
+ if (sync) {
224
+ const result = await runExtraction(url, opts);
225
+ if (!result.ok)
226
+ return errorResult(result.error);
227
+ return jsonResult(pick(result.data));
228
+ }
229
+ const jobId = jobQueue.enqueue(url, opts, pick);
230
+ return jsonResult({ job_id: jobId, status: "queued" });
231
+ };
232
+ }
233
+ // ── Server entry ───────────────────────────────────────────────────────
234
+ async function main() {
235
+ let McpServer, StdioServerTransport, z;
236
+ try {
237
+ ({ McpServer, StdioServerTransport, z } = await loadMcpDeps());
238
+ }
239
+ catch (err) {
240
+ console.error(err.message);
241
+ process.exit(1);
242
+ }
243
+ const server = new McpServer({ name: "dembrandt", version });
244
+ // ── Shared params ──────────────────────────────────────────────────────
245
+ const url = z.string().describe("Website URL (e.g. example.com)");
246
+ const slow = z.boolean().optional().default(false).describe("3x timeouts for heavy SPAs");
247
+ const sync = z.boolean().optional().default(false).describe("Wait for result directly instead of returning a job_id (blocks 15-40s)");
248
+ // ── Extraction tools ───────────────────────────────────────────────────
249
+ server.tool("get_design_tokens", "Extract the full design system from a live website. Launches a real browser, navigates to the site, and returns production-ready design tokens: color palette (hex, RGB, LCH, OKLCH) with semantic roles and CSS custom properties, typography scale (families, fallbacks, sizes, weights, line heights, letter spacing by context), spacing system with grid detection, border radii, border patterns, box shadows for elevation, component styles (buttons with hover/focus states, inputs, links, badges), responsive breakpoints, logo and favicons, site name, detected CSS frameworks, and icon systems. Returns a job_id by default — use get_job_status to poll for the result.", { url, slow, sync }, toolHandler((d) => d));
250
+ server.tool("get_color_palette", "Extract brand colors from a live website. Returns semantic colors (primary, secondary, accent), full palette ranked by usage frequency and confidence (high/medium/low), CSS custom properties with their design-system names, and hover/focus state colors discovered by simulating real user interactions. Each color in hex, RGB, LCH, and OKLCH. Returns a job_id by default — use get_job_status to poll for the result.", {
251
+ url, slow, sync,
252
+ darkMode: z.boolean().optional().default(false).describe("Also extract dark mode palette"),
253
+ }, toolHandler((d) => ({ url: d.url, colors: d.colors })));
254
+ server.tool("get_typography", "Extract typography from a live website. Returns every font family with its fallback stack, the complete type scale grouped by context (heading, body, button, link, caption) with pixel and rem sizes, weights, line heights, letter spacing, and text transforms. Also reports font sources: Google Fonts URLs, Adobe Fonts usage, and variable font detection. Returns a job_id by default — use get_job_status to poll for the result.", { url, slow, sync }, toolHandler((d) => ({ url: d.url, typography: d.typography })));
255
+ server.tool("get_component_styles", "Extract UI component styles from a live website. Returns button variants with default, hover, active, and focus states (background, text color, padding, border radius, border, shadow, outline, opacity), input field styles (border, focus ring, padding, placeholder), link styles (color, text decoration, hover changes), and badge/tag styles. Returns a job_id by default — use get_job_status to poll for the result.", { url, slow, sync }, toolHandler((d) => ({ url: d.url, components: d.components })));
256
+ server.tool("get_surfaces", "Extract surface treatment tokens from a live website: border radii with element context (which radii are used on buttons vs cards vs inputs vs modals), border patterns (width + style + color combinations), and box shadow elevation levels. Returns a job_id by default — use get_job_status to poll for the result.", { url, slow, sync }, toolHandler((d) => ({
257
+ url: d.url,
258
+ borderRadius: d.borderRadius,
259
+ borders: d.borders,
260
+ shadows: d.shadows,
261
+ })));
262
+ server.tool("get_spacing", "Extract the spacing system from a live website: common margin and padding values sorted by frequency, pixel and rem values, and grid system detection (4px, 8px, or custom scale). Returns a job_id by default — use get_job_status to poll for the result.", { url, slow, sync }, toolHandler((d) => ({ url: d.url, spacing: d.spacing })));
263
+ server.tool("get_brand_identity", "Extract brand identity from a live website: site name, logo (source, dimensions, safe zone), all favicon variants (icon, apple-touch-icon, og:image, twitter:image with sizes and URLs), detected CSS frameworks (Tailwind, Bootstrap, MUI, etc.), icon systems (Font Awesome, Material Icons, SVG), and responsive breakpoints. Returns a job_id by default — use get_job_status to poll for the result.", { url, slow, sync }, toolHandler((d) => ({
264
+ url: d.url,
265
+ siteName: d.siteName,
266
+ logo: d.logo,
267
+ favicons: d.favicons,
268
+ frameworks: d.frameworks,
269
+ iconSystem: d.iconSystem,
270
+ breakpoints: d.breakpoints,
271
+ })));
272
+ // ── Drift & report tools (synchronous, no browser) ─────────────────────
273
+ // zod 4: z.record needs explicit key + value types; z.record(z.any()) treats
274
+ // the lone arg as the KEY and leaves value undefined, which crashes tools/list.
275
+ const extract = z.record(z.string(), z.any()).describe("A dembrandt extraction object, as returned by get_design_tokens");
276
+ server.tool("compute_drift", "Compare two dembrandt extractions and return a design-drift report: a 0-100 score (0 = identical), a stable/drift verdict, per-category scores, and the list of changed/added/removed tokens (colors, typography, spacing, radius, shadows). Pure and synchronous — no browser. Use it to check whether generated or updated UI has drifted from a brand baseline.", {
277
+ baseline: extract,
278
+ candidate: extract,
279
+ failThreshold: z.number().optional().describe("Score above this yields a 'drift' verdict (default 10)"),
280
+ }, ({ baseline, candidate, failThreshold }) => {
281
+ const report = computeDrift(baseline, candidate, failThreshold != null ? { failThreshold } : {});
282
+ return jsonResult(report);
283
+ });
284
+ server.tool("render_report", "Render a self-contained HTML report (inline CSS, no external resources) from a dembrandt extraction, optionally including a drift diff. Returns the HTML as text — write it to a .html file to open offline or attach as a CI artifact.", {
285
+ result: extract,
286
+ drift: z.any().optional().describe("A drift report from compute_drift, to render the diff banner"),
287
+ }, ({ result, drift }) => {
288
+ const html = generateHtmlReport(result, { drift: drift ?? undefined });
289
+ return { content: [{ type: "text", text: html }] };
290
+ });
291
+ // ── Job management tools ───────────────────────────────────────────────
292
+ server.tool("get_job_status", "Poll for the result of an async extraction job. Returns status (queued/running/completed/failed/cancelled) and the full result once completed. Call this after any extraction tool that returned a job_id.", { job_id: z.string().describe("The job_id returned by an extraction tool") }, ({ job_id }) => {
293
+ const job = jobQueue.get(job_id);
294
+ if (!job)
295
+ return errorResult(`No job found with id: ${job_id}`);
296
+ if (job.status === "completed")
297
+ return jsonResult({ job_id, status: "completed", result: job.result });
298
+ if (job.status === "failed")
299
+ return errorResult(`Job failed: ${job.error}`);
300
+ return jsonResult({ job_id, status: job.status });
301
+ });
302
+ server.tool("cancel_job", "Cancel a queued extraction job. Has no effect on jobs that are already running.", { job_id: z.string().describe("The job_id to cancel") }, ({ job_id }) => {
303
+ const cancelled = jobQueue.cancel(job_id);
304
+ return jsonResult({ job_id, cancelled });
305
+ });
306
+ // ── Start ──────────────────────────────────────────────────────────────
307
+ const transport = new StdioServerTransport();
308
+ await server.connect(transport);
309
+ }
310
+ await main();
311
+ //# sourceMappingURL=mcp-server.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mcp-server.js","sourceRoot":"","sources":["../mcp-server.ts"],"names":[],"mappings":";AAEA;;;;;;;;GAQG;AAEH,OAAO,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AACvC,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAC5C,OAAO,EAAE,kBAAkB,EAAE,sBAAsB,EAAE,MAAM,kBAAkB,CAAC;AAC9E,OAAO,EAAE,eAAe,EAAE,MAAM,2BAA2B,CAAC;AAC5D,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAC9C,OAAO,EAAE,kBAAkB,EAAE,MAAM,0BAA0B,CAAC;AAE9D,MAAM,EAAE,OAAO,EAAE,GAAG,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,IAAI,GAAG,CAAC,gBAAgB,EAAE,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,MAAM,CAAC,CAAC,CAAC;AAEjG;;;;;;GAMG;AACH,MAAM,mBAAoB,SAAQ,KAAK;IACrC;QACE,KAAK,CAAC,iFAAiF,CAAC,CAAC;QACzF,IAAI,CAAC,IAAI,GAAG,qBAAqB,CAAC;IACpC,CAAC;CACF;AAED,KAAK,UAAU,WAAW;IACxB,IAAI,CAAC;QACH,MAAM,CAAC,GAAG,EAAE,KAAK,EAAE,GAAG,CAAC,GAAG,MAAM,OAAO,CAAC,GAAG,CAAC;YAC1C,MAAM,CAAC,yCAAyC,CAAC;YACjD,MAAM,CAAC,2CAA2C,CAAC;YACnD,MAAM,CAAC,KAAK,CAAC;SACd,CAAC,CAAC;QACH,OAAO,EAAE,SAAS,EAAE,GAAG,CAAC,SAAS,EAAE,oBAAoB,EAAE,KAAK,CAAC,oBAAoB,EAAE,CAAC,EAAE,GAAG,CAAC,CAAC,EAAE,CAAC;IAClG,CAAC;IAAC,MAAM,CAAC;QACP,MAAM,IAAI,mBAAmB,EAAE,CAAC;IAClC,CAAC;AACH,CAAC;AAED,8DAA8D;AAC9D,MAAM,WAAW,GAAG;IAClB,IAAI,EAAE,EAAE;IACR,KAAK,CAAC,GAAG,IAAI,IAAI,CAAC,IAAI,GAAG,GAAG,CAAC,CAAC,OAAO,IAAI,CAAC,CAAC,CAAC;IAC5C,IAAI,KAAK,OAAO,IAAI,CAAC,CAAC,CAAC;IACvB,OAAO,CAAC,IAAI,IAAI,OAAO,IAAI,CAAC,CAAC,CAAC;IAC9B,IAAI,CAAC,IAAI,IAAI,OAAO,IAAI,CAAC,CAAC,CAAC;IAC3B,IAAI,CAAC,IAAI,IAAI,OAAO,IAAI,CAAC,CAAC,CAAC;IAC3B,IAAI,CAAC,IAAI,IAAI,OAAO,IAAI,CAAC,CAAC,CAAC;CAC5B,CAAC;AAEF;;;GAGG;AACH,KAAK,UAAU,aAAa,CAAC,GAAW,EAAE,UAAe,EAAE;IACzD,IAAI,CAAC,eAAe,CAAC,IAAI,CAAC,GAAG,CAAC;QAAE,GAAG,GAAG,UAAU,GAAG,GAAG,CAAC;IACvD,IAAI,OAAO,CAAC;IACZ,IAAI,QAAQ,CAAC;IACb,IAAI,CAAC;QACH,CAAC,EAAE,QAAQ,EAAE,GAAG,MAAM,kBAAkB,EAAE,CAAC,CAAC;IAC9C,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,IAAI,GAAG,YAAY,sBAAsB;YAAE,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,GAAG,CAAC,OAAO,EAAE,CAAC;QACpF,MAAM,GAAG,CAAC;IACZ,CAAC;IACD,MAAM,SAAS,GAAG,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,8BAA8B,CAAC,CAAC,OAAO,CAAC;IACzF,IAAI,CAAC;QACH,OAAO,GAAG,MAAM,QAAQ,CAAC,MAAM,CAAC;YAC9B,QAAQ,EAAE,IAAI;YACd,IAAI,EAAE,CAAC,+CAA+C,CAAC;SACxD,CAAC,CAAC;IACL,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,OAAO;YACL,EAAE,EAAE,KAAK;YACT,KAAK,EAAE,uEAAuE,SAAS,wBAAwB,GAAG,CAAC,OAAO,EAAE;SAC7H,CAAC;IACJ,CAAC;IAED,oEAAoE;IACpE,0CAA0C;IAC1C,MAAM,IAAI,GAAG,OAAO,CAAC,GAAG,CAAC;IACzB,MAAM,KAAK,GAAG,OAAO,CAAC,IAAI,CAAC;IAC3B,MAAM,MAAM,GAAG,OAAO,CAAC,KAAK,CAAC;IAC7B,OAAO,CAAC,GAAG,GAAG,GAAG,EAAE,GAAE,CAAC,CAAC;IACvB,OAAO,CAAC,IAAI,GAAG,GAAG,EAAE,GAAE,CAAC,CAAC;IACxB,OAAO,CAAC,KAAK,GAAG,GAAG,EAAE,GAAE,CAAC,CAAC;IAEzB,IAAI,CAAC;QACH,MAAM,IAAI,GAAG,MAAM,eAAe,CAAC,GAAG,EAAE,WAAW,EAAE,OAAO,EAAE;YAC5D,iBAAiB,EAAE,KAAK;YACxB,IAAI,EAAE,OAAO,CAAC,IAAI,IAAI,KAAK;YAC3B,QAAQ,EAAE,OAAO,CAAC,QAAQ,IAAI,KAAK;YACnC,MAAM,EAAE,OAAO,CAAC,MAAM,IAAI,KAAK;SAChC,CAAC,CAAC;QACH,OAAO,EAAE,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC;IAC5B,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,MAAM,GAAG,GAAG,GAAG,CAAC,OAAO,IAAI,MAAM,CAAC,GAAG,CAAC,CAAC;QACvC,IAAI,GAAG,CAAC,QAAQ,CAAC,SAAS,CAAC,IAAI,GAAG,CAAC,QAAQ,CAAC,SAAS,CAAC,EAAE,CAAC;YACvD,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,4BAA4B,GAAG,uCAAuC,EAAE,CAAC;QACtG,CAAC;QACD,IAAI,GAAG,CAAC,QAAQ,CAAC,4BAA4B,CAAC,EAAE,CAAC;YAC/C,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,qBAAqB,GAAG,kBAAkB,EAAE,CAAC;QAC1E,CAAC;QACD,IAAI,GAAG,CAAC,QAAQ,CAAC,6BAA6B,CAAC,EAAE,CAAC;YAChD,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,yBAAyB,GAAG,GAAG,EAAE,CAAC;QAC/D,CAAC;QACD,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,yBAAyB,GAAG,KAAK,GAAG,EAAE,EAAE,CAAC;IACtE,CAAC;YAAS,CAAC;QACT,OAAO,CAAC,GAAG,GAAG,IAAI,CAAC;QACnB,OAAO,CAAC,IAAI,GAAG,KAAK,CAAC;QACrB,OAAO,CAAC,KAAK,GAAG,MAAM,CAAC;QACvB,MAAM,OAAO,CAAC,KAAK,EAAE,CAAC,KAAK,CAAC,GAAG,EAAE,GAAE,CAAC,CAAC,CAAC;IACxC,CAAC;AACH,CAAC;AAED,SAAS,UAAU,CAAC,IAAI;IACtB,OAAO,EAAE,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC;AAC9E,CAAC;AAED,SAAS,WAAW,CAAC,OAAO;IAC1B,OAAO,EAAE,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,EAAE,CAAC,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC;AACvE,CAAC;AAED,0EAA0E;AAE1E,MAAM,QAAQ;IACZ,KAAK,GAAG,IAAI,GAAG,EAAE,CAAC;IAClB,MAAM,GAAG,EAAE,CAAC;IACZ,QAAQ,GAAG,IAAI,GAAG,EAAE,CAAC;IACrB,cAAc,GAAG,CAAC,CAAC;IAEnB,OAAO,CAAC,GAAG,EAAE,IAAI,EAAE,IAAI;QACrB,MAAM,EAAE,GAAG,OAAO,IAAI,CAAC,GAAG,EAAE,IAAI,IAAI,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC;QACzE,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,EAAE,EAAE;YACjB,MAAM,EAAE,QAAQ;YAChB,GAAG;YACH,IAAI;YACJ,IAAI;YACJ,SAAS,EAAE,IAAI,CAAC,GAAG,EAAE;YACrB,SAAS,EAAE,SAAS;YACpB,WAAW,EAAE,SAAS;YACtB,MAAM,EAAE,SAAS;YACjB,KAAK,EAAE,SAAS;SACjB,CAAC,CAAC;QACH,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;QACrB,KAAK,IAAI,CAAC,MAAM,EAAE,CAAC;QACnB,OAAO,EAAE,CAAC;IACZ,CAAC;IAED,GAAG,CAAC,EAAE;QACJ,OAAO,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,EAAE,CAAC,IAAI,IAAI,CAAC;IACpC,CAAC;IAED,MAAM,CAAC,EAAE;QACP,MAAM,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;QAC/B,IAAI,CAAC,GAAG,IAAI,GAAG,CAAC,MAAM,KAAK,QAAQ;YAAE,OAAO,KAAK,CAAC;QAClD,GAAG,CAAC,MAAM,GAAG,WAAW,CAAC;QACzB,GAAG,CAAC,WAAW,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;QAC7B,MAAM,GAAG,GAAG,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC;QACpC,IAAI,GAAG,KAAK,CAAC,CAAC;YAAE,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC;QAC3C,OAAO,IAAI,CAAC;IACd,CAAC;IAED,KAAK,CAAC,MAAM;QACV,OAAO,IAAI,CAAC,MAAM,CAAC,MAAM,GAAG,CAAC,IAAI,IAAI,CAAC,QAAQ,CAAC,IAAI,GAAG,IAAI,CAAC,cAAc,EAAE,CAAC;YAC1E,MAAM,EAAE,GAAG,IAAI,CAAC,MAAM,CAAC,KAAK,EAAE,CAAC;YAC/B,MAAM,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;YAC/B,IAAI,CAAC,GAAG,IAAI,GAAG,CAAC,MAAM,KAAK,WAAW;gBAAE,SAAS;YAEjD,GAAG,CAAC,MAAM,GAAG,SAAS,CAAC;YACvB,GAAG,CAAC,SAAS,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;YAC3B,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;YAEtB,aAAa,CAAC,GAAG,CAAC,GAAG,EAAE,GAAG,CAAC,IAAI,CAAC;iBAC7B,IAAI,CAAC,CAAC,MAAM,EAAE,EAAE;gBACf,IAAI,GAAG,CAAC,MAAM,KAAK,WAAW;oBAAE,OAAO;gBACvC,IAAI,MAAM,CAAC,EAAE,EAAE,CAAC;oBACd,GAAG,CAAC,MAAM,GAAG,WAAW,CAAC;oBACzB,GAAG,CAAC,MAAM,GAAG,GAAG,CAAC,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;gBACrC,CAAC;qBAAM,CAAC;oBACN,GAAG,CAAC,MAAM,GAAG,QAAQ,CAAC;oBACtB,GAAG,CAAC,KAAK,GAAG,MAAM,CAAC,KAAK,CAAC;gBAC3B,CAAC;YACH,CAAC,CAAC;iBACD,KAAK,CAAC,CAAC,GAAG,EAAE,EAAE;gBACb,IAAI,GAAG,CAAC,MAAM,KAAK,WAAW,EAAE,CAAC;oBAC/B,GAAG,CAAC,MAAM,GAAG,QAAQ,CAAC;oBACtB,GAAG,CAAC,KAAK,GAAG,GAAG,CAAC,OAAO,IAAI,MAAM,CAAC,GAAG,CAAC,CAAC;gBACzC,CAAC;YACH,CAAC,CAAC;iBACD,OAAO,CAAC,GAAG,EAAE;gBACZ,GAAG,CAAC,WAAW,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;gBAC7B,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;gBACzB,KAAK,IAAI,CAAC,MAAM,EAAE,CAAC;YACrB,CAAC,CAAC,CAAC;QACP,CAAC;IACH,CAAC;IAED,2DAA2D;IAC3D,OAAO;QACL,MAAM,MAAM,GAAG,IAAI,CAAC,GAAG,EAAE,GAAG,SAAS,CAAC;QACtC,KAAK,MAAM,CAAC,EAAE,EAAE,GAAG,CAAC,IAAI,IAAI,CAAC,KAAK,EAAE,CAAC;YACnC,IACE,CAAC,WAAW,EAAE,QAAQ,EAAE,WAAW,CAAC,CAAC,QAAQ,CAAC,GAAG,CAAC,MAAM,CAAC;gBACzD,GAAG,CAAC,WAAW,KAAK,SAAS;gBAC7B,GAAG,CAAC,WAAW,GAAG,MAAM,EACxB,CAAC;gBACD,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;YACxB,CAAC;QACH,CAAC;IACH,CAAC;CACF;AAED,MAAM,QAAQ,GAAG,IAAI,QAAQ,EAAE,CAAC;AAChC,WAAW,CAAC,GAAG,EAAE,CAAC,QAAQ,CAAC,OAAO,EAAE,EAAE,OAAO,CAAC,CAAC;AAE/C,0EAA0E;AAE1E;;;;GAIG;AACH,SAAS,WAAW,CAAC,IAAI,EAAE,YAAY,GAAG,EAAE;IAC1C,OAAO,KAAK,EAAE,MAAM,EAAE,EAAE;QACtB,MAAM,EAAE,GAAG,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE,GAAG,MAAM,CAAC;QAC7C,MAAM,IAAI,GAAG,EAAE,IAAI,EAAE,QAAQ,EAAE,GAAG,YAAY,EAAE,CAAC;QAEjD,IAAI,IAAI,EAAE,CAAC;YACT,MAAM,MAAM,GAAG,MAAM,aAAa,CAAC,GAAG,EAAE,IAAI,CAAC,CAAC;YAC9C,IAAI,CAAC,MAAM,CAAC,EAAE;gBAAE,OAAO,WAAW,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;YACjD,OAAO,UAAU,CAAC,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC;QACvC,CAAC;QAED,MAAM,KAAK,GAAG,QAAQ,CAAC,OAAO,CAAC,GAAG,EAAE,IAAI,EAAE,IAAI,CAAC,CAAC;QAChD,OAAO,UAAU,CAAC,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,CAAC,CAAC;IACzD,CAAC,CAAC;AACJ,CAAC;AAED,0EAA0E;AAE1E,KAAK,UAAU,IAAI;IACjB,IAAI,SAAS,EAAE,oBAAoB,EAAE,CAAC,CAAC;IACvC,IAAI,CAAC;QACH,CAAC,EAAE,SAAS,EAAE,oBAAoB,EAAE,CAAC,EAAE,GAAG,MAAM,WAAW,EAAE,CAAC,CAAC;IACjE,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,OAAO,CAAC,KAAK,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;QAC3B,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;IAED,MAAM,MAAM,GAAG,IAAI,SAAS,CAAC,EAAE,IAAI,EAAE,WAAW,EAAE,OAAO,EAAE,CAAC,CAAC;IAE7D,0EAA0E;IAE1E,MAAM,GAAG,GAAG,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,gCAAgC,CAAC,CAAC;IAClE,MAAM,IAAI,GAAG,CAAC,CAAC,OAAO,EAAE,CAAC,QAAQ,EAAE,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,QAAQ,CAAC,4BAA4B,CAAC,CAAC;IAC1F,MAAM,IAAI,GAAG,CAAC,CAAC,OAAO,EAAE,CAAC,QAAQ,EAAE,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,QAAQ,CAAC,wEAAwE,CAAC,CAAC;IAEtI,0EAA0E;IAEzE,MAAM,CAAC,IAAY,CAClB,mBAAmB,EACnB,ypBAAypB,EACzpB,EAAE,GAAG,EAAE,IAAI,EAAE,IAAI,EAAE,EACnB,WAAW,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CACtB,CAAC;IAED,MAAM,CAAC,IAAY,CAClB,mBAAmB,EACnB,+ZAA+Z,EAC/Z;QACE,GAAG,EAAE,IAAI,EAAE,IAAI;QACf,QAAQ,EAAE,CAAC,CAAC,OAAO,EAAE,CAAC,QAAQ,EAAE,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,QAAQ,CAAC,gCAAgC,CAAC;KAC3F,EACD,WAAW,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,EAAE,GAAG,EAAE,CAAC,CAAC,GAAG,EAAE,MAAM,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC,CACvD,CAAC;IAED,MAAM,CAAC,IAAY,CAClB,gBAAgB,EAChB,2aAA2a,EAC3a,EAAE,GAAG,EAAE,IAAI,EAAE,IAAI,EAAE,EACnB,WAAW,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,EAAE,GAAG,EAAE,CAAC,CAAC,GAAG,EAAE,UAAU,EAAE,CAAC,CAAC,UAAU,EAAE,CAAC,CAAC,CAC/D,CAAC;IAED,MAAM,CAAC,IAAY,CAClB,sBAAsB,EACtB,+ZAA+Z,EAC/Z,EAAE,GAAG,EAAE,IAAI,EAAE,IAAI,EAAE,EACnB,WAAW,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,EAAE,GAAG,EAAE,CAAC,CAAC,GAAG,EAAE,UAAU,EAAE,CAAC,CAAC,UAAU,EAAE,CAAC,CAAC,CAC/D,CAAC;IAED,MAAM,CAAC,IAAY,CAClB,cAAc,EACd,yTAAyT,EACzT,EAAE,GAAG,EAAE,IAAI,EAAE,IAAI,EAAE,EACnB,WAAW,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;QAClB,GAAG,EAAE,CAAC,CAAC,GAAG;QACV,YAAY,EAAE,CAAC,CAAC,YAAY;QAC5B,OAAO,EAAE,CAAC,CAAC,OAAO;QAClB,OAAO,EAAE,CAAC,CAAC,OAAO;KACnB,CAAC,CAAC,CACJ,CAAC;IAED,MAAM,CAAC,IAAY,CAClB,aAAa,EACb,6PAA6P,EAC7P,EAAE,GAAG,EAAE,IAAI,EAAE,IAAI,EAAE,EACnB,WAAW,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,EAAE,GAAG,EAAE,CAAC,CAAC,GAAG,EAAE,OAAO,EAAE,CAAC,CAAC,OAAO,EAAE,CAAC,CAAC,CACzD,CAAC;IAED,MAAM,CAAC,IAAY,CAClB,oBAAoB,EACpB,2YAA2Y,EAC3Y,EAAE,GAAG,EAAE,IAAI,EAAE,IAAI,EAAE,EACnB,WAAW,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;QAClB,GAAG,EAAE,CAAC,CAAC,GAAG;QACV,QAAQ,EAAE,CAAC,CAAC,QAAQ;QACpB,IAAI,EAAE,CAAC,CAAC,IAAI;QACZ,QAAQ,EAAE,CAAC,CAAC,QAAQ;QACpB,UAAU,EAAE,CAAC,CAAC,UAAU;QACxB,UAAU,EAAE,CAAC,CAAC,UAAU;QACxB,WAAW,EAAE,CAAC,CAAC,WAAW;KAC3B,CAAC,CAAC,CACJ,CAAC;IAEF,0EAA0E;IAE1E,6EAA6E;IAC7E,gFAAgF;IAChF,MAAM,OAAO,GAAG,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC,GAAG,EAAE,CAAC,CAAC,QAAQ,CAAC,iEAAiE,CAAC,CAAC;IAEzH,MAAM,CAAC,IAAY,CAClB,eAAe,EACf,oWAAoW,EACpW;QACE,QAAQ,EAAE,OAAO;QACjB,SAAS,EAAE,OAAO;QAClB,aAAa,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,wDAAwD,CAAC;KACxG,EACD,CAAC,EAAE,QAAQ,EAAE,SAAS,EAAE,aAAa,EAAO,EAAE,EAAE;QAC9C,MAAM,MAAM,GAAG,YAAY,CAAC,QAAQ,EAAE,SAAS,EAAE,aAAa,IAAI,IAAI,CAAC,CAAC,CAAC,EAAE,aAAa,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;QACjG,OAAO,UAAU,CAAC,MAAM,CAAC,CAAC;IAC5B,CAAC,CACF,CAAC;IAED,MAAM,CAAC,IAAY,CAClB,eAAe,EACf,yOAAyO,EACzO;QACE,MAAM,EAAE,OAAO;QACf,KAAK,EAAE,CAAC,CAAC,GAAG,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,8DAA8D,CAAC;KACnG,EACD,CAAC,EAAE,MAAM,EAAE,KAAK,EAAO,EAAE,EAAE;QACzB,MAAM,IAAI,GAAG,kBAAkB,CAAC,MAAM,EAAE,EAAE,KAAK,EAAE,KAAK,IAAI,SAAS,EAAE,CAAC,CAAC;QACvE,OAAO,EAAE,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,EAAE,CAAC;IACrD,CAAC,CACF,CAAC;IAEF,0EAA0E;IAEzE,MAAM,CAAC,IAAY,CAClB,gBAAgB,EAChB,4MAA4M,EAC5M,EAAE,MAAM,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,2CAA2C,CAAC,EAAE,EAC5E,CAAC,EAAE,MAAM,EAAE,EAAE,EAAE;QACb,MAAM,GAAG,GAAG,QAAQ,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;QACjC,IAAI,CAAC,GAAG;YAAE,OAAO,WAAW,CAAC,yBAAyB,MAAM,EAAE,CAAC,CAAC;QAChE,IAAI,GAAG,CAAC,MAAM,KAAK,WAAW;YAAE,OAAO,UAAU,CAAC,EAAE,MAAM,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,EAAE,GAAG,CAAC,MAAM,EAAE,CAAC,CAAC;QACvG,IAAI,GAAG,CAAC,MAAM,KAAK,QAAQ;YAAE,OAAO,WAAW,CAAC,eAAe,GAAG,CAAC,KAAK,EAAE,CAAC,CAAC;QAC5E,OAAO,UAAU,CAAC,EAAE,MAAM,EAAE,MAAM,EAAE,GAAG,CAAC,MAAM,EAAE,CAAC,CAAC;IACpD,CAAC,CACF,CAAC;IAED,MAAM,CAAC,IAAY,CAClB,YAAY,EACZ,iFAAiF,EACjF,EAAE,MAAM,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,sBAAsB,CAAC,EAAE,EACvD,CAAC,EAAE,MAAM,EAAE,EAAE,EAAE;QACb,MAAM,SAAS,GAAG,QAAQ,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;QAC1C,OAAO,UAAU,CAAC,EAAE,MAAM,EAAE,SAAS,EAAE,CAAC,CAAC;IAC3C,CAAC,CACF,CAAC;IAEF,0EAA0E;IAE1E,MAAM,SAAS,GAAG,IAAI,oBAAoB,EAAE,CAAC;IAC7C,MAAM,MAAM,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;AAClC,CAAC;AAED,MAAM,IAAI,EAAE,CAAC"}