@craftainer/crud-views 0.0.0-stage → 0.2.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.
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.mjs","names":["isObject","num","isEmpty","text","pick","same","same","Panel"],"sources":["../src/core/context.ts","../src/core/provider.tsx","../src/core/fields.ts","../src/core/useResource.ts","../src/core/ResourceGate.tsx","../src/core/registry.ts","../src/core/renderers/display.tsx","../src/core/filterState.ts","../src/core/renderers/filter.tsx","../src/core/values.ts","../src/core/renderers/input.tsx","../src/core/renderers/builtins.ts","../src/core/fieldComponents.tsx","../src/core/filters.ts","../src/core/shells.tsx","../src/lifecycle/status.ts","../src/lifecycle/ConfirmDialog.tsx","../src/lifecycle/mutations.ts","../src/bulk/errors.ts","../src/bulk/export.ts","../src/bulk/BulkToolbar.tsx","../src/bulk/selection.ts","../src/bulk/BulkRecords.tsx","../src/lifecycle/ArchiveControls.tsx","../src/delete/DeleteAction.tsx","../src/lifecycle/DraftControls.tsx","../src/detail/FieldList.tsx","../src/revisions/revision.ts","../src/revisions/Revisions.tsx","../src/detail/RecordDetail.tsx","../src/filter/FacetSidebar.tsx","../src/filter/FilterControl.tsx","../src/filter/FilterBar.tsx","../src/filter/queryState.ts","../src/filter/FilterBuilder.tsx","../src/filter/QuickSearch.tsx","../src/filter/urlAdapter.ts","../src/filter/useQueryState.ts","../src/form/layout.tsx","../src/form/sections.ts","../src/form/problem.ts","../src/form/validate.ts","../src/form/ResourceForm.tsx","../src/lifecycle/StatusFilter.tsx","../src/lifecycle/TrashList.tsx","../src/list/columns.ts","../src/list/RecordCard.tsx","../src/list/CardList.tsx","../src/list/LoadError.tsx","../src/list/CardGridList.tsx","../src/list/ColumnsMenu.tsx","../src/list/DataTableList.tsx","../src/list/LoadMoreList.tsx","../src/list/SortDropdown.tsx","../src/list/ResourceList.tsx","../src/stats/model.ts","../src/stats/shared.tsx","../src/stats/StatsKpiCards.tsx","../src/stats/StatsTimeSeries.tsx","../src/stats/StatsCategoryChart.tsx","../src/stats/StatsTablePanel.tsx","../src/stats/StatsDashboard.tsx","../src/stats/predictShared.tsx","../src/stats/PredictionChart.tsx","../src/stats/PredictionTable.tsx","../src/stats/PredictionKpi.tsx","../src/stats/PredictionsDashboard.tsx"],"sourcesContent":["import type { CrudClient } from \"@craftainer/crud-sdk\";\nimport type { QueryClient } from \"@tanstack/react-query\";\nimport { createContext, useContext, type Context } from \"react\";\nimport type { RendererOverrides } from \"./types.ts\";\n\n/** What `useCrud` returns. */\nexport interface CrudContextValue {\n readonly client: CrudClient;\n readonly queryClient: QueryClient;\n /** Separates cached manifests of different callers (e.g. the user id). */\n readonly scope: string;\n /** BCP 47 tag for number and date formatting; `undefined` = the browser's. */\n readonly locale: string | undefined;\n /** IANA zone for `datetime` display; `undefined` = the browser's. */\n readonly timeZone: string | undefined;\n readonly renderers: RendererOverrides | undefined;\n}\n\n/** The raw context (`null` outside a provider); use `useCrud` unless a missing provider is fine. */\nexport const CrudContextRaw: Context<CrudContextValue | null> =\n createContext<CrudContextValue | null>(null);\n\n/** The provider's value; throws outside a `CrudProvider`. */\nexport function useCrud(): CrudContextValue {\n const value = useContext(CrudContextRaw);\n if (value === null) {\n throw new Error(\"useCrud must be used inside <CrudProvider>\");\n }\n return value;\n}\n\n/** Formatting settings that work without a provider (tests, stand-alone use). */\nexport function useFormat(): {\n locale: string | undefined;\n timeZone: string | undefined;\n} {\n const value = useContext(CrudContextRaw);\n return { locale: value?.locale, timeZone: value?.timeZone };\n}\n","import type { CrudClient } from \"@craftainer/crud-sdk\";\nimport { ThemeProvider, type Theme } from \"@mui/material/styles\";\nimport { QueryClientProvider, type QueryClient } from \"@tanstack/react-query\";\nimport { useMemo, type ReactElement, type ReactNode } from \"react\";\nimport { CrudContextRaw, type CrudContextValue } from \"./context.ts\";\nimport type { RendererOverrides } from \"./types.ts\";\n\nexport interface CrudProviderProps {\n readonly client: CrudClient;\n readonly queryClient: QueryClient;\n /** Wraps the tree in this MUI theme. Omit to inherit the ambient theme. */\n readonly theme?: Theme | undefined;\n /** Renderer overrides for this tree (selector -> renderers). */\n readonly renderers?: RendererOverrides | undefined;\n readonly scope?: string | undefined;\n readonly locale?: string | undefined;\n readonly timeZone?: string | undefined;\n readonly children?: ReactNode;\n}\n\n/** Provides the SDK client, the TanStack `QueryClient`, an optional MUI theme and renderer overrides. */\nexport function CrudProvider({\n client,\n queryClient,\n theme,\n renderers,\n scope = \"\",\n locale,\n timeZone,\n children,\n}: CrudProviderProps): ReactElement {\n const value = useMemo<CrudContextValue>(\n () => ({ client, queryClient, scope, locale, timeZone, renderers }),\n [client, queryClient, scope, locale, timeZone, renderers],\n );\n const tree = (\n <QueryClientProvider client={queryClient}>\n <CrudContextRaw.Provider value={value}>\n {children}\n </CrudContextRaw.Provider>\n </QueryClientProvider>\n );\n return theme === undefined ? (\n tree\n ) : (\n <ThemeProvider theme={theme}>{tree}</ThemeProvider>\n );\n}\n","// Builds FieldDescriptors from a manifest resource (its `fields` list plus the\n// read/create/update JSON Schemas).\nimport type { FieldSpec, JsonObject, Resource } from \"@craftainer/crud-sdk\";\nimport type {\n FieldConstraints,\n FieldDescriptor,\n FieldKind,\n FilterOp,\n} from \"./types.ts\";\n\nconst isObject = (value: unknown): value is JsonObject =>\n typeof value === \"object\" && value !== null && !Array.isArray(value);\n\nconst KINDS: readonly string[] = [\n \"string\",\n \"number\",\n \"integer\",\n \"boolean\",\n \"date\",\n \"datetime\",\n \"enum\",\n];\n\n/** `power_level` -> `Power level`. */\nexport function humanize(name: string): string {\n const words = name.replace(/[_-]+/g, \" \").trim();\n return words.charAt(0).toUpperCase() + words.slice(1);\n}\n\ninterface Node {\n readonly type: string | undefined;\n readonly format: string | undefined;\n readonly choices: readonly string[] | undefined;\n readonly nullable: boolean;\n readonly items: JsonObject | undefined;\n readonly constraints: FieldConstraints;\n}\n\n/** A JSON pointer segment of a `$ref` fragment: percent-decoded, then `~1` -> `/` and `~0` -> `~`. */\nfunction unescapePointer(segment: string): string {\n let decoded = segment;\n try {\n decoded = decodeURIComponent(segment);\n } catch {\n // A stray `%` is kept literally.\n }\n return decoded.replace(/~1/g, \"/\").replace(/~0/g, \"~\");\n}\n\n/**\n * Follows a local `$ref` (`#/$defs/Name`, also through chains of refs) and\n * merges the target under the node's own members. An unresolvable or cyclic\n * ref leaves the node as it is.\n */\nfunction resolveRef(\n node: JsonObject,\n root: JsonObject,\n seen: ReadonlySet<string> = new Set(),\n): JsonObject {\n const ref = node[\"$ref\"];\n if (typeof ref !== \"string\" || !ref.startsWith(\"#/\") || seen.has(ref)) {\n return node;\n }\n let target: unknown = root;\n for (const part of ref.slice(2).split(\"/\").map(unescapePointer)) {\n target = isObject(target) ? own(target, part) : undefined;\n }\n if (!isObject(target)) return node;\n const resolved = resolveRef(target, root, new Set([...seen, ref]));\n return { ...resolved, ...node, $ref: undefined };\n}\n\nconst num = (value: unknown): number | undefined =>\n typeof value === \"number\" ? value : undefined;\n\n/** Flattens `$ref`, `anyOf: [X, null]` and `type: [X, \"null\"]` into one node. */\nfunction readNode(raw: unknown, root: JsonObject): Node {\n let node = isObject(raw) ? resolveRef(raw, root) : {};\n let nullable = false;\n const variants = node[\"anyOf\"] ?? node[\"oneOf\"];\n if (Array.isArray(variants)) {\n const resolved = variants\n .filter(isObject)\n .map((variant) => resolveRef(variant, root));\n const rest = resolved.filter((variant) => variant[\"type\"] !== \"null\");\n nullable = rest.length < resolved.length;\n node = { ...node, ...rest[0] };\n }\n let type = node[\"type\"];\n if (Array.isArray(type)) {\n nullable = nullable || type.includes(\"null\");\n type = type.find((t) => t !== \"null\");\n } else if (type === \"null\") {\n nullable = true;\n type = undefined;\n }\n const enumValues = node[\"enum\"];\n return {\n type: typeof type === \"string\" ? type : undefined,\n format: typeof node[\"format\"] === \"string\" ? node[\"format\"] : undefined,\n choices: Array.isArray(enumValues)\n ? enumValues.filter((v): v is string => typeof v === \"string\")\n : undefined,\n nullable,\n items: isObject(node[\"items\"]) ? node[\"items\"] : undefined,\n constraints: {\n minLength: num(node[\"minLength\"]),\n maxLength: num(node[\"maxLength\"]),\n minimum: num(node[\"minimum\"]),\n maximum: num(node[\"maximum\"]),\n pattern:\n typeof node[\"pattern\"] === \"string\" ? node[\"pattern\"] : undefined,\n },\n };\n}\n\nfunction schemaKind(node: Node): FieldKind {\n if (node.choices !== undefined && node.choices.length > 0) return \"enum\";\n switch (node.type) {\n case \"string\":\n return node.format === \"date\"\n ? \"date\"\n : node.format === \"date-time\"\n ? \"datetime\"\n : \"string\";\n case \"integer\":\n case \"number\":\n case \"boolean\":\n return node.type;\n case \"array\":\n return \"array\";\n default:\n return \"json\";\n }\n}\n\nfunction properties(schema: JsonObject): JsonObject {\n const props = schema[\"properties\"];\n return isObject(props) ? props : {};\n}\n\n/** An own property of `props` (names like \"constructor\" are not inherited members). */\nfunction own(props: JsonObject, name: string): unknown {\n return Object.hasOwn(props, name) ? props[name] : undefined;\n}\n\nfunction requiredSet(schema: JsonObject): ReadonlySet<string> {\n const list = schema[\"required\"];\n return new Set(\n Array.isArray(list)\n ? list.filter((v): v is string => typeof v === \"string\")\n : [],\n );\n}\n\nfunction describe(\n name: string,\n spec: FieldSpec | undefined,\n read: JsonObject,\n create: JsonObject,\n update: JsonObject,\n): FieldDescriptor {\n const [pRead, pCreate, pUpdate] = [read, create, update].map(properties) as [\n JsonObject,\n JsonObject,\n JsonObject,\n ];\n // `$ref`s resolve against the schema the property came from.\n const [raw, root] =\n own(pRead, name) !== undefined\n ? [own(pRead, name), read]\n : own(pCreate, name) !== undefined\n ? [own(pCreate, name), create]\n : [own(pUpdate, name), update];\n const node = readNode(raw, root);\n const kind: FieldKind =\n spec === undefined\n ? schemaKind(node)\n : KINDS.includes(spec.value_type)\n ? (spec.value_type as FieldKind)\n : \"string\";\n const itemNode = readNode(node.items, root);\n return {\n name,\n label: humanize(name),\n kind,\n format: node.format ?? null,\n nullable: node.nullable,\n readOnly: !(Object.hasOwn(pCreate, name) || Object.hasOwn(pUpdate, name)),\n required:\n spec === undefined ? requiredSet(create).has(name) : spec.required,\n choices: spec?.choices ?? node.choices ?? null,\n itemKind: kind === \"array\" ? schemaKind(itemNode) : null,\n constraints: node.constraints,\n inManifest: spec !== undefined,\n sortable: spec?.sortable ?? false,\n filterOps: (spec?.filter_ops ?? []) as readonly FilterOp[],\n numeric: spec?.numeric ?? false,\n categorical: spec?.categorical ?? false,\n };\n}\n\n/**\n * Every field of `resource`, in read-schema order, then manifest fields the\n * read schema does not list. The `id` field is included (read only).\n */\nexport function describeFields(resource: Resource): readonly FieldDescriptor[] {\n const { read, create, update } = resource.schemas;\n const specs = new Map(resource.fields.map((f) => [f.name, f]));\n const names = [\n ...new Set([\n ...Object.keys(properties(read)),\n ...resource.fields.map((f) => f.name),\n ]),\n ];\n return names.map((name) =>\n describe(name, specs.get(name), read, create, update),\n );\n}\n","import {\n UnknownResourceError,\n findResource,\n type Capabilities,\n type CrudClient,\n type JsonObject,\n type Resource,\n type ResourceClient,\n} from \"@craftainer/crud-sdk\";\nimport {\n createMutationOptions,\n deleteMutationOptions,\n infiniteListOptions,\n listOptions,\n manifestOptions,\n predictOptions,\n recordOptions,\n revisionsOptions,\n statsOptions,\n tanstackApi,\n updateMutationOptions,\n type CrudQuery,\n type InfiniteListInit,\n type TanstackApi,\n type UpdateVariables,\n} from \"@craftainer/crud-sdk/tanstack\";\nimport {\n useInfiniteQuery,\n useMutation,\n useQuery,\n type InfiniteData,\n type UseInfiniteQueryResult,\n type UseMutationResult,\n type UseQueryResult,\n} from \"@tanstack/react-query\";\nimport { useMemo } from \"react\";\nimport { describeFields } from \"./fields.ts\";\nimport { useCrud } from \"./context.ts\";\nimport type { FieldDescriptor } from \"./types.ts\";\n\n/** TanStack hooks bound to one resource. Stable between renders while the resource is. */\nexport interface ResourceHooks<\n Read extends object = JsonObject,\n Create extends object = JsonObject,\n Update extends object = JsonObject,\n> {\n useList(query?: CrudQuery): UseQueryResult<Read[]>;\n useInfiniteList(\n query?: CrudQuery,\n init?: InfiniteListInit,\n ): UseInfiniteQueryResult<InfiniteData<Read[], number>>;\n useRecord(id: number): UseQueryResult<Read>;\n useStats(query?: CrudQuery): UseQueryResult<JsonObject>;\n usePredict(query?: CrudQuery): UseQueryResult<JsonObject>;\n useRevisions(id: number): UseQueryResult<JsonObject[]>;\n /** Invalidates lists, stats and predictions on success. */\n useCreate(): UseMutationResult<Read, Error, Create>;\n /** Variables carry `ifMatch` for `If-Match`; a stale one fails with `PreconditionFailed`. */\n useUpdate(): UseMutationResult<Read, Error, UpdateVariables<Update>>;\n useDelete(): UseMutationResult<unknown, Error, number>;\n}\n\n/** The loaded state of `useResource`. */\nexport interface ReadyResource<\n Read extends object = JsonObject,\n Create extends object = JsonObject,\n Update extends object = JsonObject,\n> {\n readonly status: \"ready\";\n readonly error: null;\n /** The manifest entry (schemas, fields, pagination, paths, ...). */\n readonly resource: Resource;\n /** Shortcut for `resource.capabilities`: gate every optional view on it. */\n readonly capabilities: Capabilities;\n readonly fields: readonly FieldDescriptor[];\n field(name: string): FieldDescriptor | undefined;\n /** The SDK handle, for calls the hooks do not cover (clone, publish, restore, bulk). */\n readonly handle: ResourceClient<Read, Create, Update>;\n readonly api: TanstackApi<Read, Create, Update>;\n readonly hooks: ResourceHooks<Read, Create, Update>;\n}\n\nexport interface PendingResource {\n readonly status: \"pending\";\n readonly error: null;\n}\n\nexport interface FailedResource {\n readonly status: \"error\";\n readonly error: Error;\n}\n\nexport type UseResourceResult<\n Read extends object = JsonObject,\n Create extends object = JsonObject,\n Update extends object = JsonObject,\n> = PendingResource | FailedResource | ReadyResource<Read, Create, Update>;\n\nconst clientIds = new WeakMap<CrudClient, number>();\nlet nextClientId = 0;\nfunction clientId(client: CrudClient): number {\n let id = clientIds.get(client);\n if (id === undefined) {\n id = nextClientId++;\n clientIds.set(client, id);\n }\n return id;\n}\n\nfunction buildHooks<\n Read extends object,\n Create extends object,\n Update extends object,\n>(\n name: string,\n api: TanstackApi<Read, Create, Update>,\n queryClient: ReturnType<typeof useCrud>[\"queryClient\"],\n): ResourceHooks<Read, Create, Update> {\n return {\n useList: (query) => useQuery(listOptions(name, api, query)),\n useInfiniteList: (query, init) =>\n useInfiniteQuery(infiniteListOptions(name, api, query, init)),\n useRecord: (id) => useQuery(recordOptions(name, api, id)),\n useStats: (query) => useQuery(statsOptions(name, api, query)),\n usePredict: (query) => useQuery(predictOptions(name, api, query)),\n useRevisions: (id) => useQuery(revisionsOptions(name, api, id)),\n useCreate: () => useMutation(createMutationOptions(queryClient, name, api)),\n useUpdate: () => useMutation(updateMutationOptions(queryClient, name, api)),\n useDelete: () => useMutation(deleteMutationOptions(queryClient, name, api)),\n };\n}\n\n/**\n * Loads the manifest (once per caller scope) and returns the resource `name`\n * (the highest `api_version` unless given) with its capabilities, described\n * fields, SDK handle and TanStack hooks. Query keys use `name`, or\n * `name@apiVersion` when `apiVersion` is given, so two versions never share a cache entry.\n */\nexport function useResource<\n Read extends object = JsonObject,\n Create extends object = JsonObject,\n Update extends object = JsonObject,\n>(name: string, apiVersion?: string): UseResourceResult<Read, Create, Update> {\n const { client, queryClient, scope } = useCrud();\n const manifest = useQuery({\n ...manifestOptions(\n { manifest: () => client.manifest() },\n `${clientId(client)}:${scope}`,\n ),\n staleTime: Number.POSITIVE_INFINITY,\n });\n const resource =\n manifest.data === undefined\n ? undefined\n : findResource(manifest.data, name, apiVersion);\n const handle = useQuery({\n queryKey: [\n \"crud\",\n \"_handle\",\n clientId(client),\n scope,\n name,\n apiVersion ?? null,\n ],\n queryFn: () => client.resource<Read, Create, Update>(name, apiVersion),\n enabled: resource !== undefined,\n staleTime: Number.POSITIVE_INFINITY,\n });\n const ready = handle.data;\n return useMemo<UseResourceResult<Read, Create, Update>>(() => {\n if (manifest.error !== null && manifest.data === undefined)\n return { status: \"error\", error: manifest.error };\n if (manifest.data !== undefined && resource === undefined) {\n return {\n status: \"error\",\n error: new UnknownResourceError(\n `the manifest has no resource \"${name}\"${apiVersion === undefined ? \"\" : ` ${apiVersion}`} for this caller`,\n ),\n };\n }\n if (handle.error !== null && ready === undefined)\n return { status: \"error\", error: handle.error };\n if (resource === undefined || ready === undefined)\n return { status: \"pending\", error: null };\n const fields = describeFields(resource);\n const api = tanstackApi(client, ready);\n return {\n status: \"ready\",\n error: null,\n resource,\n capabilities: resource.capabilities,\n fields,\n field: (fieldName) => fields.find((f) => f.name === fieldName),\n handle: ready,\n api,\n hooks: buildHooks(\n apiVersion === undefined ? name : `${name}@${apiVersion}`,\n api,\n queryClient,\n ),\n };\n }, [\n manifest.error,\n manifest.data,\n resource,\n handle.error,\n ready,\n name,\n apiVersion,\n client,\n queryClient,\n ]);\n}\n","import Alert from \"@mui/material/Alert\";\nimport CircularProgress from \"@mui/material/CircularProgress\";\nimport Box from \"@mui/material/Box\";\nimport type { ReactElement, ReactNode } from \"react\";\nimport { useResource, type ReadyResource } from \"./useResource.ts\";\n\nexport interface ResourceGateProps {\n readonly name: string;\n readonly apiVersion?: string | undefined;\n /** Shown while the manifest loads. Default: a spinner. */\n readonly pending?: ReactNode;\n /** Shown on failure (unknown resource, network). Default: an error alert. */\n readonly fallback?: ((error: Error) => ReactNode) | undefined;\n readonly children: (ready: ReadyResource) => ReactNode;\n}\n\n/** Renders `children` once the resource is loaded; the common loading and error states otherwise. */\nexport function ResourceGate({\n name,\n apiVersion,\n pending,\n fallback,\n children,\n}: ResourceGateProps): ReactElement {\n const state = useResource(name, apiVersion);\n if (state.status === \"pending\") {\n return (\n <>\n {pending ?? (\n <Box sx={{ display: \"flex\", justifyContent: \"center\", p: 4 }}>\n <CircularProgress aria-label=\"Loading\" />\n </Box>\n )}\n </>\n );\n }\n if (state.status === \"error\") {\n return (\n <>\n {fallback === undefined ? (\n <Alert severity=\"error\">{state.error.message}</Alert>\n ) : (\n fallback(state.error)\n )}\n </>\n );\n }\n return <>{children(state)}</>;\n}\n","// The field-renderer registry (contract I4): selectors, layers and the\n// resolver. Precedence: nearest layer wins; inside a layer the most specific\n// selector wins (see docs/contracts/I4-field-renderers.md).\nimport type {\n DisplayRenderer,\n FieldDescriptor,\n FilterRenderer,\n InputRenderer,\n FieldRenderers,\n RendererOverrides,\n RendererRole,\n} from \"./types.ts\";\n\n/** The renderer type of each role. */\nexport interface RendererByRole {\n readonly display: DisplayRenderer;\n readonly input: InputRenderer;\n readonly filter: FilterRenderer;\n}\n\n/** The selectors that match `field` of `resource`, most specific first. */\nexport function selectorsFor(\n field: FieldDescriptor,\n resource: string,\n): readonly string[] {\n const selectors = [`${resource}.${field.name}`];\n if (field.format !== null) {\n selectors.push(`${field.kind}:${field.format}`);\n }\n selectors.push(field.kind);\n return selectors;\n}\n\n/** One renderer role resolved from `layers` (nearest first); `undefined` when no layer has one. */\nexport function resolveRenderer<R extends RendererRole>(\n role: R,\n field: FieldDescriptor,\n resource: string,\n layers: readonly (RendererOverrides | undefined)[],\n): RendererByRole[R] | undefined {\n const selectors = selectorsFor(field, resource);\n for (const layer of layers) {\n if (layer === undefined) continue;\n for (const selector of selectors) {\n const found = layer[selector]?.[role] as RendererByRole[R] | undefined;\n if (found !== undefined) return found;\n }\n }\n return undefined;\n}\n\ninterface Registration {\n readonly selector: string;\n readonly renderers: FieldRenderers;\n}\n\nlet registrations: readonly Registration[] = [];\nlet snapshot: RendererOverrides = {};\nconst listeners = new Set<() => void>();\n\nfunction rebuild(): void {\n const next: Record<string, FieldRenderers> = {};\n for (const { selector, renderers } of registrations) {\n next[selector] = { ...next[selector], ...renderers };\n }\n snapshot = next;\n for (const listener of listeners) listener();\n}\n\n/** Subscribes to registration changes (for `useSyncExternalStore`); returns the unsubscribe function. */\nexport function subscribeRegisteredRenderers(listener: () => void): () => void {\n listeners.add(listener);\n return () => {\n listeners.delete(listener);\n };\n}\n\n/**\n * Registers renderers process-wide (the layer between `CrudProvider`'s\n * `renderers` and the built-ins). A later registration wins per role. Returns\n * the function that removes exactly this registration, in any order.\n * Prefer the provider's `renderers` prop in apps: this is shared state.\n */\nexport function registerFieldRenderer(\n selector: string,\n renderers: FieldRenderers,\n): () => void {\n const mine: Registration = { selector, renderers };\n registrations = [...registrations, mine];\n rebuild();\n return () => {\n registrations = registrations.filter((r) => r !== mine);\n rebuild();\n };\n}\n\n/** The process-wide registrations merged (a new object after every change). */\nexport function getRegisteredRenderers(): RendererOverrides {\n return snapshot;\n}\n","import Chip from \"@mui/material/Chip\";\nimport Link from \"@mui/material/Link\";\nimport Stack from \"@mui/material/Stack\";\nimport Typography from \"@mui/material/Typography\";\nimport type { ReactElement } from \"react\";\nimport { humanize } from \"../fields.ts\";\nimport { useFormat } from \"../context.ts\";\nimport type { DisplayRendererProps, FieldValue } from \"../types.ts\";\n\nfunction Empty(): ReactElement {\n return (\n <Typography component=\"span\" variant=\"body2\" color=\"text.secondary\">\n {\"—\"}\n </Typography>\n );\n}\n\nconst isEmpty = (value: FieldValue): boolean =>\n value === null || value === undefined || value === \"\";\n\nfunction asText(value: FieldValue): string {\n return typeof value === \"string\" ? value : JSON.stringify(value);\n}\n\n/** Parses `YYYY-MM-DD` (UTC midnight) or an ISO datetime. */\nfunction asDate(value: FieldValue): Date | null {\n const date = new Date(typeof value === \"string\" ? value : Number.NaN);\n return Number.isNaN(date.getTime()) ? null : date;\n}\n\nexport function StringDisplay({\n value,\n field,\n}: DisplayRendererProps): ReactElement {\n if (isEmpty(value)) return <Empty />;\n const text = asText(value);\n if (field.format === \"email\") {\n return <Link href={`mailto:${text}`}>{text}</Link>;\n }\n if (field.format === \"uri\" && /^https?:\\/\\//i.test(text)) {\n return (\n <Link href={text} target=\"_blank\" rel=\"noreferrer noopener\">\n {text}\n </Link>\n );\n }\n return (\n <Typography component=\"span\" variant=\"body2\">\n {text}\n </Typography>\n );\n}\n\nexport function NumberDisplay({\n value,\n field,\n}: DisplayRendererProps): ReactElement {\n const { locale } = useFormat();\n if (typeof value !== \"number\") return <Empty />;\n const text = new Intl.NumberFormat(locale, {\n maximumFractionDigits: field.kind === \"integer\" ? 0 : 20,\n }).format(value);\n return (\n <Typography component=\"span\" variant=\"body2\">\n {text}\n </Typography>\n );\n}\n\nexport function BooleanDisplay({\n value,\n size,\n}: DisplayRendererProps): ReactElement {\n if (typeof value !== \"boolean\") return <Empty />;\n return (\n <Chip\n size={size ?? \"small\"}\n variant=\"outlined\"\n color={value ? \"primary\" : \"default\"}\n label={value ? \"Yes\" : \"No\"}\n />\n );\n}\n\nexport function DateDisplay({ value }: DisplayRendererProps): ReactElement {\n const { locale } = useFormat();\n const date = asDate(value);\n if (date === null) return <Empty />;\n // A date has no zone: format it in UTC so it never shifts a day.\n const text = new Intl.DateTimeFormat(locale, {\n dateStyle: \"medium\",\n timeZone: \"UTC\",\n }).format(date);\n return (\n <Typography component=\"span\" variant=\"body2\">\n {text}\n </Typography>\n );\n}\n\nexport function DatetimeDisplay({ value }: DisplayRendererProps): ReactElement {\n const { locale, timeZone } = useFormat();\n const date = asDate(value);\n if (date === null) return <Empty />;\n const text = new Intl.DateTimeFormat(locale, {\n dateStyle: \"medium\",\n timeStyle: \"short\",\n timeZone,\n }).format(date);\n return (\n <Typography component=\"time\" variant=\"body2\" dateTime={date.toISOString()}>\n {text}\n </Typography>\n );\n}\n\nexport function EnumDisplay({\n value,\n size,\n}: DisplayRendererProps): ReactElement {\n if (isEmpty(value)) return <Empty />;\n return (\n <Chip\n size={size ?? \"small\"}\n variant=\"outlined\"\n label={humanize(asText(value))}\n />\n );\n}\n\nexport function ArrayDisplay({\n value,\n size,\n}: DisplayRendererProps): ReactElement {\n if (!Array.isArray(value) || value.length === 0) return <Empty />;\n return (\n <Stack direction=\"row\" spacing={0.5} useFlexGap sx={{ flexWrap: \"wrap\" }}>\n {value.map((item, index) => (\n <Chip\n key={index}\n size={size ?? \"small\"}\n variant=\"outlined\"\n label={asText(item)}\n />\n ))}\n </Stack>\n );\n}\n\nexport function JsonDisplay({ value }: DisplayRendererProps): ReactElement {\n if (value === null || value === undefined) return <Empty />;\n return (\n <Typography\n component=\"code\"\n variant=\"body2\"\n sx={{ fontFamily: \"monospace\" }}\n >\n {JSON.stringify(value)}\n </Typography>\n );\n}\n","import type {\n FieldDescriptor,\n FieldFilter,\n FilterOp,\n FilterScalar,\n} from \"./types.ts\";\n\n/** Sets `op` on `current`; an empty operand removes it, and no operators left is `undefined`. */\nexport function withOp(\n current: FieldFilter | undefined,\n op: FilterOp,\n operand: FilterScalar | readonly FilterScalar[] | undefined,\n): FieldFilter | undefined {\n const next: Record<string, FilterScalar | readonly FilterScalar[]> = {\n ...current,\n };\n if (\n operand === undefined ||\n (Array.isArray(operand) && operand.length === 0)\n ) {\n delete next[op];\n } else {\n next[op] = operand;\n }\n return Object.keys(next).length === 0 ? undefined : (next as FieldFilter);\n}\n\n/** Whether the manifest lets a client filter on this field at all. */\nexport const isFilterable = (field: FieldDescriptor): boolean =>\n field.filterOps.length > 0 && field.name !== \"id\";\n","import MenuItem from \"@mui/material/MenuItem\";\nimport Stack from \"@mui/material/Stack\";\nimport TextField from \"@mui/material/TextField\";\nimport type { ReactElement } from \"react\";\nimport { humanize } from \"../fields.ts\";\nimport { withOp } from \"../filterState.ts\";\nimport type {\n FieldDescriptor,\n FilterOp,\n FilterRendererProps,\n FilterScalar,\n} from \"../types.ts\";\n\nconst has = (field: FieldDescriptor, op: FilterOp): boolean =>\n field.filterOps.includes(op);\n\nconst scalar = (v: unknown): string =>\n typeof v === \"string\" || typeof v === \"number\" ? String(v) : \"\";\n\nconst label = (field: FieldDescriptor, suffix?: string): string =>\n suffix === undefined ? field.label : `${field.label} ${suffix}`;\n\nexport function StringFilter({\n field,\n value,\n onChange,\n size,\n}: FilterRendererProps): ReactElement | null {\n const op = ([\"icontains\", \"contains\", \"eq\"] as const).find((o) =>\n has(field, o),\n );\n if (op === undefined) return null;\n return (\n <TextField\n size={size ?? \"small\"}\n fullWidth\n label={label(field)}\n value={scalar(value?.[op])}\n onChange={(e) =>\n onChange(\n withOp(value, op, e.target.value === \"\" ? undefined : e.target.value),\n )\n }\n />\n );\n}\n\n/** `min`/`max` for numbers, dates and datetimes; `eq` when the field has no range operators. */\nfunction RangeFilter({\n field,\n value,\n onChange,\n size,\n type,\n parse,\n show,\n}: FilterRendererProps & {\n type: \"number\" | \"date\" | \"datetime-local\";\n parse: (raw: string) => FilterScalar;\n show: (v: unknown) => string;\n}): ReactElement | null {\n const ops = ([\"min\", \"max\"] as const).filter((o) => has(field, o));\n const used = ops.length > 0 ? ops : has(field, \"eq\") ? ([\"eq\"] as const) : [];\n if (used.length === 0) return null;\n return (\n <Stack direction=\"row\" spacing={1}>\n {used.map((op) => (\n <TextField\n key={op}\n type={type}\n size={size ?? \"small\"}\n fullWidth\n label={\n op === \"eq\"\n ? label(field)\n : label(field, op === \"min\" ? \"from\" : \"to\")\n }\n value={show(value?.[op])}\n onChange={(e) =>\n onChange(\n withOp(\n value,\n op,\n e.target.value === \"\" ? undefined : parse(e.target.value),\n ),\n )\n }\n slotProps={{\n inputLabel: { shrink: type !== \"number\" ? true : undefined },\n }}\n />\n ))}\n </Stack>\n );\n}\n\nexport function NumberFilter(props: FilterRendererProps): ReactElement | null {\n return <RangeFilter {...props} type=\"number\" parse={Number} show={scalar} />;\n}\n\nexport function DateFilter(props: FilterRendererProps): ReactElement | null {\n return <RangeFilter {...props} type=\"date\" parse={String} show={scalar} />;\n}\n\n/** Datetime operands are `Date`s; the browser field is read as UTC. */\nexport function DatetimeFilter(\n props: FilterRendererProps,\n): ReactElement | null {\n return (\n <RangeFilter\n {...props}\n type=\"datetime-local\"\n parse={(raw) => new Date(`${raw}Z`)}\n show={(v) =>\n v instanceof Date && !Number.isNaN(v.getTime())\n ? v.toISOString().slice(0, 16)\n : \"\"\n }\n />\n );\n}\n\nexport function BooleanFilter({\n field,\n value,\n onChange,\n size,\n}: FilterRendererProps): ReactElement | null {\n if (!has(field, \"eq\")) return null;\n const current = value?.eq;\n return (\n <TextField\n select\n size={size ?? \"small\"}\n fullWidth\n label={label(field)}\n value={typeof current === \"boolean\" ? String(current) : \"\"}\n onChange={(e) =>\n onChange(\n withOp(\n value,\n \"eq\",\n e.target.value === \"\" ? undefined : e.target.value === \"true\",\n ),\n )\n }\n >\n <MenuItem value=\"\">Any</MenuItem>\n <MenuItem value=\"true\">Yes</MenuItem>\n <MenuItem value=\"false\">No</MenuItem>\n </TextField>\n );\n}\n\n/** Multi-select over `choices` as `in`, or a single choice as `eq`. */\nexport function EnumFilter({\n field,\n value,\n onChange,\n size,\n}: FilterRendererProps): ReactElement | null {\n const op = has(field, \"in\") ? \"in\" : has(field, \"eq\") ? \"eq\" : undefined;\n if (op === undefined) return null;\n const selected = value?.[op];\n const many = op === \"in\";\n return (\n <TextField\n select\n size={size ?? \"small\"}\n fullWidth\n label={label(field)}\n value={\n many\n ? Array.isArray(selected)\n ? selected.map(String)\n : []\n : scalar(selected)\n }\n onChange={(e) => {\n const raw = e.target.value as unknown as string | string[];\n onChange(withOp(value, op, raw === \"\" ? undefined : raw));\n }}\n slotProps={{ select: { multiple: many } }}\n >\n {!many && <MenuItem value=\"\">Any</MenuItem>}\n {(field.choices ?? []).map((choice) => (\n <MenuItem key={choice} value={choice}>\n {humanize(choice)}\n </MenuItem>\n ))}\n </TextField>\n );\n}\n\n/** For kinds the manifest cannot filter (`array`, `json`): renders nothing. */\nexport function NoFilter(): null {\n return null;\n}\n","import type { FieldDescriptor, FieldValue } from \"./types.ts\";\n\n/** What a cleared input emits: `null` for a nullable field, else `undefined`. */\nexport const emptyValue = (field: FieldDescriptor): FieldValue =>\n field.nullable ? null : undefined;\n","import FormControl from \"@mui/material/FormControl\";\nimport FormControlLabel from \"@mui/material/FormControlLabel\";\nimport FormHelperText from \"@mui/material/FormHelperText\";\nimport MenuItem from \"@mui/material/MenuItem\";\nimport Switch from \"@mui/material/Switch\";\nimport TextField from \"@mui/material/TextField\";\nimport { useEffect, useId, useRef, useState, type ReactElement } from \"react\";\nimport { humanize } from \"../fields.ts\";\nimport { emptyValue } from \"../values.ts\";\nimport type { FieldValue, InputRendererProps } from \"../types.ts\";\n\nfunction common(props: InputRendererProps): {\n id: string | undefined;\n label: string;\n size: \"small\" | \"medium\";\n fullWidth: true;\n required: boolean;\n disabled: boolean;\n autoFocus: boolean;\n error: boolean;\n helperText: string | undefined;\n onBlur: (() => void) | undefined;\n} {\n return {\n id: props.id,\n label: props.field.label,\n size: props.size ?? \"small\",\n fullWidth: true,\n required: props.field.required,\n disabled: props.disabled === true,\n autoFocus: props.autoFocus === true,\n error: props.error !== undefined,\n helperText: props.error ?? props.helperText,\n onBlur: props.onBlur,\n };\n}\n\n/**\n * Tells `onInvalid` when `reason` changes, and clears it when the input\n * unmounts so a hidden field never keeps a form blocked.\n */\nfunction useReportInvalid(\n reason: string | null,\n onInvalid: InputRendererProps[\"onInvalid\"],\n): void {\n const callback = useRef(onInvalid);\n const reported = useRef<string | null>(null);\n useEffect(() => {\n callback.current = onInvalid;\n });\n useEffect(() => {\n if (reported.current !== reason) {\n reported.current = reason;\n callback.current?.(reason);\n }\n }, [reason]);\n useEffect(\n () => () => {\n if (reported.current !== null) {\n reported.current = null;\n callback.current?.(null);\n }\n },\n [],\n );\n}\n\nconst text = (value: FieldValue): string =>\n typeof value === \"string\" || typeof value === \"number\" ? String(value) : \"\";\n\nexport function StringInput(props: InputRendererProps): ReactElement {\n const { field, value, onChange } = props;\n const { maxLength, minLength, pattern } = field.constraints;\n const type =\n field.format === \"email\"\n ? \"email\"\n : field.format === \"uri\"\n ? \"url\"\n : \"text\";\n return (\n <TextField\n {...common(props)}\n type={type}\n multiline={maxLength !== undefined && maxLength > 200}\n minRows={3}\n value={text(value)}\n onChange={(e) =>\n onChange(e.target.value === \"\" ? emptyValue(field) : e.target.value)\n }\n slotProps={{ htmlInput: { maxLength, minLength, pattern } }}\n />\n );\n}\n\n/** Why a number is out of the field's bounds, or `null`. */\nfunction numberProblem(\n field: InputRendererProps[\"field\"],\n value: FieldValue,\n): string | null {\n if (typeof value !== \"number\") return null;\n const { minimum, maximum } = field.constraints;\n if (field.kind === \"integer\" && !Number.isInteger(value)) {\n return \"Enter a whole number\";\n }\n if (minimum !== undefined && value < minimum) {\n return `Must be at least ${minimum}`;\n }\n if (maximum !== undefined && value > maximum) {\n return `Must be at most ${maximum}`;\n }\n return null;\n}\n\nexport function NumberInput(props: InputRendererProps): ReactElement {\n const { field, value, onChange } = props;\n const { minimum, maximum } = field.constraints;\n // The browser hands over \"\" for text that is not a number; remember that.\n const [unparsable, setUnparsable] = useState(false);\n // A number set from outside (reset, reload) replaces whatever was typed.\n const [seen, setSeen] = useState(value);\n if (seen !== value) {\n setSeen(value);\n if (typeof value === \"number\") setUnparsable(false);\n }\n const problem = unparsable ? \"Enter a number\" : numberProblem(field, value);\n useReportInvalid(problem, props.onInvalid);\n return (\n <TextField\n {...common(props)}\n type=\"number\"\n value={text(value)}\n error={problem !== null || props.error !== undefined}\n helperText={props.error ?? problem ?? props.helperText}\n onChange={(e) => {\n setUnparsable(e.target.value === \"\" && e.target.validity.badInput);\n onChange(\n e.target.value === \"\" ? emptyValue(field) : Number(e.target.value),\n );\n }}\n slotProps={{\n htmlInput: {\n min: minimum,\n max: maximum,\n step: field.kind === \"integer\" ? 1 : \"any\",\n },\n }}\n />\n );\n}\n\nexport function BooleanInput(props: InputRendererProps): ReactElement {\n const { field, value, onChange, disabled, onBlur, size } = props;\n const help = props.error ?? props.helperText;\n return (\n <FormControl error={props.error !== undefined} disabled={disabled === true}>\n <FormControlLabel\n label={field.label}\n required={field.required}\n sx={{ ml: 0 }}\n control={\n <Switch\n id={props.id}\n size={size ?? \"small\"}\n checked={value === true}\n autoFocus={props.autoFocus === true}\n onBlur={onBlur}\n onChange={(e) => onChange(e.target.checked)}\n />\n }\n />\n {help === undefined ? null : <FormHelperText>{help}</FormHelperText>}\n </FormControl>\n );\n}\n\nexport function DateInput(props: InputRendererProps): ReactElement {\n const { field, value, onChange } = props;\n return (\n <TextField\n {...common(props)}\n type=\"date\"\n value={text(value).slice(0, 10)}\n onChange={(e) =>\n onChange(e.target.value === \"\" ? emptyValue(field) : e.target.value)\n }\n slotProps={{ inputLabel: { shrink: true } }}\n />\n );\n}\n\n/** Edits an ISO-8601 UTC timestamp; the browser's `datetime-local` field is read as UTC. */\nexport function DatetimeInput(props: InputRendererProps): ReactElement {\n const { field, value, onChange } = props;\n const toLocal = (v: FieldValue): string => {\n const date = new Date(text(v));\n return Number.isNaN(date.getTime()) ? \"\" : date.toISOString().slice(0, 16);\n };\n return (\n <TextField\n {...common(props)}\n type=\"datetime-local\"\n value={toLocal(value)}\n onChange={(e) => {\n const raw = e.target.value;\n onChange(\n raw === \"\" ? emptyValue(field) : new Date(`${raw}Z`).toISOString(),\n );\n }}\n helperText={props.error ?? props.helperText ?? \"UTC\"}\n slotProps={{ inputLabel: { shrink: true } }}\n />\n );\n}\n\nexport function EnumInput(props: InputRendererProps): ReactElement {\n const { field, value, onChange } = props;\n const labelId = useId();\n return (\n <TextField\n {...common(props)}\n select\n value={text(value)}\n onChange={(e) =>\n onChange(e.target.value === \"\" ? emptyValue(field) : e.target.value)\n }\n slotProps={{ inputLabel: { id: labelId }, select: { labelId } }}\n >\n {!field.required && (\n <MenuItem value=\"\">\n <em>None</em>\n </MenuItem>\n )}\n {(field.choices ?? []).map((choice) => (\n <MenuItem key={choice} value={choice}>\n {humanize(choice)}\n </MenuItem>\n ))}\n </TextField>\n );\n}\n\nconst INVALID = Symbol(\"invalid\");\ntype Parsed = { ok: true; value: FieldValue } | { ok: false };\n\n/**\n * Keeps the typed text while it has no valid value yet, and follows outside\n * changes of `value` (React's \"adjust state during render\" pattern).\n */\nfunction useDraft(\n value: FieldValue,\n toText: (v: FieldValue) => string,\n fromText: (raw: string) => Parsed,\n): [string, (raw: string) => FieldValue | typeof INVALID] {\n const key = JSON.stringify(value);\n const [draft, setDraft] = useState(() => toText(value));\n const [seen, setSeen] = useState(key);\n if (seen !== key) {\n setSeen(key);\n const parsed = fromText(draft);\n if (!parsed.ok || JSON.stringify(parsed.value) !== key) {\n setDraft(toText(value));\n }\n }\n return [\n draft,\n (raw) => {\n setDraft(raw);\n const parsed = fromText(raw);\n return parsed.ok ? parsed.value : INVALID;\n },\n ];\n}\n\nexport function ArrayInput(props: InputRendererProps): ReactElement {\n const { field, value, onChange } = props;\n const numeric = field.itemKind === \"number\" || field.itemKind === \"integer\";\n const [draft, edit] = useDraft(\n value,\n (v) => (Array.isArray(v) ? v.join(\", \") : \"\"),\n (raw) => {\n const items = raw\n .split(\",\")\n .map((s) => s.trim())\n .filter((s) => s !== \"\");\n if (items.length === 0) return { ok: true, value: emptyValue(field) };\n if (!numeric) return { ok: true, value: items };\n const numbers = items.map(Number);\n return numbers.some(Number.isNaN)\n ? { ok: false }\n : { ok: true, value: numbers };\n },\n );\n const invalid =\n numeric &&\n draft.split(\",\").some((s) => s.trim() !== \"\" && Number.isNaN(Number(s)));\n useReportInvalid(invalid ? \"Items must be numbers\" : null, props.onInvalid);\n return (\n <TextField\n {...common(props)}\n value={draft}\n error={invalid || props.error !== undefined}\n helperText={\n invalid\n ? \"Items must be numbers\"\n : (props.error ?? props.helperText ?? \"Separate items with commas\")\n }\n onChange={(e) => {\n const next = edit(e.target.value);\n if (next !== INVALID) onChange(next);\n }}\n />\n );\n}\n\nfunction isJson(raw: string): boolean {\n try {\n JSON.parse(raw);\n return true;\n } catch {\n return false;\n }\n}\n\nexport function JsonInput(props: InputRendererProps): ReactElement {\n const { field, value, onChange } = props;\n const [draft, edit] = useDraft(\n value,\n (v) => (v === null || v === undefined ? \"\" : JSON.stringify(v, null, 2)),\n (raw) => {\n if (raw.trim() === \"\") return { ok: true, value: emptyValue(field) };\n try {\n return { ok: true, value: JSON.parse(raw) as FieldValue };\n } catch {\n return { ok: false };\n }\n },\n );\n // Derived from the text, so it follows resets of the draft.\n const invalid = draft.trim() !== \"\" && !isJson(draft);\n useReportInvalid(invalid ? \"Not valid JSON\" : null, props.onInvalid);\n return (\n <TextField\n {...common(props)}\n multiline\n minRows={3}\n value={draft}\n error={invalid || props.error !== undefined}\n helperText={\n invalid ? \"Not valid JSON\" : (props.error ?? props.helperText)\n }\n slotProps={{ htmlInput: { style: { fontFamily: \"monospace\" } } }}\n onChange={(e) => {\n const next = edit(e.target.value);\n if (next !== INVALID) onChange(next);\n }}\n />\n );\n}\n","import type { FieldKind, FieldRenderers, RendererOverrides } from \"../types.ts\";\nimport {\n ArrayDisplay,\n BooleanDisplay,\n DateDisplay,\n DatetimeDisplay,\n EnumDisplay,\n JsonDisplay,\n NumberDisplay,\n StringDisplay,\n} from \"./display.tsx\";\nimport {\n BooleanFilter,\n DateFilter,\n DatetimeFilter,\n EnumFilter,\n NoFilter,\n NumberFilter,\n StringFilter,\n} from \"./filter.tsx\";\nimport {\n ArrayInput,\n BooleanInput,\n DateInput,\n DatetimeInput,\n EnumInput,\n JsonInput,\n NumberInput,\n StringInput,\n} from \"./input.tsx\";\n\nconst kinds: Record<FieldKind, Required<FieldRenderers>> = {\n string: { display: StringDisplay, input: StringInput, filter: StringFilter },\n number: { display: NumberDisplay, input: NumberInput, filter: NumberFilter },\n integer: { display: NumberDisplay, input: NumberInput, filter: NumberFilter },\n boolean: {\n display: BooleanDisplay,\n input: BooleanInput,\n filter: BooleanFilter,\n },\n date: { display: DateDisplay, input: DateInput, filter: DateFilter },\n datetime: {\n display: DatetimeDisplay,\n input: DatetimeInput,\n filter: DatetimeFilter,\n },\n enum: { display: EnumDisplay, input: EnumInput, filter: EnumFilter },\n array: { display: ArrayDisplay, input: ArrayInput, filter: NoFilter },\n json: { display: JsonDisplay, input: JsonInput, filter: NoFilter },\n};\n\n/** The built-in layer: one entry per `FieldKind`. */\nexport const builtinRenderers: RendererOverrides = kinds;\n","// <FieldDisplay>, <FieldInput> and <FieldFilterInput>: what the views render.\n// Each resolves its renderer through the layers (docs/contracts/I4-field-renderers.md).\nimport {\n createElement,\n useContext,\n useSyncExternalStore,\n type ReactElement,\n} from \"react\";\nimport { CrudContextRaw } from \"./context.ts\";\nimport {\n getRegisteredRenderers,\n resolveRenderer,\n subscribeRegisteredRenderers,\n type RendererByRole,\n} from \"./registry.ts\";\nimport { builtinRenderers } from \"./renderers/builtins.ts\";\nimport type {\n DisplayRendererProps,\n FilterRendererProps,\n InputRendererProps,\n RendererOverrides,\n RendererRole,\n} from \"./types.ts\";\n\n/** Props of the three field components: the renderer props plus a per-component override layer. */\ntype WithOverrides<P> = P & {\n /** Highest-precedence layer, for this one component. */\n readonly renderers?: RendererOverrides | undefined;\n};\n\n/** The layers, nearest first. */\nfunction useRendererLayers(\n own: RendererOverrides | undefined,\n): readonly (RendererOverrides | undefined)[] {\n const crud = useContext(CrudContextRaw);\n const registered = useSyncExternalStore(\n subscribeRegisteredRenderers,\n getRegisteredRenderers,\n getRegisteredRenderers,\n );\n return [own, crud?.renderers, registered, builtinRenderers];\n}\n\nfunction pick<R extends RendererRole>(\n role: R,\n props: { field: DisplayRendererProps[\"field\"]; resource: string },\n layers: readonly (RendererOverrides | undefined)[],\n): RendererByRole[R] {\n // The built-ins define every role for every kind, so this never misses.\n return resolveRenderer(\n role,\n props.field,\n props.resource,\n layers,\n ) as RendererByRole[R];\n}\n\n/** Shows `value` with the resolved display renderer. */\nexport function FieldDisplay({\n renderers,\n ...props\n}: WithOverrides<DisplayRendererProps>): ReactElement {\n const layers = useRendererLayers(renderers);\n return createElement(pick(\"display\", props, layers), props);\n}\n\n/** Edits a value with the resolved input renderer. */\nexport function FieldInput({\n renderers,\n ...props\n}: WithOverrides<InputRendererProps>): ReactElement {\n const layers = useRendererLayers(renderers);\n return createElement(pick(\"input\", props, layers), props);\n}\n\n/** Edits the filter of a field with the resolved filter renderer. */\nexport function FieldFilterInput({\n renderers,\n ...props\n}: WithOverrides<FilterRendererProps>): ReactElement {\n const layers = useRendererLayers(renderers);\n return createElement(pick(\"filter\", props, layers), props);\n}\n","import type { Filters } from \"@craftainer/crud-sdk\";\nimport type { FieldFilters } from \"./types.ts\";\n\n/**\n * Turns per-field filter state into the SDK's flat `Filters`: `eq` is the bare\n * field name, every other operator is `field__op`.\n */\nexport function toQueryFilters(filters: FieldFilters): Filters {\n const out: Record<string, unknown> = {};\n for (const [name, byOp] of Object.entries(filters)) {\n for (const [op, operand] of Object.entries(byOp ?? {})) {\n out[op === \"eq\" ? name : `${name}__${op}`] = operand;\n }\n }\n return out;\n}\n","// Layout shells: the frames views render into. Styled with theme tokens only.\nimport Box from \"@mui/material/Box\";\nimport Breadcrumbs from \"@mui/material/Breadcrumbs\";\nimport Button from \"@mui/material/Button\";\nimport Container from \"@mui/material/Container\";\nimport Dialog from \"@mui/material/Dialog\";\nimport DialogActions from \"@mui/material/DialogActions\";\nimport DialogContent from \"@mui/material/DialogContent\";\nimport DialogTitle from \"@mui/material/DialogTitle\";\nimport Drawer from \"@mui/material/Drawer\";\nimport Stack from \"@mui/material/Stack\";\nimport Typography from \"@mui/material/Typography\";\nimport { useId, type ReactElement, type ReactNode } from \"react\";\n\n/** Props every shell shares. */\nexport interface ShellProps {\n readonly title: ReactNode;\n /** Buttons for the footer (dialog, drawer) or the header (page). */\n readonly actions?: ReactNode;\n readonly children?: ReactNode;\n}\n\nexport interface PageShellProps extends ShellProps {\n readonly subtitle?: ReactNode;\n /** Links shown above the title, e.g. `[<Link>Heroes</Link>]`. */\n readonly breadcrumbs?: readonly ReactNode[] | undefined;\n readonly maxWidth?: \"sm\" | \"md\" | \"lg\" | \"xl\" | false;\n}\n\n/** A full page: heading row (title, subtitle, actions) above the content. */\nexport function PageShell({\n title,\n subtitle,\n actions,\n breadcrumbs,\n maxWidth = \"lg\",\n children,\n}: PageShellProps): ReactElement {\n return (\n <Container component=\"main\" maxWidth={maxWidth} sx={{ py: 3 }}>\n {breadcrumbs !== undefined && breadcrumbs.length > 0 && (\n <Breadcrumbs aria-label=\"Breadcrumb\" sx={{ mb: 1 }}>\n {breadcrumbs.map((crumb, index) => (\n <Box key={index} component=\"span\">\n {crumb}\n </Box>\n ))}\n </Breadcrumbs>\n )}\n <Stack\n direction={{ xs: \"column\", sm: \"row\" }}\n spacing={2}\n sx={{\n alignItems: { sm: \"center\" },\n justifyContent: \"space-between\",\n mb: 3,\n }}\n >\n <Box>\n <Typography component=\"h1\" variant=\"h4\">\n {title}\n </Typography>\n {subtitle !== undefined && (\n <Typography variant=\"body1\" color=\"text.secondary\">\n {subtitle}\n </Typography>\n )}\n </Box>\n {actions !== undefined && (\n <Stack direction=\"row\" spacing={1}>\n {actions}\n </Stack>\n )}\n </Stack>\n {children}\n </Container>\n );\n}\n\nexport interface OverlayShellProps extends ShellProps {\n readonly open: boolean;\n readonly onClose: () => void;\n /** Label of the close button that is always present. Default \"Close\". */\n readonly closeLabel?: string;\n}\n\nexport interface DialogShellProps extends OverlayShellProps {\n readonly maxWidth?: \"xs\" | \"sm\" | \"md\" | \"lg\";\n}\n\n/** A modal dialog with a title, scrolling content and a footer of actions. */\nexport function DialogShell({\n open,\n onClose,\n title,\n actions,\n closeLabel = \"Close\",\n maxWidth = \"sm\",\n children,\n}: DialogShellProps): ReactElement {\n const titleId = useId();\n return (\n <Dialog\n open={open}\n onClose={onClose}\n fullWidth\n maxWidth={maxWidth}\n aria-labelledby={titleId}\n >\n <DialogTitle id={titleId}>{title}</DialogTitle>\n <DialogContent dividers>{children}</DialogContent>\n <DialogActions>\n <Button onClick={onClose}>{closeLabel}</Button>\n {actions}\n </DialogActions>\n </Dialog>\n );\n}\n\nexport interface DrawerShellProps extends OverlayShellProps {\n readonly anchor?: \"left\" | \"right\";\n /** Width in theme spacing units on screens from `sm` up (full width below). Default 60. */\n readonly width?: number;\n}\n\n/** A side drawer with a title, scrolling content and a footer of actions. */\nexport function DrawerShell({\n open,\n onClose,\n title,\n actions,\n closeLabel = \"Close\",\n anchor = \"right\",\n width = 60,\n children,\n}: DrawerShellProps): ReactElement {\n const titleId = useId();\n return (\n <Drawer\n open={open}\n onClose={onClose}\n anchor={anchor}\n slotProps={{\n paper: {\n \"aria-labelledby\": titleId,\n sx: { width: (theme) => ({ xs: \"100%\", sm: theme.spacing(width) }) },\n },\n }}\n >\n <Stack sx={{ height: \"100%\" }}>\n <Typography id={titleId} component=\"h2\" variant=\"h6\" sx={{ p: 2 }}>\n {title}\n </Typography>\n <Box\n sx={{\n flex: 1,\n overflow: \"auto\",\n p: 2,\n borderTop: 1,\n borderColor: \"divider\",\n }}\n >\n {children}\n </Box>\n <Stack\n direction=\"row\"\n spacing={1}\n sx={{\n justifyContent: \"flex-end\",\n p: 2,\n borderTop: 1,\n borderColor: \"divider\",\n }}\n >\n <Button onClick={onClose}>{closeLabel}</Button>\n {actions}\n </Stack>\n </Stack>\n </Drawer>\n );\n}\n","import type { JsonObject } from \"@craftainer/crud-sdk\";\n\nexport type RecordStatus = \"published\" | \"draft\" | \"archived\";\n\n/** Fields the server maintains (lifecycle and audit); the detail view shows them in its metadata panel. */\nexport const SYSTEM_FIELDS: readonly string[] = [\n \"id\",\n \"owner_id\",\n \"created_at\",\n \"updated_at\",\n \"is_draft\",\n \"archived_at\",\n \"publish_at\",\n \"unpublish_at\",\n \"is_locked\",\n];\n\n/** `archived` wins over `draft`; a record with neither marker is `published`. */\nexport function recordStatus(record: JsonObject): RecordStatus {\n if (typeof record[\"archived_at\"] === \"string\") return \"archived\";\n return record[\"is_draft\"] === true ? \"draft\" : \"published\";\n}\n\nexport type StatusFilterValue = \"published\" | \"draft\" | \"all\";\n\n/** What a list query needs for a status choice: spread into `useList`'s query. */\nexport interface StatusQuery {\n readonly includeUnpublished: boolean;\n readonly filters: Readonly<Record<string, unknown>>;\n}\n\n/**\n * The list query for a status choice. The server hides drafts unless\n * `include_unpublished` is set; `draft` also filters on `is_draft`.\n */\nexport function statusQuery(value: StatusFilterValue): StatusQuery {\n return {\n includeUnpublished: value !== \"published\",\n filters: value === \"draft\" ? { is_draft: true } : {},\n };\n}\n","import Button from \"@mui/material/Button\";\nimport Typography from \"@mui/material/Typography\";\nimport type { ReactElement, ReactNode } from \"react\";\nimport { DialogShell } from \"../core/index.ts\";\n\nexport interface ConfirmDialogProps {\n readonly open: boolean;\n readonly title: string;\n readonly children: ReactNode;\n readonly confirmLabel: string;\n readonly busy?: boolean;\n readonly onConfirm: () => void;\n readonly onClose: () => void;\n}\n\n/** A small confirmation built on `DialogShell`: Cancel and one destructive action. */\nexport function ConfirmDialog({\n open,\n title,\n children,\n confirmLabel,\n busy = false,\n onConfirm,\n onClose,\n}: ConfirmDialogProps): ReactElement {\n return (\n <DialogShell\n open={open}\n onClose={onClose}\n title={title}\n closeLabel=\"Cancel\"\n maxWidth=\"xs\"\n actions={\n <Button\n color=\"error\"\n variant=\"contained\"\n disabled={busy}\n onClick={onConfirm}\n >\n {confirmLabel}\n </Button>\n }\n >\n <Typography>{children}</Typography>\n </DialogShell>\n );\n}\n","import { useMutation, type UseMutationResult } from \"@tanstack/react-query\";\nimport { useCallback } from \"react\";\nimport type { BulkResult, JsonObject } from \"@craftainer/crud-sdk\";\nimport { useCrud, type ReadyResource } from \"../core/index.ts\";\n\n/**\n * Refreshes every cached query of one resource (all API versions), for the\n * calls the core's hooks do not cover: publish, restore and bulk.\n */\nexport function useInvalidateResource(name: string): () => Promise<void> {\n const { queryClient } = useCrud();\n return useCallback(\n () =>\n queryClient.invalidateQueries({\n predicate: (query) =>\n `${String(query.queryKey[0])}/${String(query.queryKey[1]).split(\"@\")[0]}` ===\n `crud/${name}`,\n }),\n [queryClient, name],\n );\n}\n\n/** `POST publish?id=`: turns a draft into a published record. */\nexport function usePublish(\n ready: ReadyResource,\n): UseMutationResult<JsonObject, Error, number> {\n const invalidate = useInvalidateResource(ready.resource.name);\n return useMutation({\n mutationFn: (id: number) => ready.handle.publish(id),\n onSuccess: invalidate,\n });\n}\n\n/** `POST restore?id=`: brings an archived record back. */\nexport function useRestore(\n ready: ReadyResource,\n): UseMutationResult<BulkResult, Error, number> {\n const invalidate = useInvalidateResource(ready.resource.name);\n return useMutation({\n mutationFn: (id: number) => ready.handle.restore({ id }),\n onSuccess: invalidate,\n });\n}\n","import { BadRequest } from \"@craftainer/crud-sdk\";\n\n/** More records than the server will touch in one call (`bulk.max_matched`). */\nexport class BulkLimitError extends Error {\n constructor(max: number) {\n super(limitMessage(max));\n this.name = \"BulkLimitError\";\n }\n}\n\nfunction limitMessage(max: number): string {\n return `More than ${max} records match. Narrow the filter or select fewer records.`;\n}\n\n/**\n * A message for a failed bulk call. The server answers `400` when a filter\n * matches more than `bulk.max_matched` records (or the request is bad for\n * another reason, which its own message then says).\n */\nexport function describeBulkError(error: Error, max: number): string {\n return error instanceof BadRequest\n ? `${error.message.replace(/[.\\s]+$/, \"\")}. A bulk call touches at most ${max} records; if the filter matches more, narrow it.`\n : error.message;\n}\n","import type { JsonObject } from \"@craftainer/crud-sdk\";\nimport type { FieldDescriptor } from \"../core/index.ts\";\n\nfunction cell(value: unknown): string {\n if (value === null || value === undefined) return \"\";\n const raw = typeof value === \"string\" ? value : JSON.stringify(value);\n // A leading = + - @ (or tab/CR) makes a spreadsheet read the cell as a formula.\n const text =\n typeof value === \"string\" && /^[=+\\-@\\t\\r]/.test(raw) ? `'${raw}` : raw;\n return /[\",\\r\\n]/.test(text) ? `\"${text.replaceAll('\"', '\"\"')}\"` : text;\n}\n\n/** RFC 4180 CSV: a header of field names, then one line per record. Objects and arrays become JSON. */\nexport function toCsv(\n fields: readonly FieldDescriptor[],\n rows: readonly JsonObject[],\n): string {\n const lines = [\n fields.map((f) => cell(f.name)).join(\",\"),\n ...rows.map((row) => fields.map((f) => cell(row[f.name])).join(\",\")),\n ];\n return `${lines.join(\"\\r\\n\")}\\r\\n`;\n}\n\n/** Offers `text` to the browser as a file download. */\nexport function downloadText(\n filename: string,\n text: string,\n type = \"text/csv\",\n): void {\n const url = URL.createObjectURL(new Blob([text], { type }));\n const link = document.createElement(\"a\");\n link.href = url;\n link.download = filename;\n link.click();\n // Revoking at once can cancel the download in some browsers.\n setTimeout(() => URL.revokeObjectURL(url), 10_000);\n}\n","import type { BulkResult, Filters, JsonObject } from \"@craftainer/crud-sdk\";\nimport Alert from \"@mui/material/Alert\";\nimport Button from \"@mui/material/Button\";\nimport Paper from \"@mui/material/Paper\";\nimport Stack from \"@mui/material/Stack\";\nimport Typography from \"@mui/material/Typography\";\nimport { useState, type ReactElement } from \"react\";\nimport {\n toQueryFilters,\n type FieldFilters,\n type ReadyResource,\n} from \"../core/index.ts\";\nimport { ConfirmDialog } from \"../lifecycle/ConfirmDialog.tsx\";\nimport { useInvalidateResource } from \"../lifecycle/mutations.ts\";\nimport { BulkLimitError, describeBulkError } from \"./errors.ts\";\nimport { downloadText, toCsv } from \"./export.ts\";\nimport type { BulkSelection } from \"./selection.ts\";\n\nexport type BulkAction = \"delete\" | \"export\" | \"publish\";\n\nexport interface BulkDone {\n readonly action: BulkAction;\n /** Records the call touched. */\n readonly count: number;\n}\n\nexport interface BulkToolbarProps {\n readonly ready: ReadyResource;\n readonly selection: BulkSelection;\n /** The list's current filters. \"Select all matching\" needs at least one. */\n readonly filters?: FieldFilters | undefined;\n /** Actions to offer; each also needs the matching capability. Default: all. */\n readonly actions?: readonly BulkAction[] | undefined;\n /** Receives the CSV of \"Export\"; default: a file download. */\n readonly onExport?: ((csv: string, filename: string) => void) | undefined;\n readonly onDone?: ((done: BulkDone) => void) | undefined;\n}\n\nconst ALL: readonly BulkAction[] = [\"delete\", \"export\", \"publish\"];\n\n/**\n * Bulk calls use filters, never `?id=` with filters (the server rejects that):\n * the ticked ids become `id__in`, \"all matching\" is the list's own filters.\n */\nfunction serverFilters(\n ready: ReadyResource,\n selection: BulkSelection,\n filters: FieldFilters,\n): Filters {\n return selection.allMatching\n ? toQueryFilters(filters)\n : { [`${ready.resource.id_field}__in`]: selection.selected };\n}\n\n/** The toolbar over a list's selection: count, bulk delete, export and bulk publish. Hidden while nothing is selected. */\nexport function BulkToolbar({\n ready,\n selection,\n filters = {},\n actions = ALL,\n onExport,\n onDone,\n}: BulkToolbarProps): ReactElement | null {\n const invalidate = useInvalidateResource(ready.resource.name);\n const [confirming, setConfirming] = useState(false);\n const [busy, setBusy] = useState(false);\n const [error, setError] = useState<string | null>(null);\n const [notice, setNotice] = useState<string | null>(null);\n const { capabilities, bulk, id_field } = ready.resource;\n const max = bulk.max_matched;\n const hasFilters = Object.keys(toQueryFilters(filters)).length > 0;\n const count = selection.selected.length;\n const noticeAlert =\n notice === null ? null : (\n <Alert severity=\"success\" role=\"status\" sx={{ mt: 1.5 }}>\n {notice}\n </Alert>\n );\n if (count === 0 && !selection.allMatching) return noticeAlert;\n\n /** Runs `work`, then reports it. `work` returns the number of records it touched. */\n const run = async (\n action: BulkAction,\n changes: boolean,\n done: (count: number) => string,\n work: () => Promise<number>,\n ): Promise<void> => {\n setBusy(true);\n setError(null);\n setNotice(null);\n try {\n if (!selection.allMatching && count > max) throw new BulkLimitError(max);\n // \"All matching\" with the filters gone would mean every record.\n if (selection.allMatching && !hasFilters) {\n throw new Error(\"The filter was cleared. Select the records again.\");\n }\n const touched = await work();\n if (changes) {\n await invalidate();\n selection.clear();\n }\n setNotice(done(touched));\n onDone?.({ action, count: touched });\n } catch (caught) {\n // A partly done change (publish goes one record at a time) still moved the server.\n if (changes) void invalidate();\n setError(describeBulkError(caught as Error, max));\n } finally {\n setBusy(false);\n setConfirming(false);\n }\n };\n\n const records = async (): Promise<JsonObject[]> => {\n const rows: JsonObject[] = [];\n for await (const row of ready.handle.iterAll({\n filters: serverFilters(ready, selection, filters),\n includeUnpublished: true,\n })) {\n if (rows.length === max) throw new BulkLimitError(max);\n rows.push(row);\n }\n return rows;\n };\n\n const remove = (): Promise<void> =>\n run(\n \"delete\",\n true,\n (n) => `Deleted ${n} ${n === 1 ? \"record\" : \"records\"}.`,\n async () => {\n const result: BulkResult = await ready.handle.deleteMany(\n serverFilters(ready, selection, filters),\n );\n return result.matched;\n },\n );\n\n const exportRows = (): Promise<void> =>\n run(\n \"export\",\n false,\n (n) => `Exported ${n} ${n === 1 ? \"record\" : \"records\"}.`,\n async () => {\n const rows = await records();\n const filename = `${ready.resource.name}-export.csv`;\n const csv = toCsv(ready.fields, rows);\n if (onExport === undefined) downloadText(filename, csv);\n else onExport(csv, filename);\n return rows.length;\n },\n );\n\n const publish = (): Promise<void> =>\n run(\n \"publish\",\n true,\n (n) => `Published ${n} ${n === 1 ? \"record\" : \"records\"}.`,\n async () => {\n const drafts = (await records()).filter(\n (row) => row[\"is_draft\"] === true,\n );\n for (const row of drafts) {\n await ready.handle.publish(row[id_field] as number);\n }\n return drafts.length;\n },\n );\n\n const label = selection.allMatching\n ? \"All records matching the filter are selected\"\n : `${count} selected`;\n return (\n <Paper variant=\"outlined\" sx={{ p: 1.5 }}>\n <Stack\n direction=\"row\"\n spacing={1}\n useFlexGap\n sx={{ alignItems: \"center\", flexWrap: \"wrap\" }}\n >\n <Typography aria-live=\"polite\" sx={{ mr: 1 }}>\n {label}\n </Typography>\n {!selection.allMatching && hasFilters && (\n <Button size=\"small\" onClick={selection.selectAllMatching}>\n Select all matching the filter\n </Button>\n )}\n {actions.includes(\"export\") && (\n <Button\n size=\"small\"\n disabled={busy}\n onClick={() => void exportRows()}\n >\n Export\n </Button>\n )}\n {actions.includes(\"publish\") && capabilities.draft_publish && (\n <Button size=\"small\" disabled={busy} onClick={() => void publish()}>\n Publish\n </Button>\n )}\n {actions.includes(\"delete\") && capabilities.bulk_delete && (\n <Button\n size=\"small\"\n color=\"error\"\n disabled={busy}\n onClick={() => setConfirming(true)}\n >\n Delete\n </Button>\n )}\n <Button size=\"small\" disabled={busy} onClick={selection.clear}>\n Clear selection\n </Button>\n </Stack>\n {noticeAlert}\n {error !== null && (\n <Alert severity=\"error\" sx={{ mt: 1.5 }}>\n {error}\n </Alert>\n )}\n <ConfirmDialog\n open={confirming}\n title=\"Delete the selected records?\"\n confirmLabel=\"Delete\"\n busy={busy}\n onClose={() => setConfirming(false)}\n onConfirm={() => void remove()}\n >\n {selection.allMatching\n ? \"Every record matching the filter is deleted.\"\n : `${count} ${count === 1 ? \"record is\" : \"records are\"} deleted.`}\n </ConfirmDialog>\n </Paper>\n );\n}\n","import { useCallback, useMemo, useState } from \"react\";\n\n/** Which records are selected: explicit ids, or every record matching the current filters. */\nexport interface BulkSelection {\n /** Ids ticked by hand (empty while `allMatching`). */\n readonly selected: readonly number[];\n /** All records matching the list's filters are selected, on every page. */\n readonly allMatching: boolean;\n isSelected(id: number): boolean;\n /**\n * Ticks or unticks one record. Passing the visible page's ids lets an\n * untick while `allMatching` keep the other visible records selected.\n */\n toggle(id: number, visible?: readonly number[]): void;\n /** Ticks or unticks every id of the visible page. */\n setPage(ids: readonly number[], on: boolean): void;\n selectAllMatching(): void;\n clear(): void;\n}\n\n/** Selection state for a list. Ticking a row after \"select all matching\" returns to explicit ids. */\nexport function useBulkSelection(): BulkSelection {\n const [selected, setSelected] = useState<readonly number[]>([]);\n const [allMatching, setAllMatching] = useState(false);\n const toggle = useCallback(\n (id: number, visible: readonly number[] = []) => {\n setAllMatching(false);\n setSelected((current) => {\n // Every visible row showed ticked: unticking one leaves the others ticked.\n if (allMatching) return visible.filter((x) => x !== id);\n return current.includes(id)\n ? current.filter((x) => x !== id)\n : [...current, id];\n });\n },\n [allMatching],\n );\n const setPage = useCallback((ids: readonly number[], on: boolean) => {\n setAllMatching(false);\n setSelected((current) => {\n const rest = current.filter((x) => !ids.includes(x));\n return on ? [...rest, ...ids] : rest;\n });\n }, []);\n const selectAllMatching = useCallback(() => {\n setSelected([]);\n setAllMatching(true);\n }, []);\n const clear = useCallback(() => {\n setSelected([]);\n setAllMatching(false);\n }, []);\n return useMemo(\n () => ({\n selected,\n allMatching,\n isSelected: (id) => selected.includes(id),\n toggle,\n setPage,\n selectAllMatching,\n clear,\n }),\n [selected, allMatching, toggle, setPage, selectAllMatching, clear],\n );\n}\n","import type { JsonObject } from \"@craftainer/crud-sdk\";\nimport Alert from \"@mui/material/Alert\";\nimport Box from \"@mui/material/Box\";\nimport Checkbox from \"@mui/material/Checkbox\";\nimport CircularProgress from \"@mui/material/CircularProgress\";\nimport Stack from \"@mui/material/Stack\";\nimport Table from \"@mui/material/Table\";\nimport TableBody from \"@mui/material/TableBody\";\nimport TableCell from \"@mui/material/TableCell\";\nimport TableHead from \"@mui/material/TableHead\";\nimport TableRow from \"@mui/material/TableRow\";\nimport { useState, type ReactElement } from \"react\";\nimport {\n FieldDisplay,\n ResourceGate,\n toQueryFilters,\n type FieldFilters,\n type FieldValue,\n type ReadyResource,\n type RendererOverrides,\n} from \"../core/index.ts\";\nimport { SYSTEM_FIELDS } from \"../lifecycle/status.ts\";\nimport { BulkToolbar, type BulkToolbarProps } from \"./BulkToolbar.tsx\";\nimport { useBulkSelection } from \"./selection.ts\";\n\nexport interface BulkPanelProps extends Pick<\n BulkToolbarProps,\n \"actions\" | \"onExport\" | \"onDone\"\n> {\n readonly ready: ReadyResource;\n readonly filters?: FieldFilters | undefined;\n /** Columns to show; default: the first four non-system fields. */\n readonly columns?: readonly string[] | undefined;\n /** Page size; default 25. */\n readonly limit?: number | undefined;\n readonly renderers?: RendererOverrides | undefined;\n}\n\n/** A selectable table over one page of an already loaded resource, with the bulk toolbar above it. */\nexport function BulkPanel({\n ready,\n filters,\n columns,\n limit = 25,\n renderers,\n ...toolbar\n}: BulkPanelProps): ReactElement {\n const selection = useBulkSelection();\n // A selection made under other filters no longer describes what is listed.\n const filterKey = JSON.stringify(filters ?? {});\n const [seenFilters, setSeenFilters] = useState(filterKey);\n if (seenFilters !== filterKey) {\n setSeenFilters(filterKey);\n selection.clear();\n }\n const list = ready.hooks.useList({\n filters: toQueryFilters(filters ?? {}),\n limit,\n });\n const fields =\n columns === undefined\n ? ready.fields.filter((f) => !SYSTEM_FIELDS.includes(f.name)).slice(0, 4)\n : ready.fields.filter((f) => columns.includes(f.name));\n if (list.isPending) {\n return (\n <Box sx={{ display: \"flex\", justifyContent: \"center\", p: 4 }}>\n <CircularProgress aria-label=\"Loading\" />\n </Box>\n );\n }\n if (list.error !== null) {\n return <Alert severity=\"error\">{list.error.message}</Alert>;\n }\n const idOf = (row: JsonObject): number =>\n row[ready.resource.id_field] as number;\n const ids = list.data.map(idOf);\n const ticked = ids.filter(\n (id) => selection.allMatching || selection.isSelected(id),\n );\n return (\n <Stack spacing={2}>\n <BulkToolbar\n ready={ready}\n selection={selection}\n filters={filters}\n {...toolbar}\n />\n <Table size=\"small\" aria-label={ready.resource.title}>\n <TableHead>\n <TableRow>\n <TableCell padding=\"checkbox\">\n <Checkbox\n checked={ids.length > 0 && ticked.length === ids.length}\n indeterminate={ticked.length > 0 && ticked.length < ids.length}\n onChange={(event) =>\n selection.setPage(ids, event.target.checked)\n }\n slotProps={{\n input: { \"aria-label\": \"Select all on this page\" },\n }}\n />\n </TableCell>\n {fields.map((f) => (\n <TableCell key={f.name}>{f.label}</TableCell>\n ))}\n </TableRow>\n </TableHead>\n <TableBody>\n {list.data.map((row) => {\n const id = idOf(row);\n const on = selection.allMatching || selection.isSelected(id);\n return (\n <TableRow key={id} hover selected={on}>\n <TableCell padding=\"checkbox\">\n <Checkbox\n checked={on}\n onChange={() => selection.toggle(id, ids)}\n slotProps={{\n input: { \"aria-label\": `Select record ${id}` },\n }}\n />\n </TableCell>\n {fields.map((f) => (\n <TableCell key={f.name}>\n <FieldDisplay\n field={f}\n resource={ready.resource.name}\n value={row[f.name] as FieldValue}\n renderers={renderers}\n />\n </TableCell>\n ))}\n </TableRow>\n );\n })}\n </TableBody>\n </Table>\n </Stack>\n );\n}\n\nexport interface BulkRecordsProps extends Omit<BulkPanelProps, \"ready\"> {\n readonly resource: string;\n readonly apiVersion?: string | undefined;\n}\n\n/**\n * Records with checkboxes and the bulk toolbar: selection count, bulk delete,\n * export, bulk publish and filter-based select-all (no count preview). Bulk\n * calls respect `bulk.max_matched`.\n */\nexport function BulkRecords({\n resource,\n apiVersion,\n ...rest\n}: BulkRecordsProps): ReactElement {\n return (\n <ResourceGate name={resource} apiVersion={apiVersion}>\n {(ready) => <BulkPanel ready={ready} {...rest} />}\n </ResourceGate>\n );\n}\n","import Alert from \"@mui/material/Alert\";\nimport Button from \"@mui/material/Button\";\nimport FormControlLabel from \"@mui/material/FormControlLabel\";\nimport Snackbar from \"@mui/material/Snackbar\";\nimport Switch from \"@mui/material/Switch\";\nimport { useState, type ReactElement } from \"react\";\nimport type { ReadyResource } from \"../core/index.ts\";\nimport type { RecordActionProps } from \"./DraftControls.tsx\";\nimport { useRestore } from \"./mutations.ts\";\n\nexport interface ArchivedToggleProps {\n readonly ready: ReadyResource;\n /** Maps to the list query's `includeArchived`. */\n readonly checked: boolean;\n readonly onChange: (checked: boolean) => void;\n}\n\n/** \"Show archived\" switch. Hidden unless `capabilities.archive_restore`. */\nexport function ArchivedToggle({\n ready,\n checked,\n onChange,\n}: ArchivedToggleProps): ReactElement | null {\n if (!ready.capabilities.archive_restore) return null;\n return (\n <FormControlLabel\n label=\"Show archived\"\n control={\n <Switch\n checked={checked}\n onChange={(event) => onChange(event.target.checked)}\n />\n }\n />\n );\n}\n\n/**\n * Archives a record (the server's delete is a soft delete when it has an\n * archive) and offers Undo, which restores it. Hidden without `archive_restore`.\n */\nexport function ArchiveButton({\n ready,\n id,\n onDone,\n onArchived,\n onUndone,\n label = \"Archive\",\n ariaLabel,\n archived = false,\n}: RecordActionProps & {\n /** Button text. Default \"Archive\". */\n readonly label?: string | undefined;\n /** Accessible name when the text alone is ambiguous, e.g. \"Delete hero 1\". */\n readonly ariaLabel?: string | undefined;\n /** Called once the record is archived (`onDone` also runs, as after an undo). */\n readonly onArchived?: (() => void) | undefined;\n /** Called once Undo restored the record. */\n readonly onUndone?: (() => void) | undefined;\n /** The record is archived already: the button hides, an Undo toast can still show. */\n readonly archived?: boolean;\n}): ReactElement | null {\n const remove = ready.hooks.useDelete();\n const restore = useRestore(ready);\n const [undoOpen, setUndoOpen] = useState(false);\n if (!ready.capabilities.archive_restore) return null;\n const error = remove.error ?? restore.error;\n return (\n <>\n {!archived && (\n <Button\n color=\"error\"\n size=\"small\"\n aria-label={ariaLabel}\n disabled={remove.isPending}\n onClick={() =>\n remove.mutate(id, {\n onSuccess: () => {\n setUndoOpen(true);\n onArchived?.();\n onDone?.();\n },\n })\n }\n >\n {label}\n </Button>\n )}\n {error !== null && <Alert severity=\"error\">{error.message}</Alert>}\n <Snackbar\n open={undoOpen}\n autoHideDuration={8000}\n onClose={(_event, reason) => {\n if (reason !== \"clickaway\") setUndoOpen(false);\n }}\n message=\"Record archived\"\n action={\n <Button\n size=\"small\"\n color=\"inherit\"\n onClick={() =>\n restore.mutate(id, {\n onSuccess: () => {\n setUndoOpen(false);\n onUndone?.();\n onDone?.();\n },\n })\n }\n >\n Undo\n </Button>\n }\n />\n </>\n );\n}\n\n/** Restores an archived record. Hidden without `archive_restore`. */\nexport function RestoreButton({\n ready,\n id,\n onDone,\n}: RecordActionProps): ReactElement | null {\n const restore = useRestore(ready);\n if (!ready.capabilities.archive_restore) return null;\n return (\n <>\n <Button\n size=\"small\"\n variant=\"contained\"\n disabled={restore.isPending}\n onClick={() => restore.mutate(id, { onSuccess: () => onDone?.() })}\n >\n Restore\n </Button>\n {restore.error !== null && (\n <Alert severity=\"error\">{restore.error.message}</Alert>\n )}\n </>\n );\n}\n","// <DeleteAction>: a delete button with four ways to confirm or take back the\n// deletion (see ./README.md).\nimport Alert from \"@mui/material/Alert\";\nimport Button from \"@mui/material/Button\";\nimport Snackbar from \"@mui/material/Snackbar\";\nimport Stack from \"@mui/material/Stack\";\nimport Typography from \"@mui/material/Typography\";\nimport { useEffect, useRef, useState, type ReactElement } from \"react\";\nimport {\n DialogShell,\n FieldDisplay,\n ResourceGate,\n type FieldValue,\n type ReadyResource,\n type RendererOverrides,\n} from \"../core/index.ts\";\nimport { ArchiveButton } from \"../lifecycle/ArchiveControls.tsx\";\n\n/**\n * - `immediate`: delete on click.\n * - `confirm`: ask first, showing the record.\n * - `undo`: hold the deletion back for `undoMs`; Undo cancels it.\n * - `soft`: delete (the server archives the record) and offer Undo, which\n * restores it; renders lifecycle's `ArchiveButton`, needs the `archive_restore`\n * capability, else renders nothing.\n */\nexport type DeleteVariant = \"immediate\" | \"confirm\" | \"undo\" | \"soft\";\n\nexport interface DeleteActionProps {\n readonly name: string;\n readonly apiVersion?: string | undefined;\n readonly id: number;\n /** Default `\"confirm\"`. */\n readonly variant?: DeleteVariant;\n /** Button text. Default \"Delete\". */\n readonly label?: string | undefined;\n /** What one record is called in messages. Default \"record\". */\n readonly recordLabel?: string | undefined;\n /** Called once the record is deleted on the server. */\n readonly onDeleted?: ((id: number) => void) | undefined;\n /** Called when Undo cancelled a pending deletion or restored the record. */\n readonly onUndone?: ((id: number) => void) | undefined;\n /** `undo`: how long the deletion waits, in milliseconds. Default 6000. */\n readonly undoMs?: number | undefined;\n /** `confirm`: the fields shown. Default the first three besides `id`. */\n readonly summaryFields?: readonly string[] | undefined;\n readonly renderers?: RendererOverrides | undefined;\n}\n\ninterface Toast {\n readonly text: string;\n readonly undo: () => void;\n}\n\n/** A delete button for one record; see `DeleteActionProps`. */\nexport function DeleteAction(props: DeleteActionProps): ReactElement {\n return (\n <ResourceGate\n name={props.name}\n apiVersion={props.apiVersion}\n pending={<></>}\n fallback={() => null}\n >\n {(ready) =>\n props.variant === \"soft\" ? (\n ready.capabilities.archive_restore ? (\n <ArchiveButton\n ready={ready}\n id={props.id}\n label={props.label ?? \"Delete\"}\n ariaLabel={`${props.label ?? \"Delete\"} ${props.recordLabel ?? \"record\"} ${props.id}`}\n onArchived={() => props.onDeleted?.(props.id)}\n onUndone={() => props.onUndone?.(props.id)}\n />\n ) : null\n ) : (\n <DeleteController ready={ready} {...props} />\n )\n }\n </ResourceGate>\n );\n}\n\nfunction RecordSummary({\n ready,\n id,\n names,\n renderers,\n}: {\n readonly ready: ReadyResource;\n readonly id: number;\n readonly names: readonly string[] | undefined;\n readonly renderers: RendererOverrides | undefined;\n}): ReactElement {\n const record = ready.hooks.useRecord(id);\n const shown =\n names === undefined\n ? ready.fields.filter((f) => f.name !== \"id\").slice(0, 3)\n : ready.fields.filter((f) => names.includes(f.name));\n const row = record.data as Record<string, FieldValue> | undefined;\n return (\n <Stack component=\"dl\" spacing={1} sx={{ m: 0 }}>\n {row !== undefined &&\n shown.map((field) => (\n <Stack key={field.name} direction=\"row\" spacing={2}>\n <Typography\n component=\"dt\"\n variant=\"body2\"\n sx={{ color: \"text.secondary\", minWidth: \"10ch\" }}\n >\n {field.label}\n </Typography>\n <Typography component=\"dd\" variant=\"body2\" sx={{ m: 0 }}>\n <FieldDisplay\n field={field}\n resource={ready.resource.name}\n value={row[field.name]}\n record={row}\n renderers={renderers}\n />\n </Typography>\n </Stack>\n ))}\n </Stack>\n );\n}\n\nfunction DeleteController({\n ready,\n ...props\n}: DeleteActionProps & { readonly ready: ReadyResource }): ReactElement | null {\n const { id, variant = \"confirm\", undoMs = 6000 } = props;\n const label = props.recordLabel ?? \"record\";\n const remove = ready.hooks.useDelete();\n const [confirming, setConfirming] = useState(false);\n const [toast, setToast] = useState<Toast | null>(null);\n const [error, setError] = useState<string | null>(null);\n const [busy, setBusy] = useState(false);\n const timer = useRef<ReturnType<typeof setTimeout> | undefined>(undefined);\n\n const run = async (): Promise<boolean> => {\n setBusy(true);\n try {\n await remove.mutateAsync(id);\n props.onDeleted?.(id);\n return true;\n } catch (failure) {\n setError(failure instanceof Error ? failure.message : \"Could not delete\");\n return false;\n } finally {\n setBusy(false);\n }\n };\n\n // Leaving while an `undo` deletion waits commits it: the user asked for it.\n const pending = useRef<(() => Promise<boolean>) | undefined>(undefined);\n useEffect(\n () => () => {\n if (timer.current !== undefined) {\n clearTimeout(timer.current);\n void pending.current?.();\n }\n },\n [],\n );\n\n const undoLater = (): void => {\n pending.current = run;\n setToast({\n text: `Deleting ${label} ${id}…`,\n undo: () => {\n clearTimeout(timer.current);\n timer.current = undefined;\n setToast(null);\n props.onUndone?.(id);\n },\n });\n timer.current = setTimeout(() => {\n timer.current = undefined;\n setToast(null);\n void run();\n }, undoMs);\n };\n\n const click = (): void => {\n if (variant === \"confirm\") setConfirming(true);\n else if (variant === \"undo\") undoLater();\n else void run();\n };\n\n return (\n <>\n <Button\n color=\"error\"\n size=\"small\"\n disabled={busy || (variant === \"undo\" && toast !== null)}\n onClick={click}\n aria-label={`${props.label ?? \"Delete\"} ${label} ${id}`}\n >\n {props.label ?? \"Delete\"}\n </Button>\n {variant === \"confirm\" && (\n <DialogShell\n open={confirming}\n onClose={() => setConfirming(false)}\n title={`Delete ${label} ${id}?`}\n closeLabel=\"Cancel\"\n maxWidth=\"xs\"\n actions={\n <Button\n color=\"error\"\n variant=\"contained\"\n onClick={() => {\n setConfirming(false);\n void run();\n }}\n >\n {props.label ?? \"Delete\"}\n </Button>\n }\n >\n <RecordSummary\n ready={ready}\n id={id}\n names={props.summaryFields}\n renderers={props.renderers}\n />\n </DialogShell>\n )}\n <Snackbar\n open={toast !== null}\n message={toast?.text}\n autoHideDuration={null}\n action={\n <Button color=\"inherit\" size=\"small\" onClick={toast?.undo}>\n Undo\n </Button>\n }\n />\n <Snackbar open={error !== null} onClose={() => setError(null)}>\n <Alert severity=\"error\" onClose={() => setError(null)}>\n {error}\n </Alert>\n </Snackbar>\n </>\n );\n}\n","import type { JsonObject } from \"@craftainer/crud-sdk\";\nimport Alert from \"@mui/material/Alert\";\nimport Button from \"@mui/material/Button\";\nimport Chip from \"@mui/material/Chip\";\nimport Stack from \"@mui/material/Stack\";\nimport { useState, type ReactElement } from \"react\";\nimport type { ReadyResource } from \"../core/index.ts\";\nimport { ConfirmDialog } from \"./ConfirmDialog.tsx\";\nimport { usePublish } from \"./mutations.ts\";\nimport { recordStatus, type RecordStatus } from \"./status.ts\";\n\nconst STATUS_LABEL: Record<RecordStatus, string> = {\n published: \"Published\",\n draft: \"Draft\",\n archived: \"Archived\",\n};\n\nconst STATUS_COLOR = {\n published: \"success\",\n draft: \"warning\",\n archived: \"default\",\n} as const satisfies Record<RecordStatus, \"success\" | \"warning\" | \"default\">;\n\nexport interface StatusBadgeProps {\n readonly ready: ReadyResource;\n readonly record: JsonObject;\n}\n\n/** A chip with the record's state. Hidden unless the resource has drafts or an archive. */\nexport function StatusBadge({\n ready,\n record,\n}: StatusBadgeProps): ReactElement | null {\n const { draft_publish, archive_restore } = ready.capabilities;\n if (!draft_publish && !archive_restore) return null;\n const status = recordStatus(record);\n return (\n <Chip\n size=\"small\"\n variant=\"outlined\"\n color={STATUS_COLOR[status]}\n label={STATUS_LABEL[status]}\n />\n );\n}\n\nexport interface RecordActionProps {\n readonly ready: ReadyResource;\n readonly id: number;\n /** Called after the server accepted the change. */\n readonly onDone?: (() => void) | undefined;\n}\n\n/** Publishes a draft. Hidden unless `capabilities.draft_publish`. */\nexport function PublishButton({\n ready,\n id,\n onDone,\n}: RecordActionProps): ReactElement | null {\n const publish = usePublish(ready);\n if (!ready.capabilities.draft_publish) return null;\n return (\n <>\n <Button\n variant=\"contained\"\n size=\"small\"\n disabled={publish.isPending}\n onClick={() => publish.mutate(id, { onSuccess: () => onDone?.() })}\n >\n Publish\n </Button>\n {publish.error !== null && (\n <Alert severity=\"error\">{publish.error.message}</Alert>\n )}\n </>\n );\n}\n\n/** Discards a draft after a confirmation (a draft has no published state to fall back to, so it is deleted). */\nexport function DiscardDraftButton({\n ready,\n id,\n onDone,\n}: RecordActionProps): ReactElement | null {\n const remove = ready.hooks.useDelete();\n const [open, setOpen] = useState(false);\n if (!ready.capabilities.draft_publish) return null;\n return (\n <>\n <Button\n color=\"error\"\n size=\"small\"\n onClick={() => {\n remove.reset();\n setOpen(true);\n }}\n >\n Discard draft\n </Button>\n <ConfirmDialog\n open={open}\n title=\"Discard this draft?\"\n confirmLabel=\"Discard\"\n busy={remove.isPending}\n onClose={() => setOpen(false)}\n onConfirm={() =>\n remove.mutate(id, {\n onSuccess: () => {\n setOpen(false);\n onDone?.();\n },\n })\n }\n >\n The draft is deleted and cannot be brought back.\n {remove.error !== null && ` ${remove.error.message}`}\n </ConfirmDialog>\n </>\n );\n}\n\nexport interface DraftControlsProps {\n readonly ready: ReadyResource;\n readonly record: JsonObject;\n readonly id: number;\n /** Called after a publish or a discard. */\n readonly onChanged?: (() => void) | undefined;\n}\n\n/** Status badge plus, for a draft, Publish and Discard draft. Hidden without `draft_publish`. */\nexport function DraftControls({\n ready,\n record,\n id,\n onChanged,\n}: DraftControlsProps): ReactElement | null {\n if (!ready.capabilities.draft_publish) return null;\n return (\n <Stack\n direction=\"row\"\n spacing={1}\n sx={{ alignItems: \"center\", flexWrap: \"wrap\" }}\n >\n <StatusBadge ready={ready} record={record} />\n {recordStatus(record) === \"draft\" && (\n <>\n <PublishButton ready={ready} id={id} onDone={onChanged} />\n <DiscardDraftButton ready={ready} id={id} onDone={onChanged} />\n </>\n )}\n </Stack>\n );\n}\n","import type { JsonObject } from \"@craftainer/crud-sdk\";\nimport Box from \"@mui/material/Box\";\nimport Typography from \"@mui/material/Typography\";\nimport type { ReactElement } from \"react\";\nimport {\n FieldDisplay,\n type FieldDescriptor,\n type FieldValue,\n type RendererOverrides,\n} from \"../core/index.ts\";\n\nexport interface FieldListProps {\n readonly resource: string;\n readonly fields: readonly FieldDescriptor[];\n readonly record: JsonObject;\n readonly renderers?: RendererOverrides | undefined;\n}\n\n/** A label and value for each field, as a description list. */\nexport function FieldList({\n resource,\n fields,\n record,\n renderers,\n}: FieldListProps): ReactElement {\n return (\n <Box\n component=\"dl\"\n sx={{\n display: \"grid\",\n gridTemplateColumns: {\n xs: \"minmax(0, 1fr)\",\n sm: \"minmax(0, 1fr) minmax(0, 2fr)\",\n },\n columnGap: 3,\n rowGap: 1.5,\n m: 0,\n }}\n >\n {fields.map((field) => (\n <Box key={field.name} sx={{ display: \"contents\" }}>\n <Typography\n component=\"dt\"\n variant=\"subtitle2\"\n color=\"text.secondary\"\n sx={{ pt: 0.5 }}\n >\n {field.label}\n </Typography>\n <Box component=\"dd\" sx={{ m: 0, minWidth: 0 }}>\n <FieldDisplay\n field={field}\n resource={resource}\n value={record[field.name] as FieldValue}\n record={record as Record<string, FieldValue>}\n renderers={renderers}\n />\n </Box>\n </Box>\n ))}\n </Box>\n );\n}\n","import type { JsonObject } from \"@craftainer/crud-sdk\";\nimport type { FieldDescriptor } from \"../core/index.ts\";\n\n/** One entry of a record's history (`GET revisions?id=`, newest first). */\nexport interface Revision {\n readonly id: number;\n readonly action: string;\n readonly actor: string;\n /** ISO-8601 UTC. */\n readonly createdAt: string;\n /** The record as it was after the action. */\n readonly snapshot: JsonObject;\n}\n\n/** Reads the server's revision rows. A row without a snapshot gets an empty one. */\nexport function toRevisions(rows: readonly JsonObject[]): Revision[] {\n return rows.map((row) => ({\n id: Number(row[\"id\"]),\n action: String(row[\"action\"]),\n actor: String(row[\"actor\"]),\n createdAt: String(row[\"created_at\"]),\n snapshot: (row[\"snapshot\"] ?? {}) as JsonObject,\n }));\n}\n\nconst same = (a: unknown, b: unknown): boolean =>\n JSON.stringify(a) === JSON.stringify(b);\n\n/** Names of the `fields` whose value differs between two snapshots. */\nexport function changedFields(\n fields: readonly FieldDescriptor[],\n before: JsonObject,\n after: JsonObject,\n): string[] {\n return fields\n .filter((f) => !same(before[f.name], after[f.name]))\n .map((f) => f.name);\n}\n\n/**\n * The `PATCH` body that puts a record back to `snapshot`: the writable fields\n * the snapshot has. A `null` for a field that does not take `null` is left out,\n * as a cleared optional field is everywhere else.\n */\nexport function restorePatch(\n fields: readonly FieldDescriptor[],\n snapshot: JsonObject,\n): JsonObject {\n const patch: Record<string, unknown> = {};\n for (const f of fields) {\n if (f.readOnly || !(f.name in snapshot)) continue;\n const value = snapshot[f.name];\n if (value === null && !f.nullable) continue;\n patch[f.name] = value;\n }\n return patch;\n}\n\n/** A descriptor for the revision timestamp, so it renders like any datetime. */\nexport const CREATED_AT_FIELD: FieldDescriptor = {\n name: \"created_at\",\n label: \"When\",\n kind: \"datetime\",\n format: \"date-time\",\n nullable: false,\n readOnly: true,\n required: false,\n choices: null,\n itemKind: null,\n constraints: {\n minLength: undefined,\n maxLength: undefined,\n minimum: undefined,\n maximum: undefined,\n pattern: undefined,\n },\n inManifest: false,\n sortable: false,\n filterOps: [],\n numeric: false,\n categorical: false,\n};\n","import type { JsonObject } from \"@craftainer/crud-sdk\";\nimport Alert from \"@mui/material/Alert\";\nimport Box from \"@mui/material/Box\";\nimport Button from \"@mui/material/Button\";\nimport Chip from \"@mui/material/Chip\";\nimport CircularProgress from \"@mui/material/CircularProgress\";\nimport FormControlLabel from \"@mui/material/FormControlLabel\";\nimport List from \"@mui/material/List\";\nimport ListItem from \"@mui/material/ListItem\";\nimport ListItemText from \"@mui/material/ListItemText\";\nimport MenuItem from \"@mui/material/MenuItem\";\nimport Stack from \"@mui/material/Stack\";\nimport Switch from \"@mui/material/Switch\";\nimport Table from \"@mui/material/Table\";\nimport TableBody from \"@mui/material/TableBody\";\nimport TableCell from \"@mui/material/TableCell\";\nimport TableHead from \"@mui/material/TableHead\";\nimport TableRow from \"@mui/material/TableRow\";\nimport TextField from \"@mui/material/TextField\";\nimport Typography from \"@mui/material/Typography\";\nimport { useState, type ReactElement } from \"react\";\nimport {\n FieldDisplay,\n ResourceGate,\n type FieldDescriptor,\n type FieldValue,\n type ReadyResource,\n type RendererOverrides,\n} from \"../core/index.ts\";\nimport { FieldList } from \"../detail/FieldList.tsx\";\nimport { ConfirmDialog } from \"../lifecycle/ConfirmDialog.tsx\";\nimport { useInvalidateResource } from \"../lifecycle/mutations.ts\";\nimport {\n CREATED_AT_FIELD,\n changedFields,\n restorePatch,\n toRevisions,\n type Revision,\n} from \"./revision.ts\";\n\nexport type RevisionsVariant = \"list\" | \"audit\" | \"diff\" | \"preview\";\n\nexport interface RevisionsPanelProps {\n readonly ready: ReadyResource;\n readonly id: number;\n readonly variant?: RevisionsVariant | undefined;\n readonly renderers?: RendererOverrides | undefined;\n /** Called after a revision was restored (list variant). */\n readonly onRestored?: ((revision: Revision) => void) | undefined;\n}\n\ninterface VariantProps {\n readonly ready: ReadyResource;\n readonly id: number;\n readonly revisions: readonly Revision[];\n readonly renderers: RendererOverrides | undefined;\n readonly onRestored: ((revision: Revision) => void) | undefined;\n}\n\nfunction When({\n ready,\n value,\n renderers,\n}: {\n ready: ReadyResource;\n value: string;\n renderers: RendererOverrides | undefined;\n}): ReactElement {\n return (\n <FieldDisplay\n field={CREATED_AT_FIELD}\n resource={ready.resource.name}\n value={value}\n renderers={renderers}\n />\n );\n}\n\n/** Revisions newest first, each with Restore: a `PATCH` of the snapshot's writable fields. */\nfunction RevisionListVariant({\n ready,\n id,\n revisions,\n renderers,\n onRestored,\n}: VariantProps): ReactElement {\n const update = ready.hooks.useUpdate();\n const invalidate = useInvalidateResource(ready.resource.name);\n const [target, setTarget] = useState<Revision | null>(null);\n return (\n <>\n {update.error !== null && (\n <Alert severity=\"error\">{update.error.message}</Alert>\n )}\n <List aria-label=\"Revisions\" disablePadding>\n {revisions.map((revision) => (\n <ListItem\n key={revision.id}\n divider\n secondaryAction={\n <Button\n size=\"small\"\n aria-label={`Restore revision ${revision.id}`}\n onClick={() => {\n update.reset();\n setTarget(revision);\n }}\n >\n Restore\n </Button>\n }\n >\n <ListItemText\n primary={`${revision.action} by ${revision.actor}`}\n secondary={\n <When\n ready={ready}\n value={revision.createdAt}\n renderers={renderers}\n />\n }\n slotProps={{ secondary: { component: \"div\" } }}\n />\n </ListItem>\n ))}\n </List>\n <ConfirmDialog\n open={target !== null}\n title=\"Restore this revision?\"\n confirmLabel=\"Restore\"\n busy={update.isPending}\n onClose={() => setTarget(null)}\n onConfirm={() => {\n // The dialog is only open with a target.\n const revision = target as Revision;\n update.mutate(\n { id, patch: restorePatch(ready.fields, revision.snapshot) },\n {\n onSuccess: () => {\n setTarget(null);\n void invalidate();\n onRestored?.(revision);\n },\n },\n );\n }}\n >\n The record is updated with the values of this revision.\n </ConfirmDialog>\n </>\n );\n}\n\nconst changedLabels = (\n fields: readonly FieldDescriptor[],\n before: JsonObject,\n after: JsonObject,\n): string => {\n const names = changedFields(fields, before, after);\n return fields\n .filter((f) => names.includes(f.name))\n .map((f) => f.label)\n .join(\", \");\n};\n\n/** A table of who did what and when, with the fields each change touched. */\nfunction RevisionAuditVariant({\n ready,\n revisions,\n renderers,\n}: VariantProps): ReactElement {\n return (\n <Table size=\"small\" aria-label=\"Audit trail\">\n <TableHead>\n <TableRow>\n <TableCell>When</TableCell>\n <TableCell>Action</TableCell>\n <TableCell>Actor</TableCell>\n <TableCell>Changed fields</TableCell>\n </TableRow>\n </TableHead>\n <TableBody>\n {revisions.map((revision, index) => (\n <TableRow key={revision.id}>\n <TableCell>\n <When\n ready={ready}\n value={revision.createdAt}\n renderers={renderers}\n />\n </TableCell>\n <TableCell>{revision.action}</TableCell>\n <TableCell>{revision.actor}</TableCell>\n <TableCell>\n {changedLabels(\n ready.fields,\n revisions[index + 1]?.snapshot ?? {},\n revision.snapshot,\n )}\n </TableCell>\n </TableRow>\n ))}\n </TableBody>\n </Table>\n );\n}\n\nfunction RevisionSelect({\n label,\n value,\n revisions,\n onChange,\n}: {\n label: string;\n value: number;\n revisions: readonly Revision[];\n onChange: (id: number) => void;\n}): ReactElement {\n return (\n <TextField\n select\n size=\"small\"\n label={label}\n value={value}\n onChange={(event) => onChange(Number(event.target.value))}\n sx={{ minWidth: 220 }}\n >\n {revisions.map((revision) => (\n <MenuItem key={revision.id} value={revision.id}>\n {`#${revision.id} ${revision.action}`}\n </MenuItem>\n ))}\n </TextField>\n );\n}\n\n/** Two revisions side by side, field by field; unchanged fields are hidden by default. */\nfunction RevisionDiffVariant({\n ready,\n revisions,\n renderers,\n}: VariantProps): ReactElement {\n const newest = revisions[0] as Revision;\n const [toId, setToId] = useState<number | null>(null);\n const [fromId, setFromId] = useState<number | null>(null);\n const [all, setAll] = useState(false);\n const to = revisions.find((r) => r.id === toId) ?? newest;\n const from =\n revisions.find((r) => r.id === fromId) ??\n revisions[revisions.indexOf(to) + 1] ??\n to;\n const changed = new Set(\n changedFields(ready.fields, from.snapshot, to.snapshot),\n );\n const rows = ready.fields.filter((f) => all || changed.has(f.name));\n const show = (field: FieldDescriptor, revision: Revision): ReactElement => (\n <FieldDisplay\n field={field}\n resource={ready.resource.name}\n value={revision.snapshot[field.name] as FieldValue}\n renderers={renderers}\n />\n );\n return (\n <Stack spacing={2}>\n <Stack direction=\"row\" spacing={2} useFlexGap sx={{ flexWrap: \"wrap\" }}>\n <RevisionSelect\n label=\"From\"\n value={from.id}\n revisions={revisions}\n onChange={setFromId}\n />\n <RevisionSelect\n label=\"To\"\n value={to.id}\n revisions={revisions}\n onChange={setToId}\n />\n <FormControlLabel\n label=\"Show unchanged fields\"\n control={\n <Switch\n checked={all}\n onChange={(event) => setAll(event.target.checked)}\n />\n }\n />\n </Stack>\n {rows.length === 0 ? (\n <Typography color=\"text.secondary\">\n These revisions are identical.\n </Typography>\n ) : (\n <Table size=\"small\" aria-label=\"Changes\">\n <TableHead>\n <TableRow>\n <TableCell>Field</TableCell>\n <TableCell>Before</TableCell>\n <TableCell>After</TableCell>\n </TableRow>\n </TableHead>\n <TableBody>\n {rows.map((field) => (\n <TableRow\n key={field.name}\n sx={\n changed.has(field.name)\n ? { bgcolor: \"action.selected\" }\n : undefined\n }\n >\n <TableCell component=\"th\" scope=\"row\">\n {field.label}\n {changed.has(field.name) && (\n <Chip size=\"small\" label=\"changed\" sx={{ ml: 1 }} />\n )}\n </TableCell>\n <TableCell>{show(field, from)}</TableCell>\n <TableCell>{show(field, to)}</TableCell>\n </TableRow>\n ))}\n </TableBody>\n </Table>\n )}\n </Stack>\n );\n}\n\n/** One revision's snapshot as a read-only field list; pick the revision from a menu. */\nfunction RevisionPreviewVariant({\n ready,\n revisions,\n renderers,\n}: VariantProps): ReactElement {\n const [pickedId, setPickedId] = useState<number | null>(null);\n const picked =\n revisions.find((r) => r.id === pickedId) ?? (revisions[0] as Revision);\n return (\n <Stack spacing={2}>\n <Box>\n <RevisionSelect\n label=\"Revision\"\n value={picked.id}\n revisions={revisions}\n onChange={setPickedId}\n />\n </Box>\n <FieldList\n resource={ready.resource.name}\n fields={ready.fields}\n record={picked.snapshot}\n renderers={renderers}\n />\n </Stack>\n );\n}\n\nconst VARIANTS = {\n list: RevisionListVariant,\n audit: RevisionAuditVariant,\n diff: RevisionDiffVariant,\n preview: RevisionPreviewVariant,\n} as const satisfies Record<\n RevisionsVariant,\n (p: VariantProps) => ReactElement\n>;\n\nfunction RevisionsBody({\n ready,\n id,\n variant = \"list\",\n renderers,\n onRestored,\n}: RevisionsPanelProps): ReactElement {\n const query = ready.hooks.useRevisions(id);\n if (query.isPending) {\n return (\n <Box sx={{ display: \"flex\", justifyContent: \"center\", p: 4 }}>\n <CircularProgress aria-label=\"Loading\" />\n </Box>\n );\n }\n if (query.error !== null) {\n return <Alert severity=\"error\">{query.error.message}</Alert>;\n }\n const revisions = toRevisions(query.data);\n if (revisions.length === 0) {\n return <Typography color=\"text.secondary\">No revisions yet.</Typography>;\n }\n const Variant = VARIANTS[variant];\n return (\n <Variant\n ready={ready}\n id={id}\n revisions={revisions}\n renderers={renderers}\n onRestored={onRestored}\n />\n );\n}\n\n/** The history of one record of an already loaded resource. Hidden without `capabilities.revisions`. */\nexport function RevisionsPanel(\n props: RevisionsPanelProps,\n): ReactElement | null {\n return props.ready.capabilities.revisions ? (\n <RevisionsBody {...props} />\n ) : null;\n}\n\nexport interface RecordRevisionsProps extends Omit<\n RevisionsPanelProps,\n \"ready\"\n> {\n readonly resource: string;\n readonly apiVersion?: string | undefined;\n}\n\n/**\n * A record's revisions in one of four shapes: `list` (with Restore), `audit`\n * (table), `diff` (two revisions compared) or `preview` (one snapshot).\n */\nexport function RecordRevisions({\n resource,\n apiVersion,\n ...rest\n}: RecordRevisionsProps): ReactElement {\n return (\n <ResourceGate name={resource} apiVersion={apiVersion}>\n {(ready) => <RevisionsPanel ready={ready} {...rest} />}\n </ResourceGate>\n );\n}\n","import type { JsonObject } from \"@craftainer/crud-sdk\";\nimport Alert from \"@mui/material/Alert\";\nimport Box from \"@mui/material/Box\";\nimport CircularProgress from \"@mui/material/CircularProgress\";\nimport Paper from \"@mui/material/Paper\";\nimport Stack from \"@mui/material/Stack\";\nimport Tab from \"@mui/material/Tab\";\nimport Tabs from \"@mui/material/Tabs\";\nimport Typography from \"@mui/material/Typography\";\nimport { useId, useState, type ReactElement, type ReactNode } from \"react\";\nimport {\n DialogShell,\n DrawerShell,\n PageShell,\n ResourceGate,\n type ReadyResource,\n type RendererOverrides,\n} from \"../core/index.ts\";\nimport { ArchiveButton, RestoreButton } from \"../lifecycle/ArchiveControls.tsx\";\nimport { DraftControls } from \"../lifecycle/DraftControls.tsx\";\nimport { recordStatus, SYSTEM_FIELDS } from \"../lifecycle/status.ts\";\nimport { RevisionsPanel } from \"../revisions/Revisions.tsx\";\nimport { FieldList } from \"./FieldList.tsx\";\n\nexport type DetailVariant =\n \"page\" | \"form\" | \"metadata\" | \"tabs\" | \"dialog\" | \"drawer\";\n\n/** What `renderForm` receives: enough to mount VW2's edit form for this record. */\nexport interface DetailFormContext {\n readonly ready: ReadyResource;\n readonly id: number;\n readonly record: JsonObject;\n /** Call after a save so the detail refetches. */\n readonly onDone: () => void;\n}\n\nexport interface DetailPanelProps {\n readonly ready: ReadyResource;\n readonly id: number;\n readonly variant?: DetailVariant | undefined;\n readonly renderers?: RendererOverrides | undefined;\n /** Replaces the page title; default `<Resource title> #<id>`. */\n readonly title?: ReactNode;\n /**\n * The `form` variant renders this in place of the field list, so the edit\n * form (VW2's `RecordForm`, or your own) lives in the detail page without\n * this package importing it.\n */\n readonly renderForm?: ((context: DetailFormContext) => ReactNode) | undefined;\n /** `dialog` and `drawer`: whether it is shown (default true). */\n readonly open?: boolean | undefined;\n /** `dialog` and `drawer`: called when the overlay asks to close. */\n readonly onClose?: (() => void) | undefined;\n /** Called after a publish, discard, archive or restore. */\n readonly onChanged?: (() => void) | undefined;\n}\n\nconst doNothing = (): void => {};\n\ninterface BodyProps {\n readonly ready: ReadyResource;\n readonly record: JsonObject;\n readonly renderers: RendererOverrides | undefined;\n}\n\nfunction mainFields(ready: ReadyResource): ReadyResource[\"fields\"] {\n return ready.fields.filter((f) => !SYSTEM_FIELDS.includes(f.name));\n}\n\nfunction Main({ ready, record, renderers }: BodyProps): ReactElement {\n return (\n <FieldList\n resource={ready.resource.name}\n fields={mainFields(ready)}\n record={record}\n renderers={renderers}\n />\n );\n}\n\n/** The server-maintained fields: ids, owner, lifecycle and audit timestamps. */\nexport function DetailMetadata({\n ready,\n record,\n renderers,\n}: BodyProps): ReactElement {\n return (\n <Paper variant=\"outlined\" sx={{ p: 2 }}>\n <Typography component=\"h2\" variant=\"subtitle1\" sx={{ mb: 1.5 }}>\n Metadata\n </Typography>\n <FieldList\n resource={ready.resource.name}\n fields={ready.fields.filter((f) => SYSTEM_FIELDS.includes(f.name))}\n record={record}\n renderers={renderers}\n />\n </Paper>\n );\n}\n\nfunction Tabbed({\n ready,\n record,\n renderers,\n id,\n}: BodyProps & { id: number }): ReactElement {\n const base = useId();\n const tabs = [\n { key: \"details\", label: \"Details\" },\n { key: \"metadata\", label: \"Metadata\" },\n ...(ready.capabilities.revisions\n ? [{ key: \"history\", label: \"History\" }]\n : []),\n ];\n const [current, setCurrent] = useState(\"details\");\n return (\n <Box>\n <Tabs\n value={current}\n onChange={(_event, key: string) => setCurrent(key)}\n aria-label=\"Record sections\"\n sx={{ borderBottom: 1, borderColor: \"divider\", mb: 2 }}\n >\n {tabs.map((tab) => (\n <Tab\n key={tab.key}\n value={tab.key}\n label={tab.label}\n id={`${base}-${tab.key}-tab`}\n aria-controls={`${base}-${tab.key}-panel`}\n />\n ))}\n </Tabs>\n <Box\n role=\"tabpanel\"\n id={`${base}-${current}-panel`}\n aria-labelledby={`${base}-${current}-tab`}\n >\n {current === \"details\" && (\n <Main ready={ready} record={record} renderers={renderers} />\n )}\n {current === \"metadata\" && (\n <DetailMetadata ready={ready} record={record} renderers={renderers} />\n )}\n {current === \"history\" && (\n <RevisionsPanel\n ready={ready}\n id={id}\n variant=\"audit\"\n renderers={renderers}\n />\n )}\n </Box>\n </Box>\n );\n}\n\nfunction RecordActions({\n ready,\n record,\n id,\n onChanged,\n}: {\n ready: ReadyResource;\n record: JsonObject;\n id: number;\n onChanged: () => void;\n}): ReactElement {\n const archived = recordStatus(record) === \"archived\";\n return (\n <Stack direction=\"row\" spacing={1} sx={{ alignItems: \"center\" }}>\n <DraftControls\n ready={ready}\n record={record}\n id={id}\n onChanged={onChanged}\n />\n {archived && <RestoreButton ready={ready} id={id} onDone={onChanged} />}\n <ArchiveButton\n ready={ready}\n id={id}\n onDone={onChanged}\n archived={archived}\n />\n </Stack>\n );\n}\n\nfunction DetailLoaded({\n ready,\n id,\n record,\n variant,\n renderers,\n title,\n renderForm,\n open,\n onClose,\n refetch,\n onChanged,\n}: DetailPanelProps & {\n record: JsonObject;\n variant: DetailVariant;\n open: boolean;\n refetch: () => void;\n}): ReactElement {\n const heading = title ?? `${ready.resource.title} #${id}`;\n const changed = (): void => {\n refetch();\n onChanged?.();\n };\n const actions = (\n <RecordActions ready={ready} record={record} id={id} onChanged={changed} />\n );\n const body: BodyProps = { ready, record, renderers };\n switch (variant) {\n case \"form\":\n return (\n <PageShell title={heading} actions={actions}>\n {renderForm === undefined ? (\n <Main {...body} />\n ) : (\n renderForm({ ready, id, record, onDone: changed })\n )}\n </PageShell>\n );\n case \"metadata\":\n return (\n <PageShell title={heading} actions={actions}>\n <Stack\n direction={{ xs: \"column\", md: \"row\" }}\n spacing={3}\n sx={{ alignItems: { md: \"flex-start\" } }}\n >\n <Box sx={{ flex: 2, minWidth: 0 }}>\n <Main {...body} />\n </Box>\n <Box sx={{ flex: 1, minWidth: 0 }}>\n <DetailMetadata {...body} />\n </Box>\n </Stack>\n </PageShell>\n );\n case \"tabs\":\n return (\n <PageShell title={heading} actions={actions}>\n <Tabbed {...body} id={id} />\n </PageShell>\n );\n case \"dialog\":\n case \"drawer\": {\n const Shell = variant === \"dialog\" ? DialogShell : DrawerShell;\n return (\n <Shell\n open={open}\n onClose={onClose ?? doNothing}\n title={heading}\n actions={actions}\n >\n <Stack spacing={3}>\n <Main {...body} />\n <DetailMetadata {...body} />\n </Stack>\n </Shell>\n );\n }\n default:\n return (\n <PageShell title={heading} actions={actions}>\n <Main {...body} />\n </PageShell>\n );\n }\n}\n\n/** One record of an already loaded resource, in the chosen `variant` (default `page`). */\nexport function DetailPanel({\n variant = \"page\",\n open = true,\n ...rest\n}: DetailPanelProps): ReactElement {\n const query = rest.ready.hooks.useRecord(rest.id);\n if (query.isPending) {\n return (\n <Box sx={{ display: \"flex\", justifyContent: \"center\", p: 4 }}>\n <CircularProgress aria-label=\"Loading\" />\n </Box>\n );\n }\n if (query.error !== null) {\n return <Alert severity=\"error\">{query.error.message}</Alert>;\n }\n return (\n <DetailLoaded\n {...rest}\n record={query.data}\n variant={variant}\n open={open}\n refetch={() => void query.refetch()}\n />\n );\n}\n\nexport interface RecordDetailProps extends Omit<DetailPanelProps, \"ready\"> {\n readonly resource: string;\n readonly apiVersion?: string | undefined;\n}\n\n/**\n * The detail of one record: `page` (read-only fields), `form` (an edit form\n * from `renderForm`), `metadata` (fields beside a metadata panel), `tabs`,\n * `dialog` or `drawer`. Status, publish, discard, archive and restore actions\n * show only when the manifest's `capabilities` allow them.\n */\nexport function RecordDetail({\n resource,\n apiVersion,\n ...rest\n}: RecordDetailProps): ReactElement {\n return (\n <ResourceGate name={resource} apiVersion={apiVersion}>\n {(ready) => <DetailPanel ready={ready} {...rest} />}\n </ResourceGate>\n );\n}\n","import Box from \"@mui/material/Box\";\nimport Checkbox from \"@mui/material/Checkbox\";\nimport FormControl from \"@mui/material/FormControl\";\nimport FormControlLabel from \"@mui/material/FormControlLabel\";\nimport FormGroup from \"@mui/material/FormGroup\";\nimport FormLabel from \"@mui/material/FormLabel\";\nimport type { ReactElement } from \"react\";\nimport {\n humanize,\n withOp,\n type FieldDescriptor,\n type FieldFilters,\n type FilterOp,\n type FilterScalar,\n type ReadyResource,\n} from \"../core/index.ts\";\n\nexport interface FacetSidebarProps {\n readonly ready: ReadyResource;\n readonly filters: FieldFilters;\n readonly onChange: (filters: FieldFilters) => void;\n /** Field names to show. Default: every categorical field with known values. */\n readonly fields?: readonly string[] | undefined;\n}\n\ninterface Facet {\n readonly field: FieldDescriptor;\n readonly op: FilterOp;\n readonly values: readonly { label: string; value: FilterScalar }[];\n}\n\n/** The facets: categorical enum and boolean fields filterable by `in` or `eq`. */\nfunction facetsOf(ready: ReadyResource, names?: readonly string[]): Facet[] {\n return ready.fields.flatMap((field): Facet[] => {\n if (!field.categorical) return [];\n if (names !== undefined && !names.includes(field.name)) return [];\n const op = ([\"in\", \"eq\"] as const).find((o) => field.filterOps.includes(o));\n if (op === undefined) return [];\n if (field.kind === \"boolean\")\n return [\n {\n field,\n op,\n values: [\n { label: \"Yes\", value: true },\n { label: \"No\", value: false },\n ],\n },\n ];\n if (field.choices === null) return [];\n return [\n {\n field,\n op,\n values: field.choices.map((c) => ({ label: humanize(c), value: c })),\n },\n ];\n });\n}\n\n/** Checkboxes for the categorical fields: pick values, the list narrows to them. */\nexport function FacetSidebar({\n ready,\n filters,\n onChange,\n fields,\n}: FacetSidebarProps): ReactElement | null {\n const facets = facetsOf(ready, fields);\n if (facets.length === 0) return null;\n return (\n <Box component=\"aside\" aria-label=\"Facets\">\n {facets.map(({ field, op, values }) => {\n const operand = filters[field.name]?.[op];\n const selected: readonly FilterScalar[] =\n operand === undefined\n ? []\n : Array.isArray(operand)\n ? (operand as readonly FilterScalar[])\n : [operand as FilterScalar];\n const toggle = (value: FilterScalar): void => {\n const on = selected.includes(value);\n // `eq` holds one value: picking another replaces it.\n const next =\n op === \"in\"\n ? on\n ? selected.filter((v) => v !== value)\n : [...selected, value]\n : on\n ? undefined\n : value;\n onChange({\n ...filters,\n [field.name]: withOp(filters[field.name], op, next),\n });\n };\n return (\n <FormControl\n key={field.name}\n component=\"fieldset\"\n variant=\"standard\"\n sx={{ display: \"block\", mb: 2 }}\n >\n <FormLabel component=\"legend\">{field.label}</FormLabel>\n <FormGroup>\n {values.map(({ label, value }) => (\n <FormControlLabel\n key={String(value)}\n label={label}\n control={\n <Checkbox\n size=\"small\"\n checked={selected.includes(value)}\n onChange={() => toggle(value)}\n />\n }\n />\n ))}\n </FormGroup>\n </FormControl>\n );\n })}\n </Box>\n );\n}\n","import FormHelperText from \"@mui/material/FormHelperText\";\nimport Stack from \"@mui/material/Stack\";\nimport type { ReactElement } from \"react\";\nimport {\n FieldFilterInput,\n type FieldDescriptor,\n type FieldFilter,\n type RendererOverrides,\n} from \"../core/index.ts\";\n\nexport interface FilterControlProps {\n readonly field: FieldDescriptor;\n readonly resource: string;\n readonly value: FieldFilter | undefined;\n readonly onChange: (value: FieldFilter | undefined) => void;\n readonly renderers?: RendererOverrides | undefined;\n}\n\n/** The filter renderer of one field. A datetime filter says its operands are UTC. */\nexport function FilterControl({\n field,\n resource,\n value,\n onChange,\n renderers,\n}: FilterControlProps): ReactElement {\n return (\n <Stack spacing={0.5}>\n <FieldFilterInput\n field={field}\n resource={resource}\n value={value}\n onChange={onChange}\n renderers={renderers}\n />\n {field.kind === \"datetime\" && (\n <FormHelperText>{`${field.label}: times are UTC`}</FormHelperText>\n )}\n </Stack>\n );\n}\n","import Button from \"@mui/material/Button\";\nimport Stack from \"@mui/material/Stack\";\nimport type { ReactElement } from \"react\";\nimport {\n isFilterable,\n type FieldFilters,\n type ReadyResource,\n type RendererOverrides,\n} from \"../core/index.ts\";\nimport { FilterControl } from \"./FilterControl.tsx\";\n\nexport interface FilterBarProps {\n readonly ready: ReadyResource;\n readonly filters: FieldFilters;\n readonly onChange: (filters: FieldFilters) => void;\n /** Field names to show, in order. Default: every filterable field except the id. */\n readonly fields?: readonly string[] | undefined;\n readonly renderers?: RendererOverrides | undefined;\n}\n\n/** One filter control per field, side by side: the filters are all visible at once. */\nexport function FilterBar({\n ready,\n filters,\n onChange,\n fields,\n renderers,\n}: FilterBarProps): ReactElement {\n const shown =\n fields === undefined\n ? ready.fields.filter(isFilterable)\n : fields.flatMap((name) => {\n const field = ready.field(name);\n return field !== undefined && isFilterable(field) ? [field] : [];\n });\n const active = Object.values(filters).some(\n (f) => f !== undefined && Object.keys(f).length > 0,\n );\n return (\n <Stack\n component=\"section\"\n aria-label=\"Filters\"\n direction=\"row\"\n useFlexGap\n sx={{ flexWrap: \"wrap\", gap: 2, alignItems: \"flex-start\" }}\n >\n {shown.map((field) => (\n <Stack key={field.name} sx={{ minWidth: 0, flex: \"1 1 14rem\" }}>\n <FilterControl\n field={field}\n resource={ready.resource.name}\n value={filters[field.name]}\n onChange={(value) => onChange({ ...filters, [field.name]: value })}\n renderers={renderers}\n />\n </Stack>\n ))}\n {active && <Button onClick={() => onChange({})}>Clear filters</Button>}\n </Stack>\n );\n}\n","// The state of a list (filters, quick search, sort, page) and its codecs: the\n// URL query string (the page's own address, not an API URL) and the SDK's\n// query object. API URLs are never built here: `toQueryFilters` and the SDK's\n// query builder do that.\nimport type { CrudQuery } from \"@craftainer/crud-sdk/tanstack\";\nimport {\n isFilterable,\n toQueryFilters,\n withOp,\n type FieldDescriptor,\n type FieldFilter,\n type FieldFilters,\n type FilterOp,\n type FilterScalar,\n} from \"../core/index.ts\";\n\n/** One sort key: a sortable field and its direction. */\nexport interface SortKey {\n readonly field: string;\n readonly desc: boolean;\n}\n\n/** Everything a list view reads: filters, quick search, sort, paging and the visibility toggles. */\nexport interface QueryState {\n readonly filters: FieldFilters;\n /** Quick-search text (`icontains` on `qField`); empty means off. */\n readonly q: string;\n readonly qField: string | undefined;\n readonly sort: readonly SortKey[];\n /** 1-based. */\n readonly page: number;\n readonly pageSize: number;\n readonly includeArchived: boolean;\n readonly includeUnpublished: boolean;\n}\n\n/** Values the state falls back to while the URL says nothing. */\nexport interface QueryDefaults {\n /** Default filter values; the user clears them and the URL remembers that. */\n readonly filters?: FieldFilters | undefined;\n readonly sort?: readonly SortKey[] | undefined;\n readonly pageSize?: number | undefined;\n}\n\n/** What the codecs need to know about the resource. */\nexport interface QueryContext {\n readonly fields: readonly FieldDescriptor[];\n readonly defaults: QueryDefaults;\n /** Prefix of every URL parameter, so several lists can share one page. */\n readonly prefix: string;\n /** Default quick-search field, from the `searchField` option or the first searchable one. */\n readonly searchField: string | undefined;\n /** The largest page size the server accepts, less one (the view asks for one extra row to learn whether a next page exists). */\n readonly maxPageSize: number;\n}\n\nexport const DEFAULT_PAGE_SIZE = 25;\n\n/** Fields the quick search can target: strings with `icontains`. */\nexport const searchableFields = (\n fields: readonly FieldDescriptor[],\n): FieldDescriptor[] =>\n fields.filter(\n (f) => f.kind === \"string\" && f.filterOps.includes(\"icontains\"),\n );\n\n/** The sort a header click or dropdown can use. */\nexport const sortableFields = (\n fields: readonly FieldDescriptor[],\n): FieldDescriptor[] => fields.filter((f) => f.sortable && f.inManifest);\n\n/** The state with nothing in the URL. */\nexport function initialState(ctx: QueryContext): QueryState {\n return {\n filters: ctx.defaults.filters ?? {},\n q: \"\",\n qField: ctx.searchField,\n sort: ctx.defaults.sort ?? [],\n page: 1,\n pageSize: ctx.defaults.pageSize ?? DEFAULT_PAGE_SIZE,\n includeArchived: false,\n includeUnpublished: false,\n };\n}\n\n// ---- operands ---------------------------------------------------------\n\nconst NAIVE_DATETIME = /^\\d{4}-\\d\\d-\\d\\dT\\d\\d:\\d\\d(:\\d\\d(\\.\\d+)?)?$/;\n\nfunction parseScalar(\n field: FieldDescriptor,\n text: string,\n): FilterScalar | undefined {\n switch (field.kind) {\n case \"number\":\n case \"integer\": {\n const n = Number(text);\n return text.trim() !== \"\" && Number.isFinite(n) ? n : undefined;\n }\n case \"boolean\":\n return text === \"true\" ? true : text === \"false\" ? false : undefined;\n case \"datetime\": {\n // A datetime filter is UTC: a bare local time is read as UTC.\n const d = new Date(NAIVE_DATETIME.test(text) ? `${text}Z` : text);\n return Number.isNaN(d.getTime()) ? undefined : d;\n }\n default:\n return text === \"\" ? undefined : text;\n }\n}\n\n/** Splits on commas that are not escaped as `\\,`; `\\\\` is a backslash. */\nfunction splitList(text: string): string[] {\n const parts: string[] = [\"\"];\n for (let i = 0; i < text.length; i++) {\n const ch = text.charAt(i);\n const next = text.charAt(i + 1);\n if (ch === \"\\\\\" && (next === \",\" || next === \"\\\\\")) {\n parts[parts.length - 1] += next;\n i++;\n } else if (ch === \",\") parts.push(\"\");\n else parts[parts.length - 1] += ch;\n }\n return parts;\n}\n\nconst escapeItem = (text: string): string =>\n text.replaceAll(\"\\\\\", \"\\\\\\\\\").replaceAll(\",\", \"\\\\,\");\n\n/** Reads typed text as the operand of `op` on `field` (`in` takes a comma-separated list); `undefined` when it does not parse. */\nexport function parseOperand(\n field: FieldDescriptor,\n op: FilterOp,\n text: string,\n): FilterScalar | readonly FilterScalar[] | undefined {\n if (op !== \"in\") return parseScalar(field, text);\n const items = splitList(text)\n .map((part) => parseScalar(field, part.trim()))\n .filter((v): v is FilterScalar => v !== undefined);\n return items.length === 0 ? undefined : items;\n}\n\n/** The text form of an operand: the inverse of `parseOperand`. */\nexport function formatOperand(\n operand: FilterScalar | readonly FilterScalar[],\n): string {\n if (Array.isArray(operand))\n return (operand as readonly FilterScalar[])\n .map((item) => escapeItem(formatOperand(item)))\n .join(\",\");\n return operand instanceof Date ? operand.toISOString() : String(operand);\n}\n\n// ---- URL ---------------------------------------------------------------\n\nconst names = (prefix: string) => ({\n q: `${prefix}q`,\n qf: `${prefix}qf`,\n sort: `${prefix}sort`,\n page: `${prefix}page`,\n size: `${prefix}size`,\n archived: `${prefix}archived`,\n drafts: `${prefix}drafts`,\n f: `${prefix}f`,\n});\n\nconst isOwned = (key: string, prefix: string): boolean =>\n key.startsWith(`${prefix}f.`) ||\n (Object.values(names(prefix)) as string[]).includes(key);\n\n/** `f.<field>.<op>` -> text, sorted, for every operand that is set. */\nfunction filterEntries(filters: FieldFilters): [string, string][] {\n const out: [string, string][] = [];\n for (const name of Object.keys(filters).sort()) {\n const byOp = filters[name] ?? {};\n for (const op of Object.keys(byOp).sort()) {\n const operand = byOp[op as FilterOp];\n if (\n operand === undefined ||\n (Array.isArray(operand) && operand.length === 0)\n )\n continue;\n out.push([`f.${name}.${op}`, formatOperand(operand)]);\n }\n }\n return out;\n}\n\nconst sortText = (sort: readonly SortKey[]): string =>\n sort.map((k) => (k.desc ? `-${k.field}` : k.field)).join(\",\");\n\nconst sameEntries = (\n a: readonly (readonly [string, string])[],\n b: readonly (readonly [string, string])[],\n): boolean =>\n a.length === b.length &&\n a.every(([k, v], i) => k === b[i]?.[0] && v === b[i]?.[1]);\n\n/**\n * The query string for `state`, merged into `base` (other parameters of the\n * page survive). Values equal to the defaults are left out; a filter set that\n * differs from the defaults is written with an `f` marker, so clearing a\n * default filter sticks.\n */\nexport function encodeState(\n state: QueryState,\n ctx: QueryContext,\n base = \"\",\n): string {\n const n = names(ctx.prefix);\n const params = new URLSearchParams(base);\n for (const key of new Set(params.keys()))\n if (isOwned(key, ctx.prefix)) params.delete(key);\n const base0 = initialState(ctx);\n const entries = filterEntries(state.filters);\n if (!sameEntries(entries, filterEntries(base0.filters))) {\n params.set(n.f, \"\");\n for (const [key, value] of entries)\n params.set(`${ctx.prefix}${key}`, value);\n }\n if (state.q !== \"\") params.set(n.q, state.q);\n if (state.qField !== undefined && state.qField !== base0.qField)\n params.set(n.qf, state.qField);\n if (sortText(state.sort) !== sortText(base0.sort))\n params.set(n.sort, sortText(state.sort));\n if (state.page > 1) params.set(n.page, String(state.page));\n if (state.pageSize !== base0.pageSize)\n params.set(n.size, String(state.pageSize));\n if (state.includeArchived) params.set(n.archived, \"1\");\n if (state.includeUnpublished) params.set(n.drafts, \"1\");\n return params.toString();\n}\n\nfunction positiveInt(text: string | null): number | undefined {\n const n = Number(text);\n return text !== null && Number.isInteger(n) && n >= 1 ? n : undefined;\n}\n\n/** The state a query string describes; anything invalid for the resource is ignored. */\nexport function decodeState(search: string, ctx: QueryContext): QueryState {\n const n = names(ctx.prefix);\n const params = new URLSearchParams(search);\n const base = initialState(ctx);\n\n let filters = base.filters;\n if (params.has(n.f)) {\n const next: Record<string, FieldFilter | undefined> = {};\n const lead = `${ctx.prefix}f.`;\n for (const [key, text] of params) {\n if (!key.startsWith(lead)) continue;\n const rest = key.slice(lead.length);\n const dot = rest.lastIndexOf(\".\");\n const field = ctx.fields.find((f) => f.name === rest.slice(0, dot));\n const op = rest.slice(dot + 1) as FilterOp;\n if (\n field === undefined ||\n !isFilterable(field) ||\n !field.filterOps.includes(op)\n )\n continue;\n const operand = parseOperand(field, op, text);\n if (operand !== undefined)\n next[field.name] = withOp(next[field.name], op, operand);\n }\n filters = next;\n }\n\n let sort = base.sort;\n if (params.has(n.sort)) {\n const sortable = new Set(sortableFields(ctx.fields).map((f) => f.name));\n sort = (params.get(n.sort) as string)\n .split(\",\")\n .map((part) => ({\n field: part.replace(/^-/, \"\"),\n desc: part.startsWith(\"-\"),\n }))\n .filter((k) => sortable.has(k.field));\n }\n\n const qField = params.get(n.qf);\n const searchable = searchableFields(ctx.fields).some(\n (f) => f.name === qField,\n );\n const size = positiveInt(params.get(n.size));\n return {\n filters,\n q: params.get(n.q) ?? \"\",\n qField: searchable ? (qField as string) : base.qField,\n sort,\n page: positiveInt(params.get(n.page)) ?? 1,\n pageSize: Math.min(size ?? base.pageSize, ctx.maxPageSize),\n includeArchived: params.get(n.archived) === \"1\",\n includeUnpublished: params.get(n.drafts) === \"1\",\n };\n}\n\n// ---- SDK query -----------------------------------------------------------\n\n/** The filters including the quick search, as per-field state. */\nexport function effectiveFilters(state: QueryState): FieldFilters {\n if (state.q === \"\" || state.qField === undefined) return state.filters;\n return {\n ...state.filters,\n [state.qField]: withOp(state.filters[state.qField], \"icontains\", state.q),\n };\n}\n\n/**\n * The SDK query for `state`. `paged` adds `skip` and `limit` (one extra row,\n * to learn whether a next page exists); an infinite list pages itself.\n */\nexport function toCrudQuery(state: QueryState, paged: boolean): CrudQuery {\n const query: Record<string, unknown> = {\n filters: toQueryFilters(effectiveFilters(state)),\n };\n if (state.sort.length > 0) query[\"sort\"] = sortText(state.sort).split(\",\");\n if (paged) {\n query[\"skip\"] = (state.page - 1) * state.pageSize;\n query[\"limit\"] = state.pageSize + 1;\n }\n if (state.includeArchived) query[\"includeArchived\"] = true;\n if (state.includeUnpublished) query[\"includeUnpublished\"] = true;\n return query;\n}\n\n/** Whether any filter or quick search narrows the list. */\nexport const isFiltered = (state: QueryState): boolean =>\n state.q !== \"\" || filterEntries(state.filters).length > 0;\n","import Button from \"@mui/material/Button\";\nimport MenuItem from \"@mui/material/MenuItem\";\nimport Stack from \"@mui/material/Stack\";\nimport TextField from \"@mui/material/TextField\";\nimport { useState, type ReactElement } from \"react\";\nimport {\n isFilterable,\n withOp,\n type FieldDescriptor,\n type FieldFilter,\n type FieldFilters,\n type FilterOp,\n type ReadyResource,\n type RendererOverrides,\n} from \"../core/index.ts\";\nimport { FilterControl } from \"./FilterControl.tsx\";\nimport { formatOperand, parseOperand } from \"./queryState.ts\";\n\nexport interface FilterBuilderProps {\n readonly ready: ReadyResource;\n readonly filters: FieldFilters;\n readonly onChange: (filters: FieldFilters) => void;\n readonly renderers?: RendererOverrides | undefined;\n}\n\ninterface Condition {\n readonly field: string;\n readonly op: FilterOp;\n}\n\n/** Operators the built-in filter renderers edit one at a time; the others get a text box. */\nconst RENDERED: Readonly<Record<string, readonly FilterOp[]>> = {\n string: [\"eq\", \"contains\", \"icontains\"],\n number: [\"eq\", \"min\", \"max\"],\n integer: [\"eq\", \"min\", \"max\"],\n date: [\"eq\", \"min\", \"max\"],\n datetime: [\"eq\", \"min\", \"max\"],\n enum: [\"eq\", \"in\"],\n boolean: [\"eq\"],\n};\n\nconst OP_LABEL: Readonly<Record<FilterOp, string>> = {\n eq: \"equals\",\n min: \"at least\",\n max: \"at most\",\n in: \"is one of\",\n contains: \"contains\",\n icontains: \"contains (any case)\",\n regex: \"matches pattern\",\n};\n\nconst keyOf = (c: Condition): string => `${c.field}\\u0000${c.op}`;\n\n/** The conditions the filters already hold, in field then operator order. */\nfunction conditionsOf(filters: FieldFilters): Condition[] {\n return Object.keys(filters).flatMap((field) =>\n Object.keys(filters[field] ?? {}).map((op) => ({\n field,\n op: op as FilterOp,\n })),\n );\n}\n\ninterface OperandProps {\n readonly field: FieldDescriptor;\n readonly op: FilterOp;\n readonly resource: string;\n readonly value: FieldFilter | undefined;\n readonly onChange: (value: FieldFilter | undefined) => void;\n readonly renderers?: RendererOverrides | undefined;\n}\n\n/** The operand of one condition: the field's own filter renderer restricted to the operator, or a text box. */\nfunction Operand({ field, op, ...rest }: OperandProps): ReactElement {\n if (RENDERED[field.kind]?.includes(op) === true) {\n return <FilterControl field={{ ...field, filterOps: [op] }} {...rest} />;\n }\n return <TextOperand field={field} op={op} {...rest} />;\n}\n\nconst textOf = (operand: FieldFilter[FilterOp] | undefined): string =>\n operand === undefined ? \"\" : formatOperand(operand);\n\n/** The text box of a condition. It keeps what was typed while that does not parse yet, and follows filters changed from outside (Clear all, Back). */\nfunction TextOperand({\n field,\n op,\n value,\n onChange,\n}: OperandProps): ReactElement {\n const operand = value?.[op];\n const [text, setText] = useState(textOf(operand));\n const [seen, setSeen] = useState(operand);\n if (operand !== seen) {\n setSeen(operand);\n // Typed text that already means this operand stays as typed.\n if (textOf(parseOperand(field, op, text)) !== textOf(operand)) {\n setText(textOf(operand));\n }\n }\n return (\n <TextField\n size=\"small\"\n fullWidth\n label={`${field.label} ${OP_LABEL[op]}`}\n helperText={\n op === \"in\"\n ? field.kind === \"datetime\"\n ? \"Comma-separated, times are UTC\"\n : \"Comma-separated\"\n : undefined\n }\n value={text}\n onChange={(e) => {\n setText(e.target.value);\n onChange(withOp(value, op, parseOperand(field, op, e.target.value)));\n }}\n />\n );\n}\n\n/**\n * A list of conditions, each \"field, operator, operand\". Operands use the\n * field's filter renderer where it edits that operator, a text box otherwise.\n * Several conditions on one field combine as the API does: all must hold.\n */\nexport function FilterBuilder({\n ready,\n filters,\n onChange,\n renderers,\n}: FilterBuilderProps): ReactElement {\n const filterable = ready.fields.filter(isFilterable);\n // Conditions added but not yet given an operand; the rest come from `filters`.\n const [pending, setPending] = useState<readonly Condition[]>([]);\n const present = conditionsOf(filters);\n const rows = [\n ...present,\n ...pending.filter((p) => !present.some((c) => keyOf(c) === keyOf(p))),\n ];\n const setOperand = (c: Condition, value: FieldFilter | undefined): void => {\n // Clearing the operand must not make the row vanish under the cursor.\n if (!pending.some((p) => keyOf(p) === keyOf(c)))\n setPending([...pending, c]);\n onChange({ ...filters, [c.field]: value });\n };\n const drop = (c: Condition): void => {\n setPending(pending.filter((p) => keyOf(p) !== keyOf(c)));\n onChange({\n ...filters,\n [c.field]: withOp(filters[c.field], c.op, undefined),\n });\n };\n const move = (from: Condition, to: Condition): void => {\n setPending([...pending.filter((p) => keyOf(p) !== keyOf(from)), to]);\n onChange({\n ...filters,\n [from.field]: withOp(filters[from.field], from.op, undefined),\n });\n };\n const add = (): void => {\n const field =\n filterable.find((f) => !rows.some((c) => c.field === f.name)) ??\n filterable[0];\n if (field === undefined) return;\n const op = field.filterOps[0] as FilterOp;\n // Every field has a condition already: do not queue a twin of one.\n if (\n [...rows, ...pending].some((c) => c.field === field.name && c.op === op)\n )\n return;\n setPending([\n ...pending,\n { field: field.name, op: field.filterOps[0] as FilterOp },\n ]);\n };\n return (\n <Stack component=\"section\" aria-label=\"Filter builder\" spacing={2}>\n {rows.map((c, index) => {\n const field = ready.field(c.field) as FieldDescriptor;\n const label = `Condition ${index + 1}`;\n return (\n <Stack\n key={keyOf(c)}\n direction=\"row\"\n role=\"group\"\n aria-label={label}\n useFlexGap\n sx={{ flexWrap: \"wrap\", gap: 1, alignItems: \"flex-start\" }}\n >\n <TextField\n select\n size=\"small\"\n label=\"Field\"\n value={c.field}\n onChange={(e) => {\n const next = ready.field(e.target.value) as FieldDescriptor;\n move(c, {\n field: next.name,\n op: next.filterOps[0] as FilterOp,\n });\n }}\n sx={{ minWidth: \"10rem\" }}\n >\n {filterable.map((f) => (\n <MenuItem key={f.name} value={f.name}>\n {f.label}\n </MenuItem>\n ))}\n </TextField>\n <TextField\n select\n size=\"small\"\n label=\"Operator\"\n value={c.op}\n onChange={(e) =>\n move(c, { field: c.field, op: e.target.value as FilterOp })\n }\n sx={{ minWidth: \"10rem\" }}\n >\n {field.filterOps.map((op) => (\n <MenuItem key={op} value={op}>\n {OP_LABEL[op]}\n </MenuItem>\n ))}\n </TextField>\n <Stack sx={{ minWidth: \"12rem\", flex: \"1 1 12rem\" }}>\n <Operand\n field={field}\n op={c.op}\n resource={ready.resource.name}\n value={filters[c.field]}\n onChange={(value) => setOperand(c, value)}\n renderers={renderers}\n />\n </Stack>\n <Button\n aria-label={`Remove ${label.toLowerCase()}`}\n onClick={() => drop(c)}\n >\n Remove\n </Button>\n </Stack>\n );\n })}\n <Stack direction=\"row\" spacing={1}>\n <Button onClick={add}>Add condition</Button>\n {rows.length > 0 && (\n <Button\n onClick={() => {\n setPending([]);\n onChange({});\n }}\n >\n Clear all\n </Button>\n )}\n </Stack>\n </Stack>\n );\n}\n","import MenuItem from \"@mui/material/MenuItem\";\nimport Stack from \"@mui/material/Stack\";\nimport TextField from \"@mui/material/TextField\";\nimport { useEffect, useState, type ReactElement } from \"react\";\nimport type { FieldDescriptor } from \"../core/index.ts\";\n\nexport interface QuickSearchProps {\n /** The string fields to search (`icontains`); see `QueryStateApi.searchFields`. */\n readonly fields: readonly FieldDescriptor[];\n readonly value: string;\n /** The searched field; with several, a selector appears (the API cannot OR fields). */\n readonly field: string | undefined;\n readonly onChange: (value: string) => void;\n readonly onFieldChange: (field: string) => void;\n /** Wait this long after the last keystroke before calling `onChange`. Default 300. */\n readonly debounceMs?: number | undefined;\n}\n\n/** A search box: case-insensitive \"contains\" on one string field. Renders nothing without one. */\nexport function QuickSearch({\n fields,\n value,\n field,\n onChange,\n onFieldChange,\n debounceMs = 300,\n}: QuickSearchProps): ReactElement | null {\n const [text, setText] = useState(value);\n const [seen, setSeen] = useState(value);\n if (value !== seen) {\n // The URL changed under us (back button, reset): follow it.\n setSeen(value);\n setText(value);\n }\n useEffect(() => {\n if (text === value) return undefined;\n const timer = setTimeout(() => onChange(text), debounceMs);\n return () => clearTimeout(timer);\n }, [text, value, onChange, debounceMs]);\n if (fields.length === 0) return null;\n const current =\n fields.find((f) => f.name === field) ?? (fields[0] as FieldDescriptor);\n return (\n <Stack\n direction=\"row\"\n spacing={1}\n role=\"search\"\n aria-label=\"Quick search\"\n sx={{ alignItems: \"flex-start\" }}\n >\n <TextField\n type=\"search\"\n size=\"small\"\n label={`Search ${current.label.toLowerCase()}`}\n value={text}\n onChange={(e) => setText(e.target.value)}\n sx={{ minWidth: 0, flex: \"1 1 14rem\" }}\n />\n {fields.length > 1 && (\n <TextField\n select\n size=\"small\"\n label=\"Search in\"\n value={current.name}\n onChange={(e) => onFieldChange(e.target.value)}\n sx={{ minWidth: \"10rem\" }}\n >\n {fields.map((f) => (\n <MenuItem key={f.name} value={f.name}>\n {f.label}\n </MenuItem>\n ))}\n </TextField>\n )}\n </Stack>\n );\n}\n","// Where filter, sort and paging state lives: the page's query string by default.\n// A framework router supplies its own adapter instead.\n\n/** Reads and writes the query string (no leading `?`) the list state is kept in. */\nexport interface UrlAdapter {\n /** The current query string. */\n read(): string;\n /** Replaces the query string; `push` adds a history entry, `replace` does not. */\n write(search: string, mode: \"push\" | \"replace\"): void;\n /** Calls `listener` whenever the query string changes, from anywhere; returns the unsubscribe. */\n subscribe(listener: () => void): () => void;\n}\n\n/** An in-memory adapter: tests, stories, and embedded lists that must not touch the address bar. */\nexport function memoryUrlAdapter(initial = \"\"): UrlAdapter {\n let search = initial;\n const listeners = new Set<() => void>();\n return {\n read: () => search,\n write(next) {\n search = next;\n for (const listener of listeners) listener();\n },\n subscribe(listener) {\n listeners.add(listener);\n return () => listeners.delete(listener);\n },\n };\n}\n\n/** The default adapter: `window.location` and `history` (back and forward work). */\nexport function windowUrlAdapter(): UrlAdapter {\n const listeners = new Set<() => void>();\n const notify = (): void => {\n for (const listener of listeners) listener();\n };\n return {\n read: () => window.location.search.replace(/^\\?/, \"\"),\n write(search, mode) {\n const { pathname, hash } = window.location;\n const url = `${pathname}${search === \"\" ? \"\" : `?${search}`}${hash}`;\n if (mode === \"replace\")\n window.history.replaceState(window.history.state, \"\", url);\n else window.history.pushState(window.history.state, \"\", url);\n notify();\n },\n subscribe(listener) {\n listeners.add(listener);\n // `popstate` fires on back and forward; pushState and replaceState do not fire it.\n window.addEventListener(\"popstate\", listener);\n return () => {\n listeners.delete(listener);\n window.removeEventListener(\"popstate\", listener);\n };\n },\n };\n}\n\nlet shared: UrlAdapter | undefined;\n\n/** The process-wide window adapter, so every list on a page shares one listener set. */\nexport function defaultUrlAdapter(): UrlAdapter {\n shared ??= windowUrlAdapter();\n return shared;\n}\n","import type { CrudQuery } from \"@craftainer/crud-sdk/tanstack\";\nimport { useMemo, useState, useSyncExternalStore } from \"react\";\nimport type {\n FieldDescriptor,\n FieldFilters,\n ReadyResource,\n} from \"../core/index.ts\";\nimport {\n decodeState,\n encodeState,\n searchableFields,\n toCrudQuery,\n type QueryContext,\n type QueryDefaults,\n type QueryState,\n type SortKey,\n} from \"./queryState.ts\";\nimport { defaultUrlAdapter, type UrlAdapter } from \"./urlAdapter.ts\";\n\nexport interface QueryStateOptions {\n /** Where the state lives. Default: the window's query string. */\n readonly adapter?: UrlAdapter | undefined;\n /** Prefix of this list's URL parameters; give each list on a page its own. */\n readonly prefix?: string | undefined;\n readonly defaults?: QueryDefaults | undefined;\n /** The field the quick search targets first. Default: the first string field with `icontains`. */\n readonly searchField?: string | undefined;\n}\n\n/** The URL-synced state of one list plus the setters and the SDK queries derived from it. */\nexport interface QueryStateApi {\n readonly state: QueryState;\n readonly fields: readonly FieldDescriptor[];\n /** Fields the quick search can target. */\n readonly searchFields: readonly FieldDescriptor[];\n /** The query of a paged view: `skip` and `limit` (page size + 1, to detect a next page). */\n readonly pagedQuery: CrudQuery;\n /** The query of an infinite view: filters and sort only. */\n readonly feedQuery: CrudQuery;\n /** Any change but the page itself returns to page 1. */\n setFilters(filters: FieldFilters): void;\n setQuickSearch(q: string): void;\n setQuickSearchField(field: string): void;\n setSort(sort: readonly SortKey[]): void;\n setPage(page: number): void;\n setPageSize(pageSize: number): void;\n setIncludeArchived(on: boolean): void;\n setIncludeUnpublished(on: boolean): void;\n /** Back to the defaults. */\n reset(): void;\n}\n\n/**\n * Filter, sort and paging state for `ready`, kept in the URL through the\n * adapter. Operands are validated against the manifest, so a stale or\n * hand-edited link degrades to the defaults instead of failing the request.\n */\nexport function useQueryState(\n ready: ReadyResource,\n options: QueryStateOptions = {},\n): QueryStateApi {\n const { adapter = defaultUrlAdapter(), prefix = \"\" } = options;\n const fields = ready.fields;\n const searchFields = useMemo(() => searchableFields(fields), [fields]);\n const searchField = options.searchField ?? searchFields[0]?.name;\n // Callers pass `defaults` as a literal; hold the first value of each distinct content.\n const given = options.defaults ?? {};\n const givenKey = JSON.stringify([given.pageSize, given.sort, given.filters]);\n const [held, setHeld] = useState({ key: givenKey, value: given });\n if (held.key !== givenKey) setHeld({ key: givenKey, value: given });\n const defaults = held.value;\n const ctx = useMemo<QueryContext>(\n () => ({\n fields,\n defaults,\n prefix,\n searchField,\n maxPageSize: ready.resource.pagination.max_limit - 1,\n }),\n [\n fields,\n defaults,\n prefix,\n searchField,\n ready.resource.pagination.max_limit,\n ],\n );\n const search = useSyncExternalStore(\n adapter.subscribe,\n adapter.read,\n () => \"\",\n );\n const state = useMemo(() => decodeState(search, ctx), [search, ctx]);\n const pagedQuery = useMemo(() => toCrudQuery(state, true), [state]);\n const feedQuery = useMemo(() => toCrudQuery(state, false), [state]);\n\n return useMemo<QueryStateApi>(() => {\n // Setters read the URL at call time, so two changes in one tick both land.\n const change = (\n patch: (current: QueryState) => Partial<QueryState>,\n mode: \"push\" | \"replace\" = \"push\",\n ): void => {\n const current = decodeState(adapter.read(), ctx);\n adapter.write(\n encodeState({ ...current, ...patch(current) }, ctx, adapter.read()),\n mode,\n );\n };\n const first = { page: 1 };\n return {\n state,\n fields,\n searchFields,\n pagedQuery,\n feedQuery,\n setFilters: (filters) => change(() => ({ filters, ...first })),\n setQuickSearch: (q) => change(() => ({ q, ...first }), \"replace\"),\n setQuickSearchField: (qField) => change(() => ({ qField, ...first })),\n setSort: (sort) => change(() => ({ sort, ...first })),\n setPage: (page) => change(() => ({ page })),\n setPageSize: (pageSize) => change(() => ({ pageSize, ...first })),\n setIncludeArchived: (includeArchived) =>\n change(() => ({ includeArchived, ...first })),\n setIncludeUnpublished: (includeUnpublished) =>\n change(() => ({ includeUnpublished, ...first })),\n reset: () => change(() => decodeState(\"\", ctx)),\n };\n }, [state, fields, searchFields, pagedQuery, feedQuery, adapter, ctx]);\n}\n","// How a form arranges its fields: flat, titled sections, tabs or a stepper.\nimport Badge from \"@mui/material/Badge\";\nimport Box from \"@mui/material/Box\";\nimport Button from \"@mui/material/Button\";\nimport Stack from \"@mui/material/Stack\";\nimport Step from \"@mui/material/Step\";\nimport StepLabel from \"@mui/material/StepLabel\";\nimport Stepper from \"@mui/material/Stepper\";\nimport Tab from \"@mui/material/Tab\";\nimport Tabs from \"@mui/material/Tabs\";\nimport Typography from \"@mui/material/Typography\";\nimport { useId, type ReactElement, type ReactNode } from \"react\";\nimport type { FormLayoutKind, FormSection } from \"./sections.ts\";\n\nexport interface FormLayoutProps {\n readonly layout: FormLayoutKind;\n readonly sections: readonly FormSection[];\n /** The input of one field. */\n readonly renderField: (name: string) => ReactNode;\n /** Visible error count of a section (tabs and steps show it). */\n readonly errorCount: (section: FormSection) => number;\n /** The tab or step shown. */\n readonly active: number;\n readonly onActive: (index: number) => void;\n /** Stepper: leave the step forward; the form validates it first. */\n readonly onNext: () => void;\n /** Stepper: the submit button, shown on the last step. */\n readonly submit: ReactNode;\n}\n\nconst stack = (\n section: FormSection,\n renderField: FormLayoutProps[\"renderField\"],\n): ReactElement => (\n <Stack spacing={2.5}>{section.fields.map((name) => renderField(name))}</Stack>\n);\n\nconst errorSuffix = (count: number): string =>\n count === 0 ? \"\" : ` (${count} ${count === 1 ? \"error\" : \"errors\"})`;\n\n/** Arranges `sections` as the chosen layout. Every panel stays mounted so drafts survive; inactive ones are hidden. */\nexport function FormLayout({\n layout,\n sections,\n renderField,\n errorCount,\n active,\n onActive,\n onNext,\n submit,\n}: FormLayoutProps): ReactElement {\n const id = useId();\n if (layout === \"flat\") {\n return stack(\n { title: \"\", fields: sections.flatMap((s) => s.fields) },\n renderField,\n );\n }\n if (layout === \"sections\") {\n return (\n <Stack spacing={4}>\n {sections.map((section, index) => (\n <Box\n key={section.title}\n component=\"section\"\n aria-labelledby={`${id}-s${index}`}\n >\n <Typography\n id={`${id}-s${index}`}\n component=\"h3\"\n variant=\"subtitle1\"\n sx={{ mb: 2 }}\n >\n {section.title}\n </Typography>\n {stack(section, renderField)}\n </Box>\n ))}\n </Stack>\n );\n }\n const panel = (section: FormSection, index: number): ReactElement => (\n <Box\n key={section.title}\n role={layout === \"tabs\" ? \"tabpanel\" : \"group\"}\n id={`${id}-p${index}`}\n aria-labelledby={`${id}-t${index}`}\n hidden={index !== active}\n sx={{ pt: 2 }}\n >\n {stack(section, renderField)}\n </Box>\n );\n if (layout === \"tabs\") {\n return (\n <Box>\n <Tabs\n value={active}\n onChange={(_event, index: number) => onActive(index)}\n variant=\"scrollable\"\n aria-label=\"Form sections\"\n >\n {sections.map((section, index) => {\n const count = errorCount(section);\n return (\n <Tab\n key={section.title}\n id={`${id}-t${index}`}\n aria-controls={`${id}-p${index}`}\n label={\n <Badge color=\"error\" variant=\"dot\" invisible={count === 0}>\n {section.title + errorSuffix(count)}\n </Badge>\n }\n />\n );\n })}\n </Tabs>\n {sections.map(panel)}\n </Box>\n );\n }\n const last = active === sections.length - 1;\n return (\n <Box>\n <Stepper activeStep={active} alternativeLabel sx={{ mb: 2 }}>\n {sections.map((section, index) => {\n const count = errorCount(section);\n return (\n <Step key={section.title} id={`${id}-t${index}`}>\n <StepLabel error={count > 0}>\n {section.title + errorSuffix(count)}\n </StepLabel>\n </Step>\n );\n })}\n </Stepper>\n {sections.map(panel)}\n <Stack\n direction=\"row\"\n spacing={1}\n sx={{ justifyContent: \"flex-end\", mt: 3 }}\n >\n <Button disabled={active === 0} onClick={() => onActive(active - 1)}>\n Back\n </Button>\n {last ? submit : <Button onClick={onNext}>Next</Button>}\n </Stack>\n </Box>\n );\n}\n","// Which fields go in which section of a form.\nimport type { FieldDescriptor } from \"../core/index.ts\";\n\n/** A titled group of fields, by field name. */\nexport interface FormSection {\n readonly title: string;\n readonly fields: readonly string[];\n}\n\nexport type FormLayoutKind = \"flat\" | \"sections\" | \"tabs\" | \"stepper\";\n\n/**\n * The sections of a form. Given `sections`, fields they do not name go to a\n * trailing \"Other\" section; without them, required fields come first under\n * \"Required\", the rest under \"Optional\". Empty sections are dropped.\n */\nexport function groupFields(\n fields: readonly FieldDescriptor[],\n sections: readonly FormSection[] | undefined,\n): readonly FormSection[] {\n const names = new Set(fields.map((f) => f.name));\n const given =\n sections === undefined\n ? [\n {\n title: \"Required\",\n fields: fields.filter((f) => f.required).map((f) => f.name),\n },\n {\n title: \"Optional\",\n fields: fields.filter((f) => !f.required).map((f) => f.name),\n },\n ]\n : sections.map((s) => ({\n title: s.title,\n fields: s.fields.filter((name) => names.has(name)),\n }));\n const used = new Set(given.flatMap((s) => s.fields));\n const rest = fields.map((f) => f.name).filter((name) => !used.has(name));\n return [...given, { title: \"Other\", fields: rest }].filter(\n (s) => s.fields.length > 0,\n );\n}\n","// Maps SDK errors onto the form: 422 problem details onto fields, 412 to a conflict.\nimport { PreconditionFailed, ProblemError } from \"@craftainer/crud-sdk\";\n\n/** What a failed save shows. */\nexport interface SaveFailure {\n /** 412: the record changed since it was loaded. */\n readonly conflict: boolean;\n /** Messages by field name, from 422 `errors`. */\n readonly fieldErrors: Readonly<Record<string, string>>;\n /** Text for an alert: everything not tied to a visible field. */\n readonly message: string | null;\n}\n\n/** Normalises `loc` (`[\"body\", \"name\", 0]`) to its field name. */\nfunction fieldOf(loc: readonly (string | number)[]): string | undefined {\n const parts = loc.filter((part) => part !== \"body\" && part !== \"query\");\n const first = parts[0];\n return first === undefined ? undefined : String(first);\n}\n\n/** Splits a mutation error into field messages, a conflict flag and an alert message. */\nexport function describeFailure(\n error: unknown,\n fieldNames: readonly string[],\n): SaveFailure {\n if (error instanceof PreconditionFailed) {\n return { conflict: true, fieldErrors: {}, message: null };\n }\n const fieldErrors: Record<string, string> = {};\n const general: string[] = [];\n if (error instanceof ProblemError && error.errors.length > 0) {\n for (const entry of error.errors) {\n const name = fieldOf(entry.loc);\n if (name !== undefined && fieldNames.includes(name)) {\n fieldErrors[name] ??= entry.msg;\n } else {\n general.push(name === undefined ? entry.msg : `${name}: ${entry.msg}`);\n }\n }\n return {\n conflict: false,\n fieldErrors,\n message: general.length === 0 ? null : general.join(\"; \"),\n };\n }\n const message =\n error instanceof ProblemError\n ? `${error.title}${error.detail === undefined ? \"\" : `: ${error.detail}`}`\n : error instanceof Error\n ? error.message\n : \"The record could not be saved\";\n return { conflict: false, fieldErrors, message };\n}\n","// Client-side checks against the schema constraints, run before submit.\nimport type { FieldDescriptor, FieldValue } from \"../core/index.ts\";\n\nconst isEmpty = (value: FieldValue): boolean =>\n value === undefined ||\n value === null ||\n value === \"\" ||\n (Array.isArray(value) && value.length === 0);\n\nfunction matches(pattern: string, value: string): boolean {\n try {\n return new RegExp(pattern, \"u\").test(value);\n } catch {\n // A pattern JavaScript cannot compile (Python flavour): the server checks it.\n return true;\n }\n}\n\n/**\n * The message for the first schema constraint `value` breaks, or `null`.\n * A missing value breaks only `required`; booleans are never missing.\n */\nexport function validateValue(\n field: FieldDescriptor,\n value: FieldValue,\n): string | null {\n if (isEmpty(value)) {\n return field.required && field.kind !== \"boolean\" ? \"Required\" : null;\n }\n const { minimum, maximum, minLength, maxLength, pattern } = field.constraints;\n if (typeof value === \"number\") {\n if (field.kind === \"integer\" && !Number.isInteger(value)) {\n return \"Enter a whole number\";\n }\n if (minimum !== undefined && value < minimum) {\n return `Must be at least ${minimum}`;\n }\n if (maximum !== undefined && value > maximum) {\n return `Must be at most ${maximum}`;\n }\n }\n if (typeof value === \"string\") {\n if (minLength !== undefined && value.length < minLength) {\n return `Must be at least ${minLength} characters`;\n }\n if (maxLength !== undefined && value.length > maxLength) {\n return `Must be at most ${maxLength} characters`;\n }\n if (pattern !== undefined && !matches(pattern, value)) {\n return \"Does not match the expected format\";\n }\n }\n return null;\n}\n\n/** Errors by field name for every field whose value breaks a constraint. */\nexport function validateAll(\n fields: readonly FieldDescriptor[],\n values: Readonly<Record<string, FieldValue>>,\n): Record<string, string> {\n const errors: Record<string, string> = {};\n for (const field of fields) {\n const message = validateValue(field, values[field.name]);\n if (message !== null) errors[field.name] = message;\n }\n return errors;\n}\n","// <ResourceForm>: a create or edit form generated from a resource's\n// `create`/`update` schemas (see ./README.md).\nimport Alert from \"@mui/material/Alert\";\nimport Box from \"@mui/material/Box\";\nimport Button from \"@mui/material/Button\";\nimport CircularProgress from \"@mui/material/CircularProgress\";\nimport Stack from \"@mui/material/Stack\";\nimport Typography from \"@mui/material/Typography\";\nimport type { JsonObject } from \"@craftainer/crud-sdk\";\nimport { recordOptions } from \"@craftainer/crud-sdk/tanstack\";\nimport { useQuery } from \"@tanstack/react-query\";\nimport {\n useEffect,\n useId,\n useRef,\n useState,\n type ReactElement,\n type ReactNode,\n} from \"react\";\nimport {\n DialogShell,\n DrawerShell,\n FieldInput,\n PageShell,\n ResourceGate,\n type FieldDescriptor,\n type FieldValue,\n type ReadyResource,\n type RendererOverrides,\n} from \"../core/index.ts\";\nimport { FormLayout } from \"./layout.tsx\";\nimport {\n groupFields,\n type FormLayoutKind,\n type FormSection,\n} from \"./sections.ts\";\nimport { describeFailure } from \"./problem.ts\";\nimport { validateAll } from \"./validate.ts\";\n\ntype Row = Readonly<Record<string, FieldValue>>;\n\nexport interface ResourceFormProps {\n /** The manifest resource name. */\n readonly name: string;\n readonly apiVersion?: string | undefined;\n /** Edit this record; without it the form creates one. */\n readonly id?: number | undefined;\n /** Where the form renders. Default `\"page\"`. */\n readonly presentation?: \"page\" | \"dialog\" | \"drawer\";\n /** Dialog and drawer: whether it shows (a closed one renders nothing). */\n readonly open?: boolean | undefined;\n readonly onClose?: (() => void) | undefined;\n /** How fields are arranged. Default `\"flat\"`. */\n readonly layout?: FormLayoutKind;\n /** Titled groups of field names for `sections`, `tabs` and `stepper`; default Required and Optional. */\n readonly sections?: readonly FormSection[] | undefined;\n /** Only these fields (in the resource's order). Default every writable field. */\n readonly fields?: readonly string[] | undefined;\n /** Create: starting values. */\n readonly initial?: Row | undefined;\n /** Edit: save by itself after a pause in typing, while the form is valid. */\n readonly autoSave?: boolean | undefined;\n /** Pause before an auto-save, in milliseconds. Default 1000. */\n readonly autoSaveDelayMs?: number | undefined;\n /**\n * The record's current ETag, sent as `If-Match` on every save (edit only,\n * when the resource has `conditional_requests`). Called before each save,\n * because a save changes the ETag. Without it no header is sent by the form\n * (the SDK cache's `autoIfMatch` can still add one).\n */\n readonly etag?:\n | ((id: number) => string | undefined | Promise<string | undefined>)\n | undefined;\n readonly onSaved?: ((record: JsonObject) => void) | undefined;\n /** Heading override. Default \"New <recordLabel>\" or \"Edit <recordLabel> <id>\". */\n readonly title?: ReactNode;\n /** What one record is called in titles. Default \"record\". */\n readonly recordLabel?: string | undefined;\n readonly renderers?: RendererOverrides | undefined;\n}\n\nconst noop = (): void => {};\n\nconst same = (a: FieldValue, b: FieldValue): boolean =>\n JSON.stringify(a) === JSON.stringify(b);\n\nconst pick = (fields: readonly FieldDescriptor[], row: Row): Row =>\n Object.fromEntries(fields.map((f) => [f.name, row[f.name]]));\n\n/** Members of the create body or update patch: set values, and in edit only those that changed. */\nfunction changes(\n fields: readonly FieldDescriptor[],\n values: Row,\n baseline: Row | undefined,\n): Record<string, FieldValue> {\n const out: Record<string, FieldValue> = {};\n for (const field of fields) {\n const value = values[field.name];\n // A cleared field with no null to send is left out of the request.\n if (value === undefined) continue;\n if (baseline !== undefined && same(value, baseline[field.name])) continue;\n out[field.name] = value;\n }\n return out;\n}\n\nconst hasProperty = (schema: JsonObject, name: string): boolean => {\n const props = schema[\"properties\"];\n return (\n typeof props === \"object\" &&\n props !== null &&\n Object.hasOwn(props as object, name)\n );\n};\n\ntype Status = \"idle\" | \"saving\" | \"saved\" | \"nothing\";\n\nconst STATUS_TEXT: Record<Status, string> = {\n idle: \"\",\n saving: \"Saving…\",\n saved: \"Saved\",\n nothing: \"No changes to save\",\n};\n\n/** A create or edit form for a resource; see `ResourceFormProps`. */\nexport function ResourceForm(props: ResourceFormProps): ReactElement | null {\n const presentation = props.presentation ?? \"page\";\n if (presentation !== \"page\" && props.open !== true) return null;\n return (\n <ResourceGate name={props.name} apiVersion={props.apiVersion}>\n {(ready) => (\n <FormController key={props.id ?? \"new\"} ready={ready} {...props} />\n )}\n </ResourceGate>\n );\n}\n\nfunction FormController({\n ready,\n ...props\n}: ResourceFormProps & { readonly ready: ReadyResource }): ReactElement {\n const { id, layout = \"flat\", autoSave = false, renderers } = props;\n const mode = id === undefined ? \"create\" : \"edit\";\n const presentation = props.presentation ?? \"page\";\n const { hooks, resource, capabilities } = ready;\n const formId = useId();\n\n const queryName =\n props.apiVersion === undefined\n ? props.name\n : `${props.name}@${props.apiVersion}`;\n const record = useQuery({\n ...recordOptions(queryName, ready.api, id ?? 0),\n enabled: mode === \"edit\",\n });\n const create = hooks.useCreate();\n const update = hooks.useUpdate();\n\n const writable =\n mode === \"create\" ? resource.schemas.create : resource.schemas.update;\n const editable = ready.fields.filter(\n (f) =>\n !f.readOnly &&\n hasProperty(writable, f.name) &&\n (props.fields === undefined || props.fields.includes(f.name)),\n );\n const sections = groupFields(\n editable,\n layout === \"flat\"\n ? [{ title: \"\", fields: editable.map((f) => f.name) }]\n : props.sections,\n );\n\n const [baseline, setBaseline] = useState<Row | undefined>(undefined);\n const [values, setValues] = useState<Row>(() =>\n mode === \"create\" ? pick(editable, props.initial ?? {}) : {},\n );\n const [loaded, setLoaded] = useState(mode === \"create\");\n if (!loaded && record.data !== undefined) {\n // The record arrived: it becomes both the baseline and the first values.\n setLoaded(true);\n setBaseline(record.data as Row);\n setValues(pick(editable, record.data as Row));\n }\n\n const [touched, setTouched] = useState<ReadonlySet<string>>(new Set());\n const [invalid, setInvalid] = useState<Readonly<Record<string, string>>>({});\n const [serverErrors, setServerErrors] = useState<\n Readonly<Record<string, string>>\n >({});\n const [message, setMessage] = useState<string | null>(null);\n const [conflict, setConflict] = useState(false);\n const [status, setStatus] = useState<Status>(\"idle\");\n const [active, setActive] = useState(0);\n const saving = useRef(false);\n\n const local = validateAll(editable, values);\n const invalidCount = Object.keys(invalid).length;\n const patch = changes(\n editable,\n values,\n mode === \"edit\" ? baseline : undefined,\n );\n const dirty = Object.keys(patch).length > 0;\n const errorOf = (name: string): string | undefined =>\n serverErrors[name] ?? (touched.has(name) ? local[name] : undefined);\n const errorCount = (section: FormSection): number =>\n section.fields.filter(\n (name) => errorOf(name) !== undefined || invalid[name] !== undefined,\n ).length;\n\n const edits = useRef(0);\n const setValue = (name: string, value: FieldValue): void => {\n edits.current += 1;\n setValues((prev) => ({ ...prev, [name]: value }));\n setServerErrors(({ [name]: _removed, ...rest }) => rest);\n setMessage(null);\n setStatus(\"idle\");\n };\n\n const reset = (row: Row): void => {\n setBaseline(row);\n setValues(pick(editable, row));\n setTouched(new Set());\n setServerErrors({});\n setMessage(null);\n setConflict(false);\n setStatus(\"idle\");\n };\n\n const save = async (options: {\n overwrite?: boolean;\n quiet?: boolean;\n }): Promise<void> => {\n if (saving.current) return;\n if (options.quiet !== true) {\n setTouched(new Set(editable.map((f) => f.name)));\n const firstBad = sections.findIndex((s) =>\n s.fields.some(\n (name) => local[name] !== undefined || invalid[name] !== undefined,\n ),\n );\n if (firstBad >= 0) setActive(firstBad);\n }\n if (Object.keys(local).length > 0 || invalidCount > 0) return;\n if (mode === \"edit\" && !dirty) {\n setStatus(\"nothing\");\n return;\n }\n saving.current = true;\n setStatus(\"saving\");\n setConflict(false);\n setMessage(null);\n setServerErrors({});\n try {\n if (mode === \"create\") {\n const created = await create.mutateAsync(patch as JsonObject);\n reset(pick(editable, props.initial ?? {}));\n setStatus(\"saved\");\n props.onSaved?.(created);\n } else {\n const ifMatch =\n options.overwrite === true ||\n !capabilities.conditional_requests ||\n props.etag === undefined\n ? undefined\n : await props.etag(id as number);\n const seen = edits.current;\n const saved = await update.mutateAsync({\n id: id as number,\n patch: patch as JsonObject,\n ...(ifMatch === undefined ? {} : { ifMatch }),\n });\n setBaseline(saved as Row);\n // Edits made while the request ran are not saved yet.\n setStatus(edits.current === seen ? \"saved\" : \"idle\");\n props.onSaved?.(saved);\n }\n } catch (error) {\n const failure = describeFailure(\n error,\n editable.map((f) => f.name),\n );\n setConflict(failure.conflict);\n setServerErrors(failure.fieldErrors);\n setMessage(failure.message);\n setStatus(\"idle\");\n const firstBad = sections.findIndex((s) =>\n s.fields.some((name) => failure.fieldErrors[name] !== undefined),\n );\n if (firstBad >= 0) setActive(firstBad);\n } finally {\n saving.current = false;\n }\n };\n\n const reload = async (): Promise<void> => {\n const result = await record.refetch();\n if (result.isError) {\n setMessage(`The record could not be reloaded: ${result.error.message}`);\n } else {\n reset(result.data as Row);\n }\n };\n\n // Auto-save: a quiet pause after the last edit, only while valid and not in conflict.\n const latestSave = useRef(save);\n useEffect(() => {\n latestSave.current = save;\n });\n const delay = props.autoSaveDelayMs ?? 1000;\n const autoSaveReady =\n autoSave &&\n mode === \"edit\" &&\n dirty &&\n !conflict &&\n message === null &&\n Object.keys(serverErrors).length === 0 &&\n Object.keys(local).length === 0 &&\n invalidCount === 0 &&\n status === \"idle\";\n useEffect(() => {\n if (!autoSaveReady) return undefined;\n const timer = setTimeout(\n () => void latestSave.current({ quiet: true }),\n delay,\n );\n return () => clearTimeout(timer);\n }, [autoSaveReady, values, delay]);\n\n const goNext = (): void => {\n const section = sections[active] as FormSection;\n setTouched((prev) => new Set([...prev, ...section.fields]));\n const blocked = section.fields.some(\n (name) => local[name] !== undefined || invalid[name] !== undefined,\n );\n if (!blocked) setActive(active + 1);\n };\n\n const label = props.recordLabel ?? \"record\";\n const title =\n props.title ?? (mode === \"create\" ? `New ${label}` : `Edit ${label} ${id}`);\n const stepper = layout === \"stepper\";\n const submit = (\n <Button\n type=\"submit\"\n form={formId}\n variant=\"contained\"\n disabled={invalidCount > 0 || status === \"saving\"}\n >\n {mode === \"create\" ? \"Create\" : \"Save\"}\n </Button>\n );\n const actions = stepper || (autoSave && mode === \"edit\") ? undefined : submit;\n\n const fieldByName = new Map(editable.map((f) => [f.name, f]));\n const renderField = (name: string): ReactElement => (\n <FieldInput\n key={name}\n field={fieldByName.get(name) as FieldDescriptor}\n resource={resource.name}\n value={values[name]}\n id={`${formId}-${name}`}\n error={errorOf(name)}\n renderers={renderers}\n onChange={(value) => setValue(name, value)}\n onBlur={() => setTouched((prev) => new Set(prev).add(name))}\n onInvalid={(reason) =>\n setInvalid((prev) => {\n if ((prev[name] ?? null) === reason) return prev;\n const { [name]: _removed, ...rest } = prev;\n return reason === null ? rest : { ...rest, [name]: reason };\n })\n }\n />\n );\n\n let content: ReactElement;\n if (!loaded && record.isError) {\n content = <Alert severity=\"error\">{record.error.message}</Alert>;\n } else if (!loaded) {\n content = (\n <Box sx={{ display: \"flex\", justifyContent: \"center\", p: 4 }}>\n <CircularProgress aria-label=\"Loading\" />\n </Box>\n );\n } else {\n content = (\n <Box\n component=\"form\"\n id={formId}\n noValidate\n aria-label={typeof title === \"string\" ? title : \"Form\"}\n onSubmit={(event) => {\n event.preventDefault();\n void save({});\n }}\n >\n <Stack spacing={2}>\n {message !== null && <Alert severity=\"error\">{message}</Alert>}\n {conflict && (\n <Alert\n severity=\"warning\"\n action={\n <>\n <Button\n color=\"inherit\"\n size=\"small\"\n onClick={() => void reload()}\n >\n Reload\n </Button>\n <Button\n color=\"inherit\"\n size=\"small\"\n onClick={() => void save({ overwrite: true })}\n >\n Overwrite\n </Button>\n </>\n }\n >\n This record was changed since you opened it. Reload to discard\n your edits and see the current version, or overwrite it with\n yours.\n </Alert>\n )}\n <FormLayout\n layout={layout}\n sections={sections}\n renderField={renderField}\n errorCount={errorCount}\n active={Math.min(active, sections.length - 1)}\n onActive={setActive}\n onNext={goNext}\n submit={submit}\n />\n <Typography\n role=\"status\"\n variant=\"body2\"\n sx={{ color: \"text.secondary\", minHeight: \"1lh\" }}\n >\n {STATUS_TEXT[status]}\n </Typography>\n </Stack>\n </Box>\n );\n }\n\n if (presentation === \"dialog\") {\n return (\n <DialogShell\n open\n title={title}\n actions={actions}\n onClose={props.onClose ?? noop}\n >\n {content}\n </DialogShell>\n );\n }\n if (presentation === \"drawer\") {\n return (\n <DrawerShell\n open\n title={title}\n actions={actions}\n onClose={props.onClose ?? noop}\n >\n {content}\n </DrawerShell>\n );\n }\n return (\n <PageShell title={title} actions={actions}>\n {content}\n </PageShell>\n );\n}\n","import Box from \"@mui/material/Box\";\nimport ToggleButton from \"@mui/material/ToggleButton\";\nimport ToggleButtonGroup from \"@mui/material/ToggleButtonGroup\";\nimport type { ReactElement } from \"react\";\nimport type { ReadyResource } from \"../core/index.ts\";\nimport type { StatusFilterValue } from \"./status.ts\";\n\nexport interface StatusFilterProps {\n readonly ready: ReadyResource;\n readonly value: StatusFilterValue;\n readonly onChange: (value: StatusFilterValue) => void;\n}\n\n/** Published / Draft / All. Hidden unless `capabilities.draft_publish`. */\nexport function StatusFilter({\n ready,\n value,\n onChange,\n}: StatusFilterProps): ReactElement | null {\n if (!ready.capabilities.draft_publish) return null;\n return (\n <Box>\n <ToggleButtonGroup\n exclusive\n size=\"small\"\n value={value}\n aria-label=\"Status\"\n sx={{ \"& .MuiToggleButton-root\": { color: \"text.primary\" } }}\n onChange={(_event, next: StatusFilterValue | null) => {\n if (next !== null) onChange(next);\n }}\n >\n <ToggleButton value=\"published\">Published</ToggleButton>\n <ToggleButton value=\"draft\">Draft</ToggleButton>\n <ToggleButton value=\"all\">All</ToggleButton>\n </ToggleButtonGroup>\n </Box>\n );\n}\n","import type { JsonObject } from \"@craftainer/crud-sdk\";\nimport { useQuery } from \"@tanstack/react-query\";\nimport type { FieldValue } from \"../core/index.ts\";\nimport Alert from \"@mui/material/Alert\";\nimport Box from \"@mui/material/Box\";\nimport Button from \"@mui/material/Button\";\nimport CircularProgress from \"@mui/material/CircularProgress\";\nimport Table from \"@mui/material/Table\";\nimport TableBody from \"@mui/material/TableBody\";\nimport TableCell from \"@mui/material/TableCell\";\nimport TableHead from \"@mui/material/TableHead\";\nimport TableRow from \"@mui/material/TableRow\";\nimport Typography from \"@mui/material/Typography\";\nimport type { ReactElement } from \"react\";\nimport {\n FieldDisplay,\n ResourceGate,\n type ReadyResource,\n type RendererOverrides,\n} from \"../core/index.ts\";\nimport { useRestore } from \"./mutations.ts\";\nimport { SYSTEM_FIELDS } from \"./status.ts\";\n\nexport interface TrashPanelProps {\n readonly ready: ReadyResource;\n readonly renderers?: RendererOverrides | undefined;\n /** Columns to show; default: the first three non-system fields. */\n readonly columns?: readonly string[] | undefined;\n /** Called after a record was restored. */\n readonly onRestored?: ((id: number) => void) | undefined;\n}\n\n/** The archived records of an already loaded resource, each with Restore. Hidden without `archive_restore`. */\nexport function TrashPanel(props: TrashPanelProps): ReactElement | null {\n return props.ready.capabilities.archive_restore ? (\n <TrashBody {...props} />\n ) : null;\n}\n\nfunction TrashBody({\n ready,\n renderers,\n columns,\n onRestored,\n}: TrashPanelProps): ReactElement {\n // `archived_at` is no filter field, so the archived rows are picked out of\n // every page: with `includeArchived` alone they share pages with live rows.\n const list = useQuery({\n queryKey: [\n \"crud\",\n `${ready.resource.name}@${ready.resource.api_version}`,\n \"trash\",\n ],\n queryFn: async (): Promise<JsonObject[]> => {\n const rows: JsonObject[] = [];\n for await (const row of ready.handle.iterAll({\n includeArchived: true,\n includeUnpublished: true,\n })) {\n if (typeof row[\"archived_at\"] === \"string\") rows.push(row);\n }\n return rows;\n },\n });\n const restore = useRestore(ready);\n const fields =\n columns === undefined\n ? ready.fields.filter((f) => !SYSTEM_FIELDS.includes(f.name)).slice(0, 3)\n : ready.fields.filter((f) => columns.includes(f.name));\n if (list.isPending) {\n return (\n <Box sx={{ display: \"flex\", justifyContent: \"center\", p: 4 }}>\n <CircularProgress aria-label=\"Loading\" />\n </Box>\n );\n }\n if (list.isError) {\n return <Alert severity=\"error\">{list.error.message}</Alert>;\n }\n const archived = list.data;\n const error = restore.error;\n return (\n <>\n {error !== null && <Alert severity=\"error\">{error.message}</Alert>}\n {archived.length === 0 ? (\n <Typography color=\"text.secondary\">The trash is empty.</Typography>\n ) : (\n <Table size=\"small\" aria-label=\"Trash\">\n <TableHead>\n <TableRow>\n {fields.map((f) => (\n <TableCell key={f.name}>{f.label}</TableCell>\n ))}\n <TableCell>Archived</TableCell>\n <TableCell align=\"right\">Actions</TableCell>\n </TableRow>\n </TableHead>\n <TableBody>\n {archived.map((row) => {\n const id = row[ready.resource.id_field] as number;\n return (\n <TableRow key={id}>\n {fields.map((f) => (\n <TableCell key={f.name}>\n <FieldDisplay\n field={f}\n resource={ready.resource.name}\n value={row[f.name] as FieldValue}\n renderers={renderers}\n />\n </TableCell>\n ))}\n <TableCell>{String(row[\"archived_at\"])}</TableCell>\n <TableCell align=\"right\">\n <Button\n size=\"small\"\n aria-label={`Restore record ${id}`}\n disabled={restore.isPending}\n onClick={() =>\n restore.mutate(id, {\n onSuccess: () => onRestored?.(id),\n })\n }\n >\n Restore\n </Button>\n </TableCell>\n </TableRow>\n );\n })}\n </TableBody>\n </Table>\n )}\n </>\n );\n}\n\nexport interface TrashListProps extends Omit<TrashPanelProps, \"ready\"> {\n readonly resource: string;\n readonly apiVersion?: string | undefined;\n}\n\n/** The trash: archived records with Restore. Renders nothing for a resource without an archive. */\nexport function TrashList({\n resource,\n apiVersion,\n ...rest\n}: TrashListProps): ReactElement {\n return (\n <ResourceGate name={resource} apiVersion={apiVersion}>\n {(ready) => <TrashPanel ready={ready} {...rest} />}\n </ResourceGate>\n );\n}\n","import type { FieldDescriptor, ReadyResource } from \"../core/index.ts\";\n\n/** A column: a field name, or a name with a header and a size. */\nexport type ColumnSpec =\n | string\n | {\n readonly field: string;\n /** Header text. Default: the field's label. */\n readonly header?: string | undefined;\n /** Width in pixels (a number) for the table. */\n readonly width?: number | undefined;\n };\n\n/** A resolved column. */\nexport interface Column {\n readonly field: FieldDescriptor;\n readonly header: string;\n readonly width: number | undefined;\n}\n\n/**\n * The columns to show. Default: every described field except JSON ones.\n * Names the resource does not have are skipped.\n */\nexport function resolveColumns(\n ready: ReadyResource,\n columns?: readonly ColumnSpec[],\n): Column[] {\n if (columns === undefined)\n return ready.fields\n .filter((f) => f.kind !== \"json\")\n .map((field) => ({ field, header: field.label, width: undefined }));\n return columns.flatMap((spec): Column[] => {\n const {\n field: name,\n header,\n width,\n } = typeof spec === \"string\"\n ? { field: spec, header: undefined, width: undefined }\n : spec;\n const field = ready.field(name);\n return field === undefined\n ? []\n : [{ field, header: header ?? field.label, width }];\n });\n}\n","import Button from \"@mui/material/Button\";\nimport Card from \"@mui/material/Card\";\nimport CardContent from \"@mui/material/CardContent\";\nimport Stack from \"@mui/material/Stack\";\nimport Typography from \"@mui/material/Typography\";\nimport type { ReactElement } from \"react\";\nimport {\n FieldDisplay,\n type FieldValue,\n type ReadyResource,\n type RendererOverrides,\n} from \"../core/index.ts\";\nimport { resolveColumns, type ColumnSpec } from \"./columns.ts\";\n\nexport type Row = Readonly<Record<string, FieldValue>>;\n\nexport interface RecordCardProps {\n readonly ready: ReadyResource;\n readonly row: Row;\n readonly columns?: readonly ColumnSpec[] | undefined;\n /** The field shown as the card's heading. Default: the first column. */\n readonly titleField?: string | undefined;\n readonly renderers?: RendererOverrides | undefined;\n readonly onClick?: ((row: Row) => void) | undefined;\n}\n\n/** One record as a card: a heading and a label/value pair per other column. */\nexport function RecordCard({\n ready,\n row,\n columns,\n titleField,\n renderers,\n onClick,\n}: RecordCardProps): ReactElement {\n const all = resolveColumns(ready, columns);\n const head = all.find((c) => c.field.name === titleField) ?? all[0];\n const rest = all.filter((c) => c !== head);\n const resource = ready.resource.name;\n const display = (c: (typeof all)[number]): ReactElement => (\n <FieldDisplay\n field={c.field}\n resource={resource}\n size=\"small\"\n value={row[c.field.name]}\n record={row}\n renderers={renderers}\n />\n );\n return (\n <Card variant=\"outlined\" component=\"article\">\n <CardContent>\n {head !== undefined && (\n <Typography component=\"h3\" variant=\"h6\" gutterBottom>\n {display(head)}\n </Typography>\n )}\n <Stack component=\"dl\" spacing={0.5} sx={{ m: 0 }}>\n {rest.map((c) => (\n <Stack\n key={c.field.name}\n direction=\"row\"\n spacing={1}\n sx={{ alignItems: \"baseline\" }}\n >\n <Typography\n component=\"dt\"\n variant=\"body2\"\n color=\"text.secondary\"\n sx={{ minWidth: \"8rem\" }}\n >\n {c.header}\n </Typography>\n <Typography\n component=\"dd\"\n variant=\"body2\"\n sx={{ m: 0, minWidth: 0 }}\n >\n {display(c)}\n </Typography>\n </Stack>\n ))}\n </Stack>\n {onClick !== undefined && (\n <Button size=\"small\" sx={{ mt: 1 }} onClick={() => onClick(row)}>\n Open\n </Button>\n )}\n </CardContent>\n </Card>\n );\n}\n","import Box from \"@mui/material/Box\";\nimport Typography from \"@mui/material/Typography\";\nimport type { ReactElement } from \"react\";\nimport type { ReadyResource, RendererOverrides } from \"../core/index.ts\";\nimport type { ColumnSpec } from \"./columns.ts\";\nimport { RecordCard, type Row } from \"./RecordCard.tsx\";\n\nexport interface CardListProps {\n readonly ready: ReadyResource;\n readonly rows: readonly Row[];\n readonly columns?: readonly ColumnSpec[] | undefined;\n readonly titleField?: string | undefined;\n /** `list`: one card per row; `grid`: as many as fit. */\n readonly layout: \"list\" | \"grid\";\n readonly onRowClick?: ((row: Row) => void) | undefined;\n readonly renderers?: RendererOverrides | undefined;\n}\n\n/** The cards of the card views (and their empty state). */\nexport function CardList({\n ready,\n rows,\n columns,\n titleField,\n layout,\n onRowClick,\n renderers,\n}: CardListProps): ReactElement {\n if (rows.length === 0)\n return <Typography color=\"text.secondary\">No records.</Typography>;\n return (\n <Box\n component=\"ul\"\n aria-label={ready.resource.title}\n sx={{\n listStyle: \"none\",\n m: 0,\n p: 0,\n display: \"grid\",\n gap: 2,\n gridTemplateColumns:\n layout === \"grid\" ? \"repeat(auto-fill, minmax(16rem, 1fr))\" : \"1fr\",\n }}\n >\n {rows.map((row) => (\n <li key={String(row[ready.resource.id_field])}>\n <RecordCard\n ready={ready}\n row={row}\n columns={columns}\n titleField={titleField}\n renderers={renderers}\n onClick={onRowClick}\n />\n </li>\n ))}\n </Box>\n );\n}\n","import Alert from \"@mui/material/Alert\";\nimport Button from \"@mui/material/Button\";\nimport type { ReactElement } from \"react\";\n\n/** The shared \"could not load\" alert with a Retry action. */\nexport function LoadError({\n title,\n error,\n onRetry,\n}: {\n readonly title: string;\n readonly error: Error;\n readonly onRetry: () => void;\n}): ReactElement {\n return (\n <Alert severity=\"error\" action={<Button onClick={onRetry}>Retry</Button>}>\n {`Could not load ${title}: ${error.message}`}\n </Alert>\n );\n}\n","import Button from \"@mui/material/Button\";\nimport CircularProgress from \"@mui/material/CircularProgress\";\nimport Stack from \"@mui/material/Stack\";\nimport Typography from \"@mui/material/Typography\";\nimport type { ReactElement } from \"react\";\nimport type { ReadyResource, RendererOverrides } from \"../core/index.ts\";\nimport type { QueryStateApi } from \"../filter/index.ts\";\nimport type { ColumnSpec } from \"./columns.ts\";\nimport { CardList } from \"./CardList.tsx\";\nimport { LoadError } from \"./LoadError.tsx\";\nimport type { Row } from \"./RecordCard.tsx\";\n\nexport interface CardGridListProps {\n readonly ready: ReadyResource;\n readonly state: QueryStateApi;\n readonly columns?: readonly ColumnSpec[] | undefined;\n readonly titleField?: string | undefined;\n readonly onRowClick?: ((row: Row) => void) | undefined;\n readonly renderers?: RendererOverrides | undefined;\n}\n\n/** A page of cards in a responsive grid, with Previous and Next (the server reports no total). */\nexport function CardGridList({\n ready,\n state,\n columns,\n titleField,\n onRowClick,\n renderers,\n}: CardGridListProps): ReactElement {\n const { page, pageSize } = state.state;\n const list = ready.hooks.useList(state.pagedQuery);\n if (list.isError)\n return (\n <LoadError\n title={ready.resource.title}\n error={list.error}\n onRetry={() => void list.refetch()}\n />\n );\n if (list.isPending) return <CircularProgress aria-label=\"Loading\" />;\n const rows = list.data.slice(0, pageSize) as Row[];\n return (\n <Stack spacing={2}>\n <CardList\n ready={ready}\n rows={rows}\n columns={columns}\n titleField={titleField}\n layout=\"grid\"\n onRowClick={onRowClick}\n renderers={renderers}\n />\n <Stack\n direction=\"row\"\n spacing={1}\n component=\"nav\"\n aria-label=\"Pages\"\n sx={{ alignItems: \"center\" }}\n >\n <Button disabled={page <= 1} onClick={() => state.setPage(page - 1)}>\n Previous\n </Button>\n <Typography variant=\"body2\">{`Page ${page}`}</Typography>\n <Button\n disabled={list.data.length <= pageSize}\n onClick={() => state.setPage(page + 1)}\n >\n Next\n </Button>\n </Stack>\n </Stack>\n );\n}\n","import Button from \"@mui/material/Button\";\nimport Checkbox from \"@mui/material/Checkbox\";\nimport FormControlLabel from \"@mui/material/FormControlLabel\";\nimport FormGroup from \"@mui/material/FormGroup\";\nimport Popover from \"@mui/material/Popover\";\nimport { useId, useState, type ReactElement } from \"react\";\nimport type { Column } from \"./columns.ts\";\n\nexport interface ColumnsMenuProps {\n readonly columns: readonly Column[];\n /** Field names currently hidden. */\n readonly hidden: ReadonlySet<string>;\n readonly onChange: (hidden: ReadonlySet<string>) => void;\n}\n\n/** A button that opens a checklist of the columns, to show or hide each. */\nexport function ColumnsMenu({\n columns,\n hidden,\n onChange,\n}: ColumnsMenuProps): ReactElement {\n const [anchor, setAnchor] = useState<HTMLElement | null>(null);\n const id = useId();\n return (\n <>\n <Button\n aria-haspopup=\"dialog\"\n aria-expanded={anchor !== null}\n aria-controls={anchor === null ? undefined : id}\n onClick={(e) => setAnchor(e.currentTarget)}\n >\n Columns\n </Button>\n <Popover\n id={id}\n open={anchor !== null}\n anchorEl={anchor}\n onClose={() => setAnchor(null)}\n slotProps={{\n paper: { \"aria-label\": \"Columns\", role: \"dialog\", sx: { p: 2 } },\n }}\n >\n <FormGroup>\n {columns.map((c) => (\n <FormControlLabel\n key={c.field.name}\n label={c.header}\n control={\n <Checkbox\n size=\"small\"\n checked={!hidden.has(c.field.name)}\n onChange={() => {\n const next = new Set(hidden);\n if (!next.delete(c.field.name)) next.add(c.field.name);\n onChange(next);\n }}\n />\n }\n />\n ))}\n </FormGroup>\n </Popover>\n </>\n );\n}\n","import Alert from \"@mui/material/Alert\";\nimport Box from \"@mui/material/Box\";\nimport {\n DataGrid,\n useGridApiContext,\n type DataGridProps,\n type GridColDef,\n type GridRenderCellParams,\n type GridRenderEditCellParams,\n type GridSortModel,\n} from \"@mui/x-data-grid\";\nimport { PreconditionFailed } from \"@craftainer/crud-sdk\";\nimport { useMemo, useState, type ReactElement } from \"react\";\nimport {\n FieldDisplay,\n FieldInput,\n type FieldDescriptor,\n type FieldValue,\n type ReadyResource,\n type RendererOverrides,\n} from \"../core/index.ts\";\nimport type { QueryStateApi } from \"../filter/index.ts\";\nimport { LoadError } from \"./LoadError.tsx\";\nimport { ColumnsMenu } from \"./ColumnsMenu.tsx\";\nimport { resolveColumns, type ColumnSpec } from \"./columns.ts\";\n\ntype Row = Readonly<Record<string, FieldValue>>;\n\n/** DataGrid props a caller may pass through (not the ones this view controls). */\nexport type GridOptions = Partial<\n Omit<DataGridProps, \"onRowClick\" | \"rows\" | \"columns\">\n>;\n\nexport interface DataTableListProps {\n readonly ready: ReadyResource;\n /** Filter, sort and paging state; see `useQueryState`. */\n readonly state: QueryStateApi;\n /** Columns in order. Default: every field but JSON ones. */\n readonly columns?: readonly ColumnSpec[] | undefined;\n /** Show only columns the server can sort by. */\n readonly sortableOnly?: boolean | undefined;\n /** Let the user hide columns (a \"Columns\" button). Default true. */\n readonly configurableColumns?: boolean | undefined;\n /** Edit cells in place (double-click or Enter; Enter saves, Escape cancels). Read-only fields stay read-only. */\n readonly editable?: boolean | undefined;\n /**\n * The ETag of a row, sent as `If-Match` on an inline edit (a stale one fails\n * with 412 and the view reloads the row). The list endpoint returns no ETags,\n * so the app supplies them (for example from its SDK cache); without this\n * prop the edit is unconditional. May return a promise (same shape as\n * `ResourceFormProps.etag`): the edit waits for it, stays in a saving state\n * meanwhile, and is not sent if it rejects (the error is shown like any save\n * error). `undefined` sends the PATCH without `If-Match`.\n */\n readonly ifMatch?:\n | ((row: Row) => string | undefined | Promise<string | undefined>)\n | undefined;\n readonly pageSizeOptions?: readonly number[] | undefined;\n readonly onRowClick?: ((row: Row) => void) | undefined;\n readonly renderers?: RendererOverrides | undefined;\n /** Passed to the DataGrid last (a way to reach options this view does not expose). */\n readonly gridProps?: GridOptions | undefined;\n}\n\ninterface EditCellProps extends GridRenderEditCellParams {\n readonly descriptor: FieldDescriptor;\n readonly resource: string;\n readonly renderers: RendererOverrides | undefined;\n}\n\nfunction EditCell({\n descriptor,\n resource,\n renderers,\n id,\n field,\n value,\n}: EditCellProps): ReactElement {\n const apiRef = useGridApiContext();\n return (\n <FieldInput\n field={descriptor}\n resource={resource}\n size=\"small\"\n value={value as FieldValue}\n autoFocus\n renderers={renderers}\n onChange={(next) =>\n void apiRef.current.setEditCellValue({ id, field, value: next })\n }\n />\n );\n}\n\nconst canEdit = (\n f: FieldDescriptor,\n editable: boolean,\n idField: string,\n): boolean => editable && !f.readOnly && f.name !== idField;\n\nconst same = (a: unknown, b: unknown): boolean =>\n JSON.stringify(a) === JSON.stringify(b);\n\n/** A paged data table (MUI X DataGrid): server-side sort and paging, optional inline editing. */\nexport function DataTableList({\n ready,\n state,\n columns,\n sortableOnly = false,\n configurableColumns = true,\n editable = false,\n ifMatch,\n pageSizeOptions = [10, 25, 50, 100],\n onRowClick,\n renderers,\n gridProps,\n}: DataTableListProps): ReactElement {\n const { resource } = ready;\n const idField = resource.id_field;\n const { page, pageSize, sort } = state.state;\n const list = ready.hooks.useList(state.pagedQuery);\n const update = ready.hooks.useUpdate();\n const [hidden, setHidden] = useState<ReadonlySet<string>>(new Set());\n const [notice, setNotice] = useState<string | null>(null);\n // Edits in flight (several rows can save at once).\n const [saving, setSaving] = useState(0);\n const shown = useMemo(\n () =>\n resolveColumns(ready, columns).filter(\n (c) => !sortableOnly || c.field.sortable,\n ),\n [ready, columns, sortableOnly],\n );\n\n const gridColumns = useMemo<GridColDef[]>(\n () =>\n shown.map(({ field, header, width }) => ({\n field: field.name,\n headerName: header,\n sortable: field.sortable,\n filterable: false,\n editable: canEdit(field, editable, idField),\n ...(width === undefined ? { flex: 1, minWidth: 140 } : { width }),\n renderCell: (p: GridRenderCellParams) => (\n <FieldDisplay\n field={field}\n resource={resource.name}\n size=\"small\"\n value={p.value as FieldValue}\n record={p.row as Row}\n renderers={renderers}\n />\n ),\n renderEditCell: (p: GridRenderEditCellParams) => (\n <EditCell\n {...p}\n descriptor={field}\n resource={resource.name}\n renderers={renderers}\n />\n ),\n })),\n [shown, resource.name, renderers, editable, idField],\n );\n\n // Keep showing the previous page while the next loads: with no rows the grid\n // would clamp to page 1 and undo the page change.\n const [previous, setPrevious] = useState(list.data);\n if (list.data !== undefined && list.data !== previous) setPrevious(list.data);\n const data = list.data ?? previous;\n const rows = (data ?? []).slice(0, pageSize) as Row[];\n const hasNextPage = (data?.length ?? 0) > pageSize;\n // The server reports no total, so the grid gets the least count that is true:\n // everything up to this page, plus one more row when a next page exists.\n const rowCount =\n data === undefined\n ? page * pageSize + 1\n : (page - 1) * pageSize + rows.length + (hasNextPage ? 1 : 0);\n // The grid treats a new model object as a sort change and returns to page 1,\n // so rebuild it only when the keys change, not when the URL is decoded again.\n const sortText = sort\n .map((k) => (k.desc ? `-${k.field}` : k.field))\n .join(\",\");\n const sortModel = useMemo<GridSortModel>(\n () =>\n sortText === \"\"\n ? []\n : sortText.split(\",\").map((key) => ({\n field: key.replace(/^-/, \"\"),\n sort: key.startsWith(\"-\") ? \"desc\" : \"asc\",\n })),\n [sortText],\n );\n const visibility = Object.fromEntries([...hidden].map((n) => [n, false]));\n const sizes = [...new Set([...pageSizeOptions, pageSize])].sort(\n (a, b) => a - b,\n );\n\n async function save(next: Row, previous: Row): Promise<Row> {\n const patch: Record<string, FieldValue> = {};\n for (const { field } of shown) {\n const value = next[field.name];\n if (\n canEdit(field, editable, idField) &&\n value !== undefined &&\n !same(value, previous[field.name])\n )\n patch[field.name] = value;\n }\n if (Object.keys(patch).length === 0) return previous;\n setSaving((n) => n + 1);\n try {\n const tag = await ifMatch?.(previous);\n const saved = await update.mutateAsync({\n id: previous[idField] as number,\n patch,\n ...(tag === undefined ? {} : { ifMatch: tag }),\n });\n setNotice(null);\n return saved as Row;\n } finally {\n setSaving((n) => n - 1);\n }\n }\n\n function saveFailed(error: unknown): void {\n if (error instanceof PreconditionFailed) {\n setNotice(\"This row changed elsewhere. It was reloaded; edit it again.\");\n void list.refetch();\n } else {\n setNotice(\n `Could not save: ${error instanceof Error ? error.message : String(error)}`,\n );\n }\n }\n\n if (list.isError)\n return (\n <LoadError\n title={resource.title}\n error={list.error}\n onRetry={() => void list.refetch()}\n />\n );\n return (\n <Box aria-busy={saving > 0}>\n {configurableColumns && (\n <ColumnsMenu columns={shown} hidden={hidden} onChange={setHidden} />\n )}\n {notice !== null && (\n <Alert\n severity=\"warning\"\n onClose={() => setNotice(null)}\n sx={{ mb: 1 }}\n >\n {notice}\n </Alert>\n )}\n <DataGrid\n aria-label={resource.title}\n autoHeight\n rows={rows}\n columns={gridColumns}\n getRowId={(row: Row) => row[idField] as number}\n loading={list.isFetching}\n columnVisibilityModel={visibility}\n paginationMode=\"server\"\n sortingMode=\"server\"\n filterMode=\"server\"\n rowCount={rowCount}\n localeText={{\n paginationDisplayedRows: ({ from, to }) =>\n hasNextPage ? `${from}–${to}` : `${from}–${to} of ${rowCount}`,\n }}\n paginationModel={{ page: page - 1, pageSize }}\n pageSizeOptions={sizes}\n onPaginationModelChange={(model) =>\n model.pageSize === pageSize\n ? state.setPage(model.page + 1)\n : state.setPageSize(model.pageSize)\n }\n sortModel={sortModel}\n onSortModelChange={(model) =>\n state.setSort(\n model.map((m) => ({ field: m.field, desc: m.sort === \"desc\" })),\n )\n }\n disableColumnFilter\n disableColumnMenu\n disableRowSelectionOnClick\n processRowUpdate={save}\n onProcessRowUpdateError={saveFailed}\n onRowClick={(p) => onRowClick?.(p.row as Row)}\n {...gridProps}\n />\n </Box>\n );\n}\n","import Box from \"@mui/material/Box\";\nimport Button from \"@mui/material/Button\";\nimport CircularProgress from \"@mui/material/CircularProgress\";\nimport Stack from \"@mui/material/Stack\";\nimport type { ReactElement } from \"react\";\nimport type { ReadyResource, RendererOverrides } from \"../core/index.ts\";\nimport type { QueryStateApi } from \"../filter/index.ts\";\nimport type { ColumnSpec } from \"./columns.ts\";\nimport { CardList } from \"./CardList.tsx\";\nimport { LoadError } from \"./LoadError.tsx\";\nimport type { Row } from \"./RecordCard.tsx\";\n\nexport interface LoadMoreListProps {\n readonly ready: ReadyResource;\n readonly state: QueryStateApi;\n readonly columns?: readonly ColumnSpec[] | undefined;\n readonly titleField?: string | undefined;\n /** `list`: one card per row; `grid`: cards side by side. Default `list`. */\n readonly layout?: \"list\" | \"grid\" | undefined;\n readonly onRowClick?: ((row: Row) => void) | undefined;\n readonly renderers?: RendererOverrides | undefined;\n}\n\n/** A growing list: the first page, then \"Load more\" appends the next (`useInfiniteList`). The page number is not used. */\nexport function LoadMoreList({\n ready,\n state,\n columns,\n titleField,\n layout = \"list\",\n onRowClick,\n renderers,\n}: LoadMoreListProps): ReactElement {\n const query = ready.hooks.useInfiniteList(state.feedQuery, {\n limit: state.state.pageSize,\n });\n if (query.isError)\n return (\n <LoadError\n title={ready.resource.title}\n error={query.error}\n onRetry={() => void query.refetch()}\n />\n );\n if (query.isPending) return <CircularProgress aria-label=\"Loading\" />;\n const rows = query.data.pages.flat() as Row[];\n return (\n <Stack spacing={2}>\n <CardList\n ready={ready}\n rows={rows}\n columns={columns}\n titleField={titleField}\n layout={layout}\n onRowClick={onRowClick}\n renderers={renderers}\n />\n {query.hasNextPage && (\n <Box>\n <Button\n variant=\"outlined\"\n disabled={query.isFetchingNextPage}\n aria-busy={query.isFetchingNextPage}\n onClick={() => void query.fetchNextPage()}\n >\n Load more\n </Button>\n </Box>\n )}\n </Stack>\n );\n}\n","import MenuItem from \"@mui/material/MenuItem\";\nimport Stack from \"@mui/material/Stack\";\nimport TextField from \"@mui/material/TextField\";\nimport type { ReactElement } from \"react\";\nimport { sortableFields, type SortKey } from \"../filter/index.ts\";\nimport type { ReadyResource } from \"../core/index.ts\";\n\nexport interface SortDropdownProps {\n readonly ready: ReadyResource;\n readonly sort: readonly SortKey[];\n readonly onChange: (sort: readonly SortKey[]) => void;\n}\n\nconst NONE = \"\";\n\n/** Sort by one field, for layouts with no header row to click. Lists only fields the manifest marks sortable. */\nexport function SortDropdown({\n ready,\n sort,\n onChange,\n}: SortDropdownProps): ReactElement | null {\n const fields = sortableFields(ready.fields);\n if (fields.length === 0) return null;\n const key = sort[0];\n const field =\n key !== undefined && fields.some((f) => f.name === key.field)\n ? key.field\n : NONE;\n return (\n <Stack direction=\"row\" spacing={1}>\n <TextField\n select\n size=\"small\"\n label=\"Sort by\"\n value={field}\n onChange={(e) =>\n onChange(\n e.target.value === NONE\n ? []\n : [{ field: e.target.value, desc: key?.desc ?? false }],\n )\n }\n sx={{ minWidth: \"10rem\" }}\n >\n <MenuItem value={NONE}>Default order</MenuItem>\n {fields.map((f) => (\n <MenuItem key={f.name} value={f.name}>\n {f.label}\n </MenuItem>\n ))}\n </TextField>\n {field !== NONE && (\n <TextField\n select\n size=\"small\"\n label=\"Direction\"\n value={key?.desc === true ? \"desc\" : \"asc\"}\n onChange={(e) =>\n onChange([{ field, desc: e.target.value === \"desc\" }])\n }\n sx={{ minWidth: \"9rem\" }}\n >\n <MenuItem value=\"asc\">Ascending</MenuItem>\n <MenuItem value=\"desc\">Descending</MenuItem>\n </TextField>\n )}\n </Stack>\n );\n}\n","import Box from \"@mui/material/Box\";\nimport FormControlLabel from \"@mui/material/FormControlLabel\";\nimport Stack from \"@mui/material/Stack\";\nimport Switch from \"@mui/material/Switch\";\nimport type { ReactElement } from \"react\";\nimport {\n ResourceGate,\n type ReadyResource,\n type RendererOverrides,\n} from \"../core/index.ts\";\nimport {\n FacetSidebar,\n FilterBar,\n FilterBuilder,\n QuickSearch,\n useQueryState,\n type QueryDefaults,\n type UrlAdapter,\n} from \"../filter/index.ts\";\nimport { CardGridList } from \"./CardGridList.tsx\";\nimport type { ColumnSpec } from \"./columns.ts\";\nimport { DataTableList, type GridOptions } from \"./DataTableList.tsx\";\nimport { LoadMoreList } from \"./LoadMoreList.tsx\";\nimport type { Row } from \"./RecordCard.tsx\";\nimport { SortDropdown } from \"./SortDropdown.tsx\";\n\n/** `table`: paged data table; `loadMore`: growing list; `cards`: paged card grid. */\nexport type ListVariant = \"table\" | \"loadMore\" | \"cards\";\n/** `quick`: search box; `bar`: a control per field; `builder`: field/operator/operand rows; `facets`: checkboxes for categorical fields. */\nexport type FilterVariant = \"quick\" | \"bar\" | \"builder\" | \"facets\";\n\nexport interface ResourceListProps {\n readonly resource: string;\n readonly apiVersion?: string | undefined;\n readonly variant?: ListVariant | undefined;\n /** Which filter UIs to show, in addition to default filter values. Default `[\"quick\"]`. */\n readonly filters?: readonly FilterVariant[] | undefined;\n /** Fields of the filter bar, in order. Default: all filterable fields. */\n readonly barFields?: readonly string[] | undefined;\n /** Fields of the facet sidebar. Default: all categorical fields. */\n readonly facetFields?: readonly string[] | undefined;\n readonly columns?: readonly ColumnSpec[] | undefined;\n readonly titleField?: string | undefined;\n /** Table only: edit cells in place. */\n readonly editable?: boolean | undefined;\n /** Table only: a row's ETag for inline edits; may be async. See `DataTableListProps.ifMatch`. */\n readonly ifMatch?:\n | ((row: Row) => string | undefined | Promise<string | undefined>)\n | undefined;\n readonly sortableOnly?: boolean | undefined;\n /** Show the sort dropdown. Default: for the card variants, which have no header to click. */\n readonly sortDropdown?: boolean | undefined;\n /** Where the state lives. Default: the window's query string. */\n readonly urlAdapter?: UrlAdapter | undefined;\n /** Prefix of this list's URL parameters. */\n readonly prefix?: string | undefined;\n readonly defaults?: QueryDefaults | undefined;\n readonly searchField?: string | undefined;\n readonly renderers?: RendererOverrides | undefined;\n readonly onRowClick?: ((row: Row) => void) | undefined;\n readonly gridProps?: GridOptions | undefined;\n}\n\ntype BodyProps = Omit<ResourceListProps, \"resource\" | \"apiVersion\"> & {\n readonly ready: ReadyResource;\n};\n\nfunction ResourceListBody({\n ready,\n variant = \"table\",\n filters = [\"quick\"],\n barFields,\n facetFields,\n columns,\n titleField,\n editable,\n ifMatch,\n sortableOnly,\n sortDropdown = variant !== \"table\",\n urlAdapter,\n prefix,\n defaults,\n searchField,\n renderers,\n onRowClick,\n gridProps,\n}: BodyProps): ReactElement {\n const state = useQueryState(ready, {\n adapter: urlAdapter,\n prefix,\n defaults,\n searchField,\n });\n const { capabilities } = ready;\n const has = (f: (typeof filters)[number]): boolean => filters.includes(f);\n return (\n <Stack spacing={2}>\n <Stack\n direction=\"row\"\n useFlexGap\n sx={{ flexWrap: \"wrap\", gap: 2, alignItems: \"flex-start\" }}\n >\n {has(\"quick\") && (\n <QuickSearch\n fields={state.searchFields}\n value={state.state.q}\n field={state.state.qField}\n onChange={state.setQuickSearch}\n onFieldChange={state.setQuickSearchField}\n />\n )}\n {sortDropdown && (\n <SortDropdown\n ready={ready}\n sort={state.state.sort}\n onChange={state.setSort}\n />\n )}\n {capabilities.archive_restore && (\n <FormControlLabel\n label=\"Include archived\"\n control={\n <Switch\n checked={state.state.includeArchived}\n onChange={(e) => state.setIncludeArchived(e.target.checked)}\n />\n }\n />\n )}\n {capabilities.draft_publish && (\n <FormControlLabel\n label=\"Include drafts\"\n control={\n <Switch\n checked={state.state.includeUnpublished}\n onChange={(e) => state.setIncludeUnpublished(e.target.checked)}\n />\n }\n />\n )}\n </Stack>\n {has(\"bar\") && (\n <FilterBar\n ready={ready}\n filters={state.state.filters}\n onChange={state.setFilters}\n fields={barFields}\n renderers={renderers}\n />\n )}\n {has(\"builder\") && (\n <FilterBuilder\n ready={ready}\n filters={state.state.filters}\n onChange={state.setFilters}\n renderers={renderers}\n />\n )}\n <Stack\n direction=\"row\"\n useFlexGap\n sx={{ gap: 3, alignItems: \"flex-start\" }}\n >\n {has(\"facets\") && (\n <Box sx={{ flex: \"none\", minWidth: \"12rem\" }}>\n <FacetSidebar\n ready={ready}\n filters={state.state.filters}\n onChange={state.setFilters}\n fields={facetFields}\n />\n </Box>\n )}\n <Box sx={{ flex: 1, minWidth: 0 }}>\n {variant === \"table\" ? (\n <DataTableList\n ready={ready}\n state={state}\n columns={columns}\n editable={editable}\n ifMatch={ifMatch}\n sortableOnly={sortableOnly}\n onRowClick={onRowClick}\n renderers={renderers}\n gridProps={gridProps}\n />\n ) : variant === \"loadMore\" ? (\n <LoadMoreList\n ready={ready}\n state={state}\n columns={columns}\n titleField={titleField}\n onRowClick={onRowClick}\n renderers={renderers}\n />\n ) : (\n <CardGridList\n ready={ready}\n state={state}\n columns={columns}\n titleField={titleField}\n onRowClick={onRowClick}\n renderers={renderers}\n />\n )}\n </Box>\n </Stack>\n </Stack>\n );\n}\n\n/** A resource's list, ready to use: filters, sort and paging in the URL, one of three layouts. */\nexport function ResourceList({\n resource,\n apiVersion,\n ...props\n}: ResourceListProps): ReactElement {\n return (\n <ResourceGate name={resource} apiVersion={apiVersion}>\n {(ready) => <ResourceListBody ready={ready} {...props} />}\n </ResourceGate>\n );\n}\n","// Typed reads of the `/stats` and `/predict` bodies (lib-crud-py's\n// `ResourceStatsView` and `PredictionView`). The SDK hands them over as plain\n// JSON, so every member is read defensively and an unexpected shape degrades\n// to an empty value instead of throwing inside a render.\nimport type { JsonObject } from \"@craftainer/crud-sdk\";\n\n/** The time buckets the server aggregates by. */\nexport type Bucket = \"day\" | \"week\" | \"month\";\n\nexport const BUCKETS: readonly Bucket[] = [\"day\", \"week\", \"month\"];\n\nexport interface NumericStat {\n readonly field: string;\n readonly count: number;\n readonly minimum: number | null;\n readonly maximum: number | null;\n readonly average: number | null;\n readonly total: number | null;\n}\n\nexport interface CategoryCount {\n readonly field: string;\n readonly value: string;\n readonly count: number;\n}\n\nexport interface SeriesPoint {\n /** Start of the bucket, an instant (the server's buckets are UTC calendar buckets). */\n readonly at: Date;\n readonly value: number;\n}\n\nexport interface StatsData {\n readonly total: number;\n readonly numeric: readonly NumericStat[];\n readonly categorical: readonly CategoryCount[];\n /** Bucketed record counts; empty unless a bucket was requested. */\n readonly timeSeries: readonly SeriesPoint[];\n}\n\nexport interface PredictionData {\n /** The forecast numeric field; `null` forecasts the record count. */\n readonly field: string | null;\n readonly bucket: string;\n readonly method: string;\n readonly lastKnown: SeriesPoint | null;\n readonly predictions: readonly SeriesPoint[];\n}\n\nconst isObject = (value: unknown): value is JsonObject =>\n typeof value === \"object\" && value !== null && !Array.isArray(value);\n\nconst objects = (value: unknown): JsonObject[] =>\n Array.isArray(value) ? value.filter(isObject) : [];\n\nconst num = (value: unknown): number => (typeof value === \"number\" ? value : 0);\n\nconst numOrNull = (value: unknown): number | null =>\n typeof value === \"number\" ? value : null;\n\nconst text = (value: unknown): string =>\n typeof value === \"string\" ? value : String(value ?? \"\");\n\n/**\n * Parses a bucket start. The server's buckets are UTC; a value without a zone\n * designator is read as UTC rather than as the browser's local time.\n */\nexport function parseInstant(value: unknown): Date | null {\n if (typeof value !== \"string\") return null;\n const zoned = /(?:[zZ]|[+-]\\d{2}(?::?\\d{2})?)$/.test(value);\n const date = new Date(zoned ? value : `${value}Z`);\n return Number.isNaN(date.getTime()) ? null : date;\n}\n\nfunction points(rows: readonly JsonObject[], valueKey: string): SeriesPoint[] {\n const result: SeriesPoint[] = [];\n for (const row of rows) {\n const at = parseInstant(row[\"bucket_start\"]);\n if (at !== null) result.push({ at, value: num(row[valueKey]) });\n }\n return result.sort((a, b) => a.at.getTime() - b.at.getTime());\n}\n\n/** Reads a `/stats` body. */\nexport function parseStats(body: JsonObject): StatsData {\n return {\n total: num(body[\"total\"]),\n numeric: objects(body[\"numeric\"]).map((row) => ({\n field: text(row[\"field\"]),\n count: num(row[\"count\"]),\n minimum: numOrNull(row[\"minimum\"]),\n maximum: numOrNull(row[\"maximum\"]),\n average: numOrNull(row[\"average\"]),\n total: numOrNull(row[\"total\"]),\n })),\n categorical: objects(body[\"categorical\"]).map((row) => ({\n field: text(row[\"field\"]),\n value: text(row[\"value\"]),\n count: num(row[\"count\"]),\n })),\n timeSeries: points(objects(body[\"time_series\"]), \"count\"),\n };\n}\n\nconst pointOf = (value: unknown): SeriesPoint | null => {\n if (!isObject(value)) return null;\n const at = parseInstant(value[\"bucket_start\"]);\n return at === null ? null : { at, value: num(value[\"value\"]) };\n};\n\n/** Reads a `/predict` body. */\nexport function parsePrediction(body: JsonObject): PredictionData {\n const field = body[\"field\"];\n return {\n field: typeof field === \"string\" ? field : null,\n bucket: text(body[\"bucket\"]),\n method: text(body[\"method\"]),\n lastKnown: pointOf(body[\"last_known\"]),\n predictions: points(objects(body[\"predictions\"]), \"value\"),\n };\n}\n\n/** The distinct categorical field names, in first-seen order. */\nexport function categoricalFields(data: StatsData): string[] {\n return [...new Set(data.categorical.map((row) => row.field))];\n}\n\n/**\n * A bucket start as a label, always in UTC: `Jan 5, 2026` for a `day` or\n * `week` bucket, `Jan 2026` for a `month`. `compact` drops the year of a day\n * or week, for axis ticks.\n */\nexport function formatBucket(\n at: Date,\n bucket: string,\n locale: string | undefined,\n compact = false,\n): string {\n const monthly = bucket === \"month\";\n return new Intl.DateTimeFormat(locale, {\n timeZone: \"UTC\",\n month: \"short\",\n ...(monthly || !compact ? { year: \"numeric\" } : {}),\n ...(monthly ? {} : { day: \"numeric\" }),\n }).format(at);\n}\n\nconst round2 = (value: number): number => Math.round(value * 100) / 100;\n\n/** Averages and forecasts are fractional; two decimals read well in a card. */\nexport const rounded = (value: number | null): number | null =>\n value === null ? null : round2(value);\n\nexport interface ForecastSeries {\n /** Every x position, oldest first. */\n readonly at: readonly Date[];\n /** Known values (`null` where only the forecast has a point). */\n readonly known: readonly (number | null)[];\n /** The forecast, anchored at the last known point so the lines meet. */\n readonly forecast: readonly (number | null)[];\n}\n\n/**\n * Lines up the known series and the forecast on one time axis. The positions\n * are the buckets the server returned, so a gap in the history stays a gap and\n * the forecast follows the bucket spacing; nothing is interpolated.\n */\nexport function forecastSeries(\n history: readonly SeriesPoint[],\n prediction: PredictionData,\n): ForecastSeries {\n const known = new Map<number, number>();\n for (const point of history) known.set(point.at.getTime(), point.value);\n const { lastKnown } = prediction;\n if (lastKnown !== null && !known.has(lastKnown.at.getTime())) {\n known.set(lastKnown.at.getTime(), lastKnown.value);\n }\n const projected = new Map<number, number>();\n if (lastKnown !== null) {\n projected.set(lastKnown.at.getTime(), lastKnown.value);\n }\n for (const point of prediction.predictions) {\n projected.set(point.at.getTime(), point.value);\n }\n const times = [...new Set([...known.keys(), ...projected.keys()])].sort(\n (a, b) => a - b,\n );\n return {\n at: times.map((time) => new Date(time)),\n known: times.map((time) => known.get(time) ?? null),\n forecast: times.map((time) => projected.get(time) ?? null),\n };\n}\n","// Pieces the stats and prediction variants share: the capability gate, the\n// query states, the field descriptors for aggregates and the chart colors.\nimport Alert from \"@mui/material/Alert\";\nimport Box from \"@mui/material/Box\";\nimport Typography from \"@mui/material/Typography\";\nimport CircularProgress from \"@mui/material/CircularProgress\";\nimport { useTheme } from \"@mui/material/styles\";\nimport type { UseQueryResult } from \"@tanstack/react-query\";\nimport type { JsonObject } from \"@craftainer/crud-sdk\";\nimport type { ReactElement, ReactNode } from \"react\";\nimport { formatBucket, type NumericStat, type StatsData } from \"./model.ts\";\nimport {\n FieldDisplay,\n ResourceGate,\n humanize,\n type FieldDescriptor,\n type FieldKind,\n type ReadyResource,\n type RendererOverrides,\n} from \"../core/index.ts\";\n\n/** Props every stats and prediction variant takes. */\nexport interface ViewProps {\n /** The manifest resource name (`\"heroes\"`). */\n readonly resource: string;\n readonly apiVersion?: string | undefined;\n /** Field-renderer overrides, passed to every `FieldDisplay` the view renders. */\n readonly renderers?: RendererOverrides | undefined;\n}\n\n/**\n * Loads the resource and renders `children` only when the server offers\n * `capability`; without it the view renders nothing (hidden, not disabled).\n */\nexport function CapabilityGate({\n resource,\n apiVersion,\n capability,\n children,\n}: {\n readonly resource: string;\n readonly apiVersion: string | undefined;\n readonly capability: \"stats\" | \"predict\";\n readonly children: (ready: ReadyResource) => ReactNode;\n}): ReactElement {\n return (\n <ResourceGate name={resource} apiVersion={apiVersion}>\n {(ready) => (ready.capabilities[capability] ? children(ready) : null)}\n </ResourceGate>\n );\n}\n\n/** The loading and error states of one query; `children` gets the body once it is there. */\nexport function QueryBoundary({\n query,\n label,\n children,\n}: {\n readonly query: UseQueryResult<JsonObject>;\n /** What is loading, for the spinner's accessible name (`\"statistics\"`). */\n readonly label: string;\n readonly children: (body: JsonObject) => ReactNode;\n}): ReactElement {\n if (query.data !== undefined) return <>{children(query.data)}</>;\n if (query.error !== null) {\n return <Alert severity=\"warning\">{query.error.message}</Alert>;\n }\n return (\n <Box sx={{ display: \"flex\", justifyContent: \"center\", p: 3 }}>\n <CircularProgress aria-label={`Loading ${label}`} />\n </Box>\n );\n}\n\n/** A descriptor for a field the manifest does not describe (aggregates still have a name). */\nfunction syntheticField(name: string, kind: FieldKind): FieldDescriptor {\n return {\n name,\n label: humanize(name),\n kind,\n format: null,\n nullable: true,\n readOnly: true,\n required: false,\n choices: null,\n itemKind: null,\n constraints: {\n minLength: undefined,\n maxLength: undefined,\n minimum: undefined,\n maximum: undefined,\n pattern: undefined,\n },\n inManifest: false,\n sortable: false,\n filterOps: [],\n numeric: kind === \"number\",\n categorical: kind !== \"number\",\n };\n}\n\n/**\n * The descriptor an aggregate of `name` is displayed with. An average or a\n * forecast of an `integer` field is fractional, so it shows as a `number`.\n */\nexport function aggregateField(\n ready: ReadyResource,\n name: string,\n value: number | null,\n): FieldDescriptor {\n const base = ready.field(name) ?? syntheticField(name, \"number\");\n return base.kind === \"integer\" && value !== null && !Number.isInteger(value)\n ? { ...base, kind: \"number\" }\n : base;\n}\n\n/** The descriptor and wire value a categorical count row is displayed with. */\nexport function categoryField(\n ready: ReadyResource,\n name: string,\n): FieldDescriptor {\n return ready.field(name) ?? syntheticField(name, \"string\");\n}\n\n/** Category values travel as strings; a boolean field's display wants a boolean. */\nexport const categoryValue = (\n field: FieldDescriptor,\n raw: string,\n): string | boolean =>\n field.kind === \"boolean\" ? raw.toLowerCase() === \"true\" : raw;\n\n/** A number rendered by the field's display renderer, at card or table size. */\nexport function Aggregate({\n ready,\n name,\n value,\n renderers,\n}: {\n readonly ready: ReadyResource;\n readonly name: string;\n readonly value: number | null;\n readonly renderers: RendererOverrides | undefined;\n}): ReactElement {\n return (\n <FieldDisplay\n field={aggregateField(ready, name, value)}\n resource={ready.resource.name}\n value={value}\n renderers={renderers}\n />\n );\n}\n\nexport type ChartColors = readonly [\n string,\n string,\n string,\n string,\n string,\n string,\n];\n\n/** The `index`-th color, cycling. */\nexport const colorAt = (colors: ChartColors, index: number): string =>\n colors[index % colors.length] as string;\n\n/** Categorical series colors from the theme: CSS variables when the theme has them, so dark mode follows. */\nexport function useChartColors(): ChartColors {\n const theme = useTheme();\n const palette = (theme.vars ?? theme).palette;\n return [\n palette.primary.main,\n palette.secondary.main,\n palette.info.main,\n palette.warning.main,\n palette.success.main,\n palette.error.main,\n ];\n}\n\n/** Lets the label, number and detail of a card read as one block. */\nexport const kpiValueSx = {\n \"&& > *\": { font: \"inherit\", color: \"inherit\" },\n typography: \"h4\",\n fontVariantNumeric: \"tabular-nums\",\n} as const;\n\n/** The numeric aggregates worth showing: the id column's statistics say nothing. */\nexport const dataStats = (\n ready: ReadyResource,\n stats: StatsData,\n): readonly NumericStat[] =>\n stats.numeric.filter((stat) => stat.field !== ready.resource.id_field);\n\n/**\n * A chart with its accessible name and a visible caption. The charts' own\n * `title` prop would put an `aria-label` on a role-less element, which axe\n * rejects, so the label lives on a `figure`.\n */\nexport function ChartFigure({\n title,\n caption,\n children,\n}: {\n readonly title: string;\n readonly caption: string;\n readonly children: ReactNode;\n}): ReactElement {\n return (\n <Box component=\"figure\" aria-label={title} sx={{ m: 0 }}>\n {children}\n <Typography\n component=\"figcaption\"\n variant=\"caption\"\n color=\"text.secondary\"\n >\n {caption}\n </Typography>\n </Box>\n );\n}\n\n/** The x axis of a chart over UTC buckets: positioned by real time, so gaps stay gaps, and labelled in UTC. */\nexport function timeAxis(\n at: readonly Date[],\n bucket: string,\n locale: string | undefined,\n): {\n scaleType: \"utc\";\n data: Date[];\n tickNumber: number;\n height: number;\n label: string;\n valueFormatter: (value: Date) => string;\n} {\n return {\n scaleType: \"utc\",\n data: [...at],\n tickNumber: 6,\n // Room for tick labels and the axis label; the default height leaves the labels no space.\n height: 56,\n label: \"Bucket start (UTC)\",\n valueFormatter: (value) => formatBucket(value, bucket, locale, true),\n };\n}\n","import Box from \"@mui/material/Box\";\nimport Card from \"@mui/material/Card\";\nimport CardContent from \"@mui/material/CardContent\";\nimport Typography from \"@mui/material/Typography\";\nimport type { ReactElement } from \"react\";\nimport { humanize, type ReadyResource } from \"../core/index.ts\";\nimport { parseStats, rounded, type NumericStat } from \"./model.ts\";\nimport {\n Aggregate,\n dataStats,\n CapabilityGate,\n QueryBoundary,\n kpiValueSx,\n type ViewProps,\n} from \"./shared.tsx\";\n\nfunction Kpi({\n label,\n children,\n detail,\n}: {\n readonly label: string;\n readonly children: ReactElement;\n readonly detail?: ReactElement | undefined;\n}): ReactElement {\n return (\n <Card variant=\"outlined\" component=\"li\" sx={{ listStyle: \"none\" }}>\n <CardContent>\n <Typography component=\"h3\" variant=\"overline\" color=\"text.secondary\">\n {label}\n </Typography>\n <Box sx={kpiValueSx}>{children}</Box>\n {detail}\n </CardContent>\n </Card>\n );\n}\n\nfunction Range({\n ready,\n stat,\n renderers,\n}: {\n readonly ready: ReadyResource;\n readonly stat: NumericStat;\n readonly renderers: ViewProps[\"renderers\"];\n}): ReactElement {\n return (\n <Typography\n variant=\"caption\"\n color=\"text.secondary\"\n sx={{ display: \"flex\", gap: 0.5, alignItems: \"baseline\" }}\n >\n {\"Range\"}\n <Aggregate\n ready={ready}\n name={stat.field}\n value={stat.minimum}\n renderers={renderers}\n />\n {\"to\"}\n <Aggregate\n ready={ready}\n name={stat.field}\n value={stat.maximum}\n renderers={renderers}\n />\n </Typography>\n );\n}\n\nfunction Cards({\n ready,\n renderers,\n}: {\n readonly ready: ReadyResource;\n readonly renderers: ViewProps[\"renderers\"];\n}): ReactElement {\n const query = ready.hooks.useStats();\n return (\n <QueryBoundary query={query} label=\"statistics\">\n {(body) => {\n const stats = parseStats(body);\n return (\n <Box\n component=\"ul\"\n aria-label={`${ready.resource.title} key figures`}\n sx={{\n display: \"grid\",\n gridTemplateColumns: \"repeat(auto-fill, minmax(12rem, 1fr))\",\n gap: 2,\n m: 0,\n p: 0,\n }}\n >\n <Kpi label=\"Records\">\n <Aggregate\n ready={ready}\n name=\"count\"\n value={stats.total}\n renderers={renderers}\n />\n </Kpi>\n {dataStats(ready, stats).map((stat) => (\n <Kpi\n key={stat.field}\n label={`Average ${humanize(stat.field).toLowerCase()}`}\n detail={\n stat.minimum === null || stat.maximum === null ? undefined : (\n <Range ready={ready} stat={stat} renderers={renderers} />\n )\n }\n >\n <Aggregate\n ready={ready}\n name={stat.field}\n value={rounded(stat.average)}\n renderers={renderers}\n />\n </Kpi>\n ))}\n </Box>\n );\n }}\n </QueryBoundary>\n );\n}\n\n/** Variant 1: one card for the record count and one per numeric field (average, with its range). Hidden without the `stats` capability. */\nexport function StatsKpiCards({\n resource,\n apiVersion,\n renderers,\n}: ViewProps): ReactElement {\n return (\n <CapabilityGate\n resource={resource}\n apiVersion={apiVersion}\n capability=\"stats\"\n >\n {(ready) => <Cards ready={ready} renderers={renderers} />}\n </CapabilityGate>\n );\n}\n","import Box from \"@mui/material/Box\";\nimport ToggleButton from \"@mui/material/ToggleButton\";\nimport ToggleButtonGroup from \"@mui/material/ToggleButtonGroup\";\nimport Typography from \"@mui/material/Typography\";\nimport { LineChart } from \"@mui/x-charts/LineChart\";\nimport { useState, type ReactElement } from \"react\";\nimport { useCrud } from \"../core/index.ts\";\nimport { BUCKETS, parseStats, type Bucket } from \"./model.ts\";\nimport {\n CapabilityGate,\n ChartFigure,\n QueryBoundary,\n timeAxis,\n useChartColors,\n type ViewProps,\n} from \"./shared.tsx\";\nimport type { ReadyResource } from \"../core/index.ts\";\n\nexport interface BucketPickerProps {\n readonly value: Bucket;\n readonly onChange: (bucket: Bucket) => void;\n}\n\n/** Day / week / month toggle, labelled and keyboard-operable. */\nexport function BucketPicker({\n value,\n onChange,\n}: BucketPickerProps): ReactElement {\n return (\n <ToggleButtonGroup\n exclusive\n size=\"small\"\n value={value}\n aria-label=\"Bucket size\"\n onChange={(_event, next: Bucket | null) => {\n if (next !== null) onChange(next);\n }}\n >\n {BUCKETS.map((bucket) => (\n <ToggleButton\n key={bucket}\n value={bucket}\n sx={{ color: \"text.primary\" }}\n >\n {bucket}\n </ToggleButton>\n ))}\n </ToggleButtonGroup>\n );\n}\n\nfunction Series({\n ready,\n bucket,\n}: {\n readonly ready: ReadyResource;\n readonly bucket: Bucket;\n}): ReactElement {\n const { locale } = useCrud();\n const [color] = useChartColors();\n const query = ready.hooks.useStats({ bucket });\n return (\n <QueryBoundary query={query} label=\"time series\">\n {(body) => {\n const { timeSeries } = parseStats(body);\n if (timeSeries.length === 0) {\n return (\n <Typography color=\"text.secondary\">\n {\"No records in this period.\"}\n </Typography>\n );\n }\n return (\n <ChartFigure\n title={`${ready.resource.title} created per ${bucket}`}\n caption={`Records created per ${bucket}; buckets are UTC calendar buckets and empty ones are left out.`}\n >\n <LineChart\n height={280}\n skipAnimation\n hideLegend\n xAxis={[\n timeAxis(\n timeSeries.map((point) => point.at),\n bucket,\n locale,\n ),\n ]}\n yAxis={[{ label: \"Records\", min: 0 }]}\n series={[\n {\n id: \"count\",\n label: \"Records\",\n data: timeSeries.map((point) => point.value),\n color,\n showMark: true,\n curve: \"linear\",\n connectNulls: true,\n },\n ]}\n />\n </ChartFigure>\n );\n }}\n </QueryBoundary>\n );\n}\n\nexport interface StatsTimeSeriesProps extends ViewProps {\n /** The initial bucket size. Default `\"day\"`. */\n readonly bucket?: Bucket | undefined;\n}\n\n/**\n * Variant 2: records created per UTC bucket as a line chart, with a\n * day/week/month toggle. Buckets with no records are absent from the server's\n * series and stay absent on the time axis. Hidden without the `stats`\n * capability.\n */\nexport function StatsTimeSeries({\n resource,\n apiVersion,\n bucket: initial = \"day\",\n}: StatsTimeSeriesProps): ReactElement {\n const [bucket, setBucket] = useState<Bucket>(initial);\n return (\n <CapabilityGate\n resource={resource}\n apiVersion={apiVersion}\n capability=\"stats\"\n >\n {(ready) => (\n <Box component=\"section\" aria-label=\"Records over time\">\n <Box sx={{ display: \"flex\", justifyContent: \"flex-end\", mb: 1 }}>\n <BucketPicker value={bucket} onChange={setBucket} />\n </Box>\n <Series ready={ready} bucket={bucket} />\n </Box>\n )}\n </CapabilityGate>\n );\n}\n","import Box from \"@mui/material/Box\";\nimport MenuItem from \"@mui/material/MenuItem\";\nimport TextField from \"@mui/material/TextField\";\nimport ToggleButton from \"@mui/material/ToggleButton\";\nimport ToggleButtonGroup from \"@mui/material/ToggleButtonGroup\";\nimport Typography from \"@mui/material/Typography\";\nimport { BarChart } from \"@mui/x-charts/BarChart\";\nimport { PieChart } from \"@mui/x-charts/PieChart\";\nimport { useState, type ReactElement } from \"react\";\nimport { humanize, type ReadyResource } from \"../core/index.ts\";\nimport { categoricalFields, parseStats, type StatsData } from \"./model.ts\";\nimport {\n CapabilityGate,\n ChartFigure,\n colorAt,\n QueryBoundary,\n useChartColors,\n type ViewProps,\n} from \"./shared.tsx\";\n\nexport type CategoryChartKind = \"bar\" | \"pie\";\n\n/** `true` / `false` and enum values, as a chart label. */\nconst labelOf = (raw: string): string => humanize(raw);\n\nfunction Chart({\n ready,\n stats,\n field,\n kind,\n}: {\n readonly ready: ReadyResource;\n readonly stats: StatsData;\n readonly field: string;\n readonly kind: CategoryChartKind;\n}): ReactElement {\n const colors = useChartColors();\n const rows = stats.categorical.filter((row) => row.field === field);\n const title = `${ready.resource.title} by ${humanize(field).toLowerCase()}`;\n const caption = `Number of records for each value of ${humanize(field)}.`;\n if (kind === \"pie\") {\n return (\n <ChartFigure title={title} caption={caption}>\n <PieChart\n height={280}\n skipAnimation\n series={[\n {\n innerRadius: 40,\n paddingAngle: 2,\n data: rows.map((row, index) => ({\n id: row.value,\n label: labelOf(row.value),\n value: row.count,\n color: colorAt(colors, index),\n })),\n },\n ]}\n />\n </ChartFigure>\n );\n }\n return (\n <ChartFigure title={title} caption={caption}>\n <BarChart\n height={280}\n skipAnimation\n hideLegend\n xAxis={[\n {\n scaleType: \"band\",\n data: rows.map((row) => labelOf(row.value)),\n colorMap: {\n type: \"ordinal\",\n values: rows.map((row) => labelOf(row.value)),\n colors: rows.map((_row, index) => colorAt(colors, index)),\n },\n },\n ]}\n yAxis={[{ label: \"Records\", min: 0 }]}\n series={[\n { id: \"count\", label: \"Records\", data: rows.map((r) => r.count) },\n ]}\n />\n </ChartFigure>\n );\n}\n\nfunction Panel({\n ready,\n kind,\n initialField,\n}: {\n readonly ready: ReadyResource;\n readonly kind: CategoryChartKind;\n readonly initialField: string | undefined;\n}): ReactElement {\n const [chosen, setChosen] = useState<string | undefined>(initialField);\n const [shape, setShape] = useState<CategoryChartKind>(kind);\n const query = ready.hooks.useStats();\n return (\n <QueryBoundary query={query} label=\"distribution\">\n {(body) => {\n const stats = parseStats(body);\n const fields = categoricalFields(stats);\n const field =\n chosen !== undefined && fields.includes(chosen) ? chosen : fields[0];\n if (field === undefined) {\n return (\n <Typography color=\"text.secondary\">\n {\"No categorical fields to chart.\"}\n </Typography>\n );\n }\n return (\n <>\n <Box\n sx={{\n display: \"flex\",\n flexWrap: \"wrap\",\n gap: 2,\n justifyContent: \"space-between\",\n mb: 1,\n }}\n >\n <TextField\n select\n size=\"small\"\n label=\"Field\"\n value={field}\n sx={{ minWidth: \"12rem\" }}\n onChange={(event) => setChosen(event.target.value)}\n >\n {fields.map((name) => (\n <MenuItem key={name} value={name}>\n {humanize(name)}\n </MenuItem>\n ))}\n </TextField>\n <ToggleButtonGroup\n exclusive\n size=\"small\"\n value={shape}\n aria-label=\"Chart type\"\n onChange={(_event, next: CategoryChartKind | null) => {\n if (next !== null) setShape(next);\n }}\n >\n <ToggleButton value=\"bar\" sx={{ color: \"text.primary\" }}>\n {\"Bar\"}\n </ToggleButton>\n <ToggleButton value=\"pie\" sx={{ color: \"text.primary\" }}>\n {\"Pie\"}\n </ToggleButton>\n </ToggleButtonGroup>\n </Box>\n <Chart ready={ready} stats={stats} field={field} kind={shape} />\n </>\n );\n }}\n </QueryBoundary>\n );\n}\n\nexport interface StatsCategoryChartProps extends ViewProps {\n /** The initial chart. Default `\"bar\"`. */\n readonly kind?: CategoryChartKind | undefined;\n /** The categorical field shown first. Default: the first the server reports. */\n readonly field?: string | undefined;\n}\n\n/**\n * Variant 3: the value distribution of a boolean or enum field as a bar or pie\n * chart, with a field picker and a chart-type toggle. Hidden without the\n * `stats` capability.\n */\nexport function StatsCategoryChart({\n resource,\n apiVersion,\n kind = \"bar\",\n field,\n}: StatsCategoryChartProps): ReactElement {\n return (\n <CapabilityGate\n resource={resource}\n apiVersion={apiVersion}\n capability=\"stats\"\n >\n {(ready) => (\n <Box component=\"section\" aria-label=\"Distribution\">\n <Panel ready={ready} kind={kind} initialField={field} />\n </Box>\n )}\n </CapabilityGate>\n );\n}\n","import Box from \"@mui/material/Box\";\nimport Table from \"@mui/material/Table\";\nimport TableBody from \"@mui/material/TableBody\";\nimport TableCell from \"@mui/material/TableCell\";\nimport TableContainer from \"@mui/material/TableContainer\";\nimport TableHead from \"@mui/material/TableHead\";\nimport TableRow from \"@mui/material/TableRow\";\nimport Typography from \"@mui/material/Typography\";\nimport type { ReactElement } from \"react\";\nimport { FieldDisplay, humanize, type ReadyResource } from \"../core/index.ts\";\nimport { parseStats, rounded } from \"./model.ts\";\nimport {\n Aggregate,\n dataStats,\n CapabilityGate,\n QueryBoundary,\n categoryField,\n categoryValue,\n type ViewProps,\n} from \"./shared.tsx\";\n\nfunction Panel({\n ready,\n renderers,\n}: {\n readonly ready: ReadyResource;\n readonly renderers: ViewProps[\"renderers\"];\n}): ReactElement {\n const query = ready.hooks.useStats();\n return (\n <QueryBoundary query={query} label=\"statistics\">\n {(body) => {\n const stats = parseStats(body);\n return (\n <Box sx={{ display: \"grid\", gap: 3 }}>\n <TableContainer component=\"section\" aria-label=\"Numeric fields\">\n <Typography component=\"h3\" variant=\"h6\" sx={{ mb: 1 }}>\n {\"Numeric fields\"}\n </Typography>\n <Table size=\"small\" aria-label=\"Numeric field statistics\">\n <TableHead>\n <TableRow>\n <TableCell>{\"Field\"}</TableCell>\n <TableCell align=\"right\">{\"Count\"}</TableCell>\n <TableCell align=\"right\">{\"Minimum\"}</TableCell>\n <TableCell align=\"right\">{\"Maximum\"}</TableCell>\n <TableCell align=\"right\">{\"Average\"}</TableCell>\n <TableCell align=\"right\">{\"Total\"}</TableCell>\n </TableRow>\n </TableHead>\n <TableBody>\n {dataStats(ready, stats).map((stat) => (\n <TableRow key={stat.field}>\n <TableCell component=\"th\" scope=\"row\">\n {humanize(stat.field)}\n </TableCell>\n <TableCell align=\"right\">{stat.count}</TableCell>\n {(\n [\n stat.minimum,\n stat.maximum,\n stat.average,\n stat.total,\n ] as const\n ).map((value, index) => (\n <TableCell key={index} align=\"right\">\n <Aggregate\n ready={ready}\n name={stat.field}\n value={rounded(value)}\n renderers={renderers}\n />\n </TableCell>\n ))}\n </TableRow>\n ))}\n </TableBody>\n </Table>\n </TableContainer>\n <TableContainer component=\"section\" aria-label=\"Value counts\">\n <Typography component=\"h3\" variant=\"h6\" sx={{ mb: 1 }}>\n {\"Value counts\"}\n </Typography>\n <Table size=\"small\" aria-label=\"Categorical value counts\">\n <TableHead>\n <TableRow>\n <TableCell>{\"Field\"}</TableCell>\n <TableCell>{\"Value\"}</TableCell>\n <TableCell align=\"right\">{\"Records\"}</TableCell>\n </TableRow>\n </TableHead>\n <TableBody>\n {stats.categorical.map((row) => {\n const field = categoryField(ready, row.field);\n return (\n <TableRow key={`${row.field}:${row.value}`}>\n <TableCell component=\"th\" scope=\"row\">\n {field.label}\n </TableCell>\n <TableCell>\n <FieldDisplay\n field={field}\n resource={ready.resource.name}\n value={categoryValue(field, row.value)}\n renderers={renderers}\n />\n </TableCell>\n <TableCell align=\"right\">{row.count}</TableCell>\n </TableRow>\n );\n })}\n </TableBody>\n </Table>\n </TableContainer>\n </Box>\n );\n }}\n </QueryBoundary>\n );\n}\n\n/**\n * Variant 4: two tables, the numeric aggregates of every numeric field and\n * the value counts of every categorical field. Values go through the field\n * renderers. Hidden without the `stats` capability.\n */\nexport function StatsTablePanel({\n resource,\n apiVersion,\n renderers,\n}: ViewProps): ReactElement {\n return (\n <CapabilityGate\n resource={resource}\n apiVersion={apiVersion}\n capability=\"stats\"\n >\n {(ready) => <Panel ready={ready} renderers={renderers} />}\n </CapabilityGate>\n );\n}\n","import Box from \"@mui/material/Box\";\nimport Typography from \"@mui/material/Typography\";\nimport type { ReactElement, ReactNode } from \"react\";\nimport { CapabilityGate, type ViewProps } from \"./shared.tsx\";\nimport { StatsCategoryChart } from \"./StatsCategoryChart.tsx\";\nimport { StatsKpiCards } from \"./StatsKpiCards.tsx\";\nimport { StatsTablePanel } from \"./StatsTablePanel.tsx\";\nimport { StatsTimeSeries } from \"./StatsTimeSeries.tsx\";\n\nexport function Section({\n title,\n children,\n}: {\n readonly title: string;\n readonly children: ReactNode;\n}): ReactElement {\n return (\n <Box component=\"section\" aria-label={title}>\n <Typography component=\"h2\" variant=\"h6\" sx={{ mb: 1 }}>\n {title}\n </Typography>\n {children}\n </Box>\n );\n}\n\n/** All four statistics variants on one page. Hidden without the `stats` capability. */\nexport function StatsDashboard(props: ViewProps): ReactElement {\n return (\n <CapabilityGate\n resource={props.resource}\n apiVersion={props.apiVersion}\n capability=\"stats\"\n >\n {() => (\n <Box sx={{ display: \"grid\", gap: 4 }}>\n <StatsKpiCards {...props} />\n <Box\n sx={{\n display: \"grid\",\n gap: 3,\n gridTemplateColumns: { xs: \"1fr\", md: \"1fr 1fr\" },\n }}\n >\n <Section title=\"Over time\">\n <StatsTimeSeries {...props} />\n </Section>\n <Section title=\"By category\">\n <StatsCategoryChart {...props} />\n </Section>\n </Box>\n <StatsTablePanel {...props} />\n </Box>\n )}\n </CapabilityGate>\n );\n}\n","import type { ReactElement, ReactNode } from \"react\";\nimport type { ReadyResource } from \"../core/index.ts\";\nimport { parsePrediction, type Bucket, type PredictionData } from \"./model.ts\";\nimport { CapabilityGate, QueryBoundary, type ViewProps } from \"./shared.tsx\";\n\n/** What `/predict` is asked: a numeric field (default the record count), how many buckets ahead, and the bucket size. */\nexport interface PredictionQuery {\n /** A numeric field to forecast the per-bucket sum of; omit to forecast the record count. */\n readonly field?: string | undefined;\n /** Buckets to project, 1 to 52. Default 4. */\n readonly periods?: number | undefined;\n /** Default `\"day\"`. */\n readonly bucket?: Bucket | undefined;\n}\n\nexport type PredictionProps = ViewProps & PredictionQuery;\n\nconst DEFAULT_PERIODS = 4;\n\n/** The `/predict` request for a view's props. */\nexport function predictionRequest(query: PredictionQuery): {\n field?: string;\n periods: number;\n bucket: Bucket;\n} {\n return {\n ...(query.field === undefined ? {} : { field: query.field }),\n periods: query.periods ?? DEFAULT_PERIODS,\n bucket: query.bucket ?? \"day\",\n };\n}\n\nfunction Loaded({\n ready,\n query,\n children,\n}: {\n readonly ready: ReadyResource;\n readonly query: PredictionQuery;\n readonly children: (\n prediction: PredictionData,\n ready: ReadyResource,\n ) => ReactNode;\n}): ReactElement {\n const result = ready.hooks.usePredict(predictionRequest(query));\n return (\n <QueryBoundary query={result} label=\"forecast\">\n {(body) => children(parsePrediction(body), ready)}\n </QueryBoundary>\n );\n}\n\n/**\n * The gate of every prediction variant: hidden without the `predict`\n * capability; otherwise `children` gets the parsed forecast. A resource with\n * too little history answers 422 and the server's message shows as a warning.\n */\nexport function PredictionBoundary({\n resource,\n apiVersion,\n query,\n children,\n}: {\n readonly resource: string;\n readonly apiVersion: string | undefined;\n readonly query: PredictionQuery;\n readonly children: (\n prediction: PredictionData,\n ready: ReadyResource,\n ) => ReactNode;\n}): ReactElement {\n return (\n <CapabilityGate\n resource={resource}\n apiVersion={apiVersion}\n capability=\"predict\"\n >\n {(ready) => (\n <Loaded ready={ready} query={query}>\n {children}\n </Loaded>\n )}\n </CapabilityGate>\n );\n}\n","import Box from \"@mui/material/Box\";\nimport { LineChart } from \"@mui/x-charts/LineChart\";\nimport type { ReactElement, ReactNode } from \"react\";\nimport { humanize, useCrud, type ReadyResource } from \"../core/index.ts\";\nimport {\n forecastSeries,\n parseStats,\n type PredictionData,\n type SeriesPoint,\n} from \"./model.ts\";\nimport {\n PredictionBoundary,\n predictionRequest,\n type PredictionProps,\n} from \"./predictShared.tsx\";\nimport { ChartFigure, timeAxis, useChartColors } from \"./shared.tsx\";\n\nfunction Plot({\n ready,\n prediction,\n history,\n}: {\n readonly ready: ReadyResource;\n readonly prediction: PredictionData;\n readonly history: readonly SeriesPoint[];\n}): ReactElement {\n const { locale } = useCrud();\n const [knownColor, forecastColor] = useChartColors();\n const series = forecastSeries(history, prediction);\n const what =\n prediction.field === null ? \"Records\" : humanize(prediction.field);\n return (\n <ChartFigure\n title={`${ready.resource.title}: ${what.toLowerCase()} per ${prediction.bucket} with forecast`}\n caption={`Dashed: ${prediction.predictions.length} ${prediction.bucket} buckets forecast by ${prediction.method.replace(\"_\", \" \")} over the bucket sequence; buckets are UTC.`}\n >\n <LineChart\n height={300}\n skipAnimation\n xAxis={[timeAxis(series.at, prediction.bucket, locale)]}\n yAxis={[{ label: what }]}\n series={[\n {\n id: \"known\",\n label: \"Known\",\n data: [...series.known],\n color: knownColor,\n showMark: true,\n curve: \"linear\",\n connectNulls: true,\n },\n {\n id: \"forecast\",\n label: \"Forecast\",\n data: [...series.forecast],\n color: forecastColor,\n showMark: true,\n curve: \"linear\",\n },\n ]}\n sx={{ '& [data-series=\"forecast\"]': { strokeDasharray: \"6 4\" } }}\n />\n </ChartFigure>\n );\n}\n\n/** Loads the count history when the forecast is of the record count and the server serves `stats`. */\nfunction WithHistory({\n ready,\n bucket,\n children,\n}: {\n readonly ready: ReadyResource;\n readonly bucket: \"day\" | \"week\" | \"month\";\n readonly children: (history: readonly SeriesPoint[]) => ReactNode;\n}): ReactElement {\n const query = ready.hooks.useStats({ bucket });\n return (\n <>\n {children(\n query.data === undefined ? [] : parseStats(query.data).timeSeries,\n )}\n </>\n );\n}\n\n/**\n * Predictions variant 1: a line chart of the known series and the forecast\n * after it. The history is the server's count series, so it is drawn only\n * when the forecast is of the record count (no `field`) and `stats` is\n * available; a field forecast shows its last known value and the projection.\n * Hidden without the `predict` capability.\n */\nexport function PredictionChart(props: PredictionProps): ReactElement {\n const { resource, apiVersion } = props;\n const { bucket } = predictionRequest(props);\n return (\n <PredictionBoundary\n resource={resource}\n apiVersion={apiVersion}\n query={props}\n >\n {(prediction, ready) => (\n <Box component=\"section\" aria-label=\"Forecast chart\">\n {prediction.field === null && ready.capabilities.stats ? (\n <WithHistory ready={ready} bucket={bucket}>\n {(history) => (\n <Plot ready={ready} prediction={prediction} history={history} />\n )}\n </WithHistory>\n ) : (\n <Plot ready={ready} prediction={prediction} history={[]} />\n )}\n </Box>\n )}\n </PredictionBoundary>\n );\n}\n","import Table from \"@mui/material/Table\";\nimport TableBody from \"@mui/material/TableBody\";\nimport TableCell from \"@mui/material/TableCell\";\nimport TableContainer from \"@mui/material/TableContainer\";\nimport TableHead from \"@mui/material/TableHead\";\nimport TableRow from \"@mui/material/TableRow\";\nimport type { ReactElement } from \"react\";\nimport { humanize, useCrud } from \"../core/index.ts\";\nimport { formatBucket, rounded } from \"./model.ts\";\nimport { PredictionBoundary, type PredictionProps } from \"./predictShared.tsx\";\nimport { Aggregate } from \"./shared.tsx\";\n\n/**\n * Predictions variant 2: the last known value and every forecast bucket as a\n * table, values shown by the field's renderer. Hidden without the `predict`\n * capability.\n */\nexport function PredictionTable(props: PredictionProps): ReactElement {\n const { locale } = useCrud();\n return (\n <PredictionBoundary\n resource={props.resource}\n apiVersion={props.apiVersion}\n query={props}\n >\n {(prediction, ready) => {\n const name = prediction.field ?? \"count\";\n const rows = [\n ...(prediction.lastKnown === null\n ? []\n : [{ kind: \"Last known\", point: prediction.lastKnown }]),\n ...prediction.predictions.map((point) => ({\n kind: \"Forecast\",\n point,\n })),\n ];\n return (\n <TableContainer component=\"section\" aria-label=\"Forecast table\">\n <Table\n size=\"small\"\n aria-label={`Forecast of ${prediction.field === null ? \"records\" : humanize(prediction.field).toLowerCase()} per ${prediction.bucket}`}\n >\n <TableHead>\n <TableRow>\n <TableCell>{`${humanize(prediction.bucket)} starting (UTC)`}</TableCell>\n <TableCell>{\"Kind\"}</TableCell>\n <TableCell align=\"right\">\n {prediction.field === null\n ? \"Records\"\n : humanize(prediction.field)}\n </TableCell>\n </TableRow>\n </TableHead>\n <TableBody>\n {rows.map(({ kind, point }) => (\n <TableRow key={`${kind}:${point.at.toISOString()}`}>\n <TableCell component=\"th\" scope=\"row\">\n {formatBucket(point.at, prediction.bucket, locale)}\n </TableCell>\n <TableCell>{kind}</TableCell>\n <TableCell align=\"right\">\n <Aggregate\n ready={ready}\n name={name}\n value={rounded(point.value)}\n renderers={props.renderers}\n />\n </TableCell>\n </TableRow>\n ))}\n </TableBody>\n </Table>\n </TableContainer>\n );\n }}\n </PredictionBoundary>\n );\n}\n","import Box from \"@mui/material/Box\";\nimport Card from \"@mui/material/Card\";\nimport CardContent from \"@mui/material/CardContent\";\nimport Typography from \"@mui/material/Typography\";\nimport type { ReactElement } from \"react\";\nimport { humanize, useCrud } from \"../core/index.ts\";\nimport { formatBucket, rounded } from \"./model.ts\";\nimport { PredictionBoundary, type PredictionProps } from \"./predictShared.tsx\";\nimport { Aggregate, kpiValueSx } from \"./shared.tsx\";\n\n/**\n * Predictions variant 3: a card with the first forecast bucket's value and how\n * it moves from the last known one. Hidden without the `predict` capability.\n */\nexport function PredictionKpi(props: PredictionProps): ReactElement {\n const { locale } = useCrud();\n return (\n <PredictionBoundary\n resource={props.resource}\n apiVersion={props.apiVersion}\n query={props}\n >\n {(prediction, ready) => {\n const next = prediction.predictions[0];\n const name = prediction.field ?? \"count\";\n const what =\n prediction.field === null\n ? \"records\"\n : humanize(prediction.field).toLowerCase();\n if (next === undefined) {\n return (\n <Typography color=\"text.secondary\">\n {\"The server returned no forecast.\"}\n </Typography>\n );\n }\n const delta =\n prediction.lastKnown === null\n ? null\n : rounded(next.value - prediction.lastKnown.value);\n return (\n <Card\n variant=\"outlined\"\n component=\"section\"\n aria-label=\"Next period forecast\"\n >\n <CardContent>\n <Typography\n component=\"h3\"\n variant=\"overline\"\n color=\"text.secondary\"\n >\n {`Next ${prediction.bucket}: ${what}`}\n </Typography>\n <Box sx={kpiValueSx}>\n <Aggregate\n ready={ready}\n name={name}\n value={rounded(next.value)}\n renderers={props.renderers}\n />\n </Box>\n <Typography\n variant=\"caption\"\n color=\"text.secondary\"\n sx={{ display: \"block\" }}\n >\n {`Bucket starting ${formatBucket(next.at, prediction.bucket, locale)} (UTC)`}\n </Typography>\n {delta === null ? null : (\n <Typography\n variant=\"caption\"\n color=\"text.secondary\"\n sx={{ display: \"flex\", gap: 0.5, alignItems: \"baseline\" }}\n >\n {delta < 0 ? \"Down\" : \"Up\"}\n <Aggregate\n ready={ready}\n name={name}\n value={Math.abs(delta)}\n renderers={props.renderers}\n />\n {\"from the last known\"}\n </Typography>\n )}\n </CardContent>\n </Card>\n );\n }}\n </PredictionBoundary>\n );\n}\n","import Box from \"@mui/material/Box\";\nimport MenuItem from \"@mui/material/MenuItem\";\nimport TextField from \"@mui/material/TextField\";\nimport { useState, type ReactElement } from \"react\";\nimport type { Bucket } from \"./model.ts\";\nimport { PredictionChart } from \"./PredictionChart.tsx\";\nimport { PredictionKpi } from \"./PredictionKpi.tsx\";\nimport { PredictionTable } from \"./PredictionTable.tsx\";\nimport { CapabilityGate, type ViewProps } from \"./shared.tsx\";\nimport { BucketPicker } from \"./StatsTimeSeries.tsx\";\nimport { Section } from \"./StatsDashboard.tsx\";\n\nconst COUNT = \"\";\n\n/** The server accepts 1 to 52 buckets ahead. */\nconst isPeriods = (n: number): boolean =>\n Number.isInteger(n) && n >= 1 && n <= 52;\n\n/** All three prediction variants with the controls that drive them (field, buckets ahead, bucket size). Hidden without the `predict` capability. */\nexport function PredictionsDashboard(props: ViewProps): ReactElement {\n const [field, setField] = useState(COUNT);\n const [periods, setPeriods] = useState(4);\n const [periodsText, setPeriodsText] = useState(\"4\");\n const periodsValid = isPeriods(Number(periodsText));\n const [bucket, setBucket] = useState<Bucket>(\"day\");\n const query = { field: field === COUNT ? undefined : field, periods, bucket };\n return (\n <CapabilityGate\n resource={props.resource}\n apiVersion={props.apiVersion}\n capability=\"predict\"\n >\n {(ready) => (\n <Box sx={{ display: \"grid\", gap: 3 }}>\n <Box\n component=\"form\"\n aria-label=\"Forecast settings\"\n onSubmit={(event) => event.preventDefault()}\n sx={{\n display: \"flex\",\n flexWrap: \"wrap\",\n gap: 2,\n alignItems: \"center\",\n }}\n >\n <TextField\n select\n size=\"small\"\n label=\"Forecast\"\n value={field}\n sx={{ minWidth: \"12rem\" }}\n onChange={(event) => setField(event.target.value)}\n >\n <MenuItem value={COUNT}>{\"Record count\"}</MenuItem>\n {ready.fields\n .filter((f) => f.numeric && f.name !== ready.resource.id_field)\n .map((f) => (\n <MenuItem key={f.name} value={f.name}>\n {`Sum of ${f.label.toLowerCase()}`}\n </MenuItem>\n ))}\n </TextField>\n <TextField\n size=\"small\"\n type=\"number\"\n label=\"Buckets ahead\"\n value={periodsText}\n error={!periodsValid}\n helperText={periodsValid ? undefined : \"1 to 52\"}\n slotProps={{ htmlInput: { min: 1, max: 52 } }}\n sx={{ width: \"9rem\" }}\n onChange={(event) => {\n setPeriodsText(event.target.value);\n const next = Number(event.target.value);\n if (isPeriods(next)) setPeriods(next);\n }}\n />\n <BucketPicker value={bucket} onChange={setBucket} />\n </Box>\n <Box\n sx={{\n display: \"grid\",\n gap: 3,\n gridTemplateColumns: { xs: \"1fr\", md: \"2fr 1fr\" },\n }}\n >\n <Section title=\"Forecast\">\n <PredictionChart {...props} {...query} />\n </Section>\n <Box sx={{ display: \"grid\", gap: 3, alignContent: \"start\" }}>\n <PredictionKpi {...props} {...query} />\n <PredictionTable {...props} {...query} />\n </Box>\n </Box>\n </Box>\n )}\n </CapabilityGate>\n );\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAmBA,MAAa,iBACX,cAAuC,IAAI;;AAG7C,SAAgB,UAA4B;CAC1C,MAAM,QAAQ,WAAW,cAAc;CACvC,IAAI,UAAU,MACZ,MAAM,IAAI,MAAM,4CAA4C;CAE9D,OAAO;AACT;;AAGA,SAAgB,YAGd;CACA,MAAM,QAAQ,WAAW,cAAc;CACvC,OAAO;EAAE,QAAQ,OAAO;EAAQ,UAAU,OAAO;CAAS;AAC5D;;;;ACjBA,SAAgB,aAAa,EAC3B,QACA,aACA,OACA,WACA,QAAQ,IACR,QACA,UACA,YACkC;CAClC,MAAM,QAAQ,eACL;EAAE;EAAQ;EAAa;EAAO;EAAQ;EAAU;CAAU,IACjE;EAAC;EAAQ;EAAa;EAAO;EAAQ;EAAU;CAAS,CAC1D;CACA,MAAM,OACJ,oBAAC,qBAAD;EAAqB,QAAQ;EAC3B,UAAA,oBAAC,eAAe,UAAhB;GAAgC;GAC7B;EACsB,CAAA;CACN,CAAA;CAEvB,OAAO,UAAU,KAAA,IACf,OAEA,oBAAC,eAAD;EAAsB;EAAQ,UAAA;CAAoB,CAAA;AAEtD;;;ACrCA,MAAMA,cAAY,UAChB,OAAO,UAAU,YAAY,UAAU,QAAQ,CAAC,MAAM,QAAQ,KAAK;AAErE,MAAM,QAA2B;CAC/B;CACA;CACA;CACA;CACA;CACA;CACA;AACF;;AAGA,SAAgB,SAAS,MAAsB;CAC7C,MAAM,QAAQ,KAAK,QAAQ,UAAU,GAAG,CAAC,CAAC,KAAK;CAC/C,OAAO,MAAM,OAAO,CAAC,CAAC,CAAC,YAAY,IAAI,MAAM,MAAM,CAAC;AACtD;;AAYA,SAAS,gBAAgB,SAAyB;CAChD,IAAI,UAAU;CACd,IAAI;EACF,UAAU,mBAAmB,OAAO;CACtC,QAAQ,CAER;CACA,OAAO,QAAQ,QAAQ,OAAO,GAAG,CAAC,CAAC,QAAQ,OAAO,GAAG;AACvD;;;;;;AAOA,SAAS,WACP,MACA,MACA,uBAA4B,IAAI,IAAI,GACxB;CACZ,MAAM,MAAM,KAAK;CACjB,IAAI,OAAO,QAAQ,YAAY,CAAC,IAAI,WAAW,IAAI,KAAK,KAAK,IAAI,GAAG,GAClE,OAAO;CAET,IAAI,SAAkB;CACtB,KAAK,MAAM,QAAQ,IAAI,MAAM,CAAC,CAAC,CAAC,MAAM,GAAG,CAAC,CAAC,IAAI,eAAe,GAC5D,SAASA,WAAS,MAAM,IAAI,IAAI,QAAQ,IAAI,IAAI,KAAA;CAElD,IAAI,CAACA,WAAS,MAAM,GAAG,OAAO;CAE9B,OAAO;EAAE,GADQ,WAAW,QAAQ,sBAAM,IAAI,IAAI,CAAC,GAAG,MAAM,GAAG,CAAC,CAC7C;EAAG,GAAG;EAAM,MAAM,KAAA;CAAU;AACjD;AAEA,MAAMC,SAAO,UACX,OAAO,UAAU,WAAW,QAAQ,KAAA;;AAGtC,SAAS,SAAS,KAAc,MAAwB;CACtD,IAAI,OAAOD,WAAS,GAAG,IAAI,WAAW,KAAK,IAAI,IAAI,CAAC;CACpD,IAAI,WAAW;CACf,MAAM,WAAW,KAAK,YAAY,KAAK;CACvC,IAAI,MAAM,QAAQ,QAAQ,GAAG;EAC3B,MAAM,WAAW,SACd,OAAOA,UAAQ,CAAC,CAChB,KAAK,YAAY,WAAW,SAAS,IAAI,CAAC;EAC7C,MAAM,OAAO,SAAS,QAAQ,YAAY,QAAQ,YAAY,MAAM;EACpE,WAAW,KAAK,SAAS,SAAS;EAClC,OAAO;GAAE,GAAG;GAAM,GAAG,KAAK;EAAG;CAC/B;CACA,IAAI,OAAO,KAAK;CAChB,IAAI,MAAM,QAAQ,IAAI,GAAG;EACvB,WAAW,YAAY,KAAK,SAAS,MAAM;EAC3C,OAAO,KAAK,MAAM,MAAM,MAAM,MAAM;CACtC,OAAO,IAAI,SAAS,QAAQ;EAC1B,WAAW;EACX,OAAO,KAAA;CACT;CACA,MAAM,aAAa,KAAK;CACxB,OAAO;EACL,MAAM,OAAO,SAAS,WAAW,OAAO,KAAA;EACxC,QAAQ,OAAO,KAAK,cAAc,WAAW,KAAK,YAAY,KAAA;EAC9D,SAAS,MAAM,QAAQ,UAAU,IAC7B,WAAW,QAAQ,MAAmB,OAAO,MAAM,QAAQ,IAC3D,KAAA;EACJ;EACA,OAAOA,WAAS,KAAK,QAAQ,IAAI,KAAK,WAAW,KAAA;EACjD,aAAa;GACX,WAAWC,MAAI,KAAK,YAAY;GAChC,WAAWA,MAAI,KAAK,YAAY;GAChC,SAASA,MAAI,KAAK,UAAU;GAC5B,SAASA,MAAI,KAAK,UAAU;GAC5B,SACE,OAAO,KAAK,eAAe,WAAW,KAAK,aAAa,KAAA;EAC5D;CACF;AACF;AAEA,SAAS,WAAW,MAAuB;CACzC,IAAI,KAAK,YAAY,KAAA,KAAa,KAAK,QAAQ,SAAS,GAAG,OAAO;CAClE,QAAQ,KAAK,MAAb;EACE,KAAK,UACH,OAAO,KAAK,WAAW,SACnB,SACA,KAAK,WAAW,cACd,aACA;EACR,KAAK;EACL,KAAK;EACL,KAAK,WACH,OAAO,KAAK;EACd,KAAK,SACH,OAAO;EACT,SACE,OAAO;CACX;AACF;AAEA,SAAS,WAAW,QAAgC;CAClD,MAAM,QAAQ,OAAO;CACrB,OAAOD,WAAS,KAAK,IAAI,QAAQ,CAAC;AACpC;;AAGA,SAAS,IAAI,OAAmB,MAAuB;CACrD,OAAO,OAAO,OAAO,OAAO,IAAI,IAAI,MAAM,QAAQ,KAAA;AACpD;AAEA,SAAS,YAAY,QAAyC;CAC5D,MAAM,OAAO,OAAO;CACpB,OAAO,IAAI,IACT,MAAM,QAAQ,IAAI,IACd,KAAK,QAAQ,MAAmB,OAAO,MAAM,QAAQ,IACrD,CAAC,CACP;AACF;AAEA,SAAS,SACP,MACA,MACA,MACA,QACA,QACiB;CACjB,MAAM,CAAC,OAAO,SAAS,WAAW;EAAC;EAAM;EAAQ;CAAM,CAAC,CAAC,IAAI,UAAU;CAMvE,MAAM,CAAC,KAAK,QACV,IAAI,OAAO,IAAI,MAAM,KAAA,IACjB,CAAC,IAAI,OAAO,IAAI,GAAG,IAAI,IACvB,IAAI,SAAS,IAAI,MAAM,KAAA,IACrB,CAAC,IAAI,SAAS,IAAI,GAAG,MAAM,IAC3B,CAAC,IAAI,SAAS,IAAI,GAAG,MAAM;CACnC,MAAM,OAAO,SAAS,KAAK,IAAI;CAC/B,MAAM,OACJ,SAAS,KAAA,IACL,WAAW,IAAI,IACf,MAAM,SAAS,KAAK,UAAU,IAC3B,KAAK,aACN;CACR,MAAM,WAAW,SAAS,KAAK,OAAO,IAAI;CAC1C,OAAO;EACL;EACA,OAAO,SAAS,IAAI;EACpB;EACA,QAAQ,KAAK,UAAU;EACvB,UAAU,KAAK;EACf,UAAU,EAAE,OAAO,OAAO,SAAS,IAAI,KAAK,OAAO,OAAO,SAAS,IAAI;EACvE,UACE,SAAS,KAAA,IAAY,YAAY,MAAM,CAAC,CAAC,IAAI,IAAI,IAAI,KAAK;EAC5D,SAAS,MAAM,WAAW,KAAK,WAAW;EAC1C,UAAU,SAAS,UAAU,WAAW,QAAQ,IAAI;EACpD,aAAa,KAAK;EAClB,YAAY,SAAS,KAAA;EACrB,UAAU,MAAM,YAAY;EAC5B,WAAY,MAAM,cAAc,CAAC;EACjC,SAAS,MAAM,WAAW;EAC1B,aAAa,MAAM,eAAe;CACpC;AACF;;;;;AAMA,SAAgB,eAAe,UAAgD;CAC7E,MAAM,EAAE,MAAM,QAAQ,WAAW,SAAS;CAC1C,MAAM,QAAQ,IAAI,IAAI,SAAS,OAAO,KAAK,MAAM,CAAC,EAAE,MAAM,CAAC,CAAC,CAAC;CAO7D,OAAO,CALL,mBAAG,IAAI,IAAI,CACT,GAAG,OAAO,KAAK,WAAW,IAAI,CAAC,GAC/B,GAAG,SAAS,OAAO,KAAK,MAAM,EAAE,IAAI,CACtC,CAAC,CAEQ,CAAC,CAAC,KAAK,SAChB,SAAS,MAAM,MAAM,IAAI,IAAI,GAAG,MAAM,QAAQ,MAAM,CACtD;AACF;;;ACxHA,MAAM,4BAAY,IAAI,QAA4B;AAClD,IAAI,eAAe;AACnB,SAAS,SAAS,QAA4B;CAC5C,IAAI,KAAK,UAAU,IAAI,MAAM;CAC7B,IAAI,OAAO,KAAA,GAAW;EACpB,KAAK;EACL,UAAU,IAAI,QAAQ,EAAE;CAC1B;CACA,OAAO;AACT;AAEA,SAAS,WAKP,MACA,KACA,aACqC;CACrC,OAAO;EACL,UAAU,UAAU,SAAS,YAAY,MAAM,KAAK,KAAK,CAAC;EAC1D,kBAAkB,OAAO,SACvB,iBAAiB,oBAAoB,MAAM,KAAK,OAAO,IAAI,CAAC;EAC9D,YAAY,OAAO,SAAS,cAAc,MAAM,KAAK,EAAE,CAAC;EACxD,WAAW,UAAU,SAAS,aAAa,MAAM,KAAK,KAAK,CAAC;EAC5D,aAAa,UAAU,SAAS,eAAe,MAAM,KAAK,KAAK,CAAC;EAChE,eAAe,OAAO,SAAS,iBAAiB,MAAM,KAAK,EAAE,CAAC;EAC9D,iBAAiB,YAAY,sBAAsB,aAAa,MAAM,GAAG,CAAC;EAC1E,iBAAiB,YAAY,sBAAsB,aAAa,MAAM,GAAG,CAAC;EAC1E,iBAAiB,YAAY,sBAAsB,aAAa,MAAM,GAAG,CAAC;CAC5E;AACF;;;;;;;AAQA,SAAgB,YAId,MAAc,YAA8D;CAC5E,MAAM,EAAE,QAAQ,aAAa,UAAU,QAAQ;CAC/C,MAAM,WAAW,SAAS;EACxB,GAAG,gBACD,EAAE,gBAAgB,OAAO,SAAS,EAAE,GACpC,GAAG,SAAS,MAAM,EAAE,GAAG,OACzB;EACA,WAAW,OAAO;CACpB,CAAC;CACD,MAAM,WACJ,SAAS,SAAS,KAAA,IACd,KAAA,IACA,aAAa,SAAS,MAAM,MAAM,UAAU;CAClD,MAAM,SAAS,SAAS;EACtB,UAAU;GACR;GACA;GACA,SAAS,MAAM;GACf;GACA;GACA,cAAc;EAChB;EACA,eAAe,OAAO,SAA+B,MAAM,UAAU;EACrE,SAAS,aAAa,KAAA;EACtB,WAAW,OAAO;CACpB,CAAC;CACD,MAAM,QAAQ,OAAO;CACrB,OAAO,cAAuD;EAC5D,IAAI,SAAS,UAAU,QAAQ,SAAS,SAAS,KAAA,GAC/C,OAAO;GAAE,QAAQ;GAAS,OAAO,SAAS;EAAM;EAClD,IAAI,SAAS,SAAS,KAAA,KAAa,aAAa,KAAA,GAC9C,OAAO;GACL,QAAQ;GACR,OAAO,IAAI,qBACT,iCAAiC,KAAK,GAAG,eAAe,KAAA,IAAY,KAAK,IAAI,aAAa,iBAC5F;EACF;EAEF,IAAI,OAAO,UAAU,QAAQ,UAAU,KAAA,GACrC,OAAO;GAAE,QAAQ;GAAS,OAAO,OAAO;EAAM;EAChD,IAAI,aAAa,KAAA,KAAa,UAAU,KAAA,GACtC,OAAO;GAAE,QAAQ;GAAW,OAAO;EAAK;EAC1C,MAAM,SAAS,eAAe,QAAQ;EACtC,MAAM,MAAM,YAAY,QAAQ,KAAK;EACrC,OAAO;GACL,QAAQ;GACR,OAAO;GACP;GACA,cAAc,SAAS;GACvB;GACA,QAAQ,cAAc,OAAO,MAAM,MAAM,EAAE,SAAS,SAAS;GAC7D,QAAQ;GACR;GACA,OAAO,WACL,eAAe,KAAA,IAAY,OAAO,GAAG,KAAK,GAAG,cAC7C,KACA,WACF;EACF;CACF,GAAG;EACD,SAAS;EACT,SAAS;EACT;EACA,OAAO;EACP;EACA;EACA;EACA;EACA;CACF,CAAC;AACH;;;;ACnMA,SAAgB,aAAa,EAC3B,MACA,YACA,SACA,UACA,YACkC;CAClC,MAAM,QAAQ,YAAY,MAAM,UAAU;CAC1C,IAAI,MAAM,WAAW,WACnB,OACE,oBAAA,UAAA,EAAA,UACG,WACC,oBAAC,KAAD;EAAK,IAAI;GAAE,SAAS;GAAQ,gBAAgB;GAAU,GAAG;EAAE;EACzD,UAAA,oBAAC,kBAAD,EAAkB,cAAW,UAAW,CAAA;CACrC,CAAA,EAEP,CAAA;CAGN,IAAI,MAAM,WAAW,SACnB,OACE,oBAAA,UAAA,EAAA,UACG,aAAa,KAAA,IACZ,oBAAC,OAAD;EAAO,UAAS;EAAS,UAAA,MAAM,MAAM;CAAe,CAAA,IAEpD,SAAS,MAAM,KAAK,EAEtB,CAAA;CAGN,OAAO,oBAAA,UAAA,EAAA,UAAG,SAAS,KAAK,EAAI,CAAA;AAC9B;;;;AC3BA,SAAgB,aACd,OACA,UACmB;CACnB,MAAM,YAAY,CAAC,GAAG,SAAS,GAAG,MAAM,MAAM;CAC9C,IAAI,MAAM,WAAW,MACnB,UAAU,KAAK,GAAG,MAAM,KAAK,GAAG,MAAM,QAAQ;CAEhD,UAAU,KAAK,MAAM,IAAI;CACzB,OAAO;AACT;;AAGA,SAAgB,gBACd,MACA,OACA,UACA,QAC+B;CAC/B,MAAM,YAAY,aAAa,OAAO,QAAQ;CAC9C,KAAK,MAAM,SAAS,QAAQ;EAC1B,IAAI,UAAU,KAAA,GAAW;EACzB,KAAK,MAAM,YAAY,WAAW;GAChC,MAAM,QAAQ,MAAM,SAAS,GAAG;GAChC,IAAI,UAAU,KAAA,GAAW,OAAO;EAClC;CACF;AAEF;AAOA,IAAI,gBAAyC,CAAC;AAC9C,IAAI,WAA8B,CAAC;AACnC,MAAM,4BAAY,IAAI,IAAgB;AAEtC,SAAS,UAAgB;CACvB,MAAM,OAAuC,CAAC;CAC9C,KAAK,MAAM,EAAE,UAAU,eAAe,eACpC,KAAK,YAAY;EAAE,GAAG,KAAK;EAAW,GAAG;CAAU;CAErD,WAAW;CACX,KAAK,MAAM,YAAY,WAAW,SAAS;AAC7C;;AAGA,SAAgB,6BAA6B,UAAkC;CAC7E,UAAU,IAAI,QAAQ;CACtB,aAAa;EACX,UAAU,OAAO,QAAQ;CAC3B;AACF;;;;;;;AAQA,SAAgB,sBACd,UACA,WACY;CACZ,MAAM,OAAqB;EAAE;EAAU;CAAU;CACjD,gBAAgB,CAAC,GAAG,eAAe,IAAI;CACvC,QAAQ;CACR,aAAa;EACX,gBAAgB,cAAc,QAAQ,MAAM,MAAM,IAAI;EACtD,QAAQ;CACV;AACF;;AAGA,SAAgB,yBAA4C;CAC1D,OAAO;AACT;;;AC1FA,SAAS,QAAsB;CAC7B,OACE,oBAAC,YAAD;EAAY,WAAU;EAAO,SAAQ;EAAQ,OAAM;EAChD,UAAA;CACS,CAAA;AAEhB;AAEA,MAAME,aAAW,UACf,UAAU,QAAQ,UAAU,KAAA,KAAa,UAAU;AAErD,SAAS,OAAO,OAA2B;CACzC,OAAO,OAAO,UAAU,WAAW,QAAQ,KAAK,UAAU,KAAK;AACjE;;AAGA,SAAS,OAAO,OAAgC;CAC9C,MAAM,OAAO,IAAI,KAAK,OAAO,UAAU,WAAW,QAAQ,GAAU;CACpE,OAAO,OAAO,MAAM,KAAK,QAAQ,CAAC,IAAI,OAAO;AAC/C;AAEA,SAAgB,cAAc,EAC5B,OACA,SACqC;CACrC,IAAIA,UAAQ,KAAK,GAAG,OAAO,oBAAC,OAAD,CAAQ,CAAA;CACnC,MAAM,OAAO,OAAO,KAAK;CACzB,IAAI,MAAM,WAAW,SACnB,OAAO,oBAAC,MAAD;EAAM,MAAM,UAAU;EAAS,UAAA;CAAW,CAAA;CAEnD,IAAI,MAAM,WAAW,SAAS,gBAAgB,KAAK,IAAI,GACrD,OACE,oBAAC,MAAD;EAAM,MAAM;EAAM,QAAO;EAAS,KAAI;EACnC,UAAA;CACG,CAAA;CAGV,OACE,oBAAC,YAAD;EAAY,WAAU;EAAO,SAAQ;EAClC,UAAA;CACS,CAAA;AAEhB;AAEA,SAAgB,cAAc,EAC5B,OACA,SACqC;CACrC,MAAM,EAAE,WAAW,UAAU;CAC7B,IAAI,OAAO,UAAU,UAAU,OAAO,oBAAC,OAAD,CAAQ,CAAA;CAC9C,MAAM,OAAO,IAAI,KAAK,aAAa,QAAQ,EACzC,uBAAuB,MAAM,SAAS,YAAY,IAAI,GACxD,CAAC,CAAC,CAAC,OAAO,KAAK;CACf,OACE,oBAAC,YAAD;EAAY,WAAU;EAAO,SAAQ;EAClC,UAAA;CACS,CAAA;AAEhB;AAEA,SAAgB,eAAe,EAC7B,OACA,QACqC;CACrC,IAAI,OAAO,UAAU,WAAW,OAAO,oBAAC,OAAD,CAAQ,CAAA;CAC/C,OACE,oBAAC,MAAD;EACE,MAAM,QAAQ;EACd,SAAQ;EACR,OAAO,QAAQ,YAAY;EAC3B,OAAO,QAAQ,QAAQ;CACxB,CAAA;AAEL;AAEA,SAAgB,YAAY,EAAE,SAA6C;CACzE,MAAM,EAAE,WAAW,UAAU;CAC7B,MAAM,OAAO,OAAO,KAAK;CACzB,IAAI,SAAS,MAAM,OAAO,oBAAC,OAAD,CAAQ,CAAA;CAElC,MAAM,OAAO,IAAI,KAAK,eAAe,QAAQ;EAC3C,WAAW;EACX,UAAU;CACZ,CAAC,CAAC,CAAC,OAAO,IAAI;CACd,OACE,oBAAC,YAAD;EAAY,WAAU;EAAO,SAAQ;EAClC,UAAA;CACS,CAAA;AAEhB;AAEA,SAAgB,gBAAgB,EAAE,SAA6C;CAC7E,MAAM,EAAE,QAAQ,aAAa,UAAU;CACvC,MAAM,OAAO,OAAO,KAAK;CACzB,IAAI,SAAS,MAAM,OAAO,oBAAC,OAAD,CAAQ,CAAA;CAClC,MAAM,OAAO,IAAI,KAAK,eAAe,QAAQ;EAC3C,WAAW;EACX,WAAW;EACX;CACF,CAAC,CAAC,CAAC,OAAO,IAAI;CACd,OACE,oBAAC,YAAD;EAAY,WAAU;EAAO,SAAQ;EAAQ,UAAU,KAAK,YAAY;EACrE,UAAA;CACS,CAAA;AAEhB;AAEA,SAAgB,YAAY,EAC1B,OACA,QACqC;CACrC,IAAIA,UAAQ,KAAK,GAAG,OAAO,oBAAC,OAAD,CAAQ,CAAA;CACnC,OACE,oBAAC,MAAD;EACE,MAAM,QAAQ;EACd,SAAQ;EACR,OAAO,SAAS,OAAO,KAAK,CAAC;CAC9B,CAAA;AAEL;AAEA,SAAgB,aAAa,EAC3B,OACA,QACqC;CACrC,IAAI,CAAC,MAAM,QAAQ,KAAK,KAAK,MAAM,WAAW,GAAG,OAAO,oBAAC,OAAD,CAAQ,CAAA;CAChE,OACE,oBAAC,OAAD;EAAO,WAAU;EAAM,SAAS;EAAK,YAAA;EAAW,IAAI,EAAE,UAAU,OAAO;EACpE,UAAA,MAAM,KAAK,MAAM,UAChB,oBAAC,MAAD;GAEE,MAAM,QAAQ;GACd,SAAQ;GACR,OAAO,OAAO,IAAI;EACnB,GAJM,KAIN,CACF;CACI,CAAA;AAEX;AAEA,SAAgB,YAAY,EAAE,SAA6C;CACzE,IAAI,UAAU,QAAQ,UAAU,KAAA,GAAW,OAAO,oBAAC,OAAD,CAAQ,CAAA;CAC1D,OACE,oBAAC,YAAD;EACE,WAAU;EACV,SAAQ;EACR,IAAI,EAAE,YAAY,YAAY;EAE7B,UAAA,KAAK,UAAU,KAAK;CACX,CAAA;AAEhB;;;;ACxJA,SAAgB,OACd,SACA,IACA,SACyB;CACzB,MAAM,OAA+D,EACnE,GAAG,QACL;CACA,IACE,YAAY,KAAA,KACX,MAAM,QAAQ,OAAO,KAAK,QAAQ,WAAW,GAE9C,OAAO,KAAK;MAEZ,KAAK,MAAM;CAEb,OAAO,OAAO,KAAK,IAAI,CAAC,CAAC,WAAW,IAAI,KAAA,IAAa;AACvD;;AAGA,MAAa,gBAAgB,UAC3B,MAAM,UAAU,SAAS,KAAK,MAAM,SAAS;;;AChB/C,MAAM,OAAO,OAAwB,OACnC,MAAM,UAAU,SAAS,EAAE;AAE7B,MAAM,UAAU,MACd,OAAO,MAAM,YAAY,OAAO,MAAM,WAAW,OAAO,CAAC,IAAI;AAE/D,MAAM,SAAS,OAAwB,WACrC,WAAW,KAAA,IAAY,MAAM,QAAQ,GAAG,MAAM,MAAM,GAAG;AAEzD,SAAgB,aAAa,EAC3B,OACA,OACA,UACA,QAC2C;CAC3C,MAAM,KAAM;EAAC;EAAa;EAAY;CAAI,CAAC,CAAW,MAAM,MAC1D,IAAI,OAAO,CAAC,CACd;CACA,IAAI,OAAO,KAAA,GAAW,OAAO;CAC7B,OACE,oBAAC,WAAD;EACE,MAAM,QAAQ;EACd,WAAA;EACA,OAAO,MAAM,KAAK;EAClB,OAAO,OAAO,QAAQ,GAAG;EACzB,WAAW,MACT,SACE,OAAO,OAAO,IAAI,EAAE,OAAO,UAAU,KAAK,KAAA,IAAY,EAAE,OAAO,KAAK,CACtE;CAEH,CAAA;AAEL;;AAGA,SAAS,YAAY,EACnB,OACA,OACA,UACA,MACA,MACA,OACA,QAKsB;CACtB,MAAM,MAAO,CAAC,OAAO,KAAK,CAAC,CAAW,QAAQ,MAAM,IAAI,OAAO,CAAC,CAAC;CACjE,MAAM,OAAO,IAAI,SAAS,IAAI,MAAM,IAAI,OAAO,IAAI,IAAK,CAAC,IAAI,IAAc,CAAC;CAC5E,IAAI,KAAK,WAAW,GAAG,OAAO;CAC9B,OACE,oBAAC,OAAD;EAAO,WAAU;EAAM,SAAS;EAC7B,UAAA,KAAK,KAAK,OACT,oBAAC,WAAD;GAEQ;GACN,MAAM,QAAQ;GACd,WAAA;GACA,OACE,OAAO,OACH,MAAM,KAAK,IACX,MAAM,OAAO,OAAO,QAAQ,SAAS,IAAI;GAE/C,OAAO,KAAK,QAAQ,GAAG;GACvB,WAAW,MACT,SACE,OACE,OACA,IACA,EAAE,OAAO,UAAU,KAAK,KAAA,IAAY,MAAM,EAAE,OAAO,KAAK,CAC1D,CACF;GAEF,WAAW,EACT,YAAY,EAAE,QAAQ,SAAS,WAAW,OAAO,KAAA,EAAU,EAC7D;EACD,GAtBM,EAsBN,CACF;CACI,CAAA;AAEX;AAEA,SAAgB,aAAa,OAAiD;CAC5E,OAAO,oBAAC,aAAD;EAAa,GAAI;EAAO,MAAK;EAAS,OAAO;EAAQ,MAAM;CAAS,CAAA;AAC7E;AAEA,SAAgB,WAAW,OAAiD;CAC1E,OAAO,oBAAC,aAAD;EAAa,GAAI;EAAO,MAAK;EAAO,OAAO;EAAQ,MAAM;CAAS,CAAA;AAC3E;;AAGA,SAAgB,eACd,OACqB;CACrB,OACE,oBAAC,aAAD;EACE,GAAI;EACJ,MAAK;EACL,QAAQ,wBAAQ,IAAI,KAAK,GAAG,IAAI,EAAE;EAClC,OAAO,MACL,aAAa,QAAQ,CAAC,OAAO,MAAM,EAAE,QAAQ,CAAC,IAC1C,EAAE,YAAY,CAAC,CAAC,MAAM,GAAG,EAAE,IAC3B;CAEP,CAAA;AAEL;AAEA,SAAgB,cAAc,EAC5B,OACA,OACA,UACA,QAC2C;CAC3C,IAAI,CAAC,IAAI,OAAO,IAAI,GAAG,OAAO;CAC9B,MAAM,UAAU,OAAO;CACvB,OACE,qBAAC,WAAD;EACE,QAAA;EACA,MAAM,QAAQ;EACd,WAAA;EACA,OAAO,MAAM,KAAK;EAClB,OAAO,OAAO,YAAY,YAAY,OAAO,OAAO,IAAI;EACxD,WAAW,MACT,SACE,OACE,OACA,MACA,EAAE,OAAO,UAAU,KAAK,KAAA,IAAY,EAAE,OAAO,UAAU,MACzD,CACF;EAbJ,UAAA;GAgBE,oBAAC,UAAD;IAAU,OAAM;IAAG,UAAA;GAAa,CAAA;GAChC,oBAAC,UAAD;IAAU,OAAM;IAAO,UAAA;GAAa,CAAA;GACpC,oBAAC,UAAD;IAAU,OAAM;IAAQ,UAAA;GAAY,CAAA;EAC3B;;AAEf;;AAGA,SAAgB,WAAW,EACzB,OACA,OACA,UACA,QAC2C;CAC3C,MAAM,KAAK,IAAI,OAAO,IAAI,IAAI,OAAO,IAAI,OAAO,IAAI,IAAI,OAAO,KAAA;CAC/D,IAAI,OAAO,KAAA,GAAW,OAAO;CAC7B,MAAM,WAAW,QAAQ;CACzB,MAAM,OAAO,OAAO;CACpB,OACE,qBAAC,WAAD;EACE,QAAA;EACA,MAAM,QAAQ;EACd,WAAA;EACA,OAAO,MAAM,KAAK;EAClB,OACE,OACI,MAAM,QAAQ,QAAQ,IACpB,SAAS,IAAI,MAAM,IACnB,CAAC,IACH,OAAO,QAAQ;EAErB,WAAW,MAAM;GACf,MAAM,MAAM,EAAE,OAAO;GACrB,SAAS,OAAO,OAAO,IAAI,QAAQ,KAAK,KAAA,IAAY,GAAG,CAAC;EAC1D;EACA,WAAW,EAAE,QAAQ,EAAE,UAAU,KAAK,EAAE;EAhB1C,UAAA,CAkBG,CAAC,QAAQ,oBAAC,UAAD;GAAU,OAAM;GAAG,UAAA;EAAa,CAAA,IACxC,MAAM,WAAW,CAAC,EAAA,CAAG,KAAK,WAC1B,oBAAC,UAAD;GAAuB,OAAO;GAC3B,UAAA,SAAS,MAAM;EACR,GAFK,MAEL,CACX,CACQ;;AAEf;;AAGA,SAAgB,WAAiB;CAC/B,OAAO;AACT;;;;AClMA,MAAa,cAAc,UACzB,MAAM,WAAW,OAAO,KAAA;;;ACO1B,SAAS,OAAO,OAWd;CACA,OAAO;EACL,IAAI,MAAM;EACV,OAAO,MAAM,MAAM;EACnB,MAAM,MAAM,QAAQ;EACpB,WAAW;EACX,UAAU,MAAM,MAAM;EACtB,UAAU,MAAM,aAAa;EAC7B,WAAW,MAAM,cAAc;EAC/B,OAAO,MAAM,UAAU,KAAA;EACvB,YAAY,MAAM,SAAS,MAAM;EACjC,QAAQ,MAAM;CAChB;AACF;;;;;AAMA,SAAS,iBACP,QACA,WACM;CACN,MAAM,WAAW,OAAO,SAAS;CACjC,MAAM,WAAW,OAAsB,IAAI;CAC3C,gBAAgB;EACd,SAAS,UAAU;CACrB,CAAC;CACD,gBAAgB;EACd,IAAI,SAAS,YAAY,QAAQ;GAC/B,SAAS,UAAU;GACnB,SAAS,UAAU,MAAM;EAC3B;CACF,GAAG,CAAC,MAAM,CAAC;CACX,sBACc;EACV,IAAI,SAAS,YAAY,MAAM;GAC7B,SAAS,UAAU;GACnB,SAAS,UAAU,IAAI;EACzB;CACF,GACA,CAAC,CACH;AACF;AAEA,MAAMC,UAAQ,UACZ,OAAO,UAAU,YAAY,OAAO,UAAU,WAAW,OAAO,KAAK,IAAI;AAE3E,SAAgB,YAAY,OAAyC;CACnE,MAAM,EAAE,OAAO,OAAO,aAAa;CACnC,MAAM,EAAE,WAAW,WAAW,YAAY,MAAM;CAChD,MAAM,OACJ,MAAM,WAAW,UACb,UACA,MAAM,WAAW,QACf,QACA;CACR,OACE,oBAAC,WAAD;EACE,GAAI,OAAO,KAAK;EACV;EACN,WAAW,cAAc,KAAA,KAAa,YAAY;EAClD,SAAS;EACT,OAAOA,OAAK,KAAK;EACjB,WAAW,MACT,SAAS,EAAE,OAAO,UAAU,KAAK,WAAW,KAAK,IAAI,EAAE,OAAO,KAAK;EAErE,WAAW,EAAE,WAAW;GAAE;GAAW;GAAW;EAAQ,EAAE;CAC3D,CAAA;AAEL;;AAGA,SAAS,cACP,OACA,OACe;CACf,IAAI,OAAO,UAAU,UAAU,OAAO;CACtC,MAAM,EAAE,SAAS,YAAY,MAAM;CACnC,IAAI,MAAM,SAAS,aAAa,CAAC,OAAO,UAAU,KAAK,GACrD,OAAO;CAET,IAAI,YAAY,KAAA,KAAa,QAAQ,SACnC,OAAO,oBAAoB;CAE7B,IAAI,YAAY,KAAA,KAAa,QAAQ,SACnC,OAAO,mBAAmB;CAE5B,OAAO;AACT;AAEA,SAAgB,YAAY,OAAyC;CACnE,MAAM,EAAE,OAAO,OAAO,aAAa;CACnC,MAAM,EAAE,SAAS,YAAY,MAAM;CAEnC,MAAM,CAAC,YAAY,iBAAiB,SAAS,KAAK;CAElD,MAAM,CAAC,MAAM,WAAW,SAAS,KAAK;CACtC,IAAI,SAAS,OAAO;EAClB,QAAQ,KAAK;EACb,IAAI,OAAO,UAAU,UAAU,cAAc,KAAK;CACpD;CACA,MAAM,UAAU,aAAa,mBAAmB,cAAc,OAAO,KAAK;CAC1E,iBAAiB,SAAS,MAAM,SAAS;CACzC,OACE,oBAAC,WAAD;EACE,GAAI,OAAO,KAAK;EAChB,MAAK;EACL,OAAOA,OAAK,KAAK;EACjB,OAAO,YAAY,QAAQ,MAAM,UAAU,KAAA;EAC3C,YAAY,MAAM,SAAS,WAAW,MAAM;EAC5C,WAAW,MAAM;GACf,cAAc,EAAE,OAAO,UAAU,MAAM,EAAE,OAAO,SAAS,QAAQ;GACjE,SACE,EAAE,OAAO,UAAU,KAAK,WAAW,KAAK,IAAI,OAAO,EAAE,OAAO,KAAK,CACnE;EACF;EACA,WAAW,EACT,WAAW;GACT,KAAK;GACL,KAAK;GACL,MAAM,MAAM,SAAS,YAAY,IAAI;EACvC,EACF;CACD,CAAA;AAEL;AAEA,SAAgB,aAAa,OAAyC;CACpE,MAAM,EAAE,OAAO,OAAO,UAAU,UAAU,QAAQ,SAAS;CAC3D,MAAM,OAAO,MAAM,SAAS,MAAM;CAClC,OACE,qBAAC,aAAD;EAAa,OAAO,MAAM,UAAU,KAAA;EAAW,UAAU,aAAa;EAAtE,UAAA,CACE,oBAAC,kBAAD;GACE,OAAO,MAAM;GACb,UAAU,MAAM;GAChB,IAAI,EAAE,IAAI,EAAE;GACZ,SACE,oBAAC,QAAD;IACE,IAAI,MAAM;IACV,MAAM,QAAQ;IACd,SAAS,UAAU;IACnB,WAAW,MAAM,cAAc;IACvB;IACR,WAAW,MAAM,SAAS,EAAE,OAAO,OAAO;GAC3C,CAAA;EAEJ,CAAA,GACA,SAAS,KAAA,IAAY,OAAO,oBAAC,gBAAD,EAAA,UAAiB,KAAqB,CAAA,CACxD;;AAEjB;AAEA,SAAgB,UAAU,OAAyC;CACjE,MAAM,EAAE,OAAO,OAAO,aAAa;CACnC,OACE,oBAAC,WAAD;EACE,GAAI,OAAO,KAAK;EAChB,MAAK;EACL,OAAOA,OAAK,KAAK,CAAC,CAAC,MAAM,GAAG,EAAE;EAC9B,WAAW,MACT,SAAS,EAAE,OAAO,UAAU,KAAK,WAAW,KAAK,IAAI,EAAE,OAAO,KAAK;EAErE,WAAW,EAAE,YAAY,EAAE,QAAQ,KAAK,EAAE;CAC3C,CAAA;AAEL;;AAGA,SAAgB,cAAc,OAAyC;CACrE,MAAM,EAAE,OAAO,OAAO,aAAa;CACnC,MAAM,WAAW,MAA0B;EACzC,MAAM,OAAO,IAAI,KAAKA,OAAK,CAAC,CAAC;EAC7B,OAAO,OAAO,MAAM,KAAK,QAAQ,CAAC,IAAI,KAAK,KAAK,YAAY,CAAC,CAAC,MAAM,GAAG,EAAE;CAC3E;CACA,OACE,oBAAC,WAAD;EACE,GAAI,OAAO,KAAK;EAChB,MAAK;EACL,OAAO,QAAQ,KAAK;EACpB,WAAW,MAAM;GACf,MAAM,MAAM,EAAE,OAAO;GACrB,SACE,QAAQ,KAAK,WAAW,KAAK,qBAAI,IAAI,KAAK,GAAG,IAAI,EAAE,EAAA,CAAE,YAAY,CACnE;EACF;EACA,YAAY,MAAM,SAAS,MAAM,cAAc;EAC/C,WAAW,EAAE,YAAY,EAAE,QAAQ,KAAK,EAAE;CAC3C,CAAA;AAEL;AAEA,SAAgB,UAAU,OAAyC;CACjE,MAAM,EAAE,OAAO,OAAO,aAAa;CACnC,MAAM,UAAU,MAAM;CACtB,OACE,qBAAC,WAAD;EACE,GAAI,OAAO,KAAK;EAChB,QAAA;EACA,OAAOA,OAAK,KAAK;EACjB,WAAW,MACT,SAAS,EAAE,OAAO,UAAU,KAAK,WAAW,KAAK,IAAI,EAAE,OAAO,KAAK;EAErE,WAAW;GAAE,YAAY,EAAE,IAAI,QAAQ;GAAG,QAAQ,EAAE,QAAQ;EAAE;EAPhE,UAAA,CASG,CAAC,MAAM,YACN,oBAAC,UAAD;GAAU,OAAM;GACd,UAAA,oBAAC,MAAD,EAAA,UAAI,OAAQ,CAAA;EACJ,CAAA,IAEV,MAAM,WAAW,CAAC,EAAA,CAAG,KAAK,WAC1B,oBAAC,UAAD;GAAuB,OAAO;GAC3B,UAAA,SAAS,MAAM;EACR,GAFK,MAEL,CACX,CACQ;;AAEf;AAEA,MAAM,UAAU,OAAO,SAAS;;;;;AAOhC,SAAS,SACP,OACA,QACA,UACwD;CACxD,MAAM,MAAM,KAAK,UAAU,KAAK;CAChC,MAAM,CAAC,OAAO,YAAY,eAAe,OAAO,KAAK,CAAC;CACtD,MAAM,CAAC,MAAM,WAAW,SAAS,GAAG;CACpC,IAAI,SAAS,KAAK;EAChB,QAAQ,GAAG;EACX,MAAM,SAAS,SAAS,KAAK;EAC7B,IAAI,CAAC,OAAO,MAAM,KAAK,UAAU,OAAO,KAAK,MAAM,KACjD,SAAS,OAAO,KAAK,CAAC;CAE1B;CACA,OAAO,CACL,QACC,QAAQ;EACP,SAAS,GAAG;EACZ,MAAM,SAAS,SAAS,GAAG;EAC3B,OAAO,OAAO,KAAK,OAAO,QAAQ;CACpC,CACF;AACF;AAEA,SAAgB,WAAW,OAAyC;CAClE,MAAM,EAAE,OAAO,OAAO,aAAa;CACnC,MAAM,UAAU,MAAM,aAAa,YAAY,MAAM,aAAa;CAClE,MAAM,CAAC,OAAO,QAAQ,SACpB,QACC,MAAO,MAAM,QAAQ,CAAC,IAAI,EAAE,KAAK,IAAI,IAAI,KACzC,QAAQ;EACP,MAAM,QAAQ,IACX,MAAM,GAAG,CAAC,CACV,KAAK,MAAM,EAAE,KAAK,CAAC,CAAC,CACpB,QAAQ,MAAM,MAAM,EAAE;EACzB,IAAI,MAAM,WAAW,GAAG,OAAO;GAAE,IAAI;GAAM,OAAO,WAAW,KAAK;EAAE;EACpE,IAAI,CAAC,SAAS,OAAO;GAAE,IAAI;GAAM,OAAO;EAAM;EAC9C,MAAM,UAAU,MAAM,IAAI,MAAM;EAChC,OAAO,QAAQ,KAAK,OAAO,KAAK,IAC5B,EAAE,IAAI,MAAM,IACZ;GAAE,IAAI;GAAM,OAAO;EAAQ;CACjC,CACF;CACA,MAAM,UACJ,WACA,MAAM,MAAM,GAAG,CAAC,CAAC,MAAM,MAAM,EAAE,KAAK,MAAM,MAAM,OAAO,MAAM,OAAO,CAAC,CAAC,CAAC;CACzE,iBAAiB,UAAU,0BAA0B,MAAM,MAAM,SAAS;CAC1E,OACE,oBAAC,WAAD;EACE,GAAI,OAAO,KAAK;EAChB,OAAO;EACP,OAAO,WAAW,MAAM,UAAU,KAAA;EAClC,YACE,UACI,0BACC,MAAM,SAAS,MAAM,cAAc;EAE1C,WAAW,MAAM;GACf,MAAM,OAAO,KAAK,EAAE,OAAO,KAAK;GAChC,IAAI,SAAS,SAAS,SAAS,IAAI;EACrC;CACD,CAAA;AAEL;AAEA,SAAS,OAAO,KAAsB;CACpC,IAAI;EACF,KAAK,MAAM,GAAG;EACd,OAAO;CACT,QAAQ;EACN,OAAO;CACT;AACF;AAEA,SAAgB,UAAU,OAAyC;CACjE,MAAM,EAAE,OAAO,OAAO,aAAa;CACnC,MAAM,CAAC,OAAO,QAAQ,SACpB,QACC,MAAO,MAAM,QAAQ,MAAM,KAAA,IAAY,KAAK,KAAK,UAAU,GAAG,MAAM,CAAC,IACrE,QAAQ;EACP,IAAI,IAAI,KAAK,MAAM,IAAI,OAAO;GAAE,IAAI;GAAM,OAAO,WAAW,KAAK;EAAE;EACnE,IAAI;GACF,OAAO;IAAE,IAAI;IAAM,OAAO,KAAK,MAAM,GAAG;GAAgB;EAC1D,QAAQ;GACN,OAAO,EAAE,IAAI,MAAM;EACrB;CACF,CACF;CAEA,MAAM,UAAU,MAAM,KAAK,MAAM,MAAM,CAAC,OAAO,KAAK;CACpD,iBAAiB,UAAU,mBAAmB,MAAM,MAAM,SAAS;CACnE,OACE,oBAAC,WAAD;EACE,GAAI,OAAO,KAAK;EAChB,WAAA;EACA,SAAS;EACT,OAAO;EACP,OAAO,WAAW,MAAM,UAAU,KAAA;EAClC,YACE,UAAU,mBAAoB,MAAM,SAAS,MAAM;EAErD,WAAW,EAAE,WAAW,EAAE,OAAO,EAAE,YAAY,YAAY,EAAE,EAAE;EAC/D,WAAW,MAAM;GACf,MAAM,OAAO,KAAK,EAAE,OAAO,KAAK;GAChC,IAAI,SAAS,SAAS,SAAS,IAAI;EACrC;CACD,CAAA;AAEL;;ACjTA,MAAa,mBAAsC;CApBjD,QAAQ;EAAE,SAAS;EAAe,OAAO;EAAa,QAAQ;CAAa;CAC3E,QAAQ;EAAE,SAAS;EAAe,OAAO;EAAa,QAAQ;CAAa;CAC3E,SAAS;EAAE,SAAS;EAAe,OAAO;EAAa,QAAQ;CAAa;CAC5E,SAAS;EACP,SAAS;EACT,OAAO;EACP,QAAQ;CACV;CACA,MAAM;EAAE,SAAS;EAAa,OAAO;EAAW,QAAQ;CAAW;CACnE,UAAU;EACR,SAAS;EACT,OAAO;EACP,QAAQ;CACV;CACA,MAAM;EAAE,SAAS;EAAa,OAAO;EAAW,QAAQ;CAAW;CACnE,OAAO;EAAE,SAAS;EAAc,OAAO;EAAY,QAAQ;CAAS;CACpE,MAAM;EAAE,SAAS;EAAa,OAAO;EAAW,QAAQ;CAAS;AAIhB;;;;ACrBnD,SAAS,kBACP,KAC4C;CAC5C,MAAM,OAAO,WAAW,cAAc;CACtC,MAAM,aAAa,qBACjB,8BACA,wBACA,sBACF;CACA,OAAO;EAAC;EAAK,MAAM;EAAW;EAAY;CAAgB;AAC5D;AAEA,SAASC,OACP,MACA,OACA,QACmB;CAEnB,OAAO,gBACL,MACA,MAAM,OACN,MAAM,UACN,MACF;AACF;;AAGA,SAAgB,aAAa,EAC3B,WACA,GAAG,SACiD;CACpD,MAAM,SAAS,kBAAkB,SAAS;CAC1C,OAAO,cAAcA,OAAK,WAAW,OAAO,MAAM,GAAG,KAAK;AAC5D;;AAGA,SAAgB,WAAW,EACzB,WACA,GAAG,SAC+C;CAClD,MAAM,SAAS,kBAAkB,SAAS;CAC1C,OAAO,cAAcA,OAAK,SAAS,OAAO,MAAM,GAAG,KAAK;AAC1D;;AAGA,SAAgB,iBAAiB,EAC/B,WACA,GAAG,SACgD;CACnD,MAAM,SAAS,kBAAkB,SAAS;CAC1C,OAAO,cAAcA,OAAK,UAAU,OAAO,MAAM,GAAG,KAAK;AAC3D;;;;;;;AC3EA,SAAgB,eAAe,SAAgC;CAC7D,MAAM,MAA+B,CAAC;CACtC,KAAK,MAAM,CAAC,MAAM,SAAS,OAAO,QAAQ,OAAO,GAC/C,KAAK,MAAM,CAAC,IAAI,YAAY,OAAO,QAAQ,QAAQ,CAAC,CAAC,GACnD,IAAI,OAAO,OAAO,OAAO,GAAG,KAAK,IAAI,QAAQ;CAGjD,OAAO;AACT;;;;ACeA,SAAgB,UAAU,EACxB,OACA,UACA,SACA,aACA,WAAW,MACX,YAC+B;CAC/B,OACE,qBAAC,WAAD;EAAW,WAAU;EAAiB;EAAU,IAAI,EAAE,IAAI,EAAE;EAA5D,UAAA;GACG,gBAAgB,KAAA,KAAa,YAAY,SAAS,KACjD,oBAAC,aAAD;IAAa,cAAW;IAAa,IAAI,EAAE,IAAI,EAAE;IAC9C,UAAA,YAAY,KAAK,OAAO,UACvB,oBAAC,KAAD;KAAiB,WAAU;KACxB,UAAA;IACE,GAFK,KAEL,CACN;GACU,CAAA;GAEf,qBAAC,OAAD;IACE,WAAW;KAAE,IAAI;KAAU,IAAI;IAAM;IACrC,SAAS;IACT,IAAI;KACF,YAAY,EAAE,IAAI,SAAS;KAC3B,gBAAgB;KAChB,IAAI;IACN;IAPF,UAAA,CASE,qBAAC,KAAD,EAAA,UAAA,CACE,oBAAC,YAAD;KAAY,WAAU;KAAK,SAAQ;KAChC,UAAA;IACS,CAAA,GACX,aAAa,KAAA,KACZ,oBAAC,YAAD;KAAY,SAAQ;KAAQ,OAAM;KAC/B,UAAA;IACS,CAAA,CAEX,EAAA,CAAA,GACJ,YAAY,KAAA,KACX,oBAAC,OAAD;KAAO,WAAU;KAAM,SAAS;KAC7B,UAAA;IACI,CAAA,CAEJ;;GACN;EACQ;;AAEf;;AAcA,SAAgB,YAAY,EAC1B,MACA,SACA,OACA,SACA,aAAa,SACb,WAAW,MACX,YACiC;CACjC,MAAM,UAAU,MAAM;CACtB,OACE,qBAAC,QAAD;EACQ;EACG;EACT,WAAA;EACU;EACV,mBAAiB;EALnB,UAAA;GAOE,oBAAC,aAAD;IAAa,IAAI;IAAU,UAAA;GAAmB,CAAA;GAC9C,oBAAC,eAAD;IAAe,UAAA;IAAU;GAAwB,CAAA;GACjD,qBAAC,eAAD,EAAA,UAAA,CACE,oBAAC,QAAD;IAAQ,SAAS;IAAU,UAAA;GAAmB,CAAA,GAC7C,OACY,EAAA,CAAA;EACT;;AAEZ;;AASA,SAAgB,YAAY,EAC1B,MACA,SACA,OACA,SACA,aAAa,SACb,SAAS,SACT,QAAQ,IACR,YACiC;CACjC,MAAM,UAAU,MAAM;CACtB,OACE,oBAAC,QAAD;EACQ;EACG;EACD;EACR,WAAW,EACT,OAAO;GACL,mBAAmB;GACnB,IAAI,EAAE,QAAQ,WAAW;IAAE,IAAI;IAAQ,IAAI,MAAM,QAAQ,KAAK;GAAE,GAAG;EACrE,EACF;EAEA,UAAA,qBAAC,OAAD;GAAO,IAAI,EAAE,QAAQ,OAAO;GAA5B,UAAA;IACE,oBAAC,YAAD;KAAY,IAAI;KAAS,WAAU;KAAK,SAAQ;KAAK,IAAI,EAAE,GAAG,EAAE;KAC7D,UAAA;IACS,CAAA;IACZ,oBAAC,KAAD;KACE,IAAI;MACF,MAAM;MACN,UAAU;MACV,GAAG;MACH,WAAW;MACX,aAAa;KACf;KAEC;IACE,CAAA;IACL,qBAAC,OAAD;KACE,WAAU;KACV,SAAS;KACT,IAAI;MACF,gBAAgB;MAChB,GAAG;MACH,WAAW;MACX,aAAa;KACf;KARF,UAAA,CAUE,oBAAC,QAAD;MAAQ,SAAS;MAAU,UAAA;KAAmB,CAAA,GAC7C,OACI;;GACF;;CACD,CAAA;AAEZ;;;;AC/KA,MAAa,gBAAmC;CAC9C;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;AACF;;AAGA,SAAgB,aAAa,QAAkC;CAC7D,IAAI,OAAO,OAAO,mBAAmB,UAAU,OAAO;CACtD,OAAO,OAAO,gBAAgB,OAAO,UAAU;AACjD;;;;;AAcA,SAAgB,YAAY,OAAuC;CACjE,OAAO;EACL,oBAAoB,UAAU;EAC9B,SAAS,UAAU,UAAU,EAAE,UAAU,KAAK,IAAI,CAAC;CACrD;AACF;;;;ACxBA,SAAgB,cAAc,EAC5B,MACA,OACA,UACA,cACA,OAAO,OACP,WACA,WACmC;CACnC,OACE,oBAAC,aAAD;EACQ;EACG;EACF;EACP,YAAW;EACX,UAAS;EACT,SACE,oBAAC,QAAD;GACE,OAAM;GACN,SAAQ;GACR,UAAU;GACV,SAAS;GAER,UAAA;EACK,CAAA;EAGV,UAAA,oBAAC,YAAD,EAAa,SAAqB,CAAA;CACvB,CAAA;AAEjB;;;;;;;ACrCA,SAAgB,sBAAsB,MAAmC;CACvE,MAAM,EAAE,gBAAgB,QAAQ;CAChC,OAAO,kBAEH,YAAY,kBAAkB,EAC5B,YAAY,UACV,GAAG,OAAO,MAAM,SAAS,EAAE,EAAE,GAAG,OAAO,MAAM,SAAS,EAAE,CAAC,CAAC,MAAM,GAAG,CAAC,CAAC,SACrE,QAAQ,OACZ,CAAC,GACH,CAAC,aAAa,IAAI,CACpB;AACF;;AAGA,SAAgB,WACd,OAC8C;CAC9C,MAAM,aAAa,sBAAsB,MAAM,SAAS,IAAI;CAC5D,OAAO,YAAY;EACjB,aAAa,OAAe,MAAM,OAAO,QAAQ,EAAE;EACnD,WAAW;CACb,CAAC;AACH;;AAGA,SAAgB,WACd,OAC8C;CAC9C,MAAM,aAAa,sBAAsB,MAAM,SAAS,IAAI;CAC5D,OAAO,YAAY;EACjB,aAAa,OAAe,MAAM,OAAO,QAAQ,EAAE,GAAG,CAAC;EACvD,WAAW;CACb,CAAC;AACH;;;;ACvCA,IAAa,iBAAb,cAAoC,MAAM;CACxC,YAAY,KAAa;EACvB,MAAM,aAAa,GAAG,CAAC;EACvB,KAAK,OAAO;CACd;AACF;AAEA,SAAS,aAAa,KAAqB;CACzC,OAAO,aAAa,IAAI;AAC1B;;;;;;AAOA,SAAgB,kBAAkB,OAAc,KAAqB;CACnE,OAAO,iBAAiB,aACpB,GAAG,MAAM,QAAQ,QAAQ,WAAW,EAAE,EAAE,gCAAgC,IAAI,oDAC5E,MAAM;AACZ;;;ACpBA,SAAS,KAAK,OAAwB;CACpC,IAAI,UAAU,QAAQ,UAAU,KAAA,GAAW,OAAO;CAClD,MAAM,MAAM,OAAO,UAAU,WAAW,QAAQ,KAAK,UAAU,KAAK;CAEpE,MAAM,OACJ,OAAO,UAAU,YAAY,eAAe,KAAK,GAAG,IAAI,IAAI,QAAQ;CACtE,OAAO,WAAW,KAAK,IAAI,IAAI,IAAI,KAAK,WAAW,MAAK,MAAI,EAAE,KAAK;AACrE;;AAGA,SAAgB,MACd,QACA,MACQ;CAKR,OAAO,GAAG,CAHR,OAAO,KAAK,MAAM,KAAK,EAAE,IAAI,CAAC,CAAC,CAAC,KAAK,GAAG,GACxC,GAAG,KAAK,KAAK,QAAQ,OAAO,KAAK,MAAM,KAAK,IAAI,EAAE,KAAK,CAAC,CAAC,CAAC,KAAK,GAAG,CAAC,CAEvD,CAAC,CAAC,KAAK,MAAM,EAAE;AAC/B;;AAGA,SAAgB,aACd,UACA,MACA,OAAO,YACD;CACN,MAAM,MAAM,IAAI,gBAAgB,IAAI,KAAK,CAAC,IAAI,GAAG,EAAE,KAAK,CAAC,CAAC;CAC1D,MAAM,OAAO,SAAS,cAAc,GAAG;CACvC,KAAK,OAAO;CACZ,KAAK,WAAW;CAChB,KAAK,MAAM;CAEX,iBAAiB,IAAI,gBAAgB,GAAG,GAAG,GAAM;AACnD;;;ACCA,MAAM,MAA6B;CAAC;CAAU;CAAU;AAAS;;;;;AAMjE,SAAS,cACP,OACA,WACA,SACS;CACT,OAAO,UAAU,cACb,eAAe,OAAO,IACtB,GAAG,GAAG,MAAM,SAAS,SAAS,QAAQ,UAAU,SAAS;AAC/D;;AAGA,SAAgB,YAAY,EAC1B,OACA,WACA,UAAU,CAAC,GACX,UAAU,KACV,UACA,UACwC;CACxC,MAAM,aAAa,sBAAsB,MAAM,SAAS,IAAI;CAC5D,MAAM,CAAC,YAAY,iBAAiB,SAAS,KAAK;CAClD,MAAM,CAAC,MAAM,WAAW,SAAS,KAAK;CACtC,MAAM,CAAC,OAAO,YAAY,SAAwB,IAAI;CACtD,MAAM,CAAC,QAAQ,aAAa,SAAwB,IAAI;CACxD,MAAM,EAAE,cAAc,MAAM,aAAa,MAAM;CAC/C,MAAM,MAAM,KAAK;CACjB,MAAM,aAAa,OAAO,KAAK,eAAe,OAAO,CAAC,CAAC,CAAC,SAAS;CACjE,MAAM,QAAQ,UAAU,SAAS;CACjC,MAAM,cACJ,WAAW,OAAO,OAChB,oBAAC,OAAD;EAAO,UAAS;EAAU,MAAK;EAAS,IAAI,EAAE,IAAI,IAAI;EACnD,UAAA;CACI,CAAA;CAEX,IAAI,UAAU,KAAK,CAAC,UAAU,aAAa,OAAO;;CAGlD,MAAM,MAAM,OACV,QACA,SACA,MACA,SACkB;EAClB,QAAQ,IAAI;EACZ,SAAS,IAAI;EACb,UAAU,IAAI;EACd,IAAI;GACF,IAAI,CAAC,UAAU,eAAe,QAAQ,KAAK,MAAM,IAAI,eAAe,GAAG;GAEvE,IAAI,UAAU,eAAe,CAAC,YAC5B,MAAM,IAAI,MAAM,mDAAmD;GAErE,MAAM,UAAU,MAAM,KAAK;GAC3B,IAAI,SAAS;IACX,MAAM,WAAW;IACjB,UAAU,MAAM;GAClB;GACA,UAAU,KAAK,OAAO,CAAC;GACvB,SAAS;IAAE;IAAQ,OAAO;GAAQ,CAAC;EACrC,SAAS,QAAQ;GAEf,IAAI,SAAS,WAAgB;GAC7B,SAAS,kBAAkB,QAAiB,GAAG,CAAC;EAClD,UAAU;GACR,QAAQ,KAAK;GACb,cAAc,KAAK;EACrB;CACF;CAEA,MAAM,UAAU,YAAmC;EACjD,MAAM,OAAqB,CAAC;EAC5B,WAAW,MAAM,OAAO,MAAM,OAAO,QAAQ;GAC3C,SAAS,cAAc,OAAO,WAAW,OAAO;GAChD,oBAAoB;EACtB,CAAC,GAAG;GACF,IAAI,KAAK,WAAW,KAAK,MAAM,IAAI,eAAe,GAAG;GACrD,KAAK,KAAK,GAAG;EACf;EACA,OAAO;CACT;CAEA,MAAM,eACJ,IACE,UACA,OACC,MAAM,WAAW,EAAE,GAAG,MAAM,IAAI,WAAW,UAAU,IACtD,YAAY;EAIV,QAAO,MAH0B,MAAM,OAAO,WAC5C,cAAc,OAAO,WAAW,OAAO,CACzC,EAAA,CACc;CAChB,CACF;CAEF,MAAM,mBACJ,IACE,UACA,QACC,MAAM,YAAY,EAAE,GAAG,MAAM,IAAI,WAAW,UAAU,IACvD,YAAY;EACV,MAAM,OAAO,MAAM,QAAQ;EAC3B,MAAM,WAAW,GAAG,MAAM,SAAS,KAAK;EACxC,MAAM,MAAM,MAAM,MAAM,QAAQ,IAAI;EACpC,IAAI,aAAa,KAAA,GAAW,aAAa,UAAU,GAAG;OACjD,SAAS,KAAK,QAAQ;EAC3B,OAAO,KAAK;CACd,CACF;CAEF,MAAM,gBACJ,IACE,WACA,OACC,MAAM,aAAa,EAAE,GAAG,MAAM,IAAI,WAAW,UAAU,IACxD,YAAY;EACV,MAAM,UAAU,MAAM,QAAQ,EAAA,CAAG,QAC9B,QAAQ,IAAI,gBAAgB,IAC/B;EACA,KAAK,MAAM,OAAO,QAChB,MAAM,MAAM,OAAO,QAAQ,IAAI,SAAmB;EAEpD,OAAO,OAAO;CAChB,CACF;CAEF,MAAM,QAAQ,UAAU,cACpB,iDACA,GAAG,MAAM;CACb,OACE,qBAAC,OAAD;EAAO,SAAQ;EAAW,IAAI,EAAE,GAAG,IAAI;EAAvC,UAAA;GACE,qBAAC,OAAD;IACE,WAAU;IACV,SAAS;IACT,YAAA;IACA,IAAI;KAAE,YAAY;KAAU,UAAU;IAAO;IAJ/C,UAAA;KAME,oBAAC,YAAD;MAAY,aAAU;MAAS,IAAI,EAAE,IAAI,EAAE;MACxC,UAAA;KACS,CAAA;KACX,CAAC,UAAU,eAAe,cACzB,oBAAC,QAAD;MAAQ,MAAK;MAAQ,SAAS,UAAU;MAAmB,UAAA;KAEnD,CAAA;KAET,QAAQ,SAAS,QAAQ,KACxB,oBAAC,QAAD;MACE,MAAK;MACL,UAAU;MACV,eAAe,KAAK,WAAW;MAChC,UAAA;KAEO,CAAA;KAET,QAAQ,SAAS,SAAS,KAAK,aAAa,iBAC3C,oBAAC,QAAD;MAAQ,MAAK;MAAQ,UAAU;MAAM,eAAe,KAAK,QAAQ;MAAG,UAAA;KAE5D,CAAA;KAET,QAAQ,SAAS,QAAQ,KAAK,aAAa,eAC1C,oBAAC,QAAD;MACE,MAAK;MACL,OAAM;MACN,UAAU;MACV,eAAe,cAAc,IAAI;MAClC,UAAA;KAEO,CAAA;KAEV,oBAAC,QAAD;MAAQ,MAAK;MAAQ,UAAU;MAAM,SAAS,UAAU;MAAO,UAAA;KAEvD,CAAA;IACH;;GACN;GACA,UAAU,QACT,oBAAC,OAAD;IAAO,UAAS;IAAQ,IAAI,EAAE,IAAI,IAAI;IACnC,UAAA;GACI,CAAA;GAET,oBAAC,eAAD;IACE,MAAM;IACN,OAAM;IACN,cAAa;IACP;IACN,eAAe,cAAc,KAAK;IAClC,iBAAiB,KAAK,OAAO;IAE5B,UAAA,UAAU,cACP,iDACA,GAAG,MAAM,GAAG,UAAU,IAAI,cAAc,cAAc;GAC7C,CAAA;EACV;;AAEX;;;;ACvNA,SAAgB,mBAAkC;CAChD,MAAM,CAAC,UAAU,eAAe,SAA4B,CAAC,CAAC;CAC9D,MAAM,CAAC,aAAa,kBAAkB,SAAS,KAAK;CACpD,MAAM,SAAS,aACZ,IAAY,UAA6B,CAAC,MAAM;EAC/C,eAAe,KAAK;EACpB,aAAa,YAAY;GAEvB,IAAI,aAAa,OAAO,QAAQ,QAAQ,MAAM,MAAM,EAAE;GACtD,OAAO,QAAQ,SAAS,EAAE,IACtB,QAAQ,QAAQ,MAAM,MAAM,EAAE,IAC9B,CAAC,GAAG,SAAS,EAAE;EACrB,CAAC;CACH,GACA,CAAC,WAAW,CACd;CACA,MAAM,UAAU,aAAa,KAAwB,OAAgB;EACnE,eAAe,KAAK;EACpB,aAAa,YAAY;GACvB,MAAM,OAAO,QAAQ,QAAQ,MAAM,CAAC,IAAI,SAAS,CAAC,CAAC;GACnD,OAAO,KAAK,CAAC,GAAG,MAAM,GAAG,GAAG,IAAI;EAClC,CAAC;CACH,GAAG,CAAC,CAAC;CACL,MAAM,oBAAoB,kBAAkB;EAC1C,YAAY,CAAC,CAAC;EACd,eAAe,IAAI;CACrB,GAAG,CAAC,CAAC;CACL,MAAM,QAAQ,kBAAkB;EAC9B,YAAY,CAAC,CAAC;EACd,eAAe,KAAK;CACtB,GAAG,CAAC,CAAC;CACL,OAAO,eACE;EACL;EACA;EACA,aAAa,OAAO,SAAS,SAAS,EAAE;EACxC;EACA;EACA;EACA;CACF,IACA;EAAC;EAAU;EAAa;EAAQ;EAAS;EAAmB;CAAK,CACnE;AACF;;;;ACzBA,SAAgB,UAAU,EACxB,OACA,SACA,SACA,QAAQ,IACR,WACA,GAAG,WAC4B;CAC/B,MAAM,YAAY,iBAAiB;CAEnC,MAAM,YAAY,KAAK,UAAU,WAAW,CAAC,CAAC;CAC9C,MAAM,CAAC,aAAa,kBAAkB,SAAS,SAAS;CACxD,IAAI,gBAAgB,WAAW;EAC7B,eAAe,SAAS;EACxB,UAAU,MAAM;CAClB;CACA,MAAM,OAAO,MAAM,MAAM,QAAQ;EAC/B,SAAS,eAAe,WAAW,CAAC,CAAC;EACrC;CACF,CAAC;CACD,MAAM,SACJ,YAAY,KAAA,IACR,MAAM,OAAO,QAAQ,MAAM,CAAC,cAAc,SAAS,EAAE,IAAI,CAAC,CAAC,CAAC,MAAM,GAAG,CAAC,IACtE,MAAM,OAAO,QAAQ,MAAM,QAAQ,SAAS,EAAE,IAAI,CAAC;CACzD,IAAI,KAAK,WACP,OACE,oBAAC,KAAD;EAAK,IAAI;GAAE,SAAS;GAAQ,gBAAgB;GAAU,GAAG;EAAE;EACzD,UAAA,oBAAC,kBAAD,EAAkB,cAAW,UAAW,CAAA;CACrC,CAAA;CAGT,IAAI,KAAK,UAAU,MACjB,OAAO,oBAAC,OAAD;EAAO,UAAS;EAAS,UAAA,KAAK,MAAM;CAAe,CAAA;CAE5D,MAAM,QAAQ,QACZ,IAAI,MAAM,SAAS;CACrB,MAAM,MAAM,KAAK,KAAK,IAAI,IAAI;CAC9B,MAAM,SAAS,IAAI,QAChB,OAAO,UAAU,eAAe,UAAU,WAAW,EAAE,CAC1D;CACA,OACE,qBAAC,OAAD;EAAO,SAAS;EAAhB,UAAA,CACE,oBAAC,aAAD;GACS;GACI;GACF;GACT,GAAI;EACL,CAAA,GACD,qBAAC,OAAD;GAAO,MAAK;GAAQ,cAAY,MAAM,SAAS;GAA/C,UAAA,CACE,oBAAC,WAAD,EAAA,UACE,qBAAC,UAAD,EAAA,UAAA,CACE,oBAAC,WAAD;IAAW,SAAQ;IACjB,UAAA,oBAAC,UAAD;KACE,SAAS,IAAI,SAAS,KAAK,OAAO,WAAW,IAAI;KACjD,eAAe,OAAO,SAAS,KAAK,OAAO,SAAS,IAAI;KACxD,WAAW,UACT,UAAU,QAAQ,KAAK,MAAM,OAAO,OAAO;KAE7C,WAAW,EACT,OAAO,EAAE,cAAc,0BAA0B,EACnD;IACD,CAAA;GACQ,CAAA,GACV,OAAO,KAAK,MACX,oBAAC,WAAD,EAAA,UAAyB,EAAE,MAAiB,GAA5B,EAAE,IAA0B,CAC7C,CACO,EAAA,CAAA,EACD,CAAA,GACX,oBAAC,WAAD,EAAA,UACG,KAAK,KAAK,KAAK,QAAQ;IACtB,MAAM,KAAK,KAAK,GAAG;IACnB,MAAM,KAAK,UAAU,eAAe,UAAU,WAAW,EAAE;IAC3D,OACE,qBAAC,UAAD;KAAmB,OAAA;KAAM,UAAU;KAAnC,UAAA,CACE,oBAAC,WAAD;MAAW,SAAQ;MACjB,UAAA,oBAAC,UAAD;OACE,SAAS;OACT,gBAAgB,UAAU,OAAO,IAAI,GAAG;OACxC,WAAW,EACT,OAAO,EAAE,cAAc,iBAAiB,KAAK,EAC/C;MACD,CAAA;KACQ,CAAA,GACV,OAAO,KAAK,MACX,oBAAC,WAAD,EAAA,UACE,oBAAC,cAAD;MACE,OAAO;MACP,UAAU,MAAM,SAAS;MACzB,OAAO,IAAI,EAAE;MACF;KACZ,CAAA,EACQ,GAPK,EAAE,IAOP,CACZ,CACO;IApBK,GAAA,EAoBL;GAEd,CAAC,EACQ,CAAA,CACN;EACF,CAAA,CAAA;;AAEX;;;;;;AAYA,SAAgB,YAAY,EAC1B,UACA,YACA,GAAG,QAC8B;CACjC,OACE,oBAAC,cAAD;EAAc,MAAM;EAAsB;EACtC,WAAA,UAAU,oBAAC,WAAD;GAAkB;GAAO,GAAI;EAAO,CAAA;CACpC,CAAA;AAElB;;;;AC/IA,SAAgB,eAAe,EAC7B,OACA,SACA,YAC2C;CAC3C,IAAI,CAAC,MAAM,aAAa,iBAAiB,OAAO;CAChD,OACE,oBAAC,kBAAD;EACE,OAAM;EACN,SACE,oBAAC,QAAD;GACW;GACT,WAAW,UAAU,SAAS,MAAM,OAAO,OAAO;EACnD,CAAA;CAEJ,CAAA;AAEL;;;;;AAMA,SAAgB,cAAc,EAC5B,OACA,IACA,QACA,YACA,UACA,QAAQ,WACR,WACA,WAAW,SAYW;CACtB,MAAM,SAAS,MAAM,MAAM,UAAU;CACrC,MAAM,UAAU,WAAW,KAAK;CAChC,MAAM,CAAC,UAAU,eAAe,SAAS,KAAK;CAC9C,IAAI,CAAC,MAAM,aAAa,iBAAiB,OAAO;CAChD,MAAM,QAAQ,OAAO,SAAS,QAAQ;CACtC,OACE,qBAAA,UAAA,EAAA,UAAA;EACG,CAAC,YACA,oBAAC,QAAD;GACE,OAAM;GACN,MAAK;GACL,cAAY;GACZ,UAAU,OAAO;GACjB,eACE,OAAO,OAAO,IAAI,EAChB,iBAAiB;IACf,YAAY,IAAI;IAChB,aAAa;IACb,SAAS;GACX,EACF,CAAC;GAGF,UAAA;EACK,CAAA;EAET,UAAU,QAAQ,oBAAC,OAAD;GAAO,UAAS;GAAS,UAAA,MAAM;EAAe,CAAA;EACjE,oBAAC,UAAD;GACE,MAAM;GACN,kBAAkB;GAClB,UAAU,QAAQ,WAAW;IAC3B,IAAI,WAAW,aAAa,YAAY,KAAK;GAC/C;GACA,SAAQ;GACR,QACE,oBAAC,QAAD;IACE,MAAK;IACL,OAAM;IACN,eACE,QAAQ,OAAO,IAAI,EACjB,iBAAiB;KACf,YAAY,KAAK;KACjB,WAAW;KACX,SAAS;IACX,EACF,CAAC;IAEJ,UAAA;GAEO,CAAA;EAEX,CAAA;CACD,EAAA,CAAA;AAEN;;AAGA,SAAgB,cAAc,EAC5B,OACA,IACA,UACyC;CACzC,MAAM,UAAU,WAAW,KAAK;CAChC,IAAI,CAAC,MAAM,aAAa,iBAAiB,OAAO;CAChD,OACE,qBAAA,UAAA,EAAA,UAAA,CACE,oBAAC,QAAD;EACE,MAAK;EACL,SAAQ;EACR,UAAU,QAAQ;EAClB,eAAe,QAAQ,OAAO,IAAI,EAAE,iBAAiB,SAAS,EAAE,CAAC;EAClE,UAAA;CAEO,CAAA,GACP,QAAQ,UAAU,QACjB,oBAAC,OAAD;EAAO,UAAS;EAAS,UAAA,QAAQ,MAAM;CAAe,CAAA,CAExD,EAAA,CAAA;AAEN;;;;ACtFA,SAAgB,aAAa,OAAwC;CACnE,OACE,oBAAC,cAAD;EACE,MAAM,MAAM;EACZ,YAAY,MAAM;EAClB,SAAS,oBAAA,UAAA,CAAI,CAAA;EACb,gBAAgB;EAEd,WAAA,UACA,MAAM,YAAY,SAChB,MAAM,aAAa,kBACjB,oBAAC,eAAD;GACS;GACP,IAAI,MAAM;GACV,OAAO,MAAM,SAAS;GACtB,WAAW,GAAG,MAAM,SAAS,SAAS,GAAG,MAAM,eAAe,SAAS,GAAG,MAAM;GAChF,kBAAkB,MAAM,YAAY,MAAM,EAAE;GAC5C,gBAAgB,MAAM,WAAW,MAAM,EAAE;EAC1C,CAAA,IACC,OAEJ,oBAAC,kBAAD;GAAyB;GAAO,GAAI;EAAQ,CAAA;CAGpC,CAAA;AAElB;AAEA,SAAS,cAAc,EACrB,OACA,IACA,OACA,aAMe;CACf,MAAM,SAAS,MAAM,MAAM,UAAU,EAAE;CACvC,MAAM,QACJ,UAAU,KAAA,IACN,MAAM,OAAO,QAAQ,MAAM,EAAE,SAAS,IAAI,CAAC,CAAC,MAAM,GAAG,CAAC,IACtD,MAAM,OAAO,QAAQ,MAAM,MAAM,SAAS,EAAE,IAAI,CAAC;CACvD,MAAM,MAAM,OAAO;CACnB,OACE,oBAAC,OAAD;EAAO,WAAU;EAAK,SAAS;EAAG,IAAI,EAAE,GAAG,EAAE;EAC1C,UAAA,QAAQ,KAAA,KACP,MAAM,KAAK,UACT,qBAAC,OAAD;GAAwB,WAAU;GAAM,SAAS;GAAjD,UAAA,CACE,oBAAC,YAAD;IACE,WAAU;IACV,SAAQ;IACR,IAAI;KAAE,OAAO;KAAkB,UAAU;IAAO;IAE/C,UAAA,MAAM;GACG,CAAA,GACZ,oBAAC,YAAD;IAAY,WAAU;IAAK,SAAQ;IAAQ,IAAI,EAAE,GAAG,EAAE;IACpD,UAAA,oBAAC,cAAD;KACS;KACP,UAAU,MAAM,SAAS;KACzB,OAAO,IAAI,MAAM;KACjB,QAAQ;KACG;IACZ,CAAA;GACS,CAAA,CACP;EAjBK,GAAA,MAAM,IAiBX,CACR;CACE,CAAA;AAEX;AAEA,SAAS,iBAAiB,EACxB,OACA,GAAG,SAC0E;CAC7E,MAAM,EAAE,IAAI,UAAU,WAAW,SAAS,QAAS;CACnD,MAAM,QAAQ,MAAM,eAAe;CACnC,MAAM,SAAS,MAAM,MAAM,UAAU;CACrC,MAAM,CAAC,YAAY,iBAAiB,SAAS,KAAK;CAClD,MAAM,CAAC,OAAO,YAAY,SAAuB,IAAI;CACrD,MAAM,CAAC,OAAO,YAAY,SAAwB,IAAI;CACtD,MAAM,CAAC,MAAM,WAAW,SAAS,KAAK;CACtC,MAAM,QAAQ,OAAkD,KAAA,CAAS;CAEzE,MAAM,MAAM,YAA8B;EACxC,QAAQ,IAAI;EACZ,IAAI;GACF,MAAM,OAAO,YAAY,EAAE;GAC3B,MAAM,YAAY,EAAE;GACpB,OAAO;EACT,SAAS,SAAS;GAChB,SAAS,mBAAmB,QAAQ,QAAQ,UAAU,kBAAkB;GACxE,OAAO;EACT,UAAU;GACR,QAAQ,KAAK;EACf;CACF;CAGA,MAAM,UAAU,OAA6C,KAAA,CAAS;CACtE,sBACc;EACV,IAAI,MAAM,YAAY,KAAA,GAAW;GAC/B,aAAa,MAAM,OAAO;GAC1B,QAAa,UAAU;EACzB;CACF,GACA,CAAC,CACH;CAEA,MAAM,kBAAwB;EAC5B,QAAQ,UAAU;EAClB,SAAS;GACP,MAAM,YAAY,MAAM,GAAG,GAAG;GAC9B,YAAY;IACV,aAAa,MAAM,OAAO;IAC1B,MAAM,UAAU,KAAA;IAChB,SAAS,IAAI;IACb,MAAM,WAAW,EAAE;GACrB;EACF,CAAC;EACD,MAAM,UAAU,iBAAiB;GAC/B,MAAM,UAAU,KAAA;GAChB,SAAS,IAAI;GACb,IAAS;EACX,GAAG,MAAM;CACX;CAEA,MAAM,cAAoB;EACxB,IAAI,YAAY,WAAW,cAAc,IAAI;OACxC,IAAI,YAAY,QAAQ,UAAU;OAClC,IAAS;CAChB;CAEA,OACE,qBAAA,UAAA,EAAA,UAAA;EACE,oBAAC,QAAD;GACE,OAAM;GACN,MAAK;GACL,UAAU,QAAS,YAAY,UAAU,UAAU;GACnD,SAAS;GACT,cAAY,GAAG,MAAM,SAAS,SAAS,GAAG,MAAM,GAAG;GAElD,UAAA,MAAM,SAAS;EACV,CAAA;EACP,YAAY,aACX,oBAAC,aAAD;GACE,MAAM;GACN,eAAe,cAAc,KAAK;GAClC,OAAO,UAAU,MAAM,GAAG,GAAG;GAC7B,YAAW;GACX,UAAS;GACT,SACE,oBAAC,QAAD;IACE,OAAM;IACN,SAAQ;IACR,eAAe;KACb,cAAc,KAAK;KACnB,IAAS;IACX;IAEC,UAAA,MAAM,SAAS;GACV,CAAA;GAGV,UAAA,oBAAC,eAAD;IACS;IACH;IACJ,OAAO,MAAM;IACb,WAAW,MAAM;GAClB,CAAA;EACU,CAAA;EAEf,oBAAC,UAAD;GACE,MAAM,UAAU;GAChB,SAAS,OAAO;GAChB,kBAAkB;GAClB,QACE,oBAAC,QAAD;IAAQ,OAAM;IAAU,MAAK;IAAQ,SAAS,OAAO;IAAM,UAAA;GAEnD,CAAA;EAEX,CAAA;EACD,oBAAC,UAAD;GAAU,MAAM,UAAU;GAAM,eAAe,SAAS,IAAI;GAC1D,UAAA,oBAAC,OAAD;IAAO,UAAS;IAAQ,eAAe,SAAS,IAAI;IACjD,UAAA;GACI,CAAA;EACC,CAAA;CACV,EAAA,CAAA;AAEN;;;AC3OA,MAAM,eAA6C;CACjD,WAAW;CACX,OAAO;CACP,UAAU;AACZ;AAEA,MAAM,eAAe;CACnB,WAAW;CACX,OAAO;CACP,UAAU;AACZ;;AAQA,SAAgB,YAAY,EAC1B,OACA,UACwC;CACxC,MAAM,EAAE,eAAe,oBAAoB,MAAM;CACjD,IAAI,CAAC,iBAAiB,CAAC,iBAAiB,OAAO;CAC/C,MAAM,SAAS,aAAa,MAAM;CAClC,OACE,oBAAC,MAAD;EACE,MAAK;EACL,SAAQ;EACR,OAAO,aAAa;EACpB,OAAO,aAAa;CACrB,CAAA;AAEL;;AAUA,SAAgB,cAAc,EAC5B,OACA,IACA,UACyC;CACzC,MAAM,UAAU,WAAW,KAAK;CAChC,IAAI,CAAC,MAAM,aAAa,eAAe,OAAO;CAC9C,OACE,qBAAA,UAAA,EAAA,UAAA,CACE,oBAAC,QAAD;EACE,SAAQ;EACR,MAAK;EACL,UAAU,QAAQ;EAClB,eAAe,QAAQ,OAAO,IAAI,EAAE,iBAAiB,SAAS,EAAE,CAAC;EAClE,UAAA;CAEO,CAAA,GACP,QAAQ,UAAU,QACjB,oBAAC,OAAD;EAAO,UAAS;EAAS,UAAA,QAAQ,MAAM;CAAe,CAAA,CAExD,EAAA,CAAA;AAEN;;AAGA,SAAgB,mBAAmB,EACjC,OACA,IACA,UACyC;CACzC,MAAM,SAAS,MAAM,MAAM,UAAU;CACrC,MAAM,CAAC,MAAM,WAAW,SAAS,KAAK;CACtC,IAAI,CAAC,MAAM,aAAa,eAAe,OAAO;CAC9C,OACE,qBAAA,UAAA,EAAA,UAAA,CACE,oBAAC,QAAD;EACE,OAAM;EACN,MAAK;EACL,eAAe;GACb,OAAO,MAAM;GACb,QAAQ,IAAI;EACd;EACD,UAAA;CAEO,CAAA,GACR,qBAAC,eAAD;EACQ;EACN,OAAM;EACN,cAAa;EACb,MAAM,OAAO;EACb,eAAe,QAAQ,KAAK;EAC5B,iBACE,OAAO,OAAO,IAAI,EAChB,iBAAiB;GACf,QAAQ,KAAK;GACb,SAAS;EACX,EACF,CAAC;EAZL,UAAA,CAcC,oDAEE,OAAO,UAAU,QAAQ,IAAI,OAAO,MAAM,SAC9B;CACf,CAAA,CAAA,EAAA,CAAA;AAEN;;AAWA,SAAgB,cAAc,EAC5B,OACA,QACA,IACA,aAC0C;CAC1C,IAAI,CAAC,MAAM,aAAa,eAAe,OAAO;CAC9C,OACE,qBAAC,OAAD;EACE,WAAU;EACV,SAAS;EACT,IAAI;GAAE,YAAY;GAAU,UAAU;EAAO;EAH/C,UAAA,CAKE,oBAAC,aAAD;GAAoB;GAAe;EAAS,CAAA,GAC3C,aAAa,MAAM,MAAM,WACxB,qBAAA,UAAA,EAAA,UAAA,CACE,oBAAC,eAAD;GAAsB;GAAW;GAAI,QAAQ;EAAY,CAAA,GACzD,oBAAC,oBAAD;GAA2B;GAAW;GAAI,QAAQ;EAAY,CAAA,CAC9D,EAAA,CAAA,CAEC;;AAEX;;;;ACrIA,SAAgB,UAAU,EACxB,UACA,QACA,QACA,aAC+B;CAC/B,OACE,oBAAC,KAAD;EACE,WAAU;EACV,IAAI;GACF,SAAS;GACT,qBAAqB;IACnB,IAAI;IACJ,IAAI;GACN;GACA,WAAW;GACX,QAAQ;GACR,GAAG;EACL;EAEC,UAAA,OAAO,KAAK,UACX,qBAAC,KAAD;GAAsB,IAAI,EAAE,SAAS,WAAW;GAAhD,UAAA,CACE,oBAAC,YAAD;IACE,WAAU;IACV,SAAQ;IACR,OAAM;IACN,IAAI,EAAE,IAAI,GAAI;IAEb,UAAA,MAAM;GACG,CAAA,GACZ,oBAAC,KAAD;IAAK,WAAU;IAAK,IAAI;KAAE,GAAG;KAAG,UAAU;IAAE;IAC1C,UAAA,oBAAC,cAAD;KACS;KACG;KACV,OAAO,OAAO,MAAM;KACZ;KACG;IACZ,CAAA;GACE,CAAA,CACF;EAlBK,GAAA,MAAM,IAkBX,CACN;CACE,CAAA;AAET;;;;AC/CA,SAAgB,YAAY,MAAyC;CACnE,OAAO,KAAK,KAAK,SAAS;EACxB,IAAI,OAAO,IAAI,KAAK;EACpB,QAAQ,OAAO,IAAI,SAAS;EAC5B,OAAO,OAAO,IAAI,QAAQ;EAC1B,WAAW,OAAO,IAAI,aAAa;EACnC,UAAW,IAAI,eAAe,CAAC;CACjC,EAAE;AACJ;AAEA,MAAMC,UAAQ,GAAY,MACxB,KAAK,UAAU,CAAC,MAAM,KAAK,UAAU,CAAC;;AAGxC,SAAgB,cACd,QACA,QACA,OACU;CACV,OAAO,OACJ,QAAQ,MAAM,CAACA,OAAK,OAAO,EAAE,OAAO,MAAM,EAAE,KAAK,CAAC,CAAC,CACnD,KAAK,MAAM,EAAE,IAAI;AACtB;;;;;;AAOA,SAAgB,aACd,QACA,UACY;CACZ,MAAM,QAAiC,CAAC;CACxC,KAAK,MAAM,KAAK,QAAQ;EACtB,IAAI,EAAE,YAAY,EAAE,EAAE,QAAQ,WAAW;EACzC,MAAM,QAAQ,SAAS,EAAE;EACzB,IAAI,UAAU,QAAQ,CAAC,EAAE,UAAU;EACnC,MAAM,EAAE,QAAQ;CAClB;CACA,OAAO;AACT;;AAGA,MAAa,mBAAoC;CAC/C,MAAM;CACN,OAAO;CACP,MAAM;CACN,QAAQ;CACR,UAAU;CACV,UAAU;CACV,UAAU;CACV,SAAS;CACT,UAAU;CACV,aAAa;EACX,WAAW,KAAA;EACX,WAAW,KAAA;EACX,SAAS,KAAA;EACT,SAAS,KAAA;EACT,SAAS,KAAA;CACX;CACA,YAAY;CACZ,UAAU;CACV,WAAW,CAAC;CACZ,SAAS;CACT,aAAa;AACf;;;ACtBA,SAAS,KAAK,EACZ,OACA,OACA,aAKe;CACf,OACE,oBAAC,cAAD;EACE,OAAO;EACP,UAAU,MAAM,SAAS;EAClB;EACI;CACZ,CAAA;AAEL;;AAGA,SAAS,oBAAoB,EAC3B,OACA,IACA,WACA,WACA,cAC6B;CAC7B,MAAM,SAAS,MAAM,MAAM,UAAU;CACrC,MAAM,aAAa,sBAAsB,MAAM,SAAS,IAAI;CAC5D,MAAM,CAAC,QAAQ,aAAa,SAA0B,IAAI;CAC1D,OACE,qBAAA,UAAA,EAAA,UAAA;EACG,OAAO,UAAU,QAChB,oBAAC,OAAD;GAAO,UAAS;GAAS,UAAA,OAAO,MAAM;EAAe,CAAA;EAEvD,oBAAC,MAAD;GAAM,cAAW;GAAY,gBAAA;GAC1B,UAAA,UAAU,KAAK,aACd,oBAAC,UAAD;IAEE,SAAA;IACA,iBACE,oBAAC,QAAD;KACE,MAAK;KACL,cAAY,oBAAoB,SAAS;KACzC,eAAe;MACb,OAAO,MAAM;MACb,UAAU,QAAQ;KACpB;KACD,UAAA;IAEO,CAAA;IAGV,UAAA,oBAAC,cAAD;KACE,SAAS,GAAG,SAAS,OAAO,MAAM,SAAS;KAC3C,WACE,oBAAC,MAAD;MACS;MACP,OAAO,SAAS;MACL;KACZ,CAAA;KAEH,WAAW,EAAE,WAAW,EAAE,WAAW,MAAM,EAAE;IAC9C,CAAA;GACO,GA1BH,SAAS,EA0BN,CACX;EACG,CAAA;EACN,oBAAC,eAAD;GACE,MAAM,WAAW;GACjB,OAAM;GACN,cAAa;GACb,MAAM,OAAO;GACb,eAAe,UAAU,IAAI;GAC7B,iBAAiB;IAEf,MAAM,WAAW;IACjB,OAAO,OACL;KAAE;KAAI,OAAO,aAAa,MAAM,QAAQ,SAAS,QAAQ;IAAE,GAC3D,EACE,iBAAiB;KACf,UAAU,IAAI;KACd,WAAgB;KAChB,aAAa,QAAQ;IACvB,EACF,CACF;GACF;GACD,UAAA;EAEc,CAAA;CACf,EAAA,CAAA;AAEN;AAEA,MAAM,iBACJ,QACA,QACA,UACW;CACX,MAAM,QAAQ,cAAc,QAAQ,QAAQ,KAAK;CACjD,OAAO,OACJ,QAAQ,MAAM,MAAM,SAAS,EAAE,IAAI,CAAC,CAAC,CACrC,KAAK,MAAM,EAAE,KAAK,CAAC,CACnB,KAAK,IAAI;AACd;;AAGA,SAAS,qBAAqB,EAC5B,OACA,WACA,aAC6B;CAC7B,OACE,qBAAC,OAAD;EAAO,MAAK;EAAQ,cAAW;EAA/B,UAAA,CACE,oBAAC,WAAD,EAAA,UACE,qBAAC,UAAD,EAAA,UAAA;GACE,oBAAC,WAAD,EAAA,UAAW,OAAe,CAAA;GAC1B,oBAAC,WAAD,EAAA,UAAW,SAAiB,CAAA;GAC5B,oBAAC,WAAD,EAAA,UAAW,QAAgB,CAAA;GAC3B,oBAAC,WAAD,EAAA,UAAW,iBAAyB,CAAA;EAC5B,EAAA,CAAA,EACD,CAAA,GACX,oBAAC,WAAD,EAAA,UACG,UAAU,KAAK,UAAU,UACxB,qBAAC,UAAD,EAAA,UAAA;GACE,oBAAC,WAAD,EAAA,UACE,oBAAC,MAAD;IACS;IACP,OAAO,SAAS;IACL;GACZ,CAAA,EACQ,CAAA;GACX,oBAAC,WAAD,EAAA,UAAY,SAAS,OAAkB,CAAA;GACvC,oBAAC,WAAD,EAAA,UAAY,SAAS,MAAiB,CAAA;GACtC,oBAAC,WAAD,EAAA,UACG,cACC,MAAM,QACN,UAAU,QAAQ,EAAE,EAAE,YAAY,CAAC,GACnC,SAAS,QACX,EACS,CAAA;EACH,EAAA,GAjBK,SAAS,EAiBd,CACX,EACQ,CAAA,CACN;;AAEX;AAEA,SAAS,eAAe,EACtB,OACA,OACA,WACA,YAMe;CACf,OACE,oBAAC,WAAD;EACE,QAAA;EACA,MAAK;EACE;EACA;EACP,WAAW,UAAU,SAAS,OAAO,MAAM,OAAO,KAAK,CAAC;EACxD,IAAI,EAAE,UAAU,IAAI;EAEnB,UAAA,UAAU,KAAK,aACd,oBAAC,UAAD;GAA4B,OAAO,SAAS;GACzC,UAAA,IAAI,SAAS,GAAG,GAAG,SAAS;EACrB,GAFK,SAAS,EAEd,CACX;CACQ,CAAA;AAEf;;AAGA,SAAS,oBAAoB,EAC3B,OACA,WACA,aAC6B;CAC7B,MAAM,SAAS,UAAU;CACzB,MAAM,CAAC,MAAM,WAAW,SAAwB,IAAI;CACpD,MAAM,CAAC,QAAQ,aAAa,SAAwB,IAAI;CACxD,MAAM,CAAC,KAAK,UAAU,SAAS,KAAK;CACpC,MAAM,KAAK,UAAU,MAAM,MAAM,EAAE,OAAO,IAAI,KAAK;CACnD,MAAM,OACJ,UAAU,MAAM,MAAM,EAAE,OAAO,MAAM,KACrC,UAAU,UAAU,QAAQ,EAAE,IAAI,MAClC;CACF,MAAM,UAAU,IAAI,IAClB,cAAc,MAAM,QAAQ,KAAK,UAAU,GAAG,QAAQ,CACxD;CACA,MAAM,OAAO,MAAM,OAAO,QAAQ,MAAM,OAAO,QAAQ,IAAI,EAAE,IAAI,CAAC;CAClE,MAAM,QAAQ,OAAwB,aACpC,oBAAC,cAAD;EACS;EACP,UAAU,MAAM,SAAS;EACzB,OAAO,SAAS,SAAS,MAAM;EACpB;CACZ,CAAA;CAEH,OACE,qBAAC,OAAD;EAAO,SAAS;EAAhB,UAAA,CACE,qBAAC,OAAD;GAAO,WAAU;GAAM,SAAS;GAAG,YAAA;GAAW,IAAI,EAAE,UAAU,OAAO;GAArE,UAAA;IACE,oBAAC,gBAAD;KACE,OAAM;KACN,OAAO,KAAK;KACD;KACX,UAAU;IACX,CAAA;IACD,oBAAC,gBAAD;KACE,OAAM;KACN,OAAO,GAAG;KACC;KACX,UAAU;IACX,CAAA;IACD,oBAAC,kBAAD;KACE,OAAM;KACN,SACE,oBAAC,QAAD;MACE,SAAS;MACT,WAAW,UAAU,OAAO,MAAM,OAAO,OAAO;KACjD,CAAA;IAEJ,CAAA;GACI;EACN,CAAA,GAAA,KAAK,WAAW,IACf,oBAAC,YAAD;GAAY,OAAM;GAAiB,UAAA;EAEvB,CAAA,IAEZ,qBAAC,OAAD;GAAO,MAAK;GAAQ,cAAW;GAA/B,UAAA,CACE,oBAAC,WAAD,EAAA,UACE,qBAAC,UAAD,EAAA,UAAA;IACE,oBAAC,WAAD,EAAA,UAAW,QAAgB,CAAA;IAC3B,oBAAC,WAAD,EAAA,UAAW,SAAiB,CAAA;IAC5B,oBAAC,WAAD,EAAA,UAAW,QAAgB,CAAA;GACnB,EAAA,CAAA,EACD,CAAA,GACX,oBAAC,WAAD,EAAA,UACG,KAAK,KAAK,UACT,qBAAC,UAAD;IAEE,IACE,QAAQ,IAAI,MAAM,IAAI,IAClB,EAAE,SAAS,kBAAkB,IAC7B,KAAA;IALR,UAAA;KAQE,qBAAC,WAAD;MAAW,WAAU;MAAK,OAAM;MAAhC,UAAA,CACG,MAAM,OACN,QAAQ,IAAI,MAAM,IAAI,KACrB,oBAAC,MAAD;OAAM,MAAK;OAAQ,OAAM;OAAU,IAAI,EAAE,IAAI,EAAE;MAAI,CAAA,CAE5C;;KACX,oBAAC,WAAD,EAAA,UAAY,KAAK,OAAO,IAAI,EAAa,CAAA;KACzC,oBAAC,WAAD,EAAA,UAAY,KAAK,OAAO,EAAE,EAAa,CAAA;IAC/B;GAfH,GAAA,MAAM,IAeH,CACX,EACQ,CAAA,CACN;EAEJ,CAAA,CAAA;;AAEX;;AAGA,SAAS,uBAAuB,EAC9B,OACA,WACA,aAC6B;CAC7B,MAAM,CAAC,UAAU,eAAe,SAAwB,IAAI;CAC5D,MAAM,SACJ,UAAU,MAAM,MAAM,EAAE,OAAO,QAAQ,KAAM,UAAU;CACzD,OACE,qBAAC,OAAD;EAAO,SAAS;EAAhB,UAAA,CACE,oBAAC,KAAD,EAAA,UACE,oBAAC,gBAAD;GACE,OAAM;GACN,OAAO,OAAO;GACH;GACX,UAAU;EACX,CAAA,EACE,CAAA,GACL,oBAAC,WAAD;GACE,UAAU,MAAM,SAAS;GACzB,QAAQ,MAAM;GACd,QAAQ,OAAO;GACJ;EACZ,CAAA,CACI;;AAEX;AAEA,MAAM,WAAW;CACf,MAAM;CACN,OAAO;CACP,MAAM;CACN,SAAS;AACX;AAKA,SAAS,cAAc,EACrB,OACA,IACA,UAAU,QACV,WACA,cACoC;CACpC,MAAM,QAAQ,MAAM,MAAM,aAAa,EAAE;CACzC,IAAI,MAAM,WACR,OACE,oBAAC,KAAD;EAAK,IAAI;GAAE,SAAS;GAAQ,gBAAgB;GAAU,GAAG;EAAE;EACzD,UAAA,oBAAC,kBAAD,EAAkB,cAAW,UAAW,CAAA;CACrC,CAAA;CAGT,IAAI,MAAM,UAAU,MAClB,OAAO,oBAAC,OAAD;EAAO,UAAS;EAAS,UAAA,MAAM,MAAM;CAAe,CAAA;CAE7D,MAAM,YAAY,YAAY,MAAM,IAAI;CACxC,IAAI,UAAU,WAAW,GACvB,OAAO,oBAAC,YAAD;EAAY,OAAM;EAAiB,UAAA;CAA6B,CAAA;CAEzE,MAAM,UAAU,SAAS;CACzB,OACE,oBAAC,SAAD;EACS;EACH;EACO;EACA;EACC;CACb,CAAA;AAEL;;AAGA,SAAgB,eACd,OACqB;CACrB,OAAO,MAAM,MAAM,aAAa,YAC9B,oBAAC,eAAD,EAAe,GAAI,MAAQ,CAAA,IACzB;AACN;;;;;AAcA,SAAgB,gBAAgB,EAC9B,UACA,YACA,GAAG,QACkC;CACrC,OACE,oBAAC,cAAD;EAAc,MAAM;EAAsB;EACtC,WAAA,UAAU,oBAAC,gBAAD;GAAuB;GAAO,GAAI;EAAO,CAAA;CACzC,CAAA;AAElB;;;ACvXA,MAAM,kBAAwB,CAAC;AAQ/B,SAAS,WAAW,OAA+C;CACjE,OAAO,MAAM,OAAO,QAAQ,MAAM,CAAC,cAAc,SAAS,EAAE,IAAI,CAAC;AACnE;AAEA,SAAS,KAAK,EAAE,OAAO,QAAQ,aAAsC;CACnE,OACE,oBAAC,WAAD;EACE,UAAU,MAAM,SAAS;EACzB,QAAQ,WAAW,KAAK;EAChB;EACG;CACZ,CAAA;AAEL;;AAGA,SAAgB,eAAe,EAC7B,OACA,QACA,aAC0B;CAC1B,OACE,qBAAC,OAAD;EAAO,SAAQ;EAAW,IAAI,EAAE,GAAG,EAAE;EAArC,UAAA,CACE,oBAAC,YAAD;GAAY,WAAU;GAAK,SAAQ;GAAY,IAAI,EAAE,IAAI,IAAI;GAAG,UAAA;EAEpD,CAAA,GACZ,oBAAC,WAAD;GACE,UAAU,MAAM,SAAS;GACzB,QAAQ,MAAM,OAAO,QAAQ,MAAM,cAAc,SAAS,EAAE,IAAI,CAAC;GACzD;GACG;EACZ,CAAA,CACI;;AAEX;AAEA,SAAS,OAAO,EACd,OACA,QACA,WACA,MAC2C;CAC3C,MAAM,OAAO,MAAM;CACnB,MAAM,OAAO;EACX;GAAE,KAAK;GAAW,OAAO;EAAU;EACnC;GAAE,KAAK;GAAY,OAAO;EAAW;EACrC,GAAI,MAAM,aAAa,YACnB,CAAC;GAAE,KAAK;GAAW,OAAO;EAAU,CAAC,IACrC,CAAC;CACP;CACA,MAAM,CAAC,SAAS,cAAc,SAAS,SAAS;CAChD,OACE,qBAAC,KAAD,EAAA,UAAA,CACE,oBAAC,MAAD;EACE,OAAO;EACP,WAAW,QAAQ,QAAgB,WAAW,GAAG;EACjD,cAAW;EACX,IAAI;GAAE,cAAc;GAAG,aAAa;GAAW,IAAI;EAAE;EAEpD,UAAA,KAAK,KAAK,QACT,oBAAC,KAAD;GAEE,OAAO,IAAI;GACX,OAAO,IAAI;GACX,IAAI,GAAG,KAAK,GAAG,IAAI,IAAI;GACvB,iBAAe,GAAG,KAAK,GAAG,IAAI,IAAI;EACnC,GALM,IAAI,GAKV,CACF;CACG,CAAA,GACN,qBAAC,KAAD;EACE,MAAK;EACL,IAAI,GAAG,KAAK,GAAG,QAAQ;EACvB,mBAAiB,GAAG,KAAK,GAAG,QAAQ;EAHtC,UAAA;GAKG,YAAY,aACX,oBAAC,MAAD;IAAa;IAAe;IAAmB;GAAY,CAAA;GAE5D,YAAY,cACX,oBAAC,gBAAD;IAAuB;IAAe;IAAmB;GAAY,CAAA;GAEtE,YAAY,aACX,oBAAC,gBAAD;IACS;IACH;IACJ,SAAQ;IACG;GACZ,CAAA;EAEA;CACF,CAAA,CAAA,EAAA,CAAA;AAET;AAEA,SAAS,cAAc,EACrB,OACA,QACA,IACA,aAMe;CACf,MAAM,WAAW,aAAa,MAAM,MAAM;CAC1C,OACE,qBAAC,OAAD;EAAO,WAAU;EAAM,SAAS;EAAG,IAAI,EAAE,YAAY,SAAS;EAA9D,UAAA;GACE,oBAAC,eAAD;IACS;IACC;IACJ;IACO;GACZ,CAAA;GACA,YAAY,oBAAC,eAAD;IAAsB;IAAW;IAAI,QAAQ;GAAY,CAAA;GACtE,oBAAC,eAAD;IACS;IACH;IACJ,QAAQ;IACE;GACX,CAAA;EACI;;AAEX;AAEA,SAAS,aAAa,EACpB,OACA,IACA,QACA,SACA,WACA,OACA,YACA,MACA,SACA,SACA,aAMe;CACf,MAAM,UAAU,SAAS,GAAG,MAAM,SAAS,MAAM,IAAI;CACrD,MAAM,gBAAsB;EAC1B,QAAQ;EACR,YAAY;CACd;CACA,MAAM,UACJ,oBAAC,eAAD;EAAsB;EAAe;EAAY;EAAI,WAAW;CAAU,CAAA;CAE5E,MAAM,OAAkB;EAAE;EAAO;EAAQ;CAAU;CACnD,QAAQ,SAAR;EACE,KAAK,QACH,OACE,oBAAC,WAAD;GAAW,OAAO;GAAkB;GACjC,UAAA,eAAe,KAAA,IACd,oBAAC,MAAD,EAAM,GAAI,KAAO,CAAA,IAEjB,WAAW;IAAE;IAAO;IAAI;IAAQ,QAAQ;GAAQ,CAAC;EAE1C,CAAA;EAEf,KAAK,YACH,OACE,oBAAC,WAAD;GAAW,OAAO;GAAkB;GAClC,UAAA,qBAAC,OAAD;IACE,WAAW;KAAE,IAAI;KAAU,IAAI;IAAM;IACrC,SAAS;IACT,IAAI,EAAE,YAAY,EAAE,IAAI,aAAa,EAAE;IAHzC,UAAA,CAKE,oBAAC,KAAD;KAAK,IAAI;MAAE,MAAM;MAAG,UAAU;KAAE;KAC9B,UAAA,oBAAC,MAAD,EAAM,GAAI,KAAO,CAAA;IACd,CAAA,GACL,oBAAC,KAAD;KAAK,IAAI;MAAE,MAAM;MAAG,UAAU;KAAE;KAC9B,UAAA,oBAAC,gBAAD,EAAgB,GAAI,KAAO,CAAA;IACxB,CAAA,CACA;;EACE,CAAA;EAEf,KAAK,QACH,OACE,oBAAC,WAAD;GAAW,OAAO;GAAkB;GAClC,UAAA,oBAAC,QAAD;IAAQ,GAAI;IAAU;GAAK,CAAA;EAClB,CAAA;EAEf,KAAK;EACL,KAAK,UAEH,OACE,oBAFY,YAAY,WAAW,cAAc,aAEjD;GACQ;GACN,SAAS,WAAW;GACpB,OAAO;GACE;GAET,UAAA,qBAAC,OAAD;IAAO,SAAS;IAAhB,UAAA,CACE,oBAAC,MAAD,EAAM,GAAI,KAAO,CAAA,GACjB,oBAAC,gBAAD,EAAgB,GAAI,KAAO,CAAA,CACtB;;EACF,CAAA;EAGX,SACE,OACE,oBAAC,WAAD;GAAW,OAAO;GAAkB;GAClC,UAAA,oBAAC,MAAD,EAAM,GAAI,KAAO,CAAA;EACR,CAAA;CAEjB;AACF;;AAGA,SAAgB,YAAY,EAC1B,UAAU,QACV,OAAO,MACP,GAAG,QAC8B;CACjC,MAAM,QAAQ,KAAK,MAAM,MAAM,UAAU,KAAK,EAAE;CAChD,IAAI,MAAM,WACR,OACE,oBAAC,KAAD;EAAK,IAAI;GAAE,SAAS;GAAQ,gBAAgB;GAAU,GAAG;EAAE;EACzD,UAAA,oBAAC,kBAAD,EAAkB,cAAW,UAAW,CAAA;CACrC,CAAA;CAGT,IAAI,MAAM,UAAU,MAClB,OAAO,oBAAC,OAAD;EAAO,UAAS;EAAS,UAAA,MAAM,MAAM;CAAe,CAAA;CAE7D,OACE,oBAAC,cAAD;EACE,GAAI;EACJ,QAAQ,MAAM;EACL;EACH;EACN,eAAe,KAAK,MAAM,QAAQ;CACnC,CAAA;AAEL;;;;;;;AAaA,SAAgB,aAAa,EAC3B,UACA,YACA,GAAG,QAC+B;CAClC,OACE,oBAAC,cAAD;EAAc,MAAM;EAAsB;EACtC,WAAA,UAAU,oBAAC,aAAD;GAAoB;GAAO,GAAI;EAAO,CAAA;CACtC,CAAA;AAElB;;;;ACrSA,SAAS,SAAS,OAAsB,OAAoC;CAC1E,OAAO,MAAM,OAAO,SAAS,UAAmB;EAC9C,IAAI,CAAC,MAAM,aAAa,OAAO,CAAC;EAChC,IAAI,UAAU,KAAA,KAAa,CAAC,MAAM,SAAS,MAAM,IAAI,GAAG,OAAO,CAAC;EAChE,MAAM,KAAM,CAAC,MAAM,IAAI,CAAC,CAAW,MAAM,MAAM,MAAM,UAAU,SAAS,CAAC,CAAC;EAC1E,IAAI,OAAO,KAAA,GAAW,OAAO,CAAC;EAC9B,IAAI,MAAM,SAAS,WACjB,OAAO,CACL;GACE;GACA;GACA,QAAQ,CACN;IAAE,OAAO;IAAO,OAAO;GAAK,GAC5B;IAAE,OAAO;IAAM,OAAO;GAAM,CAC9B;EACF,CACF;EACF,IAAI,MAAM,YAAY,MAAM,OAAO,CAAC;EACpC,OAAO,CACL;GACE;GACA;GACA,QAAQ,MAAM,QAAQ,KAAK,OAAO;IAAE,OAAO,SAAS,CAAC;IAAG,OAAO;GAAE,EAAE;EACrE,CACF;CACF,CAAC;AACH;;AAGA,SAAgB,aAAa,EAC3B,OACA,SACA,UACA,UACyC;CACzC,MAAM,SAAS,SAAS,OAAO,MAAM;CACrC,IAAI,OAAO,WAAW,GAAG,OAAO;CAChC,OACE,oBAAC,KAAD;EAAK,WAAU;EAAQ,cAAW;EAC/B,UAAA,OAAO,KAAK,EAAE,OAAO,IAAI,aAAa;GACrC,MAAM,UAAU,QAAQ,MAAM,KAAK,GAAG;GACtC,MAAM,WACJ,YAAY,KAAA,IACR,CAAC,IACD,MAAM,QAAQ,OAAO,IAClB,UACD,CAAC,OAAuB;GAChC,MAAM,UAAU,UAA8B;IAC5C,MAAM,KAAK,SAAS,SAAS,KAAK;IAElC,MAAM,OACJ,OAAO,OACH,KACE,SAAS,QAAQ,MAAM,MAAM,KAAK,IAClC,CAAC,GAAG,UAAU,KAAK,IACrB,KACE,KAAA,IACA;IACR,SAAS;KACP,GAAG;MACF,MAAM,OAAO,OAAO,QAAQ,MAAM,OAAO,IAAI,IAAI;IACpD,CAAC;GACH;GACA,OACE,qBAAC,aAAD;IAEE,WAAU;IACV,SAAQ;IACR,IAAI;KAAE,SAAS;KAAS,IAAI;IAAE;IAJhC,UAAA,CAME,oBAAC,WAAD;KAAW,WAAU;KAAU,UAAA,MAAM;IAAiB,CAAA,GACtD,oBAAC,WAAD,EAAA,UACG,OAAO,KAAK,EAAE,OAAO,YACpB,oBAAC,kBAAD;KAES;KACP,SACE,oBAAC,UAAD;MACE,MAAK;MACL,SAAS,SAAS,SAAS,KAAK;MAChC,gBAAgB,OAAO,KAAK;KAC7B,CAAA;IAEJ,GATM,OAAO,KAAK,CASlB,CACF,EACQ,CAAA,CACA;GArBN,GAAA,MAAM,IAqBA;EAEjB,CAAC;CACE,CAAA;AAET;;;;ACxGA,SAAgB,cAAc,EAC5B,OACA,UACA,OACA,UACA,aACmC;CACnC,OACE,qBAAC,OAAD;EAAO,SAAS;EAAhB,UAAA,CACE,oBAAC,kBAAD;GACS;GACG;GACH;GACG;GACC;EACZ,CAAA,GACA,MAAM,SAAS,cACd,oBAAC,gBAAD,EAAA,UAAiB,GAAG,MAAM,MAAM,iBAAiC,CAAA,CAE9D;;AAEX;;;;ACnBA,SAAgB,UAAU,EACxB,OACA,SACA,UACA,QACA,aAC+B;CAC/B,MAAM,QACJ,WAAW,KAAA,IACP,MAAM,OAAO,OAAO,YAAY,IAChC,OAAO,SAAS,SAAS;EACvB,MAAM,QAAQ,MAAM,MAAM,IAAI;EAC9B,OAAO,UAAU,KAAA,KAAa,aAAa,KAAK,IAAI,CAAC,KAAK,IAAI,CAAC;CACjE,CAAC;CACP,MAAM,SAAS,OAAO,OAAO,OAAO,CAAC,CAAC,MACnC,MAAM,MAAM,KAAA,KAAa,OAAO,KAAK,CAAC,CAAC,CAAC,SAAS,CACpD;CACA,OACE,qBAAC,OAAD;EACE,WAAU;EACV,cAAW;EACX,WAAU;EACV,YAAA;EACA,IAAI;GAAE,UAAU;GAAQ,KAAK;GAAG,YAAY;EAAa;EAL3D,UAAA,CAOG,MAAM,KAAK,UACV,oBAAC,OAAD;GAAwB,IAAI;IAAE,UAAU;IAAG,MAAM;GAAY;GAC3D,UAAA,oBAAC,eAAD;IACS;IACP,UAAU,MAAM,SAAS;IACzB,OAAO,QAAQ,MAAM;IACrB,WAAW,UAAU,SAAS;KAAE,GAAG;MAAU,MAAM,OAAO;IAAM,CAAC;IACtD;GACZ,CAAA;EACI,GARK,MAAM,IAQX,CACR,GACA,UAAU,oBAAC,QAAD;GAAQ,eAAe,SAAS,CAAC,CAAC;GAAG,UAAA;EAAqB,CAAA,CAChE;;AAEX;;;ACJA,MAAa,oBAAoB;;AAGjC,MAAa,oBACX,WAEA,OAAO,QACJ,MAAM,EAAE,SAAS,YAAY,EAAE,UAAU,SAAS,WAAW,CAChE;;AAGF,MAAa,kBACX,WACsB,OAAO,QAAQ,MAAM,EAAE,YAAY,EAAE,UAAU;;AAGvE,SAAgB,aAAa,KAA+B;CAC1D,OAAO;EACL,SAAS,IAAI,SAAS,WAAW,CAAC;EAClC,GAAG;EACH,QAAQ,IAAI;EACZ,MAAM,IAAI,SAAS,QAAQ,CAAC;EAC5B,MAAM;EACN,UAAU,IAAI,SAAS,YAAA;EACvB,iBAAiB;EACjB,oBAAoB;CACtB;AACF;AAIA,MAAM,iBAAiB;AAEvB,SAAS,YACP,OACA,MAC0B;CAC1B,QAAQ,MAAM,MAAd;EACE,KAAK;EACL,KAAK,WAAW;GACd,MAAM,IAAI,OAAO,IAAI;GACrB,OAAO,KAAK,KAAK,MAAM,MAAM,OAAO,SAAS,CAAC,IAAI,IAAI,KAAA;EACxD;EACA,KAAK,WACH,OAAO,SAAS,SAAS,OAAO,SAAS,UAAU,QAAQ,KAAA;EAC7D,KAAK,YAAY;GAEf,MAAM,IAAI,IAAI,KAAK,eAAe,KAAK,IAAI,IAAI,GAAG,KAAK,KAAK,IAAI;GAChE,OAAO,OAAO,MAAM,EAAE,QAAQ,CAAC,IAAI,KAAA,IAAY;EACjD;EACA,SACE,OAAO,SAAS,KAAK,KAAA,IAAY;CACrC;AACF;;AAGA,SAAS,UAAU,MAAwB;CACzC,MAAM,QAAkB,CAAC,EAAE;CAC3B,KAAK,IAAI,IAAI,GAAG,IAAI,KAAK,QAAQ,KAAK;EACpC,MAAM,KAAK,KAAK,OAAO,CAAC;EACxB,MAAM,OAAO,KAAK,OAAO,IAAI,CAAC;EAC9B,IAAI,OAAO,SAAS,SAAS,OAAO,SAAS,OAAO;GAClD,MAAM,MAAM,SAAS,MAAM;GAC3B;EACF,OAAO,IAAI,OAAO,KAAK,MAAM,KAAK,EAAE;OAC/B,MAAM,MAAM,SAAS,MAAM;CAClC;CACA,OAAO;AACT;AAEA,MAAM,cAAc,SAClB,KAAK,WAAW,MAAM,MAAM,CAAC,CAAC,WAAW,KAAK,KAAK;;AAGrD,SAAgB,aACd,OACA,IACA,MACoD;CACpD,IAAI,OAAO,MAAM,OAAO,YAAY,OAAO,IAAI;CAC/C,MAAM,QAAQ,UAAU,IAAI,CAAC,CAC1B,KAAK,SAAS,YAAY,OAAO,KAAK,KAAK,CAAC,CAAC,CAAC,CAC9C,QAAQ,MAAyB,MAAM,KAAA,CAAS;CACnD,OAAO,MAAM,WAAW,IAAI,KAAA,IAAY;AAC1C;;AAGA,SAAgB,cACd,SACQ;CACR,IAAI,MAAM,QAAQ,OAAO,GACvB,OAAQ,QACL,KAAK,SAAS,WAAW,cAAc,IAAI,CAAC,CAAC,CAAC,CAC9C,KAAK,GAAG;CACb,OAAO,mBAAmB,OAAO,QAAQ,YAAY,IAAI,OAAO,OAAO;AACzE;AAIA,MAAM,SAAS,YAAoB;CACjC,GAAG,GAAG,OAAO;CACb,IAAI,GAAG,OAAO;CACd,MAAM,GAAG,OAAO;CAChB,MAAM,GAAG,OAAO;CAChB,MAAM,GAAG,OAAO;CAChB,UAAU,GAAG,OAAO;CACpB,QAAQ,GAAG,OAAO;CAClB,GAAG,GAAG,OAAO;AACf;AAEA,MAAM,WAAW,KAAa,WAC5B,IAAI,WAAW,GAAG,OAAO,GAAG,KAC3B,OAAO,OAAO,MAAM,MAAM,CAAC,CAAC,CAAc,SAAS,GAAG;;AAGzD,SAAS,cAAc,SAA2C;CAChE,MAAM,MAA0B,CAAC;CACjC,KAAK,MAAM,QAAQ,OAAO,KAAK,OAAO,CAAC,CAAC,KAAK,GAAG;EAC9C,MAAM,OAAO,QAAQ,SAAS,CAAC;EAC/B,KAAK,MAAM,MAAM,OAAO,KAAK,IAAI,CAAC,CAAC,KAAK,GAAG;GACzC,MAAM,UAAU,KAAK;GACrB,IACE,YAAY,KAAA,KACX,MAAM,QAAQ,OAAO,KAAK,QAAQ,WAAW,GAE9C;GACF,IAAI,KAAK,CAAC,KAAK,KAAK,GAAG,MAAM,cAAc,OAAO,CAAC,CAAC;EACtD;CACF;CACA,OAAO;AACT;AAEA,MAAM,YAAY,SAChB,KAAK,KAAK,MAAO,EAAE,OAAO,IAAI,EAAE,UAAU,EAAE,KAAM,CAAC,CAAC,KAAK,GAAG;AAE9D,MAAM,eACJ,GACA,MAEA,EAAE,WAAW,EAAE,UACf,EAAE,OAAO,CAAC,GAAG,IAAI,MAAM,MAAM,EAAE,EAAE,GAAG,MAAM,MAAM,EAAE,EAAE,GAAG,EAAE;;;;;;;AAQ3D,SAAgB,YACd,OACA,KACA,OAAO,IACC;CACR,MAAM,IAAI,MAAM,IAAI,MAAM;CAC1B,MAAM,SAAS,IAAI,gBAAgB,IAAI;CACvC,KAAK,MAAM,OAAO,IAAI,IAAI,OAAO,KAAK,CAAC,GACrC,IAAI,QAAQ,KAAK,IAAI,MAAM,GAAG,OAAO,OAAO,GAAG;CACjD,MAAM,QAAQ,aAAa,GAAG;CAC9B,MAAM,UAAU,cAAc,MAAM,OAAO;CAC3C,IAAI,CAAC,YAAY,SAAS,cAAc,MAAM,OAAO,CAAC,GAAG;EACvD,OAAO,IAAI,EAAE,GAAG,EAAE;EAClB,KAAK,MAAM,CAAC,KAAK,UAAU,SACzB,OAAO,IAAI,GAAG,IAAI,SAAS,OAAO,KAAK;CAC3C;CACA,IAAI,MAAM,MAAM,IAAI,OAAO,IAAI,EAAE,GAAG,MAAM,CAAC;CAC3C,IAAI,MAAM,WAAW,KAAA,KAAa,MAAM,WAAW,MAAM,QACvD,OAAO,IAAI,EAAE,IAAI,MAAM,MAAM;CAC/B,IAAI,SAAS,MAAM,IAAI,MAAM,SAAS,MAAM,IAAI,GAC9C,OAAO,IAAI,EAAE,MAAM,SAAS,MAAM,IAAI,CAAC;CACzC,IAAI,MAAM,OAAO,GAAG,OAAO,IAAI,EAAE,MAAM,OAAO,MAAM,IAAI,CAAC;CACzD,IAAI,MAAM,aAAa,MAAM,UAC3B,OAAO,IAAI,EAAE,MAAM,OAAO,MAAM,QAAQ,CAAC;CAC3C,IAAI,MAAM,iBAAiB,OAAO,IAAI,EAAE,UAAU,GAAG;CACrD,IAAI,MAAM,oBAAoB,OAAO,IAAI,EAAE,QAAQ,GAAG;CACtD,OAAO,OAAO,SAAS;AACzB;AAEA,SAAS,YAAY,MAAyC;CAC5D,MAAM,IAAI,OAAO,IAAI;CACrB,OAAO,SAAS,QAAQ,OAAO,UAAU,CAAC,KAAK,KAAK,IAAI,IAAI,KAAA;AAC9D;;AAGA,SAAgB,YAAY,QAAgB,KAA+B;CACzE,MAAM,IAAI,MAAM,IAAI,MAAM;CAC1B,MAAM,SAAS,IAAI,gBAAgB,MAAM;CACzC,MAAM,OAAO,aAAa,GAAG;CAE7B,IAAI,UAAU,KAAK;CACnB,IAAI,OAAO,IAAI,EAAE,CAAC,GAAG;EACnB,MAAM,OAAgD,CAAC;EACvD,MAAM,OAAO,GAAG,IAAI,OAAO;EAC3B,KAAK,MAAM,CAAC,KAAK,SAAS,QAAQ;GAChC,IAAI,CAAC,IAAI,WAAW,IAAI,GAAG;GAC3B,MAAM,OAAO,IAAI,MAAM,KAAK,MAAM;GAClC,MAAM,MAAM,KAAK,YAAY,GAAG;GAChC,MAAM,QAAQ,IAAI,OAAO,MAAM,MAAM,EAAE,SAAS,KAAK,MAAM,GAAG,GAAG,CAAC;GAClE,MAAM,KAAK,KAAK,MAAM,MAAM,CAAC;GAC7B,IACE,UAAU,KAAA,KACV,CAAC,aAAa,KAAK,KACnB,CAAC,MAAM,UAAU,SAAS,EAAE,GAE5B;GACF,MAAM,UAAU,aAAa,OAAO,IAAI,IAAI;GAC5C,IAAI,YAAY,KAAA,GACd,KAAK,MAAM,QAAQ,OAAO,KAAK,MAAM,OAAO,IAAI,OAAO;EAC3D;EACA,UAAU;CACZ;CAEA,IAAI,OAAO,KAAK;CAChB,IAAI,OAAO,IAAI,EAAE,IAAI,GAAG;EACtB,MAAM,WAAW,IAAI,IAAI,eAAe,IAAI,MAAM,CAAC,CAAC,KAAK,MAAM,EAAE,IAAI,CAAC;EACtE,OAAQ,OAAO,IAAI,EAAE,IAAI,CAAC,CACvB,MAAM,GAAG,CAAC,CACV,KAAK,UAAU;GACd,OAAO,KAAK,QAAQ,MAAM,EAAE;GAC5B,MAAM,KAAK,WAAW,GAAG;EAC3B,EAAE,CAAC,CACF,QAAQ,MAAM,SAAS,IAAI,EAAE,KAAK,CAAC;CACxC;CAEA,MAAM,SAAS,OAAO,IAAI,EAAE,EAAE;CAC9B,MAAM,aAAa,iBAAiB,IAAI,MAAM,CAAC,CAAC,MAC7C,MAAM,EAAE,SAAS,MACpB;CACA,MAAM,OAAO,YAAY,OAAO,IAAI,EAAE,IAAI,CAAC;CAC3C,OAAO;EACL;EACA,GAAG,OAAO,IAAI,EAAE,CAAC,KAAK;EACtB,QAAQ,aAAc,SAAoB,KAAK;EAC/C;EACA,MAAM,YAAY,OAAO,IAAI,EAAE,IAAI,CAAC,KAAK;EACzC,UAAU,KAAK,IAAI,QAAQ,KAAK,UAAU,IAAI,WAAW;EACzD,iBAAiB,OAAO,IAAI,EAAE,QAAQ,MAAM;EAC5C,oBAAoB,OAAO,IAAI,EAAE,MAAM,MAAM;CAC/C;AACF;;AAKA,SAAgB,iBAAiB,OAAiC;CAChE,IAAI,MAAM,MAAM,MAAM,MAAM,WAAW,KAAA,GAAW,OAAO,MAAM;CAC/D,OAAO;EACL,GAAG,MAAM;GACR,MAAM,SAAS,OAAO,MAAM,QAAQ,MAAM,SAAS,aAAa,MAAM,CAAC;CAC1E;AACF;;;;;AAMA,SAAgB,YAAY,OAAmB,OAA2B;CACxE,MAAM,QAAiC,EACrC,SAAS,eAAe,iBAAiB,KAAK,CAAC,EACjD;CACA,IAAI,MAAM,KAAK,SAAS,GAAG,MAAM,UAAU,SAAS,MAAM,IAAI,CAAC,CAAC,MAAM,GAAG;CACzE,IAAI,OAAO;EACT,MAAM,WAAW,MAAM,OAAO,KAAK,MAAM;EACzC,MAAM,WAAW,MAAM,WAAW;CACpC;CACA,IAAI,MAAM,iBAAiB,MAAM,qBAAqB;CACtD,IAAI,MAAM,oBAAoB,MAAM,wBAAwB;CAC5D,OAAO;AACT;;AAGA,MAAa,cAAc,UACzB,MAAM,MAAM,MAAM,cAAc,MAAM,OAAO,CAAC,CAAC,SAAS;;;;ACxS1D,MAAM,WAA0D;CAC9D,QAAQ;EAAC;EAAM;EAAY;CAAW;CACtC,QAAQ;EAAC;EAAM;EAAO;CAAK;CAC3B,SAAS;EAAC;EAAM;EAAO;CAAK;CAC5B,MAAM;EAAC;EAAM;EAAO;CAAK;CACzB,UAAU;EAAC;EAAM;EAAO;CAAK;CAC7B,MAAM,CAAC,MAAM,IAAI;CACjB,SAAS,CAAC,IAAI;AAChB;AAEA,MAAM,WAA+C;CACnD,IAAI;CACJ,KAAK;CACL,KAAK;CACL,IAAI;CACJ,UAAU;CACV,WAAW;CACX,OAAO;AACT;AAEA,MAAM,SAAS,MAAyB,GAAG,EAAE,MAAM,QAAQ,EAAE;;AAG7D,SAAS,aAAa,SAAoC;CACxD,OAAO,OAAO,KAAK,OAAO,CAAC,CAAC,SAAS,UACnC,OAAO,KAAK,QAAQ,UAAU,CAAC,CAAC,CAAC,CAAC,KAAK,QAAQ;EAC7C;EACI;CACN,EAAE,CACJ;AACF;;AAYA,SAAS,QAAQ,EAAE,OAAO,IAAI,GAAG,QAAoC;CACnE,IAAI,SAAS,MAAM,KAAK,EAAE,SAAS,EAAE,MAAM,MACzC,OAAO,oBAAC,eAAD;EAAe,OAAO;GAAE,GAAG;GAAO,WAAW,CAAC,EAAE;EAAE;EAAG,GAAI;CAAO,CAAA;CAEzE,OAAO,oBAAC,aAAD;EAAoB;EAAW;EAAI,GAAI;CAAO,CAAA;AACvD;AAEA,MAAM,UAAU,YACd,YAAY,KAAA,IAAY,KAAK,cAAc,OAAO;;AAGpD,SAAS,YAAY,EACnB,OACA,IACA,OACA,YAC6B;CAC7B,MAAM,UAAU,QAAQ;CACxB,MAAM,CAAC,MAAM,WAAW,SAAS,OAAO,OAAO,CAAC;CAChD,MAAM,CAAC,MAAM,WAAW,SAAS,OAAO;CACxC,IAAI,YAAY,MAAM;EACpB,QAAQ,OAAO;EAEf,IAAI,OAAO,aAAa,OAAO,IAAI,IAAI,CAAC,MAAM,OAAO,OAAO,GAC1D,QAAQ,OAAO,OAAO,CAAC;CAE3B;CACA,OACE,oBAAC,WAAD;EACE,MAAK;EACL,WAAA;EACA,OAAO,GAAG,MAAM,MAAM,GAAG,SAAS;EAClC,YACE,OAAO,OACH,MAAM,SAAS,aACb,mCACA,oBACF,KAAA;EAEN,OAAO;EACP,WAAW,MAAM;GACf,QAAQ,EAAE,OAAO,KAAK;GACtB,SAAS,OAAO,OAAO,IAAI,aAAa,OAAO,IAAI,EAAE,OAAO,KAAK,CAAC,CAAC;EACrE;CACD,CAAA;AAEL;;;;;;AAOA,SAAgB,cAAc,EAC5B,OACA,SACA,UACA,aACmC;CACnC,MAAM,aAAa,MAAM,OAAO,OAAO,YAAY;CAEnD,MAAM,CAAC,SAAS,cAAc,SAA+B,CAAC,CAAC;CAC/D,MAAM,UAAU,aAAa,OAAO;CACpC,MAAM,OAAO,CACX,GAAG,SACH,GAAG,QAAQ,QAAQ,MAAM,CAAC,QAAQ,MAAM,MAAM,MAAM,CAAC,MAAM,MAAM,CAAC,CAAC,CAAC,CACtE;CACA,MAAM,cAAc,GAAc,UAAyC;EAEzE,IAAI,CAAC,QAAQ,MAAM,MAAM,MAAM,CAAC,MAAM,MAAM,CAAC,CAAC,GAC5C,WAAW,CAAC,GAAG,SAAS,CAAC,CAAC;EAC5B,SAAS;GAAE,GAAG;IAAU,EAAE,QAAQ;EAAM,CAAC;CAC3C;CACA,MAAM,QAAQ,MAAuB;EACnC,WAAW,QAAQ,QAAQ,MAAM,MAAM,CAAC,MAAM,MAAM,CAAC,CAAC,CAAC;EACvD,SAAS;GACP,GAAG;IACF,EAAE,QAAQ,OAAO,QAAQ,EAAE,QAAQ,EAAE,IAAI,KAAA,CAAS;EACrD,CAAC;CACH;CACA,MAAM,QAAQ,MAAiB,OAAwB;EACrD,WAAW,CAAC,GAAG,QAAQ,QAAQ,MAAM,MAAM,CAAC,MAAM,MAAM,IAAI,CAAC,GAAG,EAAE,CAAC;EACnE,SAAS;GACP,GAAG;IACF,KAAK,QAAQ,OAAO,QAAQ,KAAK,QAAQ,KAAK,IAAI,KAAA,CAAS;EAC9D,CAAC;CACH;CACA,MAAM,YAAkB;EACtB,MAAM,QACJ,WAAW,MAAM,MAAM,CAAC,KAAK,MAAM,MAAM,EAAE,UAAU,EAAE,IAAI,CAAC,KAC5D,WAAW;EACb,IAAI,UAAU,KAAA,GAAW;EACzB,MAAM,KAAK,MAAM,UAAU;EAE3B,IACE,CAAC,GAAG,MAAM,GAAG,OAAO,CAAC,CAAC,MAAM,MAAM,EAAE,UAAU,MAAM,QAAQ,EAAE,OAAO,EAAE,GAEvE;EACF,WAAW,CACT,GAAG,SACH;GAAE,OAAO,MAAM;GAAM,IAAI,MAAM,UAAU;EAAe,CAC1D,CAAC;CACH;CACA,OACE,qBAAC,OAAD;EAAO,WAAU;EAAU,cAAW;EAAiB,SAAS;EAAhE,UAAA,CACG,KAAK,KAAK,GAAG,UAAU;GACtB,MAAM,QAAQ,MAAM,MAAM,EAAE,KAAK;GACjC,MAAM,QAAQ,aAAa,QAAQ;GACnC,OACE,qBAAC,OAAD;IAEE,WAAU;IACV,MAAK;IACL,cAAY;IACZ,YAAA;IACA,IAAI;KAAE,UAAU;KAAQ,KAAK;KAAG,YAAY;IAAa;IAN3D,UAAA;KAQE,oBAAC,WAAD;MACE,QAAA;MACA,MAAK;MACL,OAAM;MACN,OAAO,EAAE;MACT,WAAW,MAAM;OACf,MAAM,OAAO,MAAM,MAAM,EAAE,OAAO,KAAK;OACvC,KAAK,GAAG;QACN,OAAO,KAAK;QACZ,IAAI,KAAK,UAAU;OACrB,CAAC;MACH;MACA,IAAI,EAAE,UAAU,QAAQ;MAEvB,UAAA,WAAW,KAAK,MACf,oBAAC,UAAD;OAAuB,OAAO,EAAE;OAC7B,UAAA,EAAE;MACK,GAFK,EAAE,IAEP,CACX;KACQ,CAAA;KACX,oBAAC,WAAD;MACE,QAAA;MACA,MAAK;MACL,OAAM;MACN,OAAO,EAAE;MACT,WAAW,MACT,KAAK,GAAG;OAAE,OAAO,EAAE;OAAO,IAAI,EAAE,OAAO;MAAkB,CAAC;MAE5D,IAAI,EAAE,UAAU,QAAQ;MAEvB,UAAA,MAAM,UAAU,KAAK,OACpB,oBAAC,UAAD;OAAmB,OAAO;OACvB,UAAA,SAAS;MACF,GAFK,EAEL,CACX;KACQ,CAAA;KACX,oBAAC,OAAD;MAAO,IAAI;OAAE,UAAU;OAAS,MAAM;MAAY;MAChD,UAAA,oBAAC,SAAD;OACS;OACP,IAAI,EAAE;OACN,UAAU,MAAM,SAAS;OACzB,OAAO,QAAQ,EAAE;OACjB,WAAW,UAAU,WAAW,GAAG,KAAK;OAC7B;MACZ,CAAA;KACI,CAAA;KACP,oBAAC,QAAD;MACE,cAAY,UAAU,MAAM,YAAY;MACxC,eAAe,KAAK,CAAC;MACtB,UAAA;KAEO,CAAA;IACH;GA3DA,GAAA,MAAM,CAAC,CA2DP;EAEX,CAAC,GACD,qBAAC,OAAD;GAAO,WAAU;GAAM,SAAS;GAAhC,UAAA,CACE,oBAAC,QAAD;IAAQ,SAAS;IAAK,UAAA;GAAqB,CAAA,GAC1C,KAAK,SAAS,KACb,oBAAC,QAAD;IACE,eAAe;KACb,WAAW,CAAC,CAAC;KACb,SAAS,CAAC,CAAC;IACb;IACD,UAAA;GAEO,CAAA,CAEL;EACF,CAAA,CAAA;;AAEX;;;;ACjPA,SAAgB,YAAY,EAC1B,QACA,OACA,OACA,UACA,eACA,aAAa,OAC2B;CACxC,MAAM,CAAC,MAAM,WAAW,SAAS,KAAK;CACtC,MAAM,CAAC,MAAM,WAAW,SAAS,KAAK;CACtC,IAAI,UAAU,MAAM;EAElB,QAAQ,KAAK;EACb,QAAQ,KAAK;CACf;CACA,gBAAgB;EACd,IAAI,SAAS,OAAO,OAAO,KAAA;EAC3B,MAAM,QAAQ,iBAAiB,SAAS,IAAI,GAAG,UAAU;EACzD,aAAa,aAAa,KAAK;CACjC,GAAG;EAAC;EAAM;EAAO;EAAU;CAAU,CAAC;CACtC,IAAI,OAAO,WAAW,GAAG,OAAO;CAChC,MAAM,UACJ,OAAO,MAAM,MAAM,EAAE,SAAS,KAAK,KAAM,OAAO;CAClD,OACE,qBAAC,OAAD;EACE,WAAU;EACV,SAAS;EACT,MAAK;EACL,cAAW;EACX,IAAI,EAAE,YAAY,aAAa;EALjC,UAAA,CAOE,oBAAC,WAAD;GACE,MAAK;GACL,MAAK;GACL,OAAO,UAAU,QAAQ,MAAM,YAAY;GAC3C,OAAO;GACP,WAAW,MAAM,QAAQ,EAAE,OAAO,KAAK;GACvC,IAAI;IAAE,UAAU;IAAG,MAAM;GAAY;EACtC,CAAA,GACA,OAAO,SAAS,KACf,oBAAC,WAAD;GACE,QAAA;GACA,MAAK;GACL,OAAM;GACN,OAAO,QAAQ;GACf,WAAW,MAAM,cAAc,EAAE,OAAO,KAAK;GAC7C,IAAI,EAAE,UAAU,QAAQ;GAEvB,UAAA,OAAO,KAAK,MACX,oBAAC,UAAD;IAAuB,OAAO,EAAE;IAC7B,UAAA,EAAE;GACK,GAFK,EAAE,IAEP,CACX;EACQ,CAAA,CAER;;AAEX;;;;AC9DA,SAAgB,iBAAiB,UAAU,IAAgB;CACzD,IAAI,SAAS;CACb,MAAM,4BAAY,IAAI,IAAgB;CACtC,OAAO;EACL,YAAY;EACZ,MAAM,MAAM;GACV,SAAS;GACT,KAAK,MAAM,YAAY,WAAW,SAAS;EAC7C;EACA,UAAU,UAAU;GAClB,UAAU,IAAI,QAAQ;GACtB,aAAa,UAAU,OAAO,QAAQ;EACxC;CACF;AACF;;AAGA,SAAgB,mBAA+B;CAC7C,MAAM,4BAAY,IAAI,IAAgB;CACtC,MAAM,eAAqB;EACzB,KAAK,MAAM,YAAY,WAAW,SAAS;CAC7C;CACA,OAAO;EACL,YAAY,OAAO,SAAS,OAAO,QAAQ,OAAO,EAAE;EACpD,MAAM,QAAQ,MAAM;GAClB,MAAM,EAAE,UAAU,SAAS,OAAO;GAClC,MAAM,MAAM,GAAG,WAAW,WAAW,KAAK,KAAK,IAAI,WAAW;GAC9D,IAAI,SAAS,WACX,OAAO,QAAQ,aAAa,OAAO,QAAQ,OAAO,IAAI,GAAG;QACtD,OAAO,QAAQ,UAAU,OAAO,QAAQ,OAAO,IAAI,GAAG;GAC3D,OAAO;EACT;EACA,UAAU,UAAU;GAClB,UAAU,IAAI,QAAQ;GAEtB,OAAO,iBAAiB,YAAY,QAAQ;GAC5C,aAAa;IACX,UAAU,OAAO,QAAQ;IACzB,OAAO,oBAAoB,YAAY,QAAQ;GACjD;EACF;CACF;AACF;AAEA,IAAI;;AAGJ,SAAgB,oBAAgC;CAC9C,WAAW,iBAAiB;CAC5B,OAAO;AACT;;;;;;;;ACPA,SAAgB,cACd,OACA,UAA6B,CAAC,GACf;CACf,MAAM,EAAE,UAAU,kBAAkB,GAAG,SAAS,OAAO;CACvD,MAAM,SAAS,MAAM;CACrB,MAAM,eAAe,cAAc,iBAAiB,MAAM,GAAG,CAAC,MAAM,CAAC;CACrE,MAAM,cAAc,QAAQ,eAAe,aAAa,EAAE,EAAE;CAE5D,MAAM,QAAQ,QAAQ,YAAY,CAAC;CACnC,MAAM,WAAW,KAAK,UAAU;EAAC,MAAM;EAAU,MAAM;EAAM,MAAM;CAAO,CAAC;CAC3E,MAAM,CAAC,MAAM,WAAW,SAAS;EAAE,KAAK;EAAU,OAAO;CAAM,CAAC;CAChE,IAAI,KAAK,QAAQ,UAAU,QAAQ;EAAE,KAAK;EAAU,OAAO;CAAM,CAAC;CAClE,MAAM,WAAW,KAAK;CACtB,MAAM,MAAM,eACH;EACL;EACA;EACA;EACA;EACA,aAAa,MAAM,SAAS,WAAW,YAAY;CACrD,IACA;EACE;EACA;EACA;EACA;EACA,MAAM,SAAS,WAAW;CAC5B,CACF;CACA,MAAM,SAAS,qBACb,QAAQ,WACR,QAAQ,YACF,EACR;CACA,MAAM,QAAQ,cAAc,YAAY,QAAQ,GAAG,GAAG,CAAC,QAAQ,GAAG,CAAC;CACnE,MAAM,aAAa,cAAc,YAAY,OAAO,IAAI,GAAG,CAAC,KAAK,CAAC;CAClE,MAAM,YAAY,cAAc,YAAY,OAAO,KAAK,GAAG,CAAC,KAAK,CAAC;CAElE,OAAO,cAA6B;EAElC,MAAM,UACJ,OACA,OAA2B,WAClB;GACT,MAAM,UAAU,YAAY,QAAQ,KAAK,GAAG,GAAG;GAC/C,QAAQ,MACN,YAAY;IAAE,GAAG;IAAS,GAAG,MAAM,OAAO;GAAE,GAAG,KAAK,QAAQ,KAAK,CAAC,GAClE,IACF;EACF;EACA,MAAM,QAAQ,EAAE,MAAM,EAAE;EACxB,OAAO;GACL;GACA;GACA;GACA;GACA;GACA,aAAa,YAAY,cAAc;IAAE;IAAS,GAAG;GAAM,EAAE;GAC7D,iBAAiB,MAAM,cAAc;IAAE;IAAG,GAAG;GAAM,IAAI,SAAS;GAChE,sBAAsB,WAAW,cAAc;IAAE;IAAQ,GAAG;GAAM,EAAE;GACpE,UAAU,SAAS,cAAc;IAAE;IAAM,GAAG;GAAM,EAAE;GACpD,UAAU,SAAS,cAAc,EAAE,KAAK,EAAE;GAC1C,cAAc,aAAa,cAAc;IAAE;IAAU,GAAG;GAAM,EAAE;GAChE,qBAAqB,oBACnB,cAAc;IAAE;IAAiB,GAAG;GAAM,EAAE;GAC9C,wBAAwB,uBACtB,cAAc;IAAE;IAAoB,GAAG;GAAM,EAAE;GACjD,aAAa,aAAa,YAAY,IAAI,GAAG,CAAC;EAChD;CACF,GAAG;EAAC;EAAO;EAAQ;EAAc;EAAY;EAAW;EAAS;CAAG,CAAC;AACvE;;;AClGA,MAAM,SACJ,SACA,gBAEA,oBAAC,OAAD;CAAO,SAAS;CAAM,UAAA,QAAQ,OAAO,KAAK,SAAS,YAAY,IAAI,CAAC;AAAS,CAAA;AAG/E,MAAM,eAAe,UACnB,UAAU,IAAI,KAAK,KAAK,MAAM,GAAG,UAAU,IAAI,UAAU,SAAS;;AAGpE,SAAgB,WAAW,EACzB,QACA,UACA,aACA,YACA,QACA,UACA,QACA,UACgC;CAChC,MAAM,KAAK,MAAM;CACjB,IAAI,WAAW,QACb,OAAO,MACL;EAAE,OAAO;EAAI,QAAQ,SAAS,SAAS,MAAM,EAAE,MAAM;CAAE,GACvD,WACF;CAEF,IAAI,WAAW,YACb,OACE,oBAAC,OAAD;EAAO,SAAS;EACb,UAAA,SAAS,KAAK,SAAS,UACtB,qBAAC,KAAD;GAEE,WAAU;GACV,mBAAiB,GAAG,GAAG,IAAI;GAH7B,UAAA,CAKE,oBAAC,YAAD;IACE,IAAI,GAAG,GAAG,IAAI;IACd,WAAU;IACV,SAAQ;IACR,IAAI,EAAE,IAAI,EAAE;IAEX,UAAA,QAAQ;GACC,CAAA,GACX,MAAM,SAAS,WAAW,CACxB;EAbE,GAAA,QAAQ,KAaV,CACN;CACI,CAAA;CAGX,MAAM,SAAS,SAAsB,UACnC,oBAAC,KAAD;EAEE,MAAM,WAAW,SAAS,aAAa;EACvC,IAAI,GAAG,GAAG,IAAI;EACd,mBAAiB,GAAG,GAAG,IAAI;EAC3B,QAAQ,UAAU;EAClB,IAAI,EAAE,IAAI,EAAE;EAEX,UAAA,MAAM,SAAS,WAAW;CACxB,GARE,QAAQ,KAQV;CAEP,IAAI,WAAW,QACb,OACE,qBAAC,KAAD,EAAA,UAAA,CACE,oBAAC,MAAD;EACE,OAAO;EACP,WAAW,QAAQ,UAAkB,SAAS,KAAK;EACnD,SAAQ;EACR,cAAW;EAEV,UAAA,SAAS,KAAK,SAAS,UAAU;GAChC,MAAM,QAAQ,WAAW,OAAO;GAChC,OACE,oBAAC,KAAD;IAEE,IAAI,GAAG,GAAG,IAAI;IACd,iBAAe,GAAG,GAAG,IAAI;IACzB,OACE,oBAAC,OAAD;KAAO,OAAM;KAAQ,SAAQ;KAAM,WAAW,UAAU;KACrD,UAAA,QAAQ,QAAQ,YAAY,KAAK;IAC7B,CAAA;GAEV,GARM,QAAQ,KAQd;EAEL,CAAC;CACG,CAAA,GACL,SAAS,IAAI,KAAK,CAChB,EAAA,CAAA;CAGT,MAAM,OAAO,WAAW,SAAS,SAAS;CAC1C,OACE,qBAAC,KAAD,EAAA,UAAA;EACE,oBAAC,SAAD;GAAS,YAAY;GAAQ,kBAAA;GAAiB,IAAI,EAAE,IAAI,EAAE;GACvD,UAAA,SAAS,KAAK,SAAS,UAAU;IAChC,MAAM,QAAQ,WAAW,OAAO;IAChC,OACE,oBAAC,MAAD;KAA0B,IAAI,GAAG,GAAG,IAAI;KACtC,UAAA,oBAAC,WAAD;MAAW,OAAO,QAAQ;MACvB,UAAA,QAAQ,QAAQ,YAAY,KAAK;KACzB,CAAA;IACP,GAJK,QAAQ,KAIb;GAEV,CAAC;EACM,CAAA;EACR,SAAS,IAAI,KAAK;EACnB,qBAAC,OAAD;GACE,WAAU;GACV,SAAS;GACT,IAAI;IAAE,gBAAgB;IAAY,IAAI;GAAE;GAH1C,UAAA,CAKE,oBAAC,QAAD;IAAQ,UAAU,WAAW;IAAG,eAAe,SAAS,SAAS,CAAC;IAAG,UAAA;GAE7D,CAAA,GACP,OAAO,SAAS,oBAAC,QAAD;IAAQ,SAAS;IAAQ,UAAA;GAAY,CAAA,CACjD;;CACJ,EAAA,CAAA;AAET;;;;;;;;ACtIA,SAAgB,YACd,QACA,UACwB;CACxB,MAAM,QAAQ,IAAI,IAAI,OAAO,KAAK,MAAM,EAAE,IAAI,CAAC;CAC/C,MAAM,QACJ,aAAa,KAAA,IACT,CACE;EACE,OAAO;EACP,QAAQ,OAAO,QAAQ,MAAM,EAAE,QAAQ,CAAC,CAAC,KAAK,MAAM,EAAE,IAAI;CAC5D,GACA;EACE,OAAO;EACP,QAAQ,OAAO,QAAQ,MAAM,CAAC,EAAE,QAAQ,CAAC,CAAC,KAAK,MAAM,EAAE,IAAI;CAC7D,CACF,IACA,SAAS,KAAK,OAAO;EACnB,OAAO,EAAE;EACT,QAAQ,EAAE,OAAO,QAAQ,SAAS,MAAM,IAAI,IAAI,CAAC;CACnD,EAAE;CACR,MAAM,OAAO,IAAI,IAAI,MAAM,SAAS,MAAM,EAAE,MAAM,CAAC;CACnD,MAAM,OAAO,OAAO,KAAK,MAAM,EAAE,IAAI,CAAC,CAAC,QAAQ,SAAS,CAAC,KAAK,IAAI,IAAI,CAAC;CACvE,OAAO,CAAC,GAAG,OAAO;EAAE,OAAO;EAAS,QAAQ;CAAK,CAAC,CAAC,CAAC,QACjD,MAAM,EAAE,OAAO,SAAS,CAC3B;AACF;;;;AC5BA,SAAS,QAAQ,KAAuD;CAEtE,MAAM,QADQ,IAAI,QAAQ,SAAS,SAAS,UAAU,SAAS,OAC7C,CAAC,CAAC;CACpB,OAAO,UAAU,KAAA,IAAY,KAAA,IAAY,OAAO,KAAK;AACvD;;AAGA,SAAgB,gBACd,OACA,YACa;CACb,IAAI,iBAAiB,oBACnB,OAAO;EAAE,UAAU;EAAM,aAAa,CAAC;EAAG,SAAS;CAAK;CAE1D,MAAM,cAAsC,CAAC;CAC7C,MAAM,UAAoB,CAAC;CAC3B,IAAI,iBAAiB,gBAAgB,MAAM,OAAO,SAAS,GAAG;EAC5D,KAAK,MAAM,SAAS,MAAM,QAAQ;GAChC,MAAM,OAAO,QAAQ,MAAM,GAAG;GAC9B,IAAI,SAAS,KAAA,KAAa,WAAW,SAAS,IAAI,GAChD,YAAY,UAAU,MAAM;QAE5B,QAAQ,KAAK,SAAS,KAAA,IAAY,MAAM,MAAM,GAAG,KAAK,IAAI,MAAM,KAAK;EAEzE;EACA,OAAO;GACL,UAAU;GACV;GACA,SAAS,QAAQ,WAAW,IAAI,OAAO,QAAQ,KAAK,IAAI;EAC1D;CACF;CAOA,OAAO;EAAE,UAAU;EAAO;EAAa,SALrC,iBAAiB,eACb,GAAG,MAAM,QAAQ,MAAM,WAAW,KAAA,IAAY,KAAK,KAAK,MAAM,aAC9D,iBAAiB,QACf,MAAM,UACN;CACuC;AACjD;;;ACjDA,MAAM,WAAW,UACf,UAAU,KAAA,KACV,UAAU,QACV,UAAU,MACT,MAAM,QAAQ,KAAK,KAAK,MAAM,WAAW;AAE5C,SAAS,QAAQ,SAAiB,OAAwB;CACxD,IAAI;EACF,OAAO,IAAI,OAAO,SAAS,GAAG,CAAC,CAAC,KAAK,KAAK;CAC5C,QAAQ;EAEN,OAAO;CACT;AACF;;;;;AAMA,SAAgB,cACd,OACA,OACe;CACf,IAAI,QAAQ,KAAK,GACf,OAAO,MAAM,YAAY,MAAM,SAAS,YAAY,aAAa;CAEnE,MAAM,EAAE,SAAS,SAAS,WAAW,WAAW,YAAY,MAAM;CAClE,IAAI,OAAO,UAAU,UAAU;EAC7B,IAAI,MAAM,SAAS,aAAa,CAAC,OAAO,UAAU,KAAK,GACrD,OAAO;EAET,IAAI,YAAY,KAAA,KAAa,QAAQ,SACnC,OAAO,oBAAoB;EAE7B,IAAI,YAAY,KAAA,KAAa,QAAQ,SACnC,OAAO,mBAAmB;CAE9B;CACA,IAAI,OAAO,UAAU,UAAU;EAC7B,IAAI,cAAc,KAAA,KAAa,MAAM,SAAS,WAC5C,OAAO,oBAAoB,UAAU;EAEvC,IAAI,cAAc,KAAA,KAAa,MAAM,SAAS,WAC5C,OAAO,mBAAmB,UAAU;EAEtC,IAAI,YAAY,KAAA,KAAa,CAAC,QAAQ,SAAS,KAAK,GAClD,OAAO;CAEX;CACA,OAAO;AACT;;AAGA,SAAgB,YACd,QACA,QACwB;CACxB,MAAM,SAAiC,CAAC;CACxC,KAAK,MAAM,SAAS,QAAQ;EAC1B,MAAM,UAAU,cAAc,OAAO,OAAO,MAAM,KAAK;EACvD,IAAI,YAAY,MAAM,OAAO,MAAM,QAAQ;CAC7C;CACA,OAAO;AACT;;;ACeA,MAAM,aAAmB,CAAC;AAE1B,MAAMC,UAAQ,GAAe,MAC3B,KAAK,UAAU,CAAC,MAAM,KAAK,UAAU,CAAC;AAExC,MAAM,QAAQ,QAAoC,QAChD,OAAO,YAAY,OAAO,KAAK,MAAM,CAAC,EAAE,MAAM,IAAI,EAAE,KAAK,CAAC,CAAC;;AAG7D,SAAS,QACP,QACA,QACA,UAC4B;CAC5B,MAAM,MAAkC,CAAC;CACzC,KAAK,MAAM,SAAS,QAAQ;EAC1B,MAAM,QAAQ,OAAO,MAAM;EAE3B,IAAI,UAAU,KAAA,GAAW;EACzB,IAAI,aAAa,KAAA,KAAaA,OAAK,OAAO,SAAS,MAAM,KAAK,GAAG;EACjE,IAAI,MAAM,QAAQ;CACpB;CACA,OAAO;AACT;AAEA,MAAM,eAAe,QAAoB,SAA0B;CACjE,MAAM,QAAQ,OAAO;CACrB,OACE,OAAO,UAAU,YACjB,UAAU,QACV,OAAO,OAAO,OAAiB,IAAI;AAEvC;AAIA,MAAM,cAAsC;CAC1C,MAAM;CACN,QAAQ;CACR,OAAO;CACP,SAAS;AACX;;AAGA,SAAgB,aAAa,OAA+C;CAE1E,KADqB,MAAM,gBAAgB,YACtB,UAAU,MAAM,SAAS,MAAM,OAAO;CAC3D,OACE,oBAAC,cAAD;EAAc,MAAM,MAAM;EAAM,YAAY,MAAM;EAC9C,WAAA,UACA,oBAAC,gBAAD;GAA+C;GAAO,GAAI;EAAQ,GAA7C,MAAM,MAAM,KAAiC;CAExD,CAAA;AAElB;AAEA,SAAS,eAAe,EACtB,OACA,GAAG,SACmE;CACtE,MAAM,EAAE,IAAI,SAAS,QAAQ,WAAW,OAAO,cAAc;CAC7D,MAAM,OAAO,OAAO,KAAA,IAAY,WAAW;CAC3C,MAAM,eAAe,MAAM,gBAAgB;CAC3C,MAAM,EAAE,OAAO,UAAU,iBAAiB;CAC1C,MAAM,SAAS,MAAM;CAErB,MAAM,YACJ,MAAM,eAAe,KAAA,IACjB,MAAM,OACN,GAAG,MAAM,KAAK,GAAG,MAAM;CAC7B,MAAM,SAAS,SAAS;EACtB,GAAG,cAAc,WAAW,MAAM,KAAK,MAAM,CAAC;EAC9C,SAAS,SAAS;CACpB,CAAC;CACD,MAAM,SAAS,MAAM,UAAU;CAC/B,MAAM,SAAS,MAAM,UAAU;CAE/B,MAAM,WACJ,SAAS,WAAW,SAAS,QAAQ,SAAS,SAAS,QAAQ;CACjE,MAAM,WAAW,MAAM,OAAO,QAC3B,MACC,CAAC,EAAE,YACH,YAAY,UAAU,EAAE,IAAI,MAC3B,MAAM,WAAW,KAAA,KAAa,MAAM,OAAO,SAAS,EAAE,IAAI,EAC/D;CACA,MAAM,WAAW,YACf,UACA,WAAW,SACP,CAAC;EAAE,OAAO;EAAI,QAAQ,SAAS,KAAK,MAAM,EAAE,IAAI;CAAE,CAAC,IACnD,MAAM,QACZ;CAEA,MAAM,CAAC,UAAU,eAAe,SAA0B,KAAA,CAAS;CACnE,MAAM,CAAC,QAAQ,aAAa,eAC1B,SAAS,WAAW,KAAK,UAAU,MAAM,WAAW,CAAC,CAAC,IAAI,CAAC,CAC7D;CACA,MAAM,CAAC,QAAQ,aAAa,SAAS,SAAS,QAAQ;CACtD,IAAI,CAAC,UAAU,OAAO,SAAS,KAAA,GAAW;EAExC,UAAU,IAAI;EACd,YAAY,OAAO,IAAW;EAC9B,UAAU,KAAK,UAAU,OAAO,IAAW,CAAC;CAC9C;CAEA,MAAM,CAAC,SAAS,cAAc,yBAA8B,IAAI,IAAI,CAAC;CACrE,MAAM,CAAC,SAAS,cAAc,SAA2C,CAAC,CAAC;CAC3E,MAAM,CAAC,cAAc,mBAAmB,SAEtC,CAAC,CAAC;CACJ,MAAM,CAAC,SAAS,cAAc,SAAwB,IAAI;CAC1D,MAAM,CAAC,UAAU,eAAe,SAAS,KAAK;CAC9C,MAAM,CAAC,QAAQ,aAAa,SAAiB,MAAM;CACnD,MAAM,CAAC,QAAQ,aAAa,SAAS,CAAC;CACtC,MAAM,SAAS,OAAO,KAAK;CAE3B,MAAM,QAAQ,YAAY,UAAU,MAAM;CAC1C,MAAM,eAAe,OAAO,KAAK,OAAO,CAAC,CAAC;CAC1C,MAAM,QAAQ,QACZ,UACA,QACA,SAAS,SAAS,WAAW,KAAA,CAC/B;CACA,MAAM,QAAQ,OAAO,KAAK,KAAK,CAAC,CAAC,SAAS;CAC1C,MAAM,WAAW,SACf,aAAa,UAAU,QAAQ,IAAI,IAAI,IAAI,MAAM,QAAQ,KAAA;CAC3D,MAAM,cAAc,YAClB,QAAQ,OAAO,QACZ,SAAS,QAAQ,IAAI,MAAM,KAAA,KAAa,QAAQ,UAAU,KAAA,CAC7D,CAAC,CAAC;CAEJ,MAAM,QAAQ,OAAO,CAAC;CACtB,MAAM,YAAY,MAAc,UAA4B;EAC1D,MAAM,WAAW;EACjB,WAAW,UAAU;GAAE,GAAG;IAAO,OAAO;EAAM,EAAE;EAChD,iBAAiB,GAAG,OAAO,UAAU,GAAG,WAAW,IAAI;EACvD,WAAW,IAAI;EACf,UAAU,MAAM;CAClB;CAEA,MAAM,SAAS,QAAmB;EAChC,YAAY,GAAG;EACf,UAAU,KAAK,UAAU,GAAG,CAAC;EAC7B,2BAAW,IAAI,IAAI,CAAC;EACpB,gBAAgB,CAAC,CAAC;EAClB,WAAW,IAAI;EACf,YAAY,KAAK;EACjB,UAAU,MAAM;CAClB;CAEA,MAAM,OAAO,OAAO,YAGC;EACnB,IAAI,OAAO,SAAS;EACpB,IAAI,QAAQ,UAAU,MAAM;GAC1B,WAAW,IAAI,IAAI,SAAS,KAAK,MAAM,EAAE,IAAI,CAAC,CAAC;GAC/C,MAAM,WAAW,SAAS,WAAW,MACnC,EAAE,OAAO,MACN,SAAS,MAAM,UAAU,KAAA,KAAa,QAAQ,UAAU,KAAA,CAC3D,CACF;GACA,IAAI,YAAY,GAAG,UAAU,QAAQ;EACvC;EACA,IAAI,OAAO,KAAK,KAAK,CAAC,CAAC,SAAS,KAAK,eAAe,GAAG;EACvD,IAAI,SAAS,UAAU,CAAC,OAAO;GAC7B,UAAU,SAAS;GACnB;EACF;EACA,OAAO,UAAU;EACjB,UAAU,QAAQ;EAClB,YAAY,KAAK;EACjB,WAAW,IAAI;EACf,gBAAgB,CAAC,CAAC;EAClB,IAAI;GACF,IAAI,SAAS,UAAU;IACrB,MAAM,UAAU,MAAM,OAAO,YAAY,KAAmB;IAC5D,MAAM,KAAK,UAAU,MAAM,WAAW,CAAC,CAAC,CAAC;IACzC,UAAU,OAAO;IACjB,MAAM,UAAU,OAAO;GACzB,OAAO;IACL,MAAM,UACJ,QAAQ,cAAc,QACtB,CAAC,aAAa,wBACd,MAAM,SAAS,KAAA,IACX,KAAA,IACA,MAAM,MAAM,KAAK,EAAY;IACnC,MAAM,OAAO,MAAM;IACnB,MAAM,QAAQ,MAAM,OAAO,YAAY;KACjC;KACG;KACP,GAAI,YAAY,KAAA,IAAY,CAAC,IAAI,EAAE,QAAQ;IAC7C,CAAC;IACD,YAAY,KAAY;IAExB,UAAU,MAAM,YAAY,OAAO,UAAU,MAAM;IACnD,MAAM,UAAU,KAAK;GACvB;EACF,SAAS,OAAO;GACd,MAAM,UAAU,gBACd,OACA,SAAS,KAAK,MAAM,EAAE,IAAI,CAC5B;GACA,YAAY,QAAQ,QAAQ;GAC5B,gBAAgB,QAAQ,WAAW;GACnC,WAAW,QAAQ,OAAO;GAC1B,UAAU,MAAM;GAChB,MAAM,WAAW,SAAS,WAAW,MACnC,EAAE,OAAO,MAAM,SAAS,QAAQ,YAAY,UAAU,KAAA,CAAS,CACjE;GACA,IAAI,YAAY,GAAG,UAAU,QAAQ;EACvC,UAAU;GACR,OAAO,UAAU;EACnB;CACF;CAEA,MAAM,SAAS,YAA2B;EACxC,MAAM,SAAS,MAAM,OAAO,QAAQ;EACpC,IAAI,OAAO,SACT,WAAW,qCAAqC,OAAO,MAAM,SAAS;OAEtE,MAAM,OAAO,IAAW;CAE5B;CAGA,MAAM,aAAa,OAAO,IAAI;CAC9B,gBAAgB;EACd,WAAW,UAAU;CACvB,CAAC;CACD,MAAM,QAAQ,MAAM,mBAAmB;CACvC,MAAM,gBACJ,YACA,SAAS,UACT,SACA,CAAC,YACD,YAAY,QACZ,OAAO,KAAK,YAAY,CAAC,CAAC,WAAW,KACrC,OAAO,KAAK,KAAK,CAAC,CAAC,WAAW,KAC9B,iBAAiB,KACjB,WAAW;CACb,gBAAgB;EACd,IAAI,CAAC,eAAe,OAAO,KAAA;EAC3B,MAAM,QAAQ,iBACN,KAAK,WAAW,QAAQ,EAAE,OAAO,KAAK,CAAC,GAC7C,KACF;EACA,aAAa,aAAa,KAAK;CACjC,GAAG;EAAC;EAAe;EAAQ;CAAK,CAAC;CAEjC,MAAM,eAAqB;EACzB,MAAM,UAAU,SAAS;EACzB,YAAY,yBAAS,IAAI,IAAI,CAAC,GAAG,MAAM,GAAG,QAAQ,MAAM,CAAC,CAAC;EAI1D,IAAI,CAHY,QAAQ,OAAO,MAC5B,SAAS,MAAM,UAAU,KAAA,KAAa,QAAQ,UAAU,KAAA,CAEhD,GAAG,UAAU,SAAS,CAAC;CACpC;CAEA,MAAM,QAAQ,MAAM,eAAe;CACnC,MAAM,QACJ,MAAM,UAAU,SAAS,WAAW,OAAO,UAAU,QAAQ,MAAM,GAAG;CACxE,MAAM,UAAU,WAAW;CAC3B,MAAM,SACJ,oBAAC,QAAD;EACE,MAAK;EACL,MAAM;EACN,SAAQ;EACR,UAAU,eAAe,KAAK,WAAW;EAExC,UAAA,SAAS,WAAW,WAAW;CAC1B,CAAA;CAEV,MAAM,UAAU,WAAY,YAAY,SAAS,SAAU,KAAA,IAAY;CAEvE,MAAM,cAAc,IAAI,IAAI,SAAS,KAAK,MAAM,CAAC,EAAE,MAAM,CAAC,CAAC,CAAC;CAC5D,MAAM,eAAe,SACnB,oBAAC,YAAD;EAEE,OAAO,YAAY,IAAI,IAAI;EAC3B,UAAU,SAAS;EACnB,OAAO,OAAO;EACd,IAAI,GAAG,OAAO,GAAG;EACjB,OAAO,QAAQ,IAAI;EACR;EACX,WAAW,UAAU,SAAS,MAAM,KAAK;EACzC,cAAc,YAAY,SAAS,IAAI,IAAI,IAAI,CAAC,CAAC,IAAI,IAAI,CAAC;EAC1D,YAAY,WACV,YAAY,SAAS;GACnB,KAAK,KAAK,SAAS,UAAU,QAAQ,OAAO;GAC5C,MAAM,GAAG,OAAO,UAAU,GAAG,SAAS;GACtC,OAAO,WAAW,OAAO,OAAO;IAAE,GAAG;KAAO,OAAO;GAAO;EAC5D,CAAC;CAEJ,GAhBM,IAgBN;CAGH,IAAI;CACJ,IAAI,CAAC,UAAU,OAAO,SACpB,UAAU,oBAAC,OAAD;EAAO,UAAS;EAAS,UAAA,OAAO,MAAM;CAAe,CAAA;MAC1D,IAAI,CAAC,QACV,UACE,oBAAC,KAAD;EAAK,IAAI;GAAE,SAAS;GAAQ,gBAAgB;GAAU,GAAG;EAAE;EACzD,UAAA,oBAAC,kBAAD,EAAkB,cAAW,UAAW,CAAA;CACrC,CAAA;MAGP,UACE,oBAAC,KAAD;EACE,WAAU;EACV,IAAI;EACJ,YAAA;EACA,cAAY,OAAO,UAAU,WAAW,QAAQ;EAChD,WAAW,UAAU;GACnB,MAAM,eAAe;GACrB,KAAU,CAAC,CAAC;EACd;EAEA,UAAA,qBAAC,OAAD;GAAO,SAAS;GAAhB,UAAA;IACG,YAAY,QAAQ,oBAAC,OAAD;KAAO,UAAS;KAAS,UAAA;IAAe,CAAA;IAC5D,YACC,oBAAC,OAAD;KACE,UAAS;KACT,QACE,qBAAA,UAAA,EAAA,UAAA,CACE,oBAAC,QAAD;MACE,OAAM;MACN,MAAK;MACL,eAAe,KAAK,OAAO;MAC5B,UAAA;KAEO,CAAA,GACR,oBAAC,QAAD;MACE,OAAM;MACN,MAAK;MACL,eAAe,KAAK,KAAK,EAAE,WAAW,KAAK,CAAC;MAC7C,UAAA;KAEO,CAAA,CACR,EAAA,CAAA;KAEL,UAAA;IAIM,CAAA;IAET,oBAAC,YAAD;KACU;KACE;KACG;KACD;KACZ,QAAQ,KAAK,IAAI,QAAQ,SAAS,SAAS,CAAC;KAC5C,UAAU;KACV,QAAQ;KACA;IACT,CAAA;IACD,oBAAC,YAAD;KACE,MAAK;KACL,SAAQ;KACR,IAAI;MAAE,OAAO;MAAkB,WAAW;KAAM;KAE/C,UAAA,YAAY;IACH,CAAA;GACP;;CACJ,CAAA;CAIT,IAAI,iBAAiB,UACnB,OACE,oBAAC,aAAD;EACE,MAAA;EACO;EACE;EACT,SAAS,MAAM,WAAW;EAEzB,UAAA;CACU,CAAA;CAGjB,IAAI,iBAAiB,UACnB,OACE,oBAAC,aAAD;EACE,MAAA;EACO;EACE;EACT,SAAS,MAAM,WAAW;EAEzB,UAAA;CACU,CAAA;CAGjB,OACE,oBAAC,WAAD;EAAkB;EAAgB;EAC/B,UAAA;CACQ,CAAA;AAEf;;;;AChdA,SAAgB,aAAa,EAC3B,OACA,OACA,YACyC;CACzC,IAAI,CAAC,MAAM,aAAa,eAAe,OAAO;CAC9C,OACE,oBAAC,KAAD,EAAA,UACE,qBAAC,mBAAD;EACE,WAAA;EACA,MAAK;EACE;EACP,cAAW;EACX,IAAI,EAAE,2BAA2B,EAAE,OAAO,eAAe,EAAE;EAC3D,WAAW,QAAQ,SAAmC;GACpD,IAAI,SAAS,MAAM,SAAS,IAAI;EAClC;EARF,UAAA;GAUE,oBAAC,cAAD;IAAc,OAAM;IAAY,UAAA;GAAuB,CAAA;GACvD,oBAAC,cAAD;IAAc,OAAM;IAAQ,UAAA;GAAmB,CAAA;GAC/C,oBAAC,cAAD;IAAc,OAAM;IAAM,UAAA;GAAiB,CAAA;EAC1B;CAChB,CAAA,EAAA,CAAA;AAET;;;;ACLA,SAAgB,WAAW,OAA6C;CACtE,OAAO,MAAM,MAAM,aAAa,kBAC9B,oBAAC,WAAD,EAAW,GAAI,MAAQ,CAAA,IACrB;AACN;AAEA,SAAS,UAAU,EACjB,OACA,WACA,SACA,cACgC;CAGhC,MAAM,OAAO,SAAS;EACpB,UAAU;GACR;GACA,GAAG,MAAM,SAAS,KAAK,GAAG,MAAM,SAAS;GACzC;EACF;EACA,SAAS,YAAmC;GAC1C,MAAM,OAAqB,CAAC;GAC5B,WAAW,MAAM,OAAO,MAAM,OAAO,QAAQ;IAC3C,iBAAiB;IACjB,oBAAoB;GACtB,CAAC,GACC,IAAI,OAAO,IAAI,mBAAmB,UAAU,KAAK,KAAK,GAAG;GAE3D,OAAO;EACT;CACF,CAAC;CACD,MAAM,UAAU,WAAW,KAAK;CAChC,MAAM,SACJ,YAAY,KAAA,IACR,MAAM,OAAO,QAAQ,MAAM,CAAC,cAAc,SAAS,EAAE,IAAI,CAAC,CAAC,CAAC,MAAM,GAAG,CAAC,IACtE,MAAM,OAAO,QAAQ,MAAM,QAAQ,SAAS,EAAE,IAAI,CAAC;CACzD,IAAI,KAAK,WACP,OACE,oBAAC,KAAD;EAAK,IAAI;GAAE,SAAS;GAAQ,gBAAgB;GAAU,GAAG;EAAE;EACzD,UAAA,oBAAC,kBAAD,EAAkB,cAAW,UAAW,CAAA;CACrC,CAAA;CAGT,IAAI,KAAK,SACP,OAAO,oBAAC,OAAD;EAAO,UAAS;EAAS,UAAA,KAAK,MAAM;CAAe,CAAA;CAE5D,MAAM,WAAW,KAAK;CACtB,MAAM,QAAQ,QAAQ;CACtB,OACE,qBAAA,UAAA,EAAA,UAAA,CACG,UAAU,QAAQ,oBAAC,OAAD;EAAO,UAAS;EAAS,UAAA,MAAM;CAAe,CAAA,GAChE,SAAS,WAAW,IACnB,oBAAC,YAAD;EAAY,OAAM;EAAiB,UAAA;CAA+B,CAAA,IAElE,qBAAC,OAAD;EAAO,MAAK;EAAQ,cAAW;EAA/B,UAAA,CACE,oBAAC,WAAD,EAAA,UACE,qBAAC,UAAD,EAAA,UAAA;GACG,OAAO,KAAK,MACX,oBAAC,WAAD,EAAA,UAAyB,EAAE,MAAiB,GAA5B,EAAE,IAA0B,CAC7C;GACD,oBAAC,WAAD,EAAA,UAAW,WAAmB,CAAA;GAC9B,oBAAC,WAAD;IAAW,OAAM;IAAQ,UAAA;GAAkB,CAAA;EACnC,EAAA,CAAA,EACD,CAAA,GACX,oBAAC,WAAD,EAAA,UACG,SAAS,KAAK,QAAQ;GACrB,MAAM,KAAK,IAAI,MAAM,SAAS;GAC9B,OACE,qBAAC,UAAD,EAAA,UAAA;IACG,OAAO,KAAK,MACX,oBAAC,WAAD,EAAA,UACE,oBAAC,cAAD;KACE,OAAO;KACP,UAAU,MAAM,SAAS;KACzB,OAAO,IAAI,EAAE;KACF;IACZ,CAAA,EACQ,GAPK,EAAE,IAOP,CACZ;IACD,oBAAC,WAAD,EAAA,UAAY,OAAO,IAAI,cAAc,EAAa,CAAA;IAClD,oBAAC,WAAD;KAAW,OAAM;KACf,UAAA,oBAAC,QAAD;MACE,MAAK;MACL,cAAY,kBAAkB;MAC9B,UAAU,QAAQ;MAClB,eACE,QAAQ,OAAO,IAAI,EACjB,iBAAiB,aAAa,EAAE,EAClC,CAAC;MAEJ,UAAA;KAEO,CAAA;IACC,CAAA;GACH,EAAA,GA1BK,EA0BL;EAEd,CAAC,EACQ,CAAA,CACN;CAET,CAAA,CAAA,EAAA,CAAA;AAEN;;AAQA,SAAgB,UAAU,EACxB,UACA,YACA,GAAG,QAC4B;CAC/B,OACE,oBAAC,cAAD;EAAc,MAAM;EAAsB;EACtC,WAAA,UAAU,oBAAC,YAAD;GAAmB;GAAO,GAAI;EAAO,CAAA;CACrC,CAAA;AAElB;;;;;;;ACjIA,SAAgB,eACd,OACA,SACU;CACV,IAAI,YAAY,KAAA,GACd,OAAO,MAAM,OACV,QAAQ,MAAM,EAAE,SAAS,MAAM,CAAC,CAChC,KAAK,WAAW;EAAE;EAAO,QAAQ,MAAM;EAAO,OAAO,KAAA;CAAU,EAAE;CACtE,OAAO,QAAQ,SAAS,SAAmB;EACzC,MAAM,EACJ,OAAO,MACP,QACA,UACE,OAAO,SAAS,WAChB;GAAE,OAAO;GAAM,QAAQ,KAAA;GAAW,OAAO,KAAA;EAAU,IACnD;EACJ,MAAM,QAAQ,MAAM,MAAM,IAAI;EAC9B,OAAO,UAAU,KAAA,IACb,CAAC,IACD,CAAC;GAAE;GAAO,QAAQ,UAAU,MAAM;GAAO;EAAM,CAAC;CACtD,CAAC;AACH;;;;AClBA,SAAgB,WAAW,EACzB,OACA,KACA,SACA,YACA,WACA,WACgC;CAChC,MAAM,MAAM,eAAe,OAAO,OAAO;CACzC,MAAM,OAAO,IAAI,MAAM,MAAM,EAAE,MAAM,SAAS,UAAU,KAAK,IAAI;CACjE,MAAM,OAAO,IAAI,QAAQ,MAAM,MAAM,IAAI;CACzC,MAAM,WAAW,MAAM,SAAS;CAChC,MAAM,WAAW,MACf,oBAAC,cAAD;EACE,OAAO,EAAE;EACC;EACV,MAAK;EACL,OAAO,IAAI,EAAE,MAAM;EACnB,QAAQ;EACG;CACZ,CAAA;CAEH,OACE,oBAAC,MAAD;EAAM,SAAQ;EAAW,WAAU;EACjC,UAAA,qBAAC,aAAD,EAAA,UAAA;GACG,SAAS,KAAA,KACR,oBAAC,YAAD;IAAY,WAAU;IAAK,SAAQ;IAAK,cAAA;IACrC,UAAA,QAAQ,IAAI;GACH,CAAA;GAEd,oBAAC,OAAD;IAAO,WAAU;IAAK,SAAS;IAAK,IAAI,EAAE,GAAG,EAAE;IAC5C,UAAA,KAAK,KAAK,MACT,qBAAC,OAAD;KAEE,WAAU;KACV,SAAS;KACT,IAAI,EAAE,YAAY,WAAW;KAJ/B,UAAA,CAME,oBAAC,YAAD;MACE,WAAU;MACV,SAAQ;MACR,OAAM;MACN,IAAI,EAAE,UAAU,OAAO;MAEtB,UAAA,EAAE;KACO,CAAA,GACZ,oBAAC,YAAD;MACE,WAAU;MACV,SAAQ;MACR,IAAI;OAAE,GAAG;OAAG,UAAU;MAAE;MAEvB,UAAA,QAAQ,CAAC;KACA,CAAA,CACP;IApBA,GAAA,EAAE,MAAM,IAoBR,CACR;GACI,CAAA;GACN,YAAY,KAAA,KACX,oBAAC,QAAD;IAAQ,MAAK;IAAQ,IAAI,EAAE,IAAI,EAAE;IAAG,eAAe,QAAQ,GAAG;IAAG,UAAA;GAEzD,CAAA;EAEC,EAAA,CAAA;CACT,CAAA;AAEV;;;;ACxEA,SAAgB,SAAS,EACvB,OACA,MACA,SACA,YACA,QACA,YACA,aAC8B;CAC9B,IAAI,KAAK,WAAW,GAClB,OAAO,oBAAC,YAAD;EAAY,OAAM;EAAiB,UAAA;CAAuB,CAAA;CACnE,OACE,oBAAC,KAAD;EACE,WAAU;EACV,cAAY,MAAM,SAAS;EAC3B,IAAI;GACF,WAAW;GACX,GAAG;GACH,GAAG;GACH,SAAS;GACT,KAAK;GACL,qBACE,WAAW,SAAS,0CAA0C;EAClE;EAEC,UAAA,KAAK,KAAK,QACT,oBAAC,MAAD,EAAA,UACE,oBAAC,YAAD;GACS;GACF;GACI;GACG;GACD;GACX,SAAS;EACV,CAAA,EACC,GATK,OAAO,IAAI,MAAM,SAAS,SAAS,CASxC,CACL;CACE,CAAA;AAET;;;;ACrDA,SAAgB,UAAU,EACxB,OACA,OACA,WAKe;CACf,OACE,oBAAC,OAAD;EAAO,UAAS;EAAQ,QAAQ,oBAAC,QAAD;GAAQ,SAAS;GAAS,UAAA;EAAa,CAAA;EACpE,UAAA,kBAAkB,MAAM,IAAI,MAAM;CAC9B,CAAA;AAEX;;;;ACGA,SAAgB,aAAa,EAC3B,OACA,OACA,SACA,YACA,YACA,aACkC;CAClC,MAAM,EAAE,MAAM,aAAa,MAAM;CACjC,MAAM,OAAO,MAAM,MAAM,QAAQ,MAAM,UAAU;CACjD,IAAI,KAAK,SACP,OACE,oBAAC,WAAD;EACE,OAAO,MAAM,SAAS;EACtB,OAAO,KAAK;EACZ,eAAe,KAAK,KAAK,QAAQ;CAClC,CAAA;CAEL,IAAI,KAAK,WAAW,OAAO,oBAAC,kBAAD,EAAkB,cAAW,UAAW,CAAA;CACnE,MAAM,OAAO,KAAK,KAAK,MAAM,GAAG,QAAQ;CACxC,OACE,qBAAC,OAAD;EAAO,SAAS;EAAhB,UAAA,CACE,oBAAC,UAAD;GACS;GACD;GACG;GACG;GACZ,QAAO;GACK;GACD;EACZ,CAAA,GACD,qBAAC,OAAD;GACE,WAAU;GACV,SAAS;GACT,WAAU;GACV,cAAW;GACX,IAAI,EAAE,YAAY,SAAS;GAL7B,UAAA;IAOE,oBAAC,QAAD;KAAQ,UAAU,QAAQ;KAAG,eAAe,MAAM,QAAQ,OAAO,CAAC;KAAG,UAAA;IAE7D,CAAA;IACR,oBAAC,YAAD;KAAY,SAAQ;KAAS,UAAA,QAAQ;IAAmB,CAAA;IACxD,oBAAC,QAAD;KACE,UAAU,KAAK,KAAK,UAAU;KAC9B,eAAe,MAAM,QAAQ,OAAO,CAAC;KACtC,UAAA;IAEO,CAAA;GACH;EACF,CAAA,CAAA;;AAEX;;;;ACzDA,SAAgB,YAAY,EAC1B,SACA,QACA,YACiC;CACjC,MAAM,CAAC,QAAQ,aAAa,SAA6B,IAAI;CAC7D,MAAM,KAAK,MAAM;CACjB,OACE,qBAAA,UAAA,EAAA,UAAA,CACE,oBAAC,QAAD;EACE,iBAAc;EACd,iBAAe,WAAW;EAC1B,iBAAe,WAAW,OAAO,KAAA,IAAY;EAC7C,UAAU,MAAM,UAAU,EAAE,aAAa;EAC1C,UAAA;CAEO,CAAA,GACR,oBAAC,SAAD;EACM;EACJ,MAAM,WAAW;EACjB,UAAU;EACV,eAAe,UAAU,IAAI;EAC7B,WAAW,EACT,OAAO;GAAE,cAAc;GAAW,MAAM;GAAU,IAAI,EAAE,GAAG,EAAE;EAAE,EACjE;EAEA,UAAA,oBAAC,WAAD,EAAA,UACG,QAAQ,KAAK,MACZ,oBAAC,kBAAD;GAEE,OAAO,EAAE;GACT,SACE,oBAAC,UAAD;IACE,MAAK;IACL,SAAS,CAAC,OAAO,IAAI,EAAE,MAAM,IAAI;IACjC,gBAAgB;KACd,MAAM,OAAO,IAAI,IAAI,MAAM;KAC3B,IAAI,CAAC,KAAK,OAAO,EAAE,MAAM,IAAI,GAAG,KAAK,IAAI,EAAE,MAAM,IAAI;KACrD,SAAS,IAAI;IACf;GACD,CAAA;EAEJ,GAbM,EAAE,MAAM,IAad,CACF,EACQ,CAAA;CACJ,CAAA,CACT,EAAA,CAAA;AAEN;;;ACMA,SAAS,SAAS,EAChB,YACA,UACA,WACA,IACA,OACA,SAC8B;CAC9B,MAAM,SAAS,kBAAkB;CACjC,OACE,oBAAC,YAAD;EACE,OAAO;EACG;EACV,MAAK;EACE;EACP,WAAA;EACW;EACX,WAAW,SACT,KAAK,OAAO,QAAQ,iBAAiB;GAAE;GAAI;GAAO,OAAO;EAAK,CAAC;CAElE,CAAA;AAEL;AAEA,MAAM,WACJ,GACA,UACA,YACY,YAAY,CAAC,EAAE,YAAY,EAAE,SAAS;AAEpD,MAAM,QAAQ,GAAY,MACxB,KAAK,UAAU,CAAC,MAAM,KAAK,UAAU,CAAC;;AAGxC,SAAgB,cAAc,EAC5B,OACA,OACA,SACA,eAAe,OACf,sBAAsB,MACtB,WAAW,OACX,SACA,kBAAkB;CAAC;CAAI;CAAI;CAAI;AAAG,GAClC,YACA,WACA,aACmC;CACnC,MAAM,EAAE,aAAa;CACrB,MAAM,UAAU,SAAS;CACzB,MAAM,EAAE,MAAM,UAAU,SAAS,MAAM;CACvC,MAAM,OAAO,MAAM,MAAM,QAAQ,MAAM,UAAU;CACjD,MAAM,SAAS,MAAM,MAAM,UAAU;CACrC,MAAM,CAAC,QAAQ,aAAa,yBAA8B,IAAI,IAAI,CAAC;CACnE,MAAM,CAAC,QAAQ,aAAa,SAAwB,IAAI;CAExD,MAAM,CAAC,QAAQ,aAAa,SAAS,CAAC;CACtC,MAAM,QAAQ,cAEV,eAAe,OAAO,OAAO,CAAC,CAAC,QAC5B,MAAM,CAAC,gBAAgB,EAAE,MAAM,QAClC,GACF;EAAC;EAAO;EAAS;CAAY,CAC/B;CAEA,MAAM,cAAc,cAEhB,MAAM,KAAK,EAAE,OAAO,QAAQ,aAAa;EACvC,OAAO,MAAM;EACb,YAAY;EACZ,UAAU,MAAM;EAChB,YAAY;EACZ,UAAU,QAAQ,OAAO,UAAU,OAAO;EAC1C,GAAI,UAAU,KAAA,IAAY;GAAE,MAAM;GAAG,UAAU;EAAI,IAAI,EAAE,MAAM;EAC/D,aAAa,MACX,oBAAC,cAAD;GACS;GACP,UAAU,SAAS;GACnB,MAAK;GACL,OAAO,EAAE;GACT,QAAQ,EAAE;GACC;EACZ,CAAA;EAEH,iBAAiB,MACf,oBAAC,UAAD;GACE,GAAI;GACJ,YAAY;GACZ,UAAU,SAAS;GACR;EACZ,CAAA;CAEL,EAAE,GACJ;EAAC;EAAO,SAAS;EAAM;EAAW;EAAU;CAAO,CACrD;CAIA,MAAM,CAAC,UAAU,eAAe,SAAS,KAAK,IAAI;CAClD,IAAI,KAAK,SAAS,KAAA,KAAa,KAAK,SAAS,UAAU,YAAY,KAAK,IAAI;CAC5E,MAAM,OAAO,KAAK,QAAQ;CAC1B,MAAM,QAAQ,QAAQ,CAAC,EAAA,CAAG,MAAM,GAAG,QAAQ;CAC3C,MAAM,eAAe,MAAM,UAAU,KAAK;CAG1C,MAAM,WACJ,SAAS,KAAA,IACL,OAAO,WAAW,KACjB,OAAO,KAAK,WAAW,KAAK,UAAU,cAAc,IAAI;CAG/D,MAAM,WAAW,KACd,KAAK,MAAO,EAAE,OAAO,IAAI,EAAE,UAAU,EAAE,KAAM,CAAC,CAC9C,KAAK,GAAG;CACX,MAAM,YAAY,cAEd,aAAa,KACT,CAAC,IACD,SAAS,MAAM,GAAG,CAAC,CAAC,KAAK,SAAS;EAChC,OAAO,IAAI,QAAQ,MAAM,EAAE;EAC3B,MAAM,IAAI,WAAW,GAAG,IAAI,SAAS;CACvC,EAAE,GACR,CAAC,QAAQ,CACX;CACA,MAAM,aAAa,OAAO,YAAY,CAAC,GAAG,MAAM,CAAC,CAAC,KAAK,MAAM,CAAC,GAAG,KAAK,CAAC,CAAC;CACxE,MAAM,QAAQ,CAAC,mBAAG,IAAI,IAAI,CAAC,GAAG,iBAAiB,QAAQ,CAAC,CAAC,CAAC,CAAC,MACxD,GAAG,MAAM,IAAI,CAChB;CAEA,eAAe,KAAK,MAAW,UAA6B;EAC1D,MAAM,QAAoC,CAAC;EAC3C,KAAK,MAAM,EAAE,WAAW,OAAO;GAC7B,MAAM,QAAQ,KAAK,MAAM;GACzB,IACE,QAAQ,OAAO,UAAU,OAAO,KAChC,UAAU,KAAA,KACV,CAAC,KAAK,OAAO,SAAS,MAAM,KAAK,GAEjC,MAAM,MAAM,QAAQ;EACxB;EACA,IAAI,OAAO,KAAK,KAAK,CAAC,CAAC,WAAW,GAAG,OAAO;EAC5C,WAAW,MAAM,IAAI,CAAC;EACtB,IAAI;GACF,MAAM,MAAM,MAAM,UAAU,QAAQ;GACpC,MAAM,QAAQ,MAAM,OAAO,YAAY;IACrC,IAAI,SAAS;IACb;IACA,GAAI,QAAQ,KAAA,IAAY,CAAC,IAAI,EAAE,SAAS,IAAI;GAC9C,CAAC;GACD,UAAU,IAAI;GACd,OAAO;EACT,UAAU;GACR,WAAW,MAAM,IAAI,CAAC;EACxB;CACF;CAEA,SAAS,WAAW,OAAsB;EACxC,IAAI,iBAAiB,oBAAoB;GACvC,UAAU,6DAA6D;GACvE,KAAU,QAAQ;EACpB,OACE,UACE,mBAAmB,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK,GAC1E;CAEJ;CAEA,IAAI,KAAK,SACP,OACE,oBAAC,WAAD;EACE,OAAO,SAAS;EAChB,OAAO,KAAK;EACZ,eAAe,KAAK,KAAK,QAAQ;CAClC,CAAA;CAEL,OACE,qBAAC,KAAD;EAAK,aAAW,SAAS;EAAzB,UAAA;GACG,uBACC,oBAAC,aAAD;IAAa,SAAS;IAAe;IAAQ,UAAU;GAAY,CAAA;GAEpE,WAAW,QACV,oBAAC,OAAD;IACE,UAAS;IACT,eAAe,UAAU,IAAI;IAC7B,IAAI,EAAE,IAAI,EAAE;IAEX,UAAA;GACI,CAAA;GAET,oBAAC,UAAD;IACE,cAAY,SAAS;IACrB,YAAA;IACM;IACN,SAAS;IACT,WAAW,QAAa,IAAI;IAC5B,SAAS,KAAK;IACd,uBAAuB;IACvB,gBAAe;IACf,aAAY;IACZ,YAAW;IACD;IACV,YAAY,EACV,0BAA0B,EAAE,MAAM,SAChC,cAAc,GAAG,KAAK,GAAG,OAAO,GAAG,KAAK,GAAG,GAAG,MAAM,WACxD;IACA,iBAAiB;KAAE,MAAM,OAAO;KAAG;IAAS;IAC5C,iBAAiB;IACjB,0BAA0B,UACxB,MAAM,aAAa,WACf,MAAM,QAAQ,MAAM,OAAO,CAAC,IAC5B,MAAM,YAAY,MAAM,QAAQ;IAE3B;IACX,oBAAoB,UAClB,MAAM,QACJ,MAAM,KAAK,OAAO;KAAE,OAAO,EAAE;KAAO,MAAM,EAAE,SAAS;IAAO,EAAE,CAChE;IAEF,qBAAA;IACA,mBAAA;IACA,4BAAA;IACA,kBAAkB;IAClB,yBAAyB;IACzB,aAAa,MAAM,aAAa,EAAE,GAAU;IAC5C,GAAI;GACL,CAAA;EACE;;AAET;;;;ACjRA,SAAgB,aAAa,EAC3B,OACA,OACA,SACA,YACA,SAAS,QACT,YACA,aACkC;CAClC,MAAM,QAAQ,MAAM,MAAM,gBAAgB,MAAM,WAAW,EACzD,OAAO,MAAM,MAAM,SACrB,CAAC;CACD,IAAI,MAAM,SACR,OACE,oBAAC,WAAD;EACE,OAAO,MAAM,SAAS;EACtB,OAAO,MAAM;EACb,eAAe,KAAK,MAAM,QAAQ;CACnC,CAAA;CAEL,IAAI,MAAM,WAAW,OAAO,oBAAC,kBAAD,EAAkB,cAAW,UAAW,CAAA;CACpE,MAAM,OAAO,MAAM,KAAK,MAAM,KAAK;CACnC,OACE,qBAAC,OAAD;EAAO,SAAS;EAAhB,UAAA,CACE,oBAAC,UAAD;GACS;GACD;GACG;GACG;GACJ;GACI;GACD;EACZ,CAAA,GACA,MAAM,eACL,oBAAC,KAAD,EAAA,UACE,oBAAC,QAAD;GACE,SAAQ;GACR,UAAU,MAAM;GAChB,aAAW,MAAM;GACjB,eAAe,KAAK,MAAM,cAAc;GACzC,UAAA;EAEO,CAAA,EACL,CAAA,CAEF;;AAEX;;;AC1DA,MAAM,OAAO;;AAGb,SAAgB,aAAa,EAC3B,OACA,MACA,YACyC;CACzC,MAAM,SAAS,eAAe,MAAM,MAAM;CAC1C,IAAI,OAAO,WAAW,GAAG,OAAO;CAChC,MAAM,MAAM,KAAK;CACjB,MAAM,QACJ,QAAQ,KAAA,KAAa,OAAO,MAAM,MAAM,EAAE,SAAS,IAAI,KAAK,IACxD,IAAI,QACJ;CACN,OACE,qBAAC,OAAD;EAAO,WAAU;EAAM,SAAS;EAAhC,UAAA,CACE,qBAAC,WAAD;GACE,QAAA;GACA,MAAK;GACL,OAAM;GACN,OAAO;GACP,WAAW,MACT,SACE,EAAE,OAAO,UAAU,OACf,CAAC,IACD,CAAC;IAAE,OAAO,EAAE,OAAO;IAAO,MAAM,KAAK,QAAQ;GAAM,CAAC,CAC1D;GAEF,IAAI,EAAE,UAAU,QAAQ;GAZ1B,UAAA,CAcE,oBAAC,UAAD;IAAU,OAAO;IAAM,UAAA;GAAuB,CAAA,GAC7C,OAAO,KAAK,MACX,oBAAC,UAAD;IAAuB,OAAO,EAAE;IAC7B,UAAA,EAAE;GACK,GAFK,EAAE,IAEP,CACX,CACQ;EACV,CAAA,GAAA,UAAU,QACT,qBAAC,WAAD;GACE,QAAA;GACA,MAAK;GACL,OAAM;GACN,OAAO,KAAK,SAAS,OAAO,SAAS;GACrC,WAAW,MACT,SAAS,CAAC;IAAE;IAAO,MAAM,EAAE,OAAO,UAAU;GAAO,CAAC,CAAC;GAEvD,IAAI,EAAE,UAAU,OAAO;GARzB,UAAA,CAUE,oBAAC,UAAD;IAAU,OAAM;IAAM,UAAA;GAAmB,CAAA,GACzC,oBAAC,UAAD;IAAU,OAAM;IAAO,UAAA;GAAoB,CAAA,CAClC;EAER,CAAA,CAAA;;AAEX;;;ACDA,SAAS,iBAAiB,EACxB,OACA,UAAU,SACV,UAAU,CAAC,OAAO,GAClB,WACA,aACA,SACA,YACA,UACA,SACA,cACA,eAAe,YAAY,SAC3B,YACA,QACA,UACA,aACA,WACA,YACA,aAC0B;CAC1B,MAAM,QAAQ,cAAc,OAAO;EACjC,SAAS;EACT;EACA;EACA;CACF,CAAC;CACD,MAAM,EAAE,iBAAiB;CACzB,MAAM,OAAO,MAAyC,QAAQ,SAAS,CAAC;CACxE,OACE,qBAAC,OAAD;EAAO,SAAS;EAAhB,UAAA;GACE,qBAAC,OAAD;IACE,WAAU;IACV,YAAA;IACA,IAAI;KAAE,UAAU;KAAQ,KAAK;KAAG,YAAY;IAAa;IAH3D,UAAA;KAKG,IAAI,OAAO,KACV,oBAAC,aAAD;MACE,QAAQ,MAAM;MACd,OAAO,MAAM,MAAM;MACnB,OAAO,MAAM,MAAM;MACnB,UAAU,MAAM;MAChB,eAAe,MAAM;KACtB,CAAA;KAEF,gBACC,oBAAC,cAAD;MACS;MACP,MAAM,MAAM,MAAM;MAClB,UAAU,MAAM;KACjB,CAAA;KAEF,aAAa,mBACZ,oBAAC,kBAAD;MACE,OAAM;MACN,SACE,oBAAC,QAAD;OACE,SAAS,MAAM,MAAM;OACrB,WAAW,MAAM,MAAM,mBAAmB,EAAE,OAAO,OAAO;MAC3D,CAAA;KAEJ,CAAA;KAEF,aAAa,iBACZ,oBAAC,kBAAD;MACE,OAAM;MACN,SACE,oBAAC,QAAD;OACE,SAAS,MAAM,MAAM;OACrB,WAAW,MAAM,MAAM,sBAAsB,EAAE,OAAO,OAAO;MAC9D,CAAA;KAEJ,CAAA;IAEE;;GACN,IAAI,KAAK,KACR,oBAAC,WAAD;IACS;IACP,SAAS,MAAM,MAAM;IACrB,UAAU,MAAM;IAChB,QAAQ;IACG;GACZ,CAAA;GAEF,IAAI,SAAS,KACZ,oBAAC,eAAD;IACS;IACP,SAAS,MAAM,MAAM;IACrB,UAAU,MAAM;IACL;GACZ,CAAA;GAEH,qBAAC,OAAD;IACE,WAAU;IACV,YAAA;IACA,IAAI;KAAE,KAAK;KAAG,YAAY;IAAa;IAHzC,UAAA,CAKG,IAAI,QAAQ,KACX,oBAAC,KAAD;KAAK,IAAI;MAAE,MAAM;MAAQ,UAAU;KAAQ;KACzC,UAAA,oBAAC,cAAD;MACS;MACP,SAAS,MAAM,MAAM;MACrB,UAAU,MAAM;MAChB,QAAQ;KACT,CAAA;IACE,CAAA,GAEP,oBAAC,KAAD;KAAK,IAAI;MAAE,MAAM;MAAG,UAAU;KAAE;KAC7B,UAAA,YAAY,UACX,oBAAC,eAAD;MACS;MACA;MACE;MACC;MACD;MACK;MACF;MACD;MACA;KACZ,CAAA,IACC,YAAY,aACd,oBAAC,cAAD;MACS;MACA;MACE;MACG;MACA;MACD;KACZ,CAAA,IAED,oBAAC,cAAD;MACS;MACA;MACE;MACG;MACA;MACD;KACZ,CAAA;IAEA,CAAA,CACA;;EACF;;AAEX;;AAGA,SAAgB,aAAa,EAC3B,UACA,YACA,GAAG,SAC+B;CAClC,OACE,oBAAC,cAAD;EAAc,MAAM;EAAsB;EACtC,WAAA,UAAU,oBAAC,kBAAD;GAAyB;GAAO,GAAI;EAAQ,CAAA;CAC5C,CAAA;AAElB;;;ACrNA,MAAa,UAA6B;CAAC;CAAO;CAAQ;AAAO;AAwCjE,MAAM,YAAY,UAChB,OAAO,UAAU,YAAY,UAAU,QAAQ,CAAC,MAAM,QAAQ,KAAK;AAErE,MAAM,WAAW,UACf,MAAM,QAAQ,KAAK,IAAI,MAAM,OAAO,QAAQ,IAAI,CAAC;AAEnD,MAAM,OAAO,UAA4B,OAAO,UAAU,WAAW,QAAQ;AAE7E,MAAM,aAAa,UACjB,OAAO,UAAU,WAAW,QAAQ;AAEtC,MAAM,QAAQ,UACZ,OAAO,UAAU,WAAW,QAAQ,OAAO,SAAS,EAAE;;;;;AAMxD,SAAgB,aAAa,OAA6B;CACxD,IAAI,OAAO,UAAU,UAAU,OAAO;CACtC,MAAM,QAAQ,kCAAkC,KAAK,KAAK;CAC1D,MAAM,OAAO,IAAI,KAAK,QAAQ,QAAQ,GAAG,MAAM,EAAE;CACjD,OAAO,OAAO,MAAM,KAAK,QAAQ,CAAC,IAAI,OAAO;AAC/C;AAEA,SAAS,OAAO,MAA6B,UAAiC;CAC5E,MAAM,SAAwB,CAAC;CAC/B,KAAK,MAAM,OAAO,MAAM;EACtB,MAAM,KAAK,aAAa,IAAI,eAAe;EAC3C,IAAI,OAAO,MAAM,OAAO,KAAK;GAAE;GAAI,OAAO,IAAI,IAAI,SAAS;EAAE,CAAC;CAChE;CACA,OAAO,OAAO,MAAM,GAAG,MAAM,EAAE,GAAG,QAAQ,IAAI,EAAE,GAAG,QAAQ,CAAC;AAC9D;;AAGA,SAAgB,WAAW,MAA6B;CACtD,OAAO;EACL,OAAO,IAAI,KAAK,QAAQ;EACxB,SAAS,QAAQ,KAAK,UAAU,CAAC,CAAC,KAAK,SAAS;GAC9C,OAAO,KAAK,IAAI,QAAQ;GACxB,OAAO,IAAI,IAAI,QAAQ;GACvB,SAAS,UAAU,IAAI,UAAU;GACjC,SAAS,UAAU,IAAI,UAAU;GACjC,SAAS,UAAU,IAAI,UAAU;GACjC,OAAO,UAAU,IAAI,QAAQ;EAC/B,EAAE;EACF,aAAa,QAAQ,KAAK,cAAc,CAAC,CAAC,KAAK,SAAS;GACtD,OAAO,KAAK,IAAI,QAAQ;GACxB,OAAO,KAAK,IAAI,QAAQ;GACxB,OAAO,IAAI,IAAI,QAAQ;EACzB,EAAE;EACF,YAAY,OAAO,QAAQ,KAAK,cAAc,GAAG,OAAO;CAC1D;AACF;AAEA,MAAM,WAAW,UAAuC;CACtD,IAAI,CAAC,SAAS,KAAK,GAAG,OAAO;CAC7B,MAAM,KAAK,aAAa,MAAM,eAAe;CAC7C,OAAO,OAAO,OAAO,OAAO;EAAE;EAAI,OAAO,IAAI,MAAM,QAAQ;CAAE;AAC/D;;AAGA,SAAgB,gBAAgB,MAAkC;CAChE,MAAM,QAAQ,KAAK;CACnB,OAAO;EACL,OAAO,OAAO,UAAU,WAAW,QAAQ;EAC3C,QAAQ,KAAK,KAAK,SAAS;EAC3B,QAAQ,KAAK,KAAK,SAAS;EAC3B,WAAW,QAAQ,KAAK,aAAa;EACrC,aAAa,OAAO,QAAQ,KAAK,cAAc,GAAG,OAAO;CAC3D;AACF;;AAGA,SAAgB,kBAAkB,MAA2B;CAC3D,OAAO,CAAC,GAAG,IAAI,IAAI,KAAK,YAAY,KAAK,QAAQ,IAAI,KAAK,CAAC,CAAC;AAC9D;;;;;;AAOA,SAAgB,aACd,IACA,QACA,QACA,UAAU,OACF;CACR,MAAM,UAAU,WAAW;CAC3B,OAAO,IAAI,KAAK,eAAe,QAAQ;EACrC,UAAU;EACV,OAAO;EACP,GAAI,WAAW,CAAC,UAAU,EAAE,MAAM,UAAU,IAAI,CAAC;EACjD,GAAI,UAAU,CAAC,IAAI,EAAE,KAAK,UAAU;CACtC,CAAC,CAAC,CAAC,OAAO,EAAE;AACd;AAEA,MAAM,UAAU,UAA0B,KAAK,MAAM,QAAQ,GAAG,IAAI;;AAGpE,MAAa,WAAW,UACtB,UAAU,OAAO,OAAO,OAAO,KAAK;;;;;;AAgBtC,SAAgB,eACd,SACA,YACgB;CAChB,MAAM,wBAAQ,IAAI,IAAoB;CACtC,KAAK,MAAM,SAAS,SAAS,MAAM,IAAI,MAAM,GAAG,QAAQ,GAAG,MAAM,KAAK;CACtE,MAAM,EAAE,cAAc;CACtB,IAAI,cAAc,QAAQ,CAAC,MAAM,IAAI,UAAU,GAAG,QAAQ,CAAC,GACzD,MAAM,IAAI,UAAU,GAAG,QAAQ,GAAG,UAAU,KAAK;CAEnD,MAAM,4BAAY,IAAI,IAAoB;CAC1C,IAAI,cAAc,MAChB,UAAU,IAAI,UAAU,GAAG,QAAQ,GAAG,UAAU,KAAK;CAEvD,KAAK,MAAM,SAAS,WAAW,aAC7B,UAAU,IAAI,MAAM,GAAG,QAAQ,GAAG,MAAM,KAAK;CAE/C,MAAM,QAAQ,CAAC,mBAAG,IAAI,IAAI,CAAC,GAAG,MAAM,KAAK,GAAG,GAAG,UAAU,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,MAChE,GAAG,MAAM,IAAI,CAChB;CACA,OAAO;EACL,IAAI,MAAM,KAAK,SAAS,IAAI,KAAK,IAAI,CAAC;EACtC,OAAO,MAAM,KAAK,SAAS,MAAM,IAAI,IAAI,KAAK,IAAI;EAClD,UAAU,MAAM,KAAK,SAAS,UAAU,IAAI,IAAI,KAAK,IAAI;CAC3D;AACF;;;;;;;AC9JA,SAAgB,eAAe,EAC7B,UACA,YACA,YACA,YAMe;CACf,OACE,oBAAC,cAAD;EAAc,MAAM;EAAsB;EACtC,WAAA,UAAW,MAAM,aAAa,cAAc,SAAS,KAAK,IAAI;CACpD,CAAA;AAElB;;AAGA,SAAgB,cAAc,EAC5B,OACA,OACA,YAMe;CACf,IAAI,MAAM,SAAS,KAAA,GAAW,OAAO,oBAAA,UAAA,EAAA,UAAG,SAAS,MAAM,IAAI,EAAI,CAAA;CAC/D,IAAI,MAAM,UAAU,MAClB,OAAO,oBAAC,OAAD;EAAO,UAAS;EAAW,UAAA,MAAM,MAAM;CAAe,CAAA;CAE/D,OACE,oBAAC,KAAD;EAAK,IAAI;GAAE,SAAS;GAAQ,gBAAgB;GAAU,GAAG;EAAE;EACzD,UAAA,oBAAC,kBAAD,EAAkB,cAAY,WAAW,QAAU,CAAA;CAChD,CAAA;AAET;;AAGA,SAAS,eAAe,MAAc,MAAkC;CACtE,OAAO;EACL;EACA,OAAO,SAAS,IAAI;EACpB;EACA,QAAQ;EACR,UAAU;EACV,UAAU;EACV,UAAU;EACV,SAAS;EACT,UAAU;EACV,aAAa;GACX,WAAW,KAAA;GACX,WAAW,KAAA;GACX,SAAS,KAAA;GACT,SAAS,KAAA;GACT,SAAS,KAAA;EACX;EACA,YAAY;EACZ,UAAU;EACV,WAAW,CAAC;EACZ,SAAS,SAAS;EAClB,aAAa,SAAS;CACxB;AACF;;;;;AAMA,SAAgB,eACd,OACA,MACA,OACiB;CACjB,MAAM,OAAO,MAAM,MAAM,IAAI,KAAK,eAAe,MAAM,QAAQ;CAC/D,OAAO,KAAK,SAAS,aAAa,UAAU,QAAQ,CAAC,OAAO,UAAU,KAAK,IACvE;EAAE,GAAG;EAAM,MAAM;CAAS,IAC1B;AACN;;AAGA,SAAgB,cACd,OACA,MACiB;CACjB,OAAO,MAAM,MAAM,IAAI,KAAK,eAAe,MAAM,QAAQ;AAC3D;;AAGA,MAAa,iBACX,OACA,QAEA,MAAM,SAAS,YAAY,IAAI,YAAY,MAAM,SAAS;;AAG5D,SAAgB,UAAU,EACxB,OACA,MACA,OACA,aAMe;CACf,OACE,oBAAC,cAAD;EACE,OAAO,eAAe,OAAO,MAAM,KAAK;EACxC,UAAU,MAAM,SAAS;EAClB;EACI;CACZ,CAAA;AAEL;;AAYA,MAAa,WAAW,QAAqB,UAC3C,OAAO,QAAQ,OAAO;;AAGxB,SAAgB,iBAA8B;CAC5C,MAAM,QAAQ,SAAS;CACvB,MAAM,WAAW,MAAM,QAAQ,MAAA,CAAO;CACtC,OAAO;EACL,QAAQ,QAAQ;EAChB,QAAQ,UAAU;EAClB,QAAQ,KAAK;EACb,QAAQ,QAAQ;EAChB,QAAQ,QAAQ;EAChB,QAAQ,MAAM;CAChB;AACF;;AAGA,MAAa,aAAa;CACxB,UAAU;EAAE,MAAM;EAAW,OAAO;CAAU;CAC9C,YAAY;CACZ,oBAAoB;AACtB;;AAGA,MAAa,aACX,OACA,UAEA,MAAM,QAAQ,QAAQ,SAAS,KAAK,UAAU,MAAM,SAAS,QAAQ;;;;;;AAOvE,SAAgB,YAAY,EAC1B,OACA,SACA,YAKe;CACf,OACE,qBAAC,KAAD;EAAK,WAAU;EAAS,cAAY;EAAO,IAAI,EAAE,GAAG,EAAE;EAAtD,UAAA,CACG,UACD,oBAAC,YAAD;GACE,WAAU;GACV,SAAQ;GACR,OAAM;GAEL,UAAA;EACS,CAAA,CACT;;AAET;;AAGA,SAAgB,SACd,IACA,QACA,QAQA;CACA,OAAO;EACL,WAAW;EACX,MAAM,CAAC,GAAG,EAAE;EACZ,YAAY;EAEZ,QAAQ;EACR,OAAO;EACP,iBAAiB,UAAU,aAAa,OAAO,QAAQ,QAAQ,IAAI;CACrE;AACF;;;ACpOA,SAAS,IAAI,EACX,OACA,UACA,UAKe;CACf,OACE,oBAAC,MAAD;EAAM,SAAQ;EAAW,WAAU;EAAK,IAAI,EAAE,WAAW,OAAO;EAC9D,UAAA,qBAAC,aAAD,EAAA,UAAA;GACE,oBAAC,YAAD;IAAY,WAAU;IAAK,SAAQ;IAAW,OAAM;IACjD,UAAA;GACS,CAAA;GACZ,oBAAC,KAAD;IAAK,IAAI;IAAa;GAAc,CAAA;GACnC;EACU,EAAA,CAAA;CACT,CAAA;AAEV;AAEA,SAAS,MAAM,EACb,OACA,MACA,aAKe;CACf,OACE,qBAAC,YAAD;EACE,SAAQ;EACR,OAAM;EACN,IAAI;GAAE,SAAS;GAAQ,KAAK;GAAK,YAAY;EAAW;EAH1D,UAAA;GAKG;GACD,oBAAC,WAAD;IACS;IACP,MAAM,KAAK;IACX,OAAO,KAAK;IACD;GACZ,CAAA;GACA;GACD,oBAAC,WAAD;IACS;IACP,MAAM,KAAK;IACX,OAAO,KAAK;IACD;GACZ,CAAA;EACS;;AAEhB;AAEA,SAAS,MAAM,EACb,OACA,aAIe;CACf,MAAM,QAAQ,MAAM,MAAM,SAAS;CACnC,OACE,oBAAC,eAAD;EAAsB;EAAO,OAAM;EAC/B,WAAA,SAAS;GACT,MAAM,QAAQ,WAAW,IAAI;GAC7B,OACE,qBAAC,KAAD;IACE,WAAU;IACV,cAAY,GAAG,MAAM,SAAS,MAAM;IACpC,IAAI;KACF,SAAS;KACT,qBAAqB;KACrB,KAAK;KACL,GAAG;KACH,GAAG;IACL;IATF,UAAA,CAWE,oBAAC,KAAD;KAAK,OAAM;KACT,UAAA,oBAAC,WAAD;MACS;MACP,MAAK;MACL,OAAO,MAAM;MACF;KACZ,CAAA;IACE,CAAA,GACJ,UAAU,OAAO,KAAK,CAAC,CAAC,KAAK,SAC5B,oBAAC,KAAD;KAEE,OAAO,WAAW,SAAS,KAAK,KAAK,CAAC,CAAC,YAAY;KACnD,QACE,KAAK,YAAY,QAAQ,KAAK,YAAY,OAAO,KAAA,IAC/C,oBAAC,OAAD;MAAc;MAAa;MAAiB;KAAY,CAAA;KAI5D,UAAA,oBAAC,WAAD;MACS;MACP,MAAM,KAAK;MACX,OAAO,QAAQ,KAAK,OAAO;MAChB;KACZ,CAAA;IACE,GAdE,KAAK,KAcP,CACN,CACE;;EAET;CACa,CAAA;AAEnB;;AAGA,SAAgB,cAAc,EAC5B,UACA,YACA,aAC0B;CAC1B,OACE,oBAAC,gBAAD;EACY;EACE;EACZ,YAAW;EAET,WAAA,UAAU,oBAAC,OAAD;GAAc;GAAkB;EAAY,CAAA;CAC1C,CAAA;AAEpB;;;;ACvHA,SAAgB,aAAa,EAC3B,OACA,YACkC;CAClC,OACE,oBAAC,mBAAD;EACE,WAAA;EACA,MAAK;EACE;EACP,cAAW;EACX,WAAW,QAAQ,SAAwB;GACzC,IAAI,SAAS,MAAM,SAAS,IAAI;EAClC;EAEC,UAAA,QAAQ,KAAK,WACZ,oBAAC,cAAD;GAEE,OAAO;GACP,IAAI,EAAE,OAAO,eAAe;GAE3B,UAAA;EACW,GALP,MAKO,CACf;CACgB,CAAA;AAEvB;AAEA,SAAS,OAAO,EACd,OACA,UAIe;CACf,MAAM,EAAE,WAAW,QAAQ;CAC3B,MAAM,CAAC,SAAS,eAAe;CAC/B,MAAM,QAAQ,MAAM,MAAM,SAAS,EAAE,OAAO,CAAC;CAC7C,OACE,oBAAC,eAAD;EAAsB;EAAO,OAAM;EAC/B,WAAA,SAAS;GACT,MAAM,EAAE,eAAe,WAAW,IAAI;GACtC,IAAI,WAAW,WAAW,GACxB,OACE,oBAAC,YAAD;IAAY,OAAM;IACf,UAAA;GACS,CAAA;GAGhB,OACE,oBAAC,aAAD;IACE,OAAO,GAAG,MAAM,SAAS,MAAM,eAAe;IAC9C,SAAS,uBAAuB,OAAO;IAEvC,UAAA,oBAAC,WAAD;KACE,QAAQ;KACR,eAAA;KACA,YAAA;KACA,OAAO,CACL,SACE,WAAW,KAAK,UAAU,MAAM,EAAE,GAClC,QACA,MACF,CACF;KACA,OAAO,CAAC;MAAE,OAAO;MAAW,KAAK;KAAE,CAAC;KACpC,QAAQ,CACN;MACE,IAAI;MACJ,OAAO;MACP,MAAM,WAAW,KAAK,UAAU,MAAM,KAAK;MAC3C;MACA,UAAU;MACV,OAAO;MACP,cAAc;KAChB,CACF;IACD,CAAA;GACU,CAAA;EAEjB;CACa,CAAA;AAEnB;;;;;;;AAaA,SAAgB,gBAAgB,EAC9B,UACA,YACA,QAAQ,UAAU,SACmB;CACrC,MAAM,CAAC,QAAQ,aAAa,SAAiB,OAAO;CACpD,OACE,oBAAC,gBAAD;EACY;EACE;EACZ,YAAW;EAET,WAAA,UACA,qBAAC,KAAD;GAAK,WAAU;GAAU,cAAW;GAApC,UAAA,CACE,oBAAC,KAAD;IAAK,IAAI;KAAE,SAAS;KAAQ,gBAAgB;KAAY,IAAI;IAAE;IAC5D,UAAA,oBAAC,cAAD;KAAc,OAAO;KAAQ,UAAU;IAAY,CAAA;GAChD,CAAA,GACL,oBAAC,QAAD;IAAe;IAAe;GAAS,CAAA,CACpC;;CAEO,CAAA;AAEpB;;;;ACtHA,MAAM,WAAW,QAAwB,SAAS,GAAG;AAErD,SAAS,MAAM,EACb,OACA,OACA,OACA,QAMe;CACf,MAAM,SAAS,eAAe;CAC9B,MAAM,OAAO,MAAM,YAAY,QAAQ,QAAQ,IAAI,UAAU,KAAK;CAClE,MAAM,QAAQ,GAAG,MAAM,SAAS,MAAM,MAAM,SAAS,KAAK,CAAC,CAAC,YAAY;CACxE,MAAM,UAAU,uCAAuC,SAAS,KAAK,EAAE;CACvE,IAAI,SAAS,OACX,OACE,oBAAC,aAAD;EAAoB;EAAgB;EAClC,UAAA,oBAAC,UAAD;GACE,QAAQ;GACR,eAAA;GACA,QAAQ,CACN;IACE,aAAa;IACb,cAAc;IACd,MAAM,KAAK,KAAK,KAAK,WAAW;KAC9B,IAAI,IAAI;KACR,OAAO,QAAQ,IAAI,KAAK;KACxB,OAAO,IAAI;KACX,OAAO,QAAQ,QAAQ,KAAK;IAC9B,EAAE;GACJ,CACF;EACD,CAAA;CACU,CAAA;CAGjB,OACE,oBAAC,aAAD;EAAoB;EAAgB;EAClC,UAAA,oBAAC,UAAD;GACE,QAAQ;GACR,eAAA;GACA,YAAA;GACA,OAAO,CACL;IACE,WAAW;IACX,MAAM,KAAK,KAAK,QAAQ,QAAQ,IAAI,KAAK,CAAC;IAC1C,UAAU;KACR,MAAM;KACN,QAAQ,KAAK,KAAK,QAAQ,QAAQ,IAAI,KAAK,CAAC;KAC5C,QAAQ,KAAK,KAAK,MAAM,UAAU,QAAQ,QAAQ,KAAK,CAAC;IAC1D;GACF,CACF;GACA,OAAO,CAAC;IAAE,OAAO;IAAW,KAAK;GAAE,CAAC;GACpC,QAAQ,CACN;IAAE,IAAI;IAAS,OAAO;IAAW,MAAM,KAAK,KAAK,MAAM,EAAE,KAAK;GAAE,CAClE;EACD,CAAA;CACU,CAAA;AAEjB;AAEA,SAASC,QAAM,EACb,OACA,MACA,gBAKe;CACf,MAAM,CAAC,QAAQ,aAAa,SAA6B,YAAY;CACrE,MAAM,CAAC,OAAO,YAAY,SAA4B,IAAI;CAC1D,MAAM,QAAQ,MAAM,MAAM,SAAS;CACnC,OACE,oBAAC,eAAD;EAAsB;EAAO,OAAM;EAC/B,WAAA,SAAS;GACT,MAAM,QAAQ,WAAW,IAAI;GAC7B,MAAM,SAAS,kBAAkB,KAAK;GACtC,MAAM,QACJ,WAAW,KAAA,KAAa,OAAO,SAAS,MAAM,IAAI,SAAS,OAAO;GACpE,IAAI,UAAU,KAAA,GACZ,OACE,oBAAC,YAAD;IAAY,OAAM;IACf,UAAA;GACS,CAAA;GAGhB,OACE,qBAAA,UAAA,EAAA,UAAA,CACE,qBAAC,KAAD;IACE,IAAI;KACF,SAAS;KACT,UAAU;KACV,KAAK;KACL,gBAAgB;KAChB,IAAI;IACN;IAPF,UAAA,CASE,oBAAC,WAAD;KACE,QAAA;KACA,MAAK;KACL,OAAM;KACN,OAAO;KACP,IAAI,EAAE,UAAU,QAAQ;KACxB,WAAW,UAAU,UAAU,MAAM,OAAO,KAAK;KAEhD,UAAA,OAAO,KAAK,SACX,oBAAC,UAAD;MAAqB,OAAO;MACzB,UAAA,SAAS,IAAI;KACN,GAFK,IAEL,CACX;IACQ,CAAA,GACX,qBAAC,mBAAD;KACE,WAAA;KACA,MAAK;KACL,OAAO;KACP,cAAW;KACX,WAAW,QAAQ,SAAmC;MACpD,IAAI,SAAS,MAAM,SAAS,IAAI;KAClC;KAPF,UAAA,CASE,oBAAC,cAAD;MAAc,OAAM;MAAM,IAAI,EAAE,OAAO,eAAe;MACnD,UAAA;KACW,CAAA,GACd,oBAAC,cAAD;MAAc,OAAM;MAAM,IAAI,EAAE,OAAO,eAAe;MACnD,UAAA;KACW,CAAA,CACG;IAChB,CAAA,CAAA;GACL,CAAA,GAAA,oBAAC,OAAD;IAAc;IAAc;IAAc;IAAO,MAAM;GAAQ,CAAA,CAC/D,EAAA,CAAA;EAEN;CACa,CAAA;AAEnB;;;;;;AAcA,SAAgB,mBAAmB,EACjC,UACA,YACA,OAAO,OACP,SACwC;CACxC,OACE,oBAAC,gBAAD;EACY;EACE;EACZ,YAAW;EAET,WAAA,UACA,oBAAC,KAAD;GAAK,WAAU;GAAU,cAAW;GAClC,UAAA,oBAACA,SAAD;IAAc;IAAa;IAAM,cAAc;GAAQ,CAAA;EACpD,CAAA;CAEO,CAAA;AAEpB;;;AC9KA,SAAS,MAAM,EACb,OACA,aAIe;CACf,MAAM,QAAQ,MAAM,MAAM,SAAS;CACnC,OACE,oBAAC,eAAD;EAAsB;EAAO,OAAM;EAC/B,WAAA,SAAS;GACT,MAAM,QAAQ,WAAW,IAAI;GAC7B,OACE,qBAAC,KAAD;IAAK,IAAI;KAAE,SAAS;KAAQ,KAAK;IAAE;IAAnC,UAAA,CACE,qBAAC,gBAAD;KAAgB,WAAU;KAAU,cAAW;KAA/C,UAAA,CACE,oBAAC,YAAD;MAAY,WAAU;MAAK,SAAQ;MAAK,IAAI,EAAE,IAAI,EAAE;MACjD,UAAA;KACS,CAAA,GACZ,qBAAC,OAAD;MAAO,MAAK;MAAQ,cAAW;MAA/B,UAAA,CACE,oBAAC,WAAD,EAAA,UACE,qBAAC,UAAD,EAAA,UAAA;OACE,oBAAC,WAAD,EAAA,UAAY,QAAmB,CAAA;OAC/B,oBAAC,WAAD;QAAW,OAAM;QAAS,UAAA;OAAmB,CAAA;OAC7C,oBAAC,WAAD;QAAW,OAAM;QAAS,UAAA;OAAqB,CAAA;OAC/C,oBAAC,WAAD;QAAW,OAAM;QAAS,UAAA;OAAqB,CAAA;OAC/C,oBAAC,WAAD;QAAW,OAAM;QAAS,UAAA;OAAqB,CAAA;OAC/C,oBAAC,WAAD;QAAW,OAAM;QAAS,UAAA;OAAmB,CAAA;MACrC,EAAA,CAAA,EACD,CAAA,GACX,oBAAC,WAAD,EAAA,UACG,UAAU,OAAO,KAAK,CAAC,CAAC,KAAK,SAC5B,qBAAC,UAAD,EAAA,UAAA;OACE,oBAAC,WAAD;QAAW,WAAU;QAAK,OAAM;QAC7B,UAAA,SAAS,KAAK,KAAK;OACX,CAAA;OACX,oBAAC,WAAD;QAAW,OAAM;QAAS,UAAA,KAAK;OAAiB,CAAA;OAE9C;QACE,KAAK;QACL,KAAK;QACL,KAAK;QACL,KAAK;OACP,CAAC,CACD,KAAK,OAAO,UACZ,oBAAC,WAAD;QAAuB,OAAM;QAC3B,UAAA,oBAAC,WAAD;SACS;SACP,MAAM,KAAK;SACX,OAAO,QAAQ,KAAK;SACT;QACZ,CAAA;OACQ,GAPK,KAOL,CACZ;MACO,EAAA,GAtBK,KAAK,KAsBV,CACX,EACQ,CAAA,CACN;KACO,CAAA,CAAA;IAChB,CAAA,GAAA,qBAAC,gBAAD;KAAgB,WAAU;KAAU,cAAW;KAA/C,UAAA,CACE,oBAAC,YAAD;MAAY,WAAU;MAAK,SAAQ;MAAK,IAAI,EAAE,IAAI,EAAE;MACjD,UAAA;KACS,CAAA,GACZ,qBAAC,OAAD;MAAO,MAAK;MAAQ,cAAW;MAA/B,UAAA,CACE,oBAAC,WAAD,EAAA,UACE,qBAAC,UAAD,EAAA,UAAA;OACE,oBAAC,WAAD,EAAA,UAAY,QAAmB,CAAA;OAC/B,oBAAC,WAAD,EAAA,UAAY,QAAmB,CAAA;OAC/B,oBAAC,WAAD;QAAW,OAAM;QAAS,UAAA;OAAqB,CAAA;MACvC,EAAA,CAAA,EACD,CAAA,GACX,oBAAC,WAAD,EAAA,UACG,MAAM,YAAY,KAAK,QAAQ;OAC9B,MAAM,QAAQ,cAAc,OAAO,IAAI,KAAK;OAC5C,OACE,qBAAC,UAAD,EAAA,UAAA;QACE,oBAAC,WAAD;SAAW,WAAU;SAAK,OAAM;SAC7B,UAAA,MAAM;QACE,CAAA;QACX,oBAAC,WAAD,EAAA,UACE,oBAAC,cAAD;SACS;SACP,UAAU,MAAM,SAAS;SACzB,OAAO,cAAc,OAAO,IAAI,KAAK;SAC1B;QACZ,CAAA,EACQ,CAAA;QACX,oBAAC,WAAD;SAAW,OAAM;SAAS,UAAA,IAAI;QAAiB,CAAA;OACvC,EAAA,GAbK,GAAG,IAAI,MAAM,GAAG,IAAI,OAazB;MAEd,CAAC,EACQ,CAAA,CACN;KACO,CAAA,CAAA;IACb,CAAA,CAAA;;EAET;CACa,CAAA;AAEnB;;;;;;AAOA,SAAgB,gBAAgB,EAC9B,UACA,YACA,aAC0B;CAC1B,OACE,oBAAC,gBAAD;EACY;EACE;EACZ,YAAW;EAET,WAAA,UAAU,oBAAC,OAAD;GAAc;GAAkB;EAAY,CAAA;CAC1C,CAAA;AAEpB;;;ACnIA,SAAgB,QAAQ,EACtB,OACA,YAIe;CACf,OACE,qBAAC,KAAD;EAAK,WAAU;EAAU,cAAY;EAArC,UAAA,CACE,oBAAC,YAAD;GAAY,WAAU;GAAK,SAAQ;GAAK,IAAI,EAAE,IAAI,EAAE;GACjD,UAAA;EACS,CAAA,GACX,QACE;;AAET;;AAGA,SAAgB,eAAe,OAAgC;CAC7D,OACE,oBAAC,gBAAD;EACE,UAAU,MAAM;EAChB,YAAY,MAAM;EAClB,YAAW;EAGT,gBAAA,qBAAC,KAAD;GAAK,IAAI;IAAE,SAAS;IAAQ,KAAK;GAAE;GAAnC,UAAA;IACE,oBAAC,eAAD,EAAe,GAAI,MAAQ,CAAA;IAC3B,qBAAC,KAAD;KACE,IAAI;MACF,SAAS;MACT,KAAK;MACL,qBAAqB;OAAE,IAAI;OAAO,IAAI;MAAU;KAClD;KALF,UAAA,CAOE,oBAAC,SAAD;MAAS,OAAM;MACb,UAAA,oBAAC,iBAAD,EAAiB,GAAI,MAAQ,CAAA;KACtB,CAAA,GACT,oBAAC,SAAD;MAAS,OAAM;MACb,UAAA,oBAAC,oBAAD,EAAoB,GAAI,MAAQ,CAAA;KACzB,CAAA,CACN;;IACL,oBAAC,iBAAD,EAAiB,GAAI,MAAQ,CAAA;GAC1B;;CAEO,CAAA;AAEpB;;;ACvCA,MAAM,kBAAkB;;AAGxB,SAAgB,kBAAkB,OAIhC;CACA,OAAO;EACL,GAAI,MAAM,UAAU,KAAA,IAAY,CAAC,IAAI,EAAE,OAAO,MAAM,MAAM;EAC1D,SAAS,MAAM,WAAW;EAC1B,QAAQ,MAAM,UAAU;CAC1B;AACF;AAEA,SAAS,OAAO,EACd,OACA,OACA,YAQe;CACf,MAAM,SAAS,MAAM,MAAM,WAAW,kBAAkB,KAAK,CAAC;CAC9D,OACE,oBAAC,eAAD;EAAe,OAAO;EAAQ,OAAM;EAChC,WAAA,SAAS,SAAS,gBAAgB,IAAI,GAAG,KAAK;CACnC,CAAA;AAEnB;;;;;;AAOA,SAAgB,mBAAmB,EACjC,UACA,YACA,OACA,YASe;CACf,OACE,oBAAC,gBAAD;EACY;EACE;EACZ,YAAW;EAET,WAAA,UACA,oBAAC,QAAD;GAAe;GAAc;GAC1B;EACK,CAAA;CAEI,CAAA;AAEpB;;;ACnEA,SAAS,KAAK,EACZ,OACA,YACA,WAKe;CACf,MAAM,EAAE,WAAW,QAAQ;CAC3B,MAAM,CAAC,YAAY,iBAAiB,eAAe;CACnD,MAAM,SAAS,eAAe,SAAS,UAAU;CACjD,MAAM,OACJ,WAAW,UAAU,OAAO,YAAY,SAAS,WAAW,KAAK;CACnE,OACE,oBAAC,aAAD;EACE,OAAO,GAAG,MAAM,SAAS,MAAM,IAAI,KAAK,YAAY,EAAE,OAAO,WAAW,OAAO;EAC/E,SAAS,WAAW,WAAW,YAAY,OAAO,GAAG,WAAW,OAAO,uBAAuB,WAAW,OAAO,QAAQ,KAAK,GAAG,EAAE;EAElI,UAAA,oBAAC,WAAD;GACE,QAAQ;GACR,eAAA;GACA,OAAO,CAAC,SAAS,OAAO,IAAI,WAAW,QAAQ,MAAM,CAAC;GACtD,OAAO,CAAC,EAAE,OAAO,KAAK,CAAC;GACvB,QAAQ,CACN;IACE,IAAI;IACJ,OAAO;IACP,MAAM,CAAC,GAAG,OAAO,KAAK;IACtB,OAAO;IACP,UAAU;IACV,OAAO;IACP,cAAc;GAChB,GACA;IACE,IAAI;IACJ,OAAO;IACP,MAAM,CAAC,GAAG,OAAO,QAAQ;IACzB,OAAO;IACP,UAAU;IACV,OAAO;GACT,CACF;GACA,IAAI,EAAE,gCAA8B,EAAE,iBAAiB,MAAM,EAAE;EAChE,CAAA;CACU,CAAA;AAEjB;;AAGA,SAAS,YAAY,EACnB,OACA,QACA,YAKe;CACf,MAAM,QAAQ,MAAM,MAAM,SAAS,EAAE,OAAO,CAAC;CAC7C,OACE,oBAAA,UAAA,EAAA,UACG,SACC,MAAM,SAAS,KAAA,IAAY,CAAC,IAAI,WAAW,MAAM,IAAI,CAAC,CAAC,UACzD,EACA,CAAA;AAEN;;;;;;;;AASA,SAAgB,gBAAgB,OAAsC;CACpE,MAAM,EAAE,UAAU,eAAe;CACjC,MAAM,EAAE,WAAW,kBAAkB,KAAK;CAC1C,OACE,oBAAC,oBAAD;EACY;EACE;EACZ,OAAO;EAEL,WAAA,YAAY,UACZ,oBAAC,KAAD;GAAK,WAAU;GAAU,cAAW;GACjC,UAAA,WAAW,UAAU,QAAQ,MAAM,aAAa,QAC/C,oBAAC,aAAD;IAAoB;IAAe;IAC/B,WAAA,YACA,oBAAC,MAAD;KAAa;KAAmB;KAAqB;IAAU,CAAA;GAEtD,CAAA,IAEb,oBAAC,MAAD;IAAa;IAAmB;IAAY,SAAS,CAAC;GAAI,CAAA;EAEzD,CAAA;CAEW,CAAA;AAExB;;;;;;;;ACpGA,SAAgB,gBAAgB,OAAsC;CACpE,MAAM,EAAE,WAAW,QAAQ;CAC3B,OACE,oBAAC,oBAAD;EACE,UAAU,MAAM;EAChB,YAAY,MAAM;EAClB,OAAO;EAEL,WAAA,YAAY,UAAU;GACtB,MAAM,OAAO,WAAW,SAAS;GACjC,MAAM,OAAO,CACX,GAAI,WAAW,cAAc,OACzB,CAAC,IACD,CAAC;IAAE,MAAM;IAAc,OAAO,WAAW;GAAU,CAAC,GACxD,GAAG,WAAW,YAAY,KAAK,WAAW;IACxC,MAAM;IACN;GACF,EAAE,CACJ;GACA,OACE,oBAAC,gBAAD;IAAgB,WAAU;IAAU,cAAW;IAC7C,UAAA,qBAAC,OAAD;KACE,MAAK;KACL,cAAY,eAAe,WAAW,UAAU,OAAO,YAAY,SAAS,WAAW,KAAK,CAAC,CAAC,YAAY,EAAE,OAAO,WAAW;KAFhI,UAAA,CAIE,oBAAC,WAAD,EAAA,UACE,qBAAC,UAAD,EAAA,UAAA;MACE,oBAAC,WAAD,EAAA,UAAY,GAAG,SAAS,WAAW,MAAM,EAAE,iBAA4B,CAAA;MACvE,oBAAC,WAAD,EAAA,UAAY,OAAkB,CAAA;MAC9B,oBAAC,WAAD;OAAW,OAAM;OACd,UAAA,WAAW,UAAU,OAClB,YACA,SAAS,WAAW,KAAK;MACpB,CAAA;KACH,EAAA,CAAA,EACD,CAAA,GACX,oBAAC,WAAD,EAAA,UACG,KAAK,KAAK,EAAE,MAAM,YACjB,qBAAC,UAAD,EAAA,UAAA;MACE,oBAAC,WAAD;OAAW,WAAU;OAAK,OAAM;OAC7B,UAAA,aAAa,MAAM,IAAI,WAAW,QAAQ,MAAM;MACxC,CAAA;MACX,oBAAC,WAAD,EAAA,UAAY,KAAgB,CAAA;MAC5B,oBAAC,WAAD;OAAW,OAAM;OACf,UAAA,oBAAC,WAAD;QACS;QACD;QACN,OAAO,QAAQ,MAAM,KAAK;QAC1B,WAAW,MAAM;OAClB,CAAA;MACQ,CAAA;KACH,EAAA,GAbK,GAAG,KAAK,GAAG,MAAM,GAAG,YAAY,GAarC,CACX,EACQ,CAAA,CACN;;GACO,CAAA;EAEpB;CACkB,CAAA;AAExB;;;;;;;AC/DA,SAAgB,cAAc,OAAsC;CAClE,MAAM,EAAE,WAAW,QAAQ;CAC3B,OACE,oBAAC,oBAAD;EACE,UAAU,MAAM;EAChB,YAAY,MAAM;EAClB,OAAO;EAEL,WAAA,YAAY,UAAU;GACtB,MAAM,OAAO,WAAW,YAAY;GACpC,MAAM,OAAO,WAAW,SAAS;GACjC,MAAM,OACJ,WAAW,UAAU,OACjB,YACA,SAAS,WAAW,KAAK,CAAC,CAAC,YAAY;GAC7C,IAAI,SAAS,KAAA,GACX,OACE,oBAAC,YAAD;IAAY,OAAM;IACf,UAAA;GACS,CAAA;GAGhB,MAAM,QACJ,WAAW,cAAc,OACrB,OACA,QAAQ,KAAK,QAAQ,WAAW,UAAU,KAAK;GACrD,OACE,oBAAC,MAAD;IACE,SAAQ;IACR,WAAU;IACV,cAAW;IAEX,UAAA,qBAAC,aAAD,EAAA,UAAA;KACE,oBAAC,YAAD;MACE,WAAU;MACV,SAAQ;MACR,OAAM;MAEL,UAAA,QAAQ,WAAW,OAAO,IAAI;KACrB,CAAA;KACZ,oBAAC,KAAD;MAAK,IAAI;MACP,UAAA,oBAAC,WAAD;OACS;OACD;OACN,OAAO,QAAQ,KAAK,KAAK;OACzB,WAAW,MAAM;MAClB,CAAA;KACE,CAAA;KACL,oBAAC,YAAD;MACE,SAAQ;MACR,OAAM;MACN,IAAI,EAAE,SAAS,QAAQ;MAEtB,UAAA,mBAAmB,aAAa,KAAK,IAAI,WAAW,QAAQ,MAAM,EAAE;KAC3D,CAAA;KACX,UAAU,OAAO,OAChB,qBAAC,YAAD;MACE,SAAQ;MACR,OAAM;MACN,IAAI;OAAE,SAAS;OAAQ,KAAK;OAAK,YAAY;MAAW;MAH1D,UAAA;OAKG,QAAQ,IAAI,SAAS;OACtB,oBAAC,WAAD;QACS;QACD;QACN,OAAO,KAAK,IAAI,KAAK;QACrB,WAAW,MAAM;OAClB,CAAA;OACA;MACS;;IAEH,EAAA,CAAA;GACT,CAAA;EAEV;CACkB,CAAA;AAExB;;;AC/EA,MAAM,QAAQ;;AAGd,MAAM,aAAa,MACjB,OAAO,UAAU,CAAC,KAAK,KAAK,KAAK,KAAK;;AAGxC,SAAgB,qBAAqB,OAAgC;CACnE,MAAM,CAAC,OAAO,YAAY,SAAS,KAAK;CACxC,MAAM,CAAC,SAAS,cAAc,SAAS,CAAC;CACxC,MAAM,CAAC,aAAa,kBAAkB,SAAS,GAAG;CAClD,MAAM,eAAe,UAAU,OAAO,WAAW,CAAC;CAClD,MAAM,CAAC,QAAQ,aAAa,SAAiB,KAAK;CAClD,MAAM,QAAQ;EAAE,OAAO,UAAU,QAAQ,KAAA,IAAY;EAAO;EAAS;CAAO;CAC5E,OACE,oBAAC,gBAAD;EACE,UAAU,MAAM;EAChB,YAAY,MAAM;EAClB,YAAW;EAET,WAAA,UACA,qBAAC,KAAD;GAAK,IAAI;IAAE,SAAS;IAAQ,KAAK;GAAE;GAAnC,UAAA,CACE,qBAAC,KAAD;IACE,WAAU;IACV,cAAW;IACX,WAAW,UAAU,MAAM,eAAe;IAC1C,IAAI;KACF,SAAS;KACT,UAAU;KACV,KAAK;KACL,YAAY;IACd;IATF,UAAA;KAWE,qBAAC,WAAD;MACE,QAAA;MACA,MAAK;MACL,OAAM;MACN,OAAO;MACP,IAAI,EAAE,UAAU,QAAQ;MACxB,WAAW,UAAU,SAAS,MAAM,OAAO,KAAK;MANlD,UAAA,CAQE,oBAAC,UAAD;OAAU,OAAO;OAAQ,UAAA;MAAyB,CAAA,GACjD,MAAM,OACJ,QAAQ,MAAM,EAAE,WAAW,EAAE,SAAS,MAAM,SAAS,QAAQ,CAAC,CAC9D,KAAK,MACJ,oBAAC,UAAD;OAAuB,OAAO,EAAE;OAC7B,UAAA,UAAU,EAAE,MAAM,YAAY;MACvB,GAFK,EAAE,IAEP,CACX,CACM;;KACX,oBAAC,WAAD;MACE,MAAK;MACL,MAAK;MACL,OAAM;MACN,OAAO;MACP,OAAO,CAAC;MACR,YAAY,eAAe,KAAA,IAAY;MACvC,WAAW,EAAE,WAAW;OAAE,KAAK;OAAG,KAAK;MAAG,EAAE;MAC5C,IAAI,EAAE,OAAO,OAAO;MACpB,WAAW,UAAU;OACnB,eAAe,MAAM,OAAO,KAAK;OACjC,MAAM,OAAO,OAAO,MAAM,OAAO,KAAK;OACtC,IAAI,UAAU,IAAI,GAAG,WAAW,IAAI;MACtC;KACD,CAAA;KACD,oBAAC,cAAD;MAAc,OAAO;MAAQ,UAAU;KAAY,CAAA;IAChD;GACL,CAAA,GAAA,qBAAC,KAAD;IACE,IAAI;KACF,SAAS;KACT,KAAK;KACL,qBAAqB;MAAE,IAAI;MAAO,IAAI;KAAU;IAClD;IALF,UAAA,CAOE,oBAAC,SAAD;KAAS,OAAM;KACb,UAAA,oBAAC,iBAAD;MAAiB,GAAI;MAAO,GAAI;KAAQ,CAAA;IACjC,CAAA,GACT,qBAAC,KAAD;KAAK,IAAI;MAAE,SAAS;MAAQ,KAAK;MAAG,cAAc;KAAQ;KAA1D,UAAA,CACE,oBAAC,eAAD;MAAe,GAAI;MAAO,GAAI;KAAQ,CAAA,GACtC,oBAAC,iBAAD;MAAiB,GAAI;MAAO,GAAI;KAAQ,CAAA,CACrC;IACF,CAAA,CAAA;GACF,CAAA,CAAA;;CAEO,CAAA;AAEpB"}