cascivo 0.4.2 → 0.5.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/README.md CHANGED
@@ -62,6 +62,9 @@ npx shadcn@latest add https://cascivo.com/r/shadcn/button.json
62
62
  ```
63
63
 
64
64
  Every item inlines its source and resolves its cascivo dependencies transitively.
65
+ Page **blocks** are in the shadcn registry too, under a `block-` slug — install
66
+ `block/dashboard-overview` as `https://cascivo.com/r/shadcn/block-dashboard-overview.json`
67
+ (the `cascivo` binary addresses the same block as `npx cascivo add block/dashboard-overview`).
65
68
 
66
69
  Building **with an AI assistant?** cascivo has no training-data footprint yet, so
67
70
  give the tool the knowledge directly rather than relying on it to browse the site:
@@ -77,6 +80,6 @@ pnpm add cascivo
77
80
 
78
81
  ---
79
82
 
80
- [cascivo.com](https://cascivo.com) · [Docs](https://docs.cascivo.com) · [Storybook](https://storybook.cascivo.com) · [GitHub](https://github.com/cascivo/cascivo) · AI agents: use [`@cascivo/mcp`](https://github.com/cascivo/cascivo/tree/main/packages/mcp) and [`registry.json`](https://github.com/cascivo/cascivo/blob/main/registry.json) · MIT
83
+ [cascivo.com](https://cascivo.com) · [Docs](https://docs.cascivo.com) · [Storybook](https://storybook.cascivo.com) · [GitHub](https://github.com/cascivo/cascivo) · AI agents: read [`llms.txt`](https://cascivo.com/llms.txt) (install steps + component index, plain text) or use [`@cascivo/mcp`](https://github.com/cascivo/cascivo/tree/main/packages/mcp) and [`registry.json`](https://github.com/cascivo/cascivo/blob/main/registry.json) · MIT
81
84
 
82
85
  <div align="center"><a href="https://cascivo.com"><img src="https://cascivo.com/favicon.svg" width="28" height="28" alt="cascivo"></a></div>
@@ -0,0 +1,171 @@
1
+ import "node:module";
2
+ import { pathToFileURL } from "node:url";
3
+ import { existsSync, readFileSync } from "node:fs";
4
+ import { dirname, join } from "node:path";
5
+ //#region \0rolldown/runtime.js
6
+ var __defProp = Object.defineProperty;
7
+ var __exportAll = (all, no_symbols) => {
8
+ let target = {};
9
+ for (var name in all) __defProp(target, name, {
10
+ get: all[name],
11
+ enumerable: true
12
+ });
13
+ if (!no_symbols) __defProp(target, Symbol.toStringTag, { value: "Module" });
14
+ return target;
15
+ };
16
+ //#endregion
17
+ //#region src/utils/config.ts
18
+ var config_exports = /* @__PURE__ */ __exportAll({
19
+ CASCIVO_HOST: () => CASCIVO_HOST,
20
+ DEFAULT_CONFIG: () => DEFAULT_CONFIG,
21
+ THEMES: () => THEMES,
22
+ applyEnvOverrides: () => applyEnvOverrides,
23
+ detectPackageManager: () => detectPackageManager,
24
+ installCommand: () => installCommand,
25
+ installHint: () => installHint,
26
+ isPackageManager: () => isPackageManager,
27
+ loadConfig: () => loadConfig,
28
+ resolveConfig: () => resolveConfig
29
+ });
30
+ /**
31
+ * Canonical host for hosted cascivo artifacts (registry.json, per-item
32
+ * r/<name>.json, marketplace.json). docs.cascivo.com mirrors the same tree.
33
+ * Keep in sync with CASCIVO_HOST in packages/mcp.
34
+ */
35
+ const CASCIVO_HOST = "https://cascivo.com";
36
+ /** All first-party themes shipped by @cascivo/themes (selectable via data-theme). */
37
+ const THEMES = [
38
+ "light",
39
+ "dark",
40
+ "warm",
41
+ "flat",
42
+ "minimal",
43
+ "midnight",
44
+ "pastel",
45
+ "brutalist",
46
+ "corporate",
47
+ "terminal",
48
+ "cyberpunk",
49
+ "arcade"
50
+ ];
51
+ const DEFAULT_CONFIG = {
52
+ registry: `${CASCIVO_HOST}/registry.json`,
53
+ outputDir: "src/components/ui",
54
+ theme: "light"
55
+ };
56
+ const CONFIG_FILES = [
57
+ "cascivo.config.ts",
58
+ "cascivo.config.js",
59
+ "cascivo.config.mjs"
60
+ ];
61
+ /** Apply defaults over a (possibly partial) user config object. */
62
+ function resolveConfig(partial) {
63
+ return {
64
+ ...DEFAULT_CONFIG,
65
+ ...partial
66
+ };
67
+ }
68
+ /** Let env vars override config — used by the MCP server to pass `outputDir`. */
69
+ function applyEnvOverrides(config, env = process.env) {
70
+ return {
71
+ ...config,
72
+ ...env.CASCIVO_REGISTRY ? { registry: env.CASCIVO_REGISTRY } : {},
73
+ ...env.CASCIVO_OUTPUT_DIR ? { outputDir: env.CASCIVO_OUTPUT_DIR } : {}
74
+ };
75
+ }
76
+ /**
77
+ * Locate and load `cascivo.config.{ts,js,mjs}` from `cwd`. Falls back to the
78
+ * default config when no file is found or the file cannot be loaded. Env vars
79
+ * (`CASCIVO_REGISTRY`, `CASCIVO_OUTPUT_DIR`) take precedence.
80
+ */
81
+ async function loadConfig(cwd = process.cwd()) {
82
+ for (const file of CONFIG_FILES) {
83
+ const path = join(cwd, file);
84
+ if (!existsSync(path)) continue;
85
+ try {
86
+ const mod = await import(pathToFileURL(path).href);
87
+ return applyEnvOverrides(resolveConfig(mod.default ?? mod));
88
+ } catch {
89
+ return applyEnvOverrides(resolveConfig(null));
90
+ }
91
+ }
92
+ return applyEnvOverrides(resolveConfig(null));
93
+ }
94
+ /** Narrow an arbitrary string to a known PackageManager. */
95
+ function isPackageManager(value) {
96
+ return value === "pnpm" || value === "yarn" || value === "npm" || value === "bun";
97
+ }
98
+ /**
99
+ * Lock files in probe order. `bun.lock` (bun ≥ 1.2 text lockfile) sits beside the
100
+ * legacy binary `bun.lockb`; `package-lock.json` is npm's marker so a walk that
101
+ * reaches an npm workspace root still resolves to npm rather than the default.
102
+ */
103
+ const PM_LOCKFILES = [
104
+ ["pnpm-lock.yaml", "pnpm"],
105
+ ["yarn.lock", "yarn"],
106
+ ["bun.lockb", "bun"],
107
+ ["bun.lock", "bun"],
108
+ ["package-lock.json", "npm"]
109
+ ];
110
+ /** The package manager that invoked this process, from `npm_config_user_agent`. */
111
+ function pmFromUserAgent(ua) {
112
+ if (!ua) return void 0;
113
+ const name = ua.split("/")[0];
114
+ return isPackageManager(name) ? name : void 0;
115
+ }
116
+ /** The `packageManager` corepack field of a package.json, if it names a known PM. */
117
+ function pmFromPackageJson(dir) {
118
+ try {
119
+ const name = JSON.parse(readFileSync(join(dir, "package.json"), "utf8")).packageManager?.split("@")[0];
120
+ return isPackageManager(name) ? name : void 0;
121
+ } catch {
122
+ return;
123
+ }
124
+ }
125
+ /**
126
+ * Detect the package manager in use. Precedence, highest first:
127
+ * 1. explicit override (the `--package-manager`/`--pm` flag)
128
+ * 2. `CASCIVO_PACKAGE_MANAGER` env var
129
+ * 3. `npm_config_user_agent` (the PM that spawned the CLI, e.g. `pnpm dlx`)
130
+ * 4. an upward walk from `cwd` for a lock file or `packageManager` field —
131
+ * this is what makes detection work inside a workspace, where the lock
132
+ * file lives at the repo root, not in the app subdirectory the user runs
133
+ * the CLI from. The walk stops after a directory containing `.git`.
134
+ * 5. default `npm`.
135
+ */
136
+ function detectPackageManager(cwd = process.cwd(), opts = {}) {
137
+ const env = opts.env ?? process.env;
138
+ if (isPackageManager(opts.override)) return opts.override;
139
+ const envPm = env.CASCIVO_PACKAGE_MANAGER;
140
+ if (isPackageManager(envPm)) return envPm;
141
+ const uaPm = pmFromUserAgent(env.npm_config_user_agent);
142
+ if (uaPm) return uaPm;
143
+ let current = cwd;
144
+ for (;;) {
145
+ for (const [file, pm] of PM_LOCKFILES) if (existsSync(join(current, file))) return pm;
146
+ const fromField = pmFromPackageJson(current);
147
+ if (fromField) return fromField;
148
+ if (existsSync(join(current, ".git"))) break;
149
+ const parent = dirname(current);
150
+ if (parent === current) break;
151
+ current = parent;
152
+ }
153
+ return "npm";
154
+ }
155
+ /** The install subcommand each package manager uses to add dependencies. */
156
+ function installCommand(pm, packages, opts = {}) {
157
+ return [pm, [
158
+ pm === "npm" ? "install" : "add",
159
+ ...opts.dev ? [pm === "npm" ? "--save-dev" : "-D"] : [],
160
+ ...packages
161
+ ]];
162
+ }
163
+ /** Human-readable install command a user can copy-paste, e.g. `pnpm add -D cascivo`. */
164
+ function installHint(pm, packages, opts = {}) {
165
+ const [cmd, args] = installCommand(pm, packages, opts);
166
+ return `${cmd} ${args.join(" ")}`;
167
+ }
168
+ //#endregion
169
+ export { detectPackageManager as a, isPackageManager as c, config_exports as i, loadConfig as l, DEFAULT_CONFIG as n, installCommand as o, THEMES as r, installHint as s, CASCIVO_HOST as t, __exportAll as u };
170
+
171
+ //# sourceMappingURL=config-CYlTGdmE.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config-CYlTGdmE.mjs","names":[],"sources":["../src/utils/config.ts"],"sourcesContent":["import { existsSync, readFileSync } from 'node:fs'\nimport { dirname, join } from 'node:path'\nimport { pathToFileURL } from 'node:url'\n\n/**\n * Canonical host for hosted cascivo artifacts (registry.json, per-item\n * r/<name>.json, marketplace.json). docs.cascivo.com mirrors the same tree.\n * Keep in sync with CASCIVO_HOST in packages/mcp.\n */\nexport const CASCIVO_HOST = 'https://cascivo.com'\n\n/** All first-party themes shipped by @cascivo/themes (selectable via data-theme). */\nexport const THEMES = [\n 'light',\n 'dark',\n 'warm',\n 'flat',\n 'minimal',\n 'midnight',\n 'pastel',\n 'brutalist',\n 'corporate',\n 'terminal',\n 'cyberpunk',\n 'arcade',\n] as const\n\nexport type ThemeName = (typeof THEMES)[number]\n\nexport type RegistryNamespaceConfig =\n | string\n | { url: string; headers?: Record<string, string>; params?: Record<string, string> }\n\nexport interface CascadeConfig {\n /** URL of the registry.json index. */\n registry: string\n /** Directory (relative to project root) where components are written. */\n outputDir: string\n /** Default theme imported by `cascade init`. */\n theme: ThemeName\n /** Namespace → registry URL template (with {name} placeholder) or auth config. */\n registries?: Record<string, RegistryNamespaceConfig>\n /** Whether to copy test files (*.contract.test.tsx) when adding components. */\n tests?: boolean\n}\n\nexport const DEFAULT_CONFIG: CascadeConfig = {\n // Canonical hosted registry index (served from the landing site, documented in\n // llms.txt). Prefer this over a branch's GitHub raw URL, which 404s for\n // unauthenticated/private-repo requests and breaks `cascivo list`/`add`.\n registry: `${CASCIVO_HOST}/registry.json`,\n outputDir: 'src/components/ui',\n theme: 'light',\n}\n\nconst CONFIG_FILES = ['cascivo.config.ts', 'cascivo.config.js', 'cascivo.config.mjs']\n\n/** Apply defaults over a (possibly partial) user config object. */\nexport function resolveConfig(partial: Partial<CascadeConfig> | null | undefined): CascadeConfig {\n return { ...DEFAULT_CONFIG, ...partial }\n}\n\n/** Let env vars override config — used by the MCP server to pass `outputDir`. */\nexport function applyEnvOverrides(\n config: CascadeConfig,\n env: NodeJS.ProcessEnv = process.env,\n): CascadeConfig {\n return {\n ...config,\n ...(env.CASCIVO_REGISTRY ? { registry: env.CASCIVO_REGISTRY } : {}),\n ...(env.CASCIVO_OUTPUT_DIR ? { outputDir: env.CASCIVO_OUTPUT_DIR } : {}),\n }\n}\n\n/**\n * Locate and load `cascivo.config.{ts,js,mjs}` from `cwd`. Falls back to the\n * default config when no file is found or the file cannot be loaded. Env vars\n * (`CASCIVO_REGISTRY`, `CASCIVO_OUTPUT_DIR`) take precedence.\n */\nexport async function loadConfig(cwd: string = process.cwd()): Promise<CascadeConfig> {\n for (const file of CONFIG_FILES) {\n const path = join(cwd, file)\n if (!existsSync(path)) continue\n try {\n const mod = (await import(pathToFileURL(path).href)) as {\n default?: Partial<CascadeConfig>\n }\n return applyEnvOverrides(resolveConfig(mod.default ?? (mod as Partial<CascadeConfig>)))\n } catch {\n // Unloadable config (e.g. unsupported TS syntax) — fall back to defaults.\n return applyEnvOverrides(resolveConfig(null))\n }\n }\n return applyEnvOverrides(resolveConfig(null))\n}\n\nexport type PackageManager = 'pnpm' | 'yarn' | 'npm' | 'bun'\n\n/** Narrow an arbitrary string to a known PackageManager. */\nexport function isPackageManager(value: string | undefined): value is PackageManager {\n return value === 'pnpm' || value === 'yarn' || value === 'npm' || value === 'bun'\n}\n\n/**\n * Lock files in probe order. `bun.lock` (bun ≥ 1.2 text lockfile) sits beside the\n * legacy binary `bun.lockb`; `package-lock.json` is npm's marker so a walk that\n * reaches an npm workspace root still resolves to npm rather than the default.\n */\nconst PM_LOCKFILES: readonly [string, PackageManager][] = [\n ['pnpm-lock.yaml', 'pnpm'],\n ['yarn.lock', 'yarn'],\n ['bun.lockb', 'bun'],\n ['bun.lock', 'bun'],\n ['package-lock.json', 'npm'],\n]\n\n/** The package manager that invoked this process, from `npm_config_user_agent`. */\nfunction pmFromUserAgent(ua: string | undefined): PackageManager | undefined {\n if (!ua) return undefined\n const name = ua.split('/')[0]\n return isPackageManager(name) ? name : undefined\n}\n\n/** The `packageManager` corepack field of a package.json, if it names a known PM. */\nfunction pmFromPackageJson(dir: string): PackageManager | undefined {\n try {\n const pkg = JSON.parse(readFileSync(join(dir, 'package.json'), 'utf8')) as {\n packageManager?: string\n }\n const name = pkg.packageManager?.split('@')[0]\n return isPackageManager(name) ? name : undefined\n } catch {\n return undefined\n }\n}\n\n/**\n * Detect the package manager in use. Precedence, highest first:\n * 1. explicit override (the `--package-manager`/`--pm` flag)\n * 2. `CASCIVO_PACKAGE_MANAGER` env var\n * 3. `npm_config_user_agent` (the PM that spawned the CLI, e.g. `pnpm dlx`)\n * 4. an upward walk from `cwd` for a lock file or `packageManager` field —\n * this is what makes detection work inside a workspace, where the lock\n * file lives at the repo root, not in the app subdirectory the user runs\n * the CLI from. The walk stops after a directory containing `.git`.\n * 5. default `npm`.\n */\nexport function detectPackageManager(\n cwd: string = process.cwd(),\n opts: { override?: string; env?: NodeJS.ProcessEnv } = {},\n): PackageManager {\n const env = opts.env ?? process.env\n\n if (isPackageManager(opts.override)) return opts.override\n\n const envPm = env.CASCIVO_PACKAGE_MANAGER\n if (isPackageManager(envPm)) return envPm\n\n const uaPm = pmFromUserAgent(env.npm_config_user_agent)\n if (uaPm) return uaPm\n\n let current = cwd\n for (;;) {\n for (const [file, pm] of PM_LOCKFILES) {\n if (existsSync(join(current, file))) return pm\n }\n const fromField = pmFromPackageJson(current)\n if (fromField) return fromField\n // A `.git` directory marks the repo root — do not walk past it.\n if (existsSync(join(current, '.git'))) break\n const parent = dirname(current)\n if (parent === current) break\n current = parent\n }\n\n return 'npm'\n}\n\n/** The install subcommand each package manager uses to add dependencies. */\nexport function installCommand(\n pm: PackageManager,\n packages: string[],\n opts: { dev?: boolean } = {},\n): [string, string[]] {\n const verb = pm === 'npm' ? 'install' : 'add'\n const devFlag = opts.dev ? [pm === 'npm' ? '--save-dev' : '-D'] : []\n return [pm, [verb, ...devFlag, ...packages]]\n}\n\n/** Human-readable install command a user can copy-paste, e.g. `pnpm add -D cascivo`. */\nexport function installHint(\n pm: PackageManager,\n packages: string[],\n opts: { dev?: boolean } = {},\n): string {\n const [cmd, args] = installCommand(pm, packages, opts)\n return `${cmd} ${args.join(' ')}`\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AASA,MAAa,eAAe;;AAG5B,MAAa,SAAS;CACpB;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;AACF;AAqBA,MAAa,iBAAgC;CAI3C,UAAU,GAAG,aAAa;CAC1B,WAAW;CACX,OAAO;AACT;AAEA,MAAM,eAAe;CAAC;CAAqB;CAAqB;AAAoB;;AAGpF,SAAgB,cAAc,SAAmE;CAC/F,OAAO;EAAE,GAAG;EAAgB,GAAG;CAAQ;AACzC;;AAGA,SAAgB,kBACd,QACA,MAAyB,QAAQ,KAClB;CACf,OAAO;EACL,GAAG;EACH,GAAI,IAAI,mBAAmB,EAAE,UAAU,IAAI,iBAAiB,IAAI,CAAC;EACjE,GAAI,IAAI,qBAAqB,EAAE,WAAW,IAAI,mBAAmB,IAAI,CAAC;CACxE;AACF;;;;;;AAOA,eAAsB,WAAW,MAAc,QAAQ,IAAI,GAA2B;CACpF,KAAK,MAAM,QAAQ,cAAc;EAC/B,MAAM,OAAO,KAAK,KAAK,IAAI;EAC3B,IAAI,CAAC,WAAW,IAAI,GAAG;EACvB,IAAI;GACF,MAAM,MAAO,MAAM,OAAO,cAAc,IAAI,CAAC,CAAC;GAG9C,OAAO,kBAAkB,cAAc,IAAI,WAAY,GAA8B,CAAC;EACxF,QAAQ;GAEN,OAAO,kBAAkB,cAAc,IAAI,CAAC;EAC9C;CACF;CACA,OAAO,kBAAkB,cAAc,IAAI,CAAC;AAC9C;;AAKA,SAAgB,iBAAiB,OAAoD;CACnF,OAAO,UAAU,UAAU,UAAU,UAAU,UAAU,SAAS,UAAU;AAC9E;;;;;;AAOA,MAAM,eAAoD;CACxD,CAAC,kBAAkB,MAAM;CACzB,CAAC,aAAa,MAAM;CACpB,CAAC,aAAa,KAAK;CACnB,CAAC,YAAY,KAAK;CAClB,CAAC,qBAAqB,KAAK;AAC7B;;AAGA,SAAS,gBAAgB,IAAoD;CAC3E,IAAI,CAAC,IAAI,OAAO,KAAA;CAChB,MAAM,OAAO,GAAG,MAAM,GAAG,CAAC,CAAC;CAC3B,OAAO,iBAAiB,IAAI,IAAI,OAAO,KAAA;AACzC;;AAGA,SAAS,kBAAkB,KAAyC;CAClE,IAAI;EAIF,MAAM,OAHM,KAAK,MAAM,aAAa,KAAK,KAAK,cAAc,GAAG,MAAM,CAGtD,CAAC,CAAC,gBAAgB,MAAM,GAAG,CAAC,CAAC;EAC5C,OAAO,iBAAiB,IAAI,IAAI,OAAO,KAAA;CACzC,QAAQ;EACN;CACF;AACF;;;;;;;;;;;;AAaA,SAAgB,qBACd,MAAc,QAAQ,IAAI,GAC1B,OAAuD,CAAC,GACxC;CAChB,MAAM,MAAM,KAAK,OAAO,QAAQ;CAEhC,IAAI,iBAAiB,KAAK,QAAQ,GAAG,OAAO,KAAK;CAEjD,MAAM,QAAQ,IAAI;CAClB,IAAI,iBAAiB,KAAK,GAAG,OAAO;CAEpC,MAAM,OAAO,gBAAgB,IAAI,qBAAqB;CACtD,IAAI,MAAM,OAAO;CAEjB,IAAI,UAAU;CACd,SAAS;EACP,KAAK,MAAM,CAAC,MAAM,OAAO,cACvB,IAAI,WAAW,KAAK,SAAS,IAAI,CAAC,GAAG,OAAO;EAE9C,MAAM,YAAY,kBAAkB,OAAO;EAC3C,IAAI,WAAW,OAAO;EAEtB,IAAI,WAAW,KAAK,SAAS,MAAM,CAAC,GAAG;EACvC,MAAM,SAAS,QAAQ,OAAO;EAC9B,IAAI,WAAW,SAAS;EACxB,UAAU;CACZ;CAEA,OAAO;AACT;;AAGA,SAAgB,eACd,IACA,UACA,OAA0B,CAAC,GACP;CAGpB,OAAO,CAAC,IAAI;EAFC,OAAO,QAAQ,YAAY;EAErB,GADH,KAAK,MAAM,CAAC,OAAO,QAAQ,eAAe,IAAI,IAAI,CAAC;EACpC,GAAG;CAAQ,CAAC;AAC7C;;AAGA,SAAgB,YACd,IACA,UACA,OAA0B,CAAC,GACnB;CACR,MAAM,CAAC,KAAK,QAAQ,eAAe,IAAI,UAAU,IAAI;CACrD,OAAO,GAAG,IAAI,GAAG,KAAK,KAAK,GAAG;AAChC"}
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.mts","names":[],"sources":["../src/utils/config.ts","../src/index.ts"],"mappings":";AA2BA;AAAA,cAfa,MAAA;AAAA,KAeD,SAAA,WAAoB,MAAM;AAAA,KAE1B,uBAAA;EAEN,GAAA;EAAa,OAAA,GAAU,MAAA;EAAwB,MAAA,GAAS,MAAM;AAAA;AAAA,UAEnD,aAAA;EAFX;EAIJ,QAAA;EAJ2B;EAM3B,SAAA;EAN4D;EAQ5D,KAAA,EAAO,SAAA;EAR2D;EAUlE,UAAA,GAAa,MAAA,SAAe,uBAAA;EARA;EAU5B,KAAA;AAAA;;;cCxBW,OAAA;AAAA,iBAmJS,GAAA,CAAI,IAAA,aAAiB,OAAO"}
1
+ {"version":3,"file":"index.d.mts","names":[],"sources":["../src/utils/config.ts","../src/index.ts"],"mappings":";AA2BA;AAAA,cAfa,MAAA;AAAA,KAeD,SAAA,WAAoB,MAAM;AAAA,KAE1B,uBAAA;EAEN,GAAA;EAAa,OAAA,GAAU,MAAA;EAAwB,MAAA,GAAS,MAAM;AAAA;AAAA,UAEnD,aAAA;EAFX;EAIJ,QAAA;EAJ2B;EAM3B,SAAA;EAN4D;EAQ5D,KAAA,EAAO,SAAA;EAR2D;EAUlE,UAAA,GAAa,MAAA,SAAe,uBAAA;EARA;EAU5B,KAAA;AAAA;;;cCvBW,OAAA;AAAA,iBA4JS,GAAA,CAAI,IAAA,aAAiB,OAAO"}