col-browser 2.4.0 → 2.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +34 -2
- package/es/bibtex.js +1 -1
- package/es/chunks/{BibTex-79CCKAOK.js → BibTex-DRE71Hg-.js} +2 -2
- package/es/chunks/{BibTex-79CCKAOK.js.map → BibTex-DRE71Hg-.js.map} +1 -1
- package/es/chunks/{DatasetCitation-BXtAmjdZ.js → DatasetCitation-Cep2dces.js} +2 -2
- package/es/chunks/{DatasetCitation-BXtAmjdZ.js.map → DatasetCitation-Cep2dces.js.map} +1 -1
- package/es/chunks/{DatasetlogoWithFallback-Dava2uqZ.js → DatasetlogoWithFallback-Bb-kmHts.js} +2 -2
- package/es/chunks/{DatasetlogoWithFallback-Dava2uqZ.js.map → DatasetlogoWithFallback-Bb-kmHts.js.map} +1 -1
- package/es/chunks/Distributions-Czffme5Y.js +1185 -0
- package/es/chunks/Distributions-Czffme5Y.js.map +1 -0
- package/es/chunks/{MergedDataBadge-C1CgoRFz.js → MergedDataBadge-DK53L3R8.js} +2 -2
- package/es/chunks/{MergedDataBadge-C1CgoRFz.js.map → MergedDataBadge-DK53L3R8.js.map} +1 -1
- package/es/chunks/{TaxonBreakdown-DeWamLu_.js → TaxonBreakdown-DqdQ18QM.js} +2 -2
- package/es/chunks/{TaxonBreakdown-DeWamLu_.js.map → TaxonBreakdown-DqdQ18QM.js.map} +1 -1
- package/es/chunks/{XrGutter-CU7_QPAp.js → XrGutter-COJhHpia.js} +2 -2
- package/es/chunks/{XrGutter-CU7_QPAp.js.map → XrGutter-COJhHpia.js.map} +1 -1
- package/es/chunks/config--bs_09I6.js +32 -0
- package/es/chunks/config--bs_09I6.js.map +1 -0
- package/es/chunks/{dataset-BL6g4w0G.js → dataset-BZpjo3Yq.js} +2 -2
- package/es/chunks/{dataset-BL6g4w0G.js.map → dataset-BZpjo3Yq.js.map} +1 -1
- package/es/chunks/{enumeration-DM8Hb36g.js → enumeration-CV8i_q_O.js} +2 -2
- package/es/chunks/{enumeration-DM8Hb36g.js.map → enumeration-CV8i_q_O.js.map} +1 -1
- package/es/chunks/{sector-Qeo1zPxr.js → sector-ucUgPp75.js} +2 -2
- package/es/chunks/{sector-Qeo1zPxr.js.map → sector-ucUgPp75.js.map} +1 -1
- package/es/config.js +1 -1
- package/es/index.js +1 -1
- package/es/search.js +5 -5
- package/es/sourceDataset.js +4 -4
- package/es/sourceDatasetList.js +4 -4
- package/es/taxon.js +758 -754
- package/es/taxon.js.map +1 -1
- package/es/taxonBreakdown.js +2 -2
- package/es/taxonDistribution.js +21 -19
- package/es/taxonDistribution.js.map +1 -1
- package/es/tree.js +5 -5
- package/package.json +1 -1
- package/types/index.d.ts +25 -0
- package/umd/col-browser.js +67 -25
- package/umd/col-browser.js.map +1 -1
- package/umd/col-browser.min.js +4 -4
- package/umd/col-browser.min.js.map +1 -1
- package/es/chunks/Distributions-Bd4hFYdS.js +0 -1169
- package/es/chunks/Distributions-Bd4hFYdS.js.map +0 -1
- package/es/chunks/config-D1NH4DTr.js +0 -22
- package/es/chunks/config-D1NH4DTr.js.map +0 -1
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Distributions-Czffme5Y.js","sources":["../../node_modules/@ant-design/icons-svg/es/asn/BookOutlined.js","../../node_modules/@ant-design/icons/es/icons/BookOutlined.js","../../src/Taxon/ReferencePopover.js","../../src/Taxon/DistributionsMap/descendantRanks.js","../../src/Taxon/DistributionsMap/descendantFetch.js","../../src/Taxon/DistributionsMap/colorAssignment.js","../../src/Taxon/DistributionsMap/basemap.js","../../src/Taxon/DistributionsMap/IncludedTaxaLegend.js","../../src/Taxon/DistributionsMap/index.js","../../src/Taxon/Distributions.js"],"sourcesContent":["// This icon file is generated automatically.\nvar BookOutlined = { \"icon\": { \"tag\": \"svg\", \"attrs\": { \"viewBox\": \"64 64 896 896\", \"focusable\": \"false\" }, \"children\": [{ \"tag\": \"path\", \"attrs\": { \"d\": \"M832 64H192c-17.7 0-32 14.3-32 32v832c0 17.7 14.3 32 32 32h640c17.7 0 32-14.3 32-32V96c0-17.7-14.3-32-32-32zm-260 72h96v209.9L621.5 312 572 347.4V136zm220 752H232V136h280v296.9c0 3.3 1 6.6 3 9.3a15.9 15.9 0 0022.3 3.7l83.8-59.9 81.4 59.4c2.7 2 6 3.1 9.4 3.1 8.8 0 16-7.2 16-16V136h64v752z\" } }] }, \"name\": \"book\", \"theme\": \"outlined\" };\nexport default BookOutlined;\n","function _extends() { _extends = Object.assign ? Object.assign.bind() : function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; return _extends.apply(this, arguments); }\n// GENERATE BY ./scripts/generate.ts\n// DON NOT EDIT IT MANUALLY\n\nimport * as React from 'react';\nimport BookOutlinedSvg from \"@ant-design/icons-svg/es/asn/BookOutlined\";\nimport AntdIcon from \"../components/AntdIcon\";\nconst BookOutlined = (props, ref) => /*#__PURE__*/React.createElement(AntdIcon, _extends({}, props, {\n ref: ref,\n icon: BookOutlinedSvg\n}));\n\n/** */\nconst RefIcon = /*#__PURE__*/React.forwardRef(BookOutlined);\nif (process.env.NODE_ENV !== 'production') {\n RefIcon.displayName = 'BookOutlined';\n}\nexport default RefIcon;","import React from \"react\";\nimport { BookOutlined } from \"@ant-design/icons\";\nimport { Popover, Spin } from \"antd\";\nimport client from \"../api/client\";\nimport config from \"../config\";\nimport { get, isArray } from \"lodash-es\";\nimport ErrorMsg from \"../components/ErrorMsg\";\n\nclass ReferencePopover extends React.Component {\n constructor(props) {\n super(props);\n\n this.state = {\n reference: [],\n loading: false,\n error: null,\n };\n }\n\n getData = () => {\n const { referenceId, datasetKey, references } = this.props;\n if (referenceId) {\n const refIds = !isArray(referenceId) ? [referenceId] : referenceId;\n const reference = [];\n this.setState({ loading: true });\n Promise.allSettled(\n refIds.map((id) => get(references, id) ? Promise.resolve(reference.push(references[id])) :\n\n client(\n `${config.dataApi}dataset/${datasetKey}/reference/${id}`\n ).then((res) => reference.push(res.data)).catch(err => this.setState({error: err}))\n\n \n )\n ).then(() => this.setState({ reference, loading: false }));\n }\n };\n\n getContent = () => {\n const { error, reference, loading } = this.state;\n if (loading) {\n return <Spin />;\n } else if (error) {\n return <ErrorMsg error={error}/>;\n } else if (reference.length === 1) {\n return reference[0].citation;\n } else {\n return (\n <ul>\n {reference.map((r) => (\n <li key={r.id}>{r.citation}</li>\n ))}\n </ul>\n );\n }\n };\n\n scrollToReference = (e, id) => {\n // Default <a href=\"#col-reference-{id}\"> behaviour writes the hash into\n // window.location, which hijacks hosts using hash-based routing (the\n // GitHub Pages demo, COL portal preview). Scroll without touching the\n // URL.\n const el = document.getElementById(`col-reference-${id}`);\n if (el) {\n e.preventDefault();\n el.scrollIntoView({ behavior: \"smooth\", block: \"start\" });\n }\n };\n\n render = () => {\n const { referenceId, referenceIndexMap, trigger } = this.props;\n // Cap the inline [n] markers so a name linked to many references does not\n // render an unreadable trail across the row. Overflow collapses into a\n // \"+N\" indicator; the hover popover still lists every citation.\n const maxInline = this.props.maxInline || 4;\n const refIds = !isArray(referenceId) ? [referenceId] : referenceId;\n let icon = referenceIndexMap && get(referenceIndexMap, refIds[0])\n ? (() => {\n const shown = refIds.slice(0, maxInline);\n const overflow = refIds.length - shown.length;\n return [\n ...shown.map((r) => (\n <a\n key={r}\n className=\"col-reference-link\"\n href={`#col-reference-${r}`}\n onClick={(e) => this.scrollToReference(e, r)}\n >\n {`[${referenceIndexMap[r]}]`}\n </a>\n )),\n overflow > 0 ? (\n <span key=\"overflow\" className=\"col-reference-link\">\n {` +${overflow}`}\n </span>\n ) : null,\n ];\n })()\n : <BookOutlined style={{ cursor: \"pointer\" }} />;\n\n return referenceId ? (\n <div id={`reference_${referenceId}`} key={`reference_${referenceId}`} style={this.props.style}>\n <Popover\n getPopupContainer={() =>\n document.getElementById(`reference_${referenceId}`)\n }\n placement={this.props.placement || \"left\"}\n title=\"Reference\"\n onOpenChange={(visible) => visible && this.getData()}\n content={\n <div\n style={{\n maxWidth: \"500px\",\n maxHeight: \"60vh\",\n overflowY: \"auto\",\n }}\n >\n {this.getContent()}\n </div>\n }\n trigger={trigger || \"hover\"}\n >\n {icon}\n </Popover>\n </div>\n ) : (\n \"\"\n );\n };\n}\n\nexport default ReferencePopover;\n","export const INFRASPECIFIC_RANKS = [\n \"subspecies\",\n \"variety\",\n \"subvariety\",\n \"form\",\n \"subform\",\n \"infraspecific name\",\n];\n\nexport const getDescendantRanks = (focalRank, rankOrder) => {\n const focalIdx = rankOrder.indexOf(focalRank);\n if (focalIdx === -1) return [];\n return INFRASPECIFIC_RANKS.filter((r) => {\n const i = rankOrder.indexOf(r);\n return i > focalIdx;\n });\n};\n","import client from \"../../api/client\";\nimport config from \"../../config\";\nimport { getDescendantRanks } from \"./descendantRanks\";\n\nconst POOL_SIZE = 16;\n\nconst isMappable = (r) =>\n r?.area?.gazetteer !== \"text\" && !!r?.area?.globalId;\n\nconst runPool = async (items, worker, size) => {\n const results = new Array(items.length);\n let next = 0;\n const runners = Array.from({ length: Math.min(size, items.length) }, async () => {\n while (true) {\n const i = next++;\n if (i >= items.length) return;\n results[i] = await worker(items[i], i);\n }\n });\n await Promise.all(runners);\n return results;\n};\n\nconst searchDescendants = async (datasetKey, focalId, ranks) => {\n if (ranks.length === 0) return [];\n const params = new URLSearchParams();\n params.append(\"TAXON_ID\", focalId);\n ranks.forEach((r) => params.append(\"rank\", r));\n [\"accepted\", \"provisionally accepted\"].forEach((s) =>\n params.append(\"status\", s)\n );\n params.append(\"limit\", \"1000\");\n const url = `${config.dataApi}dataset/${datasetKey}/nameusage/search?${params}`;\n const res = await client(url);\n const list = res?.data?.result || [];\n return list\n .filter((u) => u?.usage?.id)\n .map((u) => ({\n id: u.usage.id,\n scientificName:\n u.usage?.name?.scientificName || u.usage?.label || u.usage.id,\n rank: u.usage?.name?.rank,\n parentId: u.usage?.parentId,\n }));\n};\n\nconst fetchDistributions = async (datasetKey, taxonId) => {\n const url = `${config.dataApi}dataset/${datasetKey}/taxon/${encodeURIComponent(taxonId)}/distribution`;\n try {\n const res = await client(url);\n return Array.isArray(res?.data) ? res.data : [];\n } catch {\n return [];\n }\n};\n\n/**\n * Fetch all infraspecific descendants of `focalTaxon` and their distributions.\n * Returns { taxa, descendantsFailed } where each taxon carries `mappable` (the\n * mappable subset of its distributions) and `distributions` (the full list).\n */\nexport const fetchDescendants = async ({ datasetKey, focalTaxon, rankOrder }) => {\n const ranks = getDescendantRanks(focalTaxon?.name?.rank, rankOrder);\n let descendantsFailed = false;\n let list = [];\n try {\n list = await searchDescendants(datasetKey, focalTaxon.id, ranks);\n } catch {\n descendantsFailed = true;\n return { taxa: [], descendantsFailed };\n }\n\n const distributions = await runPool(\n list,\n (t) => fetchDistributions(datasetKey, t.id),\n POOL_SIZE\n );\n\n const taxa = list.map((t, i) => {\n const all = distributions[i] || [];\n return { ...t, distributions: all, mappable: all.filter(isMappable) };\n });\n return { taxa, descendantsFailed };\n};\n","export const VIVID_PALETTE = [\n \"#E58606\",\n \"#5D69B1\",\n \"#52BCA3\",\n \"#99C945\",\n \"#CC61B0\",\n \"#24796C\",\n \"#DAA51B\",\n \"#2F8AC4\",\n \"#764E9F\",\n \"#ED645A\",\n \"#CC3A8E\",\n \"#A5AA99\",\n];\n\nconst rankIndex = (rank, rankOrder) => {\n const i = rankOrder.indexOf(rank);\n return i === -1 ? rankOrder.length : i;\n};\n\nexport const assignColors = (taxa, rankOrder) => {\n const sorted = [...taxa].sort((a, b) => {\n const ra = rankIndex(a.rank, rankOrder);\n const rb = rankIndex(b.rank, rankOrder);\n if (ra !== rb) return ra - rb;\n return a.scientificName.localeCompare(b.scientificName);\n });\n const out = {};\n sorted.forEach((t, i) => {\n out[t.id] = VIVID_PALETTE[i % VIVID_PALETTE.length];\n });\n return out;\n};\n","import config from \"../../config\";\n\n/**\n * The MapLibre style spec the distribution map should render on.\n *\n * A per-instance `basemapStyle` prop wins over the global `configure()`\n * default. Either may be a style URL or an inline style object — whatever\n * MapLibre accepts as `style`.\n */\nexport const resolveBasemapStyle = (prop) => prop ?? config.basemapStyle;\n\n// CARTO serves the style from basemaps.cartocdn.com and the tiles, glyphs and\n// sprites from tiles*.basemaps.cartocdn.com.\nconst CARTO_HOST = /(^|\\.)cartocdn\\.com$/i;\n\n/**\n * A MapLibre `transformRequest` that authenticates CARTO basemap traffic.\n *\n * CARTO's published styles are static files whose `glyphs`, `sprite` and\n * vector-source URLs are absolute and key-free, so baking `?key=` into the\n * style URL authenticates that one request and nothing else. CARTO meters\n * *tile* requests, so the key has to ride on all of them — this appends it to\n * every cartocdn.com request the map makes and leaves other hosts (GBIF\n * occurrence tiles, ChecklistBank) untouched.\n *\n * Returns undefined when no key is set, so MapLibre keeps its own default.\n */\nexport const cartoTransformRequest = (key = config.cartoKey) => {\n if (!key) return undefined;\n return (url) => {\n let parsed;\n try {\n parsed = new URL(url);\n } catch {\n return { url };\n }\n // Leave a key already baked into the style URL alone.\n if (!CARTO_HOST.test(parsed.hostname) || parsed.searchParams.has(\"key\")) {\n return { url };\n }\n parsed.searchParams.set(\"key\", key);\n return { url: parsed.toString() };\n };\n};\n","import { useState } from \"react\";\n\nconst wrapStyle = {\n position: \"absolute\",\n bottom: 8,\n left: 8,\n zIndex: 1000,\n background: \"#fff\",\n borderRadius: 4,\n boxShadow: \"0 1px 4px rgba(0,0,0,0.2)\",\n padding: \"6px 8px\",\n fontSize: 12,\n lineHeight: 1.5,\n maxWidth: 260,\n};\n\nconst scrollStyle = {\n maxHeight: 240,\n overflowY: \"auto\",\n};\n\nconst groupHeadingStyle = {\n fontWeight: 600,\n marginTop: 4,\n};\n\nconst firstGroupHeadingStyle = {\n ...groupHeadingStyle,\n marginTop: 0,\n};\n\nconst rowStyle = {\n display: \"flex\",\n alignItems: \"center\",\n gap: 6,\n paddingLeft: 4,\n};\n\nconst swatchStyle = (color) => ({\n display: \"inline-block\",\n width: 12,\n height: 12,\n background: color,\n border: \"1px solid rgba(0,0,0,0.15)\",\n borderRadius: 2,\n flex: \"0 0 auto\",\n});\n\nconst footerToggleStyle = {\n marginTop: 6,\n cursor: \"pointer\",\n color: \"#1890ff\",\n fontSize: 11,\n};\n\nconst footerWrapStyle = {\n marginTop: 4,\n borderTop: \"1px solid #eee\",\n paddingTop: 4,\n color: \"#666\",\n};\n\nconst footerGroupHeadingStyle = {\n fontWeight: 600,\n marginTop: 4,\n};\n\nconst footerFirstGroupHeadingStyle = {\n ...footerGroupHeadingStyle,\n marginTop: 0,\n};\n\nconst footerNameStyle = {\n fontStyle: \"italic\",\n paddingLeft: 4,\n};\n\nconst totalCount = (groups) =>\n groups.reduce((sum, g) => sum + g.taxa.length, 0);\n\nconst GbifHexEntry = () => (\n <div style={rowStyle}>\n <svg width=\"12\" height=\"12\" viewBox=\"0 0 12 12\" aria-hidden=\"true\">\n <polygon\n points=\"3,1 9,1 11,6 9,11 3,11 1,6\"\n fill=\"#de1e6e\"\n stroke=\"rgba(0,0,0,0.25)\"\n strokeWidth=\"0.75\"\n />\n </svg>\n <span>GBIF occurrences</span>\n </div>\n);\n\nconst IncludedTaxaLegend = ({ visibleGroups, unmappableGroups, showGbif }) => {\n const [showUnmappable, setShowUnmappable] = useState(false);\n const visibleCount = totalCount(visibleGroups);\n const unmappableCount = totalCount(unmappableGroups);\n if (visibleCount === 0 && unmappableCount === 0 && !showGbif) return null;\n return (\n <div style={wrapStyle}>\n <div style={scrollStyle}>\n {visibleGroups.map((g, i) => (\n <div key={g.rank}>\n <div style={i === 0 ? firstGroupHeadingStyle : groupHeadingStyle}>\n {g.label}\n </div>\n {g.taxa.map((t) => (\n <div key={t.id} style={rowStyle}>\n <span style={swatchStyle(t.color)} />\n <span style={{ fontStyle: \"italic\" }}>\n {t.displayName || t.scientificName}\n </span>\n </div>\n ))}\n </div>\n ))}\n {showGbif && <GbifHexEntry />}\n </div>\n {unmappableCount > 0 && (\n <>\n <div\n style={footerToggleStyle}\n onClick={() => setShowUnmappable((v) => !v)}\n >\n {showUnmappable ? \"− Hide\" : \"+\"} {unmappableCount} without map data\n </div>\n {showUnmappable && (\n <div style={footerWrapStyle}>\n {unmappableGroups.map((g, i) => (\n <div key={g.rank}>\n <div\n style={\n i === 0\n ? footerFirstGroupHeadingStyle\n : footerGroupHeadingStyle\n }\n >\n {g.label}\n </div>\n {g.taxa.map((t) => (\n <div key={t.id} style={footerNameStyle}>\n {t.displayName || t.scientificName}\n </div>\n ))}\n </div>\n ))}\n </div>\n )}\n </>\n )}\n </div>\n );\n};\n\nexport default IncludedTaxaLegend;\n","import { useEffect, useMemo, useRef, useState } from \"react\";\nimport maplibregl from \"maplibre-gl\";\nimport \"maplibre-gl/dist/maplibre-gl.css\";\nimport \"./treeControl.css\";\nimport client from \"../../api/client\";\nimport config from \"../../config\";\nimport { fetchDescendants } from \"./descendantFetch\";\nimport { getDescendantRanks, INFRASPECIFIC_RANKS } from \"./descendantRanks\";\nimport { assignColors } from \"./colorAssignment\";\nimport { cartoTransformRequest, resolveBasemapStyle } from \"./basemap\";\nimport IncludedTaxaLegend from \"./IncludedTaxaLegend\";\nimport { readSetting, writeSetting } from \"../../storage\";\n\nconst POPUP_FIELDS = [\n \"establishmentMeans\",\n \"degreeOfEstablishment\",\n \"pathway\",\n \"threatStatus\",\n \"year\",\n \"lifeStage\",\n];\n\nexport const ESTABLISHMENT_MEANS = [\n { key: \"nativeendemic\", label: \"Native endemic\", color: \"#0F8554\" },\n { key: \"native\", label: \"Native\", color: \"#87C55F\" },\n { key: \"nativereintroduced\", label: \"Native reintroduced\", color: \"#C9DB74\" },\n { key: \"introduced\", label: \"Introduced\", color: \"#FE88B1\" },\n {\n key: \"introducedassistedcolonisation\",\n label: \"Introduced assisted colonisation\",\n color: \"#DCB0F2\",\n },\n { key: \"vagrant\", label: \"Vagrant\", color: \"#F6CF71\" },\n { key: \"uncertain\", label: \"Uncertain\", color: \"#8BE0A4\" },\n];\n\nconst ESTABLISHMENT_COLORS = Object.fromEntries(\n ESTABLISHMENT_MEANS.map((m) => [m.key, m.color])\n);\nexport const MISSING_COLOR = \"#66C5CC\";\n\nconst normalizeKey = (v) =>\n String(v || \"\")\n .toLowerCase()\n .replace(/[^a-z]/g, \"\");\n\nconst resolveKey = (record) => {\n const raw = record?.establishmentMeans;\n if (raw == null || raw === \"\") return null;\n const k = normalizeKey(raw);\n return ESTABLISHMENT_COLORS[k] ? k : \"uncertain\";\n};\n\nconst colorFor = (record) => {\n const k = resolveKey(record);\n return k == null ? MISSING_COLOR : ESTABLISHMENT_COLORS[k];\n};\n\n// localStorage-backed GBIF overlay preference: a user who turns the overlay off\n// keeps it off across page loads and sessions. Applies to all maps, including\n// GBIF-only ones — there, turning it off collapses the (otherwise empty) map to\n// a small activate bar (see the render below).\nconst GBIF_VISIBLE_KEY = \"gbif-visible\";\nconst readStoredGbifVisible = (defaultValue) =>\n readSetting(GBIF_VISIBLE_KEY, defaultValue);\nconst writeStoredGbifVisible = (visible) =>\n writeSetting(GBIF_VISIBLE_KEY, visible);\n\n// GBIF v2 occurrence-density tile path (multitaxonomy). Concatenated with\n// config.gbifApi at request time.\nconst GBIF_TILE_PATH =\n \"/v2/map/occurrence/density/{z}/{x}/{y}@1x.png\" +\n \"?srs=EPSG%3A3857&style=iNaturalist.poly&bin=hex&hexPerTile=64\" +\n \"&hasCoordinate=true&hasGeospatialIssue=false&occurrenceStatus=PRESENT\" +\n \"&checklistKey={checklistKey}&taxonKey={taxonKey}\";\n\n// Layer IDs\nconst FOCAL_SOURCE = \"col-focal-distributions\";\nconst FOCAL_FILL = \"col-focal-fill\";\nconst FOCAL_LINE = \"col-focal-line\";\nconst GBIF_SOURCE = \"col-gbif-occurrences\";\nconst GBIF_LAYER = \"col-gbif-occurrences\";\nconst descendantSourceId = (id) => `col-descendant-${id}`;\nconst descendantFillId = (id) => `col-descendant-fill-${id}`;\nconst descendantLineId = (id) => `col-descendant-line-${id}`;\n\nconst cache = new Map();\n\nconst fetchShape = (gazetteer, id) => {\n const key = `${gazetteer}:${id}`;\n if (cache.has(key)) return cache.get(key);\n const url = `${config.dataApi}vocab/area/${key}`;\n const p = client(url, {\n headers: { Accept: \"application/geo+json\" },\n }).then(\n (r) => r.data,\n () => null\n );\n cache.set(key, p);\n return p;\n};\n\nconst escapeHtml = (s) =>\n String(s)\n .replace(/&/g, \"&\")\n .replace(/</g, \"<\")\n .replace(/>/g, \">\")\n .replace(/\"/g, \""\");\n\nconst popupHtml = (record) => {\n const title = record?.area?.name || record?.area?.globalId || \"\";\n const rows = POPUP_FIELDS.map((f) => [f, record?.[f]])\n .filter(([, v]) => v != null && v !== \"\")\n .map(\n ([k, v]) =>\n `<div><strong>${escapeHtml(k)}:</strong> ${escapeHtml(v)}</div>`\n )\n .join(\"\");\n return `<div style=\"min-width:180px\"><div style=\"font-weight:600;margin-bottom:4px\">${escapeHtml(\n title\n )}</div>${rows}</div>`;\n};\n\nconst descendantPopupHtml = (taxon, record) => {\n const head =\n `<div style=\"font-weight:600;font-style:italic;margin-bottom:4px\">${escapeHtml(\n taxon.scientificName\n )}</div>` +\n `<div style=\"color:#888;margin-bottom:4px\">${escapeHtml(taxon.rank || \"\")}</div>`;\n return head + popupHtml(record);\n};\n\nconst RANK_LABEL_PLURAL = {\n subspecies: \"subspecies\",\n variety: \"varieties\",\n subvariety: \"subvarieties\",\n form: \"forms\",\n subform: \"subforms\",\n \"infraspecific name\": \"infraspecific names\",\n};\nconst rankLabelPlural = (rank) => RANK_LABEL_PLURAL[rank] || rank;\n\nconst epithet = (scientificName) => {\n if (!scientificName) return \"\";\n const tokens = scientificName.trim().split(/\\s+/);\n return tokens[tokens.length - 1];\n};\n\n// Hex swatch + label for the GBIF density layer.\nconst GbifLegendEntry = () => (\n <div style={{ display: \"flex\", alignItems: \"center\", gap: 6 }}>\n <svg width=\"12\" height=\"12\" viewBox=\"0 0 12 12\" aria-hidden=\"true\">\n <polygon\n points=\"3,1 9,1 11,6 9,11 3,11 1,6\"\n fill=\"#de1e6e\"\n stroke=\"rgba(0,0,0,0.25)\"\n strokeWidth=\"0.75\"\n />\n </svg>\n <span>GBIF occurrences</span>\n </div>\n);\n\n// Compute bounds [[minLng,minLat],[maxLng,maxLat]] of a FeatureCollection.\nconst computeBounds = (features) => {\n let minLng = Infinity,\n minLat = Infinity,\n maxLng = -Infinity,\n maxLat = -Infinity;\n const visit = (coords) => {\n if (typeof coords[0] === \"number\") {\n const [lng, lat] = coords;\n if (lng < minLng) minLng = lng;\n if (lng > maxLng) maxLng = lng;\n if (lat < minLat) minLat = lat;\n if (lat > maxLat) maxLat = lat;\n } else {\n for (let i = 0; i < coords.length; i++) visit(coords[i]);\n }\n };\n for (let i = 0; i < features.length; i++) {\n const g = features[i]?.geometry;\n if (g?.coordinates) visit(g.coordinates);\n }\n if (minLng === Infinity) return null;\n return [\n [minLng, minLat],\n [maxLng, maxLat],\n ];\n};\n\nconst flattenFeatures = (geojson) => {\n if (!geojson) return [];\n if (geojson.type === \"FeatureCollection\") return geojson.features || [];\n return [geojson];\n};\n\nconst supported = () => {\n if (typeof maplibregl?.supported === \"function\") return maplibregl.supported();\n // Newer maplibre-gl uses isWebGLSupported / no helper — assume true at SSR time.\n return typeof WebGLRenderingContext !== \"undefined\";\n};\n\nconst DistributionsMap = ({\n records,\n onUnmappable,\n datasetKey,\n focalTaxon,\n rankOrder,\n gbifChecklistKey,\n // true | null → show GBIF layer; false → GBIF API returned 0 occurrences,\n // grey out the toggle and skip loading tiles. Defaults to true so the\n // component works without the count check.\n gbifAvailable = true,\n // MapLibre style URL or inline style object; falls back to the global\n // `configure({ basemapStyle })` value. Changing it rebuilds the map.\n basemapStyle,\n}) => {\n const containerRef = useRef(null);\n const wrapperRef = useRef(null);\n const mapRef = useRef(null);\n const popupRef = useRef(null);\n const recordMapRef = useRef(new Map()); // recordKey → record\n const descendantTaxonMapRef = useRef(new Map()); // taxonId → taxon\n const descendantRecordMapRef = useRef(new Map()); // recordKey → { taxon, record }\n const focalAttachedRef = useRef(false);\n const gbifAttachedRef = useRef(false);\n const descendantLayersRef = useRef(new Set()); // taxonIds currently attached\n\n const [readyMap, setReadyMap] = useState(null);\n const [focalReady, setFocalReady] = useState(false);\n const [descendantState, setDescendantState] = useState({\n status: \"idle\", // idle | loading | ready | empty | error\n taxa: [],\n });\n const [focalVisible, setFocalVisible] = useState(true);\n const isGbifOnly = !!gbifChecklistKey && (!records || records.length === 0);\n // Respect the saved GBIF preference on every map. On a GBIF-only map, an\n // off preference collapses to a small activate bar instead of an empty map.\n const [gbifVisible, setGbifVisible] = useState(() =>\n readStoredGbifVisible(true)\n );\n const [visibleTaxonIds, setVisibleTaxonIds] = useState(new Set());\n const [controlOpen, setControlOpen] = useState(false);\n const fetchTriggeredRef = useRef(false);\n\n const handleToggleGbif = () => {\n setGbifVisible((v) => {\n const next = !v;\n writeStoredGbifVisible(next);\n return next;\n });\n };\n\n const activateGbif = () => {\n setGbifVisible(true);\n writeStoredGbifVisible(true);\n };\n\n const presentMeans = useMemo(() => {\n if (!records?.length) return [];\n const seen = new Set();\n records.forEach((r) => {\n const k = resolveKey(r);\n if (k != null) seen.add(k);\n });\n return ESTABLISHMENT_MEANS.filter((m) => seen.has(m.key));\n }, [records]);\n\n const descendantColors = useMemo(() => {\n if (descendantState.status !== \"ready\") return {};\n return assignColors(\n descendantState.taxa.filter((t) => t.mappable.length > 0),\n rankOrder || []\n );\n }, [descendantState, rankOrder]);\n\n const descendantLegend = useMemo(() => {\n if (descendantState.status !== \"ready\") {\n return { visibleGroups: [], unmappableGroups: [] };\n }\n const decorate = (t) => ({\n ...t,\n color: descendantColors[t.id],\n displayName: epithet(t.scientificName),\n });\n const groupByRank = (taxa) => {\n const byRank = {};\n taxa.forEach((t) => {\n (byRank[t.rank] = byRank[t.rank] || []).push(decorate(t));\n });\n return INFRASPECIFIC_RANKS.filter((r) => byRank[r]).map((r) => ({\n rank: r,\n label: rankLabelPlural(r),\n taxa: byRank[r],\n }));\n };\n const visibleGroups = groupByRank(\n descendantState.taxa.filter(\n (t) => t.mappable.length > 0 && visibleTaxonIds.has(t.id)\n )\n );\n const unmappableGroups = groupByRank(\n descendantState.taxa.filter((t) => t.mappable.length === 0)\n );\n return { visibleGroups, unmappableGroups };\n }, [descendantState, descendantColors, visibleTaxonIds]);\n\n const showDescendantLegend = descendantLegend.visibleGroups.length > 0;\n\n const styleSpec = resolveBasemapStyle(basemapStyle);\n const cartoKey = config.cartoKey;\n // Depend on a stable key, not the spec itself: an inline style object passed\n // as a prop is a fresh reference on every render and would otherwise rebuild\n // the map continuously. The CARTO key is folded in so that configuring one\n // after first render rebuilds the map onto authenticated tiles.\n const styleKey = `${\n typeof styleSpec === \"string\" ? styleSpec : JSON.stringify(styleSpec)\n }|${cartoKey || \"\"}`;\n\n // Mount the map. Re-runs when the basemap style changes: the cleanup below\n // tears the old map down completely, so the layer effects rebuild onto the\n // new style.\n useEffect(() => {\n if (!containerRef.current || mapRef.current) return;\n if (!supported()) return;\n const map = new maplibregl.Map({\n container: containerRef.current,\n style: styleSpec,\n transformRequest: cartoTransformRequest(cartoKey),\n center: [0, 20],\n zoom: 1,\n minZoom: 0,\n attributionControl: false,\n renderWorldCopies: true,\n });\n map.addControl(\n new maplibregl.AttributionControl({ compact: true }),\n \"bottom-right\"\n );\n map.addControl(\n new maplibregl.NavigationControl({ showCompass: false }),\n \"top-left\"\n );\n // Fullscreen toggle, top-right. Expand the whole wrapper (not just the map\n // canvas) so the legend and the layer control come along into fullscreen.\n // The custom layer \"+\" button is positioned just below this control.\n map.addControl(\n new maplibregl.FullscreenControl({ container: wrapperRef.current }),\n \"top-right\"\n );\n mapRef.current = map;\n\n map.on(\"load\", () => {\n setReadyMap(map);\n // Start the attribution control collapsed. MapLibre opens it by\n // default in compact mode and only closes it on drag; remove the\n // `compact-show` class to hide the inner attribution text until the\n // user clicks the (i) button.\n const attrib = map\n .getContainer()\n .querySelector(\".maplibregl-ctrl-attrib\");\n if (attrib) attrib.classList.remove(\"maplibregl-compact-show\");\n });\n\n const resizeObserver =\n typeof ResizeObserver !== \"undefined\"\n ? new ResizeObserver(() => map.resize())\n : null;\n if (resizeObserver) resizeObserver.observe(containerRef.current);\n\n return () => {\n if (resizeObserver) resizeObserver.disconnect();\n if (popupRef.current) {\n popupRef.current.remove();\n popupRef.current = null;\n }\n map.remove();\n mapRef.current = null;\n focalAttachedRef.current = false;\n gbifAttachedRef.current = false;\n descendantLayersRef.current = new Set();\n // The layer effects below key off this. Clearing it on teardown — and\n // setting it again only from the new map's \"load\" — means they can never\n // run against a map that is gone or whose style has not loaded yet.\n setReadyMap(null);\n };\n }, [styleKey]);\n\n // Focal taxon polygons.\n useEffect(() => {\n const map = readyMap;\n if (!map || !records?.length) return;\n let cancelled = false;\n setFocalReady(false);\n\n Promise.allSettled(\n records.map((r) =>\n fetchShape(r.area.gazetteer, r.area.id).then((geojson) => ({\n record: r,\n geojson,\n }))\n )\n ).then((results) => {\n if (cancelled || mapRef.current !== map) return;\n const features = [];\n const recordMap = new Map();\n let failures = 0;\n results.forEach((res, i) => {\n if (res.status !== \"fulfilled\" || !res.value.geojson) {\n failures += 1;\n return;\n }\n const { record, geojson } = res.value;\n const color = colorFor(record);\n const recordKey = `focal-${i}`;\n recordMap.set(recordKey, record);\n flattenFeatures(geojson).forEach((f) => {\n features.push({\n ...f,\n properties: {\n ...(f.properties || {}),\n _recordKey: recordKey,\n _color: color,\n },\n });\n });\n });\n recordMapRef.current = recordMap;\n\n const data = { type: \"FeatureCollection\", features };\n if (map.getSource(FOCAL_SOURCE)) {\n map.getSource(FOCAL_SOURCE).setData(data);\n } else {\n // GBIF raster may already be on the map (its effect runs synchronously\n // while this one is async). Insert focal layers below GBIF so the\n // occurrence overlay always paints on top.\n const beforeId = map.getLayer(GBIF_LAYER) ? GBIF_LAYER : undefined;\n map.addSource(FOCAL_SOURCE, { type: \"geojson\", data });\n map.addLayer(\n {\n id: FOCAL_FILL,\n type: \"fill\",\n source: FOCAL_SOURCE,\n paint: {\n \"fill-color\": [\"coalesce\", [\"get\", \"_color\"], MISSING_COLOR],\n \"fill-opacity\": 0.65,\n },\n },\n beforeId\n );\n map.addLayer(\n {\n id: FOCAL_LINE,\n type: \"line\",\n source: FOCAL_SOURCE,\n paint: {\n \"line-color\": [\"coalesce\", [\"get\", \"_color\"], MISSING_COLOR],\n \"line-width\": 1,\n },\n },\n beforeId\n );\n map.on(\"click\", FOCAL_FILL, onFocalClick);\n map.on(\"mouseenter\", FOCAL_FILL, onMouseEnter);\n map.on(\"mouseleave\", FOCAL_FILL, onMouseLeave);\n focalAttachedRef.current = true;\n }\n\n if (features.length > 0) {\n const bounds = computeBounds(features);\n if (bounds) map.fitBounds(bounds, { padding: 20, animate: false });\n }\n if (typeof onUnmappable === \"function\") onUnmappable(failures);\n setFocalReady(true);\n });\n\n return () => {\n cancelled = true;\n };\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [readyMap, records]);\n\n // Focal click handler — defined as stable closure that reads ref.\n const onFocalClick = (e) => {\n const map = mapRef.current;\n if (!map) return;\n const feature = e.features?.[0];\n const key = feature?.properties?._recordKey;\n const record = key ? recordMapRef.current.get(key) : null;\n if (!record) return;\n if (popupRef.current) popupRef.current.remove();\n popupRef.current = new maplibregl.Popup({ closeButton: true, maxWidth: \"320px\" })\n .setLngLat(e.lngLat)\n .setHTML(popupHtml(record))\n .addTo(map);\n };\n\n const onMouseEnter = () => {\n const map = mapRef.current;\n if (map) map.getCanvas().style.cursor = \"pointer\";\n };\n const onMouseLeave = () => {\n const map = mapRef.current;\n if (map) map.getCanvas().style.cursor = \"\";\n };\n\n // Sync focal visibility.\n useEffect(() => {\n const map = mapRef.current;\n if (!map || !focalAttachedRef.current) return;\n const v = focalVisible ? \"visible\" : \"none\";\n if (map.getLayer(FOCAL_FILL)) map.setLayoutProperty(FOCAL_FILL, \"visibility\", v);\n if (map.getLayer(FOCAL_LINE)) map.setLayoutProperty(FOCAL_LINE, \"visibility\", v);\n }, [focalVisible, focalReady]);\n\n // GBIF raster layer — added always last so it sits on top.\n useEffect(() => {\n const map = readyMap;\n if (!map) return;\n const removeGbif = () => {\n if (map.getLayer(GBIF_LAYER)) map.removeLayer(GBIF_LAYER);\n if (map.getSource(GBIF_SOURCE)) map.removeSource(GBIF_SOURCE);\n gbifAttachedRef.current = false;\n };\n removeGbif();\n if (!gbifChecklistKey || !focalTaxon?.id) return;\n // GBIF API said this taxon has 0 occurrences — skip the tile request.\n if (gbifAvailable === false) return;\n const url = (config.gbifApi + GBIF_TILE_PATH)\n .replace(\"{checklistKey}\", encodeURIComponent(gbifChecklistKey))\n .replace(\"{taxonKey}\", encodeURIComponent(focalTaxon.id));\n // Link to GBIF's multitaxonomy occurrence search for the focal taxon on\n // the production portal (config.gbifPortal); same checklistKey we pass to\n // the tile API.\n const searchUrl =\n config.gbifPortal +\n \"/occurrence/search?checklist_key=\" +\n encodeURIComponent(gbifChecklistKey) +\n \"&taxon_key=\" +\n encodeURIComponent(focalTaxon.id);\n map.addSource(GBIF_SOURCE, {\n type: \"raster\",\n tiles: [url],\n tileSize: 256,\n attribution:\n '<a href=\"' +\n searchUrl +\n '\" target=\"_blank\" rel=\"noopener\">GBIF</a> occurrence data',\n });\n map.addLayer({\n id: GBIF_LAYER,\n type: \"raster\",\n source: GBIF_SOURCE,\n paint: { \"raster-opacity\": 0.9 },\n layout: { visibility: gbifVisible ? \"visible\" : \"none\" },\n });\n gbifAttachedRef.current = true;\n // Intentionally no cleanup return: deps changes are handled by the\n // removeGbif() call at the top of the next run, and unmount is handled\n // by the mount effect's map.remove() which disposes everything. If we\n // returned removeGbif here, it could run after map.remove() (React\n // runs cleanups in reverse declaration order on unmount) and throw\n // because MapLibre nulls map.style during remove().\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [readyMap, gbifChecklistKey, focalTaxon?.id, gbifAvailable]);\n\n // Sync GBIF visibility.\n useEffect(() => {\n const map = mapRef.current;\n if (!map || !gbifAttachedRef.current) return;\n const v = gbifVisible ? \"visible\" : \"none\";\n if (map.getLayer(GBIF_LAYER)) map.setLayoutProperty(GBIF_LAYER, \"visibility\", v);\n }, [gbifVisible]);\n\n // Layers start hidden and the visibility effect below reveals the ones the\n // user has ticked. After a basemap switch they are re-added from scratch\n // while `visibleTaxonIds` is unchanged — so that effect would not re-run and\n // the selection would silently disappear. Add them at their current\n // visibility instead.\n const descendantVisibility = (id) =>\n visibleTaxonIds.has(id) ? \"visible\" : \"none\";\n\n // Descendant layers — added once when state.status becomes \"ready\".\n useEffect(() => {\n const map = readyMap;\n if (!map) return;\n // Tear down previous descendant layers.\n descendantLayersRef.current.forEach((id) => {\n if (map.getLayer(descendantFillId(id))) map.removeLayer(descendantFillId(id));\n if (map.getLayer(descendantLineId(id))) map.removeLayer(descendantLineId(id));\n if (map.getSource(descendantSourceId(id))) map.removeSource(descendantSourceId(id));\n });\n descendantLayersRef.current = new Set();\n descendantTaxonMapRef.current = new Map();\n descendantRecordMapRef.current = new Map();\n\n if (descendantState.status !== \"ready\") return;\n const colors = descendantColors;\n descendantState.taxa.forEach((t) => {\n if (t.mappable.length === 0) return;\n descendantTaxonMapRef.current.set(t.id, t);\n Promise.allSettled(\n t.mappable.map((rec) =>\n fetchShape(rec.area.gazetteer, rec.area.id).then((geojson) => ({\n record: rec,\n geojson,\n }))\n )\n ).then((results) => {\n // Same guard as the focal layer: a basemap switch mid-fetch replaces\n // the map, and these writes must not land on the new one.\n if (mapRef.current !== map) return;\n const features = [];\n results.forEach((res, i) => {\n if (res.status !== \"fulfilled\" || !res.value.geojson) return;\n const { record, geojson } = res.value;\n const recordKey = `desc-${t.id}-${i}`;\n descendantRecordMapRef.current.set(recordKey, { taxon: t, record });\n flattenFeatures(geojson).forEach((f) => {\n features.push({\n ...f,\n properties: {\n ...(f.properties || {}),\n _recordKey: recordKey,\n },\n });\n });\n });\n const color = colors[t.id] || MISSING_COLOR;\n const data = { type: \"FeatureCollection\", features };\n const srcId = descendantSourceId(t.id);\n if (mapRef.current.getSource(srcId)) {\n mapRef.current.getSource(srcId).setData(data);\n } else {\n mapRef.current.addSource(srcId, { type: \"geojson\", data });\n const fillId = descendantFillId(t.id);\n const lineId = descendantLineId(t.id);\n const beforeId = mapRef.current.getLayer(GBIF_LAYER) ? GBIF_LAYER : undefined;\n mapRef.current.addLayer(\n {\n id: fillId,\n type: \"fill\",\n source: srcId,\n paint: { \"fill-color\": color, \"fill-opacity\": 0.55 },\n layout: { visibility: descendantVisibility(t.id) },\n },\n beforeId\n );\n mapRef.current.addLayer(\n {\n id: lineId,\n type: \"line\",\n source: srcId,\n paint: { \"line-color\": color, \"line-width\": 2 },\n layout: { visibility: descendantVisibility(t.id) },\n },\n beforeId\n );\n mapRef.current.on(\"click\", fillId, onDescendantClick);\n mapRef.current.on(\"mouseenter\", fillId, onMouseEnter);\n mapRef.current.on(\"mouseleave\", fillId, onMouseLeave);\n descendantLayersRef.current.add(t.id);\n }\n });\n });\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [readyMap, descendantState, descendantColors]);\n\n const onDescendantClick = (e) => {\n const map = mapRef.current;\n if (!map) return;\n const feature = e.features?.[0];\n const key = feature?.properties?._recordKey;\n const data = key ? descendantRecordMapRef.current.get(key) : null;\n if (!data) return;\n if (popupRef.current) popupRef.current.remove();\n popupRef.current = new maplibregl.Popup({ closeButton: true, maxWidth: \"320px\" })\n .setLngLat(e.lngLat)\n .setHTML(descendantPopupHtml(data.taxon, data.record))\n .addTo(map);\n };\n\n // Sync descendant visibility.\n useEffect(() => {\n const map = mapRef.current;\n if (!map) return;\n descendantLayersRef.current.forEach((id) => {\n const v = visibleTaxonIds.has(id) ? \"visible\" : \"none\";\n if (map.getLayer(descendantFillId(id))) {\n map.setLayoutProperty(descendantFillId(id), \"visibility\", v);\n }\n if (map.getLayer(descendantLineId(id))) {\n map.setLayoutProperty(descendantLineId(id), \"visibility\", v);\n }\n });\n }, [visibleTaxonIds, descendantState]);\n\n // Trigger descendant fetch (on control open).\n const triggerDescendantFetch = () => {\n if (fetchTriggeredRef.current) return;\n if (!datasetKey || !focalTaxon || !rankOrder) return;\n const focalRank = focalTaxon?.name?.rank;\n if (!focalRank) return;\n if (focalRank !== \"species\" && !INFRASPECIFIC_RANKS.includes(focalRank)) return;\n const ranks = getDescendantRanks(focalRank, rankOrder);\n if (ranks.length === 0) return;\n fetchTriggeredRef.current = true;\n setDescendantState({ status: \"loading\", taxa: [] });\n fetchDescendants({ datasetKey, focalTaxon, rankOrder }).then(\n ({ taxa, descendantsFailed }) => {\n if (descendantsFailed) {\n setDescendantState({ status: \"error\", taxa: [] });\n return;\n }\n if (taxa.length === 0) {\n setDescendantState({ status: \"empty\", taxa: [] });\n return;\n }\n setDescendantState({ status: \"ready\", taxa });\n }\n );\n };\n\n const openControl = () => {\n setControlOpen(true);\n triggerDescendantFetch();\n };\n\n // Group descendants by rank for the control panel.\n const descendantsByRank = useMemo(() => {\n if (descendantState.status !== \"ready\") return [];\n const byRank = {};\n descendantState.taxa\n .filter((t) => t.mappable.length > 0)\n .forEach((t) => {\n (byRank[t.rank] = byRank[t.rank] || []).push(t);\n });\n return INFRASPECIFIC_RANKS.filter((r) => byRank[r]).map((r) => ({\n rank: r,\n label: rankLabelPlural(r),\n taxa: byRank[r].slice().sort((a, b) =>\n a.scientificName.localeCompare(b.scientificName)\n ),\n }));\n }, [descendantState]);\n\n const toggleTaxon = (id) => {\n setVisibleTaxonIds((prev) => {\n const next = new Set(prev);\n if (next.has(id)) next.delete(id);\n else next.add(id);\n return next;\n });\n };\n\n const toggleRankGroup = (rankTaxa) => {\n setVisibleTaxonIds((prev) => {\n const next = new Set(prev);\n const allOn = rankTaxa.every((t) => prev.has(t.id));\n rankTaxa.forEach((t) => {\n if (allOn) next.delete(t.id);\n else next.add(t.id);\n });\n return next;\n });\n };\n\n if (!supported()) {\n return (\n <div\n style={{\n padding: 12,\n background: \"#fafafa\",\n border: \"1px solid #eee\",\n borderRadius: 4,\n color: \"#666\",\n fontSize: 12,\n }}\n >\n Maps require WebGL, which your browser doesn't support.\n </div>\n );\n }\n\n // A GBIF-only taxon (no curated distribution polygons) with the GBIF overlay\n // turned off would render a blank map — collapse to a slim bar that\n // re-activates the map + overlay.\n if (isGbifOnly && !gbifVisible) {\n return (\n <div\n className=\"col-distributions-map col-distributions-map--collapsed\"\n style={{\n display: \"flex\",\n alignItems: \"center\",\n gap: 6,\n padding: \"8px 12px\",\n background: \"#fafafa\",\n border: \"1px solid #eee\",\n borderRadius: 4,\n color: \"#666\",\n fontSize: 12,\n }}\n >\n <span>No curated distribution data.</span>\n <a\n role=\"button\"\n tabIndex={0}\n style={{ cursor: \"pointer\" }}\n onClick={activateGbif}\n onKeyDown={(e) => {\n if (e.key === \"Enter\" || e.key === \" \") {\n e.preventDefault();\n activateGbif();\n }\n }}\n >\n Show GBIF occurrences\n </a>\n </div>\n );\n }\n\n const focalName = focalTaxon?.name?.scientificName || \"This taxon\";\n\n return (\n <div\n className=\"col-distributions-map\"\n ref={wrapperRef}\n style={{ position: \"relative\" }}\n >\n <div\n ref={containerRef}\n className=\"col-distributions-map__canvas\"\n style={{ height: 360, width: \"100%\", background: \"#f5f5f5\" }}\n />\n\n <LayerControl\n open={controlOpen}\n onOpen={openControl}\n onClose={() => setControlOpen(false)}\n focalName={focalName}\n focalReady={focalReady}\n focalVisible={focalVisible}\n onToggleFocal={() => setFocalVisible((v) => !v)}\n gbifEnabled={!!gbifChecklistKey}\n gbifVisible={gbifVisible}\n gbifAvailable={gbifAvailable}\n onToggleGbif={handleToggleGbif}\n descendantStatus={descendantState.status}\n descendantsByRank={descendantsByRank}\n descendantColors={descendantColors}\n visibleTaxonIds={visibleTaxonIds}\n onToggleTaxon={toggleTaxon}\n onToggleRankGroup={toggleRankGroup}\n onRetry={() => {\n fetchTriggeredRef.current = false;\n setDescendantState({ status: \"idle\", taxa: [] });\n triggerDescendantFetch();\n }}\n />\n\n {!showDescendantLegend &&\n (presentMeans.length > 0 ||\n (gbifChecklistKey && gbifAvailable !== false && gbifVisible)) && (\n <div\n style={{\n position: \"absolute\",\n bottom: 8,\n left: 8,\n zIndex: 1,\n background: \"#fff\",\n borderRadius: 4,\n boxShadow: \"0 1px 4px rgba(0,0,0,0.2)\",\n padding: \"6px 8px\",\n fontSize: 12,\n lineHeight: 1.5,\n }}\n >\n {presentMeans.map((m) => (\n <div\n key={m.key}\n style={{ display: \"flex\", alignItems: \"center\", gap: 6 }}\n >\n <span\n style={{\n display: \"inline-block\",\n width: 12,\n height: 12,\n background: m.color,\n border: \"1px solid rgba(0,0,0,0.15)\",\n borderRadius: 2,\n }}\n />\n <span>{m.label}</span>\n </div>\n ))}\n {gbifChecklistKey && gbifAvailable !== false && gbifVisible && (\n <GbifLegendEntry />\n )}\n </div>\n )}\n {showDescendantLegend && (\n <IncludedTaxaLegend\n visibleGroups={descendantLegend.visibleGroups}\n unmappableGroups={descendantLegend.unmappableGroups}\n showGbif={!!gbifChecklistKey && gbifAvailable !== false && gbifVisible}\n />\n )}\n </div>\n );\n};\n\n// Layer toggle panel — collapsed \"+\" button at top-right that expands on click.\nconst LayerControl = ({\n open,\n onOpen,\n onClose,\n focalName,\n focalReady,\n focalVisible,\n onToggleFocal,\n gbifEnabled,\n gbifVisible,\n gbifAvailable,\n onToggleGbif,\n descendantStatus,\n descendantsByRank,\n descendantColors,\n visibleTaxonIds,\n onToggleTaxon,\n onToggleRankGroup,\n onRetry,\n}) => {\n if (!open) {\n return (\n <button\n type=\"button\"\n onClick={onOpen}\n onMouseEnter={onOpen}\n title=\"Layers\"\n style={{\n position: \"absolute\",\n // Sits just below the maplibre fullscreen control (top-right).\n top: 48,\n right: 10,\n zIndex: 2,\n width: 30,\n height: 30,\n background: \"#fff\",\n border: \"1px solid rgba(0,0,0,0.2)\",\n borderRadius: 4,\n cursor: \"pointer\",\n fontSize: 18,\n lineHeight: \"26px\",\n padding: 0,\n boxShadow: \"0 1px 4px rgba(0,0,0,0.2)\",\n }}\n >\n +\n </button>\n );\n }\n return (\n <div\n style={{\n position: \"absolute\",\n // Aligns with the collapsed \"+\" button, below the fullscreen control.\n top: 48,\n right: 10,\n zIndex: 2,\n background: \"#fff\",\n borderRadius: 4,\n boxShadow: \"0 1px 4px rgba(0,0,0,0.2)\",\n padding: \"6px 10px\",\n fontSize: 12,\n lineHeight: 1.5,\n maxHeight: 320,\n overflowY: \"auto\",\n minWidth: 160,\n }}\n onMouseLeave={onClose}\n >\n <div style={{ display: \"flex\", alignItems: \"center\", gap: 6 }}>\n <input\n type=\"checkbox\"\n checked={focalVisible}\n disabled={!focalReady}\n onChange={onToggleFocal}\n />\n <span style={{ fontStyle: \"italic\" }}>{focalName}</span>\n </div>\n {gbifEnabled && (\n <div\n style={{\n display: \"flex\",\n alignItems: \"center\",\n gap: 6,\n opacity: gbifAvailable === false ? 0.5 : 1,\n }}\n title={\n gbifAvailable === false\n ? \"GBIF has no occurrence records for this taxon.\"\n : undefined\n }\n >\n <input\n type=\"checkbox\"\n checked={gbifAvailable === false ? false : gbifVisible}\n disabled={gbifAvailable === false}\n onChange={onToggleGbif}\n />\n <span>GBIF occurrences</span>\n </div>\n )}\n {descendantStatus === \"loading\" && (\n <div style={{ marginTop: 6, color: \"#888\" }}>Loading descendants…</div>\n )}\n {descendantStatus === \"error\" && (\n <div style={{ marginTop: 6, color: \"#888\" }}>\n Couldn't load descendants.{\" \"}\n <a onClick={onRetry} style={{ cursor: \"pointer\" }}>\n Retry\n </a>\n </div>\n )}\n {descendantStatus === \"ready\" &&\n descendantsByRank.map((group) => {\n const allOn = group.taxa.every((t) => visibleTaxonIds.has(t.id));\n const someOn = group.taxa.some((t) => visibleTaxonIds.has(t.id));\n return (\n <div key={group.rank} style={{ marginTop: 6 }}>\n <label\n style={{\n display: \"flex\",\n alignItems: \"center\",\n gap: 6,\n fontWeight: 600,\n }}\n >\n <input\n type=\"checkbox\"\n checked={allOn}\n ref={(el) => {\n if (el) el.indeterminate = !allOn && someOn;\n }}\n onChange={() => onToggleRankGroup(group.taxa)}\n />\n {group.label}\n </label>\n <div style={{ paddingLeft: 18 }}>\n {group.taxa.map((t) => (\n <label\n key={t.id}\n style={{\n display: \"flex\",\n alignItems: \"center\",\n gap: 6,\n }}\n >\n <input\n type=\"checkbox\"\n checked={visibleTaxonIds.has(t.id)}\n onChange={() => onToggleTaxon(t.id)}\n />\n <span\n style={{\n display: \"inline-block\",\n width: 10,\n height: 10,\n background: descendantColors[t.id],\n border: \"1px solid rgba(0,0,0,0.15)\",\n borderRadius: 2,\n }}\n />\n <span style={{ fontStyle: \"italic\" }}>\n {epithet(t.scientificName)}\n </span>\n </label>\n ))}\n </div>\n </div>\n );\n })}\n </div>\n );\n};\n\nexport default DistributionsMap;\n","import { useState, useEffect } from \"react\";\nimport { Radio } from \"antd\";\nimport { get, keyBy, startCase } from \"lodash-es\";\nimport ReferencePopover from \"./ReferencePopover\";\nimport config from \"../config\";\n// publicClient (no CoL auth) for the third-party GBIF occurrence API below.\nimport client, { publicClient } from \"../api/client\";\nimport MergedDataBadge from \"../components/MergedDataBadge\";\nimport PresentationItem from \"../components/PresentationItem\";\nimport DistributionsMap from \"./DistributionsMap\";\n\nconst isMappable = (r) =>\n r?.area?.gazetteer !== \"text\" && !!r?.area?.globalId;\n\nconst ListView = ({ datasetKey, data }) => {\n const [iso3Map, setIso3Map] = useState({});\n\n useEffect(() => {\n let isIso = false;\n for (let i = 0; i < data.length; i++) {\n if (data[i].gazetteer === \"iso\") {\n isIso = true;\n break;\n }\n }\n if (isIso) {\n client(`${config.dataApi}vocab/country`).then((res) => {\n setIso3Map(keyBy(res.data, \"alpha3\"));\n });\n }\n }, []);\n\n return (\n <div>\n {data.map((s, i) => (\n <span key={i}>\n {s?.merged && (\n <MergedDataBadge\n createdBy={s?.createdBy}\n datasetKey={s.datasetKey}\n sourceDatasetKey={s?.sourceDatasetKey}\n verbatimSourceKey={s?.verbatimSourceKey}\n style={{ marginRight: \"4px\" }}\n />\n )}\n {(get(iso3Map, `[${get(s, \"area.name\")}].name`)\n ? startCase(get(iso3Map, `[${get(s, \"area.name\")}].name`))\n : null) ||\n get(s, \"area.name\") ||\n get(s, \"area.globalId\")}{\" \"}\n {s.referenceId && (\n <ReferencePopover\n datasetKey={datasetKey}\n referenceId={s.referenceId}\n placement=\"bottom\"\n />\n )}\n {i < data.length - 1 && \", \"}\n </span>\n ))}\n </div>\n );\n};\n\nconst DistributionsTable = ({\n datasetKey,\n data,\n style,\n showDistributionMap,\n focalTaxon,\n rankOrder,\n gbifChecklistKey,\n basemapStyle,\n label,\n md,\n}) => {\n const mappable = data.filter(isMappable);\n const baseUnmappable = data.length - mappable.length;\n const hasGbifConfigured = !!gbifChecklistKey;\n const hasAnyRecords = data.length > 0;\n const [view, setView] = useState(\"map\");\n const [fetchFailures, setFetchFailures] = useState(0);\n\n // null = unknown (loading or unconfigured), number = occurrence count.\n const [gbifCount, setGbifCount] = useState(null);\n useEffect(() => {\n if (!gbifChecklistKey || !focalTaxon?.id) {\n setGbifCount(null);\n return undefined;\n }\n setGbifCount(null);\n let cancelled = false;\n publicClient\n .get(`${config.gbifApi}/v1/occurrence/search`, {\n params: {\n checklistKey: gbifChecklistKey,\n taxonKey: focalTaxon.id,\n hasCoordinate: true,\n hasGeospatialIssue: false,\n occurrenceStatus: 'PRESENT',\n limit: 0,\n },\n })\n .then(\n (res) => {\n if (!cancelled) setGbifCount(res?.data?.count ?? 0);\n },\n () => {\n // On API failure, treat as \"unknown\" — leave the toggle enabled\n // rather than greying it out for an outage.\n if (!cancelled) setGbifCount(null);\n }\n );\n return () => {\n cancelled = true;\n };\n }, [gbifChecklistKey, focalTaxon?.id]);\n\n // true → GBIF has occurrences (or unknown — still loading or API failed)\n // false → GBIF returned count = 0\n const gbifAvailable = !hasGbifConfigured\n ? false\n : gbifCount === null || gbifCount > 0;\n\n const allMappableFailed =\n mappable.length > 0 && fetchFailures >= mappable.length;\n const showMap =\n showDistributionMap &&\n (mappable.length > 0 || gbifAvailable) &&\n !(mappable.length > 0 && allMappableFailed && !gbifAvailable);\n\n // Nothing to show — no map (no mappable records and no GBIF occurrences) and\n // no records to list. Hide the whole block, like other empty content blocks.\n if (!showMap && !hasAnyRecords) return null;\n\n const unmappable = baseUnmappable + fetchFailures;\n const showToggle = hasAnyRecords;\n\n let body;\n if (!showMap) {\n // No map to show — just the plain text list.\n body = <ListView datasetKey={datasetKey} data={data} />;\n } else {\n // Map available. The Map/List toggle is rendered above the view switch so\n // it stays visible in BOTH sub-views — the user can always go back to the\n // map after looking at the list.\n const activeView = showToggle ? view : \"map\";\n body = (\n <>\n {showToggle ? (\n <Radio.Group\n size=\"small\"\n value={activeView}\n onChange={(e) => setView(e.target.value)}\n style={{ marginBottom: 8 }}\n >\n <Radio.Button value=\"map\">Map</Radio.Button>\n <Radio.Button value=\"list\">List</Radio.Button>\n </Radio.Group>\n ) : (\n // Reserve the vertical space the Map/List toggle would occupy so the\n // map's top edge lines up with the \"Distributions\" label.\n <div style={{ height: 24, marginBottom: 8 }} />\n )}\n {activeView === \"map\" ? (\n <>\n <DistributionsMap\n records={mappable}\n onUnmappable={setFetchFailures}\n datasetKey={datasetKey}\n focalTaxon={focalTaxon}\n rankOrder={rankOrder}\n gbifChecklistKey={gbifChecklistKey}\n gbifAvailable={gbifAvailable}\n basemapStyle={basemapStyle}\n />\n {showToggle && unmappable > 0 && (\n <div style={{ marginTop: 6 }}>\n <a onClick={() => setView(\"list\")} style={{ cursor: \"pointer\" }}>\n +{unmappable} distribution{unmappable === 1 ? \"\" : \"s\"} not on\n map\n </a>\n </div>\n )}\n </>\n ) : (\n <ListView datasetKey={datasetKey} data={data} />\n )}\n </>\n );\n }\n\n // No negative top nudge: the map block's top element (the Map/List toggle, or\n // the spacer reserving its height) lines up with the \"Distributions\" label\n // the same way every other content row does. The plain text-only list aligns\n // naturally too.\n const content = <div style={style}>{body}</div>;\n\n // When a `label` is given (the Taxon page), own the labelled block so it\n // disappears entirely when empty (returning null above). Standalone embeds\n // pass no label and just get the bare block.\n return label ? (\n <PresentationItem md={md} label={label}>\n {content}\n </PresentationItem>\n ) : (\n content\n );\n};\n\nexport default DistributionsTable;\n"],"names":["BookOutlined","_extends","target","i","source","key","props","ref","React","AntdIcon","BookOutlinedSvg","RefIcon","ReferencePopover","__publicField","referenceId","datasetKey","references","refIds","isArray","reference","id","get","client","config","res","err","error","loading","Spin","jsx","ErrorMsg","r","e","el","referenceIndexMap","trigger","maxInline","icon","shown","overflow","Popover","visible","INFRASPECIFIC_RANKS","getDescendantRanks","focalRank","rankOrder","focalIdx","POOL_SIZE","isMappable","_a","_b","runPool","items","worker","size","results","next","runners","searchDescendants","focalId","ranks","params","s","url","u","_c","_e","_d","_f","fetchDistributions","taxonId","fetchDescendants","focalTaxon","descendantsFailed","list","distributions","t","all","VIVID_PALETTE","rankIndex","rank","assignColors","taxa","sorted","a","b","ra","rb","out","resolveBasemapStyle","prop","CARTO_HOST","cartoTransformRequest","parsed","wrapStyle","scrollStyle","groupHeadingStyle","firstGroupHeadingStyle","rowStyle","swatchStyle","color","footerToggleStyle","footerWrapStyle","footerGroupHeadingStyle","footerFirstGroupHeadingStyle","footerNameStyle","totalCount","groups","sum","g","GbifHexEntry","jsxs","IncludedTaxaLegend","visibleGroups","unmappableGroups","showGbif","showUnmappable","setShowUnmappable","useState","visibleCount","unmappableCount","Fragment","v","POPUP_FIELDS","ESTABLISHMENT_MEANS","ESTABLISHMENT_COLORS","m","MISSING_COLOR","normalizeKey","resolveKey","record","raw","k","colorFor","GBIF_VISIBLE_KEY","readStoredGbifVisible","defaultValue","readSetting","writeStoredGbifVisible","writeSetting","GBIF_TILE_PATH","FOCAL_SOURCE","FOCAL_FILL","FOCAL_LINE","GBIF_SOURCE","GBIF_LAYER","descendantSourceId","descendantFillId","descendantLineId","cache","fetchShape","gazetteer","p","escapeHtml","popupHtml","title","rows","f","descendantPopupHtml","taxon","RANK_LABEL_PLURAL","rankLabelPlural","epithet","scientificName","tokens","GbifLegendEntry","computeBounds","features","minLng","minLat","maxLng","maxLat","visit","coords","lng","lat","flattenFeatures","geojson","supported","maplibregl","DistributionsMap","records","onUnmappable","gbifChecklistKey","gbifAvailable","basemapStyle","containerRef","useRef","wrapperRef","mapRef","popupRef","recordMapRef","descendantTaxonMapRef","descendantRecordMapRef","focalAttachedRef","gbifAttachedRef","descendantLayersRef","readyMap","setReadyMap","focalReady","setFocalReady","descendantState","setDescendantState","focalVisible","setFocalVisible","isGbifOnly","gbifVisible","setGbifVisible","visibleTaxonIds","setVisibleTaxonIds","controlOpen","setControlOpen","fetchTriggeredRef","handleToggleGbif","activateGbif","presentMeans","useMemo","seen","descendantColors","descendantLegend","decorate","groupByRank","byRank","showDescendantLegend","styleSpec","cartoKey","styleKey","useEffect","map","attrib","resizeObserver","cancelled","recordMap","failures","recordKey","data","beforeId","onFocalClick","onMouseEnter","onMouseLeave","bounds","feature","searchUrl","descendantVisibility","colors","rec","srcId","fillId","lineId","onDescendantClick","triggerDescendantFetch","openControl","descendantsByRank","toggleTaxon","prev","toggleRankGroup","rankTaxa","allOn","focalName","LayerControl","open","onOpen","onClose","onToggleFocal","gbifEnabled","onToggleGbif","descendantStatus","onToggleTaxon","onToggleRankGroup","onRetry","group","someOn","ListView","iso3Map","setIso3Map","isIso","keyBy","MergedDataBadge","startCase","DistributionsTable","style","showDistributionMap","label","md","mappable","baseUnmappable","hasGbifConfigured","hasAnyRecords","view","setView","fetchFailures","setFetchFailures","gbifCount","setGbifCount","publicClient","allMappableFailed","showMap","unmappable","showToggle","body","activeView","Radio","content","PresentationItem"],"mappings":";;;;;;;;;;;;;;;;;AACA,IAAIA,KAAe,EAAE,MAAQ,EAAE,KAAO,OAAO,OAAS,EAAE,SAAW,iBAAiB,WAAa,QAAO,GAAI,UAAY,CAAC,EAAE,KAAO,QAAQ,OAAS,EAAE,GAAK,mSAAkS,GAAI,EAAC,GAAI,MAAQ,QAAQ,OAAS,WAAU;ACDxe,SAASC,KAAW;AAAE,SAAAA,KAAW,OAAO,SAAS,OAAO,OAAO,SAAS,SAAUC,GAAQ;AAAE,aAASC,IAAI,GAAGA,IAAI,UAAU,QAAQA,KAAK;AAAE,UAAIC,IAAS,UAAUD,CAAC;AAAG,eAASE,KAAOD;AAAU,QAAI,OAAO,UAAU,eAAe,KAAKA,GAAQC,CAAG,MAAKH,EAAOG,CAAG,IAAID,EAAOC,CAAG;AAAA,IAAO;AAAE,WAAOH;AAAA,EAAQ,GAAUD,GAAS,MAAM,MAAM,SAAS;AAAG;AAOlV,MAAMD,KAAe,CAACM,GAAOC,MAAqB,gBAAAC,GAAM,cAAcC,IAAUR,GAAS,CAAA,GAAIK,GAAO;AAAA,EAClG,KAAKC;AAAA,EACL,MAAMG;AACR,CAAC,CAAC,GAGIC,KAAuB,gBAAAH,GAAM,WAAWR,EAAY;AACtD,QAAQ,IAAI,aAAa,iBAC3BW,GAAQ,cAAc;ACPxB,MAAMC,WAAyBJ,GAAM,UAAU;AAAA,EAC7C,YAAYF,GAAO;AACjB,UAAMA,CAAK;AASb,IAAAO,EAAA,iBAAU,MAAM;AACd,YAAM,EAAE,aAAAC,GAAa,YAAAC,GAAY,YAAAC,EAAA,IAAe,KAAK;AACpD,UAAIF,GAAa;AAChB,cAAMG,IAAUC,GAAQJ,CAAW,IAAoBA,IAAhB,CAACA,CAAW,GAC7CK,IAAY,CAAA;AAClB,aAAK,SAAS,EAAE,SAAS,GAAA,CAAM,GAC/B,QAAQ;AAAA,UACNF,EAAO;AAAA,YAAI,CAACG,MAAOC,EAAIL,GAAYI,CAAE,IAAI,QAAQ,QAAQD,EAAU,KAAKH,EAAWI,CAAE,CAAC,CAAC,IAErFE;AAAA,cACE,GAAGC,EAAO,OAAO,WAAWR,CAAU,cAAcK,CAAE;AAAA,YAAA,EACtD,KAAK,CAACI,MAAQL,EAAU,KAAKK,EAAI,IAAI,CAAC,EAAE,MAAM,OAAO,KAAK,SAAS,EAAC,OAAOC,GAAI,CAAC;AAAA,UAAA;AAAA,QAGpF,EACA,KAAK,MAAM,KAAK,SAAS,EAAE,WAAAN,GAAW,SAAS,GAAA,CAAO,CAAC;AAAA,MAC3D;AAAA,IACF;AAEA,IAAAN,EAAA,oBAAa,MAAM;AACjB,YAAM,EAAE,OAAAa,GAAO,WAAAP,GAAW,SAAAQ,EAAA,IAAY,KAAK;AAC3C,aAAIA,0BACMC,IAAA,EAAK,IACJF,IACFG,gBAAAA,MAACC,MAAS,OAAAJ,GAAa,IACrBP,EAAU,WAAW,IACvBA,EAAU,CAAC,EAAE,WAGlBU,gBAAAA,EAAAA,IAAC,MAAA,EACE,UAAAV,EAAU,IAAI,CAACY,MACdF,gBAAAA,EAAAA,IAAC,MAAA,EAAe,UAAAE,EAAE,SAAA,GAATA,EAAE,EAAgB,CAC5B,GACH;AAAA,IAGN;AAEA,IAAAlB,EAAA,2BAAoB,CAACmB,GAAGZ,MAAO;AAK7B,YAAMa,IAAK,SAAS,eAAe,iBAAiBb,CAAE,EAAE;AACxD,MAAIa,MACFD,EAAE,eAAA,GACFC,EAAG,eAAe,EAAE,UAAU,UAAU,OAAO,SAAS;AAAA,IAE5D;AAEA,IAAApB,EAAA,gBAAS,MAAM;AACb,YAAM,EAAE,aAAAC,GAAa,mBAAAoB,GAAmB,SAAAC,EAAA,IAAY,KAAK,OAInDC,IAAY,KAAK,MAAM,aAAa,GACpCnB,IAAUC,GAAQJ,CAAW,IAAoBA,IAAhB,CAACA,CAAW;AACnD,UAAIuB,IAAOH,KAAqBb,EAAIa,GAAmBjB,EAAO,CAAC,CAAC,KAC3D,MAAM;AACL,cAAMqB,IAAQrB,EAAO,MAAM,GAAGmB,CAAS,GACjCG,IAAWtB,EAAO,SAASqB,EAAM;AACvC,eAAO;AAAA,UACL,GAAGA,EAAM,IAAI,CAACP,MACZF,gBAAAA,EAAAA;AAAAA,YAAC;AAAA,YAAA;AAAA,cAEC,WAAU;AAAA,cACV,MAAM,kBAAkBE,CAAC;AAAA,cACzB,SAAS,CAACC,MAAM,KAAK,kBAAkBA,GAAGD,CAAC;AAAA,cAE1C,UAAA,IAAIG,EAAkBH,CAAC,CAAC;AAAA,YAAA;AAAA,YALpBA;AAAA,UAAA,CAOR;AAAA,UACDQ,IAAW,IACTV,gBAAAA,EAAAA,IAAC,QAAA,EAAoB,WAAU,sBAC5B,UAAA,KAAKU,CAAQ,GAAA,GADN,UAEV,IACE;AAAA,QAAA;AAAA,MAER,GAAA,IACAV,gBAAAA,EAAAA,IAAC7B,IAAA,EAAa,OAAO,EAAE,QAAQ,aAAa;AAEhD,aAAOc,IACLe,gBAAAA,EAAAA,IAAC,OAAA,EAAI,IAAI,aAAaf,CAAW,IAAqC,OAAO,KAAK,MAAM,OACtF,UAAAe,gBAAAA,EAAAA;AAAAA,QAACW;AAAA,QAAA;AAAA,UACC,mBAAmB,MACjB,SAAS,eAAe,aAAa1B,CAAW,EAAE;AAAA,UAEpD,WAAW,KAAK,MAAM,aAAa;AAAA,UACnC,OAAM;AAAA,UACN,cAAc,CAAC2B,MAAYA,KAAW,KAAK,QAAA;AAAA,UAC3C,SACEZ,gBAAAA,EAAAA;AAAAA,YAAC;AAAA,YAAA;AAAA,cACC,OAAO;AAAA,gBACL,UAAU;AAAA,gBACV,WAAW;AAAA,gBACX,WAAW;AAAA,cAAA;AAAA,cAGZ,eAAK,WAAA;AAAA,YAAW;AAAA,UAAA;AAAA,UAGrB,SAASM,KAAW;AAAA,UAEnB,UAAAE;AAAA,QAAA;AAAA,MAAA,EACH,GAtBwC,aAAavB,CAAW,EAuBlE,IAEA;AAAA,IAEJ;AApHE,SAAK,QAAQ;AAAA,MACX,WAAW,CAAA;AAAA,MACX,SAAS;AAAA,MACT,OAAO;AAAA,IAAA;AAAA,EAEX;AAgHF;ACjIO,MAAM4B,KAAsB;AAAA,EACjC;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,GAEaC,KAAqB,CAACC,GAAWC,MAAc;AAC1D,QAAMC,IAAWD,EAAU,QAAQD,CAAS;AAC5C,SAAIE,MAAa,KAAW,CAAA,IACrBJ,GAAoB,OAAO,CAACX,MACvBc,EAAU,QAAQd,CAAC,IAClBe,CACZ;AACH,GCZMC,KAAY,IAEZC,KAAa,CAACjB,MAAA;;AAClB,WAAAkB,IAAAlB,KAAA,gBAAAA,EAAG,SAAH,gBAAAkB,EAAS,eAAc,UAAU,CAAC,GAACC,IAAAnB,KAAA,gBAAAA,EAAG,SAAH,QAAAmB,EAAS;AAAA,GAExCC,KAAU,OAAOC,GAAOC,GAAQC,MAAS;AAC7C,QAAMC,IAAU,IAAI,MAAMH,EAAM,MAAM;AACtC,MAAII,IAAO;AACX,QAAMC,IAAU,MAAM,KAAK,EAAE,QAAQ,KAAK,IAAIH,GAAMF,EAAM,MAAM,EAAA,GAAK,YAAY;AAC/E,eAAa;AACX,YAAMjD,IAAIqD;AACV,UAAIrD,KAAKiD,EAAM,OAAQ;AACvB,MAAAG,EAAQpD,CAAC,IAAI,MAAMkD,EAAOD,EAAMjD,CAAC,GAAGA,CAAC;AAAA,IACvC;AAAA,EACF,CAAC;AACD,eAAM,QAAQ,IAAIsD,CAAO,GAClBF;AACT,GAEMG,KAAoB,OAAO3C,GAAY4C,GAASC,MAAU;;AAC9D,MAAIA,EAAM,WAAW,EAAG,QAAO,CAAA;AAC/B,QAAMC,IAAS,IAAI,gBAAA;AACnB,EAAAA,EAAO,OAAO,YAAYF,CAAO,GACjCC,EAAM,QAAQ,CAAC7B,MAAM8B,EAAO,OAAO,QAAQ9B,CAAC,CAAC,GAC7C,CAAC,YAAY,wBAAwB,EAAE;AAAA,IAAQ,CAAC+B,MAC9CD,EAAO,OAAO,UAAUC,CAAC;AAAA,EAAA,GAE3BD,EAAO,OAAO,SAAS,MAAM;AAC7B,QAAME,IAAM,GAAGxC,EAAO,OAAO,WAAWR,CAAU,qBAAqB8C,CAAM,IACvErC,IAAM,MAAMF,GAAOyC,CAAG;AAE5B,YADad,IAAAzB,KAAA,gBAAAA,EAAK,SAAL,gBAAAyB,EAAW,WAAU,CAAA,GAE/B,OAAO,CAACe,MAAA;;AAAM,YAAAf,IAAAe,KAAA,gBAAAA,EAAG,UAAH,gBAAAf,EAAU;AAAA,GAAE,EAC1B,IAAI,CAACe,MAAA;;AAAO;AAAA,MACX,IAAIA,EAAE,MAAM;AAAA,MACZ,kBACEd,KAAAD,IAAAe,EAAE,UAAF,gBAAAf,EAAS,SAAT,gBAAAC,EAAe,qBAAkBe,IAAAD,EAAE,UAAF,gBAAAC,EAAS,UAASD,EAAE,MAAM;AAAA,MAC7D,OAAME,KAAAC,IAAAH,EAAE,UAAF,gBAAAG,EAAS,SAAT,gBAAAD,EAAe;AAAA,MACrB,WAAUE,IAAAJ,EAAE,UAAF,gBAAAI,EAAS;AAAA,IAAA;AAAA,GACnB;AACN,GAEMC,KAAqB,OAAOtD,GAAYuD,MAAY;AACxD,QAAMP,IAAM,GAAGxC,EAAO,OAAO,WAAWR,CAAU,UAAU,mBAAmBuD,CAAO,CAAC;AACvF,MAAI;AACF,UAAM9C,IAAM,MAAMF,GAAOyC,CAAG;AAC5B,WAAO,MAAM,QAAQvC,KAAA,gBAAAA,EAAK,IAAI,IAAIA,EAAI,OAAO,CAAA;AAAA,EAC/C,QAAQ;AACN,WAAO,CAAA;AAAA,EACT;AACF,GAOa+C,KAAmB,OAAO,EAAE,YAAAxD,GAAY,YAAAyD,GAAY,WAAA3B,QAAgB;;AAC/E,QAAMe,IAAQjB,IAAmBM,IAAAuB,KAAA,gBAAAA,EAAY,SAAZ,gBAAAvB,EAAkB,MAAMJ,CAAS;AAClE,MAAI4B,IAAoB,IACpBC,IAAO,CAAA;AACX,MAAI;AACF,IAAAA,IAAO,MAAMhB,GAAkB3C,GAAYyD,EAAW,IAAIZ,CAAK;AAAA,EACjE,QAAQ;AACN,WAAAa,IAAoB,IACb,EAAE,MAAM,CAAA,GAAI,mBAAAA,EAAA;AAAA,EACrB;AAEA,QAAME,IAAgB,MAAMxB;AAAA,IAC1BuB;AAAA,IACA,CAACE,MAAMP,GAAmBtD,GAAY6D,EAAE,EAAE;AAAA,IAC1C7B;AAAA,EAAA;AAOF,SAAO,EAAE,MAJI2B,EAAK,IAAI,CAACE,GAAGzE,MAAM;AAC9B,UAAM0E,IAAMF,EAAcxE,CAAC,KAAK,CAAA;AAChC,WAAO,EAAE,GAAGyE,GAAG,eAAeC,GAAK,UAAUA,EAAI,OAAO7B,EAAU,EAAA;AAAA,EACpE,CAAC,GACc,mBAAAyB,EAAA;AACjB,GCnFaK,KAAgB;AAAA,EAC3B;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,GAEMC,KAAY,CAACC,GAAMnC,MAAc;AACrC,QAAM1C,IAAI0C,EAAU,QAAQmC,CAAI;AAChC,SAAO7E,MAAM,KAAK0C,EAAU,SAAS1C;AACvC,GAEa8E,KAAe,CAACC,GAAMrC,MAAc;AAC/C,QAAMsC,IAAS,CAAC,GAAGD,CAAI,EAAE,KAAK,CAACE,GAAGC,MAAM;AACtC,UAAMC,IAAKP,GAAUK,EAAE,MAAMvC,CAAS,GAChC0C,IAAKR,GAAUM,EAAE,MAAMxC,CAAS;AACtC,WAAIyC,MAAOC,IAAWD,IAAKC,IACpBH,EAAE,eAAe,cAAcC,EAAE,cAAc;AAAA,EACxD,CAAC,GACKG,IAAM,CAAA;AACZ,SAAAL,EAAO,QAAQ,CAACP,GAAGzE,MAAM;AACvB,IAAAqF,EAAIZ,EAAE,EAAE,IAAIE,GAAc3E,IAAI2E,GAAc,MAAM;AAAA,EACpD,CAAC,GACMU;AACT,GCvBaC,KAAsB,CAACC,MAASA,KAAQnE,EAAO,cAItDoE,KAAa,yBAcNC,KAAwB,CAACvF,IAAMkB,EAAO,aAAa;AAC5D,MAAKlB;AACL,WAAO,CAAC0D,MAAQ;AACZ,UAAI8B;AACJ,UAAI;AACA,QAAAA,IAAS,IAAI,IAAI9B,CAAG;AAAA,MACxB,QAAQ;AACJ,eAAO,EAAE,KAAAA,EAAA;AAAA,MACb;AAEA,aAAI,CAAC4B,GAAW,KAAKE,EAAO,QAAQ,KAAKA,EAAO,aAAa,IAAI,KAAK,IAC3D,EAAE,KAAA9B,EAAA,KAEb8B,EAAO,aAAa,IAAI,OAAOxF,CAAG,GAC3B,EAAE,KAAKwF,EAAO,WAAS;AAAA,IAClC;AACJ,GCzCMC,KAAY;AAAA,EAChB,UAAU;AAAA,EACV,QAAQ;AAAA,EACR,MAAM;AAAA,EACN,QAAQ;AAAA,EACR,YAAY;AAAA,EACZ,cAAc;AAAA,EACd,WAAW;AAAA,EACX,SAAS;AAAA,EACT,UAAU;AAAA,EACV,YAAY;AAAA,EACZ,UAAU;AACZ,GAEMC,KAAc;AAAA,EAClB,WAAW;AAAA,EACX,WAAW;AACb,GAEMC,KAAoB;AAAA,EACxB,YAAY;AAAA,EACZ,WAAW;AACb,GAEMC,KAAyB;AAAA,EAC7B,GAAGD;AAAA,EACH,WAAW;AACb,GAEME,KAAW;AAAA,EACf,SAAS;AAAA,EACT,YAAY;AAAA,EACZ,KAAK;AAAA,EACL,aAAa;AACf,GAEMC,KAAc,CAACC,OAAW;AAAA,EAC9B,SAAS;AAAA,EACT,OAAO;AAAA,EACP,QAAQ;AAAA,EACR,YAAYA;AAAA,EACZ,QAAQ;AAAA,EACR,cAAc;AAAA,EACd,MAAM;AACR,IAEMC,KAAoB;AAAA,EACxB,WAAW;AAAA,EACX,QAAQ;AAAA,EACR,OAAO;AAAA,EACP,UAAU;AACZ,GAEMC,KAAkB;AAAA,EACtB,WAAW;AAAA,EACX,WAAW;AAAA,EACX,YAAY;AAAA,EACZ,OAAO;AACT,GAEMC,KAA0B;AAAA,EAC9B,YAAY;AAAA,EACZ,WAAW;AACb,GAEMC,KAA+B;AAAA,EACnC,GAAGD;AAAA,EACH,WAAW;AACb,GAEME,KAAkB;AAAA,EACtB,WAAW;AAAA,EACX,aAAa;AACf,GAEMC,KAAa,CAACC,MAClBA,EAAO,OAAO,CAACC,GAAKC,MAAMD,IAAMC,EAAE,KAAK,QAAQ,CAAC,GAE5CC,KAAe,MACnBC,gBAAAA,EAAAA,KAAC,OAAA,EAAI,OAAOb,IACV,UAAA;AAAA,EAAArE,gBAAAA,EAAAA,IAAC,OAAA,EAAI,OAAM,MAAK,QAAO,MAAK,SAAQ,aAAY,eAAY,QAC1D,UAAAA,gBAAAA,EAAAA;AAAAA,IAAC;AAAA,IAAA;AAAA,MACC,QAAO;AAAA,MACP,MAAK;AAAA,MACL,QAAO;AAAA,MACP,aAAY;AAAA,IAAA;AAAA,EAAA,GAEhB;AAAA,EACAA,gBAAAA,EAAAA,IAAC,UAAK,UAAA,mBAAA,CAAgB;AAAA,GACxB,GAGImF,KAAqB,CAAC,EAAE,eAAAC,GAAe,kBAAAC,GAAkB,UAAAC,QAAe;AAC5E,QAAM,CAACC,GAAgBC,CAAiB,IAAIC,EAAS,EAAK,GACpDC,IAAeb,GAAWO,CAAa,GACvCO,IAAkBd,GAAWQ,CAAgB;AACnD,SAAIK,MAAiB,KAAKC,MAAoB,KAAK,CAACL,IAAiB,OAEnEJ,gBAAAA,EAAAA,KAAC,OAAA,EAAI,OAAOjB,IACV,UAAA;AAAA,IAAAiB,gBAAAA,EAAAA,KAAC,OAAA,EAAI,OAAOhB,IACT,UAAA;AAAA,MAAAkB,EAAc,IAAI,CAACJ,GAAG1G,6BACpB,OAAA,EACC,UAAA;AAAA,QAAA0B,gBAAAA,EAAAA,IAAC,SAAI,OAAO1B,MAAM,IAAI8F,KAAyBD,IAC5C,YAAE,MAAA,CACL;AAAA,QACCa,EAAE,KAAK,IAAI,CAACjC,MACXmC,gBAAAA,OAAC,OAAA,EAAe,OAAOb,IACrB,UAAA;AAAA,UAAArE,gBAAAA,EAAAA,IAAC,QAAA,EAAK,OAAOsE,GAAYvB,EAAE,KAAK,GAAG;AAAA,UACnC/C,gBAAAA,EAAAA,IAAC,QAAA,EAAK,OAAO,EAAE,WAAW,YACvB,UAAA+C,EAAE,eAAeA,EAAE,eAAA,CACtB;AAAA,QAAA,EAAA,GAJQA,EAAE,EAKZ,CACD;AAAA,MAAA,KAXOiC,EAAE,IAYZ,CACD;AAAA,MACAM,2BAAaL,IAAA,CAAA,CAAa;AAAA,IAAA,GAC7B;AAAA,IACCU,IAAkB,KACjBT,gBAAAA,EAAAA,KAAAU,EAAAA,UAAA,EACE,UAAA;AAAA,MAAAV,gBAAAA,EAAAA;AAAAA,QAAC;AAAA,QAAA;AAAA,UACC,OAAOV;AAAA,UACP,SAAS,MAAMgB,EAAkB,CAACK,MAAM,CAACA,CAAC;AAAA,UAEzC,UAAA;AAAA,YAAAN,IAAiB,WAAW;AAAA,YAAI;AAAA,YAAEI;AAAA,YAAgB;AAAA,UAAA;AAAA,QAAA;AAAA,MAAA;AAAA,MAEpDJ,KACCvF,gBAAAA,EAAAA,IAAC,OAAA,EAAI,OAAOyE,IACT,UAAAY,EAAiB,IAAI,CAACL,GAAG1G,MACxB4G,gBAAAA,EAAAA,KAAC,OAAA,EACC,UAAA;AAAA,QAAAlF,gBAAAA,EAAAA;AAAAA,UAAC;AAAA,UAAA;AAAA,YACC,OACE1B,MAAM,IACFqG,KACAD;AAAA,YAGL,UAAAM,EAAE;AAAA,UAAA;AAAA,QAAA;AAAA,QAEJA,EAAE,KAAK,IAAI,CAACjC,MACX/C,gBAAAA,EAAAA,IAAC,OAAA,EAAe,OAAO4E,IACpB,YAAE,eAAe7B,EAAE,eAAA,GADZA,EAAE,EAEZ,CACD;AAAA,MAAA,KAdOiC,EAAE,IAeZ,CACD,EAAA,CACH;AAAA,IAAA,EAAA,CAEJ;AAAA,EAAA,GAEJ;AAEJ,GC5IMc,KAAe;AAAA,EACnB;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,GAEaC,KAAsB;AAAA,EACjC,EAAE,KAAK,iBAAiB,OAAO,kBAAkB,OAAO,UAAA;AAAA,EACxD,EAAE,KAAK,UAAU,OAAO,UAAU,OAAO,UAAA;AAAA,EACzC,EAAE,KAAK,sBAAsB,OAAO,uBAAuB,OAAO,UAAA;AAAA,EAClE,EAAE,KAAK,cAAc,OAAO,cAAc,OAAO,UAAA;AAAA,EACjD;AAAA,IACE,KAAK;AAAA,IACL,OAAO;AAAA,IACP,OAAO;AAAA,EAAA;AAAA,EAET,EAAE,KAAK,WAAW,OAAO,WAAW,OAAO,UAAA;AAAA,EAC3C,EAAE,KAAK,aAAa,OAAO,aAAa,OAAO,UAAA;AACjD,GAEMC,KAAuB,OAAO;AAAA,EAClCD,GAAoB,IAAI,CAACE,MAAM,CAACA,EAAE,KAAKA,EAAE,KAAK,CAAC;AACjD,GACaC,KAAgB,WAEvBC,KAAe,CAACN,MACpB,OAAOA,KAAK,EAAE,EACX,cACA,QAAQ,WAAW,EAAE,GAEpBO,KAAa,CAACC,MAAW;AAC7B,QAAMC,IAAMD,KAAA,gBAAAA,EAAQ;AACpB,MAAIC,KAAO,QAAQA,MAAQ,GAAI,QAAO;AACtC,QAAMC,IAAIJ,GAAaG,CAAG;AAC1B,SAAON,GAAqBO,CAAC,IAAIA,IAAI;AACvC,GAEMC,KAAW,CAACH,MAAW;AAC3B,QAAME,IAAIH,GAAWC,CAAM;AAC3B,SAAOE,KAAK,OAAOL,KAAgBF,GAAqBO,CAAC;AAC3D,GAMME,KAAmB,gBACnBC,KAAwB,CAACC,MAC7BC,GAAYH,IAAkBE,CAAY,GACtCE,KAAyB,CAACjG,MAC9BkG,GAAaL,IAAkB7F,CAAO,GAIlCmG,KACJ,mOAMIC,IAAe,2BACfC,IAAa,kBACbC,KAAa,kBACbC,KAAc,wBACdC,IAAa,wBACbC,KAAqB,CAAC9H,MAAO,kBAAkBA,CAAE,IACjD+H,KAAmB,CAAC/H,MAAO,uBAAuBA,CAAE,IACpDgI,KAAmB,CAAChI,MAAO,uBAAuBA,CAAE,IAEpDiI,yBAAY,IAAA,GAEZC,KAAa,CAACC,GAAWnI,MAAO;AACpC,QAAMf,IAAM,GAAGkJ,CAAS,IAAInI,CAAE;AAC9B,MAAIiI,GAAM,IAAIhJ,CAAG,EAAG,QAAOgJ,GAAM,IAAIhJ,CAAG;AACxC,QAAM0D,IAAM,GAAGxC,EAAO,OAAO,cAAclB,CAAG,IACxCmJ,IAAIlI,GAAOyC,GAAK;AAAA,IACpB,SAAS,EAAE,QAAQ,uBAAA;AAAA,EAAuB,CAC3C,EAAE;AAAA,IACD,CAAChC,MAAMA,EAAE;AAAA,IACT,MAAM;AAAA,EAAA;AAER,SAAAsH,GAAM,IAAIhJ,GAAKmJ,CAAC,GACTA;AACT,GAEMC,KAAa,CAAC3F,MAClB,OAAOA,CAAC,EACL,QAAQ,MAAM,OAAO,EACrB,QAAQ,MAAM,MAAM,EACpB,QAAQ,MAAM,MAAM,EACpB,QAAQ,MAAM,QAAQ,GAErB4F,KAAY,CAACxB,MAAW;;AAC5B,QAAMyB,MAAQ1G,IAAAiF,KAAA,gBAAAA,EAAQ,SAAR,gBAAAjF,EAAc,WAAQC,IAAAgF,KAAA,gBAAAA,EAAQ,SAAR,gBAAAhF,EAAc,aAAY,IACxD0G,IAAOjC,GAAa,IAAI,CAACkC,MAAM,CAACA,GAAG3B,KAAA,gBAAAA,EAAS2B,EAAE,CAAC,EAClD,OAAO,CAAC,CAAA,EAAGnC,CAAC,MAAMA,KAAK,QAAQA,MAAM,EAAE,EACvC;AAAA,IACC,CAAC,CAACU,GAAGV,CAAC,MACJ,gBAAgB+B,GAAWrB,CAAC,CAAC,cAAcqB,GAAW/B,CAAC,CAAC;AAAA,EAAA,EAE3D,KAAK,EAAE;AACV,SAAO,+EAA+E+B;AAAA,IACpFE;AAAA,EAAA,CACD,SAASC,CAAI;AAChB,GAEME,KAAsB,CAACC,GAAO7B,MAEhC,oEAAoEuB;AAAA,EAClEM,EAAM;AAAA,CACP,mDAC4CN,GAAWM,EAAM,QAAQ,EAAE,CAAC,WAC7DL,GAAUxB,CAAM,GAG1B8B,KAAoB;AAAA,EACxB,YAAY;AAAA,EACZ,SAAS;AAAA,EACT,YAAY;AAAA,EACZ,MAAM;AAAA,EACN,SAAS;AAAA,EACT,sBAAsB;AACxB,GACMC,KAAkB,CAACjF,MAASgF,GAAkBhF,CAAI,KAAKA,GAEvDkF,KAAU,CAACC,MAAmB;AAClC,MAAI,CAACA,EAAgB,QAAO;AAC5B,QAAMC,IAASD,EAAe,KAAA,EAAO,MAAM,KAAK;AAChD,SAAOC,EAAOA,EAAO,SAAS,CAAC;AACjC,GAGMC,KAAkB,MACtBtD,gBAAAA,EAAAA,KAAC,OAAA,EAAI,OAAO,EAAE,SAAS,QAAQ,YAAY,UAAU,KAAK,EAAA,GACxD,UAAA;AAAA,EAAAlF,gBAAAA,EAAAA,IAAC,OAAA,EAAI,OAAM,MAAK,QAAO,MAAK,SAAQ,aAAY,eAAY,QAC1D,UAAAA,gBAAAA,EAAAA;AAAAA,IAAC;AAAA,IAAA;AAAA,MACC,QAAO;AAAA,MACP,MAAK;AAAA,MACL,QAAO;AAAA,MACP,aAAY;AAAA,IAAA;AAAA,EAAA,GAEhB;AAAA,EACAA,gBAAAA,EAAAA,IAAC,UAAK,UAAA,mBAAA,CAAgB;AAAA,GACxB,GAIIyI,KAAgB,CAACC,MAAa;;AAClC,MAAIC,IAAS,OACXC,IAAS,OACTC,IAAS,QACTC,IAAS;AACX,QAAMC,IAAQ,CAACC,MAAW;AACxB,QAAI,OAAOA,EAAO,CAAC,KAAM,UAAU;AACjC,YAAM,CAACC,GAAKC,CAAG,IAAIF;AACnB,MAAIC,IAAMN,MAAQA,IAASM,IACvBA,IAAMJ,MAAQA,IAASI,IACvBC,IAAMN,MAAQA,IAASM,IACvBA,IAAMJ,MAAQA,IAASI;AAAA,IAC7B;AACE,eAAS5K,IAAI,GAAGA,IAAI0K,EAAO,QAAQ1K,IAAK,CAAAyK,EAAMC,EAAO1K,CAAC,CAAC;AAAA,EAE3D;AACA,WAASA,IAAI,GAAGA,IAAIoK,EAAS,QAAQpK,KAAK;AACxC,UAAM0G,KAAI5D,IAAAsH,EAASpK,CAAC,MAAV,gBAAA8C,EAAa;AACvB,IAAI4D,KAAA,QAAAA,EAAG,eAAa+D,EAAM/D,EAAE,WAAW;AAAA,EACzC;AACA,SAAI2D,MAAW,QAAiB,OACzB;AAAA,IACL,CAACA,GAAQC,CAAM;AAAA,IACf,CAACC,GAAQC,CAAM;AAAA,EAAA;AAEnB,GAEMK,KAAkB,CAACC,MAClBA,IACDA,EAAQ,SAAS,sBAA4BA,EAAQ,YAAY,CAAA,IAC9D,CAACA,CAAO,IAFM,CAAA,GAKjBC,KAAY,MAAM;;AACtB,SAAI,SAAOjI,IAAAkI,MAAA,gBAAAlI,EAAY,cAAc,aAAmBkI,EAAW,UAAA,IAE5D,OAAO,wBAA0B;AAC1C,GAEMC,KAAmB,CAAC;AAAA,EACxB,SAAAC;AAAA,EACA,cAAAC;AAAA,EACA,YAAAvK;AAAA,EACA,YAAAyD;AAAA,EACA,WAAA3B;AAAA,EACA,kBAAA0I;AAAA;AAAA;AAAA;AAAA,EAIA,eAAAC,IAAgB;AAAA;AAAA;AAAA,EAGhB,cAAAC;AACF,MAAM;;AACJ,QAAMC,IAAeC,EAAO,IAAI,GAC1BC,IAAaD,EAAO,IAAI,GACxBE,IAASF,EAAO,IAAI,GACpBG,IAAWH,EAAO,IAAI,GACtBI,IAAeJ,EAAO,oBAAI,KAAK,GAC/BK,IAAwBL,EAAO,oBAAI,KAAK,GACxCM,IAAyBN,EAAO,oBAAI,KAAK,GACzCO,IAAmBP,EAAO,EAAK,GAC/BQ,IAAkBR,EAAO,EAAK,GAC9BS,IAAsBT,EAAO,oBAAI,KAAK,GAEtC,CAACU,GAAUC,CAAW,IAAIhF,EAAS,IAAI,GACvC,CAACiF,GAAYC,CAAa,IAAIlF,EAAS,EAAK,GAC5C,CAACmF,GAAiBC,CAAkB,IAAIpF,EAAS;AAAA,IACrD,QAAQ;AAAA;AAAA,IACR,MAAM,CAAA;AAAA,EAAC,CACR,GACK,CAACqF,GAAcC,CAAe,IAAItF,EAAS,EAAI,GAC/CuF,KAAa,CAAC,CAACtB,MAAqB,CAACF,KAAWA,EAAQ,WAAW,IAGnE,CAACyB,GAAaC,CAAc,IAAIzF;AAAA,IAAS,MAC7CiB,GAAsB,EAAI;AAAA,EAAA,GAEtB,CAACyE,GAAiBC,EAAkB,IAAI3F,EAAS,oBAAI,KAAK,GAC1D,CAAC4F,IAAaC,EAAc,IAAI7F,EAAS,EAAK,GAC9C8F,KAAoBzB,EAAO,EAAK,GAEhC0B,KAAmB,MAAM;AAC7B,IAAAN,EAAe,CAACrF,MAAM;AACpB,YAAMlE,IAAO,CAACkE;AACd,aAAAgB,GAAuBlF,CAAI,GACpBA;AAAA,IACT,CAAC;AAAA,EACH,GAEM8J,KAAe,MAAM;AACzB,IAAAP,EAAe,EAAI,GACnBrE,GAAuB,EAAI;AAAA,EAC7B,GAEM6E,KAAeC,GAAQ,MAAM;AACjC,QAAI,EAACnC,KAAA,QAAAA,EAAS,QAAQ,QAAO,CAAA;AAC7B,UAAMoC,wBAAW,IAAA;AACjB,WAAApC,EAAQ,QAAQ,CAACtJ,MAAM;AACrB,YAAMqG,IAAIH,GAAWlG,CAAC;AACtB,MAAIqG,KAAK,QAAMqF,EAAK,IAAIrF,CAAC;AAAA,IAC3B,CAAC,GACMR,GAAoB,OAAO,CAACE,MAAM2F,EAAK,IAAI3F,EAAE,GAAG,CAAC;AAAA,EAC1D,GAAG,CAACuD,CAAO,CAAC,GAENqC,IAAmBF,GAAQ,MAC3Bf,EAAgB,WAAW,UAAgB,CAAA,IACxCxH;AAAA,IACLwH,EAAgB,KAAK,OAAO,CAAC,MAAM,EAAE,SAAS,SAAS,CAAC;AAAA,IACxD5J,KAAa,CAAA;AAAA,EAAC,GAEf,CAAC4J,GAAiB5J,CAAS,CAAC,GAEzB8K,KAAmBH,GAAQ,MAAM;AACrC,QAAIf,EAAgB,WAAW;AAC7B,aAAO,EAAE,eAAe,IAAI,kBAAkB,CAAA,EAAC;AAEjD,UAAMmB,IAAW,CAAChJ,OAAO;AAAA,MACvB,GAAGA;AAAA,MACH,OAAO8I,EAAiB9I,EAAE,EAAE;AAAA,MAC5B,aAAasF,GAAQtF,EAAE,cAAc;AAAA,IAAA,IAEjCiJ,IAAc,CAAC3I,MAAS;AAC5B,YAAM4I,IAAS,CAAA;AACf,aAAA5I,EAAK,QAAQ,CAACN,MAAM;AAClB,SAACkJ,EAAOlJ,EAAE,IAAI,IAAIkJ,EAAOlJ,EAAE,IAAI,KAAK,CAAA,GAAI,KAAKgJ,EAAShJ,CAAC,CAAC;AAAA,MAC1D,CAAC,GACMlC,GAAoB,OAAO,CAACX,MAAM+L,EAAO/L,CAAC,CAAC,EAAE,IAAI,CAACA,OAAO;AAAA,QAC9D,MAAMA;AAAA,QACN,OAAOkI,GAAgBlI,CAAC;AAAA,QACxB,MAAM+L,EAAO/L,CAAC;AAAA,MAAA,EACd;AAAA,IACJ,GACMkF,IAAgB4G;AAAA,MACpBpB,EAAgB,KAAK;AAAA,QACnB,CAAC7H,MAAMA,EAAE,SAAS,SAAS,KAAKoI,EAAgB,IAAIpI,EAAE,EAAE;AAAA,MAAA;AAAA,IAC1D,GAEIsC,IAAmB2G;AAAA,MACvBpB,EAAgB,KAAK,OAAO,CAAC7H,MAAMA,EAAE,SAAS,WAAW,CAAC;AAAA,IAAA;AAE5D,WAAO,EAAE,eAAAqC,GAAe,kBAAAC,EAAA;AAAA,EAC1B,GAAG,CAACuF,GAAiBiB,GAAkBV,CAAe,CAAC,GAEjDe,KAAuBJ,GAAiB,cAAc,SAAS,GAE/DK,KAAYvI,GAAoBgG,CAAY,GAC5CwC,KAAW1M,EAAO,UAKlB2M,KAAW,GACf,OAAOF,MAAc,WAAWA,KAAY,KAAK,UAAUA,EAAS,CACtE,IAAIC,MAAY,EAAE;AAKlB,EAAAE,EAAU,MAAM;AAEd,QADI,CAACzC,EAAa,WAAWG,EAAO,WAChC,CAACX,KAAa;AAClB,UAAMkD,IAAM,IAAIjD,EAAW,IAAI;AAAA,MAC7B,WAAWO,EAAa;AAAA,MACxB,OAAOsC;AAAA,MACP,kBAAkBpI,GAAsBqI,EAAQ;AAAA,MAChD,QAAQ,CAAC,GAAG,EAAE;AAAA,MACd,MAAM;AAAA,MACN,SAAS;AAAA,MACT,oBAAoB;AAAA,MACpB,mBAAmB;AAAA,IAAA,CACpB;AACD,IAAAG,EAAI;AAAA,MACF,IAAIjD,EAAW,mBAAmB,EAAE,SAAS,IAAM;AAAA,MACnD;AAAA,IAAA,GAEFiD,EAAI;AAAA,MACF,IAAIjD,EAAW,kBAAkB,EAAE,aAAa,IAAO;AAAA,MACvD;AAAA,IAAA,GAKFiD,EAAI;AAAA,MACF,IAAIjD,EAAW,kBAAkB,EAAE,WAAWS,EAAW,SAAS;AAAA,MAClE;AAAA,IAAA,GAEFC,EAAO,UAAUuC,GAEjBA,EAAI,GAAG,QAAQ,MAAM;AACnB,MAAA9B,EAAY8B,CAAG;AAKf,YAAMC,IAASD,EACZ,aAAA,EACA,cAAc,yBAAyB;AAC1C,MAAIC,KAAQA,EAAO,UAAU,OAAO,yBAAyB;AAAA,IAC/D,CAAC;AAED,UAAMC,IACJ,OAAO,iBAAmB,MACtB,IAAI,eAAe,MAAMF,EAAI,OAAA,CAAQ,IACrC;AACN,WAAIE,KAAgBA,EAAe,QAAQ5C,EAAa,OAAO,GAExD,MAAM;AACX,MAAI4C,OAA+B,WAAA,GAC/BxC,EAAS,YACXA,EAAS,QAAQ,OAAA,GACjBA,EAAS,UAAU,OAErBsC,EAAI,OAAA,GACJvC,EAAO,UAAU,MACjBK,EAAiB,UAAU,IAC3BC,EAAgB,UAAU,IAC1BC,EAAoB,8BAAc,IAAA,GAIlCE,EAAY,IAAI;AAAA,IAClB;AAAA,EACF,GAAG,CAAC4B,EAAQ,CAAC,GAGbC,EAAU,MAAM;AACd,UAAMC,IAAM/B;AACZ,QAAI,CAAC+B,KAAO,EAAC/C,KAAA,QAAAA,EAAS,QAAQ;AAC9B,QAAIkD,IAAY;AAChB,WAAA/B,EAAc,EAAK,GAEnB,QAAQ;AAAA,MACNnB,EAAQ;AAAA,QAAI,CAACtJ,MACXuH,GAAWvH,EAAE,KAAK,WAAWA,EAAE,KAAK,EAAE,EAAE,KAAK,CAACkJ,OAAa;AAAA,UACzD,QAAQlJ;AAAA,UACR,SAAAkJ;AAAA,QAAA,EACA;AAAA,MAAA;AAAA,IACJ,EACA,KAAK,CAAC1H,MAAY;AAClB,UAAIgL,KAAa1C,EAAO,YAAYuC,EAAK;AACzC,YAAM7D,IAAW,CAAA,GACXiE,wBAAgB,IAAA;AACtB,UAAIC,IAAW;AACf,MAAAlL,EAAQ,QAAQ,CAAC/B,GAAKrB,MAAM;AAC1B,YAAIqB,EAAI,WAAW,eAAe,CAACA,EAAI,MAAM,SAAS;AACpD,UAAAiN,KAAY;AACZ;AAAA,QACF;AACA,cAAM,EAAE,QAAAvG,GAAQ,SAAA+C,EAAA,IAAYzJ,EAAI,OAC1B4E,KAAQiC,GAASH,CAAM,GACvBwG,IAAY,SAASvO,CAAC;AAC5B,QAAAqO,EAAU,IAAIE,GAAWxG,CAAM,GAC/B8C,GAAgBC,CAAO,EAAE,QAAQ,CAACpB,MAAM;AACtC,UAAAU,EAAS,KAAK;AAAA,YACZ,GAAGV;AAAA,YACH,YAAY;AAAA,cACV,GAAIA,EAAE,cAAc,CAAA;AAAA,cACpB,YAAY6E;AAAA,cACZ,QAAQtI;AAAA,YAAA;AAAA,UACV,CACD;AAAA,QACH,CAAC;AAAA,MACH,CAAC,GACD2F,EAAa,UAAUyC;AAEvB,YAAMG,IAAO,EAAE,MAAM,qBAAqB,UAAApE,EAAA;AAC1C,UAAI6D,EAAI,UAAUvF,CAAY;AAC5B,QAAAuF,EAAI,UAAUvF,CAAY,EAAE,QAAQ8F,CAAI;AAAA,WACnC;AAIL,cAAMC,IAAWR,EAAI,SAASnF,CAAU,IAAIA,IAAa;AACzD,QAAAmF,EAAI,UAAUvF,GAAc,EAAE,MAAM,WAAW,MAAA8F,GAAM,GACrDP,EAAI;AAAA,UACF;AAAA,YACE,IAAItF;AAAA,YACJ,MAAM;AAAA,YACN,QAAQD;AAAA,YACR,OAAO;AAAA,cACL,cAAc,CAAC,YAAY,CAAC,OAAO,QAAQ,GAAGd,EAAa;AAAA,cAC3D,gBAAgB;AAAA,YAAA;AAAA,UAClB;AAAA,UAEF6G;AAAA,QAAA,GAEFR,EAAI;AAAA,UACF;AAAA,YACE,IAAIrF;AAAA,YACJ,MAAM;AAAA,YACN,QAAQF;AAAA,YACR,OAAO;AAAA,cACL,cAAc,CAAC,YAAY,CAAC,OAAO,QAAQ,GAAGd,EAAa;AAAA,cAC3D,cAAc;AAAA,YAAA;AAAA,UAChB;AAAA,UAEF6G;AAAA,QAAA,GAEFR,EAAI,GAAG,SAAStF,GAAY+F,EAAY,GACxCT,EAAI,GAAG,cAActF,GAAYgG,EAAY,GAC7CV,EAAI,GAAG,cAActF,GAAYiG,EAAY,GAC7C7C,EAAiB,UAAU;AAAA,MAC7B;AAEA,UAAI3B,EAAS,SAAS,GAAG;AACvB,cAAMyE,IAAS1E,GAAcC,CAAQ;AACrC,QAAIyE,OAAY,UAAUA,GAAQ,EAAE,SAAS,IAAI,SAAS,IAAO;AAAA,MACnE;AACA,MAAI,OAAO1D,KAAiB,cAAYA,EAAamD,CAAQ,GAC7DjC,EAAc,EAAI;AAAA,IACpB,CAAC,GAEM,MAAM;AACX,MAAA+B,IAAY;AAAA,IACd;AAAA,EAEF,GAAG,CAAClC,GAAUhB,CAAO,CAAC;AAGtB,QAAMwD,KAAe,CAAC7M,MAAM;;AAC1B,UAAMoM,IAAMvC,EAAO;AACnB,QAAI,CAACuC,EAAK;AACV,UAAMa,KAAUhM,IAAAjB,EAAE,aAAF,gBAAAiB,EAAa,IACvB5C,KAAM6C,IAAA+L,KAAA,gBAAAA,EAAS,eAAT,gBAAA/L,EAAqB,YAC3BgF,IAAS7H,IAAM0L,EAAa,QAAQ,IAAI1L,CAAG,IAAI;AACrD,IAAK6H,MACD4D,EAAS,WAASA,EAAS,QAAQ,OAAA,GACvCA,EAAS,UAAU,IAAIX,EAAW,MAAM,EAAE,aAAa,IAAM,UAAU,QAAA,CAAS,EAC7E,UAAUnJ,EAAE,MAAM,EAClB,QAAQ0H,GAAUxB,CAAM,CAAC,EACzB,MAAMkG,CAAG;AAAA,EACd,GAEMU,KAAe,MAAM;AACzB,UAAMV,IAAMvC,EAAO;AACnB,IAAIuC,MAAKA,EAAI,UAAA,EAAY,MAAM,SAAS;AAAA,EAC1C,GACMW,KAAe,MAAM;AACzB,UAAMX,IAAMvC,EAAO;AACnB,IAAIuC,MAAKA,EAAI,UAAA,EAAY,MAAM,SAAS;AAAA,EAC1C;AAGA,EAAAD,EAAU,MAAM;AACd,UAAMC,IAAMvC,EAAO;AACnB,QAAI,CAACuC,KAAO,CAAClC,EAAiB,QAAS;AACvC,UAAMxE,IAAIiF,IAAe,YAAY;AACrC,IAAIyB,EAAI,SAAStF,CAAU,OAAO,kBAAkBA,GAAY,cAAcpB,CAAC,GAC3E0G,EAAI,SAASrF,EAAU,OAAO,kBAAkBA,IAAY,cAAcrB,CAAC;AAAA,EACjF,GAAG,CAACiF,GAAcJ,CAAU,CAAC,GAG7B4B,EAAU,MAAM;AACd,UAAMC,IAAM/B;AAUZ,QATI,CAAC+B,OACc,MAAM;AACvB,MAAIA,EAAI,SAASnF,CAAU,KAAGmF,EAAI,YAAYnF,CAAU,GACpDmF,EAAI,UAAUpF,EAAW,KAAGoF,EAAI,aAAapF,EAAW,GAC5DmD,EAAgB,UAAU;AAAA,IAC5B,GACA,GACI,CAACZ,KAAoB,EAAC/G,KAAA,QAAAA,EAAY,QAElCgH,MAAkB,GAAO;AAC7B,UAAMzH,KAAOxC,EAAO,UAAUqH,IAC3B,QAAQ,kBAAkB,mBAAmB2C,CAAgB,CAAC,EAC9D,QAAQ,cAAc,mBAAmB/G,EAAW,EAAE,CAAC,GAIpD0K,IACJ3N,EAAO,aACP,sCACA,mBAAmBgK,CAAgB,IACnC,gBACA,mBAAmB/G,EAAW,EAAE;AAClC,IAAA4J,EAAI,UAAUpF,IAAa;AAAA,MACzB,MAAM;AAAA,MACN,OAAO,CAACjF,CAAG;AAAA,MACX,UAAU;AAAA,MACV,aACE,cACAmL,IACA;AAAA,IAAA,CACH,GACDd,EAAI,SAAS;AAAA,MACX,IAAInF;AAAA,MACJ,MAAM;AAAA,MACN,QAAQD;AAAA,MACR,OAAO,EAAE,kBAAkB,IAAA;AAAA,MAC3B,QAAQ,EAAE,YAAY8D,IAAc,YAAY,OAAA;AAAA,IAAO,CACxD,GACDX,EAAgB,UAAU;AAAA,EAQ5B,GAAG,CAACE,GAAUd,GAAkB/G,KAAA,gBAAAA,EAAY,IAAIgH,CAAa,CAAC,GAG9D2C,EAAU,MAAM;AACd,UAAMC,IAAMvC,EAAO;AACnB,QAAI,CAACuC,KAAO,CAACjC,EAAgB,QAAS;AACtC,UAAMzE,IAAIoF,IAAc,YAAY;AACpC,IAAIsB,EAAI,SAASnF,CAAU,OAAO,kBAAkBA,GAAY,cAAcvB,CAAC;AAAA,EACjF,GAAG,CAACoF,CAAW,CAAC;AAOhB,QAAMqC,KAAuB,CAAC/N,MAC5B4L,EAAgB,IAAI5L,CAAE,IAAI,YAAY;AAGxC,EAAA+M,EAAU,MAAM;AACd,UAAMC,IAAM/B;AAYZ,QAXI,CAAC+B,MAELhC,EAAoB,QAAQ,QAAQ,CAAChL,MAAO;AAC1C,MAAIgN,EAAI,SAASjF,GAAiB/H,CAAE,CAAC,KAAGgN,EAAI,YAAYjF,GAAiB/H,CAAE,CAAC,GACxEgN,EAAI,SAAShF,GAAiBhI,CAAE,CAAC,KAAGgN,EAAI,YAAYhF,GAAiBhI,CAAE,CAAC,GACxEgN,EAAI,UAAUlF,GAAmB9H,CAAE,CAAC,KAAGgN,EAAI,aAAalF,GAAmB9H,CAAE,CAAC;AAAA,IACpF,CAAC,GACDgL,EAAoB,8BAAc,IAAA,GAClCJ,EAAsB,8BAAc,IAAA,GACpCC,EAAuB,8BAAc,IAAA,GAEjCQ,EAAgB,WAAW,SAAS;AACxC,UAAM2C,IAAS1B;AACf,IAAAjB,EAAgB,KAAK,QAAQ,CAAC7H,MAAM;AAClC,MAAIA,EAAE,SAAS,WAAW,MAC1BoH,EAAsB,QAAQ,IAAIpH,EAAE,IAAIA,CAAC,GACzC,QAAQ;AAAA,QACNA,EAAE,SAAS;AAAA,UAAI,CAACyK,MACd/F,GAAW+F,EAAI,KAAK,WAAWA,EAAI,KAAK,EAAE,EAAE,KAAK,CAACpE,OAAa;AAAA,YAC7D,QAAQoE;AAAA,YACR,SAAApE;AAAA,UAAA,EACA;AAAA,QAAA;AAAA,MACJ,EACA,KAAK,CAAC1H,MAAY;AAGlB,YAAIsI,EAAO,YAAYuC,EAAK;AAC5B,cAAM7D,IAAW,CAAA;AACjB,QAAAhH,EAAQ,QAAQ,CAAC/B,GAAKrB,MAAM;AAC1B,cAAIqB,EAAI,WAAW,eAAe,CAACA,EAAI,MAAM,QAAS;AACtD,gBAAM,EAAE,QAAA0G,GAAQ,SAAA+C,GAAA,IAAYzJ,EAAI,OAC1BkN,IAAY,QAAQ9J,EAAE,EAAE,IAAIzE,CAAC;AACnC,UAAA8L,EAAuB,QAAQ,IAAIyC,GAAW,EAAE,OAAO9J,GAAG,QAAAsD,GAAQ,GAClE8C,GAAgBC,EAAO,EAAE,QAAQ,CAACpB,MAAM;AACtC,YAAAU,EAAS,KAAK;AAAA,cACZ,GAAGV;AAAA,cACH,YAAY;AAAA,gBACV,GAAIA,EAAE,cAAc,CAAA;AAAA,gBACpB,YAAY6E;AAAA,cAAA;AAAA,YACd,CACD;AAAA,UACH,CAAC;AAAA,QACH,CAAC;AACD,cAAMtI,IAAQgJ,EAAOxK,EAAE,EAAE,KAAKmD,IACxB4G,IAAO,EAAE,MAAM,qBAAqB,UAAApE,EAAA,GACpC+E,IAAQpG,GAAmBtE,EAAE,EAAE;AACrC,YAAIiH,EAAO,QAAQ,UAAUyD,CAAK;AAChC,UAAAzD,EAAO,QAAQ,UAAUyD,CAAK,EAAE,QAAQX,CAAI;AAAA,aACvC;AACL,UAAA9C,EAAO,QAAQ,UAAUyD,GAAO,EAAE,MAAM,WAAW,MAAAX,GAAM;AACzD,gBAAMY,IAASpG,GAAiBvE,EAAE,EAAE,GAC9B4K,IAASpG,GAAiBxE,EAAE,EAAE,GAC9BgK,IAAW/C,EAAO,QAAQ,SAAS5C,CAAU,IAAIA,IAAa;AACpE,UAAA4C,EAAO,QAAQ;AAAA,YACb;AAAA,cACE,IAAI0D;AAAA,cACJ,MAAM;AAAA,cACN,QAAQD;AAAA,cACR,OAAO,EAAE,cAAclJ,GAAO,gBAAgB,KAAA;AAAA,cAC9C,QAAQ,EAAE,YAAY+I,GAAqBvK,EAAE,EAAE,EAAA;AAAA,YAAE;AAAA,YAEnDgK;AAAA,UAAA,GAEF/C,EAAO,QAAQ;AAAA,YACb;AAAA,cACE,IAAI2D;AAAA,cACJ,MAAM;AAAA,cACN,QAAQF;AAAA,cACR,OAAO,EAAE,cAAclJ,GAAO,cAAc,EAAA;AAAA,cAC5C,QAAQ,EAAE,YAAY+I,GAAqBvK,EAAE,EAAE,EAAA;AAAA,YAAE;AAAA,YAEnDgK;AAAA,UAAA,GAEF/C,EAAO,QAAQ,GAAG,SAAS0D,GAAQE,EAAiB,GACpD5D,EAAO,QAAQ,GAAG,cAAc0D,GAAQT,EAAY,GACpDjD,EAAO,QAAQ,GAAG,cAAc0D,GAAQR,EAAY,GACpD3C,EAAoB,QAAQ,IAAIxH,EAAE,EAAE;AAAA,QACtC;AAAA,MACF,CAAC;AAAA,IACH,CAAC;AAAA,EAEH,GAAG,CAACyH,GAAUI,GAAiBiB,CAAgB,CAAC;AAEhD,QAAM+B,KAAoB,CAACzN,MAAM;;AAC/B,UAAMoM,IAAMvC,EAAO;AACnB,QAAI,CAACuC,EAAK;AACV,UAAMa,KAAUhM,IAAAjB,EAAE,aAAF,gBAAAiB,EAAa,IACvB5C,KAAM6C,IAAA+L,KAAA,gBAAAA,EAAS,eAAT,gBAAA/L,EAAqB,YAC3ByL,IAAOtO,IAAM4L,EAAuB,QAAQ,IAAI5L,CAAG,IAAI;AAC7D,IAAKsO,MACD7C,EAAS,WAASA,EAAS,QAAQ,OAAA,GACvCA,EAAS,UAAU,IAAIX,EAAW,MAAM,EAAE,aAAa,IAAM,UAAU,QAAA,CAAS,EAC7E,UAAUnJ,EAAE,MAAM,EAClB,QAAQ8H,GAAoB6E,EAAK,OAAOA,EAAK,MAAM,CAAC,EACpD,MAAMP,CAAG;AAAA,EACd;AAGA,EAAAD,EAAU,MAAM;AACd,UAAMC,IAAMvC,EAAO;AACnB,IAAKuC,KACLhC,EAAoB,QAAQ,QAAQ,CAAChL,MAAO;AAC1C,YAAMsG,IAAIsF,EAAgB,IAAI5L,CAAE,IAAI,YAAY;AAChD,MAAIgN,EAAI,SAASjF,GAAiB/H,CAAE,CAAC,KACnCgN,EAAI,kBAAkBjF,GAAiB/H,CAAE,GAAG,cAAcsG,CAAC,GAEzD0G,EAAI,SAAShF,GAAiBhI,CAAE,CAAC,KACnCgN,EAAI,kBAAkBhF,GAAiBhI,CAAE,GAAG,cAAcsG,CAAC;AAAA,IAE/D,CAAC;AAAA,EACH,GAAG,CAACsF,GAAiBP,CAAe,CAAC;AAGrC,QAAMiD,KAAyB,MAAM;;AAEnC,QADItC,GAAkB,WAClB,CAACrM,KAAc,CAACyD,KAAc,CAAC3B,EAAW;AAC9C,UAAMD,KAAYK,IAAAuB,KAAA,gBAAAA,EAAY,SAAZ,gBAAAvB,EAAkB;AAIpC,IAHI,CAACL,KACDA,MAAc,aAAa,CAACF,GAAoB,SAASE,CAAS,KACxDD,GAAmBC,GAAWC,CAAS,EAC3C,WAAW,MACrBuK,GAAkB,UAAU,IAC5BV,EAAmB,EAAE,QAAQ,WAAW,MAAM,CAAA,GAAI,GAClDnI,GAAiB,EAAE,YAAAxD,GAAY,YAAAyD,GAAY,WAAA3B,EAAA,CAAW,EAAE;AAAA,MACtD,CAAC,EAAE,MAAAqC,GAAM,mBAAAT,QAAwB;AAC/B,YAAIA,GAAmB;AACrB,UAAAiI,EAAmB,EAAE,QAAQ,SAAS,MAAM,CAAA,GAAI;AAChD;AAAA,QACF;AACA,YAAIxH,EAAK,WAAW,GAAG;AACrB,UAAAwH,EAAmB,EAAE,QAAQ,SAAS,MAAM,CAAA,GAAI;AAChD;AAAA,QACF;AACA,QAAAA,EAAmB,EAAE,QAAQ,SAAS,MAAAxH,EAAA,CAAM;AAAA,MAC9C;AAAA,IAAA;AAAA,EAEJ,GAEMyK,KAAc,MAAM;AACxB,IAAAxC,GAAe,EAAI,GACnBuC,GAAA;AAAA,EACF,GAGME,KAAoBpC,GAAQ,MAAM;AACtC,QAAIf,EAAgB,WAAW,QAAS,QAAO,CAAA;AAC/C,UAAMqB,IAAS,CAAA;AACf,WAAArB,EAAgB,KACb,OAAO,CAAC7H,MAAMA,EAAE,SAAS,SAAS,CAAC,EACnC,QAAQ,CAACA,MAAM;AACd,OAACkJ,EAAOlJ,EAAE,IAAI,IAAIkJ,EAAOlJ,EAAE,IAAI,KAAK,CAAA,GAAI,KAAKA,CAAC;AAAA,IAChD,CAAC,GACIlC,GAAoB,OAAO,CAACX,MAAM+L,EAAO/L,CAAC,CAAC,EAAE,IAAI,CAACA,OAAO;AAAA,MAC9D,MAAMA;AAAA,MACN,OAAOkI,GAAgBlI,CAAC;AAAA,MACxB,MAAM+L,EAAO/L,CAAC,EAAE,QAAQ;AAAA,QAAK,CAACqD,GAAGC,MAC/BD,EAAE,eAAe,cAAcC,EAAE,cAAc;AAAA,MAAA;AAAA,IACjD,EACA;AAAA,EACJ,GAAG,CAACoH,CAAe,CAAC,GAEdoD,KAAc,CAACzO,MAAO;AAC1B,IAAA6L,GAAmB,CAAC6C,MAAS;AAC3B,YAAMtM,IAAO,IAAI,IAAIsM,CAAI;AACzB,aAAItM,EAAK,IAAIpC,CAAE,IAAGoC,EAAK,OAAOpC,CAAE,IAC3BoC,EAAK,IAAIpC,CAAE,GACToC;AAAA,IACT,CAAC;AAAA,EACH,GAEMuM,KAAkB,CAACC,MAAa;AACpC,IAAA/C,GAAmB,CAAC6C,MAAS;AAC3B,YAAMtM,IAAO,IAAI,IAAIsM,CAAI,GACnBG,IAAQD,EAAS,MAAM,CAACpL,MAAMkL,EAAK,IAAIlL,EAAE,EAAE,CAAC;AAClD,aAAAoL,EAAS,QAAQ,CAACpL,MAAM;AACtB,QAAIqL,IAAOzM,EAAK,OAAOoB,EAAE,EAAE,IACtBpB,EAAK,IAAIoB,EAAE,EAAE;AAAA,MACpB,CAAC,GACMpB;AAAA,IACT,CAAC;AAAA,EACH;AAEA,MAAI,CAAC0H;AACH,WACErJ,gBAAAA,EAAAA;AAAAA,MAAC;AAAA,MAAA;AAAA,QACC,OAAO;AAAA,UACL,SAAS;AAAA,UACT,YAAY;AAAA,UACZ,QAAQ;AAAA,UACR,cAAc;AAAA,UACd,OAAO;AAAA,UACP,UAAU;AAAA,QAAA;AAAA,QAEb,UAAA;AAAA,MAAA;AAAA,IAAA;AASL,MAAIgL,MAAc,CAACC;AACjB,WACE/F,gBAAAA,EAAAA;AAAAA,MAAC;AAAA,MAAA;AAAA,QACC,WAAU;AAAA,QACV,OAAO;AAAA,UACL,SAAS;AAAA,UACT,YAAY;AAAA,UACZ,KAAK;AAAA,UACL,SAAS;AAAA,UACT,YAAY;AAAA,UACZ,QAAQ;AAAA,UACR,cAAc;AAAA,UACd,OAAO;AAAA,UACP,UAAU;AAAA,QAAA;AAAA,QAGZ,UAAA;AAAA,UAAAlF,gBAAAA,EAAAA,IAAC,UAAK,UAAA,gCAAA,CAA6B;AAAA,UACnCA,gBAAAA,EAAAA;AAAAA,YAAC;AAAA,YAAA;AAAA,cACC,MAAK;AAAA,cACL,UAAU;AAAA,cACV,OAAO,EAAE,QAAQ,UAAA;AAAA,cACjB,SAASyL;AAAA,cACT,WAAW,CAACtL,MAAM;AAChB,iBAAIA,EAAE,QAAQ,WAAWA,EAAE,QAAQ,SACjCA,EAAE,eAAA,GACFsL,GAAA;AAAA,cAEJ;AAAA,cACD,UAAA;AAAA,YAAA;AAAA,UAAA;AAAA,QAED;AAAA,MAAA;AAAA,IAAA;AAKN,QAAM4C,OAAYjN,KAAAuB,KAAA,gBAAAA,EAAY,SAAZ,gBAAAvB,GAAkB,mBAAkB;AAEtD,SACE8D,gBAAAA,EAAAA;AAAAA,IAAC;AAAA,IAAA;AAAA,MACC,WAAU;AAAA,MACV,KAAK6E;AAAA,MACL,OAAO,EAAE,UAAU,WAAA;AAAA,MAEnB,UAAA;AAAA,QAAA/J,gBAAAA,EAAAA;AAAAA,UAAC;AAAA,UAAA;AAAA,YACC,KAAK6J;AAAA,YACL,WAAU;AAAA,YACV,OAAO,EAAE,QAAQ,KAAK,OAAO,QAAQ,YAAY,UAAA;AAAA,UAAU;AAAA,QAAA;AAAA,QAG7D7J,gBAAAA,EAAAA;AAAAA,UAACsO;AAAA,UAAA;AAAA,YACC,MAAMjD;AAAA,YACN,QAAQyC;AAAA,YACR,SAAS,MAAMxC,GAAe,EAAK;AAAA,YACnC,WAAA+C;AAAA,YACA,YAAA3D;AAAA,YACA,cAAAI;AAAA,YACA,eAAe,MAAMC,EAAgB,CAAClF,MAAM,CAACA,CAAC;AAAA,YAC9C,aAAa,CAAC,CAAC6D;AAAA,YACf,aAAAuB;AAAA,YACA,eAAAtB;AAAA,YACA,cAAc6B;AAAA,YACd,kBAAkBZ,EAAgB;AAAA,YAClC,mBAAAmD;AAAA,YACA,kBAAAlC;AAAA,YACA,iBAAAV;AAAA,YACA,eAAe6C;AAAA,YACf,mBAAmBE;AAAA,YACnB,SAAS,MAAM;AACb,cAAA3C,GAAkB,UAAU,IAC5BV,EAAmB,EAAE,QAAQ,QAAQ,MAAM,CAAA,GAAI,GAC/CgD,GAAA;AAAA,YACF;AAAA,UAAA;AAAA,QAAA;AAAA,QAGD,CAAC3B,OACCR,GAAa,SAAS,KACpBhC,KAAoBC,MAAkB,MAASsB,MAChD/F,gBAAAA,EAAAA;AAAAA,UAAC;AAAA,UAAA;AAAA,YACC,OAAO;AAAA,cACL,UAAU;AAAA,cACV,QAAQ;AAAA,cACR,MAAM;AAAA,cACN,QAAQ;AAAA,cACR,YAAY;AAAA,cACZ,cAAc;AAAA,cACd,WAAW;AAAA,cACX,SAAS;AAAA,cACT,UAAU;AAAA,cACV,YAAY;AAAA,YAAA;AAAA,YAGb,UAAA;AAAA,cAAAwG,GAAa,IAAI,CAACzF,MACjBf,gBAAAA,EAAAA;AAAAA,gBAAC;AAAA,gBAAA;AAAA,kBAEC,OAAO,EAAE,SAAS,QAAQ,YAAY,UAAU,KAAK,EAAA;AAAA,kBAErD,UAAA;AAAA,oBAAAlF,gBAAAA,EAAAA;AAAAA,sBAAC;AAAA,sBAAA;AAAA,wBACC,OAAO;AAAA,0BACL,SAAS;AAAA,0BACT,OAAO;AAAA,0BACP,QAAQ;AAAA,0BACR,YAAYiG,EAAE;AAAA,0BACd,QAAQ;AAAA,0BACR,cAAc;AAAA,wBAAA;AAAA,sBAChB;AAAA,oBAAA;AAAA,oBAEFjG,gBAAAA,EAAAA,IAAC,QAAA,EAAM,UAAAiG,EAAE,MAAA,CAAM;AAAA,kBAAA;AAAA,gBAAA;AAAA,gBAbVA,EAAE;AAAA,cAAA,CAeV;AAAA,cACAyD,KAAoBC,MAAkB,MAASsB,2BAC7CzC,IAAA,CAAA,CAAgB;AAAA,YAAA;AAAA,UAAA;AAAA,QAAA;AAAA,QAIxB0D,MACClM,gBAAAA,EAAAA;AAAAA,UAACmF;AAAA,UAAA;AAAA,YACC,eAAe2G,GAAiB;AAAA,YAChC,kBAAkBA,GAAiB;AAAA,YACnC,UAAU,CAAC,CAACpC,KAAoBC,MAAkB,MAASsB;AAAA,UAAA;AAAA,QAAA;AAAA,MAC7D;AAAA,IAAA;AAAA,EAAA;AAIR,GAGMqD,KAAe,CAAC;AAAA,EACpB,MAAAC;AAAA,EACA,QAAAC;AAAA,EACA,SAAAC;AAAA,EACA,WAAAJ;AAAA,EACA,YAAA3D;AAAA,EACA,cAAAI;AAAA,EACA,eAAA4D;AAAA,EACA,aAAAC;AAAA,EACA,aAAA1D;AAAA,EACA,eAAAtB;AAAA,EACA,cAAAiF;AAAA,EACA,kBAAAC;AAAA,EACA,mBAAAd;AAAA,EACA,kBAAAlC;AAAA,EACA,iBAAAV;AAAA,EACA,eAAA2D;AAAA,EACA,mBAAAC;AAAA,EACA,SAAAC;AACF,MACOT,IA8BHrJ,gBAAAA,EAAAA;AAAAA,EAAC;AAAA,EAAA;AAAA,IACC,OAAO;AAAA,MACL,UAAU;AAAA;AAAA,MAEV,KAAK;AAAA,MACL,OAAO;AAAA,MACP,QAAQ;AAAA,MACR,YAAY;AAAA,MACZ,cAAc;AAAA,MACd,WAAW;AAAA,MACX,SAAS;AAAA,MACT,UAAU;AAAA,MACV,YAAY;AAAA,MACZ,WAAW;AAAA,MACX,WAAW;AAAA,MACX,UAAU;AAAA,IAAA;AAAA,IAEZ,cAAcuJ;AAAA,IAEd,UAAA;AAAA,MAAAvJ,gBAAAA,EAAAA,KAAC,OAAA,EAAI,OAAO,EAAE,SAAS,QAAQ,YAAY,UAAU,KAAK,EAAA,GACxD,UAAA;AAAA,QAAAlF,gBAAAA,EAAAA;AAAAA,UAAC;AAAA,UAAA;AAAA,YACC,MAAK;AAAA,YACL,SAAS8K;AAAA,YACT,UAAU,CAACJ;AAAA,YACX,UAAUgE;AAAA,UAAA;AAAA,QAAA;AAAA,8BAEX,QAAA,EAAK,OAAO,EAAE,WAAW,SAAA,GAAa,UAAAL,EAAA,CAAU;AAAA,MAAA,GACnD;AAAA,MACCM,KACCzJ,gBAAAA,EAAAA;AAAAA,QAAC;AAAA,QAAA;AAAA,UACC,OAAO;AAAA,YACL,SAAS;AAAA,YACT,YAAY;AAAA,YACZ,KAAK;AAAA,YACL,SAASyE,MAAkB,KAAQ,MAAM;AAAA,UAAA;AAAA,UAE3C,OACEA,MAAkB,KACd,mDACA;AAAA,UAGN,UAAA;AAAA,YAAA3J,gBAAAA,EAAAA;AAAAA,cAAC;AAAA,cAAA;AAAA,gBACC,MAAK;AAAA,gBACL,SAAS2J,MAAkB,KAAQ,KAAQsB;AAAA,gBAC3C,UAAUtB,MAAkB;AAAA,gBAC5B,UAAUiF;AAAA,cAAA;AAAA,YAAA;AAAA,YAEZ5O,gBAAAA,EAAAA,IAAC,UAAK,UAAA,mBAAA,CAAgB;AAAA,UAAA;AAAA,QAAA;AAAA,MAAA;AAAA,MAGzB6O,MAAqB,aACpB7O,gBAAAA,EAAAA,IAAC,OAAA,EAAI,OAAO,EAAE,WAAW,GAAG,OAAO,OAAA,GAAU,UAAA,uBAAA,CAAoB;AAAA,MAElE6O,MAAqB,WACpB3J,gBAAAA,OAAC,OAAA,EAAI,OAAO,EAAE,WAAW,GAAG,OAAO,OAAA,GAAU,UAAA;AAAA,QAAA;AAAA,QACX;AAAA,QAChClF,gBAAAA,EAAAA,IAAC,OAAE,SAASgP,GAAS,OAAO,EAAE,QAAQ,UAAA,GAAa,UAAA,QAAA,CAEnD;AAAA,MAAA,GACF;AAAA,MAEDH,MAAqB,WACpBd,EAAkB,IAAI,CAACkB,MAAU;AAC/B,cAAMb,IAAQa,EAAM,KAAK,MAAM,CAAClM,MAAMoI,EAAgB,IAAIpI,EAAE,EAAE,CAAC,GACzDmM,IAASD,EAAM,KAAK,KAAK,CAAClM,MAAMoI,EAAgB,IAAIpI,EAAE,EAAE,CAAC;AAC/D,sCACG,OAAA,EAAqB,OAAO,EAAE,WAAW,KACxC,UAAA;AAAA,UAAAmC,gBAAAA,EAAAA;AAAAA,YAAC;AAAA,YAAA;AAAA,cACC,OAAO;AAAA,gBACL,SAAS;AAAA,gBACT,YAAY;AAAA,gBACZ,KAAK;AAAA,gBACL,YAAY;AAAA,cAAA;AAAA,cAGd,UAAA;AAAA,gBAAAlF,gBAAAA,EAAAA;AAAAA,kBAAC;AAAA,kBAAA;AAAA,oBACC,MAAK;AAAA,oBACL,SAASoO;AAAA,oBACT,KAAK,CAAChO,MAAO;AACX,sBAAIA,MAAIA,EAAG,gBAAgB,CAACgO,KAASc;AAAA,oBACvC;AAAA,oBACA,UAAU,MAAMH,EAAkBE,EAAM,IAAI;AAAA,kBAAA;AAAA,gBAAA;AAAA,gBAE7CA,EAAM;AAAA,cAAA;AAAA,YAAA;AAAA,UAAA;AAAA,UAETjP,gBAAAA,EAAAA,IAAC,OAAA,EAAI,OAAO,EAAE,aAAa,GAAA,GACxB,UAAAiP,EAAM,KAAK,IAAI,CAAClM,MACfmC,gBAAAA,EAAAA;AAAAA,YAAC;AAAA,YAAA;AAAA,cAEC,OAAO;AAAA,gBACL,SAAS;AAAA,gBACT,YAAY;AAAA,gBACZ,KAAK;AAAA,cAAA;AAAA,cAGP,UAAA;AAAA,gBAAAlF,gBAAAA,EAAAA;AAAAA,kBAAC;AAAA,kBAAA;AAAA,oBACC,MAAK;AAAA,oBACL,SAASmL,EAAgB,IAAIpI,EAAE,EAAE;AAAA,oBACjC,UAAU,MAAM+L,EAAc/L,EAAE,EAAE;AAAA,kBAAA;AAAA,gBAAA;AAAA,gBAEpC/C,gBAAAA,EAAAA;AAAAA,kBAAC;AAAA,kBAAA;AAAA,oBACC,OAAO;AAAA,sBACL,SAAS;AAAA,sBACT,OAAO;AAAA,sBACP,QAAQ;AAAA,sBACR,YAAY6L,EAAiB9I,EAAE,EAAE;AAAA,sBACjC,QAAQ;AAAA,sBACR,cAAc;AAAA,oBAAA;AAAA,kBAChB;AAAA,gBAAA;AAAA,gBAEF/C,gBAAAA,EAAAA,IAAC,QAAA,EAAK,OAAO,EAAE,WAAW,YACvB,UAAAqI,GAAQtF,EAAE,cAAc,EAAA,CAC3B;AAAA,cAAA;AAAA,YAAA;AAAA,YAxBKA,EAAE;AAAA,UAAA,CA0BV,EAAA,CACH;AAAA,QAAA,EAAA,GAjDQkM,EAAM,IAkDhB;AAAA,MAEJ,CAAC;AAAA,IAAA;AAAA,EAAA;AAAA,IAnJHjP,gBAAAA,EAAAA;AAAAA,EAAC;AAAA,EAAA;AAAA,IACC,MAAK;AAAA,IACL,SAASwO;AAAA,IACT,cAAcA;AAAA,IACd,OAAM;AAAA,IACN,OAAO;AAAA,MACL,UAAU;AAAA;AAAA,MAEV,KAAK;AAAA,MACL,OAAO;AAAA,MACP,QAAQ;AAAA,MACR,OAAO;AAAA,MACP,QAAQ;AAAA,MACR,YAAY;AAAA,MACZ,QAAQ;AAAA,MACR,cAAc;AAAA,MACd,QAAQ;AAAA,MACR,UAAU;AAAA,MACV,YAAY;AAAA,MACZ,SAAS;AAAA,MACT,WAAW;AAAA,IAAA;AAAA,IAEd,UAAA;AAAA,EAAA;AAAA,GCn7BDrN,KAAa,CAACjB,MAAA;;AAClB,WAAAkB,IAAAlB,KAAA,gBAAAA,EAAG,SAAH,gBAAAkB,EAAS,eAAc,UAAU,CAAC,GAACC,IAAAnB,KAAA,gBAAAA,EAAG,SAAH,QAAAmB,EAAS;AAAA,GAExC8N,KAAW,CAAC,EAAE,YAAAjQ,GAAY,MAAA4N,QAAW;AACzC,QAAM,CAACsC,GAASC,CAAU,IAAI5J,EAAS,CAAA,CAAE;AAEzC,SAAA6G,EAAU,MAAM;AACd,QAAIgD,IAAQ;AACZ,aAAShR,IAAI,GAAGA,IAAIwO,EAAK,QAAQxO;AAC/B,UAAIwO,EAAKxO,CAAC,EAAE,cAAc,OAAO;AAC/B,QAAAgR,IAAQ;AACR;AAAA,MACF;AAEF,IAAIA,KACF7P,GAAO,GAAGC,EAAO,OAAO,eAAe,EAAE,KAAK,CAACC,MAAQ;AACrD,MAAA0P,EAAWE,GAAM5P,EAAI,MAAM,QAAQ,CAAC;AAAA,IACtC,CAAC;AAAA,EAEL,GAAG,CAAA,CAAE,GAGHK,gBAAAA,MAAC,SACE,UAAA8M,EAAK,IAAI,CAAC7K,GAAG3D,6BACX,QAAA,EACE,UAAA;AAAA,KAAA2D,KAAA,gBAAAA,EAAG,WACFjC,gBAAAA,EAAAA;AAAAA,MAACwP;AAAA,MAAA;AAAA,QACC,WAAWvN,KAAA,gBAAAA,EAAG;AAAA,QACd,YAAYA,EAAE;AAAA,QACd,kBAAkBA,KAAA,gBAAAA,EAAG;AAAA,QACrB,mBAAmBA,KAAA,gBAAAA,EAAG;AAAA,QACtB,OAAO,EAAE,aAAa,MAAA;AAAA,MAAM;AAAA,IAAA;AAAA,KAG9BzC,EAAI4P,GAAS,IAAI5P,EAAIyC,GAAG,WAAW,CAAC,QAAQ,IAC1CwN,GAAUjQ,EAAI4P,GAAS,IAAI5P,EAAIyC,GAAG,WAAW,CAAC,QAAQ,CAAC,IACvD,SACFzC,EAAIyC,GAAG,WAAW,KAClBzC,EAAIyC,GAAG,eAAe;AAAA,IAAG;AAAA,IAC1BA,EAAE,eACDjC,gBAAAA,EAAAA;AAAAA,MAACjB;AAAA,MAAA;AAAA,QACC,YAAAG;AAAA,QACA,aAAa+C,EAAE;AAAA,QACf,WAAU;AAAA,MAAA;AAAA,IAAA;AAAA,IAGb3D,IAAIwO,EAAK,SAAS,KAAK;AAAA,EAAA,KAtBfxO,CAuBX,CACD,GACH;AAEJ,GAEMoR,KAAqB,CAAC;AAAA,EAC1B,YAAAxQ;AAAA,EACA,MAAA4N;AAAA,EACA,OAAA6C;AAAA,EACA,qBAAAC;AAAA,EACA,YAAAjN;AAAA,EACA,WAAA3B;AAAA,EACA,kBAAA0I;AAAA,EACA,cAAAE;AAAA,EACA,OAAAiG;AAAA,EACA,IAAAC;AACF,MAAM;AACJ,QAAMC,IAAWjD,EAAK,OAAO3L,EAAU,GACjC6O,IAAiBlD,EAAK,SAASiD,EAAS,QACxCE,IAAoB,CAAC,CAACvG,GACtBwG,IAAgBpD,EAAK,SAAS,GAC9B,CAACqD,GAAMC,CAAO,IAAI3K,EAAS,KAAK,GAChC,CAAC4K,GAAeC,CAAgB,IAAI7K,EAAS,CAAC,GAG9C,CAAC8K,GAAWC,CAAY,IAAI/K,EAAS,IAAI;AAC/C,EAAA6G,EAAU,MAAM;AACd,QAAI,CAAC5C,KAAoB,EAAC/G,KAAA,QAAAA,EAAY,KAAI;AACxC,MAAA6N,EAAa,IAAI;AACjB;AAAA,IACF;AACA,IAAAA,EAAa,IAAI;AACjB,QAAI9D,IAAY;AAChB,WAAA+D,GACG,IAAI,GAAG/Q,EAAO,OAAO,yBAAyB;AAAA,MAC7C,QAAQ;AAAA,QACN,cAAcgK;AAAA,QACd,UAAU/G,EAAW;AAAA,QACrB,eAAe;AAAA,QACf,oBAAoB;AAAA,QACpB,kBAAkB;AAAA,QAClB,OAAO;AAAA,MAAA;AAAA,IACT,CACD,EACA;AAAA,MACC,CAAChD,MAAQ;;AACP,QAAK+M,KAAW8D,IAAapP,IAAAzB,KAAA,gBAAAA,EAAK,SAAL,gBAAAyB,EAAW,UAAS,CAAC;AAAA,MACpD;AAAA,MACA,MAAM;AAGJ,QAAKsL,KAAW8D,EAAa,IAAI;AAAA,MACnC;AAAA,IAAA,GAEG,MAAM;AACX,MAAA9D,IAAY;AAAA,IACd;AAAA,EACF,GAAG,CAAChD,GAAkB/G,KAAA,gBAAAA,EAAY,EAAE,CAAC;AAIrC,QAAMgH,IAAiBsG,IAEnBM,MAAc,QAAQA,IAAY,IADlC,IAGEG,IACJX,EAAS,SAAS,KAAKM,KAAiBN,EAAS,QAC7CY,IACJf,MACCG,EAAS,SAAS,KAAKpG,MACxB,EAAEoG,EAAS,SAAS,KAAKW,KAAqB,CAAC/G;AAIjD,MAAI,CAACgH,KAAW,CAACT,EAAe,QAAO;AAEvC,QAAMU,IAAaZ,IAAiBK,GAC9BQ,IAAaX;AAEnB,MAAIY;AACJ,MAAI,CAACH;AAEH,IAAAG,IAAO9Q,gBAAAA,EAAAA,IAACmP,IAAA,EAAS,YAAAjQ,GAAwB,MAAA4N,EAAA,CAAY;AAAA,OAChD;AAIL,UAAMiE,IAAaF,IAAaV,IAAO;AACvC,IAAAW,IACE5L,gBAAAA,EAAAA,KAAAU,YAAA,EACG,UAAA;AAAA,MAAAiL,IACC3L,gBAAAA,EAAAA;AAAAA,QAAC8L,GAAM;AAAA,QAAN;AAAA,UACC,MAAK;AAAA,UACL,OAAOD;AAAA,UACP,UAAU,CAAC5Q,MAAMiQ,EAAQjQ,EAAE,OAAO,KAAK;AAAA,UACvC,OAAO,EAAE,cAAc,EAAA;AAAA,UAEvB,UAAA;AAAA,YAAAH,gBAAAA,EAAAA,IAACgR,GAAM,QAAN,EAAa,OAAM,OAAM,UAAA,OAAG;AAAA,kCAC5BA,GAAM,QAAN,EAAa,OAAM,QAAO,UAAA,OAAA,CAAI;AAAA,UAAA;AAAA,QAAA;AAAA,MAAA;AAAA;AAAA;AAAA,QAKjChR,gBAAAA,MAAC,SAAI,OAAO,EAAE,QAAQ,IAAI,cAAc,IAAE,CAAG;AAAA;AAAA,MAE9C+Q,MAAe,QACd7L,gBAAAA,EAAAA,KAAAU,EAAAA,UAAA,EACE,UAAA;AAAA,QAAA5F,gBAAAA,EAAAA;AAAAA,UAACuJ;AAAA,UAAA;AAAA,YACC,SAASwG;AAAA,YACT,cAAcO;AAAA,YACd,YAAApR;AAAA,YACA,YAAAyD;AAAA,YACA,WAAA3B;AAAA,YACA,kBAAA0I;AAAA,YACA,eAAAC;AAAA,YACA,cAAAC;AAAA,UAAA;AAAA,QAAA;AAAA,QAEDiH,KAAcD,IAAa,KAC1B5Q,gBAAAA,MAAC,SAAI,OAAO,EAAE,WAAW,EAAA,GACvB,iCAAC,KAAA,EAAE,SAAS,MAAMoQ,EAAQ,MAAM,GAAG,OAAO,EAAE,QAAQ,UAAA,GAAa,UAAA;AAAA,UAAA;AAAA,UAC7DQ;AAAA,UAAW;AAAA,UAAcA,MAAe,IAAI,KAAK;AAAA,UAAI;AAAA,QAAA,EAAA,CAEzD,EAAA,CACF;AAAA,MAAA,EAAA,CAEJ,IAEA5Q,gBAAAA,EAAAA,IAACmP,IAAA,EAAS,YAAAjQ,GAAwB,MAAA4N,EAAA,CAAY;AAAA,IAAA,GAElD;AAAA,EAEJ;AAMA,QAAMmE,KAAUjR,gBAAAA,EAAAA,IAAC,OAAA,EAAI,OAAA2P,GAAe,UAAAmB,GAAK;AAKzC,SAAOjB,IACL7P,gBAAAA,MAACkR,IAAA,EAAiB,IAAApB,GAAQ,OAAAD,GACvB,cACH,IAEAoB;AAEJ;","x_google_ignoreList":[0,1]}
|
|
@@ -2,7 +2,7 @@ import { j as e } from "./jsx-runtime-BzflLqGi.js";
|
|
|
2
2
|
import { useState as c, useEffect as E, useRef as b } from "react";
|
|
3
3
|
import { Tag as p, Popover as H } from "antd";
|
|
4
4
|
import { c as L, L as O } from "./router-CssZk5qZ.js";
|
|
5
|
-
import { c as $ } from "./config
|
|
5
|
+
import { c as $ } from "./config--bs_09I6.js";
|
|
6
6
|
const f = {
|
|
7
7
|
14: "The data was created by the homotypic grouping algorithm"
|
|
8
8
|
}, q = ({
|
|
@@ -79,4 +79,4 @@ const f = {
|
|
|
79
79
|
export {
|
|
80
80
|
q as M
|
|
81
81
|
};
|
|
82
|
-
//# sourceMappingURL=MergedDataBadge-
|
|
82
|
+
//# sourceMappingURL=MergedDataBadge-DK53L3R8.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"MergedDataBadge-
|
|
1
|
+
{"version":3,"file":"MergedDataBadge-DK53L3R8.js","sources":["../../src/components/MergedDataBadge.js"],"sourcesContent":["import React, { useEffect, useState, useRef } from \"react\";\nimport { Tag, Popover } from \"antd\";\nimport client from \"../api/client\";\nimport config from \"../config\";\nimport { LinkTo } from \"../router\";\n\nconst createdByAlgorithm = {\n 14: \"The data was created by the homotypic grouping algorithm\",\n};\n\nconst MergedDataBadge = ({\n style = {},\n datasetKey,\n sourceDatasetKey,\n sourceId,\n popoverPlacement,\n verbatimSourceKey,\n sectorKey,\n createdBy,\n}) => {\n const [sourceDataset, setSourceDataset] = useState(null);\n const [sourceDatasetLoading, setSourceDatasetLoading] = useState(false);\n const [verbatimRecord, setVerbatimRecord] = useState(null);\n const [verbatimRecordLoading, setVerbatimRecordLoading] = useState(false);\n const [open, setOpen] = useState(false);\n\n // A merged record's provenance can arrive two ways: explicit props, or — for\n // merged usages, whose own sourceDatasetKey is null — only on the verbatim\n // source record. Resolve both so the popover can always name the source\n // dataset and link the source id when one exists.\n const effectiveSourceDatasetKey =\n sourceDatasetKey || verbatimRecord?.sourceDatasetKey;\n const effectiveSourceId = sourceId || verbatimRecord?.sourceId;\n\n // Fetch the verbatim record (carries sourceDatasetKey / sourceId / entity).\n useEffect(() => {\n if (open && verbatimSourceKey && !createdByAlgorithm[createdBy]) {\n getVerbatimRecord();\n }\n }, [verbatimSourceKey, open]);\n\n // Fetch the source dataset once its key is known — from the prop, or from the\n // verbatim record once that has loaded.\n useEffect(() => {\n if (open && effectiveSourceDatasetKey) {\n getSourceDataset(effectiveSourceDatasetKey);\n }\n }, [open, effectiveSourceDatasetKey]);\n\n const getSourceDataset = (key) => {\n setSourceDatasetLoading(true);\n client(`${config.dataApi}dataset/${key}`)\n .then((res) => {\n setSourceDatasetLoading(false);\n setSourceDataset(res.data);\n })\n .catch((err) => {\n console.error(\"Error fetching source dataset:\", err);\n setSourceDatasetLoading(false);\n setSourceDataset(null);\n });\n };\n\n const getVerbatimRecord = () => {\n setVerbatimRecordLoading(true);\n setVerbatimRecord(null);\n client(\n `${config.dataApi}dataset/${datasetKey}/verbatimsource/${verbatimSourceKey}`\n )\n .then((res) => {\n setVerbatimRecordLoading(false);\n setVerbatimRecord(res.data);\n })\n .catch((err) => {\n console.error(\"Error fetching verbatim record:\", err);\n setVerbatimRecordLoading(false);\n setVerbatimRecord(null);\n });\n };\n\n const idRef = useRef(Math.random().toString(36).substring(2, 15));\n\n // ChecklistBank link to the source record. References live under /reference;\n // everything else (the common name-usage case) under /taxon.\n const clbEntity = (verbatimRecord?.sourceEntity || \"\")\n .toLowerCase()\n .replace(/\\s+/g, \"\");\n const clbPath = clbEntity === \"reference\" ? \"reference\" : \"taxon\";\n const sourceRecordHref =\n effectiveSourceId && effectiveSourceDatasetKey\n ? `https://www.checklistbank.org/dataset/${effectiveSourceDatasetKey}/${clbPath}/${encodeURIComponent(\n effectiveSourceId\n )}`\n : null;\n\n const loadingSource =\n sourceDatasetLoading || (!!verbatimSourceKey && verbatimRecordLoading);\n\n const content = (\n <div style={{ minWidth: \"300px\" }}>\n {!!createdByAlgorithm[createdBy] && (\n <div>{createdByAlgorithm[createdBy]}</div>\n )}\n <div>\n <strong>Source:</strong>{\" \"}\n {sourceDataset ? (\n <LinkTo to=\"source\" args={sourceDataset.key}>\n {sourceDataset.title}\n </LinkTo>\n ) : loadingSource ? (\n \"Loading...\"\n ) : (\n \"—\"\n )}\n </div>\n {sourceRecordHref && (\n <div>\n <strong>ID:</strong>{\" \"}\n <a href={sourceRecordHref} target=\"_blank\" rel=\"noreferrer\">\n {effectiveSourceId}\n </a>\n </div>\n )}\n {verbatimRecord?.issues && verbatimRecord.issues.length > 0 && (\n <div>\n <span>Issues: </span>\n {verbatimRecord.issues.map((issue, index) => (\n <Tag key={index} style={{ margin: \"2px\" }}>\n {issue}\n </Tag>\n ))}\n </div>\n )}\n </div>\n );\n\n const tagStyle = {\n cursor: \"pointer\",\n fontFamily: \"monospace\",\n fontSize: \"8px\",\n fontWeight: 900,\n padding: \"2px\",\n lineHeight: \"8px\",\n verticalAlign: \"middle\",\n marginRight: \"2px\",\n ...style,\n };\n\n return !!sourceDatasetKey || !!verbatimSourceKey ? (\n <div style={{ display: \"inline\" }} id={idRef.current}>\n <Popover\n getPopupContainer={() => document.getElementById(idRef.current)}\n content={content}\n trigger={\"click\"}\n placement={popoverPlacement || \"right\"}\n onOpenChange={setOpen}\n >\n <Tag color=\"purple\" style={tagStyle}>\n XR\n </Tag>\n </Popover>\n </div>\n ) : (\n <div style={{ display: \"inline\" }}>\n <Tag color=\"purple\" style={{ ...tagStyle, cursor: \"default\" }}>\n XR\n </Tag>\n </div>\n );\n};\n\nexport default MergedDataBadge;\n"],"names":["createdByAlgorithm","MergedDataBadge","style","datasetKey","sourceDatasetKey","sourceId","popoverPlacement","verbatimSourceKey","sectorKey","createdBy","sourceDataset","setSourceDataset","useState","sourceDatasetLoading","setSourceDatasetLoading","verbatimRecord","setVerbatimRecord","verbatimRecordLoading","setVerbatimRecordLoading","open","setOpen","effectiveSourceDatasetKey","effectiveSourceId","useEffect","getVerbatimRecord","getSourceDataset","key","client","config","res","err","idRef","useRef","clbPath","sourceRecordHref","loadingSource","content","jsxs","jsx","LinkTo","issue","index","Tag","tagStyle","Popover"],"mappings":";;;;;AAMA,MAAMA,IAAqB;AAAA,EACzB,IAAI;AACN,GAEMC,IAAkB,CAAC;AAAA,EACvB,OAAAC,IAAQ,CAAA;AAAA,EACR,YAAAC;AAAA,EACA,kBAAAC;AAAA,EACA,UAAAC;AAAA,EACA,kBAAAC;AAAA,EACA,mBAAAC;AAAA,EACA,WAAAC;AAAA,EACA,WAAAC;AACF,MAAM;AACJ,QAAM,CAACC,GAAeC,CAAgB,IAAIC,EAAS,IAAI,GACjD,CAACC,GAAsBC,CAAuB,IAAIF,EAAS,EAAK,GAChE,CAACG,GAAgBC,CAAiB,IAAIJ,EAAS,IAAI,GACnD,CAACK,GAAuBC,CAAwB,IAAIN,EAAS,EAAK,GAClE,CAACO,GAAMC,CAAO,IAAIR,EAAS,EAAK,GAMhCS,IACJjB,MAAoBW,KAAA,gBAAAA,EAAgB,mBAChCO,IAAoBjB,MAAYU,KAAA,gBAAAA,EAAgB;AAGtD,EAAAQ,EAAU,MAAM;AACd,IAAIJ,KAAQZ,KAAqB,CAACP,EAAmBS,CAAS,KAC5De,EAAA;AAAA,EAEJ,GAAG,CAACjB,GAAmBY,CAAI,CAAC,GAI5BI,EAAU,MAAM;AACd,IAAIJ,KAAQE,KACVI,EAAiBJ,CAAyB;AAAA,EAE9C,GAAG,CAACF,GAAME,CAAyB,CAAC;AAEpC,QAAMI,IAAmB,CAACC,MAAQ;AAChC,IAAAZ,EAAwB,EAAI,GAC5Ba,EAAO,GAAGC,EAAO,OAAO,WAAWF,CAAG,EAAE,EACrC,KAAK,CAACG,MAAQ;AACb,MAAAf,EAAwB,EAAK,GAC7BH,EAAiBkB,EAAI,IAAI;AAAA,IAC3B,CAAC,EACA,MAAM,CAACC,MAAQ;AACd,cAAQ,MAAM,kCAAkCA,CAAG,GACnDhB,EAAwB,EAAK,GAC7BH,EAAiB,IAAI;AAAA,IACvB,CAAC;AAAA,EACL,GAEMa,IAAoB,MAAM;AAC9B,IAAAN,EAAyB,EAAI,GAC7BF,EAAkB,IAAI,GACtBW;AAAA,MACE,GAAGC,EAAO,OAAO,WAAWzB,CAAU,mBAAmBI,CAAiB;AAAA,IAAA,EAEzE,KAAK,CAACsB,MAAQ;AACb,MAAAX,EAAyB,EAAK,GAC9BF,EAAkBa,EAAI,IAAI;AAAA,IAC5B,CAAC,EACA,MAAM,CAACC,MAAQ;AACd,cAAQ,MAAM,mCAAmCA,CAAG,GACpDZ,EAAyB,EAAK,GAC9BF,EAAkB,IAAI;AAAA,IACxB,CAAC;AAAA,EACL,GAEMe,IAAQC,EAAO,KAAK,OAAA,EAAS,SAAS,EAAE,EAAE,UAAU,GAAG,EAAE,CAAC,GAO1DC,MAHalB,KAAA,gBAAAA,EAAgB,iBAAgB,IAChD,cACA,QAAQ,QAAQ,EAAE,MACS,cAAc,cAAc,SACpDmB,IACJZ,KAAqBD,IACjB,yCAAyCA,CAAyB,IAAIY,CAAO,IAAI;AAAA,IAC/EX;AAAA,EAAA,CACD,KACD,MAEAa,IACJtB,KAAyB,CAAC,CAACN,KAAqBU,GAE5CmB,IACJC,gBAAAA,EAAAA,KAAC,OAAA,EAAI,OAAO,EAAE,UAAU,WACrB,UAAA;AAAA,IAAA,CAAC,CAACrC,EAAmBS,CAAS,2BAC5B,OAAA,EAAK,UAAAT,EAAmBS,CAAS,GAAE;AAAA,2BAErC,OAAA,EACC,UAAA;AAAA,MAAA6B,gBAAAA,EAAAA,IAAC,YAAO,UAAA,UAAA,CAAO;AAAA,MAAU;AAAA,MACxB5B,IACC4B,gBAAAA,EAAAA,IAACC,GAAA,EAAO,IAAG,UAAS,MAAM7B,EAAc,KACrC,UAAAA,EAAc,MAAA,CACjB,IACEyB,IACF,eAEA;AAAA,IAAA,GAEJ;AAAA,IACCD,4BACE,OAAA,EACC,UAAA;AAAA,MAAAI,gBAAAA,EAAAA,IAAC,YAAO,UAAA,MAAA,CAAG;AAAA,MAAU;AAAA,MACrBA,gBAAAA,EAAAA,IAAC,OAAE,MAAMJ,GAAkB,QAAO,UAAS,KAAI,cAC5C,UAAAZ,EAAA,CACH;AAAA,IAAA,GACF;AAAA,KAEDP,KAAA,gBAAAA,EAAgB,WAAUA,EAAe,OAAO,SAAS,4BACvD,OAAA,EACC,UAAA;AAAA,MAAAuB,gBAAAA,EAAAA,IAAC,UAAK,UAAA,WAAA,CAAQ;AAAA,MACbvB,EAAe,OAAO,IAAI,CAACyB,GAAOC,MACjCH,gBAAAA,EAAAA,IAACI,GAAA,EAAgB,OAAO,EAAE,QAAQ,MAAA,GAC/B,UAAAF,EAAA,GADOC,CAEV,CACD;AAAA,IAAA,EAAA,CACH;AAAA,EAAA,GAEJ,GAGIE,IAAW;AAAA,IACf,QAAQ;AAAA,IACR,YAAY;AAAA,IACZ,UAAU;AAAA,IACV,YAAY;AAAA,IACZ,SAAS;AAAA,IACT,YAAY;AAAA,IACZ,eAAe;AAAA,IACf,aAAa;AAAA,IACb,GAAGzC;AAAA,EAAA;AAGL,SAASE,KAAsBG,IAC7B+B,gBAAAA,EAAAA,IAAC,OAAA,EAAI,OAAO,EAAE,SAAS,SAAA,GAAY,IAAIP,EAAM,SAC3C,UAAAO,gBAAAA,EAAAA;AAAAA,IAACM;AAAA,IAAA;AAAA,MACC,mBAAmB,MAAM,SAAS,eAAeb,EAAM,OAAO;AAAA,MAC9D,SAAAK;AAAA,MACA,SAAS;AAAA,MACT,WAAW9B,KAAoB;AAAA,MAC/B,cAAcc;AAAA,MAEd,gCAACsB,GAAA,EAAI,OAAM,UAAS,OAAOC,GAAU,UAAA,KAAA,CAErC;AAAA,IAAA;AAAA,EAAA,EACF,CACF,IAEAL,gBAAAA,EAAAA,IAAC,OAAA,EAAI,OAAO,EAAE,SAAS,YACrB,UAAAA,gBAAAA,EAAAA,IAACI,KAAI,OAAM,UAAS,OAAO,EAAE,GAAGC,GAAU,QAAQ,UAAA,GAAa,UAAA,KAAA,CAE/D,GACF;AAEJ;"}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { j as l } from "./jsx-runtime-BzflLqGi.js";
|
|
2
2
|
import { useState as _, useEffect as R } from "react";
|
|
3
|
-
import { c as S } from "./config
|
|
3
|
+
import { c as S } from "./config--bs_09I6.js";
|
|
4
4
|
import { u as K, c as A } from "./router-CssZk5qZ.js";
|
|
5
5
|
import I from "highcharts";
|
|
6
6
|
import "highcharts/modules/exporting";
|
|
@@ -207,4 +207,4 @@ const T = "breakdown-level", z = 100, ae = [
|
|
|
207
207
|
export {
|
|
208
208
|
ve as T
|
|
209
209
|
};
|
|
210
|
-
//# sourceMappingURL=TaxonBreakdown-
|
|
210
|
+
//# sourceMappingURL=TaxonBreakdown-DqdQ18QM.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"TaxonBreakdown-DeWamLu_.js","sources":["../../src/Taxon/TaxonBreakdown.js"],"sourcesContent":["import React, { useState, useEffect } from \"react\";\nimport config from \"../config\";\nimport client from \"../api/client\";\nimport Highcharts from \"highcharts\";\nimport \"highcharts/modules/exporting\";\nimport HighchartsReact from \"highcharts-react-official\";\nimport { get, keyBy } from \"lodash-es\";\nimport { Spin, Row, Col, Switch } from \"antd\";\nimport { useNavigateTo } from \"../router\";\nimport { readSetting, writeSetting } from \"../storage\";\n\nconst BREAKDOWN_LEVEL_KEY = \"breakdown-level\";\n\nconst MAX_SLICES_PER_RING = 100;\nconst canonicalRanks = [\n \"kingdom\",\n \"phylum\",\n \"class\",\n \"order\",\n \"family\",\n \"genus\",\n \"species\",\n];\n\nconst notAssignedLabel = (rk) => (rk ? `Not assigned ${rk}` : \"Not assigned\");\n\nconst sortAndClip = (nodes) => {\n if (!nodes || nodes.length === 0) return [];\n const sorted = [...nodes].sort((a, b) => (b.species || 0) - (a.species || 0));\n return sorted.length <= MAX_SLICES_PER_RING\n ? sorted\n : sorted.slice(0, MAX_SLICES_PER_RING);\n};\n\n// Append a \"Not assigned <rank>\" slice for the difference between a parent's\n// total species count and the sum of its visible children. Covers two cases:\n// 1. species that sit directly under the parent without an intermediate rank\n// 2. species under children that were clipped out by sortAndClip\nconst padNotAssigned = (kids, parentSpecies) => {\n const sorted = sortAndClip(kids || []);\n const sum = sorted.reduce((a, n) => a + (n.species || 0), 0);\n if (sum >= parentSpecies) return sorted;\n return [\n ...sorted,\n {\n name: notAssignedLabel(get(sorted, \"[0].rank\", \"\")),\n species: parentSpecies - sum,\n children: [],\n },\n ];\n};\n\nconst TaxonBreakdown = ({\n taxon,\n datasetKey,\n rank = [],\n dataset,\n level = 1,\n showLevelSwitch = false,\n darkMode,\n}) => {\n const navigateToTaxon = useNavigateTo(\"taxon\");\n const [options, setOptions] = useState(null);\n const [loading, setLoading] = useState(false);\n const [invalid, setInvalid] = useState(false);\n // The chart's effective level is controlled internally when the switch\n // is enabled, so toggling can refetch + re-render the chart. Otherwise\n // the prop drives directly.\n const [activeLevel, setActiveLevel] = useState(() =>\n showLevelSwitch ? readSetting(BREAKDOWN_LEVEL_KEY, level) : level\n );\n useEffect(() => {\n // When the 1/2 switch is shown the remembered choice owns the level, so a\n // (usually static) `level` prop must not clobber it; otherwise the prop\n // drives directly.\n if (!showLevelSwitch) setActiveLevel(level);\n }, [level, showLevelSwitch]);\n useEffect(() => {\n if (showLevelSwitch) writeSetting(BREAKDOWN_LEVEL_KEY, activeLevel);\n }, [activeLevel, showLevelSwitch]);\n useEffect(() => {\n if (taxon?.id && datasetKey) {\n getData();\n }\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [taxon, datasetKey, activeLevel]);\n\n const getOverView = async () => {\n const res = await client(\n `${\n config.dataApi\n }dataset/${datasetKey}/nameusage/search?TAXON_ID=${encodeURIComponent(\n taxon.id\n )}&facet=rank&status=accepted&status=provisionally%20accepted&limit=0`\n );\n return keyBy(get(res, \"data.facets.rank\", []), \"value\");\n };\n\n const getData = async () => {\n setLoading(true);\n try {\n const counts = await getOverView();\n\n // confirm the focal taxon has at least one child rank with content\n const ranks = canonicalRanks;\n let taxonRankIdx = ranks.indexOf(get(taxon, \"name.rank\"));\n if (taxonRankIdx === -1) {\n let rankIndex = rank.indexOf(get(taxon, \"name.rank\")) + 1;\n while (taxonRankIdx === -1 && rankIndex < rank.length - 1) {\n const canonicalRankIndex = ranks.indexOf(rank[rankIndex]);\n if (canonicalRankIndex > -1) {\n taxonRankIdx = canonicalRankIndex - 1;\n }\n rankIndex++;\n }\n }\n let childRank;\n let childRankIndex = taxonRankIdx + 1;\n while (!childRank && childRankIndex < ranks.length) {\n const nextRank = get(ranks, `[${childRankIndex}]`);\n if (nextRank && get(counts, `${nextRank}.count`, 0) > 0) {\n childRank = nextRank;\n } else {\n childRankIndex++;\n }\n }\n if (!childRank) {\n setInvalid(true);\n setLoading(false);\n return;\n }\n\n const res = await client(\n `${config.dataApi}dataset/${datasetKey}/taxon/${taxon.id}/breakdown?level=${activeLevel}`\n );\n const children = res.data || [];\n const totalSpecies = get(counts, \"species.count\", 0);\n\n setLoading(false);\n buildChart(children, totalSpecies);\n } catch (err) {\n setLoading(false);\n }\n };\n\n const buildChart = (children, totalSpecies) => {\n const DOI = dataset.doi ? \"https://doi.org/\" + dataset.doi : null;\n const baseColors = Highcharts.getOptions().colors;\n // Colour used for outer-ring \"gap\" slices: match the page background so\n // the wedge reads as empty space rather than overlapping the inner pie.\n // Follows the explicit `darkMode` prop if given, otherwise prefers-color-scheme.\n const prefersDark =\n typeof darkMode === \"boolean\"\n ? darkMode\n : typeof window !== \"undefined\" &&\n typeof window.matchMedia === \"function\" &&\n window.matchMedia(\"(prefers-color-scheme: dark)\").matches;\n const gapColor = prefersDark ? \"#1f1f1f\" : \"#ffffff\";\n const taxonClickHandler = {\n click: (e) => {\n if (e.point._id) {\n navigateToTaxon(e.point._id);\n }\n },\n };\n\n // Inner pie: direct children of the focal taxon. Pad with a single\n // \"Not assigned <rank>\" slice if focal-taxon species don't fully sum up.\n const innerNodes = padNotAssigned(children, totalSpecies);\n const innerData = innerNodes.map((n, i) => ({\n name: n.name,\n y: n.species,\n _id: n.id,\n color: baseColors[i % baseColors.length],\n _kids: n.children,\n }));\n\n // Outer ring: children of each inner slice (grandchildren of focal),\n // coloured as a monochrome brightness shift of the parent so each\n // family of arcs reads as one hue group. Only rendered when level >= 2\n // AND the response actually carries that depth. With level=1 we draw\n // a single-ring pie even if the API returned nested children.\n const outerData = [];\n const hasOuterData =\n activeLevel >= 2 && innerData.some((s) => s._kids && s._kids.length > 0);\n if (hasOuterData) {\n innerData.forEach((slice) => {\n const sorted = sortAndClip(slice._kids || []);\n const sum = sorted.reduce((a, n) => a + (n.species || 0), 0);\n sorted.forEach((g, j) => {\n const t = sorted.length > 1 ? j / (sorted.length - 1) : 0;\n const shift = -0.1 + t * 0.4;\n outerData.push({\n name: g.name,\n y: g.species,\n _id: g.id,\n color: Highcharts.color(slice.color).brighten(shift).get(),\n });\n });\n // Where children don't fully account for the inner slice, add a\n // transparent gap slice so the outer ring stays angularly aligned\n // with the inner pie but the missing portion reads as empty space\n // (rather than a labelled \"Not assigned\" wedge).\n if (sum < slice.y) {\n outerData.push({\n name: notAssignedLabel(get(sorted, \"[0].rank\", \"\")),\n y: slice.y - sum,\n color: gapColor,\n borderColor: gapColor,\n borderWidth: 0,\n dataLabels: { enabled: false },\n });\n }\n });\n }\n\n const clean = (rows) => rows.map(({ _kids, ...rest }) => rest);\n const grandTotal = totalSpecies || innerData.reduce((a, s) => a + s.y, 0);\n\n const innerLabelStyle = {\n color: \"contrast\",\n textOutline: \"1px contrast\",\n fontWeight: \"bold\",\n };\n\n // Inner-ring data labels: only positioned inside the ring when there's\n // an outer ring fighting for the external label gutter. With just one\n // ring (level=1) the labels live outside the chart, same as the outer\n // ring at level=2, with the slice name + species count.\n const innerDataLabels = hasOuterData\n ? {\n formatter: function () {\n return this.y > grandTotal / 10 ? this.point.name : null;\n },\n distance: -30,\n style: innerLabelStyle,\n }\n : {\n formatter: function () {\n return this.y > 1\n ? \"<b>\" +\n this.point.name +\n \":</b> \" +\n this.y.toLocaleString(\"en-GB\")\n : null;\n },\n };\n\n const series = [\n {\n name: \"Species\",\n data: clean(innerData),\n size: hasOuterData ? \"60%\" : \"85%\",\n dataLabels: innerDataLabels,\n point: { events: taxonClickHandler },\n },\n ];\n if (hasOuterData) {\n series.push({\n name: \"Species\",\n data: outerData,\n size: \"85%\",\n innerSize: \"60%\",\n dataLabels: {\n formatter: function () {\n return this.y > 1\n ? \"<b>\" +\n this.point.name +\n \":</b> \" +\n this.y.toLocaleString(\"en-GB\")\n : null;\n },\n },\n point: { events: taxonClickHandler },\n });\n }\n\n setOptions({\n chart: { type: \"pie\" },\n credits: {\n text: `${taxon.name.scientificName} in ${dataset.title}${\n dataset.version ? \" (\" + dataset.version + \")\" : \"\"\n }. ${(dataset.doi ? \"DOI:\" + dataset.doi : null) || dataset.url || \"\"}`,\n href: DOI || dataset.url || \"\",\n },\n title: { text: \"\" },\n plotOptions: { pie: { shadow: false, center: [\"50%\", \"50%\"] } },\n tooltip: {},\n series,\n responsive: {\n rules: [\n {\n condition: { maxWidth: 400 },\n chartOptions: {\n series: hasOuterData\n ? [{}, { dataLabels: { enabled: false } }]\n : [{}],\n },\n },\n ],\n },\n exporting: {\n chartOptions: {\n plotOptions: { series: { dataLabels: { enabled: true } } },\n },\n fallbackToExportServer: false,\n },\n });\n };\n\n if (invalid) return null;\n\n // Place the level toggle inside the chart's top-right area, just left of\n // the Highcharts context-menu (≡) icon, so it doesn't consume an extra\n // row. Colourless switch with lvl1 / lvl2 labels.\n const levelSwitch = showLevelSwitch ? (\n <Switch\n size=\"small\"\n checked={activeLevel === 2}\n onChange={(checked) => setActiveLevel(checked ? 2 : 1)}\n checkedChildren=\"lvl2\"\n unCheckedChildren=\"lvl1\"\n style={{\n position: \"absolute\",\n top: 11,\n right: 44,\n zIndex: 2,\n background: activeLevel === 2 ? \"#8c8c8c\" : \"#bfbfbf\",\n }}\n />\n ) : null;\n\n return (\n <div style={{ position: \"relative\" }}>\n {levelSwitch}\n {loading || !options ? (\n <Row style={{ padding: \"48px\" }}>\n <Col flex=\"auto\"></Col>\n <Col>\n <Spin size=\"large\" />\n </Col>\n <Col flex=\"auto\"></Col>\n </Row>\n ) : (\n <HighchartsReact highcharts={Highcharts} options={options} />\n )}\n </div>\n );\n};\n\nexport default TaxonBreakdown;\n"],"names":["BREAKDOWN_LEVEL_KEY","MAX_SLICES_PER_RING","canonicalRanks","notAssignedLabel","rk","sortAndClip","nodes","sorted","a","b","padNotAssigned","kids","parentSpecies","sum","n","get","TaxonBreakdown","taxon","datasetKey","rank","dataset","level","showLevelSwitch","darkMode","navigateToTaxon","useNavigateTo","options","setOptions","useState","loading","setLoading","invalid","setInvalid","activeLevel","setActiveLevel","readSetting","useEffect","writeSetting","getData","getOverView","res","client","config","keyBy","counts","ranks","taxonRankIdx","rankIndex","canonicalRankIndex","childRank","childRankIndex","nextRank","children","totalSpecies","buildChart","DOI","baseColors","Highcharts","gapColor","taxonClickHandler","innerData","i","outerData","hasOuterData","s","slice","g","j","shift","clean","rows","_kids","rest","grandTotal","innerDataLabels","series","levelSwitch","jsx","Switch","checked","jsxs","Row","Col","Spin","HighchartsReact"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"TaxonBreakdown-DqdQ18QM.js","sources":["../../src/Taxon/TaxonBreakdown.js"],"sourcesContent":["import React, { useState, useEffect } from \"react\";\nimport config from \"../config\";\nimport client from \"../api/client\";\nimport Highcharts from \"highcharts\";\nimport \"highcharts/modules/exporting\";\nimport HighchartsReact from \"highcharts-react-official\";\nimport { get, keyBy } from \"lodash-es\";\nimport { Spin, Row, Col, Switch } from \"antd\";\nimport { useNavigateTo } from \"../router\";\nimport { readSetting, writeSetting } from \"../storage\";\n\nconst BREAKDOWN_LEVEL_KEY = \"breakdown-level\";\n\nconst MAX_SLICES_PER_RING = 100;\nconst canonicalRanks = [\n \"kingdom\",\n \"phylum\",\n \"class\",\n \"order\",\n \"family\",\n \"genus\",\n \"species\",\n];\n\nconst notAssignedLabel = (rk) => (rk ? `Not assigned ${rk}` : \"Not assigned\");\n\nconst sortAndClip = (nodes) => {\n if (!nodes || nodes.length === 0) return [];\n const sorted = [...nodes].sort((a, b) => (b.species || 0) - (a.species || 0));\n return sorted.length <= MAX_SLICES_PER_RING\n ? sorted\n : sorted.slice(0, MAX_SLICES_PER_RING);\n};\n\n// Append a \"Not assigned <rank>\" slice for the difference between a parent's\n// total species count and the sum of its visible children. Covers two cases:\n// 1. species that sit directly under the parent without an intermediate rank\n// 2. species under children that were clipped out by sortAndClip\nconst padNotAssigned = (kids, parentSpecies) => {\n const sorted = sortAndClip(kids || []);\n const sum = sorted.reduce((a, n) => a + (n.species || 0), 0);\n if (sum >= parentSpecies) return sorted;\n return [\n ...sorted,\n {\n name: notAssignedLabel(get(sorted, \"[0].rank\", \"\")),\n species: parentSpecies - sum,\n children: [],\n },\n ];\n};\n\nconst TaxonBreakdown = ({\n taxon,\n datasetKey,\n rank = [],\n dataset,\n level = 1,\n showLevelSwitch = false,\n darkMode,\n}) => {\n const navigateToTaxon = useNavigateTo(\"taxon\");\n const [options, setOptions] = useState(null);\n const [loading, setLoading] = useState(false);\n const [invalid, setInvalid] = useState(false);\n // The chart's effective level is controlled internally when the switch\n // is enabled, so toggling can refetch + re-render the chart. Otherwise\n // the prop drives directly.\n const [activeLevel, setActiveLevel] = useState(() =>\n showLevelSwitch ? readSetting(BREAKDOWN_LEVEL_KEY, level) : level\n );\n useEffect(() => {\n // When the 1/2 switch is shown the remembered choice owns the level, so a\n // (usually static) `level` prop must not clobber it; otherwise the prop\n // drives directly.\n if (!showLevelSwitch) setActiveLevel(level);\n }, [level, showLevelSwitch]);\n useEffect(() => {\n if (showLevelSwitch) writeSetting(BREAKDOWN_LEVEL_KEY, activeLevel);\n }, [activeLevel, showLevelSwitch]);\n useEffect(() => {\n if (taxon?.id && datasetKey) {\n getData();\n }\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [taxon, datasetKey, activeLevel]);\n\n const getOverView = async () => {\n const res = await client(\n `${\n config.dataApi\n }dataset/${datasetKey}/nameusage/search?TAXON_ID=${encodeURIComponent(\n taxon.id\n )}&facet=rank&status=accepted&status=provisionally%20accepted&limit=0`\n );\n return keyBy(get(res, \"data.facets.rank\", []), \"value\");\n };\n\n const getData = async () => {\n setLoading(true);\n try {\n const counts = await getOverView();\n\n // confirm the focal taxon has at least one child rank with content\n const ranks = canonicalRanks;\n let taxonRankIdx = ranks.indexOf(get(taxon, \"name.rank\"));\n if (taxonRankIdx === -1) {\n let rankIndex = rank.indexOf(get(taxon, \"name.rank\")) + 1;\n while (taxonRankIdx === -1 && rankIndex < rank.length - 1) {\n const canonicalRankIndex = ranks.indexOf(rank[rankIndex]);\n if (canonicalRankIndex > -1) {\n taxonRankIdx = canonicalRankIndex - 1;\n }\n rankIndex++;\n }\n }\n let childRank;\n let childRankIndex = taxonRankIdx + 1;\n while (!childRank && childRankIndex < ranks.length) {\n const nextRank = get(ranks, `[${childRankIndex}]`);\n if (nextRank && get(counts, `${nextRank}.count`, 0) > 0) {\n childRank = nextRank;\n } else {\n childRankIndex++;\n }\n }\n if (!childRank) {\n setInvalid(true);\n setLoading(false);\n return;\n }\n\n const res = await client(\n `${config.dataApi}dataset/${datasetKey}/taxon/${taxon.id}/breakdown?level=${activeLevel}`\n );\n const children = res.data || [];\n const totalSpecies = get(counts, \"species.count\", 0);\n\n setLoading(false);\n buildChart(children, totalSpecies);\n } catch (err) {\n setLoading(false);\n }\n };\n\n const buildChart = (children, totalSpecies) => {\n const DOI = dataset.doi ? \"https://doi.org/\" + dataset.doi : null;\n const baseColors = Highcharts.getOptions().colors;\n // Colour used for outer-ring \"gap\" slices: match the page background so\n // the wedge reads as empty space rather than overlapping the inner pie.\n // Follows the explicit `darkMode` prop if given, otherwise prefers-color-scheme.\n const prefersDark =\n typeof darkMode === \"boolean\"\n ? darkMode\n : typeof window !== \"undefined\" &&\n typeof window.matchMedia === \"function\" &&\n window.matchMedia(\"(prefers-color-scheme: dark)\").matches;\n const gapColor = prefersDark ? \"#1f1f1f\" : \"#ffffff\";\n const taxonClickHandler = {\n click: (e) => {\n if (e.point._id) {\n navigateToTaxon(e.point._id);\n }\n },\n };\n\n // Inner pie: direct children of the focal taxon. Pad with a single\n // \"Not assigned <rank>\" slice if focal-taxon species don't fully sum up.\n const innerNodes = padNotAssigned(children, totalSpecies);\n const innerData = innerNodes.map((n, i) => ({\n name: n.name,\n y: n.species,\n _id: n.id,\n color: baseColors[i % baseColors.length],\n _kids: n.children,\n }));\n\n // Outer ring: children of each inner slice (grandchildren of focal),\n // coloured as a monochrome brightness shift of the parent so each\n // family of arcs reads as one hue group. Only rendered when level >= 2\n // AND the response actually carries that depth. With level=1 we draw\n // a single-ring pie even if the API returned nested children.\n const outerData = [];\n const hasOuterData =\n activeLevel >= 2 && innerData.some((s) => s._kids && s._kids.length > 0);\n if (hasOuterData) {\n innerData.forEach((slice) => {\n const sorted = sortAndClip(slice._kids || []);\n const sum = sorted.reduce((a, n) => a + (n.species || 0), 0);\n sorted.forEach((g, j) => {\n const t = sorted.length > 1 ? j / (sorted.length - 1) : 0;\n const shift = -0.1 + t * 0.4;\n outerData.push({\n name: g.name,\n y: g.species,\n _id: g.id,\n color: Highcharts.color(slice.color).brighten(shift).get(),\n });\n });\n // Where children don't fully account for the inner slice, add a\n // transparent gap slice so the outer ring stays angularly aligned\n // with the inner pie but the missing portion reads as empty space\n // (rather than a labelled \"Not assigned\" wedge).\n if (sum < slice.y) {\n outerData.push({\n name: notAssignedLabel(get(sorted, \"[0].rank\", \"\")),\n y: slice.y - sum,\n color: gapColor,\n borderColor: gapColor,\n borderWidth: 0,\n dataLabels: { enabled: false },\n });\n }\n });\n }\n\n const clean = (rows) => rows.map(({ _kids, ...rest }) => rest);\n const grandTotal = totalSpecies || innerData.reduce((a, s) => a + s.y, 0);\n\n const innerLabelStyle = {\n color: \"contrast\",\n textOutline: \"1px contrast\",\n fontWeight: \"bold\",\n };\n\n // Inner-ring data labels: only positioned inside the ring when there's\n // an outer ring fighting for the external label gutter. With just one\n // ring (level=1) the labels live outside the chart, same as the outer\n // ring at level=2, with the slice name + species count.\n const innerDataLabels = hasOuterData\n ? {\n formatter: function () {\n return this.y > grandTotal / 10 ? this.point.name : null;\n },\n distance: -30,\n style: innerLabelStyle,\n }\n : {\n formatter: function () {\n return this.y > 1\n ? \"<b>\" +\n this.point.name +\n \":</b> \" +\n this.y.toLocaleString(\"en-GB\")\n : null;\n },\n };\n\n const series = [\n {\n name: \"Species\",\n data: clean(innerData),\n size: hasOuterData ? \"60%\" : \"85%\",\n dataLabels: innerDataLabels,\n point: { events: taxonClickHandler },\n },\n ];\n if (hasOuterData) {\n series.push({\n name: \"Species\",\n data: outerData,\n size: \"85%\",\n innerSize: \"60%\",\n dataLabels: {\n formatter: function () {\n return this.y > 1\n ? \"<b>\" +\n this.point.name +\n \":</b> \" +\n this.y.toLocaleString(\"en-GB\")\n : null;\n },\n },\n point: { events: taxonClickHandler },\n });\n }\n\n setOptions({\n chart: { type: \"pie\" },\n credits: {\n text: `${taxon.name.scientificName} in ${dataset.title}${\n dataset.version ? \" (\" + dataset.version + \")\" : \"\"\n }. ${(dataset.doi ? \"DOI:\" + dataset.doi : null) || dataset.url || \"\"}`,\n href: DOI || dataset.url || \"\",\n },\n title: { text: \"\" },\n plotOptions: { pie: { shadow: false, center: [\"50%\", \"50%\"] } },\n tooltip: {},\n series,\n responsive: {\n rules: [\n {\n condition: { maxWidth: 400 },\n chartOptions: {\n series: hasOuterData\n ? [{}, { dataLabels: { enabled: false } }]\n : [{}],\n },\n },\n ],\n },\n exporting: {\n chartOptions: {\n plotOptions: { series: { dataLabels: { enabled: true } } },\n },\n fallbackToExportServer: false,\n },\n });\n };\n\n if (invalid) return null;\n\n // Place the level toggle inside the chart's top-right area, just left of\n // the Highcharts context-menu (≡) icon, so it doesn't consume an extra\n // row. Colourless switch with lvl1 / lvl2 labels.\n const levelSwitch = showLevelSwitch ? (\n <Switch\n size=\"small\"\n checked={activeLevel === 2}\n onChange={(checked) => setActiveLevel(checked ? 2 : 1)}\n checkedChildren=\"lvl2\"\n unCheckedChildren=\"lvl1\"\n style={{\n position: \"absolute\",\n top: 11,\n right: 44,\n zIndex: 2,\n background: activeLevel === 2 ? \"#8c8c8c\" : \"#bfbfbf\",\n }}\n />\n ) : null;\n\n return (\n <div style={{ position: \"relative\" }}>\n {levelSwitch}\n {loading || !options ? (\n <Row style={{ padding: \"48px\" }}>\n <Col flex=\"auto\"></Col>\n <Col>\n <Spin size=\"large\" />\n </Col>\n <Col flex=\"auto\"></Col>\n </Row>\n ) : (\n <HighchartsReact highcharts={Highcharts} options={options} />\n )}\n </div>\n );\n};\n\nexport default TaxonBreakdown;\n"],"names":["BREAKDOWN_LEVEL_KEY","MAX_SLICES_PER_RING","canonicalRanks","notAssignedLabel","rk","sortAndClip","nodes","sorted","a","b","padNotAssigned","kids","parentSpecies","sum","n","get","TaxonBreakdown","taxon","datasetKey","rank","dataset","level","showLevelSwitch","darkMode","navigateToTaxon","useNavigateTo","options","setOptions","useState","loading","setLoading","invalid","setInvalid","activeLevel","setActiveLevel","readSetting","useEffect","writeSetting","getData","getOverView","res","client","config","keyBy","counts","ranks","taxonRankIdx","rankIndex","canonicalRankIndex","childRank","childRankIndex","nextRank","children","totalSpecies","buildChart","DOI","baseColors","Highcharts","gapColor","taxonClickHandler","innerData","i","outerData","hasOuterData","s","slice","g","j","shift","clean","rows","_kids","rest","grandTotal","innerDataLabels","series","levelSwitch","jsx","Switch","checked","jsxs","Row","Col","Spin","HighchartsReact"],"mappings":"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"}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { j as t } from "./jsx-runtime-BzflLqGi.js";
|
|
2
2
|
import "react";
|
|
3
|
-
import { M as i } from "./MergedDataBadge-
|
|
3
|
+
import { M as i } from "./MergedDataBadge-DK53L3R8.js";
|
|
4
4
|
const m = ({ merged: r, style: o, children: s, ...a }) => r ? /* @__PURE__ */ t.jsxs("span", { style: { position: "relative", display: "inline-block", ...o }, children: [
|
|
5
5
|
/* @__PURE__ */ t.jsx(
|
|
6
6
|
i,
|
|
@@ -20,4 +20,4 @@ const m = ({ merged: r, style: o, children: s, ...a }) => r ? /* @__PURE__ */ t.
|
|
|
20
20
|
export {
|
|
21
21
|
m as X
|
|
22
22
|
};
|
|
23
|
-
//# sourceMappingURL=XrGutter-
|
|
23
|
+
//# sourceMappingURL=XrGutter-COJhHpia.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"XrGutter-
|
|
1
|
+
{"version":3,"file":"XrGutter-COJhHpia.js","sources":["../../src/components/XrGutter.js"],"sourcesContent":["import React from \"react\";\nimport MergedDataBadge from \"./MergedDataBadge\";\n\n// Renders the XR (merged-data) badge in the left gutter of a line or table\n// cell. The badge is absolutely positioned just left of the content, so it\n// takes no flow width — the content stays at the same position whether or not\n// the badge is shown. This keeps list/table rows aligned (mirroring how the\n// taxon title places its XR badge) instead of appending the badge after the\n// name or wedging it mid-line.\n//\n// When `merged` is falsy the children render unchanged (no wrapper). Any extra\n// props are forwarded to MergedDataBadge (datasetKey, verbatimSourceKey,\n// sourceDatasetKey, sourceId, createdBy, …).\nconst XrGutter = ({ merged, style, children, ...badgeProps }) =>\n merged ? (\n <span style={{ position: \"relative\", display: \"inline-block\", ...style }}>\n <MergedDataBadge\n {...badgeProps}\n style={{\n position: \"absolute\",\n right: \"100%\",\n top: \"50%\",\n transform: \"translateY(-50%)\",\n marginRight: \"4px\",\n }}\n />\n {children}\n </span>\n ) : (\n <>{children}</>\n );\n\nexport default XrGutter;\n"],"names":["XrGutter","merged","style","children","badgeProps","jsx","MergedDataBadge"],"mappings":";;;AAaA,MAAMA,IAAW,CAAC,EAAE,QAAAC,GAAQ,OAAAC,GAAO,UAAAC,GAAU,GAAGC,QAC9CH,2BACG,QAAA,EAAK,OAAO,EAAE,UAAU,YAAY,SAAS,gBAAgB,GAAGC,KAC/D,UAAA;AAAA,EAAAG,gBAAAA,EAAAA;AAAAA,IAACC;AAAA,IAAA;AAAA,MACE,GAAGF;AAAA,MACJ,OAAO;AAAA,QACL,UAAU;AAAA,QACV,OAAO;AAAA,QACP,KAAK;AAAA,QACL,WAAW;AAAA,QACX,aAAa;AAAA,MAAA;AAAA,IACf;AAAA,EAAA;AAAA,EAEDD;AAAA,EAAA,CACH,wCAEG,UAAAA,EAAA,CAAS;"}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
const o = {
|
|
2
|
+
dataApi: "https://api.checklistbank.org/",
|
|
3
|
+
// Human-facing ChecklistBank portal. Used for outbound links to
|
|
4
|
+
// dataset / publisher pages we don't host ourselves.
|
|
5
|
+
clbPortal: "https://www.checklistbank.org",
|
|
6
|
+
// GBIF API base (no trailing slash). Used for the occurrence count and
|
|
7
|
+
// the v2 map tile endpoint.
|
|
8
|
+
gbifApi: "https://api.gbif.org",
|
|
9
|
+
// GBIF human-facing portal where the attribution link points. The
|
|
10
|
+
// multitaxonomy occurrence search now ships on the production portal.
|
|
11
|
+
gbifPortal: "https://www.gbif.org",
|
|
12
|
+
// MapLibre basemap for the distribution map. Anything MapLibre accepts as
|
|
13
|
+
// `style` works: a style URL (bake your provider's API key into it) or an
|
|
14
|
+
// inline style object. The default is CARTO's public Positron CDN, which
|
|
15
|
+
// needs no key.
|
|
16
|
+
basemapStyle: "https://basemaps.cartocdn.com/gl/positron-gl-style/style.json",
|
|
17
|
+
// CARTO Basemaps API key. Empty means unauthenticated (fine today, but
|
|
18
|
+
// CARTO is moving to enforce keys). Set it and every cartocdn.com request
|
|
19
|
+
// the map makes — style, vector tiles, glyphs, sprites — carries `?key=`.
|
|
20
|
+
// Not needed when `basemapStyle` points at a non-CARTO provider.
|
|
21
|
+
cartoKey: ""
|
|
22
|
+
}, c = /* @__PURE__ */ new Set(["dataApi"]), e = /* @__PURE__ */ new Set(["basemapStyle", "cartoKey"]), r = (a, t) => c.has(a) ? t.replace(/\/*$/, "/") : t.replace(/\/+$/, "");
|
|
23
|
+
function n(a = {}) {
|
|
24
|
+
return Object.entries(a).forEach(([t, s]) => {
|
|
25
|
+
o[t] = typeof s == "string" && !e.has(t) ? r(t, s) : s;
|
|
26
|
+
}), o;
|
|
27
|
+
}
|
|
28
|
+
export {
|
|
29
|
+
n as a,
|
|
30
|
+
o as c
|
|
31
|
+
};
|
|
32
|
+
//# sourceMappingURL=config--bs_09I6.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config--bs_09I6.js","sources":["../../src/config.js"],"sourcesContent":["const config = {\n dataApi: \"https://api.checklistbank.org/\",\n // Human-facing ChecklistBank portal. Used for outbound links to\n // dataset / publisher pages we don't host ourselves.\n clbPortal: \"https://www.checklistbank.org\",\n // GBIF API base (no trailing slash). Used for the occurrence count and\n // the v2 map tile endpoint.\n gbifApi: \"https://api.gbif.org\",\n // GBIF human-facing portal where the attribution link points. The\n // multitaxonomy occurrence search now ships on the production portal.\n gbifPortal: \"https://www.gbif.org\",\n // MapLibre basemap for the distribution map. Anything MapLibre accepts as\n // `style` works: a style URL (bake your provider's API key into it) or an\n // inline style object. The default is CARTO's public Positron CDN, which\n // needs no key.\n basemapStyle: \"https://basemaps.cartocdn.com/gl/positron-gl-style/style.json\",\n // CARTO Basemaps API key. Empty means unauthenticated (fine today, but\n // CARTO is moving to enforce keys). Set it and every cartocdn.com request\n // the map makes — style, vector tiles, glyphs, sprites — carries `?key=`.\n // Not needed when `basemapStyle` points at a non-CARTO provider.\n cartoKey: \"\",\n};\n\n// `dataApi` is concatenated with bare paths (`${dataApi}dataset/…`) so it must\n// end with a slash; the others are concatenated with paths that carry their own\n// leading slash, so they must not. Normalising here means callers can pass\n// either form without breaking every URL the components build.\nconst SLASH_TERMINATED = new Set([\"dataApi\"]);\n\n// Keys that are not base URLs and must survive untouched — a basemap style URL\n// carries its own path and query string (e.g. an API key), and an API key is\n// an opaque credential.\nconst VERBATIM = new Set([\"basemapStyle\", \"cartoKey\"]);\n\nconst normalize = (key, value) =>\n SLASH_TERMINATED.has(key)\n ? value.replace(/\\/*$/, \"/\")\n : value.replace(/\\/+$/, \"\");\n\n/**\n * Override the base URLs the components talk to, e.g. to point them at the\n * ChecklistBank dev API. Merges into the shared config, so keys left out keep\n * their current value. Call once before rendering.\n *\n * configure({ dataApi: \"https://api.dev.checklistbank.org/\" })\n */\nexport function configure(overrides = {}) {\n Object.entries(overrides).forEach(([key, value]) => {\n config[key] =\n typeof value === \"string\" && !VERBATIM.has(key)\n ? normalize(key, value)\n : value;\n });\n return config;\n}\n\nexport default config;\n"],"names":["config","SLASH_TERMINATED","VERBATIM","normalize","key","value","configure","overrides"],"mappings":"AAAA,MAAMA,IAAS;AAAA,EACX,SAAS;AAAA;AAAA;AAAA,EAGT,WAAW;AAAA;AAAA;AAAA,EAGX,SAAS;AAAA;AAAA;AAAA,EAGT,YAAY;AAAA;AAAA;AAAA;AAAA;AAAA,EAKZ,cAAc;AAAA;AAAA;AAAA;AAAA;AAAA,EAKd,UAAU;AACd,GAMMC,IAAmB,oBAAI,IAAI,CAAC,SAAS,CAAC,GAKtCC,IAAW,oBAAI,IAAI,CAAC,gBAAgB,UAAU,CAAC,GAE/CC,IAAY,CAACC,GAAKC,MACpBJ,EAAiB,IAAIG,CAAG,IAClBC,EAAM,QAAQ,QAAQ,GAAG,IACzBA,EAAM,QAAQ,QAAQ,EAAE;AAS3B,SAASC,EAAUC,IAAY,IAAI;AACtC,gBAAO,QAAQA,CAAS,EAAE,QAAQ,CAAC,CAACH,GAAKC,CAAK,MAAM;AAChD,IAAAL,EAAOI,CAAG,IACN,OAAOC,KAAU,YAAY,CAACH,EAAS,IAAIE,CAAG,IACxCD,EAAUC,GAAKC,CAAK,IACpBA;AAAA,EACd,CAAC,GACML;AACX;"}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { c } from "./router-CssZk5qZ.js";
|
|
2
|
-
import { c as s } from "./config
|
|
2
|
+
import { c as s } from "./config--bs_09I6.js";
|
|
3
3
|
const p = (t) => t.then(
|
|
4
4
|
(e) => e.data,
|
|
5
5
|
(e) => null
|
|
@@ -27,4 +27,4 @@ export {
|
|
|
27
27
|
h as c,
|
|
28
28
|
g
|
|
29
29
|
};
|
|
30
|
-
//# sourceMappingURL=dataset-
|
|
30
|
+
//# sourceMappingURL=dataset-BZpjo3Yq.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"dataset-
|
|
1
|
+
{"version":3,"file":"dataset-BZpjo3Yq.js","sources":["../../src/api/dataset.js"],"sourcesContent":["import client from \"./client\";\nimport config from \"../config\";\n\nconst reflect = (p) =>\n p.then(\n (v) => v.data,\n (e) => null\n );\n\n// Bulk lookup using the API's `/source/simple?id=…&id=…` endpoint. One\n// HTTP request resolves all ids in the batch. The endpoint returns a\n// lightweight dataset object per id; results may come back in any order,\n// so we reorder by `key` to match what DataLoader expects (same length\n// and same order as the requested ids).\n//\n// Tolerates any failure mode (404, network error, malformed response, …)\n// by resolving every id in the failing batch to null. Returning the\n// expected-length array is critical — DataLoader rejects every pending\n// load() if the batch function rejects or returns the wrong length, and\n// the per-id load() rejections would in turn reject the Promise.all in\n// TaxonSources and leave the popover spinner stuck.\nexport const getDatasetsBatch = (ids, datasetKey) => {\n if (!ids?.length) return Promise.resolve([]);\n const nullsForAll = () => ids.map(() => null);\n const params = ids.map((id) => `id=${encodeURIComponent(id)}`).join(\"&\");\n return client(`${config.dataApi}dataset/${datasetKey}/source/simple?${params}`)\n .then((res) => {\n try {\n const byKey = new Map();\n const arr = Array.isArray(res?.data) ? res.data : [];\n arr.forEach((d) => {\n if (d && d.key != null) byKey.set(d.key, d);\n });\n return ids.map((id) => byKey.get(id) ?? byKey.get(Number(id)) ?? null);\n } catch (parseErr) {\n return nullsForAll();\n }\n })\n .catch(() => nullsForAll());\n};\n\nexport const getPublishersBatch = (ids, datasetKey) => {\n return Promise.all(\n ids.map((i) =>\n reflect(client(`${config.dataApi}dataset/${datasetKey}/sector/publisher/${i}`))\n )\n );\n};\n\nexport const getCatalogues = () => {\n return client(`${config.dataApi}dataset/catalogues`).then(({ data }) =>\n getDatasetsBatch(data)\n );\n};\n\nexport const getDataset = (datasetKey) =>\n client(`${config.dataApi}dataset/${datasetKey}`);\n\n// Lightweight dataset descriptor — includes `origin`, `title`, `version`,\n// `key`, etc. Used by Search to gate filter UI on the dataset's origin.\n// TODO: switch to `/dataset/{key}/simple` once that endpoint deploys.\n// The full /dataset/{key} response is a superset, so it works today.\nexport const getDatasetSimple = (datasetKey) =>\n client(`${config.dataApi}dataset/${datasetKey}`);\n"],"names":["reflect","p","v","getDatasetsBatch","ids","datasetKey","nullsForAll","params","id","client","config","res","byKey","d","getPublishersBatch","i","getDataset","getDatasetSimple"],"mappings":";;AAGA,MAAMA,IAAU,CAACC,MACfA,EAAE;AAAA,EACA,CAACC,MAAMA,EAAE;AAAA,EACT,CAAC,MAAM;AACT,GAcWC,IAAmB,CAACC,GAAKC,MAAe;AACnD,MAAI,EAACD,KAAA,QAAAA,EAAK,gBAAe,QAAQ,QAAQ,CAAA,CAAE;AAC3C,QAAME,IAAc,MAAMF,EAAI,IAAI,MAAM,IAAI,GACtCG,IAASH,EAAI,IAAI,CAACI,MAAO,MAAM,mBAAmBA,CAAE,CAAC,EAAE,EAAE,KAAK,GAAG;AACvE,SAAOC,EAAO,GAAGC,EAAO,OAAO,WAAWL,CAAU,kBAAkBE,CAAM,EAAE,EAC3E,KAAK,CAACI,MAAQ;AACb,QAAI;AACF,YAAMC,wBAAY,IAAA;AAElB,cADY,MAAM,QAAQD,KAAA,gBAAAA,EAAK,IAAI,IAAIA,EAAI,OAAO,CAAA,GAC9C,QAAQ,CAACE,MAAM;AACjB,QAAIA,KAAKA,EAAE,OAAO,UAAY,IAAIA,EAAE,KAAKA,CAAC;AAAA,MAC5C,CAAC,GACMT,EAAI,IAAI,CAACI,MAAOI,EAAM,IAAIJ,CAAE,KAAKI,EAAM,IAAI,OAAOJ,CAAE,CAAC,KAAK,IAAI;AAAA,IACvE,QAAmB;AACjB,aAAOF,EAAA;AAAA,IACT;AAAA,EACF,CAAC,EACA,MAAM,MAAMA,GAAa;AAC9B,GAEaQ,IAAqB,CAACV,GAAKC,MAC/B,QAAQ;AAAA,EACbD,EAAI;AAAA,IAAI,CAACW,MACPf,EAAQS,EAAO,GAAGC,EAAO,OAAO,WAAWL,CAAU,qBAAqBU,CAAC,EAAE,CAAC;AAAA,EAAA;AAChF,GAUSC,IAAa,CAACX,MACzBI,EAAO,GAAGC,EAAO,OAAO,WAAWL,CAAU,EAAE,GAMpCY,IAAmB,CAACZ,MAC/BI,EAAO,GAAGC,EAAO,OAAO,WAAWL,CAAU,EAAE;"}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { c as a } from "./router-CssZk5qZ.js";
|
|
2
|
-
import { c as o } from "./config
|
|
2
|
+
import { c as o } from "./config--bs_09I6.js";
|
|
3
3
|
const c = () => a(`${o.dataApi}vocab/country`).then(
|
|
4
4
|
(t) => t.data
|
|
5
5
|
), e = () => a(`${o.dataApi}vocab/taxgroup`).then(
|
|
@@ -9,4 +9,4 @@ export {
|
|
|
9
9
|
e as a,
|
|
10
10
|
c as g
|
|
11
11
|
};
|
|
12
|
-
//# sourceMappingURL=enumeration-
|
|
12
|
+
//# sourceMappingURL=enumeration-CV8i_q_O.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"enumeration-
|
|
1
|
+
{"version":3,"file":"enumeration-CV8i_q_O.js","sources":["../../src/api/enumeration.js"],"sourcesContent":["// import axiosInstance from './util/axiosInstance';\nimport client from \"./client\";\nimport config from \"../config\";\n\nexport const getFrequency = () => {\n return client(`${config.dataApi}vocab/frequency`).then(res =>\n res.data.map(e => e.name)\n );\n};\n\nexport const getDatasetType = () => {\n return client(`${config.dataApi}vocab/datasettype`).then(res =>\n res.data.map(e => e.name)\n );\n};\n\nexport const getDataFormatType = () => {\n return client(`${config.dataApi}vocab/dataformat`).then(res =>\n res.data.map(e => e.name)\n );\n};\n\nexport const getDatasetOrigin = () => {\n return client(`${config.dataApi}vocab/datasetorigin`).then(res =>\n res.data.map(e => e.name)\n );\n};\n\nexport const getRank = () => {\n return client(`${config.dataApi}vocab/rank`).then(res =>\n res.data.map(e => e.name)\n );\n};\n\nexport const getTaxonomicStatus = () => {\n return client(`${config.dataApi}vocab/taxonomicstatus`).then(res =>\n res.data.map(e => e.name)\n );\n};\n\nexport const getIssue = () => {\n return client(`${config.dataApi}vocab/issue`).then(res =>\n res.data\n );\n};\n\nexport const getNameType = () => {\n return client(`${config.dataApi}vocab/nametype`).then(res =>\n res.data.map(e => e.name)\n );\n};\n\nexport const getNameField = () => {\n return client(`${config.dataApi}vocab/namefield`).then(res =>\n res.data.map(e => e.name)\n );\n};\n\nexport const getNomStatus = () => {\n return client(`${config.dataApi}vocab/nomstatus`).then(res =>\n res.data.map(e => e.name)\n );\n};\n\nexport const getLicense = () => {\n return client(`${config.dataApi}vocab/license`).then(res =>\n res.data.map(e => e.name)\n );\n};\n\nexport const getNomCode = () => {\n return client(`${config.dataApi}vocab/nomcode`).then(res =>\n res.data\n );\n};\n\nexport const getImportState = () => {\n return client(`${config.dataApi}vocab/importstate`).then(res =>\n res.data\n );\n};\n\nexport const getLifezones = () => {\n return client(`${config.dataApi}vocab/lifezone`).then(res =>\n res.data\n );\n};\n\nexport const getSectorImportState = () => {\n return client(`${config.dataApi}vocab/sectorimport$state`).then(res =>\n res.data.map(e => e.name)\n );\n};\n\nexport const getCountries = () => {\n return client(`${config.dataApi}vocab/country`).then(res =>\n res.data\n );\n};\n\nexport const getTaxGroup = () => {\n return client(`${config.dataApi}vocab/taxgroup`).then(res =>\n res.data\n );\n};\n\n\n\n\n"],"names":["getCountries","client","config","res","getTaxGroup"],"mappings":";;AA8FO,MAAMA,IAAe,MACnBC,EAAO,GAAGC,EAAO,OAAO,eAAe,EAAE;AAAA,EAAK,OACnDC,EAAI;AAAA,GAIKC,IAAc,MAClBH,EAAO,GAAGC,EAAO,OAAO,gBAAgB,EAAE;AAAA,EAAK,OACpDC,EAAI;AAAA;"}
|