@getvitops/utils 4.0.0 → 5.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.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,177 @@
1
1
  # @getvitops/utils
2
2
 
3
+ ## 5.0.0
4
+
5
+ ### Major Changes
6
+
7
+ - **Dangling token references are now a build failure.** `validate()` resolves every `var(--…)` a
8
+ config authors — in `patterns.defaults` / `radii` / `groups` / `items.*.{base,overrides,states}`,
9
+ `typography.roles` and `shadows` — against the tokens that config actually emits. A reference to a
10
+ token that does not exist used to validate, generate, minify and ship, then resolve to nothing in
11
+ the browser: one downstream config shipped a `.cta` whose `color` fell back to `inherit` on a brand
12
+ fill (unreadable text on every filled button), and two of its four dead references had been dead for
13
+ several releases with nothing ever reporting them.
14
+
15
+ The check is deliberately anchored to the namespaces the generator owns — `--color-*`, `--shadow-*`,
16
+ `--z-tier-*`, `--surface-glass`, `--overlay` — the same discipline `vitops lint` follows. A pattern
17
+ may legitimately reference a framework token from `@getvitops/core` or a hook of your own, and
18
+ enumerating "every valid token" would make those false positives. A reference carrying a fallback
19
+ (`var(--x, 0.25rem)`) is never flagged: that is you saying what happens when the token is absent.
20
+ Errors name the config path and suggest the nearest token that does exist.
21
+
22
+ Two related diagnostics ship with it:
23
+ - **Pre-1.0 colour-grammar references are reported as one rename table**, not as a dozen separate
24
+ "no such token" errors — the shape the 3.0 flat-config detector uses, applied to the 1.0 colour
25
+ change. It is built from your own role names, and it says to apply the renames _simultaneously_,
26
+ because several of them rotate (`--surface-bg` → `--color-bg-surface-muted`,
27
+ `--surface-bg-bold` → `--color-bg-surface`) and sequential replacement compounds them.
28
+ - **A surface-shaped role declared chromatic now warns.** A bare hue string is shorthand for
29
+ `kind: "chromatic"`, which emits no bare `--color-bg-<role>` and no `.bg-<role>` — so writing
30
+ `"surface": "ink"` silently removed `--color-bg-surface` and the 36 references the framework's own
31
+ CSS makes to it. Relatedly, `--surface-glass`, `--overlay` and `.glass` are no longer emitted when
32
+ `surface` is chromatic: they read `--color-bg-surface`, so emitting them pointed at nothing.
33
+
34
+ **`vitops lint --fix` is now the migration tool.** It reads `var(--…)` out of CSS and `<style>`
35
+ blocks (not just `class` attributes) and rewrites pre-1.0 token references in a **single pass**, so
36
+ the rotating renames cannot compound. Nothing else is rewritten — every other finding it reports is
37
+ a judgement call. Run it after a major bump.
38
+
39
+ **`--help` works on every subcommand.** `vitops lint --help` used to exit non-zero with
40
+ `Unknown option '--help'`; every leaf subcommand parsed its own argv strictly and none declared the
41
+ option. It is now answered before dispatch, so no command can forget it, and a drift guard fails the
42
+ build if a command has no documented options. (`validate`'s options were genuinely undocumented and
43
+ now are.)
44
+
45
+ **The Astro integration reads `site.tracking` and `site.legal.cookieConsent`.** These drive the
46
+ generated cookie notice, while `vitops({ consent, tracking })` drove the runtime — two hand-synced
47
+ declarations of the same fact with nothing comparing them, so a site could ship a notice naming
48
+ categories its banner never offered, or disclosing an `_ac` cookie no capture script ever wrote, and
49
+ the build was clean. The config blocks are now defaults (as `css` / `fonts` / `favicon` / `ads`
50
+ already were) and a genuine contradiction — `true` against `false` on the same fact — **fails the
51
+ build**, naming both sides. An absent option is not a contradiction; it just takes the config's
52
+ value.
53
+
54
+ Also fixed, each from a downstream report:
55
+ - **`@getvitops/astro/tracking`** re-exports `@getvitops/utils/tracking` (plus `TRACKING_ENDPOINT`),
56
+ so the documented conversion flow works with one install. Under strict pnpm app code cannot
57
+ resolve a transitive dependency, and the obvious workaround — importing the same symbols from the
58
+ package index — is the one that drags the integration's Node builtins toward a Worker bundle. This
59
+ entry and `./routes` are both clean.
60
+ - **`createConversionRoute`'s example was broken on every supported Astro.** It read the binding off
61
+ `locals.runtime.env`, removed in Astro v6, while the package peers on `>= 7` — and because the
62
+ throw precedes the response, Astro re-reads the request and reports a misleading "Body has already
63
+ been used". It also called a `toNotifyContext()` helper that does not exist. The example now uses
64
+ `import { env } from 'cloudflare:workers'` and a plain `NotifyContext`.
65
+ - **`/api/track` is exported as `TRACKING_ENDPOINT`**, and the integration warns at build when
66
+ tracking is on and no route answers it. It was a bare literal inside the inlined capture script:
67
+ name the route file anything else and every `tel:` beacon 404s, conversions vanish, and nothing
68
+ errors anywhere.
69
+ - **`describeEvent` no longer reports "from Unknown"** for forms that don't have a field literally
70
+ named `name`. It now falls back through `first_name`/`last_name`, `full_name`, and finally the
71
+ email address.
72
+ - **`sendEmail` takes `timeoutMs` (default 10s).** `binding.send()` had no deadline, so one hung
73
+ attempt hung the request that produced it — indefinitely, in the one module otherwise built on
74
+ always saying why. A timeout is retried, like any other transient failure.
75
+ - **`vitops search notify` warns when the sitemap's URLs aren't on the configured origin.** A 404
76
+ fails loudly; a well-formed sitemap belonging to someone else did not — a route collision served a
77
+ valid document listing another site's pages and the run reported a healthy submission. Surfaces at
78
+ `--dry`.
79
+ - **`require()` warns when the page has no `<wc-consent>`.** The demand can never be granted, so
80
+ whatever waited on it never runs — silently. Hit by rendering `<Tracking />` on pages where
81
+ `<CookieConsent />` wasn't.
82
+ - **`vitops agents` no longer writes a path it guessed.** It used to warn and then write "tokens
83
+ live in `design-system.json`" into a project whose tokens are in `company.json`, with the four
84
+ emitted `vitops generate` commands hard-coded to match — copy-paste-broken in exactly the projects
85
+ that most need the block to be right. It now finds the config by shape, interpolates the resolved
86
+ path into every emitted command, and fails rather than guessing when there is nothing to name.
87
+ - **`vitops search setup --dry` and `vitops ads setup --dry` run without credentials.** A dry run
88
+ that mutates nothing should not demand the token to mutate; with none set it plans from scratch
89
+ and says so. (`--check` still needs them — drift is a comparison against live state.) Both now
90
+ also mention that the Cloudflare token needs `Zone:Read` alongside `Zone:DNS:Edit` — the
91
+ zone-by-name lookup uses it, and its absence read as "the zone isn't in this account".
92
+ - **`vitops legal` names the files it wrote and flags new ones.** Enabling `cookieConsent` silently
93
+ produced a `cookie-notice` document that then needs a page, a route, a link and a `policyUrl`; the
94
+ command said only "3 files". The review reminder is also printed on the stdout path, where it was
95
+ missing entirely.
96
+ - **`vitops init` writes a versioned `$schema`** — `./node_modules/@getvitops/generator/schema.json`,
97
+ following wrangler — instead of an unpinned unpkg URL that resolved to whatever was newest, so an
98
+ editor validated a pinned project against a schema it wasn't built with.
99
+ - **`favicon.backgroundColor` and `favicon.name` are described accurately.** `backgroundColor` is
100
+ not manifest-only: it fills the opaque `apple-touch-icon.png` and `icon-mask.png`, which are
101
+ written whether or not a manifest is. `name` documents that it and `themeColor` **together** are
102
+ what make a site installable. The missing-background warning now also fires for a dark opaque mark,
103
+ not only a transparent source — `apple-touch-icon` insets the logo and fills the surround either
104
+ way.
105
+
106
+ ## 4.1.0
107
+
108
+ ### Minor Changes
109
+
110
+ - 2c890c0: Link a site to its ad properties: `site.ads`, `vitops ads`, and `<Ads />`.
111
+
112
+ `vitops search` covers the whole Search Console relationship. Nothing covered the equivalent one
113
+ with ad platforms, and a site's ad accounts had nowhere to live — so a Meta pixel pasted into a
114
+ template was invisible to the rest of the toolchain. It set `_fbp` on a site whose generated cookie
115
+ notice never mentioned it, whose consent gate never cleared it on revoke, and — for LinkedIn and
116
+ Pinterest — whose attribution never captured the click ID at all, so every conversion from those
117
+ platforms arrived indistinguishable from organic traffic.
118
+
119
+ **New `site.ads` block**, keyed by platform (`google`, `meta`, `linkedin`, `reddit`, `tiktok`,
120
+ `microsoft`, `pinterest`, `snapchat`):
121
+
122
+ ```jsonc
123
+ {
124
+ "site": {
125
+ "ads": {
126
+ "meta": { "pixelId": "123456789", "domainVerification": "abc123" },
127
+ "google": {
128
+ "accountId": "123-456-7890",
129
+ "pixelId": "AW-987654321",
130
+ "conversionLabel": "xyz",
131
+ },
132
+ },
133
+ },
134
+ }
135
+ ```
136
+
137
+ **`vitops ads setup`** ensures each platform's domain-verification DNS record. Only four platforms
138
+ verify a domain at all — Meta, TikTok, Pinterest and Snapchat, by apex DNS TXT — and that record is
139
+ the one thing created for you (in Cloudflare, via `CLOUDFLARE_API_TOKEN`; created only, never edited
140
+ or deleted). Google Ads, LinkedIn, Reddit and Microsoft Ads have no domain verification: linking
141
+ there is the tag and the account id, and the run says so rather than skipping in silence. No
142
+ platform Marketing API is called — Meta's needs a system-user token and Google's an approved
143
+ developer token with your own account on the line — so the final "Verify" click is surfaced as a
144
+ reminder. `--dry` prints the plan, `--check` reports drift and exits non-zero.
145
+
146
+ **It asks for what the config is missing.** A verification token does not exist until someone
147
+ fetches it from the platform UI, so a first run prompts for it, naming the exact UI path, folds the
148
+ answer into the plan and writes it to your config. The token is not a secret — it is published in
149
+ DNS, and the platform fetching it back is the ownership proof, exactly like the IndexNow key.
150
+ Prompting requires a TTY: with `--dry`, `--check`, `--no-prompt`, or in CI, you get a named error
151
+ instead and the run never hangs. `--no-write` keeps the answer out of the config.
152
+
153
+ **`vitops ads tags`** prints each pixel as an inert, consent-gated `<script>` — `type="text/plain"`
154
+ with the library URL on `data-src`, so an undecided visitor's page issues no third-party request.
155
+ For Bricks, WordPress, Eleventy: any stack without the Astro integration.
156
+
157
+ **`vitops ads lint`** reports the gaps that are invisible at runtime: a click ID the platform stamps
158
+ that attribution does not capture, a pixel while `site.tracking` is off, a property with no tag id.
159
+
160
+ **`<Ads />` in `@getvitops/astro`**, a sibling of `<Analytics />` rather than part of it — ad
161
+ properties come from the site config, state their own consent category (`marketing` by default,
162
+ rather than being derived), and switch per environment on their own
163
+ (`environments.<env>.ads`, defaulting to `analytics`, then true, so a preview deployment can send
164
+ pageviews without firing conversion pixels). Both components now render through one `<GatedTags />`,
165
+ so the inert markup has a single implementation.
166
+
167
+ **Your cookie notice now discloses every configured pixel** — name, cookies and opt-out — from the
168
+ same table that writes `data-consent-cookies`, so the notice and the revoke cannot disagree. If you
169
+ add `site.ads` to a config whose privacy policy or cookie notice you have already published,
170
+ re-generate and re-read them.
171
+
172
+ `li_fat_id` (LinkedIn) and `epik` (Pinterest) join the click-ID capture vocabulary; a site running
173
+ either platform starts attributing conversions it previously recorded as organic.
174
+
3
175
  ## 4.0.0
