@aglyn/plugins-data 1.0.0-beta.234 → 1.0.0-beta.235

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.
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../../../../libs/plugins/data/src/lib/components/host-datasets-card.component.tsx"],"sourcesContent":["/**\n * @license\n * Copyright 2026 Aglyn LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n'use client'\n\nimport { TransferResumeImport } from '@aglyn/aglyn/app-utils/transfer-resume-import'\nimport {\n type AglynOrgBilling,\n checkDatasetQuota,\n checkEntitlement,\n checkQuota,\n getCustomFieldType,\n pluginDocsHelp,\n useTransferLauncher,\n} from '@aglyn/aglyn'\nimport { CardDisplay, useConfirmationContext } from '@aglyn/shared-ui-jsx'\nimport ListFilterChips from '@aglyn/shared-ui-jsx/components/list-filter-chips.component'\nimport { ListPagination } from '@aglyn/shared-ui-jsx/components/list-pagination.component'\nimport ListQueryNotices, {\n listQueryRefusals,\n} from '@aglyn/shared-ui-jsx/components/list-query-notices.component'\nimport {\n ListTable,\n listActionsColumn,\n} from '@aglyn/shared-ui-jsx/components/list-table.component'\nimport QuotaReadoutComponent from '@aglyn/shared-ui-jsx/components/quota-readout.component'\nimport { listFilterGridColumns } from '@aglyn/shared-ui-jsx/const/list-grid-filter'\nimport { useListGridFilter } from '@aglyn/shared-ui-jsx/hooks/use-list-grid-filter'\nimport { useSnackbar } from '@aglyn/shared-ui-snackstack'\nimport { Timestamp } from '@aglyn/shared-util-timestamp'\nimport {\n Button,\n Dialog,\n DialogActions,\n DialogContent,\n DialogTitle,\n MenuItem,\n Stack,\n TextField,\n Typography,\n} from '@mui/material'\nimport {\n collection,\n deleteDoc,\n deleteField,\n doc,\n getCountFromServer,\n getDocs,\n limit,\n query,\n where,\n setDoc,\n writeBatch,\n} from 'firebase/firestore'\nimport { useCallback, useEffect, useMemo, useState } from 'react'\nimport { useListColumnSort } from '@aglyn/shared-ui-jsx/hooks/use-list-column-sort'\nimport {\n useFirestore,\n useFirestoreCollection,\n useHostActivityLogger,\n useOrgDataScope,\n usePagedCollection,\n useScopeTokens,\n useUser,\n} from '@aglyn/tenant-feature-instance'\nimport { listQueryConstraints } from '@aglyn/tenant-feature-instance/hooks/use-list-query'\nimport { authorizedFetch } from '@aglyn/shared-util-http/authorized-token'\nimport { DatasetSchemaDialog } from './dataset-schema-dialog.component'\nimport { DatasetRecordDialog } from './dataset-record-dialog.component'\nimport {\n datasetRecordFilter,\n planRecordQuery,\n recordColumn,\n} from './dataset-record-filter'\nimport { coerceDocumentValues, datasetIntegrityUpdate, datasetValueToInput, effectiveDatasetModel, formatDatasetValue, modelFromFieldEntries, validateDocument } from '../model/dataset-models'\nimport { fillRecordAddresses } from '../record-pages/record-pages'\nimport { datasetDisplayName, parseDatasetFieldEntries } from '../model/datasets'\nimport { datasetTransferResourceKey } from '../transfer/dataset-transfer-key'\n\nexport interface HostDatasetsCardProps {\n /** Host context: resolves the owning org and logs host activity. */\n hostId?: string\n /**\n * Direct org scope (AGL-239): the org Data page renders the editor\n * without any host context. Wins over `hostId` resolution when set.\n */\n orgId?: string\n /**\n * The resolved entitlement source (org billing doc). Passed in by both\n * callers (the plugin Data page via the shell, the org Data page via its\n * own resolver) so this relocated card runs entitlement/quota checks\n * without console-app org/session hooks (AGL-395).\n */\n org?: Partial<AglynOrgBilling>\n}\n\n/**\n * The sentence that says who a NEW dataset is shared with, for the card and\n * for the site Data page's banner above it.\n *\n * `siteOnly` is true only on a site's Data page in an org whose Default\n * sharing is \"Only the site they were created in\". Everywhere else a new\n * dataset starts on All sites: the org Data page has no site to limit it to.\n */\n/** The records walk serves no header order: every header sorts the page. */\nconst NO_QUERY_SORTS: never[] = []\n\nexport function newDatasetSharingNote(siteOnly: boolean): string {\n return siteOnly\n ? 'Datasets belong to your organization. Your default sharing starts a ' +\n 'new one on this site only — use Schema to share it with more.'\n : 'Datasets belong to your organization. A new one is shared with ' +\n 'every site — use Schema to narrow that.'\n}\n\n/**\n * Datasets editor (AGL-102): org-shared document collections at\n * `orgs/{orgId}/datasets` (AGL-237/239) with a `records` subcollection,\n * consumed by repeatable components (AGL-103) via `{{item.field}}`.\n * Starter+ (`data-store` flag) with per-plan dataset and record caps —\n * dark-launch rule as everywhere (no plan, no gate). The host path is\n * the pre-migration fallback for hosts not yet org-wired.\n */\nexport function HostDatasetsCard(props: HostDatasetsCardProps) {\n const { hostId } = props\n // `dataScope` is null until the async org lookup settles (AGL-1061), and\n // for a host with no owning org — there is no host fallback to act on\n // any more (AGL-1050), so every path built from it is guarded rather\n // than redirected.\n const { scope: dataScope, orgId } = useOrgDataScope({\n hostId,\n orgId: props.orgId,\n })\n // Scoped sharing (AGL-1044). Required, not cosmetic: under the AGL-1041\n // rules a scoped member's UNFILTERED list is rejected outright —\n // Firestore fails the whole query if any candidate would fail — so\n // without this the Data page errors rather than showing fewer rows.\n // Org-wide members get no filter: they read everything, and adding one\n // would hide any dataset the AGL-1040 backfill missed.\n const {\n tokens: scopeTokens,\n orgWide: viewerOrgWide,\n loaded: scopeLoaded,\n } = useScopeTokens(orgId)\n // Every dataset this card can now reach is an org dataset, and org\n // datasets are all scoped (AGL-1041) — so the filter turns purely on\n // whether the VIEWER is org-wide. It used to also ask whether an org had\n // resolved, for the sake of unscoped rows on the host path.\n const needsScope = !viewerOrgWide\n // Two answers must be in before listing: the org path (AGL-1061) and the\n // viewer's scope tokens (AGL-1047). `useScopeTokens` reports org-wide\n // while loading, so without `scopeLoaded` a scoped collaborator's first\n // render sends an UNFILTERED list that the AGL-1041 rules deny per\n // document. It recovers on the next render, which is exactly what makes\n // it easy to miss: the page looks right and logs a denial every mount.\n const scopeReady = Boolean(dataScope) && scopeLoaded\n const firestore = useFirestore()\n const { enqueueSnackbar } = useSnackbar()\n const { confirm } = useConfirmationContext()\n const { org } = props\n const logActivity = useHostActivityLogger(hostId)\n const { data: user } = useUser()\n /**\n * The site a dataset created here is created FROM, or undefined on the\n * organization Data page.\n *\n * `/api/orgs/datasets` stamps a new dataset with the org's Default sharing,\n * and that setting can only narrow to a site the request names — so a\n * create that names none lands on All sites whatever the org chose. The\n * explicit `orgId` is the org Data page's own scope and already wins over\n * `hostId` when the org is resolved, so it wins here too: a create made\n * there names no site, even if a caller hands the card both.\n */\n const createdFromHostId = props.orgId ? undefined : hostId || undefined\n const createdFrom = useMemo(\n () => (createdFromHostId ? { hostId: createdFromHostId } : {}),\n [createdFromHostId],\n )\n /**\n * Whether a dataset created here starts on this site alone: the org chose\n * \"Only the site they were created in\" and there is a site to limit it to.\n * The caption reads it so it never promises All sites to a create that\n * will not get it.\n */\n const createsSiteOnly =\n Boolean(createdFromHostId) &&\n (org as { defaultResourceScope?: 'org' | 'host' } | undefined)\n ?.defaultResourceScope === 'host'\n\n // Creates go through the console API (AGL-473): rules deny client-side\n // `create` on org datasets/records so quotas are server-enforced.\n // Updates/deletes stay client-direct (they don't consume quota). The\n // legacy host scope (no org resolved) keeps the old client writes.\n const callDatasetApi = useCallback(\n async (payload: Record<string, unknown>) => {\n const response = await authorizedFetch(user, '/api/orgs/datasets', {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({ orgId, ...payload }),\n })\n const result = await response.json().catch(() => ({}))\n if (!response.ok) {\n throw new Error(result?.error ?? 'Dataset operation failed')\n }\n return result\n },\n [user, orgId],\n )\n\n /**\n * Refresh the live pages showing a dataset after a write the BROWSER made\n * (AGL-3113).\n *\n * Record edits and deletes are client-direct — they consume no quota, so\n * AGL-473 left them out of the server leg — which also left them with\n * nothing to announce from. They make a page listing the rows exactly as\n * stale as a create does, so they take the same trip the create already\n * takes, through the route that already holds the org membership check.\n *\n * BEST EFFORT. The record is stored by the time this runs, and the pages\n * catch up on their own window regardless; a refused cache must never be\n * shown to somebody as a refused save.\n */\n const announceRecords = useCallback(\n async (datasetId: string) => {\n try {\n await callDatasetApi({ action: 'announce-records', datasetId })\n } catch (error) {\n console.error(error)\n }\n },\n [callDatasetApi],\n )\n\n const {\n data: datasetDocs,\n status: datasetsStatus,\n /**\n * The dataset rows are unconfirmed by the server (AGL-1358). The schema\n * dialog is seeded from one of them and writes the whole `model` plus\n * `visibleTo` back, so the freshness verdict belongs to THIS listener —\n * the dialog has none of its own, which is why it is handed down rather\n * than recomputed there.\n */\n fromCache: datasetsFromCache,\n } = useFirestoreCollection<any>(\n () =>\n // `scopeReady` already implies a non-null `dataScope`; testing it\n // directly is what lets the compiler see that too.\n dataScope && scopeReady\n ? query(\n collection(firestore, dataScope[0], dataScope[1], 'datasets'),\n ...(needsScope\n ? [where('visibleTo', 'array-contains-any', scopeTokens)]\n : []),\n limit(100),\n )\n : null,\n [firestore, dataScope, needsScope, scopeTokens, scopeReady],\n { idField: '$id' },\n )\n const datasets = useMemo(\n () =>\n [...(datasetDocs ?? [])].sort((a, b) =>\n datasetDisplayName(a).localeCompare(datasetDisplayName(b)),\n ),\n [datasetDocs],\n )\n const [selectedId, setSelectedId] = useState<string | null>(null)\n const [schemaOpen, setSchemaOpen] = useState(false)\n const selected =\n datasets.find((item) => item.$id === selectedId) ?? datasets[0]\n // Typed model (AGL-179): drives headers, cell rendering, and the\n // document form; v1 datasets get a derived all-text model.\n const model = useMemo(\n () => effectiveDatasetModel(selected ?? {}),\n [selected],\n )\n const fields: string[] = useMemo(() => model.order, [model])\n // The records grid's Filters panel, from the dataset's own schema.\n const recordFilter = useMemo(() => datasetRecordFilter(model), [model])\n\n // Guarded on BOTH the scope and a real selection (AGL-1440): with no\n // datasets, `selected` never resolves, and `datasets/-none-/records` is not\n // an empty read for everyone — the AGL-1044 scoped-sharing rules deny it\n // outright for a scoped collaborator, and a permanently denied listen is\n // reopened forever by the refusal loop.\n /**\n * The records table PAGES (AGL-2501). It used to be `limit(500)` with no\n * `orderBy`, every row rendered at once and no control anywhere.\n *\n * That was wrong twice. Five hundred documents were read and billed on\n * every mount of a card nobody had scrolled — and past five hundred the\n * remaining rows were not merely unrendered, they were UNREACHABLE, because\n * nothing showed them and nothing asked for more. Firestore answers an\n * unordered limit in document-id order over auto-ids, so which five hundred\n * a reader got was arbitrary and could differ between two loads of the same\n * dataset; `sortDatasetRecords` then sorted that sample by `order`, which\n * made the table look ordered while being a sample. The export leg\n * (AGL-2335) fixed exactly this shape for the file and left the table.\n *\n * ## Why the walk orders on the document id, and not on a field\n *\n * The usual fix is `orderBy` on the field the rows are sorted by. It cannot\n * be used here: `orderBy` matches only documents that HAVE the field, so\n * ordering on one that any writer omits does not mis-order the list, it\n * hides rows from it — a worse failure than the one being fixed, and a\n * silent one. Every candidate on this collection is omitted by some writer:\n *\n * * `order` — set by `/api/orgs/datasets` and by `POST /v1/datasets/{id}\n * /records`, and NOT by the tenant form-submit leg or by the workflow\n * `appendDataset`/`updateDataset` actions, which write `values` and\n * `createdAt` only. Ordering on it would drop every row a public form or\n * an automation ever produced — the rows a lead dataset is mostly made\n * of.\n * * `createdAt` — written by all four of those, and NOT by a site import:\n * `IMPORTABLE_FIELDS.records` is `['values', 'order']`, so a restored\n * record carries no `createdAt` at all.\n * * `updatedAt` — the mirror image: the import stamps it, the form and\n * automation legs do not.\n *\n * A document's NAME is not a field and cannot be absent, so ordering on it\n * drops nothing and the walk is total: every record is reachable by paging,\n * which is the property the old query lacked. It is not insertion order —\n * ids are random — so the rows are not claimed to be in one. What they are\n * is stable, complete, and the same on every load.\n *\n * `sortDatasetRecords` is deliberately NOT applied to the page. Re-sorting a\n * window of an id-ordered walk by `order` is the same lie the old code told:\n * rows would run in one order within a page and another across pages.\n * For the same reason a header sorts THIS PAGE only, and says so\n * (AGL-3680, `recordColumnSort` below): no stored field could serve it.\n *\n * ## Filtering: every clause and the search word are on the query\n *\n * The grid's Filters panel and quick search are predicates on this same\n * walk (AGL-3321), planned by `planRecordQuery` (`./dataset-record-filter`,\n * over the shared `planListQuery`): equalities ask the record's\n * `filterValues`, and one word-level clause — a text `contains`, a list\n * member, or the search word — asks its `filterKeys`. Firestore's\n * automatic single-field indexes merge them under the same document-name\n * order, so every filter pages through every matching record exactly as\n * the plain walk pages through all of them, with no composite index and\n * no index deploy.\n *\n * Nothing is matched over the rows already loaded. What one query cannot\n * hold is not offered (ranges, negations, empty checks) or is refused by\n * name above the table (a second `contains`, a `contains` beside the\n * search), and a many-word `contains` or search says it asked the first\n * word.\n */\n const gridFilter = useListGridFilter({ selectFields: recordFilter.selectFields })\n // A clause on a field this dataset does not have (the reader switched\n // datasets) narrows nothing and is not shown.\n const recordClauses = useMemo(\n () =>\n gridFilter.clauses.filter((clause) =>\n recordFilter.fields.some((field) => field.column === clause.field),\n ),\n [gridFilter.clauses, recordFilter.fields],\n )\n const recordPlan = useMemo(\n () => planRecordQuery(model, recordFilter, recordClauses, gridFilter.searchWords),\n [model, recordFilter, recordClauses, gridFilter.searchWords],\n )\n // The query's identity: a new plan is a new walk, from page one.\n const recordPlanKey = JSON.stringify({\n filters: recordPlan.plan.filters,\n orderBy: recordPlan.plan.orderBy,\n })\n const {\n rows: records,\n hasMore: hasMoreRecords,\n page: recordPage,\n setPage: setRecordPage,\n pageSize: recordPageSize,\n setPageSize: setRecordPageSize,\n } = usePagedCollection<any>(\n (pageLimit) =>\n dataScope && selected?.$id\n ? query(\n collection(\n firestore,\n dataScope[0],\n dataScope[1],\n 'datasets',\n selected.$id,\n 'records',\n ),\n ...listQueryConstraints(recordPlan.plan),\n limit(pageLimit),\n )\n : null,\n [firestore, dataScope, selected?.$id, recordPlanKey],\n { idField: '$id' },\n )\n const recordRefusals = useMemo(\n () =>\n listQueryRefusals(recordPlan.refused, {\n fields: recordFilter.fields,\n headers: recordFilter.headers,\n options: recordFilter.options,\n }),\n [recordPlan.refused, recordFilter],\n )\n const filteringRecords =\n recordClauses.length > 0 || gridFilter.searchWords.some((word) => word.trim())\n /**\n * The two HEAD-COUNTS on this card are server aggregates, not the lengths\n * of the two capped listeners above (AGL-1716, the AGL-1706 shape).\n *\n * Both listeners are capped correctly — 100 datasets in a picker, 500 rows\n * in a table, nobody needs more streamed in. What neither may do is answer\n * \"how many does this org have\", and both did:\n *\n * * `records.length` saturated at 500 and was handed to\n * `checkQuota(org, 'recordsPerDataset', …)`. The bands are 1,000 /\n * 10,000 / 100,000 / 500,000 / 1,000,000, so on EVERY paid plan the\n * check read 500-against-thousands and could never refuse. Worse, the\n * importer computed its room as `limit − records.length`, so an\n * understated count *inflated* the slots it offered.\n * * `datasets.length` saturated at 100 and fed `checkDatasetQuota`, whose\n * bands run to 250 / 500 / 2,000 above that window.\n *\n * `api/orgs/datasets` — the route that actually enforces both — counts with\n * `collection('datasets').count()` and `collection('records').count()` on\n * these exact paths, so this card was offering headroom the API would then\n * refuse. It now asks the same question the same way, and the console\n * billing page and the staff org page already read the dataset count with\n * this identical unscoped aggregate.\n *\n * THE LISTS KEEP THEIR CAPS. The list and the count are different\n * questions; only the count moved. A one-shot goes stale where a listener\n * refreshed for free, so both are re-read after any mutation that can move\n * them — the epochs below.\n *\n * No counting RULE moves: `checkQuota` and `checkDatasetQuota` are\n * untouched entitlement inputs, and nothing here is metered by\n * `report-usage` (it samples record counts server-side for storage, on its\n * own read). Only this card's inputs stopped being saturated.\n */\n const [datasetCountEpoch, setDatasetCountEpoch] = useState(0)\n const [recordCountEpoch, setRecordCountEpoch] = useState(0)\n const [serverDatasetCount, setServerDatasetCount] = useState<number | null>(\n null,\n )\n // TAGGED with the dataset it describes. A bare number would have to be\n // cleared when the selection changes, and clearing state from inside the\n // effect that fills it is a render loop waiting for one unstable dep;\n // tagging answers \"whose count is this?\" without writing state on render.\n const [serverRecordCount, setServerRecordCount] = useState<{\n datasetId: string\n count: number\n } | null>(null)\n useEffect(() => {\n if (!dataScope) return\n let active = true\n // Unscoped, exactly like `api/orgs/datasets` and the billing page: the\n // quota is about the ORG's datasets, not the subset this collaborator\n // can see. A scoped collaborator whom AGL-1044 denies the read falls\n // through to the catch and keeps the visible-rows lower bound.\n void getCountFromServer(\n collection(firestore, dataScope[0], dataScope[1], 'datasets'),\n )\n .then((snapshot) => {\n if (active) setServerDatasetCount(snapshot.data().count)\n })\n .catch(() => {\n // Falls back to the listener length below — a LOWER bound, and this\n // card's prior behaviour. Deliberately not 0: `checkDatasetQuota`\n // answers from whatever it is handed, and 0 used is a confident\n // wrong number in the flattering direction.\n })\n return () => {\n active = false\n }\n }, [firestore, dataScope, datasetCountEpoch])\n // The dataset the counts below belong to. Distinct from `selectedId`\n // above, which is the PICKER value and is null until the user chooses.\n const countedDatasetId: string | undefined = selected?.$id\n useEffect(() => {\n if (!dataScope || !countedDatasetId) return\n let active = true\n void getCountFromServer(\n collection(\n firestore,\n dataScope[0],\n dataScope[1],\n 'datasets',\n countedDatasetId,\n 'records',\n ),\n )\n .then((snapshot) => {\n if (active) {\n setServerRecordCount({\n datasetId: countedDatasetId,\n count: snapshot.data().count,\n })\n }\n })\n .catch(() => {\n // Same fallback, same reason as above.\n })\n return () => {\n active = false\n }\n }, [firestore, dataScope, countedDatasetId, recordCountEpoch])\n // Pending, denied, or answered about the PREVIOUS selection, the loaded\n // rows stand in. They can only UNDERSTATE (same collections, capped),\n // never overstate, so nothing these figures gate fires on a count larger\n // than the truth. Since AGL-2501 the record fallback is one PAGE, so it\n // understates by more — which moves it further in the safe direction and\n // changes nothing about which way it can be wrong.\n const datasetCount = serverDatasetCount ?? datasets.length\n const recordCount =\n serverRecordCount && serverRecordCount.datasetId === countedDatasetId\n ? serverRecordCount.count\n : records.length\n\n // --- Create dataset -----------------------------------------------------\n const [creator, setCreator] = useState<{\n name: string\n fields: string\n } | null>(null)\n const handleOpenCreator = useCallback(() => {\n if (!checkEntitlement(org, 'dataStore')) {\n return enqueueSnackbar(\n 'Datasets require a Starter plan or higher — see Billing',\n { variant: 'warning', persist: false },\n )\n }\n // Addon-aware quota (AGL-132): purchased extra datasets raise the\n // limit up to the plan's hard max; beyond that only an upgrade helps.\n // The ORG's datasets, not the picker's window (AGL-1716).\n const quota = checkDatasetQuota(org as any, datasetCount)\n if (!quota.allowed) {\n return enqueueSnackbar(\n quota.upgradeRequired\n ? `Dataset limit reached (${quota.limit}) — upgrade in Billing`\n : `Dataset limit reached (${quota.limit}) — add extra datasets ` +\n `for $${quota.addonPriceUsd}/mo each or upgrade in Billing`,\n { variant: 'warning', persist: false },\n )\n }\n setCreator({ name: '', fields: '' })\n }, [org, datasetCount, enqueueSnackbar])\n // Entries are human names — \"Roast preference\" → stable id\n // `roast_preference` with the pretty name kept for headers (AGL-558).\n const creatorEntries = parseDatasetFieldEntries(creator?.fields ?? '')\n const creatorFields = creatorEntries.map((entry) => entry.id)\n const handleCreate = useCallback(async () => {\n // No org, no create. The `else` that used to sit below this was the\n // legacy host-scope client write (AGL-1050) — the one path by which a\n // dataset could be created with NO quota check, since /api/orgs/datasets\n // is where AGL-473 enforces it. The rules now deny that path outright;\n // this is the client side of the same closure. The Add button is\n // disabled without a scope, so reaching the guard means a stale closure.\n if (!creator?.name.trim() || creatorFields.length === 0 || !orgId) return\n let id: string\n try {\n const result = await callDatasetApi({\n action: 'create-dataset',\n displayName: creator.name.trim(),\n fields: creatorFields,\n // Typed model from day one (AGL-178); refine in the Schema dialog.\n model: modelFromFieldEntries(creatorEntries),\n ...createdFrom,\n })\n id = String(result.id)\n } catch (error: any) {\n return void enqueueSnackbar(error?.message ?? 'Dataset create failed', {\n variant: 'warning',\n persist: false,\n })\n }\n setCreator(null)\n setSelectedId(id)\n setDatasetCountEpoch((epoch) => epoch + 1)\n enqueueSnackbar(`Dataset \"${creator.name.trim()}\" created`, {\n variant: 'success',\n persist: false,\n })\n logActivity('Created dataset', {\n type: 'content',\n id,\n name: creator.name.trim(),\n })\n }, [creator, creatorEntries, creatorFields, orgId, createdFrom, callDatasetApi, enqueueSnackbar, logActivity])\n\n // Join collection template (AGL-180): extrinsic many-to-many as a\n // visible, editable collection of FKey pairs — no magic.\n const [joiner, setJoiner] = useState<{ a: string; b: string } | null>(null)\n const handleCreateJoin = useCallback(async () => {\n if (!joiner?.a || !joiner?.b || joiner.a === joiner.b) return\n const a = datasets.find((item) => item.$id === joiner.a)\n const b = datasets.find((item) => item.$id === joiner.b)\n // A join collection is a dataset and consumes the same quota, so it\n // takes the same API-only route (AGL-1050) — the host-scope client\n // write that used to stand in for it is gone.\n if (!a || !b || !orgId) return\n const fieldFor = (target: any, fieldId: string) => ({\n name: datasetDisplayName(target) || fieldId,\n type: 'reference' as const,\n required: true,\n reference: {\n datasetId: target.$id as string,\n displayFieldId: effectiveDatasetModel(target).order[0],\n onDelete: 'setNull' as const,\n },\n })\n const payload = {\n displayName: `${datasetDisplayName(a)} ↔ ${datasetDisplayName(b)}`,\n fields: ['aRef', 'bRef'],\n model: {\n order: ['aRef', 'bRef'],\n fields: { aRef: fieldFor(a, 'aRef'), bRef: fieldFor(b, 'bRef') },\n },\n }\n let id: string\n try {\n const result = await callDatasetApi({\n action: 'create-dataset',\n ...payload,\n // A join collection is a dataset, so the same Default sharing applies.\n ...createdFrom,\n })\n id = String(result.id)\n } catch (error: any) {\n return void enqueueSnackbar(error?.message ?? 'Join create failed', {\n variant: 'warning',\n persist: false,\n })\n }\n setJoiner(null)\n setSelectedId(id)\n // A join collection IS a dataset and consumes the same quota.\n setDatasetCountEpoch((epoch) => epoch + 1)\n enqueueSnackbar('Join collection created', {\n variant: 'success',\n persist: false,\n })\n }, [joiner, datasets, orgId, createdFrom, callDatasetApi, enqueueSnackbar])\n\n const handleDeleteDataset = useCallback(async () => {\n if (!selected) return\n const confirmed = await confirm({\n title: 'Delete this collection?',\n description:\n `\"${datasetDisplayName(selected)}\"` +\n // What is actually being destroyed, not what is loaded (AGL-1716):\n // a 40,000-row dataset used to warn about \"its 500 documents\".\n (recordCount\n ? ` and its ${recordCount} document${recordCount === 1 ? '' : 's'}`\n : '') +\n ' stop resolving in repeatable components and bindings that ' +\n 'reference it.',\n confirmationText: 'Delete',\n confirmationButtonProps: { color: 'error' },\n })\n .then(() => true)\n .catch(() => false)\n if (!confirmed || !dataScope) return\n // Deleting the dataset doc client-side would strand its `records`\n // subcollection — Firestore doesn't cascade and only the Admin SDK has\n // `recursiveDelete`, so the delete goes through the erase route\n // (AGL-945). Single-record deletes below stay client-direct.\n try {\n const response = await authorizedFetch(user, '/api/resources/erase', {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({\n scope: dataScope[0],\n scopeId: dataScope[1],\n kind: 'datasets',\n id: selected.$id,\n // Names the site this delete was issued from, so the route can\n // refuse to destroy a dataset shared beyond it (AGL-1046). The\n // org Data page passes no host and keeps the org-wide delete.\n hostId,\n }),\n })\n const result = await response.json().catch(() => ({}))\n if (!response.ok) throw new Error(result?.error ?? 'Dataset delete failed')\n } catch (error: any) {\n return void enqueueSnackbar(error?.message ?? 'Dataset delete failed', {\n variant: 'warning',\n persist: false,\n })\n }\n setSelectedId(null)\n setDatasetCountEpoch((epoch) => epoch + 1)\n enqueueSnackbar('Dataset deleted', { variant: 'success', persist: false })\n logActivity('Deleted dataset', {\n type: 'content',\n id: selected.$id,\n name: datasetDisplayName(selected),\n })\n }, [\n selected,\n recordCount,\n confirm,\n dataScope,\n hostId,\n user,\n enqueueSnackbar,\n logActivity,\n ])\n\n // Reference pickers (AGL-180): load target-collection rows for every\n // reference field in the model (id -> display label).\n const [refOptions, setRefOptions] = useState<\n Record<string, Array<{ id: string; label: string }>>\n >({})\n useEffect(() => {\n let active = true\n const referenceFields = model.order.filter(\n (fieldId) =>\n model.fields[fieldId]?.type === 'reference' &&\n model.fields[fieldId]?.reference?.datasetId,\n )\n if (!referenceFields.length || !dataScope) {\n setRefOptions({})\n return\n }\n void Promise.all(\n referenceFields.map(async (fieldId) => {\n const reference = model.fields[fieldId].reference as {\n datasetId: string\n displayFieldId?: string\n }\n const target = datasets.find(\n (item) => item.$id === reference.datasetId,\n )\n const displayFieldId =\n reference.displayFieldId ??\n effectiveDatasetModel(target ?? {}).order[0]\n const snapshot = await getDocs(\n query(\n collection(\n firestore,\n dataScope[0],\n dataScope[1],\n 'datasets',\n reference.datasetId,\n 'records',\n ),\n limit(200),\n ),\n ).catch(() => null)\n const options = (snapshot?.docs ?? []).map((docSnapshot) => ({\n id: docSnapshot.id,\n label: String(\n docSnapshot.get('values')?.[displayFieldId ?? ''] ??\n docSnapshot.id,\n ),\n }))\n return [fieldId, options] as const\n }),\n ).then((entries) => {\n if (active) setRefOptions(Object.fromEntries(entries))\n })\n return () => {\n active = false\n }\n }, [model, datasets, firestore, dataScope])\n /**\n * One reference target's label, or `null` when this ID resolves to nothing.\n *\n * The distinction the grid cannot draw. `referenceLabel` below falls back to\n * the raw ID, which is the only thing a cell has room for and is\n * indistinguishable from a resolved label that happens to look like an ID.\n * The record view has room to say which, so it asks the question that has a\n * `null` answer.\n *\n * Unresolvable covers more than a deleted target: `refOptions` loads at most\n * 200 rows per referenced collection, so a live target outside that window\n * reports the same way. Either way the ID is shown and neither is claimed to\n * be a working link.\n */\n const resolveReferenceLabel = useCallback(\n (fieldId: string, id: string): string | null =>\n refOptions[fieldId]?.find((option) => option.id === id)?.label ?? null,\n [refOptions],\n )\n const referenceLabel = useCallback(\n (fieldId: string, value: unknown): string => {\n const ids = Array.isArray(value) ? value : value != null ? [value] : []\n return ids\n .map((id) => resolveReferenceLabel(fieldId, String(id)) ?? String(id))\n .join(', ')\n },\n [resolveReferenceLabel],\n )\n /**\n * The record the viewer is showing, held as an ID and resolved against the\n * page the table already has.\n *\n * Holding the ID rather than the row is what keeps the view live without\n * costing a read: the same listener that draws the table re-resolves it, so\n * an edit landing underneath updates the open dialog. When the row leaves\n * the page — deleted, or paged past — this answers `null` and the dialog\n * closes, which is the honest response to a record no longer in front of\n * this reader. Nothing here queries: `records` is the page (or filter window)\n * query's answer.\n */\n const [viewerId, setViewerId] = useState<string | null>(null)\n const viewerRecord = useMemo(\n () =>\n viewerId\n ? (records.find((record: any) => record.$id === viewerId) ?? null)\n : null,\n [viewerId, records],\n )\n\n // --- Document editor (null id = new; AGL-179 typed inputs) --------------\n const [editor, setEditor] = useState<{\n id: string | null\n values: Record<string, string>\n errors: Record<string, string>\n } | null>(null)\n const handleOpenRecord = useCallback(\n (record?: any) => () => {\n if (!record) {\n // The dataset's documents, not the loaded window (AGL-1716).\n const quota = checkQuota(org, 'recordsPerDataset', recordCount)\n if (!quota.allowed) {\n return enqueueSnackbar(\n `Record limit reached (${quota.limit}) — see Billing to upgrade`,\n { variant: 'warning', persist: false },\n )\n }\n }\n const values: Record<string, string> = {}\n for (const fieldId of model.order) {\n const field = model.fields[fieldId]\n if (!field) continue\n if (record) {\n values[fieldId] = datasetValueToInput(\n field,\n record.values?.[fieldId],\n )\n } else if (field.default != null) {\n values[fieldId] = String(field.default)\n }\n }\n // Flag non-conforming stored values (AGL-178 policy: type changes\n // never rewrite documents; the editor surfaces the mismatch).\n const errors = record\n ? validateDocument(model, record.values ?? {})\n : {}\n setEditor({ id: record?.$id ?? null, values, errors })\n },\n [org, recordCount, model, enqueueSnackbar],\n )\n const handleSaveRecord = useCallback(async () => {\n if (!editor || !selected || !dataScope) return\n // The editor holds the record's WHOLE values, so an address it already\n // has stays and an empty one fills in from its source (AGL-3475).\n const coerced = fillRecordAddresses(\n model,\n coerceDocumentValues(model, editor.values),\n )\n const errors = validateDocument(model, coerced)\n if (Object.keys(errors).length) {\n return void setEditor((prev) => (prev ? { ...prev, errors } : prev))\n }\n // `values` is replaced wholesale (not merged) so orphaned values from\n // removed fields strip here, lazily, per the documented AGL-178 policy.\n try {\n if (editor.id) {\n // Updates stay client-direct (no quota consumed).\n const recordRef = doc(\n firestore,\n dataScope[0],\n dataScope[1],\n 'datasets',\n selected.$id,\n 'records',\n editor.id,\n )\n await setDoc(\n recordRef,\n {\n values: coerced,\n // The integrity index moves with the values it describes\n // (`datasetIntegrityUpdate`); the merging form, because clearing\n // the last reference has to REMOVE the field rather than omit it.\n ...datasetIntegrityUpdate(model, coerced, deleteField()),\n updatedAt: Timestamp.now(),\n },\n {\n mergeFields: ['values', 'referencedIds', 'filterKeys', 'filterValues', 'updatedAt'],\n },\n )\n await announceRecords(selected.$id)\n } else {\n // Creates go through the quota-enforcing API (AGL-473). The legacy\n // host-scope client write that used to follow this branch is gone\n // (AGL-1050): a non-null `dataScope` is an org scope, so `orgId` is\n // set and there is no third case to fall into.\n await callDatasetApi({\n action: 'create-record',\n datasetId: selected.$id,\n values: coerced,\n })\n }\n } catch (error: any) {\n return void enqueueSnackbar(error?.message ?? 'Record save failed', {\n variant: 'warning',\n persist: false,\n })\n }\n setEditor(null)\n // A create moves the count; an update cannot. Same reason as the\n // importer: the one-shot aggregate does not refresh itself.\n if (!editor.id) setRecordCountEpoch((epoch) => epoch + 1)\n enqueueSnackbar(editor.id ? 'Record saved' : 'Record added', {\n variant: 'success',\n persist: false,\n })\n logActivity(editor.id ? 'Updated record' : 'Added record', {\n type: 'content',\n id: selected.$id,\n name: datasetDisplayName(selected),\n })\n }, [\n editor,\n selected,\n firestore,\n dataScope,\n model,\n callDatasetApi,\n announceRecords,\n enqueueSnackbar,\n logActivity,\n ])\n const handleDeleteRecord = useCallback(\n (record: any) => async () => {\n // Datasets whose records this delete rewrites through a reference\n // fixup, beside the one the record belongs to. Each has pages of its\n // own to refresh (AGL-3113).\n const alsoChanged = new Set<string>()\n if (!selected || !dataScope) return\n /**\n * Delete integrity (AGL-180): every collection whose model references\n * this one is asked whether it still points at this record. `restrict`\n * blocks the delete; `setNull` strips the FKey from the holders.\n *\n * The question is a QUERY over the denormalized `referencedIds` index,\n * not a page of records filtered in the browser. A page answers for the\n * rows it happened to fetch — an unordered `limit` is answered in\n * document-id order over auto-ids, so it is an arbitrary sample — and a\n * reference held by a row outside it reads as no reference at all: the\n * delete goes through and `restrict` silently fails to restrict, leaving\n * a document pointing at something that no longer exists. `values`\n * itself cannot be queried (it carries a deliberate index exemption —\n * see `datasetIntegrityFields`), which is why the index exists.\n *\n * The query narrows to the candidates; the per-field test below keeps it\n * EXACT, since `referencedIds` is the union across every reference field\n * and one of them may point at a different collection entirely.\n *\n * ⚠️ FAILS CLOSED. A query that rejects — a missing index, a rules\n * refusal on a collection this member cannot read — refuses the delete\n * rather than treating silence as \"nothing references it\". A check that\n * fails open is worse than no check, because the UI then tells the user\n * the record is safe to remove.\n *\n * ⚠️ Reaches the collections in `datasets`, which is this viewer's\n * scoped, capped picker window. A referencing collection shared with no\n * site this member can see is one the client may not read at all, so it\n * is not consulted; only a server route could close that.\n */\n for (const other of datasets) {\n const otherModel = effectiveDatasetModel(other)\n const referencing = otherModel.order.filter(\n (fieldId) =>\n otherModel.fields[fieldId]?.type === 'reference' &&\n otherModel.fields[fieldId]?.reference?.datasetId === selected.$id,\n )\n if (!referencing.length) continue\n let snapshot\n try {\n snapshot = await getDocs(\n query(\n collection(\n firestore,\n dataScope[0],\n dataScope[1],\n 'datasets',\n other.$id,\n 'records',\n ),\n where('referencedIds', 'array-contains', record.$id),\n ),\n )\n } catch {\n return void enqueueSnackbar(\n `Cannot delete: \"${datasetDisplayName(other)}\" could not be checked for ` +\n 'references, so removing this record could break it. Nothing ' +\n 'was deleted.',\n { variant: 'error' },\n )\n }\n const hits = snapshot.docs.filter((docSnapshot) =>\n referencing.some((fieldId) => {\n const stored = docSnapshot.get('values')?.[fieldId]\n return Array.isArray(stored)\n ? stored.includes(record.$id)\n : stored === record.$id\n }),\n )\n if (!hits.length) continue\n const restricted = referencing.some(\n (fieldId) =>\n otherModel.fields[fieldId]?.reference?.onDelete === 'restrict',\n )\n if (restricted) {\n return void enqueueSnackbar(\n `Cannot delete: referenced by ${hits.length} document` +\n `${hits.length === 1 ? '' : 's'} in \"${datasetDisplayName(other)}\"`,\n { variant: 'warning', persist: false },\n )\n }\n // Chunked under Firestore's 500-writes-per-batch cap. The query is no\n // longer bounded by a page size, so the number of holders is whatever\n // the collection really holds.\n for (let start = 0; start < hits.length; start += 400) {\n const batch = writeBatch(firestore)\n for (const hit of hits.slice(start, start + 400)) {\n const values = { ...(hit.get('values') ?? {}) }\n for (const fieldId of referencing) {\n const stored = values[fieldId]\n if (Array.isArray(stored)) {\n values[fieldId] = stored.filter(\n (id: string) => id !== record.$id,\n )\n } else if (stored === record.$id) {\n delete values[fieldId]\n }\n }\n batch.update(hit.ref, {\n values,\n ...datasetIntegrityUpdate(otherModel, values, deleteField()),\n })\n }\n await batch.commit()\n }\n // The fixups rewrote rows in ANOTHER dataset, whose own pages are now\n // showing a reference that no longer resolves.\n alsoChanged.add(other.$id)\n }\n await deleteDoc(\n doc(\n firestore,\n dataScope[0],\n dataScope[1],\n 'datasets',\n selected.$id,\n 'records',\n record.$id,\n ),\n )\n setRecordCountEpoch((epoch) => epoch + 1)\n for (const datasetId of [selected.$id, ...alsoChanged]) {\n await announceRecords(datasetId)\n }\n enqueueSnackbar('Record deleted', { variant: 'success', persist: false })\n },\n [selected, datasets, firestore, dataScope, announceRecords, enqueueSnackbar],\n )\n\n /**\n * Import and export (AGL-3530) open the console's import wizard and export\n * dialog on this dataset (`data.dataset:<datasetId>`): the file is read,\n * matched and written on the server, through the same record writes as\n * every other create and update, and the export streams the fields the\n * person picks. Outside the console shell there is no launcher, and no\n * Import or Export to offer. Inside it, Import is offered to a member who\n * may import (Manage data) and Export to any member who can see the\n * dataset (AGL-3546) — the transfer routes' own rule.\n */\n const transfer = useTransferLauncher()\n const transferTarget = selected?.$id\n ? { resource: datasetTransferResourceKey(selected.$id), scope: 'org' as const }\n : null\n const canImport = Boolean(transfer && transferTarget && transfer.can('import', transferTarget))\n const canExport = Boolean(transfer && transferTarget && transfer.can('export', transferTarget))\n const handleImport = useCallback(() => {\n if (!transfer || !selected?.$id) return\n const dataset = { id: selected.$id, name: datasetDisplayName(selected) }\n transfer.openImport({\n resource: datasetTransferResourceKey(dataset.id),\n scope: 'org',\n title: dataset.name ? `Import into ${dataset.name}` : 'Import records',\n onFinished: () => {\n // An import moves the record count, and the aggregate is a one-shot.\n setRecordCountEpoch((epoch) => epoch + 1)\n logActivity('Imported records', { type: 'content', id: dataset.id, name: dataset.name })\n },\n })\n }, [transfer, selected, logActivity])\n const handleExport = useCallback(() => {\n if (!transfer || !selected?.$id) return\n const name = datasetDisplayName(selected)\n transfer.openExport({\n resource: datasetTransferResourceKey(selected.$id),\n scope: 'org',\n title: name ? `Export ${name}` : 'Export records',\n // The table's own query, re-planned on the server the way the table\n // plans it, so \"the current filter\" exports what the table shows.\n ...(filteringRecords\n ? {\n filter: {\n label: 'The records the table’s filters and search show',\n value: { clauses: recordClauses, search: gridFilter.searchWords },\n },\n }\n : {}),\n })\n }, [transfer, selected, filteringRecords, recordClauses, gridFilter.searchWords])\n\n /*\n * One column per schema field, filterable as far as `datasetRecordFilter`\n * declares it. The row OPENS the record, read-only (`onOpen`); the actions\n * column holds the keyboard's way in (`View`, a real button) beside Edit\n * and Delete, and a press anywhere in it never opens the row.\n */\n const recordGridColumns = useMemo(\n () =>\n listFilterGridColumns(\n [\n ...fields.map((fieldId) => {\n const field = model.fields[fieldId]\n return {\n field: recordColumn(fieldId),\n headerName: field?.name ?? fieldId,\n // Field descriptions (AGL-560) surface as header hints.\n description: field?.description,\n flex: 1,\n minWidth: 140,\n renderCell: ({ row }: { row: any }) =>\n field?.type === 'reference'\n ? referenceLabel(fieldId, row.values?.[fieldId]) || '--'\n : field\n ? formatDatasetValue(field, row.values?.[fieldId]) || '--'\n : '--',\n }\n }),\n listActionsColumn(\n (record: any) => (\n <Stack\n direction=\"row\"\n sx={{ height: '100%', alignItems: 'center', justifyContent: 'flex-end' }}\n >\n <Button size=\"small\" onClick={() => setViewerId(record.$id)}>\n {'View'}\n </Button>\n <Button size=\"small\" onClick={handleOpenRecord(record)}>\n {'Edit'}\n </Button>\n <Button\n size=\"small\"\n color=\"error\"\n onClick={handleDeleteRecord(record)}\n >\n {'Delete'}\n </Button>\n </Stack>\n ),\n { width: 220 },\n ),\n ] as Parameters<typeof listFilterGridColumns>[0],\n recordFilter.fields,\n recordFilter.options,\n recordFilter.headers,\n ),\n [\n fields,\n model,\n referenceLabel,\n handleOpenRecord,\n handleDeleteRecord,\n recordFilter,\n ],\n )\n\n /*\n * EVERY HEADER SORTS — THE PAGE ON SCREEN (AGL-3680). A record's values are\n * per-schema and no field is on every record (see the walk above), so no\n * query can order by one; each value column sorts the loaded page by what\n * it shows (a reference by its label, a number or switch by its value) and\n * the notice says it is this page only.\n */\n const recordPageSorts = useMemo(\n () =>\n Object.fromEntries(\n fields.map((fieldId) => {\n const field = model.fields[fieldId]\n return [\n recordColumn(fieldId),\n (row: any) => {\n const value = row.values?.[fieldId]\n if (field?.type === 'reference') return referenceLabel(fieldId, value) || null\n if (typeof value === 'number' || typeof value === 'boolean') return value\n return field ? formatDatasetValue(field, value) || null : null\n },\n ]\n }),\n ),\n [fields, model, referenceLabel],\n )\n const recordSortHeaders = useMemo(\n () =>\n Object.fromEntries(\n fields.map((fieldId) => [recordColumn(fieldId), model.fields[fieldId]?.name ?? fieldId]),\n ),\n [fields, model],\n )\n const recordColumnSort = useListColumnSort<any>({\n sorts: NO_QUERY_SORTS,\n rows: records,\n pageSorts: recordPageSorts,\n headers: recordSortHeaders,\n })\n\n return (\n <CardDisplay\n header={'Data'}\n help={pluginDocsHelp('datasets', { anchor: '#filter-records' })}\n contentGutterX\n contentGutterY\n contentBordered=\"all\"\n >\n <Stack spacing={1.5}>\n {orgId ? (\n <Typography variant=\"caption\" color=\"text.secondary\">\n {/* Ownership and visibility are separate facts (AGL-1044), and\n what a new dataset starts on depends on where it is made. */}\n {newDatasetSharingNote(createsSiteOnly)}\n </Typography>\n ) : null}\n {datasets.length === 0 ? (\n <Typography variant=\"body2\" color=\"text.secondary\">\n {'Create a dataset (e.g. Products) and repeat a component over ' +\n 'its records with {{item.field}} bindings.'}\n </Typography>\n ) : (\n <Stack\n direction=\"row\"\n spacing={1}\n useFlexGap\n sx={{ alignItems: 'center', flexWrap: 'wrap' }}\n >\n {/* A scope, not a filter: it picks which collection the table\n walks, and the grid's own Filters panel narrows within it. */}\n <TextField\n select\n size=\"small\"\n label=\"Dataset\"\n value={selected?.$id ?? ''}\n onChange={(event) => setSelectedId(event.target.value)}\n sx={{ minWidth: 180 }}\n >\n {datasets.map((item) => (\n <MenuItem key={item.$id} value={item.$id}>\n {datasetDisplayName(item)}\n </MenuItem>\n ))}\n </TextField>\n <Button\n size=\"small\"\n color=\"primary\"\n onClick={handleOpenRecord()}\n >\n {'Add record'}\n </Button>\n <Button size=\"small\" onClick={() => setSchemaOpen(true)}>\n {'Schema'}\n </Button>\n {/* An import left unfinished, reopened where it stopped (AGL-3549). */}\n {transferTarget ? (\n <TransferResumeImport\n target={transferTarget}\n {...(selected ? { title: `Import into ${datasetDisplayName(selected)}` } : {})}\n onFinished={() => setRecordCountEpoch((epoch) => epoch + 1)}\n />\n ) : null}\n {canImport ? (\n <Button size=\"small\" onClick={handleImport}>\n {'Import'}\n </Button>\n ) : null}\n {/* The real dataset size, not the loaded window (AGL-2335) —\n the export is a server stream, so a dataset whose first page\n has not landed yet is still exportable. */}\n {canExport && (recordCount || records.length) ? (\n <Button size=\"small\" onClick={handleExport}>\n {'Export'}\n </Button>\n ) : null}\n <Button size=\"small\" color=\"error\" onClick={handleDeleteDataset}>\n {'Delete'}\n </Button>\n </Stack>\n )}\n {/* The per-dataset record cap, standing rather than only on refusal\n (AGL-2113). `recordCount` is the dataset's real size — the same\n number `handleOpenRecord` and the importer hand to `checkQuota`,\n not the loaded window (AGL-1716). */}\n {selected ? (\n <QuotaReadoutComponent\n ready={org != null}\n used={recordCount}\n limit={checkQuota(org, 'recordsPerDataset', recordCount).limit}\n noun=\"record\"\n />\n ) : null}\n {selected && (records.length > 0 || recordPage > 0 || filteringRecords) ? (\n <>\n <ListFilterChips\n fields={recordFilter.fields}\n headers={recordFilter.headers}\n clauses={recordClauses}\n onChange={gridFilter.setClauses}\n options={recordFilter.options}\n />\n <ListQueryNotices\n refused={recordRefusals}\n notices={[...recordPlan.notices, ...recordColumnSort.notices]}\n />\n <ListTable\n aria-label=\"Records\"\n rows={recordColumnSort.rows}\n columnSort={recordColumnSort}\n columns={recordGridColumns}\n onOpen={(id) => setViewerId(id)}\n // One page of the walk, turned by the footer below: the grid\n // neither slices nor filters it.\n hideFooter\n filterMode=\"server\"\n filterModel={gridFilter.filterModel}\n onFilterModelChange={gridFilter.onFilterModelChange}\n quickFilter\n noRowsLabel={\n filteringRecords ? 'No records match these filters' : 'No records yet.'\n }\n />\n {/* The count line is the PAGE's, deliberately. `recordCount` is the\n dataset's real size and it already has its own readout above —\n handing it to the footer as `count` would tell MUI the walk is\n that long and leave Next live past the end of it whenever a rule,\n a scope or a filter has narrowed what this reader may list.\n `hasMore` is a fact from the probe row, so the footer answers\n for what it is actually paging. */}\n <ListPagination\n page={recordPage}\n pageSize={recordPageSize}\n rowCount={records.length}\n hasMore={hasMoreRecords}\n onPageChange={setRecordPage}\n onPageSizeChange={setRecordPageSize}\n />\n </>\n ) : selected ? (\n <Typography variant=\"body2\" color=\"text.secondary\">\n {'No records yet.'}\n </Typography>\n ) : null}\n <Stack\n direction=\"row\"\n spacing={1}\n useFlexGap\n sx={{ flexWrap: 'wrap' }}\n >\n <Button\n size=\"small\"\n variant=\"outlined\"\n color=\"primary\"\n onClick={handleOpenCreator}\n >\n {'Add dataset'}\n </Button>\n {datasets.length >= 2 ? (\n <Button size=\"small\" onClick={() => setJoiner({ a: '', b: '' })}>\n {'Add join collection'}\n </Button>\n ) : null}\n </Stack>\n </Stack>\n <Dialog\n open={Boolean(creator)}\n onClose={() => setCreator(null)}\n maxWidth=\"xs\"\n fullWidth\n >\n <DialogTitle>{'New dataset'}</DialogTitle>\n <DialogContent\n sx={{ display: 'flex', flexDirection: 'column', gap: 2 }}\n >\n <TextField\n label=\"Name\"\n value={creator?.name ?? ''}\n onChange={(event) =>\n setCreator((prev) =>\n prev ? { ...prev, name: event.target.value } : prev,\n )\n }\n size=\"small\"\n autoFocus\n sx={{ mt: 1 }}\n helperText=\"e.g. Products, Team, FAQ\"\n />\n <TextField\n label=\"Fields\"\n value={creator?.fields ?? ''}\n onChange={(event) =>\n setCreator((prev) =>\n prev ? { ...prev, fields: event.target.value } : prev,\n )\n }\n size=\"small\"\n helperText={\n creatorEntries.length\n ? `Columns: ${creatorEntries\n .map((entry) => entry.name)\n .join(', ')}`\n : 'Comma-separated column names, e.g. Title, Unit price'\n }\n />\n </DialogContent>\n <DialogActions>\n <Button onClick={() => setCreator(null)}>{'Cancel'}</Button>\n <Button\n variant=\"contained\"\n color=\"primary\"\n disabled={\n !scopeReady ||\n !creator?.name.trim() ||\n creatorFields.length === 0\n }\n onClick={handleCreate}\n >\n {'Create'}\n </Button>\n </DialogActions>\n </Dialog>\n {/*\n ONE viewer for the table, not one per row. Its record is a prop out of\n the page already in hand, so opening it reads nothing — and mounting\n the table does not open a dialog per row to discover that.\n */}\n <DatasetRecordDialog\n record={viewerRecord}\n model={model}\n resolveReference={resolveReferenceLabel}\n onClose={() => setViewerId(null)}\n // Explicitly separate, and a hand-off rather than a second editor:\n // the viewer closes and the record opens in the dialog that has\n // always owned writing.\n onEdit={() => {\n const record = viewerRecord\n setViewerId(null)\n if (record) handleOpenRecord(record)()\n }}\n />\n <Dialog\n open={Boolean(editor)}\n onClose={() => setEditor(null)}\n maxWidth=\"xs\"\n fullWidth\n >\n <DialogTitle>{editor?.id ? 'Edit record' : 'New record'}</DialogTitle>\n <DialogContent\n sx={{ display: 'flex', flexDirection: 'column', gap: 2 }}\n >\n {fields.map((fieldId, index) => {\n const field = model.fields[fieldId]\n if (!field) return null\n const value = editor?.values[fieldId] ?? ''\n const error = editor?.errors[fieldId]\n const label = field.required ? `${field.name} *` : field.name\n const setValue = (nextValue: string) =>\n setEditor((prev) =>\n prev\n ? {\n ...prev,\n values: { ...prev.values, [fieldId]: nextValue },\n errors: { ...prev.errors, [fieldId]: '' },\n }\n : prev,\n )\n const common = {\n label,\n value,\n size: 'small' as const,\n autoFocus: index === 0,\n error: Boolean(error),\n helperText: error || field.description,\n sx: index === 0 ? { mt: 1 } : undefined,\n onChange: (event: { target: { value: string } }) =>\n setValue(event.target.value),\n }\n // Custom field types (AGL-434): the declaring plugin's Input\n // takes over; values stay in input form (strings) so the\n // existing coerce/validate pipeline is unchanged.\n const customFieldType = getCustomFieldType(field.customType)\n if (customFieldType?.Input) {\n const CustomInput = customFieldType.Input\n return (\n <Stack key={fieldId} sx={index === 0 ? { mt: 1 } : undefined}>\n <CustomInput\n value={value}\n label={common.label}\n onChange={(next) => setValue(String(next ?? ''))}\n />\n {(error || field.description) ? (\n <Typography\n variant=\"caption\"\n color={error ? 'error' : 'text.secondary'}\n >\n {error || field.description}\n </Typography>\n ) : null}\n </Stack>\n )\n }\n // Typed inputs per FT.Tag (AGL-179).\n if (field.type === 'bool') {\n return (\n <TextField key={fieldId} {...common} select>\n <MenuItem value=\"\">{'—'}</MenuItem>\n <MenuItem value=\"true\">{'Yes'}</MenuItem>\n <MenuItem value=\"false\">{'No'}</MenuItem>\n </TextField>\n )\n }\n if (field.type === 'text' && field.validation?.options?.length) {\n return (\n <TextField key={fieldId} {...common} select>\n <MenuItem value=\"\">{'—'}</MenuItem>\n {field.validation.options.map((option) => (\n <MenuItem key={option} value={option}>\n {option}\n </MenuItem>\n ))}\n </TextField>\n )\n }\n if (field.type === 'reference') {\n const options = refOptions[fieldId] ?? []\n const multiple = Boolean(field.reference?.multiple)\n const selectedIds = value\n .split(',')\n .map((part) => part.trim())\n .filter(Boolean)\n return (\n <TextField\n key={fieldId}\n {...common}\n select\n value={multiple ? selectedIds : value}\n slotProps={{\n select: multiple\n ? {\n multiple: true,\n onChange: (event: any) =>\n setValue(\n (event.target.value as string[]).join(', '),\n ),\n }\n : undefined,\n }}\n >\n {multiple ? null : <MenuItem value=\"\">{'—'}</MenuItem>}\n {options.map((option) => (\n <MenuItem key={option.id} value={option.id}>\n {option.label}\n </MenuItem>\n ))}\n </TextField>\n )\n }\n if (\n field.type === 'int32' ||\n field.type === 'int64' ||\n field.type === 'float'\n ) {\n return <TextField key={fieldId} {...common} type=\"number\" />\n }\n if (field.type === 'timestamp') {\n return (\n <TextField\n key={fieldId}\n {...common}\n type=\"datetime-local\"\n slotProps={{ inputLabel: { shrink: true } }}\n />\n )\n }\n if (field.type === 'coordinates') {\n return (\n <TextField\n key={fieldId}\n {...common}\n helperText={error || field.description || 'lat, lon'}\n />\n )\n }\n if (field.type === 'sorted') {\n return (\n <TextField\n key={fieldId}\n {...common}\n helperText={\n error || field.description || 'Comma-separated list'\n }\n />\n )\n }\n return <TextField key={fieldId} {...common} />\n })}\n </DialogContent>\n <DialogActions>\n <Button onClick={() => setEditor(null)}>{'Cancel'}</Button>\n <Button\n variant=\"contained\"\n color=\"primary\"\n onClick={handleSaveRecord}\n >\n {editor?.id ? 'Save' : 'Add'}\n </Button>\n </DialogActions>\n </Dialog>\n <Dialog\n open={Boolean(joiner)}\n onClose={() => setJoiner(null)}\n maxWidth=\"xs\"\n fullWidth\n >\n <DialogTitle>{'New join collection'}</DialogTitle>\n <DialogContent\n sx={{ display: 'flex', flexDirection: 'column', gap: 2 }}\n >\n <Typography variant=\"body2\" color=\"text.secondary\" sx={{ mt: 1 }}>\n {'Links two collections many-to-many; each row pairs one ' +\n 'document from each side.'}\n </Typography>\n {(['a', 'b'] as const).map((side) => (\n <TextField\n key={side}\n select\n size=\"small\"\n label={side === 'a' ? 'First collection' : 'Second collection'}\n value={joiner?.[side] ?? ''}\n onChange={(event) =>\n setJoiner((prev) =>\n prev ? { ...prev, [side]: event.target.value } : prev,\n )\n }\n >\n {datasets.map((item) => (\n <MenuItem key={item.$id} value={item.$id}>\n {datasetDisplayName(item)}\n </MenuItem>\n ))}\n </TextField>\n ))}\n </DialogContent>\n <DialogActions>\n <Button onClick={() => setJoiner(null)}>{'Cancel'}</Button>\n <Button\n variant=\"contained\"\n color=\"primary\"\n disabled={\n !scopeReady || !joiner?.a || !joiner?.b || joiner.a === joiner.b\n }\n onClick={handleCreateJoin}\n >\n {'Create'}\n </Button>\n </DialogActions>\n </Dialog>\n <DatasetSchemaDialog\n hostId={hostId}\n orgId={orgId ?? undefined}\n dataset={schemaOpen && selected ? selected : null}\n datasets={datasets}\n // The dataset's documents, not the loaded window (AGL-1716) — the\n // dialog warns \"N documents exist\" before a narrowing type change,\n // and 500 was the cap talking, not the collection.\n recordCount={recordCount}\n seedFromCache={datasetsFromCache}\n seedUnreadable={datasetsStatus === 'error'}\n onClose={() => setSchemaOpen(false)}\n />\n </CardDisplay>\n )\n}\nHostDatasetsCard.displayName = 'HostDatasetsCard'\n\nexport default HostDatasetsCard\n"],"names":["TransferResumeImport","checkDatasetQuota","checkEntitlement","checkQuota","getCustomFieldType","pluginDocsHelp","useTransferLauncher","CardDisplay","useConfirmationContext","ListFilterChips","ListPagination","ListQueryNotices","listQueryRefusals","ListTable","listActionsColumn","QuotaReadoutComponent","listFilterGridColumns","useListGridFilter","useSnackbar","Timestamp","Button","Dialog","DialogActions","DialogContent","DialogTitle","MenuItem","Stack","TextField","Typography","collection","deleteDoc","deleteField","doc","getCountFromServer","getDocs","limit","query","where","setDoc","writeBatch","useCallback","useEffect","useMemo","useState","useListColumnSort","useFirestore","useFirestoreCollection","useHostActivityLogger","useOrgDataScope","usePagedCollection","useScopeTokens","useUser","listQueryConstraints","authorizedFetch","DatasetSchemaDialog","DatasetRecordDialog","datasetRecordFilter","planRecordQuery","recordColumn","coerceDocumentValues","datasetIntegrityUpdate","datasetValueToInput","effectiveDatasetModel","formatDatasetValue","modelFromFieldEntries","validateDocument","fillRecordAddresses","datasetDisplayName","parseDatasetFieldEntries","datasetTransferResourceKey","NO_QUERY_SORTS","newDatasetSharingNote","siteOnly","HostDatasetsCard","props","datasets","hostId","scope","dataScope","orgId","tokens","scopeTokens","orgWide","viewerOrgWide","loaded","scopeLoaded","needsScope","scopeReady","Boolean","firestore","enqueueSnackbar","confirm","org","logActivity","data","user","createdFromHostId","undefined","createdFrom","createsSiteOnly","defaultResourceScope","callDatasetApi","payload","response","method","headers","body","JSON","stringify","result","json","catch","ok","Error","error","announceRecords","datasetId","action","console","datasetDocs","status","datasetsStatus","fromCache","datasetsFromCache","idField","sort","a","b","localeCompare","selectedId","setSelectedId","schemaOpen","setSchemaOpen","selected","find","item","$id","model","fields","order","recordFilter","gridFilter","selectFields","recordClauses","clauses","filter","clause","some","field","column","recordPlan","searchWords","recordPlanKey","filters","plan","orderBy","rows","records","hasMore","hasMoreRecords","page","recordPage","setPage","setRecordPage","pageSize","recordPageSize","setPageSize","setRecordPageSize","pageLimit","recordRefusals","refused","options","filteringRecords","length","word","trim","datasetCountEpoch","setDatasetCountEpoch","recordCountEpoch","setRecordCountEpoch","serverDatasetCount","setServerDatasetCount","serverRecordCount","setServerRecordCount","active","then","snapshot","count","countedDatasetId","datasetCount","recordCount","creator","setCreator","handleOpenCreator","variant","persist","quota","allowed","upgradeRequired","addonPriceUsd","name","creatorEntries","creatorFields","map","entry","id","handleCreate","displayName","String","message","epoch","type","joiner","setJoiner","handleCreateJoin","fieldFor","target","fieldId","required","reference","displayFieldId","onDelete","aRef","bRef","handleDeleteDataset","confirmed","title","description","confirmationText","confirmationButtonProps","color","scopeId","kind","refOptions","setRefOptions","referenceFields","Promise","all","docs","docSnapshot","label","get","entries","Object","fromEntries","resolveReferenceLabel","option","referenceLabel","value","ids","Array","isArray","join","viewerId","setViewerId","viewerRecord","record","editor","setEditor","handleOpenRecord","values","default","errors","handleSaveRecord","coerced","keys","prev","recordRef","updatedAt","now","mergeFields","handleDeleteRecord","alsoChanged","Set","other","otherModel","referencing","hits","stored","includes","restricted","start","batch","hit","slice","update","ref","commit","add","transfer","transferTarget","resource","canImport","can","canExport","handleImport","dataset","openImport","onFinished","handleExport","openExport","search","recordGridColumns","headerName","flex","minWidth","renderCell","row","direction","sx","height","alignItems","justifyContent","size","onClick","width","recordPageSorts","recordSortHeaders","recordColumnSort","sorts","pageSorts","header","help","anchor","contentGutterX","contentGutterY","contentBordered","spacing","useFlexGap","flexWrap","select","onChange","event","ready","used","noun","setClauses","notices","aria-label","columnSort","columns","onOpen","hideFooter","filterMode","filterModel","onFilterModelChange","quickFilter","noRowsLabel","rowCount","onPageChange","onPageSizeChange","open","onClose","maxWidth","fullWidth","display","flexDirection","gap","autoFocus","mt","helperText","disabled","resolveReference","onEdit","index","setValue","nextValue","common","customFieldType","customType","Input","CustomInput","next","validation","multiple","selectedIds","split","part","slotProps","inputLabel","shrink","side","seedFromCache","seedUnreadable"],"mappings":"AAAA;;;;;;;;;;;;;;;CAeC,GACD;;;AAEA,SAASA,oBAAoB,QAAQ,gDAA+C;AACpF,SAEEC,iBAAiB,EACjBC,gBAAgB,EAChBC,UAAU,EACVC,kBAAkB,EAClBC,cAAc,EACdC,mBAAmB,QACd,eAAc;AACrB,SAASC,WAAW,EAAEC,sBAAsB,QAAQ,uBAAsB;AAC1E,OAAOC,qBAAqB,8DAA6D;AACzF,SAASC,cAAc,QAAQ,4DAA2D;AAC1F,OAAOC,oBACLC,iBAAiB,QACZ,+DAA8D;AACrE,SACEC,SAAS,EACTC,iBAAiB,QACZ,uDAAsD;AAC7D,OAAOC,2BAA2B,0DAAyD;AAC3F,SAASC,qBAAqB,QAAQ,8CAA6C;AACnF,SAASC,iBAAiB,QAAQ,kDAAiD;AACnF,SAASC,WAAW,QAAQ,8BAA6B;AACzD,SAASC,SAAS,QAAQ,+BAA8B;AACxD,SACEC,MAAM,EACNC,MAAM,EACNC,aAAa,EACbC,aAAa,EACbC,WAAW,EACXC,QAAQ,EACRC,KAAK,EACLC,SAAS,EACTC,UAAU,QACL,gBAAe;AACtB,SACEC,UAAU,EACVC,SAAS,EACTC,WAAW,EACXC,GAAG,EACHC,kBAAkB,EAClBC,OAAO,EACPC,KAAK,EACLC,KAAK,EACLC,KAAK,EACLC,MAAM,EACNC,UAAU,QACL,qBAAoB;AAC3B,SAASC,WAAW,EAAEC,SAAS,EAAEC,OAAO,EAAEC,QAAQ,QAAQ,QAAO;AACjE,SAASC,iBAAiB,QAAQ,kDAAiD;AACnF,SACEC,YAAY,EACZC,sBAAsB,EACtBC,qBAAqB,EACrBC,eAAe,EACfC,kBAAkB,EAClBC,cAAc,EACdC,OAAO,QACF,iCAAgC;AACvC,SAASC,oBAAoB,QAAQ,sDAAqD;AAC1F,SAASC,eAAe,QAAQ,2CAA0C;AAC1E,SAASC,mBAAmB,QAAQ,uCAAmC;AACvE,SAASC,mBAAmB,QAAQ,uCAAmC;AACvE,SACEC,mBAAmB,EACnBC,eAAe,EACfC,YAAY,QACP,6BAAyB;AAChC,SAASC,oBAAoB,EAAEC,sBAAsB,EAAEC,mBAAmB,EAAEC,qBAAqB,EAAEC,kBAAkB,EAAEC,qBAAqB,EAAEC,gBAAgB,QAAQ,6BAAyB;AAC/L,SAASC,mBAAmB,QAAQ,kCAA8B;AAClE,SAASC,kBAAkB,EAAEC,wBAAwB,QAAQ,uBAAmB;AAChF,SAASC,0BAA0B,QAAQ,sCAAkC;AAmB7E;;;;;;;CAOC,GACD,0EAA0E,GAC1E,MAAMC,iBAA0B,EAAE;AAElC,OAAO,SAASC,sBAAsBC,QAAiB;IACrD,OAAOA,WACH,yEACE,kEACF,oEACE;AACR;AAEA;;;;;;;CAOC,GACD,OAAO,SAASC,iBAAiBC,KAA4B;QAoJzDC;IAnJF,MAAM,EAAEC,MAAM,EAAE,GAAGF;IACnB,yEAAyE;IACzE,sEAAsE;IACtE,qEAAqE;IACrE,mBAAmB;IACnB,MAAM,EAAEG,OAAOC,SAAS,EAAEC,KAAK,EAAE,GAAG/B,gBAAgB;QAClD4B;QACAG,OAAOL,MAAMK,KAAK;IACpB;IACA,wEAAwE;IACxE,iEAAiE;IACjE,mEAAmE;IACnE,oEAAoE;IACpE,uEAAuE;IACvE,uDAAuD;IACvD,MAAM,EACJC,QAAQC,WAAW,EACnBC,SAASC,aAAa,EACtBC,QAAQC,WAAW,EACpB,GAAGnC,eAAe6B;IACnB,mEAAmE;IACnE,qEAAqE;IACrE,yEAAyE;IACzE,4DAA4D;IAC5D,MAAMO,aAAa,CAACH;IACpB,yEAAyE;IACzE,sEAAsE;IACtE,wEAAwE;IACxE,mEAAmE;IACnE,wEAAwE;IACxE,uEAAuE;IACvE,MAAMI,aAAaC,QAAQV,cAAcO;IACzC,MAAMI,YAAY5C;IAClB,MAAM,EAAE6C,eAAe,EAAE,GAAGxE;IAC5B,MAAM,EAAEyE,OAAO,EAAE,GAAGnF;IACpB,MAAM,EAAEoF,GAAG,EAAE,GAAGlB;IAChB,MAAMmB,cAAc9C,sBAAsB6B;IAC1C,MAAM,EAAEkB,MAAMC,IAAI,EAAE,GAAG5C;IACvB;;;;;;;;;;GAUC,GACD,MAAM6C,oBAAoBtB,MAAMK,KAAK,GAAGkB,YAAYrB,UAAUqB;IAC9D,MAAMC,cAAcxD,QAClB,IAAOsD,oBAAoB;YAAEpB,QAAQoB;QAAkB,IAAI,CAAC,GAC5D;QAACA;KAAkB;IAErB;;;;;GAKC,GACD,MAAMG,kBACJX,QAAQQ,sBACR,CAACJ,uBAAD,AAACA,IACGQ,oBAAoB,MAAK;IAE/B,uEAAuE;IACvE,kEAAkE;IAClE,qEAAqE;IACrE,mEAAmE;IACnE,MAAMC,iBAAiB7D,YACrB,OAAO8D;QACL,MAAMC,WAAW,MAAMlD,gBAAgB0C,MAAM,sBAAsB;YACjES,QAAQ;YACRC,SAAS;gBAAE,gBAAgB;YAAmB;YAC9CC,MAAMC,KAAKC,SAAS,CAAC;gBAAE7B;eAAUuB;QACnC;QACA,MAAMO,SAAS,MAAMN,SAASO,IAAI,GAAGC,KAAK,CAAC,IAAO,CAAA,CAAC,CAAA;QACnD,IAAI,CAACR,SAASS,EAAE,EAAE;;YAChB,MAAM,IAAIC,cAAMJ,0BAAAA,OAAQK,KAAK,mBAAI;QACnC;QACA,OAAOL;IACT,GACA;QAACd;QAAMhB;KAAM;IAGf;;;;;;;;;;;;;GAaC,GACD,MAAMoC,kBAAkB3E,YACtB,OAAO4E;QACL,IAAI;YACF,MAAMf,eAAe;gBAAEgB,QAAQ;gBAAoBD;YAAU;QAC/D,EAAE,OAAOF,OAAO;YACdI,QAAQJ,KAAK,CAACA;QAChB;IACF,GACA;QAACb;KAAe;IAGlB,MAAM,EACJP,MAAMyB,WAAW,EACjBC,QAAQC,cAAc,EACtB;;;;;;KAMC,GACDC,WAAWC,iBAAiB,EAC7B,GAAG7E,uBACF,IACE,kEAAkE;QAClE,mDAAmD;QACnDgC,aAAaS,aACTnD,MACEP,WAAW4D,WAAWX,SAAS,CAAC,EAAE,EAAEA,SAAS,CAAC,EAAE,EAAE,gBAC9CQ,aACA;YAACjD,MAAM,aAAa,sBAAsB4C;SAAa,GACvD,EAAE,EACN9C,MAAM,QAER,MACN;QAACsD;QAAWX;QAAWQ;QAAYL;QAAaM;KAAW,EAC3D;QAAEqC,SAAS;IAAM;IAEnB,MAAMjD,WAAWjC,QACf,IACE;eAAK6E,sBAAAA,cAAe,EAAE;SAAE,CAACM,IAAI,CAAC,CAACC,GAAGC,IAChC5D,mBAAmB2D,GAAGE,aAAa,CAAC7D,mBAAmB4D,MAE3D;QAACR;KAAY;IAEf,MAAM,CAACU,YAAYC,cAAc,GAAGvF,SAAwB;IAC5D,MAAM,CAACwF,YAAYC,cAAc,GAAGzF,SAAS;IAC7C,MAAM0F,YACJ1D,iBAAAA,SAAS2D,IAAI,CAAC,CAACC,OAASA,KAAKC,GAAG,KAAKP,uBAArCtD,iBAAoDA,QAAQ,CAAC,EAAE;IACjE,iEAAiE;IACjE,2DAA2D;IAC3D,MAAM8D,QAAQ/F,QACZ,IAAMoB,sBAAsBuE,mBAAAA,WAAY,CAAC,IACzC;QAACA;KAAS;IAEZ,MAAMK,SAAmBhG,QAAQ,IAAM+F,MAAME,KAAK,EAAE;QAACF;KAAM;IAC3D,mEAAmE;IACnE,MAAMG,eAAelG,QAAQ,IAAMc,oBAAoBiF,QAAQ;QAACA;KAAM;IAEtE,qEAAqE;IACrE,4EAA4E;IAC5E,yEAAyE;IACzE,yEAAyE;IACzE,wCAAwC;IACxC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+DC,GACD,MAAMI,aAAa5H,kBAAkB;QAAE6H,cAAcF,aAAaE,YAAY;IAAC;IAC/E,sEAAsE;IACtE,8CAA8C;IAC9C,MAAMC,gBAAgBrG,QACpB,IACEmG,WAAWG,OAAO,CAACC,MAAM,CAAC,CAACC,SACzBN,aAAaF,MAAM,CAACS,IAAI,CAAC,CAACC,QAAUA,MAAMC,MAAM,KAAKH,OAAOE,KAAK,IAErE;QAACP,WAAWG,OAAO;QAAEJ,aAAaF,MAAM;KAAC;IAE3C,MAAMY,aAAa5G,QACjB,IAAMe,gBAAgBgF,OAAOG,cAAcG,eAAeF,WAAWU,WAAW,GAChF;QAACd;QAAOG;QAAcG;QAAeF,WAAWU,WAAW;KAAC;IAE9D,iEAAiE;IACjE,MAAMC,gBAAgB7C,KAAKC,SAAS,CAAC;QACnC6C,SAASH,WAAWI,IAAI,CAACD,OAAO;QAChCE,SAASL,WAAWI,IAAI,CAACC,OAAO;IAClC;IACA,MAAM,EACJC,MAAMC,OAAO,EACbC,SAASC,cAAc,EACvBC,MAAMC,UAAU,EAChBC,SAASC,aAAa,EACtBC,UAAUC,cAAc,EACxBC,aAAaC,iBAAiB,EAC/B,GAAGtH,mBACF,CAACuH,YACC1F,cAAauD,4BAAAA,SAAUG,GAAG,IACtBpG,MACEP,WACE4D,WACAX,SAAS,CAAC,EAAE,EACZA,SAAS,CAAC,EAAE,EACZ,YACAuD,SAASG,GAAG,EACZ,eAECpF,qBAAqBkG,WAAWI,IAAI,GACvCvH,MAAMqI,cAER,MACN;QAAC/E;QAAWX;QAAWuD,4BAAAA,SAAUG,GAAG;QAAEgB;KAAc,EACpD;QAAE5B,SAAS;IAAM;IAEnB,MAAM6C,iBAAiB/H,QACrB,IACE9B,kBAAkB0I,WAAWoB,OAAO,EAAE;YACpChC,QAAQE,aAAaF,MAAM;YAC3BjC,SAASmC,aAAanC,OAAO;YAC7BkE,SAAS/B,aAAa+B,OAAO;QAC/B,IACF;QAACrB,WAAWoB,OAAO;QAAE9B;KAAa;IAEpC,MAAMgC,mBACJ7B,cAAc8B,MAAM,GAAG,KAAKhC,WAAWU,WAAW,CAACJ,IAAI,CAAC,CAAC2B,OAASA,KAAKC,IAAI;IAC7E;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiCC,GACD,MAAM,CAACC,mBAAmBC,qBAAqB,GAAGtI,SAAS;IAC3D,MAAM,CAACuI,kBAAkBC,oBAAoB,GAAGxI,SAAS;IACzD,MAAM,CAACyI,oBAAoBC,sBAAsB,GAAG1I,SAClD;IAEF,uEAAuE;IACvE,yEAAyE;IACzE,sEAAsE;IACtE,0EAA0E;IAC1E,MAAM,CAAC2I,mBAAmBC,qBAAqB,GAAG5I,SAGxC;IACVF,UAAU;QACR,IAAI,CAACqC,WAAW;QAChB,IAAI0G,SAAS;QACb,uEAAuE;QACvE,sEAAsE;QACtE,qEAAqE;QACrE,+DAA+D;QAC/D,KAAKvJ,mBACHJ,WAAW4D,WAAWX,SAAS,CAAC,EAAE,EAAEA,SAAS,CAAC,EAAE,EAAE,aAEjD2G,IAAI,CAAC,CAACC;YACL,IAAIF,QAAQH,sBAAsBK,SAAS5F,IAAI,GAAG6F,KAAK;QACzD,GACC5E,KAAK,CAAC;QACL,oEAAoE;QACpE,kEAAkE;QAClE,gEAAgE;QAChE,4CAA4C;QAC9C;QACF,OAAO;YACLyE,SAAS;QACX;IACF,GAAG;QAAC/F;QAAWX;QAAWkG;KAAkB;IAC5C,qEAAqE;IACrE,uEAAuE;IACvE,MAAMY,mBAAuCvD,4BAAAA,SAAUG,GAAG;IAC1D/F,UAAU;QACR,IAAI,CAACqC,aAAa,CAAC8G,kBAAkB;QACrC,IAAIJ,SAAS;QACb,KAAKvJ,mBACHJ,WACE4D,WACAX,SAAS,CAAC,EAAE,EACZA,SAAS,CAAC,EAAE,EACZ,YACA8G,kBACA,YAGDH,IAAI,CAAC,CAACC;YACL,IAAIF,QAAQ;gBACVD,qBAAqB;oBACnBnE,WAAWwE;oBACXD,OAAOD,SAAS5F,IAAI,GAAG6F,KAAK;gBAC9B;YACF;QACF,GACC5E,KAAK,CAAC;QACL,uCAAuC;QACzC;QACF,OAAO;YACLyE,SAAS;QACX;IACF,GAAG;QAAC/F;QAAWX;QAAW8G;QAAkBV;KAAiB;IAC7D,wEAAwE;IACxE,sEAAsE;IACtE,yEAAyE;IACzE,wEAAwE;IACxE,yEAAyE;IACzE,mDAAmD;IACnD,MAAMW,eAAeT,6BAAAA,qBAAsBzG,SAASkG,MAAM;IAC1D,MAAMiB,cACJR,qBAAqBA,kBAAkBlE,SAAS,KAAKwE,mBACjDN,kBAAkBK,KAAK,GACvB9B,QAAQgB,MAAM;IAEpB,2EAA2E;IAC3E,MAAM,CAACkB,SAASC,WAAW,GAAGrJ,SAGpB;IACV,MAAMsJ,oBAAoBzJ,YAAY;QACpC,IAAI,CAACtC,iBAAiB0F,KAAK,cAAc;YACvC,OAAOF,gBACL,2DACA;gBAAEwG,SAAS;gBAAWC,SAAS;YAAM;QAEzC;QACA,kEAAkE;QAClE,sEAAsE;QACtE,0DAA0D;QAC1D,MAAMC,QAAQnM,kBAAkB2F,KAAYiG;QAC5C,IAAI,CAACO,MAAMC,OAAO,EAAE;YAClB,OAAO3G,gBACL0G,MAAME,eAAe,GACjB,CAAC,uBAAuB,EAAEF,MAAMjK,KAAK,CAAC,sBAAsB,CAAC,GAC7D,CAAC,uBAAuB,EAAEiK,MAAMjK,KAAK,CAAC,uBAAuB,CAAC,GAC9D,CAAC,KAAK,EAAEiK,MAAMG,aAAa,CAAC,8BAA8B,CAAC,EAC/D;gBAAEL,SAAS;gBAAWC,SAAS;YAAM;QAEzC;QACAH,WAAW;YAAEQ,MAAM;YAAI9D,QAAQ;QAAG;IACpC,GAAG;QAAC9C;QAAKiG;QAAcnG;KAAgB;IACvC,2DAA2D;IAC3D,sEAAsE;IACtE,MAAM+G,iBAAiBrI,iCAAyB2H,2BAAAA,QAASrD,MAAM,mBAAI;IACnE,MAAMgE,gBAAgBD,eAAeE,GAAG,CAAC,CAACC,QAAUA,MAAMC,EAAE;IAC5D,MAAMC,eAAetK,YAAY;QAC/B,oEAAoE;QACpE,sEAAsE;QACtE,yEAAyE;QACzE,uEAAuE;QACvE,iEAAiE;QACjE,yEAAyE;QACzE,IAAI,EAACuJ,2BAAAA,QAASS,IAAI,CAACzB,IAAI,OAAM2B,cAAc7B,MAAM,KAAK,KAAK,CAAC9F,OAAO;QACnE,IAAI8H;QACJ,IAAI;YACF,MAAMhG,SAAS,MAAMR,eAAe;gBAClCgB,QAAQ;gBACR0F,aAAahB,QAAQS,IAAI,CAACzB,IAAI;gBAC9BrC,QAAQgE;gBACR,mEAAmE;gBACnEjE,OAAOzE,sBAAsByI;eAC1BvG;YAEL2G,KAAKG,OAAOnG,OAAOgG,EAAE;QACvB,EAAE,OAAO3F,OAAY;;YACnB,OAAO,KAAKxB,wBAAgBwB,yBAAAA,MAAO+F,OAAO,mBAAI,yBAAyB;gBACrEf,SAAS;gBACTC,SAAS;YACX;QACF;QACAH,WAAW;QACX9D,cAAc2E;QACd5B,qBAAqB,CAACiC,QAAUA,QAAQ;QACxCxH,gBAAgB,CAAC,SAAS,EAAEqG,QAAQS,IAAI,CAACzB,IAAI,GAAG,SAAS,CAAC,EAAE;YAC1DmB,SAAS;YACTC,SAAS;QACX;QACAtG,YAAY,mBAAmB;YAC7BsH,MAAM;YACNN;YACAL,MAAMT,QAAQS,IAAI,CAACzB,IAAI;QACzB;IACF,GAAG;QAACgB;QAASU;QAAgBC;QAAe3H;QAAOmB;QAAaG;QAAgBX;QAAiBG;KAAY;IAE7G,kEAAkE;IAClE,yDAAyD;IACzD,MAAM,CAACuH,QAAQC,UAAU,GAAG1K,SAA0C;IACtE,MAAM2K,mBAAmB9K,YAAY;QACnC,IAAI,EAAC4K,0BAAAA,OAAQtF,CAAC,KAAI,EAACsF,0BAAAA,OAAQrF,CAAC,KAAIqF,OAAOtF,CAAC,KAAKsF,OAAOrF,CAAC,EAAE;QACvD,MAAMD,IAAInD,SAAS2D,IAAI,CAAC,CAACC,OAASA,KAAKC,GAAG,KAAK4E,OAAOtF,CAAC;QACvD,MAAMC,IAAIpD,SAAS2D,IAAI,CAAC,CAACC,OAASA,KAAKC,GAAG,KAAK4E,OAAOrF,CAAC;QACvD,oEAAoE;QACpE,mEAAmE;QACnE,8CAA8C;QAC9C,IAAI,CAACD,KAAK,CAACC,KAAK,CAAChD,OAAO;QACxB,MAAMwI,WAAW,CAACC,QAAaC,UAAqB,CAAA;gBAClDjB,MAAMrI,mBAAmBqJ,WAAWC;gBACpCN,MAAM;gBACNO,UAAU;gBACVC,WAAW;oBACTvG,WAAWoG,OAAOhF,GAAG;oBACrBoF,gBAAgB9J,sBAAsB0J,QAAQ7E,KAAK,CAAC,EAAE;oBACtDkF,UAAU;gBACZ;YACF,CAAA;QACA,MAAMvH,UAAU;YACdyG,aAAa,GAAG5I,mBAAmB2D,GAAG,GAAG,EAAE3D,mBAAmB4D,IAAI;YAClEW,QAAQ;gBAAC;gBAAQ;aAAO;YACxBD,OAAO;gBACLE,OAAO;oBAAC;oBAAQ;iBAAO;gBACvBD,QAAQ;oBAAEoF,MAAMP,SAASzF,GAAG;oBAASiG,MAAMR,SAASxF,GAAG;gBAAQ;YACjE;QACF;QACA,IAAI8E;QACJ,IAAI;YACF,MAAMhG,SAAS,MAAMR,eAAe;gBAClCgB,QAAQ;eACLf,SAEAJ;YAEL2G,KAAKG,OAAOnG,OAAOgG,EAAE;QACvB,EAAE,OAAO3F,OAAY;;YACnB,OAAO,KAAKxB,wBAAgBwB,yBAAAA,MAAO+F,OAAO,mBAAI,sBAAsB;gBAClEf,SAAS;gBACTC,SAAS;YACX;QACF;QACAkB,UAAU;QACVnF,cAAc2E;QACd,8DAA8D;QAC9D5B,qBAAqB,CAACiC,QAAUA,QAAQ;QACxCxH,gBAAgB,2BAA2B;YACzCwG,SAAS;YACTC,SAAS;QACX;IACF,GAAG;QAACiB;QAAQzI;QAAUI;QAAOmB;QAAaG;QAAgBX;KAAgB;IAE1E,MAAMsI,sBAAsBxL,YAAY;QACtC,IAAI,CAAC6F,UAAU;QACf,MAAM4F,YAAY,MAAMtI,QAAQ;YAC9BuI,OAAO;YACPC,aACE,CAAC,CAAC,EAAEhK,mBAAmBkE,UAAU,CAAC,CAAC,GACnC,mEAAmE;YACnE,+DAA+D;YAC9DyD,CAAAA,cACG,CAAC,SAAS,EAAEA,YAAY,SAAS,EAAEA,gBAAgB,IAAI,KAAK,KAAK,GACjE,EAAC,IACL,gEACA;YACFsC,kBAAkB;YAClBC,yBAAyB;gBAAEC,OAAO;YAAQ;QAC5C,GACG7C,IAAI,CAAC,IAAM,MACX1E,KAAK,CAAC,IAAM;QACf,IAAI,CAACkH,aAAa,CAACnJ,WAAW;QAC9B,kEAAkE;QAClE,uEAAuE;QACvE,gEAAgE;QAChE,6DAA6D;QAC7D,IAAI;;YACF,MAAMyB,WAAW,MAAMlD,gBAAgB0C,MAAM,wBAAwB;gBACnES,QAAQ;gBACRC,SAAS;oBAAE,gBAAgB;gBAAmB;gBAC9CC,MAAMC,KAAKC,SAAS,CAAC;oBACnB/B,OAAOC,SAAS,CAAC,EAAE;oBACnByJ,SAASzJ,SAAS,CAAC,EAAE;oBACrB0J,MAAM;oBACN3B,IAAIxE,SAASG,GAAG;oBAChB,+DAA+D;oBAC/D,+DAA+D;oBAC/D,8DAA8D;oBAC9D5D;gBACF;YACF;YACA,MAAMiC,SAAS,MAAMN,SAASO,IAAI,GAAGC,KAAK,CAAC,IAAO,CAAA,CAAC,CAAA;YACnD,IAAI,CAACR,SAASS,EAAE,EAAE,MAAM,IAAIC,cAAMJ,0BAAAA,OAAQK,KAAK,mBAAI;QACrD,EAAE,OAAOA,OAAY;;YACnB,OAAO,KAAKxB,yBAAgBwB,yBAAAA,MAAO+F,OAAO,oBAAI,yBAAyB;gBACrEf,SAAS;gBACTC,SAAS;YACX;QACF;QACAjE,cAAc;QACd+C,qBAAqB,CAACiC,QAAUA,QAAQ;QACxCxH,gBAAgB,mBAAmB;YAAEwG,SAAS;YAAWC,SAAS;QAAM;QACxEtG,YAAY,mBAAmB;YAC7BsH,MAAM;YACNN,IAAIxE,SAASG,GAAG;YAChBgE,MAAMrI,mBAAmBkE;QAC3B;IACF,GAAG;QACDA;QACAyD;QACAnG;QACAb;QACAF;QACAmB;QACAL;QACAG;KACD;IAED,qEAAqE;IACrE,sDAAsD;IACtD,MAAM,CAAC4I,YAAYC,cAAc,GAAG/L,SAElC,CAAC;IACHF,UAAU;QACR,IAAI+I,SAAS;QACb,MAAMmD,kBAAkBlG,MAAME,KAAK,CAACM,MAAM,CACxC,CAACwE;gBACChF,uBACAA,iCAAAA;mBADAA,EAAAA,wBAAAA,MAAMC,MAAM,CAAC+E,QAAQ,qBAArBhF,sBAAuB0E,IAAI,MAAK,iBAChC1E,yBAAAA,MAAMC,MAAM,CAAC+E,QAAQ,sBAArBhF,kCAAAA,uBAAuBkF,SAAS,qBAAhClF,gCAAkCrB,SAAS;;QAE/C,IAAI,CAACuH,gBAAgB9D,MAAM,IAAI,CAAC/F,WAAW;YACzC4J,cAAc,CAAC;YACf;QACF;QACA,KAAKE,QAAQC,GAAG,CACdF,gBAAgBhC,GAAG,CAAC,OAAOc;gBASvBE;YARF,MAAMA,YAAYlF,MAAMC,MAAM,CAAC+E,QAAQ,CAACE,SAAS;YAIjD,MAAMH,SAAS7I,SAAS2D,IAAI,CAC1B,CAACC,OAASA,KAAKC,GAAG,KAAKmF,UAAUvG,SAAS;YAE5C,MAAMwG,kBACJD,4BAAAA,UAAUC,cAAc,YAAxBD,4BACA7J,sBAAsB0J,iBAAAA,SAAU,CAAC,GAAG7E,KAAK,CAAC,EAAE;YAC9C,MAAM+C,WAAW,MAAMxJ,QACrBE,MACEP,WACE4D,WACAX,SAAS,CAAC,EAAE,EACZA,SAAS,CAAC,EAAE,EACZ,YACA6I,UAAUvG,SAAS,EACnB,YAEFjF,MAAM,OAER4E,KAAK,CAAC,IAAM;YACd,MAAM4D,UAAU,SAACe,4BAAAA,SAAUoD,IAAI,mBAAI,EAAE,EAAEnC,GAAG,CAAC,CAACoC;;oBAGxCA;uBAHyD;oBAC3DlC,IAAIkC,YAAYlC,EAAE;oBAClBmC,OAAOhC,gBACL+B,mBAAAA,YAAYE,GAAG,CAAC,8BAAhBF,gBAA2B,CAACnB,yBAAAA,iBAAkB,GAAG,mBAC/CmB,YAAYlC,EAAE;gBAEpB;;YACA,OAAO;gBAACY;gBAAS9C;aAAQ;QAC3B,IACAc,IAAI,CAAC,CAACyD;YACN,IAAI1D,QAAQkD,cAAcS,OAAOC,WAAW,CAACF;QAC/C;QACA,OAAO;YACL1D,SAAS;QACX;IACF,GAAG;QAAC/C;QAAO9D;QAAUc;QAAWX;KAAU;IAC1C;;;;;;;;;;;;;GAaC,GACD,MAAMuK,wBAAwB7M,YAC5B,CAACiL,SAAiBZ;;YAChB4B,0BAAAA;wBAAAA,sBAAAA,UAAU,CAAChB,QAAQ,sBAAnBgB,2BAAAA,oBAAqBnG,IAAI,CAAC,CAACgH,SAAWA,OAAOzC,EAAE,KAAKA,wBAApD4B,yBAAyDO,KAAK,mBAAI;OACpE;QAACP;KAAW;IAEd,MAAMc,iBAAiB/M,YACrB,CAACiL,SAAiB+B;QAChB,MAAMC,MAAMC,MAAMC,OAAO,CAACH,SAASA,QAAQA,SAAS,OAAO;YAACA;SAAM,GAAG,EAAE;QACvE,OAAOC,IACJ9C,GAAG,CAAC,CAACE;gBAAOwC;oBAAAA,yBAAAA,sBAAsB5B,SAAST,OAAOH,gBAAtCwC,yBAA8CrC,OAAOH;WACjE+C,IAAI,CAAC;IACV,GACA;QAACP;KAAsB;IAEzB;;;;;;;;;;;GAWC,GACD,MAAM,CAACQ,UAAUC,YAAY,GAAGnN,SAAwB;IACxD,MAAMoN,eAAerN,QACnB;YAEOmH;eADLgG,YACKhG,gBAAAA,QAAQvB,IAAI,CAAC,CAAC0H,SAAgBA,OAAOxH,GAAG,KAAKqH,qBAA7ChG,gBAA0D,OAC3D;OACN;QAACgG;QAAUhG;KAAQ;IAGrB,2EAA2E;IAC3E,MAAM,CAACoG,QAAQC,UAAU,GAAGvN,SAIlB;IACV,MAAMwN,mBAAmB3N,YACvB,CAACwN,SAAiB;gBA2BYA;YA1B5B,IAAI,CAACA,QAAQ;gBACX,6DAA6D;gBAC7D,MAAM5D,QAAQjM,WAAWyF,KAAK,qBAAqBkG;gBACnD,IAAI,CAACM,MAAMC,OAAO,EAAE;oBAClB,OAAO3G,gBACL,CAAC,sBAAsB,EAAE0G,MAAMjK,KAAK,CAAC,0BAA0B,CAAC,EAChE;wBAAE+J,SAAS;wBAAWC,SAAS;oBAAM;gBAEzC;YACF;YACA,MAAMiE,SAAiC,CAAC;YACxC,KAAK,MAAM3C,WAAWhF,MAAME,KAAK,CAAE;gBACjC,MAAMS,QAAQX,MAAMC,MAAM,CAAC+E,QAAQ;gBACnC,IAAI,CAACrE,OAAO;gBACZ,IAAI4G,QAAQ;wBAGRA;oBAFFI,MAAM,CAAC3C,QAAQ,GAAG5J,oBAChBuF,QACA4G,kBAAAA,OAAOI,MAAM,qBAAbJ,eAAe,CAACvC,QAAQ;gBAE5B,OAAO,IAAIrE,MAAMiH,OAAO,IAAI,MAAM;oBAChCD,MAAM,CAAC3C,QAAQ,GAAGT,OAAO5D,MAAMiH,OAAO;gBACxC;YACF;YACA,kEAAkE;YAClE,8DAA8D;YAC9D,MAAMC,SAASN,SACX/L,iBAAiBwE,QAAOuH,iBAAAA,OAAOI,MAAM,YAAbJ,iBAAiB,CAAC,KAC1C,CAAC;YACLE,UAAU;gBAAErD,EAAE,UAAEmD,0BAAAA,OAAQxH,GAAG,mBAAI;gBAAM4H;gBAAQE;YAAO;QACtD,GACA;QAAC1K;QAAKkG;QAAarD;QAAO/C;KAAgB;IAE5C,MAAM6K,mBAAmB/N,YAAY;QACnC,IAAI,CAACyN,UAAU,CAAC5H,YAAY,CAACvD,WAAW;QACxC,uEAAuE;QACvE,kEAAkE;QAClE,MAAM0L,UAAUtM,oBACduE,OACA9E,qBAAqB8E,OAAOwH,OAAOG,MAAM;QAE3C,MAAME,SAASrM,iBAAiBwE,OAAO+H;QACvC,IAAIrB,OAAOsB,IAAI,CAACH,QAAQzF,MAAM,EAAE;YAC9B,OAAO,KAAKqF,UAAU,CAACQ,OAAUA,OAAO,aAAKA;oBAAMJ;qBAAWI;QAChE;QACA,sEAAsE;QACtE,wEAAwE;QACxE,IAAI;YACF,IAAIT,OAAOpD,EAAE,EAAE;gBACb,kDAAkD;gBAClD,MAAM8D,YAAY3O,IAChByD,WACAX,SAAS,CAAC,EAAE,EACZA,SAAS,CAAC,EAAE,EACZ,YACAuD,SAASG,GAAG,EACZ,WACAyH,OAAOpD,EAAE;gBAEX,MAAMvK,OACJqO,WACA;oBACEP,QAAQI;mBAIL5M,uBAAuB6E,OAAO+H,SAASzO;oBAC1C6O,WAAWzP,UAAU0P,GAAG;oBAE1B;oBACEC,aAAa;wBAAC;wBAAU;wBAAiB;wBAAc;wBAAgB;qBAAY;gBACrF;gBAEF,MAAM3J,gBAAgBkB,SAASG,GAAG;YACpC,OAAO;gBACL,mEAAmE;gBACnE,kEAAkE;gBAClE,oEAAoE;gBACpE,+CAA+C;gBAC/C,MAAMnC,eAAe;oBACnBgB,QAAQ;oBACRD,WAAWiB,SAASG,GAAG;oBACvB4H,QAAQI;gBACV;YACF;QACF,EAAE,OAAOtJ,OAAY;;YACnB,OAAO,KAAKxB,wBAAgBwB,yBAAAA,MAAO+F,OAAO,mBAAI,sBAAsB;gBAClEf,SAAS;gBACTC,SAAS;YACX;QACF;QACA+D,UAAU;QACV,iEAAiE;QACjE,4DAA4D;QAC5D,IAAI,CAACD,OAAOpD,EAAE,EAAE1B,oBAAoB,CAAC+B,QAAUA,QAAQ;QACvDxH,gBAAgBuK,OAAOpD,EAAE,GAAG,iBAAiB,gBAAgB;YAC3DX,SAAS;YACTC,SAAS;QACX;QACAtG,YAAYoK,OAAOpD,EAAE,GAAG,mBAAmB,gBAAgB;YACzDM,MAAM;YACNN,IAAIxE,SAASG,GAAG;YAChBgE,MAAMrI,mBAAmBkE;QAC3B;IACF,GAAG;QACD4H;QACA5H;QACA5C;QACAX;QACA2D;QACApC;QACAc;QACAzB;QACAG;KACD;IACD,MAAMkL,qBAAqBvO,YACzB,CAACwN,SAAgB;YACf,kEAAkE;YAClE,qEAAqE;YACrE,6BAA6B;YAC7B,MAAMgB,cAAc,IAAIC;YACxB,IAAI,CAAC5I,YAAY,CAACvD,WAAW;YAC7B;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OA6BC,GACD,KAAK,MAAMoM,SAASvM,SAAU;gBAC5B,MAAMwM,aAAarN,sBAAsBoN;gBACzC,MAAME,cAAcD,WAAWxI,KAAK,CAACM,MAAM,CACzC,CAACwE;wBACC0D,4BACAA,sCAAAA;2BADAA,EAAAA,6BAAAA,WAAWzI,MAAM,CAAC+E,QAAQ,qBAA1B0D,2BAA4BhE,IAAI,MAAK,eACrCgE,EAAAA,8BAAAA,WAAWzI,MAAM,CAAC+E,QAAQ,sBAA1B0D,uCAAAA,4BAA4BxD,SAAS,qBAArCwD,qCAAuC/J,SAAS,MAAKiB,SAASG,GAAG;;gBAErE,IAAI,CAAC4I,YAAYvG,MAAM,EAAE;gBACzB,IAAIa;gBACJ,IAAI;oBACFA,WAAW,MAAMxJ,QACfE,MACEP,WACE4D,WACAX,SAAS,CAAC,EAAE,EACZA,SAAS,CAAC,EAAE,EACZ,YACAoM,MAAM1I,GAAG,EACT,YAEFnG,MAAM,iBAAiB,kBAAkB2N,OAAOxH,GAAG;gBAGzD,EAAE,eAAM;oBACN,OAAO,KAAK9C,gBACV,CAAC,gBAAgB,EAAEvB,mBAAmB+M,OAAO,2BAA2B,CAAC,GACvE,iEACA,gBACF;wBAAEhF,SAAS;oBAAQ;gBAEvB;gBACA,MAAMmF,OAAO3F,SAASoD,IAAI,CAAC7F,MAAM,CAAC,CAAC8F,cACjCqC,YAAYjI,IAAI,CAAC,CAACsE;4BACDsB;wBAAf,MAAMuC,UAASvC,mBAAAA,YAAYE,GAAG,CAAC,8BAAhBF,gBAA2B,CAACtB,QAAQ;wBACnD,OAAOiC,MAAMC,OAAO,CAAC2B,UACjBA,OAAOC,QAAQ,CAACvB,OAAOxH,GAAG,IAC1B8I,WAAWtB,OAAOxH,GAAG;oBAC3B;gBAEF,IAAI,CAAC6I,KAAKxG,MAAM,EAAE;gBAClB,MAAM2G,aAAaJ,YAAYjI,IAAI,CACjC,CAACsE;wBACC0D,sCAAAA;2BAAAA,EAAAA,6BAAAA,WAAWzI,MAAM,CAAC+E,QAAQ,sBAA1B0D,uCAAAA,2BAA4BxD,SAAS,qBAArCwD,qCAAuCtD,QAAQ,MAAK;;gBAExD,IAAI2D,YAAY;oBACd,OAAO,KAAK9L,gBACV,CAAC,6BAA6B,EAAE2L,KAAKxG,MAAM,CAAC,SAAS,CAAC,GACpD,GAAGwG,KAAKxG,MAAM,KAAK,IAAI,KAAK,IAAI,KAAK,EAAE1G,mBAAmB+M,OAAO,CAAC,CAAC,EACrE;wBAAEhF,SAAS;wBAAWC,SAAS;oBAAM;gBAEzC;gBACA,sEAAsE;gBACtE,sEAAsE;gBACtE,+BAA+B;gBAC/B,IAAK,IAAIsF,QAAQ,GAAGA,QAAQJ,KAAKxG,MAAM,EAAE4G,SAAS,IAAK;oBACrD,MAAMC,QAAQnP,WAAWkD;oBACzB,KAAK,MAAMkM,OAAON,KAAKO,KAAK,CAACH,OAAOA,QAAQ,KAAM;4BAC3BE;wBAArB,MAAMvB,SAAS,cAAMuB,WAAAA,IAAI1C,GAAG,CAAC,qBAAR0C,WAAqB,CAAC;wBAC3C,KAAK,MAAMlE,WAAW2D,YAAa;4BACjC,MAAME,SAASlB,MAAM,CAAC3C,QAAQ;4BAC9B,IAAIiC,MAAMC,OAAO,CAAC2B,SAAS;gCACzBlB,MAAM,CAAC3C,QAAQ,GAAG6D,OAAOrI,MAAM,CAC7B,CAAC4D,KAAeA,OAAOmD,OAAOxH,GAAG;4BAErC,OAAO,IAAI8I,WAAWtB,OAAOxH,GAAG,EAAE;gCAChC,OAAO4H,MAAM,CAAC3C,QAAQ;4BACxB;wBACF;wBACAiE,MAAMG,MAAM,CAACF,IAAIG,GAAG,EAAE;4BACpB1B;2BACGxM,uBAAuBuN,YAAYf,QAAQrO;oBAElD;oBACA,MAAM2P,MAAMK,MAAM;gBACpB;gBACA,sEAAsE;gBACtE,+CAA+C;gBAC/Cf,YAAYgB,GAAG,CAACd,MAAM1I,GAAG;YAC3B;YACA,MAAM1G,UACJE,IACEyD,WACAX,SAAS,CAAC,EAAE,EACZA,SAAS,CAAC,EAAE,EACZ,YACAuD,SAASG,GAAG,EACZ,WACAwH,OAAOxH,GAAG;YAGd2C,oBAAoB,CAAC+B,QAAUA,QAAQ;YACvC,KAAK,MAAM9F,aAAa;gBAACiB,SAASG,GAAG;mBAAKwI;aAAY,CAAE;gBACtD,MAAM7J,gBAAgBC;YACxB;YACA1B,gBAAgB,kBAAkB;gBAAEwG,SAAS;gBAAWC,SAAS;YAAM;QACzE,GACA;QAAC9D;QAAU1D;QAAUc;QAAWX;QAAWqC;QAAiBzB;KAAgB;IAG9E;;;;;;;;;GASC,GACD,MAAMuM,WAAW3R;IACjB,MAAM4R,iBAAiB7J,CAAAA,4BAAAA,SAAUG,GAAG,IAChC;QAAE2J,UAAU9N,2BAA2BgE,SAASG,GAAG;QAAG3D,OAAO;IAAe,IAC5E;IACJ,MAAMuN,YAAY5M,QAAQyM,YAAYC,kBAAkBD,SAASI,GAAG,CAAC,UAAUH;IAC/E,MAAMI,YAAY9M,QAAQyM,YAAYC,kBAAkBD,SAASI,GAAG,CAAC,UAAUH;IAC/E,MAAMK,eAAe/P,YAAY;QAC/B,IAAI,CAACyP,YAAY,EAAC5J,4BAAAA,SAAUG,GAAG,GAAE;QACjC,MAAMgK,UAAU;YAAE3F,IAAIxE,SAASG,GAAG;YAAEgE,MAAMrI,mBAAmBkE;QAAU;QACvE4J,SAASQ,UAAU,CAAC;YAClBN,UAAU9N,2BAA2BmO,QAAQ3F,EAAE;YAC/ChI,OAAO;YACPqJ,OAAOsE,QAAQhG,IAAI,GAAG,CAAC,YAAY,EAAEgG,QAAQhG,IAAI,EAAE,GAAG;YACtDkG,YAAY;gBACV,qEAAqE;gBACrEvH,oBAAoB,CAAC+B,QAAUA,QAAQ;gBACvCrH,YAAY,oBAAoB;oBAAEsH,MAAM;oBAAWN,IAAI2F,QAAQ3F,EAAE;oBAAEL,MAAMgG,QAAQhG,IAAI;gBAAC;YACxF;QACF;IACF,GAAG;QAACyF;QAAU5J;QAAUxC;KAAY;IACpC,MAAM8M,eAAenQ,YAAY;QAC/B,IAAI,CAACyP,YAAY,EAAC5J,4BAAAA,SAAUG,GAAG,GAAE;QACjC,MAAMgE,OAAOrI,mBAAmBkE;QAChC4J,SAASW,UAAU,CAAC;YAClBT,UAAU9N,2BAA2BgE,SAASG,GAAG;YACjD3D,OAAO;YACPqJ,OAAO1B,OAAO,CAAC,OAAO,EAAEA,MAAM,GAAG;WAG7B5B,mBACA;YACE3B,QAAQ;gBACN+F,OAAO;gBACPQ,OAAO;oBAAExG,SAASD;oBAAe8J,QAAQhK,WAAWU,WAAW;gBAAC;YAClE;QACF,IACA,CAAC;IAET,GAAG;QAAC0I;QAAU5J;QAAUuC;QAAkB7B;QAAeF,WAAWU,WAAW;KAAC;IAEhF;;;;;GAKC,GACD,MAAMuJ,oBAAoBpQ,QACxB,IACE1B,sBACE;eACK0H,OAAOiE,GAAG,CAAC,CAACc;;gBACb,MAAMrE,QAAQX,MAAMC,MAAM,CAAC+E,QAAQ;gBACnC,OAAO;oBACLrE,OAAO1F,aAAa+J;oBACpBsF,UAAU,UAAE3J,yBAAAA,MAAOoD,IAAI,mBAAIiB;oBAC3B,wDAAwD;oBACxDU,WAAW,EAAE/E,yBAAAA,MAAO+E,WAAW;oBAC/B6E,MAAM;oBACNC,UAAU;oBACVC,YAAY,CAAC,EAAEC,GAAG,EAAgB;4BAEJA,aAEIA;+BAHhC/J,CAAAA,yBAAAA,MAAO+D,IAAI,MAAK,cACZoC,eAAe9B,UAAS0F,cAAAA,IAAI/C,MAAM,qBAAV+C,WAAY,CAAC1F,QAAQ,KAAK,OAClDrE,QACErF,mBAAmBqF,QAAO+J,eAAAA,IAAI/C,MAAM,qBAAV+C,YAAY,CAAC1F,QAAQ,KAAK,OACpD;;gBACV;YACF;YACA3M,kBACE,CAACkP,uBACC,MAACtO;oBACC0R,WAAU;oBACVC,IAAI;wBAAEC,QAAQ;wBAAQC,YAAY;wBAAUC,gBAAgB;oBAAW;;sCAEvE,KAACpS;4BAAOqS,MAAK;4BAAQC,SAAS,IAAM5D,YAAYE,OAAOxH,GAAG;sCACvD;;sCAEH,KAACpH;4BAAOqS,MAAK;4BAAQC,SAASvD,iBAAiBH;sCAC5C;;sCAEH,KAAC5O;4BACCqS,MAAK;4BACLnF,OAAM;4BACNoF,SAAS3C,mBAAmBf;sCAE3B;;;oBAIP;gBAAE2D,OAAO;YAAI;SAEhB,EACD/K,aAAaF,MAAM,EACnBE,aAAa+B,OAAO,EACpB/B,aAAanC,OAAO,GAExB;QACEiC;QACAD;QACA8G;QACAY;QACAY;QACAnI;KACD;IAGH;;;;;;GAMC,GACD,MAAMgL,kBAAkBlR,QACtB,IACEyM,OAAOC,WAAW,CAChB1G,OAAOiE,GAAG,CAAC,CAACc;YACV,MAAMrE,QAAQX,MAAMC,MAAM,CAAC+E,QAAQ;YACnC,OAAO;gBACL/J,aAAa+J;gBACb,CAAC0F;wBACeA;oBAAd,MAAM3D,SAAQ2D,cAAAA,IAAI/C,MAAM,qBAAV+C,WAAY,CAAC1F,QAAQ;oBACnC,IAAIrE,CAAAA,yBAAAA,MAAO+D,IAAI,MAAK,aAAa,OAAOoC,eAAe9B,SAAS+B,UAAU;oBAC1E,IAAI,OAAOA,UAAU,YAAY,OAAOA,UAAU,WAAW,OAAOA;oBACpE,OAAOpG,QAAQrF,mBAAmBqF,OAAOoG,UAAU,OAAO;gBAC5D;aACD;QACH,KAEJ;QAAC9G;QAAQD;QAAO8G;KAAe;IAEjC,MAAMsE,oBAAoBnR,QACxB,IACEyM,OAAOC,WAAW,CAChB1G,OAAOiE,GAAG,CAAC,CAACc;;gBAAoChF;mBAAxB;gBAAC/E,aAAa+J;yBAAUhF,wBAAAA,MAAMC,MAAM,CAAC+E,QAAQ,qBAArBhF,sBAAuB+D,IAAI,mBAAIiB;aAAQ;aAE3F;QAAC/E;QAAQD;KAAM;IAEjB,MAAMqL,mBAAmBlR,kBAAuB;QAC9CmR,OAAOzP;QACPsF,MAAMC;QACNmK,WAAWJ;QACXnN,SAASoN;IACX;IAEA,qBACE,MAACtT;QACC0T,QAAQ;QACRC,MAAM7T,eAAe,YAAY;YAAE8T,QAAQ;QAAkB;QAC7DC,cAAc;QACdC,cAAc;QACdC,iBAAgB;;0BAEhB,MAAC5S;gBAAM6S,SAAS;;oBACbxP,sBACC,KAACnD;wBAAWsK,SAAQ;wBAAUoC,OAAM;kCAGjC/J,sBAAsB4B;yBAEvB;oBACHxB,SAASkG,MAAM,KAAK,kBACnB,KAACjJ;wBAAWsK,SAAQ;wBAAQoC,OAAM;kCAC/B,kEACC;uCAGJ,MAAC5M;wBACC0R,WAAU;wBACVmB,SAAS;wBACTC,UAAU;wBACVnB,IAAI;4BAAEE,YAAY;4BAAUkB,UAAU;wBAAO;;0CAI7C,KAAC9S;gCACC+S,MAAM;gCACNjB,MAAK;gCACLzE,OAAM;gCACNQ,KAAK,WAAEnH,4BAAAA,SAAUG,GAAG,oBAAI;gCACxBmM,UAAU,CAACC,QAAU1M,cAAc0M,MAAMpH,MAAM,CAACgC,KAAK;gCACrD6D,IAAI;oCAAEJ,UAAU;gCAAI;0CAEnBtO,SAASgI,GAAG,CAAC,CAACpE,qBACb,KAAC9G;wCAAwB+N,OAAOjH,KAAKC,GAAG;kDACrCrE,mBAAmBoE;uCADPA,KAAKC,GAAG;;0CAK3B,KAACpH;gCACCqS,MAAK;gCACLnF,OAAM;gCACNoF,SAASvD;0CAER;;0CAEH,KAAC/O;gCAAOqS,MAAK;gCAAQC,SAAS,IAAMtL,cAAc;0CAC/C;;4BAGF8J,+BACC,KAAClS;gCACCwN,QAAQ0E;+BACH7J,WAAW;gCAAE6F,OAAO,CAAC,YAAY,EAAE/J,mBAAmBkE,WAAW;4BAAC,IAAI,CAAC;gCAC5EqK,YAAY,IAAMvH,oBAAoB,CAAC+B,QAAUA,QAAQ;kCAEzD;4BACHkF,0BACC,KAAChR;gCAAOqS,MAAK;gCAAQC,SAASnB;0CAC3B;iCAED;4BAIHD,aAAcxG,CAAAA,eAAejC,QAAQgB,MAAM,AAAD,kBACzC,KAACzJ;gCAAOqS,MAAK;gCAAQC,SAASf;0CAC3B;iCAED;0CACJ,KAACvR;gCAAOqS,MAAK;gCAAQnF,OAAM;gCAAQoF,SAAS1F;0CACzC;;;;oBAQN3F,yBACC,KAACtH;wBACC8T,OAAOjP,OAAO;wBACdkP,MAAMhJ;wBACN3J,OAAOhC,WAAWyF,KAAK,qBAAqBkG,aAAa3J,KAAK;wBAC9D4S,MAAK;yBAEL;oBACH1M,YAAawB,CAAAA,QAAQgB,MAAM,GAAG,KAAKZ,aAAa,KAAKW,gBAAe,kBACnE;;0CACA,KAACnK;gCACCiI,QAAQE,aAAaF,MAAM;gCAC3BjC,SAASmC,aAAanC,OAAO;gCAC7BuC,SAASD;gCACT4L,UAAU9L,WAAWmM,UAAU;gCAC/BrK,SAAS/B,aAAa+B,OAAO;;0CAE/B,KAAChK;gCACC+J,SAASD;gCACTwK,SAAS;uCAAI3L,WAAW2L,OAAO;uCAAKnB,iBAAiBmB,OAAO;iCAAC;;0CAE/D,KAACpU;gCACCqU,cAAW;gCACXtL,MAAMkK,iBAAiBlK,IAAI;gCAC3BuL,YAAYrB;gCACZsB,SAAStC;gCACTuC,QAAQ,CAACxI,KAAOiD,YAAYjD;gCAC5B,6DAA6D;gCAC7D,iCAAiC;gCACjCyI,UAAU;gCACVC,YAAW;gCACXC,aAAa3M,WAAW2M,WAAW;gCACnCC,qBAAqB5M,WAAW4M,mBAAmB;gCACnDC,WAAW;gCACXC,aACE/K,mBAAmB,mCAAmC;;0CAU1D,KAAClK;gCACCsJ,MAAMC;gCACNG,UAAUC;gCACVuL,UAAU/L,QAAQgB,MAAM;gCACxBf,SAASC;gCACT8L,cAAc1L;gCACd2L,kBAAkBvL;;;yBAGlBlC,yBACF,KAACzG;wBAAWsK,SAAQ;wBAAQoC,OAAM;kCAC/B;yBAED;kCACJ,MAAC5M;wBACC0R,WAAU;wBACVmB,SAAS;wBACTC,UAAU;wBACVnB,IAAI;4BAAEoB,UAAU;wBAAO;;0CAEvB,KAACrT;gCACCqS,MAAK;gCACLvH,SAAQ;gCACRoC,OAAM;gCACNoF,SAASzH;0CAER;;4BAEFtH,SAASkG,MAAM,IAAI,kBAClB,KAACzJ;gCAAOqS,MAAK;gCAAQC,SAAS,IAAMrG,UAAU;wCAAEvF,GAAG;wCAAIC,GAAG;oCAAG;0CAC1D;iCAED;;;;;0BAGR,MAAC1G;gBACC0U,MAAMvQ,QAAQuG;gBACdiK,SAAS,IAAMhK,WAAW;gBAC1BiK,UAAS;gBACTC,SAAS;;kCAET,KAAC1U;kCAAa;;kCACd,MAACD;wBACC8R,IAAI;4BAAE8C,SAAS;4BAAQC,eAAe;4BAAUC,KAAK;wBAAE;;0CAEvD,KAAC1U;gCACCqN,OAAM;gCACNQ,KAAK,WAAEzD,2BAAAA,QAASS,IAAI,oBAAI;gCACxBmI,UAAU,CAACC,QACT5I,WAAW,CAAC0E,OACVA,OAAO,aAAKA;4CAAMlE,MAAMoI,MAAMpH,MAAM,CAACgC,KAAK;6CAAKkB;gCAGnD+C,MAAK;gCACL6C,SAAS;gCACTjD,IAAI;oCAAEkD,IAAI;gCAAE;gCACZC,YAAW;;0CAEb,KAAC7U;gCACCqN,OAAM;gCACNQ,KAAK,WAAEzD,2BAAAA,QAASrD,MAAM,oBAAI;gCAC1BiM,UAAU,CAACC,QACT5I,WAAW,CAAC0E,OACVA,OAAO,aAAKA;4CAAMhI,QAAQkM,MAAMpH,MAAM,CAACgC,KAAK;6CAAKkB;gCAGrD+C,MAAK;gCACL+C,YACE/J,eAAe5B,MAAM,GACjB,CAAC,SAAS,EAAE4B,eACTE,GAAG,CAAC,CAACC,QAAUA,MAAMJ,IAAI,EACzBoD,IAAI,CAAC,OAAO,GACf;;;;kCAIV,MAACtO;;0CACC,KAACF;gCAAOsS,SAAS,IAAM1H,WAAW;0CAAQ;;0CAC1C,KAAC5K;gCACC8K,SAAQ;gCACRoC,OAAM;gCACNmI,UACE,CAAClR,cACD,EAACwG,2BAAAA,QAASS,IAAI,CAACzB,IAAI,OACnB2B,cAAc7B,MAAM,KAAK;gCAE3B6I,SAAS5G;0CAER;;;;;;0BASP,KAACvJ;gBACCyM,QAAQD;gBACRtH,OAAOA;gBACPiO,kBAAkBrH;gBAClB2G,SAAS,IAAMlG,YAAY;gBAC3B,mEAAmE;gBACnE,gEAAgE;gBAChE,wBAAwB;gBACxB6G,QAAQ;oBACN,MAAM3G,SAASD;oBACfD,YAAY;oBACZ,IAAIE,QAAQG,iBAAiBH;gBAC/B;;0BAEF,MAAC3O;gBACC0U,MAAMvQ,QAAQyK;gBACd+F,SAAS,IAAM9F,UAAU;gBACzB+F,UAAS;gBACTC,SAAS;;kCAET,KAAC1U;kCAAayO,CAAAA,0BAAAA,OAAQpD,EAAE,IAAG,gBAAgB;;kCAC3C,KAACtL;wBACC8R,IAAI;4BAAE8C,SAAS;4BAAQC,eAAe;4BAAUC,KAAK;wBAAE;kCAEtD3N,OAAOiE,GAAG,CAAC,CAACc,SAASmJ;;gCA6DSxN,2BAAAA;4BA5D7B,MAAMA,QAAQX,MAAMC,MAAM,CAAC+E,QAAQ;4BACnC,IAAI,CAACrE,OAAO,OAAO;4BACnB,MAAMoG,gBAAQS,0BAAAA,OAAQG,MAAM,CAAC3C,QAAQ,mBAAI;4BACzC,MAAMvG,QAAQ+I,0BAAAA,OAAQK,MAAM,CAAC7C,QAAQ;4BACrC,MAAMuB,QAAQ5F,MAAMsE,QAAQ,GAAG,GAAGtE,MAAMoD,IAAI,CAAC,EAAE,CAAC,GAAGpD,MAAMoD,IAAI;4BAC7D,MAAMqK,WAAW,CAACC,YAChB5G,UAAU,CAACQ,OACTA,OACI,aACKA;wCACHN,QAAQ,aAAKM,KAAKN,MAAM;4CAAE,CAAC3C,QAAQ,EAAEqJ;;wCACrCxG,QAAQ,aAAKI,KAAKJ,MAAM;4CAAE,CAAC7C,QAAQ,EAAE;;yCAEvCiD;4BAER,MAAMqG,SAAS;gCACb/H;gCACAQ;gCACAiE,MAAM;gCACN6C,WAAWM,UAAU;gCACrB1P,OAAO1B,QAAQ0B;gCACfsP,YAAYtP,SAASkC,MAAM+E,WAAW;gCACtCkF,IAAIuD,UAAU,IAAI;oCAAEL,IAAI;gCAAE,IAAItQ;gCAC9B0O,UAAU,CAACC,QACTiC,SAASjC,MAAMpH,MAAM,CAACgC,KAAK;4BAC/B;4BACA,6DAA6D;4BAC7D,yDAAyD;4BACzD,kDAAkD;4BAClD,MAAMwH,kBAAkB5W,mBAAmBgJ,MAAM6N,UAAU;4BAC3D,IAAID,mCAAAA,gBAAiBE,KAAK,EAAE;gCAC1B,MAAMC,cAAcH,gBAAgBE,KAAK;gCACzC,qBACE,MAACxV;oCAAoB2R,IAAIuD,UAAU,IAAI;wCAAEL,IAAI;oCAAE,IAAItQ;;sDACjD,KAACkR;4CACC3H,OAAOA;4CACPR,OAAO+H,OAAO/H,KAAK;4CACnB2F,UAAU,CAACyC,OAASP,SAAS7J,OAAOoK,eAAAA,OAAQ;;wCAE5ClQ,SAASkC,MAAM+E,WAAW,iBAC1B,KAACvM;4CACCsK,SAAQ;4CACRoC,OAAOpH,QAAQ,UAAU;sDAExBA,SAASkC,MAAM+E,WAAW;6CAE3B;;mCAbMV;4BAgBhB;4BACA,qCAAqC;4BACrC,IAAIrE,MAAM+D,IAAI,KAAK,QAAQ;gCACzB,qBACE,MAACxL,wBAA4BoV;oCAAQrC,MAAM;;sDACzC,KAACjT;4CAAS+N,OAAM;sDAAI;;sDACpB,KAAC/N;4CAAS+N,OAAM;sDAAQ;;sDACxB,KAAC/N;4CAAS+N,OAAM;sDAAS;;;oCAHX/B;4BAMpB;4BACA,IAAIrE,MAAM+D,IAAI,KAAK,YAAU/D,oBAAAA,MAAMiO,UAAU,sBAAhBjO,4BAAAA,kBAAkBuB,OAAO,qBAAzBvB,0BAA2ByB,MAAM,GAAE;gCAC9D,qBACE,MAAClJ,wBAA4BoV;oCAAQrC,MAAM;;sDACzC,KAACjT;4CAAS+N,OAAM;sDAAI;;wCACnBpG,MAAMiO,UAAU,CAAC1M,OAAO,CAACgC,GAAG,CAAC,CAAC2C,uBAC7B,KAAC7N;gDAAsB+N,OAAOF;0DAC3BA;+CADYA;;oCAHH7B;4BASpB;4BACA,IAAIrE,MAAM+D,IAAI,KAAK,aAAa;oCACdsB;oCACSrF;gCADzB,MAAMuB,WAAU8D,sBAAAA,UAAU,CAAChB,QAAQ,YAAnBgB,sBAAuB,EAAE;gCACzC,MAAM6I,WAAW9R,SAAQ4D,mBAAAA,MAAMuE,SAAS,qBAAfvE,iBAAiBkO,QAAQ;gCAClD,MAAMC,cAAc/H,MACjBgI,KAAK,CAAC,KACN7K,GAAG,CAAC,CAAC8K,OAASA,KAAK1M,IAAI,IACvB9B,MAAM,CAACzD;gCACV,qBACE,MAAC7D,wBAEKoV;oCACJrC,MAAM;oCACNlF,OAAO8H,WAAWC,cAAc/H;oCAChCkI,WAAW;wCACThD,QAAQ4C,WACJ;4CACEA,UAAU;4CACV3C,UAAU,CAACC,QACTiC,SACE,AAACjC,MAAMpH,MAAM,CAACgC,KAAK,CAAcI,IAAI,CAAC;wCAE5C,IACA3J;oCACN;;wCAECqR,WAAW,qBAAO,KAAC7V;4CAAS+N,OAAM;sDAAI;;wCACtC7E,QAAQgC,GAAG,CAAC,CAAC2C,uBACZ,KAAC7N;gDAAyB+N,OAAOF,OAAOzC,EAAE;0DACvCyC,OAAON,KAAK;+CADAM,OAAOzC,EAAE;;oCAlBrBY;4BAwBX;4BACA,IACErE,MAAM+D,IAAI,KAAK,WACf/D,MAAM+D,IAAI,KAAK,WACf/D,MAAM+D,IAAI,KAAK,SACf;gCACA,qBAAO,KAACxL,wBAA4BoV;oCAAQ5J,MAAK;oCAA1BM;4BACzB;4BACA,IAAIrE,MAAM+D,IAAI,KAAK,aAAa;gCAC9B,qBACE,KAACxL,wBAEKoV;oCACJ5J,MAAK;oCACLuK,WAAW;wCAAEC,YAAY;4CAAEC,QAAQ;wCAAK;oCAAE;oCAHrCnK;4BAMX;4BACA,IAAIrE,MAAM+D,IAAI,KAAK,eAAe;gCAChC,qBACE,KAACxL,wBAEKoV;oCACJP,YAAYtP,SAASkC,MAAM+E,WAAW,IAAI;oCAFrCV;4BAKX;4BACA,IAAIrE,MAAM+D,IAAI,KAAK,UAAU;gCAC3B,qBACE,KAACxL,wBAEKoV;oCACJP,YACEtP,SAASkC,MAAM+E,WAAW,IAAI;oCAH3BV;4BAOX;4BACA,qBAAO,KAAC9L,wBAA4BoV,SAAbtJ;wBACzB;;kCAEF,MAACnM;;0CACC,KAACF;gCAAOsS,SAAS,IAAMxD,UAAU;0CAAQ;;0CACzC,KAAC9O;gCACC8K,SAAQ;gCACRoC,OAAM;gCACNoF,SAASnD;0CAERN,CAAAA,0BAAAA,OAAQpD,EAAE,IAAG,SAAS;;;;;;0BAI7B,MAACxL;gBACC0U,MAAMvQ,QAAQ4H;gBACd4I,SAAS,IAAM3I,UAAU;gBACzB4I,UAAS;gBACTC,SAAS;;kCAET,KAAC1U;kCAAa;;kCACd,MAACD;wBACC8R,IAAI;4BAAE8C,SAAS;4BAAQC,eAAe;4BAAUC,KAAK;wBAAE;;0CAEvD,KAACzU;gCAAWsK,SAAQ;gCAAQoC,OAAM;gCAAiB+E,IAAI;oCAAEkD,IAAI;gCAAE;0CAC5D,4DACC;;4BAEF;gCAAC;gCAAK;6BAAI,CAAW5J,GAAG,CAAC,CAACkL;;qDAC1B,KAAClW;oCAEC+S,MAAM;oCACNjB,MAAK;oCACLzE,OAAO6I,SAAS,MAAM,qBAAqB;oCAC3CrI,KAAK,UAAEpC,0BAAAA,MAAQ,CAACyK,KAAK,mBAAI;oCACzBlD,UAAU,CAACC,QACTvH,UAAU,CAACqD,OACTA,OAAO,aAAKA;gDAAM,CAACmH,KAAK,EAAEjD,MAAMpH,MAAM,CAACgC,KAAK;iDAAKkB;8CAIpD/L,SAASgI,GAAG,CAAC,CAACpE,qBACb,KAAC9G;4CAAwB+N,OAAOjH,KAAKC,GAAG;sDACrCrE,mBAAmBoE;2CADPA,KAAKC,GAAG;mCAZpBqP;;;;kCAmBX,MAACvW;;0CACC,KAACF;gCAAOsS,SAAS,IAAMrG,UAAU;0CAAQ;;0CACzC,KAACjM;gCACC8K,SAAQ;gCACRoC,OAAM;gCACNmI,UACE,CAAClR,cAAc,EAAC6H,0BAAAA,OAAQtF,CAAC,KAAI,EAACsF,0BAAAA,OAAQrF,CAAC,KAAIqF,OAAOtF,CAAC,KAAKsF,OAAOrF,CAAC;gCAElE2L,SAASpG;0CAER;;;;;;0BAIP,KAAChK;gBACCsB,QAAQA;gBACRG,KAAK,EAAEA,gBAAAA,QAASkB;gBAChBuM,SAASrK,cAAcE,WAAWA,WAAW;gBAC7C1D,UAAUA;gBACV,kEAAkE;gBAClE,mEAAmE;gBACnE,mDAAmD;gBACnDmH,aAAaA;gBACbgM,eAAenQ;gBACfoQ,gBAAgBtQ,mBAAmB;gBACnCuO,SAAS,IAAM5N,cAAc;;;;AAIrC;AACA3D,iBAAiBsI,WAAW,GAAG;AAE/B,eAAetI,iBAAgB"}
1
+ {"version":3,"sources":["../../../../../../../libs/plugins/data/src/lib/components/host-datasets-card.component.tsx"],"sourcesContent":["/**\n * @license\n * Copyright 2026 Aglyn LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n'use client'\n\nimport { TransferResumeImport } from '@aglyn/aglyn/app-utils/transfer-resume-import'\nimport {\n type AglynOrgBilling,\n checkDatasetQuota,\n checkEntitlement,\n checkQuota,\n getCustomFieldType,\n pluginDocsHelp,\n useTransferLauncher,\n} from '@aglyn/aglyn'\nimport { CardDisplay, useConfirmationContext } from '@aglyn/shared-ui-jsx'\nimport ListFilterChips from '@aglyn/shared-ui-jsx/components/list-filter-chips.component'\nimport { ListPagination } from '@aglyn/shared-ui-jsx/components/list-pagination.component'\nimport ListQueryNotices, {\n listQueryRefusals,\n} from '@aglyn/shared-ui-jsx/components/list-query-notices.component'\nimport {\n ListTable,\n listActionsColumn,\n} from '@aglyn/shared-ui-jsx/components/list-table.component'\nimport QuotaReadoutComponent from '@aglyn/shared-ui-jsx/components/quota-readout.component'\nimport { listFilterGridColumns } from '@aglyn/shared-ui-jsx/const/list-grid-filter'\nimport { useListGridFilter } from '@aglyn/shared-ui-jsx/hooks/use-list-grid-filter'\nimport { useSnackbar } from '@aglyn/shared-ui-snackstack'\nimport { Timestamp } from '@aglyn/shared-util-timestamp'\nimport {\n Button,\n Dialog,\n DialogActions,\n DialogContent,\n DialogTitle,\n MenuItem,\n Stack,\n TextField,\n Typography,\n} from '@mui/material'\nimport {\n collection,\n deleteDoc,\n deleteField,\n doc,\n getCountFromServer,\n getDocs,\n limit,\n query,\n where,\n setDoc,\n writeBatch,\n} from 'firebase/firestore'\nimport { useCallback, useEffect, useMemo, useState } from 'react'\nimport { useListColumnSort } from '@aglyn/shared-ui-jsx/hooks/use-list-column-sort'\nimport {\n useFirestore,\n useFirestoreCollection,\n useHostActivityLogger,\n useOrgDataScope,\n usePagedCollection,\n useScopeTokens,\n useUser,\n} from '@aglyn/tenant-feature-instance'\nimport { listQueryConstraints } from '@aglyn/tenant-feature-instance/hooks/use-list-query'\nimport { authorizedFetch } from '@aglyn/shared-util-http/authorized-token'\nimport { DatasetSchemaDialog } from './dataset-schema-dialog.component'\nimport { DatasetRecordDialog } from './dataset-record-dialog.component'\nimport {\n datasetRecordFilter,\n planRecordQuery,\n recordColumn,\n} from './dataset-record-filter'\nimport { coerceDocumentValues, datasetIntegrityUpdate, datasetValueToInput, effectiveDatasetModel, formatDatasetValue, modelFromFieldEntries, validateDocument } from '../model/dataset-models'\nimport { fillRecordAddresses } from '../record-pages/record-pages'\nimport { planReferenceFixups, referencingFieldIds, restrictedDeleteMessage } from '../model/dataset-record-delete-plan'\nimport { datasetDisplayName, parseDatasetFieldEntries } from '../model/datasets'\nimport { datasetTransferResourceKey } from '../transfer/dataset-transfer-key'\n\nexport interface HostDatasetsCardProps {\n /** Host context: resolves the owning org and logs host activity. */\n hostId?: string\n /**\n * Direct org scope (AGL-239): the org Data page renders the editor\n * without any host context. Wins over `hostId` resolution when set.\n */\n orgId?: string\n /**\n * The resolved entitlement source (org billing doc). Passed in by both\n * callers (the plugin Data page via the shell, the org Data page via its\n * own resolver) so this relocated card runs entitlement/quota checks\n * without console-app org/session hooks (AGL-395).\n */\n org?: Partial<AglynOrgBilling>\n}\n\n/**\n * The sentence that says who a NEW dataset is shared with, for the card and\n * for the site Data page's banner above it.\n *\n * `siteOnly` is true only on a site's Data page in an org whose Default\n * sharing is \"Only the site they were created in\". Everywhere else a new\n * dataset starts on All sites: the org Data page has no site to limit it to.\n */\n/** The records walk serves no header order: every header sorts the page. */\nconst NO_QUERY_SORTS: never[] = []\n\nexport function newDatasetSharingNote(siteOnly: boolean): string {\n return siteOnly\n ? 'Datasets belong to your organization. Your default sharing starts a ' +\n 'new one on this site only — use Schema to share it with more.'\n : 'Datasets belong to your organization. A new one is shared with ' +\n 'every site — use Schema to narrow that.'\n}\n\n/**\n * Datasets editor (AGL-102): org-shared document collections at\n * `orgs/{orgId}/datasets` (AGL-237/239) with a `records` subcollection,\n * consumed by repeatable components (AGL-103) via `{{item.field}}`.\n * Starter+ (`data-store` flag) with per-plan dataset and record caps —\n * dark-launch rule as everywhere (no plan, no gate). The host path is\n * the pre-migration fallback for hosts not yet org-wired.\n */\nexport function HostDatasetsCard(props: HostDatasetsCardProps) {\n const { hostId } = props\n // `dataScope` is null until the async org lookup settles (AGL-1061), and\n // for a host with no owning org — there is no host fallback to act on\n // any more (AGL-1050), so every path built from it is guarded rather\n // than redirected.\n const { scope: dataScope, orgId } = useOrgDataScope({\n hostId,\n orgId: props.orgId,\n })\n // Scoped sharing (AGL-1044). Required, not cosmetic: under the AGL-1041\n // rules a scoped member's UNFILTERED list is rejected outright —\n // Firestore fails the whole query if any candidate would fail — so\n // without this the Data page errors rather than showing fewer rows.\n // Org-wide members get no filter: they read everything, and adding one\n // would hide any dataset the AGL-1040 backfill missed.\n const {\n tokens: scopeTokens,\n orgWide: viewerOrgWide,\n loaded: scopeLoaded,\n } = useScopeTokens(orgId)\n // Every dataset this card can now reach is an org dataset, and org\n // datasets are all scoped (AGL-1041) — so the filter turns purely on\n // whether the VIEWER is org-wide. It used to also ask whether an org had\n // resolved, for the sake of unscoped rows on the host path.\n const needsScope = !viewerOrgWide\n // Two answers must be in before listing: the org path (AGL-1061) and the\n // viewer's scope tokens (AGL-1047). `useScopeTokens` reports org-wide\n // while loading, so without `scopeLoaded` a scoped collaborator's first\n // render sends an UNFILTERED list that the AGL-1041 rules deny per\n // document. It recovers on the next render, which is exactly what makes\n // it easy to miss: the page looks right and logs a denial every mount.\n const scopeReady = Boolean(dataScope) && scopeLoaded\n const firestore = useFirestore()\n const { enqueueSnackbar } = useSnackbar()\n const { confirm } = useConfirmationContext()\n const { org } = props\n const logActivity = useHostActivityLogger(hostId)\n const { data: user } = useUser()\n /**\n * The site a dataset created here is created FROM, or undefined on the\n * organization Data page.\n *\n * `/api/orgs/datasets` stamps a new dataset with the org's Default sharing,\n * and that setting can only narrow to a site the request names — so a\n * create that names none lands on All sites whatever the org chose. The\n * explicit `orgId` is the org Data page's own scope and already wins over\n * `hostId` when the org is resolved, so it wins here too: a create made\n * there names no site, even if a caller hands the card both.\n */\n const createdFromHostId = props.orgId ? undefined : hostId || undefined\n const createdFrom = useMemo(\n () => (createdFromHostId ? { hostId: createdFromHostId } : {}),\n [createdFromHostId],\n )\n /**\n * Whether a dataset created here starts on this site alone: the org chose\n * \"Only the site they were created in\" and there is a site to limit it to.\n * The caption reads it so it never promises All sites to a create that\n * will not get it.\n */\n const createsSiteOnly =\n Boolean(createdFromHostId) &&\n (org as { defaultResourceScope?: 'org' | 'host' } | undefined)\n ?.defaultResourceScope === 'host'\n\n // Creates go through the console API (AGL-473): rules deny client-side\n // `create` on org datasets/records so quotas are server-enforced.\n // Updates/deletes stay client-direct (they don't consume quota). The\n // legacy host scope (no org resolved) keeps the old client writes.\n const callDatasetApi = useCallback(\n async (payload: Record<string, unknown>) => {\n const response = await authorizedFetch(user, '/api/orgs/datasets', {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({ orgId, ...payload }),\n })\n const result = await response.json().catch(() => ({}))\n if (!response.ok) {\n throw new Error(result?.error ?? 'Dataset operation failed')\n }\n return result\n },\n [user, orgId],\n )\n\n /**\n * Refresh the live pages showing a dataset after a write the BROWSER made\n * (AGL-3113).\n *\n * Record edits and deletes are client-direct — they consume no quota, so\n * AGL-473 left them out of the server leg — which also left them with\n * nothing to announce from. They make a page listing the rows exactly as\n * stale as a create does, so they take the same trip the create already\n * takes, through the route that already holds the org membership check.\n *\n * BEST EFFORT. The record is stored by the time this runs, and the pages\n * catch up on their own window regardless; a refused cache must never be\n * shown to somebody as a refused save.\n */\n const announceRecords = useCallback(\n async (datasetId: string) => {\n try {\n await callDatasetApi({ action: 'announce-records', datasetId })\n } catch (error) {\n console.error(error)\n }\n },\n [callDatasetApi],\n )\n\n const {\n data: datasetDocs,\n status: datasetsStatus,\n /**\n * The dataset rows are unconfirmed by the server (AGL-1358). The schema\n * dialog is seeded from one of them and writes the whole `model` plus\n * `visibleTo` back, so the freshness verdict belongs to THIS listener —\n * the dialog has none of its own, which is why it is handed down rather\n * than recomputed there.\n */\n fromCache: datasetsFromCache,\n } = useFirestoreCollection<any>(\n () =>\n // `scopeReady` already implies a non-null `dataScope`; testing it\n // directly is what lets the compiler see that too.\n dataScope && scopeReady\n ? query(\n collection(firestore, dataScope[0], dataScope[1], 'datasets'),\n ...(needsScope\n ? [where('visibleTo', 'array-contains-any', scopeTokens)]\n : []),\n limit(100),\n )\n : null,\n [firestore, dataScope, needsScope, scopeTokens, scopeReady],\n { idField: '$id' },\n )\n const datasets = useMemo(\n () =>\n [...(datasetDocs ?? [])].sort((a, b) =>\n datasetDisplayName(a).localeCompare(datasetDisplayName(b)),\n ),\n [datasetDocs],\n )\n const [selectedId, setSelectedId] = useState<string | null>(null)\n const [schemaOpen, setSchemaOpen] = useState(false)\n const selected =\n datasets.find((item) => item.$id === selectedId) ?? datasets[0]\n // Typed model (AGL-179): drives headers, cell rendering, and the\n // document form; v1 datasets get a derived all-text model.\n const model = useMemo(\n () => effectiveDatasetModel(selected ?? {}),\n [selected],\n )\n const fields: string[] = useMemo(() => model.order, [model])\n // The records grid's Filters panel, from the dataset's own schema.\n const recordFilter = useMemo(() => datasetRecordFilter(model), [model])\n\n // Guarded on BOTH the scope and a real selection (AGL-1440): with no\n // datasets, `selected` never resolves, and `datasets/-none-/records` is not\n // an empty read for everyone — the AGL-1044 scoped-sharing rules deny it\n // outright for a scoped collaborator, and a permanently denied listen is\n // reopened forever by the refusal loop.\n /**\n * The records table PAGES (AGL-2501). It used to be `limit(500)` with no\n * `orderBy`, every row rendered at once and no control anywhere.\n *\n * That was wrong twice. Five hundred documents were read and billed on\n * every mount of a card nobody had scrolled — and past five hundred the\n * remaining rows were not merely unrendered, they were UNREACHABLE, because\n * nothing showed them and nothing asked for more. Firestore answers an\n * unordered limit in document-id order over auto-ids, so which five hundred\n * a reader got was arbitrary and could differ between two loads of the same\n * dataset; `sortDatasetRecords` then sorted that sample by `order`, which\n * made the table look ordered while being a sample. The export leg\n * (AGL-2335) fixed exactly this shape for the file and left the table.\n *\n * ## Why the walk orders on the document id, and not on a field\n *\n * The usual fix is `orderBy` on the field the rows are sorted by. It cannot\n * be used here: `orderBy` matches only documents that HAVE the field, so\n * ordering on one that any writer omits does not mis-order the list, it\n * hides rows from it — a worse failure than the one being fixed, and a\n * silent one. Every candidate on this collection is omitted by some writer:\n *\n * * `order` — set by `/api/orgs/datasets` and by `POST /v1/datasets/{id}\n * /records`, and NOT by the tenant form-submit leg or by the workflow\n * `appendDataset`/`updateDataset` actions, which write `values` and\n * `createdAt` only. Ordering on it would drop every row a public form or\n * an automation ever produced — the rows a lead dataset is mostly made\n * of.\n * * `createdAt` — written by all four of those, and NOT by a site import:\n * `IMPORTABLE_FIELDS.records` is `['values', 'order']`, so a restored\n * record carries no `createdAt` at all.\n * * `updatedAt` — the mirror image: the import stamps it, the form and\n * automation legs do not.\n *\n * A document's NAME is not a field and cannot be absent, so ordering on it\n * drops nothing and the walk is total: every record is reachable by paging,\n * which is the property the old query lacked. It is not insertion order —\n * ids are random — so the rows are not claimed to be in one. What they are\n * is stable, complete, and the same on every load.\n *\n * `sortDatasetRecords` is deliberately NOT applied to the page. Re-sorting a\n * window of an id-ordered walk by `order` is the same lie the old code told:\n * rows would run in one order within a page and another across pages.\n * For the same reason a header sorts THIS PAGE only, and says so\n * (AGL-3680, `recordColumnSort` below): no stored field could serve it.\n *\n * ## Filtering: every clause and the search word are on the query\n *\n * The grid's Filters panel and quick search are predicates on this same\n * walk (AGL-3321), planned by `planRecordQuery` (`./dataset-record-filter`,\n * over the shared `planListQuery`): equalities ask the record's\n * `filterValues`, and one word-level clause — a text `contains`, a list\n * member, or the search word — asks its `filterKeys`. Firestore's\n * automatic single-field indexes merge them under the same document-name\n * order, so every filter pages through every matching record exactly as\n * the plain walk pages through all of them, with no composite index and\n * no index deploy.\n *\n * Nothing is matched over the rows already loaded. What one query cannot\n * hold is not offered (ranges, negations, empty checks) or is refused by\n * name above the table (a second `contains`, a `contains` beside the\n * search), and a many-word `contains` or search says it asked the first\n * word.\n */\n const gridFilter = useListGridFilter({ selectFields: recordFilter.selectFields })\n // A clause on a field this dataset does not have (the reader switched\n // datasets) narrows nothing and is not shown.\n const recordClauses = useMemo(\n () =>\n gridFilter.clauses.filter((clause) =>\n recordFilter.fields.some((field) => field.column === clause.field),\n ),\n [gridFilter.clauses, recordFilter.fields],\n )\n const recordPlan = useMemo(\n () => planRecordQuery(model, recordFilter, recordClauses, gridFilter.searchWords),\n [model, recordFilter, recordClauses, gridFilter.searchWords],\n )\n // The query's identity: a new plan is a new walk, from page one.\n const recordPlanKey = JSON.stringify({\n filters: recordPlan.plan.filters,\n orderBy: recordPlan.plan.orderBy,\n })\n const {\n rows: records,\n hasMore: hasMoreRecords,\n page: recordPage,\n setPage: setRecordPage,\n pageSize: recordPageSize,\n setPageSize: setRecordPageSize,\n } = usePagedCollection<any>(\n (pageLimit) =>\n dataScope && selected?.$id\n ? query(\n collection(\n firestore,\n dataScope[0],\n dataScope[1],\n 'datasets',\n selected.$id,\n 'records',\n ),\n ...listQueryConstraints(recordPlan.plan),\n limit(pageLimit),\n )\n : null,\n [firestore, dataScope, selected?.$id, recordPlanKey],\n { idField: '$id' },\n )\n const recordRefusals = useMemo(\n () =>\n listQueryRefusals(recordPlan.refused, {\n fields: recordFilter.fields,\n headers: recordFilter.headers,\n options: recordFilter.options,\n }),\n [recordPlan.refused, recordFilter],\n )\n const filteringRecords =\n recordClauses.length > 0 || gridFilter.searchWords.some((word) => word.trim())\n /**\n * The two HEAD-COUNTS on this card are server aggregates, not the lengths\n * of the two capped listeners above (AGL-1716, the AGL-1706 shape).\n *\n * Both listeners are capped correctly — 100 datasets in a picker, 500 rows\n * in a table, nobody needs more streamed in. What neither may do is answer\n * \"how many does this org have\", and both did:\n *\n * * `records.length` saturated at 500 and was handed to\n * `checkQuota(org, 'recordsPerDataset', …)`. The bands are 1,000 /\n * 10,000 / 100,000 / 500,000 / 1,000,000, so on EVERY paid plan the\n * check read 500-against-thousands and could never refuse. Worse, the\n * importer computed its room as `limit − records.length`, so an\n * understated count *inflated* the slots it offered.\n * * `datasets.length` saturated at 100 and fed `checkDatasetQuota`, whose\n * bands run to 250 / 500 / 2,000 above that window.\n *\n * `api/orgs/datasets` — the route that actually enforces both — counts with\n * `collection('datasets').count()` and `collection('records').count()` on\n * these exact paths, so this card was offering headroom the API would then\n * refuse. It now asks the same question the same way, and the console\n * billing page and the staff org page already read the dataset count with\n * this identical unscoped aggregate.\n *\n * THE LISTS KEEP THEIR CAPS. The list and the count are different\n * questions; only the count moved. A one-shot goes stale where a listener\n * refreshed for free, so both are re-read after any mutation that can move\n * them — the epochs below.\n *\n * No counting RULE moves: `checkQuota` and `checkDatasetQuota` are\n * untouched entitlement inputs, and nothing here is metered by\n * `report-usage` (it samples record counts server-side for storage, on its\n * own read). Only this card's inputs stopped being saturated.\n */\n const [datasetCountEpoch, setDatasetCountEpoch] = useState(0)\n const [recordCountEpoch, setRecordCountEpoch] = useState(0)\n const [serverDatasetCount, setServerDatasetCount] = useState<number | null>(\n null,\n )\n // TAGGED with the dataset it describes. A bare number would have to be\n // cleared when the selection changes, and clearing state from inside the\n // effect that fills it is a render loop waiting for one unstable dep;\n // tagging answers \"whose count is this?\" without writing state on render.\n const [serverRecordCount, setServerRecordCount] = useState<{\n datasetId: string\n count: number\n } | null>(null)\n useEffect(() => {\n if (!dataScope) return\n let active = true\n // Unscoped, exactly like `api/orgs/datasets` and the billing page: the\n // quota is about the ORG's datasets, not the subset this collaborator\n // can see. A scoped collaborator whom AGL-1044 denies the read falls\n // through to the catch and keeps the visible-rows lower bound.\n void getCountFromServer(\n collection(firestore, dataScope[0], dataScope[1], 'datasets'),\n )\n .then((snapshot) => {\n if (active) setServerDatasetCount(snapshot.data().count)\n })\n .catch(() => {\n // Falls back to the listener length below — a LOWER bound, and this\n // card's prior behaviour. Deliberately not 0: `checkDatasetQuota`\n // answers from whatever it is handed, and 0 used is a confident\n // wrong number in the flattering direction.\n })\n return () => {\n active = false\n }\n }, [firestore, dataScope, datasetCountEpoch])\n // The dataset the counts below belong to. Distinct from `selectedId`\n // above, which is the PICKER value and is null until the user chooses.\n const countedDatasetId: string | undefined = selected?.$id\n useEffect(() => {\n if (!dataScope || !countedDatasetId) return\n let active = true\n void getCountFromServer(\n collection(\n firestore,\n dataScope[0],\n dataScope[1],\n 'datasets',\n countedDatasetId,\n 'records',\n ),\n )\n .then((snapshot) => {\n if (active) {\n setServerRecordCount({\n datasetId: countedDatasetId,\n count: snapshot.data().count,\n })\n }\n })\n .catch(() => {\n // Same fallback, same reason as above.\n })\n return () => {\n active = false\n }\n }, [firestore, dataScope, countedDatasetId, recordCountEpoch])\n // Pending, denied, or answered about the PREVIOUS selection, the loaded\n // rows stand in. They can only UNDERSTATE (same collections, capped),\n // never overstate, so nothing these figures gate fires on a count larger\n // than the truth. Since AGL-2501 the record fallback is one PAGE, so it\n // understates by more — which moves it further in the safe direction and\n // changes nothing about which way it can be wrong.\n const datasetCount = serverDatasetCount ?? datasets.length\n const recordCount =\n serverRecordCount && serverRecordCount.datasetId === countedDatasetId\n ? serverRecordCount.count\n : records.length\n\n // --- Create dataset -----------------------------------------------------\n const [creator, setCreator] = useState<{\n name: string\n fields: string\n } | null>(null)\n const handleOpenCreator = useCallback(() => {\n if (!checkEntitlement(org, 'dataStore')) {\n return enqueueSnackbar(\n 'Datasets require a Starter plan or higher — see Billing',\n { variant: 'warning', persist: false },\n )\n }\n // Addon-aware quota (AGL-132): purchased extra datasets raise the\n // limit up to the plan's hard max; beyond that only an upgrade helps.\n // The ORG's datasets, not the picker's window (AGL-1716).\n const quota = checkDatasetQuota(org as any, datasetCount)\n if (!quota.allowed) {\n return enqueueSnackbar(\n quota.upgradeRequired\n ? `Dataset limit reached (${quota.limit}) — upgrade in Billing`\n : `Dataset limit reached (${quota.limit}) — add extra datasets ` +\n `for $${quota.addonPriceUsd}/mo each or upgrade in Billing`,\n { variant: 'warning', persist: false },\n )\n }\n setCreator({ name: '', fields: '' })\n }, [org, datasetCount, enqueueSnackbar])\n // Entries are human names — \"Roast preference\" → stable id\n // `roast_preference` with the pretty name kept for headers (AGL-558).\n const creatorEntries = parseDatasetFieldEntries(creator?.fields ?? '')\n const creatorFields = creatorEntries.map((entry) => entry.id)\n const handleCreate = useCallback(async () => {\n // No org, no create. The `else` that used to sit below this was the\n // legacy host-scope client write (AGL-1050) — the one path by which a\n // dataset could be created with NO quota check, since /api/orgs/datasets\n // is where AGL-473 enforces it. The rules now deny that path outright;\n // this is the client side of the same closure. The Add button is\n // disabled without a scope, so reaching the guard means a stale closure.\n if (!creator?.name.trim() || creatorFields.length === 0 || !orgId) return\n let id: string\n try {\n const result = await callDatasetApi({\n action: 'create-dataset',\n displayName: creator.name.trim(),\n fields: creatorFields,\n // Typed model from day one (AGL-178); refine in the Schema dialog.\n model: modelFromFieldEntries(creatorEntries),\n ...createdFrom,\n })\n id = String(result.id)\n } catch (error: any) {\n return void enqueueSnackbar(error?.message ?? 'Dataset create failed', {\n variant: 'warning',\n persist: false,\n })\n }\n setCreator(null)\n setSelectedId(id)\n setDatasetCountEpoch((epoch) => epoch + 1)\n enqueueSnackbar(`Dataset \"${creator.name.trim()}\" created`, {\n variant: 'success',\n persist: false,\n })\n logActivity('Created dataset', {\n type: 'content',\n id,\n name: creator.name.trim(),\n })\n }, [creator, creatorEntries, creatorFields, orgId, createdFrom, callDatasetApi, enqueueSnackbar, logActivity])\n\n // Join collection template (AGL-180): extrinsic many-to-many as a\n // visible, editable collection of FKey pairs — no magic.\n const [joiner, setJoiner] = useState<{ a: string; b: string } | null>(null)\n const handleCreateJoin = useCallback(async () => {\n if (!joiner?.a || !joiner?.b || joiner.a === joiner.b) return\n const a = datasets.find((item) => item.$id === joiner.a)\n const b = datasets.find((item) => item.$id === joiner.b)\n // A join collection is a dataset and consumes the same quota, so it\n // takes the same API-only route (AGL-1050) — the host-scope client\n // write that used to stand in for it is gone.\n if (!a || !b || !orgId) return\n const fieldFor = (target: any, fieldId: string) => ({\n name: datasetDisplayName(target) || fieldId,\n type: 'reference' as const,\n required: true,\n reference: {\n datasetId: target.$id as string,\n displayFieldId: effectiveDatasetModel(target).order[0],\n onDelete: 'setNull' as const,\n },\n })\n const payload = {\n displayName: `${datasetDisplayName(a)} ↔ ${datasetDisplayName(b)}`,\n fields: ['aRef', 'bRef'],\n model: {\n order: ['aRef', 'bRef'],\n fields: { aRef: fieldFor(a, 'aRef'), bRef: fieldFor(b, 'bRef') },\n },\n }\n let id: string\n try {\n const result = await callDatasetApi({\n action: 'create-dataset',\n ...payload,\n // A join collection is a dataset, so the same Default sharing applies.\n ...createdFrom,\n })\n id = String(result.id)\n } catch (error: any) {\n return void enqueueSnackbar(error?.message ?? 'Join create failed', {\n variant: 'warning',\n persist: false,\n })\n }\n setJoiner(null)\n setSelectedId(id)\n // A join collection IS a dataset and consumes the same quota.\n setDatasetCountEpoch((epoch) => epoch + 1)\n enqueueSnackbar('Join collection created', {\n variant: 'success',\n persist: false,\n })\n }, [joiner, datasets, orgId, createdFrom, callDatasetApi, enqueueSnackbar])\n\n const handleDeleteDataset = useCallback(async () => {\n if (!selected) return\n const confirmed = await confirm({\n title: 'Delete this collection?',\n description:\n `\"${datasetDisplayName(selected)}\"` +\n // What is actually being destroyed, not what is loaded (AGL-1716):\n // a 40,000-row dataset used to warn about \"its 500 documents\".\n (recordCount\n ? ` and its ${recordCount} document${recordCount === 1 ? '' : 's'}`\n : '') +\n ' stop resolving in repeatable components and bindings that ' +\n 'reference it.',\n confirmationText: 'Delete',\n confirmationButtonProps: { color: 'error' },\n })\n .then(() => true)\n .catch(() => false)\n if (!confirmed || !dataScope) return\n // Deleting the dataset doc client-side would strand its `records`\n // subcollection — Firestore doesn't cascade and only the Admin SDK has\n // `recursiveDelete`, so the delete goes through the erase route\n // (AGL-945). Single-record deletes below stay client-direct.\n try {\n const response = await authorizedFetch(user, '/api/resources/erase', {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({\n scope: dataScope[0],\n scopeId: dataScope[1],\n kind: 'datasets',\n id: selected.$id,\n // Names the site this delete was issued from, so the route can\n // refuse to destroy a dataset shared beyond it (AGL-1046). The\n // org Data page passes no host and keeps the org-wide delete.\n hostId,\n }),\n })\n const result = await response.json().catch(() => ({}))\n if (!response.ok) throw new Error(result?.error ?? 'Dataset delete failed')\n } catch (error: any) {\n return void enqueueSnackbar(error?.message ?? 'Dataset delete failed', {\n variant: 'warning',\n persist: false,\n })\n }\n setSelectedId(null)\n setDatasetCountEpoch((epoch) => epoch + 1)\n enqueueSnackbar('Dataset deleted', { variant: 'success', persist: false })\n logActivity('Deleted dataset', {\n type: 'content',\n id: selected.$id,\n name: datasetDisplayName(selected),\n })\n }, [\n selected,\n recordCount,\n confirm,\n dataScope,\n hostId,\n user,\n enqueueSnackbar,\n logActivity,\n ])\n\n // Reference pickers (AGL-180): load target-collection rows for every\n // reference field in the model (id -> display label).\n const [refOptions, setRefOptions] = useState<\n Record<string, Array<{ id: string; label: string }>>\n >({})\n useEffect(() => {\n let active = true\n const referenceFields = model.order.filter(\n (fieldId) =>\n model.fields[fieldId]?.type === 'reference' &&\n model.fields[fieldId]?.reference?.datasetId,\n )\n if (!referenceFields.length || !dataScope) {\n setRefOptions({})\n return\n }\n void Promise.all(\n referenceFields.map(async (fieldId) => {\n const reference = model.fields[fieldId].reference as {\n datasetId: string\n displayFieldId?: string\n }\n const target = datasets.find(\n (item) => item.$id === reference.datasetId,\n )\n const displayFieldId =\n reference.displayFieldId ??\n effectiveDatasetModel(target ?? {}).order[0]\n const snapshot = await getDocs(\n query(\n collection(\n firestore,\n dataScope[0],\n dataScope[1],\n 'datasets',\n reference.datasetId,\n 'records',\n ),\n limit(200),\n ),\n ).catch(() => null)\n const options = (snapshot?.docs ?? []).map((docSnapshot) => ({\n id: docSnapshot.id,\n label: String(\n docSnapshot.get('values')?.[displayFieldId ?? ''] ??\n docSnapshot.id,\n ),\n }))\n return [fieldId, options] as const\n }),\n ).then((entries) => {\n if (active) setRefOptions(Object.fromEntries(entries))\n })\n return () => {\n active = false\n }\n }, [model, datasets, firestore, dataScope])\n /**\n * One reference target's label, or `null` when this ID resolves to nothing.\n *\n * The distinction the grid cannot draw. `referenceLabel` below falls back to\n * the raw ID, which is the only thing a cell has room for and is\n * indistinguishable from a resolved label that happens to look like an ID.\n * The record view has room to say which, so it asks the question that has a\n * `null` answer.\n *\n * Unresolvable covers more than a deleted target: `refOptions` loads at most\n * 200 rows per referenced collection, so a live target outside that window\n * reports the same way. Either way the ID is shown and neither is claimed to\n * be a working link.\n */\n const resolveReferenceLabel = useCallback(\n (fieldId: string, id: string): string | null =>\n refOptions[fieldId]?.find((option) => option.id === id)?.label ?? null,\n [refOptions],\n )\n const referenceLabel = useCallback(\n (fieldId: string, value: unknown): string => {\n const ids = Array.isArray(value) ? value : value != null ? [value] : []\n return ids\n .map((id) => resolveReferenceLabel(fieldId, String(id)) ?? String(id))\n .join(', ')\n },\n [resolveReferenceLabel],\n )\n /**\n * The record the viewer is showing, held as an ID and resolved against the\n * page the table already has.\n *\n * Holding the ID rather than the row is what keeps the view live without\n * costing a read: the same listener that draws the table re-resolves it, so\n * an edit landing underneath updates the open dialog. When the row leaves\n * the page — deleted, or paged past — this answers `null` and the dialog\n * closes, which is the honest response to a record no longer in front of\n * this reader. Nothing here queries: `records` is the page (or filter window)\n * query's answer.\n */\n const [viewerId, setViewerId] = useState<string | null>(null)\n const viewerRecord = useMemo(\n () =>\n viewerId\n ? (records.find((record: any) => record.$id === viewerId) ?? null)\n : null,\n [viewerId, records],\n )\n\n // --- Document editor (null id = new; AGL-179 typed inputs) --------------\n const [editor, setEditor] = useState<{\n id: string | null\n values: Record<string, string>\n errors: Record<string, string>\n } | null>(null)\n const handleOpenRecord = useCallback(\n (record?: any) => () => {\n if (!record) {\n // The dataset's documents, not the loaded window (AGL-1716).\n const quota = checkQuota(org, 'recordsPerDataset', recordCount)\n if (!quota.allowed) {\n return enqueueSnackbar(\n `Record limit reached (${quota.limit}) — see Billing to upgrade`,\n { variant: 'warning', persist: false },\n )\n }\n }\n const values: Record<string, string> = {}\n for (const fieldId of model.order) {\n const field = model.fields[fieldId]\n if (!field) continue\n if (record) {\n values[fieldId] = datasetValueToInput(\n field,\n record.values?.[fieldId],\n )\n } else if (field.default != null) {\n values[fieldId] = String(field.default)\n }\n }\n // Flag non-conforming stored values (AGL-178 policy: type changes\n // never rewrite documents; the editor surfaces the mismatch).\n const errors = record\n ? validateDocument(model, record.values ?? {})\n : {}\n setEditor({ id: record?.$id ?? null, values, errors })\n },\n [org, recordCount, model, enqueueSnackbar],\n )\n const handleSaveRecord = useCallback(async () => {\n if (!editor || !selected || !dataScope) return\n // The editor holds the record's WHOLE values, so an address it already\n // has stays and an empty one fills in from its source (AGL-3475).\n const coerced = fillRecordAddresses(\n model,\n coerceDocumentValues(model, editor.values),\n )\n const errors = validateDocument(model, coerced)\n if (Object.keys(errors).length) {\n return void setEditor((prev) => (prev ? { ...prev, errors } : prev))\n }\n // `values` is replaced wholesale (not merged) so orphaned values from\n // removed fields strip here, lazily, per the documented AGL-178 policy.\n try {\n if (editor.id) {\n // Updates stay client-direct (no quota consumed).\n const recordRef = doc(\n firestore,\n dataScope[0],\n dataScope[1],\n 'datasets',\n selected.$id,\n 'records',\n editor.id,\n )\n await setDoc(\n recordRef,\n {\n values: coerced,\n // The integrity index moves with the values it describes\n // (`datasetIntegrityUpdate`); the merging form, because clearing\n // the last reference has to REMOVE the field rather than omit it.\n ...datasetIntegrityUpdate(model, coerced, deleteField()),\n updatedAt: Timestamp.now(),\n },\n {\n mergeFields: ['values', 'referencedIds', 'filterKeys', 'filterValues', 'updatedAt'],\n },\n )\n await announceRecords(selected.$id)\n } else {\n // Creates go through the quota-enforcing API (AGL-473). The legacy\n // host-scope client write that used to follow this branch is gone\n // (AGL-1050): a non-null `dataScope` is an org scope, so `orgId` is\n // set and there is no third case to fall into.\n await callDatasetApi({\n action: 'create-record',\n datasetId: selected.$id,\n values: coerced,\n })\n }\n } catch (error: any) {\n return void enqueueSnackbar(error?.message ?? 'Record save failed', {\n variant: 'warning',\n persist: false,\n })\n }\n setEditor(null)\n // A create moves the count; an update cannot. Same reason as the\n // importer: the one-shot aggregate does not refresh itself.\n if (!editor.id) setRecordCountEpoch((epoch) => epoch + 1)\n enqueueSnackbar(editor.id ? 'Record saved' : 'Record added', {\n variant: 'success',\n persist: false,\n })\n logActivity(editor.id ? 'Updated record' : 'Added record', {\n type: 'content',\n id: selected.$id,\n name: datasetDisplayName(selected),\n })\n }, [\n editor,\n selected,\n firestore,\n dataScope,\n model,\n callDatasetApi,\n announceRecords,\n enqueueSnackbar,\n logActivity,\n ])\n const handleDeleteRecord = useCallback(\n (record: any) => async () => {\n // Datasets whose records this delete rewrites through a reference\n // fixup, beside the one the record belongs to. Each has pages of its\n // own to refresh (AGL-3113).\n const alsoChanged = new Set<string>()\n if (!selected || !dataScope) return\n /**\n * Delete integrity (AGL-180): every collection whose model references\n * this one is asked whether it still points at this record. `restrict`\n * blocks the delete; `setNull` strips the FKey from the holders.\n *\n * The question is a QUERY over the denormalized `referencedIds` index,\n * not a page of records filtered in the browser. A page answers for the\n * rows it happened to fetch — an unordered `limit` is answered in\n * document-id order over auto-ids, so it is an arbitrary sample — and a\n * reference held by a row outside it reads as no reference at all: the\n * delete goes through and `restrict` silently fails to restrict, leaving\n * a document pointing at something that no longer exists. `values`\n * itself cannot be queried (it carries a deliberate index exemption —\n * see `datasetIntegrityFields`), which is why the index exists.\n *\n * The query narrows to the candidates; the per-field test below keeps it\n * EXACT, since `referencedIds` is the union across every reference field\n * and one of them may point at a different collection entirely.\n *\n * ⚠️ FAILS CLOSED. A query that rejects — a missing index, a rules\n * refusal on a collection this member cannot read — refuses the delete\n * rather than treating silence as \"nothing references it\". A check that\n * fails open is worse than no check, because the UI then tells the user\n * the record is safe to remove.\n *\n * ⚠️ Reaches the collections in `datasets`, which is this viewer's\n * scoped, capped picker window. A referencing collection shared with no\n * site this member can see is one the client may not read at all, so it\n * is not consulted; only a server route could close that.\n */\n for (const other of datasets) {\n const otherModel = effectiveDatasetModel(other)\n if (!referencingFieldIds(otherModel, selected.$id).length) continue\n let snapshot\n try {\n snapshot = await getDocs(\n query(\n collection(\n firestore,\n dataScope[0],\n dataScope[1],\n 'datasets',\n other.$id,\n 'records',\n ),\n where('referencedIds', 'array-contains', record.$id),\n ),\n )\n } catch {\n return void enqueueSnackbar(\n `Cannot delete: \"${datasetDisplayName(other)}\" could not be checked for ` +\n 'references, so removing this record could break it. Nothing ' +\n 'was deleted.',\n { variant: 'error' },\n )\n }\n // The verdict is shared with `/api/orgs/datasets` `delete-record`\n // (`planReferenceFixups`): the per-field test keeps the query EXACT,\n // since `referencedIds` is the union across every reference field.\n const plan = planReferenceFixups(\n otherModel,\n selected.$id,\n record.$id,\n snapshot.docs.map((docSnapshot) => ({ id: docSnapshot.id, values: docSnapshot.get('values') })),\n )\n if (plan.kind === 'none') continue\n if (plan.kind === 'restricted') {\n return void enqueueSnackbar(\n restrictedDeleteMessage(plan.holders, datasetDisplayName(other)),\n { variant: 'warning', persist: false },\n )\n }\n // Chunked under Firestore's 500-writes-per-batch cap. The query is no\n // longer bounded by a page size, so the number of holders is whatever\n // the collection really holds.\n for (let start = 0; start < plan.updates.length; start += 400) {\n const batch = writeBatch(firestore)\n for (const update of plan.updates.slice(start, start + 400)) {\n const holder = snapshot.docs.find((docSnapshot) => docSnapshot.id === update.id)\n if (!holder) continue\n batch.update(holder.ref, {\n values: update.values,\n ...datasetIntegrityUpdate(otherModel, update.values, deleteField()),\n })\n }\n await batch.commit()\n }\n // The fixups rewrote rows in ANOTHER dataset, whose own pages are now\n // showing a reference that no longer resolves.\n alsoChanged.add(other.$id)\n }\n await deleteDoc(\n doc(\n firestore,\n dataScope[0],\n dataScope[1],\n 'datasets',\n selected.$id,\n 'records',\n record.$id,\n ),\n )\n setRecordCountEpoch((epoch) => epoch + 1)\n for (const datasetId of [selected.$id, ...alsoChanged]) {\n await announceRecords(datasetId)\n }\n enqueueSnackbar('Record deleted', { variant: 'success', persist: false })\n },\n [selected, datasets, firestore, dataScope, announceRecords, enqueueSnackbar],\n )\n\n /**\n * Import and export (AGL-3530) open the console's import wizard and export\n * dialog on this dataset (`data.dataset:<datasetId>`): the file is read,\n * matched and written on the server, through the same record writes as\n * every other create and update, and the export streams the fields the\n * person picks. Outside the console shell there is no launcher, and no\n * Import or Export to offer. Inside it, Import is offered to a member who\n * may import (Manage data) and Export to any member who can see the\n * dataset (AGL-3546) — the transfer routes' own rule.\n */\n const transfer = useTransferLauncher()\n const transferTarget = selected?.$id\n ? { resource: datasetTransferResourceKey(selected.$id), scope: 'org' as const }\n : null\n const canImport = Boolean(transfer && transferTarget && transfer.can('import', transferTarget))\n const canExport = Boolean(transfer && transferTarget && transfer.can('export', transferTarget))\n const handleImport = useCallback(() => {\n if (!transfer || !selected?.$id) return\n const dataset = { id: selected.$id, name: datasetDisplayName(selected) }\n transfer.openImport({\n resource: datasetTransferResourceKey(dataset.id),\n scope: 'org',\n title: dataset.name ? `Import into ${dataset.name}` : 'Import records',\n onFinished: () => {\n // An import moves the record count, and the aggregate is a one-shot.\n setRecordCountEpoch((epoch) => epoch + 1)\n logActivity('Imported records', { type: 'content', id: dataset.id, name: dataset.name })\n },\n })\n }, [transfer, selected, logActivity])\n const handleExport = useCallback(() => {\n if (!transfer || !selected?.$id) return\n const name = datasetDisplayName(selected)\n transfer.openExport({\n resource: datasetTransferResourceKey(selected.$id),\n scope: 'org',\n title: name ? `Export ${name}` : 'Export records',\n // The table's own query, re-planned on the server the way the table\n // plans it, so \"the current filter\" exports what the table shows.\n ...(filteringRecords\n ? {\n filter: {\n label: 'The records the table’s filters and search show',\n value: { clauses: recordClauses, search: gridFilter.searchWords },\n },\n }\n : {}),\n })\n }, [transfer, selected, filteringRecords, recordClauses, gridFilter.searchWords])\n\n /*\n * One column per schema field, filterable as far as `datasetRecordFilter`\n * declares it. The row OPENS the record, read-only (`onOpen`); the actions\n * column holds the keyboard's way in (`View`, a real button) beside Edit\n * and Delete, and a press anywhere in it never opens the row.\n */\n const recordGridColumns = useMemo(\n () =>\n listFilterGridColumns(\n [\n ...fields.map((fieldId) => {\n const field = model.fields[fieldId]\n return {\n field: recordColumn(fieldId),\n headerName: field?.name ?? fieldId,\n // Field descriptions (AGL-560) surface as header hints.\n description: field?.description,\n flex: 1,\n minWidth: 140,\n renderCell: ({ row }: { row: any }) =>\n field?.type === 'reference'\n ? referenceLabel(fieldId, row.values?.[fieldId]) || '--'\n : field\n ? formatDatasetValue(field, row.values?.[fieldId]) || '--'\n : '--',\n }\n }),\n listActionsColumn(\n (record: any) => (\n <Stack\n direction=\"row\"\n sx={{ height: '100%', alignItems: 'center', justifyContent: 'flex-end' }}\n >\n <Button size=\"small\" onClick={() => setViewerId(record.$id)}>\n {'View'}\n </Button>\n <Button size=\"small\" onClick={handleOpenRecord(record)}>\n {'Edit'}\n </Button>\n <Button\n size=\"small\"\n color=\"error\"\n onClick={handleDeleteRecord(record)}\n >\n {'Delete'}\n </Button>\n </Stack>\n ),\n { width: 220 },\n ),\n ] as Parameters<typeof listFilterGridColumns>[0],\n recordFilter.fields,\n recordFilter.options,\n recordFilter.headers,\n ),\n [\n fields,\n model,\n referenceLabel,\n handleOpenRecord,\n handleDeleteRecord,\n recordFilter,\n ],\n )\n\n /*\n * EVERY HEADER SORTS — THE PAGE ON SCREEN (AGL-3680). A record's values are\n * per-schema and no field is on every record (see the walk above), so no\n * query can order by one; each value column sorts the loaded page by what\n * it shows (a reference by its label, a number or switch by its value) and\n * the notice says it is this page only.\n */\n const recordPageSorts = useMemo(\n () =>\n Object.fromEntries(\n fields.map((fieldId) => {\n const field = model.fields[fieldId]\n return [\n recordColumn(fieldId),\n (row: any) => {\n const value = row.values?.[fieldId]\n if (field?.type === 'reference') return referenceLabel(fieldId, value) || null\n if (typeof value === 'number' || typeof value === 'boolean') return value\n return field ? formatDatasetValue(field, value) || null : null\n },\n ]\n }),\n ),\n [fields, model, referenceLabel],\n )\n const recordSortHeaders = useMemo(\n () =>\n Object.fromEntries(\n fields.map((fieldId) => [recordColumn(fieldId), model.fields[fieldId]?.name ?? fieldId]),\n ),\n [fields, model],\n )\n const recordColumnSort = useListColumnSort<any>({\n sorts: NO_QUERY_SORTS,\n rows: records,\n pageSorts: recordPageSorts,\n headers: recordSortHeaders,\n })\n\n return (\n <CardDisplay\n header={'Data'}\n help={pluginDocsHelp('datasets', { anchor: '#filter-records' })}\n contentGutterX\n contentGutterY\n contentBordered=\"all\"\n >\n <Stack spacing={1.5}>\n {orgId ? (\n <Typography variant=\"caption\" color=\"text.secondary\">\n {/* Ownership and visibility are separate facts (AGL-1044), and\n what a new dataset starts on depends on where it is made. */}\n {newDatasetSharingNote(createsSiteOnly)}\n </Typography>\n ) : null}\n {datasets.length === 0 ? (\n <Typography variant=\"body2\" color=\"text.secondary\">\n {'Create a dataset (e.g. Products) and repeat a component over ' +\n 'its records with {{item.field}} bindings.'}\n </Typography>\n ) : (\n <Stack\n direction=\"row\"\n spacing={1}\n useFlexGap\n sx={{ alignItems: 'center', flexWrap: 'wrap' }}\n >\n {/* A scope, not a filter: it picks which collection the table\n walks, and the grid's own Filters panel narrows within it. */}\n <TextField\n select\n size=\"small\"\n label=\"Dataset\"\n value={selected?.$id ?? ''}\n onChange={(event) => setSelectedId(event.target.value)}\n sx={{ minWidth: 180 }}\n >\n {datasets.map((item) => (\n <MenuItem key={item.$id} value={item.$id}>\n {datasetDisplayName(item)}\n </MenuItem>\n ))}\n </TextField>\n <Button\n size=\"small\"\n color=\"primary\"\n onClick={handleOpenRecord()}\n >\n {'Add record'}\n </Button>\n <Button size=\"small\" onClick={() => setSchemaOpen(true)}>\n {'Schema'}\n </Button>\n {/* An import left unfinished, reopened where it stopped (AGL-3549). */}\n {transferTarget ? (\n <TransferResumeImport\n target={transferTarget}\n {...(selected ? { title: `Import into ${datasetDisplayName(selected)}` } : {})}\n onFinished={() => setRecordCountEpoch((epoch) => epoch + 1)}\n />\n ) : null}\n {canImport ? (\n <Button size=\"small\" onClick={handleImport}>\n {'Import'}\n </Button>\n ) : null}\n {/* The real dataset size, not the loaded window (AGL-2335) —\n the export is a server stream, so a dataset whose first page\n has not landed yet is still exportable. */}\n {canExport && (recordCount || records.length) ? (\n <Button size=\"small\" onClick={handleExport}>\n {'Export'}\n </Button>\n ) : null}\n <Button size=\"small\" color=\"error\" onClick={handleDeleteDataset}>\n {'Delete'}\n </Button>\n </Stack>\n )}\n {/* The per-dataset record cap, standing rather than only on refusal\n (AGL-2113). `recordCount` is the dataset's real size — the same\n number `handleOpenRecord` and the importer hand to `checkQuota`,\n not the loaded window (AGL-1716). */}\n {selected ? (\n <QuotaReadoutComponent\n ready={org != null}\n used={recordCount}\n limit={checkQuota(org, 'recordsPerDataset', recordCount).limit}\n noun=\"record\"\n />\n ) : null}\n {selected && (records.length > 0 || recordPage > 0 || filteringRecords) ? (\n <>\n <ListFilterChips\n fields={recordFilter.fields}\n headers={recordFilter.headers}\n clauses={recordClauses}\n onChange={gridFilter.setClauses}\n options={recordFilter.options}\n />\n <ListQueryNotices\n refused={recordRefusals}\n notices={[...recordPlan.notices, ...recordColumnSort.notices]}\n />\n <ListTable\n aria-label=\"Records\"\n rows={recordColumnSort.rows}\n columnSort={recordColumnSort}\n columns={recordGridColumns}\n onOpen={(id) => setViewerId(id)}\n // One page of the walk, turned by the footer below: the grid\n // neither slices nor filters it.\n hideFooter\n filterMode=\"server\"\n filterModel={gridFilter.filterModel}\n onFilterModelChange={gridFilter.onFilterModelChange}\n quickFilter\n noRowsLabel={\n filteringRecords ? 'No records match these filters' : 'No records yet.'\n }\n />\n {/* The count line is the PAGE's, deliberately. `recordCount` is the\n dataset's real size and it already has its own readout above —\n handing it to the footer as `count` would tell MUI the walk is\n that long and leave Next live past the end of it whenever a rule,\n a scope or a filter has narrowed what this reader may list.\n `hasMore` is a fact from the probe row, so the footer answers\n for what it is actually paging. */}\n <ListPagination\n page={recordPage}\n pageSize={recordPageSize}\n rowCount={records.length}\n hasMore={hasMoreRecords}\n onPageChange={setRecordPage}\n onPageSizeChange={setRecordPageSize}\n />\n </>\n ) : selected ? (\n <Typography variant=\"body2\" color=\"text.secondary\">\n {'No records yet.'}\n </Typography>\n ) : null}\n <Stack\n direction=\"row\"\n spacing={1}\n useFlexGap\n sx={{ flexWrap: 'wrap' }}\n >\n <Button\n size=\"small\"\n variant=\"outlined\"\n color=\"primary\"\n onClick={handleOpenCreator}\n >\n {'Add dataset'}\n </Button>\n {datasets.length >= 2 ? (\n <Button size=\"small\" onClick={() => setJoiner({ a: '', b: '' })}>\n {'Add join collection'}\n </Button>\n ) : null}\n </Stack>\n </Stack>\n <Dialog\n open={Boolean(creator)}\n onClose={() => setCreator(null)}\n maxWidth=\"xs\"\n fullWidth\n >\n <DialogTitle>{'New dataset'}</DialogTitle>\n <DialogContent\n sx={{ display: 'flex', flexDirection: 'column', gap: 2 }}\n >\n <TextField\n label=\"Name\"\n value={creator?.name ?? ''}\n onChange={(event) =>\n setCreator((prev) =>\n prev ? { ...prev, name: event.target.value } : prev,\n )\n }\n size=\"small\"\n autoFocus\n sx={{ mt: 1 }}\n helperText=\"e.g. Products, Team, FAQ\"\n />\n <TextField\n label=\"Fields\"\n value={creator?.fields ?? ''}\n onChange={(event) =>\n setCreator((prev) =>\n prev ? { ...prev, fields: event.target.value } : prev,\n )\n }\n size=\"small\"\n helperText={\n creatorEntries.length\n ? `Columns: ${creatorEntries\n .map((entry) => entry.name)\n .join(', ')}`\n : 'Comma-separated column names, e.g. Title, Unit price'\n }\n />\n </DialogContent>\n <DialogActions>\n <Button onClick={() => setCreator(null)}>{'Cancel'}</Button>\n <Button\n variant=\"contained\"\n color=\"primary\"\n disabled={\n !scopeReady ||\n !creator?.name.trim() ||\n creatorFields.length === 0\n }\n onClick={handleCreate}\n >\n {'Create'}\n </Button>\n </DialogActions>\n </Dialog>\n {/*\n ONE viewer for the table, not one per row. Its record is a prop out of\n the page already in hand, so opening it reads nothing — and mounting\n the table does not open a dialog per row to discover that.\n */}\n <DatasetRecordDialog\n record={viewerRecord}\n model={model}\n resolveReference={resolveReferenceLabel}\n onClose={() => setViewerId(null)}\n // Explicitly separate, and a hand-off rather than a second editor:\n // the viewer closes and the record opens in the dialog that has\n // always owned writing.\n onEdit={() => {\n const record = viewerRecord\n setViewerId(null)\n if (record) handleOpenRecord(record)()\n }}\n />\n <Dialog\n open={Boolean(editor)}\n onClose={() => setEditor(null)}\n maxWidth=\"xs\"\n fullWidth\n >\n <DialogTitle>{editor?.id ? 'Edit record' : 'New record'}</DialogTitle>\n <DialogContent\n sx={{ display: 'flex', flexDirection: 'column', gap: 2 }}\n >\n {fields.map((fieldId, index) => {\n const field = model.fields[fieldId]\n if (!field) return null\n const value = editor?.values[fieldId] ?? ''\n const error = editor?.errors[fieldId]\n const label = field.required ? `${field.name} *` : field.name\n const setValue = (nextValue: string) =>\n setEditor((prev) =>\n prev\n ? {\n ...prev,\n values: { ...prev.values, [fieldId]: nextValue },\n errors: { ...prev.errors, [fieldId]: '' },\n }\n : prev,\n )\n const common = {\n label,\n value,\n size: 'small' as const,\n autoFocus: index === 0,\n error: Boolean(error),\n helperText: error || field.description,\n sx: index === 0 ? { mt: 1 } : undefined,\n onChange: (event: { target: { value: string } }) =>\n setValue(event.target.value),\n }\n // Custom field types (AGL-434): the declaring plugin's Input\n // takes over; values stay in input form (strings) so the\n // existing coerce/validate pipeline is unchanged.\n const customFieldType = getCustomFieldType(field.customType)\n if (customFieldType?.Input) {\n const CustomInput = customFieldType.Input\n return (\n <Stack key={fieldId} sx={index === 0 ? { mt: 1 } : undefined}>\n <CustomInput\n value={value}\n label={common.label}\n onChange={(next) => setValue(String(next ?? ''))}\n />\n {(error || field.description) ? (\n <Typography\n variant=\"caption\"\n color={error ? 'error' : 'text.secondary'}\n >\n {error || field.description}\n </Typography>\n ) : null}\n </Stack>\n )\n }\n // Typed inputs per FT.Tag (AGL-179).\n if (field.type === 'bool') {\n return (\n <TextField key={fieldId} {...common} select>\n <MenuItem value=\"\">{'—'}</MenuItem>\n <MenuItem value=\"true\">{'Yes'}</MenuItem>\n <MenuItem value=\"false\">{'No'}</MenuItem>\n </TextField>\n )\n }\n if (field.type === 'text' && field.validation?.options?.length) {\n return (\n <TextField key={fieldId} {...common} select>\n <MenuItem value=\"\">{'—'}</MenuItem>\n {field.validation.options.map((option) => (\n <MenuItem key={option} value={option}>\n {option}\n </MenuItem>\n ))}\n </TextField>\n )\n }\n if (field.type === 'reference') {\n const options = refOptions[fieldId] ?? []\n const multiple = Boolean(field.reference?.multiple)\n const selectedIds = value\n .split(',')\n .map((part) => part.trim())\n .filter(Boolean)\n return (\n <TextField\n key={fieldId}\n {...common}\n select\n value={multiple ? selectedIds : value}\n slotProps={{\n select: multiple\n ? {\n multiple: true,\n onChange: (event: any) =>\n setValue(\n (event.target.value as string[]).join(', '),\n ),\n }\n : undefined,\n }}\n >\n {multiple ? null : <MenuItem value=\"\">{'—'}</MenuItem>}\n {options.map((option) => (\n <MenuItem key={option.id} value={option.id}>\n {option.label}\n </MenuItem>\n ))}\n </TextField>\n )\n }\n if (\n field.type === 'int32' ||\n field.type === 'int64' ||\n field.type === 'float'\n ) {\n return <TextField key={fieldId} {...common} type=\"number\" />\n }\n if (field.type === 'timestamp') {\n return (\n <TextField\n key={fieldId}\n {...common}\n type=\"datetime-local\"\n slotProps={{ inputLabel: { shrink: true } }}\n />\n )\n }\n if (field.type === 'coordinates') {\n return (\n <TextField\n key={fieldId}\n {...common}\n helperText={error || field.description || 'lat, lon'}\n />\n )\n }\n if (field.type === 'sorted') {\n return (\n <TextField\n key={fieldId}\n {...common}\n helperText={\n error || field.description || 'Comma-separated list'\n }\n />\n )\n }\n return <TextField key={fieldId} {...common} />\n })}\n </DialogContent>\n <DialogActions>\n <Button onClick={() => setEditor(null)}>{'Cancel'}</Button>\n <Button\n variant=\"contained\"\n color=\"primary\"\n onClick={handleSaveRecord}\n >\n {editor?.id ? 'Save' : 'Add'}\n </Button>\n </DialogActions>\n </Dialog>\n <Dialog\n open={Boolean(joiner)}\n onClose={() => setJoiner(null)}\n maxWidth=\"xs\"\n fullWidth\n >\n <DialogTitle>{'New join collection'}</DialogTitle>\n <DialogContent\n sx={{ display: 'flex', flexDirection: 'column', gap: 2 }}\n >\n <Typography variant=\"body2\" color=\"text.secondary\" sx={{ mt: 1 }}>\n {'Links two collections many-to-many; each row pairs one ' +\n 'document from each side.'}\n </Typography>\n {(['a', 'b'] as const).map((side) => (\n <TextField\n key={side}\n select\n size=\"small\"\n label={side === 'a' ? 'First collection' : 'Second collection'}\n value={joiner?.[side] ?? ''}\n onChange={(event) =>\n setJoiner((prev) =>\n prev ? { ...prev, [side]: event.target.value } : prev,\n )\n }\n >\n {datasets.map((item) => (\n <MenuItem key={item.$id} value={item.$id}>\n {datasetDisplayName(item)}\n </MenuItem>\n ))}\n </TextField>\n ))}\n </DialogContent>\n <DialogActions>\n <Button onClick={() => setJoiner(null)}>{'Cancel'}</Button>\n <Button\n variant=\"contained\"\n color=\"primary\"\n disabled={\n !scopeReady || !joiner?.a || !joiner?.b || joiner.a === joiner.b\n }\n onClick={handleCreateJoin}\n >\n {'Create'}\n </Button>\n </DialogActions>\n </Dialog>\n <DatasetSchemaDialog\n hostId={hostId}\n orgId={orgId ?? undefined}\n dataset={schemaOpen && selected ? selected : null}\n datasets={datasets}\n // The dataset's documents, not the loaded window (AGL-1716) — the\n // dialog warns \"N documents exist\" before a narrowing type change,\n // and 500 was the cap talking, not the collection.\n recordCount={recordCount}\n seedFromCache={datasetsFromCache}\n seedUnreadable={datasetsStatus === 'error'}\n onClose={() => setSchemaOpen(false)}\n />\n </CardDisplay>\n )\n}\nHostDatasetsCard.displayName = 'HostDatasetsCard'\n\nexport default HostDatasetsCard\n"],"names":["TransferResumeImport","checkDatasetQuota","checkEntitlement","checkQuota","getCustomFieldType","pluginDocsHelp","useTransferLauncher","CardDisplay","useConfirmationContext","ListFilterChips","ListPagination","ListQueryNotices","listQueryRefusals","ListTable","listActionsColumn","QuotaReadoutComponent","listFilterGridColumns","useListGridFilter","useSnackbar","Timestamp","Button","Dialog","DialogActions","DialogContent","DialogTitle","MenuItem","Stack","TextField","Typography","collection","deleteDoc","deleteField","doc","getCountFromServer","getDocs","limit","query","where","setDoc","writeBatch","useCallback","useEffect","useMemo","useState","useListColumnSort","useFirestore","useFirestoreCollection","useHostActivityLogger","useOrgDataScope","usePagedCollection","useScopeTokens","useUser","listQueryConstraints","authorizedFetch","DatasetSchemaDialog","DatasetRecordDialog","datasetRecordFilter","planRecordQuery","recordColumn","coerceDocumentValues","datasetIntegrityUpdate","datasetValueToInput","effectiveDatasetModel","formatDatasetValue","modelFromFieldEntries","validateDocument","fillRecordAddresses","planReferenceFixups","referencingFieldIds","restrictedDeleteMessage","datasetDisplayName","parseDatasetFieldEntries","datasetTransferResourceKey","NO_QUERY_SORTS","newDatasetSharingNote","siteOnly","HostDatasetsCard","props","datasets","hostId","scope","dataScope","orgId","tokens","scopeTokens","orgWide","viewerOrgWide","loaded","scopeLoaded","needsScope","scopeReady","Boolean","firestore","enqueueSnackbar","confirm","org","logActivity","data","user","createdFromHostId","undefined","createdFrom","createsSiteOnly","defaultResourceScope","callDatasetApi","payload","response","method","headers","body","JSON","stringify","result","json","catch","ok","Error","error","announceRecords","datasetId","action","console","datasetDocs","status","datasetsStatus","fromCache","datasetsFromCache","idField","sort","a","b","localeCompare","selectedId","setSelectedId","schemaOpen","setSchemaOpen","selected","find","item","$id","model","fields","order","recordFilter","gridFilter","selectFields","recordClauses","clauses","filter","clause","some","field","column","recordPlan","searchWords","recordPlanKey","filters","plan","orderBy","rows","records","hasMore","hasMoreRecords","page","recordPage","setPage","setRecordPage","pageSize","recordPageSize","setPageSize","setRecordPageSize","pageLimit","recordRefusals","refused","options","filteringRecords","length","word","trim","datasetCountEpoch","setDatasetCountEpoch","recordCountEpoch","setRecordCountEpoch","serverDatasetCount","setServerDatasetCount","serverRecordCount","setServerRecordCount","active","then","snapshot","count","countedDatasetId","datasetCount","recordCount","creator","setCreator","handleOpenCreator","variant","persist","quota","allowed","upgradeRequired","addonPriceUsd","name","creatorEntries","creatorFields","map","entry","id","handleCreate","displayName","String","message","epoch","type","joiner","setJoiner","handleCreateJoin","fieldFor","target","fieldId","required","reference","displayFieldId","onDelete","aRef","bRef","handleDeleteDataset","confirmed","title","description","confirmationText","confirmationButtonProps","color","scopeId","kind","refOptions","setRefOptions","referenceFields","Promise","all","docs","docSnapshot","label","get","entries","Object","fromEntries","resolveReferenceLabel","option","referenceLabel","value","ids","Array","isArray","join","viewerId","setViewerId","viewerRecord","record","editor","setEditor","handleOpenRecord","values","default","errors","handleSaveRecord","coerced","keys","prev","recordRef","updatedAt","now","mergeFields","handleDeleteRecord","alsoChanged","Set","other","otherModel","holders","start","updates","batch","update","slice","holder","ref","commit","add","transfer","transferTarget","resource","canImport","can","canExport","handleImport","dataset","openImport","onFinished","handleExport","openExport","search","recordGridColumns","headerName","flex","minWidth","renderCell","row","direction","sx","height","alignItems","justifyContent","size","onClick","width","recordPageSorts","recordSortHeaders","recordColumnSort","sorts","pageSorts","header","help","anchor","contentGutterX","contentGutterY","contentBordered","spacing","useFlexGap","flexWrap","select","onChange","event","ready","used","noun","setClauses","notices","aria-label","columnSort","columns","onOpen","hideFooter","filterMode","filterModel","onFilterModelChange","quickFilter","noRowsLabel","rowCount","onPageChange","onPageSizeChange","open","onClose","maxWidth","fullWidth","display","flexDirection","gap","autoFocus","mt","helperText","disabled","resolveReference","onEdit","index","setValue","nextValue","common","customFieldType","customType","Input","CustomInput","next","validation","multiple","selectedIds","split","part","slotProps","inputLabel","shrink","side","seedFromCache","seedUnreadable"],"mappings":"AAAA;;;;;;;;;;;;;;;CAeC,GACD;;;AAEA,SAASA,oBAAoB,QAAQ,gDAA+C;AACpF,SAEEC,iBAAiB,EACjBC,gBAAgB,EAChBC,UAAU,EACVC,kBAAkB,EAClBC,cAAc,EACdC,mBAAmB,QACd,eAAc;AACrB,SAASC,WAAW,EAAEC,sBAAsB,QAAQ,uBAAsB;AAC1E,OAAOC,qBAAqB,8DAA6D;AACzF,SAASC,cAAc,QAAQ,4DAA2D;AAC1F,OAAOC,oBACLC,iBAAiB,QACZ,+DAA8D;AACrE,SACEC,SAAS,EACTC,iBAAiB,QACZ,uDAAsD;AAC7D,OAAOC,2BAA2B,0DAAyD;AAC3F,SAASC,qBAAqB,QAAQ,8CAA6C;AACnF,SAASC,iBAAiB,QAAQ,kDAAiD;AACnF,SAASC,WAAW,QAAQ,8BAA6B;AACzD,SAASC,SAAS,QAAQ,+BAA8B;AACxD,SACEC,MAAM,EACNC,MAAM,EACNC,aAAa,EACbC,aAAa,EACbC,WAAW,EACXC,QAAQ,EACRC,KAAK,EACLC,SAAS,EACTC,UAAU,QACL,gBAAe;AACtB,SACEC,UAAU,EACVC,SAAS,EACTC,WAAW,EACXC,GAAG,EACHC,kBAAkB,EAClBC,OAAO,EACPC,KAAK,EACLC,KAAK,EACLC,KAAK,EACLC,MAAM,EACNC,UAAU,QACL,qBAAoB;AAC3B,SAASC,WAAW,EAAEC,SAAS,EAAEC,OAAO,EAAEC,QAAQ,QAAQ,QAAO;AACjE,SAASC,iBAAiB,QAAQ,kDAAiD;AACnF,SACEC,YAAY,EACZC,sBAAsB,EACtBC,qBAAqB,EACrBC,eAAe,EACfC,kBAAkB,EAClBC,cAAc,EACdC,OAAO,QACF,iCAAgC;AACvC,SAASC,oBAAoB,QAAQ,sDAAqD;AAC1F,SAASC,eAAe,QAAQ,2CAA0C;AAC1E,SAASC,mBAAmB,QAAQ,uCAAmC;AACvE,SAASC,mBAAmB,QAAQ,uCAAmC;AACvE,SACEC,mBAAmB,EACnBC,eAAe,EACfC,YAAY,QACP,6BAAyB;AAChC,SAASC,oBAAoB,EAAEC,sBAAsB,EAAEC,mBAAmB,EAAEC,qBAAqB,EAAEC,kBAAkB,EAAEC,qBAAqB,EAAEC,gBAAgB,QAAQ,6BAAyB;AAC/L,SAASC,mBAAmB,QAAQ,kCAA8B;AAClE,SAASC,mBAAmB,EAAEC,mBAAmB,EAAEC,uBAAuB,QAAQ,yCAAqC;AACvH,SAASC,kBAAkB,EAAEC,wBAAwB,QAAQ,uBAAmB;AAChF,SAASC,0BAA0B,QAAQ,sCAAkC;AAmB7E;;;;;;;CAOC,GACD,0EAA0E,GAC1E,MAAMC,iBAA0B,EAAE;AAElC,OAAO,SAASC,sBAAsBC,QAAiB;IACrD,OAAOA,WACH,yEACE,kEACF,oEACE;AACR;AAEA;;;;;;;CAOC,GACD,OAAO,SAASC,iBAAiBC,KAA4B;QAoJzDC;IAnJF,MAAM,EAAEC,MAAM,EAAE,GAAGF;IACnB,yEAAyE;IACzE,sEAAsE;IACtE,qEAAqE;IACrE,mBAAmB;IACnB,MAAM,EAAEG,OAAOC,SAAS,EAAEC,KAAK,EAAE,GAAGlC,gBAAgB;QAClD+B;QACAG,OAAOL,MAAMK,KAAK;IACpB;IACA,wEAAwE;IACxE,iEAAiE;IACjE,mEAAmE;IACnE,oEAAoE;IACpE,uEAAuE;IACvE,uDAAuD;IACvD,MAAM,EACJC,QAAQC,WAAW,EACnBC,SAASC,aAAa,EACtBC,QAAQC,WAAW,EACpB,GAAGtC,eAAegC;IACnB,mEAAmE;IACnE,qEAAqE;IACrE,yEAAyE;IACzE,4DAA4D;IAC5D,MAAMO,aAAa,CAACH;IACpB,yEAAyE;IACzE,sEAAsE;IACtE,wEAAwE;IACxE,mEAAmE;IACnE,wEAAwE;IACxE,uEAAuE;IACvE,MAAMI,aAAaC,QAAQV,cAAcO;IACzC,MAAMI,YAAY/C;IAClB,MAAM,EAAEgD,eAAe,EAAE,GAAG3E;IAC5B,MAAM,EAAE4E,OAAO,EAAE,GAAGtF;IACpB,MAAM,EAAEuF,GAAG,EAAE,GAAGlB;IAChB,MAAMmB,cAAcjD,sBAAsBgC;IAC1C,MAAM,EAAEkB,MAAMC,IAAI,EAAE,GAAG/C;IACvB;;;;;;;;;;GAUC,GACD,MAAMgD,oBAAoBtB,MAAMK,KAAK,GAAGkB,YAAYrB,UAAUqB;IAC9D,MAAMC,cAAc3D,QAClB,IAAOyD,oBAAoB;YAAEpB,QAAQoB;QAAkB,IAAI,CAAC,GAC5D;QAACA;KAAkB;IAErB;;;;;GAKC,GACD,MAAMG,kBACJX,QAAQQ,sBACR,CAACJ,uBAAD,AAACA,IACGQ,oBAAoB,MAAK;IAE/B,uEAAuE;IACvE,kEAAkE;IAClE,qEAAqE;IACrE,mEAAmE;IACnE,MAAMC,iBAAiBhE,YACrB,OAAOiE;QACL,MAAMC,WAAW,MAAMrD,gBAAgB6C,MAAM,sBAAsB;YACjES,QAAQ;YACRC,SAAS;gBAAE,gBAAgB;YAAmB;YAC9CC,MAAMC,KAAKC,SAAS,CAAC;gBAAE7B;eAAUuB;QACnC;QACA,MAAMO,SAAS,MAAMN,SAASO,IAAI,GAAGC,KAAK,CAAC,IAAO,CAAA,CAAC,CAAA;QACnD,IAAI,CAACR,SAASS,EAAE,EAAE;;YAChB,MAAM,IAAIC,cAAMJ,0BAAAA,OAAQK,KAAK,mBAAI;QACnC;QACA,OAAOL;IACT,GACA;QAACd;QAAMhB;KAAM;IAGf;;;;;;;;;;;;;GAaC,GACD,MAAMoC,kBAAkB9E,YACtB,OAAO+E;QACL,IAAI;YACF,MAAMf,eAAe;gBAAEgB,QAAQ;gBAAoBD;YAAU;QAC/D,EAAE,OAAOF,OAAO;YACdI,QAAQJ,KAAK,CAACA;QAChB;IACF,GACA;QAACb;KAAe;IAGlB,MAAM,EACJP,MAAMyB,WAAW,EACjBC,QAAQC,cAAc,EACtB;;;;;;KAMC,GACDC,WAAWC,iBAAiB,EAC7B,GAAGhF,uBACF,IACE,kEAAkE;QAClE,mDAAmD;QACnDmC,aAAaS,aACTtD,MACEP,WAAW+D,WAAWX,SAAS,CAAC,EAAE,EAAEA,SAAS,CAAC,EAAE,EAAE,gBAC9CQ,aACA;YAACpD,MAAM,aAAa,sBAAsB+C;SAAa,GACvD,EAAE,EACNjD,MAAM,QAER,MACN;QAACyD;QAAWX;QAAWQ;QAAYL;QAAaM;KAAW,EAC3D;QAAEqC,SAAS;IAAM;IAEnB,MAAMjD,WAAWpC,QACf,IACE;eAAKgF,sBAAAA,cAAe,EAAE;SAAE,CAACM,IAAI,CAAC,CAACC,GAAGC,IAChC5D,mBAAmB2D,GAAGE,aAAa,CAAC7D,mBAAmB4D,MAE3D;QAACR;KAAY;IAEf,MAAM,CAACU,YAAYC,cAAc,GAAG1F,SAAwB;IAC5D,MAAM,CAAC2F,YAAYC,cAAc,GAAG5F,SAAS;IAC7C,MAAM6F,YACJ1D,iBAAAA,SAAS2D,IAAI,CAAC,CAACC,OAASA,KAAKC,GAAG,KAAKP,uBAArCtD,iBAAoDA,QAAQ,CAAC,EAAE;IACjE,iEAAiE;IACjE,2DAA2D;IAC3D,MAAM8D,QAAQlG,QACZ,IAAMoB,sBAAsB0E,mBAAAA,WAAY,CAAC,IACzC;QAACA;KAAS;IAEZ,MAAMK,SAAmBnG,QAAQ,IAAMkG,MAAME,KAAK,EAAE;QAACF;KAAM;IAC3D,mEAAmE;IACnE,MAAMG,eAAerG,QAAQ,IAAMc,oBAAoBoF,QAAQ;QAACA;KAAM;IAEtE,qEAAqE;IACrE,4EAA4E;IAC5E,yEAAyE;IACzE,yEAAyE;IACzE,wCAAwC;IACxC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+DC,GACD,MAAMI,aAAa/H,kBAAkB;QAAEgI,cAAcF,aAAaE,YAAY;IAAC;IAC/E,sEAAsE;IACtE,8CAA8C;IAC9C,MAAMC,gBAAgBxG,QACpB,IACEsG,WAAWG,OAAO,CAACC,MAAM,CAAC,CAACC,SACzBN,aAAaF,MAAM,CAACS,IAAI,CAAC,CAACC,QAAUA,MAAMC,MAAM,KAAKH,OAAOE,KAAK,IAErE;QAACP,WAAWG,OAAO;QAAEJ,aAAaF,MAAM;KAAC;IAE3C,MAAMY,aAAa/G,QACjB,IAAMe,gBAAgBmF,OAAOG,cAAcG,eAAeF,WAAWU,WAAW,GAChF;QAACd;QAAOG;QAAcG;QAAeF,WAAWU,WAAW;KAAC;IAE9D,iEAAiE;IACjE,MAAMC,gBAAgB7C,KAAKC,SAAS,CAAC;QACnC6C,SAASH,WAAWI,IAAI,CAACD,OAAO;QAChCE,SAASL,WAAWI,IAAI,CAACC,OAAO;IAClC;IACA,MAAM,EACJC,MAAMC,OAAO,EACbC,SAASC,cAAc,EACvBC,MAAMC,UAAU,EAChBC,SAASC,aAAa,EACtBC,UAAUC,cAAc,EACxBC,aAAaC,iBAAiB,EAC/B,GAAGzH,mBACF,CAAC0H,YACC1F,cAAauD,4BAAAA,SAAUG,GAAG,IACtBvG,MACEP,WACE+D,WACAX,SAAS,CAAC,EAAE,EACZA,SAAS,CAAC,EAAE,EACZ,YACAuD,SAASG,GAAG,EACZ,eAECvF,qBAAqBqG,WAAWI,IAAI,GACvC1H,MAAMwI,cAER,MACN;QAAC/E;QAAWX;QAAWuD,4BAAAA,SAAUG,GAAG;QAAEgB;KAAc,EACpD;QAAE5B,SAAS;IAAM;IAEnB,MAAM6C,iBAAiBlI,QACrB,IACE9B,kBAAkB6I,WAAWoB,OAAO,EAAE;YACpChC,QAAQE,aAAaF,MAAM;YAC3BjC,SAASmC,aAAanC,OAAO;YAC7BkE,SAAS/B,aAAa+B,OAAO;QAC/B,IACF;QAACrB,WAAWoB,OAAO;QAAE9B;KAAa;IAEpC,MAAMgC,mBACJ7B,cAAc8B,MAAM,GAAG,KAAKhC,WAAWU,WAAW,CAACJ,IAAI,CAAC,CAAC2B,OAASA,KAAKC,IAAI;IAC7E;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiCC,GACD,MAAM,CAACC,mBAAmBC,qBAAqB,GAAGzI,SAAS;IAC3D,MAAM,CAAC0I,kBAAkBC,oBAAoB,GAAG3I,SAAS;IACzD,MAAM,CAAC4I,oBAAoBC,sBAAsB,GAAG7I,SAClD;IAEF,uEAAuE;IACvE,yEAAyE;IACzE,sEAAsE;IACtE,0EAA0E;IAC1E,MAAM,CAAC8I,mBAAmBC,qBAAqB,GAAG/I,SAGxC;IACVF,UAAU;QACR,IAAI,CAACwC,WAAW;QAChB,IAAI0G,SAAS;QACb,uEAAuE;QACvE,sEAAsE;QACtE,qEAAqE;QACrE,+DAA+D;QAC/D,KAAK1J,mBACHJ,WAAW+D,WAAWX,SAAS,CAAC,EAAE,EAAEA,SAAS,CAAC,EAAE,EAAE,aAEjD2G,IAAI,CAAC,CAACC;YACL,IAAIF,QAAQH,sBAAsBK,SAAS5F,IAAI,GAAG6F,KAAK;QACzD,GACC5E,KAAK,CAAC;QACL,oEAAoE;QACpE,kEAAkE;QAClE,gEAAgE;QAChE,4CAA4C;QAC9C;QACF,OAAO;YACLyE,SAAS;QACX;IACF,GAAG;QAAC/F;QAAWX;QAAWkG;KAAkB;IAC5C,qEAAqE;IACrE,uEAAuE;IACvE,MAAMY,mBAAuCvD,4BAAAA,SAAUG,GAAG;IAC1DlG,UAAU;QACR,IAAI,CAACwC,aAAa,CAAC8G,kBAAkB;QACrC,IAAIJ,SAAS;QACb,KAAK1J,mBACHJ,WACE+D,WACAX,SAAS,CAAC,EAAE,EACZA,SAAS,CAAC,EAAE,EACZ,YACA8G,kBACA,YAGDH,IAAI,CAAC,CAACC;YACL,IAAIF,QAAQ;gBACVD,qBAAqB;oBACnBnE,WAAWwE;oBACXD,OAAOD,SAAS5F,IAAI,GAAG6F,KAAK;gBAC9B;YACF;QACF,GACC5E,KAAK,CAAC;QACL,uCAAuC;QACzC;QACF,OAAO;YACLyE,SAAS;QACX;IACF,GAAG;QAAC/F;QAAWX;QAAW8G;QAAkBV;KAAiB;IAC7D,wEAAwE;IACxE,sEAAsE;IACtE,yEAAyE;IACzE,wEAAwE;IACxE,yEAAyE;IACzE,mDAAmD;IACnD,MAAMW,eAAeT,6BAAAA,qBAAsBzG,SAASkG,MAAM;IAC1D,MAAMiB,cACJR,qBAAqBA,kBAAkBlE,SAAS,KAAKwE,mBACjDN,kBAAkBK,KAAK,GACvB9B,QAAQgB,MAAM;IAEpB,2EAA2E;IAC3E,MAAM,CAACkB,SAASC,WAAW,GAAGxJ,SAGpB;IACV,MAAMyJ,oBAAoB5J,YAAY;QACpC,IAAI,CAACtC,iBAAiB6F,KAAK,cAAc;YACvC,OAAOF,gBACL,2DACA;gBAAEwG,SAAS;gBAAWC,SAAS;YAAM;QAEzC;QACA,kEAAkE;QAClE,sEAAsE;QACtE,0DAA0D;QAC1D,MAAMC,QAAQtM,kBAAkB8F,KAAYiG;QAC5C,IAAI,CAACO,MAAMC,OAAO,EAAE;YAClB,OAAO3G,gBACL0G,MAAME,eAAe,GACjB,CAAC,uBAAuB,EAAEF,MAAMpK,KAAK,CAAC,sBAAsB,CAAC,GAC7D,CAAC,uBAAuB,EAAEoK,MAAMpK,KAAK,CAAC,uBAAuB,CAAC,GAC9D,CAAC,KAAK,EAAEoK,MAAMG,aAAa,CAAC,8BAA8B,CAAC,EAC/D;gBAAEL,SAAS;gBAAWC,SAAS;YAAM;QAEzC;QACAH,WAAW;YAAEQ,MAAM;YAAI9D,QAAQ;QAAG;IACpC,GAAG;QAAC9C;QAAKiG;QAAcnG;KAAgB;IACvC,2DAA2D;IAC3D,sEAAsE;IACtE,MAAM+G,iBAAiBrI,iCAAyB2H,2BAAAA,QAASrD,MAAM,mBAAI;IACnE,MAAMgE,gBAAgBD,eAAeE,GAAG,CAAC,CAACC,QAAUA,MAAMC,EAAE;IAC5D,MAAMC,eAAezK,YAAY;QAC/B,oEAAoE;QACpE,sEAAsE;QACtE,yEAAyE;QACzE,uEAAuE;QACvE,iEAAiE;QACjE,yEAAyE;QACzE,IAAI,EAAC0J,2BAAAA,QAASS,IAAI,CAACzB,IAAI,OAAM2B,cAAc7B,MAAM,KAAK,KAAK,CAAC9F,OAAO;QACnE,IAAI8H;QACJ,IAAI;YACF,MAAMhG,SAAS,MAAMR,eAAe;gBAClCgB,QAAQ;gBACR0F,aAAahB,QAAQS,IAAI,CAACzB,IAAI;gBAC9BrC,QAAQgE;gBACR,mEAAmE;gBACnEjE,OAAO5E,sBAAsB4I;eAC1BvG;YAEL2G,KAAKG,OAAOnG,OAAOgG,EAAE;QACvB,EAAE,OAAO3F,OAAY;;YACnB,OAAO,KAAKxB,wBAAgBwB,yBAAAA,MAAO+F,OAAO,mBAAI,yBAAyB;gBACrEf,SAAS;gBACTC,SAAS;YACX;QACF;QACAH,WAAW;QACX9D,cAAc2E;QACd5B,qBAAqB,CAACiC,QAAUA,QAAQ;QACxCxH,gBAAgB,CAAC,SAAS,EAAEqG,QAAQS,IAAI,CAACzB,IAAI,GAAG,SAAS,CAAC,EAAE;YAC1DmB,SAAS;YACTC,SAAS;QACX;QACAtG,YAAY,mBAAmB;YAC7BsH,MAAM;YACNN;YACAL,MAAMT,QAAQS,IAAI,CAACzB,IAAI;QACzB;IACF,GAAG;QAACgB;QAASU;QAAgBC;QAAe3H;QAAOmB;QAAaG;QAAgBX;QAAiBG;KAAY;IAE7G,kEAAkE;IAClE,yDAAyD;IACzD,MAAM,CAACuH,QAAQC,UAAU,GAAG7K,SAA0C;IACtE,MAAM8K,mBAAmBjL,YAAY;QACnC,IAAI,EAAC+K,0BAAAA,OAAQtF,CAAC,KAAI,EAACsF,0BAAAA,OAAQrF,CAAC,KAAIqF,OAAOtF,CAAC,KAAKsF,OAAOrF,CAAC,EAAE;QACvD,MAAMD,IAAInD,SAAS2D,IAAI,CAAC,CAACC,OAASA,KAAKC,GAAG,KAAK4E,OAAOtF,CAAC;QACvD,MAAMC,IAAIpD,SAAS2D,IAAI,CAAC,CAACC,OAASA,KAAKC,GAAG,KAAK4E,OAAOrF,CAAC;QACvD,oEAAoE;QACpE,mEAAmE;QACnE,8CAA8C;QAC9C,IAAI,CAACD,KAAK,CAACC,KAAK,CAAChD,OAAO;QACxB,MAAMwI,WAAW,CAACC,QAAaC,UAAqB,CAAA;gBAClDjB,MAAMrI,mBAAmBqJ,WAAWC;gBACpCN,MAAM;gBACNO,UAAU;gBACVC,WAAW;oBACTvG,WAAWoG,OAAOhF,GAAG;oBACrBoF,gBAAgBjK,sBAAsB6J,QAAQ7E,KAAK,CAAC,EAAE;oBACtDkF,UAAU;gBACZ;YACF,CAAA;QACA,MAAMvH,UAAU;YACdyG,aAAa,GAAG5I,mBAAmB2D,GAAG,GAAG,EAAE3D,mBAAmB4D,IAAI;YAClEW,QAAQ;gBAAC;gBAAQ;aAAO;YACxBD,OAAO;gBACLE,OAAO;oBAAC;oBAAQ;iBAAO;gBACvBD,QAAQ;oBAAEoF,MAAMP,SAASzF,GAAG;oBAASiG,MAAMR,SAASxF,GAAG;gBAAQ;YACjE;QACF;QACA,IAAI8E;QACJ,IAAI;YACF,MAAMhG,SAAS,MAAMR,eAAe;gBAClCgB,QAAQ;eACLf,SAEAJ;YAEL2G,KAAKG,OAAOnG,OAAOgG,EAAE;QACvB,EAAE,OAAO3F,OAAY;;YACnB,OAAO,KAAKxB,wBAAgBwB,yBAAAA,MAAO+F,OAAO,mBAAI,sBAAsB;gBAClEf,SAAS;gBACTC,SAAS;YACX;QACF;QACAkB,UAAU;QACVnF,cAAc2E;QACd,8DAA8D;QAC9D5B,qBAAqB,CAACiC,QAAUA,QAAQ;QACxCxH,gBAAgB,2BAA2B;YACzCwG,SAAS;YACTC,SAAS;QACX;IACF,GAAG;QAACiB;QAAQzI;QAAUI;QAAOmB;QAAaG;QAAgBX;KAAgB;IAE1E,MAAMsI,sBAAsB3L,YAAY;QACtC,IAAI,CAACgG,UAAU;QACf,MAAM4F,YAAY,MAAMtI,QAAQ;YAC9BuI,OAAO;YACPC,aACE,CAAC,CAAC,EAAEhK,mBAAmBkE,UAAU,CAAC,CAAC,GACnC,mEAAmE;YACnE,+DAA+D;YAC9DyD,CAAAA,cACG,CAAC,SAAS,EAAEA,YAAY,SAAS,EAAEA,gBAAgB,IAAI,KAAK,KAAK,GACjE,EAAC,IACL,gEACA;YACFsC,kBAAkB;YAClBC,yBAAyB;gBAAEC,OAAO;YAAQ;QAC5C,GACG7C,IAAI,CAAC,IAAM,MACX1E,KAAK,CAAC,IAAM;QACf,IAAI,CAACkH,aAAa,CAACnJ,WAAW;QAC9B,kEAAkE;QAClE,uEAAuE;QACvE,gEAAgE;QAChE,6DAA6D;QAC7D,IAAI;;YACF,MAAMyB,WAAW,MAAMrD,gBAAgB6C,MAAM,wBAAwB;gBACnES,QAAQ;gBACRC,SAAS;oBAAE,gBAAgB;gBAAmB;gBAC9CC,MAAMC,KAAKC,SAAS,CAAC;oBACnB/B,OAAOC,SAAS,CAAC,EAAE;oBACnByJ,SAASzJ,SAAS,CAAC,EAAE;oBACrB0J,MAAM;oBACN3B,IAAIxE,SAASG,GAAG;oBAChB,+DAA+D;oBAC/D,+DAA+D;oBAC/D,8DAA8D;oBAC9D5D;gBACF;YACF;YACA,MAAMiC,SAAS,MAAMN,SAASO,IAAI,GAAGC,KAAK,CAAC,IAAO,CAAA,CAAC,CAAA;YACnD,IAAI,CAACR,SAASS,EAAE,EAAE,MAAM,IAAIC,cAAMJ,0BAAAA,OAAQK,KAAK,mBAAI;QACrD,EAAE,OAAOA,OAAY;;YACnB,OAAO,KAAKxB,yBAAgBwB,yBAAAA,MAAO+F,OAAO,oBAAI,yBAAyB;gBACrEf,SAAS;gBACTC,SAAS;YACX;QACF;QACAjE,cAAc;QACd+C,qBAAqB,CAACiC,QAAUA,QAAQ;QACxCxH,gBAAgB,mBAAmB;YAAEwG,SAAS;YAAWC,SAAS;QAAM;QACxEtG,YAAY,mBAAmB;YAC7BsH,MAAM;YACNN,IAAIxE,SAASG,GAAG;YAChBgE,MAAMrI,mBAAmBkE;QAC3B;IACF,GAAG;QACDA;QACAyD;QACAnG;QACAb;QACAF;QACAmB;QACAL;QACAG;KACD;IAED,qEAAqE;IACrE,sDAAsD;IACtD,MAAM,CAAC4I,YAAYC,cAAc,GAAGlM,SAElC,CAAC;IACHF,UAAU;QACR,IAAIkJ,SAAS;QACb,MAAMmD,kBAAkBlG,MAAME,KAAK,CAACM,MAAM,CACxC,CAACwE;gBACChF,uBACAA,iCAAAA;mBADAA,EAAAA,wBAAAA,MAAMC,MAAM,CAAC+E,QAAQ,qBAArBhF,sBAAuB0E,IAAI,MAAK,iBAChC1E,yBAAAA,MAAMC,MAAM,CAAC+E,QAAQ,sBAArBhF,kCAAAA,uBAAuBkF,SAAS,qBAAhClF,gCAAkCrB,SAAS;;QAE/C,IAAI,CAACuH,gBAAgB9D,MAAM,IAAI,CAAC/F,WAAW;YACzC4J,cAAc,CAAC;YACf;QACF;QACA,KAAKE,QAAQC,GAAG,CACdF,gBAAgBhC,GAAG,CAAC,OAAOc;gBASvBE;YARF,MAAMA,YAAYlF,MAAMC,MAAM,CAAC+E,QAAQ,CAACE,SAAS;YAIjD,MAAMH,SAAS7I,SAAS2D,IAAI,CAC1B,CAACC,OAASA,KAAKC,GAAG,KAAKmF,UAAUvG,SAAS;YAE5C,MAAMwG,kBACJD,4BAAAA,UAAUC,cAAc,YAAxBD,4BACAhK,sBAAsB6J,iBAAAA,SAAU,CAAC,GAAG7E,KAAK,CAAC,EAAE;YAC9C,MAAM+C,WAAW,MAAM3J,QACrBE,MACEP,WACE+D,WACAX,SAAS,CAAC,EAAE,EACZA,SAAS,CAAC,EAAE,EACZ,YACA6I,UAAUvG,SAAS,EACnB,YAEFpF,MAAM,OAER+E,KAAK,CAAC,IAAM;YACd,MAAM4D,UAAU,SAACe,4BAAAA,SAAUoD,IAAI,mBAAI,EAAE,EAAEnC,GAAG,CAAC,CAACoC;;oBAGxCA;uBAHyD;oBAC3DlC,IAAIkC,YAAYlC,EAAE;oBAClBmC,OAAOhC,gBACL+B,mBAAAA,YAAYE,GAAG,CAAC,8BAAhBF,gBAA2B,CAACnB,yBAAAA,iBAAkB,GAAG,mBAC/CmB,YAAYlC,EAAE;gBAEpB;;YACA,OAAO;gBAACY;gBAAS9C;aAAQ;QAC3B,IACAc,IAAI,CAAC,CAACyD;YACN,IAAI1D,QAAQkD,cAAcS,OAAOC,WAAW,CAACF;QAC/C;QACA,OAAO;YACL1D,SAAS;QACX;IACF,GAAG;QAAC/C;QAAO9D;QAAUc;QAAWX;KAAU;IAC1C;;;;;;;;;;;;;GAaC,GACD,MAAMuK,wBAAwBhN,YAC5B,CAACoL,SAAiBZ;;YAChB4B,0BAAAA;wBAAAA,sBAAAA,UAAU,CAAChB,QAAQ,sBAAnBgB,2BAAAA,oBAAqBnG,IAAI,CAAC,CAACgH,SAAWA,OAAOzC,EAAE,KAAKA,wBAApD4B,yBAAyDO,KAAK,mBAAI;OACpE;QAACP;KAAW;IAEd,MAAMc,iBAAiBlN,YACrB,CAACoL,SAAiB+B;QAChB,MAAMC,MAAMC,MAAMC,OAAO,CAACH,SAASA,QAAQA,SAAS,OAAO;YAACA;SAAM,GAAG,EAAE;QACvE,OAAOC,IACJ9C,GAAG,CAAC,CAACE;gBAAOwC;oBAAAA,yBAAAA,sBAAsB5B,SAAST,OAAOH,gBAAtCwC,yBAA8CrC,OAAOH;WACjE+C,IAAI,CAAC;IACV,GACA;QAACP;KAAsB;IAEzB;;;;;;;;;;;GAWC,GACD,MAAM,CAACQ,UAAUC,YAAY,GAAGtN,SAAwB;IACxD,MAAMuN,eAAexN,QACnB;YAEOsH;eADLgG,YACKhG,gBAAAA,QAAQvB,IAAI,CAAC,CAAC0H,SAAgBA,OAAOxH,GAAG,KAAKqH,qBAA7ChG,gBAA0D,OAC3D;OACN;QAACgG;QAAUhG;KAAQ;IAGrB,2EAA2E;IAC3E,MAAM,CAACoG,QAAQC,UAAU,GAAG1N,SAIlB;IACV,MAAM2N,mBAAmB9N,YACvB,CAAC2N,SAAiB;gBA2BYA;YA1B5B,IAAI,CAACA,QAAQ;gBACX,6DAA6D;gBAC7D,MAAM5D,QAAQpM,WAAW4F,KAAK,qBAAqBkG;gBACnD,IAAI,CAACM,MAAMC,OAAO,EAAE;oBAClB,OAAO3G,gBACL,CAAC,sBAAsB,EAAE0G,MAAMpK,KAAK,CAAC,0BAA0B,CAAC,EAChE;wBAAEkK,SAAS;wBAAWC,SAAS;oBAAM;gBAEzC;YACF;YACA,MAAMiE,SAAiC,CAAC;YACxC,KAAK,MAAM3C,WAAWhF,MAAME,KAAK,CAAE;gBACjC,MAAMS,QAAQX,MAAMC,MAAM,CAAC+E,QAAQ;gBACnC,IAAI,CAACrE,OAAO;gBACZ,IAAI4G,QAAQ;wBAGRA;oBAFFI,MAAM,CAAC3C,QAAQ,GAAG/J,oBAChB0F,QACA4G,kBAAAA,OAAOI,MAAM,qBAAbJ,eAAe,CAACvC,QAAQ;gBAE5B,OAAO,IAAIrE,MAAMiH,OAAO,IAAI,MAAM;oBAChCD,MAAM,CAAC3C,QAAQ,GAAGT,OAAO5D,MAAMiH,OAAO;gBACxC;YACF;YACA,kEAAkE;YAClE,8DAA8D;YAC9D,MAAMC,SAASN,SACXlM,iBAAiB2E,QAAOuH,iBAAAA,OAAOI,MAAM,YAAbJ,iBAAiB,CAAC,KAC1C,CAAC;YACLE,UAAU;gBAAErD,EAAE,UAAEmD,0BAAAA,OAAQxH,GAAG,mBAAI;gBAAM4H;gBAAQE;YAAO;QACtD,GACA;QAAC1K;QAAKkG;QAAarD;QAAO/C;KAAgB;IAE5C,MAAM6K,mBAAmBlO,YAAY;QACnC,IAAI,CAAC4N,UAAU,CAAC5H,YAAY,CAACvD,WAAW;QACxC,uEAAuE;QACvE,kEAAkE;QAClE,MAAM0L,UAAUzM,oBACd0E,OACAjF,qBAAqBiF,OAAOwH,OAAOG,MAAM;QAE3C,MAAME,SAASxM,iBAAiB2E,OAAO+H;QACvC,IAAIrB,OAAOsB,IAAI,CAACH,QAAQzF,MAAM,EAAE;YAC9B,OAAO,KAAKqF,UAAU,CAACQ,OAAUA,OAAO,aAAKA;oBAAMJ;qBAAWI;QAChE;QACA,sEAAsE;QACtE,wEAAwE;QACxE,IAAI;YACF,IAAIT,OAAOpD,EAAE,EAAE;gBACb,kDAAkD;gBAClD,MAAM8D,YAAY9O,IAChB4D,WACAX,SAAS,CAAC,EAAE,EACZA,SAAS,CAAC,EAAE,EACZ,YACAuD,SAASG,GAAG,EACZ,WACAyH,OAAOpD,EAAE;gBAEX,MAAM1K,OACJwO,WACA;oBACEP,QAAQI;mBAIL/M,uBAAuBgF,OAAO+H,SAAS5O;oBAC1CgP,WAAW5P,UAAU6P,GAAG;oBAE1B;oBACEC,aAAa;wBAAC;wBAAU;wBAAiB;wBAAc;wBAAgB;qBAAY;gBACrF;gBAEF,MAAM3J,gBAAgBkB,SAASG,GAAG;YACpC,OAAO;gBACL,mEAAmE;gBACnE,kEAAkE;gBAClE,oEAAoE;gBACpE,+CAA+C;gBAC/C,MAAMnC,eAAe;oBACnBgB,QAAQ;oBACRD,WAAWiB,SAASG,GAAG;oBACvB4H,QAAQI;gBACV;YACF;QACF,EAAE,OAAOtJ,OAAY;;YACnB,OAAO,KAAKxB,wBAAgBwB,yBAAAA,MAAO+F,OAAO,mBAAI,sBAAsB;gBAClEf,SAAS;gBACTC,SAAS;YACX;QACF;QACA+D,UAAU;QACV,iEAAiE;QACjE,4DAA4D;QAC5D,IAAI,CAACD,OAAOpD,EAAE,EAAE1B,oBAAoB,CAAC+B,QAAUA,QAAQ;QACvDxH,gBAAgBuK,OAAOpD,EAAE,GAAG,iBAAiB,gBAAgB;YAC3DX,SAAS;YACTC,SAAS;QACX;QACAtG,YAAYoK,OAAOpD,EAAE,GAAG,mBAAmB,gBAAgB;YACzDM,MAAM;YACNN,IAAIxE,SAASG,GAAG;YAChBgE,MAAMrI,mBAAmBkE;QAC3B;IACF,GAAG;QACD4H;QACA5H;QACA5C;QACAX;QACA2D;QACApC;QACAc;QACAzB;QACAG;KACD;IACD,MAAMkL,qBAAqB1O,YACzB,CAAC2N,SAAgB;YACf,kEAAkE;YAClE,qEAAqE;YACrE,6BAA6B;YAC7B,MAAMgB,cAAc,IAAIC;YACxB,IAAI,CAAC5I,YAAY,CAACvD,WAAW;YAC7B;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OA6BC,GACD,KAAK,MAAMoM,SAASvM,SAAU;gBAC5B,MAAMwM,aAAaxN,sBAAsBuN;gBACzC,IAAI,CAACjN,oBAAoBkN,YAAY9I,SAASG,GAAG,EAAEqC,MAAM,EAAE;gBAC3D,IAAIa;gBACJ,IAAI;oBACFA,WAAW,MAAM3J,QACfE,MACEP,WACE+D,WACAX,SAAS,CAAC,EAAE,EACZA,SAAS,CAAC,EAAE,EACZ,YACAoM,MAAM1I,GAAG,EACT,YAEFtG,MAAM,iBAAiB,kBAAkB8N,OAAOxH,GAAG;gBAGzD,EAAE,eAAM;oBACN,OAAO,KAAK9C,gBACV,CAAC,gBAAgB,EAAEvB,mBAAmB+M,OAAO,2BAA2B,CAAC,GACvE,iEACA,gBACF;wBAAEhF,SAAS;oBAAQ;gBAEvB;gBACA,kEAAkE;gBAClE,qEAAqE;gBACrE,mEAAmE;gBACnE,MAAMxC,OAAO1F,oBACXmN,YACA9I,SAASG,GAAG,EACZwH,OAAOxH,GAAG,EACVkD,SAASoD,IAAI,CAACnC,GAAG,CAAC,CAACoC,cAAiB,CAAA;wBAAElC,IAAIkC,YAAYlC,EAAE;wBAAEuD,QAAQrB,YAAYE,GAAG,CAAC;oBAAU,CAAA;gBAE9F,IAAIvF,KAAK8E,IAAI,KAAK,QAAQ;gBAC1B,IAAI9E,KAAK8E,IAAI,KAAK,cAAc;oBAC9B,OAAO,KAAK9I,gBACVxB,wBAAwBwF,KAAK0H,OAAO,EAAEjN,mBAAmB+M,SACzD;wBAAEhF,SAAS;wBAAWC,SAAS;oBAAM;gBAEzC;gBACA,sEAAsE;gBACtE,sEAAsE;gBACtE,+BAA+B;gBAC/B,IAAK,IAAIkF,QAAQ,GAAGA,QAAQ3H,KAAK4H,OAAO,CAACzG,MAAM,EAAEwG,SAAS,IAAK;oBAC7D,MAAME,QAAQnP,WAAWqD;oBACzB,KAAK,MAAM+L,UAAU9H,KAAK4H,OAAO,CAACG,KAAK,CAACJ,OAAOA,QAAQ,KAAM;wBAC3D,MAAMK,SAAShG,SAASoD,IAAI,CAACxG,IAAI,CAAC,CAACyG,cAAgBA,YAAYlC,EAAE,KAAK2E,OAAO3E,EAAE;wBAC/E,IAAI,CAAC6E,QAAQ;wBACbH,MAAMC,MAAM,CAACE,OAAOC,GAAG,EAAE;4BACvBvB,QAAQoB,OAAOpB,MAAM;2BAClB3M,uBAAuB0N,YAAYK,OAAOpB,MAAM,EAAExO;oBAEzD;oBACA,MAAM2P,MAAMK,MAAM;gBACpB;gBACA,sEAAsE;gBACtE,+CAA+C;gBAC/CZ,YAAYa,GAAG,CAACX,MAAM1I,GAAG;YAC3B;YACA,MAAM7G,UACJE,IACE4D,WACAX,SAAS,CAAC,EAAE,EACZA,SAAS,CAAC,EAAE,EACZ,YACAuD,SAASG,GAAG,EACZ,WACAwH,OAAOxH,GAAG;YAGd2C,oBAAoB,CAAC+B,QAAUA,QAAQ;YACvC,KAAK,MAAM9F,aAAa;gBAACiB,SAASG,GAAG;mBAAKwI;aAAY,CAAE;gBACtD,MAAM7J,gBAAgBC;YACxB;YACA1B,gBAAgB,kBAAkB;gBAAEwG,SAAS;gBAAWC,SAAS;YAAM;QACzE,GACA;QAAC9D;QAAU1D;QAAUc;QAAWX;QAAWqC;QAAiBzB;KAAgB;IAG9E;;;;;;;;;GASC,GACD,MAAMoM,WAAW3R;IACjB,MAAM4R,iBAAiB1J,CAAAA,4BAAAA,SAAUG,GAAG,IAChC;QAAEwJ,UAAU3N,2BAA2BgE,SAASG,GAAG;QAAG3D,OAAO;IAAe,IAC5E;IACJ,MAAMoN,YAAYzM,QAAQsM,YAAYC,kBAAkBD,SAASI,GAAG,CAAC,UAAUH;IAC/E,MAAMI,YAAY3M,QAAQsM,YAAYC,kBAAkBD,SAASI,GAAG,CAAC,UAAUH;IAC/E,MAAMK,eAAe/P,YAAY;QAC/B,IAAI,CAACyP,YAAY,EAACzJ,4BAAAA,SAAUG,GAAG,GAAE;QACjC,MAAM6J,UAAU;YAAExF,IAAIxE,SAASG,GAAG;YAAEgE,MAAMrI,mBAAmBkE;QAAU;QACvEyJ,SAASQ,UAAU,CAAC;YAClBN,UAAU3N,2BAA2BgO,QAAQxF,EAAE;YAC/ChI,OAAO;YACPqJ,OAAOmE,QAAQ7F,IAAI,GAAG,CAAC,YAAY,EAAE6F,QAAQ7F,IAAI,EAAE,GAAG;YACtD+F,YAAY;gBACV,qEAAqE;gBACrEpH,oBAAoB,CAAC+B,QAAUA,QAAQ;gBACvCrH,YAAY,oBAAoB;oBAAEsH,MAAM;oBAAWN,IAAIwF,QAAQxF,EAAE;oBAAEL,MAAM6F,QAAQ7F,IAAI;gBAAC;YACxF;QACF;IACF,GAAG;QAACsF;QAAUzJ;QAAUxC;KAAY;IACpC,MAAM2M,eAAenQ,YAAY;QAC/B,IAAI,CAACyP,YAAY,EAACzJ,4BAAAA,SAAUG,GAAG,GAAE;QACjC,MAAMgE,OAAOrI,mBAAmBkE;QAChCyJ,SAASW,UAAU,CAAC;YAClBT,UAAU3N,2BAA2BgE,SAASG,GAAG;YACjD3D,OAAO;YACPqJ,OAAO1B,OAAO,CAAC,OAAO,EAAEA,MAAM,GAAG;WAG7B5B,mBACA;YACE3B,QAAQ;gBACN+F,OAAO;gBACPQ,OAAO;oBAAExG,SAASD;oBAAe2J,QAAQ7J,WAAWU,WAAW;gBAAC;YAClE;QACF,IACA,CAAC;IAET,GAAG;QAACuI;QAAUzJ;QAAUuC;QAAkB7B;QAAeF,WAAWU,WAAW;KAAC;IAEhF;;;;;GAKC,GACD,MAAMoJ,oBAAoBpQ,QACxB,IACE1B,sBACE;eACK6H,OAAOiE,GAAG,CAAC,CAACc;;gBACb,MAAMrE,QAAQX,MAAMC,MAAM,CAAC+E,QAAQ;gBACnC,OAAO;oBACLrE,OAAO7F,aAAakK;oBACpBmF,UAAU,UAAExJ,yBAAAA,MAAOoD,IAAI,mBAAIiB;oBAC3B,wDAAwD;oBACxDU,WAAW,EAAE/E,yBAAAA,MAAO+E,WAAW;oBAC/B0E,MAAM;oBACNC,UAAU;oBACVC,YAAY,CAAC,EAAEC,GAAG,EAAgB;4BAEJA,aAEIA;+BAHhC5J,CAAAA,yBAAAA,MAAO+D,IAAI,MAAK,cACZoC,eAAe9B,UAASuF,cAAAA,IAAI5C,MAAM,qBAAV4C,WAAY,CAACvF,QAAQ,KAAK,OAClDrE,QACExF,mBAAmBwF,QAAO4J,eAAAA,IAAI5C,MAAM,qBAAV4C,YAAY,CAACvF,QAAQ,KAAK,OACpD;;gBACV;YACF;YACA9M,kBACE,CAACqP,uBACC,MAACzO;oBACC0R,WAAU;oBACVC,IAAI;wBAAEC,QAAQ;wBAAQC,YAAY;wBAAUC,gBAAgB;oBAAW;;sCAEvE,KAACpS;4BAAOqS,MAAK;4BAAQC,SAAS,IAAMzD,YAAYE,OAAOxH,GAAG;sCACvD;;sCAEH,KAACvH;4BAAOqS,MAAK;4BAAQC,SAASpD,iBAAiBH;sCAC5C;;sCAEH,KAAC/O;4BACCqS,MAAK;4BACLhF,OAAM;4BACNiF,SAASxC,mBAAmBf;sCAE3B;;;oBAIP;gBAAEwD,OAAO;YAAI;SAEhB,EACD5K,aAAaF,MAAM,EACnBE,aAAa+B,OAAO,EACpB/B,aAAanC,OAAO,GAExB;QACEiC;QACAD;QACA8G;QACAY;QACAY;QACAnI;KACD;IAGH;;;;;;GAMC,GACD,MAAM6K,kBAAkBlR,QACtB,IACE4M,OAAOC,WAAW,CAChB1G,OAAOiE,GAAG,CAAC,CAACc;YACV,MAAMrE,QAAQX,MAAMC,MAAM,CAAC+E,QAAQ;YACnC,OAAO;gBACLlK,aAAakK;gBACb,CAACuF;wBACeA;oBAAd,MAAMxD,SAAQwD,cAAAA,IAAI5C,MAAM,qBAAV4C,WAAY,CAACvF,QAAQ;oBACnC,IAAIrE,CAAAA,yBAAAA,MAAO+D,IAAI,MAAK,aAAa,OAAOoC,eAAe9B,SAAS+B,UAAU;oBAC1E,IAAI,OAAOA,UAAU,YAAY,OAAOA,UAAU,WAAW,OAAOA;oBACpE,OAAOpG,QAAQxF,mBAAmBwF,OAAOoG,UAAU,OAAO;gBAC5D;aACD;QACH,KAEJ;QAAC9G;QAAQD;QAAO8G;KAAe;IAEjC,MAAMmE,oBAAoBnR,QACxB,IACE4M,OAAOC,WAAW,CAChB1G,OAAOiE,GAAG,CAAC,CAACc;;gBAAoChF;mBAAxB;gBAAClF,aAAakK;yBAAUhF,wBAAAA,MAAMC,MAAM,CAAC+E,QAAQ,qBAArBhF,sBAAuB+D,IAAI,mBAAIiB;aAAQ;aAE3F;QAAC/E;QAAQD;KAAM;IAEjB,MAAMkL,mBAAmBlR,kBAAuB;QAC9CmR,OAAOtP;QACPsF,MAAMC;QACNgK,WAAWJ;QACXhN,SAASiN;IACX;IAEA,qBACE,MAACtT;QACC0T,QAAQ;QACRC,MAAM7T,eAAe,YAAY;YAAE8T,QAAQ;QAAkB;QAC7DC,cAAc;QACdC,cAAc;QACdC,iBAAgB;;0BAEhB,MAAC5S;gBAAM6S,SAAS;;oBACbrP,sBACC,KAACtD;wBAAWyK,SAAQ;wBAAUoC,OAAM;kCAGjC/J,sBAAsB4B;yBAEvB;oBACHxB,SAASkG,MAAM,KAAK,kBACnB,KAACpJ;wBAAWyK,SAAQ;wBAAQoC,OAAM;kCAC/B,kEACC;uCAGJ,MAAC/M;wBACC0R,WAAU;wBACVmB,SAAS;wBACTC,UAAU;wBACVnB,IAAI;4BAAEE,YAAY;4BAAUkB,UAAU;wBAAO;;0CAI7C,KAAC9S;gCACC+S,MAAM;gCACNjB,MAAK;gCACLtE,OAAM;gCACNQ,KAAK,WAAEnH,4BAAAA,SAAUG,GAAG,oBAAI;gCACxBgM,UAAU,CAACC,QAAUvM,cAAcuM,MAAMjH,MAAM,CAACgC,KAAK;gCACrD0D,IAAI;oCAAEJ,UAAU;gCAAI;0CAEnBnO,SAASgI,GAAG,CAAC,CAACpE,qBACb,KAACjH;wCAAwBkO,OAAOjH,KAAKC,GAAG;kDACrCrE,mBAAmBoE;uCADPA,KAAKC,GAAG;;0CAK3B,KAACvH;gCACCqS,MAAK;gCACLhF,OAAM;gCACNiF,SAASpD;0CAER;;0CAEH,KAAClP;gCAAOqS,MAAK;gCAAQC,SAAS,IAAMnL,cAAc;0CAC/C;;4BAGF2J,+BACC,KAAClS;gCACC2N,QAAQuE;+BACH1J,WAAW;gCAAE6F,OAAO,CAAC,YAAY,EAAE/J,mBAAmBkE,WAAW;4BAAC,IAAI,CAAC;gCAC5EkK,YAAY,IAAMpH,oBAAoB,CAAC+B,QAAUA,QAAQ;kCAEzD;4BACH+E,0BACC,KAAChR;gCAAOqS,MAAK;gCAAQC,SAASnB;0CAC3B;iCAED;4BAIHD,aAAcrG,CAAAA,eAAejC,QAAQgB,MAAM,AAAD,kBACzC,KAAC5J;gCAAOqS,MAAK;gCAAQC,SAASf;0CAC3B;iCAED;0CACJ,KAACvR;gCAAOqS,MAAK;gCAAQhF,OAAM;gCAAQiF,SAASvF;0CACzC;;;;oBAQN3F,yBACC,KAACzH;wBACC8T,OAAO9O,OAAO;wBACd+O,MAAM7I;wBACN9J,OAAOhC,WAAW4F,KAAK,qBAAqBkG,aAAa9J,KAAK;wBAC9D4S,MAAK;yBAEL;oBACHvM,YAAawB,CAAAA,QAAQgB,MAAM,GAAG,KAAKZ,aAAa,KAAKW,gBAAe,kBACnE;;0CACA,KAACtK;gCACCoI,QAAQE,aAAaF,MAAM;gCAC3BjC,SAASmC,aAAanC,OAAO;gCAC7BuC,SAASD;gCACTyL,UAAU3L,WAAWgM,UAAU;gCAC/BlK,SAAS/B,aAAa+B,OAAO;;0CAE/B,KAACnK;gCACCkK,SAASD;gCACTqK,SAAS;uCAAIxL,WAAWwL,OAAO;uCAAKnB,iBAAiBmB,OAAO;iCAAC;;0CAE/D,KAACpU;gCACCqU,cAAW;gCACXnL,MAAM+J,iBAAiB/J,IAAI;gCAC3BoL,YAAYrB;gCACZsB,SAAStC;gCACTuC,QAAQ,CAACrI,KAAOiD,YAAYjD;gCAC5B,6DAA6D;gCAC7D,iCAAiC;gCACjCsI,UAAU;gCACVC,YAAW;gCACXC,aAAaxM,WAAWwM,WAAW;gCACnCC,qBAAqBzM,WAAWyM,mBAAmB;gCACnDC,WAAW;gCACXC,aACE5K,mBAAmB,mCAAmC;;0CAU1D,KAACrK;gCACCyJ,MAAMC;gCACNG,UAAUC;gCACVoL,UAAU5L,QAAQgB,MAAM;gCACxBf,SAASC;gCACT2L,cAAcvL;gCACdwL,kBAAkBpL;;;yBAGlBlC,yBACF,KAAC5G;wBAAWyK,SAAQ;wBAAQoC,OAAM;kCAC/B;yBAED;kCACJ,MAAC/M;wBACC0R,WAAU;wBACVmB,SAAS;wBACTC,UAAU;wBACVnB,IAAI;4BAAEoB,UAAU;wBAAO;;0CAEvB,KAACrT;gCACCqS,MAAK;gCACLpH,SAAQ;gCACRoC,OAAM;gCACNiF,SAAStH;0CAER;;4BAEFtH,SAASkG,MAAM,IAAI,kBAClB,KAAC5J;gCAAOqS,MAAK;gCAAQC,SAAS,IAAMlG,UAAU;wCAAEvF,GAAG;wCAAIC,GAAG;oCAAG;0CAC1D;iCAED;;;;;0BAGR,MAAC7G;gBACC0U,MAAMpQ,QAAQuG;gBACd8J,SAAS,IAAM7J,WAAW;gBAC1B8J,UAAS;gBACTC,SAAS;;kCAET,KAAC1U;kCAAa;;kCACd,MAACD;wBACC8R,IAAI;4BAAE8C,SAAS;4BAAQC,eAAe;4BAAUC,KAAK;wBAAE;;0CAEvD,KAAC1U;gCACCwN,OAAM;gCACNQ,KAAK,WAAEzD,2BAAAA,QAASS,IAAI,oBAAI;gCACxBgI,UAAU,CAACC,QACTzI,WAAW,CAAC0E,OACVA,OAAO,aAAKA;4CAAMlE,MAAMiI,MAAMjH,MAAM,CAACgC,KAAK;6CAAKkB;gCAGnD4C,MAAK;gCACL6C,SAAS;gCACTjD,IAAI;oCAAEkD,IAAI;gCAAE;gCACZC,YAAW;;0CAEb,KAAC7U;gCACCwN,OAAM;gCACNQ,KAAK,WAAEzD,2BAAAA,QAASrD,MAAM,oBAAI;gCAC1B8L,UAAU,CAACC,QACTzI,WAAW,CAAC0E,OACVA,OAAO,aAAKA;4CAAMhI,QAAQ+L,MAAMjH,MAAM,CAACgC,KAAK;6CAAKkB;gCAGrD4C,MAAK;gCACL+C,YACE5J,eAAe5B,MAAM,GACjB,CAAC,SAAS,EAAE4B,eACTE,GAAG,CAAC,CAACC,QAAUA,MAAMJ,IAAI,EACzBoD,IAAI,CAAC,OAAO,GACf;;;;kCAIV,MAACzO;;0CACC,KAACF;gCAAOsS,SAAS,IAAMvH,WAAW;0CAAQ;;0CAC1C,KAAC/K;gCACCiL,SAAQ;gCACRoC,OAAM;gCACNgI,UACE,CAAC/Q,cACD,EAACwG,2BAAAA,QAASS,IAAI,CAACzB,IAAI,OACnB2B,cAAc7B,MAAM,KAAK;gCAE3B0I,SAASzG;0CAER;;;;;;0BASP,KAAC1J;gBACC4M,QAAQD;gBACRtH,OAAOA;gBACP8N,kBAAkBlH;gBAClBwG,SAAS,IAAM/F,YAAY;gBAC3B,mEAAmE;gBACnE,gEAAgE;gBAChE,wBAAwB;gBACxB0G,QAAQ;oBACN,MAAMxG,SAASD;oBACfD,YAAY;oBACZ,IAAIE,QAAQG,iBAAiBH;gBAC/B;;0BAEF,MAAC9O;gBACC0U,MAAMpQ,QAAQyK;gBACd4F,SAAS,IAAM3F,UAAU;gBACzB4F,UAAS;gBACTC,SAAS;;kCAET,KAAC1U;kCAAa4O,CAAAA,0BAAAA,OAAQpD,EAAE,IAAG,gBAAgB;;kCAC3C,KAACzL;wBACC8R,IAAI;4BAAE8C,SAAS;4BAAQC,eAAe;4BAAUC,KAAK;wBAAE;kCAEtDxN,OAAOiE,GAAG,CAAC,CAACc,SAASgJ;;gCA6DSrN,2BAAAA;4BA5D7B,MAAMA,QAAQX,MAAMC,MAAM,CAAC+E,QAAQ;4BACnC,IAAI,CAACrE,OAAO,OAAO;4BACnB,MAAMoG,gBAAQS,0BAAAA,OAAQG,MAAM,CAAC3C,QAAQ,mBAAI;4BACzC,MAAMvG,QAAQ+I,0BAAAA,OAAQK,MAAM,CAAC7C,QAAQ;4BACrC,MAAMuB,QAAQ5F,MAAMsE,QAAQ,GAAG,GAAGtE,MAAMoD,IAAI,CAAC,EAAE,CAAC,GAAGpD,MAAMoD,IAAI;4BAC7D,MAAMkK,WAAW,CAACC,YAChBzG,UAAU,CAACQ,OACTA,OACI,aACKA;wCACHN,QAAQ,aAAKM,KAAKN,MAAM;4CAAE,CAAC3C,QAAQ,EAAEkJ;;wCACrCrG,QAAQ,aAAKI,KAAKJ,MAAM;4CAAE,CAAC7C,QAAQ,EAAE;;yCAEvCiD;4BAER,MAAMkG,SAAS;gCACb5H;gCACAQ;gCACA8D,MAAM;gCACN6C,WAAWM,UAAU;gCACrBvP,OAAO1B,QAAQ0B;gCACfmP,YAAYnP,SAASkC,MAAM+E,WAAW;gCACtC+E,IAAIuD,UAAU,IAAI;oCAAEL,IAAI;gCAAE,IAAInQ;gCAC9BuO,UAAU,CAACC,QACTiC,SAASjC,MAAMjH,MAAM,CAACgC,KAAK;4BAC/B;4BACA,6DAA6D;4BAC7D,yDAAyD;4BACzD,kDAAkD;4BAClD,MAAMqH,kBAAkB5W,mBAAmBmJ,MAAM0N,UAAU;4BAC3D,IAAID,mCAAAA,gBAAiBE,KAAK,EAAE;gCAC1B,MAAMC,cAAcH,gBAAgBE,KAAK;gCACzC,qBACE,MAACxV;oCAAoB2R,IAAIuD,UAAU,IAAI;wCAAEL,IAAI;oCAAE,IAAInQ;;sDACjD,KAAC+Q;4CACCxH,OAAOA;4CACPR,OAAO4H,OAAO5H,KAAK;4CACnBwF,UAAU,CAACyC,OAASP,SAAS1J,OAAOiK,eAAAA,OAAQ;;wCAE5C/P,SAASkC,MAAM+E,WAAW,iBAC1B,KAAC1M;4CACCyK,SAAQ;4CACRoC,OAAOpH,QAAQ,UAAU;sDAExBA,SAASkC,MAAM+E,WAAW;6CAE3B;;mCAbMV;4BAgBhB;4BACA,qCAAqC;4BACrC,IAAIrE,MAAM+D,IAAI,KAAK,QAAQ;gCACzB,qBACE,MAAC3L,wBAA4BoV;oCAAQrC,MAAM;;sDACzC,KAACjT;4CAASkO,OAAM;sDAAI;;sDACpB,KAAClO;4CAASkO,OAAM;sDAAQ;;sDACxB,KAAClO;4CAASkO,OAAM;sDAAS;;;oCAHX/B;4BAMpB;4BACA,IAAIrE,MAAM+D,IAAI,KAAK,YAAU/D,oBAAAA,MAAM8N,UAAU,sBAAhB9N,4BAAAA,kBAAkBuB,OAAO,qBAAzBvB,0BAA2ByB,MAAM,GAAE;gCAC9D,qBACE,MAACrJ,wBAA4BoV;oCAAQrC,MAAM;;sDACzC,KAACjT;4CAASkO,OAAM;sDAAI;;wCACnBpG,MAAM8N,UAAU,CAACvM,OAAO,CAACgC,GAAG,CAAC,CAAC2C,uBAC7B,KAAChO;gDAAsBkO,OAAOF;0DAC3BA;+CADYA;;oCAHH7B;4BASpB;4BACA,IAAIrE,MAAM+D,IAAI,KAAK,aAAa;oCACdsB;oCACSrF;gCADzB,MAAMuB,WAAU8D,sBAAAA,UAAU,CAAChB,QAAQ,YAAnBgB,sBAAuB,EAAE;gCACzC,MAAM0I,WAAW3R,SAAQ4D,mBAAAA,MAAMuE,SAAS,qBAAfvE,iBAAiB+N,QAAQ;gCAClD,MAAMC,cAAc5H,MACjB6H,KAAK,CAAC,KACN1K,GAAG,CAAC,CAAC2K,OAASA,KAAKvM,IAAI,IACvB9B,MAAM,CAACzD;gCACV,qBACE,MAAChE,wBAEKoV;oCACJrC,MAAM;oCACN/E,OAAO2H,WAAWC,cAAc5H;oCAChC+H,WAAW;wCACThD,QAAQ4C,WACJ;4CACEA,UAAU;4CACV3C,UAAU,CAACC,QACTiC,SACE,AAACjC,MAAMjH,MAAM,CAACgC,KAAK,CAAcI,IAAI,CAAC;wCAE5C,IACA3J;oCACN;;wCAECkR,WAAW,qBAAO,KAAC7V;4CAASkO,OAAM;sDAAI;;wCACtC7E,QAAQgC,GAAG,CAAC,CAAC2C,uBACZ,KAAChO;gDAAyBkO,OAAOF,OAAOzC,EAAE;0DACvCyC,OAAON,KAAK;+CADAM,OAAOzC,EAAE;;oCAlBrBY;4BAwBX;4BACA,IACErE,MAAM+D,IAAI,KAAK,WACf/D,MAAM+D,IAAI,KAAK,WACf/D,MAAM+D,IAAI,KAAK,SACf;gCACA,qBAAO,KAAC3L,wBAA4BoV;oCAAQzJ,MAAK;oCAA1BM;4BACzB;4BACA,IAAIrE,MAAM+D,IAAI,KAAK,aAAa;gCAC9B,qBACE,KAAC3L,wBAEKoV;oCACJzJ,MAAK;oCACLoK,WAAW;wCAAEC,YAAY;4CAAEC,QAAQ;wCAAK;oCAAE;oCAHrChK;4BAMX;4BACA,IAAIrE,MAAM+D,IAAI,KAAK,eAAe;gCAChC,qBACE,KAAC3L,wBAEKoV;oCACJP,YAAYnP,SAASkC,MAAM+E,WAAW,IAAI;oCAFrCV;4BAKX;4BACA,IAAIrE,MAAM+D,IAAI,KAAK,UAAU;gCAC3B,qBACE,KAAC3L,wBAEKoV;oCACJP,YACEnP,SAASkC,MAAM+E,WAAW,IAAI;oCAH3BV;4BAOX;4BACA,qBAAO,KAACjM,wBAA4BoV,SAAbnJ;wBACzB;;kCAEF,MAACtM;;0CACC,KAACF;gCAAOsS,SAAS,IAAMrD,UAAU;0CAAQ;;0CACzC,KAACjP;gCACCiL,SAAQ;gCACRoC,OAAM;gCACNiF,SAAShD;0CAERN,CAAAA,0BAAAA,OAAQpD,EAAE,IAAG,SAAS;;;;;;0BAI7B,MAAC3L;gBACC0U,MAAMpQ,QAAQ4H;gBACdyI,SAAS,IAAMxI,UAAU;gBACzByI,UAAS;gBACTC,SAAS;;kCAET,KAAC1U;kCAAa;;kCACd,MAACD;wBACC8R,IAAI;4BAAE8C,SAAS;4BAAQC,eAAe;4BAAUC,KAAK;wBAAE;;0CAEvD,KAACzU;gCAAWyK,SAAQ;gCAAQoC,OAAM;gCAAiB4E,IAAI;oCAAEkD,IAAI;gCAAE;0CAC5D,4DACC;;4BAEF;gCAAC;gCAAK;6BAAI,CAAWzJ,GAAG,CAAC,CAAC+K;;qDAC1B,KAAClW;oCAEC+S,MAAM;oCACNjB,MAAK;oCACLtE,OAAO0I,SAAS,MAAM,qBAAqB;oCAC3ClI,KAAK,UAAEpC,0BAAAA,MAAQ,CAACsK,KAAK,mBAAI;oCACzBlD,UAAU,CAACC,QACTpH,UAAU,CAACqD,OACTA,OAAO,aAAKA;gDAAM,CAACgH,KAAK,EAAEjD,MAAMjH,MAAM,CAACgC,KAAK;iDAAKkB;8CAIpD/L,SAASgI,GAAG,CAAC,CAACpE,qBACb,KAACjH;4CAAwBkO,OAAOjH,KAAKC,GAAG;sDACrCrE,mBAAmBoE;2CADPA,KAAKC,GAAG;mCAZpBkP;;;;kCAmBX,MAACvW;;0CACC,KAACF;gCAAOsS,SAAS,IAAMlG,UAAU;0CAAQ;;0CACzC,KAACpM;gCACCiL,SAAQ;gCACRoC,OAAM;gCACNgI,UACE,CAAC/Q,cAAc,EAAC6H,0BAAAA,OAAQtF,CAAC,KAAI,EAACsF,0BAAAA,OAAQrF,CAAC,KAAIqF,OAAOtF,CAAC,KAAKsF,OAAOrF,CAAC;gCAElEwL,SAASjG;0CAER;;;;;;0BAIP,KAACnK;gBACCyB,QAAQA;gBACRG,KAAK,EAAEA,gBAAAA,QAASkB;gBAChBoM,SAASlK,cAAcE,WAAWA,WAAW;gBAC7C1D,UAAUA;gBACV,kEAAkE;gBAClE,mEAAmE;gBACnE,mDAAmD;gBACnDmH,aAAaA;gBACb6L,eAAehQ;gBACfiQ,gBAAgBnQ,mBAAmB;gBACnCoO,SAAS,IAAMzN,cAAc;;;;AAIrC;AACA3D,iBAAiBsI,WAAW,GAAG;AAE/B,eAAetI,iBAAgB"}