UNPKG

@grafana/ui

Version:
1 lines • 32.7 kB
{"version":3,"file":"utils.mjs","sources":["../../../../../src/components/Table/TableNG/utils.ts"],"sourcesContent":["import { css } from '@emotion/css';\nimport { Property } from 'csstype';\nimport React from 'react';\nimport { SortColumn, SortDirection } from 'react-data-grid';\nimport tinycolor from 'tinycolor2';\nimport { varPreLine } from 'uwrap';\n\nimport {\n FieldType,\n Field,\n formattedValueToString,\n reduceField,\n GrafanaTheme2,\n DisplayValue,\n LinkModel,\n DisplayValueAlignmentFactors,\n DataFrame,\n} from '@grafana/data';\nimport {\n BarGaugeDisplayMode,\n TableAutoCellOptions,\n TableCellBackgroundDisplayMode,\n TableCellDisplayMode,\n TableCellHeight,\n TableCellOptions,\n TableSortByFieldState,\n} from '@grafana/schema';\n\nimport { TableCellInspectorMode } from '../..';\nimport { getTextColorForAlphaBackground } from '../../../utils';\n\nimport { TABLE } from './constants';\nimport {\n CellColors,\n TableRow,\n TableFieldOptionsType,\n ColumnTypes,\n FilterType,\n FrameToRowsConverter,\n TableNGProps,\n Comparator,\n TableFooterCalc,\n} from './types';\n\n/* ---------------------------- Cell calculations --------------------------- */\nexport function getCellHeight(\n text: string,\n cellWidth: number, // width of the cell without padding\n ctx: CanvasRenderingContext2D,\n lineHeight: number,\n defaultRowHeight: number,\n padding = 0\n) {\n const PADDING = padding * 2;\n\n if (typeof text === 'string') {\n const words = text.split(/\\s/);\n const lines = [];\n let currentLine = '';\n\n // Let's just wrap the lines and see how well the measurement works\n for (let i = 0; i < words.length; i++) {\n const currentWord = words[i];\n // TODO: this method is not accurate\n let lineWidth = ctx.measureText(currentLine + ' ' + currentWord).width;\n\n // if line width is less than the cell width, add the word to the current line and continue\n // else add the current line to the lines array and start a new line with the current word\n if (lineWidth < cellWidth) {\n currentLine += ' ' + currentWord;\n } else {\n lines.push({\n width: lineWidth,\n line: currentLine,\n });\n\n currentLine = currentWord;\n }\n\n // if we are at the last word, add the current line to the lines array\n if (i === words.length - 1) {\n lines.push({\n width: lineWidth,\n line: currentLine,\n });\n }\n }\n\n if (lines.length === 1) {\n return defaultRowHeight;\n }\n\n // TODO: double padding to adjust osContext.measureText() results\n const height = lines.length * lineHeight + PADDING * 2;\n\n return height;\n }\n\n return defaultRowHeight;\n}\n\nexport type CellHeightCalculator = (text: string, cellWidth: number) => number;\n\nexport function getCellHeightCalculator(\n // should be pre-configured with font and letterSpacing\n ctx: CanvasRenderingContext2D,\n lineHeight: number,\n defaultRowHeight: number,\n padding = 0\n) {\n const { count } = varPreLine(ctx);\n\n return (text: string, cellWidth: number) => {\n const effectiveCellWidth = Math.max(cellWidth, 20); // Minimum width to work with\n const TOTAL_PADDING = padding * 2;\n const numLines = count(text, effectiveCellWidth);\n const totalHeight = numLines * lineHeight + TOTAL_PADDING;\n return Math.max(totalHeight, defaultRowHeight);\n };\n}\n\nexport function getDefaultRowHeight(theme: GrafanaTheme2, cellHeight: TableCellHeight | undefined): number {\n const bodyFontSize = theme.typography.fontSize;\n const lineHeight = theme.typography.body.lineHeight;\n\n switch (cellHeight) {\n case TableCellHeight.Sm:\n return 36;\n case TableCellHeight.Md:\n return 42;\n case TableCellHeight.Lg:\n return TABLE.MAX_CELL_HEIGHT;\n }\n\n return TABLE.CELL_PADDING * 2 + bodyFontSize * lineHeight;\n}\n\n/**\n * getRowHeight determines cell height based on cell width + text length. Used\n * for when textWrap is enabled.\n */\nexport function getRowHeight(\n row: TableRow,\n calc: CellHeightCalculator,\n avgCharWidth: number,\n defaultRowHeight: number,\n fieldsData: {\n headersLength: number;\n textWraps: { [key: string]: boolean };\n columnTypes: ColumnTypes;\n columnWidths: Record<string, number>;\n fieldDisplayType: Record<string, TableCellDisplayMode>;\n }\n): number {\n let maxLines = 1;\n let maxLinesCol = '';\n\n for (const key in row) {\n if (\n fieldsData.columnTypes[key] === FieldType.string &&\n fieldsData.textWraps[key] &&\n fieldsData.fieldDisplayType[key] !== TableCellDisplayMode.Image\n ) {\n const cellText = row[key] as string;\n\n if (cellText != null) {\n const charsPerLine = fieldsData.columnWidths[key] / avgCharWidth;\n const approxLines = cellText.length / charsPerLine;\n\n if (approxLines > maxLines) {\n maxLines = approxLines;\n maxLinesCol = key;\n }\n }\n }\n }\n\n return maxLinesCol === '' ? defaultRowHeight : calc(row[maxLinesCol] as string, fieldsData.columnWidths[maxLinesCol]);\n}\n\nexport function isTextCell(key: string, columnTypes: Record<string, string>): boolean {\n return columnTypes[key] === FieldType.string;\n}\n\nexport function shouldTextOverflow(\n key: string,\n row: TableRow,\n columnTypes: ColumnTypes,\n headerCellRefs: React.MutableRefObject<Record<string, HTMLDivElement>>,\n ctx: CanvasRenderingContext2D,\n lineHeight: number,\n defaultRowHeight: number,\n padding: number,\n textWrap: boolean,\n field: Field,\n cellType: TableCellDisplayMode\n): boolean {\n const cellInspect = field.config?.custom?.inspect ?? false;\n\n // Tech debt: Technically image cells are of type string, which is misleading (kinda?)\n // so we need to ensure we don't apply overflow hover states fo type image\n if (textWrap || cellInspect || cellType === TableCellDisplayMode.Image || !isTextCell(key, columnTypes)) {\n return false;\n }\n\n return true;\n}\n\nexport function getTextAlign(field?: Field): Property.JustifyContent {\n if (!field) {\n return 'flex-start';\n }\n\n if (field.config.custom) {\n const custom: TableFieldOptionsType = field.config.custom;\n\n switch (custom.align) {\n case 'right':\n return 'flex-end';\n case 'left':\n return 'flex-start';\n case 'center':\n return 'center';\n }\n }\n\n if (field.type === FieldType.number) {\n return 'flex-end';\n }\n\n return 'flex-start';\n}\n\nconst defaultCellOptions: TableAutoCellOptions = { type: TableCellDisplayMode.Auto };\n\nexport function getCellOptions(field: Field): TableCellOptions {\n if (field.config.custom?.displayMode) {\n return migrateTableDisplayModeToCellOptions(field.config.custom?.displayMode);\n }\n\n if (!field.config.custom?.cellOptions) {\n return defaultCellOptions;\n }\n\n return field.config.custom.cellOptions;\n}\n\n/**\n * Getting gauge or sparkline values to align is very tricky without looking at all values and passing them through display processor.\n * For very large tables that could pretty expensive. So this is kind of a compromise. We look at the first 1000 rows and cache the longest value.\n * If we have a cached value we just check if the current value is longer and update the alignmentFactor. This can obviously still lead to\n * unaligned gauges but it should a lot less common.\n **/\nexport function getAlignmentFactor(\n field: Field,\n displayValue: DisplayValue,\n rowIndex: number\n): DisplayValueAlignmentFactors {\n let alignmentFactor = field.state?.alignmentFactors;\n\n if (alignmentFactor) {\n // check if current alignmentFactor is still the longest\n if (formattedValueToString(alignmentFactor).length < formattedValueToString(displayValue).length) {\n alignmentFactor = { ...displayValue };\n field.state!.alignmentFactors = alignmentFactor;\n }\n return alignmentFactor;\n } else {\n // look at the next 1000 rows\n alignmentFactor = { ...displayValue };\n const maxIndex = Math.min(field.values.length, rowIndex + 1000);\n\n for (let i = rowIndex + 1; i < maxIndex; i++) {\n const nextDisplayValue = field.display!(field.values[i]);\n if (formattedValueToString(alignmentFactor).length > formattedValueToString(nextDisplayValue).length) {\n alignmentFactor.text = displayValue.text;\n }\n }\n\n if (field.state) {\n field.state.alignmentFactors = alignmentFactor;\n } else {\n field.state = { alignmentFactors: alignmentFactor };\n }\n\n return alignmentFactor;\n }\n}\n\n/* ------------------------------ Footer calculations ------------------------------ */\nexport function getFooterItemNG(rows: TableRow[], field: Field, options: TableFooterCalc | undefined): string {\n if (options === undefined) {\n return '';\n }\n\n if (field.type !== FieldType.number) {\n return '';\n }\n\n // Check if reducer array exists and has at least one element\n if (!options.reducer || !options.reducer.length) {\n return '';\n }\n\n // If fields array is specified, only show footer for fields included in that array\n if (options.fields && options.fields.length > 0) {\n if (!options.fields.includes(field.name)) {\n return '';\n }\n }\n\n const calc = options.reducer[0];\n const value = reduceField({\n field: {\n ...field,\n values: rows.map((row) => row[getDisplayName(field)]),\n },\n reducers: options.reducer,\n })[calc];\n\n const formattedValue = formattedValueToString(field.display!(value));\n\n return formattedValue;\n}\n\nexport const getFooterStyles = (justifyContent: Property.JustifyContent) => ({\n footerCell: css({\n display: 'flex',\n justifyContent: justifyContent || 'space-between',\n }),\n});\n\n/* ------------------------- Cell color calculation ------------------------- */\nconst CELL_COLOR_DARKENING_MULTIPLIER = 10;\nconst CELL_GRADIENT_DARKENING_MULTIPLIER = 15;\nconst CELL_GRADIENT_HUE_ROTATION_DEGREES = 5;\n\nexport function getCellColors(\n theme: GrafanaTheme2,\n cellOptions: TableCellOptions,\n displayValue: DisplayValue\n): CellColors {\n // Convert RGBA hover color to hex to prevent transparency issues on cell hover\n const autoCellBackgroundHoverColor = convertRGBAToHex(theme.colors.background.primary, theme.colors.action.hover);\n\n // How much to darken elements depends upon if we're in dark mode\n const darkeningFactor = theme.isDark ? 1 : -0.7;\n\n // Setup color variables\n let textColor: string | undefined = undefined;\n let bgColor: string | undefined = undefined;\n let bgHoverColor: string = autoCellBackgroundHoverColor;\n\n if (cellOptions.type === TableCellDisplayMode.ColorText) {\n textColor = displayValue.color;\n } else if (cellOptions.type === TableCellDisplayMode.ColorBackground) {\n const mode = cellOptions.mode ?? TableCellBackgroundDisplayMode.Gradient;\n\n if (mode === TableCellBackgroundDisplayMode.Basic) {\n textColor = getTextColorForAlphaBackground(displayValue.color!, theme.isDark);\n bgColor = tinycolor(displayValue.color).toRgbString();\n bgHoverColor = tinycolor(displayValue.color)\n .darken(CELL_COLOR_DARKENING_MULTIPLIER * darkeningFactor)\n .toRgbString();\n } else if (mode === TableCellBackgroundDisplayMode.Gradient) {\n const hoverColor = tinycolor(displayValue.color)\n .darken(CELL_GRADIENT_DARKENING_MULTIPLIER * darkeningFactor)\n .toRgbString();\n const bgColor2 = tinycolor(displayValue.color)\n .darken(CELL_COLOR_DARKENING_MULTIPLIER * darkeningFactor)\n .spin(CELL_GRADIENT_HUE_ROTATION_DEGREES);\n textColor = getTextColorForAlphaBackground(displayValue.color!, theme.isDark);\n bgColor = `linear-gradient(120deg, ${bgColor2.toRgbString()}, ${displayValue.color})`;\n bgHoverColor = `linear-gradient(120deg, ${bgColor2.toRgbString()}, ${hoverColor})`;\n }\n }\n\n return { textColor, bgColor, bgHoverColor };\n}\n\n/** Extracts numeric pixel value from theme spacing */\nexport const extractPixelValue = (spacing: string | number): number => {\n return typeof spacing === 'number' ? spacing : parseFloat(spacing) || 0;\n};\n\n/** Converts an RGBA color to hex by blending it with a background color */\nexport const convertRGBAToHex = (backgroundColor: string, rgbaColor: string): string => {\n const bg = tinycolor(backgroundColor);\n const rgba = tinycolor(rgbaColor);\n return tinycolor.mix(bg, rgba, rgba.getAlpha() * 100).toHexString();\n};\n\n/* ------------------------------- Data links ------------------------------- */\n/**\n * @internal\n */\nexport const getCellLinks = (field: Field, rowIdx: number) => {\n let links: Array<LinkModel<unknown>> | undefined;\n if (field.getLinks) {\n links = field.getLinks({\n valueRowIndex: rowIdx,\n });\n }\n\n if (!links) {\n return;\n }\n\n for (let i = 0; i < links?.length; i++) {\n if (links[i].onClick) {\n const origOnClick = links[i].onClick;\n\n links[i].onClick = (event) => {\n // Allow opening in new tab\n if (!(event.ctrlKey || event.metaKey || event.shiftKey)) {\n event.preventDefault();\n origOnClick!(event, {\n field,\n rowIndex: rowIdx,\n });\n }\n };\n }\n }\n\n return links;\n};\n\n/* ----------------------------- Data grid sorting ---------------------------- */\nexport const handleSort = (\n columnKey: string,\n direction: SortDirection,\n isMultiSort: boolean,\n setSortColumns: React.Dispatch<React.SetStateAction<readonly SortColumn[]>>,\n sortColumnsRef: React.MutableRefObject<readonly SortColumn[]>\n) => {\n let currentSortColumn: SortColumn | undefined;\n\n const updatedSortColumns = sortColumnsRef.current.filter((column) => {\n const isCurrentColumn = column.columnKey === columnKey;\n if (isCurrentColumn) {\n currentSortColumn = column;\n }\n return !isCurrentColumn;\n });\n\n // sorted column exists and is descending -> remove it to reset sorting\n if (currentSortColumn && currentSortColumn.direction === 'DESC') {\n setSortColumns(updatedSortColumns);\n sortColumnsRef.current = updatedSortColumns;\n } else {\n // new sort column or changed direction\n if (isMultiSort) {\n setSortColumns([...updatedSortColumns, { columnKey, direction }]);\n sortColumnsRef.current = [...updatedSortColumns, { columnKey, direction }];\n } else {\n setSortColumns([{ columnKey, direction }]);\n sortColumnsRef.current = [{ columnKey, direction }];\n }\n }\n};\n\n/* ----------------------------- Data grid mapping ---------------------------- */\nexport const frameToRecords = (frame: DataFrame): TableRow[] => {\n const fnBody = `\n const rows = Array(frame.length);\n const values = frame.fields.map(f => f.values);\n let rowCount = 0;\n for (let i = 0; i < frame.length; i++) {\n rows[rowCount] = {\n __depth: 0,\n __index: i,\n ${frame.fields.map((field, fieldIdx) => `${JSON.stringify(getDisplayName(field))}: values[${fieldIdx}][i]`).join(',')}\n };\n rowCount += 1;\n if (rows[rowCount-1]['Nested frames']){\n const childFrame = rows[rowCount-1]['Nested frames'];\n rows[rowCount] = {__depth: 1, __index: i, data: childFrame[0]}\n rowCount += 1;\n }\n }\n return rows;\n `;\n\n // Creates a function that converts a DataFrame into an array of TableRows\n // Uses new Function() for performance as it's faster than creating rows using loops\n const convert = new Function('frame', fnBody) as unknown as FrameToRowsConverter;\n return convert(frame);\n};\n\nexport interface MapFrameToGridOptions extends TableNGProps {\n columnTypes: ColumnTypes;\n columnWidth: number | string;\n crossFilterOrder: React.MutableRefObject<string[]>;\n crossFilterRows: React.MutableRefObject<{ [key: string]: TableRow[] }>;\n defaultLineHeight: number;\n defaultRowHeight: number;\n expandedRows: number[];\n filter: FilterType;\n headerCellRefs: React.MutableRefObject<Record<string, HTMLDivElement>>;\n isCountRowsSet: boolean;\n ctx: CanvasRenderingContext2D;\n onSortByChange?: (sortBy: TableSortByFieldState[]) => void;\n rows: TableRow[];\n setContextMenuProps: (props: { value: string; top?: number; left?: number; mode?: TableCellInspectorMode }) => void;\n setFilter: React.Dispatch<React.SetStateAction<FilterType>>;\n setIsInspecting: (isInspecting: boolean) => void;\n setSortColumns: React.Dispatch<React.SetStateAction<readonly SortColumn[]>>;\n sortColumnsRef: React.MutableRefObject<readonly SortColumn[]>;\n styles: { cell: string; cellWrapped: string; dataGrid: string };\n textWraps: Record<string, boolean>;\n theme: GrafanaTheme2;\n showTypeIcons?: boolean;\n}\n\n/* ----------------------------- Data grid comparator ---------------------------- */\n// The numeric: true option is used to sort numbers as strings correctly. It recognizes numeric sequences\n// within strings and sorts numerically instead of lexicographically.\nconst compare = new Intl.Collator('en', { sensitivity: 'base', numeric: true }).compare;\nexport function getComparator(sortColumnType: FieldType): Comparator {\n switch (sortColumnType) {\n // Handle sorting for frame type fields (sparklines)\n case FieldType.frame:\n return (a, b) => {\n // @ts-ignore The values are DataFrameWithValue\n return (a?.value ?? 0) - (b?.value ?? 0);\n };\n case FieldType.time:\n case FieldType.number:\n case FieldType.boolean:\n return (a, b) => {\n if (a === b) {\n return 0;\n }\n if (a == null) {\n return -1;\n }\n if (b == null) {\n return 1;\n }\n return Number(a) - Number(b);\n };\n case FieldType.string:\n case FieldType.enum:\n default:\n return (a, b) => compare(String(a ?? ''), String(b ?? ''));\n }\n}\n\n/* ---------------------------- Miscellaneous ---------------------------- */\n/**\n * Migrates table cell display mode to new object format.\n *\n * @param displayMode The display mode of the cell\n * @returns TableCellOptions object in the correct format\n * relative to the old display mode.\n */\nexport function migrateTableDisplayModeToCellOptions(displayMode: TableCellDisplayMode): TableCellOptions {\n switch (displayMode) {\n // In the case of the gauge we move to a different option\n case 'basic':\n case 'gradient-gauge':\n case 'lcd-gauge':\n let gaugeMode = BarGaugeDisplayMode.Basic;\n\n if (displayMode === 'gradient-gauge') {\n gaugeMode = BarGaugeDisplayMode.Gradient;\n } else if (displayMode === 'lcd-gauge') {\n gaugeMode = BarGaugeDisplayMode.Lcd;\n }\n\n return {\n type: TableCellDisplayMode.Gauge,\n mode: gaugeMode,\n };\n // Also true in the case of the color background\n case 'color-background':\n case 'color-background-solid':\n let mode = TableCellBackgroundDisplayMode.Basic;\n\n // Set the new mode field, somewhat confusingly the\n // color-background mode is for gradient display\n if (displayMode === 'color-background') {\n mode = TableCellBackgroundDisplayMode.Gradient;\n }\n\n return {\n type: TableCellDisplayMode.ColorBackground,\n mode: mode,\n };\n default:\n return {\n // @ts-ignore\n type: displayMode,\n };\n }\n}\n\n/** Returns true if the DataFrame contains nested frames */\nexport const getIsNestedTable = (dataFrame: DataFrame): boolean =>\n dataFrame.fields.some(({ type }) => type === FieldType.nestedFrames);\n\n/** Processes nested table rows */\nexport const processNestedTableRows = (\n rows: TableRow[],\n processParents: (parents: TableRow[]) => TableRow[]\n): TableRow[] => {\n // Separate parent and child rows\n // Array for parentRows: enables sorting and maintains order for iteration\n // Map for childRows: provides O(1) lookup by parent index when reconstructing the result\n const parentRows: TableRow[] = [];\n const childRows: Map<number, TableRow> = new Map();\n\n rows.forEach((row) => {\n if (Number(row.__depth) === 0) {\n parentRows.push(row);\n } else {\n childRows.set(Number(row.__index), row);\n }\n });\n\n // Process parent rows (filter or sort)\n const processedParents = processParents(parentRows);\n\n // Reconstruct the result\n const result: TableRow[] = [];\n processedParents.forEach((row) => {\n result.push(row);\n const childRow = childRows.get(Number(row.__index));\n if (childRow) {\n result.push(childRow);\n }\n });\n\n return result;\n};\n\nexport const getDisplayName = (field: Field): string => {\n return field.state?.displayName ?? field.name;\n};\n"],"names":[],"mappings":";;;;;;;;;;;;;AAuGO,SAAS,uBAEd,CAAA,GAAA,EACA,UACA,EAAA,gBAAA,EACA,UAAU,CACV,EAAA;AACA,EAAA,MAAM,EAAE,KAAA,EAAU,GAAA,UAAA,CAAW,GAAG,CAAA;AAEhC,EAAO,OAAA,CAAC,MAAc,SAAsB,KAAA;AAC1C,IAAA,MAAM,kBAAqB,GAAA,IAAA,CAAK,GAAI,CAAA,SAAA,EAAW,EAAE,CAAA;AACjD,IAAA,MAAM,gBAAgB,OAAU,GAAA,CAAA;AAChC,IAAM,MAAA,QAAA,GAAW,KAAM,CAAA,IAAA,EAAM,kBAAkB,CAAA;AAC/C,IAAM,MAAA,WAAA,GAAc,WAAW,UAAa,GAAA,aAAA;AAC5C,IAAO,OAAA,IAAA,CAAK,GAAI,CAAA,WAAA,EAAa,gBAAgB,CAAA;AAAA,GAC/C;AACF;AAEgB,SAAA,mBAAA,CAAoB,OAAsB,UAAiD,EAAA;AACzG,EAAM,MAAA,YAAA,GAAe,MAAM,UAAW,CAAA,QAAA;AACtC,EAAM,MAAA,UAAA,GAAa,KAAM,CAAA,UAAA,CAAW,IAAK,CAAA,UAAA;AAEzC,EAAA,QAAQ,UAAY;AAAA,IAClB,KAAK,eAAgB,CAAA,EAAA;AACnB,MAAO,OAAA,EAAA;AAAA,IACT,KAAK,eAAgB,CAAA,EAAA;AACnB,MAAO,OAAA,EAAA;AAAA,IACT,KAAK,eAAgB,CAAA,EAAA;AACnB,MAAA,OAAO,KAAM,CAAA,eAAA;AAAA;AAGjB,EAAO,OAAA,KAAA,CAAM,YAAe,GAAA,CAAA,GAAI,YAAe,GAAA,UAAA;AACjD;AAMO,SAAS,YACd,CAAA,GAAA,EACA,IACA,EAAA,YAAA,EACA,kBACA,UAOQ,EAAA;AACR,EAAA,IAAI,QAAW,GAAA,CAAA;AACf,EAAA,IAAI,WAAc,GAAA,EAAA;AAElB,EAAA,KAAA,MAAW,OAAO,GAAK,EAAA;AACrB,IAAA,IACE,UAAW,CAAA,WAAA,CAAY,GAAG,CAAA,KAAM,UAAU,MAC1C,IAAA,UAAA,CAAW,SAAU,CAAA,GAAG,KACxB,UAAW,CAAA,gBAAA,CAAiB,GAAG,CAAA,KAAM,qBAAqB,KAC1D,EAAA;AACA,MAAM,MAAA,QAAA,GAAW,IAAI,GAAG,CAAA;AAExB,MAAA,IAAI,YAAY,IAAM,EAAA;AACpB,QAAA,MAAM,YAAe,GAAA,UAAA,CAAW,YAAa,CAAA,GAAG,CAAI,GAAA,YAAA;AACpD,QAAM,MAAA,WAAA,GAAc,SAAS,MAAS,GAAA,YAAA;AAEtC,QAAA,IAAI,cAAc,QAAU,EAAA;AAC1B,UAAW,QAAA,GAAA,WAAA;AACX,UAAc,WAAA,GAAA,GAAA;AAAA;AAChB;AACF;AACF;AAGF,EAAO,OAAA,WAAA,KAAgB,EAAK,GAAA,gBAAA,GAAmB,IAAK,CAAA,GAAA,CAAI,WAAW,CAAa,EAAA,UAAA,CAAW,YAAa,CAAA,WAAW,CAAC,CAAA;AACtH;AAEgB,SAAA,UAAA,CAAW,KAAa,WAA8C,EAAA;AACpF,EAAO,OAAA,WAAA,CAAY,GAAG,CAAA,KAAM,SAAU,CAAA,MAAA;AACxC;AAEgB,SAAA,kBAAA,CACd,GACA,EAAA,GAAA,EACA,WACA,EAAA,cAAA,EACA,GACA,EAAA,UAAA,EACA,gBACA,EAAA,OAAA,EACA,QACA,EAAA,KAAA,EACA,QACS,EAAA;AApMX,EAAA,IAAA,EAAA,EAAA,EAAA,EAAA,EAAA;AAqME,EAAA,MAAM,eAAc,EAAM,GAAA,CAAA,EAAA,GAAA,CAAA,EAAA,GAAA,KAAA,CAAA,MAAA,KAAN,mBAAc,MAAd,KAAA,IAAA,GAAA,KAAA,CAAA,GAAA,EAAA,CAAsB,YAAtB,IAAiC,GAAA,EAAA,GAAA,KAAA;AAIrD,EAAI,IAAA,QAAA,IAAY,eAAe,QAAa,KAAA,oBAAA,CAAqB,SAAS,CAAC,UAAA,CAAW,GAAK,EAAA,WAAW,CAAG,EAAA;AACvG,IAAO,OAAA,KAAA;AAAA;AAGT,EAAO,OAAA,IAAA;AACT;AAEO,SAAS,aAAa,KAAwC,EAAA;AACnE,EAAA,IAAI,CAAC,KAAO,EAAA;AACV,IAAO,OAAA,YAAA;AAAA;AAGT,EAAI,IAAA,KAAA,CAAM,OAAO,MAAQ,EAAA;AACvB,IAAM,MAAA,MAAA,GAAgC,MAAM,MAAO,CAAA,MAAA;AAEnD,IAAA,QAAQ,OAAO,KAAO;AAAA,MACpB,KAAK,OAAA;AACH,QAAO,OAAA,UAAA;AAAA,MACT,KAAK,MAAA;AACH,QAAO,OAAA,YAAA;AAAA,MACT,KAAK,QAAA;AACH,QAAO,OAAA,QAAA;AAAA;AACX;AAGF,EAAI,IAAA,KAAA,CAAM,IAAS,KAAA,SAAA,CAAU,MAAQ,EAAA;AACnC,IAAO,OAAA,UAAA;AAAA;AAGT,EAAO,OAAA,YAAA;AACT;AAEA,MAAM,kBAA2C,GAAA,EAAE,IAAM,EAAA,oBAAA,CAAqB,IAAK,EAAA;AAE5E,SAAS,eAAe,KAAgC,EAAA;AA3O/D,EAAA,IAAA,EAAA,EAAA,EAAA,EAAA,EAAA;AA4OE,EAAA,IAAA,CAAI,EAAM,GAAA,KAAA,CAAA,MAAA,CAAO,MAAb,KAAA,IAAA,GAAA,KAAA,CAAA,GAAA,EAAA,CAAqB,WAAa,EAAA;AACpC,IAAA,OAAO,oCAAqC,CAAA,CAAA,EAAA,GAAA,KAAA,CAAM,MAAO,CAAA,MAAA,KAAb,mBAAqB,WAAW,CAAA;AAAA;AAG9E,EAAA,IAAI,EAAC,CAAA,EAAA,GAAA,KAAA,CAAM,MAAO,CAAA,MAAA,KAAb,mBAAqB,WAAa,CAAA,EAAA;AACrC,IAAO,OAAA,kBAAA;AAAA;AAGT,EAAO,OAAA,KAAA,CAAM,OAAO,MAAO,CAAA,WAAA;AAC7B;AAQgB,SAAA,kBAAA,CACd,KACA,EAAA,YAAA,EACA,QAC8B,EAAA;AAjQhC,EAAA,IAAA,EAAA;AAkQE,EAAI,IAAA,eAAA,GAAA,CAAkB,EAAM,GAAA,KAAA,CAAA,KAAA,KAAN,IAAa,GAAA,KAAA,CAAA,GAAA,EAAA,CAAA,gBAAA;AAEnC,EAAA,IAAI,eAAiB,EAAA;AAEnB,IAAA,IAAI,uBAAuB,eAAe,CAAA,CAAE,SAAS,sBAAuB,CAAA,YAAY,EAAE,MAAQ,EAAA;AAChG,MAAkB,eAAA,GAAA,EAAE,GAAG,YAAa,EAAA;AACpC,MAAA,KAAA,CAAM,MAAO,gBAAmB,GAAA,eAAA;AAAA;AAElC,IAAO,OAAA,eAAA;AAAA,GACF,MAAA;AAEL,IAAkB,eAAA,GAAA,EAAE,GAAG,YAAa,EAAA;AACpC,IAAA,MAAM,WAAW,IAAK,CAAA,GAAA,CAAI,MAAM,MAAO,CAAA,MAAA,EAAQ,WAAW,GAAI,CAAA;AAE9D,IAAA,KAAA,IAAS,CAAI,GAAA,QAAA,GAAW,CAAG,EAAA,CAAA,GAAI,UAAU,CAAK,EAAA,EAAA;AAC5C,MAAA,MAAM,mBAAmB,KAAM,CAAA,OAAA,CAAS,KAAM,CAAA,MAAA,CAAO,CAAC,CAAC,CAAA;AACvD,MAAA,IAAI,uBAAuB,eAAe,CAAA,CAAE,SAAS,sBAAuB,CAAA,gBAAgB,EAAE,MAAQ,EAAA;AACpG,QAAA,eAAA,CAAgB,OAAO,YAAa,CAAA,IAAA;AAAA;AACtC;AAGF,IAAA,IAAI,MAAM,KAAO,EAAA;AACf,MAAA,KAAA,CAAM,MAAM,gBAAmB,GAAA,eAAA;AAAA,KAC1B,MAAA;AACL,MAAM,KAAA,CAAA,KAAA,GAAQ,EAAE,gBAAA,EAAkB,eAAgB,EAAA;AAAA;AAGpD,IAAO,OAAA,eAAA;AAAA;AAEX;AAGgB,SAAA,eAAA,CAAgB,IAAkB,EAAA,KAAA,EAAc,OAA8C,EAAA;AAC5G,EAAA,IAAI,YAAY,KAAW,CAAA,EAAA;AACzB,IAAO,OAAA,EAAA;AAAA;AAGT,EAAI,IAAA,KAAA,CAAM,IAAS,KAAA,SAAA,CAAU,MAAQ,EAAA;AACnC,IAAO,OAAA,EAAA;AAAA;AAIT,EAAA,IAAI,CAAC,OAAQ,CAAA,OAAA,IAAW,CAAC,OAAA,CAAQ,QAAQ,MAAQ,EAAA;AAC/C,IAAO,OAAA,EAAA;AAAA;AAIT,EAAA,IAAI,OAAQ,CAAA,MAAA,IAAU,OAAQ,CAAA,MAAA,CAAO,SAAS,CAAG,EAAA;AAC/C,IAAA,IAAI,CAAC,OAAQ,CAAA,MAAA,CAAO,QAAS,CAAA,KAAA,CAAM,IAAI,CAAG,EAAA;AACxC,MAAO,OAAA,EAAA;AAAA;AACT;AAGF,EAAM,MAAA,IAAA,GAAO,OAAQ,CAAA,OAAA,CAAQ,CAAC,CAAA;AAC9B,EAAA,MAAM,QAAQ,WAAY,CAAA;AAAA,IACxB,KAAO,EAAA;AAAA,MACL,GAAG,KAAA;AAAA,MACH,MAAA,EAAQ,KAAK,GAAI,CAAA,CAAC,QAAQ,GAAI,CAAA,cAAA,CAAe,KAAK,CAAC,CAAC;AAAA,KACtD;AAAA,IACA,UAAU,OAAQ,CAAA;AAAA,GACnB,EAAE,IAAI,CAAA;AAEP,EAAA,MAAM,cAAiB,GAAA,sBAAA,CAAuB,KAAM,CAAA,OAAA,CAAS,KAAK,CAAC,CAAA;AAEnE,EAAO,OAAA,cAAA;AACT;AAEa,MAAA,eAAA,GAAkB,CAAC,cAA6C,MAAA;AAAA,EAC3E,YAAY,GAAI,CAAA;AAAA,IACd,OAAS,EAAA,MAAA;AAAA,IACT,gBAAgB,cAAkB,IAAA;AAAA,GACnC;AACH,CAAA;AAGA,MAAM,+BAAkC,GAAA,EAAA;AACxC,MAAM,kCAAqC,GAAA,EAAA;AAC3C,MAAM,kCAAqC,GAAA,CAAA;AAE3B,SAAA,aAAA,CACd,KACA,EAAA,WAAA,EACA,YACY,EAAA;AArVd,EAAA,IAAA,EAAA;AAuVE,EAAM,MAAA,4BAAA,GAA+B,iBAAiB,KAAM,CAAA,MAAA,CAAO,WAAW,OAAS,EAAA,KAAA,CAAM,MAAO,CAAA,MAAA,CAAO,KAAK,CAAA;AAGhH,EAAM,MAAA,eAAA,GAAkB,KAAM,CAAA,MAAA,GAAS,CAAI,GAAA,CAAA,GAAA;AAG3C,EAAA,IAAI,SAAgC,GAAA,KAAA,CAAA;AACpC,EAAA,IAAI,OAA8B,GAAA,KAAA,CAAA;AAClC,EAAA,IAAI,YAAuB,GAAA,4BAAA;AAE3B,EAAI,IAAA,WAAA,CAAY,IAAS,KAAA,oBAAA,CAAqB,SAAW,EAAA;AACvD,IAAA,SAAA,GAAY,YAAa,CAAA,KAAA;AAAA,GAChB,MAAA,IAAA,WAAA,CAAY,IAAS,KAAA,oBAAA,CAAqB,eAAiB,EAAA;AACpE,IAAA,MAAM,IAAO,GAAA,CAAA,EAAA,GAAA,WAAA,CAAY,IAAZ,KAAA,IAAA,GAAA,EAAA,GAAoB,8BAA+B,CAAA,QAAA;AAEhE,IAAI,IAAA,IAAA,KAAS,+BAA+B,KAAO,EAAA;AACjD,MAAA,SAAA,GAAY,8BAA+B,CAAA,YAAA,CAAa,KAAQ,EAAA,KAAA,CAAM,MAAM,CAAA;AAC5E,MAAA,OAAA,GAAU,SAAU,CAAA,YAAA,CAAa,KAAK,CAAA,CAAE,WAAY,EAAA;AACpD,MAAe,YAAA,GAAA,SAAA,CAAU,aAAa,KAAK,CAAA,CACxC,OAAO,+BAAkC,GAAA,eAAe,EACxD,WAAY,EAAA;AAAA,KACjB,MAAA,IAAW,IAAS,KAAA,8BAAA,CAA+B,QAAU,EAAA;AAC3D,MAAM,MAAA,UAAA,GAAa,UAAU,YAAa,CAAA,KAAK,EAC5C,MAAO,CAAA,kCAAA,GAAqC,eAAe,CAAA,CAC3D,WAAY,EAAA;AACf,MAAM,MAAA,QAAA,GAAW,SAAU,CAAA,YAAA,CAAa,KAAK,CAAA,CAC1C,OAAO,+BAAkC,GAAA,eAAe,CACxD,CAAA,IAAA,CAAK,kCAAkC,CAAA;AAC1C,MAAA,SAAA,GAAY,8BAA+B,CAAA,YAAA,CAAa,KAAQ,EAAA,KAAA,CAAM,MAAM,CAAA;AAC5E,MAAA,OAAA,GAAU,2BAA2B,QAAS,CAAA,WAAA,EAAa,CAAA,EAAA,EAAK,aAAa,KAAK,CAAA,CAAA,CAAA;AAClF,MAAA,YAAA,GAAe,CAA2B,wBAAA,EAAA,QAAA,CAAS,WAAY,EAAC,KAAK,UAAU,CAAA,CAAA,CAAA;AAAA;AACjF;AAGF,EAAO,OAAA,EAAE,SAAW,EAAA,OAAA,EAAS,YAAa,EAAA;AAC5C;AAGa,MAAA,iBAAA,GAAoB,CAAC,OAAqC,KAAA;AACrE,EAAA,OAAO,OAAO,OAAY,KAAA,QAAA,GAAW,OAAU,GAAA,UAAA,CAAW,OAAO,CAAK,IAAA,CAAA;AACxE;AAGa,MAAA,gBAAA,GAAmB,CAAC,eAAA,EAAyB,SAA8B,KAAA;AACtF,EAAM,MAAA,EAAA,GAAK,UAAU,eAAe,CAAA;AACpC,EAAM,MAAA,IAAA,GAAO,UAAU,SAAS,CAAA;AAChC,EAAO,OAAA,SAAA,CAAU,IAAI,EAAI,EAAA,IAAA,EAAM,KAAK,QAAS,EAAA,GAAI,GAAG,CAAA,CAAE,WAAY,EAAA;AACpE;AAMa,MAAA,YAAA,GAAe,CAAC,KAAA,EAAc,MAAmB,KAAA;AAC5D,EAAI,IAAA,KAAA;AACJ,EAAA,IAAI,MAAM,QAAU,EAAA;AAClB,IAAA,KAAA,GAAQ,MAAM,QAAS,CAAA;AAAA,MACrB,aAAe,EAAA;AAAA,KAChB,CAAA;AAAA;AAGH,EAAA,IAAI,CAAC,KAAO,EAAA;AACV,IAAA;AAAA;AAGF,EAAA,KAAA,IAAS,CAAI,GAAA,CAAA,EAAG,CAAI,IAAA,KAAA,IAAA,IAAA,GAAA,KAAA,CAAA,GAAA,KAAA,CAAO,SAAQ,CAAK,EAAA,EAAA;AACtC,IAAI,IAAA,KAAA,CAAM,CAAC,CAAA,CAAE,OAAS,EAAA;AACpB,MAAM,MAAA,WAAA,GAAc,KAAM,CAAA,CAAC,CAAE,CAAA,OAAA;AAE7B,MAAA,KAAA,CAAM,CAAC,CAAA,CAAE,OAAU,GAAA,CAAC,KAAU,KAAA;AAE5B,QAAA,IAAI,EAAE,KAAM,CAAA,OAAA,IAAW,KAAM,CAAA,OAAA,IAAW,MAAM,QAAW,CAAA,EAAA;AACvD,UAAA,KAAA,CAAM,cAAe,EAAA;AACrB,UAAA,WAAA,CAAa,KAAO,EAAA;AAAA,YAClB,KAAA;AAAA,YACA,QAAU,EAAA;AAAA,WACX,CAAA;AAAA;AACH,OACF;AAAA;AACF;AAGF,EAAO,OAAA,KAAA;AACT;AAGO,MAAM,aAAa,CACxB,SAAA,EACA,SACA,EAAA,WAAA,EACA,gBACA,cACG,KAAA;AACH,EAAI,IAAA,iBAAA;AAEJ,EAAA,MAAM,kBAAqB,GAAA,cAAA,CAAe,OAAQ,CAAA,MAAA,CAAO,CAAC,MAAW,KAAA;AACnE,IAAM,MAAA,eAAA,GAAkB,OAAO,SAAc,KAAA,SAAA;AAC7C,IAAA,IAAI,eAAiB,EAAA;AACnB,MAAoB,iBAAA,GAAA,MAAA;AAAA;AAEtB,IAAA,OAAO,CAAC,eAAA;AAAA,GACT,CAAA;AAGD,EAAI,IAAA,iBAAA,IAAqB,iBAAkB,CAAA,SAAA,KAAc,MAAQ,EAAA;AAC/D,IAAA,cAAA,CAAe,kBAAkB,CAAA;AACjC,IAAA,cAAA,CAAe,OAAU,GAAA,kBAAA;AAAA,GACpB,MAAA;AAEL,IAAA,IAAI,WAAa,EAAA;AACf,MAAA,cAAA,CAAe,CAAC,GAAG,kBAAA,EAAoB,EAAE,SAAW,EAAA,SAAA,EAAW,CAAC,CAAA;AAChE,MAAA,cAAA,CAAe,UAAU,CAAC,GAAG,oBAAoB,EAAE,SAAA,EAAW,WAAW,CAAA;AAAA,KACpE,MAAA;AACL,MAAA,cAAA,CAAe,CAAC,EAAE,SAAW,EAAA,SAAA,EAAW,CAAC,CAAA;AACzC,MAAA,cAAA,CAAe,OAAU,GAAA,CAAC,EAAE,SAAA,EAAW,WAAW,CAAA;AAAA;AACpD;AAEJ;AAGa,MAAA,cAAA,GAAiB,CAAC,KAAiC,KAAA;AAC9D,EAAA,MAAM,MAAS,GAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,QAAA,EAQP,MAAM,MAAO,CAAA,GAAA,CAAI,CAAC,KAAO,EAAA,QAAA,KAAa,GAAG,IAAK,CAAA,SAAA,CAAU,eAAe,KAAK,CAAC,CAAC,CAAY,SAAA,EAAA,QAAQ,MAAM,CAAE,CAAA,IAAA,CAAK,GAAG,CAAC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAAA,CAAA;AAc3H,EAAA,MAAM,OAAU,GAAA,IAAI,QAAS,CAAA,OAAA,EAAS,MAAM,CAAA;AAC5C,EAAA,OAAO,QAAQ,KAAK,CAAA;AACtB;AA8BA,MAAM,OAAA,GAAU,IAAI,IAAA,CAAK,QAAS,CAAA,IAAA,EAAM,EAAE,WAAA,EAAa,MAAQ,EAAA,OAAA,EAAS,IAAK,EAAC,CAAE,CAAA,OAAA;AACzE,SAAS,cAAc,cAAuC,EAAA;AACnE,EAAA,QAAQ,cAAgB;AAAA;AAAA,IAEtB,KAAK,SAAU,CAAA,KAAA;AACb,MAAO,OAAA,CAAC,GAAG,CAAM,KAAA;AA3gBvB,QAAA,IAAA,EAAA,EAAA,EAAA;AA6gBQ,QAAA,OAAA,CAAA,CAAQ,4BAAG,KAAH,KAAA,IAAA,GAAA,EAAA,GAAY,CAAM,KAAA,CAAA,EAAA,GAAA,CAAA,IAAA,IAAA,GAAA,KAAA,CAAA,GAAA,CAAA,CAAG,UAAH,IAAY,GAAA,EAAA,GAAA,CAAA,CAAA;AAAA,OACxC;AAAA,IACF,KAAK,SAAU,CAAA,IAAA;AAAA,IACf,KAAK,SAAU,CAAA,MAAA;AAAA,IACf,KAAK,SAAU,CAAA,OAAA;AACb,MAAO,OAAA,CAAC,GAAG,CAAM,KAAA;AACf,QAAA,IAAI,MAAM,CAAG,EAAA;AACX,UAAO,OAAA,CAAA;AAAA;AAET,QAAA,IAAI,KAAK,IAAM,EAAA;AACb,UAAO,OAAA,CAAA,CAAA;AAAA;AAET,QAAA,IAAI,KAAK,IAAM,EAAA;AACb,UAAO,OAAA,CAAA;AAAA;AAET,QAAA,OAAO,MAAO,CAAA,CAAC,CAAI,GAAA,MAAA,CAAO,CAAC,CAAA;AAAA,OAC7B;AAAA,IACF,KAAK,SAAU,CAAA,MAAA;AAAA,IACf,KAAK,SAAU,CAAA,IAAA;AAAA,IACf;AACE,MAAO,OAAA,CAAC,CAAG,EAAA,CAAA,KAAM,OAAQ,CAAA,MAAA,CAAO,CAAK,IAAA,IAAA,GAAA,CAAA,GAAA,EAAE,CAAG,EAAA,MAAA,CAAO,CAAK,IAAA,IAAA,GAAA,CAAA,GAAA,EAAE,CAAC,CAAA;AAAA;AAE/D;AAUO,SAAS,qCAAqC,WAAqD,EAAA;AACxG,EAAA,QAAQ,WAAa;AAAA;AAAA,IAEnB,KAAK,OAAA;AAAA,IACL,KAAK,gBAAA;AAAA,IACL,KAAK,WAAA;AACH,MAAA,IAAI,YAAY,mBAAoB,CAAA,KAAA;AAEpC,MAAA,IAAI,gBAAgB,gBAAkB,EAAA;AACpC,QAAA,SAAA,GAAY,mBAAoB,CAAA,QAAA;AAAA,OAClC,MAAA,IAAW,gBAAgB,WAAa,EAAA;AACtC,QAAA,SAAA,GAAY,mBAAoB,CAAA,GAAA;AAAA;AAGlC,MAAO,OAAA;AAAA,QACL,MAAM,oBAAqB,CAAA,KAAA;AAAA,QAC3B,IAAM,EAAA;AAAA,OACR;AAAA;AAAA,IAEF,KAAK,kBAAA;AAAA,IACL,KAAK,wBAAA;AACH,MAAA,IAAI,OAAO,8BAA+B,CAAA,KAAA;AAI1C,MAAA,IAAI,gBAAgB,kBAAoB,EAAA;AACtC,QAAA,IAAA,GAAO,8BAA+B,CAAA,QAAA;AAAA;AAGxC,MAAO,OAAA;AAAA,QACL,MAAM,oBAAqB,CAAA,eAAA;AAAA,QAC3B;AAAA,OACF;AAAA,IACF;AACE,MAAO,OAAA;AAAA;AAAA,QAEL,IAAM,EAAA;AAAA,OACR;AAAA;AAEN;AAGO,MAAM,gBAAmB,GAAA,CAAC,SAC/B,KAAA,SAAA,CAAU,MAAO,CAAA,IAAA,CAAK,CAAC,EAAE,IAAK,EAAA,KAAM,IAAS,KAAA,SAAA,CAAU,YAAY;AAGxD,MAAA,sBAAA,GAAyB,CACpC,IAAA,EACA,cACe,KAAA;AAIf,EAAA,MAAM,aAAyB,EAAC;AAChC,EAAM,MAAA,SAAA,uBAAuC,GAAI,EAAA;AAEjD,EAAK,IAAA,CAAA,OAAA,CAAQ,CAAC,GAAQ,KAAA;AACpB,IAAA,IAAI,MAAO,CAAA,GAAA,CAAI,OAAO,CAAA,KAAM,CAAG,EAAA;AAC7B,MAAA,UAAA,CAAW,KAAK,GAAG,CAAA;AAAA,KACd,MAAA;AACL,MAAA,SAAA,CAAU,GAAI,CAAA,MAAA,CAAO,GAAI,CAAA,OAAO,GAAG,GAAG,CAAA;AAAA;AACxC,GACD,CAAA;AAGD,EAAM,MAAA,gBAAA,GAAmB,eAAe,UAAU,CAAA;AAGlD,EAAA,MAAM,SAAqB,EAAC;AAC5B,EAAiB,gBAAA,CAAA,OAAA,CAAQ,CAAC,GAAQ,KAAA;AAChC,IAAA,MAAA,CAAO,KAAK,GAAG,CAAA;AACf,IAAA,MAAM,WAAW,SAAU,CAAA,GAAA,CAAI,MAAO,CAAA,GAAA,CAAI,OAAO,CAAC,CAAA;AAClD,IAAA,IAAI,QAAU,EAAA;AACZ,MAAA,MAAA,CAAO,KAAK,QAAQ,CAAA;AAAA;AACtB,GACD,CAAA;AAED,EAAO,OAAA,MAAA;AACT;AAEa,MAAA,cAAA,GAAiB,CAAC,KAAyB,KAAA;AA7nBxD,EAAA,IAAA,EAAA,EAAA,EAAA;AA8nBE,EAAA,OAAA,CAAO,EAAM,GAAA,CAAA,EAAA,GAAA,KAAA,CAAA,KAAA,KAAN,IAAa,GAAA,KAAA,CAAA,GAAA,EAAA,CAAA,WAAA,KAAb,YAA4B,KAAM,CAAA,IAAA;AAC3C;;;;"}