4
176
 
5
177
  ### Major Changes
@@ -0,0 +1,228 @@
1
+ import { n as findZoneId, r as listApexTxt, t as createApexTxt } from "../cloudflare-BiK61Oq4.mjs";
2
+
3
+ //#region src/ads/types.d.ts
4
+ /**
5
+ * The ads module's own option surface.
6
+ *
7
+ * Deliberately structural rather than `Config['site']['ads']` imported from
8
+ * `@getvitops/generator`: the generator already depends on this package, so
9
+ * importing back would be a cycle. The vocabulary mirrors that block field for
10
+ * field, so the CLI's adapter is a flat map — the same arrangement, and for the
11
+ * same reason, as `IndexingConfig` and `DomainSetup` beside it.
12
+ *
13
+ * Optional fields are written `?: T | undefined` throughout: `exactOptionalPropertyTypes`
14
+ * is on, and these describe a *parsed JSON config* where an absent key and an explicit
15
+ * `undefined` are the same thing.
16
+ */
17
+ /**
18
+ * The ad platforms this toolchain knows how to link a site to.
19
+ *
20
+ * A closed set, mirroring `AD_PROVIDERS` in the generator's `config.ts` — the
21
+ * capability table in `providers.ts` has one entry per member, and a test in the
22
+ * generator asserts the two lists agree. An open string would mean a typo'd
23
+ * provider silently getting no verification step and no tag.
24
+ */
25
+ type AdProvider = 'google' | 'meta' | 'linkedin' | 'reddit' | 'tiktok' | 'microsoft' | 'pinterest' | 'snapchat';
26
+ /** Which consent category gates a provider's tag. */
27
+ type AdConsentCategory = 'marketing' | 'analytics';
28
+ /** One ad property to link, as the config declares it. */
29
+ interface AdPropertySetup {
30
+ provider: AdProvider;
31
+ /**
32
+ * The account as the platform shows it — Google Ads customer id, Meta ad
33
+ * account, LinkedIn partner id, Reddit advertiser id.
34
+ */
35
+ accountId?: string | undefined;
36
+ /** The tag/pixel id, when the platform issues one distinct from the account. */
37
+ pixelId?: string | undefined;
38
+ /** Google Ads only: the conversion label paired with the conversion id. */
39
+ conversionLabel?: string | undefined;
40
+ /** The host to verify, bare (`acme.ca`). The CLI defaults it from the canonical domain. */
41
+ domain?: string | undefined;
42
+ /**
43
+ * The verification token from the platform UI.
44
+ *
45
+ * A bare token gets the provider's TXT prefix applied; a value already
46
+ * containing `=` is used as the whole record content, which is the escape hatch
47
+ * for a platform changing its prefix without waiting on a toolchain release.
48
+ */
49
+ domainVerification?: string | undefined;
50
+ /** Category the tag waits on. Defaults to `marketing`. */
51
+ category?: AdConsentCategory | undefined;
52
+ enabled?: boolean | undefined;
53
+ }
54
+ /** Everything `plan()` needs, once the CLI has read the config. */
55
+ interface AdsConfig {
56
+ /** The properties to link. Already filtered to `--provider` if that was passed. */
57
+ properties: AdPropertySetup[];
58
+ }
59
+ /**
60
+ * One property's observed live state, gathered by the executor before planning.
61
+ *
62
+ * Same shape of arrangement as `DomainState`: the decision is pure, the
63
+ * observation is not. `txtContents` is every apex TXT record on the domain, so
64
+ * the planner can decide both "our record is present" and "a *different* record
65
+ * from this provider is present" — the second is a token rotation, which needs
66
+ * saying rather than silently adding a second record.
67
+ */
68
+ interface AdDomainState {
69
+ /** The Cloudflare zone id for the domain, if one was found. */
70
+ zoneId?: string | undefined;
71
+ /** Every apex TXT record content, unquoted. */
72
+ txtContents: string[];
73
+ }
74
+ //#endregion
75
+ //#region src/ads/plan.d.ts
76
+ /** A step's decision. `blocked` means the config is missing something. */
77
+ type StepAction = 'create' | 'skip' | 'blocked';
78
+ /** A config field the operator can supply to unblock a step. */
79
+ type MissingField = 'domainVerification' | 'accountId' | 'pixelId';
80
+ interface StepPlan {
81
+ action: StepAction;
82
+ /** Why it's a skip, or what the mutation will do, or what is missing. */
83
+ detail: string;
84
+ /** Set only on `blocked`: which config field would unblock it. */
85
+ needs?: MissingField | undefined;
86
+ }
87
+ /** The steps for one ad property, decided against its live state. */
88
+ interface AdPropertyPlan {
89
+ provider: AdPropertySetup['provider'];
90
+ /** The platform name, so a formatter needn't reach back into the table. */
91
+ name: string;
92
+ /** The domain being verified, when the platform verifies one. */
93
+ domain?: string | undefined;
94
+ /** Ensure the apex verification TXT. */
95
+ txt: StepPlan;
96
+ /** Whether the tag can be emitted (`ads tags`). */
97
+ tag: StepPlan;
98
+ /** The exact TXT content to create, when `txt.action` is `create`. */
99
+ txtContent?: string | undefined;
100
+ /** Manual follow-ups — including *why* a platform has no verification step. */
101
+ reminders: string[];
102
+ }
103
+ interface AdsPlan {
104
+ properties: AdPropertyPlan[];
105
+ /** Operator-facing warnings that span the whole run. */
106
+ notes: string[];
107
+ }
108
+ /**
109
+ * Decide one property's steps.
110
+ *
111
+ * The `dns-txt` branch has three outcomes, and keeping them distinct is the point:
112
+ * our record is present (skip), a *different* record from the same platform is
113
+ * present (create, and say so — a token rotation leaves the old record in place,
114
+ * since this command never edits or deletes DNS), or no token is configured yet
115
+ * (blocked, naming the field).
116
+ */
117
+ declare function planProperty(setup: AdPropertySetup, state: AdDomainState): AdPropertyPlan;
118
+ /** Plan every configured property. */
119
+ declare function plan(config: AdsConfig, states: Map<string, AdDomainState>): AdsPlan;
120
+ /** Any step that isn't a skip — i.e. the live state or the config has drifted. */
121
+ declare function hasDrift(p: AdsPlan): boolean;
122
+ /** Every field a run still needs, per provider — what the CLI asks for. */
123
+ declare function missingFields(p: AdsPlan): {
124
+ provider: string;
125
+ needs: MissingField;
126
+ }[];
127
+ /** Render a plan as the block `--dry` and `--check` print. */
128
+ declare function formatPlan(p: AdsPlan): string;
129
+ /** The outcome of one property's run, for the summary table. */
130
+ interface AdPropertyResult {
131
+ provider: string;
132
+ domain: string;
133
+ txt: 'created' | 'present' | 'blocked' | 'failed' | 'n/a';
134
+ tag: 'ready' | 'blocked';
135
+ reminders: string[];
136
+ }
137
+ /** Render the end-of-run summary: one row per property, plus any reminders. */
138
+ declare function formatSummary(results: AdPropertyResult[]): string;
139
+ //#endregion
140
+ //#region src/ads/providers.d.ts
141
+ /** How a platform proves you own the domain. */
142
+ interface AdVerificationSpec {
143
+ method: 'dns-txt' | 'none';
144
+ /**
145
+ * Prefix prepended to a bare token to form the record content. Owned here so a
146
+ * config holds the token the platform shows, not a hand-assembled record — but
147
+ * see `txtRecord`: a value already containing `=` passes through whole, which is
148
+ * the escape hatch when a platform changes its spelling.
149
+ */
150
+ txtPrefix?: string;
151
+ /** Where in the platform UI the token is found. Printed when asking for it. */
152
+ where?: string;
153
+ /** Why there is nothing to automate. Required when `method` is `none`. */
154
+ reason?: string;
155
+ }
156
+ /** The tag, and which config field carries its id. */
157
+ interface AdTagSpec {
158
+ /** Which field the tag id comes from — and therefore what to ask for when absent. */
159
+ needs: 'pixelId' | 'accountId';
160
+ /** The remote library. Absent when the platform's own bootstrap loads itself. */
161
+ src?: (id: string) => string;
162
+ /** The inline bootstrap, which the gate runs before attaching `src`. */
163
+ bootstrap: (id: string, entry: AdPropertySetup) => string;
164
+ /**
165
+ * Cookies the tag sets, for `data-consent-cookies` (what a revoke clears) and
166
+ * for the generated cookie notice. A `*` suffix is a prefix match.
167
+ */
168
+ cookies: string[];
169
+ /** The provider's own privacy policy, for the cookie notice. */
170
+ privacyUrl: string;
171
+ /** A visitor-facing opt-out, where the platform offers one. */
172
+ optOut?: string;
173
+ }
174
+ interface AdPlatform {
175
+ /** The platform as a reader would recognise it. */
176
+ name: string;
177
+ /**
178
+ * The jurisdiction that can compel this platform to produce what it receives —
179
+ * where the contracting entity is established. Feeds the generated privacy
180
+ * policy's cross-border transfer disclosure, which is a claim about foreign
181
+ * *access*, not foreign storage (see `Processor.operatorCountry` in the
182
+ * generator's `legal/providers.ts`). A consumer whose contracting entity differs
183
+ * declares their own processor entry instead.
184
+ */
185
+ operatorCountry: string;
186
+ /** Click-ID parameters this platform stamps on an ad landing URL. */
187
+ clickIdParams: string[];
188
+ /** Where the operator manages the property. */
189
+ consoleUrl: string;
190
+ verification: AdVerificationSpec;
191
+ tag: AdTagSpec;
192
+ /** Follow-ups no API covers, given this entry. */
193
+ manualSteps: (entry: AdPropertySetup) => string[];
194
+ }
195
+ declare const AD_PLATFORMS: Record<AdProvider, AdPlatform>;
196
+ /** Every provider, in table order — the one place iteration order is decided. */
197
+ declare const AD_PROVIDER_KEYS: AdProvider[];
198
+ /** Whether a string names a known provider (for CLI arg validation). */
199
+ declare const isAdProvider: (value: string) => value is AdProvider;
200
+ /**
201
+ * The DNS TXT record content for a token.
202
+ *
203
+ * A value already containing `=` is taken as the whole record and left alone. That
204
+ * is the same escape hatch an icon name containing `:` gets: a platform can change
205
+ * its prefix spelling without waiting on a toolchain release, and an operator who
206
+ * pasted the full record from the UI gets what they meant rather than a
207
+ * double-prefixed record that verifies against nothing.
208
+ */
209
+ declare function txtRecord(provider: AdProvider, token: string): string;
210
+ /** The tag id for an entry, or undefined when the field it needs is unset. */
211
+ declare function tagId(entry: AdPropertySetup): string | undefined;
212
+ /** The consent category gating an entry's tag. `marketing` unless stated otherwise. */
213
+ declare const categoryOf: (entry: AdPropertySetup) => AdConsentCategory;
214
+ /**
215
+ * One provider's tag, rendered as a **consent-gated, inert** `<script>`.
216
+ *
217
+ * `type="text/plain"` with the URL on `data-src` is what makes the gate real: the
218
+ * browser neither parses the body nor fetches the library, so an undecided
219
+ * visitor's page issues no third-party request. Never give one of these a live
220
+ * `src` — a gate that instead asks a loaded tracker not to track is a promise.
221
+ *
222
+ * Returns null when the entry has no tag id, so a caller can report the gap rather
223
+ * than emit a snippet that initialises `undefined`.
224
+ */
225
+ declare function renderTag(entry: AdPropertySetup, strategy?: 'idle' | 'async' | 'interaction'): string | null;
226
+ //#endregion
227
+ export { AD_PLATFORMS, AD_PROVIDER_KEYS, type AdConsentCategory, type AdDomainState, type AdPlatform, type AdPropertyPlan, type AdPropertyResult, type AdPropertySetup, type AdProvider, type AdTagSpec, type AdVerificationSpec, type AdsConfig, type AdsPlan, type MissingField, type StepAction, type StepPlan, categoryOf, createApexTxt, findZoneId, formatPlan, formatSummary, hasDrift, isAdProvider, listApexTxt, missingFields, plan, planProperty, renderTag, tagId, txtRecord };
228
+ //# sourceMappingURL=index.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.mts","names":[],"sources":["../../src/ads/types.ts","../../src/ads/plan.ts","../../src/ads/providers.ts"],"mappings":";;;;;;AAsBA;;;;AAAsB;AAWtB;;;;AAA6B;AAG7B;;;;;;;;AAAA,KAdY,UAAA;;KAWA,iBAAA;;UAGK,eAAA;EACf,QAAA,EAAU,UAAA;EAsBH;AAAA;AAIT;;EArBE,SAAA;EAuBA;EArBA,OAAA;EAiCe;EA/Bf,eAAA;;EAEA,MAAA;EAiCW;;;;ACzDb;;;EDgCE,kBAAA;EChCoB;EDkCpB,QAAA,GAAW,iBAAiB;EAC5B,OAAA;AAAA;;UAIe,SAAA;EClCA;EDoCf,UAAA,EAAY,eAAe;AAAA;;;;;;;;AC/BP;AAItB;UDuCiB,aAAA;;EAEf,MAAA;EClCK;EDoCL,WAAW;AAAA;;;;KCzDD,UAAA;ADFZ;AAAA,KCKY,YAAA;AAAA,UAEK,QAAA;EACf,MAAA,EAAQ,UAAA;EDRY;ECUpB,MAAA;EDC2B;ECC3B,KAAA,GAAQ,YAAY;AAAA;ADDO;AAAA,UCKZ,cAAA;EACf,QAAA,EAAU,eAAA;;EAEV,IAAA;EDJA;ECMA,MAAA;EDDA;ECGA,GAAA,EAAK,QAAA;EDCL;ECCA,GAAA,EAAK,QAAA;EDSL;ECPA,UAAA;EDSW;ECPX,SAAA;AAAA;AAAA,UAGe,OAAA;EACf,UAAA,EAAY,cAAc;EDQF;ECNxB,KAAA;AAAA;ADQ2B;AAY7B;;;;AAIa;;;;AAhBgB,iBCIb,YAAA,CAAa,KAAA,EAAO,eAAA,EAAiB,KAAA,EAAO,aAAA,GAAgB,cAAA;;iBAoD5D,IAAA,CAAK,MAAA,EAAQ,SAAA,EAAW,MAAA,EAAQ,GAAA,SAAY,aAAA,IAAiB,OAAA;;iBAe7D,QAAA,CAAS,CAAU,EAAP,OAAO;AA7GnC;AAAA,iBAkHgB,aAAA,CAAc,CAAA,EAAG,OAAA;EAAY,QAAA;EAAkB,KAAA,EAAO,YAAY;AAAA;AAhHlF;AAAA,iBA4HgB,UAAA,CAAW,CAAU,EAAP,OAAO;;UAcpB,gBAAA;EACf,QAAA;EACA,MAAA;EACA,GAAA;EACA,GAAA;EACA,SAAA;AAAA;AA1IoB;AAAA,iBAgJN,aAAA,CAAc,OAA2B,EAAlB,gBAAgB;;;ADjH1B;AAAA,UE9BZ,kBAAA;EACf,MAAA;;;AF6CW;;;;EEtCX,SAAA;EDnBoB;ECqBpB,KAAA;EDrBoB;ECuBpB,MAAA;AAAA;;UAIe,SAAA;EDxBO;EC0BtB,KAAA;EDxBe;EC0Bf,GAAA,IAAO,EAAA;;EAEP,SAAA,GAAY,EAAA,UAAY,KAAA,EAAO,eAAe;ED3B9C;;;;ECgCA,OAAA;ED5BoB;EC8BpB,UAAA;ED1Be;EC4Bf,MAAA;AAAA;AAAA,UAGe,UAAA;EDxBV;EC0BL,IAAA;EDxBa;;;;;;;;ECiCb,eAAA;EDjCK;ECmCL,aAAA;ED/BA;ECiCA,UAAA;EACA,YAAA,EAAc,kBAAA;EACd,GAAA,EAAK,SAAA;EDhCiB;ECkCtB,WAAA,GAAc,KAAA,EAAO,eAAA;AAAA;AAAA,cAaV,YAAA,EAAc,MAAA,CAAO,UAAA,EAAY,UAAA;;cAuMjC,gBAAA,EAAgD,UAAU;;cAG1D,YAAA,GAAgB,KAAA,aAAgB,KAAA,IAAS,UAAmC;AD1OzF;;;;;;;;;AAAA,iBCqPgB,SAAA,CAAU,QAAA,EAAU,UAAU,EAAE,KAAA;;iBAOhC,KAAA,CAAM,KAAsB,EAAf,eAAe;;cAM/B,UAAA,GAAc,KAAA,EAAO,eAAA,KAAkB,iBACrB;ADnQ2D;AAoD1F;;;;;;;;;;AApD0F,iBCmR1E,SAAA,CACd,KAAA,EAAO,eAAe,EACtB,QAAA"}