@fieldia/viewer 0.9.2 → 0.10.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.
Files changed (98) hide show
  1. package/README.md +20 -1
  2. package/bundle/fieldia.ar.js +3 -0
  3. package/bundle/fieldia.ar.js.map +7 -0
  4. package/bundle/fieldia.de.js +3 -0
  5. package/bundle/fieldia.de.js.map +7 -0
  6. package/bundle/fieldia.fr.js +3 -0
  7. package/bundle/fieldia.fr.js.map +7 -0
  8. package/bundle/fieldia.js +4 -4
  9. package/bundle/fieldia.js.map +4 -4
  10. package/package.json +6 -3
  11. package/src/index.d.mts +4 -0
  12. package/src/index.d.ts +4 -0
  13. package/src/index.js +12 -0
  14. package/src/index.js.map +1 -1
  15. package/src/index.mjs +4 -0
  16. package/src/index.mjs.map +1 -1
  17. package/src/lib/add-language.d.mts +20 -0
  18. package/src/lib/add-language.d.ts +20 -0
  19. package/src/lib/add-language.js +19 -0
  20. package/src/lib/add-language.js.map +1 -0
  21. package/src/lib/add-language.mjs +16 -0
  22. package/src/lib/add-language.mjs.map +1 -0
  23. package/src/lib/dialog.d.mts +7 -2
  24. package/src/lib/dialog.d.ts +7 -2
  25. package/src/lib/dialog.js +16 -21
  26. package/src/lib/dialog.js.map +1 -1
  27. package/src/lib/dialog.mjs +16 -21
  28. package/src/lib/dialog.mjs.map +1 -1
  29. package/src/lib/dom.d.mts +10 -0
  30. package/src/lib/dom.d.ts +10 -0
  31. package/src/lib/dom.js +26 -0
  32. package/src/lib/dom.js.map +1 -1
  33. package/src/lib/dom.mjs +23 -1
  34. package/src/lib/dom.mjs.map +1 -1
  35. package/src/lib/focus-trap.d.mts +2 -0
  36. package/src/lib/focus-trap.d.ts +2 -0
  37. package/src/lib/focus-trap.js +7 -0
  38. package/src/lib/focus-trap.js.map +1 -0
  39. package/src/lib/focus-trap.mjs +3 -0
  40. package/src/lib/focus-trap.mjs.map +1 -0
  41. package/src/lib/labels.d.mts +13 -0
  42. package/src/lib/labels.d.ts +13 -0
  43. package/src/lib/labels.js +103 -277
  44. package/src/lib/labels.js.map +1 -1
  45. package/src/lib/labels.mjs +102 -277
  46. package/src/lib/labels.mjs.map +1 -1
  47. package/src/lib/list-styles.d.mts +1 -1
  48. package/src/lib/list-styles.d.ts +1 -1
  49. package/src/lib/list-styles.js +3 -2
  50. package/src/lib/list-styles.js.map +1 -1
  51. package/src/lib/list-styles.mjs +3 -2
  52. package/src/lib/list-styles.mjs.map +1 -1
  53. package/src/lib/locales/all.d.mts +8 -0
  54. package/src/lib/locales/all.d.ts +8 -0
  55. package/src/lib/locales/all.js +13 -0
  56. package/src/lib/locales/all.js.map +1 -0
  57. package/src/lib/locales/all.mjs +10 -0
  58. package/src/lib/locales/all.mjs.map +1 -0
  59. package/src/lib/locales/ar.d.mts +3 -0
  60. package/src/lib/locales/ar.d.ts +3 -0
  61. package/src/lib/locales/ar.js +74 -0
  62. package/src/lib/locales/ar.js.map +1 -0
  63. package/src/lib/locales/ar.mjs +71 -0
  64. package/src/lib/locales/ar.mjs.map +1 -0
  65. package/src/lib/locales/de.d.mts +3 -0
  66. package/src/lib/locales/de.d.ts +3 -0
  67. package/src/lib/locales/de.js +74 -0
  68. package/src/lib/locales/de.js.map +1 -0
  69. package/src/lib/locales/de.mjs +71 -0
  70. package/src/lib/locales/de.mjs.map +1 -0
  71. package/src/lib/locales/fr.d.mts +3 -0
  72. package/src/lib/locales/fr.d.ts +3 -0
  73. package/src/lib/locales/fr.js +74 -0
  74. package/src/lib/locales/fr.js.map +1 -0
  75. package/src/lib/locales/fr.mjs +71 -0
  76. package/src/lib/locales/fr.mjs.map +1 -0
  77. package/src/lib/look.d.mts +21 -0
  78. package/src/lib/look.d.ts +21 -0
  79. package/src/lib/look.js +84 -0
  80. package/src/lib/look.js.map +1 -0
  81. package/src/lib/look.mjs +79 -0
  82. package/src/lib/look.mjs.map +1 -0
  83. package/src/lib/place.d.mts +35 -0
  84. package/src/lib/place.d.ts +35 -0
  85. package/src/lib/place.js +37 -0
  86. package/src/lib/place.js.map +1 -0
  87. package/src/lib/place.mjs +33 -0
  88. package/src/lib/place.mjs.map +1 -0
  89. package/src/lib/related.js +2 -1
  90. package/src/lib/related.js.map +1 -1
  91. package/src/lib/related.mjs +2 -1
  92. package/src/lib/related.mjs.map +1 -1
  93. package/src/lib/viewer.d.mts +10 -2
  94. package/src/lib/viewer.d.ts +10 -2
  95. package/src/lib/viewer.js +160 -57
  96. package/src/lib/viewer.js.map +1 -1
  97. package/src/lib/viewer.mjs +162 -59
  98. package/src/lib/viewer.mjs.map +1 -1
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
- "sources": ["../../../../tools/script-entry.ts", "../../../../libs/core/src/lib/format/names.ts", "../../../../libs/core/src/lib/format/columns.ts", "../../../../libs/core/src/lib/format/version.ts", "../../../../libs/core/src/lib/expression/evaluator.ts", "../../../../libs/core/src/lib/expression/tokenizer.ts", "../../../../libs/core/src/lib/expression/parser.ts", "../../../../libs/core/src/lib/expression/modifier.ts", "../../../../libs/core/src/lib/format/references.ts", "../../../../libs/core/src/lib/format/check-page.ts", "../../../../libs/core/src/lib/format/translate.ts", "../../../../libs/core/src/lib/expression/evaluateModifier.ts", "../../../../libs/core/src/lib/record/values.ts", "../../../../libs/core/src/lib/record/messages.ts", "../../../../libs/core/src/lib/record/check.ts", "../../../../libs/core/src/lib/record/data-source.ts", "../../../../libs/core/src/lib/record/filter.ts", "../../../../libs/core/src/lib/record/search.ts", "../../../../libs/core/src/lib/record/scheduler.ts", "../../../../libs/core/src/lib/record/memory-data-source.ts", "../../../../libs/core/src/lib/record/form.ts", "../../../../libs/widgets/src/lib/numbers.ts", "../../../../libs/widgets/src/lib/labels.ts", "../../../../libs/widgets/src/lib/relations.ts", "../../../../libs/widgets/src/lib/display.ts", "../../../../libs/widgets/src/lib/lines.ts", "../../../../libs/widgets/src/lib/files.ts", "../../../../libs/widgets/src/lib/progress.ts", "../../../../libs/widgets/src/lib/label.ts", "../../../../libs/widgets/src/lib/statusbar.ts", "../../../../libs/widgets/src/lib/calendar.ts", "../../../../libs/widgets/src/lib/properties.ts", "../../../../libs/widgets/src/lib/extras.ts", "../../../../libs/widgets/src/lib/widgets.ts", "../../../../libs/widgets/src/lib/styles.ts", "../../../../libs/widgets/src/lib/preferences.ts", "../../../../libs/widgets/src/lib/icons.ts", "../../../../libs/viewer/src/lib/dialog.ts", "../../../../libs/viewer/src/lib/related.ts", "../../../../libs/viewer/src/lib/favourites.ts", "../../../../libs/viewer/src/lib/list-groups.ts", "../../../../libs/viewer/src/lib/list-styles.ts", "../../../../libs/viewer/src/lib/custom-filter.ts", "../../../../libs/viewer/src/lib/search-bar.ts", "../../../../libs/viewer/src/lib/list.ts", "../../../../libs/viewer/src/lib/labels.ts", "../../../../libs/viewer/src/lib/viewer.ts"],
4
- "sourcesContent": ["/**\n * What the `<script>` bundle puts on `window.Fieldia`: everything a page with\n * no build step needs to show a form and handle what people enter.\n */\n// The runtime alone: the format's schemas and validation library stay out of a page with no build step.\nexport * from '../libs/core/src/runtime';\nexport * from '@fieldia/widgets';\nexport * from '@fieldia/viewer';\n\ndeclare const __FIELDIA_VERSION__: string;\n/** The version of @fieldia/viewer this bundle was built from. */\nexport const VERSION: string = __FIELDIA_VERSION__;\n", "/** Field names and kinds, apart from the schemas so code that runs a form never carries the validation library. */\n\n/** A field name: what expressions and layout nodes use to refer to a field. */\nexport const FIELD_NAME = /^[A-Za-z_][A-Za-z0-9_]*$/;\n\nexport const FIELD_TYPES = [\n 'char',\n 'text',\n 'html',\n 'integer',\n 'float',\n 'monetary',\n 'boolean',\n 'date',\n 'datetime',\n 'selection',\n 'binary',\n 'image',\n 'many2one',\n 'many2many',\n 'one2many',\n 'reference',\n 'properties',\n 'json',\n] as const;\n\nexport type FieldType = (typeof FIELD_TYPES)[number];\n", "import type { ColumnCount, ColumnsByWidth } from './layout';\n\n/** A section's columns at full width, whichever way they are written. */\nexport function wideColumns(columns: ColumnCount | ColumnsByWidth | undefined): ColumnCount {\n return typeof columns === 'object' ? columns.wide : columns ?? 1;\n}\n", "/** The page format version this build reads and writes. */\nexport const FORMAT_VERSION = '0.1' as const;\n", "/**\n * AST evaluator for modifiers, ported from the React form engine.\n *\n * Python semantics where the React version used JavaScript's: an empty list\n * or string is false, and an empty value is never smaller or larger than\n * anything \u2014 modifiers come from backends that think in Python.\n */\n\nimport type { ASTNode, BinaryOpNode, UnaryOpNode } from './parser';\n\n/**\n * Evaluate an AST node against a context object\n *\n * @param ast - The AST node to evaluate\n * @param context - Object containing field values\n * @returns The result of evaluation\n *\n * @example\n * const ast = { type: 'BinaryOp', operator: '==', left: {...}, right: {...} };\n * const context = { state: 'draft', amount: 100 };\n * evaluate(ast, context); // Returns boolean result\n */\nexport function evaluate(ast: ASTNode, context: Record<string, unknown>): unknown {\n switch (ast.type) {\n case 'BinaryOp':\n return evaluateBinaryOp(ast, context);\n\n case 'UnaryOp':\n return evaluateUnaryOp(ast, context);\n\n case 'Literal':\n return ast.value;\n\n case 'Identifier':\n return getNestedValue(context, ast.name);\n\n default:\n throw new Error(`Unknown AST node type: ${(ast as { type: string }).type}`);\n }\n}\n\n/**\n * Evaluate binary operations\n */\nfunction evaluateBinaryOp(node: BinaryOpNode, context: Record<string, unknown>): unknown {\n const left = normalize(evaluate(node.left, context));\n const right = normalize(evaluate(node.right, context));\n const operator = node.operator.toLowerCase();\n const ordered = left !== null && right !== null;\n\n switch (operator) {\n // Comparison operators\n case '==':\n return left === right;\n\n case '!=':\n case '<>':\n return left !== right;\n\n case '<':\n return ordered && (left as Comparable) < (right as Comparable);\n\n case '>':\n return ordered && (left as Comparable) > (right as Comparable);\n\n case '<=':\n return ordered && (left as Comparable) <= (right as Comparable);\n\n case '>=':\n return ordered && (left as Comparable) >= (right as Comparable);\n\n // In operators\n case 'in':\n return Array.isArray(right) && right.includes(left);\n\n case 'not in':\n return Array.isArray(right) && !right.includes(left);\n\n // Logical operators (use truthiness)\n case 'and':\n return truthy(left) && truthy(right);\n\n case 'or':\n return truthy(left) || truthy(right);\n\n default:\n throw new Error(`Unknown binary operator: ${node.operator}`);\n }\n}\n\n/**\n * Evaluate unary operations\n */\nfunction evaluateUnaryOp(node: UnaryOpNode, context: Record<string, unknown>): unknown {\n const operand = evaluate(node.operand, context);\n const operator = node.operator.toLowerCase();\n\n switch (operator) {\n case 'not':\n return !truthy(operand);\n\n default:\n throw new Error(`Unknown unary operator: ${node.operator}`);\n }\n}\n\n/** What `<` and `>` order: numbers with numbers, strings with strings. */\ntype Comparable = number | string;\n\n/** A missing value compares like None. */\nfunction normalize(value: unknown): unknown {\n return value === undefined ? null : value;\n}\n\n/** Python's truth test: empty lists, strings and objects, 0 and None are false. */\nexport function truthy(value: unknown): boolean {\n if (Array.isArray(value)) return value.length > 0;\n if (value !== null && typeof value === 'object') return Object.keys(value).length > 0;\n return Boolean(value);\n}\n\n/**\n * Get a nested value from an object using dot notation\n *\n * @param obj - The object to traverse\n * @param path - Dot-separated path (e.g., 'partner_id.country_id.name')\n * @returns The value at the path, or undefined if not found\n *\n * @example\n * getNestedValue({ a: { b: { c: 5 } } }, 'a.b.c') // Returns 5\n * getNestedValue({ a: null }, 'a.b.c') // Returns undefined\n */\nfunction getNestedValue(obj: unknown, path: string): unknown {\n const parts = path.split('.');\n let current: unknown = obj;\n\n for (const part of parts) {\n if (current === null || current === undefined) {\n return undefined;\n }\n current = (current as Record<string, unknown>)[part];\n }\n\n return current;\n}\n", "/**\n * Tokenizer for modifier expressions.\n *\n * Ported from the React form engine, with one change in behaviour: a\n * character the language does not know is an error, not something to skip.\n * The React version dropped it silently, so `amount > -5` read as\n * `amount > 5` and `a && b` read as `a b`.\n */\n\nexport type TokenType =\n | 'IDENTIFIER' // Field names, including dotted notation (e.g., partner_id.country_id)\n | 'NUMBER' // Integer or float (e.g., 42, 3.14)\n | 'STRING' // Single or double quoted string (e.g., 'draft', \"draft\")\n | 'LIST' // List literal (e.g., ['draft', 'sent'])\n | 'OPERATOR' // Comparison operators (==, !=, <>, <, >, <=, >=, in, not in)\n | 'LOGICAL' // Logical operators (and, or, not)\n | 'CONSTANT' // True, False, None (and true, false, null)\n | 'PAREN'; // Parentheses ( )\n\nexport interface Token {\n type: TokenType;\n value: string;\n position: number;\n}\n\n/**\n * Tokenizes a Flectra modifier expression.\n *\n * @param expr - The expression string to tokenize\n * @returns Array of tokens\n *\n * @example\n * tokenize(\"state == 'draft'\")\n * // Returns: [\n * // { type: 'IDENTIFIER', value: 'state', position: 0 },\n * // { type: 'OPERATOR', value: '==', position: 1 },\n * // { type: 'STRING', value: \"'draft'\", position: 2 }\n * // ]\n */\n/** The words that are values, not field names. */\nexport const CONSTANTS: ReadonlyMap<string, boolean | null> = new Map<string, boolean | null>([\n ['True', true],\n ['False', false],\n ['None', null],\n ['true', true],\n ['false', false],\n ['null', null],\n]);\n\nexport function tokenize(expr: string): Token[] {\n const tokens: Token[] = [];\n if (!expr) return tokens;\n\n // Alternatives in priority order: \"not in\" before \"not\", operators of two\n // characters before one, a signed number before anything else that could\n // start with a digit. Sticky (`y`), so a position nothing matches is an\n // error instead of a gap.\n const token =\n /(\\(|\\)|==|!=|<=|>=|<>|<|>|not\\s+in\\b|in\\b|and\\b|or\\b|not\\b|\\[[^\\]]*\\]|'[^']*'|\"[^\"]*\"|-?\\d+\\.?\\d*|\\w+(?:\\.\\w+)*)/iy;\n const space = /\\s*/y;\n let at = 0;\n\n for (;;) {\n space.lastIndex = at;\n space.exec(expr);\n at = space.lastIndex;\n if (at >= expr.length) return tokens;\n\n token.lastIndex = at;\n const match = token.exec(expr);\n if (!match) {\n throw new Error(`Unexpected \"${expr[at]}\" at character ${at + 1} of: ${expr}`);\n }\n tokens.push({ type: getTokenType(match[0]), value: match[0], position: tokens.length });\n at = token.lastIndex;\n }\n}\n\n/**\n * Determines the type of a token based on its text value.\n */\nfunction getTokenType(text: string): TokenType {\n const lowerText = text.toLowerCase().trim();\n\n // Python's constants, and their JSON spellings\n if (CONSTANTS.has(text)) {\n return 'CONSTANT';\n }\n\n // Logical operators (case-insensitive)\n if (lowerText === 'and' || lowerText === 'or' || lowerText === 'not') {\n return 'LOGICAL';\n }\n\n // Comparison operators (case-insensitive for word operators)\n if (\n ['==', '!=', '<>', '<', '>', '<=', '>='].includes(text) ||\n lowerText === 'in' ||\n lowerText === 'not in'\n ) {\n return 'OPERATOR';\n }\n\n // Parentheses\n if (text === '(' || text === ')') {\n return 'PAREN';\n }\n\n // Lists (start with '[')\n if (text.startsWith('[')) {\n return 'LIST';\n }\n\n // Strings (start with ' or \")\n if (text.startsWith(\"'\") || text.startsWith('\"')) {\n return 'STRING';\n }\n\n // Numbers (matches integer or float, either sign)\n if (/^-?\\d+\\.?\\d*$/.test(text)) {\n return 'NUMBER';\n }\n\n // Default to identifier\n return 'IDENTIFIER';\n}\n", "/**\n * Expression parser for modifiers, ported from the React form engine.\n *\n * Recursive descent parser that converts tokens into an Abstract Syntax Tree (AST).\n * Implements Python-like operator precedence:\n * 1. OR (lowest precedence)\n * 2. AND\n * 3. NOT\n * 4. Comparison operators (==, !=, <, >, <=, >=, in, not in)\n * 5. Values/Identifiers (highest precedence)\n */\n\nimport { CONSTANTS, type Token } from './tokenizer';\n\n/**\n * AST Node Types\n */\nexport type ASTNode = BinaryOpNode | UnaryOpNode | LiteralNode | IdentifierNode;\n\nexport interface BinaryOpNode {\n type: 'BinaryOp';\n operator: string;\n left: ASTNode;\n right: ASTNode;\n}\n\nexport interface UnaryOpNode {\n type: 'UnaryOp';\n operator: string;\n operand: ASTNode;\n}\n\nexport interface LiteralNode {\n type: 'Literal';\n value: unknown;\n}\n\nexport interface IdentifierNode {\n type: 'Identifier';\n name: string;\n}\n\n/**\n * Recursive Descent Expression Parser\n */\nexport class ExpressionParser {\n private tokens: Token[];\n private position: number = 0;\n\n constructor(tokens: Token[]) {\n this.tokens = tokens;\n }\n\n /**\n * Parse tokens into an AST\n */\n parse(): ASTNode {\n if (this.tokens.length === 0) {\n throw new Error('Cannot parse empty expression');\n }\n\n const ast = this.parseOr();\n\n // Ensure all tokens were consumed\n if (!this.isAtEnd()) {\n throw new Error(`Unexpected token at position ${this.position}: ${this.peek()?.value}`);\n }\n\n return ast;\n }\n\n /**\n * Parse OR expressions (lowest precedence)\n * or_expr: and_expr ('or' and_expr)*\n */\n private parseOr(): ASTNode {\n let left = this.parseAnd();\n\n while (this.matchLogical('or')) {\n const operator = this.previous().value;\n const right = this.parseAnd();\n left = {\n type: 'BinaryOp',\n operator: operator.toLowerCase(),\n left,\n right,\n };\n }\n\n return left;\n }\n\n /**\n * Parse AND expressions\n * and_expr: not_expr ('and' not_expr)*\n */\n private parseAnd(): ASTNode {\n let left = this.parseNot();\n\n while (this.matchLogical('and')) {\n const operator = this.previous().value;\n const right = this.parseNot();\n left = {\n type: 'BinaryOp',\n operator: operator.toLowerCase(),\n left,\n right,\n };\n }\n\n return left;\n }\n\n /**\n * Parse NOT expressions\n * not_expr: 'not' comparison | comparison\n */\n private parseNot(): ASTNode {\n if (this.matchLogical('not')) {\n const operator = this.previous().value;\n const operand = this.parseComparison();\n return {\n type: 'UnaryOp',\n operator: operator.toLowerCase(),\n operand,\n };\n }\n\n return this.parseComparison();\n }\n\n /**\n * Parse comparison expressions\n * comparison: value (comp_op value)?\n * comp_op: '==' | '!=' | '<>' | '<' | '>' | '<=' | '>=' | 'in' | 'not in'\n */\n private parseComparison(): ASTNode {\n const left = this.parseValue();\n\n const compOperators = ['==', '!=', '<>', '<', '>', '<=', '>=', 'in', 'not in'];\n if (this.matchOperator(...compOperators)) {\n const operator = this.previous().value;\n const right = this.parseValue();\n return {\n type: 'BinaryOp',\n operator: operator.toLowerCase(),\n left,\n right,\n };\n }\n\n // If no comparison operator, return value as-is (truthiness check)\n return left;\n }\n\n /**\n * Parse value expressions (highest precedence)\n * value: '(' or_expr ')' | literal | identifier\n */\n private parseValue(): ASTNode {\n // Parenthesized expression\n if (this.match('PAREN', '(')) {\n const expr = this.parseOr();\n this.consume('PAREN', ')', 'Expected closing parenthesis');\n return expr;\n }\n\n // String literal\n if (this.check('STRING')) {\n const token = this.advance();\n // Remove quotes\n const value = token.value.slice(1, -1);\n return { type: 'Literal', value };\n }\n\n // True, False, None\n if (this.check('CONSTANT')) {\n const token = this.advance();\n return { type: 'Literal', value: CONSTANTS.get(token.value) ?? null };\n }\n\n // Number literal\n if (this.check('NUMBER')) {\n const token = this.advance();\n return { type: 'Literal', value: Number(token.value) };\n }\n\n // List literal\n if (this.check('LIST')) {\n const token = this.advance();\n const value = parseListLiteral(token.value);\n return { type: 'Literal', value };\n }\n\n // Identifier\n if (this.check('IDENTIFIER')) {\n const token = this.advance();\n return { type: 'Identifier', name: token.value };\n }\n\n throw new Error(`Unexpected token: ${this.peek()?.value || 'EOF'}`);\n }\n\n // ========== Helper Methods ==========\n\n /**\n * Check if current token matches any of the given types/values\n */\n private match(type: string, ...values: string[]): boolean {\n if (this.check(type)) {\n if (values.length === 0) {\n this.advance();\n return true;\n }\n const token = this.peek();\n if (token && values.includes(token.value)) {\n this.advance();\n return true;\n }\n }\n return false;\n }\n\n /**\n * Match logical operators (case-insensitive)\n */\n private matchLogical(...operators: string[]): boolean {\n const token = this.peek();\n if (token && token.type === 'LOGICAL') {\n const lowerValue = token.value.toLowerCase();\n if (operators.map(op => op.toLowerCase()).includes(lowerValue)) {\n this.advance();\n return true;\n }\n }\n return false;\n }\n\n /**\n * Match comparison operators (case-insensitive)\n */\n private matchOperator(...operators: string[]): boolean {\n const token = this.peek();\n if (token && token.type === 'OPERATOR') {\n const lowerValue = token.value.toLowerCase();\n if (operators.map(op => op.toLowerCase()).includes(lowerValue)) {\n this.advance();\n return true;\n }\n }\n return false;\n }\n\n /**\n * Check if current token has given type\n */\n private check(type: string): boolean {\n const token = this.peek();\n return token?.type === type;\n }\n\n /**\n * Consume current token and advance\n */\n private advance(): Token {\n if (!this.isAtEnd()) {\n this.position++;\n }\n return this.previous();\n }\n\n /**\n * Get current token without advancing\n */\n private peek(): Token | null {\n if (this.isAtEnd()) {\n return null;\n }\n return this.tokens[this.position];\n }\n\n /**\n * Get previous token\n */\n private previous(): Token {\n return this.tokens[this.position - 1];\n }\n\n /**\n * Check if we've consumed all tokens\n */\n private isAtEnd(): boolean {\n return this.position >= this.tokens.length;\n }\n\n /**\n * Consume a token of specific type/value or throw error\n */\n private consume(type: string, value: string, message: string): Token {\n if (this.check(type)) {\n const token = this.peek();\n if (token && token.value === value) {\n return this.advance();\n }\n }\n throw new Error(message);\n }\n}\n\n/**\n * Parse a list literal string into an array\n * Example: \"['draft', 'sent']\" -> ['draft', 'sent']\n */\nfunction parseListLiteral(listStr: string): unknown[] {\n try {\n // Remove brackets\n const content = listStr.slice(1, -1).trim();\n if (!content) {\n return [];\n }\n\n // Split by comma and parse each element\n const elements: unknown[] = [];\n let current = '';\n let inString = false;\n let stringChar = '';\n\n for (let i = 0; i < content.length; i++) {\n const char = content[i];\n\n if ((char === \"'\" || char === '\"') && (i === 0 || content[i - 1] !== '\\\\')) {\n if (!inString) {\n inString = true;\n stringChar = char;\n } else if (char === stringChar) {\n inString = false;\n stringChar = '';\n }\n }\n\n if (char === ',' && !inString) {\n elements.push(parseElement(current.trim()));\n current = '';\n } else {\n current += char;\n }\n }\n\n if (current.trim()) {\n elements.push(parseElement(current.trim()));\n }\n\n return elements;\n } catch (error) {\n // A list that cannot be read is a syntax error, not an empty list.\n throw new Error(`Cannot read the list ${listStr}`, { cause: error });\n }\n}\n\n/**\n * Parse a single element from a list\n */\nfunction parseElement(element: string): unknown {\n // String\n if ((element.startsWith(\"'\") && element.endsWith(\"'\")) ||\n (element.startsWith('\"') && element.endsWith('\"'))) {\n return element.slice(1, -1);\n }\n\n // Number\n if (!isNaN(Number(element))) {\n return Number(element);\n }\n\n // Boolean\n if (element.toLowerCase() === 'true') return true;\n if (element.toLowerCase() === 'false') return false;\n\n // Default to string\n return element;\n}\n", "import type { Modifier } from '../format/layout';\nimport { evaluate, truthy } from './evaluator';\nimport { ExpressionParser, type ASTNode } from './parser';\nimport { tokenize } from './tokenizer';\n\n/** A modifier read once, ready to evaluate against a record's values. */\nexport interface CompiledModifier {\n readonly source: Modifier | undefined;\n /** The fields it reads, by their first name, in order of appearance. */\n readonly fields: readonly string[];\n evaluate(values: Readonly<Record<string, unknown>>): boolean;\n}\n\n/**\n * Read a modifier. `true`, `false` and a missing modifier become constants;\n * an expression is parsed now, so a mistake surfaces here and not on the\n * first keystroke. Throws when the expression cannot be read.\n */\nexport function compileModifier(modifier: Modifier | undefined): CompiledModifier {\n if (typeof modifier !== 'string') {\n const value = modifier === true;\n return { source: modifier, fields: [], evaluate: () => value };\n }\n const ast = new ExpressionParser(tokenize(modifier)).parse();\n return {\n source: modifier,\n fields: fieldsRead(ast),\n evaluate(values) {\n try {\n return truthy(evaluate(ast, values));\n } catch {\n return false;\n }\n },\n };\n}\n\nfunction fieldsRead(ast: ASTNode): string[] {\n const names: string[] = [];\n const visit = (node: ASTNode): void => {\n switch (node.type) {\n case 'Identifier': {\n const root = node.name.split('.')[0];\n if (!names.includes(root)) names.push(root);\n return;\n }\n case 'BinaryOp':\n visit(node.left);\n visit(node.right);\n return;\n case 'UnaryOp':\n visit(node.operand);\n return;\n default:\n return;\n }\n };\n visit(ast);\n return names;\n}\n", "import type { Field, Fields, FilterItem, LineField, LineKinds } from './field';\nimport type { FieldNode, LayoutNode, ListNode, RootLayout, SheetNode, TabsNode } from './layout';\nimport type { Page } from './page';\nimport { compileModifier } from '../expression/modifier';\n\nexport interface PageIssue {\n /** Where the problem is, as a path into the page: `layout.children[0].field`. */\n path: string;\n message: string;\n}\n\nexport type PageValidation = { ok: true; page: Page } | { ok: false; issues: PageIssue[] };\n\nconst has = (record: object, key: string) => Object.prototype.hasOwnProperty.call(record, key);\n\n/** The second pass of every check: ids unique, every name defined, every condition readable. */\nexport class ReferenceCheck {\n private readonly issues: PageIssue[] = [];\n private readonly ids = new Map<string, string>();\n\n constructor(private readonly page: Page) {}\n\n run(): PageIssue[] {\n this.checkFields(this.page.fields, 'fields');\n this.walkRoot(this.page.layout, 'layout');\n return this.issues;\n }\n\n private report(path: string, message: string) {\n this.issues.push({ path, message });\n }\n\n private claim(id: string, path: string) {\n const first = this.ids.get(id);\n if (first !== undefined) this.report(path, `duplicate id \"${id}\", also used at ${first}`);\n else this.ids.set(id, path);\n }\n\n /** The field a reference names, or a reported issue and undefined. */\n private need(name: string, path: string, scope: Record<string, Field | LineField> = this.page.fields) {\n if (has(scope, name)) return scope[name];\n this.report(path, `no field \"${name}\"`);\n return undefined;\n }\n\n /** Every modifier on `owner` must read, and read only fields of this page. */\n private checkModifiers(owner: object, path: string, keys: readonly string[] = ['invisible']) {\n for (const key of keys) {\n const value = (owner as Record<string, unknown>)[key];\n if (typeof value !== 'string') continue;\n let fields: readonly string[];\n try {\n fields = compileModifier(value).fields;\n } catch (error) {\n this.report(`${path}.${key}`, `cannot read \"${value}\": ${(error as Error).message}`);\n continue;\n }\n for (const name of fields) {\n if (!has(this.page.fields, name)) {\n this.report(`${path}.${key}`, `\"${value}\" reads \"${name}\", which is not a field of this page`);\n }\n }\n }\n }\n\n private checkFields(fields: Fields | Record<string, LineField>, base: string) {\n for (const [name, def] of Object.entries(fields)) {\n const path = `${base}.${name}`;\n if (def.type === 'monetary' && def.currencyField !== undefined) {\n const currency = this.need(def.currencyField, `${path}.currencyField`, fields);\n if (currency && !['many2one', 'selection', 'char'].includes(currency.type)) {\n this.report(\n `${path}.currencyField`,\n `\"${def.currencyField}\" is a ${currency.type}; a currency field must be a many2one, selection or char`\n );\n }\n }\n if ((def.type === 'many2one' || def.type === 'many2many') && def.filter) {\n // Groups nest: each valueFrom inside them must name a field too.\n const walk = (item: FilterItem, at: string): void => {\n if ('any' in item) return item.any.forEach((inner, i) => walk(inner, `${at}.any[${i}]`));\n if ('all' in item) return item.all.forEach((inner, i) => walk(inner, `${at}.all[${i}]`));\n if (item.valueFrom !== undefined) this.need(item.valueFrom, `${at}.valueFrom`, fields);\n };\n def.filter.forEach((item, i) => {\n walk(item, `${path}.filter[${i}]`);\n });\n }\n if (def.type === 'properties' && def.definitions) {\n const seen = new Set<string>();\n def.definitions.forEach((property, i) => {\n if (property.type === 'selection' && !property.options) {\n this.report(`${path}.definitions[${i}].options`, 'a choice property needs its choices');\n }\n if (seen.has(property.name)) this.report(`${path}.definitions[${i}].name`, `\"${property.name}\" is named twice`);\n seen.add(property.name);\n });\n }\n if (def.type === 'one2many') {\n this.checkFields(def.fields, `${path}.fields`);\n if (def.lineKinds) this.checkLineKinds(name, def.lineKinds, def.fields, `${path}.lineKinds`);\n if (def.sequenceField !== undefined) {\n const sequence = def.fields[def.sequenceField];\n if (!sequence) this.report(`${path}.sequenceField`, `\"${def.sequenceField}\" is not a field of the lines of \"${name}\"`);\n else if (sequence.type !== 'integer') {\n this.report(`${path}.sequenceField`, `\"${def.sequenceField}\" is a ${sequence.type}; the field that keeps the order of lines must be an integer`);\n }\n }\n }\n }\n }\n\n private checkLineKinds(field: string, kinds: LineKinds, lineFields: Record<string, LineField>, path: string) {\n const kindField = lineFields[kinds.field];\n if (!kindField) this.report(`${path}.field`, `\"${kinds.field}\" is not a field of the lines of \"${field}\"`);\n else if (kindField.type !== 'selection' && kindField.type !== 'char') {\n this.report(`${path}.field`, `\"${kinds.field}\" is a ${kindField.type}; the field that says what a line is must be a selection or char`);\n } else if (kindField.type === 'selection') {\n for (const which of ['section', 'note'] as const) {\n const value = kinds[which] ?? which;\n if (!kindField.options.some((o) => o.value === value)) this.report(`${path}.${which}`, `\"${kinds.field}\" has no option \"${value}\"`);\n }\n }\n const text = lineFields[kinds.text];\n if (!text) this.report(`${path}.text`, `\"${kinds.text}\" is not a field of the lines of \"${field}\"`);\n else if (text.type !== 'char' && text.type !== 'text') {\n this.report(`${path}.text`, `\"${kinds.text}\" is a ${text.type}; a section's or note's text must be a char or text field`);\n }\n }\n\n private walkRoot(root: RootLayout, path: string) {\n if (root.type === 'tabs') return this.walkNode(root, path);\n this.claim(root.id, path);\n if (root.type === 'sheet') return this.walkSheet(root, path);\n if (root.type === 'sections') return this.walkChildren(root.children, path);\n if (root.type === 'list') return this.walkList(root, path);\n root.children.forEach((step, i) => {\n const stepPath = `${path}.children[${i}]`;\n this.claim(step.id, stepPath);\n this.checkModifiers(step, stepPath);\n this.walkChildren(step.children, stepPath);\n });\n }\n\n private walkList(list: ListNode, path: string) {\n if (this.page.data.kind !== 'record') this.report('data', 'a list shows records: its data needs kind \"record\" and a model');\n list.columns.forEach((name, i) => this.need(name, `${path}.columns[${i}]`));\n list.sort?.forEach((order, i) => this.need(order.field, `${path}.sort[${i}].field`));\n list.searchFields?.forEach((name, i) => this.need(name, `${path}.searchFields[${i}]`));\n list.groupBy?.forEach((name, i) => this.need(name, `${path}.groupBy[${i}]`));\n // A list's filters are about its own records: their fields are the page's, and there is no record to take a value from.\n const walk = (item: FilterItem, at: string): void => {\n if ('any' in item) return item.any.forEach((inner, i) => walk(inner, `${at}.any[${i}]`));\n if ('all' in item) return item.all.forEach((inner, i) => walk(inner, `${at}.all[${i}]`));\n this.need(item.field, `${at}.field`);\n if (item.valueFrom !== undefined) this.report(`${at}.valueFrom`, \"a list's filter compares with values, not with another field\");\n };\n const named = new Set<string>();\n list.filters?.forEach((filter, i) => {\n this.claim(filter.id, `${path}.filters[${i}]`);\n named.add(filter.id);\n filter.filter.forEach((item, j) => walk(item, `${path}.filters[${i}].filter[${j}]`));\n });\n list.defaultFilters?.forEach((id, i) => {\n if (!named.has(id)) this.report(`${path}.defaultFilters[${i}]`, `no filter \"${id}\" in this list`);\n });\n list.actions?.forEach((button, i) => this.claim(button.id, `${path}.actions[${i}]`));\n }\n\n private walkChildren(children: LayoutNode[], path: string) {\n children.forEach((child, i) => this.walkNode(child, `${path}.children[${i}]`));\n }\n\n private walkNode(node: LayoutNode, path: string) {\n this.claim(node.id, path);\n this.checkModifiers(node, path, node.type === 'field' ? ['invisible', 'readonly', 'required'] : node.type === 'section' ? ['invisible', 'readonly'] : ['invisible']);\n switch (node.type) {\n case 'field':\n return this.checkFieldNode(node, path);\n case 'section':\n if (node.collapsible && !node.title) this.report(path, 'a collapsible section needs a title to fold it by');\n if (node.collapsed && !node.collapsible) this.report(path, 'collapsed needs collapsible: true');\n return this.walkChildren(node.children, path);\n case 'tabs':\n return this.walkTabs(node, path);\n default:\n return;\n }\n }\n\n private walkTabs(node: TabsNode, path: string) {\n node.children.forEach((tab, i) => {\n const tabPath = `${path}.children[${i}]`;\n this.claim(tab.id, tabPath);\n this.checkModifiers(tab, tabPath);\n this.walkChildren(tab.children, tabPath);\n });\n }\n\n private walkSheet(sheet: SheetNode, path: string) {\n if (sheet.title) {\n this.need(sheet.title.field, `${path}.title.field`);\n if (sheet.title.subtitleField !== undefined) this.need(sheet.title.subtitleField, `${path}.title.subtitleField`);\n if (sheet.title.avatarField !== undefined) this.need(sheet.title.avatarField, `${path}.title.avatarField`);\n }\n if (sheet.statusbar) {\n const { field, visibleStates } = sheet.statusbar;\n const def = this.need(field, `${path}.statusbar.field`);\n if (def && def.type !== 'selection' && def.type !== 'many2one') {\n this.report(`${path}.statusbar.field`, `\"${field}\" is a ${def.type}; a statusbar needs a selection or many2one`);\n }\n if (def?.type === 'selection' && visibleStates) {\n const values = new Set(def.options.map((o) => o.value));\n visibleStates.forEach((state, i) => {\n if (!values.has(state)) {\n this.report(`${path}.statusbar.visibleStates[${i}]`, `\"${state}\" is not an option of \"${field}\"`);\n }\n });\n }\n }\n sheet.buttons?.forEach((button, i) => {\n this.claim(button.id, `${path}.buttons[${i}]`);\n this.checkModifiers(button, `${path}.buttons[${i}]`);\n });\n sheet.statButtons?.forEach((stat, i) => {\n this.claim(stat.id, `${path}.statButtons[${i}]`);\n this.checkModifiers(stat, `${path}.statButtons[${i}]`);\n if (stat.field !== undefined) this.need(stat.field, `${path}.statButtons[${i}].field`);\n });\n if (sheet.ribbon) {\n this.claim(sheet.ribbon.id, `${path}.ribbon`);\n this.checkModifiers(sheet.ribbon, `${path}.ribbon`);\n }\n sheet.badges?.forEach((badge, i) => {\n this.claim(badge.id, `${path}.badges[${i}]`);\n this.checkModifiers(badge, `${path}.badges[${i}]`);\n });\n for (const place of ['above', 'below'] as const) {\n sheet.title?.[place]?.forEach((node, i) => this.walkNode(node, `${path}.title.${place}[${i}]`));\n }\n sheet.alerts?.forEach((alert, i) => {\n this.claim(alert.id, `${path}.alerts[${i}]`);\n this.checkModifiers(alert, `${path}.alerts[${i}]`);\n });\n this.walkChildren(sheet.children, path);\n if (sheet.sidePanel) {\n this.claim(sheet.sidePanel.id, `${path}.sidePanel`);\n this.checkModifiers(sheet.sidePanel, `${path}.sidePanel`);\n }\n }\n\n private checkFieldNode(node: FieldNode, path: string) {\n const def = this.need(node.field, `${path}.field`);\n if (def && node.totals) {\n if (def.type !== 'one2many') {\n this.report(`${path}.totals`, `totals only apply to one2many fields; \"${node.field}\" is a ${def.type}`);\n } else {\n node.totals.forEach((column, i) => {\n const sub = has(def.fields, column) ? def.fields[column] : undefined;\n if (!sub) this.report(`${path}.totals[${i}]`, `\"${column}\" is not a field of the lines of \"${node.field}\"`);\n else if (!['integer', 'float', 'monetary'].includes(sub.type)) {\n this.report(`${path}.totals[${i}]`, `\"${column}\" is a ${sub.type}; only integer, float and monetary columns add up`);\n }\n });\n }\n }\n // Options that point at another field: by convention their names end in \"Field\".\n for (const [key, value] of Object.entries(node.options ?? {})) {\n if (key.endsWith('Field') && typeof value === 'string') this.need(value, `${path}.options.${key}`);\n }\n if (def && node.editMode && def.type !== 'one2many') {\n this.report(`${path}.editMode`, `editMode only applies to one2many fields; \"${node.field}\" is a ${def.type}`);\n }\n if (def && node.optionalColumns) {\n if (def.type !== 'one2many') {\n this.report(`${path}.optionalColumns`, `optional columns only apply to one2many fields; \"${node.field}\" is a ${def.type}`);\n } else {\n // The columns the table shows: those named, or every line field but the structural ones.\n const shown = node.columns ?? Object.keys(def.fields).filter((c) => c !== def.lineKinds?.field && c !== def.sequenceField);\n for (const column of Object.keys(node.optionalColumns)) {\n if (!shown.includes(column)) this.report(`${path}.optionalColumns.${column}`, `\"${column}\" is not a column of \"${node.field}\"`);\n }\n }\n }\n if (!def || !node.columns) return;\n if (def.type === 'one2many') {\n node.columns.forEach((column, i) => {\n if (!has(def.fields, column)) {\n this.report(`${path}.columns[${i}]`, `\"${column}\" is not a field of the lines of \"${node.field}\"`);\n }\n });\n } else if (def.type !== 'many2many') {\n this.report(`${path}.columns`, `columns only apply to one2many and many2many fields; \"${node.field}\" is a ${def.type}`);\n }\n }\n}\n", "import { FIELD_TYPES } from './names';\nimport type { Page } from './page';\nimport { ReferenceCheck, type PageIssue, type PageValidation } from './references';\nimport { FORMAT_VERSION } from './version';\n\nconst isObject = (value: unknown): value is Record<string, unknown> => value !== null && typeof value === 'object' && !Array.isArray(value);\nconst LAYOUTS = ['sheet', 'sections', 'tabs', 'wizard'];\n\n/**\n * The check a page gets as it is shown: its outline, then every name and\n * condition in it, the same as `validatePage` finds them. It leaves out the\n * key-by-key check of the format, and so the validation library, which an app\n * showing forms need not carry; run `validatePage` where pages are made or\n * tested. A page that passes is handed back as it is.\n */\nexport function checkPage(input: unknown): PageValidation {\n if (!isObject(input)) return { ok: false, issues: [{ path: '(page)', message: 'a page is a JSON object' }] };\n const issues: PageIssue[] = [];\n const say = (path: string, message: string) => issues.push({ path, message });\n if (input['fieldia'] !== FORMAT_VERSION) say('fieldia', `this build reads format ${FORMAT_VERSION}`);\n if (typeof input['id'] !== 'string' || !input['id']) say('id', 'a page needs an id');\n const data = input['data'];\n if (!isObject(data) || !(data['kind'] === 'responses' || (data['kind'] === 'record' && typeof data['model'] === 'string' && data['model']))) {\n say('data', 'data is { \"kind\": \"record\", \"model\": \u2026 } or { \"kind\": \"responses\" }');\n }\n const fields = input['fields'];\n if (!isObject(fields)) say('fields', 'fields is an object of field definitions, by name');\n else {\n for (const [name, def] of Object.entries(fields)) {\n if (!isObject(def) || !(FIELD_TYPES as readonly unknown[]).includes(def['type']) || typeof def['label'] !== 'string') {\n say(`fields.${name}`, 'a field needs a type Fieldia knows and a label');\n }\n }\n }\n const layout = input['layout'];\n const isList = isObject(layout) && layout['type'] === 'list';\n if (!isObject(layout) || (isList ? !Array.isArray(layout['columns']) : !LAYOUTS.includes(layout['type'] as string) || !Array.isArray(layout['children']))) {\n say('layout', 'the layout is a sheet, sections, tabs or wizard, with children, or a list with columns');\n }\n if (issues.length) return { ok: false, issues };\n const page = input as unknown as Page;\n try {\n const found = new ReferenceCheck(page).run();\n return found.length ? { ok: false, issues: found } : { ok: true, page };\n } catch (error) {\n return { ok: false, issues: [{ path: '(page)', message: `a part of this page cannot be read: ${(error as Error).message}` }] };\n }\n}\n", "import type { Page } from './page';\n\n/** Keys whose text a person reads: titles, labels, help, prompts, messages and a wizard's buttons. */\nconst TEXT_KEYS = new Set(['title', 'description', 'label', 'help', 'placeholder', 'message', 'text', 'confirm', 'nextLabel', 'backLabel', 'finishLabel']);\n\n/**\n * Parts that hold names or data, never words to translate: which line fields\n * mark sections and notes, a link's filter, a default value, a widget's options,\n * and what the page's data is.\n */\nconst NOT_TEXT = new Set(['lineKinds', 'filter', 'default', 'data']);\n\n/**\n * The page with every word a person reads passed through the app's own\n * translator, for apps that keep their translations by text or by key. Ids,\n * field names, choice values, conditions and data stay as they are; the page\n * given is left alone.\n */\nexport function translatePage(page: Page, translate: (text: string) => string): Page {\n const walk = (value: unknown, key: string | null): unknown => {\n if (typeof value === 'string') return key !== null && TEXT_KEYS.has(key) ? translate(value) : value;\n if (Array.isArray(value)) return value.map((item) => walk(item, null));\n if (value === null || typeof value !== 'object') return value;\n const out: Record<string, unknown> = {};\n for (const [name, inner] of Object.entries(value)) {\n // A field node's `options` are its widget's settings, not a list of choices.\n const widgetOptions = name === 'options' && !Array.isArray(inner);\n out[name] = NOT_TEXT.has(name) || widgetOptions ? inner : walk(inner, name);\n }\n return out;\n };\n return walk(page, null) as Page;\n}\n", "/**\n * evaluateModifier - Evaluate modifier expressions with form context\n *\n * Phase 2 implementation with full expression parser.\n * Supports Python-like expressions used in Flectra modifiers.\n *\n * Structura Reference:\n * - DynBehaviorManager.evaluateCondition() method\n * - Supports Python-like expressions: \"state == 'draft' and amount > 100\"\n *\n * Supported features:\n * - Comparison operators: ==, !=, <>, <, >, <=, >=\n * - In operators: in, not in\n * - Logical operators: and, or, not\n * - Parentheses for precedence\n * - Nested field access: partner_id.country_id.name\n * - Truthiness checks: partner_id (true if partner_id has value)\n *\n * @param expression - The modifier expression to evaluate\n * @param context - Current form values\n * @returns Boolean result of evaluation\n *\n * @example\n * ```typescript\n * // Simple boolean\n * evaluateModifier(true, {}) // => true\n *\n * // String boolean\n * evaluateModifier('1', {}) // => true\n * evaluateModifier('True', {}) // => true\n *\n * // Field truthiness\n * evaluateModifier('is_company', { is_company: true }) // => true\n * evaluateModifier('partner_id', { partner_id: null }) // => false\n *\n * // Comparison expressions\n * evaluateModifier(\"state == 'done'\", { state: 'done' }) // => true\n * evaluateModifier(\"amount > 100\", { amount: 150 }) // => true\n *\n * // Logical expressions\n * evaluateModifier(\"state == 'draft' and amount > 100\", { state: 'draft', amount: 150 }) // => true\n * evaluateModifier(\"state in ['draft', 'sent']\", { state: 'draft' }) // => true\n *\n * // Nested field access\n * evaluateModifier(\"partner_id.country_id == 5\", { partner_id: { country_id: 5 } }) // => true\n * ```\n */\n\nimport { tokenize } from './tokenizer';\nimport { ExpressionParser } from './parser';\nimport { evaluate, truthy } from './evaluator';\n\nexport function evaluateModifier(\n expression: string | boolean | undefined,\n context: Record<string, unknown>\n): boolean {\n // Undefined modifier = false (field is not affected)\n if (expression === undefined) {\n return false;\n }\n\n // Direct boolean value\n if (typeof expression === 'boolean') {\n return expression;\n }\n\n // String representation of boolean\n if (expression === '1' || expression === 'True' || expression === 'true') {\n return true;\n }\n\n if (expression === '0' || expression === 'False' || expression === 'false') {\n return false;\n }\n\n // Empty string = false\n if (expression === '') {\n return false;\n }\n\n // Parse and evaluate complex expression\n try {\n const tokens = tokenize(expression);\n\n // Empty token list\n if (tokens.length === 0) {\n return false;\n }\n\n const parser = new ExpressionParser(tokens);\n const ast = parser.parse();\n const result = evaluate(ast, context);\n\n // Convert result to boolean\n return truthy(result);\n } catch {\n // A page is validated before it runs (validatePage reads every\n // expression), so this only guards pages that skipped validation.\n // Fail safely - return false so field is not hidden/disabled by broken modifier\n return false;\n }\n}\n\n/**\n * Check if a modifier expression is valid and can be parsed\n *\n * @param expression - The modifier expression to check\n * @returns true if expression is valid, false otherwise\n */\nexport function isModifierValid(expression: string | boolean | undefined): boolean {\n if (expression === undefined || typeof expression === 'boolean') {\n return true;\n }\n\n if (expression === '') {\n return true;\n }\n\n try {\n const tokens = tokenize(expression);\n if (tokens.length === 0) {\n return true;\n }\n const parser = new ExpressionParser(tokens);\n parser.parse();\n return true;\n } catch {\n return false;\n }\n}\n", "import type { Field, LineField } from '../format/field';\nimport type { JsonValue } from '../format/json';\n\n/**\n * The values a form holds while someone edits it. Plain JSON, so a draft can\n * be stored and a record handed to any data source.\n */\n\nexport type RecordId = number | string;\n\n/** A related record, as a many2one or many2many holds it: enough to show it. */\nexport interface RelatedRecord {\n id: RecordId;\n label: string;\n}\n\n/** A reference points at a record of one of several models. */\nexport interface ReferenceValue {\n model: string;\n id: RecordId;\n label: string;\n}\n\n/** An uploaded or stored file. `data` is base64; `url` is where a stored one lives. */\nexport interface FileValue {\n name: string;\n type: string;\n size: number;\n data?: string;\n url?: string;\n}\n\n/**\n * One line of a one2many. `key` is stable for the life of the form, so a line\n * keeps its identity while it is edited; `id` is the saved record's id, absent\n * until the line is saved.\n */\nexport interface Line {\n key: string;\n id?: RecordId;\n values: Values;\n}\n\nexport type Value =\n | JsonValue\n | RelatedRecord\n | RelatedRecord[]\n | ReferenceValue\n | FileValue\n | Line[];\n\nexport type Values = Record<string, Value>;\n\ntype AnyField = Field | LineField;\n\n/** What a field holds before anyone types in it. */\nexport function emptyValue(field: AnyField): Value {\n switch (field.type) {\n case 'boolean':\n return false;\n case 'many2many':\n case 'one2many':\n return [];\n case 'selection':\n return field.multiple ? [] : null;\n default:\n return null;\n }\n}\n\n/** A fresh record: each field's default, or its empty value. */\nexport function initialValues(fields: Record<string, AnyField>): Values {\n const values: Values = {};\n for (const [name, field] of Object.entries(fields)) {\n values[name] = field.default !== undefined ? structuredCopy(field.default) : emptyValue(field);\n }\n return values;\n}\n\n/** Nothing worth keeping: no value, blank text, or an empty list. Numbers and booleans never are. */\nexport function isEmpty(_field: AnyField, value: Value | undefined): boolean {\n if (value === null || value === undefined) return true;\n if (typeof value === 'string') return value.trim() === '';\n if (Array.isArray(value)) return value.length === 0;\n return false;\n}\n\n/**\n * The values as modifiers read them, matching what backends write in their\n * expressions: a many2one is its id, a many2many its ids, a reference\n * \"model,id\", a file its name, and lines a list (so `not child_ids` works).\n */\nexport function expressionContext(values: Values, fields: Record<string, AnyField>): Record<string, unknown> {\n const context: Record<string, unknown> = {};\n for (const [name, value] of Object.entries(values)) {\n const field = fields[name];\n context[name] = field ? forExpressions(field, value) : value;\n }\n return context;\n}\n\nfunction forExpressions(field: AnyField, value: Value): unknown {\n if (value === null || value === undefined) return null;\n switch (field.type) {\n case 'many2one':\n return (value as RelatedRecord).id;\n case 'many2many':\n return (value as RelatedRecord[]).map((record) => record.id);\n case 'one2many':\n return (value as Line[]).map((line) => line.key);\n case 'reference': {\n const ref = value as ReferenceValue;\n return `${ref.model},${ref.id}`;\n }\n case 'binary':\n case 'image':\n return (value as FileValue).name;\n default:\n return value;\n }\n}\n\n/**\n * What a line of a one2many is: a section heading, a note, or (null) an item.\n * Lines only have kinds when the field declares `lineKinds`.\n */\nexport function lineKind(field: Extract<Field, { type: 'one2many' }>, values: Values): 'section' | 'note' | null {\n const kinds = field.lineKinds;\n if (!kinds) return null;\n const value = values[kinds.field];\n if (value === (kinds.section ?? 'section')) return 'section';\n if (value === (kinds.note ?? 'note')) return 'note';\n return null;\n}\n\n/** A deep copy of plain JSON. */\nexport function structuredCopy<T>(value: T): T {\n return value === undefined ? value : (JSON.parse(JSON.stringify(value)) as T);\n}\n", "/**\n * Validation messages, by language. `{label}` is the field's label; the other\n * placeholders are named in each English message. English keeps the React\n * engine's wording; Arabic, German and French build on its translations.\n */\nexport interface Messages {\n required: string;\n maxLength: string;\n pattern: string;\n text: string;\n number: string;\n integer: string;\n min: string;\n max: string;\n decimals: string;\n boolean: string;\n dateFormat: string;\n dateInvalid: string;\n datetimeFormat: string;\n datetimeInvalid: string;\n choice: string;\n choices: string;\n record: string;\n records: string;\n reference: string;\n file: string;\n fileSize: string;\n fileType: string;\n /** Joins the last two items of a list: \"PDF or image\". */\n or: string;\n}\n\nexport type Locale = 'en' | 'ar' | 'de' | 'fr';\n\nexport const MESSAGES: Record<Locale, Messages> = {\n en: {\n required: '{label} is required',\n maxLength: 'Maximum {max} characters allowed',\n pattern: '{label} is not in the expected format',\n text: '{label} must be text',\n number: '{label} must be a number',\n integer: '{label} must be a whole number',\n min: '{label} must be at least {min}',\n max: '{label} must be at most {max}',\n decimals: 'Maximum {digits} decimal places allowed',\n boolean: '{label} must be yes or no',\n dateFormat: 'Invalid date format (expected YYYY-MM-DD)',\n dateInvalid: 'Invalid date (check month/day values)',\n datetimeFormat: 'Invalid date and time format (expected YYYY-MM-DDTHH:MM:SS)',\n datetimeInvalid: 'Invalid date and time (check the values)',\n choice: 'Must be one of: {options}',\n choices: '{label} must be a list of choices',\n record: '{label} must be a record',\n records: '{label} must be a list of records',\n reference: '{label} must point to {aModels}',\n file: '{label} must be a file',\n fileSize: '{label} is larger than {size}',\n fileType: '{label} must be {aTypes} file',\n or: 'or',\n },\n ar: {\n required: '{label} \u0645\u0637\u0644\u0648\u0628',\n maxLength: '\u0627\u0644\u062D\u062F \u0627\u0644\u0623\u0642\u0635\u0649 {max} \u062D\u0631\u0641\u064B\u0627',\n pattern: '\u0635\u064A\u063A\u0629 {label} \u063A\u064A\u0631 \u0635\u062D\u064A\u062D\u0629',\n text: '\u064A\u062C\u0628 \u0623\u0646 \u064A\u0643\u0648\u0646 {label} \u0646\u0635\u064B\u0627',\n number: '\u064A\u062C\u0628 \u0623\u0646 \u064A\u0643\u0648\u0646 {label} \u0631\u0642\u0645\u064B\u0627',\n integer: '\u064A\u062C\u0628 \u0623\u0646 \u064A\u0643\u0648\u0646 {label} \u0631\u0642\u0645\u064B\u0627 \u0635\u062D\u064A\u062D\u064B\u0627',\n min: '\u064A\u062C\u0628 \u0623\u0644\u0627 \u064A\u0642\u0644 {label} \u0639\u0646 {min}',\n max: '\u064A\u062C\u0628 \u0623\u0644\u0627 \u064A\u0632\u064A\u062F {label} \u0639\u0646 {max}',\n decimals: '\u0627\u0644\u062D\u062F \u0627\u0644\u0623\u0642\u0635\u0649 {digits} \u0645\u0646\u0627\u0632\u0644 \u0639\u0634\u0631\u064A\u0629',\n boolean: '\u064A\u062C\u0628 \u0623\u0646 \u064A\u0643\u0648\u0646 {label} \u0646\u0639\u0645 \u0623\u0648 \u0644\u0627',\n dateFormat: '\u0635\u064A\u063A\u0629 \u0627\u0644\u062A\u0627\u0631\u064A\u062E \u063A\u064A\u0631 \u0635\u062D\u064A\u062D\u0629 (\u0627\u0644\u0645\u062A\u0648\u0642\u0639 YYYY-MM-DD)',\n dateInvalid: '\u0627\u0644\u062A\u0627\u0631\u064A\u062E \u063A\u064A\u0631 \u0635\u062D\u064A\u062D (\u062A\u062D\u0642\u0642 \u0645\u0646 \u0627\u0644\u0634\u0647\u0631 \u0648\u0627\u0644\u064A\u0648\u0645)',\n datetimeFormat: '\u0635\u064A\u063A\u0629 \u0627\u0644\u062A\u0627\u0631\u064A\u062E \u0648\u0627\u0644\u0648\u0642\u062A \u063A\u064A\u0631 \u0635\u062D\u064A\u062D\u0629 (\u0627\u0644\u0645\u062A\u0648\u0642\u0639 YYYY-MM-DDTHH:MM:SS)',\n datetimeInvalid: '\u0627\u0644\u062A\u0627\u0631\u064A\u062E \u0648\u0627\u0644\u0648\u0642\u062A \u063A\u064A\u0631 \u0635\u062D\u064A\u062D\u064A\u0646',\n choice: '\u064A\u062C\u0628 \u0623\u0646 \u062A\u0643\u0648\u0646 \u0627\u0644\u0642\u064A\u0645\u0629 \u0648\u0627\u062D\u062F\u0629 \u0645\u0646: {options}',\n choices: '\u064A\u062C\u0628 \u0623\u0646 \u064A\u0643\u0648\u0646 {label} \u0642\u0627\u0626\u0645\u0629 \u0627\u062E\u062A\u064A\u0627\u0631\u0627\u062A',\n record: '\u064A\u062C\u0628 \u0623\u0646 \u064A\u0643\u0648\u0646 {label} \u0633\u062C\u0644\u064B\u0627',\n records: '\u064A\u062C\u0628 \u0623\u0646 \u064A\u0643\u0648\u0646 {label} \u0642\u0627\u0626\u0645\u0629 \u0633\u062C\u0644\u0627\u062A',\n reference: '\u064A\u062C\u0628 \u0623\u0646 \u064A\u0634\u064A\u0631 {label} \u0625\u0644\u0649 {models}',\n file: '\u064A\u062C\u0628 \u0623\u0646 \u064A\u0643\u0648\u0646 {label} \u0645\u0644\u0641\u064B\u0627',\n fileSize: '\u062D\u062C\u0645 {label} \u0623\u0643\u0628\u0631 \u0645\u0646 {size}',\n fileType: '\u064A\u062C\u0628 \u0623\u0646 \u064A\u0643\u0648\u0646 {label} \u0645\u0644\u0641 {types}',\n or: '\u0623\u0648',\n },\n de: {\n required: '{label} ist erforderlich',\n maxLength: 'Maximal {max} Zeichen erlaubt',\n pattern: '{label} hat nicht das erwartete Format',\n text: '{label} muss Text sein',\n number: '{label} muss eine Zahl sein',\n integer: '{label} muss eine ganze Zahl sein',\n min: '{label} muss mindestens {min} sein',\n max: '{label} darf h\u00F6chstens {max} sein',\n decimals: 'Maximal {digits} Nachkommastellen erlaubt',\n boolean: '{label} muss ja oder nein sein',\n dateFormat: 'Ung\u00FCltiges Datumsformat (erwartet JJJJ-MM-TT)',\n dateInvalid: 'Ung\u00FCltiges Datum (Monat und Tag pr\u00FCfen)',\n datetimeFormat: 'Ung\u00FCltiges Datums- und Zeitformat (erwartet JJJJ-MM-TTTHH:MM:SS)',\n datetimeInvalid: 'Ung\u00FCltiges Datum oder ung\u00FCltige Uhrzeit',\n choice: 'Muss eines davon sein: {options}',\n choices: '{label} muss eine Liste von Optionen sein',\n record: '{label} muss ein Datensatz sein',\n records: '{label} muss eine Liste von Datens\u00E4tzen sein',\n reference: '{label} muss auf {models} verweisen',\n file: '{label} muss eine Datei sein',\n fileSize: '{label} ist gr\u00F6\u00DFer als {size}',\n fileType: '{label} muss eine {types}-Datei sein',\n or: 'oder',\n },\n fr: {\n required: '{label} est obligatoire',\n maxLength: '{max} caract\u00E8res au maximum',\n pattern: \"{label} n'a pas le format attendu\",\n text: '{label} doit \u00EAtre du texte',\n number: '{label} doit \u00EAtre un nombre',\n integer: '{label} doit \u00EAtre un nombre entier',\n min: '{label} doit \u00EAtre au moins {min}',\n max: '{label} doit \u00EAtre au plus {max}',\n decimals: '{digits} d\u00E9cimales au maximum',\n boolean: '{label} doit \u00EAtre oui ou non',\n dateFormat: 'Format de date invalide (attendu AAAA-MM-JJ)',\n dateInvalid: 'Date invalide (v\u00E9rifiez le mois et le jour)',\n datetimeFormat: 'Format de date et heure invalide (attendu AAAA-MM-JJTHH:MM:SS)',\n datetimeInvalid: 'Date ou heure invalide',\n choice: 'Doit \u00EAtre parmi : {options}',\n choices: '{label} doit \u00EAtre une liste de choix',\n record: '{label} doit \u00EAtre un enregistrement',\n records: \"{label} doit \u00EAtre une liste d'enregistrements\",\n reference: '{label} doit pointer vers {models}',\n file: '{label} doit \u00EAtre un fichier',\n fileSize: '{label} d\u00E9passe {size}',\n fileType: '{label} doit \u00EAtre un fichier {types}',\n or: 'ou',\n },\n};\n\n/** Fill `{name}` placeholders. */\nexport function fill(template: string, values: Record<string, string | number>): string {\n return template.replace(/\\{(\\w+)\\}/g, (match, name: string) => (name in values ? String(values[name]) : match));\n}\n", "import type { Field, LineField } from '../format/field';\nimport { fill, MESSAGES, type Messages } from './messages';\nimport { isEmpty, type FileValue, type ReferenceValue, type RelatedRecord, type Value } from './values';\n\n/**\n * Check one value against its field. Returns the message to show, or\n * undefined when the value is fine. The wording follows the React engine's\n * (\"Name is required\", \"Maximum 120 characters allowed\").\n *\n * An empty optional value passes everything: a pattern or a minimum applies\n * to what someone typed, not to a field they left alone.\n */\nexport function checkValue(\n field: Field | LineField,\n value: Value | undefined,\n required: boolean,\n messages: Messages = MESSAGES.en\n): string | undefined {\n const label = field.label || 'This field';\n const say = (key: keyof Messages, values: Record<string, string | number> = {}) => fill(messages[key], { label, ...values });\n if (isEmpty(field, value)) return required ? say('required') : undefined;\n\n switch (field.type) {\n case 'char':\n case 'text':\n case 'html': {\n if (typeof value !== 'string') return say('text');\n if ((field.type === 'char' || field.type === 'text') && field.size !== undefined && value.length > field.size) {\n return say('maxLength', { max: field.size });\n }\n if (field.type === 'char' && field.pattern !== undefined && !new RegExp(field.pattern).test(value)) {\n return say('pattern');\n }\n return undefined;\n }\n case 'integer':\n case 'float':\n case 'monetary': {\n if (typeof value !== 'number' || !Number.isFinite(value)) return say('number');\n if (field.type === 'integer' && !Number.isInteger(value)) return say('integer');\n if (field.min !== undefined && value < field.min) return say('min', { min: field.min });\n if (field.max !== undefined && value > field.max) return say('max', { max: field.max });\n if (field.type !== 'integer' && field.digits && decimals(value) > field.digits[1]) {\n return say('decimals', { digits: field.digits[1] });\n }\n return undefined;\n }\n case 'boolean':\n return typeof value === 'boolean' ? undefined : say('boolean');\n case 'date':\n return checkDate(value, say);\n case 'datetime':\n return checkDateTime(value, say);\n case 'selection': {\n const allowed = new Set(field.options.map((o) => o.value));\n const listing = say('choice', { options: field.options.map((o) => o.label).join(', ') });\n if (field.multiple) {\n if (!Array.isArray(value)) return say('choices');\n return value.every((v) => allowed.has(v as string | number)) ? undefined : listing;\n }\n return allowed.has(value as string | number) ? undefined : listing;\n }\n case 'many2one':\n return isRecord(value) ? undefined : say('record');\n case 'many2many':\n return Array.isArray(value) && value.every(isRecord) ? undefined : say('records');\n case 'reference': {\n const ref = value as ReferenceValue;\n if (!isRecord(value) || typeof ref.model !== 'string') return say('record');\n if (!field.models.some((m) => m.value === ref.model)) {\n const models = listOr(field.models.map((m) => m.label), messages.or);\n return say('reference', { models, aModels: article(models) });\n }\n return undefined;\n }\n case 'binary':\n case 'image':\n return checkFile(field, value, say, messages);\n default:\n return undefined;\n }\n}\n\nfunction decimals(value: number): number {\n const text = String(value);\n if (text.includes('e-')) return Number(text.split('e-')[1]);\n const dot = text.indexOf('.');\n return dot === -1 ? 0 : text.length - dot - 1;\n}\n\nfunction isRecord(value: unknown): value is RelatedRecord {\n return (\n value !== null &&\n typeof value === 'object' &&\n !Array.isArray(value) &&\n (typeof (value as RelatedRecord).id === 'number' || typeof (value as RelatedRecord).id === 'string') &&\n typeof (value as RelatedRecord).label === 'string'\n );\n}\n\ntype Say = (key: keyof Messages, values?: Record<string, string | number>) => string;\n\nfunction checkDate(value: Value | undefined, say: Say): string | undefined {\n if (typeof value !== 'string' || !/^\\d{4}-\\d{2}-\\d{2}$/.test(value)) return say('dateFormat');\n const [y, m, d] = value.split('-').map(Number);\n return realDay(y, m, d) ? undefined : say('dateInvalid');\n}\n\nconst ISO_DATETIME = /^(\\d{4})-(\\d{2})-(\\d{2})T(\\d{2}):(\\d{2})(?::(\\d{2})(?:\\.\\d{1,9})?)?(?:Z|[+-]\\d{2}:\\d{2})?$/;\n\nfunction checkDateTime(value: Value | undefined, say: Say): string | undefined {\n const match = typeof value === 'string' ? ISO_DATETIME.exec(value) : null;\n if (!match) return say('datetimeFormat');\n const [y, mo, d, h, mi, s] = match.slice(1).map((part) => Number(part ?? 0));\n return realDay(y, mo, d) && h < 24 && mi < 60 && s < 60 ? undefined : say('datetimeInvalid');\n}\n\nfunction realDay(year: number, month: number, day: number): boolean {\n if (month < 1 || month > 12 || day < 1) return false;\n const lengths = [31, year % 4 === 0 && (year % 100 !== 0 || year % 400 === 0) ? 29 : 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31];\n return day <= lengths[month - 1];\n}\n\nfunction checkFile(field: Field | LineField, value: Value | undefined, say: Say, messages: Messages): string | undefined {\n const file = value as FileValue;\n if (!isFile(value)) return say('file');\n if ('maxSize' in field && field.maxSize !== undefined && file.size > field.maxSize) {\n return say('fileSize', { size: formatBytes(field.maxSize) });\n }\n if (field.type === 'binary' && field.accept && !field.accept.some((pattern) => matchesType(pattern, file.type))) {\n const types = listOr(field.accept.map(describeType), messages.or);\n return say('fileType', { types, aTypes: article(types) });\n }\n return undefined;\n}\n\nfunction isFile(value: unknown): value is FileValue {\n const file = value as FileValue;\n return value !== null && typeof value === 'object' && typeof file.name === 'string' && typeof file.size === 'number';\n}\n\nfunction matchesType(pattern: string, type: string): boolean {\n return pattern.endsWith('/*') ? type.startsWith(pattern.slice(0, -1)) : pattern === type;\n}\n\nfunction describeType(pattern: string): string {\n if (pattern.endsWith('/*')) return pattern.slice(0, -2);\n if (pattern === 'application/pdf') return 'PDF';\n return (pattern.split('/')[1] ?? pattern).toUpperCase();\n}\n\nfunction listOr(items: string[], or: string): string {\n if (items.length <= 1) return items.join('');\n return `${items.slice(0, -1).join(', ')} ${or} ${items[items.length - 1]}`;\n}\n\nfunction article(phrase: string): string {\n return /^[aeiou]/i.test(phrase) ? `an ${phrase}` : `a ${phrase}`;\n}\n\n/** 1048576 -> \"1 MB\". */\nexport function formatBytes(bytes: number): string {\n const units = ['bytes', 'KB', 'MB', 'GB'];\n let size = bytes;\n let unit = 0;\n while (size >= 1024 && unit < units.length - 1) {\n size /= 1024;\n unit++;\n }\n return `${Number(size.toFixed(1))} ${units[unit]}`;\n}\n", "import type { FilterCondition, Fields } from '../format/field';\nimport type { JsonValue } from '../format/json';\nimport type { RecordId, RelatedRecord, Values } from './values';\n\n/**\n * How Fieldia reaches data. Fieldia knows no backend: an app implements this\n * interface for its own (a Flectra adapter, a REST client, a survey store),\n * and every method is optional so a page uses only what it needs.\n */\nexport interface DataSource {\n /** Read a record. Needed to edit an existing record. */\n load?(request: LoadRequest): Promise<Values>;\n /** Create (`id: null`) or update a record. Needed to save a record page. */\n save?(request: SaveRequest): Promise<SaveResult>;\n /** Recalculate after a value changes, the way a backend's onchange does. */\n onchange?(request: OnchangeRequest): Promise<OnchangeResult>;\n /** Find records a many2one, many2many or reference may point to. */\n search?(request: SearchRequest): Promise<RelatedRecord[]>;\n /** Make a record from just its name, for \"Create 'xyz'\" in a link field (a backend's name_create). */\n create?(request: CreateRequest): Promise<RelatedRecord>;\n /** Store one response to a `responses` page, such as a survey. */\n submit?(request: SubmitRequest): Promise<SubmitResult>;\n /** Records for a list: filtered, sorted and one page of them, with how many there are in all. */\n list?(request: ListRequest): Promise<ListResult>;\n /** How many records fall under each value of a field, for a list's Group By. */\n groups?(request: GroupRequest): Promise<Group[]>;\n}\n\nexport interface CreateRequest {\n model: string;\n /** What the person typed: the new record's name. */\n name: string;\n}\n\nexport interface LoadRequest {\n model: string;\n id: RecordId;\n /** The page's fields, so the source reads exactly what the page shows. */\n fields: Fields;\n}\n\nexport interface SaveRequest {\n model: string;\n id: RecordId | null;\n /** The page's fields, so the source knows each relation's model. */\n fields: Fields;\n /** Only what changed since the record was loaded or last saved. */\n changes: RecordChanges;\n /** Every value, for sources that save whole records. */\n values: Values;\n}\n\nexport interface SaveResult {\n id: RecordId;\n /** The record as stored, when the source recalculated anything. */\n values?: Values;\n}\n\nexport interface OnchangeRequest {\n model: string;\n id: RecordId | null;\n /** The field that changed. */\n changed: string;\n values: Values;\n}\n\nexport interface OnchangeResult {\n /** New values for other fields. */\n values?: Values;\n /** Something to tell the person editing, without blocking them. */\n warning?: string;\n}\n\nexport interface SearchRequest {\n /** The related model, from the field's `relation`. */\n model: string;\n query: string;\n /** The field's filter, with every `valueFrom` already replaced by its value. */\n filter?: ResolvedFilter[];\n limit?: number;\n}\n\nexport type ResolvedFilterCondition = Omit<FilterCondition, 'valueFrom' | 'value'> & { value: JsonValue };\n\nexport interface SortOrder {\n field: string;\n desc?: boolean;\n}\n\nexport interface ListRequest {\n model: string;\n /** The fields the list shows. */\n fields: string[];\n /** What the search bar and the open groups ask for; an `any` group is an OR. */\n filter: ResolvedFilter[];\n /** By the first, then the next: a link by its label, empty values last. */\n sort: SortOrder[];\n offset: number;\n limit: number;\n}\n\nexport interface ListResult {\n records: { id: RecordId; values: Values }[];\n /** How many records match in all, for the pager. */\n total: number;\n}\n\nexport interface GroupRequest {\n model: string;\n field: string;\n filter: ResolvedFilter[];\n}\n\n/** The records under one value of a field: a link's by its id, and those with none as a group of their own (value null). */\nexport interface Group {\n value: JsonValue;\n label: string;\n count: number;\n}\n\n/**\n * A filter as a search receives it: each `valueFrom` already replaced by its\n * value. An adapter must keep the groups: `any` is an OR, `all` an AND.\n */\nexport type ResolvedFilter = ResolvedFilterCondition | { any: ResolvedFilter[] } | { all: ResolvedFilter[] };\n\nexport interface SubmitRequest {\n pageId: string;\n /** The answers to the questions that were shown. Skipped steps are left out. */\n values: Values;\n}\n\nexport interface SubmitResult {\n id?: RecordId;\n}\n\n/**\n * What changed, using the operation names Odoo gives its x2many commands, so\n * an adapter maps them one to one.\n */\nexport interface RecordChanges {\n /** Changed values of every field that is not one2many or many2many. */\n values: Values;\n /** one2many changes, per field. */\n lines: Record<string, LineOp[]>;\n /** many2many changes, per field. */\n links: Record<string, LinkOp[]>;\n}\n\nexport type LineOp =\n | { op: 'create'; key: string; values: Values }\n | { op: 'update'; id: RecordId; values: Values }\n | { op: 'delete'; id: RecordId };\n\nexport type LinkOp =\n | { op: 'link'; id: RecordId }\n | { op: 'unlink'; id: RecordId }\n | { op: 'set'; ids: RecordId[] }\n | { op: 'clear' };\n\n/**\n * Why a save was refused, so each kind is shown where it belongs: `fields`\n * under those fields, a `rule` (a backend's business rule) in a dialog,\n * `network` in a banner with Retry, and `other` beside Save with Retry.\n */\nexport interface SaveProblem {\n kind: 'fields' | 'rule' | 'network' | 'other';\n message: string;\n /** For `fields`: a message for each field, by name. */\n fields?: Record<string, string>;\n}\n\n/** An error for a data source's save to throw when the backend refuses it. */\nexport function saveRefused(problem: SaveProblem): Error & { problem: SaveProblem } {\n return Object.assign(new Error(problem.message), { problem });\n}\n\n/** What a failed save tells: its own problem, a failed fetch as the network, anything else as it is. */\nexport function saveProblemOf(error: unknown): SaveProblem {\n const carried = (error as { problem?: SaveProblem } | null)?.problem;\n if (carried && typeof carried.kind === 'string') return carried;\n const message = error instanceof Error ? error.message : String(error);\n if (error instanceof TypeError && /fetch|network|load failed/i.test(message)) return { kind: 'network', message };\n return { kind: 'other', message };\n}\n", "import type { JsonValue } from '../format/json';\nimport type { ResolvedFilter, ResolvedFilterCondition } from './data-source';\nimport type { RelatedRecord, Values } from './values';\n\n/**\n * Whether a record passes a filter, the way a search should judge it: every\n * item of the list holds, an `any` group when one of its items holds, an `all`\n * group when each does. The memory data source searches with it; an app may too.\n */\nexport function matchesFilter(values: Values, filter: readonly ResolvedFilter[]): boolean {\n return filter.every((item) => holds(values, item));\n}\n\nfunction holds(values: Values, item: ResolvedFilter): boolean {\n if ('any' in item) return item.any.some((inner) => holds(values, inner));\n if ('all' in item) return item.all.every((inner) => holds(values, inner));\n return meets(values, item);\n}\n\n/** Empty is not set: no value, empty text, an empty list. */\nfunction isSet(value: unknown): boolean {\n return value !== null && value !== undefined && value !== '' && value !== false && !(Array.isArray(value) && !value.length);\n}\n\nfunction meets(values: Values, condition: ResolvedFilterCondition): boolean {\n const raw = values[condition.field];\n // A link compares by its id.\n const actual = raw !== null && typeof raw === 'object' && !Array.isArray(raw) && 'id' in raw ? (raw as RelatedRecord).id : (raw as JsonValue | undefined);\n const expected = condition.value;\n // Text is looked for in a link's name, as a search by name does.\n const text = raw !== null && typeof raw === 'object' && !Array.isArray(raw) && 'label' in raw ? String((raw as RelatedRecord).label) : String(actual ?? '');\n switch (condition.op) {\n case '=':\n return actual === expected;\n case '!=':\n return actual !== expected;\n case '<':\n return isSet(actual) && (actual as number) < (expected as number);\n case '>':\n return isSet(actual) && (actual as number) > (expected as number);\n case '<=':\n return isSet(actual) && (actual as number) <= (expected as number);\n case '>=':\n return isSet(actual) && (actual as number) >= (expected as number);\n case 'in':\n return Array.isArray(expected) && expected.includes(actual as JsonValue);\n case 'not in':\n return Array.isArray(expected) && !expected.includes(actual as JsonValue);\n case 'like':\n return text.includes(String(expected));\n case 'ilike':\n return text.toLowerCase().includes(String(expected).toLowerCase());\n case 'startswith':\n return text.toLowerCase().startsWith(String(expected).toLowerCase());\n case 'endswith':\n return text.toLowerCase().endsWith(String(expected).toLowerCase());\n case 'set':\n return isSet(raw);\n case 'notset':\n return !isSet(raw);\n case 'between': {\n if (!isSet(actual) || !Array.isArray(expected)) return false;\n const [low, high] = expected as (number | string)[];\n return (actual as number | string) >= low && (actual as number | string) <= high;\n }\n }\n}\n", "import type { JsonValue } from '../format/json';\nimport type { ListNode } from '../format/layout';\nimport type { Page } from '../format/page';\nimport type { ResolvedFilter, ResolvedFilterCondition } from './data-source';\nimport { fill } from './messages';\n\n/**\n * What a list's search bar holds, each shown as a chip: values searched in\n * one field (any of them), named filters (any of them), a custom filter, or\n * the fields the list is grouped by. The facets all apply together.\n */\nexport type Facet =\n | { kind: 'field'; field: string; label: string; values: { op: ResolvedFilterCondition['op']; value: JsonValue; label: string }[] }\n | { kind: 'filters'; ids: string[]; labels: string[] }\n | { kind: 'custom'; label: string; filter: ResolvedFilter[] }\n | { kind: 'groupBy'; fields: string[]; labels: string[] };\n\n/** One way to search what was typed: a field, how to compare, and the words that say so. */\nexport interface Suggestion {\n field: string;\n fieldLabel: string;\n op: ResolvedFilterCondition['op'];\n value: JsonValue;\n valueLabel: string;\n label: string;\n}\n\nconst TEXT = new Set(['char', 'text', 'html']);\nconst NUMBER = new Set(['integer', 'float', 'monetary']);\nconst LINK = new Set(['many2one', 'many2many']);\n\n/**\n * The searches the typed text can be: text looked for in each text field, a\n * choice whose label it matches, a number where it is one, a link by its\n * record's name. Only the list's search fields, the columns unless it says.\n */\nexport function suggestions(typed: string, page: Page, list: ListNode, words: { searchFor: string } = { searchFor: 'Search {field} for: {text}' }): Suggestion[] {\n const text = typed.trim();\n if (!text) return [];\n const found: Suggestion[] = [];\n for (const field of list.searchFields ?? list.columns) {\n const def = page.fields[field];\n if (!def) continue;\n const say = (op: Suggestion['op'], value: JsonValue, valueLabel: string, label?: string) =>\n found.push({ field, fieldLabel: def.label, op, value, valueLabel, label: label ?? fill(words.searchFor, { field: def.label, text }) });\n if (TEXT.has(def.type) || LINK.has(def.type)) say('ilike', text, text);\n else if (def.type === 'selection') {\n const lower = text.toLowerCase();\n for (const option of def.options) if (option.label.toLowerCase().includes(lower)) say('=', option.value, option.label, `${def.label}: ${option.label}`);\n } else if (NUMBER.has(def.type)) {\n const number = Number(text.replace(/[\\s,]/g, ''));\n if (text && Number.isFinite(number)) say('=', number, text);\n }\n }\n // Text fields first, then the choices, then the links: the order a person looks in.\n const rank = (s: Suggestion) => {\n const type = page.fields[s.field]?.type ?? '';\n return TEXT.has(type) ? 0 : type === 'selection' ? 1 : NUMBER.has(type) ? 2 : 3;\n };\n return found.map((s, i) => ({ s, i })).sort((a, b) => rank(a.s) - rank(b.s) || a.i - b.i).map(({ s }) => s);\n}\n\n/** The filter a list's facets make: the values of one field any of them, named filters any of them, the facets all together. */\nexport function facetsToFilter(facets: readonly Facet[], list: ListNode): ResolvedFilter[] {\n const filter: ResolvedFilter[] = [];\n for (const facet of facets) {\n if (facet.kind === 'field') {\n const conditions = facet.values.map((v) => ({ field: facet.field, op: v.op, value: v.value }));\n filter.push(conditions.length === 1 ? conditions[0] : { any: conditions });\n } else if (facet.kind === 'filters') {\n // A list's own filters have no valueFrom: their conditions are already values.\n const chosen = facet.ids.map((id) => (list.filters?.find((f) => f.id === id)?.filter ?? []) as ResolvedFilter[]).filter((items) => items.length);\n if (chosen.length === 1) filter.push(...chosen[0]);\n else if (chosen.length > 1) filter.push({ any: chosen.map((items) => (items.length === 1 ? items[0] : { all: items })) });\n } else if (facet.kind === 'custom') {\n filter.push(...facet.filter);\n }\n }\n return filter;\n}\n\n/** The fields a list is grouped by, in order, from its Group By facet. */\nexport function groupByFields(facets: readonly Facet[]): string[] {\n return facets.find((f): f is Extract<Facet, { kind: 'groupBy' }> => f.kind === 'groupBy')?.fields ?? [];\n}\n", "/**\n * Timers, injected. Core compiles without the DOM or Node's types, and tests\n * drive time by hand instead of waiting for it.\n */\nexport interface Scheduler {\n setTimeout(callback: () => void, ms: number): unknown;\n clearTimeout(handle: unknown): void;\n}\n\ninterface HostTimers {\n setTimeout(callback: () => void, ms: number): unknown;\n clearTimeout(handle: unknown): void;\n}\n\n/** The host's own timers: the browser's or Node's, whichever is running. */\nexport const hostScheduler: Scheduler = {\n setTimeout: (callback, ms) => (globalThis as unknown as HostTimers).setTimeout(callback, ms),\n clearTimeout: (handle) => (globalThis as unknown as HostTimers).clearTimeout(handle),\n};\n\n/** Resolve after `ms`, on the given scheduler. */\nexport function wait(ms: number, scheduler: Scheduler = hostScheduler): Promise<void> {\n return new Promise((resolve) => {\n scheduler.setTimeout(resolve, ms);\n });\n}\n", "import type { Field, Fields } from '../format/field';\nimport type { JsonValue } from '../format/json';\nimport type {\n DataSource,\n Group,\n GroupRequest,\n ListRequest,\n ListResult,\n LineOp,\n LinkOp,\n LoadRequest,\n OnchangeRequest,\n OnchangeResult,\n SaveRequest,\n SaveResult,\n SearchRequest,\n CreateRequest,\n SubmitRequest,\n SubmitResult,\n} from './data-source';\nimport { matchesFilter } from './filter';\nimport { wait, type Scheduler } from './scheduler';\nimport { structuredCopy, type Line, type RecordId, type RelatedRecord, type Value, type Values } from './values';\n\nexport interface MemoryDataSourceOptions {\n /** Records by model, then by id. */\n records?: Record<string, Record<string, Values>>;\n /** Recalculation rules by model, then by the field that changed. */\n onchange?: Record<string, Record<string, (values: Values) => Values>>;\n /** Warnings by model, then by the field that changed: a message, or null for none. */\n warnings?: Record<string, Record<string, (values: Values) => string | null>>;\n /** Which value names a record in search results, per model. Defaults to `name`. */\n labelField?: Record<string, string>;\n /** Answer after this long, so a demo shows its loading states. */\n delayMs?: number;\n scheduler?: Scheduler;\n}\n\nexport interface MemoryDataSource extends Required<DataSource> {\n readonly records: Record<string, Record<string, Values>>;\n readonly responses: SubmitRequest[];\n readonly calls: { method: keyof DataSource; request: unknown }[];\n}\n\n/**\n * A data source that keeps everything in memory. It implements the whole\n * interface, the way a backend would, so tests and demos exercise the same\n * paths a real adapter takes.\n */\nexport function createMemoryDataSource(options: MemoryDataSourceOptions = {}): MemoryDataSource {\n const records = structuredCopy(options.records ?? {});\n const responses: SubmitRequest[] = [];\n const calls: MemoryDataSource['calls'] = [];\n let lineIds = 1000;\n\n const pause = () => (options.delayMs ? wait(options.delayMs, options.scheduler) : Promise.resolve());\n const table = (model: string) => (records[model] ??= {});\n const labelOf = (model: string, id: RecordId) => {\n const value = table(model)[String(id)]?.[options.labelField?.[model] ?? 'name'];\n return typeof value === 'string' ? value : String(id);\n };\n const nextId = (model: string) => Math.max(0, ...Object.keys(table(model)).map(Number).filter(Number.isFinite)) + 1;\n const asId = (key: string): RecordId => (Number.isFinite(Number(key)) ? Number(key) : key);\n\n function applyLines(current: Line[], ops: LineOp[]): Line[] {\n let lines = [...current];\n for (const op of ops) {\n if (op.op === 'create') lines.push({ key: op.key, id: ++lineIds, values: structuredCopy(op.values) });\n else if (op.op === 'update') lines = lines.map((l) => (l.id === op.id ? { ...l, values: { ...l.values, ...structuredCopy(op.values) } } : l));\n else lines = lines.filter((l) => l.id !== op.id);\n }\n return lines;\n }\n\n function applyLinks(current: RelatedRecord[], ops: LinkOp[], model: string): RelatedRecord[] {\n let links = [...current];\n const related = (id: RecordId): RelatedRecord => ({ id, label: labelOf(model, id) });\n for (const op of ops) {\n if (op.op === 'link' && !links.some((r) => r.id === op.id)) links.push(related(op.id));\n else if (op.op === 'unlink') links = links.filter((r) => r.id !== op.id);\n else if (op.op === 'set') links = op.ids.map(related);\n else if (op.op === 'clear') links = [];\n }\n return links;\n }\n\n function relationOf(fields: Fields, name: string): string {\n const field: Field | undefined = fields[name];\n return field && 'relation' in field ? field.relation : name;\n }\n\n return {\n records,\n responses,\n calls,\n\n async load(request: LoadRequest): Promise<Values> {\n calls.push({ method: 'load', request });\n await pause();\n const stored = table(request.model)[String(request.id)];\n if (!stored) throw new Error(`No ${request.model} record with id ${request.id}`);\n return structuredCopy(stored);\n },\n\n async save(request: SaveRequest): Promise<SaveResult> {\n calls.push({ method: 'save', request });\n await pause();\n const id = request.id ?? nextId(request.model);\n const stored: Values = { ...(table(request.model)[String(id)] ?? {}), ...structuredCopy(request.changes.values) };\n for (const [name, ops] of Object.entries(request.changes.lines)) {\n stored[name] = applyLines((stored[name] as Line[] | undefined) ?? [], ops);\n }\n for (const [name, ops] of Object.entries(request.changes.links)) {\n stored[name] = applyLinks((stored[name] as RelatedRecord[] | undefined) ?? [], ops, relationOf(request.fields, name));\n }\n table(request.model)[String(id)] = stored;\n return { id, values: structuredCopy(stored) };\n },\n\n async onchange(request: OnchangeRequest): Promise<OnchangeResult> {\n calls.push({ method: 'onchange', request });\n await pause();\n const rule = options.onchange?.[request.model]?.[request.changed];\n const warn = options.warnings?.[request.model]?.[request.changed];\n const result: OnchangeResult = rule ? { values: rule(structuredCopy(request.values)) } : {};\n const warning = warn?.(structuredCopy(request.values));\n return warning ? { ...result, warning } : result;\n },\n\n async search(request: SearchRequest): Promise<RelatedRecord[]> {\n calls.push({ method: 'search', request });\n await pause();\n const query = request.query.trim().toLowerCase();\n return Object.entries(table(request.model))\n .filter(([, values]) => matchesFilter(values, request.filter ?? []))\n .map(([key]) => ({ id: asId(key), label: labelOf(request.model, asId(key)) }))\n .filter((record) => record.label.toLowerCase().includes(query))\n .slice(0, request.limit ?? 8);\n },\n\n async list(request: ListRequest): Promise<ListResult> {\n calls.push({ method: 'list', request });\n await pause();\n const matching = Object.entries(table(request.model))\n .filter(([, values]) => matchesFilter(values, request.filter))\n .map(([key, values]) => ({ id: asId(key), values }));\n matching.sort((a, b) => {\n for (const order of request.sort) {\n const compared = compareValues(a.values[order.field], b.values[order.field]);\n // Empty last, whichever way the rest goes.\n if (compared.empty) return compared.result;\n if (compared.result) return order.desc ? -compared.result : compared.result;\n }\n return 0;\n });\n return {\n total: matching.length,\n records: matching.slice(request.offset, request.offset + request.limit).map(({ id, values }) => ({\n id,\n values: Object.fromEntries(request.fields.map((field) => [field, structuredCopy(values[field] ?? null) as Value])),\n })),\n };\n },\n\n async groups(request: GroupRequest): Promise<Group[]> {\n calls.push({ method: 'groups', request });\n await pause();\n const counted = new Map<string, Group>();\n for (const values of Object.values(table(request.model))) {\n if (!matchesFilter(values, request.filter)) continue;\n const raw = values[request.field] ?? null;\n const link = raw !== null && typeof raw === 'object' && !Array.isArray(raw) && 'id' in raw ? (raw as RelatedRecord) : null;\n const value = (link ? link.id : raw) as JsonValue;\n const key = JSON.stringify(value);\n const group = counted.get(key) ?? { value, label: link ? link.label : raw === null || raw === '' ? '' : String(raw), count: 0 };\n group.count++;\n counted.set(key, group);\n }\n return [...counted.values()].sort((a, b) => (a.value === null) === (b.value === null) ? a.label.localeCompare(b.label) : a.value === null ? 1 : -1);\n },\n\n async create(request: CreateRequest): Promise<RelatedRecord> {\n calls.push({ method: 'create', request });\n await pause();\n const rows = table(request.model);\n const id = Object.keys(rows).reduce((top, key) => Math.max(top, Number(key) || 0), 0) + 1;\n rows[String(id)] = { name: request.name };\n return { id, label: request.name };\n },\n\n async submit(request: SubmitRequest): Promise<SubmitResult> {\n calls.push({ method: 'submit', request });\n await pause();\n responses.push(structuredCopy(request));\n return { id: responses.length };\n },\n };\n}\n\n/** Two values in order: a link by its label, text by the reader's rules, numbers by size; `empty` says one of them had nothing. */\nfunction compareValues(a: unknown, b: unknown): { result: number; empty: boolean } {\n const blank = (v: unknown) => v === null || v === undefined || v === '';\n if (blank(a) || blank(b)) return { result: blank(a) === blank(b) ? 0 : blank(a) ? 1 : -1, empty: blank(a) !== blank(b) };\n const label = (v: unknown) => (typeof v === 'object' && v !== null && 'label' in v ? (v as RelatedRecord).label : v);\n const [x, y] = [label(a), label(b)];\n if (typeof x === 'number' && typeof y === 'number') return { result: x - y, empty: false };\n return { result: String(x).localeCompare(String(y)), empty: false };\n}\n", "import type { Field, FilterItem, LineField } from '../format/field';\nimport type { JsonValue } from '../format/json';\nimport type { ButtonNode, LayoutNode, Modifier, RootLayout, StatButton, StepNode } from '../format/layout';\nimport type { Page } from '../format/page';\nimport { compileModifier, type CompiledModifier } from '../expression/modifier';\nimport { checkValue } from './check';\nimport { MESSAGES, type Messages } from './messages';\nimport { saveProblemOf, type DataSource, type LineOp, type LinkOp, type RecordChanges, type ResolvedFilter, type SaveProblem } from './data-source';\nimport { hostScheduler, type Scheduler } from './scheduler';\nimport {\n emptyValue,\n expressionContext,\n initialValues,\n isEmpty,\n lineKind,\n structuredCopy,\n type Line,\n type RecordId,\n type RelatedRecord,\n type Value,\n type Values,\n} from './values';\n\nexport type FormStatus = 'idle' | 'loading' | 'ready' | 'saving' | 'saved' | 'error';\n\nexport interface FormState {\n readonly status: FormStatus;\n readonly recordId: RecordId | null;\n readonly values: Readonly<Values>;\n /** Messages by field name; a line's field is `field.lineKey.subfield`. */\n readonly errors: Readonly<Record<string, string>>;\n /** Fields that differ from the record as loaded or last saved. */\n readonly dirty: readonly string[];\n /** A warning from the data source's onchange, shown without blocking. */\n readonly warning: string | null;\n /** The field whose change brought the warning, so it can be shown beside it. */\n readonly warningField: string | null;\n /** Why loading or saving failed. */\n readonly error: string | null;\n /** A saved draft that can be restored. */\n readonly draft: { savedAt: string } | null;\n /** The wizard step on screen, for a wizard page. */\n readonly step: string | null;\n /** Optional steps passed over with Skip: their answers are left out, and not asked for. */\n readonly skipped: readonly string[];\n /** Why the last save was refused, until the next one starts or the form is reset. */\n readonly saveProblem: SaveProblem | null;\n}\n\n/** What a layout element looks like right now. */\nexport interface NodeState {\n invisible: boolean;\n readonly: boolean;\n required: boolean;\n}\n\n/** localStorage fits this, and so does anything else with the same three methods. */\nexport interface DraftStore {\n getItem(key: string): string | null;\n setItem(key: string, value: string): void;\n removeItem(key: string): void;\n}\n\nexport interface ActionRequest {\n /** The button or stat button pressed. */\n id: string;\n action: string;\n params?: { [key: string]: JsonValue };\n recordId: RecordId | null;\n values: Values;\n /** The records chosen in a list, when the button belongs to one. */\n recordIds?: RecordId[];\n}\n\nexport interface FormOptions {\n page: Page;\n dataSource?: DataSource;\n /** The record to edit. Leave out for a new record or a survey. */\n recordId?: RecordId | null;\n /** Values to start with, on top of each field's default. */\n values?: Values;\n /** What a button does. Fieldia hands the press over; the app decides. */\n onAction?: (request: ActionRequest) => void | Promise<void>;\n drafts?: { store: DraftStore; restore?: 'auto' | 'ask'; delayMs?: number };\n autosave?: { delayMs: number };\n scheduler?: Scheduler;\n /** Validation messages in the page's language. English by default. */\n messages?: Messages;\n}\n\nexport interface Form {\n readonly page: Page;\n getState(): FormState;\n subscribe(listener: (state: FormState) => void): () => void;\n load(): Promise<void>;\n setValue(name: string, value: Value): void;\n node(id: string): NodeState;\n fieldReadonly(name: string): boolean;\n /** What a field would be told if the form were checked now, or null when it passes. Nothing is shown. */\n problem(field: string): string | null;\n validate(): boolean;\n save(): Promise<boolean>;\n reset(): void;\n changes(): RecordChanges;\n addLine(field: string, values?: Values): string;\n updateLine(field: string, key: string, name: string, value: Value): void;\n removeLine(field: string, key: string): void;\n /** Move a line to another place among its lines, numbering its sequence field again. */\n moveLine(field: string, key: string, to: number): void;\n /**\n * What a line would become with these values once the data source's onchange\n * has run, as a line edited in a dialog shows its subtotal follow. Nothing is\n * written: the record, its changes and its autosave stay as they are.\n */\n previewLine(field: string, key: string, values: Values): Promise<Values>;\n /** Records a many2one, many2many or reference may point to. A reference needs `options.model`. */\n search(field: string, query: string, limit?: number, options?: { model?: string }): Promise<RelatedRecord[]>;\n /** The same, for a relation inside a one2many line, filtered by that line's values. */\n searchLine(field: string, key: string, subfield: string, query: string, limit?: number): Promise<RelatedRecord[]>;\n /** Whether a link field can make a record from a typed name: the data source must be able to. */\n canCreate(field: string): boolean;\n /** Make a record from a typed name, for the link field to point to. */\n quickCreate(field: string, name: string): Promise<RelatedRecord>;\n /** The same, for a link inside a one2many's lines. */\n canCreateLine(field: string, subfield: string): boolean;\n quickCreateLine(field: string, subfield: string, name: string): Promise<RelatedRecord>;\n steps(): string[];\n next(): boolean;\n back(): boolean;\n /** Pass over the step on screen, when it is optional and not the last one. */\n skip(): boolean;\n /**\n * Go to a step that applies. Back, at once; forward, only past steps that are\n * complete: it stops at the first one with a problem and shows it, and skips\n * an optional one instead.\n */\n goTo(step: string): boolean;\n /** Run a button; a list's button passes the records chosen in it. */\n runAction(id: string, chosen?: { recordIds: RecordId[] }): Promise<void>;\n restoreDraft(): void;\n discardDraft(): void;\n /** Resolves once every onchange, save and autosave started so far has finished. */\n settled(): Promise<void>;\n dispose(): void;\n}\n\ninterface IndexedNode {\n id: string;\n parent: string | null;\n kind: 'field' | 'button' | 'stat' | 'other' | 'step';\n field?: string;\n invisible: CompiledModifier;\n readonly: CompiledModifier;\n required: CompiledModifier;\n source: LayoutNode | StepNode | ButtonNode | StatButton | RootLayout | { id: string; invisible?: Modifier };\n}\n\n/**\n * The record state behind a page: values, what changed, what is visible and\n * required, errors, loading and saving. No DOM and no framework \u2014 every\n * binding renders from `getState()` and calls these methods.\n */\nexport function createForm(options: FormOptions): Form {\n const { page } = options;\n const scheduler = options.scheduler ?? hostScheduler;\n const messages = options.messages ?? MESSAGES.en;\n const index = indexLayout(page.layout);\n const steps = page.layout.type === 'wizard' ? page.layout.children.map((step) => step.id) : [];\n const draftKey = () => `fieldia:draft:${page.id}:${state.recordId ?? 'new'}`;\n\n let baseline: Values = { ...initialValues(page.fields), ...structuredCopy(options.values ?? {}) };\n let state: FormState = {\n status: options.recordId != null ? 'idle' : 'ready',\n recordId: options.recordId ?? null,\n values: structuredCopy(baseline),\n errors: {},\n dirty: [],\n warning: null,\n warningField: null,\n error: null,\n draft: null,\n step: steps[0] ?? null,\n skipped: [],\n saveProblem: null,\n };\n /** Field errors a refused save brought, each kept until its field changes from the value it was refused with. */\n let serverErrors: Record<string, { message: string; value: string }> = {};\n let lineKeys = 0;\n let onchangeSeq = 0;\n let draftTimer: unknown = null;\n let autosaveTimer: unknown = null;\n const pending = new Set<Promise<unknown>>();\n const listeners = new Set<(state: FormState) => void>();\n let contextCache: { values: Values; context: Record<string, unknown> } | null = null;\n\n function set(patch: Partial<FormState>) {\n state = { ...state, ...patch };\n for (const listener of [...listeners]) listener(state);\n }\n\n function track<T>(promise: Promise<T>): Promise<T> {\n pending.add(promise);\n const done = () => pending.delete(promise);\n promise.then(done, done);\n return promise;\n }\n\n function context(): Record<string, unknown> {\n if (contextCache?.values !== state.values) {\n contextCache = { values: state.values as Values, context: expressionContext(state.values as Values, page.fields) };\n }\n return contextCache.context;\n }\n\n function fieldDef(name: string): Field {\n const def = page.fields[name];\n if (!def) throw new Error(`The page has no field \"${name}\"`);\n return def;\n }\n\n function dirtyFields(values: Values): string[] {\n return Object.keys(page.fields).filter((name) => JSON.stringify(values[name] ?? null) !== JSON.stringify(baseline[name] ?? null));\n }\n\n function nodeState(id: string): NodeState {\n const node = index.get(id);\n if (!node) throw new Error(`The page has no element \"${id}\"`);\n const ctx = context();\n let invisible = node.invisible.evaluate(ctx);\n for (let parent = node.parent; !invisible && parent; parent = index.get(parent)?.parent ?? null) {\n invisible = index.get(parent)?.invisible.evaluate(ctx) ?? false;\n }\n // A section read-only right now makes everything inside it read-only too.\n let readonly = node.readonly.evaluate(ctx);\n for (let parent = node.parent; !readonly && parent; parent = index.get(parent)?.parent ?? null) {\n readonly = index.get(parent)?.readonly.evaluate(ctx) ?? false;\n }\n const def = node.field ? page.fields[node.field] : undefined;\n return {\n invisible,\n readonly: readonly || def?.readonly === true,\n required: node.required.evaluate(ctx) || def?.required === true,\n };\n }\n\n /** Field nodes inside `root` (or the whole page), visible right now. */\n function visibleFieldNodes(root?: string): IndexedNode[] {\n const inside = (node: IndexedNode) => {\n if (!root) return true;\n for (let at: string | null = node.id; at; at = index.get(at)?.parent ?? null) if (at === root) return true;\n return false;\n };\n // The whole page leaves out the steps passed over with Skip.\n const skipped = (node: IndexedNode) => {\n if (root || !state.skipped.length) return false;\n for (let at: string | null = node.id; at; at = index.get(at)?.parent ?? null) if (state.skipped.includes(at)) return true;\n return false;\n };\n return [...index.values()].filter((node) => node.kind === 'field' && inside(node) && !skipped(node) && !nodeState(node.id).invisible);\n }\n\n /** Errors for the visible fields under `root`, without publishing them. */\n function collectErrors(root?: string): Record<string, string> {\n const errors: Record<string, string> = {};\n for (const node of visibleFieldNodes(root)) {\n const name = node.field as string;\n if (errors[name]) continue;\n const def = page.fields[name];\n const message = checkValue(def, state.values[name], nodeState(node.id).required, messages);\n if (message) errors[name] = message;\n if (def.type === 'one2many') {\n for (const line of (state.values[name] as Line[] | null) ?? []) {\n // A section or note answers only for its text, never for what an item needs.\n const kind = lineKind(def, line.values);\n for (const [sub, subDef] of Object.entries(def.fields)) {\n if (kind && sub !== def.lineKinds?.text) continue;\n const lineMessage = checkValue(subDef, line.values[sub], subDef.required === true, messages);\n if (lineMessage) errors[`${name}.${line.key}.${sub}`] = lineMessage;\n }\n }\n }\n }\n return errors;\n }\n\n function writeValues(values: Values, extra: Partial<FormState> = {}) {\n const errors = Object.keys(state.errors).length ? revalidateShown(values) : state.errors;\n set({ values, dirty: dirtyFields(values), errors, ...extra });\n }\n\n /** Once errors are on screen, keep them current as the person fixes things. */\n function revalidateShown(values: Values): Record<string, string> {\n const previous = state;\n state = { ...state, values };\n const fresh = collectErrors(state.step ?? undefined);\n state = previous;\n const kept: Record<string, string> = {};\n for (const key of Object.keys(state.errors)) if (fresh[key]) kept[key] = fresh[key];\n for (const [name, refused] of Object.entries(serverErrors)) {\n if (JSON.stringify(values[name] ?? null) === refused.value) kept[name] ??= refused.message;\n else delete serverErrors[name];\n }\n return kept;\n }\n\n function scheduleDraft() {\n const drafts = options.drafts;\n if (!drafts) return;\n if (draftTimer !== null) scheduler.clearTimeout(draftTimer);\n draftTimer = scheduler.setTimeout(() => {\n draftTimer = null;\n drafts.store.setItem(draftKey(), JSON.stringify({ savedAt: new Date().toISOString(), values: state.values }));\n }, drafts.delayMs ?? 400);\n }\n\n function forgetDraft() {\n if (draftTimer !== null) scheduler.clearTimeout(draftTimer);\n draftTimer = null;\n options.drafts?.store.removeItem(draftKey());\n }\n\n function offerDraft() {\n const drafts = options.drafts;\n if (!drafts) return;\n const raw = drafts.store.getItem(draftKey());\n if (!raw) return;\n let draft: { savedAt: string; values: Values };\n try {\n draft = JSON.parse(raw);\n } catch {\n drafts.store.removeItem(draftKey());\n return;\n }\n if (drafts.restore === 'auto') writeValues({ ...state.values, ...draft.values }, { draft: null });\n else set({ draft: { savedAt: draft.savedAt } });\n }\n\n function scheduleAutosave() {\n const autosave = options.autosave;\n if (!autosave || page.data.kind !== 'record') return;\n if (autosaveTimer !== null) scheduler.clearTimeout(autosaveTimer);\n autosaveTimer = scheduler.setTimeout(() => {\n autosaveTimer = null;\n if (state.dirty.length && Object.keys(collectErrors()).length === 0) void track(save());\n }, autosave.delayMs);\n }\n\n function runOnchange(changed: string) {\n const source = options.dataSource;\n if (!source?.onchange || page.data.kind !== 'record') return;\n const seq = ++onchangeSeq;\n const request = { model: page.data.model, id: state.recordId, changed, values: structuredCopy(state.values as Values) };\n void track(\n source.onchange(request).then(\n (result) => {\n if (seq !== onchangeSeq) return;\n const values = { ...(state.values as Values), ...(result.values ?? {}) };\n writeValues(values, { warning: result.warning ?? null, warningField: result.warning ? changed : null });\n },\n () => undefined\n )\n );\n }\n\n function afterEdit(changed: string) {\n scheduleDraft();\n scheduleAutosave();\n runOnchange(changed);\n }\n\n function changes(): RecordChanges {\n const result: RecordChanges = { values: {}, lines: {}, links: {} };\n // A new record sends every value it holds, those it started with and defaults\n // included; a stored one sends only what changed since it was loaded.\n const creating = state.recordId === null || state.recordId === undefined;\n const names = creating\n ? Object.keys(page.fields).filter((name) => state.dirty.includes(name) || !isEmpty(page.fields[name], state.values[name]))\n : state.dirty;\n for (const name of names) {\n const def = page.fields[name];\n const now = state.values[name];\n const before = creating ? emptyValue(def) : baseline[name];\n if (def.type === 'one2many') result.lines[name] = lineOps((before as Line[] | null) ?? [], (now as Line[] | null) ?? []);\n else if (def.type === 'many2many') result.links[name] = linkOps((before as RelatedRecord[] | null) ?? [], (now as RelatedRecord[] | null) ?? []);\n else result.values[name] = structuredCopy(now) as Value;\n }\n return result;\n }\n\n /** The values to submit: only fields a visible question shows. */\n function shownValues(): Values {\n const shown: Values = {};\n for (const node of visibleFieldNodes()) {\n const name = node.field as string;\n shown[name] = structuredCopy(state.values[name]) as Value;\n }\n return shown;\n }\n\n async function save(): Promise<boolean> {\n const errors = collectErrors();\n if (Object.keys(errors).length) {\n set({ errors });\n return false;\n }\n const source = options.dataSource;\n serverErrors = {};\n set({ status: 'saving', errors: {}, error: null, saveProblem: null });\n try {\n if (page.data.kind === 'responses') {\n if (!source?.submit) throw new Error('This page has no data source to send its answers to');\n await source.submit({ pageId: page.id, values: shownValues() });\n forgetDraft();\n set({ status: 'saved' });\n return true;\n }\n if (!source?.save) throw new Error('This page has no data source to save to');\n const result = await source.save({\n model: page.data.model,\n id: state.recordId,\n fields: page.fields,\n changes: changes(),\n values: structuredCopy(state.values as Values),\n });\n forgetDraft();\n const values = result.values ? { ...(state.values as Values), ...result.values } : (state.values as Values);\n baseline = structuredCopy(values);\n set({ status: 'saved', recordId: result.id, values, dirty: [] });\n return true;\n } catch (error) {\n const problem = saveProblemOf(error);\n const fields = problem.kind === 'fields' ? problem.fields ?? {} : {};\n serverErrors = Object.fromEntries(Object.entries(fields).map(([name, message]) => [name, { message, value: JSON.stringify(state.values[name] ?? null) }]));\n set({ status: 'error', error: problem.message, saveProblem: problem, errors: { ...fields } });\n return false;\n }\n }\n\n /** The model a link field's new record belongs to, or null when it cannot make one. */\n function creatable(def: Field | LineField | undefined): string | null {\n if (!options.dataSource?.create || !def || def.readonly) return null;\n return def.type === 'many2one' || def.type === 'many2many' ? def.relation : null;\n }\n\n async function runCreate(def: Field | LineField | undefined, name: string, typed: string): Promise<RelatedRecord> {\n const model = creatable(def);\n const source = options.dataSource;\n if (!model || !source?.create) throw new Error(`\"${name}\" cannot make records: its data source has no create, or it is not a link`);\n return track(source.create({ model, name: typed.trim() }));\n }\n\n async function runSearch(\n def: Field | LineField,\n name: string,\n ctx: Record<string, unknown>,\n query: string,\n limit: number,\n model?: string\n ): Promise<RelatedRecord[]> {\n if (def.type !== 'many2one' && def.type !== 'many2many' && def.type !== 'reference') {\n throw new Error(`\"${name}\" is not a many2one, many2many or reference`);\n }\n if (def.type === 'reference' && !model) throw new Error(`Searching \"${name}\" needs a model`);\n const source = options.dataSource;\n if (!source?.search) return [];\n // Every valueFrom, in groups too, becomes the value it names before the search goes out.\n const resolve = (item: FilterItem): ResolvedFilter =>\n 'any' in item\n ? { any: item.any.map(resolve) }\n : 'all' in item\n ? { all: item.all.map(resolve) }\n : { field: item.field, op: item.op, value: (item.valueFrom !== undefined ? ctx[item.valueFrom] ?? null : item.value ?? null) as JsonValue };\n const filter: ResolvedFilter[] | undefined = def.type === 'reference' ? undefined : def.filter?.map(resolve);\n const relation = def.type === 'reference' ? (model as string) : def.relation;\n return track(source.search({ model: relation, query, ...(filter ? { filter } : {}), limit }));\n }\n\n function lineField(field: string) {\n const def = fieldDef(field);\n if (def.type !== 'one2many') throw new Error(`\"${field}\" is a ${def.type}, not a one2many`);\n return def;\n }\n\n function stepIndex(): number {\n return state.step ? steps.indexOf(state.step) : -1;\n }\n\n /** Whether a step can be passed over with Skip. */\n function optionalStep(id: string): boolean {\n return (index.get(id)?.source as { optional?: boolean } | undefined)?.optional === true;\n }\n\n async function load(): Promise<void> {\n const source = options.dataSource;\n if (state.recordId == null || page.data.kind !== 'record') return;\n if (!source?.load) {\n set({ status: 'error', error: 'This page has no data source to load from' });\n return;\n }\n set({ status: 'loading', error: null });\n try {\n const loaded = await source.load({ model: page.data.model, id: state.recordId, fields: page.fields });\n baseline = { ...initialValues(page.fields), ...loaded };\n set({ status: 'ready', values: structuredCopy(baseline), dirty: [], errors: {} });\n offerDraft();\n } catch (error) {\n set({ status: 'error', error: (error as Error).message });\n }\n }\n\n const form: Form = {\n page,\n getState: () => state,\n\n subscribe(listener) {\n listeners.add(listener);\n return () => listeners.delete(listener);\n },\n\n load: () => track(load()),\n\n setValue(name, value) {\n fieldDef(name);\n writeValues({ ...(state.values as Values), [name]: structuredCopy(value) });\n afterEdit(name);\n },\n\n node: nodeState,\n\n fieldReadonly: (name) => fieldDef(name).readonly === true,\n\n problem(name) {\n const def = fieldDef(name);\n // Only a field someone can see is asked anything, and required wherever it is shown so.\n const shown = visibleFieldNodes().filter((node) => node.field === name);\n if (!shown.length) return null;\n return checkValue(def, state.values[name], shown.some((node) => nodeState(node.id).required), messages) ?? null;\n },\n\n validate() {\n const errors = collectErrors();\n set({ errors });\n return Object.keys(errors).length === 0;\n },\n\n save: () => track(save()),\n\n reset() {\n forgetDraft();\n serverErrors = {};\n set({ values: structuredCopy(baseline), dirty: [], errors: {}, warning: null, warningField: null, draft: null, step: steps[0] ?? null, skipped: [], saveProblem: null });\n },\n\n changes,\n\n addLine(field, values = {}) {\n const def = lineField(field);\n const key = `new-${++lineKeys}`;\n const current = (state.values[field] as Line[] | null) ?? [];\n const line: Line = { key, values: { ...initialValues(def.fields as Record<string, LineField>), ...structuredCopy(values) } };\n // A new line comes last, so it is numbered after the last.\n if (def.sequenceField && line.values[def.sequenceField] == null) {\n const numbers = current.map((l) => l.values[def.sequenceField as string]).filter((n): n is number => typeof n === 'number');\n line.values[def.sequenceField] = numbers.length ? Math.max(...numbers) + 1 : 1;\n }\n const lines = [...current, line];\n writeValues({ ...(state.values as Values), [field]: lines });\n afterEdit(field);\n return key;\n },\n\n updateLine(field, key, name, value) {\n const def = lineField(field);\n if (!def.fields[name]) throw new Error(`The lines of \"${field}\" have no field \"${name}\"`);\n const lines = ((state.values[field] as Line[] | null) ?? []).map((line) =>\n line.key === key ? { ...line, values: { ...line.values, [name]: structuredCopy(value) } } : line\n );\n writeValues({ ...(state.values as Values), [field]: lines });\n afterEdit(field);\n },\n\n moveLine(field, key, to) {\n const def = lineField(field);\n const sequence = def.sequenceField;\n if (!sequence) throw new Error(`The lines of \"${field}\" keep no order: give the field a sequenceField`);\n const lines = [...((state.values[field] as Line[] | null) ?? [])];\n const from = lines.findIndex((line) => line.key === key);\n if (from < 0) throw new Error(`\"${field}\" has no line \"${key}\"`);\n const target = Math.max(0, Math.min(to, lines.length - 1));\n if (target === from) return;\n // The numbers can be reused only if they rise with the lines as shown.\n const before = lines.map((line) => line.values[sequence]);\n const trusted = before.every((n, i) => typeof n === 'number' && (i === 0 || n > (before[i - 1] as number)));\n lines.splice(target, 0, ...lines.splice(from, 1));\n // The lines that moved take the numbers they held between them, in their\n // new order, and the rest keep theirs; otherwise every line is numbered\n // afresh, 1, 2, 3\u2026, so the order saved is the order shown.\n const low = Math.min(from, target);\n const high = Math.max(from, target);\n const pool = trusted ? (before.slice(low, high + 1) as number[]) : [];\n const renumbered = lines.map((line, i) => {\n const value = trusted ? (i >= low && i <= high ? pool[i - low] : line.values[sequence]) : i + 1;\n return value === line.values[sequence] ? line : { ...line, values: { ...line.values, [sequence]: value } };\n });\n writeValues({ ...(state.values as Values), [field]: renumbered });\n afterEdit(field);\n },\n\n removeLine(field, key) {\n lineField(field);\n const lines = ((state.values[field] as Line[] | null) ?? []).filter((line) => line.key !== key);\n writeValues({ ...(state.values as Values), [field]: lines });\n afterEdit(field);\n },\n\n async search(field, query, limit = 8, options = {}) {\n return runSearch(fieldDef(field), field, context(), query, limit, options.model);\n },\n\n async previewLine(field, key, values) {\n lineField(field);\n const lines = (state.values[field] as Line[] | null) ?? [];\n const line = lines.find((l) => l.key === key);\n if (!line) throw new Error(`\"${field}\" has no line \"${key}\"`);\n const merged = { ...line.values, ...values };\n const source = options.dataSource;\n if (!source?.onchange || page.data.kind !== 'record') return merged;\n const changed = lines.map((l) => (l.key === key ? { ...l, values: merged } : l));\n const result = await source.onchange({ model: page.data.model, id: state.recordId, changed: field, values: structuredCopy({ ...(state.values as Values), [field]: changed }) });\n const after = ((result.values?.[field] as Line[] | undefined) ?? []).find((l) => l.key === key);\n return after ? { ...merged, ...after.values } : merged;\n },\n\n async searchLine(field, key, subfield, query, limit = 8) {\n const def = lineField(field);\n const sub = def.fields[subfield];\n if (!sub) throw new Error(`The lines of \"${field}\" have no field \"${subfield}\"`);\n const line = ((state.values[field] as Line[] | null) ?? []).find((l) => l.key === key);\n if (!line) throw new Error(`\"${field}\" has no line \"${key}\"`);\n return runSearch(sub, subfield, expressionContext(line.values, def.fields as Record<string, LineField>), query, limit);\n },\n\n canCreate: (field) => creatable(page.fields[field]) !== null,\n quickCreate: (field, typed) => runCreate(page.fields[field], field, typed),\n canCreateLine: (field, subfield) => creatable(lineField(field).fields[subfield]) !== null,\n quickCreateLine: (field, subfield, typed) => runCreate(lineField(field).fields[subfield], subfield, typed),\n\n steps: () => steps.filter((id) => !nodeState(id).invisible),\n\n next() {\n if (!state.step) return false;\n // A step skipped before and gone back to is answered now, and checked like any other.\n if (state.skipped.includes(state.step)) set({ skipped: state.skipped.filter((id) => id !== state.step) });\n const errors = collectErrors(state.step);\n if (Object.keys(errors).length) {\n set({ errors });\n return false;\n }\n const visible = form.steps();\n const following = steps.slice(stepIndex() + 1).find((id) => visible.includes(id));\n if (!following) return false;\n set({ step: following, errors: {} });\n return true;\n },\n\n back() {\n if (!state.step) return false;\n const visible = form.steps();\n const previous = steps.slice(0, stepIndex()).reverse().find((id) => visible.includes(id));\n if (!previous) return false;\n set({ step: previous, errors: {} });\n return true;\n },\n\n skip() {\n const current = state.step;\n if (!current || !optionalStep(current)) return false;\n const visible = form.steps();\n const following = visible[visible.indexOf(current) + 1];\n if (!following) return false;\n set({ step: following, errors: {}, skipped: [...state.skipped.filter((id) => id !== current), current] });\n return true;\n },\n\n goTo(target) {\n const visible = form.steps();\n const to = visible.indexOf(target);\n const at = state.step ? visible.indexOf(state.step) : -1;\n if (to === -1 || at === -1) return false;\n if (to <= at) {\n set({ step: target, errors: {} });\n return true;\n }\n const skipped = [...state.skipped];\n for (const id of visible.slice(at, to)) {\n if (skipped.includes(id)) continue;\n const errors = collectErrors(id);\n if (!Object.keys(errors).length) continue;\n if (optionalStep(id)) {\n skipped.push(id);\n continue;\n }\n set({ step: id, errors, skipped });\n return false;\n }\n set({ step: target, errors: {}, skipped });\n return true;\n },\n\n async runAction(id, chosen) {\n const node = index.get(id);\n if (!node || (node.kind !== 'button' && node.kind !== 'stat')) throw new Error(`The page has no button \"${id}\"`);\n if (nodeState(id).invisible) return;\n const source = node.source as ButtonNode | StatButton;\n await track(\n Promise.resolve(\n options.onAction?.({\n id,\n action: source.action,\n ...('params' in source && source.params ? { params: source.params } : {}),\n recordId: state.recordId,\n values: structuredCopy(state.values as Values),\n ...(chosen ? { recordIds: [...chosen.recordIds] } : {}),\n })\n )\n );\n },\n\n restoreDraft() {\n const raw = options.drafts?.store.getItem(draftKey());\n if (!raw) return;\n const draft = JSON.parse(raw) as { values: Values };\n writeValues({ ...(state.values as Values), ...draft.values }, { draft: null });\n },\n\n discardDraft() {\n forgetDraft();\n set({ draft: null });\n },\n\n async settled() {\n while (pending.size) await Promise.allSettled([...pending]);\n },\n\n dispose() {\n if (draftTimer !== null) scheduler.clearTimeout(draftTimer);\n if (autosaveTimer !== null) scheduler.clearTimeout(autosaveTimer);\n listeners.clear();\n },\n };\n\n if (state.recordId == null) offerDraft();\n return form;\n}\n\nfunction lineOps(before: Line[], now: Line[]): LineOp[] {\n const ops: LineOp[] = [];\n const old = new Map(before.filter((line) => line.id !== undefined).map((line) => [line.key, line]));\n for (const line of now) {\n const previous = old.get(line.key);\n if (line.id === undefined || !previous) {\n ops.push({ op: 'create', key: line.key, values: structuredCopy(line.values) });\n continue;\n }\n const changed: Values = {};\n for (const [name, value] of Object.entries(line.values)) {\n if (JSON.stringify(value) !== JSON.stringify(previous.values[name])) changed[name] = structuredCopy(value) as Value;\n }\n if (Object.keys(changed).length) ops.push({ op: 'update', id: line.id, values: changed });\n }\n const kept = new Set(now.map((line) => line.key));\n for (const line of before) if (line.id !== undefined && !kept.has(line.key)) ops.push({ op: 'delete', id: line.id });\n return ops;\n}\n\nfunction linkOps(before: RelatedRecord[], now: RelatedRecord[]): LinkOp[] {\n const had = new Set(before.map((r) => r.id));\n const has = new Set(now.map((r) => r.id));\n return [\n ...now.filter((r) => !had.has(r.id)).map((r): LinkOp => ({ op: 'link', id: r.id })),\n ...before.filter((r) => !has.has(r.id)).map((r): LinkOp => ({ op: 'unlink', id: r.id })),\n ];\n}\n\nfunction indexLayout(root: RootLayout): Map<string, IndexedNode> {\n const index = new Map<string, IndexedNode>();\n const add = (\n source: IndexedNode['source'],\n parent: string | null,\n kind: IndexedNode['kind'],\n modifiers: { invisible?: Modifier; readonly?: Modifier; required?: Modifier; field?: string }\n ) => {\n index.set(source.id, {\n id: source.id,\n parent,\n kind,\n field: modifiers.field,\n invisible: compileModifier(modifiers.invisible),\n readonly: compileModifier(modifiers.readonly),\n required: compileModifier(modifiers.required),\n source,\n });\n };\n const walk = (nodes: LayoutNode[], parent: string) => {\n for (const node of nodes) {\n if (node.type === 'field') {\n add(node, parent, 'field', { invisible: node.invisible, readonly: node.readonly, required: node.required, field: node.field });\n } else if (node.type === 'button') {\n add(node, parent, 'button', { invisible: node.invisible });\n } else if (node.type === 'tabs') {\n add(node, parent, 'other', { invisible: node.invisible });\n for (const tab of node.children) {\n add(tab, node.id, 'other', { invisible: tab.invisible });\n walk(tab.children, tab.id);\n }\n } else if (node.type === 'section') {\n add(node, parent, 'other', { invisible: node.invisible, readonly: node.readonly });\n walk(node.children, node.id);\n } else {\n add(node, parent, 'other', { invisible: node.invisible });\n }\n }\n };\n\n if (root.type === 'tabs') {\n walk([root], '');\n index.get(root.id)!.parent = null;\n return index;\n }\n add(root, null, 'other', {});\n if (root.type === 'wizard') {\n for (const step of root.children) {\n add(step, root.id, 'step', { invisible: step.invisible });\n walk(step.children, step.id);\n }\n } else if (root.type === 'sections') {\n walk(root.children, root.id);\n } else if (root.type === 'list') {\n // A list holds no fields of its own record: only the buttons for what is selected.\n for (const button of root.actions ?? []) add(button, root.id, 'button', { invisible: button.invisible });\n } else {\n // The title and statusbar show fields too, so they are validated like\n // any field node. Their ids start with \"#\", which no page id can.\n const shown = (id: string, field: string | undefined) => {\n if (field) add({ id }, root.id, 'field', { field });\n };\n shown('#title', root.title?.field);\n shown('#subtitle', root.title?.subtitleField);\n shown('#avatar', root.title?.avatarField);\n shown('#statusbar', root.statusbar?.field);\n for (const button of root.buttons ?? []) add(button, root.id, 'button', { invisible: button.invisible });\n for (const stat of root.statButtons ?? []) add(stat, root.id, 'stat', { invisible: stat.invisible });\n if (root.ribbon) add(root.ribbon, root.id, 'other', { invisible: root.ribbon.invisible });\n for (const alert of root.alerts ?? []) add(alert, root.id, 'other', { invisible: alert.invisible });\n for (const badge of root.badges ?? []) add(badge, root.id, 'other', { invisible: badge.invisible });\n // Fields over and under the title are field nodes like any other.\n walk([...(root.title?.above ?? []), ...(root.title?.below ?? [])], root.id);\n walk(root.children, root.id);\n if (root.sidePanel) add(root.sidePanel, root.id, 'other', { invisible: root.sidePanel.invisible });\n }\n return index;\n}\n", "import type { Locale } from '@fieldia/core';\n\n/**\n * Numbers as a reader of the page's language writes them: grouped, with a\n * field's decimals, in Latin digits (as business software in Arabic shows\n * them), and read back the same way. Shared by the number widget, the lines\n * grid and totals.\n */\n\nconst formats = new Map<string, Intl.NumberFormat>();\nfunction format(locale: Locale, decimals: number): Intl.NumberFormat {\n const key = `${locale}:${decimals}`;\n let found = formats.get(key);\n if (!found) {\n found = new Intl.NumberFormat(locale, { numberingSystem: 'latn', minimumFractionDigits: decimals, maximumFractionDigits: decimals });\n formats.set(key, found);\n }\n return found;\n}\n\n/** The language's grouping and decimal marks. */\nfunction marks(locale: Locale): { group: string; decimal: string } {\n const parts = format(locale, 1).formatToParts(12345.6);\n return { group: parts.find((p) => p.type === 'group')?.value ?? ',', decimal: parts.find((p) => p.type === 'decimal')?.value ?? '.' };\n}\n\n/** A number at rest: \"1,850,000.50\", \"1.850.000,50\". */\nexport function formatNumber(value: number, decimals: number, locale: Locale = 'en'): string {\n return format(locale, decimals).format(value);\n}\n\n/**\n * Typed text as a number in JavaScript's own spelling (\"1234.5\"), or the text\n * unchanged when it is not one. Arabic-Indic digits are read as digits.\n */\nexport function normalizeNumber(text: string, locale: Locale = 'en'): string {\n const { group, decimal } = marks(locale);\n let out = text\n .replace(/[\u0660-\u0669]/g, (d) => String(d.charCodeAt(0) - 0x0660))\n .replace(/[\u06F0-\u06F9]/g, (d) => String(d.charCodeAt(0) - 0x06f0))\n .replace(/\u066B/g, decimal)\n .replace(/\u066C/g, group);\n // Spaces of any width group digits too (French uses a narrow no-break space).\n out = out.replace(/[\\s\\u00a0\\u202f]/g, '');\n if (group.trim()) out = out.split(group).join('');\n return decimal === '.' ? out : out.split(decimal).join('.');\n}\n", "import type { Locale } from '@fieldia/core';\n\n/** Every word a widget shows on its own. `{label}` and `{name}` are filled in. */\nexport interface WidgetLabels {\n search: string;\n noResults: string;\n remove: string;\n clear: string;\n addLine: string;\n addSection: string;\n addNote: string;\n deleteLine: string;\n /** Heads the row that adds up a table's number columns. */\n total: string;\n /** A problem on one line of a table, under the table. `{n}` counts from 1. */\n lineProblem: string;\n /** Problems beyond the first few. */\n moreProblems: string;\n /** The choice that makes a new record from what was typed. `{name}` is filled in. */\n createNamed: string;\n /** Choices at the end of a link's list, and the button that opens the linked record (`{name}`). */\n createAndEdit: string;\n searchMore: string;\n openNamed: string;\n /** The button that opens a line of a table in a dialog. */\n openLine: string;\n /** The button that lets a person hide or show a table's optional columns. */\n chooseColumns: string;\n /** The button beside a date that opens its calendar. */\n chooseDate: string;\n previousMonth: string;\n nextMonth: string;\n /** Heads the column of week numbers: short, and in full. */\n weekShort: string;\n week: string;\n /** The formatted-text toolbar and its buttons. */\n formatting: string;\n bold: string;\n italic: string;\n underline: string;\n textStyle: string;\n paragraph: string;\n heading: string;\n subheading: string;\n bulletList: string;\n numberList: string;\n alignLeft: string;\n alignCenter: string;\n alignRight: string;\n link: string;\n linkAddress: string;\n applyLink: string;\n removeLink: string;\n upload: string;\n uploadImage: string;\n replace: string;\n removeFile: string;\n dropHere: string;\n invalidJson: string;\n}\n\nexport const WIDGET_LABELS: Record<Locale, WidgetLabels> = {\n en: {\n search: 'Search\u2026',\n noResults: 'No results',\n remove: 'Remove {name}',\n clear: 'Clear {label}',\n addLine: 'Add a line',\n addSection: 'Add a section',\n addNote: 'Add a note',\n deleteLine: 'Delete line',\n total: 'Total',\n lineProblem: 'Line {n}: {message}',\n moreProblems: 'and {n} more',\n chooseColumns: 'Choose columns',\n createNamed: 'Create \u201C{name}\u201D',\n createAndEdit: 'Create and edit\u2026',\n searchMore: 'Search more\u2026',\n openNamed: 'Open {name}',\n openLine: 'Open line',\n chooseDate: 'Choose a date',\n previousMonth: 'Previous month',\n nextMonth: 'Next month',\n weekShort: 'Wk',\n week: 'Week',\n formatting: 'Formatting',\n bold: 'Bold',\n italic: 'Italic',\n underline: 'Underline',\n textStyle: 'Text style',\n paragraph: 'Paragraph',\n heading: 'Heading',\n subheading: 'Subheading',\n bulletList: 'Bulleted list',\n numberList: 'Numbered list',\n alignLeft: 'Align left',\n alignCenter: 'Align centre',\n alignRight: 'Align right',\n link: 'Link',\n linkAddress: 'Link address',\n applyLink: 'Apply',\n removeLink: 'Remove link',\n upload: 'Upload a file',\n uploadImage: 'Add a photo',\n replace: 'Replace',\n removeFile: 'Remove',\n dropHere: 'or drop it here',\n invalidJson: 'Not valid JSON',\n },\n ar: {\n search: '\u0628\u062D\u062B\u2026',\n noResults: '\u0644\u0627 \u062A\u0648\u062C\u062F \u0646\u062A\u0627\u0626\u062C',\n remove: '\u0625\u0632\u0627\u0644\u0629 {name}',\n clear: '\u0645\u0633\u062D {label}',\n addLine: '\u0625\u0636\u0627\u0641\u0629 \u0633\u0637\u0631',\n addSection: '\u0625\u0636\u0627\u0641\u0629 \u0642\u0633\u0645',\n addNote: '\u0625\u0636\u0627\u0641\u0629 \u0645\u0644\u0627\u062D\u0638\u0629',\n deleteLine: '\u062D\u0630\u0641 \u0627\u0644\u0633\u0637\u0631',\n total: '\u0627\u0644\u0625\u062C\u0645\u0627\u0644\u064A',\n lineProblem: '\u0627\u0644\u0633\u0637\u0631 {n}: {message}',\n moreProblems: '\u0648{n} \u0623\u062E\u0631\u0649',\n chooseColumns: '\u0627\u062E\u062A\u064A\u0627\u0631 \u0627\u0644\u0623\u0639\u0645\u062F\u0629',\n createNamed: '\u0625\u0646\u0634\u0627\u0621 \u00AB{name}\u00BB',\n createAndEdit: '\u0625\u0646\u0634\u0627\u0621 \u0648\u062A\u0639\u062F\u064A\u0644\u2026',\n searchMore: '\u0628\u062D\u062B \u0645\u0648\u0633\u0651\u0639\u2026',\n openNamed: '\u0641\u062A\u062D {name}',\n openLine: '\u0641\u062A\u062D \u0627\u0644\u0633\u0637\u0631',\n chooseDate: '\u0627\u062E\u062A\u064A\u0627\u0631 \u062A\u0627\u0631\u064A\u062E',\n previousMonth: '\u0627\u0644\u0634\u0647\u0631 \u0627\u0644\u0633\u0627\u0628\u0642',\n nextMonth: '\u0627\u0644\u0634\u0647\u0631 \u0627\u0644\u062A\u0627\u0644\u064A',\n weekShort: '\u0623\u0633\u0628\u0648\u0639',\n week: '\u0627\u0644\u0623\u0633\u0628\u0648\u0639',\n formatting: '\u0627\u0644\u062A\u0646\u0633\u064A\u0642',\n bold: '\u063A\u0627\u0645\u0642',\n italic: '\u0645\u0627\u0626\u0644',\n underline: '\u062A\u0633\u0637\u064A\u0631',\n textStyle: '\u0646\u0645\u0637 \u0627\u0644\u0646\u0635',\n paragraph: '\u0641\u0642\u0631\u0629',\n heading: '\u0639\u0646\u0648\u0627\u0646',\n subheading: '\u0639\u0646\u0648\u0627\u0646 \u0641\u0631\u0639\u064A',\n bulletList: '\u0642\u0627\u0626\u0645\u0629 \u0646\u0642\u0637\u064A\u0629',\n numberList: '\u0642\u0627\u0626\u0645\u0629 \u0645\u0631\u0642\u0645\u0629',\n alignLeft: '\u0645\u062D\u0627\u0630\u0627\u0629 \u0644\u0644\u064A\u0633\u0627\u0631',\n alignCenter: '\u062A\u0648\u0633\u064A\u0637',\n alignRight: '\u0645\u062D\u0627\u0630\u0627\u0629 \u0644\u0644\u064A\u0645\u064A\u0646',\n link: '\u0631\u0627\u0628\u0637',\n linkAddress: '\u0639\u0646\u0648\u0627\u0646 \u0627\u0644\u0631\u0627\u0628\u0637',\n applyLink: '\u062A\u0637\u0628\u064A\u0642',\n removeLink: '\u0625\u0632\u0627\u0644\u0629 \u0627\u0644\u0631\u0627\u0628\u0637',\n upload: '\u0631\u0641\u0639 \u0645\u0644\u0641',\n uploadImage: '\u0625\u0636\u0627\u0641\u0629 \u0635\u0648\u0631\u0629',\n replace: '\u0627\u0633\u062A\u0628\u062F\u0627\u0644',\n removeFile: '\u0625\u0632\u0627\u0644\u0629',\n dropHere: '\u0623\u0648 \u0623\u0641\u0644\u062A\u0647 \u0647\u0646\u0627',\n invalidJson: '\u0644\u064A\u0633 JSON \u0635\u0627\u0644\u062D\u064B\u0627',\n },\n de: {\n search: 'Suchen\u2026',\n noResults: 'Keine Ergebnisse',\n remove: '{name} entfernen',\n clear: '{label} leeren',\n addLine: 'Zeile hinzuf\u00FCgen',\n addSection: 'Abschnitt hinzuf\u00FCgen',\n addNote: 'Notiz hinzuf\u00FCgen',\n deleteLine: 'Zeile l\u00F6schen',\n total: 'Summe',\n lineProblem: 'Zeile {n}: {message}',\n moreProblems: 'und {n} weitere',\n chooseColumns: 'Spalten ausw\u00E4hlen',\n createNamed: '\u201E{name}\u201C anlegen',\n createAndEdit: 'Anlegen und bearbeiten\u2026',\n searchMore: 'Weitere suchen\u2026',\n openNamed: '{name} \u00F6ffnen',\n openLine: 'Zeile \u00F6ffnen',\n chooseDate: 'Datum ausw\u00E4hlen',\n previousMonth: 'Vorheriger Monat',\n nextMonth: 'N\u00E4chster Monat',\n weekShort: 'KW',\n week: 'Kalenderwoche',\n formatting: 'Formatierung',\n bold: 'Fett',\n italic: 'Kursiv',\n underline: 'Unterstrichen',\n textStyle: 'Textstil',\n paragraph: 'Absatz',\n heading: '\u00DCberschrift',\n subheading: 'Unter\u00FCberschrift',\n bulletList: 'Aufz\u00E4hlung',\n numberList: 'Nummerierte Liste',\n alignLeft: 'Linksb\u00FCndig',\n alignCenter: 'Zentriert',\n alignRight: 'Rechtsb\u00FCndig',\n link: 'Link',\n linkAddress: 'Linkadresse',\n applyLink: '\u00DCbernehmen',\n removeLink: 'Link entfernen',\n upload: 'Datei hochladen',\n uploadImage: 'Foto hinzuf\u00FCgen',\n replace: 'Ersetzen',\n removeFile: 'Entfernen',\n dropHere: 'oder hier ablegen',\n invalidJson: 'Kein g\u00FCltiges JSON',\n },\n fr: {\n search: 'Rechercher\u2026',\n noResults: 'Aucun r\u00E9sultat',\n remove: 'Retirer {name}',\n clear: 'Effacer {label}',\n addLine: 'Ajouter une ligne',\n addSection: 'Ajouter une section',\n addNote: 'Ajouter une note',\n deleteLine: 'Supprimer la ligne',\n total: 'Total',\n lineProblem: 'Ligne {n} : {message}',\n moreProblems: 'et {n} de plus',\n chooseColumns: 'Choisir les colonnes',\n createNamed: 'Cr\u00E9er \u00AB {name} \u00BB',\n createAndEdit: 'Cr\u00E9er et modifier\u2026',\n searchMore: 'Rechercher plus\u2026',\n openNamed: 'Ouvrir {name}',\n openLine: 'Ouvrir la ligne',\n chooseDate: 'Choisir une date',\n previousMonth: 'Mois pr\u00E9c\u00E9dent',\n nextMonth: 'Mois suivant',\n weekShort: 'Sem.',\n week: 'Semaine',\n formatting: 'Mise en forme',\n bold: 'Gras',\n italic: 'Italique',\n underline: 'Soulign\u00E9',\n textStyle: 'Style du texte',\n paragraph: 'Paragraphe',\n heading: 'Titre',\n subheading: 'Sous-titre',\n bulletList: 'Liste \u00E0 puces',\n numberList: 'Liste num\u00E9rot\u00E9e',\n alignLeft: 'Aligner \u00E0 gauche',\n alignCenter: 'Centrer',\n alignRight: 'Aligner \u00E0 droite',\n link: 'Lien',\n linkAddress: 'Adresse du lien',\n applyLink: 'Appliquer',\n removeLink: 'Supprimer le lien',\n upload: 'T\u00E9l\u00E9verser un fichier',\n uploadImage: 'Ajouter une photo',\n replace: 'Remplacer',\n removeFile: 'Retirer',\n dropHere: 'ou d\u00E9posez-le ici',\n invalidJson: 'JSON invalide',\n },\n};\n", "import type { FieldNode, Form, ReferenceValue, RelatedRecord } from '@fieldia/core';\nimport { WIDGET_LABELS, type WidgetLabels } from './labels';\nimport type { Widget, WidgetContext, WidgetFactory } from './widgets';\n\n/**\n * Pickers for related records: a search-as-you-type combobox (the ARIA 1.2\n * combobox pattern), tags for a many2many, and a reference picker. Results\n * come from the data source through the form, so a field's filter applies.\n */\n\nconst DEBOUNCE_MS = 180;\n/** How many matches a link's list shows, as the data source's search would. */\nconst SHOWN = 8;\n\nfunction fill(template: string, values: Record<string, string>) {\n return template.replace(/\\{(\\w+)\\}/g, (match, name: string) => values[name] ?? match);\n}\n\ninterface Combobox {\n element: HTMLElement;\n input: HTMLInputElement;\n /** Show this text when nobody is typing. */\n setText(text: string): void;\n setReadonly(readonly: boolean): void;\n close(): void;\n}\n\n/**\n * A text box with a list of matches under it. `search` finds records,\n * `pick` takes the chosen one, `exclude` hides records already chosen.\n */\nfunction combobox(options: {\n document: Document;\n id: string;\n labels: WidgetLabels;\n search: (query: string) => Promise<RelatedRecord[]>;\n pick: (record: RelatedRecord) => void;\n exclude?: () => Set<RelatedRecord['id']>;\n onEmptyBackspace?: () => void;\n onCommitEmpty?: () => void;\n /** Make a record from what was typed, offered when nothing found has that name. */\n create?: (text: string) => Promise<RelatedRecord>;\n /** How many found records the list shows; a search may find one more, to tell there are others. */\n shown?: number;\n /** Further choices at the end of the list: each acts on the typed text and may hand back a record to pick. */\n more?: (typed: string, overflow: boolean) => { label: string; act: (typed: string) => Promise<RelatedRecord | null> }[];\n}): Combobox {\n const { document: doc, id, labels } = options;\n const listId = `${id}-list`;\n const input = doc.createElement('input');\n Object.assign(input, { id, className: 'fd-input fd-combo-input', autocomplete: 'off' });\n input.setAttribute('role', 'combobox');\n input.setAttribute('aria-autocomplete', 'list');\n input.setAttribute('aria-expanded', 'false');\n input.setAttribute('aria-controls', listId);\n input.placeholder = labels.search;\n const list = doc.createElement('ul');\n list.id = listId;\n list.className = 'fd-listbox';\n list.setAttribute('role', 'listbox');\n list.hidden = true;\n const element = doc.createElement('div');\n element.className = 'fd-combo';\n element.append(input, list);\n\n let shown = '';\n /** The \"Create \u2026\" choice in the list, and the text it would make a record from. */\n let creating: RelatedRecord | null = null;\n let creatingText = '';\n /** The further choices at the end of the list, by the entry that stands for each. */\n let extras = new Map<RelatedRecord, (typed: string) => Promise<RelatedRecord | null>>();\n /** True while the person's own typing is in the box. */\n let editing = false;\n let results: RelatedRecord[] = [];\n let active = -1;\n let seq = 0;\n let timer: ReturnType<typeof setTimeout> | undefined;\n let readonly = false;\n\n function render() {\n list.replaceChildren();\n results.forEach((record, i) => {\n const option = doc.createElement('li');\n option.id = `${listId}-${i}`;\n option.setAttribute('role', 'option');\n option.setAttribute('aria-selected', String(i === active));\n option.className = `fd-option${i === active ? ' fd-active' : ''}${record === creating || extras.has(record) ? ' fd-option-create' : ''}`;\n option.textContent = record.label;\n option.addEventListener('mousedown', (event) => event.preventDefault()); // keep focus in the box\n option.addEventListener('click', () => choose(i));\n list.append(option);\n });\n if (!results.length) {\n const empty = doc.createElement('li');\n empty.className = 'fd-empty';\n empty.textContent = labels.noResults;\n list.append(empty);\n }\n if (active >= 0) input.setAttribute('aria-activedescendant', `${listId}-${active}`);\n else input.removeAttribute('aria-activedescendant');\n }\n\n function open() {\n list.hidden = false;\n input.setAttribute('aria-expanded', 'true');\n }\n\n function close() {\n // A search still on its way must not open the list again.\n clearTimeout(timer);\n seq++;\n list.hidden = true;\n input.setAttribute('aria-expanded', 'false');\n input.removeAttribute('aria-activedescendant');\n active = -1;\n }\n\n function choose(index: number) {\n const record = results[index];\n if (!record) return;\n const typed = creatingText;\n close();\n editing = false;\n if (record === creating && options.create) {\n void options.create(typed).then(options.pick, () => undefined);\n return;\n }\n const act = extras.get(record);\n if (act) {\n void act(typed).then((picked) => picked && options.pick(picked), () => undefined);\n return;\n }\n options.pick(record);\n }\n\n function lookUp(query: string) {\n clearTimeout(timer);\n const mine = ++seq;\n timer = setTimeout(async () => {\n const found = await options.search(query).catch(() => [] as RelatedRecord[]);\n if (mine !== seq || doc.activeElement !== input) return; // a newer search, or the person left\n // A record the arrow keys reached stays reached if the answer still lists it.\n const reached = results[active];\n const held = reached && reached !== creating && !extras.has(reached) ? reached.id : undefined;\n const hidden = options.exclude?.() ?? new Set();\n const kept = found.filter((record) => !hidden.has(record.id));\n const overflow = options.shown !== undefined && kept.length > options.shown;\n results = overflow ? kept.slice(0, options.shown) : kept;\n // Nothing found by that name: offer to make it.\n const typed = query.trim();\n creating = null;\n if (options.create && typed && !found.some((record) => record.label.trim().toLowerCase() === typed.toLowerCase())) {\n creatingText = typed;\n creating = { id: '__create__', label: fill(labels.createNamed, { name: typed }) };\n results = [...results, creating];\n }\n creatingText = typed;\n extras = new Map((options.more?.(typed, overflow) ?? []).map((extra, i) => [{ id: `__more_${i}__`, label: extra.label }, extra.act]));\n results = [...results, ...extras.keys()];\n active = held === undefined ? -1 : results.findIndex((record) => record.id === held);\n render();\n open();\n }, DEBOUNCE_MS);\n }\n\n input.addEventListener('input', () => {\n editing = true;\n if (!readonly) lookUp(input.value);\n });\n input.addEventListener('focus', () => {\n if (!readonly) lookUp('');\n });\n input.addEventListener('keydown', (event) => {\n if (readonly) return;\n switch (event.key) {\n case 'ArrowDown':\n case 'ArrowUp': {\n event.preventDefault();\n if (list.hidden) return lookUp(input.value);\n if (!results.length) return;\n active = (active + (event.key === 'ArrowDown' ? 1 : -1) + results.length) % results.length;\n render();\n list.children[active]?.scrollIntoView?.({ block: 'nearest' });\n return;\n }\n case 'Enter':\n if (!list.hidden && active >= 0) {\n event.preventDefault();\n choose(active);\n }\n return;\n case 'Escape':\n if (!list.hidden) event.preventDefault();\n close();\n editing = false;\n input.value = shown;\n return;\n case 'Backspace':\n if (input.value === '') options.onEmptyBackspace?.();\n return;\n }\n });\n input.addEventListener('blur', () => {\n seq++;\n clearTimeout(timer);\n close();\n const emptied = editing && input.value.trim() === '' && shown !== '';\n editing = false;\n if (emptied) options.onCommitEmpty?.();\n else input.value = shown;\n });\n\n return {\n element,\n input,\n setText(text) {\n shown = text;\n if (!editing) input.value = text;\n },\n setReadonly(next) {\n readonly = next;\n input.readOnly = next;\n if (next) close();\n },\n close,\n };\n}\n\n/** Making a record from a typed name, unless the page turns it off or the data source cannot. */\nfunction creator(form: Form, name: string, node: FieldNode): ((text: string) => Promise<RelatedRecord>) | undefined {\n return node.options?.['create'] !== false && form.canCreate(name) ? (text) => form.quickCreate(name, text) : undefined;\n}\n\nexport const many2oneWidget: WidgetFactory = ({ form, name, field, node, id, document, labels = WIDGET_LABELS.en, dialogs }) => {\n const relation = field.type === 'many2one' ? field.relation : '';\n const canOpen = !!dialogs && dialogs.canOpen(relation);\n let readonly = false;\n const box = combobox({\n document,\n id,\n labels,\n // One past what the list shows, to know whether Search more\u2026 has more to find.\n search: (query) => form.search(name, query, SHOWN + 1),\n shown: SHOWN,\n pick: (record) => form.setValue(name, record),\n onCommitEmpty: () => form.setValue(name, null),\n create: creator(form, name, node),\n // With dialogs: make a record in its own page, or pick from a full list when the short one has no room.\n more: (typed, overflow) => {\n if (!dialogs || readonly) return [];\n const choices: { label: string; act: (text: string) => Promise<RelatedRecord | null> }[] = [];\n if (typed && canOpen && node.options?.['create'] !== false) {\n choices.push({ label: labels.createAndEdit, act: (text) => dialogs.openRecord(relation, { name: text, title: field.label }) });\n }\n if (overflow) choices.push({ label: labels.searchMore, act: () => dialogs.searchMore({ title: field.label, search: (query, limit) => form.search(name, query, limit) }) });\n return choices;\n },\n });\n // The linked record, opened in a dialog where the app can show it; a new name it is saved with follows here.\n const open = canOpen ? document.createElement('button') : null;\n if (open) {\n open.type = 'button';\n open.className = 'fd-combo-open';\n open.textContent = '\u2197';\n open.hidden = true;\n open.addEventListener('click', async () => {\n const current = form.getState().values[name] as RelatedRecord | null;\n if (!current || !dialogs) return;\n const saved = await dialogs.openRecord(relation, { recordId: current.id, title: current.label });\n if (saved && saved.label !== current.label) form.setValue(name, saved);\n });\n }\n const clear = document.createElement('button');\n clear.type = 'button';\n clear.className = 'fd-combo-clear';\n clear.textContent = '\u00D7';\n clear.setAttribute('aria-label', fill(labels.clear, { label: field.label }));\n clear.addEventListener('click', () => {\n form.setValue(name, null);\n box.input.focus();\n });\n box.element.append(clear, ...(open ? [open] : []));\n return {\n element: box.element,\n focus: () => box.input.focus(),\n update(state) {\n const record = state.value as RelatedRecord | null | undefined;\n readonly = state.readonly;\n box.setText(record?.label ?? '');\n box.setReadonly(state.readonly);\n clear.hidden = !record || state.readonly;\n if (open) {\n open.hidden = !record;\n if (record) open.setAttribute('aria-label', fill(labels.openNamed, { name: record.label }));\n }\n box.input.setAttribute('aria-invalid', String(state.invalid));\n box.input.setAttribute('aria-required', String(state.required));\n if (state.describedBy) box.input.setAttribute('aria-describedby', state.describedBy);\n },\n } satisfies Widget;\n};\n\nexport const tagsWidget: WidgetFactory = ({ form, name, node, id, document, labels = WIDGET_LABELS.en }) => {\n const current = () => (form.getState().values[name] as RelatedRecord[] | null) ?? [];\n const element = document.createElement('div');\n element.className = 'fd-tags';\n element.setAttribute('role', 'group');\n const chips = document.createElement('ul');\n chips.className = 'fd-chips';\n const box = combobox({\n document,\n id,\n labels,\n search: (query) => form.search(name, query),\n pick: (record) => {\n form.setValue(name, [...current(), record]);\n box.input.value = '';\n },\n exclude: () => new Set(current().map((record) => record.id)),\n onEmptyBackspace: () => {\n const records = current();\n if (records.length) form.setValue(name, records.slice(0, -1));\n },\n create: creator(form, name, node),\n });\n element.append(chips, box.element);\n let readonly = false;\n let drawn = '';\n return {\n element,\n focus: () => box.input.focus(),\n update(state) {\n const records = (state.value as RelatedRecord[] | null) ?? [];\n // Rebuild the chips only when they change, not on every keystroke elsewhere.\n const key = JSON.stringify([state.readonly, records]);\n readonly = state.readonly;\n box.setReadonly(readonly);\n box.element.hidden = readonly;\n box.input.setAttribute('aria-invalid', String(state.invalid));\n if (state.describedBy) box.input.setAttribute('aria-describedby', state.describedBy);\n if (key === drawn) return;\n drawn = key;\n drawChips(chips, records, readonly, labels, (record) => form.setValue(name, current().filter((r) => r.id !== record.id)));\n box.setText('');\n },\n };\n};\n\n/** Chips for tags, each with a remove button unless read-only. */\nfunction drawChips(chips: HTMLElement, records: RelatedRecord[], readonly: boolean, labels: WidgetLabels, remove: (record: RelatedRecord) => void) {\n const doc = chips.ownerDocument;\n chips.replaceChildren(\n ...records.map((record) => {\n const chip = doc.createElement('li');\n chip.className = 'fd-chip';\n const text = doc.createElement('span');\n text.className = 'fd-chip-label';\n text.textContent = record.label;\n chip.append(text);\n if (!readonly) {\n const button = doc.createElement('button');\n button.type = 'button';\n button.className = 'fd-chip-remove';\n button.textContent = '\u00D7';\n button.setAttribute('aria-label', fill(labels.remove, { name: record.label }));\n button.addEventListener('click', () => remove(record));\n chip.append(button);\n }\n return chip;\n })\n );\n}\n\n/**\n * Free-text tags on a text field, kept as \"oak, glass\": Enter or a comma adds\n * what was typed, Backspace in an empty box takes the last one away, and the\n * node's `options.suggestions` are offered as you type. `options.separator`\n * is \",\" unless set.\n */\nexport const charTagsWidget: WidgetFactory = ({ form, name, node, id, document, labels = WIDGET_LABELS.en }) => {\n const options = node.options ?? {};\n const separator = typeof options['separator'] === 'string' && options['separator'] ? options['separator'] : ',';\n const suggestions = Array.isArray(options['suggestions']) ? options['suggestions'].filter((s): s is string => typeof s === 'string') : [];\n const split = (text: unknown) =>\n typeof text === 'string' ? text.split(separator).map((t) => t.trim()).filter((t) => t !== '') : [];\n const current = () => split(form.getState().values[name]);\n const write = (tags: string[]) => form.setValue(name, tags.length ? tags.join(`${separator} `) : null);\n const add = (raw: string) => {\n const tag = raw.trim();\n const tags = current();\n if (tag && !tags.some((t) => t.toLowerCase() === tag.toLowerCase())) write([...tags, tag]);\n };\n\n const element = document.createElement('div');\n element.className = 'fd-tags';\n element.setAttribute('role', 'group');\n const chips = document.createElement('ul');\n chips.className = 'fd-chips';\n const box = combobox({\n document,\n id,\n labels,\n search: async (query) => {\n const taken = new Set(current().map((t) => t.toLowerCase()));\n const wanted = query.trim().toLowerCase();\n return suggestions\n .filter((s) => !taken.has(s.toLowerCase()) && s.toLowerCase().includes(wanted))\n .map((s) => ({ id: s, label: s }));\n },\n pick: (record) => {\n add(record.label);\n box.input.value = '';\n },\n onEmptyBackspace: () => {\n const tags = current();\n if (tags.length) write(tags.slice(0, -1));\n },\n });\n // Enter with nothing chosen from the list adds what was typed.\n box.input.addEventListener('keydown', (event) => {\n if (event.key !== 'Enter' || event.defaultPrevented || box.input.value.trim() === '') return;\n event.preventDefault();\n add(box.input.value);\n box.input.value = '';\n box.close();\n });\n // A separator typed ends a tag.\n box.input.addEventListener('input', () => {\n const parts = box.input.value.split(separator);\n if (parts.length < 2) return;\n for (const part of parts.slice(0, -1)) add(part);\n box.input.value = parts[parts.length - 1].trimStart();\n });\n // Typed and left without Enter: kept. (change comes before blur clears the box.)\n box.input.addEventListener('change', () => {\n if (box.input.value.trim()) add(box.input.value);\n });\n element.append(chips, box.element);\n let drawn = '';\n return {\n element,\n focus: () => box.input.focus(),\n update(state) {\n const tags = split(state.value);\n box.setReadonly(state.readonly);\n box.element.hidden = state.readonly;\n box.input.setAttribute('aria-invalid', String(state.invalid));\n if (state.describedBy) box.input.setAttribute('aria-describedby', state.describedBy);\n const key = JSON.stringify([state.readonly, tags]);\n if (key === drawn) return;\n drawn = key;\n drawChips(chips, tags.map((t) => ({ id: t, label: t })), state.readonly, labels, (record) => write(current().filter((t) => t !== record.label)));\n box.setText('');\n },\n };\n};\n\n/** Every record as a checkbox. For short lists: it loads up to 50. */\nexport const linkCheckboxesWidget: WidgetFactory = ({ form, name, id, document }) => {\n const element = document.createElement('div');\n element.id = id;\n element.className = 'fd-choices fd-choices-checkbox';\n element.setAttribute('role', 'group');\n let boxes: { record: RelatedRecord; box: HTMLInputElement }[] = [];\n let latest = { readonly: false, value: [] as RelatedRecord[] };\n // Built once, when the records arrive; updates only tick boxes, so focus stays put.\n const sync = () => {\n const chosen = new Set(latest.value.map((r) => r.id));\n for (const { record, box } of boxes) {\n box.checked = chosen.has(record.id);\n box.disabled = latest.readonly;\n }\n };\n void form.search(name, '', 50).then((records) => {\n boxes = records.map((record, i) => {\n const box = document.createElement('input');\n box.type = 'checkbox';\n box.id = `${id}-${i}`;\n box.addEventListener('change', () => {\n const now = (form.getState().values[name] as RelatedRecord[] | null) ?? [];\n form.setValue(name, box.checked ? [...now, record] : now.filter((r) => r.id !== record.id));\n });\n const label = document.createElement('label');\n label.className = 'fd-choice';\n label.htmlFor = box.id;\n const text = document.createElement('span');\n text.textContent = record.label;\n label.append(box, text);\n element.append(label);\n return { record, box };\n });\n sync();\n });\n return {\n element,\n focus: () => element.querySelector('input')?.focus(),\n update(state) {\n latest = { readonly: state.readonly, value: (state.value as RelatedRecord[] | null) ?? [] };\n sync();\n },\n };\n};\n\nexport const referenceWidget: WidgetFactory = (context: WidgetContext) => {\n const { form, name, field, id, document, labels = WIDGET_LABELS.en } = context;\n const models = field.type === 'reference' ? field.models : [];\n const element = document.createElement('div');\n element.className = 'fd-reference';\n const select = document.createElement('select');\n select.className = 'fd-input fd-select';\n select.setAttribute('aria-label', field.label);\n select.append(document.createElement('option'));\n for (const model of models) {\n const option = document.createElement('option');\n option.value = String(model.value);\n option.textContent = model.label;\n select.append(option);\n }\n let model = '';\n select.addEventListener('change', () => {\n model = select.value;\n form.setValue(name, null);\n });\n const box = combobox({\n document,\n id,\n labels,\n search: (query) => (model ? form.search(name, query, 8, { model }) : Promise.resolve([])),\n pick: (record) => form.setValue(name, { model, id: record.id, label: record.label }),\n onCommitEmpty: () => form.setValue(name, null),\n });\n element.append(select, box.element);\n return {\n element,\n focus: () => (model ? box.input.focus() : select.focus()),\n update(state) {\n const value = state.value as ReferenceValue | null | undefined;\n if (value) model = value.model;\n select.value = model;\n select.disabled = state.readonly;\n box.setText(value?.label ?? '');\n box.setReadonly(state.readonly || !model);\n },\n };\n};\n", "import type { LineField, Locale, Value } from '@fieldia/core';\nimport { formatNumber } from './numbers';\n\n\nfunction localDate(text: string): Date | null {\n const match = /^(\\d{4})-(\\d{2})-(\\d{2})(?:[T ](\\d{2}):(\\d{2}))?/.exec(text);\n if (!match) return null;\n const [, y, m, d, hh, mm] = match;\n return new Date(Number(y), Number(m) - 1, Number(d), Number(hh ?? 0), Number(mm ?? 0));\n}\n\n/**\n * A value as a person reads it where it is not being edited: a cell of the\n * lines grid, a totals row. Shared by the plain lines table and @fieldia/grid.\n */\nexport function displayValue(def: LineField, value: Value | undefined, values: Record<string, Value> = {}, locale: Locale = 'en'): string {\n const number = (n: number, digits: number) => formatNumber(n, digits, locale);\n if (value === null || value === undefined || value === '') return '';\n switch (def.type) {\n case 'many2one':\n case 'reference':\n return (value as { label?: string }).label ?? '';\n case 'many2many':\n return ((value as { label: string }[]) ?? []).map((r) => r.label).join(', ');\n case 'selection': {\n const label = (v: unknown) => def.options.find((o) => o.value === v)?.label ?? String(v);\n return Array.isArray(value) ? value.map(label).join(', ') : label(value);\n }\n case 'integer':\n return number(Number(value), 0);\n case 'float':\n return number(Number(value), def.digits?.[1] ?? 2);\n case 'monetary': {\n const currency = def.currency ?? (def.currencyField ? (values[def.currencyField] as { label?: string } | null)?.label : undefined);\n const amount = number(Number(value), def.digits?.[1] ?? 2);\n return currency ? `${currency} ${amount}` : amount;\n }\n case 'date': {\n const date = localDate(String(value));\n return date ? new Intl.DateTimeFormat(locale === 'en' ? 'en-GB' : locale, { day: 'numeric', month: 'short', year: 'numeric', numberingSystem: 'latn' }).format(date) : String(value);\n }\n case 'datetime': {\n const date = localDate(String(value));\n return date\n ? new Intl.DateTimeFormat(locale === 'en' ? 'en-GB' : locale, { day: 'numeric', month: 'short', year: 'numeric', hour: '2-digit', minute: '2-digit', numberingSystem: 'latn' }).format(date)\n : String(value);\n }\n case 'html':\n return String(value).replace(/<[^>]*>/g, ' ').replace(/\\s+/g, ' ').trim();\n case 'binary':\n case 'image':\n return (value as { name?: string }).name ?? '';\n case 'boolean':\n return value ? '\u2713' : '';\n default:\n return String(value);\n }\n}\n", "import { lineKind, type Field, type FieldNode, type Form, type FormState, type Line, type LineField, type Value } from '@fieldia/core';\nimport { displayValue } from './display';\nimport { WIDGET_LABELS } from './labels';\nimport { createWidget, type Widget, type WidgetFactory } from './widgets';\n\n/**\n * A one2many as an editable table. Each cell is an ordinary widget; a small\n * adapter routes its edits to `updateLine` and its searches to `searchLine`,\n * so a many2one inside a line searches with that line's own values. Rows are\n * matched by line key, so adding or removing a line never rebuilds the others.\n * When the field declares `lineKinds`, a section or a note is one wide row of\n * its text.\n */\n\ninterface Row {\n element: HTMLTableRowElement;\n kind: 'section' | 'note' | null;\n cells: { name: string; def: LineField; widget: Widget; error: HTMLElement }[];\n remove: HTMLButtonElement;\n}\n\n/** The field a section or note is typed into: one line for a heading, a growing box for a note. */\nexport function kindTextField(def: LineField, kind: 'section' | 'note'): LineField {\n return kind === 'section' ? ({ ...def, type: 'char' } as LineField) : ({ ...def, type: 'text' } as LineField);\n}\n\n/** The form a cell sees: the line's values, written back into the line. Shared with @fieldia/grid. */\nexport function lineForm(form: Form, field: string, key: string): Form {\n const values = () => (((form.getState().values[field] as Line[] | null) ?? []).find((l) => l.key === key)?.values ?? {});\n return {\n ...form,\n getState: (): FormState => ({ ...form.getState(), values: values() }),\n setValue: (name: string, value: Value) => form.updateLine(field, key, name, value),\n search: (name: string, query: string, limit?: number) => form.searchLine(field, key, name, query, limit),\n canCreate: (name: string) => form.canCreateLine(field, name),\n quickCreate: (name: string, text: string) => form.quickCreateLine(field, name, text),\n };\n}\n\nexport const linesWidget: WidgetFactory = ({ form, name, field, node, id, document, labels = WIDGET_LABELS.en, locale, dialogs }) => {\n const def = field as Extract<Field, { type: 'one2many' }>;\n const kinds = def.lineKinds;\n // The fields that say what a line is and keep the lines' order never show as columns.\n // Optional columns the page starts hidden stay out of the plain table.\n const columns = (node.columns ?? Object.keys(def.fields)).filter(\n (column) => def.fields[column] && column !== kinds?.field && column !== def.sequenceField && node.optionalColumns?.[column] !== 'hide'\n );\n const element = document.createElement('div');\n element.className = 'fd-lines';\n element.id = id;\n element.setAttribute('role', 'group');\n const scroller = document.createElement('div');\n scroller.className = 'fd-lines-scroll';\n const table = document.createElement('table');\n table.className = 'fd-lines-table';\n const head = document.createElement('thead');\n const headRow = document.createElement('tr');\n for (const column of columns) {\n const th = document.createElement('th');\n th.scope = 'col';\n th.textContent = def.fields[column].label;\n headRow.append(th);\n }\n const lastTh = document.createElement('th');\n lastTh.className = 'fd-lines-tools';\n headRow.append(lastTh);\n head.append(headRow);\n const body = document.createElement('tbody');\n table.append(head, body);\n // Number columns the page asks to add up, in a row under the lines.\n const totals = (node.totals ?? []).filter((column) => columns.includes(column));\n const sums = new Map<string, HTMLTableCellElement>();\n if (totals.length) {\n const foot = document.createElement('tfoot');\n const row = document.createElement('tr');\n row.className = 'fd-lines-totals';\n columns.forEach((column, i) => {\n const td = document.createElement('td');\n if (totals.includes(column)) sums.set(column, td);\n else if (i === 0) td.textContent = labels.total;\n row.append(td);\n });\n row.append(document.createElement('td'));\n foot.append(row);\n table.append(foot);\n }\n scroller.append(table);\n const adds = document.createElement('div');\n adds.className = 'fd-lines-adds';\n const addButton = (text: string, values: Record<string, Value>, kind: string) => {\n const button = document.createElement('button');\n button.type = 'button';\n button.className = 'fd-button fd-button-link fd-lines-add';\n button.dataset['add'] = kind;\n button.textContent = `+ ${text}`;\n button.addEventListener('click', () => {\n focusNew = form.addLine(name, values);\n const row = rows.get(focusNew);\n if (row) {\n row.cells[0]?.widget.focus();\n focusNew = null;\n }\n });\n adds.append(button);\n };\n addButton(labels.addLine, {}, 'line');\n if (kinds) {\n addButton(labels.addSection, { [kinds.field]: kinds.section ?? 'section' }, 'section');\n addButton(labels.addNote, { [kinds.field]: kinds.note ?? 'note' }, 'note');\n }\n element.append(scroller, adds);\n\n const rows = new Map<string, Row>();\n let focusNew: string | null = null;\n let readonly = false;\n\n function makeCell(tr: HTMLTableRowElement, line: Line, column: string, sub: LineField, span = 1) {\n const cellId = `${id}-${line.key}-${column}`;\n const subNode: FieldNode = { type: 'field', id: `${node.id}.${line.key}.${column}`, field: column };\n const widget = createWidget({ form: lineForm(form, name, line.key), name: column, field: sub as Field, node: subNode, id: cellId, document, labels, locale, dialogs });\n const td = document.createElement('td');\n td.colSpan = span;\n const label = document.createElement('label');\n label.className = 'fd-sr-only';\n label.htmlFor = cellId;\n label.textContent = sub.label;\n const error = document.createElement('div');\n error.className = 'fd-cell-error';\n error.hidden = true;\n td.append(label, widget.element, error);\n tr.append(td);\n return { name: column, def: sub, widget, error };\n }\n\n function makeRow(line: Line): Row {\n const tr = document.createElement('tr');\n tr.dataset['line'] = line.key;\n const kind = lineKind(def, line.values);\n if (kind) tr.className = `fd-line-${kind}`;\n const cells =\n kind && kinds\n ? [makeCell(tr, line, kinds.text, kindTextField(def.fields[kinds.text], kind), columns.length)]\n : columns.map((column) => makeCell(tr, line, column, def.fields[column]));\n const tools = document.createElement('td');\n tools.className = 'fd-lines-tools';\n const remove = document.createElement('button');\n remove.type = 'button';\n remove.className = 'fd-line-delete';\n remove.textContent = '\u00D7';\n remove.setAttribute('aria-label', labels.deleteLine);\n remove.addEventListener('click', () => form.removeLine(name, line.key));\n tools.append(remove);\n tr.append(tools);\n return { element: tr, kind, cells, remove };\n }\n\n return {\n element,\n focus: () => (body.querySelector<HTMLElement>('input, select, textarea') ?? adds.querySelector('button'))?.focus(),\n update(state) {\n readonly = state.readonly;\n adds.hidden = readonly;\n const current = (state.value as Line[] | null) ?? [];\n const errors = form.getState().errors;\n const keep = new Set(current.map((line) => line.key));\n for (const [key, row] of rows) {\n if (!keep.has(key)) {\n row.element.remove();\n rows.delete(key);\n }\n }\n current.forEach((line, index) => {\n let row = rows.get(line.key);\n // A line that changed kind is drawn afresh.\n if (row && row.kind !== lineKind(def, line.values)) {\n row.element.remove();\n row = undefined;\n }\n if (!row) {\n row = makeRow(line);\n rows.set(line.key, row);\n }\n if (body.children[index] !== row.element) body.insertBefore(row.element, body.children[index] ?? null);\n row.remove.hidden = readonly;\n if (readonly) row.remove.remove();\n else if (!row.remove.isConnected) row.element.lastElementChild?.append(row.remove);\n for (const cell of row.cells) {\n const message = errors[`${name}.${line.key}.${cell.name}`];\n cell.error.hidden = !message;\n cell.error.textContent = message ?? '';\n cell.widget.update({\n value: line.values[cell.name],\n values: line.values,\n readonly: readonly || cell.def.readonly === true,\n required: cell.def.required === true,\n invalid: !!message,\n });\n }\n });\n for (const [column, td] of sums) {\n const sum = current.filter((line) => !lineKind(def, line.values)).reduce((total, line) => total + Number(line.values[column] ?? 0), 0);\n td.textContent = displayValue(def.fields[column], sum, current[0]?.values ?? {}, locale);\n }\n if (focusNew && rows.has(focusNew)) {\n rows.get(focusNew)?.cells[0]?.widget.focus();\n focusNew = null;\n }\n },\n };\n};\n", "import { formatBytes, type FileValue } from '@fieldia/core';\nimport { WIDGET_LABELS } from './labels';\nimport type { WidgetFactory } from './widgets';\n\n/**\n * File and image fields. A chosen or dropped file is read into the value as\n * base64, the way a backend's binary fields carry it; a stored one may carry\n * a `url` instead. Size and type limits are checked by the field's validation.\n */\n\nfunction read(file: File): Promise<FileValue> {\n return new Promise((resolve, reject) => {\n const reader = new FileReader();\n reader.onload = () => {\n const url = String(reader.result ?? '');\n resolve({ name: file.name, type: file.type, size: file.size, data: url.slice(url.indexOf(',') + 1) });\n };\n reader.onerror = () => reject(reader.error);\n reader.readAsDataURL(file);\n });\n}\n\nfunction fileWidget(kind: 'binary' | 'image'): WidgetFactory {\n return ({ form, name, field, id, document, labels = WIDGET_LABELS.en }) => {\n const element = document.createElement('div');\n element.className = `fd-file fd-file-${kind}`;\n const input = document.createElement('input');\n input.type = 'file';\n input.id = id;\n input.className = 'fd-sr-only';\n const accept = field.type === 'binary' ? field.accept : kind === 'image' ? ['image/*'] : undefined;\n if (accept) input.accept = accept.join(',');\n\n const preview = document.createElement('img');\n preview.className = 'fd-image-preview';\n preview.alt = field.label;\n preview.hidden = true;\n\n const pick = document.createElement('label');\n pick.className = kind === 'image' ? 'fd-file-pick fd-image-pick' : 'fd-file-pick';\n pick.htmlFor = id;\n const pickText = document.createElement('span');\n pickText.className = 'fd-button';\n pickText.textContent = kind === 'image' ? labels.uploadImage : labels.upload;\n const hint = document.createElement('span');\n hint.className = 'fd-help';\n hint.textContent = labels.dropHere;\n pick.append(pickText, hint);\n\n const chosen = document.createElement('div');\n chosen.className = 'fd-file-chosen';\n const fileName = document.createElement('span');\n fileName.className = 'fd-file-name';\n const replace = document.createElement('button');\n replace.type = 'button';\n replace.className = 'fd-button fd-button-link';\n replace.textContent = labels.replace;\n replace.addEventListener('click', () => input.click());\n const remove = document.createElement('button');\n remove.type = 'button';\n remove.className = 'fd-button fd-button-link';\n remove.textContent = labels.removeFile;\n remove.addEventListener('click', () => form.setValue(name, null));\n chosen.append(fileName, replace, remove);\n\n element.append(input, ...(kind === 'image' ? [preview] : []), pick, chosen);\n\n let readonly = false;\n const take = async (file: File | undefined) => {\n if (!file || readonly) return;\n form.setValue(name, await read(file));\n };\n input.addEventListener('change', () => {\n void take(input.files?.[0]);\n input.value = '';\n });\n element.addEventListener('dragover', (event) => {\n if (readonly) return;\n event.preventDefault();\n element.classList.add('fd-dragging');\n });\n element.addEventListener('dragleave', () => element.classList.remove('fd-dragging'));\n element.addEventListener('drop', (event) => {\n event.preventDefault();\n element.classList.remove('fd-dragging');\n void take((event as DragEvent).dataTransfer?.files?.[0]);\n });\n\n return {\n element,\n focus: () => (pick.hidden ? replace : input).focus(),\n update(state) {\n readonly = state.readonly;\n const file = state.value as FileValue | null | undefined;\n pick.hidden = !!file || readonly;\n chosen.hidden = !file;\n replace.hidden = remove.hidden = readonly;\n input.disabled = readonly;\n input.setAttribute('aria-invalid', String(state.invalid));\n if (state.describedBy) input.setAttribute('aria-describedby', state.describedBy);\n fileName.textContent = file ? `${file.name} \u00B7 ${formatBytes(file.size)}` : '';\n if (kind === 'image') {\n const src = file ? (file.data ? `data:${file.type};base64,${file.data}` : file.url ?? '') : '';\n preview.hidden = !src;\n if (preview.getAttribute('src') !== src) {\n if (src) preview.src = src;\n else preview.removeAttribute('src');\n }\n }\n },\n };\n };\n}\n\nexport const binaryWidget = fileWidget('binary');\nexport const imageWidget = fileWidget('image');\n", "import type { Locale } from '@fieldia/core';\nimport { createWidget, type Widget, type WidgetFactory } from './widgets';\n\n/**\n * A number shown as a bar that fills towards a maximum, coloured by how far\n * it has come: red under 30 %, yellow under 70 %, green from there. Options:\n *\n * max the maximum, 100 by default (min 0)\n * maxField a number field that holds the maximum instead\n * color \"auto\", or always \"success\", \"warning\", \"danger\" or \"info\"\n * showPercent false to leave the percentage off the bar\n * editable true for a box beside the bar to type the value in\n */\n\nconst percents = new Map<Locale, Intl.NumberFormat>();\nfunction percent(value: number, locale: Locale) {\n let format = percents.get(locale);\n if (!format) {\n format = new Intl.NumberFormat(locale, { style: 'percent', maximumFractionDigits: 0, numberingSystem: 'latn' });\n percents.set(locale, format);\n }\n return format.format(value / 100);\n}\n\nexport const progressbarWidget: WidgetFactory = (context) => {\n const { node, id, document, locale = 'en' } = context;\n const options = node.options ?? {};\n const min = typeof options['min'] === 'number' ? options['min'] : 0;\n const fixedMax = typeof options['max'] === 'number' ? options['max'] : 100;\n const maxField = typeof options['maxField'] === 'string' ? options['maxField'] : null;\n const color = typeof options['color'] === 'string' ? options['color'] : 'auto';\n const showPercent = options['showPercent'] !== false;\n\n const bar = document.createElement('div');\n bar.className = 'fd-progressbar';\n bar.setAttribute('role', 'progressbar');\n const fill = document.createElement('div');\n fill.className = 'fd-progressbar-fill';\n const text = document.createElement('span');\n text.className = 'fd-progressbar-text';\n bar.append(fill, text);\n\n // Editable: the field's own number box takes the value; the bar beside it only shows it.\n let box: Widget | null = null;\n let element: HTMLElement = bar;\n if (options['editable'] === true) {\n box = createWidget({ ...context, node: { ...node, widget: undefined } });\n bar.setAttribute('aria-hidden', 'true');\n element = document.createElement('div');\n element.className = 'fd-progressbar-edit';\n element.append(bar, box.element);\n } else {\n bar.id = id;\n }\n\n return {\n element,\n focus: () => box?.focus(),\n update(state) {\n const value = typeof state.value === 'number' ? state.value : 0;\n const max = maxField ? Number(state.values[maxField] ?? 0) : fixedMax;\n const share = max > min ? Math.min(100, Math.max(0, ((value - min) / (max - min)) * 100)) : 0;\n const rounded = Math.round(share * 10) / 10;\n fill.style.width = `${rounded}%`;\n bar.setAttribute('aria-valuenow', String(value));\n bar.setAttribute('aria-valuemin', String(min));\n bar.setAttribute('aria-valuemax', String(max));\n bar.setAttribute('aria-valuetext', percent(share, locale));\n text.textContent = showPercent ? percent(share, locale) : '';\n bar.dataset['tone'] = color !== 'auto' ? color : share < 30 ? 'danger' : share < 70 ? 'warning' : 'success';\n box?.update(state);\n },\n };\n};\n", "import type { Locale, RelatedRecord, Value } from '@fieldia/core';\nimport { formatNumber } from './numbers';\nimport { summary, type WidgetFactory } from './widgets';\n\n/**\n * A value shown as text between a prefix and a suffix: \"24 months\",\n * \"240.0 m\". Never edited. Options:\n *\n * prefix, suffix words around the value\n * prefixField, suffixField a field whose value is the prefix or suffix instead\n */\n\n/** Another field's value as words: a link's label, or the value itself. */\nfunction words(value: Value | undefined): string {\n if (value === null || value === undefined) return '';\n if (typeof value === 'object' && 'label' in (value as object)) return (value as RelatedRecord).label;\n return String(value);\n}\n\nexport const labelWidget: WidgetFactory = ({ field, node, id, document, locale = 'en' as Locale }) => {\n const options = node.options ?? {};\n const text = (key: 'prefix' | 'suffix') => (typeof options[key] === 'string' ? (options[key] as string) : '');\n const from = (key: 'prefixField' | 'suffixField') => (typeof options[key] === 'string' ? (options[key] as string) : null);\n const decimals =\n field.type === 'integer' ? 0 : field.type === 'float' || field.type === 'monetary' ? (field.digits?.[1] ?? 2) : null;\n\n const output = document.createElement('output');\n output.id = id;\n output.className = 'fd-value-text';\n return {\n element: output,\n focus: () => undefined,\n update({ value, values }) {\n if (value === null || value === undefined || value === '') {\n output.textContent = '';\n return;\n }\n const shown = decimals !== null && typeof value === 'number' ? formatNumber(value, decimals, locale) : summary(value, field);\n const prefixField = from('prefixField');\n const suffixField = from('suffixField');\n const prefix = prefixField ? words(values[prefixField]) : text('prefix');\n const suffix = suffixField ? words(values[suffixField]) : text('suffix');\n output.textContent = [prefix, shown, suffix].filter((part) => part !== '').join(' ');\n },\n };\n};\n", "import type { RelatedRecord } from '@fieldia/core';\nimport type { WidgetFactory } from './widgets';\n\n/**\n * Where a record stands, as a row of steps with the current one marked: a\n * selection's states, or the records a link may point to (stages). Used in a\n * sheet's header, and anywhere in a form with `\"widget\": \"statusbar\"`. Options:\n *\n * clickable true to let a click move the record to another step\n * visibleStates the values to show; the current one always shows\n */\n\ninterface Step {\n key: string;\n label: string;\n value: unknown;\n}\n\nexport const statusbarWidget: WidgetFactory = ({ form, name, field, node, id, document }) => {\n const options = node.options ?? {};\n const clickable = options['clickable'] === true;\n const visible = Array.isArray(options['visibleStates']) ? options['visibleStates'] : null;\n const list = document.createElement('ol');\n list.className = 'fd-statusbar';\n list.id = id;\n list.setAttribute('aria-label', field.label);\n\n const keyOf = (value: unknown) =>\n value && typeof value === 'object' && 'id' in value ? `id:${String((value as RelatedRecord).id)}` : `v:${String(value)}`;\n // A selection knows its steps; a link's are looked up once.\n let steps: Step[] =\n field.type === 'selection' ? field.options.map((o) => ({ key: keyOf(o.value), label: o.label, value: o.value })) : [];\n let lookedUp = field.type === 'selection';\n let last: { value: unknown; readonly: boolean } = { value: undefined, readonly: false };\n\n function draw() {\n const { value, readonly } = last;\n const currentKey = value === null || value === undefined ? null : keyOf(value);\n let shown = steps.filter((s) => !visible || visible.some((v) => keyOf(v) === s.key) || s.key === currentKey);\n if (currentKey && !shown.some((s) => s.key === currentKey) && value && typeof value === 'object') {\n shown = [...shown, { key: currentKey, label: (value as RelatedRecord).label, value }];\n }\n list.replaceChildren(\n ...shown.map((step) => {\n const label = document.createElement('span');\n label.textContent = step.label;\n const inner = document.createElement(clickable ? 'button' : 'span');\n if (inner instanceof HTMLButtonElement) {\n inner.type = 'button';\n inner.disabled = readonly;\n inner.addEventListener('click', () => form.setValue(name, step.value as never));\n }\n inner.append(label);\n if (step.key === currentKey) inner.setAttribute('aria-current', 'step');\n const item = document.createElement('li');\n item.append(inner);\n return item;\n })\n );\n }\n\n return {\n element: list,\n focus: () => list.querySelector<HTMLElement>('button:not([disabled])')?.focus(),\n update(state) {\n last = { value: state.value, readonly: state.readonly };\n draw();\n if (!lookedUp) {\n lookedUp = true;\n void form\n .search(name, '', 20)\n .then((records) => {\n steps = records.map((r) => ({ key: keyOf(r), label: r.label, value: r }));\n draw();\n })\n .catch(() => undefined);\n }\n },\n };\n};\n", "import type { Locale, Value } from '@fieldia/core';\nimport { WIDGET_LABELS, type WidgetLabels } from './labels';\nimport type { Widget, WidgetContext } from './widgets';\n\n/**\n * A calendar beside a date, for when the person needs the week numbers\n * (`options.weekNumbers` on a date or date-and-time node). The ARIA\n * date-picker dialog: a grid of days, Monday first, an ISO 8601 week number at\n * the start of each row, arrow keys by day and week, PageUp and PageDown by\n * month, Enter to pick, Escape to close.\n */\n\n/** The ISO 8601 week a day falls in: weeks start on Monday, week 1 holds the year's first Thursday. */\nexport function isoWeek(day: Date): number {\n const t = new Date(Date.UTC(day.getFullYear(), day.getMonth(), day.getDate()));\n t.setUTCDate(t.getUTCDate() + 4 - (t.getUTCDay() || 7));\n const yearStart = Date.UTC(t.getUTCFullYear(), 0, 1);\n return Math.ceil(((t.getTime() - yearStart) / 86400000 + 1) / 7);\n}\n\nconst pad = (n: number) => String(n).padStart(2, '0');\nconst sameDay = (a: Date, b: Date) => a.getFullYear() === b.getFullYear() && a.getMonth() === b.getMonth() && a.getDate() === b.getDate();\nconst addDays = (d: Date, n: number) => new Date(d.getFullYear(), d.getMonth(), d.getDate() + n);\n/** The same day of another month, or that month's last day when it is shorter. */\nfunction addMonths(d: Date, n: number) {\n const last = new Date(d.getFullYear(), d.getMonth() + n + 1, 0).getDate();\n return new Date(d.getFullYear(), d.getMonth() + n, Math.min(d.getDate(), last));\n}\n\n/** The day a date field holds (\"2026-10-11\"), or a date and time (an ISO instant), in local time. */\nfunction dayOf(kind: 'date' | 'datetime', value: Value | undefined): Date | null {\n if (typeof value !== 'string' || !value) return null;\n if (kind === 'date') {\n const m = /^(\\d{4})-(\\d{2})-(\\d{2})/.exec(value);\n return m ? new Date(Number(m[1]), Number(m[2]) - 1, Number(m[3])) : null;\n }\n const d = new Date(value);\n return Number.isNaN(d.getTime()) ? null : d;\n}\n\nexport function withCalendar(inner: Widget, context: WidgetContext, kind: 'date' | 'datetime'): Widget {\n const { form, name, id, document: doc, locale = 'en' as Locale } = context;\n const labels: WidgetLabels = context.labels ?? WIDGET_LABELS.en;\n const lang = locale === 'en' ? 'en-GB' : locale;\n const monthName = new Intl.DateTimeFormat(lang, { month: 'long', year: 'numeric', numberingSystem: 'latn' });\n const dayName = new Intl.DateTimeFormat(lang, { weekday: 'long', day: 'numeric', month: 'long', year: 'numeric', numberingSystem: 'latn' });\n const weekdayShort = new Intl.DateTimeFormat(lang, { weekday: 'short' });\n const weekdayLong = new Intl.DateTimeFormat(lang, { weekday: 'long' });\n\n const button = doc.createElement('button');\n button.type = 'button';\n button.className = 'fd-calendar-button';\n // A drawn calendar: an emoji would look different on every system.\n const svg = 'http://www.w3.org/2000/svg';\n const icon = doc.createElementNS(svg, 'svg');\n icon.setAttribute('viewBox', '0 0 16 16');\n icon.setAttribute('aria-hidden', 'true');\n for (const [tag, attrs] of [\n ['rect', { x: '2', y: '3', width: '12', height: '11', rx: '1.5' }],\n ['path', { d: 'M2 6.5h12M5 1.5v3M11 1.5v3' }],\n ] as const) {\n const shape = doc.createElementNS(svg, tag);\n for (const [k, v] of Object.entries(attrs)) shape.setAttribute(k, v);\n icon.append(shape);\n }\n button.append(icon);\n button.setAttribute('aria-label', labels.chooseDate);\n button.setAttribute('aria-haspopup', 'dialog');\n button.setAttribute('aria-expanded', 'false');\n button.setAttribute('aria-controls', `${id}-calendar`);\n\n const dialog = doc.createElement('div');\n dialog.className = 'fd-calendar';\n dialog.id = `${id}-calendar`;\n dialog.setAttribute('role', 'dialog');\n dialog.hidden = true;\n const head = doc.createElement('div');\n head.className = 'fd-calendar-head';\n const prev = doc.createElement('button');\n prev.type = 'button';\n prev.textContent = '\u2039';\n prev.setAttribute('aria-label', labels.previousMonth);\n const title = doc.createElement('span');\n title.className = 'fd-calendar-title';\n title.setAttribute('aria-live', 'polite');\n const next = doc.createElement('button');\n next.type = 'button';\n next.textContent = '\u203A';\n next.setAttribute('aria-label', labels.nextMonth);\n head.append(prev, title, next);\n const grid = doc.createElement('table');\n grid.className = 'fd-calendar-grid';\n grid.setAttribute('role', 'grid');\n dialog.append(head, grid);\n\n const element = doc.createElement('span');\n element.className = 'fd-date-pick';\n element.append(inner.element, button, dialog);\n\n let focused = new Date();\n let readonly = false;\n\n function pick(day: Date) {\n if (kind === 'date') {\n form.setValue(name, `${day.getFullYear()}-${pad(day.getMonth() + 1)}-${pad(day.getDate())}`);\n } else {\n const was = dayOf('datetime', form.getState().values[name]);\n const at = new Date(day.getFullYear(), day.getMonth(), day.getDate(), was?.getHours() ?? 0, was?.getMinutes() ?? 0);\n form.setValue(name, at.toISOString());\n }\n close();\n }\n\n function draw(focus: boolean) {\n const chosen = dayOf(kind, form.getState().values[name]);\n const today = new Date();\n const label = monthName.format(focused);\n title.textContent = label;\n dialog.setAttribute('aria-label', label);\n const first = new Date(focused.getFullYear(), focused.getMonth(), 1);\n const start = addDays(first, -((first.getDay() + 6) % 7)); // back to Monday\n const headRow = doc.createElement('tr');\n const weekHead = doc.createElement('th');\n weekHead.scope = 'col';\n weekHead.textContent = labels.weekShort;\n weekHead.setAttribute('abbr', labels.week);\n headRow.append(weekHead);\n for (let i = 0; i < 7; i++) {\n const d = addDays(start, i);\n const th = doc.createElement('th');\n th.scope = 'col';\n th.textContent = weekdayShort.format(d).replace(/\\.$/, '');\n th.setAttribute('abbr', weekdayLong.format(d));\n headRow.append(th);\n }\n const thead = doc.createElement('thead');\n thead.append(headRow);\n const tbody = doc.createElement('tbody');\n for (let row = start; row <= new Date(focused.getFullYear(), focused.getMonth() + 1, 0); row = addDays(row, 7)) {\n const tr = doc.createElement('tr');\n const week = doc.createElement('th');\n week.scope = 'row';\n week.className = 'fd-week';\n week.textContent = String(isoWeek(row));\n tr.append(week);\n for (let i = 0; i < 7; i++) {\n const d = addDays(row, i);\n const cell = doc.createElement('td');\n const day = doc.createElement('button');\n day.type = 'button';\n day.textContent = String(d.getDate());\n day.setAttribute('aria-label', dayName.format(d));\n day.tabIndex = sameDay(d, focused) ? 0 : -1;\n if (d.getMonth() !== focused.getMonth()) day.classList.add('fd-outside');\n if (chosen && sameDay(d, chosen)) day.setAttribute('aria-selected', 'true');\n if (sameDay(d, today)) day.setAttribute('aria-current', 'date');\n day.disabled = readonly;\n day.addEventListener('click', () => pick(d));\n day.addEventListener('keydown', (event) => onKey(event, d));\n cell.append(day);\n tr.append(cell);\n }\n tbody.append(tr);\n }\n grid.replaceChildren(thead, tbody);\n if (focus) grid.querySelector<HTMLButtonElement>('button[tabindex=\"0\"]')?.focus();\n }\n\n function move(to: Date) {\n focused = to;\n draw(true);\n }\n\n function onKey(event: KeyboardEvent, day: Date) {\n const moves: Record<string, () => Date> = {\n ArrowLeft: () => addDays(day, -1),\n ArrowRight: () => addDays(day, 1),\n ArrowUp: () => addDays(day, -7),\n ArrowDown: () => addDays(day, 7),\n PageUp: () => addMonths(day, -1),\n PageDown: () => addMonths(day, 1),\n Home: () => addDays(day, -((day.getDay() + 6) % 7)),\n End: () => addDays(day, 6 - ((day.getDay() + 6) % 7)),\n };\n if (moves[event.key]) {\n event.preventDefault();\n move(moves[event.key]());\n } else if (event.key === 'Enter' || event.key === ' ') {\n event.preventDefault();\n pick(day);\n }\n }\n\n function open() {\n focused = dayOf(kind, form.getState().values[name]) ?? new Date();\n dialog.hidden = false;\n button.setAttribute('aria-expanded', 'true');\n draw(true);\n }\n\n function close() {\n if (dialog.hidden) return;\n dialog.hidden = true;\n button.setAttribute('aria-expanded', 'false');\n button.focus();\n }\n\n button.addEventListener('click', () => (dialog.hidden ? open() : close()));\n prev.addEventListener('click', () => {\n focused = addMonths(focused, -1);\n draw(false);\n });\n next.addEventListener('click', () => {\n focused = addMonths(focused, 1);\n draw(false);\n });\n dialog.addEventListener('keydown', (event) => {\n if (event.key === 'Escape') {\n event.preventDefault();\n event.stopPropagation();\n close();\n }\n });\n const outside = (event: Event) => {\n if (!dialog.hidden && !element.contains(event.target as Node)) {\n dialog.hidden = true;\n button.setAttribute('aria-expanded', 'false');\n }\n };\n doc.addEventListener('mousedown', outside);\n\n return {\n element,\n focus: () => inner.focus(),\n update(state) {\n readonly = state.readonly;\n button.hidden = state.readonly;\n if (state.readonly) dialog.hidden = true;\n inner.update(state);\n },\n destroy() {\n doc.removeEventListener('mousedown', outside);\n inner.destroy?.();\n },\n };\n}\n", "import type { Field, FieldNode, Form, FormState, JsonValue, PropertyDefinition, Value } from '@fieldia/core';\nimport { createWidget, type Widget, type WidgetFactory } from './widgets';\n\n/**\n * A properties field, one row per property, each edited with the widget for\n * its type: text, numbers, yes/no, a choice, a date. The field's `definitions`\n * say which properties there are; without them, each property is worked out\n * from its value. The properties stay one value: an object by property name.\n */\n\n/** \"lift_access\" \u2192 \"Lift access\". */\nconst humanize = (name: string) => {\n const words = name.replace(/_/g, ' ').trim();\n return words.charAt(0).toUpperCase() + words.slice(1);\n};\n\n/** A property's type, from what it holds. */\nfunction guess(name: string, value: Value | undefined): PropertyDefinition {\n const label = humanize(name);\n if (typeof value === 'boolean') return { name, label, type: 'boolean' };\n if (typeof value === 'number') return { name, label, type: Number.isInteger(value) ? 'integer' : 'float' };\n if (typeof value === 'string' && /^\\d{4}-\\d{2}-\\d{2}$/.test(value)) return { name, label, type: 'date' };\n return { name, label, type: 'char' };\n}\n\nexport const propertiesWidget: WidgetFactory = (context) => {\n const { form, name, field, node, id, document } = context;\n const declared = field.type === 'properties' ? field.definitions : undefined;\n const current = () => {\n const value = form.getState().values[name];\n return value && typeof value === 'object' && !Array.isArray(value) ? (value as Record<string, Value>) : {};\n };\n // Each property's widget sees the properties as its record, and writes into them.\n const properties: Form = {\n ...form,\n getState: (): FormState => ({ ...form.getState(), values: current() }),\n // Property values are plain JSON: text, numbers, yes/no, a choice, a date.\n setValue: (property: string, value: Value) => form.setValue(name, { ...current(), [property]: value } as JsonValue),\n };\n\n const element = document.createElement('div');\n element.className = 'fd-properties';\n element.setAttribute('role', 'group');\n let rows: { definition: PropertyDefinition; widget: Widget }[] = [];\n let drawn = '';\n\n function draw(definitions: PropertyDefinition[]) {\n for (const row of rows) row.widget.destroy?.();\n rows = definitions.map((definition) => {\n const rowId = `${id}-${definition.name}`;\n const propertyField = { type: definition.type, label: definition.label, ...(definition.options ? { options: definition.options } : {}) } as Field;\n const propertyNode: FieldNode = { type: 'field', id: `${node.id}.${definition.name}`, field: definition.name };\n const widget = createWidget({ ...context, form: properties, name: definition.name, field: propertyField, node: propertyNode, id: rowId });\n return { definition, widget };\n });\n element.replaceChildren(\n ...rows.map(({ definition, widget }) => {\n const row = document.createElement('div');\n row.className = 'fd-property';\n row.dataset['type'] = definition.type;\n const label = document.createElement('label');\n label.htmlFor = `${id}-${definition.name}`;\n label.textContent = definition.label;\n row.append(label, widget.element);\n return row;\n })\n );\n }\n\n return {\n element,\n focus: () => rows[0]?.widget.focus(),\n destroy: () => rows.forEach((row) => row.widget.destroy?.()),\n update(state) {\n const values = current();\n const definitions = declared ?? Object.keys(values).map((key) => guess(key, values[key]));\n const key = JSON.stringify(definitions);\n if (key !== drawn) {\n drawn = key;\n draw(definitions);\n }\n for (const { definition, widget } of rows) {\n widget.update({ value: values[definition.name] ?? null, values, readonly: state.readonly, required: false, invalid: false });\n }\n },\n };\n};\n", "import { WIDGET_LABELS, type WidgetLabels } from './labels';\nimport type { WidgetFactory } from './widgets';\n\n/**\n * Formatted text and JSON. Formatted text is edited in place, with a toolbar\n * (bold, italic, underline, headings, lists, alignment, links) that drives the\n * browser's own editing, so no editor library is loaded. Every value \u2014 typed,\n * pasted or loaded \u2014 passes through `sanitizeHtml`, so stored markup can never\n * run script in the page.\n */\n\nconst ALLOWED = new Set([\n 'P', 'BR', 'B', 'STRONG', 'I', 'EM', 'U', 'S', 'UL', 'OL', 'LI', 'A', 'H1', 'H2', 'H3', 'H4',\n 'BLOCKQUOTE', 'CODE', 'PRE', 'SPAN', 'DIV',\n]);\nconst DROPPED_WITH_CONTENT = new Set(['SCRIPT', 'STYLE', 'IFRAME', 'OBJECT', 'EMBED', 'TEMPLATE', 'NOSCRIPT', 'SVG', 'MATH']);\n/** Blocks that may keep their alignment, the one style the toolbar sets. */\nconst ALIGNABLE = new Set(['P', 'DIV', 'H1', 'H2', 'H3', 'H4', 'LI', 'BLOCKQUOTE', 'PRE']);\nconst ALIGNMENTS = new Set(['left', 'center', 'right', 'justify', 'start', 'end']);\n\n/** Keep text structure, block alignment and http(s)/mailto links; drop every other element and attribute. */\nexport function sanitizeHtml(html: string, document: Document = globalThis.document): string {\n const box = document.createElement('template');\n box.innerHTML = html;\n const clean = (parent: ParentNode) => {\n for (const node of [...parent.childNodes]) {\n if (node.nodeType === Node.TEXT_NODE) continue;\n if (node.nodeType !== Node.ELEMENT_NODE) {\n node.remove();\n continue;\n }\n const element = node as Element;\n if (DROPPED_WITH_CONTENT.has(element.tagName)) {\n element.remove();\n continue;\n }\n clean(element);\n if (!ALLOWED.has(element.tagName)) {\n element.replaceWith(...element.childNodes);\n continue;\n }\n const href = element.tagName === 'A' ? element.getAttribute('href') : null;\n const align = ALIGNABLE.has(element.tagName) ? (element as HTMLElement).style?.textAlign?.trim().toLowerCase() : '';\n for (const attribute of [...element.attributes]) element.removeAttribute(attribute.name);\n if (href && /^(https?:|mailto:)/i.test(href.trim())) element.setAttribute('href', href.trim());\n if (align && ALIGNMENTS.has(align)) element.setAttribute('style', `text-align: ${align};`);\n }\n };\n clean(box.content);\n const out = document.createElement('div');\n out.append(box.content);\n return out.innerHTML;\n}\n\n/** A typed address as a link target: web and mail addresses only, \"https://\" added to a bare domain. */\nexport function linkAddress(typed: string): string | null {\n const text = typed.trim();\n if (/^(https?:\\/\\/|mailto:)\\S+$/i.test(text)) return text;\n if (/^[^\\s@:/]+@[^\\s@:/]+\\.[^\\s@:/]+$/.test(text)) return `mailto:${text}`;\n if (/^[\\w-]+(\\.[\\w-]+)+([/?#]\\S*)?$/.test(text)) return `https://${text}`;\n return null;\n}\n\n/** The toolbar's buttons: [label key, editing command, drawn icon]. */\nconst TOOLS: [keyof WidgetLabels, string, string][] = [\n ['bold', 'bold', '<b>B</b>'],\n ['italic', 'italic', '<i>I</i>'],\n ['underline', 'underline', '<u>U</u>'],\n ['bulletList', 'insertUnorderedList', '<svg viewBox=\"0 0 16 16\"><circle cx=\"3\" cy=\"4\" r=\"1.2\"/><circle cx=\"3\" cy=\"8\" r=\"1.2\"/><circle cx=\"3\" cy=\"12\" r=\"1.2\"/><path d=\"M6 4h8M6 8h8M6 12h8\"/></svg>'],\n ['numberList', 'insertOrderedList', '<svg viewBox=\"0 0 16 16\"><path d=\"M2.5 3h1v3M2 10.5c.5-.8 2-.8 2 .2 0 .8-2 1.3-2 2.3h2M6 4h8M6 8h8M6 12h8\"/></svg>'],\n ['alignLeft', 'justifyLeft', '<svg viewBox=\"0 0 16 16\"><path d=\"M2 3.5h12M2 6.5h8M2 9.5h12M2 12.5h8\"/></svg>'],\n ['alignCenter', 'justifyCenter', '<svg viewBox=\"0 0 16 16\"><path d=\"M2 3.5h12M4 6.5h8M2 9.5h12M4 12.5h8\"/></svg>'],\n ['alignRight', 'justifyRight', '<svg viewBox=\"0 0 16 16\"><path d=\"M2 3.5h12M6 6.5h8M2 9.5h12M6 12.5h8\"/></svg>'],\n ['link', 'createLink', '<svg viewBox=\"0 0 16 16\"><path d=\"M7 9a3 3 0 0 0 4.2 0l2.3-2.3a3 3 0 0 0-4.2-4.2L8.2 3.6M9 7a3 3 0 0 0-4.2 0L2.5 9.3a3 3 0 0 0 4.2 4.2l1.1-1.1\"/></svg>'],\n];\n\nexport const htmlWidget: WidgetFactory = ({ form, name, node, id, document, labels = WIDGET_LABELS.en }) => {\n const area = document.createElement('div');\n area.id = id;\n area.className = 'fd-input fd-richtext';\n area.setAttribute('role', 'textbox');\n area.setAttribute('aria-multiline', 'true');\n area.setAttribute('contenteditable', 'true');\n const withToolbar = node.options?.['toolbar'] !== false;\n let last = '';\n area.addEventListener('input', () => {\n const clean = sanitizeHtml(area.innerHTML, document);\n last = clean;\n form.setValue(name, clean.trim() === '' ? null : clean);\n });\n area.addEventListener('blur', () => {\n // Show what was stored: anything unsafe that was typed or pasted is gone.\n if (area.innerHTML !== last) area.innerHTML = last;\n });\n const toolbar = withToolbar ? formattingToolbar(area, document, labels) : null;\n let element: HTMLElement = area;\n if (toolbar) {\n // The box is labelled by the field's label; the text inside it says so too.\n element = document.createElement('div');\n element.className = 'fd-richtext-box';\n element.setAttribute('role', 'group');\n area.setAttribute('aria-labelledby', `${id}-label`);\n element.append(toolbar.bar, toolbar.linkRow, area);\n }\n return {\n element,\n focus: () => area.focus(),\n destroy: () => toolbar?.destroy(),\n update(state) {\n if (toolbar) {\n toolbar.bar.hidden = state.readonly;\n if (state.readonly) toolbar.linkRow.hidden = true;\n }\n const clean = sanitizeHtml(typeof state.value === 'string' ? state.value : '', document);\n if (clean !== last || document.activeElement !== area) {\n if (area.innerHTML !== clean) area.innerHTML = clean;\n last = clean;\n }\n area.setAttribute('contenteditable', String(!state.readonly));\n area.setAttribute('aria-readonly', String(state.readonly));\n area.setAttribute('aria-invalid', String(state.invalid));\n if (state.describedBy) area.setAttribute('aria-describedby', state.describedBy);\n },\n };\n};\n\n/**\n * The toolbar of a formatted text: buttons that keep the text's selection\n * (they act on mousedown's behalf), a text-style choice, and a row for a link's\n * address. One button takes Tab; the arrow keys move along the bar.\n */\nfunction formattingToolbar(area: HTMLElement, doc: Document, labels: WidgetLabels) {\n const bar = doc.createElement('div');\n bar.className = 'fd-richtext-bar';\n bar.setAttribute('role', 'toolbar');\n bar.setAttribute('aria-label', labels.formatting);\n // The last selection made in the text: the style box and the address box take\n // the focus, and a command must act where the person had selected.\n let lastRange: Range | null = null;\n const restore = () => {\n area.focus();\n const selection = doc.getSelection();\n if (lastRange && selection) {\n selection.removeAllRanges();\n selection.addRange(lastRange);\n }\n };\n const run = (command: string, value?: string) => {\n restore();\n doc.execCommand?.(command, false, value);\n };\n\n const style = doc.createElement('select');\n style.className = 'fd-richtext-style';\n style.setAttribute('aria-label', labels.textStyle);\n for (const [value, key] of [['p', 'paragraph'], ['h2', 'heading'], ['h3', 'subheading']] as const) {\n const option = doc.createElement('option');\n option.value = value;\n option.textContent = labels[key];\n style.append(option);\n }\n style.addEventListener('change', () => run('formatBlock', `<${style.value}>`));\n\n const linkRow = doc.createElement('div');\n linkRow.className = 'fd-link-row';\n linkRow.hidden = true;\n const address = doc.createElement('input');\n address.className = 'fd-input';\n address.type = 'url';\n address.placeholder = 'https://';\n address.setAttribute('aria-label', labels.linkAddress);\n const apply = doc.createElement('button');\n apply.type = 'button';\n apply.className = 'fd-button fd-link-apply';\n apply.textContent = labels.applyLink;\n const unlink = doc.createElement('button');\n unlink.type = 'button';\n unlink.className = 'fd-button fd-button-link fd-link-remove';\n unlink.textContent = labels.removeLink;\n linkRow.append(address, apply, unlink);\n apply.addEventListener('click', () => {\n const url = linkAddress(address.value);\n if (!url) {\n address.setAttribute('aria-invalid', 'true');\n return;\n }\n address.setAttribute('aria-invalid', 'false');\n restore();\n doc.execCommand?.('createLink', false, url);\n linkRow.hidden = true;\n });\n unlink.addEventListener('click', () => {\n restore();\n doc.execCommand?.('unlink', false);\n linkRow.hidden = true;\n });\n address.addEventListener('keydown', (event) => {\n if (event.key === 'Enter') {\n event.preventDefault();\n apply.click();\n } else if (event.key === 'Escape') {\n event.preventDefault();\n linkRow.hidden = true;\n restore();\n }\n });\n\n const buttons = TOOLS.map(([key, command, icon]) => {\n const button = doc.createElement('button');\n button.type = 'button';\n button.className = 'fd-richtext-tool';\n button.setAttribute('aria-label', labels[key]);\n button.title = labels[key];\n button.innerHTML = icon;\n button.querySelector('svg')?.setAttribute('aria-hidden', 'true');\n if (['bold', 'italic', 'underline'].includes(command)) button.setAttribute('aria-pressed', 'false');\n // Keep the text's selection when the button is pressed.\n button.addEventListener('mousedown', (event) => event.preventDefault());\n button.addEventListener('click', () => {\n if (command !== 'createLink') return run(command);\n linkRow.hidden = false;\n address.value = '';\n address.focus();\n });\n return button;\n });\n bar.append(style, ...buttons);\n\n // One stop on Tab; the arrow keys move along the bar.\n const stops = [style, ...buttons];\n stops.forEach((stop, i) => (stop.tabIndex = i === 0 ? 0 : -1));\n bar.addEventListener('keydown', (event) => {\n if (event.key !== 'ArrowRight' && event.key !== 'ArrowLeft') return;\n const at = stops.indexOf(doc.activeElement as HTMLButtonElement);\n if (at < 0) return;\n const rtl = getComputedStyle(bar).direction === 'rtl';\n const step = (event.key === 'ArrowRight') !== rtl ? 1 : -1;\n const next = stops[(at + step + stops.length) % stops.length];\n event.preventDefault();\n stops.forEach((stop) => (stop.tabIndex = stop === next ? 0 : -1));\n next.focus();\n });\n\n // Show which formats the selection already has.\n const reflect = () => {\n const selection = doc.getSelection();\n if (!selection || !selection.rangeCount || !area.contains(selection.anchorNode)) return;\n lastRange = selection.getRangeAt(0).cloneRange();\n for (const button of buttons) {\n const command = TOOLS[buttons.indexOf(button)][1];\n if (button.hasAttribute('aria-pressed')) button.setAttribute('aria-pressed', String(doc.queryCommandState?.(command) ?? false));\n }\n const block = String(doc.queryCommandValue?.('formatBlock') ?? '').toLowerCase().replace(/[<>]/g, '');\n style.value = block === 'h2' || block === 'h3' ? block : 'p';\n };\n doc.addEventListener('selectionchange', reflect);\n return { bar, linkRow, destroy: () => doc.removeEventListener('selectionchange', reflect) };\n}\n\nexport const jsonWidget: WidgetFactory = ({ form, name, id, document, labels = WIDGET_LABELS.en }) => {\n const element = document.createElement('div');\n element.className = 'fd-json';\n const area = document.createElement('textarea');\n area.id = id;\n area.className = 'fd-input fd-textarea fd-code';\n area.spellcheck = false;\n const error = document.createElement('div');\n error.className = 'fd-cell-error';\n error.hidden = true;\n element.append(area, error);\n area.addEventListener('input', () => {\n if (area.value.trim() === '') {\n error.hidden = true;\n form.setValue(name, null);\n return;\n }\n try {\n const parsed = JSON.parse(area.value);\n error.hidden = true;\n form.setValue(name, parsed);\n } catch {\n error.hidden = false;\n error.textContent = labels.invalidJson;\n }\n });\n return {\n element,\n focus: () => area.focus(),\n update(state) {\n if (document.activeElement !== area) {\n const text = state.value === null || state.value === undefined ? '' : JSON.stringify(state.value, null, 2);\n if (area.value !== text) area.value = text;\n }\n area.readOnly = state.readonly;\n area.setAttribute('aria-invalid', String(state.invalid || !error.hidden));\n },\n };\n};\n", "import type {\n Field,\n FieldNode,\n FileValue,\n Form,\n Line,\n Locale,\n RecordId,\n ReferenceValue,\n RelatedRecord,\n Value,\n Values,\n} from '@fieldia/core';\nimport type { PreferenceStore } from './preferences';\nimport { formatNumber, normalizeNumber } from './numbers';\nimport type { WidgetLabels } from './labels';\nimport { charTagsWidget, linkCheckboxesWidget, many2oneWidget, referenceWidget, tagsWidget } from './relations';\nimport { linesWidget } from './lines';\nimport { binaryWidget, imageWidget } from './files';\nimport { progressbarWidget } from './progress';\nimport { labelWidget } from './label';\nimport { statusbarWidget } from './statusbar';\nimport { withCalendar } from './calendar';\nimport { propertiesWidget } from './properties';\nimport { htmlWidget, jsonWidget } from './extras';\n\n/**\n * Field inputs in plain DOM. Each widget builds its element once and then only\n * patches it from state, so typing never loses focus or the caret, and the\n * same widget serves every framework binding.\n */\n\nexport interface WidgetContext {\n form: Form;\n /** The field's name in the page. */\n name: string;\n field: Field;\n node: FieldNode;\n /** The id the field's label points at. */\n id: string;\n document: Document;\n /** Words the widget shows itself, in the page's language. English when left out. */\n labels?: WidgetLabels;\n /** Where to keep a person's choices about how the widget looks, such as a table's columns. */\n preferences?: PreferenceStore;\n /** The page's language: numbers and dates are written as its readers write them. English when left out. */\n locale?: Locale;\n /** Dialogs the page can open: a related record, a searchable list, values to edit. Left out, widgets offer none. */\n dialogs?: WidgetDialogs;\n}\n\n/** What a widget may ask of the page around it in a dialog. The viewer provides these. */\nexport interface WidgetDialogs {\n /** Whether a record of this model can be shown in a dialog: the app gave a page for it. */\n canOpen(model: string): boolean;\n /**\n * A record in a dialog: an existing one (`recordId`) or a new one, whose name\n * starts as `name`. Resolves with the record once saved, or null.\n */\n openRecord(model: string, request: { recordId?: RecordId; name?: string; title: string }): Promise<RelatedRecord | null>;\n /** Pick a record from a searchable list. */\n searchMore(request: { title: string; search(query: string, limit: number): Promise<RelatedRecord[]> }): Promise<RelatedRecord | null>;\n /**\n * Values edited in a form made of these fields. Resolves with the new values,\n * or null. `recompute` recalculates them as they change, as a line's onchange.\n */\n editValues(request: { title: string; fields: Record<string, Field>; values: Values; readonly?: boolean; recompute?: (values: Values) => Promise<Values> }): Promise<Values | null>;\n}\n\nexport interface WidgetState {\n value: Value | undefined;\n /** Every value of the record, for widgets that show one field beside another. */\n values: Readonly<Values>;\n readonly: boolean;\n required: boolean;\n invalid: boolean;\n /** Ids of the help and error text, for assistive technology. */\n describedBy?: string;\n}\n\nexport interface Widget {\n element: HTMLElement;\n update(state: WidgetState): void;\n focus(): void;\n destroy?(): void;\n}\n\nexport type WidgetFactory = (context: WidgetContext) => Widget;\n\n/**\n * Pick the widget for a field: the app's or the built-in one for\n * `type.widget` (such as `selection.radio`), then for the type alone. A type\n * with no editor yet shows its value read-only.\n */\nexport function createWidget(context: WidgetContext, registry: Record<string, WidgetFactory> = {}): Widget {\n const { field, node } = context;\n const keys = [\n node.widget ? `${field.type}.${node.widget}` : null,\n field.type === 'selection' && field.multiple ? 'selection.checkboxes' : null,\n field.type,\n ].filter((key): key is string => key !== null);\n for (const key of keys) {\n const factory = registry[key] ?? builtInWidgets[key];\n if (factory) return factory(context);\n }\n return pendingWidget(context);\n}\n\n// ---------------------------------------------------------------------------\n\nfunction make<K extends keyof HTMLElementTagNameMap>(\n doc: Document,\n tag: K,\n props: Partial<Record<string, string>> = {},\n ...children: (Node | string)[]\n): HTMLElementTagNameMap[K] {\n const element = doc.createElement(tag);\n for (const [name, value] of Object.entries(props)) if (value !== undefined) element.setAttribute(name, value);\n element.append(...children);\n return element;\n}\n\nfunction describe(element: HTMLElement, state: WidgetState) {\n element.setAttribute('aria-invalid', String(state.invalid));\n element.setAttribute('aria-required', String(state.required));\n if (state.describedBy) element.setAttribute('aria-describedby', state.describedBy);\n else element.removeAttribute('aria-describedby');\n}\n\nconst textOf = (value: Value | undefined) => (value === null || value === undefined ? '' : String(value));\n\nfunction textWidget(inputType: string): WidgetFactory {\n return ({ form, name, field, node, id, document }) => {\n const input = make(document, 'input', { id, type: inputType, class: 'fd-input', autocomplete: 'off' });\n if (field.type === 'char' && field.size !== undefined) input.maxLength = field.size;\n if (node.placeholder) input.placeholder = node.placeholder;\n input.addEventListener('input', () => form.setValue(name, input.value === '' ? null : input.value));\n return {\n element: input,\n focus: () => input.focus(),\n update(state) {\n const text = textOf(state.value);\n if (input.value !== text) input.value = text;\n input.readOnly = state.readonly;\n describe(input, state);\n },\n };\n };\n}\n\nconst textareaWidget: WidgetFactory = ({ form, name, field, node, id, document }) => {\n const area = make(document, 'textarea', { id, class: 'fd-input fd-textarea', rows: '3' });\n if (field.type === 'text' && field.size !== undefined) area.maxLength = field.size;\n if (node.placeholder) area.placeholder = node.placeholder;\n area.addEventListener('input', () => form.setValue(name, area.value === '' ? null : area.value));\n return {\n element: area,\n focus: () => area.focus(),\n update(state) {\n const text = textOf(state.value);\n if (area.value !== text) area.value = text;\n area.readOnly = state.readonly;\n describe(area, state);\n },\n };\n};\n\nconst NUMBER = /^-?(\\d+\\.?\\d*|\\.\\d+)$/;\nconst UNFINISHED = /^-?\\.?$/;\n\n/**\n * Numbers are written as readers of the page's language write them, grouped,\n * with the field's decimals, and read back the same way. What is typed stays\n * as typed while focused: \"1.\" means 1 now and 1.5 a keystroke later. The box\n * keeps its spelling when entered, so a selection made on the way in holds.\n */\nconst numberWidget: WidgetFactory = (context) => {\n const { form, name, field, node, id, document, locale = 'en' } = context;\n const integer = field.type === 'integer';\n const decimals = integer ? 0 : (field.type === 'float' || field.type === 'monetary' ? field.digits?.[1] : undefined) ?? 2;\n const shown = (value: Value | undefined) => (typeof value === 'number' ? formatNumber(value, decimals, locale) : textOf(value));\n const input = make(document, 'input', { id, type: 'text', class: 'fd-input fd-number-input', autocomplete: 'off' });\n input.inputMode = integer ? 'numeric' : 'decimal';\n if (node.placeholder) input.placeholder = node.placeholder;\n\n const parse = (raw: string): Value | undefined => {\n const text = normalizeNumber(raw.trim(), locale);\n if (text === '') return null;\n if (NUMBER.test(text)) return Number(text);\n if (UNFINISHED.test(text)) return undefined; // \"-\" or \".\": keep typing\n return text; // not a number: validation names it\n };\n input.addEventListener('input', () => {\n const value = parse(input.value);\n if (value !== undefined) form.setValue(name, value);\n });\n input.addEventListener('blur', () => {\n input.value = shown(form.getState().values[name]);\n });\n\n // Money shows its currency beside the amount (options.symbol \"after\" puts it\n // after), or with options.pickCurrency the currency field's own widget, to change it.\n const options = node.options ?? {};\n const currencyField = field.type === 'monetary' ? field.currencyField : undefined;\n const currencyDef = currencyField ? form.page.fields[currencyField] : undefined;\n const picker =\n currencyField && currencyDef && options['pickCurrency'] === true\n ? createWidget({ ...context, name: currencyField, field: currencyDef, node: { type: 'field', id: `${node.id}.currency`, field: currencyField }, id: `${id}-currency` })\n : null;\n if (picker && currencyDef) picker.element.querySelector('input, select')?.setAttribute('aria-label', currencyDef.label);\n if (picker?.element.matches('input, select') && currencyDef) picker.element.setAttribute('aria-label', currencyDef.label);\n const currency = field.type === 'monetary' && !picker ? make(document, 'span', { class: 'fd-currency', 'aria-hidden': 'true' }) : null;\n const side = picker?.element ?? currency;\n const after = options['symbol'] === 'after';\n const element = side\n ? make(document, 'span', { class: `fd-number${after ? ' fd-currency-after' : ''}${picker ? ' fd-currency-picked' : ''}` }, ...(after ? [input, side] : [side, input]))\n : input;\n\n return {\n element,\n focus: () => input.focus(),\n update(state) {\n const typing = document.activeElement === input;\n const parsed = parse(input.value);\n const showsSame = parsed === undefined || parsed === state.value;\n if (!(typing && showsSame)) {\n const text = shown(state.value);\n if (input.value !== text) input.value = text;\n }\n input.readOnly = state.readonly;\n describe(input, state);\n if (picker && currencyField) {\n picker.update({ value: state.values[currencyField], values: state.values, readonly: state.readonly, required: false, invalid: false });\n }\n if (currency && field.type === 'monetary') {\n const holder = field.currencyField ? state.values[field.currencyField] : null;\n currency.textContent =\n holder && typeof holder === 'object' && 'label' in holder ? (holder as RelatedRecord).label : (typeof holder === 'string' ? holder : field.currency ?? '');\n }\n },\n };\n};\n\nfunction checkboxWidget(role?: 'switch'): WidgetFactory {\n return ({ form, name, id, document }) => {\n const box = make(document, 'input', { id, type: 'checkbox', class: role ? 'fd-switch' : 'fd-checkbox', role });\n box.addEventListener('change', () => form.setValue(name, box.checked));\n return {\n element: box,\n focus: () => box.focus(),\n update(state) {\n box.checked = state.value === true;\n box.disabled = state.readonly;\n describe(box, state);\n },\n };\n };\n}\n\nfunction options(field: Field) {\n return field.type === 'selection' ? field.options : [];\n}\n\nconst selectWidget: WidgetFactory = ({ form, name, field, id, document }) => {\n const choices = options(field);\n const select = make(document, 'select', { id, class: 'fd-input fd-select' }, make(document, 'option', { value: '' }));\n choices.forEach((option, i) => select.append(make(document, 'option', { value: String(i) }, option.label)));\n select.addEventListener('change', () => form.setValue(name, select.value === '' ? null : choices[Number(select.value)].value));\n return {\n element: select,\n focus: () => select.focus(),\n update(state) {\n const index = choices.findIndex((option) => option.value === state.value);\n select.value = index === -1 ? '' : String(index);\n select.disabled = state.readonly;\n describe(select, state);\n },\n };\n};\n\nfunction choiceGroup(kind: 'radio' | 'checkbox'): WidgetFactory {\n return ({ form, name, field, id, document }) => {\n const choices = options(field);\n const group = make(document, 'div', { id, class: `fd-choices fd-choices-${kind}`, role: kind === 'radio' ? 'radiogroup' : 'group' });\n const inputs = choices.map((option, i) => {\n const input = make(document, 'input', { type: kind, name: id, value: String(i), id: `${id}-${i}` });\n group.append(make(document, 'label', { class: 'fd-choice', for: `${id}-${i}` }, input, make(document, 'span', {}, option.label)));\n return input;\n });\n group.addEventListener('change', () => {\n if (kind === 'radio') {\n const chosen = inputs.findIndex((input) => input.checked);\n form.setValue(name, chosen === -1 ? null : choices[chosen].value);\n } else {\n form.setValue(name, choices.filter((_, i) => inputs[i].checked).map((option) => option.value));\n }\n });\n return {\n element: group,\n focus: () => (inputs.find((input) => input.checked) ?? inputs[0])?.focus(),\n update(state) {\n const chosen = Array.isArray(state.value) ? state.value : [state.value];\n inputs.forEach((input, i) => {\n input.checked = chosen.includes(choices[i].value as never);\n input.disabled = state.readonly;\n });\n describe(group, state);\n },\n };\n };\n}\n\n/** Stars or numbers to pick from, as a radio group with arrow-key support. */\nfunction pointsWidget(style: 'rating' | 'scale'): WidgetFactory {\n return ({ form, name, field, id, document }) => {\n const min = 'min' in field && field.min !== undefined ? field.min : style === 'rating' ? 1 : 0;\n const max = 'max' in field && field.max !== undefined ? field.max : style === 'rating' ? 5 : 10;\n const group = make(document, 'div', { id, class: `fd-points fd-${style}`, role: 'radiogroup' });\n const points: HTMLButtonElement[] = [];\n for (let n = min; n <= max; n++) {\n const point = make(document, 'button', { type: 'button', role: 'radio', 'aria-label': `${n} of ${max}`, 'data-value': String(n) }, style === 'rating' ? '\u2605' : String(n));\n if (style === 'scale') point.removeAttribute('aria-label');\n point.addEventListener('click', () => form.setValue(name, n));\n points.push(point);\n group.append(point);\n }\n group.addEventListener('keydown', (event) => {\n const current = form.getState().values[name];\n const value = typeof current === 'number' ? current : min - 1;\n const step = event.key === 'ArrowRight' || event.key === 'ArrowUp' ? 1 : event.key === 'ArrowLeft' || event.key === 'ArrowDown' ? -1 : 0;\n if (!step) return;\n event.preventDefault();\n const next = Math.min(max, Math.max(min, value + step));\n form.setValue(name, next);\n points[next - min]?.focus();\n });\n return {\n element: group,\n focus: () => (points.find((p) => p.getAttribute('aria-checked') === 'true') ?? points[0])?.focus(),\n update(state) {\n const value = typeof state.value === 'number' ? state.value : null;\n points.forEach((point, i) => {\n const n = min + i;\n point.setAttribute('aria-checked', String(n === value));\n point.classList.toggle('fd-on', style === 'rating' ? value !== null && n <= value : n === value);\n point.tabIndex = n === value || (value === null && i === 0) ? 0 : -1;\n point.disabled = state.readonly;\n });\n describe(group, state);\n },\n };\n };\n}\n\nconst dateWidget: WidgetFactory = (context) => {\n const { form, name, id, document, node } = context;\n const input = make(document, 'input', { id, type: 'date', class: 'fd-input fd-date' });\n input.addEventListener('input', () => form.setValue(name, input.value || null));\n const widget: Widget = {\n element: input,\n focus: () => input.focus(),\n update(state) {\n const text = textOf(state.value);\n if (input.value !== text) input.value = text;\n input.readOnly = state.readonly;\n describe(input, state);\n },\n };\n return node.options?.['weekNumbers'] === true ? withCalendar(widget, context, 'date') : widget;\n};\n\nconst pad = (n: number) => String(n).padStart(2, '0');\n\n/** Shown in local time, stored as an ISO instant in UTC. */\nconst dateTimeWidget: WidgetFactory = (context) => {\n const { form, name, id, document, node } = context;\n const input = make(document, 'input', { id, type: 'datetime-local', class: 'fd-input fd-datetime' });\n const local = (iso: Value | undefined) => {\n if (typeof iso !== 'string' || !iso) return '';\n const d = new Date(iso);\n return Number.isNaN(d.getTime()) ? '' : `${d.getFullYear()}-${pad(d.getMonth() + 1)}-${pad(d.getDate())}T${pad(d.getHours())}:${pad(d.getMinutes())}`;\n };\n input.addEventListener('input', () => {\n if (!input.value) return form.setValue(name, null);\n const d = new Date(input.value);\n if (!Number.isNaN(d.getTime())) form.setValue(name, d.toISOString());\n });\n const widget: Widget = {\n element: input,\n focus: () => input.focus(),\n update(state) {\n const text = local(state.value);\n if (input.value !== text) input.value = text;\n input.readOnly = state.readonly;\n describe(input, state);\n },\n };\n return node.options?.['weekNumbers'] === true ? withCalendar(widget, context, 'datetime') : widget;\n};\n\n/** Until a type has its own editor (Phase 5), show what it holds. */\nfunction pendingWidget({ field, id, document }: WidgetContext): Widget {\n const span = make(document, 'span', { id, class: 'fd-pending', 'data-fd-pending': field.type });\n return {\n element: span,\n focus: () => undefined,\n update(state) {\n span.textContent = summary(state.value, field);\n },\n };\n}\n\nexport function summary(value: Value | undefined, field: Field): string {\n if (value === null || value === undefined) return '';\n switch (field.type) {\n case 'many2one':\n case 'reference':\n return (value as RelatedRecord | ReferenceValue).label;\n case 'many2many':\n return (value as RelatedRecord[]).map((record) => record.label).join(', ');\n case 'one2many': {\n const count = (value as Line[]).length;\n return `${count} ${count === 1 ? 'line' : 'lines'}`;\n }\n case 'binary':\n case 'image':\n return (value as FileValue).name;\n case 'html':\n return String(value).replace(/<[^>]*>/g, ' ').replace(/\\s+/g, ' ').trim();\n default:\n return typeof value === 'object' ? JSON.stringify(value) : String(value);\n }\n}\n\nexport const builtInWidgets: Record<string, WidgetFactory> = {\n char: textWidget('text'),\n 'char.email': textWidget('email'),\n 'char.phone': textWidget('tel'),\n 'char.url': textWidget('url'),\n 'char.password': textWidget('password'),\n 'char.tags': charTagsWidget,\n text: textareaWidget,\n integer: numberWidget,\n float: numberWidget,\n monetary: numberWidget,\n 'integer.rating': pointsWidget('rating'),\n 'integer.scale': pointsWidget('scale'),\n 'integer.progressbar': progressbarWidget,\n 'integer.label': labelWidget,\n 'float.label': labelWidget,\n 'monetary.label': labelWidget,\n 'float.progressbar': progressbarWidget,\n 'monetary.progressbar': progressbarWidget,\n boolean: checkboxWidget(),\n 'boolean.toggle': checkboxWidget('switch'),\n selection: selectWidget,\n 'selection.radio': choiceGroup('radio'),\n 'selection.checkboxes': choiceGroup('checkbox'),\n 'selection.statusbar': statusbarWidget,\n date: dateWidget,\n datetime: dateTimeWidget,\n many2one: many2oneWidget,\n 'many2one.statusbar': statusbarWidget,\n many2many: tagsWidget,\n 'many2many.tags': tagsWidget,\n 'many2many.checkboxes': linkCheckboxesWidget,\n reference: referenceWidget,\n one2many: linesWidget,\n binary: binaryWidget,\n image: imageWidget,\n html: htmlWidget,\n json: jsonWidget,\n properties: propertiesWidget,\n};\n", "/**\n * Fieldia's stylesheet: two skins and the layout chrome, all scoped to the\n * form's own root (`.fd-form[data-fd-skin=\u2026]`), so two forms on one page can\n * wear different skins and the host page's own controls are never touched.\n *\n * underline \u2014 the Flectra and Odoo style: flat inputs on a single line, labels\n * beside the field, navy accents.\n * outlined \u2014 the Ant Design style: boxed inputs with rounded corners, labels\n * above the field, a blue focus glow.\n *\n * Written with logical properties (inline/block, start/end), so a right-to-left\n * form mirrors without a second stylesheet.\n */\nexport const FIELDIA_CSS = /* css */ `.fd-form,.fd-theme{--fd-font: system-ui, -apple-system, \"Segoe UI\", Roboto, \"Noto Sans\", \"Noto Sans Arabic\", sans-serif;--fd-text: #212529;--fd-muted: #6b7280;--fd-page: #f2f3f5;--fd-surface: #ffffff;--fd-border: #cfd4da;--fd-border-strong: #9aa3ad;--fd-accent: #002855;--fd-accent-text: #ffffff;--fd-accent-soft: #e6ebf2;--fd-focus: #002855;--fd-focus-ring: none;--fd-error: #c62828;--fd-error-soft: #fdecea;--fd-success: #2e7d32;--fd-success-soft: #e8f5e9;--fd-warning: #8a5300;--fd-warning-soft: #fff4e0;--fd-info: #0b5cad;--fd-info-soft: #e7f0fb;--fd-radius: 0px;--fd-control-radius: 0px;--fd-pad-y: 3px;--fd-pad-x: 4px;--fd-input-border: 0 0 1px 0;--fd-label-weight: 600;--fd-gap-x: 32px;--fd-gap-y: 14px;container-type:inline-size;font-family:var(--fd-font);font-size:14px;line-height:1.45;color:var(--fd-text);-webkit-text-size-adjust:100%}.fd-form[data-fd-skin=outlined],.fd-theme[data-fd-skin=outlined]{--fd-text: rgba(0, 0, 0, .88);--fd-muted: rgba(0, 0, 0, .55);--fd-page: #f5f5f5;--fd-border: #d9d9d9;--fd-border-strong: #bfbfbf;--fd-accent: #1677ff;--fd-accent-soft: #e6f4ff;--fd-focus: #1677ff;--fd-focus-ring: 0 0 0 2px rgba(5, 145, 255, .12);--fd-error: #ff4d4f;--fd-error-soft: #fff2f0;--fd-radius: 8px;--fd-control-radius: 6px;--fd-pad-y: 4px;--fd-pad-x: 11px;--fd-input-border: 1px;--fd-label-weight: 400;--fd-gap-x: 24px;--fd-gap-y: 18px}.fd-form *,.fd-form *:before,.fd-form *:after{box-sizing:border-box}.fd-form [hidden]{display:none!important}.fd-page-head{display:grid;gap:4px;margin-block-end:20px}.fd-page-title{font-size:22px;font-weight:650;margin:0;line-height:1.25}.fd-page-description{color:var(--fd-muted);margin:0}.fd-form[data-max-width=narrow]{--fd-page-max: 640px}.fd-form[data-max-width=medium]{--fd-page-max: 900px}.fd-form[data-max-width=wide]{--fd-page-max: 1180px}.fd-form[data-max-width=full]{--fd-page-max: none}.fd-form[data-max-width]>.fd-content:not(:has(>.fd-sheet-page)){max-width:var(--fd-page-max);margin-inline:auto}.fd-actions.fd-actions-top{margin-block-start:0;padding-block-end:14px;margin-block-end:18px;border-block-end:1px solid var(--fd-border)}.fd-icon{width:1.15em;height:1.15em;flex:none;vertical-align:-.2em}.fd-section-title .fd-icon,.fd-tab .fd-icon,.fd-button .fd-icon,.fd-step-title .fd-icon{margin-inline-end:.4em}.fd-section-title .fd-icon{color:var(--fd-muted)}.fd-grid{display:grid;grid-template-columns:repeat(var(--fd-columns, 1),minmax(0,1fr));gap:var(--fd-gap-y) var(--fd-gap-x);align-items:start}.fd-field{display:grid;gap:4px;min-width:0;grid-column:span min(var(--fd-span, 1),var(--fd-columns, 1))}.fd-label{font-weight:var(--fd-label-weight);color:var(--fd-text)}.fd-valid-mark{color:var(--fd-success);width:1em;height:1em;margin-inline-start:6px;vertical-align:-.15em;stroke-width:2.4}.fd-field.fd-required>.fd-label:after{content:\" *\";color:var(--fd-error)}.fd-form[data-fd-skin=outlined] .fd-field.fd-required>.fd-label:after{content:\"\"}.fd-form[data-fd-skin=outlined] .fd-field.fd-required>.fd-label:before{content:\"* \";color:var(--fd-error)}.fd-help{color:var(--fd-muted);font-size:12.5px}.fd-error{color:var(--fd-error);font-size:12.5px}.fd-warning{color:var(--fd-warning);background:var(--fd-warning-soft);font-size:12.5px;padding:3px 8px;border-radius:var(--fd-control-radius);justify-self:start}.fd-form[data-fd-skin=underline] .fd-field{grid-template-columns:var(--fd-label-width, 11em) minmax(0,1fr);column-gap:12px;align-items:baseline}.fd-form[data-fd-skin=underline] .fd-field>.fd-label{grid-column:1}.fd-form[data-fd-skin=underline] .fd-field[data-type=one2many]{grid-template-columns:minmax(0,1fr)}.fd-form[data-fd-skin=underline] .fd-field[data-type=one2many]>*{grid-column:1!important}.fd-form[data-fd-skin=underline] .fd-field>:not(.fd-label){grid-column:2}@container (max-width: 760px){.fd-form[data-fd-skin=underline] .fd-grid{grid-template-columns:minmax(0,1fr)}.fd-form[data-fd-skin=underline] .fd-field{grid-column:auto}.fd-form .fd-grid[data-columns-medium]{grid-template-columns:repeat(var(--fd-columns-medium),minmax(0,1fr))}.fd-form .fd-grid[data-columns-medium]>.fd-field{grid-column:span min(var(--fd-span, 1),var(--fd-columns-medium))}.fd-form[data-fd-skin=underline] .fd-grid[data-columns-medium]:not([data-columns-medium=\"1\"]) .fd-field{grid-template-columns:minmax(0,1fr)}.fd-form[data-fd-skin=underline] .fd-grid[data-columns-medium]:not([data-columns-medium=\"1\"]) .fd-field>*{grid-column:1!important}}@container (max-width: 520px){.fd-grid{grid-template-columns:minmax(0,1fr)}.fd-field{grid-column:auto}.fd-form[data-fd-skin=underline] .fd-field{grid-template-columns:minmax(0,1fr)}.fd-form[data-fd-skin=underline] .fd-field>*{grid-column:1!important}.fd-form .fd-grid[data-columns-medium],.fd-form .fd-grid[data-columns-narrow]{grid-template-columns:repeat(var(--fd-columns-narrow, 1),minmax(0,1fr))}.fd-form .fd-grid[data-columns-medium]>.fd-field,.fd-form .fd-grid[data-columns-narrow]>.fd-field{grid-column:span min(var(--fd-span, 1),var(--fd-columns-narrow, 1))}}.fd-input{width:100%;min-width:0;font:inherit;color:inherit;background:var(--fd-surface);border:solid var(--fd-border);border-width:var(--fd-input-border);border-radius:var(--fd-control-radius);padding:var(--fd-pad-y) var(--fd-pad-x);min-height:30px;transition:border-color .15s ease,box-shadow .15s ease}.fd-input::placeholder{color:var(--fd-muted);opacity:.8}.fd-input:hover{border-color:var(--fd-border-strong)}.fd-input:focus{outline:none;border-color:var(--fd-focus);box-shadow:var(--fd-focus-ring)}.fd-form[data-fd-skin=underline] .fd-input{background:transparent}.fd-form[data-fd-skin=underline] .fd-input:focus{box-shadow:0 1px 0 0 var(--fd-focus)}.fd-form[data-fd-skin=underline] .fd-field.fd-required .fd-input{border-color:var(--fd-accent)}.fd-input[readonly]{background:transparent;border-color:transparent;padding-inline:0}.fd-form[data-fd-skin=outlined] .fd-input[readonly]{background:#0000000a;border-color:var(--fd-border);padding-inline:var(--fd-pad-x);color:var(--fd-muted)}.fd-form[data-readonly] .fd-input[readonly]{background:transparent;border-color:transparent;padding-inline:0;color:var(--fd-text)}.fd-form[data-readonly] .fd-input::placeholder{color:transparent}.fd-form[data-readonly] select.fd-input:disabled{appearance:none;background:transparent;border-color:transparent;padding-inline:0;color:var(--fd-text);opacity:1}.fd-input[aria-invalid=true]{border-color:var(--fd-error)}.fd-form[data-fd-skin=outlined] .fd-input[aria-invalid=true]:focus{box-shadow:0 0 0 2px #ff26050f}.fd-textarea{resize:vertical;min-height:64px}.fd-select{appearance:auto}.fd-number{display:flex;align-items:baseline;gap:6px}.fd-number-input{font-variant-numeric:tabular-nums}.fd-currency{color:var(--fd-muted);font-size:12.5px;font-weight:600}.fd-currency-after>.fd-number-input{text-align:end}.fd-currency-picked{align-items:center}.fd-currency-picked>:not(.fd-number-input){flex:0 0 104px;min-width:0}.fd-currency-picked>.fd-number-input{flex:1 1 auto;min-width:0}.fd-pending{color:var(--fd-muted);font-style:italic}.fd-pending:empty:before{content:\"\u2014\"}.fd-checkbox,.fd-choice input{width:16px;height:16px;accent-color:var(--fd-accent);margin:0}.fd-switch{appearance:none;width:34px;height:20px;margin:0;border-radius:999px;position:relative;background:var(--fd-border-strong);cursor:pointer;transition:background .2s ease}.fd-switch:after{content:\"\";position:absolute;inset-block-start:2px;inset-inline-start:2px;width:16px;height:16px;border-radius:50%;background:#fff;transition:transform .2s ease;box-shadow:0 1px 2px #00000040}.fd-switch:checked{background:var(--fd-accent)}.fd-switch:checked:after{transform:translate(14px)}[dir=rtl] .fd-switch:checked:after{transform:translate(-14px)}.fd-choices{display:flex;flex-wrap:wrap;gap:6px 18px}.fd-choice{display:inline-flex;align-items:center;gap:8px;cursor:pointer}.fd-points{display:flex;flex-wrap:wrap;gap:6px}.fd-points button{font:inherit;cursor:pointer;border:1px solid var(--fd-border);background:var(--fd-surface);color:var(--fd-text);border-radius:var(--fd-control-radius);min-width:34px;height:34px;padding:0 8px}.fd-points button.fd-on{background:var(--fd-accent);color:var(--fd-accent-text);border-color:var(--fd-accent)}.fd-rating button{border:none;background:none;font-size:24px;color:var(--fd-border-strong);padding:0 2px;min-width:0}.fd-rating button.fd-on{background:none;color:#f5a623}.fd-points button:disabled,.fd-choice input:disabled{cursor:default}.fd-form :focus-visible{outline:2px solid var(--fd-focus);outline-offset:2px}.fd-form .fd-input:focus-visible{outline:none}.fd-combo{position:relative;display:flex;align-items:center;min-width:0}.fd-combo-input{padding-inline-end:28px}.fd-combo-clear{position:absolute;inset-inline-end:4px;border:none;background:none;cursor:pointer;color:var(--fd-muted);font-size:16px;line-height:1;padding:2px 6px;border-radius:4px}.fd-combo-clear:hover{color:var(--fd-text);background:var(--fd-page)}.fd-combo:has(>.fd-combo-open:not([hidden])) .fd-combo-input{padding-inline-end:52px}.fd-combo-open{position:absolute;inset-inline-end:28px;border:none;background:none;cursor:pointer;color:var(--fd-accent);font-size:14px;line-height:1;padding:2px 6px;border-radius:4px}.fd-combo-open:hover{background:var(--fd-page)}.fd-listbox{position:absolute;inset-inline:0;inset-block-start:calc(100% + 2px);z-index:20;margin:0;padding:4px 0;list-style:none;background:var(--fd-surface);border:1px solid var(--fd-border);border-radius:max(var(--fd-control-radius),4px);box-shadow:0 8px 24px #0f14191f;max-height:240px;overflow-y:auto}.fd-option{padding:6px 12px;cursor:pointer}.fd-option:hover,.fd-option.fd-active{background:var(--fd-accent-soft)}.fd-option-create{color:var(--fd-accent);border-block-start:1px solid var(--fd-border)}.fd-empty{padding:6px 12px;color:var(--fd-muted);font-style:italic}.fd-tags{display:flex;flex-wrap:wrap;gap:6px;align-items:center;min-width:0}.fd-chips{display:contents;list-style:none;margin:0;padding:0}.fd-chip{display:inline-flex;align-items:center;gap:4px;padding:1px 4px 1px 10px;border-radius:999px;background:var(--fd-accent-soft);color:var(--fd-text);font-size:13px;line-height:22px}.fd-chip-remove{border:none;background:none;cursor:pointer;color:var(--fd-muted);font-size:15px;line-height:1;padding:0 4px;border-radius:999px}.fd-chip-remove:hover{color:var(--fd-error)}.fd-tags .fd-combo{flex:1 1 140px}.fd-reference{display:grid;grid-template-columns:minmax(7em,34%) minmax(0,1fr);gap:8px}.fd-lines{display:grid;grid-template-columns:minmax(0,1fr);gap:6px;min-width:0}.fd-lines-scroll{overflow-x:auto;min-width:0;position:relative}.fd-lines-table{width:100%;border-collapse:collapse;font-size:13.5px}.fd-lines-table th{text-align:start;font-weight:600;color:var(--fd-muted);font-size:12.5px;padding:6px 8px;border-block-end:1px solid var(--fd-border);white-space:nowrap}.fd-lines-table td{padding:4px 8px;border-block-end:1px solid var(--fd-border);vertical-align:top;min-width:7em}.fd-lines-table td.fd-lines-tools,.fd-lines-table th.fd-lines-tools{width:32px;min-width:32px;padding-inline:0;text-align:center}.fd-lines-table .fd-input{min-height:28px}.fd-lines-table td>.fd-checkbox,.fd-lines-table td>.fd-switch{margin-block-start:6px}.fd-line-delete{border:none;background:none;cursor:pointer;color:var(--fd-muted);font-size:16px;line-height:1;padding:4px 6px;border-radius:4px}.fd-line-delete:hover{color:var(--fd-error);background:var(--fd-error-soft)}.fd-lines-totals td{padding:8px;font-weight:600;border-block-start:1px solid var(--fd-border);font-variant-numeric:tabular-nums}.fd-lines-adds{display:flex;flex-wrap:wrap;gap:4px 16px;justify-self:start}.fd-line-section td{background:var(--fd-page)}.fd-line-section .fd-input{font-weight:600}.fd-line-note .fd-input{font-style:italic}.fd-cell-error{color:var(--fd-error);font-size:12px}.fd-sr-only{position:absolute;width:1px;height:1px;overflow:hidden;clip:rect(0 0 0 0);white-space:nowrap}.fd-file{display:grid;gap:8px;justify-items:start;padding:6px 0;border-radius:var(--fd-control-radius)}.fd-file.fd-dragging{outline:2px dashed var(--fd-accent);outline-offset:4px}.fd-file-pick{display:inline-flex;flex-wrap:wrap;gap:8px;align-items:center;cursor:pointer}.fd-file-chosen{display:inline-flex;flex-wrap:wrap;gap:4px 10px;align-items:center}.fd-file-name{font-variant-numeric:tabular-nums}.fd-image-pick{width:120px;height:120px;border:1px dashed var(--fd-border-strong);border-radius:var(--fd-control-radius);display:grid;place-content:center;justify-items:center;text-align:center;padding:8px;background:var(--fd-page)}.fd-avatar .fd-image-pick{width:88px;height:88px}.fd-image-preview{max-width:160px;max-height:160px;border-radius:var(--fd-control-radius);border:1px solid var(--fd-border);object-fit:cover;background:var(--fd-page)}.fd-richtext{min-height:96px;line-height:1.5;overflow-wrap:anywhere}.fd-richtext-box{display:grid;gap:0;min-width:0}.fd-richtext-box>.fd-richtext{border-start-start-radius:0;border-start-end-radius:0}.fd-richtext-bar{display:flex;flex-wrap:wrap;align-items:center;gap:2px;padding:4px;min-width:0;border:1px solid var(--fd-border);border-block-end:none;border-start-start-radius:var(--fd-control-radius);border-start-end-radius:var(--fd-control-radius);background:var(--fd-page)}.fd-richtext-style{font:inherit;font-size:12.5px;padding:3px 6px;margin-inline-end:4px;border:1px solid var(--fd-border);border-radius:4px;background:var(--fd-surface);color:var(--fd-text)}.fd-richtext-tool{display:grid;place-items:center;width:28px;height:28px;padding:0;border:none;border-radius:4px;background:none;cursor:pointer;color:var(--fd-text);font:inherit;font-size:14px}.fd-richtext-tool:hover{background:var(--fd-surface)}.fd-richtext-tool[aria-pressed=true]{background:var(--fd-accent-soft);color:var(--fd-accent)}.fd-richtext-tool svg{width:16px;height:16px;fill:none;stroke:currentColor;stroke-width:1.3;stroke-linecap:round}.fd-richtext-tool svg circle{fill:currentColor;stroke:none}.fd-link-row{display:flex;flex-wrap:wrap;gap:6px;align-items:center;padding:6px;border:1px solid var(--fd-border);border-block-end:none;background:var(--fd-surface)}.fd-link-row>.fd-input{flex:1 1 200px;min-width:0}.fd-richtext[contenteditable=false]{background:transparent;border-color:transparent;padding-inline:0;min-height:0}.fd-richtext p{margin:0 0 6px}.fd-code{font-family:ui-monospace,SF Mono,Menlo,Consolas,monospace;font-size:12.5px;min-height:96px}.fd-sections{display:grid;gap:24px}.fd-section{border:0;margin:0;padding:0;min-width:0;display:grid;gap:14px}.fd-section-title{font-size:15px;font-weight:650;padding:0;margin:0;float:inline-start;width:100%}.fd-section-title+*{clear:both}.fd-form[data-fd-skin=underline] .fd-section-title{text-transform:uppercase;letter-spacing:.05em;font-size:12.5px;color:var(--fd-muted);border-block-end:1px solid var(--fd-border);padding-block-end:6px;width:100%}.fd-section-description{color:var(--fd-muted);margin:0}.fd-section-toggle{font:inherit;color:inherit;background:none;border:0;padding:0;margin:0;cursor:pointer;display:inline-flex;align-items:center;gap:8px;text-align:start}.fd-section-toggle:focus-visible{outline:2px solid var(--fd-focus);outline-offset:2px;border-radius:2px}.fd-section-chevron{width:.5em;height:.5em;border:solid currentColor;border-width:0 2px 2px 0;transform:rotate(45deg);margin-block-start:-.2em;transition:transform .15s ease;flex:none}.fd-section-folded .fd-section-chevron{transform:rotate(-45deg);margin-block-start:0}[dir=rtl] .fd-section-folded .fd-section-chevron{transform:rotate(135deg)}.fd-form[data-fd-skin=outlined] .fd-sections>.fd-section{background:var(--fd-surface);border:1px solid var(--fd-border);border-radius:var(--fd-radius);padding:20px 24px}.fd-tablist{display:flex;gap:2px;border-block-end:1px solid var(--fd-border);overflow-x:auto}.fd-tab{font:inherit;background:none;border:none;cursor:pointer;padding:8px 14px;color:var(--fd-muted);border-block-end:2px solid transparent;margin-block-end:-1px;white-space:nowrap}.fd-tab[aria-selected=true]{color:var(--fd-accent);border-block-end-color:var(--fd-accent);font-weight:600}.fd-tabpanel{padding-block:16px;display:grid;gap:16px}.fd-button{font:inherit;cursor:pointer;display:inline-flex;align-items:center;gap:6px;justify-content:center;min-height:32px;padding:4px 14px;border-radius:var(--fd-control-radius);border:1px solid var(--fd-border);background:var(--fd-surface);color:var(--fd-text)}.fd-button:hover{border-color:var(--fd-accent);color:var(--fd-accent)}.fd-button-primary{background:var(--fd-accent);border-color:var(--fd-accent);color:var(--fd-accent-text)}.fd-button-primary:hover{color:var(--fd-accent-text);filter:brightness(1.12)}.fd-button-danger{color:var(--fd-error);border-color:var(--fd-error)}.fd-button-danger:hover{background:var(--fd-error);color:#fff}.fd-button-link{border-color:transparent;background:none;color:var(--fd-accent);padding-inline:4px}.fd-form[data-fd-skin=underline] .fd-button{border-radius:3px}.fd-actions{display:flex;flex-wrap:wrap;gap:8px;align-items:center}.fd-actions-end{justify-content:flex-end;margin-block-start:24px}.fd-sheet-page{background:var(--fd-page);padding:0 0 32px;min-width:0}.fd-header{display:flex;flex-wrap:wrap;gap:10px 16px;align-items:center;justify-content:space-between;background:var(--fd-surface);border-block-end:1px solid var(--fd-border);padding:8px 16px}.fd-statusbar{display:flex;list-style:none;margin:0;padding:0;overflow-x:auto}.fd-statusbar li{display:flex}.fd-statusbar li>*{font:inherit;font-size:13px;border:none;background:var(--fd-page);color:var(--fd-muted);padding:5px 18px 5px 22px;margin-inline-start:-6px;white-space:nowrap;clip-path:polygon(0 0,calc(100% - 10px) 0,100% 50%,calc(100% - 10px) 100%,0 100%,10px 50%)}.fd-statusbar li:first-child>*{margin-inline-start:0;padding-inline-start:14px;clip-path:polygon(0 0,calc(100% - 10px) 0,100% 50%,calc(100% - 10px) 100%,0 100%)}.fd-statusbar li>button{cursor:pointer}.fd-statusbar li>[aria-current=step]{background:var(--fd-accent);color:var(--fd-accent-text);font-weight:600}[dir=rtl] .fd-statusbar li>*{transform:scaleX(-1)}[dir=rtl] .fd-statusbar li>*>*{display:inline-block;transform:scaleX(-1)}.fd-sheet-layout{display:grid;grid-template-columns:minmax(0,1fr);gap:16px;max-width:var(--fd-page-max, 1180px);margin:16px auto 0;padding-inline:16px}.fd-sheet-layout{align-items:start}.fd-sheet-foot{margin:4px -28px -28px;padding:12px 28px;border-block-start:1px solid var(--fd-border);border-end-start-radius:inherit;border-end-end-radius:inherit}.fd-sheet-layout.fd-has-side{grid-template-columns:minmax(0,1fr) minmax(260px,360px)}@container (max-width: 1000px){.fd-sheet-layout.fd-has-side{grid-template-columns:minmax(0,1fr)}}.fd-card{position:relative;background:var(--fd-surface);border:1px solid var(--fd-border);border-radius:var(--fd-radius);padding:24px 28px 28px;display:grid;gap:18px;min-width:0;container-type:inline-size}.fd-ribbon-frame{position:absolute;inset:0;overflow:hidden;border-radius:inherit;pointer-events:none}.fd-ribbon{position:absolute;inset-block-start:18px;inset-inline-end:-42px;transform:rotate(45deg);width:160px;text-align:center;font-size:12px;font-weight:700;padding:4px 0;color:#fff;background:var(--fd-muted);text-transform:uppercase;letter-spacing:.06em;pointer-events:none}[dir=rtl] .fd-ribbon{transform:rotate(-45deg)}.fd-ribbon.fd-tone-danger{background:var(--fd-error)}.fd-ribbon.fd-tone-success{background:var(--fd-success)}.fd-ribbon.fd-tone-warning{background:#d97706}.fd-ribbon.fd-tone-info{background:var(--fd-info)}.fd-alert{padding:10px 14px;border-radius:var(--fd-control-radius);border:1px solid;font-size:13.5px;display:flex;align-items:flex-start;gap:10px}.fd-alert-message{flex:1 1 auto;min-width:0}.fd-alert-close{border:none;background:none;color:inherit;cursor:pointer;font:inherit;font-size:18px;line-height:1;padding:0 4px;border-radius:4px;opacity:.75}.fd-alert-close:hover{opacity:1}.fd-alert-close:focus-visible{outline:2px solid var(--fd-focus);opacity:1}.fd-alert.fd-tone-warning{background:var(--fd-warning-soft);border-color:#f0c47a;color:var(--fd-warning)}.fd-alert.fd-tone-danger{background:var(--fd-error-soft);border-color:#f1a7a7;color:var(--fd-error)}.fd-alert.fd-tone-success{background:var(--fd-success-soft);border-color:#a7d7ab;color:var(--fd-success)}.fd-alert.fd-tone-info,.fd-alert:not([class*=fd-tone-]){background:var(--fd-info-soft);border-color:#a9c8ef;color:var(--fd-info)}.fd-stats{display:flex;flex-wrap:wrap;justify-content:flex-end;gap:0;margin:-24px -28px 0;border-block-end:1px solid var(--fd-border)}.fd-stats:empty{display:none}.fd-card:has(>.fd-ribbon-frame>.fd-ribbon:not([hidden])) .fd-stats{padding-inline-end:104px}.fd-stat{font:inherit;background:none;border:none;border-inline-start:1px solid var(--fd-border);cursor:pointer;padding:8px 18px;display:grid;justify-items:start;line-height:1.2;color:var(--fd-text);min-width:120px}.fd-stat:hover{background:var(--fd-page)}.fd-stat:has(>.fd-icon){grid-template-columns:auto minmax(0,1fr);align-items:center;column-gap:10px}.fd-stat>.fd-icon{width:22px;height:22px;color:var(--fd-muted)}.fd-stat-words{display:grid;justify-items:start}.fd-stat-value{font-weight:700;font-size:15px;color:var(--fd-accent);font-variant-numeric:tabular-nums}.fd-stat-label{font-size:12.5px;color:var(--fd-muted)}.fd-title-row{display:flex;gap:16px;align-items:flex-start;justify-content:space-between}.fd-title{display:grid;gap:4px;flex:1 1 auto;min-width:0}.fd-avatar{flex:none}.fd-avatar>.fd-label{position:absolute;width:1px;height:1px;overflow:hidden;clip:rect(0 0 0 0);white-space:nowrap}.fd-form[data-fd-skin=underline] .fd-avatar{grid-template-columns:minmax(0,1fr)}.fd-form[data-fd-skin=underline] .fd-avatar>*{grid-column:1!important}.fd-avatar .fd-image-pick{width:120px;height:120px;border:1px dashed var(--fd-border-strong);border-radius:var(--fd-control-radius);display:grid;place-content:center;justify-items:center;text-align:center;padding:8px;background:var(--fd-page)}.fd-image-pick .fd-button{border:none;background:none;color:var(--fd-accent);padding:0;min-height:0}.fd-image-pick:hover{border-color:var(--fd-accent)}.fd-avatar .fd-image-pick,.fd-image-preview{width:88px;height:88px}.fd-avatar .fd-file-pick .fd-help,.fd-avatar .fd-file-name{display:none}.fd-avatar .fd-file{justify-items:center;gap:2px;padding:0}.fd-avatar .fd-file-chosen{gap:2px 8px;justify-content:center;font-size:12.5px}.fd-title>.fd-field .fd-input{font-size:24px;font-weight:600;min-height:40px}.fd-form[data-fd-skin=underline] .fd-title>.fd-field{grid-template-columns:minmax(0,1fr)}.fd-form[data-fd-skin=underline] .fd-title>.fd-field>*{grid-column:1}.fd-title>.fd-field>.fd-label{position:absolute;width:1px;height:1px;overflow:hidden;clip:rect(0 0 0 0);white-space:nowrap}.fd-title-above,.fd-title-below{display:flex;flex-wrap:wrap;align-items:center;gap:6px 24px}.fd-title-above{margin-block-end:4px}.fd-title-below{margin-block-start:6px}.fd-form .fd-title-above>.fd-field,.fd-form .fd-title-below>.fd-field{display:flex;align-items:center;gap:8px;grid-template-columns:none}.fd-form .fd-title-above>.fd-field>*,.fd-form .fd-title-below>.fd-field>*{grid-column:auto!important}.fd-title-above .fd-label:empty,.fd-title-below .fd-label:empty{display:none}.fd-title-above>.fd-field>.fd-label{position:absolute;width:1px;height:1px;overflow:hidden;clip:rect(0 0 0 0);white-space:nowrap}.fd-title-statusbar{display:flex}.fd-badges{display:flex;flex-wrap:wrap;gap:6px}.fd-badge{display:inline-flex;align-items:center;gap:5px;font-size:12px;font-weight:600;line-height:1;padding:5px 10px;border-radius:999px;border:1px solid var(--fd-border);background:var(--fd-page);color:var(--fd-muted)}.fd-badge .fd-icon{width:13px;height:13px}.fd-badge.fd-tone-info{background:var(--fd-info-soft);border-color:#a9c8ef;color:var(--fd-info)}.fd-badge.fd-tone-success{background:var(--fd-success-soft);border-color:#a7d7ab;color:var(--fd-success)}.fd-badge.fd-tone-warning{background:var(--fd-warning-soft);border-color:#f0c47a;color:var(--fd-warning)}.fd-badge.fd-tone-danger{background:var(--fd-error-soft);border-color:#f1a7a7;color:var(--fd-error)}.fd-side{display:grid;gap:12px;align-content:start;min-width:0}.fd-wizard{display:grid;gap:20px}.fd-progress{display:grid;gap:8px}.fd-progress-text{color:var(--fd-muted);font-size:13px}.fd-value-text{display:block;padding-block:6px;font-variant-numeric:tabular-nums}.fd-date-pick{position:relative;display:flex;align-items:center;gap:6px;min-width:0}.fd-date-pick>.fd-input{flex:1 1 auto;min-width:0}.fd-calendar-button{flex:0 0 auto;display:grid;place-items:center;width:32px;height:32px;padding:0;cursor:pointer;border:1px solid var(--fd-border);border-radius:var(--fd-control-radius);background:var(--fd-surface);color:var(--fd-muted)}.fd-calendar-button:hover,.fd-calendar-button[aria-expanded=true]{color:var(--fd-text);background:var(--fd-page)}.fd-calendar-button svg{width:16px;height:16px;fill:none;stroke:currentColor;stroke-width:1.4;stroke-linecap:round}.fd-calendar{position:absolute;inset-block-start:calc(100% + 4px);inset-inline-end:0;z-index:30;padding:8px;background:var(--fd-surface);border:1px solid var(--fd-border);border-radius:max(var(--fd-control-radius),6px);box-shadow:0 8px 24px #0f141924}.fd-calendar-head{display:flex;align-items:center;justify-content:space-between;gap:8px;padding:2px 4px 6px}.fd-calendar-head button{border:none;background:none;cursor:pointer;font-size:18px;line-height:1;padding:4px 8px;border-radius:4px;color:var(--fd-text)}.fd-calendar-head button:hover{background:var(--fd-page)}.fd-calendar-title{font-weight:600}.fd-calendar-grid{border-collapse:collapse;font-variant-numeric:tabular-nums}.fd-calendar-grid th{font-size:11.5px;font-weight:600;color:var(--fd-muted);padding:4px 0;width:34px;text-align:center}.fd-calendar-grid .fd-week{color:var(--fd-accent);font-weight:600;border-inline-end:1px solid var(--fd-border)}.fd-calendar-grid td{padding:1px}.fd-calendar-grid td button{width:32px;height:30px;border:none;border-radius:4px;background:none;cursor:pointer;color:var(--fd-text);font:inherit;font-size:13px}.fd-calendar-grid td button:hover{background:var(--fd-accent-soft)}.fd-calendar-grid td button.fd-outside{color:var(--fd-muted);opacity:.6}.fd-calendar-grid td button[aria-current=date]{box-shadow:inset 0 0 0 1px var(--fd-accent)}.fd-calendar-grid td button[aria-selected=true]{background:var(--fd-accent);color:var(--fd-accent-text);font-weight:600}.fd-calendar-grid td button:focus-visible{outline:2px solid var(--fd-focus);outline-offset:1px}.fd-properties{display:grid;gap:8px;min-width:0}.fd-property{display:grid;grid-template-columns:minmax(120px,30%) minmax(0,1fr);align-items:center;gap:12px;min-width:0}.fd-property>label{color:var(--fd-muted);font-size:13px}.fd-property[data-type=boolean]>:last-child{justify-self:start}@container (max-width: 520px){.fd-property{grid-template-columns:minmax(0,1fr);gap:4px}}.fd-progressbar{position:relative;height:22px;min-width:120px;border-radius:999px;overflow:hidden;background:var(--fd-page);border:1px solid var(--fd-border);font-variant-numeric:tabular-nums}.fd-progressbar-fill{height:100%;background:var(--fd-success);transition:width .2s ease}.fd-progressbar[data-tone=warning] .fd-progressbar-fill{background:#d97706}.fd-progressbar[data-tone=danger] .fd-progressbar-fill{background:var(--fd-error)}.fd-progressbar[data-tone=info] .fd-progressbar-fill{background:var(--fd-info)}.fd-progressbar-text{position:absolute;inset:0;display:grid;place-items:center;font-size:12px;font-weight:600;color:var(--fd-text)}.fd-progressbar-edit{display:flex;align-items:center;gap:12px;min-width:0}.fd-progressbar-edit>.fd-progressbar{flex:1 1 auto}.fd-progressbar-edit>.fd-input{flex:0 0 96px}.fd-progress-bar{height:4px;background:var(--fd-border);border-radius:999px;overflow:hidden}.fd-progress-bar>span{display:block;height:100%;background:var(--fd-accent);transition:width .25s ease}.fd-step{display:grid;gap:18px}.fd-step-title{font-size:18px;font-weight:650;margin:0}.fd-wizard-nav{display:flex;gap:8px;justify-content:space-between}.fd-steps-list{display:flex;flex-wrap:wrap;gap:8px;list-style:none;margin:0;padding:0;counter-reset:fd-step}.fd-steps-list>li{counter-increment:fd-step}.fd-step-link{font:inherit;font-size:13.5px;display:inline-flex;align-items:center;gap:6px;cursor:pointer;border:1px solid var(--fd-border);background:var(--fd-surface);color:var(--fd-muted);border-radius:999px;padding:4px 12px 4px 6px}.fd-step-link:before{content:counter(fd-step);display:inline-grid;place-items:center;width:20px;height:20px;border-radius:50%;background:var(--fd-page);color:var(--fd-muted);font-size:12px;font-weight:600;font-variant-numeric:tabular-nums}.fd-step-link:hover{border-color:var(--fd-accent);color:var(--fd-text)}.fd-step-link:focus-visible{outline:2px solid var(--fd-focus);outline-offset:2px}.fd-step-link.fd-step-done{color:var(--fd-text)}.fd-step-link.fd-step-done:before{content:\"\u2713\";background:var(--fd-accent-soft);color:var(--fd-accent)}.fd-step-link.fd-step-skipped{border-style:dashed;color:var(--fd-muted)}.fd-step-link.fd-step-skipped:before{content:\"\u2013\";background:var(--fd-page);color:var(--fd-muted)}.fd-step-link[aria-current=step]{border-color:var(--fd-accent);color:var(--fd-accent);font-weight:600}.fd-step-link[aria-current=step]:before{content:counter(fd-step);background:var(--fd-accent);color:var(--fd-accent-text)}.fd-wizard-nav .fd-spacer{flex:1}.fd-text-heading{font-size:16px;font-weight:650;margin:0}.fd-text-paragraph{margin:0}.fd-text-note{margin:0;color:var(--fd-muted);font-size:13px}.fd-status{min-height:1.4em;color:var(--fd-muted);font-size:13px}.fd-status-box{display:inline-flex;align-items:center;gap:6px;min-width:0}.fd-status-box .fd-retry{font-size:13px}.fd-announce{position:absolute;width:1px;height:1px;overflow:hidden;clip:rect(0 0 0 0);white-space:nowrap}.fd-banner{display:flex;flex-wrap:wrap;align-items:center;gap:8px 14px;padding:10px 14px;margin-block-end:16px;border:1px solid #f0c47a;border-radius:var(--fd-control-radius);background:var(--fd-warning-soft);color:var(--fd-warning);font-size:13.5px}.fd-banner-text{flex:1 1 16em;min-width:0}.fd-content>.fd-banner:has(+.fd-draft+.fd-sheet-page),.fd-content>.fd-banner:has(+.fd-sheet-page){margin:12px 16px 0}.fd-status-box.fd-toast{position:fixed;inset-block-end:max(20px,env(safe-area-inset-bottom,0px));inset-inline-end:20px;z-index:900;padding:10px 16px;border-radius:8px;background:var(--fd-text);box-shadow:0 8px 24px #0f141940}.fd-toast .fd-status,.fd-toast .fd-status.fd-status-saved,.fd-toast .fd-status.fd-status-error{color:var(--fd-surface);font-size:13.5px;min-height:0}.fd-toast .fd-retry{color:var(--fd-surface);text-decoration:underline}.fd-toast:has(.fd-status-error){background:var(--fd-error)}.fd-status-box.fd-status-bar{display:flex;justify-content:center;min-height:32px;padding:6px 16px;background:var(--fd-surface);border-block-end:1px solid var(--fd-border)}.fd-status-bar .fd-status-error,.fd-status.fd-status-error{color:var(--fd-error)}.fd-status.fd-status-saved{color:var(--fd-success)}.fd-draft{display:flex;flex-wrap:wrap;gap:8px 12px;align-items:center;padding:10px 14px;margin-block-end:16px;background:var(--fd-info-soft);border:1px solid #a9c8ef;border-radius:var(--fd-control-radius)}.fd-done{padding:40px 0;text-align:center;display:grid;gap:12px;justify-items:center}.fd-done-title{font-size:20px;font-weight:650;margin:0}.fd-dialog-backdrop{position:fixed;inset:0;background:#0f141973;display:grid;place-items:center;z-index:1000;padding:16px}.fd-dialog{background:var(--fd-surface);color:var(--fd-text);border-radius:max(var(--fd-radius),6px);max-width:420px;width:100%;padding:20px 22px;display:grid;gap:16px;box-shadow:0 10px 30px #0003;font-family:var(--fd-font)}.fd-dialog p{margin:0}.fd-form-dialog{display:flex;flex-direction:column;width:100%;max-height:min(90vh,100%);min-height:0;background:var(--fd-page);color:var(--fd-text);border-radius:max(var(--fd-radius),8px);box-shadow:0 24px 64px #0f14194d;overflow:hidden}.fd-form-dialog:focus{outline:none}.fd-form-dialog.fd-size-small{max-width:440px}.fd-form-dialog.fd-size-medium{max-width:760px}.fd-form-dialog.fd-size-large{max-width:1080px}.fd-form-dialog-backdrop:has(>.fd-size-full){padding:0}.fd-form-dialog.fd-size-full{max-width:none;max-height:none;height:100%;border-radius:0}.fd-form-dialog-head{display:flex;align-items:center;justify-content:space-between;gap:12px;padding:12px 16px;border-block-end:1px solid var(--fd-border);background:var(--fd-surface)}.fd-form-dialog-title{margin:0;font-size:16px;font-weight:600}.fd-dialog-close{border:none;background:none;cursor:pointer;font-size:22px;line-height:1;padding:2px 8px;border-radius:4px;color:var(--fd-muted)}.fd-dialog-close:hover{background:var(--fd-page);color:var(--fd-text)}.fd-form-dialog-body{flex:1 1 auto;min-height:0;overflow:auto;container-type:inline-size}.fd-form-dialog-body .fd-sheet-layout{margin-block-start:12px}.fd-form-dialog-body .fd-page-title{display:none}.fd-form-dialog-body .fd-page-head:not(:has(.fd-page-description)){display:none}.fd-form-dialog-body .fd-sheet-layout.fd-has-side{grid-template-columns:minmax(0,1fr)}.fd-form-dialog-body .fd-side{display:none}.fd-search-body{display:grid;gap:12px;align-content:start}.fd-search-list{list-style:none;margin:0;padding:0;border:1px solid var(--fd-border);border-radius:var(--fd-control-radius);overflow:auto;max-height:min(60vh,520px)}.fd-search-list .fd-option{padding:8px 12px}.fd-search-list .fd-option+.fd-option{border-block-start:1px solid var(--fd-border)}.fd-search-list .fd-empty{padding:10px 12px;color:var(--fd-muted)}.fd-form-dialog-body:not(:has(.fd-sheet-layout)){background:var(--fd-surface);padding:16px 20px 20px}.fd-form-dialog-foot{padding:12px 16px;border-block-start:1px solid var(--fd-border);background:var(--fd-surface);margin:0}@media(prefers-reduced-motion:reduce){.fd-form *,.fd-form *:before,.fd-form *:after{transition:none!important}}`;\n\nconst STYLE_ID = 'fieldia-styles';\n\n/** Add Fieldia's stylesheet to a document, once. */\nexport function installStyles(document: Document): void {\n if (document.getElementById(STYLE_ID)) return;\n const style = document.createElement('style');\n style.id = STYLE_ID;\n style.textContent = FIELDIA_CSS;\n (document.head ?? document.documentElement).append(style);\n}\n", "import type { JsonValue } from '@fieldia/core';\n\n/**\n * Where a person's choices about how a page looks are kept between visits:\n * a table's column widths, their order, which columns show. Never data, and\n * never anything a page needs to work: a store that forgets is fine.\n */\nexport interface PreferenceStore {\n get(key: string): JsonValue | null;\n set(key: string, value: JsonValue): void;\n}\n\n/** Preferences in the browser's local storage, under `fieldia:`. A browser that refuses storage just forgets. */\nexport function browserPreferences(storage?: Storage): PreferenceStore {\n const area = () => {\n try {\n return storage ?? globalThis.localStorage ?? null;\n } catch {\n return null; // reading localStorage itself throws where site data is blocked\n }\n };\n return {\n get(key) {\n try {\n const text = area()?.getItem(`fieldia:${key}`);\n return text == null ? null : (JSON.parse(text) as JsonValue);\n } catch {\n return null;\n }\n },\n set(key, value) {\n try {\n area()?.setItem(`fieldia:${key}`, JSON.stringify(value));\n } catch {\n // Full, private or blocked: the choice lasts until the page closes.\n }\n },\n };\n}\n\n/** Preferences that last as long as the page: for tests, and apps that keep nothing. */\nexport function memoryPreferences(): PreferenceStore {\n const values = new Map<string, JsonValue>();\n return {\n get: (key) => (values.has(key) ? structuredCloneSafe(values.get(key) as JsonValue) : null),\n set: (key, value) => void values.set(key, structuredCloneSafe(value)),\n };\n}\n\nconst structuredCloneSafe = (value: JsonValue): JsonValue => JSON.parse(JSON.stringify(value)) as JsonValue;\n", "/**\n * Icons by name, for sections, tabs, buttons, stat buttons, badges and steps.\n * Each is the inside of a 24\u00D724 SVG drawn with lines in the text colour, so it\n * takes the colour and size of the words beside it. An app adds its own, or\n * replaces one of these, with the viewer's `icons` option, in the same form.\n */\nexport type IconSet = Readonly<Record<string, string>>;\n\nconst SVG = 'http://www.w3.org/2000/svg';\n\nexport const ICONS: IconSet = {\n user: '<circle cx=\"12\" cy=\"8\" r=\"4\"/><path d=\"M4 21c0-4 3.6-6 8-6s8 2 8 6\"/>',\n users: '<circle cx=\"9\" cy=\"8\" r=\"3.5\"/><path d=\"M2 20c0-3.5 3-5.5 7-5.5s7 2 7 5.5\"/><circle cx=\"17\" cy=\"9\" r=\"2.5\"/><path d=\"M16.5 14.5c3 0 5.5 1.6 5.5 4.5\"/>',\n building: '<rect x=\"4\" y=\"3\" width=\"16\" height=\"18\" rx=\"1\"/><path d=\"M9 21v-4h6v4M8 7h2M14 7h2M8 11h2M14 11h2\"/>',\n home: '<path d=\"M3 11l9-7 9 7\"/><path d=\"M5 10v10h14V10\"/><path d=\"M10 20v-6h4v6\"/>',\n phone: '<rect x=\"7\" y=\"2\" width=\"10\" height=\"20\" rx=\"2\"/><path d=\"M11 18h2\"/>',\n mail: '<rect x=\"3\" y=\"5\" width=\"18\" height=\"14\" rx=\"2\"/><path d=\"M3 7l9 6 9-6\"/>',\n pin: '<path d=\"M12 21s-7-6.5-7-12a7 7 0 0 1 14 0c0 5.5-7 12-7 12z\"/><circle cx=\"12\" cy=\"9\" r=\"2.5\"/>',\n globe: '<circle cx=\"12\" cy=\"12\" r=\"9\"/><path d=\"M3 12h18M12 3c3 3.2 3 14.8 0 18M12 3c-3 3.2-3 14.8 0 18\"/>',\n calendar: '<rect x=\"3\" y=\"5\" width=\"18\" height=\"16\" rx=\"2\"/><path d=\"M3 10h18M8 3v4M16 3v4\"/>',\n clock: '<circle cx=\"12\" cy=\"12\" r=\"9\"/><path d=\"M12 7v5l3 3\"/>',\n money: '<rect x=\"2\" y=\"6\" width=\"20\" height=\"12\" rx=\"2\"/><circle cx=\"12\" cy=\"12\" r=\"3\"/><path d=\"M6 9.5v0M18 14.5v0\"/>',\n cart: '<path d=\"M3 4h2l2.5 11h11L21 7H6.4\"/><circle cx=\"9\" cy=\"19.5\" r=\"1.5\"/><circle cx=\"17\" cy=\"19.5\" r=\"1.5\"/>',\n box: '<path d=\"M12 3l8 4.5v9L12 21l-8-4.5v-9z\"/><path d=\"M4 7.5l8 4.5 8-4.5M12 12v9\"/>',\n truck: '<path d=\"M2 6h12v10H2zM14 9h4l3 3.5V16h-7\"/><circle cx=\"6.5\" cy=\"17.5\" r=\"1.8\"/><circle cx=\"17\" cy=\"17.5\" r=\"1.8\"/>',\n receipt: '<path d=\"M6 3h12v18l-3-2-3 2-3-2-3 2z\"/><path d=\"M9 8h6M9 12h6\"/>',\n file: '<path d=\"M6 3h8l4 4v14H6z\"/><path d=\"M14 3v4h4M9 12h6M9 16h6\"/>',\n edit: '<path d=\"M4 20h4L19 9l-4-4L4 16z\"/><path d=\"M13.5 6.5l4 4\"/>',\n tag: '<path d=\"M3 12V4h8l10 10-8 8z\"/><circle cx=\"7.5\" cy=\"8\" r=\"1.5\"/>',\n star: '<path d=\"M12 3l2.8 6 6.2.6-4.7 4.2 1.4 6.2L12 16.8 6.3 20l1.4-6.2L3 9.6 9.2 9z\"/>',\n lock: '<rect x=\"5\" y=\"11\" width=\"14\" height=\"10\" rx=\"2\"/><path d=\"M8 11V7a4 4 0 0 1 8 0v4\"/>',\n check: '<path d=\"M5 12.5l4.5 4.5L19 7.5\"/>',\n info: '<circle cx=\"12\" cy=\"12\" r=\"9\"/><path d=\"M12 11v6M12 7.5v0\"/>',\n warning: '<path d=\"M12 3l10 18H2z\"/><path d=\"M12 10v5M12 18v0\"/>',\n settings: '<path d=\"M4 6h9M17 6h3M4 12h3M11 12h9M4 18h11M19 18h1\"/><circle cx=\"15\" cy=\"6\" r=\"2\"/><circle cx=\"9\" cy=\"12\" r=\"2\"/><circle cx=\"17\" cy=\"18\" r=\"2\"/>',\n chart: '<path d=\"M3 20h18M6 20v-8M11 20V5M16 20v-6\"/>',\n link: '<path d=\"M10 14a4 4 0 0 0 5.6 0l3-3a4 4 0 0 0-5.6-5.6l-1 1\"/><path d=\"M14 10a4 4 0 0 0-5.6 0l-3 3a4 4 0 0 0 5.6 5.6l1-1\"/>',\n list: '<path d=\"M8 6h12M8 12h12M8 18h12M4 6v0M4 12v0M4 18v0\"/>',\n chat: '<path d=\"M4 5h16v11H9l-5 4z\"/>',\n search: '<circle cx=\"11\" cy=\"11\" r=\"6.5\"/><path d=\"M16 16l5 5\"/>',\n filter: '<path d=\"M3 5h18l-7 8.5V20l-4-2v-4.5z\"/>',\n layers: '<path d=\"M12 3l9 5-9 5-9-5z\"/><path d=\"M3 13l9 5 9-5\"/>',\n};\n\n/** An icon by name, the app's own first and then Fieldia's; null for a name neither has. */\nexport function drawIcon(doc: Document, name: string | undefined, own?: IconSet): SVGSVGElement | null {\n const inside = name ? own?.[name] ?? ICONS[name] : undefined;\n if (inside === undefined) return null;\n const svg = doc.createElementNS(SVG, 'svg');\n for (const [key, value] of Object.entries({\n viewBox: '0 0 24 24',\n fill: 'none',\n stroke: 'currentColor',\n 'stroke-width': '1.8',\n 'stroke-linecap': 'round',\n 'stroke-linejoin': 'round',\n 'aria-hidden': 'true',\n focusable: 'false',\n class: 'fd-icon',\n 'data-icon': name as string,\n })) {\n svg.setAttribute(key, value);\n }\n svg.innerHTML = inside;\n return svg;\n}\n", "import type { Locale, RecordId, RelatedRecord, Values } from '@fieldia/core';\nimport { WIDGET_LABELS } from '@fieldia/widgets';\nimport { mountViewer, VIEWER_LABELS, type Skin, type ViewerHandle, type ViewerOptions } from './viewer';\n\n/**\n * A page in a dialog: a new related record, a line to edit, a quick task. The\n * dialog saves (Save & Close) or closes without saving (Discard, \u00D7, Escape);\n * the page's own Save and Discard stay hidden. The focus moves into the dialog,\n * Tab stays inside it, and the focus goes back where it was when it closes.\n */\n\nexport interface FormDialogOptions extends ViewerOptions {\n title: string;\n size?: 'small' | 'medium' | 'large' | 'full';\n /**\n * \"save\" (the default) saves the record through the data source. \"values\"\n * only checks the form and hands its values back, for something saved with\n * a bigger record, such as a line.\n */\n mode?: 'save' | 'values';\n /**\n * Recalculates the values as they change, for a dialog with no data source of\n * its own: a line's subtotal following its quantity. What comes back is shown.\n */\n recompute?: (values: Values) => Promise<Values>;\n /** Where the dialog goes: the document's body by default. */\n container?: HTMLElement;\n}\n\nexport interface FormDialogResult {\n /** True when Save & Close was pressed and the form accepted. */\n saved: boolean;\n recordId: RecordId | null;\n values: Values;\n}\n\nlet dialogs = 0;\n\nconst FOCUSABLE = 'button, [href], input, select, textarea, [contenteditable=\"true\"], [tabindex]:not([tabindex=\"-1\"])';\n\nexport function openFormDialog(options: FormDialogOptions): Promise<FormDialogResult> {\n const doc = options.container?.ownerDocument ?? document;\n const container = options.container ?? doc.body;\n const opener = doc.activeElement instanceof doc.defaultView!.HTMLElement ? (doc.activeElement as HTMLElement) : null;\n const labels = { ...VIEWER_LABELS[options.locale ?? 'en'], ...options.labels };\n const id = `fd-dialog-${++dialogs}`;\n const make = <K extends keyof HTMLElementTagNameMap>(tag: K, attrs: Record<string, string> = {}, text?: string) => {\n const element = doc.createElement(tag);\n for (const [name, value] of Object.entries(attrs)) element.setAttribute(name, value);\n if (text !== undefined) element.textContent = text;\n return element;\n };\n\n const title = make('h2', { id: `${id}-title`, class: 'fd-form-dialog-title' }, options.title);\n const closeButton = make('button', { type: 'button', class: 'fd-dialog-close', 'aria-label': labels.close }, '\u00D7');\n const body = make('div', { class: 'fd-form-dialog-body' });\n const discard = make('button', { type: 'button', class: 'fd-button' }, labels.discard);\n const saveClose = make('button', { type: 'button', class: 'fd-button fd-button-primary' }, labels.saveClose);\n const box = make('div', {\n // Its own tokens and skin: the dialog sits outside the page that opened it.\n class: `fd-theme fd-form-dialog fd-size-${options.size ?? 'medium'}`,\n 'data-fd-skin': options.skin ?? 'underline',\n role: 'dialog',\n 'aria-modal': 'true',\n 'aria-labelledby': title.id,\n tabindex: '-1',\n });\n if (options.dir) box.setAttribute('dir', options.dir);\n box.append(make('div', { class: 'fd-form-dialog-head' }), body, make('div', { class: 'fd-actions fd-actions-end fd-form-dialog-foot' }));\n box.firstElementChild?.append(title, closeButton);\n box.lastElementChild?.append(discard, saveClose);\n const backdrop = make('div', { class: 'fd-dialog-backdrop fd-form-dialog-backdrop' });\n backdrop.append(box);\n container.append(backdrop);\n\n const handle = mountViewer(body, { ...options, showActions: false });\n let done = false;\n if (options.recompute) recalculate(handle.form, options.page.fields, options.recompute, () => done);\n\n const focusables = () =>\n [...box.querySelectorAll<HTMLElement>(FOCUSABLE)].filter(\n (element) => !element.closest('[hidden], [inert]') && !(element as HTMLButtonElement).disabled\n );\n // Into the dialog: its first field, once the record is in, or the dialog itself meanwhile.\n const firstField = () => body.querySelector<HTMLElement>('input:not([type=\"hidden\"]), select, textarea, [contenteditable=\"true\"]');\n (firstField() ?? box).focus();\n void handle.form.settled().then(() => {\n if (doc.activeElement === box || !box.contains(doc.activeElement)) firstField()?.focus();\n });\n\n return new Promise((resolve) => {\n const close = (saved: boolean) => {\n if (done) return;\n done = true;\n const state = handle.form.getState();\n // The form never changes its values in place, so these are safe to hand back.\n const result: FormDialogResult = { saved, recordId: state.recordId ?? null, values: state.values as Values };\n handle.destroy();\n backdrop.remove();\n opener?.focus();\n resolve(result);\n };\n saveClose.addEventListener('click', async () => {\n saveClose.disabled = true;\n const accepted = options.mode === 'values' ? handle.check() : await handle.save();\n saveClose.disabled = false;\n if (accepted) close(true);\n });\n discard.addEventListener('click', () => close(false));\n closeButton.addEventListener('click', () => close(false));\n box.addEventListener('keydown', (event) => {\n // Ctrl+Enter is Save & Close from wherever the cursor is, even after a field used the Enter\n // (a tag box adding its tag), taking what is still being typed. The grid keeps its own keys.\n if (event.key === 'Enter' && (event.ctrlKey || event.metaKey) && !event.isComposing) {\n if ((event.target as Element).closest('.ag-root-wrapper')) return;\n event.preventDefault();\n doc.activeElement?.dispatchEvent(new Event('change', { bubbles: true }));\n saveClose.click();\n return;\n }\n // A key a field used itself (Escape closing a list) is not the dialog's.\n if (event.defaultPrevented) return;\n if (event.key === 'Escape') {\n event.preventDefault();\n close(false);\n } else if (event.key === 'Tab') {\n const all = focusables();\n if (!all.length) return;\n const first = all[0];\n const last = all[all.length - 1];\n if (event.shiftKey && doc.activeElement === first) {\n event.preventDefault();\n last.focus();\n } else if (!event.shiftKey && doc.activeElement === last) {\n event.preventDefault();\n first.focus();\n }\n }\n });\n });\n}\n\n/** Each change of the values asks for them recalculated, and shows the answer unless they changed again meanwhile. */\nfunction recalculate(form: ViewerHandle['form'], fields: Record<string, unknown>, recompute: (values: Values) => Promise<Values>, closed: () => boolean) {\n let seen = JSON.stringify(form.getState().values);\n let writing = false;\n form.subscribe(() => {\n const values = form.getState().values as Values;\n const now = JSON.stringify(values);\n if (writing || now === seen) return;\n seen = now;\n recompute(values).then(\n (next) => {\n if (closed() || JSON.stringify(form.getState().values) !== now) return; // a newer answer is on its way\n writing = true;\n for (const [name, value] of Object.entries(next)) {\n if (name in fields && JSON.stringify(values[name] ?? null) !== JSON.stringify(value ?? null)) form.setValue(name, value);\n }\n writing = false;\n seen = JSON.stringify(form.getState().values);\n },\n () => undefined\n );\n });\n}\n\nexport interface SearchDialogOptions {\n title: string;\n /** Finds records for what is typed: the field's own search, filter and all. */\n search(query: string, limit: number): Promise<RelatedRecord[]>;\n locale?: Locale;\n skin?: Skin;\n dir?: 'ltr' | 'rtl';\n /** Where the dialog goes: the document's body by default. */\n container?: HTMLElement;\n}\n\n/**\n * A searchable list in a dialog, for \"Search more\u2026\": every record the field may\n * point to, narrowed as the person types, picked with a click or the keyboard.\n * Resolves with the record picked, or null when closed.\n */\nexport function openSearchDialog(options: SearchDialogOptions): Promise<RelatedRecord | null> {\n const doc = options.container?.ownerDocument ?? document;\n const container = options.container ?? doc.body;\n const opener = doc.activeElement instanceof doc.defaultView!.HTMLElement ? (doc.activeElement as HTMLElement) : null;\n const labels = VIEWER_LABELS[options.locale ?? 'en'];\n const words = WIDGET_LABELS[options.locale ?? 'en'];\n const id = `fd-dialog-${++dialogs}`;\n const make = <K extends keyof HTMLElementTagNameMap>(tag: K, attrs: Record<string, string> = {}, text?: string) => {\n const element = doc.createElement(tag);\n for (const [name, value] of Object.entries(attrs)) element.setAttribute(name, value);\n if (text !== undefined) element.textContent = text;\n return element;\n };\n const title = make('h2', { id: `${id}-title`, class: 'fd-form-dialog-title' }, options.title);\n const closeButton = make('button', { type: 'button', class: 'fd-dialog-close', 'aria-label': labels.close }, '\u00D7');\n const query = make('input', { type: 'search', class: 'fd-input', 'aria-label': words.search, placeholder: words.search, 'aria-controls': `${id}-list`, autocomplete: 'off' });\n const list = make('ul', { id: `${id}-list`, class: 'fd-search-list', role: 'listbox', 'aria-labelledby': title.id });\n const cancel = make('button', { type: 'button', class: 'fd-button' }, labels.cancel);\n const box = make('div', {\n class: `fd-theme fd-form-dialog fd-search-dialog fd-size-small`,\n 'data-fd-skin': options.skin ?? 'underline',\n role: 'dialog',\n 'aria-modal': 'true',\n 'aria-labelledby': title.id,\n });\n if (options.dir) box.setAttribute('dir', options.dir);\n const head = make('div', { class: 'fd-form-dialog-head' });\n head.append(title, closeButton);\n const body = make('div', { class: 'fd-form-dialog-body fd-search-body' });\n body.append(query, list);\n const foot = make('div', { class: 'fd-actions fd-actions-end fd-form-dialog-foot' });\n foot.append(cancel);\n box.append(head, body, foot);\n const backdrop = make('div', { class: 'fd-dialog-backdrop fd-form-dialog-backdrop' });\n backdrop.append(box);\n container.append(backdrop);\n query.focus();\n\n return new Promise((resolve) => {\n let found: RelatedRecord[] = [];\n let active = -1;\n let asked = 0;\n let timer: ReturnType<typeof setTimeout> | undefined;\n const close = (picked: RelatedRecord | null) => {\n clearTimeout(timer);\n asked++;\n backdrop.remove();\n opener?.focus();\n resolve(picked);\n };\n const draw = () => {\n list.replaceChildren(\n ...found.map((record, i) => {\n const option = make('li', { id: `${id}-option-${i}`, role: 'option', class: `fd-option${i === active ? ' fd-active' : ''}`, 'aria-selected': String(i === active) }, record.label);\n option.addEventListener('click', () => close(record));\n return option;\n })\n );\n if (!found.length) list.append(make('li', { class: 'fd-empty' }, words.noResults));\n if (active >= 0) query.setAttribute('aria-activedescendant', `${id}-option-${active}`);\n else query.removeAttribute('aria-activedescendant');\n };\n const look = () => {\n clearTimeout(timer);\n const mine = ++asked;\n timer = setTimeout(async () => {\n const records = await options.search(query.value, 80).catch(() => [] as RelatedRecord[]);\n if (mine !== asked) return; // a newer search, or the dialog closed\n found = records;\n active = -1;\n draw();\n }, 180);\n };\n query.addEventListener('input', look);\n query.addEventListener('keydown', (event) => {\n if (event.key === 'ArrowDown' || event.key === 'ArrowUp') {\n event.preventDefault();\n if (!found.length) return;\n active = (active + (event.key === 'ArrowDown' ? 1 : -1) + found.length) % found.length;\n draw();\n list.children[active]?.scrollIntoView?.({ block: 'nearest' });\n } else if (event.key === 'Enter' && active >= 0) {\n event.preventDefault();\n close(found[active]);\n }\n });\n cancel.addEventListener('click', () => close(null));\n closeButton.addEventListener('click', () => close(null));\n box.addEventListener('keydown', (event) => {\n if (event.key === 'Escape') {\n event.preventDefault();\n close(null);\n }\n });\n look();\n });\n}\n", "import type { CreateRequest, DataSource, Field, Page, SearchRequest } from '@fieldia/core';\nimport type { WidgetDialogs } from '@fieldia/widgets';\nimport { openFormDialog, openSearchDialog } from './dialog';\nimport type { ViewerOptions } from './viewer';\n\n/** The field a page's records are named by: its title, or \"name\", or its first line of text. */\nexport function nameFieldOf(page: Page): string | null {\n if (page.layout.type === 'sheet' && page.layout.title?.field) return page.layout.title.field;\n if (page.fields['name']) return 'name';\n return Object.entries(page.fields).find(([, def]) => def.type === 'char')?.[0] ?? null;\n}\n\n\n\n/** A form made of fields, for values edited in a dialog (a line, for one). */\nfunction valuesPage(fields: Record<string, Field>, title: string, readonly: boolean): Page {\n const shown = Object.fromEntries(Object.entries(fields).map(([name, def]) => [name, readonly ? { ...def, readonly: true } : def])) as Page['fields'];\n return {\n fieldia: '0.1',\n id: 'values',\n title,\n data: { kind: 'record', model: 'values' },\n fields: shown,\n layout: {\n type: 'sections',\n id: 'values',\n children: [{ type: 'section', id: 'values-section', columns: 2, children: Object.keys(shown).map((name) => ({ type: 'field' as const, id: `values-${name}`, field: name })) }],\n },\n };\n}\n\n/** Only finding and making linked records: values edited in a dialog are no record of the source's to load, save or recalculate. */\nfunction lookupsOf(source: DataSource | undefined): DataSource | undefined {\n if (!source) return undefined;\n return {\n ...(source.search ? { search: (request: SearchRequest) => source.search!(request) } : {}),\n ...(source.create ? { create: (request: CreateRequest) => source.create!(request) } : {}),\n };\n}\n\n/** The dialogs a page's widgets may open, made from the viewer's own options. */\nexport function pageDialogs(options: ViewerOptions): WidgetDialogs {\n const pageFor = (model: string) =>\n (typeof options.relatedPages === 'function' ? options.relatedPages(model) : options.relatedPages?.[model]) ?? null;\n // A dialog's page looks and reads like the page that opened it, and can open dialogs of its own.\n const shared = {\n locale: options.locale,\n skin: options.skin,\n dir: options.dir,\n widgets: options.widgets,\n preferences: options.preferences,\n relatedPages: options.relatedPages,\n translate: options.translate,\n };\n return {\n canOpen: (model) => pageFor(model) !== null,\n async openRecord(model, request) {\n const related = pageFor(model);\n if (!related) return null;\n const nameField = nameFieldOf(related);\n const result = await openFormDialog({\n ...shared,\n page: related,\n dataSource: options.dataSource,\n recordId: request.recordId ?? null,\n values: request.name && nameField ? { [nameField]: request.name } : undefined,\n title: request.title,\n size: 'large',\n });\n if (!result.saved || result.recordId === null) return null;\n const name = nameField ? result.values[nameField] : null;\n return { id: result.recordId, label: typeof name === 'string' && name ? name : request.name ?? request.title };\n },\n searchMore: (request) => openSearchDialog({ title: request.title, search: request.search, locale: options.locale, skin: options.skin, dir: options.dir }),\n async editValues(request) {\n const result = await openFormDialog({\n ...shared,\n page: valuesPage(request.fields, request.title, request.readonly === true),\n dataSource: lookupsOf(options.dataSource),\n values: request.values,\n title: request.title,\n mode: 'values',\n ...(request.recompute ? { recompute: request.recompute } : {}),\n });\n return result.saved ? result.values : null;\n },\n };\n}\n", "import type { Facet, JsonValue, ListNode, Page } from '@fieldia/core';\nimport type { PreferenceStore } from '@fieldia/widgets';\nimport type { El } from './dom';\nimport type { ViewerLabels } from './labels';\n\n/** A search a person kept, by its name; the one used by default opens the list. */\nexport interface Favourite {\n name: string;\n facets: Facet[];\n isDefault?: boolean;\n}\n\nconst key = (page: Page) => `favourites:${page.id}`;\n\nexport function readFavourites(preferences: PreferenceStore, page: Page): Favourite[] {\n const kept = preferences.get(key(page));\n return Array.isArray(kept) ? (kept as unknown as Favourite[]) : [];\n}\n\n/** What a list starts with: the favourite used by default, or else the list's own default filters. */\nexport function startingFacets(node: ListNode, preferences: PreferenceStore, page: Page): Facet[] {\n const chosen = readFavourites(preferences, page).find((favourite) => favourite.isDefault);\n if (chosen) return chosen.facets;\n if (!node.defaultFilters?.length) return [];\n return [{ kind: 'filters', ids: [...node.defaultFilters], labels: node.defaultFilters.map((id) => node.filters?.find((f) => f.id === id)?.label ?? id) }];\n}\n\n/**\n * The Favourites of the search menu: searches kept by name, each one put back\n * with a click or deleted, and the search on screen kept as a new one, used by\n * default if the person says so. Kept where the page keeps its preferences.\n */\nexport function favouritesPart(context: { page: Page; el: El; labels: ViewerLabels; fill: (template: string, values: Record<string, string>) => string; preferences: PreferenceStore; current: () => Facet[]; apply: (facets: Facet[]) => void }) {\n const { page, el, labels, fill, preferences } = context;\n const list = el('ul', { class: 'fd-favourite-list' });\n const none = el('p', { class: 'fd-favourites-none' }, labels.noFavourites);\n const name = el('input', { class: 'fd-input', 'aria-label': labels.searchName, placeholder: labels.searchName });\n const byDefault = el('input', { type: 'checkbox' });\n const save = el('button', { type: 'button', class: 'fd-button fd-button-primary' }, labels.save);\n const form = el('div', { class: 'fd-favourite-form', hidden: '' }, name, el('label', { class: 'fd-favourite-default' }, byDefault, labels.useByDefault), save);\n const open = el('button', { type: 'button', class: 'fd-search-option fd-search-add', 'aria-expanded': 'false' }, labels.saveSearch);\n\n const write = (favourites: Favourite[]) => preferences.set(key(page), favourites as unknown as JsonValue);\n\n function draw() {\n const favourites = readFavourites(preferences, page);\n none.hidden = favourites.length > 0;\n list.replaceChildren(\n ...favourites.map((favourite) => {\n const use = el('button', { type: 'button', class: 'fd-search-option', 'data-default': favourite.isDefault ? 'true' : undefined }, favourite.name);\n use.addEventListener('click', () => context.apply(favourite.facets));\n const remove = el('button', { type: 'button', class: 'fd-favourite-remove', 'aria-label': fill(labels.deleteFavourite, { name: favourite.name }) }, '\u00D7');\n remove.addEventListener('click', () => {\n write(readFavourites(preferences, page).filter((f) => f.name !== favourite.name));\n draw();\n });\n return el('li', { class: 'fd-favourite' }, use, remove);\n })\n );\n }\n\n open.addEventListener('click', () => {\n form.hidden = !form.hidden;\n open.setAttribute('aria-expanded', String(!form.hidden));\n if (!form.hidden) name.focus();\n });\n save.addEventListener('click', () => {\n const named = name.value.trim();\n if (!named) return name.focus();\n const kept: Favourite = { name: named, facets: context.current(), ...(byDefault.checked ? { isDefault: true } : {}) };\n // A name kept again replaces the old search; one default at a time.\n const others = readFavourites(preferences, page)\n .filter((f) => f.name !== named)\n .map((f) => (byDefault.checked ? { name: f.name, facets: f.facets } : f));\n write([...others, kept]);\n name.value = '';\n byDefault.checked = false;\n form.hidden = true;\n open.setAttribute('aria-expanded', 'false');\n draw();\n });\n\n draw();\n return { list, none, open, form };\n}\n", "import type { DataSource, Group, Page, RecordId, ResolvedFilter, SortOrder, Value } from '@fieldia/core';\nimport type { El } from './dom';\nimport type { ViewerLabels } from './labels';\n\nexport type Row = { id: RecordId; values: Record<string, Value> };\n\nexport interface GroupContext {\n page: Page;\n el: El;\n labels: ViewerLabels;\n fill: (template: string, values: Record<string, string | number>) => string;\n dataSource: DataSource;\n model: string;\n fields: string[];\n columns: number;\n pageSize: number;\n sort: () => SortOrder[];\n /** A record's row, at a depth under its groups. */\n recordRow: (record: Row, level: number) => HTMLTableRowElement;\n /** Rows came or went. */\n changed: () => void;\n}\n\n/** A group's name as a person reads it: the choice's label, yes or no, the linked record's name, or None. */\nfunction groupName(context: GroupContext, field: string, group: Group): string {\n const def = context.page.fields[field];\n if (group.value === null) return context.labels.none;\n if (def.type === 'selection') return def.options.find((o) => o.value === group.value)?.label ?? group.label;\n if (def.type === 'boolean') return group.value ? context.labels.yes : context.labels.no;\n return group.label || String(group.value);\n}\n\n/** Take away every row under a group: its records, its groups and theirs. */\nfunction closeUnder(tr: HTMLElement) {\n const level = Number(tr.dataset['level']);\n let next = tr.nextElementSibling as HTMLElement | null;\n while (next && Number(next.dataset['level'] ?? 0) > level) {\n const after = next.nextElementSibling as HTMLElement | null;\n next.remove();\n next = after;\n }\n}\n\n/**\n * A group's row: its name and how many records it holds. Opened, it shows\n * the next field's groups under it, or at the last field its records, a page\n * at a time; closed, everything under it goes.\n */\nexport function groupRow(context: GroupContext, group: Group, level: number, within: ResolvedFilter[], grouping: string[]): HTMLTableRowElement {\n const { el, labels } = context;\n const field = grouping[level];\n const filter: ResolvedFilter[] = [...within, group.value === null ? { field, op: 'notset', value: null } : { field, op: '=', value: group.value }];\n const toggle = el(\n 'button',\n { type: 'button', class: 'fd-group-toggle', 'aria-expanded': 'false' },\n el('span', { class: 'fd-group-label' }, groupName(context, field, group)),\n ' ',\n el('span', { class: 'fd-group-count' }, `(${group.count})`)\n );\n const tr = el('tr', { class: 'fd-list-group', 'data-level': String(level), 'aria-level': String(level + 1) }, el('td', { colspan: String(context.columns) }, toggle));\n tr.style.setProperty('--fd-level', String(level));\n let opening = false;\n\n async function open() {\n opening = true;\n try {\n const rows =\n level + 1 < grouping.length\n ? (await context.dataSource.groups?.({ model: context.model, field: grouping[level + 1], filter }))?.map((inner) => groupRow(context, inner, level + 1, filter, grouping)) ?? []\n : await recordsFrom(0);\n // Closed, or the list drawn again, while the answer was on its way.\n if (!tr.isConnected || toggle.getAttribute('aria-expanded') !== 'true') return;\n tr.after(...rows);\n context.changed();\n } finally {\n opening = false;\n }\n }\n\n /** A page of the group's records, from `offset`, and a row for the rest when there are more. */\n async function recordsFrom(offset: number): Promise<HTMLTableRowElement[]> {\n const answer = await context.dataSource.list!({ model: context.model, fields: context.fields, filter, sort: context.sort(), offset, limit: context.pageSize });\n const rows = answer.records.map((record) => context.recordRow(record, level + 1));\n const left = answer.total - offset - answer.records.length;\n if (left <= 0) return rows;\n const more = el('button', { type: 'button', class: 'fd-button fd-button-link' }, context.fill(labels.loadMore, { n: left }));\n const moreRow = el('tr', { class: 'fd-list-more', 'data-level': String(level + 1) }, el('td', { colspan: String(context.columns) }, more));\n moreRow.style.setProperty('--fd-level', String(level));\n more.addEventListener('click', async () => {\n more.disabled = true;\n const next = await recordsFrom(offset + answer.records.length);\n if (!moreRow.isConnected) return;\n moreRow.replaceWith(...next);\n context.changed();\n });\n return [...rows, moreRow];\n }\n\n toggle.addEventListener('click', () => {\n const opened = toggle.getAttribute('aria-expanded') === 'true';\n toggle.setAttribute('aria-expanded', String(!opened));\n if (opened) {\n closeUnder(tr);\n context.changed();\n } else if (!opening) void open();\n });\n return tr;\n}\n", "/** The list's look, on the same tokens as the forms it opens. */\nexport const LIST_STYLES = `.fd-list{display:grid;gap:10px;min-width:0}.fd-list [hidden]{display:none!important}.fd-list-bar{display:flex;flex-wrap:wrap;align-items:center;gap:8px 12px;min-height:34px}.fd-search{position:relative;flex:1 1 360px;max-width:680px;min-width:0;container:fd-search / inline-size}.fd-search-field{display:flex;flex-wrap:wrap;align-items:center;gap:4px;min-height:34px;box-sizing:border-box;padding:2px 2px 2px 8px;padding-inline:8px 2px;border:1px solid var(--fd-border);border-radius:var(--fd-control-radius);background:var(--fd-surface)}.fd-search-field:focus-within{border-color:var(--fd-focus);box-shadow:var(--fd-focus-ring)}.fd-search-field>.fd-icon,.fd-search-field>svg{width:16px;height:16px;color:var(--fd-muted);flex:none}.fd-facets{display:contents}.fd-facet{display:inline-flex;align-items:center;gap:4px;max-width:100%;min-width:0;padding-block:2px;padding-inline:6px 2px;border-radius:3px;background:var(--fd-accent-soft);color:var(--fd-accent);font-size:13px;line-height:18px}.fd-facet svg{width:13px;height:13px;flex:none}.fd-facet[data-kind=groupBy]{background:var(--fd-success-soft);color:var(--fd-success)}.fd-facet-text{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.fd-facet-remove{all:unset;cursor:pointer;display:grid;place-items:center;width:18px;height:18px;border-radius:2px;font-size:15px;line-height:1;opacity:.7}.fd-facet-remove:hover,.fd-facet-remove:focus-visible{opacity:1;background:var(--fd-surface)}.fd-search-input{flex:1 1 140px;min-width:100px;border:none;outline:none;background:none;font:inherit;font-size:14px;color:var(--fd-text);padding:5px 4px}.fd-form .fd-search-input:focus-visible{outline:none}.fd-search-toggle{all:unset;cursor:pointer;display:grid;place-items:center;width:30px;height:28px;border-radius:3px;color:var(--fd-muted)}.fd-search-toggle:before{content:\"\";width:7px;height:7px;border-right:1.5px solid currentColor;border-bottom:1.5px solid currentColor;transform:translateY(-2px) rotate(45deg)}.fd-search-toggle[aria-expanded=true]:before{transform:translateY(2px) rotate(-135deg)}.fd-search-toggle:hover,.fd-search-toggle[aria-expanded=true]{background:var(--fd-page);color:var(--fd-text)}.fd-search-toggle:focus-visible{outline:2px solid var(--fd-focus)}.fd-search-suggestions,.fd-search-panel{position:absolute;z-index:30;inset-inline:0;top:calc(100% + 4px);box-sizing:border-box;background:var(--fd-surface);border:1px solid var(--fd-border);border-radius:var(--fd-radius);box-shadow:0 10px 28px #0f172a24}.fd-search-suggestions{list-style:none;margin:0;padding:4px 0}.fd-search-suggestions [role=option]{padding:7px 12px;cursor:pointer;font-size:14px}.fd-search-suggestions [role=option][aria-selected=true]{background:var(--fd-accent-soft)}.fd-search-panel{display:grid;grid-auto-flow:column;grid-auto-columns:minmax(0,1fr);padding-block:6px}.fd-search-group{display:flex;flex-direction:column;align-items:stretch;gap:1px;padding:4px 10px 8px;min-width:0}.fd-search-group+.fd-search-group{border-inline-start:1px solid var(--fd-border)}@container fd-search (max-width: 540px){.fd-search-panel{grid-auto-flow:row}.fd-search-group+.fd-search-group{border-inline-start:none;border-block-start:1px solid var(--fd-border);padding-block-start:8px}}.fd-search-heading{display:flex;align-items:center;gap:6px;font-weight:600;font-size:13.5px;padding:4px 6px 6px}.fd-search-heading svg{width:15px;height:15px}.fd-search-group[data-group-kind=filters] .fd-search-heading svg{color:var(--fd-accent)}.fd-search-group[data-group-kind=groupBy] .fd-search-heading svg{color:var(--fd-success)}.fd-search-group[data-group-kind=favourites] .fd-search-heading svg{color:var(--fd-warning)}.fd-search-option{all:unset;box-sizing:border-box;cursor:pointer;display:flex;align-items:center;gap:6px;padding:5px 6px;border-radius:4px;font-size:14px;color:var(--fd-text)}.fd-search-option:before{content:\"\";width:14px;flex:none;text-align:center;color:var(--fd-accent);font-weight:700}.fd-search-option[aria-pressed=true]:before{content:\"\u2713\"}.fd-search-option:hover,.fd-search-option:focus-visible{background:var(--fd-page)}.fd-search-add{color:var(--fd-muted);margin-block-start:4px}.fd-search-add:before{content:\"+\";color:var(--fd-muted);font-weight:400}.fd-custom-filter,.fd-favourite-form{display:grid;gap:6px;padding:6px}.fd-custom-filter .fd-input,.fd-favourite-form .fd-input{width:100%;box-sizing:border-box;min-height:30px;border:1px solid var(--fd-border);border-radius:var(--fd-control-radius);padding:3px 6px;font:inherit;font-size:13.5px;background:var(--fd-surface);color:var(--fd-text)}.fd-favourite-default{display:flex;align-items:center;gap:6px;font-size:13.5px}.fd-favourite-list{list-style:none;margin:0;padding:0}.fd-favourite{display:flex;align-items:center}.fd-favourite .fd-search-option{flex:1;min-width:0}.fd-favourite .fd-search-option[data-default=true]:before{content:\"\u2605\";color:var(--fd-warning)}.fd-favourite-remove{all:unset;cursor:pointer;width:24px;height:24px;display:grid;place-items:center;border-radius:4px;color:var(--fd-muted)}.fd-favourite-remove:hover{background:var(--fd-page);color:var(--fd-error)}.fd-favourites-none{margin:0;padding:4px 6px;color:var(--fd-muted);font-size:13px}.fd-list-selection{display:flex;flex-wrap:wrap;align-items:center;gap:8px;padding:3px 4px 3px 10px;border-radius:var(--fd-control-radius);background:var(--fd-accent-soft)}.fd-list-count{font-weight:600;font-size:13.5px;color:var(--fd-accent);font-variant-numeric:tabular-nums}.fd-pager{display:flex;align-items:center;gap:4px;margin-inline-start:auto}.fd-pager-text{color:var(--fd-muted);font-size:13.5px;font-variant-numeric:tabular-nums;margin-inline-end:6px;white-space:nowrap}.fd-pager-button{min-width:32px;padding-inline:0;font-size:18px;line-height:1}.fd-list-scroll{overflow-x:auto;background:var(--fd-surface);border:1px solid var(--fd-border);border-radius:var(--fd-radius)}.fd-list-table{width:100%;border-collapse:collapse;font-size:14px}.fd-list-table th{text-align:start;font-weight:600;font-size:13px;color:var(--fd-text);padding:8px 10px;border-block-end:1px solid var(--fd-border-strong);white-space:nowrap;background:var(--fd-surface)}.fd-list-table td{padding:7px 10px;border-block-end:1px solid var(--fd-border);max-width:28em;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.fd-list-table tbody tr:last-child td{border-block-end:none}.fd-list-table .fd-num{text-align:end;font-variant-numeric:tabular-nums}.fd-list-table th.fd-list-check,.fd-list-table td.fd-list-check{width:36px;padding-inline:10px 0}.fd-list-checkbox{width:16px;height:16px;margin:0;vertical-align:middle;accent-color:var(--fd-accent);cursor:pointer}.fd-list-sort{all:unset;box-sizing:border-box;width:100%;cursor:pointer;display:flex;align-items:center;gap:4px;font:inherit;color:inherit}.fd-list-sort:after{content:\"\";width:0;height:0;border-inline:4px solid transparent;opacity:0}.fd-list-sort:hover:after{opacity:.35;border-block-start:5px solid currentColor}.fd-list-table th[aria-sort=ascending] .fd-list-sort:after{opacity:1;border-block-start:none;border-block-end:5px solid currentColor}.fd-list-table th[aria-sort=descending] .fd-list-sort:after{opacity:1;border-block-end:none;border-block-start:5px solid currentColor}.fd-list-table th.fd-num .fd-list-sort{justify-content:flex-end}.fd-list-table th.fd-num .fd-list-sort:after{order:-1}.fd-list-sort:focus-visible{outline:2px solid var(--fd-focus);outline-offset:2px}.fd-list-row:hover td{background:var(--fd-page)}.fd-list-openable{cursor:pointer}.fd-list-row[aria-selected=true] td{background:var(--fd-accent-soft)}.fd-list-row:focus-visible{outline:2px solid var(--fd-focus);outline-offset:-2px}.fd-list-table[aria-busy=true] tbody{opacity:.6;transition:opacity .2s .15s}.fd-list-group td{padding:0;background:var(--fd-page)}.fd-group-toggle{all:unset;box-sizing:border-box;cursor:pointer;display:flex;align-items:center;gap:8px;width:100%;padding:8px 10px;padding-inline-start:calc(12px + var(--fd-level, 0) * 22px);font-weight:600;font-size:13.5px;color:var(--fd-text)}.fd-group-toggle:before{content:\"\";flex:none;width:6px;height:6px;border-top:1.5px solid currentColor;border-right:1.5px solid currentColor;transform:rotate(45deg);transition:transform .12s}.fd-group-toggle:dir(rtl):before{transform:rotate(-135deg)}.fd-group-toggle[aria-expanded=true]:before{transform:rotate(135deg)}.fd-group-toggle:hover{background:var(--fd-accent-soft)}.fd-group-toggle:focus-visible{outline:2px solid var(--fd-focus);outline-offset:-2px}.fd-group-count{color:var(--fd-muted);font-weight:400;font-variant-numeric:tabular-nums}.fd-list-more td{padding:4px 10px;padding-inline-start:calc(46px + var(--fd-level, 0) * 22px)}.fd-list-empty,.fd-list-failed{margin:0;padding:28px 12px;text-align:center;color:var(--fd-muted)}.fd-list-failed{color:var(--fd-error)}`;\n\n/** Puts the list's look in the document once. */\nexport function installListStyles(doc: Document): void {\n if (doc.getElementById('fd-list-styles')) return;\n const style = doc.createElement('style');\n style.id = 'fd-list-styles';\n style.textContent = LIST_STYLES;\n doc.head.append(style);\n}\n", "import type { Facet, Field, JsonValue, Page, ResolvedFilterCondition } from '@fieldia/core';\nimport type { El } from './dom';\nimport type { ViewerLabels } from './labels';\n\ntype Op = ResolvedFilterCondition['op'];\ntype Words = Pick<ViewerLabels, 'opIs' | 'opIsNot' | 'opContains' | 'opGreater' | 'opLess' | 'opSet' | 'opNotSet'>;\n\nconst TEXT: [Op, keyof Words][] = [['ilike', 'opContains'], ['=', 'opIs'], ['!=', 'opIsNot'], ['set', 'opSet'], ['notset', 'opNotSet']];\nconst LINK: [Op, keyof Words][] = [['ilike', 'opContains'], ['set', 'opSet'], ['notset', 'opNotSet']];\nconst CHOICE: [Op, keyof Words][] = [['=', 'opIs'], ['!=', 'opIsNot'], ['set', 'opSet'], ['notset', 'opNotSet']];\nconst NUMBER: [Op, keyof Words][] = [['=', 'opIs'], ['!=', 'opIsNot'], ['>', 'opGreater'], ['<', 'opLess'], ['set', 'opSet'], ['notset', 'opNotSet']];\nconst DATE: [Op, keyof Words][] = [['=', 'opIs'], ['>', 'opGreater'], ['<', 'opLess'], ['set', 'opSet'], ['notset', 'opNotSet']];\n\n/** The conditions that suit a field, or none for a field a custom filter cannot look at. */\nfunction conditionsFor(def: Field): [Op, keyof Words][] {\n switch (def.type) {\n case 'char':\n case 'text':\n case 'html':\n return TEXT;\n case 'many2one':\n case 'many2many':\n return LINK;\n case 'selection':\n return CHOICE;\n case 'integer':\n case 'float':\n case 'monetary':\n return NUMBER;\n case 'date':\n case 'datetime':\n return DATE;\n case 'boolean':\n return [['=', 'opIs']];\n default:\n return [];\n }\n}\n\n/**\n * A filter of a person's own, under the list's filters: a field, a condition\n * that suits it, and a value of its kind. Applied, it becomes a chip.\n */\nexport function customFilterPart(context: { page: Page; el: El; labels: ViewerLabels; add: (facet: Facet) => void }) {\n const { page, el, labels } = context;\n const fields = Object.entries(page.fields).filter(([, def]) => conditionsFor(def).length);\n const field = el('select', { class: 'fd-input', 'aria-label': labels.field }, ...fields.map(([name, def]) => el('option', { value: name }, def.label)));\n const condition = el('select', { class: 'fd-input', 'aria-label': labels.condition });\n const valueBox = el('span', { class: 'fd-custom-filter-value' });\n const apply = el('button', { type: 'button', class: 'fd-button fd-button-primary' }, labels.apply);\n const form = el('div', { class: 'fd-custom-filter', hidden: '' }, field, condition, valueBox, apply);\n const button = el('button', { type: 'button', class: 'fd-search-option fd-search-add', 'aria-expanded': 'false' }, labels.addCustomFilter);\n let value: HTMLInputElement | HTMLSelectElement = el('input', { class: 'fd-input', 'aria-label': labels.value });\n\n const def = () => page.fields[field.value];\n\n function drawConditions() {\n condition.replaceChildren(...conditionsFor(def()).map(([op, word]) => el('option', { value: op }, labels[word])));\n drawValue();\n }\n\n /** A box of the field's kind: its choices, yes or no, a number, a day, or text. */\n function drawValue() {\n const current = def();\n if (current.type === 'selection') value = el('select', { class: 'fd-input', 'aria-label': labels.value }, ...current.options.map((o) => el('option', { value: String(o.value) }, o.label)));\n else if (current.type === 'boolean') value = el('select', { class: 'fd-input', 'aria-label': labels.value }, el('option', { value: 'true' }, labels.yes), el('option', { value: 'false' }, labels.no));\n else {\n const type = ['integer', 'float', 'monetary'].includes(current.type) ? 'number' : current.type === 'date' ? 'date' : current.type === 'datetime' ? 'datetime-local' : 'text';\n value = el('input', { class: 'fd-input', type, 'aria-label': labels.value });\n }\n valueBox.replaceChildren(value);\n valueBox.hidden = condition.value === 'set' || condition.value === 'notset';\n }\n\n field.addEventListener('change', drawConditions);\n condition.addEventListener('change', () => (valueBox.hidden = condition.value === 'set' || condition.value === 'notset'));\n button.addEventListener('click', () => {\n form.hidden = !form.hidden;\n button.setAttribute('aria-expanded', String(!form.hidden));\n if (!form.hidden) field.focus();\n });\n\n apply.addEventListener('click', () => {\n const current = def();\n const op = condition.value as Op;\n const word = labels[conditionsFor(current).find(([o]) => o === op)?.[1] ?? 'opIs'];\n let wanted: JsonValue = null;\n let shown = '';\n if (!valueBox.hidden) {\n const text = value.value.trim();\n if (!text) return value.focus();\n if (current.type === 'selection') {\n const option = current.options.find((o) => String(o.value) === text);\n wanted = option?.value ?? text;\n shown = option?.label ?? text;\n } else if (current.type === 'boolean') {\n wanted = text === 'true';\n shown = wanted ? labels.yes : labels.no;\n } else if (['integer', 'float', 'monetary'].includes(current.type)) {\n wanted = Number(text);\n if (!Number.isFinite(wanted)) return value.focus();\n shown = text;\n } else {\n wanted = text;\n shown = text;\n }\n }\n context.add({ kind: 'custom', label: [current.label, word, shown].filter(Boolean).join(' '), filter: [{ field: field.value, op, value: wanted }] });\n form.hidden = true;\n button.setAttribute('aria-expanded', 'false');\n });\n\n drawConditions();\n return { button, form };\n}\n", "import { suggestions, type Facet, type ListNode, type Page, type Suggestion } from '@fieldia/core';\nimport { drawIcon, type IconSet, type PreferenceStore } from '@fieldia/widgets';\nimport { customFilterPart } from './custom-filter';\nimport type { El } from './dom';\nimport { favouritesPart } from './favourites';\nimport type { ViewerLabels } from './labels';\n\ntype FieldFacet = Extract<Facet, { kind: 'field' }>;\n\nexport interface SearchContext {\n page: Page;\n node: ListNode;\n doc: Document;\n el: El;\n labels: ViewerLabels;\n fill: (template: string, values: Record<string, string | number>) => string;\n uid: (id: string) => string;\n icons?: IconSet;\n preferences: PreferenceStore;\n /** What the list starts with. */\n facets: Facet[];\n onChange: (facets: Facet[]) => void;\n}\n\n/** A chip's words: a field and the values looked for in it, filters any of which apply, or the fields grouped by. */\nexport function facetText(facet: Facet, labels: Pick<ViewerLabels, 'or'>): string {\n const or = ` ${labels.or} `;\n switch (facet.kind) {\n case 'field':\n return `${facet.label}: ${facet.values.map((v) => v.label).join(or)}`;\n case 'filters':\n return facet.labels.join(or);\n case 'groupBy':\n return facet.labels.join(' > ');\n case 'custom':\n return facet.label;\n }\n}\n\n/**\n * A list's search bar: what is typed becomes a search in one of the list's\n * fields, chosen from suggestions; the menu turns the list's filters on and\n * off, groups by its fields, builds a filter, and keeps searches as\n * favourites. Everything chosen shows as a chip, and all of it applies.\n */\nexport function searchBar(context: SearchContext) {\n const { page, node, doc, el, labels, fill, uid } = context;\n let facets = context.facets;\n const icon = (name: string) => {\n const drawn = drawIcon(doc, name, context.icons);\n drawn?.setAttribute('aria-hidden', 'true');\n return drawn ? [drawn] : [];\n };\n\n function change(next: Facet[]) {\n facets = next;\n drawChips();\n drawPanel();\n context.onChange(facets);\n }\n\n // ---- the box, its chips and its suggestions -----------------------------------------\n\n const listId = uid(`${node.id}-suggestions`);\n const panelId = uid(`${node.id}-search-panel`);\n const input = el('input', {\n class: 'fd-search-input',\n role: 'combobox',\n autocomplete: 'off',\n placeholder: labels.search,\n 'aria-label': labels.searchLabel,\n 'aria-autocomplete': 'list',\n 'aria-expanded': 'false',\n 'aria-controls': listId,\n });\n const chips = el('div', { class: 'fd-facets' });\n const offeredList = el('ul', { class: 'fd-search-suggestions', role: 'listbox', id: listId, 'aria-label': labels.searchLabel, hidden: '' });\n const toggle = el('button', { type: 'button', class: 'fd-search-toggle', 'aria-label': labels.searchOptions, 'aria-expanded': 'false', 'aria-controls': panelId });\n let offered: Suggestion[] = [];\n let active = 0;\n\n function drawChips() {\n chips.replaceChildren(\n ...facets.map((facet, index) => {\n const text = facetText(facet, labels);\n const remove = el('button', { type: 'button', class: 'fd-facet-remove', 'aria-label': fill(labels.removeFacet, { label: text }) }, '\u00D7');\n remove.addEventListener('click', () => {\n change(facets.filter((_, i) => i !== index));\n input.focus();\n });\n const kind = facet.kind === 'groupBy' ? 'layers' : facet.kind === 'field' ? '' : 'filter';\n return el('span', { class: 'fd-facet', 'data-kind': facet.kind }, ...(kind ? icon(kind) : []), el('span', { class: 'fd-facet-text' }, text), remove);\n })\n );\n }\n\n function drawOffered() {\n offeredList.replaceChildren(\n ...offered.map((suggestion, index) => {\n const option = el('li', { role: 'option', id: `${listId}-${index}`, 'aria-selected': String(index === active) }, suggestion.label);\n // The box keeps the focus while a suggestion is clicked.\n option.addEventListener('mousedown', (event) => event.preventDefault());\n option.addEventListener('click', () => pick(suggestion));\n return option;\n })\n );\n offeredList.hidden = offered.length === 0;\n input.setAttribute('aria-expanded', String(!offeredList.hidden));\n if (offeredList.hidden) input.removeAttribute('aria-activedescendant');\n else input.setAttribute('aria-activedescendant', `${listId}-${active}`);\n }\n\n function closeOffered() {\n offered = [];\n drawOffered();\n }\n\n /** A search in a field joins the field's chip, any of its values; the same value twice is once. */\n function pick(suggestion: Suggestion) {\n const value = { op: suggestion.op, value: suggestion.value, label: suggestion.valueLabel };\n const at = facets.findIndex((f) => f.kind === 'field' && f.field === suggestion.field);\n const next = [...facets];\n if (at < 0) next.push({ kind: 'field', field: suggestion.field, label: suggestion.fieldLabel, values: [value] });\n else {\n const facet = next[at] as FieldFacet;\n const known = facet.values.some((v) => v.op === value.op && JSON.stringify(v.value) === JSON.stringify(value.value));\n if (!known) next[at] = { ...facet, values: [...facet.values, value] };\n }\n input.value = '';\n closeOffered();\n change(next);\n }\n\n input.addEventListener('input', () => {\n offered = suggestions(input.value, page, node, { searchFor: labels.searchFor });\n active = 0;\n drawOffered();\n });\n input.addEventListener('blur', closeOffered);\n input.addEventListener('keydown', (event) => {\n if (event.isComposing) return;\n if ((event.key === 'ArrowDown' || event.key === 'ArrowUp') && offered.length) {\n event.preventDefault();\n active = (active + (event.key === 'ArrowDown' ? 1 : offered.length - 1)) % offered.length;\n drawOffered();\n } else if (event.key === 'Enter') {\n // Never the form's Enter: a list has nothing to send.\n event.preventDefault();\n if (offered.length) pick(offered[active]);\n } else if (event.key === 'Backspace' && !input.value && facets.length) {\n change(facets.slice(0, -1));\n } else if (event.key === 'Escape' && !offeredList.hidden) {\n event.preventDefault();\n closeOffered();\n }\n });\n\n // ---- the menu: filters, group by, favourites ---------------------------------------\n\n const heading = (iconName: string, text: string, id: string) => el('div', { class: 'fd-search-heading', id }, ...icon(iconName), text);\n const toggleIn = (kind: 'filters' | 'groupBy', key: string) => {\n const at = facets.findIndex((f) => f.kind === kind);\n const now = at < 0 ? [] : kind === 'filters' ? (facets[at] as Extract<Facet, { kind: 'filters' }>).ids : (facets[at] as Extract<Facet, { kind: 'groupBy' }>).fields;\n const keys = now.includes(key) ? now.filter((k) => k !== key) : [...now, key];\n const facet: Facet =\n kind === 'filters'\n ? { kind, ids: keys, labels: keys.map((id) => node.filters?.find((f) => f.id === id)?.label ?? id) }\n : { kind, fields: keys, labels: keys.map((field) => page.fields[field]?.label ?? field) };\n const next = [...facets];\n if (at < 0) next.push(facet);\n else if (keys.length) next[at] = facet;\n else next.splice(at, 1);\n change(next);\n };\n\n const filterButtons = (node.filters ?? []).map((filter) => {\n const button = el('button', { type: 'button', class: 'fd-search-option', 'aria-pressed': 'false', 'data-filter': filter.id }, filter.label);\n button.addEventListener('click', () => toggleIn('filters', filter.id));\n return button;\n });\n const groupButtons = (node.groupBy ?? []).map((field) => {\n const button = el('button', { type: 'button', class: 'fd-search-option', 'aria-pressed': 'false', 'data-group': field }, page.fields[field].label);\n button.addEventListener('click', () => toggleIn('groupBy', field));\n return button;\n });\n const custom = customFilterPart({ page, el, labels, add: (facet) => change([...facets, facet]) });\n const favourites = favouritesPart({ page, el, labels, fill, preferences: context.preferences, current: () => facets, apply: change });\n\n const group = (kind: string, iconName: string, title: string, ...parts: HTMLElement[]) =>\n el('div', { class: 'fd-search-group', 'data-group-kind': kind, role: 'group', 'aria-labelledby': `${panelId}-${kind}` }, heading(iconName, title, `${panelId}-${kind}`), ...parts);\n const panel = el(\n 'div',\n { class: 'fd-search-panel', id: panelId, hidden: '' },\n group('filters', 'filter', labels.filters, ...filterButtons, custom.button, custom.form),\n ...(groupButtons.length ? [group('groupBy', 'layers', labels.groupBy, ...groupButtons)] : []),\n group('favourites', 'star', labels.favourites, favourites.list, favourites.none, favourites.open, favourites.form)\n );\n\n function drawPanel() {\n const ids = (facets.find((f) => f.kind === 'filters') as Extract<Facet, { kind: 'filters' }> | undefined)?.ids ?? [];\n const fields = (facets.find((f) => f.kind === 'groupBy') as Extract<Facet, { kind: 'groupBy' }> | undefined)?.fields ?? [];\n for (const button of filterButtons) button.setAttribute('aria-pressed', String(ids.includes(button.dataset['filter'] ?? '')));\n for (const button of groupButtons) button.setAttribute('aria-pressed', String(fields.includes(button.dataset['group'] ?? '')));\n }\n\n function showPanel(open: boolean) {\n panel.hidden = !open;\n toggle.setAttribute('aria-expanded', String(open));\n if (open) closeOffered();\n }\n toggle.addEventListener('click', () => showPanel(panel.hidden));\n panel.addEventListener('keydown', (event) => {\n if (event.key !== 'Escape') return;\n event.preventDefault();\n showPanel(false);\n toggle.focus();\n });\n const element = el('div', { class: 'fd-search' }, el('div', { class: 'fd-search-field' }, ...icon('search'), chips, input, toggle), offeredList, panel);\n // A press anywhere else closes the menu.\n const outside = (event: Event) => {\n if (!panel.hidden && !element.contains(event.target as Node)) showPanel(false);\n };\n doc.addEventListener('pointerdown', outside);\n\n drawChips();\n drawPanel();\n return {\n element,\n destroy: () => doc.removeEventListener('pointerdown', outside),\n };\n}\n", "import {\n facetsToFilter,\n groupByFields,\n type ButtonNode,\n type DataSource,\n type Facet,\n type Form,\n type LineField,\n type ListNode,\n type Locale,\n type Page,\n type RecordId,\n type SortOrder,\n type Value,\n} from '@fieldia/core';\nimport { displayValue, type IconSet, type PreferenceStore } from '@fieldia/widgets';\nimport type { El } from './dom';\nimport { startingFacets } from './favourites';\nimport type { ViewerLabels } from './labels';\nimport { groupRow, type GroupContext, type Row } from './list-groups';\nimport { installListStyles } from './list-styles';\nimport { searchBar } from './search-bar';\n\nexport interface ListContext {\n page: Page;\n node: ListNode;\n form: Form;\n dataSource: DataSource | undefined;\n doc: Document;\n el: El;\n labels: ViewerLabels;\n locale: Locale;\n fill: (template: string, values: Record<string, string | number>) => string;\n confirm: (message: string) => Promise<boolean>;\n withIcon: (icon: string | undefined, text: string) => (Node | string)[];\n uid: (id: string) => string;\n icons?: IconSet;\n /** Where the list's favourite searches are kept. */\n preferences: PreferenceStore;\n onOpenRecord?: (id: RecordId) => void;\n}\n\nexport interface ListView {\n element: HTMLElement;\n /** Ask for the records again, keeping the page, the order and what is chosen where it still applies. */\n reload(): Promise<void>;\n destroy(): void;\n}\n\n/** Numbers line up on the end of their column. */\nconst NUMBERS = new Set(['integer', 'float', 'monetary']);\n/** Fields no list can put in order. */\nconst UNSORTABLE = new Set(['one2many', 'many2many', 'binary', 'image', 'html', 'json', 'properties']);\n\n/**\n * Records as a table: one page at a time, in the order a header asks for, each\n * row opening its record. Chosen rows get the list's buttons, which hand the\n * app their ids. A plain table, so it reads the same in every binding.\n */\nexport function listView(context: ListContext): ListView {\n const { page, node, form, el, labels, fill, locale, doc } = context;\n installListStyles(doc);\n const pageSize = node.pageSize ?? 40;\n const defaultSort = node.sort ?? [];\n let sort: SortOrder[] = defaultSort;\n let offset = 0;\n let total = 0;\n /** The page of records, when the list is not grouped. */\n let rows: Row[] = [];\n /** Each record's row, for the records on show however they are grouped. */\n const recordOf = new WeakMap<Element, Row>();\n const visible = () => [...body.querySelectorAll('.fd-list-row')].map((tr) => recordOf.get(tr) as Row);\n // Only a page of records gets this far: the page check refuses a list of anything else.\n const model = page.data.kind === 'record' ? page.data.model : '';\n let facets: Facet[] = startingFacets(node, context.preferences, page);\n /** In the order they were chosen, which is the order the app gets them. */\n const chosen = new Set<RecordId>();\n let asking = 0;\n let destroyed = false;\n\n // The columns, and what an amount needs to be read: its currency, from the record.\n const fields = [...new Set(node.columns.flatMap((name) => {\n const def = page.fields[name];\n return def.type === 'monetary' && def.currencyField ? [name, def.currencyField] : [name];\n }))];\n const show = (name: string, values: Record<string, Value>) => displayValue(page.fields[name] as LineField, values[name], values, locale);\n\n // ---- the table ---------------------------------------------------------------\n\n const chooseAll = el('input', { type: 'checkbox', class: 'fd-list-checkbox', 'aria-label': labels.selectAll });\n const headers = node.columns.map((name) => {\n const def = page.fields[name];\n const th = el('th', { scope: 'col', 'data-field': name, class: NUMBERS.has(def.type) ? 'fd-num' : undefined });\n if (UNSORTABLE.has(def.type)) th.append(def.label);\n else {\n const button = el('button', { type: 'button', class: 'fd-list-sort' }, def.label);\n button.addEventListener('click', () => {\n // The header's field leads; the list's own order breaks the ties.\n const desc = sort[0]?.field === name ? !sort[0].desc : false;\n sort = [{ field: name, ...(desc ? { desc } : {}) }, ...defaultSort.filter((order) => order.field !== name)];\n offset = 0;\n void load();\n });\n th.append(button);\n }\n return th;\n });\n const body = el('tbody');\n const table = el(\n 'table',\n { class: 'fd-list-table', 'aria-label': page.title },\n el('thead', {}, el('tr', {}, el('th', { class: 'fd-list-check', scope: 'col' }, chooseAll), ...headers)),\n body\n );\n const empty = el('p', { class: 'fd-list-empty', hidden: '' }, labels.noRecords);\n const retry = el('button', { type: 'button', class: 'fd-button fd-button-link' }, labels.retry);\n const failed = el('p', { class: 'fd-list-failed', role: 'alert', hidden: '' }, labels.loadFailed, ' ', retry);\n retry.addEventListener('click', () => void load());\n\n function row(record: Row, level = 0): HTMLTableRowElement {\n const name = show(node.columns[0], record.values) || String(record.id);\n const box = el('input', { type: 'checkbox', class: 'fd-list-checkbox', 'aria-label': fill(labels.selectRecord, { name }) });\n box.checked = chosen.has(record.id);\n box.addEventListener('change', () => {\n if (box.checked) chosen.add(record.id);\n else chosen.delete(record.id);\n drawChoice();\n });\n const tr = el(\n 'tr',\n { class: context.onOpenRecord ? 'fd-list-row fd-list-openable' : 'fd-list-row', tabindex: '0', 'data-id': String(record.id), 'data-level': level ? String(level) : undefined },\n el('td', { class: 'fd-list-check' }, box),\n // Each value in its own direction: a phone number or an amount reads left to right on a right-to-left page.\n ...node.columns.map((name) => el('td', { class: NUMBERS.has(page.fields[name].type) ? 'fd-num' : undefined }, el('bdi', {}, show(name, record.values))))\n );\n tr.addEventListener('click', (event) => {\n const cell = (event.target as Element).closest('td');\n // The box's own cell is a bigger target for the box.\n if (cell?.classList.contains('fd-list-check')) {\n if (event.target === cell) box.click();\n return;\n }\n context.onOpenRecord?.(record.id);\n });\n tr.addEventListener('keydown', (event) => {\n if (event.target !== tr) return;\n if (event.key === 'Enter') {\n event.preventDefault();\n context.onOpenRecord?.(record.id);\n } else if (event.key === ' ') {\n event.preventDefault();\n box.click();\n } else if (event.key === 'ArrowDown' || event.key === 'ArrowUp') {\n event.preventDefault();\n const next = event.key === 'ArrowDown' ? tr.nextElementSibling : tr.previousElementSibling;\n (next as HTMLElement | null)?.focus();\n }\n });\n recordOf.set(tr, record);\n return tr;\n }\n\n // ---- what is chosen, and the buttons for it --------------------------------------\n\n const count = el('span', { class: 'fd-list-count', role: 'status' });\n const clear = el('button', { type: 'button', class: 'fd-button fd-button-link' }, labels.clearSelection);\n const buttons = (node.actions ?? []).map((action: ButtonNode) => {\n const button = el('button', { type: 'button', class: `fd-button fd-button-${action.style ?? 'secondary'}`, 'data-node': action.id }, ...context.withIcon(action.icon, action.label));\n button.addEventListener('click', async () => {\n if (action.confirm && !(await context.confirm(action.confirm))) return;\n await form.runAction(action.id, { recordIds: [...chosen] });\n await load();\n });\n return button;\n });\n const selection = el('div', { class: 'fd-list-selection', hidden: '' }, count, ...buttons, clear);\n clear.addEventListener('click', () => {\n chosen.clear();\n for (const box of body.querySelectorAll<HTMLInputElement>('.fd-list-checkbox')) box.checked = false;\n drawChoice();\n });\n chooseAll.addEventListener('change', () => {\n for (const record of visible()) {\n if (chooseAll.checked) chosen.add(record.id);\n else chosen.delete(record.id);\n }\n for (const box of body.querySelectorAll<HTMLInputElement>('.fd-list-checkbox')) box.checked = chooseAll.checked;\n drawChoice();\n });\n\n function drawChoice() {\n const shown = visible();\n const onPage = shown.filter((record) => chosen.has(record.id)).length;\n chooseAll.checked = shown.length > 0 && onPage === shown.length;\n chooseAll.indeterminate = onPage > 0 && onPage < shown.length;\n selection.hidden = chosen.size === 0;\n count.textContent = fill(labels.selected, { n: chosen.size });\n for (const tr of body.querySelectorAll<HTMLElement>('.fd-list-row')) {\n tr.setAttribute('aria-selected', String([...chosen].some((id) => String(id) === tr.dataset['id'])));\n }\n }\n\n // ---- pages -------------------------------------------------------------------\n\n const range = el('span', { class: 'fd-pager-text' });\n const previous = el('button', { type: 'button', class: 'fd-button fd-pager-button', 'aria-label': labels.previousPage }, '\u2039');\n const next = el('button', { type: 'button', class: 'fd-button fd-pager-button', 'aria-label': labels.nextPage }, '\u203A');\n const pager = el('div', { class: 'fd-pager', role: 'group' }, range, previous, next);\n previous.addEventListener('click', () => {\n offset = Math.max(0, offset - pageSize);\n void load();\n });\n next.addEventListener('click', () => {\n offset += pageSize;\n void load();\n });\n\n function drawPager() {\n pager.hidden = total === 0;\n range.textContent = fill(labels.range, { from: offset + 1, to: Math.min(offset + rows.length, total), total });\n previous.disabled = offset === 0;\n next.disabled = offset + pageSize >= total;\n }\n\n function drawSort() {\n for (const th of headers) {\n const order = sort[0]?.field === th.dataset['field'] ? sort[0] : null;\n if (order) th.setAttribute('aria-sort', order.desc ? 'descending' : 'ascending');\n else th.removeAttribute('aria-sort');\n }\n }\n\n // ---- asking for the records ------------------------------------------------------\n\n /** Rows came or went: what is chosen keeps to the records on show. */\n function changed() {\n const shown = new Set(visible().map((record) => record.id));\n for (const id of [...chosen]) if (!shown.has(id)) chosen.delete(id);\n drawChoice();\n }\n\n const grouped = (source: DataSource): GroupContext => ({\n page,\n el,\n labels,\n fill,\n dataSource: source,\n model,\n fields,\n columns: node.columns.length + 1,\n pageSize,\n sort: () => sort,\n recordRow: row,\n changed,\n });\n\n async function load(): Promise<void> {\n const mine = ++asking;\n drawSort();\n table.setAttribute('aria-busy', 'true');\n let drawn: HTMLTableRowElement[] = [];\n try {\n const filter = facetsToFilter(facets, node);\n const grouping = groupByFields(facets);\n const source = context.dataSource;\n if (grouping.length && source?.groups && source.list) {\n // Grouped: a row for each value of the first field, each opening into the rest.\n const groups = await source.groups({ model, field: grouping[0], filter });\n if (mine !== asking || destroyed) return;\n rows = [];\n total = 0;\n drawn = groups.map((group) => groupRow(grouped(source), group, 0, filter, grouping));\n } else {\n const answer = source?.list ? await source.list({ model, fields, filter, sort, offset, limit: pageSize }) : { records: [], total: 0 };\n if (mine !== asking || destroyed) return;\n // Past the end, as when the last record of the last page went: back to the page that is left.\n if (!answer.records.length && answer.total > 0 && offset > 0) {\n offset = Math.floor((answer.total - 1) / pageSize) * pageSize;\n return load();\n }\n rows = answer.records;\n total = answer.total;\n drawn = rows.map((record) => row(record));\n }\n failed.hidden = true;\n } catch {\n if (mine !== asking || destroyed) return;\n rows = [];\n total = 0;\n failed.hidden = false;\n }\n body.replaceChildren(...drawn);\n empty.hidden = drawn.length > 0 || !failed.hidden;\n table.removeAttribute('aria-busy');\n drawPager();\n changed();\n }\n\n const search = searchBar({\n page,\n node,\n doc,\n el,\n labels,\n fill,\n uid: context.uid,\n icons: context.icons,\n preferences: context.preferences,\n facets,\n onChange(next) {\n facets = next;\n offset = 0;\n void load();\n },\n });\n const element = el(\n 'div',\n { class: 'fd-list', 'data-node': node.id },\n el('div', { class: 'fd-list-bar' }, search.element, pager),\n selection,\n el('div', { class: 'fd-list-scroll' }, table),\n empty,\n failed\n );\n void load();\n\n return {\n element,\n reload: load,\n destroy() {\n destroyed = true;\n search.destroy();\n },\n };\n}\n", "import type { Locale } from '@fieldia/core';\n\n/** Every word the viewer shows, so a page can be translated. `{n}`, `{total}` and `{time}` are filled in. */\nexport interface ViewerLabels {\n save: string;\n /** Switching a read-only form to editing, and back. */\n edit: string;\n done: string;\n discard: string;\n saving: string;\n saved: string;\n submit: string;\n next: string;\n back: string;\n /** Passing over an optional step. */\n skip: string;\n /** The list of a wizard's steps, for screen readers. */\n steps: string;\n stepOf: string;\n submitted: string;\n submitAnother: string;\n draftFound: string;\n restore: string;\n discardDraft: string;\n ok: string;\n cancel: string;\n loading: string;\n /** A form in a dialog: the button that saves it and closes the dialog, and the \u00D7 that closes it. */\n saveClose: string;\n close: string;\n /** The \u00D7 on an alert that may be dismissed. */\n dismiss: string;\n /** Saving again after a save failed. */\n retry: string;\n notSaved: string;\n notSent: string;\n /** What was not saved or sent, and the fields to look at. */\n checkFields: string;\n /** The banner when the server cannot be reached. */\n offline: string;\n /** A list: its pages (`{from}`, `{to}`, `{total}`), what is chosen in it, and an empty one. */\n previousPage: string;\n nextPage: string;\n range: string;\n selected: string;\n clearSelection: string;\n selectAll: string;\n selectRecord: string;\n noRecords: string;\n loadFailed: string;\n /**\n * A list's search bar: the box (`{field}` and `{text}` in a suggestion), its\n * chips (`{label}`), the Filters, Group By and Favourites menu (`{name}`),\n * and the conditions a custom filter offers.\n */\n search: string;\n searchLabel: string;\n searchFor: string;\n searchOptions: string;\n filters: string;\n groupBy: string;\n favourites: string;\n or: string;\n removeFacet: string;\n addCustomFilter: string;\n field: string;\n condition: string;\n value: string;\n apply: string;\n saveSearch: string;\n searchName: string;\n useByDefault: string;\n deleteFavourite: string;\n noFavourites: string;\n opIs: string;\n opIsNot: string;\n opContains: string;\n opGreater: string;\n opLess: string;\n opSet: string;\n opNotSet: string;\n yes: string;\n no: string;\n /** A list's groups: the one of records with no value, and the rest of a group's records (`{n}`). */\n none: string;\n loadMore: string;\n}\n\nexport const VIEWER_LABELS: Record<Locale, ViewerLabels> = {\n en: {\n save: 'Save',\n edit: 'Edit',\n done: 'Done',\n discard: 'Discard',\n saving: 'Saving\u2026',\n saved: 'Saved',\n submit: 'Submit',\n next: 'Next',\n back: 'Back',\n skip: 'Skip',\n steps: 'Steps',\n stepOf: 'Step {n} of {total}',\n submitted: 'Thank you. Your answers were sent.',\n submitAnother: 'Submit another response',\n draftFound: 'You have unsaved answers from {time}.',\n restore: 'Restore',\n discardDraft: 'Discard',\n ok: 'OK',\n cancel: 'Cancel',\n loading: 'Loading\u2026',\n saveClose: 'Save & Close',\n close: 'Close',\n dismiss: 'Dismiss',\n retry: 'Retry',\n notSaved: 'Not saved',\n notSent: 'Not sent',\n checkFields: '{what}. Check: {fields}',\n offline: 'Could not reach the server. Your changes are still here.',\n previousPage: 'Previous page',\n nextPage: 'Next page',\n range: '{from}\u2013{to} / {total}',\n selected: '{n} selected',\n clearSelection: 'Clear',\n selectAll: 'Select all',\n selectRecord: 'Select {name}',\n noRecords: 'No records match.',\n loadFailed: 'Could not load the records.',\n search: 'Search\u2026',\n searchLabel: 'Search',\n searchFor: 'Search {field} for: {text}',\n searchOptions: 'Search options',\n filters: 'Filters',\n groupBy: 'Group By',\n favourites: 'Favourites',\n or: 'or',\n removeFacet: 'Remove {label}',\n addCustomFilter: 'Add a custom filter',\n field: 'Field',\n condition: 'Condition',\n value: 'Value',\n apply: 'Apply',\n saveSearch: 'Save current search',\n searchName: 'Name of the search',\n useByDefault: 'Use by default',\n deleteFavourite: 'Delete {name}',\n noFavourites: 'No saved searches yet.',\n opIs: 'is',\n opIsNot: 'is not',\n opContains: 'contains',\n opGreater: 'greater than',\n opLess: 'less than',\n opSet: 'is set',\n opNotSet: 'is not set',\n yes: 'Yes',\n no: 'No',\n none: 'None',\n loadMore: 'Show {n} more',\n },\n ar: {\n save: '\u062D\u0641\u0638',\n edit: '\u062A\u0639\u062F\u064A\u0644',\n done: '\u062A\u0645',\n discard: '\u062A\u062C\u0627\u0647\u0644',\n saving: '\u062C\u0627\u0631\u064D \u0627\u0644\u062D\u0641\u0638\u2026',\n saved: '\u062A\u0645 \u0627\u0644\u062D\u0641\u0638',\n submit: '\u0625\u0631\u0633\u0627\u0644',\n next: '\u0627\u0644\u062A\u0627\u0644\u064A',\n back: '\u0631\u062C\u0648\u0639',\n skip: '\u062A\u062E\u0637\u064D\u0651',\n steps: '\u0627\u0644\u062E\u0637\u0648\u0627\u062A',\n stepOf: '\u0627\u0644\u062E\u0637\u0648\u0629 {n} \u0645\u0646 {total}',\n submitted: '\u0634\u0643\u0631\u064B\u0627 \u0644\u0643. \u062A\u0645 \u0625\u0631\u0633\u0627\u0644 \u0625\u062C\u0627\u0628\u0627\u062A\u0643.',\n submitAnother: '\u0625\u0631\u0633\u0627\u0644 \u0625\u062C\u0627\u0628\u0629 \u0623\u062E\u0631\u0649',\n draftFound: '\u0644\u062F\u064A\u0643 \u0625\u062C\u0627\u0628\u0627\u062A \u063A\u064A\u0631 \u0645\u062D\u0641\u0648\u0638\u0629 \u0645\u0646 {time}.',\n restore: '\u0627\u0633\u062A\u0639\u0627\u062F\u0629',\n discardDraft: '\u062A\u062C\u0627\u0647\u0644',\n ok: '\u0645\u0648\u0627\u0641\u0642',\n cancel: '\u0625\u0644\u063A\u0627\u0621',\n loading: '\u062C\u0627\u0631\u064D \u0627\u0644\u062A\u062D\u0645\u064A\u0644\u2026',\n saveClose: '\u062D\u0641\u0638 \u0648\u0625\u063A\u0644\u0627\u0642',\n close: '\u0625\u063A\u0644\u0627\u0642',\n dismiss: '\u0625\u062E\u0641\u0627\u0621',\n retry: '\u0623\u0639\u062F \u0627\u0644\u0645\u062D\u0627\u0648\u0644\u0629',\n notSaved: '\u0644\u0645 \u064A\u064F\u062D\u0641\u0638',\n notSent: '\u0644\u0645 \u064A\u064F\u0631\u0633\u0644',\n checkFields: '{what}. \u0631\u0627\u062C\u0650\u0639: {fields}',\n offline: '\u062A\u0639\u0630\u0651\u0631 \u0627\u0644\u0648\u0635\u0648\u0644 \u0625\u0644\u0649 \u0627\u0644\u062E\u0627\u062F\u0645. \u062A\u0639\u062F\u064A\u0644\u0627\u062A\u0643 \u0645\u0627 \u0632\u0627\u0644\u062A \u0647\u0646\u0627.',\n previousPage: '\u0627\u0644\u0635\u0641\u062D\u0629 \u0627\u0644\u0633\u0627\u0628\u0642\u0629',\n nextPage: '\u0627\u0644\u0635\u0641\u062D\u0629 \u0627\u0644\u062A\u0627\u0644\u064A\u0629',\n range: '{from}\u2013{to} \u0645\u0646 {total}',\n selected: '\u062A\u0645 \u062A\u062D\u062F\u064A\u062F {n}',\n clearSelection: '\u0625\u0644\u063A\u0627\u0621 \u0627\u0644\u062A\u062D\u062F\u064A\u062F',\n selectAll: '\u062A\u062D\u062F\u064A\u062F \u0627\u0644\u0643\u0644',\n selectRecord: '\u062A\u062D\u062F\u064A\u062F {name}',\n noRecords: '\u0644\u0627 \u062A\u0648\u062C\u062F \u0633\u062C\u0644\u0627\u062A \u0645\u0637\u0627\u0628\u0642\u0629.',\n loadFailed: '\u062A\u0639\u0630\u0651\u0631 \u062A\u062D\u0645\u064A\u0644 \u0627\u0644\u0633\u062C\u0644\u0627\u062A.',\n search: '\u0628\u062D\u062B\u2026',\n searchLabel: '\u0628\u062D\u062B',\n searchFor: '\u0627\u0628\u062D\u062B \u0641\u064A {field} \u0639\u0646: {text}',\n searchOptions: '\u062E\u064A\u0627\u0631\u0627\u062A \u0627\u0644\u0628\u062D\u062B',\n filters: '\u0639\u0648\u0627\u0645\u0644 \u0627\u0644\u062A\u0635\u0641\u064A\u0629',\n groupBy: '\u062A\u062C\u0645\u064A\u0639 \u062D\u0633\u0628',\n favourites: '\u0627\u0644\u0645\u0641\u0636\u0644\u0629',\n or: '\u0623\u0648',\n removeFacet: '\u0625\u0632\u0627\u0644\u0629 {label}',\n addCustomFilter: '\u0625\u0636\u0627\u0641\u0629 \u0639\u0627\u0645\u0644 \u062A\u0635\u0641\u064A\u0629 \u0645\u062E\u0635\u0635',\n field: '\u0627\u0644\u062D\u0642\u0644',\n condition: '\u0627\u0644\u0634\u0631\u0637',\n value: '\u0627\u0644\u0642\u064A\u0645\u0629',\n apply: '\u062A\u0637\u0628\u064A\u0642',\n saveSearch: '\u062D\u0641\u0638 \u0627\u0644\u0628\u062D\u062B \u0627\u0644\u062D\u0627\u0644\u064A',\n searchName: '\u0627\u0633\u0645 \u0627\u0644\u0628\u062D\u062B',\n useByDefault: '\u0627\u0633\u062A\u062E\u062F\u0627\u0645\u0647 \u0627\u0641\u062A\u0631\u0627\u0636\u064A\u064B\u0627',\n deleteFavourite: '\u062D\u0630\u0641 {name}',\n noFavourites: '\u0644\u0627 \u062A\u0648\u062C\u062F \u0639\u0645\u0644\u064A\u0627\u062A \u0628\u062D\u062B \u0645\u062D\u0641\u0648\u0638\u0629 \u0628\u0639\u062F.',\n opIs: '\u064A\u0633\u0627\u0648\u064A',\n opIsNot: '\u0644\u0627 \u064A\u0633\u0627\u0648\u064A',\n opContains: '\u064A\u062D\u062A\u0648\u064A \u0639\u0644\u0649',\n opGreater: '\u0623\u0643\u0628\u0631 \u0645\u0646',\n opLess: '\u0623\u0635\u063A\u0631 \u0645\u0646',\n opSet: '\u0645\u062D\u062F\u062F',\n opNotSet: '\u063A\u064A\u0631 \u0645\u062D\u062F\u062F',\n yes: '\u0646\u0639\u0645',\n no: '\u0644\u0627',\n none: '\u0628\u0644\u0627 \u0642\u064A\u0645\u0629',\n loadMore: '\u0639\u0631\u0636 {n} \u0623\u062E\u0631\u0649',\n },\n de: {\n save: 'Speichern',\n edit: 'Bearbeiten',\n done: 'Fertig',\n discard: 'Verwerfen',\n saving: 'Wird gespeichert\u2026',\n saved: 'Gespeichert',\n submit: 'Absenden',\n next: 'Weiter',\n back: 'Zur\u00FCck',\n skip: '\u00DCberspringen',\n steps: 'Schritte',\n stepOf: 'Schritt {n} von {total}',\n submitted: 'Vielen Dank. Ihre Antworten wurden gesendet.',\n submitAnother: 'Weitere Antwort senden',\n draftFound: 'Sie haben ungespeicherte Antworten vom {time}.',\n restore: 'Wiederherstellen',\n discardDraft: 'Verwerfen',\n ok: 'OK',\n cancel: 'Abbrechen',\n loading: 'Wird geladen\u2026',\n saveClose: 'Speichern und schlie\u00DFen',\n close: 'Schlie\u00DFen',\n dismiss: 'Ausblenden',\n retry: 'Erneut versuchen',\n notSaved: 'Nicht gespeichert',\n notSent: 'Nicht gesendet',\n checkFields: '{what}. Bitte pr\u00FCfen: {fields}',\n offline: 'Der Server ist nicht erreichbar. Ihre \u00C4nderungen sind noch da.',\n previousPage: 'Vorherige Seite',\n nextPage: 'N\u00E4chste Seite',\n range: '{from}\u2013{to} / {total}',\n selected: '{n} ausgew\u00E4hlt',\n clearSelection: 'Auswahl aufheben',\n selectAll: 'Alle ausw\u00E4hlen',\n selectRecord: '{name} ausw\u00E4hlen',\n noRecords: 'Keine passenden Eintr\u00E4ge.',\n loadFailed: 'Die Eintr\u00E4ge konnten nicht geladen werden.',\n search: 'Suchen\u2026',\n searchLabel: 'Suchen',\n searchFor: '{field} durchsuchen nach: {text}',\n searchOptions: 'Suchoptionen',\n filters: 'Filter',\n groupBy: 'Gruppieren nach',\n favourites: 'Favoriten',\n or: 'oder',\n removeFacet: '{label} entfernen',\n addCustomFilter: 'Eigenen Filter hinzuf\u00FCgen',\n field: 'Feld',\n condition: 'Bedingung',\n value: 'Wert',\n apply: 'Anwenden',\n saveSearch: 'Aktuelle Suche speichern',\n searchName: 'Name der Suche',\n useByDefault: 'Standardm\u00E4\u00DFig verwenden',\n deleteFavourite: '{name} l\u00F6schen',\n noFavourites: 'Noch keine gespeicherten Suchen.',\n opIs: 'ist',\n opIsNot: 'ist nicht',\n opContains: 'enth\u00E4lt',\n opGreater: 'gr\u00F6\u00DFer als',\n opLess: 'kleiner als',\n opSet: 'ist gesetzt',\n opNotSet: 'ist nicht gesetzt',\n yes: 'Ja',\n no: 'Nein',\n none: 'Ohne Angabe',\n loadMore: '{n} weitere anzeigen',\n },\n fr: {\n save: 'Enregistrer',\n edit: 'Modifier',\n done: 'Termin\u00E9',\n discard: 'Annuler les modifications',\n saving: 'Enregistrement\u2026',\n saved: 'Enregistr\u00E9',\n submit: 'Envoyer',\n next: 'Suivant',\n back: 'Retour',\n skip: 'Passer',\n steps: '\u00C9tapes',\n stepOf: '\u00C9tape {n} sur {total}',\n submitted: 'Merci. Vos r\u00E9ponses ont \u00E9t\u00E9 envoy\u00E9es.',\n submitAnother: 'Envoyer une autre r\u00E9ponse',\n draftFound: 'Vous avez des r\u00E9ponses non enregistr\u00E9es du {time}.',\n restore: 'Restaurer',\n discardDraft: 'Ignorer',\n ok: 'OK',\n cancel: 'Annuler',\n loading: 'Chargement\u2026',\n saveClose: 'Enregistrer et fermer',\n close: 'Fermer',\n dismiss: 'Masquer',\n retry: 'R\u00E9essayer',\n notSaved: 'Non enregistr\u00E9',\n notSent: 'Non envoy\u00E9',\n checkFields: '{what}. \u00C0 v\u00E9rifier : {fields}',\n offline: 'Le serveur est injoignable. Vos modifications sont toujours l\u00E0.',\n previousPage: 'Page pr\u00E9c\u00E9dente',\n nextPage: 'Page suivante',\n range: '{from}\u2013{to} / {total}',\n selected: '{n} s\u00E9lectionn\u00E9(s)',\n clearSelection: 'D\u00E9s\u00E9lectionner',\n selectAll: 'Tout s\u00E9lectionner',\n selectRecord: 'S\u00E9lectionner {name}',\n noRecords: 'Aucun enregistrement ne correspond.',\n loadFailed: 'Impossible de charger les enregistrements.',\n search: 'Rechercher\u2026',\n searchLabel: 'Rechercher',\n searchFor: 'Rechercher {field} : {text}',\n searchOptions: 'Options de recherche',\n filters: 'Filtres',\n groupBy: 'Regrouper par',\n favourites: 'Favoris',\n or: 'ou',\n removeFacet: 'Retirer {label}',\n addCustomFilter: 'Ajouter un filtre personnalis\u00E9',\n field: 'Champ',\n condition: 'Condition',\n value: 'Valeur',\n apply: 'Appliquer',\n saveSearch: 'Enregistrer la recherche',\n searchName: 'Nom de la recherche',\n useByDefault: 'Utiliser par d\u00E9faut',\n deleteFavourite: 'Supprimer {name}',\n noFavourites: 'Aucune recherche enregistr\u00E9e.',\n opIs: 'est',\n opIsNot: 'n\u2019est pas',\n opContains: 'contient',\n opGreater: 'sup\u00E9rieur \u00E0',\n opLess: 'inf\u00E9rieur \u00E0',\n opSet: 'est d\u00E9fini',\n opNotSet: 'n\u2019est pas d\u00E9fini',\n yes: 'Oui',\n no: 'Non',\n none: 'Aucun',\n loadMore: 'Afficher {n} de plus',\n },\n};\n\n/** English, kept under its old name. */\nexport const DEFAULT_LABELS: ViewerLabels = VIEWER_LABELS.en;\n", "import {\n createForm,\n checkPage,\n translatePage,\n wideColumns,\n type ButtonNode,\n type FieldNode,\n type Form,\n type FormOptions,\n type FormState,\n type JsonValue,\n type LayoutNode,\n type Page,\n type RecordId,\n type SectionNode,\n type SheetNode,\n type SlotNode,\n type TabsNode,\n type TextNode,\n type WizardNode,\n type Locale,\n MESSAGES,\n} from '@fieldia/core';\nimport { browserPreferences, createWidget, drawIcon, installStyles, WIDGET_LABELS, type IconSet, type PreferenceStore, type WidgetFactory } from '@fieldia/widgets';\nimport { pageDialogs } from './related';\nimport { listView } from './list';\n\nexport type Skin = 'underline' | 'outlined';\n\nimport { VIEWER_LABELS, type ViewerLabels } from './labels';\nexport { VIEWER_LABELS, DEFAULT_LABELS, type ViewerLabels } from './labels';\n\n/** Fill a slot with the app's own content. Return a function to clean up. */\nexport type SlotRenderer = (element: HTMLElement, context: { form: Form; name: string }) => void | (() => void);\n\nexport interface ViewerOptions extends Omit<FormOptions, 'page'> {\n page: Page;\n /** A form made elsewhere, to share one record between two views. */\n form?: Form;\n skin?: Skin;\n /** Widgets that replace or add to the built-in ones, by `type` or `type.widget`. */\n widgets?: Record<string, WidgetFactory>;\n slots?: Record<string, SlotRenderer>;\n /** The page's language: viewer labels, validation messages and widget words. Arabic runs right to left. */\n locale?: Locale;\n /** Labels that win over the language's defaults. */\n labels?: Partial<ViewerLabels>;\n dir?: 'ltr' | 'rtl';\n /** How to ask before a button with `confirm` runs. Defaults to a small dialog. */\n confirm?: (message: string) => Promise<boolean>;\n /** Where a person's choices about the page's look are kept, such as a table's columns. The browser's storage by default. */\n preferences?: PreferenceStore;\n /** False when something around the page saves it, such as a dialog: the page's own Save, Discard and Submit stay hidden. */\n showActions?: boolean;\n /**\n * Pages for the models links point to, so a link can show its record in a\n * dialog: Create and edit\u2026, and the button that opens the linked record.\n */\n relatedPages?: Record<string, Page> | ((model: string) => Page | null | undefined);\n /**\n * The app's own icons, or replacements for Fieldia's, by the name a page\n * gives them: the inside of a 24\u00D724 SVG, drawn with lines in the text colour.\n */\n icons?: IconSet;\n /**\n * Keys around the fields. Ctrl+Enter (Cmd+Enter on a Mac) saves, from\n * wherever the cursor is, unless `saveWithCtrlEnter` is false. With\n * `enterMovesToNext`, Enter moves to the next field instead of sending the form.\n */\n keys?: { saveWithCtrlEnter?: boolean; enterMovesToNext?: boolean };\n /** A \u2713 by a field's label once someone has filled it in and it would pass its checks. */\n showValid?: boolean;\n /** Where a save's progress shows: beside Save (the default), as a toast in a corner, or as a bar across the top. */\n saveStatus?: 'inline' | 'toast' | 'bar';\n /** Show the whole form read-only: every field locked, no Save. Buttons still run. */\n readonly?: boolean;\n /** An Edit button that unlocks a read-only form, and a Done that saves and locks it again. */\n editSwitch?: boolean;\n /**\n * The app's own translator, for apps that keep translations by text or by\n * key: every word of the page goes through it. Record data never does.\n */\n translate?: (text: string) => string;\n /** A list page: a row was opened, by a click or by Enter. The app shows the record. */\n onOpenRecord?: (id: RecordId) => void;\n}\n\nexport interface ViewerHandle {\n readonly form: Form;\n readonly element: HTMLElement;\n setSkin(skin: Skin): void;\n /** Save the record, or take the focus to the first problem when the form refuses. */\n save(): Promise<boolean>;\n /** Check the form without saving, taking the focus to the first problem. */\n check(): boolean;\n /** Lock or unlock the whole form. */\n setReadonly(readonly: boolean): void;\n isReadonly(): boolean;\n destroy(): void;\n}\n\ntype Updater = (state: FormState) => void;\n\nlet mounts = 0;\n\n/**\n * Render a page into `host` and keep it in step with its form. Plain DOM: the\n * React, Angular and Vue bindings are thin shells around this function.\n * Throws when the page does not validate, listing every problem.\n */\nexport function mountViewer(host: HTMLElement, options: ViewerOptions): ViewerHandle {\n const doc = host.ownerDocument;\n // The quick check of names and conditions: the full one, with its validation library, belongs where pages are made.\n const checked = checkPage(options.page);\n if (!checked.ok) {\n throw new Error(`This page cannot be shown:\\n${checked.issues.map((i) => ` ${i.path}: ${i.message}`).join('\\n')}`);\n }\n const page = options.translate ? translatePage(checked.page, options.translate) : checked.page;\n const locale = options.locale ?? 'en';\n const preferences = options.preferences ?? browserPreferences();\n const dialogs = pageDialogs(options);\n const ownsForm = !options.form;\n const form = options.form ?? createForm({ ...options, page, messages: options.messages ?? MESSAGES[locale] });\n const labels: ViewerLabels = { ...VIEWER_LABELS[locale], ...options.labels };\n const widgetLabels = WIDGET_LABELS[locale];\n const dir = options.dir ?? (locale === 'ar' ? 'rtl' : undefined);\n const prefix = `fd${++mounts}`;\n const updaters: Updater[] = [];\n const cleanups: (() => void)[] = [];\n const uid = (id: string) => `${prefix}-${id.replace(/[^A-Za-z0-9_-]/g, '_')}`;\n const fill = (template: string, values: Record<string, string | number>) =>\n template.replace(/\\{(\\w+)\\}/g, (_, key: string) => String(values[key] ?? ''));\n\n installStyles(doc);\n\n function el<K extends keyof HTMLElementTagNameMap>(tag: K, attrs: Record<string, string | undefined> = {}, ...children: (Node | string)[]) {\n const node = doc.createElement(tag);\n for (const [name, value] of Object.entries(attrs)) if (value !== undefined) node.setAttribute(name, value);\n node.append(...children);\n return node;\n }\n\n /** Words with the icon a page names before them, when there is such an icon. */\n function withIcon(name: string | undefined, text: string): (Node | string)[] {\n const icon = drawIcon(doc, name, options.icons);\n return icon ? [icon, text] : [text];\n }\n\n const root = el('form', { class: 'fd-form', novalidate: '', 'data-fd-skin': options.skin ?? 'underline', dir, lang: options.locale, 'data-max-width': page.maxWidth });\n const confirm = options.confirm ?? dialogConfirm;\n\n // ---- the parts -------------------------------------------------------\n\n function fieldItem(node: FieldNode): HTMLElement {\n const def = page.fields[node.field];\n const id = uid(node.id);\n const wrapper = el('div', { class: 'fd-field', 'data-node': node.id, 'data-field': node.field, 'data-type': def.type });\n if (node.colspan) wrapper.style.setProperty('--fd-span', String(node.colspan));\n const label = el('label', { class: 'fd-label', id: `${id}-label`, for: id }, node.label ?? def.label);\n // The \u2713 of a field filled in right; never on a yes/no box, a table or a file, where it would say nothing.\n const mark = options.showValid && !NO_VALID_MARK.has(def.type) ? drawIcon(doc, 'check') : null;\n if (mark) {\n mark.classList.add('fd-valid-mark');\n label.append(mark);\n }\n const widget = createWidget({ form, name: node.field, field: def, node, id, document: doc, labels: widgetLabels, preferences, locale, dialogs }, options.widgets);\n if (!['INPUT', 'SELECT', 'TEXTAREA'].includes(widget.element.tagName)) {\n // `for` stays: a custom field that puts the id on its own input is\n // labelled natively. Only a wrapper with a role (a radio group, say) may\n // carry a name; ARIA forbids naming a plain div or span.\n if (widget.element.getAttribute('role')) widget.element.setAttribute('aria-labelledby', label.id);\n label.addEventListener('click', () => widget.focus());\n }\n const helpText = node.help ?? def.help;\n const help = helpText ? el('div', { class: 'fd-help', id: `${id}-help` }, helpText) : null;\n // Not an alert of its own: a refused save is announced once, naming every field to look at.\n const error = el('div', { class: 'fd-error', id: `${id}-error`, hidden: '' });\n // A warning from the data source's onchange, beside the field whose change brought it.\n const warning = el('div', { class: 'fd-warning', role: 'status', hidden: '' });\n wrapper.append(label, widget.element, ...(help ? [help] : []), error, warning);\n if (widget.destroy) cleanups.push(() => widget.destroy?.());\n\n updaters.push((state) => {\n const shown = form.node(node.id);\n wrapper.hidden = shown.invisible;\n wrapper.classList.toggle('fd-required', shown.required);\n const message = state.errors[node.field];\n error.hidden = !message;\n error.textContent = message ?? '';\n const warned = state.warning && state.warningField === node.field ? state.warning : '';\n warning.hidden = !warned;\n warning.textContent = warned;\n if (mark) {\n const value = state.values[node.field];\n const filled = value !== null && value !== undefined && value !== '' && !(Array.isArray(value) && !value.length);\n const valid = !shown.readonly && !message && filled && state.dirty.includes(node.field) && form.problem(node.field) === null;\n wrapper.classList.toggle('fd-valid', valid);\n mark.toggleAttribute('hidden', !valid);\n }\n widget.update({\n value: state.values[node.field],\n values: state.values,\n readonly: shown.readonly || locked,\n required: shown.required,\n invalid: !!message,\n describedBy: [help?.id, message ? error.id : undefined].filter(Boolean).join(' ') || undefined,\n });\n });\n return wrapper;\n }\n\n function hideWhen(element: HTMLElement, id: string) {\n updaters.push(() => {\n element.hidden = form.node(id).invisible;\n });\n }\n\n function buttonItem(node: ButtonNode): HTMLElement {\n const button = el('button', { type: 'button', class: `fd-button fd-button-${node.style ?? 'secondary'}`, 'data-node': node.id }, ...withIcon(node.icon, node.label));\n button.addEventListener('click', async () => {\n if (node.confirm && !(await confirm(node.confirm))) return;\n await form.runAction(node.id);\n });\n hideWhen(button, node.id);\n return button;\n }\n\n function textItem(node: TextNode): HTMLElement {\n const style = node.style ?? 'paragraph';\n const element = el(style === 'heading' ? 'h3' : 'p', { class: `fd-text-${style}`, 'data-node': node.id }, node.text);\n hideWhen(element, node.id);\n return element;\n }\n\n function slotItem(node: SlotNode): HTMLElement {\n const element = el('div', { class: 'fd-slot', 'data-slot': node.name, 'data-node': node.id });\n const cleanup = options.slots?.[node.name]?.(element, { form, name: node.name });\n if (cleanup) cleanups.push(cleanup);\n hideWhen(element, node.id);\n return element;\n }\n\n function grid(children: LayoutNode[], columns: SectionNode['columns'] = 1): HTMLElement {\n const box = el('div', { class: 'fd-grid' });\n box.style.setProperty('--fd-columns', String(wideColumns(columns)));\n // Counts given for the narrower widths replace the skin's own stacking there.\n if (typeof columns === 'object') {\n for (const width of ['medium', 'narrow'] as const) {\n const count = columns[width];\n if (count === undefined) continue;\n box.setAttribute(`data-columns-${width}`, String(count));\n box.style.setProperty(`--fd-columns-${width}`, String(count));\n }\n }\n box.append(...children.map(item));\n return box;\n }\n\n /** Folded sections, and how to open each: a problem inside one has to be seen. */\n const folds = new Map<HTMLElement, () => void>();\n\n function sectionItem(node: SectionNode): HTMLElement {\n const section = el('fieldset', { class: 'fd-section', 'data-node': node.id });\n const description = node.description ? el('p', { class: 'fd-section-description' }, node.description) : null;\n const content = grid(node.children, node.columns);\n if (node.title && node.collapsible) {\n content.id = uid(`${node.id}-content`);\n const toggle = el(\n 'button',\n { type: 'button', class: 'fd-section-toggle', 'aria-controls': content.id },\n el('span', { class: 'fd-section-chevron', 'aria-hidden': 'true' }),\n ...withIcon(node.icon, node.title)\n );\n let open = node.collapsed !== true;\n const show = (next: boolean) => {\n open = next;\n toggle.setAttribute('aria-expanded', String(open));\n content.hidden = !open;\n if (description) description.hidden = !open;\n section.classList.toggle('fd-section-folded', !open);\n };\n toggle.addEventListener('click', () => show(!open));\n folds.set(section, () => show(true));\n show(open);\n section.append(el('legend', { class: 'fd-section-title' }, toggle));\n } else if (node.title) {\n section.append(el('legend', { class: 'fd-section-title' }, ...withIcon(node.icon, node.title)));\n }\n if (description) section.append(description);\n section.append(content);\n hideWhen(section, node.id);\n return section;\n }\n\n function tabsItem(node: TabsNode): HTMLElement {\n const box = el('div', { class: 'fd-tabs', 'data-node': node.id });\n const list = el('div', { class: 'fd-tablist', role: 'tablist' });\n // The tab someone picked. Until they pick, the first visible tab is open \u2014\n // a tab hidden while the record loads must not leave its neighbour open.\n let picked: string | null = null;\n let active = node.children[0].id;\n const parts = node.children.map((tab) => {\n const tabId = uid(`${tab.id}-tab`);\n const panelId = uid(`${tab.id}-panel`);\n const button = el('button', { type: 'button', class: 'fd-tab', role: 'tab', id: tabId, 'aria-controls': panelId, 'data-node': tab.id }, ...withIcon(tab.icon, tab.label));\n const panel = el('div', { class: 'fd-tabpanel', role: 'tabpanel', id: panelId, 'aria-labelledby': tabId }, grid(tab.children));\n button.addEventListener('click', () => {\n picked = active = tab.id;\n render(form.getState());\n });\n list.append(button);\n return { tab, button, panel };\n });\n list.addEventListener('keydown', (event) => {\n const shown = parts.filter((p) => !p.button.hidden);\n const at = shown.findIndex((p) => p.tab.id === active);\n const move = { ArrowRight: 1, ArrowLeft: -1, Home: -at, End: shown.length - 1 - at }[event.key];\n if (move === undefined || at === -1) return;\n event.preventDefault();\n const rtl = root.getAttribute('dir') === 'rtl' && (event.key === 'ArrowRight' || event.key === 'ArrowLeft');\n const next = shown[(at + (rtl ? -move : move) + shown.length) % shown.length];\n picked = active = next.tab.id;\n render(form.getState());\n next.button.focus();\n });\n box.append(list, ...parts.map((p) => p.panel));\n updaters.push(() => {\n box.hidden = form.node(node.id).invisible;\n const shown = parts.filter((p) => !form.node(p.tab.id).invisible);\n const keep = picked !== null && shown.some((p) => p.tab.id === picked);\n if (keep) active = picked as string;\n else if (shown.length) active = shown[0].tab.id;\n for (const p of parts) {\n const selected = p.tab.id === active;\n p.button.hidden = !shown.includes(p);\n p.button.setAttribute('aria-selected', String(selected));\n p.button.tabIndex = selected ? 0 : -1;\n p.panel.hidden = !selected;\n }\n });\n return box;\n }\n\n function item(node: LayoutNode): HTMLElement {\n switch (node.type) {\n case 'field':\n return fieldItem(node);\n case 'button':\n return buttonItem(node);\n case 'text':\n return textItem(node);\n case 'slot':\n return slotItem(node);\n case 'section':\n return sectionItem(node);\n case 'tabs':\n return tabsItem(node);\n }\n }\n\n // ---- shared chrome ----------------------------------------------------------\n\n /** The whole form locked: every field read-only, no Save; buttons still run. */\n let locked = options.readonly === true;\n // Edit unlocks; Done saves what changed first, and locks only once that is saved.\n const editSwitch = options.editSwitch ? el('button', { type: 'button', class: 'fd-button fd-edit-switch' }) : null;\n editSwitch?.addEventListener('click', async () => {\n if (!locked) {\n if (form.getState().dirty.length) {\n const saved = await form.save();\n if (!saved) {\n if (!form.getState().saveProblem) announce(checkText(form.getState()));\n focusFirstProblem();\n return;\n }\n }\n locked = true;\n } else locked = false;\n root.toggleAttribute('data-readonly', locked);\n render(form.getState());\n });\n root.toggleAttribute('data-readonly', locked);\n updaters.push(() => {\n if (!editSwitch) return;\n editSwitch.textContent = locked ? labels.edit : labels.done;\n editSwitch.classList.toggle('fd-button-primary', locked);\n });\n\n // The status says its words alone, so a screen reader hears them; Retry sits beside it.\n const statusText = el('div', { class: 'fd-status', role: 'status', 'aria-live': 'polite' });\n const retry = el('button', { type: 'button', class: 'fd-button fd-button-link fd-retry', hidden: '' }, labels.retry);\n retry.addEventListener('click', () => void submitOrSave());\n const status = el('div', { class: 'fd-status-box' }, statusText, retry);\n const notDone = () => (page.data.kind === 'responses' ? labels.notSent : labels.notSaved);\n /** \"Not saved. Check: Email, Phone\": the fields with a problem, in the order they show. */\n function checkText(state: FormState): string {\n const names: string[] = [];\n for (const key of Object.keys(state.errors)) {\n const field = key.split('.')[0];\n const shown = root.querySelector(`.fd-field[data-field=\"${field}\"]:not([hidden]) > .fd-label`);\n const name = shown?.firstChild?.textContent ?? page.fields[field]?.label ?? field;\n if (!names.includes(name)) names.push(name);\n }\n const inOrder = [...root.querySelectorAll('.fd-field[data-field] > .fd-label')].map((label) => label.firstChild?.textContent ?? '');\n names.sort((a, b) => (inOrder.indexOf(a) + 1 || Infinity) - (inOrder.indexOf(b) + 1 || Infinity));\n return names.length ? fill(labels.checkFields, { what: notDone(), fields: names.join(', ') }) : notDone();\n }\n let quietTimer: ReturnType<typeof setTimeout> | undefined;\n updaters.push((state) => {\n const problem = state.saveProblem;\n const text =\n state.status === 'saving' ? labels.saving\n : state.status === 'saved' ? labels.saved\n : state.status === 'loading' ? labels.loading\n : state.status === 'error' && problem ? (problem.kind === 'fields' ? checkText(state) : problem.kind === 'other' ? problem.message : notDone())\n : state.status === 'error' ? state.error ?? ''\n : '';\n statusText.textContent = text;\n retry.hidden = !(state.status === 'error' && problem?.kind === 'other');\n statusText.classList.toggle('fd-status-error', state.status === 'error');\n statusText.classList.toggle('fd-status-saved', state.status === 'saved');\n // A toast shows while there is something to say, and lets \"Saved\" go after a moment.\n if (options.saveStatus === 'toast') {\n clearTimeout(quietTimer);\n status.hidden = !text;\n if (state.status === 'saved') quietTimer = setTimeout(() => (status.hidden = true), 2500);\n }\n });\n\n // A save the network failed: a banner over the page, with Retry.\n const bannerRetry = el('button', { type: 'button', class: 'fd-button fd-retry' }, labels.retry);\n bannerRetry.addEventListener('click', () => void submitOrSave());\n const banner = el('div', { class: 'fd-banner fd-tone-warning', role: 'alert', hidden: '' }, el('span', { class: 'fd-banner-text' }, labels.offline), bannerRetry);\n /** Said at once to a screen reader: why a save or send did not go through. */\n const announcer = el('div', { class: 'fd-announce', role: 'alert', 'aria-live': 'assertive' });\n function announce(text: string) {\n announcer.textContent = '';\n setTimeout(() => (announcer.textContent = text), 0);\n }\n // Each new reason a save was refused, from Save or from autosave, is shown where it belongs.\n let seenProblem: FormState['saveProblem'] = null;\n updaters.push((state) => {\n if (state.saveProblem === seenProblem) return;\n seenProblem = state.saveProblem;\n banner.hidden = seenProblem?.kind !== 'network';\n if (!seenProblem) return;\n if (seenProblem.kind === 'rule') void dialogConfirm(seenProblem.message, false);\n else if (seenProblem.kind === 'fields') announce(checkText(state));\n else if (seenProblem.kind === 'other') announce(seenProblem.message);\n });\n\n const draft = el('div', { class: 'fd-draft', hidden: '' });\n const draftText = el('span');\n const restore = el('button', { type: 'button', class: 'fd-button fd-button-primary' }, labels.restore);\n const discardDraft = el('button', { type: 'button', class: 'fd-button fd-button-link' }, labels.discardDraft);\n restore.addEventListener('click', () => form.restoreDraft());\n discardDraft.addEventListener('click', () => form.discardDraft());\n draft.append(draftText, restore, discardDraft);\n updaters.push((state) => {\n draft.hidden = !state.draft;\n if (state.draft) draftText.textContent = fill(labels.draftFound, { time: new Date(state.draft.savedAt).toLocaleString() });\n });\n\n function focusFirstProblem() {\n const invalid = root.querySelector<HTMLElement>('[aria-invalid=\"true\"]');\n if (!invalid) return;\n for (let folded = invalid.closest<HTMLElement>('.fd-section-folded'); folded; folded = folded.parentElement?.closest<HTMLElement>('.fd-section-folded') ?? null) {\n folds.get(folded)?.();\n }\n // A widget that knows where its problem is (a cell of a grid) takes the focus there itself.\n if (!invalid.dispatchEvent(new CustomEvent('fd-focus-problem', { cancelable: true }))) return;\n const target = invalid.matches('input, select, textarea, button') ? invalid : invalid.querySelector<HTMLElement>('input, select, textarea, button');\n target?.focus();\n }\n\n const done = el('div', { class: 'fd-done', hidden: '' }, el('p', { class: 'fd-done-title' }, labels.submitted));\n const again = el('button', { type: 'button', class: 'fd-button' }, labels.submitAnother);\n done.append(again);\n const content = el('div', { class: 'fd-content' });\n\n async function submitOrSave() {\n const saved = await form.save();\n if (!saved) {\n // Stopped by the page's own checks: say which fields; a refused save says so above.\n if (!form.getState().saveProblem) announce(checkText(form.getState()));\n focusFirstProblem();\n return;\n }\n if (page.data.kind === 'responses') {\n content.hidden = true;\n done.hidden = false;\n }\n }\n again.addEventListener('click', () => {\n form.reset();\n content.hidden = false;\n done.hidden = true;\n });\n\n function pageHead(): HTMLElement | null {\n if (!page.title && !page.description) return null;\n const head = el('header', { class: 'fd-page-head' });\n if (page.title) head.append(el('h1', { class: 'fd-page-title' }, page.title));\n if (page.description) head.append(el('p', { class: 'fd-page-description' }, page.description));\n return head;\n }\n\n // ---- the four page layouts ---------------------------------------------------\n\n function sectionsLayout(node: { id: string; children: LayoutNode[] }): HTMLElement {\n const box = el('div', { class: 'fd-sections', 'data-node': node.id }, ...node.children.map(item));\n const action = el('button', { type: 'submit', class: 'fd-button fd-button-primary' }, page.data.kind === 'responses' ? labels.submit : labels.save);\n const actions = el('div', { class: 'fd-actions fd-actions-end' }, status, action);\n if (page.data.kind === 'record') {\n // A record offers Save and Discard once something changes, the same as on a sheet.\n const discard = el('button', { type: 'button', class: 'fd-button' }, labels.discard);\n discard.addEventListener('click', () => form.reset());\n actions.insertBefore(discard, action);\n updaters.push((state) => {\n const dirty = state.dirty.length > 0 && state.status !== 'saving' && !locked;\n action.hidden = !dirty;\n discard.hidden = !dirty;\n });\n } else updaters.push(() => (action.hidden = locked));\n if (editSwitch) actions.prepend(editSwitch);\n if (options.showActions === false) return el('div', {}, box);\n if (page.actionsPosition === 'top') {\n actions.classList.add('fd-actions-top');\n return el('div', {}, actions, box);\n }\n return el('div', {}, box, actions);\n }\n\n function wizardLayout(node: WizardNode): HTMLElement {\n const box = el('div', { class: 'fd-wizard', 'data-node': node.id });\n const progressText = el('div', { class: 'fd-progress-text' });\n const bar = el('span');\n box.append(el('div', { class: 'fd-progress' }, progressText, el('div', { class: 'fd-progress-bar' }, bar)));\n // A clickable wizard lists its steps: back to any, forward past those that are complete.\n const list = node.clickable ? el('ol', { class: 'fd-steps-list' }) : null;\n const stepButtons = new Map<string, HTMLButtonElement>();\n if (list) {\n for (const step of node.children) {\n const go = el('button', { type: 'button', class: 'fd-step-link' }, ...withIcon(step.icon, step.label));\n go.addEventListener('click', () => {\n if (form.goTo(step.id)) focusStep();\n else focusFirstProblem();\n });\n stepButtons.set(step.id, go);\n list.append(el('li', {}, go));\n }\n box.append(el('nav', { class: 'fd-steps', 'aria-label': labels.steps }, list));\n }\n const panels = node.children.map((step) => {\n const panel = el('section', { class: 'fd-step', 'data-node': step.id, 'aria-labelledby': uid(`${step.id}-title`) });\n panel.append(el('h2', { class: 'fd-step-title', id: uid(`${step.id}-title`) }, ...withIcon(step.icon, step.label)));\n if (step.description) panel.append(el('p', { class: 'fd-section-description' }, step.description));\n panel.append(grid(step.children));\n box.append(panel);\n return { step, panel };\n });\n const back = el('button', { type: 'button', class: 'fd-button' }, node.backLabel ?? labels.back);\n const skip = el('button', { type: 'button', class: 'fd-button fd-button-link' }, labels.skip);\n const forward = el('button', { type: 'submit', class: 'fd-button fd-button-primary' });\n box.append(el('div', { class: 'fd-wizard-nav' }, back, el('span', { class: 'fd-spacer' }), status, skip, forward));\n back.addEventListener('click', () => {\n if (form.back()) focusStep();\n });\n skip.addEventListener('click', () => {\n if (form.skip()) focusStep();\n });\n const isLast = () => {\n const steps = form.steps();\n return steps.indexOf(form.getState().step ?? '') === steps.length - 1;\n };\n wizardForward = async () => {\n if (isLast()) return submitOrSave();\n if (form.next()) focusStep();\n else focusFirstProblem();\n };\n function focusStep() {\n const current = panels.find((p) => p.step.id === form.getState().step);\n current?.panel.querySelector<HTMLElement>('input, select, textarea, [role=radio]')?.focus();\n }\n updaters.push((state) => {\n const steps = form.steps();\n const index = Math.max(0, steps.indexOf(state.step ?? ''));\n progressText.textContent = fill(labels.stepOf, { n: index + 1, total: steps.length });\n bar.style.width = `${((index + 1) / Math.max(1, steps.length)) * 100}%`;\n for (const { step, panel } of panels) panel.hidden = step.id !== state.step;\n const last = index === steps.length - 1;\n back.hidden = index === 0;\n skip.hidden = last || !node.children.find((step) => step.id === state.step)?.optional;\n forward.textContent = last ? node.finishLabel ?? labels.submit : node.nextLabel ?? labels.next;\n for (const [id, go] of stepButtons) {\n const at = steps.indexOf(id);\n (go.parentElement as HTMLElement).hidden = at === -1;\n go.classList.toggle('fd-step-done', at !== -1 && at < index);\n go.classList.toggle('fd-step-skipped', state.skipped.includes(id));\n if (id === state.step) go.setAttribute('aria-current', 'step');\n else go.removeAttribute('aria-current');\n }\n });\n return box;\n }\n\n function sheetLayout(node: SheetNode): HTMLElement {\n const pageBox = el('div', { class: 'fd-sheet-page', 'data-node': node.id });\n const actions = el('div', { class: 'fd-actions' });\n const save = el('button', { type: 'submit', class: 'fd-button fd-button-primary' }, labels.save);\n const discard = el('button', { type: 'button', class: 'fd-button' }, labels.discard);\n discard.addEventListener('click', () => form.reset());\n // Save and Discard lead the header bar, or close the sheet when the page puts them at its foot.\n const atFoot = page.actionsPosition === 'bottom';\n const foot = el('div', { class: 'fd-actions fd-actions-end fd-sheet-foot' });\n if (options.showActions === false) actions.append(...(node.buttons ?? []).map(buttonItem));\n else if (atFoot) {\n actions.append(...(node.buttons ?? []).map(buttonItem));\n foot.append(status, discard, save);\n } else actions.append(save, discard, ...(node.buttons ?? []).map(buttonItem), status);\n // The Edit switch leads the header bar, before Save and the record's own buttons.\n if (editSwitch && options.showActions !== false) actions.prepend(editSwitch);\n updaters.push((state) => {\n const dirty = state.dirty.length > 0 && state.status !== 'saving' && !locked;\n save.hidden = !dirty;\n discard.hidden = !dirty;\n });\n const header = el('div', { class: 'fd-header' }, actions);\n const underTitle = node.statusbar?.position === 'title';\n if (node.statusbar && !underTitle) header.append(statusbar(node.statusbar));\n\n const card = el('div', { class: 'fd-card' });\n if (node.ribbon) {\n const ribbon = el('div', { class: `fd-ribbon fd-tone-${node.ribbon.tone ?? 'muted'}`, 'data-node': node.ribbon.id }, node.ribbon.label);\n hideWhen(ribbon, node.ribbon.id);\n // The ribbon is clipped to the card's corner by its own frame, so the card itself never clips: lists open past it.\n card.append(el('div', { class: 'fd-ribbon-frame' }, ribbon));\n }\n if (node.statButtons?.length) {\n const stats = el('div', { class: 'fd-stats' });\n for (const stat of node.statButtons) {\n const value = el('span', { class: 'fd-stat-value' });\n const icon = drawIcon(doc, stat.icon, options.icons);\n const words = el('span', { class: 'fd-stat-words' }, value, el('span', { class: 'fd-stat-label' }, stat.label));\n const button = el('button', { type: 'button', class: 'fd-stat', 'data-node': stat.id }, ...(icon ? [icon, words] : [words]));\n button.addEventListener('click', () => void form.runAction(stat.id));\n updaters.push((state) => {\n button.hidden = form.node(stat.id).invisible;\n const count = stat.field ? state.values[stat.field] : null;\n value.textContent = count === null || count === undefined ? '' : String(count);\n });\n stats.append(button);\n }\n card.append(stats);\n }\n for (const alert of node.alerts ?? []) {\n const box = el('div', { class: `fd-alert fd-tone-${alert.tone ?? 'info'}`, role: 'status', 'data-node': alert.id }, el('span', { class: 'fd-alert-message' }, alert.message));\n if (alert.dismissible) {\n // Closed, it stays closed while the page is open, whatever its condition does.\n let dismissed = false;\n const close = el('button', { type: 'button', class: 'fd-alert-close', 'aria-label': labels.dismiss }, '\u00D7');\n close.addEventListener('click', () => {\n dismissed = true;\n box.hidden = true;\n });\n box.append(close);\n updaters.push(() => {\n box.hidden = dismissed || form.node(alert.id).invisible;\n });\n } else hideWhen(box, alert.id);\n card.append(box);\n }\n if (node.badges?.length) {\n const badges = el('div', { class: 'fd-badges' });\n for (const badge of node.badges) {\n const chip = el('span', { class: `fd-badge fd-tone-${badge.tone ?? 'muted'}`, 'data-node': badge.id }, ...withIcon(badge.icon, badge.label));\n hideWhen(chip, badge.id);\n badges.append(chip);\n }\n updaters.push(() => {\n badges.hidden = [...badges.children].every((chip) => (chip as HTMLElement).hidden);\n });\n card.append(badges);\n }\n if (node.title) {\n const title = el('div', { class: 'fd-title' });\n if (node.title.above?.length) title.append(el('div', { class: 'fd-title-above' }, ...node.title.above.map(fieldItem)));\n title.append(fieldItem({ type: 'field', id: '#title', field: node.title.field, placeholder: node.title.placeholder }));\n if (node.title.subtitleField) title.append(fieldItem({ type: 'field', id: '#subtitle', field: node.title.subtitleField }));\n if (node.title.below?.length) title.append(el('div', { class: 'fd-title-below' }, ...node.title.below.map(fieldItem)));\n const row = el('div', { class: 'fd-title-row' }, title);\n if (node.title.avatarField) {\n const avatar = fieldItem({ type: 'field', id: '#avatar', field: node.title.avatarField });\n avatar.classList.add('fd-avatar');\n row.append(avatar);\n }\n card.append(row);\n }\n if (node.statusbar && underTitle) card.append(el('div', { class: 'fd-title-statusbar' }, statusbar(node.statusbar)));\n card.append(grid(node.children));\n if (atFoot && options.showActions !== false) {\n card.append(foot);\n updaters.push((state) => {\n foot.hidden = state.dirty.length === 0 && !statusText.textContent;\n });\n }\n\n const layout = el('div', { class: 'fd-sheet-layout' }, card);\n if (node.sidePanel) {\n layout.classList.add('fd-has-side');\n layout.append(el('aside', { class: 'fd-side' }, slotItem(node.sidePanel)));\n }\n pageBox.append(header, layout);\n return pageBox;\n }\n\n /** The sheet header's statusbar: the same widget a form can place anywhere. */\n function statusbar(config: NonNullable<SheetNode['statusbar']>): HTMLElement {\n const def = page.fields[config.field];\n const barOptions: { [key: string]: JsonValue } = { clickable: config.clickable === true };\n if (config.visibleStates) barOptions['visibleStates'] = config.visibleStates;\n const node: FieldNode = { type: 'field', id: '#statusbar', field: config.field, widget: 'statusbar', options: barOptions };\n const widget = createWidget(\n { form, name: config.field, field: def, node, id: uid('statusbar'), document: doc, labels: widgetLabels, preferences, locale, dialogs },\n options.widgets\n );\n updaters.push((state) =>\n widget.update({ value: state.values[config.field], values: state.values, readonly: form.node('#statusbar').readonly || locked, required: false, invalid: false })\n );\n return widget.element;\n }\n\n let wizardForward: (() => Promise<void>) | null = null;\n\n const layout = page.layout;\n let body: HTMLElement;\n if (layout.type === 'sheet') body = sheetLayout(layout);\n else if (layout.type === 'wizard') body = wizardLayout(layout);\n else if (layout.type === 'tabs') body = sectionsLayout({ id: `${layout.id}-page`, children: [layout] });\n else if (layout.type === 'list') {\n const list = listView({\n page,\n node: layout,\n form,\n dataSource: options.dataSource,\n doc,\n el,\n labels,\n locale,\n fill,\n confirm,\n withIcon,\n uid,\n icons: options.icons,\n preferences,\n onOpenRecord: options.onOpenRecord,\n });\n cleanups.push(list.destroy);\n body = list.element;\n }\n else body = sectionsLayout(layout);\n\n const head = layout.type === 'sheet' ? null : pageHead();\n content.append(...(head ? [head] : []), banner, draft, body);\n root.append(content, done, announcer);\n // The status leaves its place beside Save when the page wants it in a corner or across the top.\n if (options.saveStatus === 'toast') {\n status.classList.add('fd-toast');\n root.append(status);\n } else if (options.saveStatus === 'bar') {\n status.classList.add('fd-status-bar');\n content.prepend(status);\n }\n\n root.addEventListener('submit', (event) => {\n event.preventDefault();\n if (layout.type === 'list') return;\n if (wizardForward) void wizardForward();\n else void submitOrSave();\n });\n\n // ---- keys -------------------------------------------------------------------\n\n /** Text typed and not yet taken, such as a tag without its Enter, is taken now. */\n function commitTyping() {\n const active = doc.activeElement;\n if (active && root.contains(active) && (active.tagName === 'INPUT' || active.tagName === 'TEXTAREA')) {\n active.dispatchEvent(new Event('change', { bubbles: true }));\n }\n }\n\n /** The fields Enter can move between: on this page, shown, with a box to type or choose in, outside tables of lines. */\n function nextField(from: HTMLElement): HTMLElement | null {\n const fields = [...root.querySelectorAll<HTMLElement>('.fd-field')].filter(\n (field) => !field.closest('[hidden], [data-type=\"one2many\"] .fd-field, .fd-form-dialog') && !field.parentElement?.closest('[data-type=\"one2many\"]')\n );\n const here = from.closest('.fd-field');\n const after = fields.slice(fields.indexOf(here as HTMLElement) + 1);\n for (const field of after) {\n const control = field.querySelector<HTMLElement>('input:not([type=\"hidden\"]):not([readonly]):not([disabled]), select:not([disabled]), textarea:not([readonly]), [contenteditable=\"true\"]');\n if (control) return control;\n }\n return null;\n }\n\n root.addEventListener('keydown', (event) => {\n // A list has nothing to save, and its rows keep their own keys.\n if (event.isComposing || event.key !== 'Enter' || layout.type === 'list') return;\n // An app's own content in a slot, such as a chatter's composer, keeps its keys.\n if ((event.target as Element).closest('.fd-slot')) return;\n const keys = options.keys ?? {};\n if (event.ctrlKey || event.metaKey) {\n // Saves even after a field used the Enter (a tag box adding its tag); the grid keeps its own keys.\n if (keys.saveWithCtrlEnter === false || options.showActions === false) return;\n if ((event.target as Element).closest('.ag-root-wrapper')) return;\n event.preventDefault();\n commitTyping();\n if (wizardForward) void wizardForward();\n else void submitOrSave();\n return;\n }\n // A plain Enter a field used itself, such as picking from an open list, is the field's.\n if (event.defaultPrevented || !keys.enterMovesToNext || event.shiftKey || event.altKey) return;\n const from = event.target as HTMLElement;\n if (from.tagName !== 'INPUT' && from.tagName !== 'SELECT') return;\n if (from.closest('[data-type=\"one2many\"]')) return;\n if (['button', 'submit', 'reset', 'file'].includes((from as HTMLInputElement).type)) return;\n event.preventDefault();\n nextField(from)?.focus();\n });\n\n // ---- confirmation dialog -----------------------------------------------------\n\n /** A question with Cancel and OK, or with `withCancel` false a notice with OK alone. */\n function dialogConfirm(message: string, withCancel = true): Promise<boolean> {\n return new Promise((resolve) => {\n const text = el('p', { id: `${prefix}-confirm` }, message);\n const cancel = el('button', { type: 'button', class: 'fd-button' }, labels.cancel);\n const ok = el('button', { type: 'button', class: 'fd-button fd-button-primary' }, labels.ok);\n const dialog = el('div', { class: 'fd-dialog', role: 'alertdialog', 'aria-modal': 'true', 'aria-labelledby': text.id }, text, el('div', { class: 'fd-actions fd-actions-end' }, ...(withCancel ? [cancel, ok] : [ok])));\n const backdrop = el('div', { class: 'fd-dialog-backdrop' }, dialog);\n const close = (answer: boolean) => {\n backdrop.remove();\n resolve(answer);\n };\n cancel.addEventListener('click', () => close(false));\n ok.addEventListener('click', () => close(true));\n backdrop.addEventListener('keydown', (event) => {\n if (event.key === 'Escape') close(false);\n });\n root.append(backdrop);\n ok.focus();\n });\n }\n\n // ---- go -------------------------------------------------------------------\n\n function render(state: FormState) {\n for (const update of updaters) update(state);\n }\n\n host.append(root);\n const unsubscribe = form.subscribe(render);\n render(form.getState());\n if (form.getState().status === 'idle') void form.load();\n\n return {\n form,\n element: root,\n setSkin(skin) {\n root.setAttribute('data-fd-skin', skin);\n },\n async save() {\n const saved = await form.save();\n if (!saved) focusFirstProblem();\n return saved;\n },\n check() {\n const valid = form.validate();\n if (!valid) focusFirstProblem();\n return valid;\n },\n setReadonly(readonly) {\n locked = readonly;\n root.toggleAttribute('data-readonly', locked);\n render(form.getState());\n },\n isReadonly: () => locked,\n destroy() {\n unsubscribe();\n for (const cleanup of cleanups) cleanup();\n root.remove();\n if (ownsForm) form.dispose();\n },\n };\n}\n\n/** Fields whose \u2713 would say nothing: a yes/no box is never wrong, a table or a file has its own look. */\nconst NO_VALID_MARK = new Set(['boolean', 'one2many', 'binary', 'image', 'html', 'json', 'properties']);\n"],
5
- "mappings": "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",
6
- "names": ["script_entry_exports", "__export", "DEFAULT_LABELS", "FIELDIA_CSS", "FIELD_NAME", "FIELD_TYPES", "FORMAT_VERSION", "ICONS", "MESSAGES", "VERSION", "VIEWER_LABELS", "WIDGET_LABELS", "binaryWidget", "browserPreferences", "builtInWidgets", "charTagsWidget", "checkPage", "checkValue", "compileModifier", "createForm", "createMemoryDataSource", "createWidget", "displayValue", "drawIcon", "emptyValue", "evaluateModifier", "expressionContext", "facetsToFilter", "fill", "formatBytes", "formatNumber", "groupByFields", "hostScheduler", "htmlWidget", "imageWidget", "initialValues", "installStyles", "isEmpty", "isModifierValid", "isoWeek", "jsonWidget", "kindTextField", "labelWidget", "lineForm", "lineKind", "linesWidget", "linkAddress", "linkCheckboxesWidget", "many2oneWidget", "matchesFilter", "memoryPreferences", "mountViewer", "normalizeNumber", "openFormDialog", "openSearchDialog", "progressbarWidget", "propertiesWidget", "referenceWidget", "sanitizeHtml", "saveProblemOf", "saveRefused", "statusbarWidget", "suggestions", "summary", "tagsWidget", "translatePage", "wait", "wideColumns", "withCalendar", "FIELD_NAME", "FIELD_TYPES", "wideColumns", "columns", "FORMAT_VERSION", "evaluate", "ast", "context", "evaluateBinaryOp", "evaluateUnaryOp", "getNestedValue", "node", "left", "normalize", "right", "operator", "ordered", "truthy", "operand", "value", "obj", "path", "parts", "current", "part", "CONSTANTS", "tokenize", "expr", "tokens", "token", "space", "at", "match", "getTokenType", "text", "lowerText", "ExpressionParser", "tokens", "__publicField", "ast", "left", "operator", "right", "operand", "compOperators", "expr", "token", "CONSTANTS", "parseListLiteral", "type", "values", "operators", "lowerValue", "op", "value", "message", "listStr", "content", "elements", "current", "inString", "stringChar", "i", "char", "parseElement", "error", "element", "compileModifier", "modifier", "value", "ast", "ExpressionParser", "tokenize", "fieldsRead", "values", "truthy", "evaluate", "names", "visit", "node", "root", "has", "record", "key", "ReferenceCheck", "page", "__publicField", "path", "message", "id", "first", "name", "scope", "owner", "keys", "value", "fields", "compileModifier", "error", "base", "def", "currency", "walk", "item", "at", "inner", "i", "seen", "property", "sequence", "field", "kinds", "lineFields", "kindField", "which", "o", "text", "root", "step", "stepPath", "list", "order", "named", "filter", "j", "button", "children", "child", "node", "tab", "tabPath", "sheet", "visibleStates", "values", "state", "stat", "badge", "place", "alert", "column", "sub", "shown", "c", "isObject", "value", "LAYOUTS", "checkPage", "input", "issues", "say", "path", "message", "data", "fields", "name", "def", "FIELD_TYPES", "layout", "isList", "page", "found", "ReferenceCheck", "error", "TEXT_KEYS", "NOT_TEXT", "translatePage", "page", "translate", "walk", "value", "key", "item", "out", "name", "inner", "widgetOptions", "evaluateModifier", "expression", "context", "tokens", "tokenize", "ast", "ExpressionParser", "result", "evaluate", "truthy", "isModifierValid", "emptyValue", "field", "initialValues", "fields", "values", "name", "structuredCopy", "isEmpty", "_field", "value", "expressionContext", "context", "forExpressions", "record", "line", "ref", "lineKind", "kinds", "MESSAGES", "fill", "template", "values", "match", "name", "checkValue", "field", "value", "required", "messages", "MESSAGES", "label", "say", "key", "values", "fill", "isEmpty", "decimals", "checkDate", "checkDateTime", "allowed", "o", "listing", "v", "isRecord", "ref", "m", "models", "listOr", "article", "checkFile", "text", "dot", "y", "d", "realDay", "ISO_DATETIME", "match", "mo", "h", "mi", "part", "year", "month", "day", "lengths", "file", "isFile", "formatBytes", "pattern", "matchesType", "types", "describeType", "type", "items", "or", "phrase", "bytes", "units", "size", "unit", "saveRefused", "problem", "saveProblemOf", "error", "carried", "message", "matchesFilter", "values", "filter", "item", "holds", "inner", "meets", "isSet", "value", "condition", "raw", "actual", "expected", "text", "low", "high", "TEXT", "NUMBER", "LINK", "suggestions", "typed", "page", "list", "words", "text", "found", "field", "def", "say", "op", "value", "valueLabel", "label", "fill", "lower", "option", "number", "rank", "s", "type", "i", "a", "b", "facetsToFilter", "facets", "filter", "facet", "conditions", "v", "chosen", "id", "f", "items", "groupByFields", "hostScheduler", "callback", "ms", "handle", "wait", "scheduler", "resolve", "createMemoryDataSource", "options", "records", "structuredCopy", "responses", "calls", "lineIds", "pause", "wait", "table", "model", "labelOf", "id", "value", "nextId", "asId", "key", "applyLines", "current", "ops", "lines", "op", "l", "applyLinks", "links", "related", "r", "relationOf", "fields", "name", "field", "request", "stored", "rule", "warn", "result", "warning", "query", "values", "matchesFilter", "record", "matching", "a", "b", "order", "compared", "compareValues", "counted", "raw", "link", "group", "rows", "top", "blank", "v", "label", "x", "y", "createForm", "options", "page", "scheduler", "hostScheduler", "messages", "MESSAGES", "index", "indexLayout", "steps", "step", "draftKey", "state", "baseline", "initialValues", "structuredCopy", "serverErrors", "lineKeys", "onchangeSeq", "draftTimer", "autosaveTimer", "pending", "listeners", "contextCache", "set", "patch", "listener", "track", "promise", "done", "context", "expressionContext", "fieldDef", "name", "def", "dirtyFields", "values", "nodeState", "id", "node", "ctx", "invisible", "parent", "readonly", "visibleFieldNodes", "root", "inside", "at", "skipped", "collectErrors", "errors", "message", "checkValue", "line", "kind", "lineKind", "sub", "subDef", "lineMessage", "writeValues", "extra", "revalidateShown", "previous", "fresh", "kept", "key", "refused", "scheduleDraft", "drafts", "forgetDraft", "offerDraft", "raw", "draft", "scheduleAutosave", "autosave", "save", "runOnchange", "changed", "source", "seq", "request", "result", "afterEdit", "changes", "creating", "names", "isEmpty", "now", "before", "emptyValue", "lineOps", "linkOps", "shownValues", "shown", "error", "problem", "saveProblemOf", "fields", "creatable", "runCreate", "typed", "model", "runSearch", "query", "limit", "resolve", "item", "filter", "relation", "lineField", "field", "stepIndex", "optionalStep", "load", "loaded", "form", "value", "current", "numbers", "l", "n", "lines", "to", "sequence", "from", "target", "trusted", "i", "low", "high", "pool", "renumbered", "merged", "after", "subfield", "visible", "following", "chosen", "ops", "old", "had", "r", "has", "add", "modifiers", "compileModifier", "walk", "nodes", "tab", "button", "stat", "alert", "badge", "formats", "format", "locale", "decimals", "key", "found", "marks", "parts", "p", "formatNumber", "value", "normalizeNumber", "text", "group", "decimal", "out", "d", "WIDGET_LABELS", "DEBOUNCE_MS", "SHOWN", "fill", "template", "values", "match", "name", "combobox", "options", "doc", "id", "labels", "listId", "input", "list", "element", "shown", "creating", "creatingText", "extras", "editing", "results", "active", "seq", "timer", "readonly", "render", "record", "i", "option", "event", "choose", "empty", "open", "close", "index", "typed", "act", "picked", "lookUp", "query", "mine", "found", "reached", "held", "hidden", "kept", "overflow", "extra", "emptied", "text", "next", "creator", "form", "node", "many2oneWidget", "field", "document", "WIDGET_LABELS", "dialogs", "relation", "canOpen", "box", "choices", "limit", "current", "saved", "clear", "state", "tagsWidget", "chips", "records", "drawn", "key", "drawChips", "r", "remove", "chip", "button", "charTagsWidget", "separator", "suggestions", "s", "split", "t", "write", "tags", "add", "raw", "tag", "taken", "wanted", "parts", "part", "linkCheckboxesWidget", "boxes", "latest", "sync", "chosen", "now", "label", "referenceWidget", "context", "models", "select", "model", "value", "localDate", "text", "match", "y", "m", "d", "hh", "mm", "displayValue", "def", "value", "values", "locale", "number", "n", "digits", "formatNumber", "label", "v", "o", "currency", "amount", "date", "kindTextField", "def", "kind", "lineForm", "form", "field", "key", "values", "l", "name", "value", "query", "limit", "text", "linesWidget", "node", "id", "document", "labels", "WIDGET_LABELS", "locale", "dialogs", "kinds", "columns", "column", "element", "scroller", "table", "head", "headRow", "th", "lastTh", "body", "totals", "sums", "foot", "row", "i", "td", "adds", "addButton", "button", "focusNew", "rows", "readonly", "makeCell", "tr", "line", "sub", "span", "cellId", "subNode", "widget", "createWidget", "label", "error", "makeRow", "lineKind", "cells", "tools", "remove", "state", "current", "errors", "keep", "index", "cell", "message", "sum", "total", "displayValue", "read", "file", "resolve", "reject", "reader", "url", "fileWidget", "kind", "form", "name", "field", "id", "document", "labels", "WIDGET_LABELS", "element", "input", "accept", "preview", "pick", "pickText", "hint", "chosen", "fileName", "replace", "remove", "readonly", "take", "event", "state", "formatBytes", "src", "binaryWidget", "imageWidget", "percents", "percent", "value", "locale", "format", "progressbarWidget", "context", "node", "id", "document", "options", "min", "fixedMax", "maxField", "color", "showPercent", "bar", "fill", "text", "box", "element", "createWidget", "state", "max", "share", "rounded", "words", "value", "labelWidget", "field", "node", "id", "document", "locale", "options", "text", "key", "from", "decimals", "output", "values", "shown", "formatNumber", "summary", "prefixField", "suffixField", "prefix", "suffix", "part", "statusbarWidget", "form", "name", "field", "node", "id", "document", "options", "clickable", "visible", "list", "keyOf", "value", "steps", "o", "lookedUp", "last", "draw", "readonly", "currentKey", "shown", "s", "v", "step", "label", "inner", "item", "state", "records", "r", "isoWeek", "day", "yearStart", "pad", "n", "sameDay", "a", "b", "addDays", "d", "addMonths", "last", "dayOf", "kind", "value", "m", "withCalendar", "inner", "context", "form", "name", "id", "doc", "locale", "labels", "WIDGET_LABELS", "lang", "monthName", "dayName", "weekdayShort", "weekdayLong", "button", "svg", "icon", "tag", "attrs", "shape", "k", "v", "dialog", "head", "prev", "title", "next", "grid", "element", "focused", "readonly", "pick", "was", "at", "close", "draw", "focus", "chosen", "today", "label", "first", "start", "headRow", "weekHead", "i", "th", "thead", "tbody", "row", "tr", "week", "cell", "event", "onKey", "move", "to", "moves", "open", "outside", "state", "humanize", "name", "words", "guess", "value", "label", "propertiesWidget", "context", "form", "field", "node", "id", "document", "declared", "current", "properties", "property", "element", "rows", "drawn", "draw", "definitions", "row", "definition", "rowId", "propertyField", "propertyNode", "widget", "createWidget", "state", "values", "key", "ALLOWED", "DROPPED_WITH_CONTENT", "ALIGNABLE", "ALIGNMENTS", "sanitizeHtml", "html", "document", "box", "clean", "parent", "node", "element", "href", "align", "attribute", "out", "linkAddress", "typed", "text", "TOOLS", "htmlWidget", "form", "name", "id", "labels", "WIDGET_LABELS", "area", "withToolbar", "last", "toolbar", "formattingToolbar", "state", "doc", "bar", "lastRange", "restore", "selection", "run", "command", "value", "style", "key", "option", "linkRow", "address", "apply", "unlink", "url", "event", "buttons", "icon", "button", "stops", "stop", "i", "at", "rtl", "step", "next", "reflect", "block", "jsonWidget", "error", "parsed", "createWidget", "context", "registry", "field", "node", "keys", "key", "factory", "builtInWidgets", "pendingWidget", "make", "doc", "tag", "props", "children", "element", "name", "value", "describe", "state", "textOf", "textWidget", "inputType", "form", "id", "document", "input", "text", "textareaWidget", "area", "NUMBER", "UNFINISHED", "numberWidget", "locale", "integer", "decimals", "shown", "formatNumber", "parse", "raw", "normalizeNumber", "options", "currencyField", "currencyDef", "picker", "currency", "side", "after", "typing", "parsed", "showsSame", "holder", "checkboxWidget", "role", "box", "selectWidget", "choices", "select", "option", "i", "index", "choiceGroup", "kind", "group", "inputs", "chosen", "_", "pointsWidget", "style", "min", "max", "points", "n", "point", "event", "current", "step", "next", "p", "dateWidget", "widget", "withCalendar", "pad", "dateTimeWidget", "local", "iso", "d", "span", "summary", "record", "count", "charTagsWidget", "progressbarWidget", "labelWidget", "statusbarWidget", "many2oneWidget", "tagsWidget", "linkCheckboxesWidget", "referenceWidget", "linesWidget", "binaryWidget", "imageWidget", "htmlWidget", "jsonWidget", "propertiesWidget", "FIELDIA_CSS", "STYLE_ID", "installStyles", "document", "style", "browserPreferences", "storage", "area", "key", "text", "value", "memoryPreferences", "values", "structuredCloneSafe", "SVG", "ICONS", "drawIcon", "doc", "name", "own", "inside", "svg", "key", "value", "dialogs", "FOCUSABLE", "openFormDialog", "options", "doc", "container", "opener", "labels", "VIEWER_LABELS", "id", "make", "tag", "attrs", "text", "element", "name", "value", "title", "closeButton", "body", "discard", "saveClose", "box", "backdrop", "handle", "mountViewer", "done", "recalculate", "focusables", "firstField", "resolve", "close", "saved", "state", "result", "accepted", "event", "all", "first", "last", "form", "fields", "recompute", "closed", "seen", "writing", "values", "now", "next", "openSearchDialog", "words", "WIDGET_LABELS", "query", "list", "cancel", "head", "foot", "found", "active", "asked", "timer", "picked", "draw", "record", "i", "option", "look", "mine", "records", "nameFieldOf", "page", "def", "valuesPage", "fields", "title", "readonly", "shown", "name", "lookupsOf", "source", "request", "pageDialogs", "options", "pageFor", "model", "shared", "related", "nameField", "result", "openFormDialog", "openSearchDialog", "key", "page", "readFavourites", "preferences", "kept", "startingFacets", "node", "chosen", "favourite", "id", "f", "favouritesPart", "context", "el", "labels", "fill", "list", "none", "name", "byDefault", "save", "form", "open", "write", "favourites", "draw", "use", "remove", "named", "others", "groupName", "context", "field", "group", "def", "o", "closeUnder", "tr", "level", "next", "after", "groupRow", "within", "grouping", "el", "labels", "filter", "toggle", "opening", "open", "rows", "inner", "recordsFrom", "offset", "answer", "record", "left", "more", "moreRow", "opened", "LIST_STYLES", "installListStyles", "doc", "style", "TEXT", "LINK", "CHOICE", "NUMBER", "DATE", "conditionsFor", "def", "customFilterPart", "context", "page", "el", "labels", "fields", "field", "name", "condition", "valueBox", "apply", "form", "button", "value", "drawConditions", "op", "word", "drawValue", "current", "o", "type", "wanted", "shown", "text", "option", "facetText", "facet", "labels", "or", "v", "searchBar", "context", "page", "node", "doc", "el", "fill", "uid", "facets", "icon", "name", "drawn", "drawIcon", "change", "next", "drawChips", "drawPanel", "listId", "panelId", "input", "chips", "offeredList", "toggle", "offered", "active", "index", "text", "remove", "_", "i", "kind", "drawOffered", "suggestion", "option", "event", "pick", "closeOffered", "value", "at", "f", "suggestions", "heading", "iconName", "id", "toggleIn", "key", "now", "keys", "k", "field", "filterButtons", "filter", "button", "groupButtons", "custom", "customFilterPart", "favourites", "favouritesPart", "group", "title", "parts", "panel", "ids", "fields", "showPanel", "open", "element", "outside", "NUMBERS", "UNSORTABLE", "listView", "context", "page", "node", "form", "el", "labels", "fill", "locale", "doc", "installListStyles", "pageSize", "defaultSort", "sort", "offset", "total", "rows", "recordOf", "visible", "body", "tr", "model", "facets", "startingFacets", "chosen", "asking", "destroyed", "fields", "name", "def", "show", "values", "displayValue", "chooseAll", "headers", "th", "button", "desc", "order", "load", "table", "empty", "retry", "failed", "row", "record", "level", "box", "drawChoice", "event", "cell", "count", "clear", "buttons", "action", "selection", "shown", "onPage", "id", "range", "previous", "next", "pager", "drawPager", "drawSort", "changed", "grouped", "source", "mine", "drawn", "filter", "facetsToFilter", "grouping", "groupByFields", "groups", "group", "groupRow", "answer", "search", "searchBar", "element", "VIEWER_LABELS", "DEFAULT_LABELS", "mounts", "mountViewer", "host", "options", "doc", "checked", "checkPage", "i", "page", "translatePage", "locale", "preferences", "browserPreferences", "dialogs", "pageDialogs", "ownsForm", "form", "createForm", "MESSAGES", "labels", "VIEWER_LABELS", "widgetLabels", "WIDGET_LABELS", "dir", "prefix", "updaters", "cleanups", "uid", "id", "fill", "template", "values", "_", "key", "installStyles", "el", "tag", "attrs", "children", "node", "name", "value", "withIcon", "text", "icon", "drawIcon", "root", "confirm", "dialogConfirm", "fieldItem", "def", "wrapper", "label", "mark", "NO_VALID_MARK", "widget", "createWidget", "helpText", "help", "error", "warning", "state", "shown", "message", "warned", "filled", "valid", "locked", "hideWhen", "element", "buttonItem", "button", "textItem", "style", "slotItem", "cleanup", "grid", "columns", "box", "wideColumns", "width", "count", "item", "folds", "sectionItem", "section", "description", "content", "toggle", "open", "show", "next", "tabsItem", "list", "picked", "active", "parts", "tab", "tabId", "panelId", "panel", "render", "event", "p", "at", "move", "rtl", "selected", "editSwitch", "announce", "checkText", "focusFirstProblem", "statusText", "retry", "submitOrSave", "status", "notDone", "names", "field", "inOrder", "a", "b", "quietTimer", "problem", "bannerRetry", "banner", "announcer", "seenProblem", "draft", "draftText", "restore", "discardDraft", "invalid", "folded", "done", "again", "pageHead", "head", "sectionsLayout", "action", "actions", "discard", "dirty", "wizardLayout", "progressText", "bar", "stepButtons", "step", "go", "focusStep", "panels", "back", "skip", "forward", "isLast", "steps", "wizardForward", "index", "last", "sheetLayout", "pageBox", "save", "atFoot", "foot", "header", "underTitle", "statusbar", "card", "ribbon", "stats", "stat", "words", "alert", "dismissed", "close", "badges", "badge", "chip", "title", "row", "avatar", "layout", "config", "barOptions", "body", "listView", "commitTyping", "nextField", "from", "fields", "here", "after", "control", "keys", "withCancel", "resolve", "cancel", "ok", "dialog", "backdrop", "answer", "update", "unsubscribe", "skin", "saved", "readonly", "VERSION"]
3
+ "sources": ["../../../../tools/script-entry.ts", "../../../../libs/core/src/lib/format/names.ts", "../../../../libs/core/src/lib/format/columns.ts", "../../../../libs/core/src/lib/format/version.ts", "../../../../libs/core/src/lib/expression/operations.ts", "../../../../libs/core/src/lib/expression/functions.ts", "../../../../libs/core/src/lib/expression/evaluator.ts", "../../../../libs/core/src/lib/expression/tokenizer.ts", "../../../../libs/core/src/lib/expression/parser.ts", "../../../../libs/core/src/lib/expression/reads.ts", "../../../../libs/core/src/lib/expression/modifier.ts", "../../../../libs/core/src/lib/expression/expression.ts", "../../../../libs/core/src/lib/expression/order.ts", "../../../../libs/core/src/lib/format/references.ts", "../../../../libs/core/src/lib/format/check-page.ts", "../../../../libs/core/src/lib/format/translate.ts", "../../../../libs/core/src/lib/expression/evaluateModifier.ts", "../../../../libs/core/src/lib/record/locales/all.ts", "../../../../libs/core/src/lib/record/messages.ts", "../../../../libs/core/src/lib/record/limits.ts", "../../../../libs/core/src/lib/record/values.ts", "../../../../libs/core/src/lib/record/check.ts", "../../../../libs/core/src/lib/record/score.ts", "../../../../libs/core/src/lib/record/data-source.ts", "../../../../libs/core/src/lib/record/filter.ts", "../../../../libs/core/src/lib/record/search.ts", "../../../../libs/core/src/lib/record/scheduler.ts", "../../../../libs/core/src/lib/record/memory-data-source.ts", "../../../../libs/core/src/lib/record/structures.ts", "../../../../libs/core/src/lib/record/inputs.ts", "../../../../libs/core/src/lib/record/env.ts", "../../../../libs/core/src/lib/record/compute.ts", "../../../../libs/core/src/lib/record/set-when.ts", "../../../../libs/core/src/lib/record/rules.ts", "../../../../libs/core/src/lib/record/form.ts", "../../../../libs/widgets/src/lib/numbers.ts", "../../../../libs/widgets/src/lib/locales/all.ts", "../../../../libs/widgets/src/lib/labels.ts", "../../../../libs/widgets/src/lib/kind-parts.ts", "../../../../libs/widgets/src/lib/relations.ts", "../../../../libs/widgets/src/lib/display.ts", "../../../../libs/widgets/src/lib/line-moves.ts", "../../../../libs/widgets/src/lib/lines.ts", "../../../../libs/widgets/src/lib/focus-trap.ts", "../../../../libs/widgets/src/lib/files.ts", "../../../../libs/widgets/src/lib/progress.ts", "../../../../libs/widgets/src/lib/label.ts", "../../../../libs/widgets/src/lib/statusbar.ts", "../../../../libs/widgets/src/lib/calendar.ts", "../../../../libs/widgets/src/lib/properties.ts", "../../../../libs/widgets/src/lib/extras.ts", "../../../../libs/widgets/src/lib/shuffle.ts", "../../../../libs/widgets/src/lib/matrix.ts", "../../../../libs/widgets/src/lib/signature.ts", "../../../../libs/widgets/src/lib/slider.ts", "../../../../libs/widgets/src/lib/choice-rules.ts", "../../../../libs/widgets/src/lib/choice-tags.ts", "../../../../libs/widgets/src/lib/choice-images.ts", "../../../../libs/widgets/src/lib/ranking.ts", "../../../../libs/widgets/src/lib/address.ts", "../../../../libs/widgets/src/lib/cards.ts", "../../../../libs/widgets/src/lib/limits.ts", "../../../../libs/widgets/src/lib/units.ts", "../../../../libs/widgets/src/lib/icons.ts", "../../../../libs/widgets/src/lib/choices-from.ts", "../../../../libs/widgets/src/lib/yes-no.ts", "../../../../libs/widgets/src/lib/widgets.ts", "../../../../libs/widgets/src/lib/styles-kinds.ts", "../../../../libs/widgets/src/lib/styles-choices.ts", "../../../../libs/widgets/src/lib/styles-inputs.ts", "../../../../libs/widgets/src/lib/layout-styles.ts", "../../../../libs/widgets/src/lib/styles.ts", "../../../../libs/widgets/src/lib/preferences.ts", "../../../../libs/viewer/src/lib/locales/all.ts", "../../../../libs/viewer/src/lib/labels.ts", "../../../../libs/viewer/src/lib/look.ts", "../../../../libs/viewer/src/lib/dialog.ts", "../../../../libs/viewer/src/lib/related.ts", "../../../../libs/viewer/src/lib/favourites.ts", "../../../../libs/viewer/src/lib/list-groups.ts", "../../../../libs/viewer/src/lib/list-styles.ts", "../../../../libs/viewer/src/lib/custom-filter.ts", "../../../../libs/viewer/src/lib/search-bar.ts", "../../../../libs/viewer/src/lib/list.ts", "../../../../libs/viewer/src/lib/place.ts", "../../../../libs/viewer/src/lib/dom.ts", "../../../../libs/viewer/src/lib/viewer.ts", "../../../../libs/viewer/src/lib/add-language.ts"],
4
+ "sourcesContent": ["/**\n * What the `<script>` bundle puts on `window.Fieldia`: everything a page with\n * no build step needs to show a form and handle what people enter. Its own\n * words are English; Arabic, German and French come as add-on scripts\n * (tools/script-language.ts).\n */\nimport { addLanguage } from '@fieldia/viewer';\nimport type { LanguageHost } from './script-language';\n\n// The runtime alone: the format's schemas and validation library stay out of a page with no build step.\nexport * from '../libs/core/src/runtime';\nexport * from '@fieldia/widgets';\nexport * from '@fieldia/viewer';\n\ndeclare const __FIELDIA_VERSION__: string;\n/** The version of @fieldia/viewer this bundle was built from. */\nexport const VERSION: string = __FIELDIA_VERSION__;\n\n// A language's script loaded before this one left its words behind: take them now.\nconst host = globalThis as LanguageHost;\nfor (const [locale, words] of host.FieldiaLanguages ?? []) addLanguage(locale, words);\ndelete host.FieldiaLanguages;\n", "/** Field names and kinds, apart from the schemas so code that runs a form never carries the validation library. */\n\n/** A field name: what expressions and layout nodes use to refer to a field. */\nexport const FIELD_NAME = /^[A-Za-z_][A-Za-z0-9_]*$/;\n\nexport const FIELD_TYPES = [\n 'char',\n 'text',\n 'html',\n 'integer',\n 'float',\n 'monetary',\n 'boolean',\n 'date',\n 'datetime',\n 'selection',\n 'binary',\n 'image',\n 'many2one',\n 'many2many',\n 'one2many',\n 'reference',\n 'properties',\n 'json',\n 'matrix',\n] as const;\n\nexport type FieldType = (typeof FIELD_TYPES)[number];\n", "import type { ColumnCount, ColumnsByWidth } from './layout';\n\n/** A section's columns at full width, whichever way they are written. */\nexport function wideColumns(columns: ColumnCount | ColumnsByWidth | undefined): ColumnCount {\n return typeof columns === 'object' ? columns.wide : columns ?? 1;\n}\n", "/** The page format version this build reads and writes. */\nexport const FORMAT_VERSION = '0.1' as const;\n", "/**\n * What the language's operators do to values, the way a form needs it:\n * arithmetic on numbers only, text joined with +, and null \u2014 never an error \u2014\n * for what cannot be worked out, such as a sum with an empty field in it or a\n * division by zero.\n */\n\n/** A number that can be counted with: not NaN, not infinite. */\nexport const isNumber = (value: unknown): value is number => typeof value === 'number' && Number.isFinite(value);\n\n/**\n * A result without the noise of binary fractions, so 0.1 + 0.2 is 0.3 and\n * money adds up; null when it is not a finite number (a division by zero).\n */\nexport function tidy(value: number): number | null {\n return Number.isFinite(value) ? Number(value.toPrecision(15)) : null;\n}\n\n/** `+ - * / %` on two values. `+` joins text when either side is text; an empty value joins as nothing. */\nexport function arithmetic(operator: string, left: unknown, right: unknown): unknown {\n if (operator === '+' && (typeof left === 'string' || typeof right === 'string')) {\n const l = joinable(left);\n const r = joinable(right);\n return l === null || r === null ? null : l + r;\n }\n if (!isNumber(left) || !isNumber(right)) return null;\n switch (operator) {\n case '+':\n return tidy(left + right);\n case '-':\n return tidy(left - right);\n case '*':\n return tidy(left * right);\n case '/':\n return tidy(left / right);\n case '%':\n // Python's remainder takes the divisor's sign: -7 % 3 is 2.\n return tidy(left - right * Math.floor(left / right));\n default:\n return null;\n }\n}\n\n/** A value as it reads inside joined text: text and numbers as written, an empty value as nothing. */\nfunction joinable(value: unknown): string | null {\n if (value === null || value === undefined) return '';\n if (typeof value === 'string') return value;\n return isNumber(value) ? String(value) : null;\n}\n\n/** A number with its sign turned, or null for anything else. */\nexport function negate(value: unknown): number | null {\n return isNumber(value) ? tidy(-value) : null;\n}\n\n/** Python's truth test: empty lists, strings and objects, 0 and None are false. */\nexport function truthy(value: unknown): boolean {\n if (Array.isArray(value)) return value.length > 0;\n if (value !== null && typeof value === 'object') return Object.keys(value).length > 0;\n return Boolean(value);\n}\n\n/**\n * A number rounded to so many digits after the point (before it, when\n * negative), half away from zero as people and invoices round: 2.5 is 3,\n * -2.5 is -3, and 1.005 to two digits is 1.01.\n */\nexport function roundTo(value: number, digits: number): number | null {\n const scale = 10 ** Math.trunc(digits);\n // Tidied first, so 1.005 \u00D7 100 is 100.5 and not 100.49999999999999.\n const scaled = Number((Math.abs(value) * scale).toPrecision(15));\n return tidy((Math.sign(value) * Math.round(scaled)) / scale);\n}\n", "import type { ASTNode } from './parser';\nimport { isNumber, roundTo, tidy, truthy } from './operations';\n\n/**\n * The functions an expression may call. Each says how many values it takes,\n * so a call with too many or too few is refused when the page is read; and\n * each gives null rather than failing when what it is handed does not fit.\n */\n\n/** What an expression is worked out with, besides the record's values. */\nexport interface ExpressionEnv {\n /**\n * The lines of a one2many, as rows of their values, for `sum` and `count`:\n * the values hold only the lines' keys. Sections and notes are left out.\n */\n lines?(field: string): readonly Readonly<Record<string, unknown>>[] | undefined;\n /** Today, as YYYY-MM-DD. The computer's own clock when left out. */\n today?(): string;\n}\n\n/** One call, as a function sees it: its values unread, a way to read each, and the env. */\ninterface Call {\n args: readonly ASTNode[];\n value(node: ASTNode): unknown;\n env: ExpressionEnv;\n}\n\ninterface ExpressionFunction {\n /** How many values it takes: at least, at most. */\n readonly takes: readonly [number, number];\n /** What is wrong with the values it was given, found as the expression is read. */\n check?(args: readonly ASTNode[]): string | undefined;\n call(call: Call): unknown;\n}\n\n/** A day as YYYY-MM-DD, in the computer's own time zone. */\nexport function localDay(date: Date): string {\n const pad = (n: number) => String(n).padStart(2, '0');\n return `${date.getFullYear()}-${pad(date.getMonth() + 1)}-${pad(date.getDate())}`;\n}\n\n/** The list a function counts or adds up: the rows of a one2many named by its field, or any list. */\nfunction listOf(call: Call): unknown {\n const first = call.args[0];\n const rows = first.type === 'Identifier' ? call.env.lines?.(first.name) : undefined;\n return rows ?? call.value(first);\n}\n\n/** The smallest or largest of the values, lists opened: empty ones left out, numbers or text but not both. */\nfunction extreme(call: Call, smaller: boolean): unknown {\n const items = call.args\n .flatMap((arg) => {\n const value = call.value(arg);\n return Array.isArray(value) ? value : [value];\n })\n .filter((value) => value !== null && value !== undefined);\n if (!items.length) return null;\n if (!items.every(isNumber) && !items.every((value) => typeof value === 'string')) return null;\n const ordered = items as (number | string)[];\n return ordered.reduce((best, value) => ((smaller ? value < best : value > best) ? value : best));\n}\n\nexport const FUNCTIONS: ReadonlyMap<string, ExpressionFunction> = new Map<string, ExpressionFunction>([\n [\n 'round',\n {\n takes: [1, 2],\n call({ args, value }) {\n const x = value(args[0]);\n const digits = args.length > 1 ? value(args[1]) : 0;\n return isNumber(x) && isNumber(digits) ? roundTo(x, digits) : null;\n },\n },\n ],\n [\n 'abs',\n {\n takes: [1, 1],\n call({ args, value }) {\n const x = value(args[0]);\n return isNumber(x) ? Math.abs(x) : null;\n },\n },\n ],\n ['min', { takes: [1, Infinity], call: (call) => extreme(call, true) }],\n ['max', { takes: [1, Infinity], call: (call) => extreme(call, false) }],\n [\n 'len',\n {\n takes: [1, 1],\n call({ args, value }) {\n const x = value(args[0]);\n if (x === null || x === undefined) return 0;\n return typeof x === 'string' || Array.isArray(x) ? x.length : null;\n },\n },\n ],\n ['today', { takes: [0, 0], call: ({ env }) => env.today?.() ?? localDay(new Date()) }],\n [\n 'sum',\n {\n takes: [1, 2],\n check(args) {\n const field = args[1];\n if (field && !(field.type === 'Literal' && typeof field.value === 'string')) {\n return \"sum takes the name of a field, in quotes, after the lines: sum(lines, 'subtotal')\";\n }\n return undefined;\n },\n call(call) {\n const list = listOf(call);\n if (list === null || list === undefined) return 0;\n if (!Array.isArray(list)) return null;\n const field = call.args[1]?.type === 'Literal' ? (call.args[1].value as string) : undefined;\n let total = 0;\n for (const item of list) {\n const n = field === undefined ? item : (item as Record<string, unknown> | null)?.[field];\n if (isNumber(n)) total += n;\n }\n return tidy(total);\n },\n },\n ],\n [\n 'count',\n {\n takes: [1, 1],\n call(call) {\n const list = listOf(call);\n if (list === null || list === undefined) return 0;\n return Array.isArray(list) ? list.length : null;\n },\n },\n ],\n [\n 'if',\n {\n takes: [3, 3],\n // Only the branch chosen is worked out.\n call: ({ args, value }) => (truthy(value(args[0])) ? value(args[1]) : value(args[2])),\n },\n ],\n]);\n\n/** How many values a function takes, in words: \"round takes 1 or 2 values\". */\nexport function takesInWords(name: string, [least, most]: readonly [number, number]): string {\n if (most === 0) return `${name} takes no values`;\n if (least === most) return `${name} takes ${least} value${least === 1 ? '' : 's'}`;\n if (most === Infinity) return `${name} takes ${least} or more values`;\n return `${name} takes ${least} or ${most} values`;\n}\n", "/**\n * AST evaluator for expressions, ported from the React form engine.\n *\n * Python semantics where the React version used JavaScript's: an empty list\n * or string is false, and an empty value is never smaller or larger than\n * anything \u2014 modifiers come from backends that think in Python. Arithmetic\n * and functions give null for what they cannot work out, never an error.\n */\n\nimport type { ASTNode, BinaryOpNode, CallNode, UnaryOpNode } from './parser';\nimport { FUNCTIONS, type ExpressionEnv } from './functions';\nimport { arithmetic, negate, truthy } from './operations';\n\nexport { truthy } from './operations';\n\n/**\n * Evaluate an AST node against a context object\n *\n * @param ast - The AST node to evaluate\n * @param context - Object containing field values\n * @returns The result of evaluation\n *\n * @example\n * const ast = { type: 'BinaryOp', operator: '==', left: {...}, right: {...} };\n * const context = { state: 'draft', amount: 100 };\n * evaluate(ast, context); // Returns boolean result\n */\nexport function evaluate(ast: ASTNode, context: Record<string, unknown>, env: ExpressionEnv = {}): unknown {\n switch (ast.type) {\n case 'BinaryOp':\n return evaluateBinaryOp(ast, context, env);\n\n case 'UnaryOp':\n return evaluateUnaryOp(ast, context, env);\n\n case 'Call':\n return evaluateCall(ast, context, env);\n\n case 'Literal':\n return ast.value;\n\n case 'Identifier':\n return getNestedValue(context, ast.name);\n\n default:\n throw new Error(`Unknown AST node type: ${(ast as { type: string }).type}`);\n }\n}\n\n/**\n * Evaluate binary operations\n */\nfunction evaluateBinaryOp(node: BinaryOpNode, context: Record<string, unknown>, env: ExpressionEnv): unknown {\n const left = normalize(evaluate(node.left, context, env));\n const right = normalize(evaluate(node.right, context, env));\n const operator = node.operator.toLowerCase();\n const ordered = left !== null && right !== null;\n\n switch (operator) {\n // Comparison operators\n case '==':\n return left === right;\n\n case '!=':\n case '<>':\n return left !== right;\n\n case '<':\n return ordered && (left as Comparable) < (right as Comparable);\n\n case '>':\n return ordered && (left as Comparable) > (right as Comparable);\n\n case '<=':\n return ordered && (left as Comparable) <= (right as Comparable);\n\n case '>=':\n return ordered && (left as Comparable) >= (right as Comparable);\n\n // In operators\n case 'in':\n return Array.isArray(right) && right.includes(left);\n\n case 'not in':\n return Array.isArray(right) && !right.includes(left);\n\n // Arithmetic, and + joining text\n case '+':\n case '-':\n case '*':\n case '/':\n case '%':\n return arithmetic(operator, left, right);\n\n // Logical operators (use truthiness)\n case 'and':\n return truthy(left) && truthy(right);\n\n case 'or':\n return truthy(left) || truthy(right);\n\n default:\n throw new Error(`Unknown binary operator: ${node.operator}`);\n }\n}\n\n/**\n * Evaluate unary operations\n */\nfunction evaluateUnaryOp(node: UnaryOpNode, context: Record<string, unknown>, env: ExpressionEnv): unknown {\n const operand = evaluate(node.operand, context, env);\n const operator = node.operator.toLowerCase();\n\n switch (operator) {\n case 'not':\n return !truthy(operand);\n\n case '-':\n return negate(operand);\n\n default:\n throw new Error(`Unknown unary operator: ${node.operator}`);\n }\n}\n\n/** A function called with its values, each read only when the function asks for it. */\nfunction evaluateCall(node: CallNode, context: Record<string, unknown>, env: ExpressionEnv): unknown {\n const fn = FUNCTIONS.get(node.name);\n if (!fn) throw new Error(`Unknown function: ${node.name}`);\n return fn.call({ args: node.args, value: (arg) => evaluate(arg, context, env), env });\n}\n\n/** What `<` and `>` order: numbers with numbers, strings with strings. */\ntype Comparable = number | string;\n\n/** A missing value compares like None. */\nfunction normalize(value: unknown): unknown {\n return value === undefined ? null : value;\n}\n\n/**\n * Get a nested value from an object using dot notation\n *\n * @param obj - The object to traverse\n * @param path - Dot-separated path (e.g., 'partner_id.country_id.name')\n * @returns The value at the path, or undefined if not found\n *\n * @example\n * getNestedValue({ a: { b: { c: 5 } } }, 'a.b.c') // Returns 5\n * getNestedValue({ a: null }, 'a.b.c') // Returns undefined\n */\nfunction getNestedValue(obj: unknown, path: string): unknown {\n const parts = path.split('.');\n let current: unknown = obj;\n\n for (const part of parts) {\n if (current === null || current === undefined) {\n return undefined;\n }\n current = (current as Record<string, unknown>)[part];\n }\n\n return current;\n}\n", "/**\n * Tokenizer for expressions: modifiers, and values worked out from others.\n *\n * Ported from the React form engine, with one change in behaviour: a\n * character the language does not know is an error, not something to skip.\n * The React version dropped it silently, so `amount > -5` read as\n * `amount > 5` and `a && b` read as `a b`. A minus sign is a token of its\n * own, so `a-5` is a subtraction; the parser reads `-5` as a negative number.\n */\n\nexport type TokenType =\n | 'IDENTIFIER' // Field names, including dotted notation (e.g., partner_id.country_id)\n | 'NUMBER' // Integer or float (e.g., 42, 3.14)\n | 'STRING' // Single or double quoted string (e.g., 'draft', \"draft\")\n | 'LIST' // List literal (e.g., ['draft', 'sent'])\n | 'OPERATOR' // Comparison operators (==, !=, <>, <, >, <=, >=, in, not in)\n | 'LOGICAL' // Logical operators (and, or, not)\n | 'CONSTANT' // True, False, None (and true, false, null)\n | 'ARITHMETIC' // + - * / %\n | 'COMMA' // Between the values a function takes\n | 'PAREN'; // Parentheses ( )\n\nexport interface Token {\n type: TokenType;\n value: string;\n position: number;\n}\n\n/** The words that are values, not field names. */\nexport const CONSTANTS: ReadonlyMap<string, boolean | null> = new Map<string, boolean | null>([\n ['True', true],\n ['False', false],\n ['None', null],\n ['true', true],\n ['false', false],\n ['null', null],\n]);\n\n/** The operators that work out numbers, and join text. */\nconst ARITHMETIC = new Set(['+', '-', '*', '/', '%']);\n\n/**\n * Tokenizes an expression: a Flectra modifier, or a value worked out from others.\n *\n * @param expr - The expression string to tokenize\n * @returns Array of tokens\n *\n * @example\n * tokenize(\"state == 'draft'\")\n * // Returns: [\n * // { type: 'IDENTIFIER', value: 'state', position: 0 },\n * // { type: 'OPERATOR', value: '==', position: 1 },\n * // { type: 'STRING', value: \"'draft'\", position: 2 }\n * // ]\n */\nexport function tokenize(expr: string): Token[] {\n const tokens: Token[] = [];\n if (!expr) return tokens;\n\n // Alternatives in priority order: \"not in\" before \"not\", operators of two\n // characters before one, a number before anything else that could start\n // with a digit. Sticky (`y`), so a position nothing matches is an error\n // instead of a gap.\n const token =\n /(\\(|\\)|,|==|!=|<=|>=|<>|<|>|[-+*/%]|not\\s+in\\b|in\\b|and\\b|or\\b|not\\b|\\[[^\\]]*\\]|'[^']*'|\"[^\"]*\"|\\d+\\.?\\d*|\\w+(?:\\.\\w+)*)/iy;\n const space = /\\s*/y;\n let at = 0;\n\n for (;;) {\n space.lastIndex = at;\n space.exec(expr);\n at = space.lastIndex;\n if (at >= expr.length) return tokens;\n\n token.lastIndex = at;\n const match = token.exec(expr);\n if (!match) {\n throw new Error(`Unexpected \"${expr[at]}\" at character ${at + 1} of: ${expr}`);\n }\n tokens.push({ type: getTokenType(match[0]), value: match[0], position: tokens.length });\n at = token.lastIndex;\n }\n}\n\n/**\n * Determines the type of a token based on its text value.\n */\nfunction getTokenType(text: string): TokenType {\n const lowerText = text.toLowerCase().trim();\n\n // Python's constants, and their JSON spellings\n if (CONSTANTS.has(text)) {\n return 'CONSTANT';\n }\n\n // Logical operators (case-insensitive)\n if (lowerText === 'and' || lowerText === 'or' || lowerText === 'not') {\n return 'LOGICAL';\n }\n\n // Comparison operators (case-insensitive for word operators)\n if (\n ['==', '!=', '<>', '<', '>', '<=', '>='].includes(text) ||\n lowerText === 'in' ||\n lowerText === 'not in'\n ) {\n return 'OPERATOR';\n }\n\n // Parentheses\n if (text === '(' || text === ')') {\n return 'PAREN';\n }\n\n // Arithmetic, and the comma between a function's values\n if (ARITHMETIC.has(text)) {\n return 'ARITHMETIC';\n }\n if (text === ',') {\n return 'COMMA';\n }\n\n // Lists (start with '[')\n if (text.startsWith('[')) {\n return 'LIST';\n }\n\n // Strings (start with ' or \")\n if (text.startsWith(\"'\") || text.startsWith('\"')) {\n return 'STRING';\n }\n\n // Numbers (integer or float; a minus sign before one is its own token)\n if (/^\\d+\\.?\\d*$/.test(text)) {\n return 'NUMBER';\n }\n\n // Default to identifier\n return 'IDENTIFIER';\n}\n", "/**\n * Expression parser, ported from the React form engine and grown arithmetic\n * and functions.\n *\n * Recursive descent parser that converts tokens into an Abstract Syntax Tree (AST).\n * Implements Python-like operator precedence:\n * 1. OR (lowest precedence)\n * 2. AND\n * 3. NOT\n * 4. Comparison operators (==, !=, <, >, <=, >=, in, not in)\n * 5. + and -\n * 6. *, / and %\n * 7. A minus sign before a value\n * 8. Values, identifiers and function calls (highest precedence)\n */\n\nimport { CONSTANTS, type Token } from './tokenizer';\nimport { FUNCTIONS, takesInWords } from './functions';\n\n/**\n * AST Node Types\n */\nexport type ASTNode = BinaryOpNode | UnaryOpNode | LiteralNode | IdentifierNode | CallNode;\n\nexport interface BinaryOpNode {\n type: 'BinaryOp';\n operator: string;\n left: ASTNode;\n right: ASTNode;\n}\n\nexport interface UnaryOpNode {\n type: 'UnaryOp';\n operator: string;\n operand: ASTNode;\n}\n\nexport interface LiteralNode {\n type: 'Literal';\n value: unknown;\n}\n\nexport interface IdentifierNode {\n type: 'Identifier';\n name: string;\n}\n\n/** A function called with its values: `round(price * qty, 2)`. */\nexport interface CallNode {\n type: 'Call';\n name: string;\n args: ASTNode[];\n}\n\n/**\n * Recursive Descent Expression Parser\n */\nexport class ExpressionParser {\n private tokens: Token[];\n private position: number = 0;\n\n constructor(tokens: Token[]) {\n this.tokens = tokens;\n }\n\n /**\n * Parse tokens into an AST\n */\n parse(): ASTNode {\n if (this.tokens.length === 0) {\n throw new Error('Cannot parse empty expression');\n }\n\n const ast = this.parseOr();\n\n // Ensure all tokens were consumed\n if (!this.isAtEnd()) {\n throw new Error(`Unexpected token at position ${this.position}: ${this.peek()?.value}`);\n }\n\n return ast;\n }\n\n /**\n * Parse OR expressions (lowest precedence)\n * or_expr: and_expr ('or' and_expr)*\n */\n private parseOr(): ASTNode {\n let left = this.parseAnd();\n\n while (this.matchLogical('or')) {\n const operator = this.previous().value;\n const right = this.parseAnd();\n left = {\n type: 'BinaryOp',\n operator: operator.toLowerCase(),\n left,\n right,\n };\n }\n\n return left;\n }\n\n /**\n * Parse AND expressions\n * and_expr: not_expr ('and' not_expr)*\n */\n private parseAnd(): ASTNode {\n let left = this.parseNot();\n\n while (this.matchLogical('and')) {\n const operator = this.previous().value;\n const right = this.parseNot();\n left = {\n type: 'BinaryOp',\n operator: operator.toLowerCase(),\n left,\n right,\n };\n }\n\n return left;\n }\n\n /**\n * Parse NOT expressions\n * not_expr: 'not' comparison | comparison\n */\n private parseNot(): ASTNode {\n if (this.matchLogical('not')) {\n const operator = this.previous().value;\n const operand = this.parseComparison();\n return {\n type: 'UnaryOp',\n operator: operator.toLowerCase(),\n operand,\n };\n }\n\n return this.parseComparison();\n }\n\n /**\n * Parse comparison expressions\n * comparison: value (comp_op value)?\n * comp_op: '==' | '!=' | '<>' | '<' | '>' | '<=' | '>=' | 'in' | 'not in'\n */\n private parseComparison(): ASTNode {\n const left = this.parseSum();\n\n const compOperators = ['==', '!=', '<>', '<', '>', '<=', '>=', 'in', 'not in'];\n if (this.matchOperator(...compOperators)) {\n const operator = this.previous().value;\n const right = this.parseSum();\n return {\n type: 'BinaryOp',\n operator: operator.toLowerCase(),\n left,\n right,\n };\n }\n\n // If no comparison operator, return value as-is (truthiness check)\n return left;\n }\n\n /**\n * Adding and taking away, left to right\n * sum: product (('+' | '-') product)*\n */\n private parseSum(): ASTNode {\n let left = this.parseProduct();\n while (this.match('ARITHMETIC', '+', '-')) {\n const operator = this.previous().value;\n left = { type: 'BinaryOp', operator, left, right: this.parseProduct() };\n }\n return left;\n }\n\n /**\n * Multiplying, dividing and the remainder, left to right\n * product: unary (('*' | '/' | '%') unary)*\n */\n private parseProduct(): ASTNode {\n let left = this.parseUnary();\n while (this.match('ARITHMETIC', '*', '/', '%')) {\n const operator = this.previous().value;\n left = { type: 'BinaryOp', operator, left, right: this.parseUnary() };\n }\n return left;\n }\n\n /**\n * A minus sign before a value: -5, -price, -(a + b)\n * unary: '-' unary | value\n */\n private parseUnary(): ASTNode {\n if (this.match('ARITHMETIC', '-')) {\n return { type: 'UnaryOp', operator: '-', operand: this.parseUnary() };\n }\n return this.parseValue();\n }\n\n /**\n * A function's name, then its values in parentheses, separated by commas.\n * call: name '(' (or_expr (',' or_expr)*)? ')'\n */\n private parseCall(name: string): ASTNode {\n const fn = FUNCTIONS.get(name);\n if (!fn) throw new Error(`no function \"${name}\": the functions are ${[...FUNCTIONS.keys()].join(', ')}`);\n this.advance(); // (\n const args: ASTNode[] = [];\n if (!this.match('PAREN', ')')) {\n do {\n args.push(this.parseOr());\n } while (this.match('COMMA'));\n this.consume('PAREN', ')', `Expected \",\" or \")\" after a value of ${name}(\u2026)`);\n }\n const [least, most] = fn.takes;\n if (args.length < least || args.length > most) throw new Error(takesInWords(name, fn.takes));\n const problem = fn.check?.(args);\n if (problem) throw new Error(problem);\n return { type: 'Call', name, args };\n }\n\n /**\n * Parse value expressions (highest precedence)\n * value: '(' or_expr ')' | literal | call | identifier\n */\n private parseValue(): ASTNode {\n // Parenthesized expression\n if (this.match('PAREN', '(')) {\n const expr = this.parseOr();\n this.consume('PAREN', ')', 'Expected closing parenthesis');\n return expr;\n }\n\n // String literal\n if (this.check('STRING')) {\n const token = this.advance();\n // Remove quotes\n const value = token.value.slice(1, -1);\n return { type: 'Literal', value };\n }\n\n // True, False, None\n if (this.check('CONSTANT')) {\n const token = this.advance();\n return { type: 'Literal', value: CONSTANTS.get(token.value) ?? null };\n }\n\n // Number literal\n if (this.check('NUMBER')) {\n const token = this.advance();\n return { type: 'Literal', value: Number(token.value) };\n }\n\n // List literal\n if (this.check('LIST')) {\n const token = this.advance();\n const value = parseListLiteral(token.value);\n return { type: 'Literal', value };\n }\n\n // A function call, or an identifier\n if (this.check('IDENTIFIER')) {\n const token = this.advance();\n const next = this.peek();\n if (next?.type === 'PAREN' && next.value === '(') return this.parseCall(token.value);\n return { type: 'Identifier', name: token.value };\n }\n\n throw new Error(`Unexpected token: ${this.peek()?.value || 'EOF'}`);\n }\n\n // ========== Helper Methods ==========\n\n /**\n * Check if current token matches any of the given types/values\n */\n private match(type: string, ...values: string[]): boolean {\n if (this.check(type)) {\n if (values.length === 0) {\n this.advance();\n return true;\n }\n const token = this.peek();\n if (token && values.includes(token.value)) {\n this.advance();\n return true;\n }\n }\n return false;\n }\n\n /**\n * Match logical operators (case-insensitive)\n */\n private matchLogical(...operators: string[]): boolean {\n const token = this.peek();\n if (token && token.type === 'LOGICAL') {\n const lowerValue = token.value.toLowerCase();\n if (operators.map(op => op.toLowerCase()).includes(lowerValue)) {\n this.advance();\n return true;\n }\n }\n return false;\n }\n\n /**\n * Match comparison operators (case-insensitive)\n */\n private matchOperator(...operators: string[]): boolean {\n const token = this.peek();\n if (token && token.type === 'OPERATOR') {\n const lowerValue = token.value.toLowerCase();\n if (operators.map(op => op.toLowerCase()).includes(lowerValue)) {\n this.advance();\n return true;\n }\n }\n return false;\n }\n\n /**\n * Check if current token has given type\n */\n private check(type: string): boolean {\n const token = this.peek();\n return token?.type === type;\n }\n\n /**\n * Consume current token and advance\n */\n private advance(): Token {\n if (!this.isAtEnd()) {\n this.position++;\n }\n return this.previous();\n }\n\n /**\n * Get current token without advancing\n */\n private peek(): Token | null {\n if (this.isAtEnd()) {\n return null;\n }\n return this.tokens[this.position];\n }\n\n /**\n * Get previous token\n */\n private previous(): Token {\n return this.tokens[this.position - 1];\n }\n\n /**\n * Check if we've consumed all tokens\n */\n private isAtEnd(): boolean {\n return this.position >= this.tokens.length;\n }\n\n /**\n * Consume a token of specific type/value or throw error\n */\n private consume(type: string, value: string, message: string): Token {\n if (this.check(type)) {\n const token = this.peek();\n if (token && token.value === value) {\n return this.advance();\n }\n }\n throw new Error(message);\n }\n}\n\n/**\n * Parse a list literal string into an array\n * Example: \"['draft', 'sent']\" -> ['draft', 'sent']\n */\nfunction parseListLiteral(listStr: string): unknown[] {\n try {\n // Remove brackets\n const content = listStr.slice(1, -1).trim();\n if (!content) {\n return [];\n }\n\n // Split by comma and parse each element\n const elements: unknown[] = [];\n let current = '';\n let inString = false;\n let stringChar = '';\n\n for (let i = 0; i < content.length; i++) {\n const char = content[i];\n\n if ((char === \"'\" || char === '\"') && (i === 0 || content[i - 1] !== '\\\\')) {\n if (!inString) {\n inString = true;\n stringChar = char;\n } else if (char === stringChar) {\n inString = false;\n stringChar = '';\n }\n }\n\n if (char === ',' && !inString) {\n elements.push(parseElement(current.trim()));\n current = '';\n } else {\n current += char;\n }\n }\n\n if (current.trim()) {\n elements.push(parseElement(current.trim()));\n }\n\n return elements;\n } catch (error) {\n // A list that cannot be read is a syntax error, not an empty list.\n throw new Error(`Cannot read the list ${listStr}`, { cause: error });\n }\n}\n\n/**\n * Parse a single element from a list\n */\nfunction parseElement(element: string): unknown {\n // String\n if ((element.startsWith(\"'\") && element.endsWith(\"'\")) ||\n (element.startsWith('\"') && element.endsWith('\"'))) {\n return element.slice(1, -1);\n }\n\n // Number\n if (!isNaN(Number(element))) {\n return Number(element);\n }\n\n // Boolean\n if (element.toLowerCase() === 'true') return true;\n if (element.toLowerCase() === 'false') return false;\n\n // Default to string\n return element;\n}\n", "import type { ASTNode } from './parser';\n\n/** Every node of an expression, each visited once, the outer before the inner. */\nfunction walk(ast: ASTNode, visit: (node: ASTNode) => void): void {\n visit(ast);\n switch (ast.type) {\n case 'BinaryOp':\n walk(ast.left, visit);\n walk(ast.right, visit);\n return;\n case 'UnaryOp':\n walk(ast.operand, visit);\n return;\n case 'Call':\n for (const arg of ast.args) walk(arg, visit);\n return;\n default:\n return;\n }\n}\n\n/** The fields an expression reads, by their first name, once each, in order of appearance. Functions are not fields. */\nexport function fieldsRead(ast: ASTNode): string[] {\n const names: string[] = [];\n walk(ast, (node) => {\n if (node.type !== 'Identifier') return;\n const root = node.name.split('.')[0];\n if (!names.includes(root)) names.push(root);\n });\n return names;\n}\n\n/** The line fields an expression adds up, as `sum(lines, 'subtotal')` names them. */\nexport function sumsRead(ast: ASTNode): { lines: string; field: string }[] {\n const sums: { lines: string; field: string }[] = [];\n walk(ast, (node) => {\n if (node.type !== 'Call' || node.name !== 'sum') return;\n const [lines, field] = node.args;\n if (lines.type === 'Identifier' && field?.type === 'Literal') sums.push({ lines: lines.name, field: field.value as string });\n });\n return sums;\n}\n", "import type { Modifier } from '../format/layout';\nimport { evaluate, truthy } from './evaluator';\nimport type { ExpressionEnv } from './functions';\nimport { ExpressionParser } from './parser';\nimport { fieldsRead } from './reads';\nimport { tokenize } from './tokenizer';\n\n/** A modifier read once, ready to evaluate against a record's values. */\nexport interface CompiledModifier {\n readonly source: Modifier | undefined;\n /** The fields it reads, by their first name, in order of appearance. */\n readonly fields: readonly string[];\n /** Whether it holds for these values; `env` gives `sum` and `count` the lines, and `today()` its day. */\n evaluate(values: Readonly<Record<string, unknown>>, env?: ExpressionEnv): boolean;\n}\n\n/**\n * Read a modifier. `true`, `false` and a missing modifier become constants;\n * an expression is parsed now, so a mistake surfaces here and not on the\n * first keystroke. Throws when the expression cannot be read.\n */\nexport function compileModifier(modifier: Modifier | undefined): CompiledModifier {\n if (typeof modifier !== 'string') {\n const value = modifier === true;\n return { source: modifier, fields: [], evaluate: () => value };\n }\n const ast = new ExpressionParser(tokenize(modifier)).parse();\n return {\n source: modifier,\n fields: fieldsRead(ast),\n evaluate(values, env) {\n try {\n return truthy(evaluate(ast, values, env));\n } catch {\n return false;\n }\n },\n };\n}\n", "import { evaluate } from './evaluator';\nimport type { ExpressionEnv } from './functions';\nimport { ExpressionParser } from './parser';\nimport { fieldsRead, sumsRead } from './reads';\nimport { tokenize } from './tokenizer';\n\nexport type { ExpressionEnv } from './functions';\n\n/** An expression read once, ready to work out a value from a record's values many times. */\nexport interface CompiledExpression {\n readonly source: string;\n /** The fields it reads, by their first name, in order of appearance. */\n readonly fields: readonly string[];\n /** The line fields it adds up, as `sum(lines, 'subtotal')` names them. */\n readonly sums: readonly { lines: string; field: string }[];\n /** The value, or null when it cannot be worked out. Never throws. */\n evaluate(values: Readonly<Record<string, unknown>>, env?: ExpressionEnv): unknown;\n}\n\n/**\n * Read an expression for a value, such as `price * qty` or\n * `if(total > 1000, 10, 0)`. It is parsed now, so a mistake surfaces when the\n * page is read and not on the first keystroke: throws when it cannot be read.\n */\nexport function compileExpression(source: string): CompiledExpression {\n const ast = new ExpressionParser(tokenize(source)).parse();\n return {\n source,\n fields: fieldsRead(ast),\n sums: sumsRead(ast),\n evaluate(values, env = {}) {\n try {\n return evaluate(ast, values as Record<string, unknown>, env) ?? null;\n } catch {\n return null;\n }\n },\n };\n}\n", "/**\n * The order to work fields out in: each after the fields it reads. `reads`\n * maps each worked-out field to the fields its expression reads; names not in\n * the map are plain values and need no order. A circle \u2014 a field read, at\n * some remove, by itself \u2014 has no order: it is listed among the cycles, as\n * the fields around it (`a \u2192 b \u2192 a`), and its fields still come out once each.\n */\nexport function dependencyOrder(reads: ReadonlyMap<string, readonly string[]>): { order: string[]; cycles: string[][] } {\n const order: string[] = [];\n const cycles: string[][] = [];\n const done = new Set<string>();\n const path: string[] = [];\n const visit = (name: string): void => {\n if (done.has(name)) return;\n const at = path.indexOf(name);\n if (at !== -1) {\n cycles.push([...path.slice(at), name]);\n return;\n }\n path.push(name);\n for (const read of reads.get(name) ?? []) if (reads.has(read)) visit(read);\n path.pop();\n done.add(name);\n order.push(name);\n };\n for (const name of reads.keys()) visit(name);\n return { order, cycles };\n}\n", "import type { Field, Fields, FilterItem, LineField, LineKinds } from './field';\nimport type { FieldNode, LayoutNode, ListNode, RootLayout, SheetNode, TabsNode } from './layout';\nimport type { Page } from './page';\nimport { compileModifier } from '../expression/modifier';\nimport { compileExpression } from '../expression/expression';\nimport { dependencyOrder } from '../expression/order';\n\nexport interface PageIssue {\n /** Where the problem is, as a path into the page: `layout.children[0].field`. */\n path: string;\n message: string;\n}\n\nexport type PageValidation = { ok: true; page: Page } | { ok: false; issues: PageIssue[] };\n\nconst has = (record: object, key: string) => Object.prototype.hasOwnProperty.call(record, key);\n\n/** The kinds of field an expression can give a value to: the rest hold records, lines or files. */\nconst EXPRESSIBLE = new Set(['char', 'text', 'html', 'integer', 'float', 'monetary', 'boolean', 'date', 'datetime', 'selection', 'json']);\nconst EXPRESSIBLE_WORDS = 'text, numbers, yes or no, dates, choices and json can';\n\n/** Where an expression's names are looked up: the page's fields, or the fields of one one2many's lines. */\ninterface Scope {\n fields: Record<string, Field | LineField>;\n /** The one2many whose lines these are; none for the page's own fields. */\n lines?: string;\n}\n\n/** Names quoted and joined as a person lists them: \"a\", \"b\" and \"c\". */\nconst listed = (names: string[]) => {\n const quoted = names.map((name) => `\"${name}\"`);\n return quoted.length < 2 ? quoted.join('') : `${quoted.slice(0, -1).join(', ')} and ${quoted[quoted.length - 1]}`;\n};\n\n/** The second pass of every check: ids unique, every name defined, every condition readable. */\nexport class ReferenceCheck {\n private readonly issues: PageIssue[] = [];\n private readonly ids = new Map<string, string>();\n\n constructor(private readonly page: Page) {}\n\n run(): PageIssue[] {\n this.checkFields(this.page.fields, 'fields');\n this.walkRoot(this.page.layout, 'layout');\n return this.issues;\n }\n\n private report(path: string, message: string) {\n this.issues.push({ path, message });\n }\n\n private claim(id: string, path: string) {\n const first = this.ids.get(id);\n if (first !== undefined) this.report(path, `duplicate id \"${id}\", also used at ${first}`);\n else this.ids.set(id, path);\n }\n\n /** The field a reference names, or a reported issue and undefined. */\n private need(name: string, path: string, scope: Record<string, Field | LineField> = this.page.fields) {\n if (has(scope, name)) return scope[name];\n this.report(path, `no field \"${name}\"`);\n return undefined;\n }\n\n /** Every modifier on `owner` must read, and read only fields of this page (or of its line). */\n private checkModifiers(owner: object, path: string, keys: readonly string[] = ['invisible'], scope: Scope = { fields: this.page.fields }) {\n for (const key of keys) {\n const value = (owner as Record<string, unknown>)[key];\n if (typeof value !== 'string') continue;\n let fields: readonly string[];\n try {\n fields = compileModifier(value).fields;\n } catch (error) {\n this.report(`${path}.${key}`, `cannot read \"${value}\": ${(error as Error).message}`);\n continue;\n }\n this.checkReads(value, fields, `${path}.${key}`, scope);\n }\n }\n\n /** Each name an expression reads must be a field where it is worked out. */\n private checkReads(source: string, fields: readonly string[], path: string, scope: Scope) {\n for (const name of fields) {\n if (has(scope.fields, name)) continue;\n const where = scope.lines === undefined ? 'of this page' : `of the lines of \"${scope.lines}\"`;\n this.report(path, `\"${source}\" reads \"${name}\", which is not a field ${where}`);\n }\n }\n\n /**\n * An expression for a value must read, read only fields where it is worked\n * out, and add up only line fields that exist. Returns the fields it reads,\n * or null when it cannot be read.\n */\n private checkExpression(source: string, path: string, scope: Scope): readonly string[] | null {\n let compiled: ReturnType<typeof compileExpression>;\n try {\n compiled = compileExpression(source);\n } catch (error) {\n this.report(path, `cannot read \"${source}\": ${(error as Error).message}`);\n return null;\n }\n this.checkReads(source, compiled.fields, path, scope);\n for (const sum of compiled.sums) {\n if (!has(scope.fields, sum.lines)) continue;\n const lines = scope.fields[sum.lines];\n if (lines.type !== 'one2many') this.report(path, `sum adds up the lines of a one2many; \"${sum.lines}\" is a ${lines.type}`);\n else if (!has(lines.fields, sum.field)) this.report(path, `\"${sum.field}\" is not a field of the lines of \"${sum.lines}\"`);\n }\n return compiled.fields;\n }\n\n /**\n * Worked-out values and values set by a condition, among one set of fields:\n * each expression checked, and no two values worked out from each other.\n */\n private checkWorkedOut(fields: Record<string, Field | LineField>, base: string, scope: Scope) {\n const reads = new Map<string, readonly string[]>();\n for (const [name, def] of Object.entries(fields)) {\n const path = `${base}.${name}`;\n if ((def.compute !== undefined || def.setWhen) && !EXPRESSIBLE.has(def.type)) {\n if (def.compute !== undefined) this.report(`${path}.compute`, `a ${def.type} cannot be worked out; ${EXPRESSIBLE_WORDS}`);\n if (def.setWhen) this.report(`${path}.setWhen`, `a ${def.type} cannot be set by a condition; ${EXPRESSIBLE_WORDS}`);\n continue;\n }\n if (def.compute !== undefined) {\n const read = this.checkExpression(def.compute, `${path}.compute`, scope);\n if (read) reads.set(name, read);\n }\n def.setWhen?.forEach((item, i) => {\n this.checkModifiers(item, `${path}.setWhen[${i}]`, ['when'], scope);\n this.checkExpression(item.value, `${path}.setWhen[${i}].value`, scope);\n });\n }\n for (const cycle of dependencyOrder(reads).cycles) {\n const names = cycle.slice(0, -1);\n const message = names.length === 1 ? `\"${names[0]}\" is worked out from itself` : `${listed(names)} are worked out from each other: ${cycle.join(' \u2192 ')}`;\n this.report(`${base}.${cycle[0]}.compute`, message);\n }\n }\n\n private checkFields(fields: Fields | Record<string, LineField>, base: string, lines?: string) {\n this.checkWorkedOut(fields, base, { fields, lines });\n for (const [name, def] of Object.entries(fields)) {\n const path = `${base}.${name}`;\n if (def.type === 'monetary' && def.currencyField !== undefined) {\n const currency = this.need(def.currencyField, `${path}.currencyField`, fields);\n if (currency && !['many2one', 'selection', 'char'].includes(currency.type)) {\n this.report(\n `${path}.currencyField`,\n `\"${def.currencyField}\" is a ${currency.type}; a currency field must be a many2one, selection or char`\n );\n }\n }\n if ((def.type === 'many2one' || def.type === 'many2many') && def.filter) {\n // Groups nest: each valueFrom inside them must name a field too.\n const walk = (item: FilterItem, at: string): void => {\n if ('any' in item) return item.any.forEach((inner, i) => walk(inner, `${at}.any[${i}]`));\n if ('all' in item) return item.all.forEach((inner, i) => walk(inner, `${at}.all[${i}]`));\n if (item.valueFrom !== undefined) this.need(item.valueFrom, `${at}.valueFrom`, fields);\n };\n def.filter.forEach((item, i) => {\n walk(item, `${path}.filter[${i}]`);\n });\n }\n if (def.type === 'selection') def.optionsFrom?.dependsOn?.forEach((other, i) => this.need(other, `${path}.optionsFrom.dependsOn[${i}]`, fields));\n if (def.type === 'properties' && def.definitions) {\n const seen = new Set<string>();\n def.definitions.forEach((property, i) => {\n if (property.type === 'selection' && !property.options) {\n this.report(`${path}.definitions[${i}].options`, 'a choice property needs its choices');\n }\n if (seen.has(property.name)) this.report(`${path}.definitions[${i}].name`, `\"${property.name}\" is named twice`);\n seen.add(property.name);\n });\n }\n if (def.type === 'one2many') {\n this.checkFields(def.fields, `${path}.fields`, name);\n if (def.lineKinds) this.checkLineKinds(name, def.lineKinds, def.fields, `${path}.lineKinds`);\n if (def.sequenceField !== undefined) {\n const sequence = def.fields[def.sequenceField];\n if (!sequence) this.report(`${path}.sequenceField`, `\"${def.sequenceField}\" is not a field of the lines of \"${name}\"`);\n else if (sequence.type !== 'integer') {\n this.report(`${path}.sequenceField`, `\"${def.sequenceField}\" is a ${sequence.type}; the field that keeps the order of lines must be an integer`);\n }\n }\n }\n }\n }\n\n private checkLineKinds(field: string, kinds: LineKinds, lineFields: Record<string, LineField>, path: string) {\n const kindField = lineFields[kinds.field];\n if (!kindField) this.report(`${path}.field`, `\"${kinds.field}\" is not a field of the lines of \"${field}\"`);\n else if (kindField.type !== 'selection' && kindField.type !== 'char') {\n this.report(`${path}.field`, `\"${kinds.field}\" is a ${kindField.type}; the field that says what a line is must be a selection or char`);\n } else if (kindField.type === 'selection') {\n for (const which of ['section', 'note'] as const) {\n const value = kinds[which] ?? which;\n if (!kindField.options.some((o) => o.value === value)) this.report(`${path}.${which}`, `\"${kinds.field}\" has no option \"${value}\"`);\n }\n }\n const text = lineFields[kinds.text];\n if (!text) this.report(`${path}.text`, `\"${kinds.text}\" is not a field of the lines of \"${field}\"`);\n else if (text.type !== 'char' && text.type !== 'text') {\n this.report(`${path}.text`, `\"${kinds.text}\" is a ${text.type}; a section's or note's text must be a char or text field`);\n }\n }\n\n private walkRoot(root: RootLayout, path: string) {\n if (root.type === 'tabs') return this.walkNode(root, path);\n this.claim(root.id, path);\n if (root.type === 'sheet') return this.walkSheet(root, path);\n if (root.type === 'sections') return this.walkChildren(root.children, path);\n if (root.type === 'list') return this.walkList(root, path);\n root.children.forEach((step, i) => {\n const stepPath = `${path}.children[${i}]`;\n this.claim(step.id, stepPath);\n this.checkModifiers(step, stepPath);\n this.walkChildren(step.children, stepPath);\n });\n }\n\n private walkList(list: ListNode, path: string) {\n if (this.page.data.kind !== 'record') this.report('data', 'a list shows records: its data needs kind \"record\" and a model');\n list.columns.forEach((name, i) => this.need(name, `${path}.columns[${i}]`));\n list.sort?.forEach((order, i) => this.need(order.field, `${path}.sort[${i}].field`));\n list.searchFields?.forEach((name, i) => this.need(name, `${path}.searchFields[${i}]`));\n list.groupBy?.forEach((name, i) => this.need(name, `${path}.groupBy[${i}]`));\n // A list's filters are about its own records: their fields are the page's, and there is no record to take a value from.\n const walk = (item: FilterItem, at: string): void => {\n if ('any' in item) return item.any.forEach((inner, i) => walk(inner, `${at}.any[${i}]`));\n if ('all' in item) return item.all.forEach((inner, i) => walk(inner, `${at}.all[${i}]`));\n this.need(item.field, `${at}.field`);\n if (item.valueFrom !== undefined) this.report(`${at}.valueFrom`, \"a list's filter compares with values, not with another field\");\n };\n const named = new Set<string>();\n list.filters?.forEach((filter, i) => {\n this.claim(filter.id, `${path}.filters[${i}]`);\n named.add(filter.id);\n filter.filter.forEach((item, j) => walk(item, `${path}.filters[${i}].filter[${j}]`));\n });\n list.defaultFilters?.forEach((id, i) => {\n if (!named.has(id)) this.report(`${path}.defaultFilters[${i}]`, `no filter \"${id}\" in this list`);\n });\n list.actions?.forEach((button, i) => this.claim(button.id, `${path}.actions[${i}]`));\n }\n\n private walkChildren(children: LayoutNode[], path: string) {\n children.forEach((child, i) => this.walkNode(child, `${path}.children[${i}]`));\n }\n\n private walkNode(node: LayoutNode, path: string) {\n this.claim(node.id, path);\n this.checkModifiers(node, path, node.type === 'field' ? ['invisible', 'readonly', 'required'] : node.type === 'section' ? ['invisible', 'readonly'] : ['invisible']);\n switch (node.type) {\n case 'field':\n return this.checkFieldNode(node, path);\n case 'section':\n if (node.collapsible && !node.title) this.report(path, 'a collapsible section needs a title to fold it by');\n if (node.collapsed && !node.collapsible) this.report(path, 'collapsed needs collapsible: true');\n return this.walkChildren(node.children, path);\n case 'tabs':\n return this.walkTabs(node, path);\n default:\n return;\n }\n }\n\n private walkTabs(node: TabsNode, path: string) {\n node.children.forEach((tab, i) => {\n const tabPath = `${path}.children[${i}]`;\n this.claim(tab.id, tabPath);\n this.checkModifiers(tab, tabPath);\n this.walkChildren(tab.children, tabPath);\n });\n }\n\n private walkSheet(sheet: SheetNode, path: string) {\n if (sheet.title) {\n this.need(sheet.title.field, `${path}.title.field`);\n if (sheet.title.subtitleField !== undefined) this.need(sheet.title.subtitleField, `${path}.title.subtitleField`);\n if (sheet.title.avatarField !== undefined) this.need(sheet.title.avatarField, `${path}.title.avatarField`);\n }\n if (sheet.statusbar) {\n const { field, visibleStates } = sheet.statusbar;\n const def = this.need(field, `${path}.statusbar.field`);\n if (def && def.type !== 'selection' && def.type !== 'many2one') {\n this.report(`${path}.statusbar.field`, `\"${field}\" is a ${def.type}; a statusbar needs a selection or many2one`);\n }\n if (def?.type === 'selection' && visibleStates) {\n const values = new Set(def.options.map((o) => o.value));\n visibleStates.forEach((state, i) => {\n if (!values.has(state)) {\n this.report(`${path}.statusbar.visibleStates[${i}]`, `\"${state}\" is not an option of \"${field}\"`);\n }\n });\n }\n }\n sheet.buttons?.forEach((button, i) => {\n this.claim(button.id, `${path}.buttons[${i}]`);\n this.checkModifiers(button, `${path}.buttons[${i}]`);\n });\n sheet.statButtons?.forEach((stat, i) => {\n this.claim(stat.id, `${path}.statButtons[${i}]`);\n this.checkModifiers(stat, `${path}.statButtons[${i}]`);\n if (stat.field !== undefined) this.need(stat.field, `${path}.statButtons[${i}].field`);\n });\n if (sheet.ribbon) {\n this.claim(sheet.ribbon.id, `${path}.ribbon`);\n this.checkModifiers(sheet.ribbon, `${path}.ribbon`);\n }\n sheet.badges?.forEach((badge, i) => {\n this.claim(badge.id, `${path}.badges[${i}]`);\n this.checkModifiers(badge, `${path}.badges[${i}]`);\n });\n for (const place of ['above', 'below'] as const) {\n sheet.title?.[place]?.forEach((node, i) => this.walkNode(node, `${path}.title.${place}[${i}]`));\n }\n sheet.alerts?.forEach((alert, i) => {\n this.claim(alert.id, `${path}.alerts[${i}]`);\n this.checkModifiers(alert, `${path}.alerts[${i}]`);\n });\n this.walkChildren(sheet.children, path);\n if (sheet.sidePanel) {\n this.claim(sheet.sidePanel.id, `${path}.sidePanel`);\n this.checkModifiers(sheet.sidePanel, `${path}.sidePanel`);\n }\n }\n\n private checkFieldNode(node: FieldNode, path: string) {\n const def = this.need(node.field, `${path}.field`);\n // Answer rules: each condition and rule across fields reads, each pattern is a regular expression.\n node.validate?.forEach((rule, i) => {\n const at = `${path}.validate[${i}]`;\n this.checkModifiers(rule, at, ['when', 'holds']);\n if (rule.pattern === undefined) return;\n try {\n new RegExp(rule.pattern);\n } catch {\n this.report(`${at}.pattern`, `\"${rule.pattern}\" is not a regular expression`);\n }\n });\n if (def && node.totals) {\n if (def.type !== 'one2many') {\n this.report(`${path}.totals`, `totals only apply to one2many fields; \"${node.field}\" is a ${def.type}`);\n } else {\n node.totals.forEach((column, i) => {\n const sub = has(def.fields, column) ? def.fields[column] : undefined;\n if (!sub) this.report(`${path}.totals[${i}]`, `\"${column}\" is not a field of the lines of \"${node.field}\"`);\n else if (!['integer', 'float', 'monetary'].includes(sub.type)) {\n this.report(`${path}.totals[${i}]`, `\"${column}\" is a ${sub.type}; only integer, float and monetary columns add up`);\n }\n });\n }\n }\n // Options that point at another field: by convention their names end in \"Field\".\n for (const [key, value] of Object.entries(node.options ?? {})) {\n if (key.endsWith('Field') && typeof value === 'string') this.need(value, `${path}.options.${key}`);\n }\n if (def && node.editMode && def.type !== 'one2many') {\n this.report(`${path}.editMode`, `editMode only applies to one2many fields; \"${node.field}\" is a ${def.type}`);\n }\n if (def && node.optionalColumns) {\n if (def.type !== 'one2many') {\n this.report(`${path}.optionalColumns`, `optional columns only apply to one2many fields; \"${node.field}\" is a ${def.type}`);\n } else {\n // The columns the table shows: those named, or every line field but the structural ones.\n const shown = node.columns ?? Object.keys(def.fields).filter((c) => c !== def.lineKinds?.field && c !== def.sequenceField);\n for (const column of Object.keys(node.optionalColumns)) {\n if (!shown.includes(column)) this.report(`${path}.optionalColumns.${column}`, `\"${column}\" is not a column of \"${node.field}\"`);\n }\n }\n }\n if (!def || !node.columns) return;\n if (def.type === 'one2many') {\n node.columns.forEach((column, i) => {\n if (!has(def.fields, column)) {\n this.report(`${path}.columns[${i}]`, `\"${column}\" is not a field of the lines of \"${node.field}\"`);\n }\n });\n } else if (def.type !== 'many2many') {\n this.report(`${path}.columns`, `columns only apply to one2many and many2many fields; \"${node.field}\" is a ${def.type}`);\n }\n }\n}\n", "import { FIELD_TYPES } from './names';\nimport type { Page } from './page';\nimport { ReferenceCheck, type PageIssue, type PageValidation } from './references';\nimport { FORMAT_VERSION } from './version';\n\nconst isObject = (value: unknown): value is Record<string, unknown> => value !== null && typeof value === 'object' && !Array.isArray(value);\nconst LAYOUTS = ['sheet', 'sections', 'tabs', 'wizard'];\n\n/**\n * The check a page gets as it is shown: its outline, then every name and\n * condition in it, the same as `validatePage` finds them. It leaves out the\n * key-by-key check of the format, and so the validation library, which an app\n * showing forms need not carry; run `validatePage` where pages are made or\n * tested. A page that passes is handed back as it is.\n */\nexport function checkPage(input: unknown): PageValidation {\n if (!isObject(input)) return { ok: false, issues: [{ path: '(page)', message: 'a page is a JSON object' }] };\n const issues: PageIssue[] = [];\n const say = (path: string, message: string) => issues.push({ path, message });\n if (input['fieldia'] !== FORMAT_VERSION) say('fieldia', `this build reads format ${FORMAT_VERSION}`);\n if (typeof input['id'] !== 'string' || !input['id']) say('id', 'a page needs an id');\n const data = input['data'];\n if (!isObject(data) || !(data['kind'] === 'responses' || (data['kind'] === 'record' && typeof data['model'] === 'string' && data['model']))) {\n say('data', 'data is { \"kind\": \"record\", \"model\": \u2026 } or { \"kind\": \"responses\" }');\n }\n const fields = input['fields'];\n if (!isObject(fields)) say('fields', 'fields is an object of field definitions, by name');\n else {\n for (const [name, def] of Object.entries(fields)) {\n if (!isObject(def) || !(FIELD_TYPES as readonly unknown[]).includes(def['type']) || typeof def['label'] !== 'string') {\n say(`fields.${name}`, 'a field needs a type Fieldia knows and a label');\n }\n }\n }\n const layout = input['layout'];\n const isList = isObject(layout) && layout['type'] === 'list';\n if (!isObject(layout) || (isList ? !Array.isArray(layout['columns']) : !LAYOUTS.includes(layout['type'] as string) || !Array.isArray(layout['children']))) {\n say('layout', 'the layout is a sheet, sections, tabs or wizard, with children, or a list with columns');\n }\n if (issues.length) return { ok: false, issues };\n const page = input as unknown as Page;\n try {\n const found = new ReferenceCheck(page).run();\n return found.length ? { ok: false, issues: found } : { ok: true, page };\n } catch (error) {\n return { ok: false, issues: [{ path: '(page)', message: `a part of this page cannot be read: ${(error as Error).message}` }] };\n }\n}\n", "import type { Page } from './page';\n\n/**\n * Keys whose text a person reads: titles, labels, help, prompts and messages.\n * Any key ending in `Label` is read too \u2014 a wizard's `nextLabel`, and in a\n * widget's settings the words at a scale's ends.\n */\nconst TEXT_KEYS = new Set(['title', 'description', 'label', 'help', 'placeholder', 'message', 'text', 'confirm', 'alt', 'caption']);\n\n/**\n * Parts that hold names or data, never words to translate: which line fields\n * mark sections and notes, a link's filter, a default value, what the page's\n * data is, and the page's translations themselves.\n */\nconst NOT_TEXT = new Set(['lineKinds', 'filter', 'default', 'data', 'translations']);\n\n/**\n * Every word a person reads in `value` passed through `text`, the rest copied\n * as it is. `enter` sees each object before its parts. In a widget's settings\n * (`widget`) only the keys ending in `Label` are words.\n */\nfunction walk(value: unknown, key: string | null, text: (words: string) => string, enter?: (node: Record<string, unknown>) => void, widget = false): unknown {\n if (typeof value === 'string') return key !== null && (key.endsWith('Label') || (!widget && TEXT_KEYS.has(key))) ? text(value) : value;\n if (Array.isArray(value)) return value.map((item) => walk(item, null, text, enter, widget));\n if (value === null || typeof value !== 'object') return value;\n enter?.(value as Record<string, unknown>);\n const out: Record<string, unknown> = {};\n for (const [name, inner] of Object.entries(value)) {\n // A field node's `options` are its widget's settings, not a list of choices.\n out[name] = NOT_TEXT.has(name) ? inner : walk(inner, name, text, enter, widget || (name === 'options' && !Array.isArray(inner)));\n }\n return out;\n}\n\n/**\n * The page with every word a person reads passed through the app's own\n * translator, for apps that keep their translations by text or by key. Ids,\n * field names, choice values, conditions and data stay as they are; the page\n * given is left alone.\n */\nexport function translatePage(page: Page, translate: (text: string) => string): Page {\n return walk(page, null, translate) as Page;\n}\n\n/**\n * Every word of the page a person reads, once each, in the order they read\n * it: the title and description, then each part of the layout \u2014 a field where\n * it stands, with its label, the words in its box, its help, its choices and\n * its messages \u2014 a wizard's buttons under its pages, and last the words of\n * fields no part shows. The same words `translatePage` translates: the list a\n * translator works through.\n */\nexport function pageWords(page: Page): string[] {\n const words = new Set<string>();\n const fields = page.fields as Record<string, Record<string, unknown>>;\n const visit = (value: unknown, key: string | null = null): unknown =>\n walk(\n value,\n key,\n (text) => (text.trim() && words.add(text), text),\n (node) => {\n // A wizard's pages before its buttons.\n if (node['type'] === 'wizard') visit(node['children']);\n const def = node['type'] === 'field' ? fields[node['field'] as string] : undefined;\n if (!def) return;\n for (const [part, name] of [[node, 'label'], [def, 'label'], [node, 'placeholder'], [node, 'help'], [def, 'help']] as const) visit(part[name], name);\n visit(def);\n }\n );\n visit({ title: page.title, description: page.description, layout: page.layout });\n visit(page);\n return [...words];\n}\n\n/**\n * The page in one of the languages it keeps in `translations`: every word a\n * person reads that has a translation there, translated; the rest as written.\n * A language the page does not keep gives the page as it is.\n */\nexport function localizePage(page: Page, locale: string): Page {\n const words = page.translations?.[locale] ?? page.translations?.[locale.split('-')[0]];\n if (!words) return page;\n return translatePage(page, (text) => words[text] ?? text);\n}\n\n/**\n * Whether a language is written right to left, by its tag: the script it\n * names (`az-Arab`), or else its language (`ar`, `he`, `fa-IR`).\n */\nexport function isRightToLeft(tag: string): boolean {\n const [language, ...rest] = tag.toLowerCase().split('-');\n const script = rest.find((part) => part.length === 4 && !/\\d/.test(part));\n return script ? /^(arab|hebr|syrc|thaa|nkoo|adlm|rohg)$/.test(script) : /^(ar|he|iw|fa|ur|ps|sd|yi|dv|ckb|ug|ks|syr|prs|pnb|azb)$/.test(language);\n}\n", "/**\n * evaluateModifier - Evaluate modifier expressions with form context\n *\n * Phase 2 implementation with full expression parser.\n * Supports Python-like expressions used in Flectra modifiers.\n *\n * Structura Reference:\n * - DynBehaviorManager.evaluateCondition() method\n * - Supports Python-like expressions: \"state == 'draft' and amount > 100\"\n *\n * Supported features:\n * - Comparison operators: ==, !=, <>, <, >, <=, >=\n * - In operators: in, not in\n * - Logical operators: and, or, not\n * - Parentheses for precedence\n * - Nested field access: partner_id.country_id.name\n * - Truthiness checks: partner_id (true if partner_id has value)\n *\n * @param expression - The modifier expression to evaluate\n * @param context - Current form values\n * @returns Boolean result of evaluation\n *\n * @example\n * ```typescript\n * // Simple boolean\n * evaluateModifier(true, {}) // => true\n *\n * // String boolean\n * evaluateModifier('1', {}) // => true\n * evaluateModifier('True', {}) // => true\n *\n * // Field truthiness\n * evaluateModifier('is_company', { is_company: true }) // => true\n * evaluateModifier('partner_id', { partner_id: null }) // => false\n *\n * // Comparison expressions\n * evaluateModifier(\"state == 'done'\", { state: 'done' }) // => true\n * evaluateModifier(\"amount > 100\", { amount: 150 }) // => true\n *\n * // Logical expressions\n * evaluateModifier(\"state == 'draft' and amount > 100\", { state: 'draft', amount: 150 }) // => true\n * evaluateModifier(\"state in ['draft', 'sent']\", { state: 'draft' }) // => true\n *\n * // Nested field access\n * evaluateModifier(\"partner_id.country_id == 5\", { partner_id: { country_id: 5 } }) // => true\n * ```\n */\n\nimport { tokenize } from './tokenizer';\nimport { ExpressionParser } from './parser';\nimport { evaluate, truthy } from './evaluator';\n\nexport function evaluateModifier(\n expression: string | boolean | undefined,\n context: Record<string, unknown>\n): boolean {\n // Undefined modifier = false (field is not affected)\n if (expression === undefined) {\n return false;\n }\n\n // Direct boolean value\n if (typeof expression === 'boolean') {\n return expression;\n }\n\n // String representation of boolean\n if (expression === '1' || expression === 'True' || expression === 'true') {\n return true;\n }\n\n if (expression === '0' || expression === 'False' || expression === 'false') {\n return false;\n }\n\n // Empty string = false\n if (expression === '') {\n return false;\n }\n\n // Parse and evaluate complex expression\n try {\n const tokens = tokenize(expression);\n\n // Empty token list\n if (tokens.length === 0) {\n return false;\n }\n\n const parser = new ExpressionParser(tokens);\n const ast = parser.parse();\n const result = evaluate(ast, context);\n\n // Convert result to boolean\n return truthy(result);\n } catch {\n // A page is validated before it runs (validatePage reads every\n // expression), so this only guards pages that skipped validation.\n // Fail safely - return false so field is not hidden/disabled by broken modifier\n return false;\n }\n}\n\n/**\n * Check if a modifier expression is valid and can be parsed\n *\n * @param expression - The modifier expression to check\n * @returns true if expression is valid, false otherwise\n */\nexport function isModifierValid(expression: string | boolean | undefined): boolean {\n if (expression === undefined || typeof expression === 'boolean') {\n return true;\n }\n\n if (expression === '') {\n return true;\n }\n\n try {\n const tokens = tokenize(expression);\n if (tokens.length === 0) {\n return true;\n }\n const parser = new ExpressionParser(tokens);\n parser.parse();\n return true;\n } catch {\n return false;\n }\n}\n", "export const LANGUAGES = {};", "import { LANGUAGES } from './locales/all';\n\n/**\n * Validation messages, by language. `{label}` is the field's label; the other\n * placeholders are named in each English message. English keeps the React\n * engine's wording; Arabic, German and French build on its translations.\n */\nexport interface Messages {\n required: string;\n maxLength: string;\n pattern: string;\n text: string;\n number: string;\n integer: string;\n min: string;\n max: string;\n decimals: string;\n boolean: string;\n dateFormat: string;\n dateInvalid: string;\n datetimeFormat: string;\n datetimeInvalid: string;\n choice: string;\n /** A choice of a field with an \"Other\" answer. */\n choiceOrOther: string;\n /** A matrix: the value is not an answer per row; a row it does not have; rows left unanswered. */\n matrix: string;\n matrixRow: string;\n matrixRows: string;\n choices: string;\n record: string;\n records: string;\n reference: string;\n file: string;\n fileSize: string;\n fileType: string;\n /** Several files: fewer than the fewest (never under two: one is what required asks), more than the most. */\n minFiles: string;\n maxFiles: string;\n /**\n * Answer rules, besides the messages above they share (maxLength, pattern,\n * min, max): a shortest length, an ending, how many may be ticked, a day\n * in the past or the future.\n */\n minLength: string;\n endsWith: string;\n atLeast: string;\n atMost: string;\n datePast: string;\n dateFuture: string;\n /** A rule across fields that does not hold, when it says nothing of its own. */\n holds: string;\n /** Joins the last two items of a list: \"PDF or image\". */\n or: string;\n /** A tick box that must be ticked to go on, as an \"I agree\" box. */\n tick: string;\n /** What to type in an email, a web address, a phone number and a time of day, by example. */\n email: string;\n url: string;\n phone: string;\n time: string;\n /** A date or a time outside its earliest (`{min}`) or latest (`{max}`), and a day of the week it may not fall on (`{days}`). */\n before: string;\n after: string;\n weekday: string;\n /** A table's or a repeating group's lines: fewer than its least, more than its most. */\n minLines: string;\n maxLines: string;\n /** An address's parts, as its boxes name them, for one that must be filled: street, line 2, city, region, postcode, country. */\n addressParts: string;\n /** The language the days in these messages are written in, as Intl reads it. */\n locale: string;\n}\n\nexport type Locale = 'en' | 'ar' | 'de' | 'fr';\n\n/** English: always here, and the words a language leaves out. */\nconst en: Messages = {\n required: '{label} is required',\n maxLength: 'Maximum {max} characters allowed',\n pattern: '{label} is not in the expected format',\n text: '{label} must be text',\n number: '{label} must be a number',\n integer: '{label} must be a whole number',\n min: '{label} must be at least {min}',\n max: '{label} must be at most {max}',\n decimals: 'Maximum {digits} decimal places allowed',\n boolean: '{label} must be yes or no',\n dateFormat: 'Invalid date format (expected YYYY-MM-DD)',\n dateInvalid: 'Invalid date (check month/day values)',\n datetimeFormat: 'Invalid date and time format (expected YYYY-MM-DDTHH:MM:SS)',\n datetimeInvalid: 'Invalid date and time (check the values)',\n choice: 'Must be one of: {options}',\n choiceOrOther: 'Must be one of: {options}, or an answer of its own',\n matrix: '{label} takes an answer for each row',\n matrixRow: 'Rows are: {rows}',\n matrixRows: 'Answer every row of {label}',\n choices: '{label} must be a list of choices',\n record: '{label} must be a record',\n records: '{label} must be a list of records',\n reference: '{label} must point to {aModels}',\n file: '{label} must be a file',\n fileSize: '{label} is larger than {size}',\n fileType: '{label} must be {aTypes} file',\n minFiles: 'Add at least {min} files to {label}',\n maxFiles: 'Too many files for {label}: at most {max}',\n minLength: '{label} must be at least {min} characters',\n endsWith: '{label} must end with {ending}',\n atLeast: 'Choose at least {min} for {label}',\n atMost: 'Choose at most {max} for {label}',\n datePast: '{label} must be in the past',\n dateFuture: '{label} must be in the future',\n holds: '{label} does not agree with the other answers',\n or: 'or',\n tick: 'Tick this box to go on',\n email: 'Enter an email address, like name@example.com',\n url: 'Enter a web address, like example.com',\n phone: 'Enter a phone number, like +20 100 123 4567',\n time: 'Enter a time, like 14:30',\n before: '{label} can\u2019t be before {min}',\n after: '{label} can\u2019t be after {max}',\n weekday: '{label} can\u2019t be on a {days}',\n minLines: 'Add at least {min} to {label}',\n maxLines: 'Too many in {label}: at most {max}',\n addressParts: 'Street address|Address line 2|City|State or region|Postcode|Country',\n locale: 'en',\n};\n\n/**\n * The messages in every language Fieldia has. This package holds all four;\n * the one-tag script holds English alone, and a page adds another language\n * with that language's script (fieldia.ar.js, \u2026), through the viewer's\n * `addLanguage`.\n */\nexport const MESSAGES: Record<Locale, Messages> = { en, ...LANGUAGES };\n\n/** Fill `{name}` placeholders. */\nexport function fill(template: string, values: Record<string, string | number>): string {\n return template.replace(/\\{(\\w+)\\}/g, (match, name: string) => (name in values ? String(values[name]) : match));\n}\n", "import type { Field, LineField } from '../format/field';\nimport { localDay } from '../expression/functions';\nimport { fill, type Messages } from './messages';\n\n/**\n * A date's limits: its earliest and latest day (`min`, `max`), each a day\n * (\"2026-03-02\") or one counted from the day the form is opened (\"today\",\n * \"today+30\", \"today-7\"), and the days of the week it may fall on (`days`,\n * ISO numbers: 1 Monday \u2026 7 Sunday). A date and time keeps them by the day\n * it falls on, where the person is.\n */\n\n/** The day a limit names, today being `today`: the day itself, or today with days added or taken away. */\nexport function dayOf(limit: string, today = localDay(new Date())): string {\n const counted = /^today([+-]\\d+)?$/.exec(limit);\n if (!counted) return limit;\n const [y, m, d] = today.split('-').map(Number);\n return new Date(Date.UTC(y, m - 1, d + Number(counted[1] ?? 0))).toISOString().slice(0, 10);\n}\n\n/** A day in words, in the messages' language: \"March 2, 2026\", \"2 \u0645\u0627\u0631\u0633 2026\". */\nconst written = (options: Intl.DateTimeFormatOptions, messages: Messages, at: number) =>\n new Intl.DateTimeFormat(messages.locale, { ...options, timeZone: 'UTC', numberingSystem: 'latn' }).format(at);\n\n/** What a day breaks of its field's limits, or undefined: before its earliest, after its latest, on a day of the week it may not fall on. */\nexport function checkDay(field: Field | LineField, value: string, today: string | undefined, messages: Messages): string | undefined {\n if (field.type !== 'date' && field.type !== 'datetime') return undefined;\n const day = field.type === 'date' ? value : localDay(new Date(value));\n const say = (key: 'before' | 'after' | 'weekday', limit: string) => fill(messages[key], { label: field.label, min: limit, max: limit, days: limit });\n const words = (limit: string) => written({ day: 'numeric', month: 'long', year: 'numeric' }, messages, Date.parse(limit));\n const min = field.min && dayOf(field.min, today);\n const max = field.max && dayOf(field.max, today);\n if (min && day < min) return say('before', words(min));\n if (max && day > max) return say('after', words(max));\n const days = field.days;\n // 1 January 2024 was a Monday: the day of the week n is the nth of that January.\n if (days && !days.includes(new Date(Date.parse(day)).getUTCDay() || 7)) {\n const not = [1, 2, 3, 4, 5, 6, 7].filter((n) => !days.includes(n)).map((n) => written({ weekday: 'long' }, messages, Date.UTC(2024, 0, n)));\n return say('weekday', not.length > 1 ? `${not.slice(0, -1).join(', ')} ${messages.or} ${not[not.length - 1]}` : not[0]);\n }\n return undefined;\n}\n", "import type { Field, LineField } from '../format/field';\nimport type { JsonValue } from '../format/json';\nimport { dayOf } from './limits';\n\n/**\n * The values a form holds while someone edits it. Plain JSON, so a draft can\n * be stored and a record handed to any data source.\n */\n\nexport type RecordId = number | string;\n\n/** A related record, as a many2one or many2many holds it: enough to show it. */\nexport interface RelatedRecord {\n id: RecordId;\n label: string;\n}\n\n/** A reference points at a record of one of several models. */\nexport interface ReferenceValue {\n model: string;\n id: RecordId;\n label: string;\n}\n\n/** An uploaded or stored file. `data` is base64; `url` is where a stored one lives. */\nexport interface FileValue {\n name: string;\n type: string;\n size: number;\n data?: string;\n url?: string;\n /** A signature typed rather than drawn: the name typed, kept beside its picture. */\n text?: string;\n}\n\n/**\n * One line of a one2many. `key` is stable for the life of the form, so a line\n * keeps its identity while it is edited; `id` is the saved record's id, absent\n * until the line is saved.\n */\nexport interface Line {\n key: string;\n id?: RecordId;\n values: Values;\n}\n\nexport type Value =\n | JsonValue\n | RelatedRecord\n | RelatedRecord[]\n | ReferenceValue\n | FileValue\n | FileValue[]\n | Line[];\n\nexport type Values = Record<string, Value>;\n\ntype AnyField = Field | LineField;\n\n/** What a field holds before anyone types in it. */\nexport function emptyValue(field: AnyField): Value {\n switch (field.type) {\n case 'boolean':\n return false;\n case 'many2many':\n case 'one2many':\n return [];\n case 'selection':\n case 'binary':\n case 'image':\n return field.multiple ? [] : null;\n default:\n return null;\n }\n}\n\n/** A fresh record: each field's default, or its empty value. A date's default may be a day counted from `today` (\"today\", \"today+1\"). */\nexport function initialValues(fields: Record<string, AnyField>, today?: string): Values {\n const values: Values = {};\n for (const [name, field] of Object.entries(fields)) {\n const start = field.default;\n values[name] = start === undefined ? emptyValue(field) : field.type === 'date' && typeof start === 'string' && start.startsWith('today') ? dayOf(start, today) : structuredCopy(start);\n }\n return values;\n}\n\n/** Nothing worth keeping: no value, blank text, or an empty list. Numbers and booleans never are. */\nexport function isEmpty(field: AnyField, value: Value | undefined): boolean {\n if (value === null || value === undefined) return true;\n if (typeof value === 'string') return value.trim() === '';\n if (Array.isArray(value)) return value.length === 0;\n // A matrix with no row answered is not answered at all.\n if (field.type === 'matrix' && typeof value === 'object') {\n return Object.values(value as Record<string, unknown>).every((a) => a === null || a === undefined || (Array.isArray(a) && !a.length));\n }\n return false;\n}\n\n/**\n * The values as modifiers read them, matching what backends write in their\n * expressions: a many2one is its id, a many2many its ids, a reference\n * \"model,id\", a file its name \u2014 several files their names \u2014 and lines a list\n * (so `not child_ids` works).\n */\nexport function expressionContext(values: Values, fields: Record<string, AnyField>): Record<string, unknown> {\n const context: Record<string, unknown> = {};\n for (const [name, value] of Object.entries(values)) {\n const field = fields[name];\n context[name] = field ? forExpressions(field, value) : value;\n }\n return context;\n}\n\nfunction forExpressions(field: AnyField, value: Value): unknown {\n if (value === null || value === undefined) return null;\n switch (field.type) {\n case 'many2one':\n return (value as RelatedRecord).id;\n case 'many2many':\n return (value as RelatedRecord[]).map((record) => record.id);\n case 'one2many':\n return (value as Line[]).map((line) => line.key);\n case 'reference': {\n const ref = value as ReferenceValue;\n return `${ref.model},${ref.id}`;\n }\n case 'binary':\n case 'image':\n return Array.isArray(value) ? (value as FileValue[]).map((file) => file.name) : (value as FileValue).name;\n default:\n return value;\n }\n}\n\n/**\n * What a line of a one2many is: a section heading, a note, or (null) an item.\n * Lines only have kinds when the field declares `lineKinds`.\n */\nexport function lineKind(field: Extract<Field, { type: 'one2many' }>, values: Values): 'section' | 'note' | null {\n const kinds = field.lineKinds;\n if (!kinds) return null;\n const value = values[kinds.field];\n if (value === (kinds.section ?? 'section')) return 'section';\n if (value === (kinds.note ?? 'note')) return 'note';\n return null;\n}\n\n/** Whether two values are the same, as they would be saved: a missing value is an empty one. */\nexport function sameValue(a: Value | undefined, b: Value | undefined): boolean {\n return JSON.stringify(a ?? null) === JSON.stringify(b ?? null);\n}\n\n/** A deep copy of plain JSON. */\nexport function structuredCopy<T>(value: T): T {\n return value === undefined ? value : (JSON.parse(JSON.stringify(value)) as T);\n}\n", "import type { Field, LineField } from '../format/field';\nimport { checkDay } from './limits';\nimport { fill, MESSAGES, type Messages } from './messages';\nimport { isEmpty, type FileValue, type ReferenceValue, type RelatedRecord, type Value } from './values';\n\n/**\n * Check one value against its field. Returns the message to show, or\n * undefined when the value is fine. The wording follows the React engine's\n * (\"Name is required\", \"Maximum 120 characters allowed\").\n *\n * An empty optional value passes everything: a pattern or a minimum applies\n * to what someone typed, not to a field they left alone.\n */\nexport function checkValue(\n field: Field | LineField,\n value: Value | undefined,\n required: boolean,\n messages: Messages = MESSAGES.en,\n /** The day it is, for a date's limits counted from today. The computer's own when left out. */\n today?: string\n): string | undefined {\n const label = field.label || 'This field';\n const say = (key: keyof Messages, values: Record<string, string | number> = {}) => fill(messages[key], { label, ...values });\n if (isEmpty(field, value)) return required ? say('required') : undefined;\n if (field.type === 'matrix') return checkMatrix(field, value, required, say);\n\n switch (field.type) {\n case 'char':\n case 'text':\n case 'html': {\n if (typeof value !== 'string') return say('text');\n if ((field.type === 'char' || field.type === 'text') && field.size !== undefined && value.length > field.size) {\n return say('maxLength', { max: field.size });\n }\n if (field.type === 'char' && field.pattern !== undefined && !new RegExp(field.pattern).test(value)) {\n return say('pattern');\n }\n return undefined;\n }\n case 'integer':\n case 'float':\n case 'monetary': {\n if (typeof value !== 'number' || !Number.isFinite(value)) return say('number');\n if (field.type === 'integer' && !Number.isInteger(value)) return say('integer');\n if (field.min !== undefined && value < field.min) return say('min', { min: field.min });\n if (field.max !== undefined && value > field.max) return say('max', { max: field.max });\n if (field.type !== 'integer' && field.digits && decimals(value) > field.digits[1]) {\n return say('decimals', { digits: field.digits[1] });\n }\n return undefined;\n }\n case 'boolean':\n return typeof value === 'boolean' ? undefined : say('boolean');\n case 'date':\n return checkDate(value, say) ?? checkDay(field, value as string, today, messages);\n case 'datetime':\n return checkDateTime(value, say) ?? checkDay(field, value as string, today, messages);\n case 'selection': {\n // The app's list, not loaded: nothing to say a choice is not one of it.\n if (field.optionsFrom) return undefined;\n const allowed = new Set(field.options.map((o) => o.value));\n const listing = say(field.other ? 'choiceOrOther' : 'choice', { options: field.options.map((o) => o.label).join(', ') });\n // An answer of one's own, where there is an \"Other\": words, never blank.\n const own = (v: unknown) => (field.other === true || field.ownAnswers === true) && typeof v === 'string' && v.trim() !== '' && !allowed.has(v);\n if (field.multiple) {\n if (!Array.isArray(value)) return say('choices');\n const owned = value.filter((v) => !allowed.has(v as string | number)).length;\n // Answers of one's own: one \"Other\", or as many as people add.\n return (owned <= 1 || field.ownAnswers) && value.every((v) => allowed.has(v as string | number) || own(v)) ? undefined : listing;\n }\n return allowed.has(value as string | number) || own(value) ? undefined : listing;\n }\n case 'many2one':\n return isRecord(value) ? undefined : say('record');\n case 'many2many':\n return Array.isArray(value) && value.every(isRecord) ? undefined : say('records');\n case 'reference': {\n const ref = value as ReferenceValue;\n if (!isRecord(value) || typeof ref.model !== 'string') return say('record');\n if (!field.models.some((m) => m.value === ref.model)) {\n const models = listOr(field.models.map((m) => m.label), messages.or);\n return say('reference', { models, aModels: article(models) });\n }\n return undefined;\n }\n case 'binary':\n case 'image':\n return checkFiles(field, value, say, messages);\n default:\n return undefined;\n }\n}\n\n/** A matrix: an answer per row, each from the columns; every row answered when required. */\nfunction checkMatrix(\n field: Extract<Field, { type: 'matrix' }>,\n value: Value | undefined,\n required: boolean,\n say: (key: keyof Messages, values?: Record<string, string | number>) => string\n): string | undefined {\n if (value === null || typeof value !== 'object' || Array.isArray(value)) return say('matrix');\n const rows = new Set(field.rows.map((r) => String(r.value)));\n const columns = new Set(field.columns.map((c) => c.value as unknown));\n const listing = say('choice', { options: field.columns.map((c) => c.label).join(', ') });\n for (const [row, answer] of Object.entries(value as Record<string, unknown>)) {\n if (!rows.has(row)) return say('matrixRow', { rows: field.rows.map((r) => r.label).join(', ') });\n const picked = field.multiple && Array.isArray(answer) ? answer : [answer];\n if (!field.multiple && Array.isArray(answer)) return listing;\n if (picked.some((a) => a !== null && a !== undefined && !columns.has(a))) return listing;\n }\n const answered = (row: string) => {\n const a = (value as Record<string, unknown>)[row];\n return a !== null && a !== undefined && !(Array.isArray(a) && !a.length);\n };\n if (required && field.rows.some((r) => !answered(String(r.value)))) return say('matrixRows');\n return undefined;\n}\n\nfunction decimals(value: number): number {\n const text = String(value);\n if (text.includes('e-')) return Number(text.split('e-')[1]);\n const dot = text.indexOf('.');\n return dot === -1 ? 0 : text.length - dot - 1;\n}\n\nfunction isRecord(value: unknown): value is RelatedRecord {\n return (\n value !== null &&\n typeof value === 'object' &&\n !Array.isArray(value) &&\n (typeof (value as RelatedRecord).id === 'number' || typeof (value as RelatedRecord).id === 'string') &&\n typeof (value as RelatedRecord).label === 'string'\n );\n}\n\ntype Say = (key: keyof Messages, values?: Record<string, string | number>) => string;\n\nfunction checkDate(value: Value | undefined, say: Say): string | undefined {\n if (typeof value !== 'string' || !/^\\d{4}-\\d{2}-\\d{2}$/.test(value)) return say('dateFormat');\n const [y, m, d] = value.split('-').map(Number);\n return realDay(y, m, d) ? undefined : say('dateInvalid');\n}\n\nconst ISO_DATETIME = /^(\\d{4})-(\\d{2})-(\\d{2})T(\\d{2}):(\\d{2})(?::(\\d{2})(?:\\.\\d{1,9})?)?(?:Z|[+-]\\d{2}:\\d{2})?$/;\n\nfunction checkDateTime(value: Value | undefined, say: Say): string | undefined {\n const match = typeof value === 'string' ? ISO_DATETIME.exec(value) : null;\n if (!match) return say('datetimeFormat');\n const [y, mo, d, h, mi, s] = match.slice(1).map((part) => Number(part ?? 0));\n return realDay(y, mo, d) && h < 24 && mi < 60 && s < 60 ? undefined : say('datetimeInvalid');\n}\n\nfunction realDay(year: number, month: number, day: number): boolean {\n if (month < 1 || month > 12 || day < 1) return false;\n const lengths = [31, year % 4 === 0 && (year % 100 !== 0 || year % 400 === 0) ? 29 : 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31];\n return day <= lengths[month - 1];\n}\n\ntype FileField = Extract<Field | LineField, { type: 'binary' | 'image' }>;\n\n/** A file, or several: as few and as many as the field says, then each against the kinds it takes and its largest size \u2014 named by its own name when there are several. */\nfunction checkFiles(field: FileField, value: Value | undefined, say: Say, messages: Messages): string | undefined {\n // A lone file where several are taken is a list of one, as a backend may send it.\n const files = field.multiple ? (Array.isArray(value) ? value : [value]) : [value];\n if (field.multiple && field.minFiles !== undefined && files.length < field.minFiles) return say('minFiles', { min: field.minFiles });\n if (field.multiple && field.maxFiles !== undefined && files.length > field.maxFiles) return say('maxFiles', { max: field.maxFiles });\n for (const file of files) {\n if (!isFile(file)) return say('file');\n const problem = fileProblem(field, file, messages, field.multiple ? file.name : field.label || 'This field');\n if (problem) return problem;\n }\n return undefined;\n}\n\n/**\n * What is wrong with one file for a file or image field \u2014 too large, or not a\n * kind it takes \u2014 said with the limit and named by the file's own name; undefined\n * when nothing is. A widget asks before it adds a file, as the check does after.\n */\nexport function fileProblem(field: FileField, file: { name: string; type: string; size: number }, messages: Messages = MESSAGES.en, label = file.name): string | undefined {\n if (field.maxSize !== undefined && file.size > field.maxSize) return fill(messages.fileSize, { label, size: formatBytes(field.maxSize) });\n const accept = field.type === 'image' ? ['image/*'] : field.accept;\n if (accept && !accepts(accept, file.type)) {\n const types = describeTypes(accept, messages.or);\n return fill(messages.fileType, { label, types, aTypes: article(types) });\n }\n return undefined;\n}\n\nfunction isFile(value: unknown): value is FileValue {\n const file = value as FileValue;\n return value !== null && typeof value === 'object' && typeof file.name === 'string' && typeof file.size === 'number';\n}\n\n/** Whether a file of this media type is one of these kinds, such as \"application/pdf\" or \"image/*\". */\nfunction accepts(patterns: readonly string[], type: string): boolean {\n return patterns.some((pattern) => (pattern.endsWith('/*') ? type.startsWith(pattern.slice(0, -1)) : pattern === type));\n}\n\n/** Office kinds by the extension people know them by, from a word in their media type. */\nconst EXTENSIONS = 'pdf PDF,msword DOC,wordprocessingml DOCX,opendocument.text ODT,plain TXT,ms-excel XLS,spreadsheetml XLSX,opendocument.spreadsheet ODS,csv CSV,ms-powerpoint PPT,presentationml PPTX,opendocument.presentation ODP'.split(',').map((pair) => pair.split(' '));\n\nfunction describeType(pattern: string): string {\n if (pattern.endsWith('/*')) return pattern.slice(0, -2);\n const sub = pattern.split('/')[1] ?? pattern;\n return EXTENSIONS.find(([word]) => sub.includes(word))?.[1] ?? sub.toUpperCase();\n}\n\n/** The kinds a file field takes, as people say them, each once: \"PDF or image\", \"DOC, DOCX or ODT\". */\nexport function describeTypes(patterns: readonly string[], or: string): string {\n return listOr([...new Set(patterns.map(describeType))], or);\n}\n\nfunction listOr(items: string[], or: string): string {\n if (items.length <= 1) return items.join('');\n return `${items.slice(0, -1).join(', ')} ${or} ${items[items.length - 1]}`;\n}\n\nfunction article(phrase: string): string {\n return /^[aeiou]/i.test(phrase) ? `an ${phrase}` : `a ${phrase}`;\n}\n\n/** 1048576 -> \"1 MB\". */\nexport function formatBytes(bytes: number): string {\n const units = ['bytes', 'KB', 'MB', 'GB'];\n let size = bytes;\n let unit = 0;\n while (size >= 1024 && unit < units.length - 1) {\n size /= 1024;\n unit++;\n }\n return `${Number(size.toFixed(1))} ${units[unit]}`;\n}\n", "import type { Option } from '../format/field';\nimport type { Page } from '../format/page';\nimport type { Values } from './values';\n\n/**\n * A quiz's points. Each option may carry a `score`; the answers earn the\n * scores of the options chosen \u2014 the one of a single choice, every one of\n * several, the column chosen in each row of a matrix \u2014 out of the most they\n * could earn: the best option of a single choice, every option worth\n * something of several, the best column of each row. An answer in one's own\n * words, or none, earns nothing. Only questions with points count; a page\n * with none has no score.\n */\n\nexport interface Score {\n score: number;\n max: number;\n}\n\n/** Sums of tenths and the like without a computer's crumbs: 0.1 + 0.2 is 0.3. */\nconst tidy = (n: number) => Math.round(n * 1e9) / 1e9;\n\nconst pointsOf = (options: readonly Option[], value: unknown) => options.find((o) => o.value === value)?.score ?? 0;\nconst best = (options: readonly Option[]) => options.reduce((most, o) => Math.max(most, o.score ?? 0), 0);\nconst allWorth = (options: readonly Option[]) => options.reduce((sum, o) => sum + Math.max(0, o.score ?? 0), 0);\n/** The points of the options a single or a several answer chose. */\nconst earned = (options: readonly Option[], answer: unknown, several: boolean) =>\n several ? (Array.isArray(answer) ? answer.reduce((sum: number, v) => sum + pointsOf(options, v), 0) : 0) : pointsOf(options, answer);\n\nexport function scoreOf(page: Page, values: Values): Score | null {\n let score = 0;\n let max = 0;\n let scored = false;\n for (const [name, field] of Object.entries(page.fields)) {\n if (field.type === 'selection' && field.options.some((o) => o.score !== undefined)) {\n scored = true;\n const several = field.multiple === true;\n score += earned(field.options, values[name], several);\n max += several ? allWorth(field.options) : best(field.options);\n } else if (field.type === 'matrix' && field.columns.some((c) => c.score !== undefined)) {\n scored = true;\n const several = field.multiple === true;\n const answers = values[name];\n const byRow = answers && typeof answers === 'object' && !Array.isArray(answers) ? (answers as Record<string, unknown>) : {};\n for (const row of field.rows) {\n score += earned(field.columns, byRow[String(row.value)], several);\n max += several ? allWorth(field.columns) : best(field.columns);\n }\n }\n }\n return scored ? { score: tidy(score), max: tidy(max) } : null;\n}\n", "import type { FilterCondition, Fields, Option } from '../format/field';\nimport type { JsonValue } from '../format/json';\nimport type { RecordId, RelatedRecord, Values } from './values';\n\n/**\n * How Fieldia reaches data. Fieldia knows no backend: an app implements this\n * interface for its own (a Flectra adapter, a REST client, a survey store),\n * and every method is optional so a page uses only what it needs.\n */\nexport interface DataSource {\n /** Read a record. Needed to edit an existing record. */\n load?(request: LoadRequest): Promise<Values>;\n /** Create (`id: null`) or update a record. Needed to save a record page. */\n save?(request: SaveRequest): Promise<SaveResult>;\n /** Recalculate after a value changes, the way a backend's onchange does. */\n onchange?(request: OnchangeRequest): Promise<OnchangeResult>;\n /** Find records a many2one, many2many or reference may point to. */\n search?(request: SearchRequest): Promise<RelatedRecord[]>;\n /** Make a record from just its name, for \"Create 'xyz'\" in a link field (a backend's name_create). */\n create?(request: CreateRequest): Promise<RelatedRecord>;\n /** Store one response to a `responses` page, such as a survey. */\n submit?(request: SubmitRequest): Promise<SubmitResult>;\n /** Records for a list: filtered, sorted and one page of them, with how many there are in all. */\n list?(request: ListRequest): Promise<ListResult>;\n /** How many records fall under each value of a field, for a list's Group By. */\n groups?(request: GroupRequest): Promise<Group[]>;\n /** The choices of one of the app's lists, for a selection with `optionsFrom`. */\n options?(request: OptionsRequest): Promise<Option[]>;\n}\n\nexport interface OptionsRequest {\n /** The list's name, from the field's `optionsFrom.list`. */\n list: string;\n /** Every value of the form, for a list that changes with another field (`dependsOn`). */\n values: Values;\n}\n\nexport interface CreateRequest {\n model: string;\n /** What the person typed: the new record's name. */\n name: string;\n}\n\nexport interface LoadRequest {\n model: string;\n id: RecordId;\n /** The page's fields, so the source reads exactly what the page shows. */\n fields: Fields;\n}\n\nexport interface SaveRequest {\n model: string;\n id: RecordId | null;\n /** The page's fields, so the source knows each relation's model. */\n fields: Fields;\n /** Only what changed since the record was loaded or last saved. */\n changes: RecordChanges;\n /** Every value, for sources that save whole records. */\n values: Values;\n}\n\nexport interface SaveResult {\n id: RecordId;\n /** The record as stored, when the source recalculated anything. */\n values?: Values;\n}\n\nexport interface OnchangeRequest {\n model: string;\n id: RecordId | null;\n /** The field that changed. */\n changed: string;\n values: Values;\n}\n\nexport interface OnchangeResult {\n /** New values for other fields. */\n values?: Values;\n /** Something to tell the person editing, without blocking them. */\n warning?: string;\n}\n\nexport interface SearchRequest {\n /** The related model, from the field's `relation`. */\n model: string;\n query: string;\n /** The field's filter, with every `valueFrom` already replaced by its value. */\n filter?: ResolvedFilter[];\n limit?: number;\n}\n\nexport type ResolvedFilterCondition = Omit<FilterCondition, 'valueFrom' | 'value'> & { value: JsonValue };\n\nexport interface SortOrder {\n field: string;\n desc?: boolean;\n}\n\nexport interface ListRequest {\n model: string;\n /** The fields the list shows. */\n fields: string[];\n /** What the search bar and the open groups ask for; an `any` group is an OR. */\n filter: ResolvedFilter[];\n /** By the first, then the next: a link by its label, empty values last. */\n sort: SortOrder[];\n offset: number;\n limit: number;\n}\n\nexport interface ListResult {\n records: { id: RecordId; values: Values }[];\n /** How many records match in all, for the pager. */\n total: number;\n}\n\nexport interface GroupRequest {\n model: string;\n field: string;\n filter: ResolvedFilter[];\n}\n\n/** The records under one value of a field: a link's by its id, and those with none as a group of their own (value null). */\nexport interface Group {\n value: JsonValue;\n label: string;\n count: number;\n}\n\n/**\n * A filter as a search receives it: each `valueFrom` already replaced by its\n * value. An adapter must keep the groups: `any` is an OR, `all` an AND.\n */\nexport type ResolvedFilter = ResolvedFilterCondition | { any: ResolvedFilter[] } | { all: ResolvedFilter[] };\n\nexport interface SubmitRequest {\n pageId: string;\n /** The answers to the questions that were shown. Skipped steps are left out. */\n values: Values;\n}\n\nexport interface SubmitResult {\n id?: RecordId;\n}\n\n/**\n * What changed, using the operation names Odoo gives its x2many commands, so\n * an adapter maps them one to one.\n */\nexport interface RecordChanges {\n /** Changed values of every field that is not one2many or many2many. */\n values: Values;\n /** one2many changes, per field. */\n lines: Record<string, LineOp[]>;\n /** many2many changes, per field. */\n links: Record<string, LinkOp[]>;\n}\n\nexport type LineOp =\n | { op: 'create'; key: string; values: Values }\n | { op: 'update'; id: RecordId; values: Values }\n | { op: 'delete'; id: RecordId };\n\nexport type LinkOp =\n | { op: 'link'; id: RecordId }\n | { op: 'unlink'; id: RecordId }\n | { op: 'set'; ids: RecordId[] }\n | { op: 'clear' };\n\n/**\n * Why a save was refused, so each kind is shown where it belongs: `fields`\n * under those fields, a `rule` (a backend's business rule) in a dialog,\n * `network` in a banner with Retry, and `other` beside Save with Retry.\n */\nexport interface SaveProblem {\n kind: 'fields' | 'rule' | 'network' | 'other';\n message: string;\n /** For `fields`: a message for each field, by name. */\n fields?: Record<string, string>;\n}\n\n/** An error for a data source's save to throw when the backend refuses it. */\nexport function saveRefused(problem: SaveProblem): Error & { problem: SaveProblem } {\n return Object.assign(new Error(problem.message), { problem });\n}\n\n/** What a failed save tells: its own problem, a failed fetch as the network, anything else as it is. */\nexport function saveProblemOf(error: unknown): SaveProblem {\n const carried = (error as { problem?: SaveProblem } | null)?.problem;\n if (carried && typeof carried.kind === 'string') return carried;\n const message = error instanceof Error ? error.message : String(error);\n if (error instanceof TypeError && /fetch|network|load failed/i.test(message)) return { kind: 'network', message };\n return { kind: 'other', message };\n}\n", "import type { JsonValue } from '../format/json';\nimport type { ResolvedFilter, ResolvedFilterCondition } from './data-source';\nimport type { RelatedRecord, Values } from './values';\n\n/**\n * Whether a record passes a filter, the way a search should judge it: every\n * item of the list holds, an `any` group when one of its items holds, an `all`\n * group when each does. The memory data source searches with it; an app may too.\n */\nexport function matchesFilter(values: Values, filter: readonly ResolvedFilter[]): boolean {\n return filter.every((item) => holds(values, item));\n}\n\nfunction holds(values: Values, item: ResolvedFilter): boolean {\n if ('any' in item) return item.any.some((inner) => holds(values, inner));\n if ('all' in item) return item.all.every((inner) => holds(values, inner));\n return meets(values, item);\n}\n\n/** Empty is not set: no value, empty text, an empty list. */\nfunction isSet(value: unknown): boolean {\n return value !== null && value !== undefined && value !== '' && value !== false && !(Array.isArray(value) && !value.length);\n}\n\nfunction meets(values: Values, condition: ResolvedFilterCondition): boolean {\n const raw = values[condition.field];\n // A link compares by its id.\n const actual = raw !== null && typeof raw === 'object' && !Array.isArray(raw) && 'id' in raw ? (raw as RelatedRecord).id : (raw as JsonValue | undefined);\n const expected = condition.value;\n // Text is looked for in a link's name, as a search by name does.\n const text = raw !== null && typeof raw === 'object' && !Array.isArray(raw) && 'label' in raw ? String((raw as RelatedRecord).label) : String(actual ?? '');\n switch (condition.op) {\n case '=':\n return actual === expected;\n case '!=':\n return actual !== expected;\n case '<':\n return isSet(actual) && (actual as number) < (expected as number);\n case '>':\n return isSet(actual) && (actual as number) > (expected as number);\n case '<=':\n return isSet(actual) && (actual as number) <= (expected as number);\n case '>=':\n return isSet(actual) && (actual as number) >= (expected as number);\n case 'in':\n return Array.isArray(expected) && expected.includes(actual as JsonValue);\n case 'not in':\n return Array.isArray(expected) && !expected.includes(actual as JsonValue);\n case 'like':\n return text.includes(String(expected));\n case 'ilike':\n return text.toLowerCase().includes(String(expected).toLowerCase());\n case 'startswith':\n return text.toLowerCase().startsWith(String(expected).toLowerCase());\n case 'endswith':\n return text.toLowerCase().endsWith(String(expected).toLowerCase());\n case 'set':\n return isSet(raw);\n case 'notset':\n return !isSet(raw);\n case 'between': {\n if (!isSet(actual) || !Array.isArray(expected)) return false;\n const [low, high] = expected as (number | string)[];\n return (actual as number | string) >= low && (actual as number | string) <= high;\n }\n }\n}\n", "import type { JsonValue } from '../format/json';\nimport type { ListNode } from '../format/layout';\nimport type { Page } from '../format/page';\nimport type { ResolvedFilter, ResolvedFilterCondition } from './data-source';\nimport { fill } from './messages';\n\n/**\n * What a list's search bar holds, each shown as a chip: values searched in\n * one field (any of them), named filters (any of them), a custom filter, or\n * the fields the list is grouped by. The facets all apply together.\n */\nexport type Facet =\n | { kind: 'field'; field: string; label: string; values: { op: ResolvedFilterCondition['op']; value: JsonValue; label: string }[] }\n | { kind: 'filters'; ids: string[]; labels: string[] }\n | { kind: 'custom'; label: string; filter: ResolvedFilter[] }\n | { kind: 'groupBy'; fields: string[]; labels: string[] };\n\n/** One way to search what was typed: a field, how to compare, and the words that say so. */\nexport interface Suggestion {\n field: string;\n fieldLabel: string;\n op: ResolvedFilterCondition['op'];\n value: JsonValue;\n valueLabel: string;\n label: string;\n}\n\nconst TEXT = new Set(['char', 'text', 'html']);\nconst NUMBER = new Set(['integer', 'float', 'monetary']);\nconst LINK = new Set(['many2one', 'many2many']);\n\n/**\n * The searches the typed text can be: text looked for in each text field, a\n * choice whose label it matches, a number where it is one, a link by its\n * record's name. Only the list's search fields, the columns unless it says.\n */\nexport function suggestions(typed: string, page: Page, list: ListNode, words: { searchFor: string } = { searchFor: 'Search {field} for: {text}' }): Suggestion[] {\n const text = typed.trim();\n if (!text) return [];\n const found: Suggestion[] = [];\n for (const field of list.searchFields ?? list.columns) {\n const def = page.fields[field];\n if (!def) continue;\n const say = (op: Suggestion['op'], value: JsonValue, valueLabel: string, label?: string) =>\n found.push({ field, fieldLabel: def.label, op, value, valueLabel, label: label ?? fill(words.searchFor, { field: def.label, text }) });\n if (TEXT.has(def.type) || LINK.has(def.type)) say('ilike', text, text);\n else if (def.type === 'selection') {\n const lower = text.toLowerCase();\n for (const option of def.options) if (option.label.toLowerCase().includes(lower)) say('=', option.value, option.label, `${def.label}: ${option.label}`);\n } else if (NUMBER.has(def.type)) {\n const number = Number(text.replace(/[\\s,]/g, ''));\n if (text && Number.isFinite(number)) say('=', number, text);\n }\n }\n // Text fields first, then the choices, then the links: the order a person looks in.\n const rank = (s: Suggestion) => {\n const type = page.fields[s.field]?.type ?? '';\n return TEXT.has(type) ? 0 : type === 'selection' ? 1 : NUMBER.has(type) ? 2 : 3;\n };\n return found.map((s, i) => ({ s, i })).sort((a, b) => rank(a.s) - rank(b.s) || a.i - b.i).map(({ s }) => s);\n}\n\n/** The filter a list's facets make: the values of one field any of them, named filters any of them, the facets all together. */\nexport function facetsToFilter(facets: readonly Facet[], list: ListNode): ResolvedFilter[] {\n const filter: ResolvedFilter[] = [];\n for (const facet of facets) {\n if (facet.kind === 'field') {\n const conditions = facet.values.map((v) => ({ field: facet.field, op: v.op, value: v.value }));\n filter.push(conditions.length === 1 ? conditions[0] : { any: conditions });\n } else if (facet.kind === 'filters') {\n // A list's own filters have no valueFrom: their conditions are already values.\n const chosen = facet.ids.map((id) => (list.filters?.find((f) => f.id === id)?.filter ?? []) as ResolvedFilter[]).filter((items) => items.length);\n if (chosen.length === 1) filter.push(...chosen[0]);\n else if (chosen.length > 1) filter.push({ any: chosen.map((items) => (items.length === 1 ? items[0] : { all: items })) });\n } else if (facet.kind === 'custom') {\n filter.push(...facet.filter);\n }\n }\n return filter;\n}\n\n/** The fields a list is grouped by, in order, from its Group By facet. */\nexport function groupByFields(facets: readonly Facet[]): string[] {\n return facets.find((f): f is Extract<Facet, { kind: 'groupBy' }> => f.kind === 'groupBy')?.fields ?? [];\n}\n", "/**\n * Timers, injected. Core compiles without the DOM or Node's types, and tests\n * drive time by hand instead of waiting for it.\n */\nexport interface Scheduler {\n setTimeout(callback: () => void, ms: number): unknown;\n clearTimeout(handle: unknown): void;\n}\n\ninterface HostTimers {\n setTimeout(callback: () => void, ms: number): unknown;\n clearTimeout(handle: unknown): void;\n}\n\n/** The host's own timers: the browser's or Node's, whichever is running. */\nexport const hostScheduler: Scheduler = {\n setTimeout: (callback, ms) => (globalThis as unknown as HostTimers).setTimeout(callback, ms),\n clearTimeout: (handle) => (globalThis as unknown as HostTimers).clearTimeout(handle),\n};\n\n/** Resolve after `ms`, on the given scheduler. */\nexport function wait(ms: number, scheduler: Scheduler = hostScheduler): Promise<void> {\n return new Promise((resolve) => {\n scheduler.setTimeout(resolve, ms);\n });\n}\n", "import type { Field, Fields, Option } from '../format/field';\nimport type { JsonValue } from '../format/json';\nimport type {\n DataSource,\n Group,\n GroupRequest,\n ListRequest,\n ListResult,\n LineOp,\n LinkOp,\n LoadRequest,\n OnchangeRequest,\n OnchangeResult,\n OptionsRequest,\n SaveRequest,\n SaveResult,\n SearchRequest,\n CreateRequest,\n SubmitRequest,\n SubmitResult,\n} from './data-source';\nimport { matchesFilter } from './filter';\nimport { wait, type Scheduler } from './scheduler';\nimport { structuredCopy, type Line, type RecordId, type RelatedRecord, type Value, type Values } from './values';\n\nexport interface MemoryDataSourceOptions {\n /** Records by model, then by id. */\n records?: Record<string, Record<string, Values>>;\n /** Recalculation rules by model, then by the field that changed. */\n onchange?: Record<string, Record<string, (values: Values) => Values>>;\n /** Warnings by model, then by the field that changed: a message, or null for none. */\n warnings?: Record<string, Record<string, (values: Values) => string | null>>;\n /** Which value names a record in search results, per model. Defaults to `name`. */\n labelField?: Record<string, string>;\n /** The app's lists of choices, by name: the choices, or a function of the form's values giving them. */\n lists?: Record<string, Option[] | ((values: Values) => Option[] | Promise<Option[]>)>;\n /** Answer after this long, so a demo shows its loading states. */\n delayMs?: number;\n scheduler?: Scheduler;\n}\n\nexport interface MemoryDataSource extends Required<DataSource> {\n readonly records: Record<string, Record<string, Values>>;\n readonly responses: SubmitRequest[];\n readonly calls: { method: keyof DataSource; request: unknown }[];\n}\n\n/**\n * A data source that keeps everything in memory. It implements the whole\n * interface, the way a backend would, so tests and demos exercise the same\n * paths a real adapter takes.\n */\nexport function createMemoryDataSource(options: MemoryDataSourceOptions = {}): MemoryDataSource {\n const records = structuredCopy(options.records ?? {});\n const responses: SubmitRequest[] = [];\n const calls: MemoryDataSource['calls'] = [];\n let lineIds = 1000;\n\n const pause = () => (options.delayMs ? wait(options.delayMs, options.scheduler) : Promise.resolve());\n const table = (model: string) => (records[model] ??= {});\n const labelOf = (model: string, id: RecordId) => {\n const value = table(model)[String(id)]?.[options.labelField?.[model] ?? 'name'];\n return typeof value === 'string' ? value : String(id);\n };\n const nextId = (model: string) => Math.max(0, ...Object.keys(table(model)).map(Number).filter(Number.isFinite)) + 1;\n const asId = (key: string): RecordId => (Number.isFinite(Number(key)) ? Number(key) : key);\n\n function applyLines(current: Line[], ops: LineOp[]): Line[] {\n let lines = [...current];\n for (const op of ops) {\n if (op.op === 'create') lines.push({ key: op.key, id: ++lineIds, values: structuredCopy(op.values) });\n else if (op.op === 'update') lines = lines.map((l) => (l.id === op.id ? { ...l, values: { ...l.values, ...structuredCopy(op.values) } } : l));\n else lines = lines.filter((l) => l.id !== op.id);\n }\n return lines;\n }\n\n function applyLinks(current: RelatedRecord[], ops: LinkOp[], model: string): RelatedRecord[] {\n let links = [...current];\n const related = (id: RecordId): RelatedRecord => ({ id, label: labelOf(model, id) });\n for (const op of ops) {\n if (op.op === 'link' && !links.some((r) => r.id === op.id)) links.push(related(op.id));\n else if (op.op === 'unlink') links = links.filter((r) => r.id !== op.id);\n else if (op.op === 'set') links = op.ids.map(related);\n else if (op.op === 'clear') links = [];\n }\n return links;\n }\n\n function relationOf(fields: Fields, name: string): string {\n const field: Field | undefined = fields[name];\n return field && 'relation' in field ? field.relation : name;\n }\n\n return {\n records,\n responses,\n calls,\n\n async load(request: LoadRequest): Promise<Values> {\n calls.push({ method: 'load', request });\n await pause();\n const stored = table(request.model)[String(request.id)];\n if (!stored) throw new Error(`No ${request.model} record with id ${request.id}`);\n return structuredCopy(stored);\n },\n\n async save(request: SaveRequest): Promise<SaveResult> {\n calls.push({ method: 'save', request });\n await pause();\n const id = request.id ?? nextId(request.model);\n const stored: Values = { ...(table(request.model)[String(id)] ?? {}), ...structuredCopy(request.changes.values) };\n for (const [name, ops] of Object.entries(request.changes.lines)) {\n stored[name] = applyLines((stored[name] as Line[] | undefined) ?? [], ops);\n }\n for (const [name, ops] of Object.entries(request.changes.links)) {\n stored[name] = applyLinks((stored[name] as RelatedRecord[] | undefined) ?? [], ops, relationOf(request.fields, name));\n }\n table(request.model)[String(id)] = stored;\n return { id, values: structuredCopy(stored) };\n },\n\n async onchange(request: OnchangeRequest): Promise<OnchangeResult> {\n calls.push({ method: 'onchange', request });\n await pause();\n const rule = options.onchange?.[request.model]?.[request.changed];\n const warn = options.warnings?.[request.model]?.[request.changed];\n const result: OnchangeResult = rule ? { values: rule(structuredCopy(request.values)) } : {};\n const warning = warn?.(structuredCopy(request.values));\n return warning ? { ...result, warning } : result;\n },\n\n async search(request: SearchRequest): Promise<RelatedRecord[]> {\n calls.push({ method: 'search', request });\n await pause();\n const query = request.query.trim().toLowerCase();\n return Object.entries(table(request.model))\n .filter(([, values]) => matchesFilter(values, request.filter ?? []))\n .map(([key]) => ({ id: asId(key), label: labelOf(request.model, asId(key)) }))\n .filter((record) => record.label.toLowerCase().includes(query))\n .slice(0, request.limit ?? 8);\n },\n\n async list(request: ListRequest): Promise<ListResult> {\n calls.push({ method: 'list', request });\n await pause();\n const matching = Object.entries(table(request.model))\n .filter(([, values]) => matchesFilter(values, request.filter))\n .map(([key, values]) => ({ id: asId(key), values }));\n matching.sort((a, b) => {\n for (const order of request.sort) {\n const compared = compareValues(a.values[order.field], b.values[order.field]);\n // Empty last, whichever way the rest goes.\n if (compared.empty) return compared.result;\n if (compared.result) return order.desc ? -compared.result : compared.result;\n }\n return 0;\n });\n return {\n total: matching.length,\n records: matching.slice(request.offset, request.offset + request.limit).map(({ id, values }) => ({\n id,\n values: Object.fromEntries(request.fields.map((field) => [field, structuredCopy(values[field] ?? null) as Value])),\n })),\n };\n },\n\n async groups(request: GroupRequest): Promise<Group[]> {\n calls.push({ method: 'groups', request });\n await pause();\n const counted = new Map<string, Group>();\n for (const values of Object.values(table(request.model))) {\n if (!matchesFilter(values, request.filter)) continue;\n const raw = values[request.field] ?? null;\n const link = raw !== null && typeof raw === 'object' && !Array.isArray(raw) && 'id' in raw ? (raw as RelatedRecord) : null;\n const value = (link ? link.id : raw) as JsonValue;\n const key = JSON.stringify(value);\n const group = counted.get(key) ?? { value, label: link ? link.label : raw === null || raw === '' ? '' : String(raw), count: 0 };\n group.count++;\n counted.set(key, group);\n }\n return [...counted.values()].sort((a, b) => (a.value === null) === (b.value === null) ? a.label.localeCompare(b.label) : a.value === null ? 1 : -1);\n },\n\n async create(request: CreateRequest): Promise<RelatedRecord> {\n calls.push({ method: 'create', request });\n await pause();\n const rows = table(request.model);\n const id = Object.keys(rows).reduce((top, key) => Math.max(top, Number(key) || 0), 0) + 1;\n rows[String(id)] = { name: request.name };\n return { id, label: request.name };\n },\n\n async submit(request: SubmitRequest): Promise<SubmitResult> {\n calls.push({ method: 'submit', request });\n await pause();\n responses.push(structuredCopy(request));\n return { id: responses.length };\n },\n\n async options(request: OptionsRequest): Promise<Option[]> {\n calls.push({ method: 'options', request });\n await pause();\n const list = options.lists?.[request.list];\n if (!list) throw new Error(`No list \"${request.list}\"`);\n return structuredCopy(typeof list === 'function' ? await list(request.values) : list);\n },\n };\n}\n\n/** Two values in order: a link by its label, text by the reader's rules, numbers by size; `empty` says one of them had nothing. */\nfunction compareValues(a: unknown, b: unknown): { result: number; empty: boolean } {\n const blank = (v: unknown) => v === null || v === undefined || v === '';\n if (blank(a) || blank(b)) return { result: blank(a) === blank(b) ? 0 : blank(a) ? 1 : -1, empty: blank(a) !== blank(b) };\n const label = (v: unknown) => (typeof v === 'object' && v !== null && 'label' in v ? (v as RelatedRecord).label : v);\n const [x, y] = [label(a), label(b)];\n if (typeof x === 'number' && typeof y === 'number') return { result: x - y, empty: false };\n return { result: String(x).localeCompare(String(y)), empty: false };\n}\n", "import type { Field } from '../format/field';\nimport type { FieldNode } from '../format/layout';\nimport { fill, type Messages } from './messages';\nimport type { Value } from './values';\n\n/**\n * What a structure's widget asks of its answer beyond Required: an address\n * (`json.address`) its parts in `options.requiredParts` filled \u2014 the first\n * missing one named \u2014 and a table of lines or a repeating group as few lines\n * as `options.min` and as many as `options.max`, once it has any. Undefined\n * when it keeps them, or when there is nothing to check.\n */\n\n/** An address's parts, in the order its boxes and its messages name them. */\nexport const ADDRESS_PARTS = ['street', 'line2', 'city', 'region', 'postcode', 'country'] as const;\n\nexport function checkStructure(field: Field, node: FieldNode, value: Value | undefined, messages: Messages): string | undefined {\n const options = node.options ?? {};\n const label = node.label ?? field.label;\n if (field.type === 'one2many' && Array.isArray(value) && value.length) {\n if (typeof options['min'] === 'number' && value.length < options['min']) return fill(messages.minLines, { label, min: options['min'] });\n if (typeof options['max'] === 'number' && value.length > options['max']) return fill(messages.maxLines, { label, max: options['max'] });\n }\n const needed = options['requiredParts'];\n if (node.widget !== 'address' || !Array.isArray(needed) || !value || typeof value !== 'object' || Array.isArray(value)) return undefined;\n const asked = Array.isArray(options['parts']) ? options['parts'] : ADDRESS_PARTS;\n const parts = value as Record<string, unknown>;\n const missing = ADDRESS_PARTS.findIndex((part) => needed.includes(part) && asked.includes(part) && !String(parts[part] ?? '').trim());\n return missing < 0 ? undefined : fill(messages.required, { label: messages.addressParts.split('|')[missing] });\n}\n", "import type { Field } from '../format/field';\nimport type { FieldNode } from '../format/layout';\nimport { fill, type Messages } from './messages';\nimport { checkStructure } from './structures';\nimport type { Value } from './values';\n\n/**\n * What a text field's widget asks of its answer, besides the field's own\n * rules: an email, a web address (example.com, www.example.com or https://\u2026),\n * a phone number (a plus, digits, spaces, dots, dashes and brackets, 7 to 15\n * digits), a time of day (HH:MM, between the node's `min` and `max`), and no\n * more keywords than the node's `max` \u2014 and the structures' own, from\n * `structures`. Undefined when it keeps them, or when there is nothing to\n * check: an empty answer is `required`'s to judge.\n */\nconst FORMATS: Record<string, RegExp> = {\n email: /^[^@\\s]+@[^@\\s]+\\.[^@\\s]+$/,\n url: /^(https?:\\/\\/)?([\\p{L}\\p{N}-]+\\.)+\\p{L}{2,}(:\\d+)?([/?#]\\S*)?$/iu,\n phone: /^\\+?[\\p{Nd}\\s.()-]+$/u,\n time: /^([01]\\d|2[0-3]):[0-5]\\d$/,\n};\n\nexport function checkInput(field: Field, node: FieldNode, value: Value | undefined, messages: Messages): string | undefined {\n const widget = node.widget ?? '';\n if (field.type !== 'char') return checkStructure(field, node, value, messages);\n if (typeof value !== 'string' || !value.trim()) return undefined;\n const text = value.trim();\n const options = node.options ?? {};\n const label = node.label ?? field.label;\n const format = FORMATS[widget];\n const digits = text.match(/\\p{Nd}/gu)?.length ?? 0;\n if (format && (!format.test(text) || (widget === 'phone' && (digits < 7 || digits > 15)))) return messages[widget as 'email'];\n if (widget === 'time') {\n if (typeof options['min'] === 'string' && text < options['min']) return fill(messages.before, { label, min: options['min'] });\n if (typeof options['max'] === 'string' && text > options['max']) return fill(messages.after, { label, max: options['max'] });\n }\n if (widget === 'tags' && typeof options['max'] === 'number') {\n const count = text.split(typeof options['separator'] === 'string' && options['separator'] ? options['separator'] : ',').filter((t) => t.trim()).length;\n if (count > options['max']) return fill(messages.atMost, { label, max: options['max'] });\n }\n return undefined;\n}\n", "import type { Field, LineField } from '../format/field';\nimport type { ExpressionEnv } from '../expression/functions';\nimport { expressionContext, lineKind, type Line, type Values } from './values';\n\n/**\n * What an expression on a record is worked out with besides its values: the\n * rows of each one2many for `sum` and `count` \u2014 the items, not the sections\n * and notes between them \u2014 and today's date for `today()`.\n */\nexport function expressionEnv(values: Values, fields: Record<string, Field | LineField>, today: () => string): ExpressionEnv {\n const rows = new Map<string, Record<string, unknown>[]>();\n return {\n today,\n lines(name) {\n const def = fields[name];\n if (def?.type !== 'one2many') return undefined;\n let found = rows.get(name);\n if (!found) {\n const items = ((values[name] as Line[] | null) ?? []).filter((line) => lineKind(def, line.values) === null);\n found = items.map((line) => expressionContext(line.values, def.fields));\n rows.set(name, found);\n }\n return found;\n },\n };\n}\n", "import type { Field, LineField } from '../format/field';\nimport type { Page } from '../format/page';\nimport { compileExpression, type CompiledExpression, type ExpressionEnv } from '../expression/expression';\nimport { isNumber, roundTo, truthy } from '../expression/operations';\nimport { dependencyOrder } from '../expression/order';\nimport { expressionEnv } from './env';\nimport { expressionContext, lineKind, sameValue, type Line, type Value, type Values } from './values';\n\n/**\n * Values worked out from others: a field's `compute`. A page's own fields are\n * worked out in the order they read each other; a one2many's line fields from\n * the fields of the same line, before the page's own, so a page's sum reads\n * lines already worked out. What does not change keeps its identity, so a\n * form redraws only what did.\n */\nexport interface Computed {\n /** The values with every worked-out field brought up to date. */\n apply(values: Values): Values;\n /** One line of a one2many with its worked-out fields brought up to date. */\n line(field: string, values: Values): Values;\n}\n\ntype Step = [name: string, expression: CompiledExpression, def: Field | LineField];\n\n/** The worked-out fields among `fields`, each read once, in the order to work them out. */\nfunction steps(fields: Record<string, Field | LineField>): Step[] {\n const compiled = new Map<string, CompiledExpression>();\n for (const [name, def] of Object.entries(fields)) if (def.compute !== undefined) compiled.set(name, compileExpression(def.compute));\n const { order } = dependencyOrder(new Map([...compiled].map(([name, expression]) => [name, expression.fields])));\n return order.map((name) => [name, compiled.get(name) as CompiledExpression, fields[name]]);\n}\n\n/**\n * A worked-out value as its field holds it: a whole number rounded, a number\n * to the field's decimals, a number as text in a text field, yes or no by\n * Python's idea of true, and null for what the field cannot hold.\n */\nexport function fitTo(def: Field | LineField, value: unknown): Value {\n if (def.type === 'boolean') return truthy(value);\n if (value === null || value === undefined) return null;\n switch (def.type) {\n case 'integer':\n return isNumber(value) ? roundTo(value, 0) : null;\n case 'float':\n case 'monetary':\n if (!isNumber(value)) return null;\n return def.digits ? roundTo(value, def.digits[1]) : value;\n case 'char':\n case 'text':\n case 'html':\n return typeof value === 'string' ? value : isNumber(value) ? String(value) : null;\n case 'date':\n case 'datetime':\n return typeof value === 'string' ? value : null;\n default:\n return value as Value;\n }\n}\n\n/** Read every `compute` of a page once. `today` is the day `today()` gives. */\nexport function compileComputed(page: Page, today: () => string): Computed {\n const own = steps(page.fields);\n const lineSteps = new Map<string, { def: Extract<Field, { type: 'one2many' }>; steps: Step[] }>();\n for (const [name, def] of Object.entries(page.fields)) {\n if (def.type !== 'one2many') continue;\n const found = steps(def.fields);\n if (found.length) lineSteps.set(name, { def, steps: found });\n }\n // Lines hold no lines of their own: inside one, only today() needs the env.\n const lineEnv: ExpressionEnv = { today };\n\n /** Work out the steps on these values, writing each change into a copy. */\n function run(values: Values, list: Step[], fields: Record<string, Field | LineField>, env: ExpressionEnv): Values {\n let next = values;\n const context = expressionContext(values, fields);\n for (const [name, expression, def] of list) {\n const value = fitTo(def, expression.evaluate(context, env));\n if (sameValue(value, next[name])) continue;\n next = { ...next, [name]: value };\n // What comes after reads this value as it is now.\n Object.assign(context, expressionContext({ [name]: value }, fields));\n }\n return next;\n }\n\n function line(field: string, values: Values): Values {\n const found = lineSteps.get(field);\n // A section or a note has nothing to work out.\n if (!found || lineKind(found.def, values) !== null) return values;\n return run(values, found.steps, found.def.fields, lineEnv);\n }\n\n return {\n line,\n apply(values) {\n let next = values;\n for (const field of lineSteps.keys()) {\n const current = next[field];\n if (!Array.isArray(current)) continue;\n let changed = false;\n const updated = (current as Line[]).map((l) => {\n const worked = line(field, l.values);\n if (worked === l.values) return l;\n changed = true;\n return { ...l, values: worked };\n });\n if (changed) next = { ...next, [field]: updated };\n }\n if (!own.length) return next;\n return run(next, own, page.fields, expressionEnv(next, page.fields, today));\n },\n };\n}\n", "import type { Field, LineField, SetWhen } from '../format/field';\nimport type { Page } from '../format/page';\nimport { compileExpression, type CompiledExpression, type ExpressionEnv } from '../expression/expression';\nimport { compileModifier, type CompiledModifier } from '../expression/modifier';\nimport { fitTo } from './compute';\nimport { expressionEnv } from './env';\nimport { expressionContext, lineKind, sameValue, type Line, type Values } from './values';\n\n/**\n * Values set when a condition starts to hold: a field's `setWhen`. A rule acts\n * only as its condition goes from not holding to holding \u2014 so people may\n * still change the value afterwards \u2014 and rules act in the order the field\n * lists them. Each rule is known by a key (`discount#0`, or in a line\n * `lines.<line key>.pallet#0`), so what held before can be remembered.\n */\nexport interface SetWhenRules {\n /** The keys of the conditions holding for these values: a starting point, where nothing is set. */\n holding(values: Values): Set<string>;\n /**\n * The values with each field whose condition holds now, and did not in\n * `before`, set to its value; and the conditions holding now. The values\n * come back as they were when nothing was set.\n */\n apply(values: Values, before: ReadonlySet<string>): { values: Values; holding: Set<string> };\n}\n\ninterface Rule {\n key: string;\n name: string;\n def: Field | LineField;\n when: CompiledModifier;\n value: CompiledExpression;\n}\n\nfunction rules(fields: Record<string, Field | LineField>): Rule[] {\n return Object.entries(fields).flatMap(([name, def]) =>\n (def.setWhen ?? []).map((rule: SetWhen, i): Rule => ({ key: `${name}#${i}`, name, def, when: compileModifier(rule.when), value: compileExpression(rule.value) }))\n );\n}\n\n/** Before anything was known: every condition counts as holding, so none starts. */\nconst EVERYTHING: ReadonlySet<string> = { has: () => true } as unknown as ReadonlySet<string>;\n\n/** Read every `setWhen` of a page once. `today` is the day `today()` gives. */\nexport function compileSetWhen(page: Page, today: () => string): SetWhenRules {\n const own = rules(page.fields);\n const lineRules = new Map<string, { def: Extract<Field, { type: 'one2many' }>; rules: Rule[] }>();\n for (const [name, def] of Object.entries(page.fields)) {\n if (def.type !== 'one2many') continue;\n const found = rules(def.fields);\n if (found.length) lineRules.set(name, { def, rules: found });\n }\n const lineEnv: ExpressionEnv = { today };\n\n /** One set of values (the record's, or a line's): every rule read against them as they are, before any is set. */\n function run(values: Values, list: Rule[], fields: Record<string, Field | LineField>, env: ExpressionEnv, prefix: string, before: ReadonlySet<string>, now: Set<string>): Values {\n let next = values;\n const context = expressionContext(values, fields);\n for (const rule of list) {\n if (!rule.when.evaluate(context, env)) continue;\n const key = prefix + rule.key;\n now.add(key);\n if (before.has(key)) continue;\n const value = fitTo(rule.def, rule.value.evaluate(context, env));\n if (!sameValue(value, next[rule.name])) next = { ...next, [rule.name]: value };\n }\n return next;\n }\n\n function apply(values: Values, before: ReadonlySet<string>) {\n const now = new Set<string>();\n let next = own.length ? run(values, own, page.fields, expressionEnv(values, page.fields, today), '', before, now) : values;\n for (const [field, { def, rules: list }] of lineRules) {\n const current = values[field];\n if (!Array.isArray(current)) continue;\n let changed = false;\n const updated = (current as Line[]).map((line) => {\n // A section or a note has nothing to set.\n if (lineKind(def, line.values) !== null) return line;\n const set = run(line.values, list, def.fields, lineEnv, `${field}.${line.key}.`, before, now);\n if (set === line.values) return line;\n changed = true;\n return { ...line, values: set };\n });\n if (changed) next = { ...next, [field]: updated };\n }\n return { values: next, holding: now };\n }\n\n return { apply, holding: (values) => apply(values, EVERYTHING).holding };\n}\n", "import type { Field } from '../format/field';\nimport type { AnswerRule } from '../format/layout';\nimport type { ExpressionEnv } from '../expression/functions';\nimport { localDay } from '../expression/functions';\nimport { compileModifier, type CompiledModifier } from '../expression/modifier';\nimport { isNumber } from '../expression/operations';\nimport { fill, type Messages } from './messages';\nimport { isEmpty, type Value } from './values';\n\n/**\n * Answer rules: what a field node's `validate` asks of an answer, besides its\n * field's own rules. An empty answer passes every rule (`required` decides\n * whether one is needed), a rule applies only while its `when` holds, and an\n * ask that does not fit the answer \u2014 a length of a number \u2014 is not broken. A\n * rule across fields (`holds`) waits until every field it reads is filled in.\n */\n\n/** A rule read once: its condition and its rule across fields parsed, its pattern made whole. */\nexport interface CompiledRule {\n readonly rule: AnswerRule;\n readonly when: CompiledModifier;\n readonly pattern: RegExp | null;\n readonly holds: CompiledModifier | null;\n}\n\nexport function compileRules(rules: readonly AnswerRule[] | undefined): CompiledRule[] {\n return (rules ?? []).map((rule) => ({\n rule,\n when: compileModifier(rule.when ?? true),\n // A pattern is about the whole answer, not a part of it.\n pattern: rule.pattern === undefined ? null : new RegExp(`^(?:${rule.pattern})$`),\n holds: rule.holds === undefined ? null : compileModifier(rule.holds),\n }));\n}\n\n/** What a rule is checked with: the record as expressions read it, the clock, and the words to say. */\nexport interface RuleContext {\n context: Record<string, unknown>;\n env: ExpressionEnv;\n now: Date;\n messages: Messages;\n}\n\n/** The first broken error rule's message and the first broken warning rule's, for one answer. */\nexport function checkRules(\n field: Field,\n label: string,\n value: Value | undefined,\n rules: readonly CompiledRule[],\n at: RuleContext\n): { error?: string; warning?: string } {\n const found: { error?: string; warning?: string } = {};\n if (!rules.length || isEmpty(field, value)) return found;\n for (const compiled of rules) {\n const level = compiled.rule.level ?? 'error';\n if (found[level] !== undefined || !compiled.when.evaluate(at.context, at.env)) continue;\n const broken = brokenAsk(compiled, field, value as Value, at.now) ?? brokenAcross(compiled, at);\n if (broken) found[level] = compiled.rule.message ?? fill(at.messages[broken.say], { label, ...broken.values });\n }\n return found;\n}\n\ntype Broken = { say: keyof Messages; values?: Record<string, string | number> };\n\n/** The first thing a rule asks that the answer does not keep, in the order a rule lists them. */\nfunction brokenAsk({ rule, pattern }: CompiledRule, field: Field, value: Value, now: Date): Broken | undefined {\n const text = typeof value === 'string' ? value : null;\n if (text !== null && rule.minLength !== undefined && text.length < rule.minLength) return { say: 'minLength', values: { min: rule.minLength } };\n if (text !== null && rule.maxLength !== undefined && text.length > rule.maxLength) return { say: 'maxLength', values: { max: rule.maxLength } };\n if (pattern && (text !== null || isNumber(value)) && !pattern.test(String(value))) return { say: 'pattern' };\n if (text !== null && rule.endsWith !== undefined && !text.trim().toLowerCase().endsWith(rule.endsWith.toLowerCase())) {\n return { say: 'endsWith', values: { ending: rule.endsWith } };\n }\n if (isNumber(value) && rule.min !== undefined && value < rule.min) return { say: 'min', values: { min: rule.min } };\n if (isNumber(value) && rule.max !== undefined && value > rule.max) return { say: 'max', values: { max: rule.max } };\n const count = Array.isArray(value) ? value.length : null;\n if (count !== null && rule.atLeast !== undefined && count < rule.atLeast) return { say: 'atLeast', values: { min: rule.atLeast } };\n if (count !== null && rule.atMost !== undefined && count > rule.atMost) return { say: 'atMost', values: { max: rule.atMost } };\n if (text !== null && rule.date !== undefined) {\n const side = whenIs(field, text, now);\n if (rule.date === 'past' && side >= 0) return { say: 'datePast' };\n if (rule.date === 'future' && side <= 0) return { say: 'dateFuture' };\n }\n return undefined;\n}\n\n/** Nothing to compare with yet: an empty value, as expressions read it. */\nconst blank = (value: unknown) => value === null || value === undefined || (typeof value === 'string' && !value.trim()) || (Array.isArray(value) && !value.length);\n\n/** A rule across fields, once every field it reads is filled in: broken when it does not hold. */\nfunction brokenAcross({ holds }: CompiledRule, at: RuleContext): Broken | undefined {\n if (!holds || holds.fields.some((name) => blank(at.context[name]))) return undefined;\n return holds.evaluate(at.context, at.env) ? undefined : { say: 'holds' };\n}\n\n/**\n * Whether an answer is before (-1) or after (1) now, or is now (0): a day\n * against today, a date and time against the clock itself. A date and time\n * that cannot be read is neither (NaN): the field's own rules name it.\n */\nfunction whenIs(field: Field, text: string, now: Date): number {\n if (field.type === 'datetime') return Math.sign(Date.parse(text) - now.getTime());\n const today = localDay(now);\n return text < today ? -1 : text > today ? 1 : 0;\n}\n", "import type { Field, FilterItem, LineField, Option, OptionsFrom } from '../format/field';\nimport type { JsonValue } from '../format/json';\nimport type { ButtonNode, FieldNode, LayoutNode, Modifier, RootLayout, StatButton, StepNode } from '../format/layout';\nimport type { Page } from '../format/page';\nimport { compileModifier, type CompiledModifier } from '../expression/modifier';\nimport type { ExpressionEnv } from '../expression/functions';\nimport { localDay } from '../expression/functions';\nimport { checkValue } from './check';\nimport { checkInput } from './inputs';\nimport { compileComputed } from './compute';\nimport { compileSetWhen } from './set-when';\nimport { checkRules, compileRules, type CompiledRule } from './rules';\nimport { expressionEnv } from './env';\nimport { MESSAGES, type Messages } from './messages';\nimport { saveProblemOf, type DataSource, type LineOp, type LinkOp, type RecordChanges, type ResolvedFilter, type SaveProblem } from './data-source';\nimport { hostScheduler, type Scheduler } from './scheduler';\nimport {\n emptyValue,\n expressionContext,\n initialValues,\n isEmpty,\n lineKind,\n structuredCopy,\n type Line,\n type RecordId,\n type RelatedRecord,\n type Value,\n type Values,\n} from './values';\n\nexport type FormStatus = 'idle' | 'loading' | 'ready' | 'saving' | 'saved' | 'error';\n\nexport interface FormState {\n readonly status: FormStatus;\n readonly recordId: RecordId | null;\n readonly values: Readonly<Values>;\n /** Messages by field name; a line's field is `field.lineKey.subfield`. */\n readonly errors: Readonly<Record<string, string>>;\n /** Fields that differ from the record as loaded or last saved. */\n readonly dirty: readonly string[];\n /**\n * Warnings by field name, from answer rules at the warning level: shown,\n * never blocking. Kept current as values change, for the fields people can see.\n */\n readonly warnings: Readonly<Record<string, string>>;\n /** A warning from the data source's onchange, shown without blocking. */\n readonly warning: string | null;\n /** The field whose change brought the warning, so it can be shown beside it. */\n readonly warningField: string | null;\n /** Why loading or saving failed. */\n readonly error: string | null;\n /** A saved draft that can be restored. */\n readonly draft: { savedAt: string } | null;\n /** The wizard step on screen, for a wizard page. */\n readonly step: string | null;\n /** Optional steps passed over with Skip: their answers are left out, and not asked for. */\n readonly skipped: readonly string[];\n /** Why the last save was refused, until the next one starts or the form is reset. */\n readonly saveProblem: SaveProblem | null;\n /** The choices loaded from the app's lists, by field: those of a selection with `optionsFrom`, once asked for. */\n readonly choices: Readonly<Record<string, Choices>>;\n}\n\n/** A field's choices from one of the app's lists, as they load. */\nexport interface Choices {\n /** The choices last loaded: null until the first load ends well. */\n readonly options: Option[] | null;\n readonly loading?: boolean;\n /** Why the last load failed. */\n readonly error?: string;\n}\n\n/** What a layout element looks like right now. */\nexport interface NodeState {\n invisible: boolean;\n readonly: boolean;\n required: boolean;\n}\n\n/** localStorage fits this, and so does anything else with the same three methods. */\nexport interface DraftStore {\n getItem(key: string): string | null;\n setItem(key: string, value: string): void;\n removeItem(key: string): void;\n}\n\nexport interface ActionRequest {\n /** The button or stat button pressed. */\n id: string;\n action: string;\n params?: { [key: string]: JsonValue };\n recordId: RecordId | null;\n values: Values;\n /** The records chosen in a list, when the button belongs to one. */\n recordIds?: RecordId[];\n}\n\nexport interface FormOptions {\n page: Page;\n dataSource?: DataSource;\n /** The record to edit. Leave out for a new record or a survey. */\n recordId?: RecordId | null;\n /** Values to start with, on top of each field's default. */\n values?: Values;\n /** What a button does. Fieldia hands the press over; the app decides. */\n onAction?: (request: ActionRequest) => void | Promise<void>;\n drafts?: { store: DraftStore; restore?: 'auto' | 'ask'; delayMs?: number };\n autosave?: { delayMs: number };\n scheduler?: Scheduler;\n /** Validation messages in the page's language. English by default. */\n messages?: Messages;\n /** The clock, for `today()` and for dates that must be past or future. The computer's own when left out. */\n now?: () => Date;\n}\n\nexport interface Form {\n readonly page: Page;\n getState(): FormState;\n subscribe(listener: (state: FormState) => void): () => void;\n load(): Promise<void>;\n setValue(name: string, value: Value): void;\n node(id: string): NodeState;\n fieldReadonly(name: string): boolean;\n /** What a field would be told if the form were checked now, or null when it passes. Nothing is shown. */\n problem(field: string): string | null;\n validate(): boolean;\n save(): Promise<boolean>;\n reset(): void;\n changes(): RecordChanges;\n addLine(field: string, values?: Values): string;\n updateLine(field: string, key: string, name: string, value: Value): void;\n removeLine(field: string, key: string): void;\n /** Move a line to another place among its lines, numbering its sequence field again. */\n moveLine(field: string, key: string, to: number): void;\n /**\n * What a line would become with these values once the data source's onchange\n * has run, as a line edited in a dialog shows its subtotal follow. Nothing is\n * written: the record, its changes and its autosave stay as they are.\n */\n previewLine(field: string, key: string, values: Values): Promise<Values>;\n /**\n * Load, or load again, the choices of a selection whose options come from\n * the app's list (`optionsFrom`). Once loaded, they load again by themselves\n * when a field they change with changes; the latest answer wins.\n */\n loadChoices(field: string): void;\n /** Records a many2one, many2many or reference may point to. A reference needs `options.model`. */\n search(field: string, query: string, limit?: number, options?: { model?: string }): Promise<RelatedRecord[]>;\n /** The same, for a relation inside a one2many line, filtered by that line's values. */\n searchLine(field: string, key: string, subfield: string, query: string, limit?: number): Promise<RelatedRecord[]>;\n /** Whether a link field can make a record from a typed name: the data source must be able to. */\n canCreate(field: string): boolean;\n /** Make a record from a typed name, for the link field to point to. */\n quickCreate(field: string, name: string): Promise<RelatedRecord>;\n /** The same, for a link inside a one2many's lines. */\n canCreateLine(field: string, subfield: string): boolean;\n quickCreateLine(field: string, subfield: string, name: string): Promise<RelatedRecord>;\n steps(): string[];\n next(): boolean;\n back(): boolean;\n /** Pass over the step on screen, when it is optional and not the last one. */\n skip(): boolean;\n /**\n * Go to a step that applies. Back, at once; forward, only past steps that are\n * complete: it stops at the first one with a problem and shows it, and skips\n * an optional one instead.\n */\n goTo(step: string): boolean;\n /** Run a button; a list's button passes the records chosen in it. */\n runAction(id: string, chosen?: { recordIds: RecordId[] }): Promise<void>;\n restoreDraft(): void;\n discardDraft(): void;\n /** Resolves once every onchange, save and autosave started so far has finished. */\n settled(): Promise<void>;\n dispose(): void;\n}\n\ninterface IndexedNode {\n id: string;\n parent: string | null;\n kind: 'field' | 'button' | 'stat' | 'other' | 'step';\n field?: string;\n invisible: CompiledModifier;\n readonly: CompiledModifier;\n required: CompiledModifier;\n source: LayoutNode | StepNode | ButtonNode | StatButton | RootLayout | { id: string; invisible?: Modifier };\n}\n\n/**\n * The record state behind a page: values, what changed, what is visible and\n * required, errors, loading and saving. No DOM and no framework \u2014 every\n * binding renders from `getState()` and calls these methods.\n */\nexport function createForm(options: FormOptions): Form {\n const { page } = options;\n const scheduler = options.scheduler ?? hostScheduler;\n const messages = options.messages ?? MESSAGES.en;\n const index = indexLayout(page.layout);\n /** Each field node's answer rules, read once. */\n const nodeRules = new Map<string, CompiledRule[]>();\n for (const node of index.values()) {\n const rules = (node.source as { validate?: FieldNode['validate'] }).validate;\n if (node.kind === 'field' && rules) nodeRules.set(node.id, compileRules(rules));\n }\n /** Whether any rule only warns: without one, there are never warnings to look for. */\n const warns = [...nodeRules.values()].some((rules) => rules.some((compiled) => compiled.rule.level === 'warning'));\n const steps = page.layout.type === 'wizard' ? page.layout.children.map((step) => step.id) : [];\n const draftKey = () => `fieldia:draft:${page.id}:${state.recordId ?? 'new'}`;\n const today = () => localDay(options.now?.() ?? new Date());\n const computed = compileComputed(page, today);\n const setWhen = compileSetWhen(page, today);\n\n let baseline: Values = computed.apply({ ...initialValues(page.fields, today()), ...structuredCopy(options.values ?? {}) });\n /** The setWhen conditions holding for the values as they last settled: one starts to hold only against these. */\n let holding = setWhen.holding(baseline);\n let state: FormState = {\n status: options.recordId != null ? 'idle' : 'ready',\n recordId: options.recordId ?? null,\n values: structuredCopy(baseline),\n errors: {},\n dirty: [],\n warnings: {},\n warning: null,\n warningField: null,\n error: null,\n draft: null,\n step: steps[0] ?? null,\n skipped: [],\n saveProblem: null,\n choices: {},\n };\n /** Field errors a refused save brought, each kept until its field changes from the value it was refused with. */\n let serverErrors: Record<string, { message: string; value: string }> = {};\n let lineKeys = 0;\n let onchangeSeq = 0;\n let draftTimer: unknown = null;\n let autosaveTimer: unknown = null;\n const pending = new Set<Promise<unknown>>();\n const listeners = new Set<(state: FormState) => void>();\n let contextCache: { values: Values; context: Record<string, unknown>; env: ExpressionEnv } | null = null;\n\n /** The latest load of each field's choices: an answer to an older one is let go. */\n const choiceLoads: Record<string, number> = {};\n\n function set(patch: Partial<FormState>) {\n const was = state.values;\n state = { ...state, ...patch };\n for (const listener of [...listeners]) listener(state);\n // Choices that change with a value that just changed are asked for again.\n if (state.values !== was) {\n for (const name in state.choices) if (fromList(name).dependsOn?.some((other) => was[other] !== state.values[other])) loadChoices(name);\n }\n }\n\n const fromList = (name: string) => (page.fields[name] as Extract<Field, { type: 'selection' }>).optionsFrom as OptionsFrom;\n\n function loadChoices(name: string) {\n const { list } = fromList(name);\n const load = (choiceLoads[name] = (choiceLoads[name] ?? 0) + 1);\n const put = (choices: Choices) => load === choiceLoads[name] && set({ choices: { ...state.choices, [name]: choices } });\n // What was shown stays while the next ones load, so the list does not flash empty.\n const shown = state.choices[name]?.options ?? null;\n put({ options: shown, loading: true });\n const source = options.dataSource;\n void track(\n (source?.options ? source.options({ list, values: structuredCopy(state.values as Values) }) : Promise.reject(new Error(`No list \"${list}\"`))).then(\n (loaded) => put({ options: loaded }),\n (error) => put({ options: shown, error: (error as Error).message ?? String(error) })\n )\n );\n }\n\n /** A field as its value is checked: a list's choices are those loaded, and until they are, any choice may be one. */\n function checked(name: string): Field {\n const def = page.fields[name];\n const loaded = state.choices[name]?.options;\n return def.type === 'selection' && def.optionsFrom && loaded ? { ...def, options: loaded, optionsFrom: undefined } : def;\n }\n\n function track<T>(promise: Promise<T>): Promise<T> {\n pending.add(promise);\n const done = () => pending.delete(promise);\n promise.then(done, done);\n return promise;\n }\n\n /** The values as expressions read them, and what else they read: the lines' rows, today. */\n function reading(): { context: Record<string, unknown>; env: ExpressionEnv } {\n if (contextCache?.values !== state.values) {\n const values = state.values as Values;\n contextCache = { values, context: expressionContext(values, page.fields), env: expressionEnv(values, page.fields, today) };\n }\n return contextCache;\n }\n\n const context = () => reading().context;\n\n function fieldDef(name: string): Field {\n const def = page.fields[name];\n if (!def) throw new Error(`The page has no field \"${name}\"`);\n return def;\n }\n\n function dirtyFields(values: Values): string[] {\n return Object.keys(page.fields).filter((name) => JSON.stringify(values[name] ?? null) !== JSON.stringify(baseline[name] ?? null));\n }\n\n function nodeState(id: string): NodeState {\n const node = index.get(id);\n if (!node) throw new Error(`The page has no element \"${id}\"`);\n const { context: ctx, env } = reading();\n let invisible = node.invisible.evaluate(ctx, env);\n for (let parent = node.parent; !invisible && parent; parent = index.get(parent)?.parent ?? null) {\n invisible = index.get(parent)?.invisible.evaluate(ctx, env) ?? false;\n }\n // A section read-only right now makes everything inside it read-only too.\n let readonly = node.readonly.evaluate(ctx, env);\n for (let parent = node.parent; !readonly && parent; parent = index.get(parent)?.parent ?? null) {\n readonly = index.get(parent)?.readonly.evaluate(ctx, env) ?? false;\n }\n const def = node.field ? page.fields[node.field] : undefined;\n return {\n invisible,\n readonly: readonly || (def !== undefined && lockedField(def)),\n required: node.required.evaluate(ctx, env) || def?.required === true,\n };\n }\n\n /** Field nodes inside `root` (or the whole page), visible right now. */\n function visibleFieldNodes(root?: string): IndexedNode[] {\n const inside = (node: IndexedNode) => {\n if (!root) return true;\n for (let at: string | null = node.id; at; at = index.get(at)?.parent ?? null) if (at === root) return true;\n return false;\n };\n // The whole page leaves out the steps passed over with Skip.\n const skipped = (node: IndexedNode) => {\n if (root || !state.skipped.length) return false;\n for (let at: string | null = node.id; at; at = index.get(at)?.parent ?? null) if (state.skipped.includes(at)) return true;\n return false;\n };\n return [...index.values()].filter((node) => node.kind === 'field' && inside(node) && !skipped(node) && !nodeState(node.id).invisible);\n }\n\n /** What a field node's answer rules say of its value now: the first error and the first warning. */\n function ruleCheck(node: IndexedNode): { error?: string; warning?: string } {\n const rules = nodeRules.get(node.id);\n if (!rules) return {};\n const name = node.field as string;\n const def = page.fields[name];\n const label = (node.source as FieldNode).label ?? def.label;\n const { context: ctx, env } = reading();\n return checkRules(def, label, state.values[name], rules, { context: ctx, env, now: options.now?.() ?? new Date(), messages });\n }\n\n /** A tick box required and not ticked, as an \"I agree\" box: \"no\" answers a yes or no, never a box to tick. */\n function unticked(node: IndexedNode): string | undefined {\n const name = node.field as string;\n const ticks = (node.source as FieldNode).widget === 'tick' && page.fields[name].type === 'boolean';\n return ticks && state.values[name] !== true && nodeState(node.id).required ? messages.tick : undefined;\n }\n\n /** A field node's error now: its field's own rules first, then its answer rules. */\n function nodeError(node: IndexedNode): string | undefined {\n const name = node.field as string;\n return unticked(node) ?? checkInput(page.fields[name], node.source as FieldNode, state.values[name], messages) ?? checkValue(checked(name), state.values[name], nodeState(node.id).required, messages, today()) ?? ruleCheck(node).error;\n }\n\n /** Warnings for the visible fields of the page, without publishing them. */\n function collectWarnings(): Record<string, string> {\n const warnings: Record<string, string> = {};\n if (!warns) return warnings;\n for (const node of visibleFieldNodes()) {\n const warning = nodeRules.has(node.id) ? ruleCheck(node).warning : undefined;\n if (warning) warnings[node.field as string] ??= warning;\n }\n return warnings;\n }\n\n /** What would be found for these values, without publishing them or touching the form. */\n function withValues<T>(values: Values, find: () => T): T {\n const previous = state;\n state = { ...state, values };\n try {\n return find();\n } finally {\n state = previous;\n }\n }\n\n /** Errors for the visible fields under `root`, without publishing them. */\n function collectErrors(root?: string): Record<string, string> {\n const errors: Record<string, string> = {};\n for (const node of visibleFieldNodes(root)) {\n const name = node.field as string;\n if (errors[name]) continue;\n const def = page.fields[name];\n const message = nodeError(node);\n if (message) errors[name] = message;\n if (def.type === 'one2many') {\n for (const line of (state.values[name] as Line[] | null) ?? []) {\n // A section or note answers only for its text, never for what an item needs.\n const kind = lineKind(def, line.values);\n for (const [sub, subDef] of Object.entries(def.fields)) {\n if (kind && sub !== def.lineKinds?.text) continue;\n const lineMessage = checkValue(subDef, line.values[sub], subDef.required === true, messages, today());\n if (lineMessage) errors[`${name}.${line.key}.${sub}`] = lineMessage;\n }\n }\n }\n }\n return errors;\n }\n\n /**\n * Values as they settle after a change: worked out, then set where a\n * condition started to hold, then worked out again from what was set \u2014 a\n * few rounds at most, so rules that set each other cannot run forever.\n */\n function settle(written: Values): Values {\n let values = computed.apply(written);\n for (let round = 0; round < 8; round++) {\n const result = setWhen.apply(values, holding);\n holding = result.holding;\n if (result.values === values) break;\n values = computed.apply(result.values);\n }\n return values;\n }\n\n /** Values to start again from, as loaded or restored: conditions holding in them hold already, and set nothing. */\n function startFrom(values: Values): Values {\n const worked = computed.apply(values);\n holding = setWhen.holding(worked);\n return worked;\n }\n\n /** Write values someone or something changed. `fresh` values are a starting point instead (a restored draft). */\n function writeValues(written: Values, extra: Partial<FormState> = {}, fresh = false) {\n const values = fresh ? startFrom(written) : settle(written);\n const errors = Object.keys(state.errors).length ? revalidateShown(values) : state.errors;\n set({ values, dirty: dirtyFields(values), errors, warnings: withValues(values, collectWarnings), ...extra });\n }\n\n /** Once errors are on screen, keep them current as the person fixes things. */\n function revalidateShown(values: Values): Record<string, string> {\n const fresh = withValues(values, () => collectErrors(state.step ?? undefined));\n const kept: Record<string, string> = {};\n for (const key of Object.keys(state.errors)) if (fresh[key]) kept[key] = fresh[key];\n for (const [name, refused] of Object.entries(serverErrors)) {\n if (JSON.stringify(values[name] ?? null) === refused.value) kept[name] ??= refused.message;\n else delete serverErrors[name];\n }\n return kept;\n }\n\n function scheduleDraft() {\n const drafts = options.drafts;\n if (!drafts) return;\n if (draftTimer !== null) scheduler.clearTimeout(draftTimer);\n draftTimer = scheduler.setTimeout(() => {\n draftTimer = null;\n drafts.store.setItem(draftKey(), JSON.stringify({ savedAt: new Date().toISOString(), values: state.values }));\n }, drafts.delayMs ?? 400);\n }\n\n function forgetDraft() {\n if (draftTimer !== null) scheduler.clearTimeout(draftTimer);\n draftTimer = null;\n options.drafts?.store.removeItem(draftKey());\n }\n\n function offerDraft() {\n const drafts = options.drafts;\n if (!drafts) return;\n const raw = drafts.store.getItem(draftKey());\n if (!raw) return;\n let draft: { savedAt: string; values: Values };\n try {\n draft = JSON.parse(raw);\n } catch {\n drafts.store.removeItem(draftKey());\n return;\n }\n if (drafts.restore === 'auto') writeValues({ ...state.values, ...draft.values }, { draft: null }, true);\n else set({ draft: { savedAt: draft.savedAt } });\n }\n\n function scheduleAutosave() {\n const autosave = options.autosave;\n if (!autosave || page.data.kind !== 'record') return;\n if (autosaveTimer !== null) scheduler.clearTimeout(autosaveTimer);\n autosaveTimer = scheduler.setTimeout(() => {\n autosaveTimer = null;\n if (state.dirty.length && Object.keys(collectErrors()).length === 0) void track(save());\n }, autosave.delayMs);\n }\n\n function runOnchange(changed: string) {\n const source = options.dataSource;\n if (!source?.onchange || page.data.kind !== 'record') return;\n const seq = ++onchangeSeq;\n const request = { model: page.data.model, id: state.recordId, changed, values: structuredCopy(state.values as Values) };\n void track(\n source.onchange(request).then(\n (result) => {\n if (seq !== onchangeSeq) return;\n const values = { ...(state.values as Values), ...(result.values ?? {}) };\n writeValues(values, { warning: result.warning ?? null, warningField: result.warning ? changed : null });\n },\n () => undefined\n )\n );\n }\n\n function afterEdit(changed: string) {\n scheduleDraft();\n scheduleAutosave();\n runOnchange(changed);\n }\n\n function changes(): RecordChanges {\n const result: RecordChanges = { values: {}, lines: {}, links: {} };\n // A new record sends every value it holds, those it started with and defaults\n // included; a stored one sends only what changed since it was loaded.\n const creating = state.recordId === null || state.recordId === undefined;\n const names = creating\n ? Object.keys(page.fields).filter((name) => state.dirty.includes(name) || !isEmpty(page.fields[name], state.values[name]))\n : state.dirty;\n for (const name of names) {\n const def = page.fields[name];\n const now = state.values[name];\n const before = creating ? emptyValue(def) : baseline[name];\n if (def.type === 'one2many') result.lines[name] = lineOps((before as Line[] | null) ?? [], (now as Line[] | null) ?? []);\n else if (def.type === 'many2many') result.links[name] = linkOps((before as RelatedRecord[] | null) ?? [], (now as RelatedRecord[] | null) ?? []);\n else result.values[name] = structuredCopy(now) as Value;\n }\n return result;\n }\n\n /** The values to submit: only fields a visible question shows. */\n function shownValues(): Values {\n const shown: Values = {};\n for (const node of visibleFieldNodes()) {\n const name = node.field as string;\n shown[name] = structuredCopy(state.values[name]) as Value;\n }\n return shown;\n }\n\n async function save(): Promise<boolean> {\n const errors = collectErrors();\n if (Object.keys(errors).length) {\n set({ errors });\n return false;\n }\n const source = options.dataSource;\n serverErrors = {};\n set({ status: 'saving', errors: {}, error: null, saveProblem: null });\n try {\n if (page.data.kind === 'responses') {\n if (!source?.submit) throw new Error('This page has no data source to send its answers to');\n await source.submit({ pageId: page.id, values: shownValues() });\n forgetDraft();\n set({ status: 'saved' });\n return true;\n }\n if (!source?.save) throw new Error('This page has no data source to save to');\n const result = await source.save({\n model: page.data.model,\n id: state.recordId,\n fields: page.fields,\n changes: changes(),\n values: structuredCopy(state.values as Values),\n });\n forgetDraft();\n const values = startFrom(result.values ? { ...(state.values as Values), ...result.values } : (state.values as Values));\n baseline = structuredCopy(values);\n set({ status: 'saved', recordId: result.id, values, dirty: [], warnings: withValues(values, collectWarnings) });\n return true;\n } catch (error) {\n const problem = saveProblemOf(error);\n const fields = problem.kind === 'fields' ? problem.fields ?? {} : {};\n serverErrors = Object.fromEntries(Object.entries(fields).map(([name, message]) => [name, { message, value: JSON.stringify(state.values[name] ?? null) }]));\n set({ status: 'error', error: problem.message, saveProblem: problem, errors: { ...fields } });\n return false;\n }\n }\n\n /** The model a link field's new record belongs to, or null when it cannot make one. */\n function creatable(def: Field | LineField | undefined): string | null {\n if (!options.dataSource?.create || !def || def.readonly) return null;\n return def.type === 'many2one' || def.type === 'many2many' ? def.relation : null;\n }\n\n async function runCreate(def: Field | LineField | undefined, name: string, typed: string): Promise<RelatedRecord> {\n const model = creatable(def);\n const source = options.dataSource;\n if (!model || !source?.create) throw new Error(`\"${name}\" cannot make records: its data source has no create, or it is not a link`);\n return track(source.create({ model, name: typed.trim() }));\n }\n\n async function runSearch(\n def: Field | LineField,\n name: string,\n ctx: Record<string, unknown>,\n query: string,\n limit: number,\n model?: string\n ): Promise<RelatedRecord[]> {\n if (def.type !== 'many2one' && def.type !== 'many2many' && def.type !== 'reference') {\n throw new Error(`\"${name}\" is not a many2one, many2many or reference`);\n }\n if (def.type === 'reference' && !model) throw new Error(`Searching \"${name}\" needs a model`);\n const source = options.dataSource;\n if (!source?.search) return [];\n // Every valueFrom, in groups too, becomes the value it names before the search goes out.\n const resolve = (item: FilterItem): ResolvedFilter =>\n 'any' in item\n ? { any: item.any.map(resolve) }\n : 'all' in item\n ? { all: item.all.map(resolve) }\n : { field: item.field, op: item.op, value: (item.valueFrom !== undefined ? ctx[item.valueFrom] ?? null : item.value ?? null) as JsonValue };\n const filter: ResolvedFilter[] | undefined = def.type === 'reference' ? undefined : def.filter?.map(resolve);\n const relation = def.type === 'reference' ? (model as string) : def.relation;\n return track(source.search({ model: relation, query, ...(filter ? { filter } : {}), limit }));\n }\n\n function lineField(field: string) {\n const def = fieldDef(field);\n if (def.type !== 'one2many') throw new Error(`\"${field}\" is a ${def.type}, not a one2many`);\n return def;\n }\n\n function stepIndex(): number {\n return state.step ? steps.indexOf(state.step) : -1;\n }\n\n /** Whether a step can be passed over with Skip. */\n function optionalStep(id: string): boolean {\n return (index.get(id)?.source as { optional?: boolean } | undefined)?.optional === true;\n }\n\n async function load(): Promise<void> {\n const source = options.dataSource;\n if (state.recordId == null || page.data.kind !== 'record') return;\n if (!source?.load) {\n set({ status: 'error', error: 'This page has no data source to load from' });\n return;\n }\n set({ status: 'loading', error: null });\n try {\n const loaded = await source.load({ model: page.data.model, id: state.recordId, fields: page.fields });\n baseline = startFrom({ ...initialValues(page.fields, today()), ...loaded });\n set({ status: 'ready', values: structuredCopy(baseline), dirty: [], errors: {}, warnings: withValues(baseline, collectWarnings) });\n offerDraft();\n } catch (error) {\n set({ status: 'error', error: (error as Error).message });\n }\n }\n\n const form: Form = {\n page,\n getState: () => state,\n\n subscribe(listener) {\n listeners.add(listener);\n return () => listeners.delete(listener);\n },\n\n load: () => track(load()),\n\n setValue(name, value) {\n fieldDef(name);\n writeValues({ ...(state.values as Values), [name]: structuredCopy(value) });\n afterEdit(name);\n },\n\n node: nodeState,\n\n fieldReadonly: (name) => lockedField(fieldDef(name)),\n\n loadChoices,\n\n problem(name) {\n fieldDef(name);\n // Only a field someone can see is asked anything, and required wherever it is shown so.\n const shown = visibleFieldNodes().filter((node) => node.field === name);\n if (!shown.length) return null;\n const own =\n shown.map(unticked).find(Boolean) ??\n shown.map((node) => checkInput(page.fields[name], node.source as FieldNode, state.values[name], messages)).find(Boolean) ??\n checkValue(checked(name), state.values[name], shown.some((node) => nodeState(node.id).required), messages, today());\n return own ?? shown.map((node) => ruleCheck(node).error).find((error) => error !== undefined) ?? null;\n },\n\n validate() {\n const errors = collectErrors();\n set({ errors });\n return Object.keys(errors).length === 0;\n },\n\n save: () => track(save()),\n\n reset() {\n forgetDraft();\n serverErrors = {};\n holding = setWhen.holding(baseline);\n set({ values: structuredCopy(baseline), dirty: [], errors: {}, warnings: withValues(baseline, collectWarnings), warning: null, warningField: null, draft: null, step: steps[0] ?? null, skipped: [], saveProblem: null });\n },\n\n changes,\n\n addLine(field, values = {}) {\n const def = lineField(field);\n const key = `new-${++lineKeys}`;\n const current = (state.values[field] as Line[] | null) ?? [];\n const line: Line = { key, values: { ...initialValues(def.fields as Record<string, LineField>, today()), ...structuredCopy(values) } };\n // A new line comes last, so it is numbered after the last.\n if (def.sequenceField && line.values[def.sequenceField] == null) {\n const numbers = current.map((l) => l.values[def.sequenceField as string]).filter((n): n is number => typeof n === 'number');\n line.values[def.sequenceField] = numbers.length ? Math.max(...numbers) + 1 : 1;\n }\n const lines = [...current, line];\n writeValues({ ...(state.values as Values), [field]: lines });\n afterEdit(field);\n return key;\n },\n\n updateLine(field, key, name, value) {\n const def = lineField(field);\n if (!def.fields[name]) throw new Error(`The lines of \"${field}\" have no field \"${name}\"`);\n const lines = ((state.values[field] as Line[] | null) ?? []).map((line) =>\n line.key === key ? { ...line, values: { ...line.values, [name]: structuredCopy(value) } } : line\n );\n writeValues({ ...(state.values as Values), [field]: lines });\n afterEdit(field);\n },\n\n moveLine(field, key, to) {\n const def = lineField(field);\n const sequence = def.sequenceField;\n if (!sequence) throw new Error(`The lines of \"${field}\" keep no order: give the field a sequenceField`);\n const lines = [...((state.values[field] as Line[] | null) ?? [])];\n const from = lines.findIndex((line) => line.key === key);\n if (from < 0) throw new Error(`\"${field}\" has no line \"${key}\"`);\n const target = Math.max(0, Math.min(to, lines.length - 1));\n if (target === from) return;\n // The numbers can be reused only if they rise with the lines as shown.\n const before = lines.map((line) => line.values[sequence]);\n const trusted = before.every((n, i) => typeof n === 'number' && (i === 0 || n > (before[i - 1] as number)));\n lines.splice(target, 0, ...lines.splice(from, 1));\n // The lines that moved take the numbers they held between them, in their\n // new order, and the rest keep theirs; otherwise every line is numbered\n // afresh, 1, 2, 3\u2026, so the order saved is the order shown.\n const low = Math.min(from, target);\n const high = Math.max(from, target);\n const pool = trusted ? (before.slice(low, high + 1) as number[]) : [];\n const renumbered = lines.map((line, i) => {\n const value = trusted ? (i >= low && i <= high ? pool[i - low] : line.values[sequence]) : i + 1;\n return value === line.values[sequence] ? line : { ...line, values: { ...line.values, [sequence]: value } };\n });\n writeValues({ ...(state.values as Values), [field]: renumbered });\n afterEdit(field);\n },\n\n removeLine(field, key) {\n lineField(field);\n const lines = ((state.values[field] as Line[] | null) ?? []).filter((line) => line.key !== key);\n writeValues({ ...(state.values as Values), [field]: lines });\n afterEdit(field);\n },\n\n async search(field, query, limit = 8, options = {}) {\n return runSearch(fieldDef(field), field, context(), query, limit, options.model);\n },\n\n async previewLine(field, key, values) {\n lineField(field);\n const lines = (state.values[field] as Line[] | null) ?? [];\n const line = lines.find((l) => l.key === key);\n if (!line) throw new Error(`\"${field}\" has no line \"${key}\"`);\n const merged = computed.line(field, { ...line.values, ...values });\n const source = options.dataSource;\n if (!source?.onchange || page.data.kind !== 'record') return merged;\n const changed = lines.map((l) => (l.key === key ? { ...l, values: merged } : l));\n const result = await source.onchange({ model: page.data.model, id: state.recordId, changed: field, values: structuredCopy({ ...(state.values as Values), [field]: changed }) });\n const after = ((result.values?.[field] as Line[] | undefined) ?? []).find((l) => l.key === key);\n return after ? computed.line(field, { ...merged, ...after.values }) : merged;\n },\n\n async searchLine(field, key, subfield, query, limit = 8) {\n const def = lineField(field);\n const sub = def.fields[subfield];\n if (!sub) throw new Error(`The lines of \"${field}\" have no field \"${subfield}\"`);\n const line = ((state.values[field] as Line[] | null) ?? []).find((l) => l.key === key);\n if (!line) throw new Error(`\"${field}\" has no line \"${key}\"`);\n return runSearch(sub, subfield, expressionContext(line.values, def.fields as Record<string, LineField>), query, limit);\n },\n\n canCreate: (field) => creatable(page.fields[field]) !== null,\n quickCreate: (field, typed) => runCreate(page.fields[field], field, typed),\n canCreateLine: (field, subfield) => creatable(lineField(field).fields[subfield]) !== null,\n quickCreateLine: (field, subfield, typed) => runCreate(lineField(field).fields[subfield], subfield, typed),\n\n steps: () => steps.filter((id) => !nodeState(id).invisible),\n\n next() {\n if (!state.step) return false;\n // A step skipped before and gone back to is answered now, and checked like any other.\n if (state.skipped.includes(state.step)) set({ skipped: state.skipped.filter((id) => id !== state.step) });\n const errors = collectErrors(state.step);\n if (Object.keys(errors).length) {\n set({ errors });\n return false;\n }\n const visible = form.steps();\n const following = steps.slice(stepIndex() + 1).find((id) => visible.includes(id));\n if (!following) return false;\n set({ step: following, errors: {} });\n return true;\n },\n\n back() {\n if (!state.step) return false;\n const visible = form.steps();\n const previous = steps.slice(0, stepIndex()).reverse().find((id) => visible.includes(id));\n if (!previous) return false;\n set({ step: previous, errors: {} });\n return true;\n },\n\n skip() {\n const current = state.step;\n if (!current || !optionalStep(current)) return false;\n const visible = form.steps();\n const following = visible[visible.indexOf(current) + 1];\n if (!following) return false;\n set({ step: following, errors: {}, skipped: [...state.skipped.filter((id) => id !== current), current] });\n return true;\n },\n\n goTo(target) {\n const visible = form.steps();\n const to = visible.indexOf(target);\n const at = state.step ? visible.indexOf(state.step) : -1;\n if (to === -1 || at === -1) return false;\n if (to <= at) {\n set({ step: target, errors: {} });\n return true;\n }\n const skipped = [...state.skipped];\n for (const id of visible.slice(at, to)) {\n if (skipped.includes(id)) continue;\n const errors = collectErrors(id);\n if (!Object.keys(errors).length) continue;\n if (optionalStep(id)) {\n skipped.push(id);\n continue;\n }\n set({ step: id, errors, skipped });\n return false;\n }\n set({ step: target, errors: {}, skipped });\n return true;\n },\n\n async runAction(id, chosen) {\n const node = index.get(id);\n if (!node || (node.kind !== 'button' && node.kind !== 'stat')) throw new Error(`The page has no button \"${id}\"`);\n if (nodeState(id).invisible) return;\n const source = node.source as ButtonNode | StatButton;\n await track(\n Promise.resolve(\n options.onAction?.({\n id,\n action: source.action,\n ...('params' in source && source.params ? { params: source.params } : {}),\n recordId: state.recordId,\n values: structuredCopy(state.values as Values),\n ...(chosen ? { recordIds: [...chosen.recordIds] } : {}),\n })\n )\n );\n },\n\n restoreDraft() {\n const raw = options.drafts?.store.getItem(draftKey());\n if (!raw) return;\n const draft = JSON.parse(raw) as { values: Values };\n writeValues({ ...(state.values as Values), ...draft.values }, { draft: null }, true);\n },\n\n discardDraft() {\n forgetDraft();\n set({ draft: null });\n },\n\n async settled() {\n while (pending.size) await Promise.allSettled([...pending]);\n },\n\n dispose() {\n if (draftTimer !== null) scheduler.clearTimeout(draftTimer);\n if (autosaveTimer !== null) scheduler.clearTimeout(autosaveTimer);\n listeners.clear();\n },\n };\n\n // A record's starting values may already break a warning rule; nothing listens yet.\n state = { ...state, warnings: collectWarnings() };\n if (state.recordId == null) offerDraft();\n return form;\n}\n\n/** A field no one types in: read-only by its definition, or worked out from others. */\nfunction lockedField(def: Field): boolean {\n return def.readonly === true || def.compute !== undefined;\n}\n\nfunction lineOps(before: Line[], now: Line[]): LineOp[] {\n const ops: LineOp[] = [];\n const old = new Map(before.filter((line) => line.id !== undefined).map((line) => [line.key, line]));\n for (const line of now) {\n const previous = old.get(line.key);\n if (line.id === undefined || !previous) {\n ops.push({ op: 'create', key: line.key, values: structuredCopy(line.values) });\n continue;\n }\n const changed: Values = {};\n for (const [name, value] of Object.entries(line.values)) {\n if (JSON.stringify(value) !== JSON.stringify(previous.values[name])) changed[name] = structuredCopy(value) as Value;\n }\n if (Object.keys(changed).length) ops.push({ op: 'update', id: line.id, values: changed });\n }\n const kept = new Set(now.map((line) => line.key));\n for (const line of before) if (line.id !== undefined && !kept.has(line.key)) ops.push({ op: 'delete', id: line.id });\n return ops;\n}\n\nfunction linkOps(before: RelatedRecord[], now: RelatedRecord[]): LinkOp[] {\n const had = new Set(before.map((r) => r.id));\n const has = new Set(now.map((r) => r.id));\n return [\n ...now.filter((r) => !had.has(r.id)).map((r): LinkOp => ({ op: 'link', id: r.id })),\n ...before.filter((r) => !has.has(r.id)).map((r): LinkOp => ({ op: 'unlink', id: r.id })),\n ];\n}\n\nfunction indexLayout(root: RootLayout): Map<string, IndexedNode> {\n const index = new Map<string, IndexedNode>();\n const add = (\n source: IndexedNode['source'],\n parent: string | null,\n kind: IndexedNode['kind'],\n modifiers: { invisible?: Modifier; readonly?: Modifier; required?: Modifier; field?: string }\n ) => {\n index.set(source.id, {\n id: source.id,\n parent,\n kind,\n field: modifiers.field,\n invisible: compileModifier(modifiers.invisible),\n readonly: compileModifier(modifiers.readonly),\n required: compileModifier(modifiers.required),\n source,\n });\n };\n const walk = (nodes: LayoutNode[], parent: string) => {\n for (const node of nodes) {\n if (node.type === 'field') {\n add(node, parent, 'field', { invisible: node.invisible, readonly: node.readonly, required: node.required, field: node.field });\n } else if (node.type === 'button') {\n add(node, parent, 'button', { invisible: node.invisible });\n } else if (node.type === 'tabs') {\n add(node, parent, 'other', { invisible: node.invisible });\n for (const tab of node.children) {\n add(tab, node.id, 'other', { invisible: tab.invisible });\n walk(tab.children, tab.id);\n }\n } else if (node.type === 'section') {\n add(node, parent, 'other', { invisible: node.invisible, readonly: node.readonly });\n walk(node.children, node.id);\n } else {\n add(node, parent, 'other', { invisible: node.invisible });\n }\n }\n };\n\n if (root.type === 'tabs') {\n walk([root], '');\n index.get(root.id)!.parent = null;\n return index;\n }\n add(root, null, 'other', {});\n if (root.type === 'wizard') {\n for (const step of root.children) {\n add(step, root.id, 'step', { invisible: step.invisible });\n walk(step.children, step.id);\n }\n } else if (root.type === 'sections') {\n walk(root.children, root.id);\n } else if (root.type === 'list') {\n // A list holds no fields of its own record: only the buttons for what is selected.\n for (const button of root.actions ?? []) add(button, root.id, 'button', { invisible: button.invisible });\n } else {\n // The title and statusbar show fields too, so they are validated like\n // any field node. Their ids start with \"#\", which no page id can.\n const shown = (id: string, field: string | undefined) => {\n if (field) add({ id }, root.id, 'field', { field });\n };\n shown('#title', root.title?.field);\n shown('#subtitle', root.title?.subtitleField);\n shown('#avatar', root.title?.avatarField);\n shown('#statusbar', root.statusbar?.field);\n for (const button of root.buttons ?? []) add(button, root.id, 'button', { invisible: button.invisible });\n for (const stat of root.statButtons ?? []) add(stat, root.id, 'stat', { invisible: stat.invisible });\n if (root.ribbon) add(root.ribbon, root.id, 'other', { invisible: root.ribbon.invisible });\n for (const alert of root.alerts ?? []) add(alert, root.id, 'other', { invisible: alert.invisible });\n for (const badge of root.badges ?? []) add(badge, root.id, 'other', { invisible: badge.invisible });\n // Fields over and under the title are field nodes like any other.\n walk([...(root.title?.above ?? []), ...(root.title?.below ?? [])], root.id);\n walk(root.children, root.id);\n if (root.sidePanel) add(root.sidePanel, root.id, 'other', { invisible: root.sidePanel.invisible });\n }\n return index;\n}\n", "import type { Locale } from '@fieldia/core';\n\n/**\n * Numbers as a reader of the page's language writes them: grouped, with a\n * field's decimals, in Latin digits (as business software in Arabic shows\n * them), and read back the same way. Shared by the number widget, the lines\n * grid and totals.\n */\n\nconst formats = new Map<string, Intl.NumberFormat>();\nfunction format(locale: Locale, decimals: number): Intl.NumberFormat {\n const key = `${locale}:${decimals}`;\n let found = formats.get(key);\n if (!found) {\n found = new Intl.NumberFormat(locale, { numberingSystem: 'latn', minimumFractionDigits: decimals, maximumFractionDigits: decimals });\n formats.set(key, found);\n }\n return found;\n}\n\n/**\n * An amount with its currency, as the page's language writes money: the\n * symbol before or after, grouped, in Latin digits (\"E\u00A3425,000.00\",\n * \"1.850.000,50 \u20AC\"). A currency named by words that are no code is written\n * before the amount as it is.\n */\nexport function formatMoney(value: number, currency: string, decimals: number, locale: Locale = 'en'): string {\n try {\n return new Intl.NumberFormat(locale, { style: 'currency', currency, currencyDisplay: 'narrowSymbol', numberingSystem: 'latn', minimumFractionDigits: decimals, maximumFractionDigits: decimals }).format(value);\n } catch {\n return `${currency} ${formatNumber(value, decimals, locale)}`;\n }\n}\n\n/** The language's grouping and decimal marks. */\nfunction marks(locale: Locale): { group: string; decimal: string } {\n const parts = format(locale, 1).formatToParts(12345.6);\n return { group: parts.find((p) => p.type === 'group')?.value ?? ',', decimal: parts.find((p) => p.type === 'decimal')?.value ?? '.' };\n}\n\n/** A number at rest: \"1,850,000.50\", \"1.850.000,50\". */\nexport function formatNumber(value: number, decimals: number, locale: Locale = 'en'): string {\n return format(locale, decimals).format(value);\n}\n\n/**\n * Typed text as a number in JavaScript's own spelling (\"1234.5\"), or the text\n * unchanged when it is not one. Arabic-Indic digits are read as digits.\n */\nexport function normalizeNumber(text: string, locale: Locale = 'en'): string {\n const { group, decimal } = marks(locale);\n let out = text\n .replace(/[\u0660-\u0669]/g, (d) => String(d.charCodeAt(0) - 0x0660))\n .replace(/[\u06F0-\u06F9]/g, (d) => String(d.charCodeAt(0) - 0x06f0))\n .replace(/\u066B/g, decimal)\n .replace(/\u066C/g, group);\n // Spaces of any width group digits too (French uses a narrow no-break space).\n out = out.replace(/[\\s\\u00a0\\u202f]/g, '');\n if (group.trim()) out = out.split(group).join('');\n return decimal === '.' ? out : out.split(decimal).join('.');\n}\n", "export const LANGUAGES = {};", "import type { Locale } from '@fieldia/core';\nimport { LANGUAGES } from './locales/all';\n\n/** Every word a widget shows on its own. `{label}` and `{name}` are filled in. */\nexport interface WidgetLabels {\n search: string;\n noResults: string;\n remove: string;\n clear: string;\n addLine: string;\n addSection: string;\n addNote: string;\n deleteLine: string;\n /** A line of a table, as a person is told of it: `{n}` counts from 1. */\n lineN: string;\n /** Heads the row that adds up a table's number columns. */\n total: string;\n /** A problem on one line of a table, under the table. `{n}` counts from 1. */\n lineProblem: string;\n /** Problems beyond the first few. */\n moreProblems: string;\n /** The choice that makes a new record from what was typed. `{name}` is filled in. */\n createNamed: string;\n /** Choices at the end of a link's list, and the button that opens the linked record (`{name}`). */\n createAndEdit: string;\n searchMore: string;\n openNamed: string;\n /** The button that opens a line of a table in a dialog. */\n openLine: string;\n /** The button that lets a person hide or show a table's optional columns. */\n chooseColumns: string;\n /** The button beside a date that opens its calendar. */\n chooseDate: string;\n /** The choice after the options for an answer of one's own, and its box. */\n other: string;\n otherAnswer: string;\n /** Under a single choice that need not be answered, once one is picked: takes the pick back. */\n clearSelection: string;\n previousMonth: string;\n nextMonth: string;\n /** Heads the column of week numbers: short, and in full. */\n weekShort: string;\n week: string;\n /** The formatted-text toolbar and its buttons. */\n formatting: string;\n bold: string;\n italic: string;\n underline: string;\n textStyle: string;\n paragraph: string;\n heading: string;\n subheading: string;\n bulletList: string;\n numberList: string;\n alignLeft: string;\n alignCenter: string;\n alignRight: string;\n link: string;\n linkAddress: string;\n applyLink: string;\n removeLink: string;\n upload: string;\n uploadImage: string;\n replace: string;\n removeFile: string;\n dropHere: string;\n /**\n * Several files: the picker's words, an image field's, and the drop zone's;\n * the limits said before anyone tries (`{size}`, `{max}`); how many there are\n * (`{n}`); why some were not added (`{name}`); removing one, asked first.\n */\n addFiles: string;\n addPhotos: string;\n dropThem: string;\n upToSize: string;\n upToEach: string;\n upToFiles: string;\n fileCount: string;\n oneFile: string;\n fileCountOf: string;\n tooMany: string;\n alreadyAdded: string;\n removeAsk: string;\n keep: string;\n /** A file opened to look at: going through them, which one of how many (`{n}` of `{total}`), and what has no preview. */\n previous: string;\n next: string;\n download: string;\n close: string;\n fileAt: string;\n noPreview: string;\n invalidJson: string;\n /** A signature: the pad, the words on it while it is blank, the box to type a name in instead, and wiping it. */\n signaturePad: string;\n signHere: string;\n typeSignature: string;\n clearDrawing: string;\n /** Takes the last stroke away; a picture of a signature, uploaded instead. */\n undo: string;\n uploadSignature: string;\n /** A slider not slid yet, as a screen reader reads it. */\n notAnswered: string;\n /** A ranking's buttons for a line (`{label}`), and where it went, said aloud: `{n}` of `{total}`, counted from 1. */\n moveUp: string;\n moveDown: string;\n movedTo: string;\n /** An address's parts. */\n addressStreet: string;\n addressCity: string;\n addressLine2: string;\n addressRegion: string;\n addressPostcode: string;\n addressCountry: string;\n /** A repeating group: a card's title (`{n}` counts from 1), the button that adds one, and a card gone, said aloud. */\n entry: string;\n addAnother: string;\n /** A repeating group's card copied right after it: `{name}` is its title. */\n copy: string;\n removed: string;\n /** Choices from the app's list: while they load, a button to load them again, and a value the list no longer has (`{name}`). */\n loadingChoices: string;\n choicesFailed: string;\n notOffered: string;\n /** A yes or no as two buttons. */\n yes: string;\n no: string;\n /** Said once as many boxes are ticked as a question takes (`{n}`). */\n upTo: string;\n /** A ranking: taking the order shown as the answer. */\n keepOrder: string;\n /** A rating's point, as a screen reader names it: `{n}` of `{max}`. */\n ofMax: string;\n /** How many more characters a box with a most takes, said to a screen reader once typing pauses. */\n charactersLeft: string;\n}\n\n/** English: always here, and the words a language leaves out. */\nconst en: WidgetLabels = {\n search: 'Search\u2026',\n noResults: 'No results',\n remove: 'Remove {name}',\n clear: 'Clear {label}',\n addLine: 'Add a line',\n addSection: 'Add a section',\n addNote: 'Add a note',\n deleteLine: 'Delete line',\n lineN: 'line {n}',\n total: 'Total',\n lineProblem: 'Line {n}: {message}',\n moreProblems: 'and {n} more',\n chooseColumns: 'Choose columns',\n createNamed: 'Create \u201C{name}\u201D',\n createAndEdit: 'Create and edit\u2026',\n searchMore: 'Search more\u2026',\n openNamed: 'Open {name}',\n openLine: 'Open line',\n chooseDate: 'Choose a date',\n other: 'Other:',\n otherAnswer: 'Your own answer',\n clearSelection: 'Clear selection',\n previousMonth: 'Previous month',\n nextMonth: 'Next month',\n weekShort: 'Wk',\n week: 'Week',\n formatting: 'Formatting',\n bold: 'Bold',\n italic: 'Italic',\n underline: 'Underline',\n textStyle: 'Text style',\n paragraph: 'Paragraph',\n heading: 'Heading',\n subheading: 'Subheading',\n bulletList: 'Bulleted list',\n numberList: 'Numbered list',\n alignLeft: 'Align left',\n alignCenter: 'Align centre',\n alignRight: 'Align right',\n link: 'Link',\n linkAddress: 'Link address',\n applyLink: 'Apply',\n removeLink: 'Remove link',\n upload: 'Upload a file',\n uploadImage: 'Add a photo',\n replace: 'Replace',\n removeFile: 'Remove',\n dropHere: 'or drop it here',\n addFiles: 'Add files',\n addPhotos: 'Add photos',\n dropThem: 'or drop them here',\n upToSize: 'up to {size}',\n upToEach: 'up to {size} each',\n upToFiles: 'up to {max} files',\n fileCount: '{n} files',\n oneFile: '1 file',\n fileCountOf: '{n} of {max} files',\n tooMany: 'Up to {max} files: {n} not added',\n alreadyAdded: '{name}: already added',\n removeAsk: 'Remove {name}?',\n keep: 'Keep',\n previous: 'Previous',\n next: 'Next',\n download: 'Download',\n close: 'Close',\n fileAt: '{n} of {total}',\n noPreview: 'No preview for this kind of file',\n invalidJson: 'Not valid JSON',\n signaturePad: 'Signature pad: draw your signature',\n signHere: 'Sign here',\n typeSignature: 'Or type your name',\n clearDrawing: 'Clear',\n undo: 'Undo',\n uploadSignature: 'Upload a picture',\n notAnswered: 'Not answered',\n moveUp: 'Move {label} up',\n moveDown: 'Move {label} down',\n movedTo: '{label} moved to place {n} of {total}',\n addressStreet: 'Street address',\n addressCity: 'City',\n addressLine2: 'Address line 2',\n addressRegion: 'State or region',\n addressPostcode: 'Postcode',\n addressCountry: 'Country',\n entry: 'Entry {n}',\n addAnother: 'Add another',\n copy: 'Copy {name}',\n removed: '{name} removed',\n loadingChoices: 'Loading choices\u2026',\n choicesFailed: 'Load the choices again',\n notOffered: '{name}: no longer offered',\n yes: 'Yes',\n no: 'No',\n upTo: 'Up to {n}',\n keepOrder: 'Keep this order',\n ofMax: '{n} of {max}',\n charactersLeft: 'Characters left: {n}',\n};\n\n/**\n * The widgets' words in every language Fieldia has. This package holds all\n * four; the one-tag script holds English alone, and a page adds another\n * language with that language's script (fieldia.ar.js, \u2026), through the\n * viewer's `addLanguage`.\n */\nexport const WIDGET_LABELS: Record<Locale, WidgetLabels> = { en, ...LANGUAGES };\n", "import type { Locale } from '@fieldia/core';\nimport { WIDGET_LABELS, type WidgetLabels } from './labels';\nimport type { WidgetState } from './widgets';\n\n/**\n * Small parts the question kinds share: making elements, their words, saying\n * what is wrong with them, and a polite voice for screen readers.\n */\n\nexport type Make = <K extends keyof HTMLElementTagNameMap>(tag: K, attrs?: Record<string, string | undefined>, ...children: (Node | string)[]) => HTMLElementTagNameMap[K];\n\n/** An element with its attributes and children, in one call. */\nexport function maker(document: Document): Make {\n return (tag, attrs = {}, ...children) => {\n const element = document.createElement(tag);\n for (const [name, value] of Object.entries(attrs)) if (value !== undefined) element.setAttribute(name, value);\n element.append(...children);\n return element;\n };\n}\n\n/** The words a widget shows: the page's, its language's, or English (a language the one-tag script was not given). */\nexport const wordsFor = (labels: WidgetLabels | undefined, locale: Locale | undefined): WidgetLabels => labels ?? WIDGET_LABELS[locale ?? 'en'] ?? WIDGET_LABELS.en;\n\n/** `{name}` and the like filled in. */\nexport const fillIn = (template: string, values: Record<string, string | number>) =>\n template.replace(/\\{(\\w+)\\}/g, (match, key: string) => (key in values ? String(values[key]) : match));\n\n/**\n * An attribute set, or taken away with null, only when that changes it.\n * Every field is brought up to date at each change of a form; writing what is\n * there already still has the browser look at the page anew, which on a big\n * page is most of the time a key takes.\n */\nexport function setAttr(element: Element, name: string, value: string | null): void {\n if (element.getAttribute(name) === value) return;\n if (value === null) element.removeAttribute(name);\n else element.setAttribute(name, value);\n}\n\n/** Shown or hidden, written only when that changes. */\nexport function setHidden(element: HTMLElement, hidden: boolean): void {\n if (element.hidden !== hidden) element.hidden = hidden;\n}\n\n/** Words written only when they change: written again, they would be new words to lay out. */\nexport function setText(element: Node, text: string): void {\n if (element.textContent !== text) element.textContent = text;\n}\n\n/** Whether the answer is wrong, and the help and error that describe it, on the element assistive technology reads. */\nexport function describeState(element: HTMLElement, state: { invalid: boolean; describedBy?: string }) {\n setAttr(element, 'aria-invalid', String(state.invalid));\n setAttr(element, 'aria-describedby', state.describedBy || null);\n}\n\n/** Words said to screen readers when something moves or goes, without taking the focus. */\nexport function announcer(make: Make) {\n const element = make('div', { class: 'fd-announce', role: 'status', 'aria-live': 'polite' });\n return {\n element,\n say(text: string) {\n // The same words twice are still said: the region is emptied first.\n element.textContent = '';\n element.textContent = text;\n },\n };\n}\n\n/** Whether the element sits in a right-to-left page, where left is forward. */\nexport const rightToLeft = (element: Element) => element.closest('[dir]')?.getAttribute('dir') === 'rtl';\n\n/**\n * \"Clear selection\", as Google Forms has it: under a single choice that need not be answered, once something is\n * picked \u2014 a radio, once picked, cannot be unpicked; nor can a slider, once slid.\n */\nexport function clearSelection(document: Document, words: WidgetLabels, clear: () => void) {\n const button = maker(document)('button', { type: 'button', class: 'fd-choice-clear', hidden: '' }, words.clearSelection);\n button.addEventListener('click', clear);\n let open = false;\n return {\n button,\n /** Whether the answer may be left out: not required, and not read-only. */\n allow(state: WidgetState) {\n open = !state.required && !state.readonly;\n },\n show(picked: boolean) {\n setHidden(button, !(open && picked));\n },\n };\n}\n\n/**\n * Removing asks first, in place: \"Remove report.pdf? Remove \u00B7 Keep\", the\n * focus on Keep, Escape keeping it. `ask` shows the question; `then` hears\n * the answer, true to remove.\n */\nexport function askFirst(make: Make, words: WidgetLabels) {\n const question = make('span');\n const yes = make('button', { type: 'button', class: 'fd-button fd-button-link' }, words.removeFile);\n const no = make('button', { type: 'button', class: 'fd-button fd-button-link' }, words.keep);\n const element = make('div', { class: 'fd-file-confirm', hidden: '' }, question, yes, no);\n let then = (_remove: boolean) => undefined as void;\n const answered = (remove: boolean) => {\n element.hidden = true;\n then(remove);\n };\n yes.addEventListener('click', () => answered(true));\n no.addEventListener('click', () => answered(false));\n element.addEventListener('keydown', (event) => event.key === 'Escape' && answered(false));\n return {\n element,\n ask(text: string, answer: (remove: boolean) => void) {\n question.textContent = text;\n then = answer;\n element.hidden = false;\n no.focus();\n },\n };\n}\n", "import type { FieldNode, Form, ReferenceValue, RelatedRecord } from '@fieldia/core';\nimport { WIDGET_LABELS, type WidgetLabels } from './labels';\nimport { setAttr, setHidden } from './kind-parts';\nimport type { Widget, WidgetContext, WidgetFactory } from './widgets';\n\n/**\n * Pickers for related records: a search-as-you-type combobox (the ARIA 1.2\n * combobox pattern), tags for a many2many, and a reference picker. Results\n * come from the data source through the form, so a field's filter applies.\n */\n\nconst DEBOUNCE_MS = 180;\n/** How many matches a link's list shows, as the data source's search would. */\nconst SHOWN = 8;\n\nfunction fill(template: string, values: Record<string, string>) {\n return template.replace(/\\{(\\w+)\\}/g, (match, name: string) => values[name] ?? match);\n}\n\ninterface Combobox {\n element: HTMLElement;\n input: HTMLInputElement;\n /** Show this text when nobody is typing. */\n setText(text: string): void;\n setReadonly(readonly: boolean): void;\n close(): void;\n}\n\n/**\n * A text box with a list of matches under it. `search` finds records,\n * `pick` takes the chosen one, `exclude` hides records already chosen.\n */\nfunction combobox(options: {\n document: Document;\n id: string;\n labels: WidgetLabels;\n search: (query: string) => Promise<RelatedRecord[]>;\n pick: (record: RelatedRecord) => void;\n exclude?: () => Set<RelatedRecord['id']>;\n onEmptyBackspace?: () => void;\n onCommitEmpty?: () => void;\n /** Make a record from what was typed, offered when nothing found has that name. */\n create?: (text: string) => Promise<RelatedRecord>;\n /** How many found records the list shows; a search may find one more, to tell there are others. */\n shown?: number;\n /** Further choices at the end of the list: each acts on the typed text and may hand back a record to pick. */\n more?: (typed: string, overflow: boolean) => { label: string; act: (typed: string) => Promise<RelatedRecord | null> }[];\n}): Combobox {\n const { document: doc, id, labels } = options;\n const listId = `${id}-list`;\n const input = doc.createElement('input');\n Object.assign(input, { id, className: 'fd-input fd-combo-input', autocomplete: 'off' });\n input.setAttribute('role', 'combobox');\n input.setAttribute('aria-autocomplete', 'list');\n input.setAttribute('aria-expanded', 'false');\n input.setAttribute('aria-controls', listId);\n input.placeholder = labels.search;\n const list = doc.createElement('ul');\n list.id = listId;\n list.className = 'fd-listbox';\n list.setAttribute('role', 'listbox');\n list.hidden = true;\n const element = doc.createElement('div');\n element.className = 'fd-combo';\n element.append(input, list);\n\n let shown = '';\n /** The \"Create \u2026\" choice in the list, and the text it would make a record from. */\n let creating: RelatedRecord | null = null;\n let creatingText = '';\n /** The further choices at the end of the list, by the entry that stands for each. */\n let extras = new Map<RelatedRecord, (typed: string) => Promise<RelatedRecord | null>>();\n /** True while the person's own typing is in the box. */\n let editing = false;\n let results: RelatedRecord[] = [];\n let active = -1;\n let seq = 0;\n let timer: ReturnType<typeof setTimeout> | undefined;\n let readonly = false;\n\n function render() {\n list.replaceChildren();\n results.forEach((record, i) => {\n const option = doc.createElement('li');\n option.id = `${listId}-${i}`;\n option.setAttribute('role', 'option');\n option.setAttribute('aria-selected', String(i === active));\n option.className = `fd-option${i === active ? ' fd-active' : ''}${record === creating || extras.has(record) ? ' fd-option-create' : ''}`;\n option.textContent = record.label;\n option.addEventListener('mousedown', (event) => event.preventDefault()); // keep focus in the box\n option.addEventListener('click', () => choose(i));\n list.append(option);\n });\n if (!results.length) {\n const empty = doc.createElement('li');\n empty.className = 'fd-empty';\n empty.textContent = labels.noResults;\n list.append(empty);\n }\n if (active >= 0) input.setAttribute('aria-activedescendant', `${listId}-${active}`);\n else input.removeAttribute('aria-activedescendant');\n }\n\n function open() {\n list.hidden = false;\n input.setAttribute('aria-expanded', 'true');\n }\n\n function close() {\n // A search still on its way must not open the list again.\n clearTimeout(timer);\n seq++;\n list.hidden = true;\n input.setAttribute('aria-expanded', 'false');\n input.removeAttribute('aria-activedescendant');\n active = -1;\n }\n\n function choose(index: number) {\n const record = results[index];\n if (!record) return;\n const typed = creatingText;\n close();\n editing = false;\n if (record === creating && options.create) {\n void options.create(typed).then(options.pick, () => undefined);\n return;\n }\n const act = extras.get(record);\n if (act) {\n void act(typed).then((picked) => picked && options.pick(picked), () => undefined);\n return;\n }\n options.pick(record);\n }\n\n function lookUp(query: string) {\n clearTimeout(timer);\n const mine = ++seq;\n timer = setTimeout(async () => {\n const found = await options.search(query).catch(() => [] as RelatedRecord[]);\n if (mine !== seq || doc.activeElement !== input) return; // a newer search, or the person left\n // A record the arrow keys reached stays reached if the answer still lists it.\n const reached = results[active];\n const held = reached && reached !== creating && !extras.has(reached) ? reached.id : undefined;\n const hidden = options.exclude?.() ?? new Set();\n const kept = found.filter((record) => !hidden.has(record.id));\n const overflow = options.shown !== undefined && kept.length > options.shown;\n results = overflow ? kept.slice(0, options.shown) : kept;\n // Nothing found by that name: offer to make it.\n const typed = query.trim();\n creating = null;\n if (options.create && typed && !found.some((record) => record.label.trim().toLowerCase() === typed.toLowerCase())) {\n creatingText = typed;\n creating = { id: '__create__', label: fill(labels.createNamed, { name: typed }) };\n results = [...results, creating];\n }\n creatingText = typed;\n extras = new Map((options.more?.(typed, overflow) ?? []).map((extra, i) => [{ id: `__more_${i}__`, label: extra.label }, extra.act]));\n results = [...results, ...extras.keys()];\n active = held === undefined ? -1 : results.findIndex((record) => record.id === held);\n render();\n open();\n }, DEBOUNCE_MS);\n }\n\n input.addEventListener('input', () => {\n editing = true;\n if (!readonly) lookUp(input.value);\n });\n input.addEventListener('focus', () => {\n if (!readonly) lookUp('');\n });\n input.addEventListener('keydown', (event) => {\n if (readonly) return;\n switch (event.key) {\n case 'ArrowDown':\n case 'ArrowUp': {\n event.preventDefault();\n if (list.hidden) return lookUp(input.value);\n if (!results.length) return;\n active = (active + (event.key === 'ArrowDown' ? 1 : -1) + results.length) % results.length;\n render();\n list.children[active]?.scrollIntoView?.({ block: 'nearest' });\n return;\n }\n case 'Enter':\n if (!list.hidden && active >= 0) {\n event.preventDefault();\n choose(active);\n }\n return;\n case 'Escape':\n if (!list.hidden) event.preventDefault();\n close();\n editing = false;\n input.value = shown;\n return;\n case 'Backspace':\n if (input.value === '') options.onEmptyBackspace?.();\n return;\n }\n });\n input.addEventListener('blur', () => {\n seq++;\n clearTimeout(timer);\n close();\n const emptied = editing && input.value.trim() === '' && shown !== '';\n editing = false;\n if (emptied) options.onCommitEmpty?.();\n else input.value = shown;\n });\n\n return {\n element,\n input,\n setText(text) {\n shown = text;\n if (!editing && input.value !== text) input.value = text;\n },\n setReadonly(next) {\n readonly = next;\n if (input.readOnly !== next) input.readOnly = next;\n if (next) close();\n },\n close,\n };\n}\n\n/** Making a record from a typed name, unless the page turns it off or the data source cannot. */\nfunction creator(form: Form, name: string, node: FieldNode): ((text: string) => Promise<RelatedRecord>) | undefined {\n return node.options?.['create'] !== false && form.canCreate(name) ? (text) => form.quickCreate(name, text) : undefined;\n}\n\nexport const many2oneWidget: WidgetFactory = ({ form, name, field, node, id, document, labels = WIDGET_LABELS.en, dialogs }) => {\n const relation = field.type === 'many2one' ? field.relation : '';\n const canOpen = !!dialogs && dialogs.canOpen(relation);\n let readonly = false;\n const box = combobox({\n document,\n id,\n labels,\n // One past what the list shows, to know whether Search more\u2026 has more to find.\n search: (query) => form.search(name, query, SHOWN + 1),\n shown: SHOWN,\n pick: (record) => form.setValue(name, record),\n onCommitEmpty: () => form.setValue(name, null),\n create: creator(form, name, node),\n // With dialogs: make a record in its own page, or pick from a full list when the short one has no room.\n more: (typed, overflow) => {\n if (!dialogs || readonly) return [];\n const choices: { label: string; act: (text: string) => Promise<RelatedRecord | null> }[] = [];\n if (typed && canOpen && node.options?.['create'] !== false) {\n choices.push({ label: labels.createAndEdit, act: (text) => dialogs.openRecord(relation, { name: text, title: field.label }) });\n }\n if (overflow) choices.push({ label: labels.searchMore, act: () => dialogs.searchMore({ title: field.label, search: (query, limit) => form.search(name, query, limit) }) });\n return choices;\n },\n });\n // The linked record, opened in a dialog where the app can show it; a new name it is saved with follows here.\n const open = canOpen ? document.createElement('button') : null;\n if (open) {\n open.type = 'button';\n open.className = 'fd-combo-open';\n open.textContent = '\u2197';\n open.hidden = true;\n open.addEventListener('click', async () => {\n const current = form.getState().values[name] as RelatedRecord | null;\n if (!current || !dialogs) return;\n const saved = await dialogs.openRecord(relation, { recordId: current.id, title: current.label });\n if (saved && saved.label !== current.label) form.setValue(name, saved);\n });\n }\n const clear = document.createElement('button');\n clear.type = 'button';\n clear.className = 'fd-combo-clear';\n clear.textContent = '\u00D7';\n clear.setAttribute('aria-label', fill(labels.clear, { label: field.label }));\n clear.addEventListener('click', () => {\n form.setValue(name, null);\n box.input.focus();\n });\n box.element.append(clear, ...(open ? [open] : []));\n return {\n element: box.element,\n focus: () => box.input.focus(),\n update(state) {\n const record = state.value as RelatedRecord | null | undefined;\n readonly = state.readonly;\n box.setText(record?.label ?? '');\n box.setReadonly(state.readonly);\n setHidden(clear, !record || state.readonly);\n if (open) {\n setHidden(open, !record);\n if (record) setAttr(open, 'aria-label', fill(labels.openNamed, { name: record.label }));\n }\n setAttr(box.input, 'aria-invalid', String(state.invalid));\n setAttr(box.input, 'aria-required', String(state.required));\n if (state.describedBy) setAttr(box.input, 'aria-describedby', state.describedBy);\n },\n } satisfies Widget;\n};\n\nexport const tagsWidget: WidgetFactory = ({ form, name, field, node, id, document, labels = WIDGET_LABELS.en, dialogs }) => {\n const relation = field.type === 'many2many' ? field.relation : '';\n const current = () => (form.getState().values[name] as RelatedRecord[] | null) ?? [];\n const element = document.createElement('div');\n element.className = 'fd-tags';\n element.setAttribute('role', 'group');\n const chips = document.createElement('ul');\n chips.className = 'fd-chips';\n const box = combobox({\n document,\n id,\n labels,\n // One past what the list shows, besides those chosen, to know whether Search more\u2026 has more to find.\n search: (query) => form.search(name, query, SHOWN + 1 + current().length),\n shown: SHOWN,\n pick: (record) => {\n if (!current().some((r) => r.id === record.id)) form.setValue(name, [...current(), record]);\n box.input.value = '';\n },\n exclude: () => new Set(current().map((record) => record.id)),\n onEmptyBackspace: () => {\n const records = current();\n if (records.length) form.setValue(name, records.slice(0, -1));\n },\n create: creator(form, name, node),\n // With dialogs: pick from a full list when the short one has no room.\n more: (_typed, overflow) => (dialogs && overflow ? [{ label: labels.searchMore, act: () => dialogs.searchMore({ title: field.label, search: (query, limit) => form.search(name, query, limit) }) }] : []),\n });\n // A linked record, opened from its tag in a dialog where the app can show it; a new name it is saved with follows here.\n const open =\n dialogs && dialogs.canOpen(relation)\n ? async (record: RelatedRecord) => {\n const saved = await dialogs.openRecord(relation, { recordId: record.id, title: record.label });\n if (saved && saved.label !== record.label) form.setValue(name, current().map((r) => (r.id === record.id ? saved : r)));\n }\n : undefined;\n element.append(chips, box.element);\n let readonly = false;\n let drawn = '';\n return {\n element,\n focus: () => box.input.focus(),\n update(state) {\n const records = (state.value as RelatedRecord[] | null) ?? [];\n // Rebuild the chips only when they change, not on every keystroke elsewhere.\n const key = JSON.stringify([state.readonly, records]);\n readonly = state.readonly;\n box.setReadonly(readonly);\n box.element.hidden = readonly;\n box.input.setAttribute('aria-invalid', String(state.invalid));\n if (state.describedBy) box.input.setAttribute('aria-describedby', state.describedBy);\n if (key === drawn) return;\n drawn = key;\n drawChips(chips, records, readonly, labels, (record) => form.setValue(name, current().filter((r) => r.id !== record.id)), open);\n box.setText('');\n },\n };\n};\n\n/** Chips for tags, each with a remove button unless read-only; with `open`, each one's words a button that opens it. */\nfunction drawChips(chips: HTMLElement, records: RelatedRecord[], readonly: boolean, labels: WidgetLabels, remove: (record: RelatedRecord) => void, open?: (record: RelatedRecord) => void) {\n const doc = chips.ownerDocument;\n chips.replaceChildren(\n ...records.map((record) => {\n const chip = doc.createElement('li');\n chip.className = 'fd-chip';\n const text = doc.createElement(open ? 'button' : 'span');\n text.className = 'fd-chip-label';\n text.textContent = record.label;\n if (open) {\n (text as HTMLButtonElement).type = 'button';\n text.setAttribute('aria-label', fill(labels.openNamed, { name: record.label }));\n text.addEventListener('click', () => open(record));\n }\n chip.append(text);\n if (!readonly) {\n const button = doc.createElement('button');\n button.type = 'button';\n button.className = 'fd-chip-remove';\n button.textContent = '\u00D7';\n button.setAttribute('aria-label', fill(labels.remove, { name: record.label }));\n button.addEventListener('click', () => remove(record));\n chip.append(button);\n }\n return chip;\n })\n );\n}\n\n/**\n * Free-text tags on a text field, kept as \"oak, glass\": Enter or a comma adds\n * what was typed, Backspace in an empty box takes the last one away, and the\n * node's `options.suggestions` are offered as you type. `options.separator`\n * is \",\" unless set; with `options.max`, the box goes once there are as many.\n */\nexport const charTagsWidget: WidgetFactory = ({ form, name, node, id, document, labels = WIDGET_LABELS.en }) => {\n const options = node.options ?? {};\n const separator = typeof options['separator'] === 'string' && options['separator'] ? options['separator'] : ',';\n const suggestions = Array.isArray(options['suggestions']) ? options['suggestions'].filter((s): s is string => typeof s === 'string') : [];\n const split = (text: unknown) =>\n typeof text === 'string' ? text.split(separator).map((t) => t.trim()).filter((t) => t !== '') : [];\n const current = () => split(form.getState().values[name]);\n const write = (tags: string[]) => form.setValue(name, tags.length ? tags.join(`${separator} `) : null);\n const add = (raw: string) => {\n const tag = raw.trim();\n const tags = current();\n if (tag && !tags.some((t) => t.toLowerCase() === tag.toLowerCase()) && !(tags.length >= (options['max'] as number))) write([...tags, tag]);\n };\n\n const element = document.createElement('div');\n element.className = 'fd-tags';\n element.setAttribute('role', 'group');\n const chips = document.createElement('ul');\n chips.className = 'fd-chips';\n const box = combobox({\n document,\n id,\n labels,\n search: async (query) => {\n const taken = new Set(current().map((t) => t.toLowerCase()));\n const wanted = query.trim().toLowerCase();\n return suggestions\n .filter((s) => !taken.has(s.toLowerCase()) && s.toLowerCase().includes(wanted))\n .map((s) => ({ id: s, label: s }));\n },\n pick: (record) => {\n add(record.label);\n box.input.value = '';\n },\n onEmptyBackspace: () => {\n const tags = current();\n if (tags.length) write(tags.slice(0, -1));\n },\n });\n // Enter with nothing chosen from the list adds what was typed.\n box.input.addEventListener('keydown', (event) => {\n if (event.key !== 'Enter' || event.defaultPrevented || box.input.value.trim() === '') return;\n event.preventDefault();\n add(box.input.value);\n box.input.value = '';\n box.close();\n });\n // A separator typed ends a tag.\n box.input.addEventListener('input', () => {\n const parts = box.input.value.split(separator);\n if (parts.length < 2) return;\n for (const part of parts.slice(0, -1)) add(part);\n box.input.value = parts[parts.length - 1].trimStart();\n });\n // Typed and left without Enter: kept. (change comes before blur clears the box.)\n box.input.addEventListener('change', () => {\n if (box.input.value.trim()) add(box.input.value);\n });\n element.append(chips, box.element);\n let drawn = '';\n return {\n element,\n focus: () => box.input.focus(),\n update(state) {\n const tags = split(state.value);\n box.setReadonly(state.readonly);\n box.element.hidden = state.readonly || tags.length >= (options['max'] as number);\n box.input.setAttribute('aria-invalid', String(state.invalid));\n if (state.describedBy) box.input.setAttribute('aria-describedby', state.describedBy);\n const key = JSON.stringify([state.readonly, tags]);\n if (key === drawn) return;\n drawn = key;\n const typing = document.activeElement === box.input;\n drawChips(chips, tags.map((t) => ({ id: t, label: t })), state.readonly, labels, (record) => write(current().filter((t) => t !== record.label)));\n box.setText('');\n // The box gone at the most, the cursor stays in the keywords: on the last one's \u00D7.\n if (typing && box.element.hidden) chips.querySelector<HTMLButtonElement>('li:last-child button')?.focus();\n },\n };\n};\n\n/** Every record as a checkbox. For short lists: it loads up to 50. */\nexport const linkCheckboxesWidget: WidgetFactory = ({ form, name, id, document }) => {\n const element = document.createElement('div');\n element.id = id;\n element.className = 'fd-choices fd-choices-checkbox';\n element.setAttribute('role', 'group');\n let boxes: { record: RelatedRecord; box: HTMLInputElement }[] = [];\n let latest = { readonly: false, value: [] as RelatedRecord[] };\n // Built once, when the records arrive; updates only tick boxes, so focus stays put.\n const sync = () => {\n const chosen = new Set(latest.value.map((r) => r.id));\n for (const { record, box } of boxes) {\n box.checked = chosen.has(record.id);\n box.disabled = latest.readonly;\n }\n };\n void form.search(name, '', 50).then((records) => {\n boxes = records.map((record, i) => {\n const box = document.createElement('input');\n box.type = 'checkbox';\n box.id = `${id}-${i}`;\n box.addEventListener('change', () => {\n const now = (form.getState().values[name] as RelatedRecord[] | null) ?? [];\n form.setValue(name, box.checked ? [...now, record] : now.filter((r) => r.id !== record.id));\n });\n const label = document.createElement('label');\n label.className = 'fd-choice';\n label.htmlFor = box.id;\n const text = document.createElement('span');\n text.textContent = record.label;\n label.append(box, text);\n element.append(label);\n return { record, box };\n });\n sync();\n });\n return {\n element,\n focus: () => element.querySelector('input')?.focus(),\n update(state) {\n latest = { readonly: state.readonly, value: (state.value as RelatedRecord[] | null) ?? [] };\n sync();\n },\n };\n};\n\nexport const referenceWidget: WidgetFactory = (context: WidgetContext) => {\n const { form, name, field, id, document, labels = WIDGET_LABELS.en } = context;\n const models = field.type === 'reference' ? field.models : [];\n const element = document.createElement('div');\n element.className = 'fd-reference';\n const select = document.createElement('select');\n select.className = 'fd-input fd-select';\n select.setAttribute('aria-label', field.label);\n select.append(document.createElement('option'));\n for (const model of models) {\n const option = document.createElement('option');\n option.value = String(model.value);\n option.textContent = model.label;\n select.append(option);\n }\n let model = '';\n select.addEventListener('change', () => {\n model = select.value;\n form.setValue(name, null);\n });\n const box = combobox({\n document,\n id,\n labels,\n search: (query) => (model ? form.search(name, query, 8, { model }) : Promise.resolve([])),\n pick: (record) => form.setValue(name, { model, id: record.id, label: record.label }),\n onCommitEmpty: () => form.setValue(name, null),\n });\n element.append(select, box.element);\n return {\n element,\n focus: () => (model ? box.input.focus() : select.focus()),\n update(state) {\n const value = state.value as ReferenceValue | null | undefined;\n if (value) model = value.model;\n select.value = model;\n select.disabled = state.readonly;\n box.setText(value?.label ?? '');\n box.setReadonly(state.readonly || !model);\n },\n };\n};\n", "import type { LineField, Locale, Value } from '@fieldia/core';\nimport { formatMoney, formatNumber } from './numbers';\n\n\nfunction localDate(text: string): Date | null {\n const match = /^(\\d{4})-(\\d{2})-(\\d{2})(?:[T ](\\d{2}):(\\d{2}))?/.exec(text);\n if (!match) return null;\n const [, y, m, d, hh, mm] = match;\n return new Date(Number(y), Number(m) - 1, Number(d), Number(hh ?? 0), Number(mm ?? 0));\n}\n\n/**\n * A value as a person reads it where it is not being edited: a cell of the\n * lines grid, a totals row. Shared by the plain lines table and @fieldia/grid.\n */\nexport function displayValue(def: LineField, value: Value | undefined, values: Record<string, Value> = {}, locale: Locale = 'en'): string {\n const number = (n: number, digits: number) => formatNumber(n, digits, locale);\n if (value === null || value === undefined || value === '') return '';\n switch (def.type) {\n case 'many2one':\n case 'reference':\n return (value as { label?: string }).label ?? '';\n case 'many2many':\n return ((value as { label: string }[]) ?? []).map((r) => r.label).join(', ');\n case 'selection': {\n const label = (v: unknown) => def.options.find((o) => o.value === v)?.label ?? String(v);\n return Array.isArray(value) ? value.map(label).join(', ') : label(value);\n }\n case 'integer':\n return number(Number(value), 0);\n case 'float':\n return number(Number(value), def.digits?.[1] ?? 2);\n case 'monetary': {\n const currency = def.currency ?? (def.currencyField ? (values[def.currencyField] as { label?: string } | null)?.label : undefined);\n // Its currency's symbol, as the amount's own box shows it.\n return currency ? formatMoney(Number(value), currency, def.digits?.[1] ?? 2, locale) : number(Number(value), def.digits?.[1] ?? 2);\n }\n case 'date': {\n const date = localDate(String(value));\n return date ? new Intl.DateTimeFormat(locale === 'en' ? 'en-GB' : locale, { day: 'numeric', month: 'short', year: 'numeric', numberingSystem: 'latn' }).format(date) : String(value);\n }\n case 'datetime': {\n const date = localDate(String(value));\n return date\n ? new Intl.DateTimeFormat(locale === 'en' ? 'en-GB' : locale, { day: 'numeric', month: 'short', year: 'numeric', hour: '2-digit', minute: '2-digit', numberingSystem: 'latn' }).format(date)\n : String(value);\n }\n case 'html':\n return String(value).replace(/<[^>]*>/g, ' ').replace(/\\s+/g, ' ').trim();\n case 'binary':\n case 'image':\n // One file, or several: their names.\n return [value].flat().map((file) => (file as { name?: string }).name ?? '').join(', ');\n case 'boolean':\n return value ? '\u2713' : '';\n default:\n return String(value);\n }\n}\n", "import type { Field, Form, Line } from '@fieldia/core';\n\n/**\n * A line of a table or a card of a repeating group moved to another place:\n * numbered again by the field's sequence where it keeps one, else the list\n * of lines in its new order. The lines a page's value holds are in the order\n * they are shown.\n */\nexport function moveLineTo(form: Form, name: string, field: Field, key: string, to: number): void {\n if (field.type === 'one2many' && field.sequenceField) return form.moveLine(name, key, to);\n const lines = [...((form.getState().values[name] as Line[] | null) ?? [])];\n const from = lines.findIndex((line) => line.key === key);\n if (from < 0 || to < 0 || to >= lines.length || to === from) return;\n lines.splice(to, 0, ...lines.splice(from, 1));\n form.setValue(name, lines);\n}\n", "import { isEmpty, lineKind, type Field, type FieldNode, type Form, type FormState, type Line, type LineField, type Value } from '@fieldia/core';\nimport { displayValue } from './display';\nimport { askFirst, fillIn, maker } from './kind-parts';\nimport { WIDGET_LABELS } from './labels';\nimport { moveLineTo } from './line-moves';\nimport { createWidget, type Widget, type WidgetFactory } from './widgets';\n\n/**\n * A one2many as an editable table. Each cell is an ordinary widget; a small\n * adapter routes its edits to `updateLine` and its searches to `searchLine`,\n * so a many2one inside a line searches with that line's own values. Rows are\n * matched by line key, so adding or removing a line never rebuilds the others.\n * When the field declares `lineKinds`, a section or a note is one wide row of\n * its text.\n *\n * A line moves by the grip at its start, or by Alt+\u2191/\u2193 from inside it, said\n * aloud. The node's `options`: `min` lines at least \u2014 a new table starts with\n * them \u2014 and `max` at most; `addLabel`, the Add button's words; `emptyLabel`,\n * a sentence while there is no line; `confirmDelete`, asking before a line\n * with something in it goes.\n */\n\ninterface Row {\n element: HTMLTableRowElement;\n kind: 'section' | 'note' | null;\n cells: { name: string; def: LineField; widget: Widget; error: HTMLElement }[];\n remove: HTMLButtonElement;\n grip: HTMLElement;\n}\n\nconst count = (value: unknown) => (typeof value === 'number' && Number.isInteger(value) && value >= 0 ? value : undefined);\n\n/** The field a section or note is typed into: one line for a heading, a growing box for a note. */\nexport function kindTextField(def: LineField, kind: 'section' | 'note'): LineField {\n return kind === 'section' ? ({ ...def, type: 'char' } as LineField) : ({ ...def, type: 'text' } as LineField);\n}\n\n/** The form a cell sees: the line's values, written back into the line. Shared with @fieldia/grid. */\nexport function lineForm(form: Form, field: string, key: string): Form {\n const values = () => (((form.getState().values[field] as Line[] | null) ?? []).find((l) => l.key === key)?.values ?? {});\n return {\n ...form,\n getState: (): FormState => ({ ...form.getState(), values: values() }),\n setValue: (name: string, value: Value) => form.updateLine(field, key, name, value),\n search: (name: string, query: string, limit?: number) => form.searchLine(field, key, name, query, limit),\n canCreate: (name: string) => form.canCreateLine(field, name),\n quickCreate: (name: string, text: string) => form.quickCreateLine(field, name, text),\n };\n}\n\nexport const linesWidget: WidgetFactory = ({ form, name, field, node, id, document, labels = WIDGET_LABELS.en, locale, dialogs }) => {\n const def = field as Extract<Field, { type: 'one2many' }>;\n const kinds = def.lineKinds;\n const make = maker(document);\n const options = node.options ?? {};\n const min = count(options['min']) ?? 0;\n const max = count(options['max']) ?? Infinity;\n const words = (key: string) => (typeof options[key] === 'string' && (options[key] as string).trim() ? (options[key] as string) : null);\n // The fields that say what a line is and keep the lines' order never show as columns.\n // Optional columns the page starts hidden stay out of the plain table.\n const columns = (node.columns ?? Object.keys(def.fields)).filter(\n (column) => def.fields[column] && column !== kinds?.field && column !== def.sequenceField && node.optionalColumns?.[column] !== 'hide'\n );\n const element = document.createElement('div');\n element.className = 'fd-lines';\n element.id = id;\n element.setAttribute('role', 'group');\n const scroller = document.createElement('div');\n scroller.className = 'fd-lines-scroll';\n const table = document.createElement('table');\n table.className = 'fd-lines-table';\n const head = document.createElement('thead');\n const headRow = document.createElement('tr');\n headRow.append(make('th', { class: 'fd-lines-grip' }));\n for (const column of columns) {\n const th = document.createElement('th');\n th.scope = 'col';\n th.textContent = def.fields[column].label;\n headRow.append(th);\n }\n const lastTh = document.createElement('th');\n lastTh.className = 'fd-lines-tools';\n headRow.append(lastTh);\n head.append(headRow);\n const body = document.createElement('tbody');\n table.append(head, body);\n // Number columns the page asks to add up, in a row under the lines.\n const totals = (node.totals ?? []).filter((column) => columns.includes(column));\n const sums = new Map<string, HTMLTableCellElement>();\n if (totals.length) {\n const foot = document.createElement('tfoot');\n const row = document.createElement('tr');\n row.className = 'fd-lines-totals';\n row.append(document.createElement('td'));\n columns.forEach((column, i) => {\n const td = document.createElement('td');\n if (totals.includes(column)) sums.set(column, td);\n else if (i === 0) td.textContent = labels.total;\n row.append(td);\n });\n row.append(document.createElement('td'));\n foot.append(row);\n table.append(foot);\n }\n scroller.append(table);\n const adds = document.createElement('div');\n adds.className = 'fd-lines-adds';\n const addButton = (text: string, values: Record<string, Value>, kind: string) => {\n const button = document.createElement('button');\n button.type = 'button';\n button.className = 'fd-button fd-button-link fd-lines-add';\n button.dataset['add'] = kind;\n button.textContent = `+ ${text}`;\n button.addEventListener('click', () => {\n focusNew = form.addLine(name, values);\n const row = rows.get(focusNew);\n if (row) {\n row.cells[0]?.widget.focus();\n focusNew = null;\n }\n });\n adds.append(button);\n };\n addButton(words('addLabel') ?? labels.addLine, {}, 'line');\n if (kinds) {\n addButton(labels.addSection, { [kinds.field]: kinds.section ?? 'section' }, 'section');\n addButton(labels.addNote, { [kinds.field]: kinds.note ?? 'note' }, 'note');\n }\n const emptyWords = words('emptyLabel');\n const empty = emptyWords ? make('div', { class: 'fd-help fd-lines-empty' }, emptyWords) : null;\n // Removing a line with something in it asks first, in place: \"Remove line 2? Remove \u00B7 Keep\".\n const confirm = askFirst(make, labels);\n // Where a line went, said politely; not the page's own announcer, which a page looks for by its class.\n const voice = make('div', { class: 'fd-sr-only', role: 'status' });\n element.append(scroller, ...(empty ? [empty] : []), adds, confirm.element, voice);\n\n const rows = new Map<string, Row>();\n let focusNew: string | null = null;\n let readonly = false;\n const current = () => (form.getState().values[name] as Line[] | null) ?? [];\n // A new table starts with the lines it needs at least.\n for (let have = current().length; have < min; have++) form.addLine(name);\n\n /** A line to another place, the focus kept where it was, and where it went said aloud. */\n function move(key: string, to: number) {\n const from = current().findIndex((line) => line.key === key);\n if (readonly || to === from || to < 0 || to >= current().length) return;\n const focused = document.activeElement as HTMLElement | null;\n // Named by its first column's words, else by where it was.\n const first = current()[from].values[columns[0]];\n moveLineTo(form, name, def, key, to);\n if (focused && focused !== document.activeElement) focused.focus();\n voice.textContent = fillIn(labels.movedTo, { label: typeof first === 'string' && first.trim() ? first : fillIn(labels.lineN, { n: from + 1 }), n: to + 1, total: current().length });\n }\n body.addEventListener('keydown', (event) => {\n const key = (event.target as Element).closest('tr')?.dataset['line'];\n if (!key || !event.altKey || (event.key !== 'ArrowUp' && event.key !== 'ArrowDown')) return;\n event.preventDefault();\n move(key, current().findIndex((line) => line.key === key) + (event.key === 'ArrowUp' ? -1 : 1));\n });\n function makeCell(tr: HTMLTableRowElement, line: Line, column: string, sub: LineField, span = 1) {\n const cellId = `${id}-${line.key}-${column}`;\n const subNode: FieldNode = { type: 'field', id: `${node.id}.${line.key}.${column}`, field: column };\n const widget = createWidget({ form: lineForm(form, name, line.key), name: column, field: sub as Field, node: subNode, id: cellId, document, labels, locale, dialogs });\n const td = document.createElement('td');\n td.colSpan = span;\n const label = document.createElement('label');\n label.className = 'fd-sr-only';\n label.htmlFor = cellId;\n label.textContent = sub.label;\n const error = document.createElement('div');\n error.className = 'fd-cell-error';\n error.hidden = true;\n td.append(label, widget.element, error);\n tr.append(td);\n return { name: column, def: sub, widget, error };\n }\n\n function makeRow(line: Line): Row {\n const tr = document.createElement('tr');\n tr.dataset['line'] = line.key;\n const kind = lineKind(def, line.values);\n if (kind) tr.className = `fd-line-${kind}`;\n // Dragged by its grip, the line takes the place the pointer is at.\n const grip = make('span', { class: 'fd-line-grip fd-rank-grip', 'aria-hidden': 'true' });\n let dragging = false;\n grip.addEventListener('pointerdown', (event) => {\n if (readonly || event.button !== 0) return;\n event.preventDefault();\n grip.setPointerCapture?.(event.pointerId);\n dragging = true;\n });\n grip.addEventListener('pointermove', (event) => {\n if (!dragging) return;\n // The place among the others: as many as have their middle above the pointer.\n move(line.key, [...body.children].filter((row) => row !== tr && row.getBoundingClientRect().top + row.getBoundingClientRect().height / 2 < event.clientY).length);\n });\n for (const end of ['pointerup', 'pointercancel']) grip.addEventListener(end, () => (dragging = false));\n tr.append(make('td', { class: 'fd-lines-grip' }, grip));\n const cells =\n kind && kinds\n ? [makeCell(tr, line, kinds.text, kindTextField(def.fields[kinds.text], kind), columns.length)]\n : columns.map((column) => makeCell(tr, line, column, def.fields[column]));\n const tools = document.createElement('td');\n tools.className = 'fd-lines-tools';\n const remove = document.createElement('button');\n remove.type = 'button';\n remove.className = 'fd-line-delete';\n remove.textContent = '\u00D7';\n remove.setAttribute('aria-label', labels.deleteLine);\n remove.addEventListener('click', () => {\n const at = current().findIndex((l) => l.key === line.key);\n const values = current()[at]?.values ?? {};\n if (options['confirmDelete'] !== true || cells.every((cell) => isEmpty(cell.def, values[cell.name]) || values[cell.name] === false)) return form.removeLine(name, line.key);\n confirm.ask(fillIn(labels.removeAsk, { name: fillIn(labels.lineN, { n: at + 1 }) }), (gone) => {\n if (gone) form.removeLine(name, line.key);\n // The line that took its place, or this one kept; else Add.\n const left = current();\n const next = left[gone ? Math.min(at, left.length - 1) : at];\n (next ? rows.get(next.key)?.remove : adds.querySelector('button'))?.focus();\n });\n });\n tools.append(remove);\n tr.append(tools);\n return { element: tr, kind, cells, remove, grip };\n }\n\n return {\n element,\n focus: () => (body.querySelector<HTMLElement>('input, select, textarea') ?? adds.querySelector('button'))?.focus(),\n update(state) {\n readonly = state.readonly;\n const current = (state.value as Line[] | null) ?? [];\n adds.hidden = readonly || current.length >= max;\n if (readonly) confirm.element.hidden = true;\n if (empty) empty.hidden = current.length > 0;\n const errors = form.getState().errors;\n const keep = new Set(current.map((line) => line.key));\n for (const [key, row] of rows) {\n if (!keep.has(key)) {\n row.element.remove();\n rows.delete(key);\n }\n }\n current.forEach((line, index) => {\n let row = rows.get(line.key);\n // A line that changed kind is drawn afresh.\n if (row && row.kind !== lineKind(def, line.values)) {\n row.element.remove();\n row = undefined;\n }\n if (!row) {\n row = makeRow(line);\n rows.set(line.key, row);\n }\n if (body.children[index] !== row.element) body.insertBefore(row.element, body.children[index] ?? null);\n row.remove.hidden = readonly || current.length <= min;\n row.grip.hidden = readonly;\n if (readonly) row.remove.remove();\n else if (!row.remove.isConnected) row.element.lastElementChild?.append(row.remove);\n for (const cell of row.cells) {\n const message = errors[`${name}.${line.key}.${cell.name}`];\n cell.error.hidden = !message;\n cell.error.textContent = message ?? '';\n cell.widget.update({\n value: line.values[cell.name],\n values: line.values,\n // A value worked out from the line's others is shown, never typed.\n readonly: readonly || cell.def.readonly === true || cell.def.compute !== undefined,\n required: cell.def.required === true,\n invalid: !!message,\n });\n }\n });\n for (const [column, td] of sums) {\n const sum = current.filter((line) => !lineKind(def, line.values)).reduce((total, line) => total + Number(line.values[column] ?? 0), 0);\n td.textContent = displayValue(def.fields[column], sum, current[0]?.values ?? {}, locale);\n }\n if (focusNew && rows.has(focusNew)) {\n rows.get(focusNew)?.cells[0]?.widget.focus();\n focusNew = null;\n }\n },\n };\n};\n", "/** What Tab can reach in a box. */\nconst FOCUSABLE = 'a[href], button, input:not([type=\"hidden\"]), select, textarea, [tabindex]:not([tabindex=\"-1\"]), [contenteditable=\"true\"]';\n\n/**\n * Keep Tab inside a modal dialog (WCAG 2.4.3, and what aria-modal promises):\n * past its last stop Tab goes round to the first, and Shift+Tab before the\n * first goes to the last. Call it from the dialog's keydown; it does nothing\n * for any other key.\n */\nexport function keepTabIn(box: HTMLElement, event: KeyboardEvent): void {\n if (event.key !== 'Tab') return;\n const all = [...box.querySelectorAll<HTMLElement>(FOCUSABLE)].filter((e) => !e.closest('[hidden], [inert]') && !(e as HTMLButtonElement).disabled);\n if (!all.length) return;\n const first = all[0];\n const last = all[all.length - 1];\n const at = box.ownerDocument.activeElement;\n if (event.shiftKey ? at === first || !box.contains(at) : at === last) {\n event.preventDefault();\n (event.shiftKey ? last : first).focus();\n }\n}\n", "import { describeTypes, fileProblem, fill, formatBytes, MESSAGES, type Field, type FileValue } from '@fieldia/core';\nimport { keepTabIn } from './focus-trap';\nimport { askFirst, describeState, maker, rightToLeft, setHidden, setText, wordsFor, type Make } from './kind-parts';\nimport type { WidgetFactory } from './widgets';\n\n/**\n * File and image fields. A chosen or dropped file is read into the value as\n * base64, the way a backend's binary fields carry it; a stored one may carry\n * a `url` instead. With `multiple` the value is a list: the picker and the\n * drop zone take many, each joining the list up to `maxFiles`, and a file of\n * a kind the field does not take, too large, already there, or past the most\n * is not added \u2014 the widget says which and why. The limits are said before\n * anyone tries. Files show as a list or as thumbnails (`options.files`); one\n * opens in a dialog that goes through them all. `options.camera` has a phone\n * offer its camera, the rear one, or the front with \"user\".\n */\n\ntype FileField = Extract<Field, { type: 'binary' | 'image' }>;\n\nexport const readFile = (file: File) =>\n new Promise<FileValue>((resolve, reject) => {\n const reader = new FileReader();\n reader.onload = () => {\n const url = String(reader.result ?? '');\n resolve({ name: file.name, type: file.type, size: file.size, data: url.slice(url.indexOf(',') + 1) });\n };\n reader.onerror = () => reject(reader.error);\n reader.readAsDataURL(file);\n });\n\nconst extension = (name: string) => (/\\.(\\w{1,5})$/.exec(name)?.[1] ?? '').toUpperCase();\n/** What a file is, for its icon and its preview: by its media type, else its extension. */\nfunction kindOf(file: FileValue): string {\n const of = `${file.type} ${extension(file.name)}`.toLowerCase();\n return /^image\\//.test(of) ? 'image' : /pdf/.test(of) ? 'pdf' : /sheet|excel|csv|xlsx?$|ods$/.test(of) ? 'sheet' : /zip|rar|7z|tar|gz/.test(of) ? 'zip' : /word|opendocument|^text|docx?$|odt$|rtf$/.test(of) ? 'doc' : 'file';\n}\nconst asText = (file: FileValue) => /^text\\/|json|xml|csv/.test(file.type);\n/** Where a file's picture is: its data, or where it is stored. */\nconst source = (file: FileValue) => (file.data ? `data:${file.type};base64,${file.data}` : (file.url ?? ''));\nconst bytes = (data: string) => Uint8Array.from(atob(data), (c) => c.charCodeAt(0));\nconst icon = (make: Make, file: FileValue) => make('span', { class: 'fd-file-icon', 'data-kind': kindOf(file), 'aria-hidden': 'true' }, extension(file.name) || '?');\n/** A name cut in the middle where it must be: its start may end in an ellipsis, its last characters \u2014 the extension \u2014 stay. */\nconst named = (make: Make, name: string) => make('span', { class: 'fd-file-name', dir: 'auto', title: name }, make('span', {}, name.slice(0, -9)), name.slice(-9));\n\nfunction fileWidget(kind: 'binary' | 'image'): WidgetFactory {\n return ({ form, name, field: def, node, id, document: doc, labels, locale = 'en' }) => {\n const field = def as FileField;\n const words = wordsFor(labels, locale);\n const messages = MESSAGES[locale] ?? MESSAGES.en;\n const make = maker(doc);\n const several = field.multiple === true;\n const most = several ? (field.maxFiles ?? Infinity) : 1;\n const image = kind === 'image';\n const thumbs = (node.options?.['files'] ?? (image ? 'thumbnails' : 'list')) === 'thumbnails';\n const camera = node.options?.['camera'];\n const accept = field.type === 'binary' ? field.accept : ['image/*'];\n const element = make('div', { class: `fd-file fd-file-${kind} fd-files-${thumbs ? 'thumbs' : 'list'}` });\n const input = make('input', { type: 'file', id, class: 'fd-sr-only', accept: accept?.join(','), capture: camera ? (camera === 'user' ? 'user' : 'environment') : undefined });\n input.multiple = several;\n\n // The limits, said before anyone tries.\n const limits = [\n !image && accept ? describeTypes(accept, messages.or) : '',\n field.maxSize ? fill(several ? words.upToEach : words.upToSize, { size: formatBytes(field.maxSize) }) : '',\n several && field.maxFiles ? fill(words.upToFiles, { max: field.maxFiles }) : '',\n ].filter(Boolean);\n // A tile among the thumbnails, a drop zone over the list.\n const pick = make(\n 'label',\n { class: `fd-file-pick${thumbs ? ' fd-image-pick' : ''}`, for: id },\n make('span', { class: 'fd-button' }, several ? (image ? words.addPhotos : words.addFiles) : image ? words.uploadImage : words.upload),\n make('span', { class: 'fd-help' }, several ? words.dropThem : words.dropHere)\n );\n const limited = make('span', { class: 'fd-help fd-file-limits' }, limits.join(' \u00B7 '));\n const count = several ? make('span', { class: 'fd-help fd-file-count' }) : null;\n const list = make('ul', { class: 'fd-files', role: 'list' });\n const replace = make('button', { type: 'button', class: 'fd-button fd-button-link' }, words.replace);\n replace.addEventListener('click', () => input.click());\n // Removing asks first, in place: \"Remove report.pdf? Remove \u00B7 Keep\".\n const confirm = askFirst(make, words);\n // Why files were not added, and one removed: said politely, and shown.\n const note = make('div', { class: 'fd-help fd-file-note', role: 'status' });\n element.append(input, pick, ...(limits.length ? [limited] : []), ...(count ? [count] : []), list, replace, confirm.element, note);\n\n let readonly = false;\n let files: FileValue[] = [];\n let shown: unknown;\n const say = (lines: string[]) => note.replaceChildren(...lines.map((line) => make('div', {}, line)));\n\n const take = async (chosen: File[]) => {\n if (readonly || !chosen.length) return;\n const kept: File[] = [];\n const lines: string[] = [];\n let over = 0;\n for (const file of chosen) {\n const problem = fileProblem(field, file, messages) ?? (several && [...files, ...kept].some((f) => f.name === file.name) ? fill(words.alreadyAdded, { name: file.name }) : undefined);\n if (problem) lines.push(problem);\n else if ((several ? files.length : 0) + kept.length < most) kept.push(file);\n else over++;\n }\n if (over && several) lines.push(fill(words.tooMany, { max: most, n: over }));\n say(lines);\n if (!kept.length) return;\n const added = await Promise.all(kept.map(readFile));\n form.setValue(name, several ? [...files, ...added] : added[0]);\n };\n input.addEventListener('change', () => {\n void take([...(input.files ?? [])]);\n input.value = '';\n });\n element.addEventListener('dragover', (event) => {\n if (readonly) return;\n event.preventDefault();\n element.classList.add('fd-dragging');\n });\n element.addEventListener('dragleave', () => element.classList.remove('fd-dragging'));\n element.addEventListener('drop', (event) => {\n event.preventDefault();\n element.classList.remove('fd-dragging');\n void take([...((event as DragEvent).dataTransfer?.files ?? [])]);\n });\n\n list.addEventListener('click', (event) => {\n const button = (event.target as Element).closest('button');\n const at = Number(button?.dataset['at']);\n if (!button) return;\n if (button.classList.contains('fd-file-open')) return view(at, button);\n confirm.ask(fill(words.removeAsk, { name: files[at].name }), (remove) => {\n const gone = files[at];\n if (remove) {\n form.setValue(name, several ? files.filter((_, i) => i !== at) : null);\n say([fill(words.removed, { name: gone.name })]);\n }\n (list.querySelectorAll<HTMLElement>('.fd-file-remove')[remove ? Math.min(at, files.length - 1) : at] ?? (pick.hidden ? replace : input)).focus();\n });\n });\n\n /** A file open in a dialog, the arrows and Previous and Next going through them all. */\n function view(at: number, opener: HTMLElement) {\n const all = files;\n let url = '';\n const title = make('h2', { id: `${id}-view`, class: 'fd-form-dialog-title' });\n const meta = make('span', { class: 'fd-help' });\n const step = (by: number, words: string, arrow: string) => {\n const button = make('button', { type: 'button', class: 'fd-button fd-file-step', 'aria-label': words }, arrow);\n button.hidden = all.length < 2;\n button.addEventListener('click', () => show(at + by));\n return button;\n };\n const download = make('a', { class: 'fd-button' }, words.download);\n const close = make('button', { type: 'button', class: 'fd-dialog-close', 'aria-label': words.close }, '\u00D7');\n const body = make('div', { class: 'fd-file-viewer-body' });\n const box = make(\n 'div',\n // A page's dialog, as the viewer's are.\n { class: 'fd-form-dialog fd-file-viewer', role: 'dialog', 'aria-modal': 'true', 'aria-labelledby': title.id, tabindex: '-1' },\n make('div', { class: 'fd-form-dialog-head' }, title, meta, step(-1, words.previous, '\u2039'), step(1, words.next, '\u203A'), download, close),\n body\n );\n const backdrop = make('div', { class: 'fd-dialog-backdrop' }, box);\n const free = () => url.startsWith('blob:') && URL.revokeObjectURL(url);\n const none = (file: FileValue) => make('div', { class: 'fd-file-none' }, icon(make, file), make('strong', {}, file.name), formatBytes(file.size), make('p', {}, words.noPreview));\n function show(to: number) {\n at = (to + all.length) % all.length;\n const file = all[at];\n free();\n const data = file.data ? bytes(file.data) : null;\n url = data ? URL.createObjectURL(new Blob([data], { type: file.type })) : (file.url ?? '');\n title.textContent = file.name;\n meta.replaceChildren(make('span', { class: 'fd-file-size' }, formatBytes(file.size)), all.length > 1 ? ` \u00B7 ${fill(words.fileAt, { n: at + 1, total: all.length })}` : '');\n download.href = url;\n download.download = file.name;\n const kind = kindOf(file);\n if (kind === 'image') return body.replaceChildren(make('img', { src: url, alt: file.name }));\n if (kind === 'pdf') return body.replaceChildren(make('iframe', { src: url, title: file.name }));\n if (!asText(file)) return body.replaceChildren(none(file));\n const pre = make('pre', { tabindex: '0' });\n body.replaceChildren(pre);\n // The first 200 KB: enough to see what it is.\n (data ? Promise.resolve(new TextDecoder().decode(data.subarray(0, 2e5))) : fetch(url).then((r) => r.text())).then(\n (words) => (pre.textContent = words.slice(0, 2e5)),\n () => pre.replaceWith(none(file))\n );\n }\n const done = () => {\n free();\n backdrop.remove();\n (opener.isConnected ? opener : list.querySelectorAll<HTMLElement>('.fd-file-open')[at])?.focus();\n };\n close.addEventListener('click', done);\n backdrop.addEventListener('click', (event) => event.target === backdrop && done());\n box.addEventListener('keydown', (event) => {\n const by = ({ ArrowLeft: -1, ArrowRight: 1 } as Record<string, number>)[event.key];\n if (event.key === 'Escape') done();\n else if (by && all.length > 1 && (event.target as Element).tagName !== 'PRE') show(at + (rightToLeft(element) ? -by : by));\n else keepTabIn(box, event);\n });\n show(at);\n // Over the page, wearing the form's skin, scheme and direction.\n (element.closest('.fd-form') ?? doc.body).append(backdrop);\n box.focus();\n }\n\n return {\n element,\n focus: () => (list.querySelector('button') ?? (pick.hidden ? replace : input)).focus(),\n update(state) {\n readonly = state.readonly;\n const value = state.value as FileValue | FileValue[] | null | undefined;\n files = Array.isArray(value) ? value : value ? [value] : [];\n const full = files.length >= most;\n setHidden(pick, full || readonly);\n setHidden(limited, readonly);\n input.disabled = readonly;\n input.hidden = pick.hidden;\n setHidden(replace, several || !files.length || readonly);\n if (count) setText(count, !files.length ? '' : several && field.maxFiles ? fill(words.fileCountOf, { n: files.length, max: field.maxFiles }) : files.length === 1 ? words.oneFile : fill(words.fileCount, { n: files.length }));\n describeState(input, state);\n if (shown === value && list.dataset['readonly'] === String(readonly)) return;\n shown = value;\n list.dataset['readonly'] = String(readonly);\n list.replaceChildren(\n ...files.map((file, at) =>\n make(\n 'li',\n { class: 'fd-file-item' },\n make(\n 'button',\n // Named whole: the name's two parts would be read as two words.\n { type: 'button', class: 'fd-file-open', 'data-at': String(at), 'aria-haspopup': 'dialog', 'aria-label': `${file.name}, ${formatBytes(file.size)}` },\n kindOf(file) === 'image' && source(file) ? make('img', { class: 'fd-file-thumb', src: source(file), alt: '' }) : icon(make, file),\n named(make, file.name),\n make('span', { class: 'fd-file-size' }, formatBytes(file.size))\n ),\n ...(readonly ? [] : [make('button', { type: 'button', class: 'fd-file-remove', 'data-at': String(at), 'aria-label': fill(words.remove, { name: file.name }) }, '\u00D7')])\n )\n )\n );\n },\n };\n };\n}\n\nexport const binaryWidget = fileWidget('binary');\nexport const imageWidget = fileWidget('image');\n", "import type { Locale } from '@fieldia/core';\nimport { createWidget, type Widget, type WidgetFactory } from './widgets';\n\n/**\n * A number shown as a bar that fills towards a maximum, coloured by how far\n * it has come: red under 30 %, yellow under 70 %, green from there. Options:\n *\n * max the maximum: the field's own, else 100 (min: the field's own, else 0)\n * maxField a number field that holds the maximum instead\n * color \"auto\", or always \"success\", \"warning\", \"danger\" or \"info\"\n * showPercent false to leave the percentage off the bar\n * editable true for a box beside the bar to type the value in\n */\n\nconst percents = new Map<Locale, Intl.NumberFormat>();\nfunction percent(value: number, locale: Locale) {\n let format = percents.get(locale);\n if (!format) {\n format = new Intl.NumberFormat(locale, { style: 'percent', maximumFractionDigits: 0, numberingSystem: 'latn' });\n percents.set(locale, format);\n }\n return format.format(value / 100);\n}\n\nexport const progressbarWidget: WidgetFactory = (context) => {\n const { field, node, id, document, locale = 'en' } = context;\n const options = node.options ?? {};\n const range = (key: 'min' | 'max', usual: number) => {\n const set = options[key] ?? (field as Record<string, unknown>)[key];\n return typeof set === 'number' ? set : usual;\n };\n const min = range('min', 0);\n const fixedMax = range('max', 100);\n const maxField = typeof options['maxField'] === 'string' ? options['maxField'] : null;\n const color = typeof options['color'] === 'string' ? options['color'] : 'auto';\n const showPercent = options['showPercent'] !== false;\n\n const bar = document.createElement('div');\n bar.className = 'fd-progressbar';\n bar.setAttribute('role', 'progressbar');\n const fill = document.createElement('div');\n fill.className = 'fd-progressbar-fill';\n const text = document.createElement('span');\n text.className = 'fd-progressbar-text';\n bar.append(fill, text);\n\n // Editable: the field's own number box takes the value; the bar beside it only shows it.\n let box: Widget | null = null;\n let element: HTMLElement = bar;\n if (options['editable'] === true) {\n box = createWidget({ ...context, node: { ...node, widget: undefined } });\n bar.setAttribute('aria-hidden', 'true');\n element = document.createElement('div');\n element.className = 'fd-progressbar-edit';\n element.append(bar, box.element);\n } else {\n bar.id = id;\n }\n\n return {\n element,\n focus: () => box?.focus(),\n update(state) {\n const value = typeof state.value === 'number' ? state.value : 0;\n const max = maxField ? Number(state.values[maxField] ?? 0) : fixedMax;\n const share = max > min ? Math.min(100, Math.max(0, ((value - min) / (max - min)) * 100)) : 0;\n const rounded = Math.round(share * 10) / 10;\n fill.style.width = `${rounded}%`;\n bar.setAttribute('aria-valuenow', String(value));\n bar.setAttribute('aria-valuemin', String(min));\n bar.setAttribute('aria-valuemax', String(max));\n bar.setAttribute('aria-valuetext', percent(share, locale));\n text.textContent = showPercent ? percent(share, locale) : '';\n bar.dataset['tone'] = color !== 'auto' ? color : share < 30 ? 'danger' : share < 70 ? 'warning' : 'success';\n box?.update(state);\n },\n };\n};\n", "import type { Locale, RelatedRecord, Value } from '@fieldia/core';\nimport { formatNumber } from './numbers';\nimport { summary, type WidgetFactory } from './widgets';\n\n/**\n * A value shown as text between a prefix and a suffix: \"24 months\",\n * \"240.0 m\". Never edited. Options:\n *\n * prefix, suffix words around the value\n * prefixField, suffixField a field whose value is the prefix or suffix instead\n */\n\n/** Another field's value as words: a link's label, or the value itself. */\nfunction words(value: Value | undefined): string {\n if (value === null || value === undefined) return '';\n if (typeof value === 'object' && 'label' in (value as object)) return (value as RelatedRecord).label;\n return String(value);\n}\n\nexport const labelWidget: WidgetFactory = ({ field, node, id, document, locale = 'en' as Locale }) => {\n const options = node.options ?? {};\n const text = (key: 'prefix' | 'suffix') => (typeof options[key] === 'string' ? (options[key] as string) : '');\n const from = (key: 'prefixField' | 'suffixField') => (typeof options[key] === 'string' ? (options[key] as string) : null);\n const decimals =\n field.type === 'integer' ? 0 : field.type === 'float' || field.type === 'monetary' ? (field.digits?.[1] ?? 2) : null;\n\n const output = document.createElement('output');\n output.id = id;\n output.className = 'fd-value-text';\n return {\n element: output,\n focus: () => undefined,\n update({ value, values }) {\n if (value === null || value === undefined || value === '') {\n output.textContent = '';\n return;\n }\n const shown = decimals !== null && typeof value === 'number' ? formatNumber(value, decimals, locale) : summary(value, field);\n const prefixField = from('prefixField');\n const suffixField = from('suffixField');\n const prefix = prefixField ? words(values[prefixField]) : text('prefix');\n const suffix = suffixField ? words(values[suffixField]) : text('suffix');\n output.textContent = [prefix, shown, suffix].filter((part) => part !== '').join(' ');\n },\n };\n};\n", "import type { RelatedRecord } from '@fieldia/core';\nimport type { WidgetFactory } from './widgets';\n\n/**\n * Where a record stands, as a row of steps with the current one marked: a\n * selection's states, or the records a link may point to (stages). Used in a\n * sheet's header, and anywhere in a form with `\"widget\": \"statusbar\"`. Options:\n *\n * clickable true to let a click move the record to another step\n * visibleStates the values to show; the current one always shows\n */\n\ninterface Step {\n key: string;\n label: string;\n value: unknown;\n}\n\nexport const statusbarWidget: WidgetFactory = ({ form, name, field, node, id, document }) => {\n const options = node.options ?? {};\n const clickable = options['clickable'] === true;\n const visible = Array.isArray(options['visibleStates']) ? options['visibleStates'] : null;\n const list = document.createElement('ol');\n list.className = 'fd-statusbar';\n list.id = id;\n list.setAttribute('aria-label', field.label);\n\n const keyOf = (value: unknown) =>\n value && typeof value === 'object' && 'id' in value ? `id:${String((value as RelatedRecord).id)}` : `v:${String(value)}`;\n // A selection knows its steps; a link's are looked up once.\n let steps: Step[] =\n field.type === 'selection' ? field.options.map((o) => ({ key: keyOf(o.value), label: o.label, value: o.value })) : [];\n let lookedUp = field.type === 'selection';\n let last: { value: unknown; readonly: boolean } = { value: undefined, readonly: false };\n\n function draw() {\n const { value, readonly } = last;\n const currentKey = value === null || value === undefined ? null : keyOf(value);\n let shown = steps.filter((s) => !visible || visible.some((v) => keyOf(v) === s.key) || s.key === currentKey);\n if (currentKey && !shown.some((s) => s.key === currentKey) && value && typeof value === 'object') {\n shown = [...shown, { key: currentKey, label: (value as RelatedRecord).label, value }];\n }\n list.replaceChildren(\n ...shown.map((step) => {\n const label = document.createElement('span');\n label.textContent = step.label;\n const inner = document.createElement(clickable ? 'button' : 'span');\n if (inner instanceof HTMLButtonElement) {\n inner.type = 'button';\n inner.disabled = readonly;\n inner.addEventListener('click', () => form.setValue(name, step.value as never));\n }\n inner.append(label);\n if (step.key === currentKey) inner.setAttribute('aria-current', 'step');\n const item = document.createElement('li');\n item.append(inner);\n return item;\n })\n );\n }\n\n return {\n element: list,\n focus: () => list.querySelector<HTMLElement>('button:not([disabled])')?.focus(),\n update(state) {\n last = { value: state.value, readonly: state.readonly };\n draw();\n if (!lookedUp) {\n lookedUp = true;\n void form\n .search(name, '', 20)\n .then((records) => {\n steps = records.map((r) => ({ key: keyOf(r), label: r.label, value: r }));\n draw();\n })\n .catch(() => undefined);\n }\n },\n };\n};\n", "import type { Locale, Value } from '@fieldia/core';\nimport { WIDGET_LABELS, type WidgetLabels } from './labels';\nimport type { Widget, WidgetContext } from './widgets';\n\n/**\n * A calendar beside a date, for when the person needs the week numbers\n * (`options.weekNumbers` on a date or date-and-time node). The ARIA\n * date-picker dialog: a grid of days, Monday first, an ISO 8601 week number at\n * the start of each row, arrow keys by day and week, PageUp and PageDown by\n * month, Enter to pick, Escape to close.\n */\n\n/** The ISO 8601 week a day falls in: weeks start on Monday, week 1 holds the year's first Thursday. */\nexport function isoWeek(day: Date): number {\n const t = new Date(Date.UTC(day.getFullYear(), day.getMonth(), day.getDate()));\n t.setUTCDate(t.getUTCDate() + 4 - (t.getUTCDay() || 7));\n const yearStart = Date.UTC(t.getUTCFullYear(), 0, 1);\n return Math.ceil(((t.getTime() - yearStart) / 86400000 + 1) / 7);\n}\n\nconst pad = (n: number) => String(n).padStart(2, '0');\nconst sameDay = (a: Date, b: Date) => a.getFullYear() === b.getFullYear() && a.getMonth() === b.getMonth() && a.getDate() === b.getDate();\nconst addDays = (d: Date, n: number) => new Date(d.getFullYear(), d.getMonth(), d.getDate() + n);\n/** The same day of another month, or that month's last day when it is shorter. */\nfunction addMonths(d: Date, n: number) {\n const last = new Date(d.getFullYear(), d.getMonth() + n + 1, 0).getDate();\n return new Date(d.getFullYear(), d.getMonth() + n, Math.min(d.getDate(), last));\n}\n\n/** The day a date field holds (\"2026-10-11\"), or a date and time (an ISO instant), in local time. */\nfunction dayOf(kind: 'date' | 'datetime', value: Value | undefined): Date | null {\n if (typeof value !== 'string' || !value) return null;\n if (kind === 'date') {\n const m = /^(\\d{4})-(\\d{2})-(\\d{2})/.exec(value);\n return m ? new Date(Number(m[1]), Number(m[2]) - 1, Number(m[3])) : null;\n }\n const d = new Date(value);\n return Number.isNaN(d.getTime()) ? null : d;\n}\n\nexport function withCalendar(inner: Widget, context: WidgetContext, kind: 'date' | 'datetime'): Widget {\n const { form, name, id, document: doc, locale = 'en' as Locale } = context;\n const labels: WidgetLabels = context.labels ?? WIDGET_LABELS.en;\n const lang = locale === 'en' ? 'en-GB' : locale;\n const monthName = new Intl.DateTimeFormat(lang, { month: 'long', year: 'numeric', numberingSystem: 'latn' });\n const dayName = new Intl.DateTimeFormat(lang, { weekday: 'long', day: 'numeric', month: 'long', year: 'numeric', numberingSystem: 'latn' });\n const weekdayShort = new Intl.DateTimeFormat(lang, { weekday: 'short' });\n const weekdayLong = new Intl.DateTimeFormat(lang, { weekday: 'long' });\n\n const button = doc.createElement('button');\n button.type = 'button';\n button.className = 'fd-calendar-button';\n // A drawn calendar: an emoji would look different on every system.\n const svg = 'http://www.w3.org/2000/svg';\n const icon = doc.createElementNS(svg, 'svg');\n icon.setAttribute('viewBox', '0 0 16 16');\n icon.setAttribute('aria-hidden', 'true');\n for (const [tag, attrs] of [\n ['rect', { x: '2', y: '3', width: '12', height: '11', rx: '1.5' }],\n ['path', { d: 'M2 6.5h12M5 1.5v3M11 1.5v3' }],\n ] as const) {\n const shape = doc.createElementNS(svg, tag);\n for (const [k, v] of Object.entries(attrs)) shape.setAttribute(k, v);\n icon.append(shape);\n }\n button.append(icon);\n button.setAttribute('aria-label', labels.chooseDate);\n button.setAttribute('aria-haspopup', 'dialog');\n button.setAttribute('aria-expanded', 'false');\n button.setAttribute('aria-controls', `${id}-calendar`);\n\n const dialog = doc.createElement('div');\n dialog.className = 'fd-calendar';\n dialog.id = `${id}-calendar`;\n dialog.setAttribute('role', 'dialog');\n dialog.hidden = true;\n const head = doc.createElement('div');\n head.className = 'fd-calendar-head';\n const prev = doc.createElement('button');\n prev.type = 'button';\n prev.textContent = '\u2039';\n prev.setAttribute('aria-label', labels.previousMonth);\n const title = doc.createElement('span');\n title.className = 'fd-calendar-title';\n title.setAttribute('aria-live', 'polite');\n const next = doc.createElement('button');\n next.type = 'button';\n next.textContent = '\u203A';\n next.setAttribute('aria-label', labels.nextMonth);\n head.append(prev, title, next);\n const grid = doc.createElement('table');\n grid.className = 'fd-calendar-grid';\n grid.setAttribute('role', 'grid');\n dialog.append(head, grid);\n\n const element = doc.createElement('span');\n element.className = 'fd-date-pick';\n element.append(inner.element, button, dialog);\n\n let focused = new Date();\n let readonly = false;\n\n function pick(day: Date) {\n if (kind === 'date') {\n form.setValue(name, `${day.getFullYear()}-${pad(day.getMonth() + 1)}-${pad(day.getDate())}`);\n } else {\n const was = dayOf('datetime', form.getState().values[name]);\n const at = new Date(day.getFullYear(), day.getMonth(), day.getDate(), was?.getHours() ?? 0, was?.getMinutes() ?? 0);\n form.setValue(name, at.toISOString());\n }\n close();\n }\n\n function draw(focus: boolean) {\n const chosen = dayOf(kind, form.getState().values[name]);\n const today = new Date();\n const label = monthName.format(focused);\n title.textContent = label;\n dialog.setAttribute('aria-label', label);\n const first = new Date(focused.getFullYear(), focused.getMonth(), 1);\n const start = addDays(first, -((first.getDay() + 6) % 7)); // back to Monday\n const headRow = doc.createElement('tr');\n const weekHead = doc.createElement('th');\n weekHead.scope = 'col';\n weekHead.textContent = labels.weekShort;\n weekHead.setAttribute('abbr', labels.week);\n headRow.append(weekHead);\n for (let i = 0; i < 7; i++) {\n const d = addDays(start, i);\n const th = doc.createElement('th');\n th.scope = 'col';\n th.textContent = weekdayShort.format(d).replace(/\\.$/, '');\n th.setAttribute('abbr', weekdayLong.format(d));\n headRow.append(th);\n }\n const thead = doc.createElement('thead');\n thead.append(headRow);\n const tbody = doc.createElement('tbody');\n for (let row = start; row <= new Date(focused.getFullYear(), focused.getMonth() + 1, 0); row = addDays(row, 7)) {\n const tr = doc.createElement('tr');\n const week = doc.createElement('th');\n week.scope = 'row';\n week.className = 'fd-week';\n week.textContent = String(isoWeek(row));\n tr.append(week);\n for (let i = 0; i < 7; i++) {\n const d = addDays(row, i);\n const cell = doc.createElement('td');\n const day = doc.createElement('button');\n day.type = 'button';\n day.textContent = String(d.getDate());\n day.setAttribute('aria-label', dayName.format(d));\n day.tabIndex = sameDay(d, focused) ? 0 : -1;\n if (d.getMonth() !== focused.getMonth()) day.classList.add('fd-outside');\n if (chosen && sameDay(d, chosen)) day.setAttribute('aria-selected', 'true');\n if (sameDay(d, today)) day.setAttribute('aria-current', 'date');\n day.disabled = readonly;\n day.addEventListener('click', () => pick(d));\n day.addEventListener('keydown', (event) => onKey(event, d));\n cell.append(day);\n tr.append(cell);\n }\n tbody.append(tr);\n }\n grid.replaceChildren(thead, tbody);\n if (focus) grid.querySelector<HTMLButtonElement>('button[tabindex=\"0\"]')?.focus();\n }\n\n function move(to: Date) {\n focused = to;\n draw(true);\n }\n\n function onKey(event: KeyboardEvent, day: Date) {\n const moves: Record<string, () => Date> = {\n ArrowLeft: () => addDays(day, -1),\n ArrowRight: () => addDays(day, 1),\n ArrowUp: () => addDays(day, -7),\n ArrowDown: () => addDays(day, 7),\n PageUp: () => addMonths(day, -1),\n PageDown: () => addMonths(day, 1),\n Home: () => addDays(day, -((day.getDay() + 6) % 7)),\n End: () => addDays(day, 6 - ((day.getDay() + 6) % 7)),\n };\n if (moves[event.key]) {\n event.preventDefault();\n move(moves[event.key]());\n } else if (event.key === 'Enter' || event.key === ' ') {\n event.preventDefault();\n pick(day);\n }\n }\n\n function open() {\n focused = dayOf(kind, form.getState().values[name]) ?? new Date();\n dialog.hidden = false;\n button.setAttribute('aria-expanded', 'true');\n draw(true);\n }\n\n function close() {\n if (dialog.hidden) return;\n dialog.hidden = true;\n button.setAttribute('aria-expanded', 'false');\n button.focus();\n }\n\n button.addEventListener('click', () => (dialog.hidden ? open() : close()));\n prev.addEventListener('click', () => {\n focused = addMonths(focused, -1);\n draw(false);\n });\n next.addEventListener('click', () => {\n focused = addMonths(focused, 1);\n draw(false);\n });\n dialog.addEventListener('keydown', (event) => {\n if (event.key === 'Escape') {\n event.preventDefault();\n event.stopPropagation();\n close();\n }\n });\n const outside = (event: Event) => {\n if (!dialog.hidden && !element.contains(event.target as Node)) {\n dialog.hidden = true;\n button.setAttribute('aria-expanded', 'false');\n }\n };\n doc.addEventListener('mousedown', outside);\n\n return {\n element,\n focus: () => inner.focus(),\n update(state) {\n readonly = state.readonly;\n button.hidden = state.readonly;\n if (state.readonly) dialog.hidden = true;\n inner.update(state);\n },\n destroy() {\n doc.removeEventListener('mousedown', outside);\n inner.destroy?.();\n },\n };\n}\n", "import type { Field, FieldNode, Form, FormState, JsonValue, PropertyDefinition, Value } from '@fieldia/core';\nimport { createWidget, type Widget, type WidgetFactory } from './widgets';\n\n/**\n * A properties field, one row per property, each edited with the widget for\n * its type: text, numbers, yes/no, a choice, a date. The field's `definitions`\n * say which properties there are; without them, each property is worked out\n * from its value. The properties stay one value: an object by property name.\n */\n\n/** \"lift_access\" \u2192 \"Lift access\". */\nconst humanize = (name: string) => {\n const words = name.replace(/_/g, ' ').trim();\n return words.charAt(0).toUpperCase() + words.slice(1);\n};\n\n/** A property's type, from what it holds. */\nfunction guess(name: string, value: Value | undefined): PropertyDefinition {\n const label = humanize(name);\n if (typeof value === 'boolean') return { name, label, type: 'boolean' };\n if (typeof value === 'number') return { name, label, type: Number.isInteger(value) ? 'integer' : 'float' };\n if (typeof value === 'string' && /^\\d{4}-\\d{2}-\\d{2}$/.test(value)) return { name, label, type: 'date' };\n return { name, label, type: 'char' };\n}\n\nexport const propertiesWidget: WidgetFactory = (context) => {\n const { form, name, field, node, id, document } = context;\n const declared = field.type === 'properties' ? field.definitions : undefined;\n const current = () => {\n const value = form.getState().values[name];\n return value && typeof value === 'object' && !Array.isArray(value) ? (value as Record<string, Value>) : {};\n };\n // Each property's widget sees the properties as its record, and writes into them.\n const properties: Form = {\n ...form,\n getState: (): FormState => ({ ...form.getState(), values: current() }),\n // Property values are plain JSON: text, numbers, yes/no, a choice, a date.\n setValue: (property: string, value: Value) => form.setValue(name, { ...current(), [property]: value } as JsonValue),\n };\n\n const element = document.createElement('div');\n element.className = 'fd-properties';\n element.setAttribute('role', 'group');\n let rows: { definition: PropertyDefinition; widget: Widget }[] = [];\n let drawn = '';\n\n function draw(definitions: PropertyDefinition[]) {\n for (const row of rows) row.widget.destroy?.();\n rows = definitions.map((definition) => {\n const rowId = `${id}-${definition.name}`;\n const propertyField = { type: definition.type, label: definition.label, ...(definition.options ? { options: definition.options } : {}) } as Field;\n const propertyNode: FieldNode = { type: 'field', id: `${node.id}.${definition.name}`, field: definition.name };\n const widget = createWidget({ ...context, form: properties, name: definition.name, field: propertyField, node: propertyNode, id: rowId });\n return { definition, widget };\n });\n element.replaceChildren(\n ...rows.map(({ definition, widget }) => {\n const row = document.createElement('div');\n row.className = 'fd-property';\n row.dataset['type'] = definition.type;\n const label = document.createElement('label');\n label.htmlFor = `${id}-${definition.name}`;\n label.textContent = definition.label;\n row.append(label, widget.element);\n return row;\n })\n );\n }\n\n return {\n element,\n focus: () => rows[0]?.widget.focus(),\n destroy: () => rows.forEach((row) => row.widget.destroy?.()),\n update(state) {\n const values = current();\n const definitions = declared ?? Object.keys(values).map((key) => guess(key, values[key]));\n const key = JSON.stringify(definitions);\n if (key !== drawn) {\n drawn = key;\n draw(definitions);\n }\n for (const { definition, widget } of rows) {\n widget.update({ value: values[definition.name] ?? null, values, readonly: state.readonly, required: false, invalid: false });\n }\n },\n };\n};\n", "import { WIDGET_LABELS, type WidgetLabels } from './labels';\nimport type { WidgetFactory } from './widgets';\n\n/**\n * Formatted text and JSON. Formatted text is edited in place, with a toolbar\n * (bold, italic, underline, headings, lists, alignment, links) that drives the\n * browser's own editing, so no editor library is loaded. Every value \u2014 typed,\n * pasted or loaded \u2014 passes through `sanitizeHtml`, so stored markup can never\n * run script in the page.\n */\n\nconst ALLOWED = new Set([\n 'P', 'BR', 'B', 'STRONG', 'I', 'EM', 'U', 'S', 'UL', 'OL', 'LI', 'A', 'H1', 'H2', 'H3', 'H4',\n 'BLOCKQUOTE', 'CODE', 'PRE', 'SPAN', 'DIV',\n]);\nconst DROPPED_WITH_CONTENT = new Set(['SCRIPT', 'STYLE', 'IFRAME', 'OBJECT', 'EMBED', 'TEMPLATE', 'NOSCRIPT', 'SVG', 'MATH']);\n/** Blocks that may keep their alignment, the one style the toolbar sets. */\nconst ALIGNABLE = new Set(['P', 'DIV', 'H1', 'H2', 'H3', 'H4', 'LI', 'BLOCKQUOTE', 'PRE']);\nconst ALIGNMENTS = new Set(['left', 'center', 'right', 'justify', 'start', 'end']);\n\n/** Keep text structure, block alignment and http(s)/mailto links; drop every other element and attribute. */\nexport function sanitizeHtml(html: string, document: Document = globalThis.document): string {\n const box = document.createElement('template');\n box.innerHTML = html;\n const clean = (parent: ParentNode) => {\n for (const node of [...parent.childNodes]) {\n if (node.nodeType === Node.TEXT_NODE) continue;\n if (node.nodeType !== Node.ELEMENT_NODE) {\n node.remove();\n continue;\n }\n const element = node as Element;\n if (DROPPED_WITH_CONTENT.has(element.tagName)) {\n element.remove();\n continue;\n }\n clean(element);\n if (!ALLOWED.has(element.tagName)) {\n element.replaceWith(...element.childNodes);\n continue;\n }\n const href = element.tagName === 'A' ? element.getAttribute('href') : null;\n const align = ALIGNABLE.has(element.tagName) ? (element as HTMLElement).style?.textAlign?.trim().toLowerCase() : '';\n for (const attribute of [...element.attributes]) element.removeAttribute(attribute.name);\n if (href && /^(https?:|mailto:)/i.test(href.trim())) element.setAttribute('href', href.trim());\n if (align && ALIGNMENTS.has(align)) element.setAttribute('style', `text-align: ${align};`);\n }\n };\n clean(box.content);\n const out = document.createElement('div');\n out.append(box.content);\n return out.innerHTML;\n}\n\n/** A typed address as a link target: web and mail addresses only, \"https://\" added to a bare domain. */\nexport function linkAddress(typed: string): string | null {\n const text = typed.trim();\n if (/^(https?:\\/\\/|mailto:)\\S+$/i.test(text)) return text;\n if (/^[^\\s@:/]+@[^\\s@:/]+\\.[^\\s@:/]+$/.test(text)) return `mailto:${text}`;\n if (/^[\\w-]+(\\.[\\w-]+)+([/?#]\\S*)?$/.test(text)) return `https://${text}`;\n return null;\n}\n\n/** The toolbar's buttons: [label key, editing command, drawn icon]. */\nconst TOOLS: [keyof WidgetLabels, string, string][] = [\n ['bold', 'bold', '<b>B</b>'],\n ['italic', 'italic', '<i>I</i>'],\n ['underline', 'underline', '<u>U</u>'],\n // A heading, or back to words: the text style list's first two, in one press.\n ['heading', 'heading', '<b>H</b>'],\n ['bulletList', 'insertUnorderedList', '<svg viewBox=\"0 0 16 16\"><circle cx=\"3\" cy=\"4\" r=\"1.2\"/><circle cx=\"3\" cy=\"8\" r=\"1.2\"/><circle cx=\"3\" cy=\"12\" r=\"1.2\"/><path d=\"M6 4h8M6 8h8M6 12h8\"/></svg>'],\n ['numberList', 'insertOrderedList', '<svg viewBox=\"0 0 16 16\"><path d=\"M2.5 3h1v3M2 10.5c.5-.8 2-.8 2 .2 0 .8-2 1.3-2 2.3h2M6 4h8M6 8h8M6 12h8\"/></svg>'],\n ['alignLeft', 'justifyLeft', '<svg viewBox=\"0 0 16 16\"><path d=\"M2 3.5h12M2 6.5h8M2 9.5h12M2 12.5h8\"/></svg>'],\n ['alignCenter', 'justifyCenter', '<svg viewBox=\"0 0 16 16\"><path d=\"M2 3.5h12M4 6.5h8M2 9.5h12M4 12.5h8\"/></svg>'],\n ['alignRight', 'justifyRight', '<svg viewBox=\"0 0 16 16\"><path d=\"M2 3.5h12M6 6.5h8M2 9.5h12M6 12.5h8\"/></svg>'],\n ['link', 'createLink', '<svg viewBox=\"0 0 16 16\"><path d=\"M7 9a3 3 0 0 0 4.2 0l2.3-2.3a3 3 0 0 0-4.2-4.2L8.2 3.6M9 7a3 3 0 0 0-4.2 0L2.5 9.3a3 3 0 0 0 4.2 4.2l1.1-1.1\"/></svg>'],\n];\n\nexport const htmlWidget: WidgetFactory = ({ form, name, node, id, document, labels = WIDGET_LABELS.en }) => {\n const area = document.createElement('div');\n area.id = id;\n area.className = 'fd-input fd-richtext';\n area.setAttribute('role', 'textbox');\n area.setAttribute('aria-multiline', 'true');\n area.setAttribute('contenteditable', 'true');\n const withToolbar = node.options?.['toolbar'] !== false;\n let last = '';\n area.addEventListener('input', () => {\n const clean = sanitizeHtml(area.innerHTML, document);\n last = clean;\n form.setValue(name, clean.trim() === '' ? null : clean);\n });\n area.addEventListener('blur', () => {\n // Show what was stored: anything unsafe that was typed or pasted is gone.\n if (area.innerHTML !== last) area.innerHTML = last;\n });\n const toolbar = withToolbar ? formattingToolbar(area, document, labels) : null;\n let element: HTMLElement = area;\n if (toolbar) {\n // The box is labelled by the field's label; the text inside it says so too.\n element = document.createElement('div');\n element.className = 'fd-richtext-box';\n element.setAttribute('role', 'group');\n area.setAttribute('aria-labelledby', `${id}-label`);\n element.append(toolbar.bar, toolbar.linkRow, area);\n }\n return {\n element,\n focus: () => area.focus(),\n destroy: () => toolbar?.destroy(),\n update(state) {\n if (toolbar) {\n toolbar.bar.hidden = state.readonly;\n if (state.readonly) toolbar.linkRow.hidden = true;\n }\n const clean = sanitizeHtml(typeof state.value === 'string' ? state.value : '', document);\n if (clean !== last || document.activeElement !== area) {\n if (area.innerHTML !== clean) area.innerHTML = clean;\n last = clean;\n }\n area.setAttribute('contenteditable', String(!state.readonly));\n area.setAttribute('aria-readonly', String(state.readonly));\n area.setAttribute('aria-invalid', String(state.invalid));\n if (state.describedBy) area.setAttribute('aria-describedby', state.describedBy);\n },\n };\n};\n\n/**\n * The toolbar of a formatted text: buttons that keep the text's selection\n * (they act on mousedown's behalf), a text-style choice, and a row for a link's\n * address. One button takes Tab; the arrow keys move along the bar.\n */\nfunction formattingToolbar(area: HTMLElement, doc: Document, labels: WidgetLabels) {\n const bar = doc.createElement('div');\n bar.className = 'fd-richtext-bar';\n bar.setAttribute('role', 'toolbar');\n bar.setAttribute('aria-label', labels.formatting);\n // The last selection made in the text: the style box and the address box take\n // the focus, and a command must act where the person had selected.\n let lastRange: Range | null = null;\n const restore = () => {\n area.focus();\n const selection = doc.getSelection();\n if (lastRange && selection) {\n selection.removeAllRanges();\n selection.addRange(lastRange);\n }\n };\n const run = (command: string, value?: string) => {\n restore();\n doc.execCommand?.(command, false, value);\n };\n\n const style = doc.createElement('select');\n style.className = 'fd-richtext-style';\n style.setAttribute('aria-label', labels.textStyle);\n for (const [value, key] of [['p', 'paragraph'], ['h2', 'heading'], ['h3', 'subheading']] as const) {\n const option = doc.createElement('option');\n option.value = value;\n option.textContent = labels[key];\n style.append(option);\n }\n style.addEventListener('change', () => run('formatBlock', `<${style.value}>`));\n\n const linkRow = doc.createElement('div');\n linkRow.className = 'fd-link-row';\n linkRow.hidden = true;\n const address = doc.createElement('input');\n address.className = 'fd-input';\n address.type = 'url';\n address.placeholder = 'https://';\n address.setAttribute('aria-label', labels.linkAddress);\n const apply = doc.createElement('button');\n apply.type = 'button';\n apply.className = 'fd-button fd-link-apply';\n apply.textContent = labels.applyLink;\n const unlink = doc.createElement('button');\n unlink.type = 'button';\n unlink.className = 'fd-button fd-button-link fd-link-remove';\n unlink.textContent = labels.removeLink;\n linkRow.append(address, apply, unlink);\n apply.addEventListener('click', () => {\n const url = linkAddress(address.value);\n if (!url) {\n address.setAttribute('aria-invalid', 'true');\n return;\n }\n address.setAttribute('aria-invalid', 'false');\n restore();\n doc.execCommand?.('createLink', false, url);\n linkRow.hidden = true;\n });\n unlink.addEventListener('click', () => {\n restore();\n doc.execCommand?.('unlink', false);\n linkRow.hidden = true;\n });\n address.addEventListener('keydown', (event) => {\n if (event.key === 'Enter') {\n event.preventDefault();\n apply.click();\n } else if (event.key === 'Escape') {\n event.preventDefault();\n linkRow.hidden = true;\n restore();\n }\n });\n\n const buttons = TOOLS.map(([key, command, icon]) => {\n const button = doc.createElement('button');\n button.type = 'button';\n button.className = 'fd-richtext-tool';\n button.setAttribute('aria-label', labels[key]);\n button.title = labels[key];\n button.innerHTML = icon;\n button.querySelector('svg')?.setAttribute('aria-hidden', 'true');\n if (['bold', 'italic', 'underline', 'heading'].includes(command)) button.setAttribute('aria-pressed', 'false');\n // Keep the text's selection when the button is pressed.\n button.addEventListener('mousedown', (event) => event.preventDefault());\n button.addEventListener('click', () => {\n if (command === 'heading') return run('formatBlock', style.value === 'h2' ? '<p>' : '<h2>');\n if (command !== 'createLink') return run(command);\n linkRow.hidden = false;\n address.value = '';\n address.focus();\n });\n return button;\n });\n bar.append(style, ...buttons);\n\n // One stop on Tab; the arrow keys move along the bar.\n const stops = [style, ...buttons];\n stops.forEach((stop, i) => (stop.tabIndex = i === 0 ? 0 : -1));\n bar.addEventListener('keydown', (event) => {\n if (event.key !== 'ArrowRight' && event.key !== 'ArrowLeft') return;\n const at = stops.indexOf(doc.activeElement as HTMLButtonElement);\n if (at < 0) return;\n const rtl = getComputedStyle(bar).direction === 'rtl';\n const step = (event.key === 'ArrowRight') !== rtl ? 1 : -1;\n const next = stops[(at + step + stops.length) % stops.length];\n event.preventDefault();\n stops.forEach((stop) => (stop.tabIndex = stop === next ? 0 : -1));\n next.focus();\n });\n\n // Show which formats the selection already has.\n const reflect = () => {\n const selection = doc.getSelection();\n if (!selection || !selection.rangeCount || !area.contains(selection.anchorNode)) return;\n lastRange = selection.getRangeAt(0).cloneRange();\n const block = String(doc.queryCommandValue?.('formatBlock') ?? '').toLowerCase().replace(/[<>]/g, '');\n style.value = block === 'h2' || block === 'h3' ? block : 'p';\n for (const button of buttons) {\n const command = TOOLS[buttons.indexOf(button)][1];\n if (button.hasAttribute('aria-pressed')) button.setAttribute('aria-pressed', String(command === 'heading' ? block === 'h2' : (doc.queryCommandState?.(command) ?? false)));\n }\n };\n doc.addEventListener('selectionchange', reflect);\n return { bar, linkRow, destroy: () => doc.removeEventListener('selectionchange', reflect) };\n}\n\nexport const jsonWidget: WidgetFactory = ({ form, name, id, document, labels = WIDGET_LABELS.en }) => {\n const element = document.createElement('div');\n element.className = 'fd-json';\n const area = document.createElement('textarea');\n area.id = id;\n area.className = 'fd-input fd-textarea fd-code';\n area.spellcheck = false;\n const error = document.createElement('div');\n error.className = 'fd-cell-error';\n error.hidden = true;\n element.append(area, error);\n area.addEventListener('input', () => {\n if (area.value.trim() === '') {\n error.hidden = true;\n form.setValue(name, null);\n return;\n }\n try {\n const parsed = JSON.parse(area.value);\n error.hidden = true;\n form.setValue(name, parsed);\n } catch {\n error.hidden = false;\n error.textContent = labels.invalidJson;\n }\n });\n return {\n element,\n focus: () => area.focus(),\n update(state) {\n if (document.activeElement !== area) {\n const text = state.value === null || state.value === undefined ? '' : JSON.stringify(state.value, null, 2);\n if (area.value !== text) area.value = text;\n }\n area.readOnly = state.readonly;\n area.setAttribute('aria-invalid', String(state.invalid || !error.hidden));\n },\n };\n};\n", "import type { FieldNode } from '@fieldia/core';\n\n/**\n * Options shuffled when a question's `options.shuffle` is true, as a survey\n * shuffles them so the first is not chosen for being first. Each form draws\n * a seed of its own once, so a question keeps its order however often the\n * form draws it, and the next form has another; each question, by its name,\n * has its own order within the form. \"Other\" is not among the options, so\n * it stays after them.\n */\n\nconst seeds = new WeakMap<object, number>();\n\n/** The form's seed, drawn the first time it is asked for. */\nfunction seedOf(form: object): number {\n let seed = seeds.get(form);\n if (seed === undefined) {\n seed = Math.floor(Math.random() * 0x100000000) >>> 0;\n seeds.set(form, seed);\n }\n return seed;\n}\n\n/** A seed for one question: the form's, stirred with the question's name. */\nfunction stir(seed: number, name: string): number {\n let h = seed ^ 0x9e3779b9;\n for (let i = 0; i < name.length; i++) {\n h = Math.imul(h ^ name.charCodeAt(i), 0x85ebca6b);\n h ^= h >>> 13;\n }\n return h >>> 0;\n}\n\n/** Numbers from 0 to 1 that follow from the seed: Mulberry32. */\nfunction numbers(seed: number): () => number {\n let a = seed;\n return () => {\n a = (a + 0x6d2b79f5) | 0;\n let t = Math.imul(a ^ (a >>> 15), 1 | a);\n t = (t + Math.imul(t ^ (t >>> 7), 61 | t)) ^ t;\n return ((t ^ (t >>> 14)) >>> 0) / 0x100000000;\n };\n}\n\n/**\n * The options in the order this form shows them: as written, or shuffled when\n * the question asks \u2014 those kept in place (`fixed`) where they were written,\n * and one that goes alone (\"None of these\") last, as \"Other\" is.\n */\nexport function shownOptions<T>(options: readonly T[], form: object, name: string, node: Pick<FieldNode, 'options'>): T[] {\n if (node.options?.['shuffle'] !== true) return [...options];\n const is = (option: T, flag: string) => (option as Record<string, unknown>)[flag] === true;\n const shown = options.filter((o) => !is(o, 'fixed') && !is(o, 'exclusive'));\n const next = numbers(stir(seedOf(form), name));\n // Fisher\u2013Yates.\n for (let i = shown.length - 1; i > 0; i--) {\n const j = Math.floor(next() * (i + 1));\n [shown[i], shown[j]] = [shown[j], shown[i]];\n }\n shown.push(...options.filter((o) => !is(o, 'fixed') && is(o, 'exclusive')));\n return options.map((o) => (is(o, 'fixed') ? o : (shown.shift() as T)));\n}\n", "import type { Field, Value } from '@fieldia/core';\nimport { setAttr } from './kind-parts';\nimport { shownOptions } from './shuffle';\nimport type { WidgetFactory } from './widgets';\n\n/**\n * A matrix question: rows down the side, columns across \u2014 a Likert grid. Each\n * row is a group of radios (or of boxes when several may be chosen), named by\n * its row for screen readers, so the arrow keys move within a row. On a phone\n * each row is a card, its answers listed with their columns' words.\n * `options.shuffle` shows the rows in an order of the form's own; with\n * `onePerColumn`, a column picked in one row leaves the row that had it.\n */\nexport const matrixWidget: WidgetFactory = ({ form, name, field, node, id, document }) => {\n const def = field as Extract<Field, { type: 'matrix' }>;\n const kind = def.multiple ? 'checkbox' : 'radio';\n const make = <K extends keyof HTMLElementTagNameMap>(tag: K, attrs: Record<string, string> = {}, ...children: (Node | string)[]) => {\n const element = document.createElement(tag);\n for (const [key, value] of Object.entries(attrs)) element.setAttribute(key, value);\n element.append(...children);\n return element;\n };\n const table = make('table', { id, class: 'fd-matrix-table' });\n table.append(make('thead', {}, make('tr', {}, make('th', { scope: 'col' }), ...def.columns.map((c) => make('th', { scope: 'col' }, c.label)))));\n const body = make('tbody');\n const inputs: HTMLInputElement[] = [];\n const rows: HTMLElement[] = [];\n for (const row of shownOptions(def.rows, form, name, node)) {\n const tr = make('tr', { role: kind === 'radio' ? 'radiogroup' : 'group', 'aria-label': row.label });\n rows.push(tr);\n tr.append(make('th', { scope: 'row' }, row.label));\n for (const column of def.columns) {\n const input = make('input', { type: kind, name: `${id}-${row.value}`, value: String(column.value), 'data-row': String(row.value), 'aria-label': `${row.label}: ${column.label}` }) as HTMLInputElement;\n input.addEventListener('change', () => {\n if (def.onePerColumn && input.checked) for (const other of inputs) if (other.value === input.value && other !== input) other.checked = false;\n save();\n });\n inputs.push(input);\n // The column's words beside the box, seen on a phone's card.\n tr.append(make('td', {}, make('label', { class: 'fd-matrix-pick' }, input, make('span', { class: 'fd-matrix-column' }, column.label))));\n }\n body.append(tr);\n }\n table.append(body);\n const element = make('div', { class: 'fd-matrix' }, table);\n\n /** Column values come back as written: a number stays a number. */\n const columnValue = (text: string) => def.columns.find((c) => String(c.value) === text)?.value ?? text;\n function save() {\n const value: Record<string, Value> = {};\n for (const row of def.rows) {\n const picked = inputs.filter((i) => i.dataset['row'] === String(row.value) && i.checked).map((i) => columnValue(i.value));\n if (def.multiple ? picked.length : picked.length === 1) value[String(row.value)] = (def.multiple ? picked : picked[0]) as Value;\n }\n form.setValue(name, Object.keys(value).length ? (value as Value) : null);\n }\n\n return {\n element,\n focus: () => (inputs.find((i) => i.checked) ?? inputs[0])?.focus(),\n update(state) {\n const value = state.value && typeof state.value === 'object' && !Array.isArray(state.value) ? (state.value as Record<string, unknown>) : {};\n for (const input of inputs) {\n const answer = value[input.dataset['row'] ?? ''];\n const chosen = Array.isArray(answer) ? answer.map(String) : answer === undefined || answer === null ? [] : [String(answer)];\n input.checked = chosen.includes(input.value);\n input.disabled = state.readonly;\n }\n table.setAttribute('aria-invalid', String(state.invalid));\n // A row of radios is a radio group, which ARIA lets say it is required.\n if (kind === 'radio') for (const tr of rows) setAttr(tr, 'aria-required', String(state.required));\n // A table cannot be marked required in ARIA; the question's label says it.\n if (state.describedBy) table.setAttribute('aria-describedby', state.describedBy);\n else table.removeAttribute('aria-describedby');\n },\n };\n};\n", "import type { FileValue } from '@fieldia/core';\nimport { readFile } from './files';\nimport { describeState, maker, wordsFor } from './kind-parts';\nimport type { WidgetFactory } from './widgets';\n\n/**\n * A signature on a file field (`binary.signature`): drawn on a pad with a\n * mouse, a finger or a pen, or \u2014 for anyone without a pointer \u2014 typed as a\n * name and drawn as a signature, the name kept as the value's `text`. Kept\n * as a PNG picture, the value a file upload has. A signature already kept\n * shows as its picture until Clear. Undo takes the last stroke away.\n *\n * `options.color` (#rrggbb) and `options.penWidth` set the pen; the node's\n * `placeholder` is the words on the blank pad (\"Sign here\"); `options.footerLabel`\n * the words kept under it; `options.upload` lets a picture of a signature be\n * uploaded as a third way.\n */\n\n/** The pad's own size, in the picture's pixels; it is drawn at whatever width its box has. */\nconst WIDTH = 600;\nconst HEIGHT = 180;\n/** Blue-black ink on a clear ground, so the picture reads on any paper. */\nconst INK = '#1b2a5c';\nconst SCRIPT = '\"Segoe Script\", \"Snell Roundhand\", \"Brush Script MT\", \"Apple Chancery\", cursive';\n\n/** The bytes a base64 text holds. */\nconst bytesOf = (base64: string) => Math.floor((base64.length * 3) / 4) - (base64.endsWith('==') ? 2 : base64.endsWith('=') ? 1 : 0);\nconst keyOf = (file: FileValue) => file.data ?? file.url ?? '';\ntype Point = { x: number; y: number };\n\nexport const signatureWidget: WidgetFactory = ({ form, name, field, node, id, document, labels, locale }) => {\n const words = wordsFor(labels, locale);\n const make = maker(document);\n const options = node.options ?? {};\n const color = options['color'];\n const ink = typeof color === 'string' && /^#[\\da-f]{6}$/i.test(color) ? color : INK;\n const penWidth = options['penWidth'];\n const width = typeof penWidth === 'number' && penWidth > 0 ? penWidth : 3;\n const footerWords = options['footerLabel'];\n const canvas = make('canvas', { class: 'fd-signature-pad', width: String(WIDTH), height: String(HEIGHT), role: 'img', 'aria-label': words.signaturePad });\n const hint = make('span', { class: 'fd-signature-hint', 'aria-hidden': 'true' }, node.placeholder || words.signHere);\n const image = make('img', { class: 'fd-signature-image', alt: field.label, hidden: '' });\n const typed = make('input', { type: 'text', class: 'fd-input fd-signature-typed', 'aria-label': words.typeSignature, placeholder: words.typeSignature, autocomplete: 'name' });\n const button = (words: string) => make('button', { type: 'button', class: 'fd-button fd-button-link', hidden: '' }, words);\n const undo = button(words.undo);\n const clear = button(words.clearDrawing);\n clear.classList.add('fd-signature-clear');\n // A picture of a signature, from this computer or a phone's camera.\n const upload = options['upload'] === true ? button(words.uploadSignature) : null;\n const file = make('input', { type: 'file', accept: 'image/*', class: 'fd-sr-only', tabindex: '-1', 'aria-hidden': 'true' });\n const element = make(\n 'div',\n { id, class: 'fd-signature', role: 'group' },\n make('div', { class: 'fd-signature-box' }, canvas, image, hint),\n ...(typeof footerWords === 'string' && footerWords ? [make('span', { class: 'fd-signature-footer' }, footerWords)] : []),\n make('div', { class: 'fd-signature-tools' }, typed, undo, ...(upload ? [upload, file] : []), clear)\n );\n\n const pen = () => {\n const context = canvas.getContext('2d');\n if (context) {\n context.strokeStyle = context.fillStyle = ink;\n context.lineWidth = width;\n context.lineCap = context.lineJoin = 'round';\n }\n return context;\n };\n /** The picture this pad last kept: coming back from the form, it leaves the pad as it is. */\n let mine: string | null = null;\n let readonly = false;\n /** What is on the pad: a typed name, and the strokes drawn, each its points. */\n let typedName: string | null = null;\n let strokes: Point[][] = [];\n let last: Point | null = null;\n\n const blank = () => !strokes.length && !typedName;\n /** The pad drawn again from what is on it: the name, then each stroke \u2014 a dot for a press that never moved. */\n function redraw() {\n const context = pen();\n if (!context) return;\n context.clearRect(0, 0, WIDTH, HEIGHT);\n if (typedName) {\n context.font = `italic 64px ${SCRIPT}`;\n context.textAlign = 'center';\n context.textBaseline = 'middle';\n context.fillText(typedName, WIDTH / 2, HEIGHT / 2, WIDTH - 40);\n }\n for (const stroke of strokes) {\n context.beginPath();\n context.arc(stroke[0].x, stroke[0].y, width / 2, 0, Math.PI * 2);\n context.fill();\n for (let i = 1; i < stroke.length; i++) line(stroke[i - 1], stroke[i]);\n }\n }\n function line(from: Point, to: Point) {\n const context = pen();\n context?.beginPath();\n context?.moveTo(from.x, from.y);\n context?.lineTo(to.x, to.y);\n context?.stroke();\n }\n function wipe() {\n strokes = [];\n typedName = null;\n redraw();\n }\n /** What is on the pad, as the field's value: nothing when it is blank. */\n function keep() {\n hint.hidden = !blank();\n if (blank()) {\n mine = null;\n return form.setValue(name, null);\n }\n let url: string | undefined;\n try {\n url = canvas.toDataURL('image/png');\n } catch {\n return; // a pad that cannot be read back keeps nothing\n }\n if (!url) return;\n const data = url.slice(url.indexOf(',') + 1);\n mine = data;\n form.setValue(name, { name: 'signature.png', type: 'image/png', size: bytesOf(data), data, ...(typedName && !strokes.length ? { text: typedName } : {}) });\n }\n /** The pad's point under the pointer: the pad is drawn smaller or larger than its own size. */\n function at(event: PointerEvent) {\n const box = canvas.getBoundingClientRect();\n return { x: ((event.clientX - box.left) * WIDTH) / (box.width || WIDTH), y: ((event.clientY - box.top) * HEIGHT) / (box.height || HEIGHT) };\n }\n\n canvas.addEventListener('pointerdown', (event) => {\n if (readonly || event.button !== 0) return;\n event.preventDefault();\n canvas.setPointerCapture?.(event.pointerId);\n last = at(event);\n strokes.push([last]);\n hint.hidden = true;\n redraw();\n });\n canvas.addEventListener('pointermove', (event) => {\n if (!last) return;\n const next = at(event);\n line(last, next);\n strokes[strokes.length - 1].push(next);\n last = next;\n });\n const end = () => {\n if (!last) return;\n last = null;\n keep();\n };\n canvas.addEventListener('pointerup', end);\n canvas.addEventListener('pointercancel', end);\n\n // A name typed is drawn in a hand's script, in place of whatever was drawn.\n typed.addEventListener('input', () => {\n showPad();\n strokes = [];\n typedName = typed.value.trim() || null;\n redraw();\n keep();\n });\n\n undo.addEventListener('click', () => {\n strokes.pop();\n redraw();\n keep();\n });\n\n upload?.addEventListener('click', () => file.click());\n file.addEventListener('change', () => {\n const chosen = file.files?.[0];\n file.value = '';\n if (chosen) void readFile(chosen).then((value) => form.setValue(name, value));\n });\n\n clear.addEventListener('click', () => {\n wipe();\n mine = null;\n typed.value = '';\n showPad();\n form.setValue(name, null);\n typed.focus();\n });\n\n function showPad() {\n image.hidden = true;\n canvas.hidden = false;\n }\n\n return {\n element,\n focus: () => (typed.hidden ? clear : typed).focus(),\n update(state) {\n readonly = state.readonly;\n const value = state.value && typeof state.value === 'object' && !Array.isArray(state.value) ? (state.value as FileValue) : null;\n const away = document.activeElement !== typed;\n if (value && keyOf(value) !== mine) {\n // Kept before, uploaded, or set from outside: its picture, until Clear.\n const src = value.data ? `data:${value.type};base64,${value.data}` : (value.url ?? '');\n if (image.getAttribute('src') !== src) image.src = src;\n image.hidden = false;\n canvas.hidden = true;\n mine = null;\n wipe();\n if (away) typed.value = value.text ?? '';\n } else if (!value) {\n if (mine !== null || !image.hidden) {\n // Emptied from outside.\n mine = null;\n wipe();\n if (away) typed.value = '';\n }\n showPad();\n }\n hint.hidden = readonly || !blank() || !image.hidden;\n typed.hidden = readonly;\n typed.readOnly = readonly;\n clear.hidden = readonly || !value;\n undo.hidden = readonly || !strokes.length || !image.hidden;\n if (upload) upload.hidden = readonly;\n canvas.classList.toggle('fd-signature-locked', readonly);\n describeState(element, state);\n typed.setAttribute('aria-invalid', String(state.invalid));\n },\n };\n};\n", "import { clearSelection, describeState, maker, wordsFor } from './kind-parts';\nimport { formatNumber } from './numbers';\nimport type { WidgetFactory } from './widgets';\n\n/**\n * A number picked on a slider (`integer.slider`, `float.slider`): the field's\n * `min` to `max` (0 to 100 when it has none), `options.step` at a time (1),\n * the value shown beside it and the ends under it, written as the page's\n * readers write numbers. A native range, so the arrow keys, Home and End move\n * it, a screen reader reads it, and it runs right to left on such a page.\n * Until it is slid it is not answered, and says so.\n */\nexport const sliderWidget: WidgetFactory = ({ form, name, field, node, id, document, labels, locale = 'en' }) => {\n const words = wordsFor(labels, locale);\n const make = maker(document);\n const has = (key: 'min' | 'max') => (key in field && typeof (field as Record<string, unknown>)[key] === 'number' ? ((field as Record<string, unknown>)[key] as number) : undefined);\n const min = has('min') ?? 0;\n const max = has('max') ?? 100;\n const step = typeof node.options?.['step'] === 'number' && node.options['step'] > 0 ? node.options['step'] : 1;\n const decimals = field.type === 'integer' ? 0 : field.type === 'float' && field.digits ? field.digits[1] : Math.max(0, -Math.floor(Math.log10(step)));\n const written = (n: number) => formatNumber(n, decimals, locale);\n\n const input = make('input', { id, type: 'range', class: 'fd-slider-input', min: String(min), max: String(max), step: String(step) });\n const output = make('output', { class: 'fd-slider-value', for: id, 'aria-hidden': 'true' });\n // Words under the ends' numbers, when the page has them: \"Never\" \u2026 \"Every day\".\n const endWords = [node.options?.['startLabel'], node.options?.['endLabel']].map((v) => (typeof v === 'string' ? v : ''));\n const end = (n: number, i: number) => make('span', { class: i ? 'fd-slider-last' : undefined }, written(n), ...(endWords[i] ? [make('span', { class: 'fd-slider-word' }, endWords[i])] : []));\n const ends = make('div', { class: 'fd-slider-ends', 'aria-hidden': 'true' }, end(min, 0), end(max, 1));\n const clear = clearSelection(document, words, () => {\n form.setValue(name, null);\n input.focus();\n });\n const element = make('div', { class: 'fd-slider' }, make('div', { class: 'fd-slider-track' }, input, output), ends, clear.button);\n if (endWords.some(Boolean)) input.setAttribute('aria-description', endWords.filter(Boolean).join(' \u2026 '));\n input.addEventListener('input', () => form.setValue(name, Number(input.value)));\n\n return {\n element,\n focus: () => input.focus(),\n update(state) {\n const value = typeof state.value === 'number' ? state.value : null;\n element.classList.toggle('fd-slider-empty', value === null);\n // Not answered: the thumb waits halfway, dimmed, and says so.\n const at = String(value ?? (min + max) / 2);\n if (input.value !== at) input.value = at;\n output.textContent = value === null ? '\u2013' : written(value);\n input.setAttribute('aria-valuetext', value === null ? words.notAnswered : written(value));\n input.disabled = state.readonly;\n clear.allow(state);\n clear.show(value !== null);\n describeState(input, state);\n },\n };\n};\n", "import type { FieldNode, Option } from '@fieldia/core';\nimport { fillIn, setText, type Make } from './kind-parts';\nimport type { WidgetLabels } from './labels';\n\n/**\n * What the choice kinds share beyond their looks: an option that goes alone\n * (\"None of these\"), a limit on how many are ticked, and the options laid\n * out in columns or in a row.\n */\n\n/** The values once `value` is added: alone when it goes alone, else without those that do. */\nexport function withAlone(options: readonly Option[], now: readonly unknown[], value: unknown): unknown[] {\n const alone = (v: unknown) => options.some((o) => o.exclusive && o.value === v);\n return alone(value) ? [value] : [...now.filter((v) => !alone(v)), value];\n}\n\n/**\n * The most a question takes, from an answer rule that always holds and stops\n * the form: once that many are ticked the rest are turned off, and a polite\n * \"Up to 3\" says why \u2014 as Form.io does, rather than complaining after.\n */\nexport function limiter(make: Make, words: WidgetLabels, node: FieldNode) {\n const most = node.validate?.find((r) => r.atMost !== undefined && (r.when ?? true) === true && r.level !== 'warning')?.atMost;\n const element = most ? make('span', { class: 'fd-choice-limit', role: 'status' }) : null;\n return {\n element,\n /** Whether `count` fills it, saying so when it does. */\n full(count: number) {\n const full = !!most && count >= most;\n if (element) setText(element, full ? fillIn(words.upTo, { n: most as number }) : '');\n return full;\n },\n };\n}\n\n/** Columns (`options.columns`, 1 to 4) or all in a row (`\"row\"`); a phone stacks them again. */\nexport function layOut(group: HTMLElement, node: FieldNode) {\n const columns = node.options?.['columns'];\n if (columns === 'row') group.classList.add('fd-choices-row');\n else if (typeof columns === 'number' && columns >= 1) {\n group.classList.add('fd-choices-columns');\n group.style.setProperty('--fd-choice-columns', String(Math.min(4, Math.round(columns))));\n }\n}\n", "import type { Option } from '@fieldia/core';\nimport { withAlone } from './choice-rules';\nimport { describeState, fillIn, maker, setAttr, wordsFor } from './kind-parts';\nimport type { WidgetContext, WidgetFactory } from './widgets';\n\n/**\n * Several answers from a list, as tags in a box (`selection.tags`): the box\n * is an ARIA combobox whose list holds the options not chosen yet, those whose\n * words hold what is typed. The arrows reach one and Enter adds it \u2014 or the\n * first match, when none is reached \u2014 as does a click. A tag goes with its \u00D7,\n * or the last with Backspace in the empty box. The answer keeps the order the\n * tags were added in; a value not among the options shows as its own words.\n * With `ownAnswers`, words that match nothing are offered as an answer of\n * their own; \"None of these\" goes alone.\n *\n * One answer, the same box (`searchWidget`): a dropdown that searches its\n * list \u2014 the box shows the choice, typing finds others, and a box left half\n * typed shows the choice again; emptied, it takes the choice away.\n */\nexport const choiceTagsWidget: WidgetFactory = (context) => combo(context, false);\nexport const searchWidget: WidgetFactory = (context) => combo(context, true);\n\nfunction combo({ form, name, field, id, document, labels, locale }: WidgetContext, single: boolean) {\n const words = wordsFor(labels, locale);\n const make = maker(document);\n const options: Option[] = field.type === 'selection' ? field.options : [];\n const own = field.type === 'selection' && field.ownAnswers === true && !single;\n const listId = `${id}-list`;\n const input = make('input', {\n id,\n type: 'text',\n class: 'fd-input fd-combo-input',\n role: 'combobox',\n 'aria-autocomplete': 'list',\n 'aria-expanded': 'false',\n 'aria-controls': listId,\n autocomplete: 'off',\n placeholder: words.search,\n });\n const list = make('ul', { id: listId, class: 'fd-listbox', role: 'listbox', hidden: '' });\n const chips = make('ul', { class: 'fd-chips' });\n const box = make('div', { class: 'fd-combo' }, input, list);\n const element = single ? make('div', { class: 'fd-choice-search' }, box) : make('div', { class: 'fd-tags fd-choice-tags' }, chips, box);\n\n const current = () => form.getState().values[name];\n const chosen = (): (string | number)[] => (Array.isArray(current()) ? (current() as (string | number)[]) : []);\n const write = (values: unknown[] | unknown) => form.setValue(name, values as never);\n const labelOf = (value: unknown) => options.find((o) => o.value === value)?.label ?? (value === null || value === undefined ? '' : String(value));\n\n /** The options on offer now, and the one the arrows reached. */\n let found: Option[] = [];\n let active = -1;\n let readonly = false;\n\n function draw() {\n list.replaceChildren(\n ...found.map((option, i) => {\n const item = make('li', { id: `${listId}-${i}`, role: 'option', class: `fd-option${i === active ? ' fd-active' : ''}`, 'aria-selected': String(i === active) }, option.label);\n // The box keeps the focus; the click adds it.\n item.addEventListener('mousedown', (event) => event.preventDefault());\n item.addEventListener('click', () => add(option));\n return item;\n })\n );\n if (!found.length) list.append(make('li', { class: 'fd-empty' }, words.noResults));\n setAttr(input, 'aria-activedescendant', active >= 0 ? `${listId}-${active}` : null);\n }\n function open() {\n const written = input.value.trim();\n // The choice's own words in the box find every option, not only itself.\n const typed = single && written === labelOf(current()) ? '' : written.toLowerCase();\n const taken = new Set(chosen());\n found = options.filter((o) => !taken.has(o.value) && o.label.toLowerCase().includes(typed));\n // Words that match nothing, offered as an answer of one's own.\n if (own && typed && !taken.has(written) && !options.some((o) => o.label.toLowerCase() === typed)) found.push({ value: written, label: fillIn(words.createNamed, { name: written }) });\n active = -1;\n draw();\n list.hidden = false;\n input.setAttribute('aria-expanded', 'true');\n }\n function close() {\n list.hidden = true;\n active = -1;\n input.setAttribute('aria-expanded', 'false');\n input.removeAttribute('aria-activedescendant');\n }\n function add(option: Option) {\n if (single) {\n input.value = option.label;\n write(option.value);\n return close();\n }\n input.value = '';\n write(withAlone(options, chosen(), option.value));\n if (document.activeElement === input) open();\n else close();\n }\n\n if (!single) input.addEventListener('focus', () => !readonly && open());\n input.addEventListener('click', () => !readonly && list.hidden && open());\n input.addEventListener('input', () => !readonly && open());\n input.addEventListener('blur', () => {\n close();\n // One answer: a box emptied takes the choice away; one left half typed shows the choice again.\n if (single && !readonly) {\n if (!input.value.trim()) write(null);\n else input.value = labelOf(current());\n }\n });\n input.addEventListener('keydown', (event) => {\n if (readonly) return;\n switch (event.key) {\n case 'ArrowDown':\n case 'ArrowUp': {\n event.preventDefault();\n if (list.hidden) return open();\n if (!found.length) return;\n const down = event.key === 'ArrowDown';\n // From none reached, down is the first and up the last; past either end it goes round.\n active = active === -1 ? (down ? 0 : found.length - 1) : (active + (down ? 1 : -1) + found.length) % found.length;\n draw();\n list.children[active]?.scrollIntoView?.({ block: 'nearest' });\n return;\n }\n case 'Enter': {\n const pick = found[active] ?? (input.value.trim() ? found[0] : undefined);\n if (list.hidden || !pick) return;\n event.preventDefault();\n add(pick);\n return;\n }\n case 'Escape':\n if (!list.hidden) event.preventDefault();\n close();\n return;\n case 'Backspace':\n if (!single && input.value === '' && chosen().length) write(chosen().slice(0, -1));\n return;\n }\n });\n\n let drawn = '';\n return {\n element,\n focus: () => input.focus(),\n update(state) {\n readonly = state.readonly;\n if (readonly) close();\n describeState(input, state);\n setAttr(input, 'aria-required', String(state.required));\n if (single) {\n input.readOnly = readonly;\n if (document.activeElement !== input) input.value = labelOf(state.value);\n return;\n }\n const values = Array.isArray(state.value) ? (state.value as unknown[]) : [];\n input.hidden = readonly;\n const key = JSON.stringify([readonly, values]);\n if (key === drawn) return;\n drawn = key;\n chips.replaceChildren(\n ...values.map((value) => {\n const label = labelOf(value);\n const chip = make('li', { class: 'fd-chip' }, make('span', { class: 'fd-chip-label' }, label));\n if (!readonly) {\n const remove = make('button', { type: 'button', class: 'fd-chip-remove', 'aria-label': fillIn(words.remove, { name: label }) }, '\u00D7');\n remove.addEventListener('click', () => write(chosen().filter((v) => v !== value)));\n chip.append(remove);\n }\n return chip;\n })\n );\n // The list follows what is chosen while it is open.\n if (!list.hidden) open();\n },\n } satisfies ReturnType<WidgetFactory>;\n}\n", "import type { Option } from '@fieldia/core';\nimport { layOut, limiter, withAlone } from './choice-rules';\nimport { clearSelection, describeState, maker, rightToLeft, wordsFor } from './kind-parts';\nimport { shownOptions } from './shuffle';\nimport type { WidgetFactory } from './widgets';\n\n/**\n * Pictures to choose from (`selection.image-choice`): each option a card of\n * its `image` over its words. One answer is a radio group with one stop for\n * Tab \u2014 the arrows move and pick, going round at the ends, Home and End go to\n * the ends, and left is forward on a right-to-left page \u2014 with \"Clear\n * selection\" when it need not be answered. Several answers, when the field\n * takes several, are checkboxes, each its own stop. \"Other\" is not offered:\n * an answer of one's own has no picture. `options.shuffle` shows the cards\n * in an order of the form's own. Each picture is described by its option's\n * `alt`. `options.showLabels: false` keeps the words out of sight (still each\n * card's name), `imageSize` is small, medium or large, `imageFit: \"whole\"`\n * shows the whole picture rather than filling the card, and `columns` lays\n * the cards in columns or in a row.\n */\n\n/** A frame with a hill and a sun: the tile of an option without a picture. */\nconst BLANK = '<svg viewBox=\"0 0 24 24\" aria-hidden=\"true\" focusable=\"false\"><rect x=\"3\" y=\"4\" width=\"18\" height=\"16\" rx=\"2\"/><circle cx=\"9\" cy=\"10\" r=\"2\"/><path d=\"M21 16l-5-5-9 9\"/></svg>';\n\nexport const imageChoiceWidget: WidgetFactory = ({ form, name, field, node, id, document, labels, locale }) => {\n const words = wordsFor(labels, locale);\n const make = maker(document);\n const multiple = field.type === 'selection' && field.multiple === true;\n const written: Option[] = field.type === 'selection' ? field.options : [];\n const options = shownOptions(written, form, name, node);\n const look = node.options ?? {};\n const bare = look['showLabels'] === false;\n const group = make('div', { id, class: `fd-image-choices${bare ? ' fd-image-choices-bare' : ''}`, role: multiple ? 'group' : 'radiogroup', 'data-size': look['imageSize'] as string, 'data-fit': look['imageFit'] as string });\n layOut(group, node);\n const limit = multiple ? limiter(make, words, node) : null;\n const cards = options.map((option) => {\n const picture = option.image ? make('img', { src: option.image, alt: option.alt ?? '', loading: 'lazy', draggable: 'false' }) : make('span', { class: 'fd-image-card-blank' });\n if (!option.image) picture.innerHTML = BLANK; // a constant drawing, never words from the page\n const card = make(\n 'button',\n { type: 'button', class: 'fd-image-card', role: multiple ? 'checkbox' : 'radio', 'aria-checked': 'false', 'aria-label': bare ? option.label : undefined },\n make('span', { class: 'fd-image-card-picture' }, picture),\n make('span', { class: 'fd-image-card-words' }, option.label)\n );\n card.addEventListener('click', () => pick(option));\n group.append(card);\n return card;\n });\n\n const current = () => form.getState().values[name];\n function pick(option: Option) {\n if (!multiple) return form.setValue(name, option.value);\n const now = Array.isArray(current()) ? (current() as unknown[]) : [];\n const on = new Set(now.includes(option.value) ? now.filter((v) => v !== option.value) : withAlone(written, now, option.value));\n // In the options' own order, as checkboxes keep them, however they are shown.\n form.setValue(name, written.filter((o) => on.has(o.value)).map((o) => o.value));\n }\n\n let readonly = false;\n if (!multiple) {\n group.addEventListener('keydown', (event) => {\n if (readonly) return;\n const at = cards.indexOf(event.target as HTMLButtonElement);\n if (at === -1) return;\n const back = rightToLeft(group);\n const steps: Record<string, number> = { ArrowDown: 1, ArrowUp: -1, ArrowRight: back ? -1 : 1, ArrowLeft: back ? 1 : -1 };\n const to = event.key === 'Home' ? 0 : event.key === 'End' ? cards.length - 1 : event.key in steps ? (at + steps[event.key] + cards.length) % cards.length : -1;\n if (to === -1) return;\n event.preventDefault();\n pick(options[to]);\n cards[to].focus();\n });\n }\n const clear = multiple\n ? null\n : clearSelection(document, words, () => {\n form.setValue(name, null);\n cards[0]?.focus();\n });\n\n if (limit?.element) group.append(limit.element);\n return {\n element: clear ? make('div', { class: 'fd-choices-box' }, group, clear.button) : group,\n focus: () => (cards.find((c) => c.getAttribute('aria-checked') === 'true') ?? cards[0])?.focus(),\n update(state) {\n readonly = state.readonly;\n const chosen = new Set<unknown>(Array.isArray(state.value) ? state.value : [state.value]);\n const stop = multiple ? -1 : Math.max(0, options.findIndex((o) => chosen.has(o.value)));\n const full = !!limit?.full(Array.isArray(state.value) ? state.value.length : 0);\n cards.forEach((card, i) => {\n const on = chosen.has(options[i].value);\n card.setAttribute('aria-checked', String(on));\n card.tabIndex = multiple || i === stop ? 0 : -1;\n card.disabled = readonly || (full && !on && !options[i].exclusive);\n });\n clear?.allow(state);\n clear?.show(options.some((o) => chosen.has(o.value)));\n describeState(group, state);\n },\n };\n};\n", "import type { Option } from '@fieldia/core';\nimport { announcer, describeState, fillIn, maker, wordsFor } from './kind-parts';\nimport { shownOptions } from './shuffle';\nimport type { WidgetFactory } from './widgets';\n\n/**\n * Options put in order (`selection.ranking`, on a field of several answers):\n * each line numbered, dragged by the pointer \u2014 the lines it passes the middle\n * of make way \u2014 or moved a place at a time with its buttons or Alt+\u2191/\u2193, the\n * cursor staying with it. Each move is said politely to screen readers. The\n * answer is the options' values in order, kept once something has moved:\n * until then the question is not answered. An order set from outside shows\n * as it is, the options it leaves out after it. `options.shuffle` starts the\n * lines in an order of the form's own, so none is first for being written first.\n * \"Keep this order\" answers it as it is shown. With `options.top` set, only\n * that many are ranked (a Top choice): each picked from the rest, then put in\n * order, and taken out with its \u00D7; \"Up to 3\" says how many.\n */\n\ninterface Item {\n option: Option;\n element: HTMLLIElement;\n place: HTMLElement;\n up: HTMLButtonElement;\n down: HTMLButtonElement;\n pick?: HTMLButtonElement;\n}\n\n/** How far the pointer goes before a press becomes a drag. */\nconst SLOP = 4;\n\nexport const rankingWidget: WidgetFactory = ({ form, name, field, node, id, document, labels, locale }) => {\n const words = wordsFor(labels, locale);\n const make = maker(document);\n const options: Option[] = shownOptions(field.type === 'selection' ? field.options : [], form, name, node);\n const list = make('ol', { class: 'fd-rank-list' });\n const voice = announcer(make);\n const most = node.options?.['top'];\n const top = typeof most === 'number' && most >= 1 && most < options.length ? Math.floor(most) : 0;\n const pool = make('div', { class: 'fd-rank-pool' });\n const keepAsShown = make('button', { type: 'button', class: 'fd-button fd-rank-keep' }, words.keepOrder);\n keepAsShown.addEventListener('click', () => form.setValue(name, shown.map((item) => item.option.value)));\n const element = make(\n 'div',\n { id, class: 'fd-ranking', role: 'group' },\n ...(top ? [make('div', { class: 'fd-choice-limit' }, fillIn(words.upTo, { n: top })), pool, list] : [list, keepAsShown]),\n voice.element\n );\n\n const items: Item[] = options.map((option) => {\n const label = option.label;\n const place = make('span', { class: 'fd-rank-place', 'aria-hidden': 'true' });\n const up = make('button', { type: 'button', class: 'fd-rank-move fd-rank-up', 'aria-label': fillIn(words.moveUp, { label }) }, '\u2191');\n const down = make('button', { type: 'button', class: 'fd-rank-move fd-rank-down', 'aria-label': fillIn(words.moveDown, { label }) }, '\u2193');\n const grip = make('span', { class: 'fd-rank-grip', 'aria-hidden': 'true' });\n const tools = make('span', { class: 'fd-rank-tools' }, up, down);\n const li = make('li', { class: 'fd-rank-item', 'data-value': String(option.value) }, grip, place, make('span', { class: 'fd-rank-words' }, label), tools);\n const item: Item = { option, element: li, place, up, down };\n if (top) {\n // Picked from the rest to the end of those ranked; its \u00D7 takes it out again.\n const pick = make('button', { type: 'button', class: 'fd-rank-pick' }, label);\n pick.addEventListener('click', () => !readonly && shown.length < top && keep([...shown, item], item));\n const out = make('button', { type: 'button', class: 'fd-rank-move fd-rank-out', 'aria-label': fillIn(words.remove, { name: label }) }, '\u00D7');\n out.addEventListener('click', () => {\n voice.say(fillIn(words.removed, { name: label }));\n form.setValue(name, shown.filter((other) => other !== item).map((other) => other.option.value));\n });\n tools.append(out);\n pool.append(pick);\n item.pick = pick;\n }\n up.addEventListener('click', () => move(item, -1, 'up'));\n down.addEventListener('click', () => move(item, 1, 'down'));\n li.addEventListener('pointerdown', (event) => press(item, event));\n return item;\n });\n\n let readonly = false;\n /** The lines in the order shown now. */\n let shown: Item[] = [...items];\n /** The button to give the cursor back to once a move has been drawn. */\n let refocus: { item: Item; which: 'up' | 'down' } | null = null;\n\n function draw(next: Item[]) {\n shown = next;\n next.forEach((item, i) => {\n if (list.children[i] !== item.element) list.insertBefore(item.element, list.children[i] ?? null);\n item.place.textContent = String(i + 1);\n item.up.disabled = i === 0;\n item.down.disabled = i === next.length - 1;\n });\n // Ranking the top few, those not ranked wait among the rest.\n while (list.children.length > next.length) list.lastElementChild?.remove();\n }\n /** Keep the order as the answer, and say where the line went. */\n function keep(next: Item[], moved: Item) {\n voice.say(fillIn(words.movedTo, { label: moved.option.label, n: next.indexOf(moved) + 1, total: next.length }));\n form.setValue(name, next.map((item) => item.option.value));\n }\n function move(item: Item, step: number, which: 'up' | 'down') {\n const from = shown.indexOf(item);\n const to = from + step;\n if (readonly || to < 0 || to >= shown.length) return;\n const next = [...shown];\n next.splice(from, 1);\n next.splice(to, 0, item);\n const holding = item.element.contains(document.activeElement);\n // At an end, the button that moved it is no use: the cursor goes to the other.\n refocus = holding ? { item, which: (which === 'up' && to === 0) || (which === 'down' && to === next.length - 1) ? (which === 'up' ? 'down' : 'up') : which } : null;\n keep(next, item);\n giveBackFocus();\n }\n function giveBackFocus() {\n if (!refocus) return;\n const { item, which } = refocus;\n refocus = null;\n item[which].focus();\n }\n\n list.addEventListener('keydown', (event) => {\n if (readonly || !event.altKey || (event.key !== 'ArrowUp' && event.key !== 'ArrowDown')) return;\n const item = items.find((i) => i.element.contains(event.target as Node));\n if (!item) return;\n event.preventDefault();\n move(item, event.key === 'ArrowUp' ? -1 : 1, event.key === 'ArrowUp' ? 'up' : 'down');\n });\n\n // Dragging: the line follows the pointer from place to place; the order is kept when it is let go.\n function press(item: Item, event: PointerEvent) {\n if (readonly || event.button !== 0 || (event.target as Element).closest('button')) return;\n // On a touch screen only the grip drags: anywhere else the page scrolls.\n if (event.pointerType === 'touch' && !(event.target as Element).closest('.fd-rank-grip')) return;\n const startY = event.clientY;\n const before = [...shown];\n let lifted = false;\n item.element.setPointerCapture?.(event.pointerId);\n const onMove = (e: PointerEvent) => {\n if (!lifted && Math.abs(e.clientY - startY) < SLOP) return;\n if (!lifted) {\n lifted = true;\n item.element.classList.add('fd-rank-lifted');\n }\n e.preventDefault();\n // Its place: after every other line whose middle the pointer has passed.\n const others = shown.filter((other) => other !== item);\n const at = others.filter((other) => {\n const box = other.element.getBoundingClientRect();\n return box.top + box.height / 2 < e.clientY;\n }).length;\n if (shown.indexOf(item) !== at) draw([...others.slice(0, at), item, ...others.slice(at)]);\n };\n const onEnd = () => {\n item.element.removeEventListener('pointermove', onMove);\n item.element.removeEventListener('pointerup', onEnd);\n item.element.removeEventListener('pointercancel', onEnd);\n item.element.classList.remove('fd-rank-lifted');\n if (shown.some((other, i) => other !== before[i])) keep(shown, item);\n };\n item.element.addEventListener('pointermove', onMove);\n item.element.addEventListener('pointerup', onEnd);\n item.element.addEventListener('pointercancel', onEnd);\n }\n\n /** The order a value says: its options first, in its order, then those it leaves out, as they were shown. */\n function orderOf(value: unknown): Item[] {\n const named = (Array.isArray(value) ? value : []).map((v) => items.find((item) => item.option.value === v)).filter((item): item is Item => !!item);\n if (top) return named.slice(0, top);\n return Array.isArray(value) ? [...new Set([...named, ...shown])] : shown;\n }\n\n draw(top ? [] : shown);\n return {\n element,\n focus: () => (items.find((item) => item.pick && !item.pick.hidden && !item.pick.disabled)?.pick ?? (shown[0]?.down.disabled ? shown[0]?.up : shown[0]?.down))?.focus(),\n update(state) {\n readonly = state.readonly;\n element.classList.toggle('fd-ranking-locked', readonly);\n const next = orderOf(state.value);\n if (next.length !== shown.length || next.some((item, i) => item !== shown[i]) || (!top && !list.children.length)) draw(next);\n for (const item of items) {\n item.up.hidden = item.down.hidden = readonly;\n if (item.pick) {\n item.pick.hidden = shown.includes(item);\n item.pick.disabled = readonly || shown.length >= top;\n (item.element.querySelector('.fd-rank-out') as HTMLElement).hidden = readonly;\n }\n }\n keepAsShown.hidden = readonly || (Array.isArray(state.value) && state.value.length > 0);\n giveBackFocus();\n describeState(element, state);\n },\n };\n};\n", "import { ADDRESS_PARTS } from '@fieldia/core';\nimport type { WidgetLabels } from './labels';\nimport { describeState, maker, wordsFor } from './kind-parts';\nimport type { WidgetFactory } from './widgets';\n\n/**\n * An address on a JSON field (`json.address`), in its parts \u2014 street, a\n * second line, city, region, postcode and country \u2014 each with its own label,\n * filled in by the browser when it can. `options.parts` chooses which, and in\n * what order: street, city, postcode and country unless it says. The country\n * is chosen from a list in the page's language and kept as its ISO code;\n * `options.country` is the one it starts on, kept once anything else is\n * typed. `options.requiredParts` are marked, and the form asks for them. The\n * value is an object of the parts filled in, keeping any part it was given\n * that it does not ask for; nothing at all when every part is empty.\n */\n\nconst PARTS: Record<(typeof ADDRESS_PARTS)[number], [keyof WidgetLabels, string]> = {\n street: ['addressStreet', 'street-address'],\n line2: ['addressLine2', 'address-line2'],\n city: ['addressCity', 'address-level2'],\n region: ['addressRegion', 'address-level1'],\n postcode: ['addressPostcode', 'postal-code'],\n country: ['addressCountry', 'country'],\n};\ntype Part = keyof typeof PARTS;\nconst isPart = (name: unknown): name is Part => typeof name === 'string' && name in PARTS;\n\n/** Codes with a region's name that are no country: old ones, groups, and the like. */\nconst NOT_COUNTRIES = 'AC AN BU CP CQ CS DD DG DY EA EU EZ FX HV IC NH QO RH SU TA TP UK UN VD XA XB YD YU ZR ZZ';\nconst countries: Record<string, [string, string][]> = {};\n/** Every country, by its code and its name in the language, in the language's order. */\nexport function countriesIn(locale: string): [string, string][] {\n if (!countries[locale]) {\n const names = new Intl.DisplayNames([locale], { type: 'region', fallback: 'none' });\n const found: [string, string][] = [];\n for (let a = 65; a < 91; a++)\n for (let b = 65; b < 91; b++) {\n const code = String.fromCharCode(a, b);\n const name = !NOT_COUNTRIES.includes(code) && names.of(code);\n if (name) found.push([code, name]);\n }\n countries[locale] = found.sort((x, y) => x[1].localeCompare(y[1], locale));\n }\n return countries[locale];\n}\n\nexport const addressWidget: WidgetFactory = ({ form, name, node, id, document, labels, locale = 'en' }) => {\n const words = wordsFor(labels, locale);\n const make = maker(document);\n const options = node.options ?? {};\n const asked = options['parts'];\n const parts: Part[] = Array.isArray(asked) ? asked.filter(isPart) : ['street', 'city', 'postcode', 'country'];\n const needed = Array.isArray(options['requiredParts']) ? options['requiredParts'] : [];\n const start = typeof options['country'] === 'string' ? options['country'] : '';\n const element = make('div', { id, class: 'fd-address', role: 'group' });\n /** The parts as they are now, a part as typed in place of its own. */\n const write = (part: Part, text: string) => {\n const now = form.getState().values[name];\n const kept: Record<string, unknown> = now && typeof now === 'object' && !Array.isArray(now) ? { ...(now as Record<string, unknown>) } : {};\n kept[part] = text;\n // The country it starts on goes with the parts typed, but is no answer on its own.\n if (start && parts.includes('country') && kept['country'] === undefined) kept['country'] = start;\n // Only the parts with something in them.\n const filled = Object.fromEntries(Object.entries(kept).filter(([, v]) => typeof v !== 'string' || v.trim() !== ''));\n const keys = Object.keys(filled);\n form.setValue(name, keys.length && (part === 'country' || keys.join() !== 'country' || filled['country'] !== start) ? (filled as never) : null);\n };\n const boxes = parts.map((part) => {\n const [label, autocomplete] = PARTS[part];\n const attrs = { id: `${id}-${part}`, class: 'fd-input', 'data-part': part, autocomplete: part === 'street' && parts.includes('line2') ? 'address-line1' : autocomplete, 'aria-required': needed.includes(part) ? 'true' : undefined };\n const input =\n part === 'country'\n ? make('select', attrs, make('option', { value: '' }), ...countriesIn(locale).map(([code, country]) => make('option', { value: code }, country)))\n : make('input', { type: 'text', ...attrs });\n input.addEventListener(part === 'country' ? 'change' : 'input', () => write(part, input.value));\n if (part === 'country') input.classList.add('fd-select');\n element.append(make('div', { class: `fd-address-part fd-address-${part}${needed.includes(part) ? ' fd-required' : ''}` }, make('label', { class: 'fd-address-label', for: input.id }, words[label]), input));\n return { part, input };\n });\n\n return {\n element,\n focus: () => boxes[0]?.input.focus(),\n update(state) {\n const value = state.value && typeof state.value === 'object' && !Array.isArray(state.value) ? (state.value as Record<string, unknown>) : {};\n for (const { part, input } of boxes) {\n const text = typeof value[part] === 'string' ? (value[part] as string) : part === 'country' && value['country'] === undefined ? start : '';\n if (input instanceof HTMLSelectElement) {\n // A country given in words is shown as it was given.\n if (text && ![...input.options].some((o) => o.value === text)) input.append(make('option', { value: text }, text));\n input.disabled = state.readonly;\n } else input.readOnly = state.readonly;\n // What is being typed stays as typed.\n if (document.activeElement !== input && input.value !== text) input.value = text;\n // Wrong, a part that must be filled and is not is marked.\n input.setAttribute('aria-invalid', String(state.invalid && (!needed.length || (needed.includes(part) && !text.trim()))));\n }\n describeState(element, state);\n },\n };\n};\n", "import type { Field, FieldNode, Line, LineField } from '@fieldia/core';\nimport { announcer, describeState, fillIn, maker, wordsFor } from './kind-parts';\nimport { moveLineTo } from './line-moves';\nimport { lineForm } from './lines';\nimport { createWidget, type Widget, type WidgetFactory } from './widgets';\n\n/**\n * A repeating group on a one2many (`one2many.cards`): each line a small card\n * of the lines' fields, one under another, its title numbered (\"Guest 2\",\n * from `options.itemLabel`, or \"Entry 2\"). \"Add another\" (`options.addLabel`)\n * adds a card and puts the cursor in its first field; \u00D7 takes one away, the\n * cursor going to the card that took its place, and the removal is said\n * aloud. `options.min` cards at least \u2014 a new form starts with them \u2014 and\n * `options.max` at most. \u2191 and \u2193 move a card, where it went said aloud; Copy puts a copy of a card, its answers too,\n * right after it.\n */\n\ninterface Card {\n element: HTMLElement;\n title: HTMLElement;\n remove: HTMLButtonElement;\n /** Up, down and Copy, by their label in `words`. */\n tools: [HTMLButtonElement, 'moveUp' | 'moveDown' | 'copy'][];\n fields: { name: string; def: LineField; widget: Widget; error: HTMLElement }[];\n}\n\nconst count = (value: unknown) => (typeof value === 'number' && Number.isInteger(value) && value >= 0 ? value : undefined);\n\nexport const cardsWidget: WidgetFactory = ({ form, name, field, node, id, document, labels, locale, dialogs }) => {\n const words = wordsFor(labels, locale);\n const make = maker(document);\n const def = field as Extract<Field, { type: 'one2many' }>;\n const options = node.options ?? {};\n const min = count(options['min']) ?? 0;\n const max = count(options['max']) ?? Infinity;\n const itemLabel = typeof options['itemLabel'] === 'string' && options['itemLabel'].trim() ? options['itemLabel'].trim() : null;\n const titleOf = (n: number) => (itemLabel ? `${itemLabel} ${n}` : fillIn(words.entry, { n }));\n // The fields that keep the lines' order or say what a line is are not asked for.\n const names = (node.columns ?? Object.keys(def.fields)).filter((f) => def.fields[f] && f !== def.sequenceField && f !== def.lineKinds?.field);\n\n const list = make('div', { class: 'fd-repeat-list' });\n const addButton = make('button', { type: 'button', class: 'fd-button fd-repeat-add' }, typeof options['addLabel'] === 'string' && options['addLabel'] ? options['addLabel'] : words.addAnother);\n const voice = announcer(make);\n const element = make('div', { id, class: 'fd-repeat', role: 'group' }, list, addButton, voice.element);\n\n const cards = new Map<string, Card>();\n const lines = () => (form.getState().values[name] as Line[] | null) ?? [];\n let readonly = false;\n /** Where the cursor goes once the cards are drawn again. */\n let focusNext: (() => void) | null = null;\n\n // A new form starts with the cards it needs at least.\n for (let have = lines().length; have < min; have++) form.addLine(name);\n\n addButton.addEventListener('click', () => {\n if (readonly || lines().length >= max) return;\n const key = form.addLine(name);\n focusNext = () => cards.get(key)?.fields[0]?.widget.focus();\n settle();\n });\n\n function makeCard(line: Line): Card {\n const titleId = `${id}-${line.key}-title`;\n const title = make('span', { id: titleId, class: 'fd-repeat-title' });\n const remove = make('button', { type: 'button', class: 'fd-repeat-remove' }, '\u00D7');\n const tool = (text: string, word: 'moveUp' | 'moveDown' | 'copy', act: () => void): [HTMLButtonElement, typeof word] => {\n const button = make('button', { type: 'button', class: 'fd-repeat-tool' }, text);\n button.addEventListener('click', act);\n return [button, word];\n };\n const at = () => lines().findIndex((l) => l.key === line.key);\n const tools = [tool('\u2191', 'moveUp', () => move(line.key, at() - 1)), tool('\u2193', 'moveDown', () => move(line.key, at() + 1)), tool('\u29C9', 'copy', () => copy(line.key))];\n const body = make('div', { class: 'fd-repeat-fields' });\n const cardElement = make('div', { class: 'fd-repeat-card', role: 'group', 'aria-labelledby': titleId, 'data-line': line.key }, make('div', { class: 'fd-repeat-head' }, title, ...tools.map(([b]) => b), remove), body);\n const fields = names.map((column) => {\n const sub = def.fields[column];\n const cellId = `${id}-${line.key}-${column}`;\n const subNode: FieldNode = { type: 'field', id: `${node.id}.${line.key}.${column}`, field: column };\n const widget = createWidget({ form: lineForm(form, name, line.key), name: column, field: sub as Field, node: subNode, id: cellId, document, labels, locale, dialogs });\n const label = make('label', { class: 'fd-repeat-label', for: cellId }, sub.label);\n if (!['INPUT', 'SELECT', 'TEXTAREA'].includes(widget.element.tagName)) label.addEventListener('click', () => widget.focus());\n const error = make('div', { class: 'fd-cell-error', hidden: '' });\n body.append(make('div', { class: 'fd-repeat-field' }, label, widget.element, error));\n return { name: column, def: sub, widget, error };\n });\n remove.addEventListener('click', () => {\n const all = lines();\n const at = all.findIndex((l) => l.key === line.key);\n if (readonly || at === -1 || all.length <= min) return;\n const gone = title.textContent ?? '';\n form.removeLine(name, line.key);\n voice.say(fillIn(words.removed, { name: gone }));\n // The card that took its place, else the one before, else \"Add another\".\n const after = lines();\n const next = after[Math.min(at, after.length - 1)];\n focusNext = () => (next ? cards.get(next.key)?.fields[0]?.widget.focus() : addButton.focus());\n settle();\n });\n return { element: cardElement, title, remove, tools, fields };\n }\n\n /** A card to another place, the focus kept on what had it, and where it went said aloud. */\n function move(key: string, to: number) {\n const from = lines().findIndex((l) => l.key === key);\n if (readonly || to < 0 || to >= lines().length || to === from) return;\n const gone = cards.get(key)?.title.textContent ?? '';\n moveLineTo(form, name, def, key, to);\n // The focus stays on the button pressed; at an end, the other way takes it.\n const way = (from > to && to > 0) || to === lines().length - 1 ? 0 : 1;\n cards.get(key)?.tools[way][0].focus();\n voice.say(fillIn(words.movedTo, { label: gone, n: to + 1, total: lines().length }));\n }\n\n /** A copy of a card, its answers too, right after it, the cursor in its first field. */\n function copy(key: string) {\n const all = lines();\n const at = all.findIndex((l) => l.key === key);\n if (readonly || at < 0 || all.length >= max) return;\n const values = { ...all[at].values };\n if (def.sequenceField) delete values[def.sequenceField];\n const made = form.addLine(name, values);\n moveLineTo(form, name, def, made, at + 1);\n cards.get(made)?.fields[0]?.widget.focus();\n }\n\n function settle() {\n const run = focusNext;\n focusNext = null;\n run?.();\n }\n\n return {\n element,\n focus: () => ([...cards.values()].find((card) => card.element === list.firstElementChild)?.fields[0]?.widget ?? addButton).focus(),\n update(state) {\n readonly = state.readonly;\n const current = (state.value as Line[] | null) ?? [];\n const errors = form.getState().errors;\n const keep = new Set(current.map((l) => l.key));\n for (const [key, card] of cards) {\n if (keep.has(key)) continue;\n card.element.remove();\n for (const f of card.fields) f.widget.destroy?.();\n cards.delete(key);\n }\n current.forEach((line, index) => {\n let card = cards.get(line.key);\n if (!card) cards.set(line.key, (card = makeCard(line)));\n if (list.children[index] !== card.element) list.insertBefore(card.element, list.children[index] ?? null);\n card.title.textContent = titleOf(index + 1);\n card.remove.setAttribute('aria-label', fillIn(words.remove, { name: card.title.textContent }));\n card.remove.hidden = readonly || current.length <= min;\n for (const [button, word] of card.tools) {\n button.setAttribute('aria-label', fillIn(words[word], { label: card.title.textContent, name: card.title.textContent }));\n button.hidden = readonly || (word === 'moveUp' ? index === 0 : word === 'moveDown' ? index === current.length - 1 : current.length >= max);\n }\n for (const f of card.fields) {\n const message = errors[`${name}.${line.key}.${f.name}`];\n f.error.hidden = !message;\n f.error.textContent = message ?? '';\n f.widget.update({ value: line.values[f.name], values: line.values, readonly: readonly || f.def.readonly === true, required: f.def.required === true, invalid: !!message });\n }\n });\n addButton.hidden = readonly || current.length >= max;\n describeState(element, state);\n },\n };\n};\n", "import { dayOf, type Field, type FieldNode } from '@fieldia/core';\nimport { fillIn, maker, setHidden, setText, wordsFor } from './kind-parts';\nimport type { Widget, WidgetContext } from './widgets';\n\n/**\n * What a text box shows of its limits: a count of the characters typed\n * against its field's most, under it \u2014 \"12 / 100\", in the warning colour from\n * nine tenths on, and how many are left said to a screen reader once typing\n * pauses \u2014 for a page's own field, not a table's cell; and a paragraph's rows,\n * growing as people type unless the page says not to (`autoGrow: false`);\n * a date's, a date and time's or a time's earliest and latest on its input.\n */\nexport function counted(widget: Widget, { form, name, field, document, labels, locale }: WidgetContext, box: HTMLInputElement | HTMLTextAreaElement): Widget {\n const size = field.type === 'char' || field.type === 'text' ? field.size : undefined;\n if (!size || form.page.fields[name] !== field) return widget;\n const make = maker(document);\n const shown = make('div', { class: 'fd-count', 'aria-hidden': 'true' });\n const said = make('div', { class: 'fd-sr-only', 'aria-live': 'polite' });\n let pause: ReturnType<typeof setTimeout> | undefined;\n return {\n ...widget,\n element: make('div', { class: 'fd-counted' }, widget.element, shown, said),\n update(state) {\n widget.update(state);\n const n = box.value.length;\n setText(shown, `${n} / ${size}`);\n shown.classList.toggle('fd-count-near', n >= size * 0.9);\n setHidden(shown, state.readonly);\n if (document.activeElement !== box) return;\n clearTimeout(pause);\n pause = setTimeout(() => setText(said, fillIn(wordsFor(labels, locale).charactersLeft, { n: size - n })), 700);\n },\n };\n}\n\n/** A paragraph's rows (`options.rows`), and a way to grow it to what it holds \u2014 nothing when it keeps its height. */\nexport function grower(area: HTMLTextAreaElement, node: FieldNode): () => void {\n const rows = node.options?.['rows'];\n if (typeof rows === 'number') area.rows = rows;\n if (node.options?.['autoGrow'] === false) return () => undefined;\n return () => {\n area.style.height = '';\n // Its height takes its borders too: what scrolls, and the borders round it.\n if (area.scrollHeight) area.style.height = `${area.scrollHeight + area.offsetHeight - area.clientHeight}px`;\n };\n}\n\n/**\n * A date's or a date and time's earliest and latest day (the field's `min`\n * and `max`, counted from today where they say so), or a time's (the node's\n * `min` and `max`, \"09:00\"), on its input for the browser's picker to keep;\n * and the node's `step` in minutes.\n */\nexport function bounds(input: HTMLInputElement, field: Field, node: FieldNode): void {\n const options = node.options ?? {};\n const time = field.type === 'char';\n const limits = time ? [options['min'], options['max']] : 'min' in field ? [field.min, field.max] : [];\n limits.forEach((limit, i) => {\n if (typeof limit === 'string') input[i ? 'max' : 'min'] = time ? limit : dayOf(limit) + (field.type === 'datetime' ? (i ? 'T23:59' : 'T00:00') : '');\n });\n if (typeof options['step'] === 'number') input.step = String(options['step'] * 60);\n}\n", "import type { Locale } from '@fieldia/core';\n\n/**\n * A currency as the page's language writes it beside an amount: its symbol \u2014\n * \"$\", \"\u20AC\", \"E\u00A3\" \u2014 and whether it comes after the number, as in \"12,50 \u20AC\".\n * A name that is no currency code stays as it is, before the number.\n */\nexport function currencySymbol(code: string, locale: Locale): { text: string; after: boolean } {\n try {\n const parts = new Intl.NumberFormat(locale, { style: 'currency', currency: code, currencyDisplay: 'narrowSymbol' }).formatToParts(1);\n const at = parts.findIndex((part) => part.type === 'currency');\n return { text: parts[at].value, after: at > parts.findIndex((part) => part.type === 'integer') };\n } catch {\n return { text: code, after: false };\n }\n}\n", "/**\n * Icons by name, for sections, tabs, buttons, stat buttons, badges and steps.\n * Each is the inside of a 24\u00D724 SVG drawn with lines in the text colour, so it\n * takes the colour and size of the words beside it. An app adds its own, or\n * replaces one of these, with the viewer's `icons` option, in the same form.\n */\nexport type IconSet = Readonly<Record<string, string>>;\n\nconst SVG = 'http://www.w3.org/2000/svg';\n\nexport const ICONS: IconSet = {\n user: '<circle cx=\"12\" cy=\"8\" r=\"4\"/><path d=\"M4 21c0-4 3.6-6 8-6s8 2 8 6\"/>',\n users: '<circle cx=\"9\" cy=\"8\" r=\"3.5\"/><path d=\"M2 20c0-3.5 3-5.5 7-5.5s7 2 7 5.5\"/><circle cx=\"17\" cy=\"9\" r=\"2.5\"/><path d=\"M16.5 14.5c3 0 5.5 1.6 5.5 4.5\"/>',\n building: '<rect x=\"4\" y=\"3\" width=\"16\" height=\"18\" rx=\"1\"/><path d=\"M9 21v-4h6v4M8 7h2M14 7h2M8 11h2M14 11h2\"/>',\n home: '<path d=\"M3 11l9-7 9 7\"/><path d=\"M5 10v10h14V10\"/><path d=\"M10 20v-6h4v6\"/>',\n phone: '<rect x=\"7\" y=\"2\" width=\"10\" height=\"20\" rx=\"2\"/><path d=\"M11 18h2\"/>',\n mail: '<rect x=\"3\" y=\"5\" width=\"18\" height=\"14\" rx=\"2\"/><path d=\"M3 7l9 6 9-6\"/>',\n pin: '<path d=\"M12 21s-7-6.5-7-12a7 7 0 0 1 14 0c0 5.5-7 12-7 12z\"/><circle cx=\"12\" cy=\"9\" r=\"2.5\"/>',\n globe: '<circle cx=\"12\" cy=\"12\" r=\"9\"/><path d=\"M3 12h18M12 3c3 3.2 3 14.8 0 18M12 3c-3 3.2-3 14.8 0 18\"/>',\n calendar: '<rect x=\"3\" y=\"5\" width=\"18\" height=\"16\" rx=\"2\"/><path d=\"M3 10h18M8 3v4M16 3v4\"/>',\n clock: '<circle cx=\"12\" cy=\"12\" r=\"9\"/><path d=\"M12 7v5l3 3\"/>',\n money: '<rect x=\"2\" y=\"6\" width=\"20\" height=\"12\" rx=\"2\"/><circle cx=\"12\" cy=\"12\" r=\"3\"/><path d=\"M6 9.5v0M18 14.5v0\"/>',\n cart: '<path d=\"M3 4h2l2.5 11h11L21 7H6.4\"/><circle cx=\"9\" cy=\"19.5\" r=\"1.5\"/><circle cx=\"17\" cy=\"19.5\" r=\"1.5\"/>',\n box: '<path d=\"M12 3l8 4.5v9L12 21l-8-4.5v-9z\"/><path d=\"M4 7.5l8 4.5 8-4.5M12 12v9\"/>',\n truck: '<path d=\"M2 6h12v10H2zM14 9h4l3 3.5V16h-7\"/><circle cx=\"6.5\" cy=\"17.5\" r=\"1.8\"/><circle cx=\"17\" cy=\"17.5\" r=\"1.8\"/>',\n receipt: '<path d=\"M6 3h12v18l-3-2-3 2-3-2-3 2z\"/><path d=\"M9 8h6M9 12h6\"/>',\n file: '<path d=\"M6 3h8l4 4v14H6z\"/><path d=\"M14 3v4h4M9 12h6M9 16h6\"/>',\n edit: '<path d=\"M4 20h4L19 9l-4-4L4 16z\"/><path d=\"M13.5 6.5l4 4\"/>',\n tag: '<path d=\"M3 12V4h8l10 10-8 8z\"/><circle cx=\"7.5\" cy=\"8\" r=\"1.5\"/>',\n star: '<path d=\"M12 3l2.8 6 6.2.6-4.7 4.2 1.4 6.2L12 16.8 6.3 20l1.4-6.2L3 9.6 9.2 9z\"/>',\n lock: '<rect x=\"5\" y=\"11\" width=\"14\" height=\"10\" rx=\"2\"/><path d=\"M8 11V7a4 4 0 0 1 8 0v4\"/>',\n check: '<path d=\"M5 12.5l4.5 4.5L19 7.5\"/>',\n info: '<circle cx=\"12\" cy=\"12\" r=\"9\"/><path d=\"M12 11v6M12 7.5v0\"/>',\n warning: '<path d=\"M12 3l10 18H2z\"/><path d=\"M12 10v5M12 18v0\"/>',\n settings: '<path d=\"M4 6h9M17 6h3M4 12h3M11 12h9M4 18h11M19 18h1\"/><circle cx=\"15\" cy=\"6\" r=\"2\"/><circle cx=\"9\" cy=\"12\" r=\"2\"/><circle cx=\"17\" cy=\"18\" r=\"2\"/>',\n chart: '<path d=\"M3 20h18M6 20v-8M11 20V5M16 20v-6\"/>',\n link: '<path d=\"M10 14a4 4 0 0 0 5.6 0l3-3a4 4 0 0 0-5.6-5.6l-1 1\"/><path d=\"M14 10a4 4 0 0 0-5.6 0l-3 3a4 4 0 0 0 5.6 5.6l1-1\"/>',\n list: '<path d=\"M8 6h12M8 12h12M8 18h12M4 6v0M4 12v0M4 18v0\"/>',\n chat: '<path d=\"M4 5h16v11H9l-5 4z\"/>',\n search: '<circle cx=\"11\" cy=\"11\" r=\"6.5\"/><path d=\"M16 16l5 5\"/>',\n filter: '<path d=\"M3 5h18l-7 8.5V20l-4-2v-4.5z\"/>',\n layers: '<path d=\"M12 3l9 5-9 5-9-5z\"/><path d=\"M3 13l9 5 9-5\"/>',\n thumb: '<path d=\"M7 21V10l4-8c1.6 0 2.6 1.3 2.2 3L12.5 9H19a2 2 0 0 1 2 2.3l-1.3 7.6a2.5 2.5 0 0 1-2.5 2.1H7zM7 10H3v11h4\"/>',\n};\n\n/** An icon by name, the app's own first and then Fieldia's; null for a name neither has. */\nexport function drawIcon(doc: Document, name: string | undefined, own?: IconSet): SVGSVGElement | null {\n const inside = name ? own?.[name] ?? ICONS[name] : undefined;\n if (inside === undefined) return null;\n const svg = doc.createElementNS(SVG, 'svg');\n for (const [key, value] of Object.entries({\n viewBox: '0 0 24 24',\n fill: 'none',\n stroke: 'currentColor',\n 'stroke-width': '1.8',\n 'stroke-linecap': 'round',\n 'stroke-linejoin': 'round',\n 'aria-hidden': 'true',\n focusable: 'false',\n class: 'fd-icon',\n 'data-icon': name as string,\n })) {\n svg.setAttribute(key, value);\n }\n svg.innerHTML = inside;\n return svg;\n}\n", "import { fill, type Field, type Option } from '@fieldia/core';\nimport { wordsFor } from './kind-parts';\nimport type { Widget, WidgetContext, WidgetFactory } from './widgets';\n\n/**\n * A choice whose options are one of the app's lists: the widget the field\n * would have anyway, drawn afresh from each answer the list gives. While the\n * choices load it says so; when they fail it offers to load them again; and\n * a value the list no longer offers is kept \u2014 the person decides \u2014 and said.\n */\nexport function listChoices(factory: WidgetFactory, context: WidgetContext): Widget {\n const { form, name, document: doc } = context;\n const words = wordsFor(context.labels, context.locale);\n const box = doc.createElement('div');\n const note = doc.createElement('div');\n const retry = doc.createElement('button');\n retry.type = 'button';\n retry.className = 'fd-button fd-button-link';\n retry.textContent = words.choicesFailed;\n retry.onclick = () => form.loadChoices(name);\n note.setAttribute('role', 'status');\n // Spaced as a field's own parts are.\n box.style.cssText = 'display:grid;gap:4px';\n /** Every choice the list has given, to name a value it no longer offers. */\n const named = new Map<unknown, string>();\n let inner: Widget;\n let shown: Option[] | null = null;\n const draw = (options: Option[]) => {\n inner?.destroy?.();\n inner = factory({ ...context, field: { ...context.field, options } as Field });\n // Named by the field's label, as the viewer names a widget with a role of its own.\n if (inner.element.getAttribute('role')) inner.element.setAttribute('aria-labelledby', `${context.id}-label`);\n box.replaceChildren(inner.element, note, retry);\n };\n draw([]);\n if (!form.getState().choices[name]) form.loadChoices(name);\n return {\n element: box,\n focus: () => inner.focus(),\n destroy: () => inner.destroy?.(),\n update(state) {\n const choices = form.getState().choices[name];\n if (choices?.options && choices.options !== shown) {\n shown = choices.options;\n for (const option of shown) named.set(option.value, option.label);\n draw(shown);\n }\n inner.update(state);\n // With \"Other\", a value not among them is an answer of the person's own.\n const lost = shown && !(context.field as { other?: boolean }).other ? [state.value].flat().filter((v) => v != null && !shown?.some((o) => o.value === v)) : [];\n note.className = choices?.loading ? 'fd-help' : 'fd-warning';\n note.textContent = choices?.loading ? words.loadingChoices : lost.length ? fill(words.notOffered, { name: lost.map((v) => named.get(v) ?? String(v)).join(', ') }) : '';\n note.hidden = !note.textContent;\n // Loading again sets the failure aside, and the button with it.\n retry.hidden = !choices?.error;\n },\n };\n}\n", "import { clearSelection, describeState, maker, setAttr, wordsFor } from './kind-parts';\nimport type { WidgetFactory } from './widgets';\n\n/**\n * A yes or no as two buttons, \"Yes\" and \"No\" (`boolean.buttons`): a radio\n * group with one stop for Tab, an arrow key going to the other and picking\n * it. Nothing is picked until one is \u2014 the field starts empty, its default\n * `null` \u2014 so a required one waits for an answer, and \"No\" is one.\n * `options.yesLabel` and `noLabel` give them other words.\n */\nexport const yesNoWidget: WidgetFactory = ({ form, name, node, id, document, labels, locale }) => {\n const words = wordsFor(labels, locale);\n const make = maker(document);\n // The points' look: a button each, the one picked filled.\n const group = make('div', { id, class: 'fd-points fd-yes-no', role: 'radiogroup' });\n let readonly = false;\n const buttons = [true, false].map((value) => {\n const own = node.options?.[value ? 'yesLabel' : 'noLabel'];\n const button = make('button', { type: 'button', role: 'radio' }, typeof own === 'string' && own ? own : value ? words.yes : words.no);\n button.addEventListener('click', () => form.setValue(name, value));\n group.append(button);\n return button;\n });\n // Two of them: every arrow goes to the other one.\n group.addEventListener('keydown', (event) => {\n const at = buttons.indexOf(event.target as HTMLButtonElement);\n if (readonly || at === -1 || !event.key.startsWith('Arrow')) return;\n event.preventDefault();\n form.setValue(name, at === 1);\n buttons[1 - at].focus();\n });\n const clear = clearSelection(document, words, () => {\n form.setValue(name, null);\n buttons[0].focus();\n });\n return {\n element: make('div', { class: 'fd-choices-box' }, group, clear.button),\n focus: () => (buttons.find((b) => b.getAttribute('aria-checked') === 'true') ?? buttons[0]).focus(),\n update(state) {\n readonly = state.readonly;\n const picked = state.value === true ? 0 : state.value === false ? 1 : -1;\n buttons.forEach((button, i) => {\n setAttr(button, 'aria-checked', String(i === picked));\n button.classList.toggle('fd-on', i === picked);\n button.tabIndex = i === Math.max(0, picked) ? 0 : -1;\n button.disabled = readonly;\n });\n setAttr(group, 'aria-required', String(state.required));\n clear.allow(state);\n clear.show(picked !== -1);\n describeState(group, state);\n },\n };\n};\n", "import type {\n Field,\n FieldNode,\n FileValue,\n Form,\n Line,\n Locale,\n RecordId,\n ReferenceValue,\n RelatedRecord,\n Value,\n Values,\n} from '@fieldia/core';\nimport type { PreferenceStore } from './preferences';\nimport { formatNumber, normalizeNumber } from './numbers';\nimport type { WidgetLabels } from './labels';\nimport { charTagsWidget, linkCheckboxesWidget, many2oneWidget, referenceWidget, tagsWidget } from './relations';\nimport { linesWidget } from './lines';\nimport { binaryWidget, imageWidget } from './files';\nimport { progressbarWidget } from './progress';\nimport { labelWidget } from './label';\nimport { statusbarWidget } from './statusbar';\nimport { withCalendar } from './calendar';\nimport { propertiesWidget } from './properties';\nimport { htmlWidget, jsonWidget } from './extras';\nimport { matrixWidget } from './matrix';\nimport { signatureWidget } from './signature';\nimport { sliderWidget } from './slider';\nimport { choiceTagsWidget, searchWidget } from './choice-tags';\nimport { imageChoiceWidget } from './choice-images';\nimport { rankingWidget } from './ranking';\nimport { addressWidget } from './address';\nimport { cardsWidget } from './cards';\nimport { clearSelection, fillIn, maker, setAttr, setText, wordsFor } from './kind-parts';\nimport { shownOptions } from './shuffle';\nimport { bounds, counted, grower } from './limits';\nimport { currencySymbol } from './units';\nimport { drawIcon } from './icons';\nimport { listChoices } from './choices-from';\nimport { yesNoWidget } from './yes-no';\nimport { layOut, limiter } from './choice-rules';\n\n/**\n * Field inputs in plain DOM. Each widget builds its element once and then only\n * patches it from state, so typing never loses focus or the caret, and the\n * same widget serves every framework binding.\n */\n\nexport interface WidgetContext {\n form: Form;\n /** The field's name in the page. */\n name: string;\n field: Field;\n node: FieldNode;\n /** The id the field's label points at. */\n id: string;\n document: Document;\n /** Words the widget shows itself, in the page's language. English when left out. */\n labels?: WidgetLabels;\n /** Where to keep a person's choices about how the widget looks, such as a table's columns. */\n preferences?: PreferenceStore;\n /** The page's language: numbers and dates are written as its readers write them. English when left out. */\n locale?: Locale;\n /** Dialogs the page can open: a related record, a searchable list, values to edit. Left out, widgets offer none. */\n dialogs?: WidgetDialogs;\n}\n\n/** What a widget may ask of the page around it in a dialog. The viewer provides these. */\nexport interface WidgetDialogs {\n /** Whether a record of this model can be shown in a dialog: the app gave a page for it. */\n canOpen(model: string): boolean;\n /**\n * A record in a dialog: an existing one (`recordId`) or a new one, whose name\n * starts as `name`. Resolves with the record once saved, or null.\n */\n openRecord(model: string, request: { recordId?: RecordId; name?: string; title: string }): Promise<RelatedRecord | null>;\n /** Pick a record from a searchable list. */\n searchMore(request: { title: string; search(query: string, limit: number): Promise<RelatedRecord[]> }): Promise<RelatedRecord | null>;\n /**\n * Values edited in a form made of these fields. Resolves with the new values,\n * or null. `recompute` recalculates them as they change, as a line's onchange.\n */\n editValues(request: { title: string; fields: Record<string, Field>; values: Values; readonly?: boolean; recompute?: (values: Values) => Promise<Values> }): Promise<Values | null>;\n}\n\nexport interface WidgetState {\n value: Value | undefined;\n /** Every value of the record, for widgets that show one field beside another. */\n values: Readonly<Values>;\n readonly: boolean;\n required: boolean;\n invalid: boolean;\n /** Ids of the help and error text, for assistive technology. */\n describedBy?: string;\n}\n\nexport interface Widget {\n element: HTMLElement;\n update(state: WidgetState): void;\n focus(): void;\n destroy?(): void;\n}\n\nexport type WidgetFactory = (context: WidgetContext) => Widget;\n\n/**\n * Pick the widget for a field: the app's or the built-in one for\n * `type.widget` (such as `selection.radio`), then for the type alone. A type\n * with no editor yet shows its value read-only.\n */\nexport function createWidget(context: WidgetContext, registry: Record<string, WidgetFactory> = {}): Widget {\n const { field, node } = context;\n const keys = [\n node.widget ? `${field.type}.${node.widget}` : null,\n field.type === 'selection' && field.multiple ? 'selection.checkboxes' : null,\n field.type,\n ].filter((key): key is string => key !== null);\n for (const key of keys) {\n const factory = registry[key] ?? builtInWidgets[key];\n // Choices from the app's list: the same widget, drawn again as they load.\n if (factory) return field.type === 'selection' && field.optionsFrom ? listChoices(factory, context) : factory(context);\n }\n return pendingWidget(context);\n}\n\n// ---------------------------------------------------------------------------\n\nfunction make<K extends keyof HTMLElementTagNameMap>(\n doc: Document,\n tag: K,\n props: Partial<Record<string, string>> = {},\n ...children: (Node | string)[]\n): HTMLElementTagNameMap[K] {\n const element = doc.createElement(tag);\n for (const [name, value] of Object.entries(props)) if (value !== undefined) element.setAttribute(name, value);\n element.append(...children);\n return element;\n}\n\nfunction describe(element: HTMLElement, state: WidgetState) {\n setAttr(element, 'aria-invalid', String(state.invalid));\n // ARIA has no \"required\" for a group of checkboxes: its label's mark says it there.\n setAttr(element, 'aria-required', element.getAttribute('role') === 'group' ? null : String(state.required));\n setAttr(element, 'aria-describedby', state.describedBy || null);\n}\n\nconst textOf = (value: Value | undefined) => (value === null || value === undefined ? '' : String(value));\n\nfunction textWidget(inputType: string): WidgetFactory {\n return (context) => {\n const { form, name, field, node, id, document } = context;\n // A person's own email, phone or web address, the browser may offer.\n const input = make(document, 'input', { id, type: inputType, class: 'fd-input', autocomplete: /^(email|tel|url)$/.test(inputType) ? inputType : 'off' });\n if (field.type === 'char' && field.size !== undefined) input.maxLength = field.size;\n if (inputType === 'time') bounds(input, field, node);\n if (node.placeholder) input.placeholder = node.placeholder;\n input.addEventListener('input', () => form.setValue(name, input.value === '' ? null : input.value));\n return counted({\n element: input,\n focus: () => input.focus(),\n update(state) {\n const text = textOf(state.value);\n if (input.value !== text) input.value = text;\n if (input.readOnly !== state.readonly) input.readOnly = state.readonly;\n describe(input, state);\n },\n }, context, input);\n };\n}\n\nconst textareaWidget: WidgetFactory = (context) => {\n const { form, name, field, node, id, document } = context;\n const area = make(document, 'textarea', { id, class: 'fd-input fd-textarea', rows: '3' });\n if (field.type === 'text' && field.size !== undefined) area.maxLength = field.size;\n if (node.placeholder) area.placeholder = node.placeholder;\n const grow = grower(area, node);\n area.addEventListener('input', () => {\n grow();\n form.setValue(name, area.value === '' ? null : area.value);\n });\n return counted({\n element: area,\n focus: () => area.focus(),\n update(state) {\n const text = textOf(state.value);\n if (area.value !== text) {\n area.value = text;\n grow();\n }\n if (area.readOnly !== state.readonly) area.readOnly = state.readonly;\n describe(area, state);\n },\n }, context, area);\n};\n\nconst NUMBER = /^-?(\\d+\\.?\\d*|\\.\\d+)$/;\nconst UNFINISHED = /^-?\\.?$/;\n\n/**\n * Numbers are written as readers of the page's language write them, grouped,\n * with the field's decimals, and read back the same way. What is typed stays\n * as typed while focused: \"1.\" means 1 now and 1.5 a keystroke later. The box\n * keeps its spelling when entered, so a selection made on the way in holds.\n */\nconst numberWidget: WidgetFactory = (context) => {\n const { form, name, field, node, id, document, locale = 'en' } = context;\n const integer = field.type === 'integer';\n const decimals = integer ? 0 : (field.type === 'float' || field.type === 'monetary' ? field.digits?.[1] : undefined) ?? 2;\n const shown = (value: Value | undefined) => (typeof value === 'number' ? formatNumber(value, decimals, locale) : textOf(value));\n const input = make(document, 'input', { id, type: 'text', class: 'fd-input fd-number-input', autocomplete: 'off' });\n input.inputMode = integer ? 'numeric' : 'decimal';\n if (node.placeholder) input.placeholder = node.placeholder;\n\n const parse = (raw: string): Value | undefined => {\n const text = normalizeNumber(raw.trim(), locale);\n if (text === '') return null;\n if (NUMBER.test(text)) return Number(text);\n if (UNFINISHED.test(text)) return undefined; // \"-\" or \".\": keep typing\n return text; // not a number: validation names it\n };\n input.addEventListener('input', () => {\n const value = parse(input.value);\n if (value !== undefined) form.setValue(name, value);\n });\n input.addEventListener('blur', () => {\n input.value = shown(form.getState().values[name]);\n });\n\n // Money shows its currency beside the amount (options.symbol \"after\" puts it\n // after), or with options.pickCurrency the currency field's own widget, to change it.\n const options = node.options ?? {};\n const currencyField = field.type === 'monetary' ? field.currencyField : undefined;\n const currencyDef = currencyField ? form.page.fields[currencyField] : undefined;\n const picker =\n currencyField && currencyDef && options['pickCurrency'] === true\n ? createWidget({ ...context, name: currencyField, field: currencyDef, node: { type: 'field', id: `${node.id}.currency`, field: currencyField }, id: `${id}-currency` })\n : null;\n if (picker && currencyDef) picker.element.querySelector('input, select')?.setAttribute('aria-label', currencyDef.label);\n if (picker?.element.matches('input, select') && currencyDef) picker.element.setAttribute('aria-label', currencyDef.label);\n // Inside the box: the currency where the page's language writes it, unless the page says before or after; a number's unit (options.prefix, options.suffix).\n const after = options['symbol'] ? options['symbol'] === 'after' : field.type === 'monetary' && currencySymbol(field.currency ?? 'USD', locale).after;\n const unit = (text: string, n: number) => make(document, 'span', { class: `fd-unit${field.type === 'monetary' ? ' fd-currency' : ''}`, id: `${id}-unit${n}` }, text);\n const currency = field.type === 'monetary' && !picker ? unit('', 0) : null;\n const [prefix, suffix] = ['prefix', 'suffix'].map((key, n) => (typeof options[key] === 'string' && options[key] ? unit(options[key] as string, n + 1) : null));\n const first = (after ? null : (picker?.element ?? currency)) ?? prefix;\n const last = (after ? (picker?.element ?? currency) : null) ?? suffix;\n const units = [first, last].filter((u): u is HTMLElement => !!u && u !== picker?.element);\n const element =\n first || last\n ? make(document, 'span', { class: `fd-number${after ? ' fd-currency-after' : ''}${picker ? ' fd-currency-picked' : ''}` }, ...[first, input, last].filter((u): u is HTMLElement => !!u))\n : input;\n\n return {\n element,\n focus: () => input.focus(),\n update(state) {\n const typing = document.activeElement === input;\n const parsed = parse(input.value);\n const showsSame = parsed === undefined || parsed === state.value;\n if (!(typing && showsSame)) {\n const text = shown(state.value);\n if (input.value !== text) input.value = text;\n }\n if (input.readOnly !== state.readonly) input.readOnly = state.readonly;\n describe(input, { ...state, describedBy: [state.describedBy, ...units.map((u) => u.id)].filter(Boolean).join(' ') });\n if (picker && currencyField) {\n picker.update({ value: state.values[currencyField], values: state.values, readonly: state.readonly, required: false, invalid: false });\n }\n if (currency && field.type === 'monetary') {\n const holder = field.currencyField ? state.values[field.currencyField] : null;\n const code = holder && typeof holder === 'object' && 'label' in holder ? (holder as RelatedRecord).label : (typeof holder === 'string' ? holder : field.currency ?? '');\n setText(currency, /^[A-Z]{3}$/.test(code) ? currencySymbol(code, locale).text : code);\n }\n // Room in the box for its units, as wide as their words.\n for (const [u, side] of [[first, 'start'], [last, 'end']] as const) if (u && units.includes(u)) input.style.setProperty(`padding-inline-${side}`, `calc(var(--fd-pad-x) + ${u.textContent?.length ?? 0}ch + 4px)`);\n },\n };\n};\n\n/** A box to tick: plain under its label, a switch, or a tick box with its words after it (the viewer puts them there). */\nfunction checkboxWidget(look: 'box' | 'switch' | 'tick' = 'box'): WidgetFactory {\n const attrs = look === 'switch' ? { class: 'fd-switch', role: 'switch' } : { class: look === 'tick' ? 'fd-checkbox fd-tick' : 'fd-checkbox' };\n return ({ form, name, id, document }) => {\n const box = make(document, 'input', { id, type: 'checkbox', ...attrs });\n box.addEventListener('change', () => form.setValue(name, box.checked));\n return {\n element: box,\n focus: () => box.focus(),\n update(state) {\n box.checked = state.value === true;\n if (box.disabled !== state.readonly) box.disabled = state.readonly;\n describe(box, state);\n },\n };\n };\n}\n\nfunction options(field: Field) {\n return field.type === 'selection' ? field.options : [];\n}\n\nconst selectWidget: WidgetFactory = (context) => {\n const { form, name, field, node, id, document } = context;\n // A long list, or one the page asks to: a box to type in, its options found as one types.\n const search = node.options?.['search'];\n if (search === true || (search !== false && options(field).length > 15)) return searchWidget(context);\n const choices = shownOptions(options(field), form, name, node);\n const select = make(document, 'select', { id, class: 'fd-input fd-select' }, make(document, 'option', { value: '' }));\n choices.forEach((option, i) => select.append(make(document, 'option', { value: String(i) }, option.label)));\n select.addEventListener('change', () => form.setValue(name, select.value === '' ? null : choices[Number(select.value)].value));\n return {\n element: select,\n focus: () => select.focus(),\n update(state) {\n const index = choices.findIndex((option) => option.value === state.value);\n select.value = index === -1 ? '' : String(index);\n if (select.disabled !== state.readonly) select.disabled = state.readonly;\n describe(select, state);\n },\n };\n};\n\nfunction choiceGroup(kind: 'radio' | 'checkbox'): WidgetFactory {\n return ({ form, name, field, node, id, document, labels, locale }) => {\n // Shown shuffled when the page asks; \"Other\" comes after them all the same.\n const choices = shownOptions(options(field), form, name, node);\n const words = wordsFor(labels, locale);\n const group = make(document, 'div', { id, class: `fd-choices fd-choices-${kind}`, role: kind === 'radio' ? 'radiogroup' : 'group' });\n layOut(group, node);\n const limit = kind === 'checkbox' ? limiter(maker(document), words, node) : null;\n const inputs = choices.map((option, i) => {\n const input = make(document, 'input', { type: kind, name: id, value: String(i), id: `${id}-${i}` });\n group.append(make(document, 'label', { class: 'fd-choice', for: `${id}-${i}` }, input, make(document, 'span', {}, option.label)));\n return input;\n });\n // \"Other:\", after the options: a choice of its own, with a box for the answer \u2014 as Google Forms has it.\n const other = field.type === 'selection' && field.other === true;\n const otherChoice = other ? make(document, 'input', { type: kind, name: id, value: 'other', id: `${id}-other` }) : null;\n const otherBox = other ? make(document, 'input', { type: 'text', class: 'fd-input fd-other-input', 'aria-label': words.otherAnswer, autocomplete: 'off' }) : null;\n if (otherChoice && otherBox) {\n group.append(make(document, 'div', { class: 'fd-choice fd-choice-other' }, make(document, 'label', { class: 'fd-choice-other-pick', for: `${id}-other` }, otherChoice, make(document, 'span', {}, words.other)), otherBox));\n // Typing picks \"Other\"; picking \"Other\" puts the cursor in its box.\n otherBox.addEventListener('input', () => {\n if (!otherChoice.checked) otherChoice.checked = true;\n save(otherChoice);\n });\n otherChoice.addEventListener('change', () => {\n if (otherChoice.checked) otherBox.focus();\n });\n }\n if (limit?.element) group.append(limit.element);\n /** The answer the boxes say now: the options picked, and the words of \"Other\" when it is picked and has any. */\n function save(ticked?: EventTarget | null) {\n // \"None of these\" goes alone: ticked, it unticks the rest; another ticked unticks it.\n if (kind === 'checkbox' && ticked instanceof HTMLInputElement && ticked.checked) {\n const alone = choices[inputs.indexOf(ticked)]?.exclusive === true;\n inputs.forEach((input, i) => input !== ticked && (alone || choices[i].exclusive) && (input.checked = false));\n if (alone && otherChoice) otherChoice.checked = false;\n }\n const own = otherChoice?.checked && otherBox && otherBox.value.trim() ? otherBox.value : null;\n if (kind === 'radio') {\n const chosen = inputs.findIndex((input) => input.checked);\n form.setValue(name, chosen !== -1 ? choices[chosen].value : own);\n } else {\n // In the options' own order, however they are shown.\n const ticked = new Set(choices.filter((_, i) => inputs[i].checked));\n form.setValue(name, [...options(field).filter((option) => ticked.has(option)).map((option) => option.value), ...(own !== null ? [own] : [])]);\n }\n }\n group.addEventListener('change', (event) => {\n if (event.target !== otherBox) save(event.target);\n });\n const known = new Set(choices.map((o) => o.value as unknown));\n const picked = () => inputs.some((input) => input.checked) || otherChoice?.checked === true;\n const clear =\n kind === 'radio'\n ? clearSelection(document, words, () => {\n for (const input of [...inputs, otherChoice]) if (input) input.checked = false;\n form.setValue(name, null);\n // The link goes; the cursor stays in the question.\n (inputs[0] ?? otherChoice)?.focus();\n })\n : null;\n return {\n element: clear ? make(document, 'div', { class: 'fd-choices-box' }, group, clear.button) : group,\n focus: () => (inputs.find((input) => input.checked) ?? (otherChoice?.checked ? otherBox : null) ?? inputs[0])?.focus(),\n update(state) {\n const chosen = Array.isArray(state.value) ? state.value : [state.value];\n // At the most a question takes, the boxes not ticked wait; \"None of these\" stays open.\n const full = !!limit?.full(Array.isArray(state.value) ? state.value.length : 0);\n inputs.forEach((input, i) => {\n input.checked = chosen.includes(choices[i].value as never);\n const off = state.readonly || (full && !input.checked && !choices[i].exclusive);\n if (input.disabled !== off) input.disabled = off;\n });\n if (otherChoice && otherBox) {\n // A value not among the options is an answer of its own: \"Other\", with its words.\n const own = chosen.find((v) => typeof v === 'string' && !known.has(v));\n // Picked with its box still empty, \"Other\" stays picked until something else is.\n const waiting = otherChoice.checked && !otherBox.value.trim() && (kind === 'checkbox' || chosen.every((v) => v === null || v === undefined));\n otherChoice.checked = own !== undefined || waiting;\n if (own !== undefined && document.activeElement !== otherBox) otherBox.value = own as string;\n const off = state.readonly || (full && !otherChoice.checked);\n if (otherChoice.disabled !== off) otherChoice.disabled = otherBox.disabled = off;\n }\n clear?.allow(state);\n clear?.show(picked());\n describe(group, state);\n },\n };\n };\n}\n\n/**\n * Stars or numbers to pick from, as a radio group with arrow-key support. A\n * rating shows `options.icon`: stars, \"heart\", \"thumb\" up, or \"number\"s that\n * mark only the one picked, as a scale's do.\n */\nfunction pointsWidget(style: 'rating' | 'scale'): WidgetFactory {\n return ({ form, name, field, node, id, document, labels, locale }) => {\n const words = wordsFor(labels, locale);\n const min = 'min' in field && typeof field.min === 'number' ? field.min : style === 'rating' ? 1 : 0;\n const max = 'max' in field && typeof field.max === 'number' ? field.max : style === 'rating' ? 5 : 10;\n const icon = style === 'rating' ? node.options?.['icon'] : 'number';\n const filling = icon !== 'number';\n // A 0\u201310 scale coloured as NPS (options.nps): 0\u20136, 7\u20138 and 9\u201310 apart, in red, amber and green.\n const nps = style === 'scale' && node.options?.['nps'] === true && min === 0 && max === 10;\n const group = make(document, 'div', { id, class: `fd-points fd-${filling ? 'rating' : 'scale'}${filling ? ` fd-rating-${icon ?? 'star'}` : ''}${nps ? ' fd-nps' : ''}`, role: 'radiogroup' });\n const points: HTMLButtonElement[] = [];\n for (let n = min; n <= max; n++) {\n const point = make(document, 'button', { type: 'button', role: 'radio', 'aria-label': fillIn(words.ofMax, { n, max }), 'data-value': String(n) }, icon === 'thumb' ? (drawIcon(document, 'thumb') as SVGSVGElement) : icon === 'heart' ? '\u2665' : filling ? '\u2605' : String(n));\n if (style === 'scale') point.removeAttribute('aria-label');\n if (nps) point.dataset['tone'] = n < 7 ? 'low' : n < 9 ? 'mid' : 'high';\n point.addEventListener('click', () => form.setValue(name, n));\n points.push(point);\n group.append(point);\n }\n group.addEventListener('keydown', (event) => {\n const current = form.getState().values[name];\n const value = typeof current === 'number' ? current : min - 1;\n const step = event.key === 'ArrowRight' || event.key === 'ArrowUp' ? 1 : event.key === 'ArrowLeft' || event.key === 'ArrowDown' ? -1 : 0;\n if (!step) return;\n event.preventDefault();\n const next = Math.min(max, Math.max(min, value + step));\n form.setValue(name, next);\n points[next - min]?.focus();\n });\n // The ends in words, under the first and last points: \"Not likely\" \u2026 \"Very likely\".\n const ends = [node.options?.['startLabel'], node.options?.['endLabel']].map((v) => (typeof v === 'string' ? v : ''));\n const clear = clearSelection(document, words, () => {\n form.setValue(name, null);\n points[0]?.focus();\n });\n const shown = ends.some(Boolean)\n ? make(document, 'div', { class: 'fd-scale-box' }, group, make(document, 'div', { class: 'fd-scale-ends', 'aria-hidden': 'true' }, make(document, 'span', {}, ends[0]), make(document, 'span', {}, ends[1])))\n : group;\n if (ends.some(Boolean)) group.setAttribute('aria-description', ends.filter(Boolean).join(' \u2026 '));\n return {\n element: make(document, 'div', { class: 'fd-choices-box' }, shown, clear.button),\n focus: () => (points.find((p) => p.getAttribute('aria-checked') === 'true') ?? points[0])?.focus(),\n update(state) {\n const value = typeof state.value === 'number' ? state.value : null;\n points.forEach((point, i) => {\n const n = min + i;\n setAttr(point, 'aria-checked', String(n === value));\n point.classList.toggle('fd-on', filling ? value !== null && n <= value : n === value);\n const tab = n === value || (value === null && i === 0) ? 0 : -1;\n if (point.tabIndex !== tab) point.tabIndex = tab;\n if (point.disabled !== state.readonly) point.disabled = state.readonly;\n });\n clear.allow(state);\n clear.show(value !== null);\n describe(group, state);\n },\n };\n };\n}\n\nconst dateWidget: WidgetFactory = (context) => {\n const { form, name, field, id, document, node } = context;\n const input = make(document, 'input', { id, type: 'date', class: 'fd-input fd-date' });\n bounds(input, field, node);\n input.addEventListener('input', () => form.setValue(name, input.value || null));\n const widget: Widget = {\n element: input,\n focus: () => input.focus(),\n update(state) {\n const text = textOf(state.value);\n if (input.value !== text) input.value = text;\n if (input.readOnly !== state.readonly) input.readOnly = state.readonly;\n describe(input, state);\n },\n };\n return node.options?.['weekNumbers'] === true ? withCalendar(widget, context, 'date') : widget;\n};\n\nconst pad = (n: number) => String(n).padStart(2, '0');\n\n/** Shown in local time, stored as an ISO instant in UTC. */\nconst dateTimeWidget: WidgetFactory = (context) => {\n const { form, name, field, id, document, node } = context;\n const input = make(document, 'input', { id, type: 'datetime-local', class: 'fd-input fd-datetime' });\n bounds(input, field, node);\n const local = (iso: Value | undefined) => {\n if (typeof iso !== 'string' || !iso) return '';\n const d = new Date(iso);\n return Number.isNaN(d.getTime()) ? '' : `${d.getFullYear()}-${pad(d.getMonth() + 1)}-${pad(d.getDate())}T${pad(d.getHours())}:${pad(d.getMinutes())}`;\n };\n input.addEventListener('input', () => {\n if (!input.value) return form.setValue(name, null);\n const d = new Date(input.value);\n if (!Number.isNaN(d.getTime())) form.setValue(name, d.toISOString());\n });\n const widget: Widget = {\n element: input,\n focus: () => input.focus(),\n update(state) {\n const text = local(state.value);\n if (input.value !== text) input.value = text;\n if (input.readOnly !== state.readonly) input.readOnly = state.readonly;\n describe(input, state);\n },\n };\n return node.options?.['weekNumbers'] === true ? withCalendar(widget, context, 'datetime') : widget;\n};\n\n/** Until a type has its own editor (Phase 5), show what it holds. */\nfunction pendingWidget({ field, id, document }: WidgetContext): Widget {\n const span = make(document, 'span', { id, class: 'fd-pending', 'data-fd-pending': field.type });\n return {\n element: span,\n focus: () => undefined,\n update(state) {\n span.textContent = summary(state.value, field);\n },\n };\n}\n\nexport function summary(value: Value | undefined, field: Field): string {\n if (value === null || value === undefined) return '';\n switch (field.type) {\n case 'many2one':\n case 'reference':\n return (value as RelatedRecord | ReferenceValue).label;\n case 'many2many':\n return (value as RelatedRecord[]).map((record) => record.label).join(', ');\n case 'one2many': {\n const count = (value as Line[]).length;\n return `${count} ${count === 1 ? 'line' : 'lines'}`;\n }\n case 'binary':\n case 'image':\n return [value as FileValue | FileValue[]].flat().map((file) => file.name).join(', ');\n case 'html':\n return String(value).replace(/<[^>]*>/g, ' ').replace(/\\s+/g, ' ').trim();\n default:\n return typeof value === 'object' ? JSON.stringify(value) : String(value);\n }\n}\n\nexport const builtInWidgets: Record<string, WidgetFactory> = {\n char: textWidget('text'),\n 'char.email': textWidget('email'),\n 'char.phone': textWidget('tel'),\n 'char.url': textWidget('url'),\n 'char.password': textWidget('password'),\n 'char.time': textWidget('time'),\n 'char.tags': charTagsWidget,\n text: textareaWidget,\n integer: numberWidget,\n float: numberWidget,\n monetary: numberWidget,\n 'integer.rating': pointsWidget('rating'),\n 'integer.scale': pointsWidget('scale'),\n 'integer.slider': sliderWidget,\n 'float.slider': sliderWidget,\n 'integer.progressbar': progressbarWidget,\n 'integer.label': labelWidget,\n 'float.label': labelWidget,\n 'monetary.label': labelWidget,\n 'float.progressbar': progressbarWidget,\n 'monetary.progressbar': progressbarWidget,\n boolean: checkboxWidget(),\n 'boolean.toggle': checkboxWidget('switch'),\n 'boolean.tick': checkboxWidget('tick'),\n 'boolean.buttons': yesNoWidget,\n selection: selectWidget,\n 'selection.radio': choiceGroup('radio'),\n 'selection.checkboxes': choiceGroup('checkbox'),\n 'selection.tags': choiceTagsWidget,\n 'selection.image-choice': imageChoiceWidget,\n 'selection.ranking': rankingWidget,\n 'selection.statusbar': statusbarWidget,\n date: dateWidget,\n datetime: dateTimeWidget,\n many2one: many2oneWidget,\n 'many2one.statusbar': statusbarWidget,\n many2many: tagsWidget,\n 'many2many.tags': tagsWidget,\n 'many2many.checkboxes': linkCheckboxesWidget,\n reference: referenceWidget,\n one2many: linesWidget,\n 'one2many.cards': cardsWidget,\n binary: binaryWidget,\n 'binary.signature': signatureWidget,\n image: imageWidget,\n html: htmlWidget,\n json: jsonWidget,\n 'json.address': addressWidget,\n properties: propertiesWidget,\n matrix: matrixWidget,\n};\n", "/**\n * The question kinds' part of the stylesheet: a signature pad, a slider, tags\n * from a list, pictures to choose from, a ranking, an address and a repeating\n * group of cards. Appended to Fieldia's stylesheet, scoped and written with\n * logical properties as the rest of it is.\n */\nexport const KINDS_CSS = /* css */ `.fd-signature{display:grid;gap:8px;justify-items:start;width:100%;max-width:480px;min-width:0}.fd-signature-box{position:relative;width:100%;aspect-ratio:10 / 3;border:1px dashed var(--fd-border-strong);border-radius:var(--fd-control-radius);background:#fff;overflow:hidden}.fd-signature-box:has(.fd-signature-pad:not([hidden]):not(.fd-signature-locked)):hover{border-color:var(--fd-accent)}.fd-signature-pad,.fd-signature-image{display:block;width:100%;height:100%}.fd-signature-pad{touch-action:none;cursor:crosshair}.fd-signature-pad.fd-signature-locked{cursor:default}.fd-signature-image{object-fit:contain}.fd-signature-hint{position:absolute;inset-inline:18px;inset-block-end:16px;padding-block-start:4px;pointer-events:none;border-block-start:1px solid var(--fd-border-strong);color:var(--fd-muted);font-size:12.5px}.fd-signature-tools{display:flex;flex-wrap:wrap;gap:8px 12px;align-items:center;width:100%}.fd-signature-typed{flex:1 1 200px;min-width:0}.fd-signature-footer{margin-block-start:-4px;color:var(--fd-muted);font-size:12.5px}.fd-slider{display:grid;grid-template-columns:minmax(0,1fr) auto;column-gap:14px;row-gap:0;align-items:center;width:100%;max-width:440px;min-width:0}.fd-slider-track{display:contents}.fd-slider-input{width:100%;min-width:0;height:26px;margin:0;accent-color:var(--fd-accent);cursor:pointer}.fd-slider-input:disabled{cursor:default}.fd-slider-value{min-width:2.5em;text-align:start;font-variant-numeric:tabular-nums;font-weight:600}.fd-slider-ends{grid-column:1;display:flex;justify-content:space-between;gap:12px;font-size:12.5px;color:var(--fd-muted);font-variant-numeric:tabular-nums}.fd-slider-empty .fd-slider-input{filter:grayscale(1);opacity:.55}.fd-slider-empty .fd-slider-value{color:var(--fd-muted);font-weight:400}.fd-slider .fd-choice-clear{grid-column:1 / -1}.fd-image-choices{display:grid;grid-template-columns:repeat(auto-fill,minmax(min(100%,130px),1fr));gap:12px;width:100%;min-width:0}.fd-image-card{position:relative;display:grid;grid-template-rows:auto 1fr;padding:0;margin:0;overflow:hidden;cursor:pointer;font:inherit;color:var(--fd-text);text-align:start;background:var(--fd-surface);border:1px solid var(--fd-border);border-radius:max(var(--fd-control-radius),6px);transition:border-color .15s ease,box-shadow .15s ease}.fd-image-card:hover:not(:disabled){border-color:var(--fd-accent)}.fd-image-card:disabled{cursor:default}.fd-image-card:disabled:not([aria-checked=true]){opacity:.6}.fd-image-card[aria-checked=true]{border-color:var(--fd-accent);box-shadow:0 0 0 1px var(--fd-accent)}.fd-image-card-picture{display:block;aspect-ratio:4 / 3;background:var(--fd-page);border-block-end:1px solid var(--fd-border)}.fd-image-card-picture img{display:block;width:100%;height:100%;object-fit:cover}.fd-image-card-blank{display:grid;place-items:center;width:100%;height:100%;color:var(--fd-border-strong)}.fd-image-card-blank svg{width:36%;height:36%;fill:none;stroke:currentColor;stroke-width:1.5;stroke-linecap:round;stroke-linejoin:round}.fd-image-card-words{display:flex;align-items:flex-start;gap:8px;padding:9px 10px;font-size:13.5px;line-height:1.35}.fd-image-card-words:before{content:\"\";flex:none;width:16px;height:16px;margin-block-start:1px;box-sizing:border-box;border:1.5px solid var(--fd-border-strong);border-radius:50%;background:var(--fd-surface)}.fd-image-card[role=checkbox] .fd-image-card-words:before{border-radius:4px}.fd-image-card[aria-checked=true] .fd-image-card-words:before{border-color:var(--fd-accent);background:var(--fd-accent);box-shadow:inset 0 0 0 3px var(--fd-surface)}.fd-image-card[role=checkbox][aria-checked=true] .fd-image-card-words:before{box-shadow:none;background:var(--fd-accent) url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3E%3Cpath d='M3.5 8.5l3 3 6-7' fill='none' stroke='white' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E\") center / 13px no-repeat}.fd-image-choices+.fd-choice-clear{justify-self:end}.fd-ranking{width:100%;max-width:480px;min-width:0}.fd-rank-list{list-style:none;margin:0;padding:0;display:grid;gap:6px}.fd-rank-item{display:flex;align-items:center;gap:10px;padding-block:5px;padding-inline:8px 5px;min-height:40px;background:var(--fd-surface);border:1px solid var(--fd-border);border-radius:var(--fd-control-radius);cursor:grab;user-select:none;-webkit-user-select:none}.fd-rank-item.fd-rank-lifted{position:relative;z-index:1;cursor:grabbing;border-color:var(--fd-accent);box-shadow:0 6px 18px #0f141929}.fd-ranking-locked .fd-rank-item{cursor:default}.fd-rank-grip{flex:none;width:10px;height:16px;touch-action:none;background:radial-gradient(circle,var(--fd-border-strong) 1.3px,transparent 1.7px) 0 0 / 5px 5.33px}.fd-ranking-locked .fd-rank-grip{visibility:hidden}.fd-rank-place{flex:none;display:grid;place-items:center;min-width:24px;height:24px;padding-inline:4px;border-radius:999px;background:var(--fd-accent-soft);color:var(--fd-accent);font-size:12.5px;font-weight:600;font-variant-numeric:tabular-nums}.fd-rank-words{flex:1;min-width:0;overflow-wrap:anywhere}.fd-rank-tools{flex:none;display:inline-flex;gap:2px}.fd-rank-move{width:30px;height:30px;padding:0;font:inherit;font-size:15px;line-height:1;color:var(--fd-muted);background:none;border:1px solid transparent;border-radius:4px;cursor:pointer}.fd-rank-move:hover:not(:disabled){background:var(--fd-page);border-color:var(--fd-border);color:var(--fd-text)}.fd-rank-move:disabled{opacity:.3;cursor:default}.fd-address{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:10px 12px;width:100%;max-width:560px;min-width:0}.fd-address-part{display:grid;gap:3px;min-width:0;align-content:start}.fd-address-street,.fd-address-line2{grid-column:1 / -1}.fd-address-part.fd-required>.fd-address-label:after{content:\" *\";color:var(--fd-error)}.fd-address-label{font-size:12.5px;color:var(--fd-muted)}@container (max-width: 420px){.fd-address{grid-template-columns:minmax(0,1fr)}}.fd-repeat{display:grid;gap:10px;justify-items:start;width:100%;min-width:0}.fd-repeat-list{display:grid;gap:10px;width:100%;min-width:0}.fd-repeat-list:empty{display:none}.fd-repeat-card{display:grid;gap:8px;min-width:0;padding:10px 14px 14px;background:var(--fd-surface);border:1px solid var(--fd-border);border-radius:max(var(--fd-radius),6px)}.fd-repeat-head{display:flex;align-items:center;gap:2px;min-height:28px}.fd-repeat-title{font-weight:600;font-size:13.5px;margin-inline-end:auto}.fd-repeat-remove,.fd-repeat-tool{border:none;background:none;cursor:pointer;color:var(--fd-muted);font-size:18px;line-height:1;padding:4px 8px;border-radius:4px}.fd-repeat-remove:hover{color:var(--fd-error);background:var(--fd-error-soft)}.fd-repeat-tool{font-size:15px}.fd-repeat-tool:hover{color:var(--fd-accent);background:var(--fd-accent-soft)}.fd-repeat-fields{display:grid;grid-template-columns:repeat(auto-fit,minmax(min(100%,200px),1fr));gap:10px 14px}.fd-repeat-field{display:grid;gap:3px;min-width:0;align-content:start}.fd-repeat-label{font-size:12.5px;color:var(--fd-muted)}.fd-repeat-add{border-style:dashed}`;\n", "/**\n * The choice kinds' details: options in columns or in a row, the words that\n * say a limit is reached, pictures' sizes and fit, a ranking's top few, and a\n * matrix whose rows become cards on a phone. A yes or no takes the points'\n * look. Appended to Fieldia's stylesheet, with logical properties.\n */\nexport const CHOICES_CSS = /* css */ `.fd-yes-no button{min-width:76px}.fd-choices-columns{display:grid;grid-template-columns:repeat(var(--fd-choice-columns),minmax(0,1fr))}.fd-choices-row{grid-template-columns:none;grid-auto-flow:column;grid-auto-columns:minmax(0,1fr)}.fd-choice-limit{grid-column:1 / -1;flex-basis:100%;font-size:12.5px;color:var(--fd-muted)}.fd-choice-limit:empty{display:none}.fd-image-choices[data-size=small]{--fd-card: 96px}.fd-image-choices[data-size=large]{--fd-card: 210px}.fd-image-choices[data-size]{grid-template-columns:repeat(auto-fill,minmax(min(100%,var(--fd-card, 130px)),1fr))}.fd-image-choices[data-fit=whole] img{object-fit:contain}.fd-image-choices-bare .fd-image-card-words{position:absolute;inset-block-start:6px;inset-inline-start:6px;padding:0;font-size:0}.fd-choice-search .fd-combo:after{content:\"\";position:absolute;inset-inline-end:12px;width:6px;height:6px;margin-block-start:-4px;pointer-events:none;border:solid var(--fd-muted);border-width:0 1.5px 1.5px 0;transform:rotate(45deg)}.fd-rank-pool{display:flex;flex-wrap:wrap;gap:8px;margin-block:6px 10px}.fd-rank-pick{min-height:32px;padding:4px 12px;font:inherit;color:inherit;cursor:pointer;background:var(--fd-surface);border:1px dashed var(--fd-border-strong);border-radius:999px}.fd-rank-pick:disabled{opacity:.5;cursor:default}.fd-rank-list:empty{display:none}.fd-rank-keep{margin-block-start:8px}.fd-matrix-pick{display:inline-flex;align-items:center;gap:8px}.fd-matrix-column{display:none}@container (max-width: 520px){.fd-choices-columns{grid-template-columns:minmax(0,1fr)}.fd-image-choices.fd-image-choices{grid-auto-flow:row;grid-template-columns:repeat(auto-fill,minmax(min(100%,130px),1fr))}.fd-matrix-table,.fd-matrix-table :is(tbody,tr,th,td){display:block}.fd-matrix-table thead{display:none}.fd-matrix-table tr{padding:10px 12px;margin-block-end:10px;border:1px solid var(--fd-border);border-radius:var(--fd-radius)}.fd-matrix-table :is(th,td){padding:2px 0;border:0;text-align:start}.fd-matrix-pick{min-height:32px}.fd-matrix-column{display:inline}}`;\n", "/**\n * The text, number and date inputs' part of the stylesheet: a count of\n * characters under a box, a number's unit and an amount's currency inside\n * its box, a rating's hearts and thumbs, words at a slider's ends, an NPS\n * scale's colours. Scoped\n * and written with logical properties as the rest of it is; it comes before\n * the question kinds' part.\n */\nexport const INPUTS_CSS = /* css */ `.fd-counted{display:grid;gap:2px;min-width:0}.fd-count{justify-self:end;direction:ltr;unicode-bidi:isolate;font-size:12px;color:var(--fd-muted);font-variant-numeric:tabular-nums}.fd-count-near{color:var(--fd-warning);font-weight:600}.fd-number:not(.fd-currency-picked){position:relative;display:block}.fd-number>.fd-unit{position:absolute;inset-block:0;display:flex;align-items:center;pointer-events:none;color:var(--fd-muted)}.fd-number>.fd-unit:first-child{inset-inline-start:var(--fd-pad-x)}.fd-number>.fd-unit:last-child{inset-inline-end:var(--fd-pad-x)}.fd-rating-heart button.fd-on{color:#e5484d}.fd-rating-thumb button.fd-on{color:var(--fd-accent)}.fd-rating .fd-icon{display:block;width:1em;height:1em}.fd-rating .fd-on .fd-icon{fill:currentColor}.fd-slider-word{display:block;max-width:12em}.fd-slider-last{text-align:end}.fd-nps [data-tone=low]{--fd-tone: var(--fd-error);--fd-tone-soft: var(--fd-error-soft)}.fd-nps [data-tone=mid]{--fd-tone: var(--fd-warning);--fd-tone-soft: var(--fd-warning-soft)}.fd-nps [data-tone=high]{--fd-tone: var(--fd-success);--fd-tone-soft: var(--fd-success-soft)}.fd-nps button{background:var(--fd-tone-soft);border-color:var(--fd-tone);color:var(--fd-tone);font-weight:600}.fd-nps button.fd-on{background:var(--fd-tone);border-color:var(--fd-tone);color:var(--fd-surface)}.fd-nps [data-value=\"7\"],.fd-nps [data-value=\"9\"]{margin-inline-start:8px}.fd-choices-box>.fd-scale-box{justify-self:start}`;\n", "/**\n * The layout on top of the skins: arrangements on their grid's columns, how\n * each group is drawn, where labels sit, and the page's own look \u2014 accent,\n * font, room, corners, light or dark. The viewer hands these over as\n * attributes and tokens on the form (see `place.ts` and `look.ts` in\n * @fieldia/viewer); this stylesheet comes after the skins, so it wins where it\n * speaks and leaves everything else as the skin draws it.\n *\n * Logical properties throughout, so right to left mirrors on its own.\n */\nexport const LAYOUT_CSS = /* css */ `.fd-grid>.fd-section[data-place=tracks]{--fd-tracks: min(var(--fd-span, 1), var(--fd-cols));grid-template-columns:subgrid;column-gap:var(--fd-gap-x)}.fd-form .fd-section[data-place=tracks]>.fd-grid{--fd-cols: var(--fd-tracks);grid-column:1 / -1;grid-template-columns:subgrid}.fd-section[data-place]>.fd-section-description{grid-column:1 / -1}.fd-grid>.fd-section[data-place=shared]{container-type:inline-size}.fd-form .fd-section[data-place=shared]>.fd-grid{--fd-cols: var(--fd-columns, 1)}@container (max-width: 330px){.fd-form .fd-section[data-place=shared]>.fd-grid{--fd-cols: 1}}.fd-form{--fd-ground: transparent}.fd-card,.fd-form[data-fd-skin=outlined] .fd-section[data-style=card][data-on-page]{--fd-ground: var(--fd-surface)}fieldset.fd-section[data-style]{background-color:var(--fd-ground)}.fd-form .fd-section[data-style=line]>.fd-section-title{border-block-end:1px solid var(--fd-border);padding-block-end:8px}.fd-form .fd-section[data-style=plain]>.fd-section-title{border-block-end:0;padding-block-end:0}.fd-form .fd-section[data-style=framed]{border:1px solid var(--fd-border);border-radius:var(--fd-control-radius);padding:6px 18px 18px}.fd-form .fd-section[data-style=framed]>.fd-section-title{float:none;width:auto;max-width:100%;padding:0 6px;margin-inline-start:-6px;border:0}.fd-form .fd-field[data-labels]{grid-template-columns:minmax(0,1fr)}.fd-form .fd-field[data-labels]>*{grid-column:1 / -1}.fd-form .fd-field[data-labels=beside]{container-type:inline-size;grid-template-columns:minmax(0,var(--fd-label-width, 140px)) minmax(0,1fr);column-gap:14px}@container (min-width: 300px){.fd-form .fd-field[data-labels=beside]>.fd-label{grid-column:1;align-self:start;padding-block-start:max(0px,calc((var(--fd-control-height, 30px) - 1.45em) / 2))}.fd-form .fd-field[data-labels=beside]>:not(.fd-label){grid-column:2}}.fd-form .fd-field[data-labels=hidden]>.fd-label{position:absolute;width:1px;height:1px;padding:0;overflow:hidden;clip:rect(0 0 0 0);white-space:nowrap}.fd-form .fd-field[data-labels=after]{grid-template-columns:auto minmax(0,1fr);column-gap:9px;align-items:start;--fd-tick-drop: max(0px, calc((var(--fd-control-height, 30px) - 1.45em) / 2))}.fd-form .fd-field[data-labels=after]>:is(.fd-tick,:has(>.fd-tick)){grid-column:1;grid-row:1;display:flex;margin-block-start:calc(var(--fd-tick-drop) + (1.45em - 17px) / 2)}.fd-form .fd-field[data-labels=after] .fd-tick{width:17px;height:17px}.fd-form .fd-field[data-labels=after]>:not(.fd-tick,:has(>.fd-tick)){grid-column:2}.fd-form .fd-field[data-labels=after]>.fd-label{grid-row:1;margin-block-start:var(--fd-tick-drop);font-weight:inherit;line-height:1.45;cursor:pointer}.fd-form .fd-field[data-labels=beside]:focus-within,.fd-grid>.fd-section[data-place=shared]:focus-within{z-index:3}:is(.fd-grid,.fd-sections)>.fd-button{justify-self:start}.fd-form .fd-text-note{background:color-mix(in srgb,var(--fd-text) 6%,transparent);color:var(--fd-text);border-radius:var(--fd-control-radius, 6px);padding:10px 12px}:is(.fd-form,.fd-form-dialog)[data-font=serif]{--fd-font: \"Source Serif 4\", Georgia, serif}:is(.fd-form,.fd-form-dialog)[data-font=rounded]{--fd-font: Nunito, \"Varela Round\", system-ui}:is(.fd-form,.fd-form-dialog)[data-density=compact]{--fd-gap-y: 10px;--fd-gap-x: 16px;--fd-control-height: 30px;--fd-gap-block: 16px;--fd-group-pad: 14px 16px}:is(.fd-form,.fd-form-dialog)[data-density=comfortable]{--fd-gap-y: 16px;--fd-gap-x: 20px;--fd-control-height: 36px;--fd-gap-block: 22px;--fd-group-pad: 18px 22px}:is(.fd-form,.fd-form-dialog)[data-density=roomy]{--fd-gap-y: 22px;--fd-gap-x: 28px;--fd-control-height: 42px;--fd-gap-block: 30px;--fd-group-pad: 24px 30px}:is(.fd-form,.fd-form-dialog)[data-corners=square]{--fd-radius: 0px;--fd-control-radius: 0px}:is(.fd-form,.fd-form-dialog)[data-corners=soft]{--fd-radius: 10px;--fd-control-radius: 6px}:is(.fd-form,.fd-form-dialog)[data-corners=round]{--fd-radius: 16px;--fd-control-radius: 12px}.fd-form[data-scheme]{color-scheme:light;background:var(--fd-page);color:var(--fd-text);border-radius:var(--fd-radius);--fd-ground: var(--fd-page)}.fd-form[data-scheme]>.fd-content:not(:has(>.fd-sheet-page)){padding:20px}.fd-form-dialog-body>.fd-form[data-scheme]{background:none;border-radius:0}.fd-form-dialog-body>.fd-form[data-scheme]>.fd-content:not(:has(>.fd-sheet-page)){padding:0}:is(.fd-form,.fd-form-dialog)[data-scheme=dark]{color-scheme:dark;--fd-text: #e8eaed;--fd-muted: #a3a9b2;--fd-page: #16191e;--fd-surface: #1f2329;--fd-border: #3a4048;--fd-border-strong: #59616c;--fd-accent: #5aa2ff;--fd-accent-text: #0b1220;--fd-accent-soft: rgba(90, 162, 255, .16);--fd-focus: #5aa2ff;--fd-error: #ff8a7a;--fd-error-soft: rgba(255, 138, 122, .13);--fd-success: #6fd08e;--fd-success-soft: rgba(111, 208, 142, .14);--fd-warning: #f2b55c;--fd-warning-soft: rgba(242, 181, 92, .13);--fd-info: #7db7ff;--fd-info-soft: rgba(90, 162, 255, .14)}@media(prefers-color-scheme:dark){:is(.fd-form,.fd-form-dialog)[data-scheme=auto]{color-scheme:dark;--fd-text: #e8eaed;--fd-muted: #a3a9b2;--fd-page: #16191e;--fd-surface: #1f2329;--fd-border: #3a4048;--fd-border-strong: #59616c;--fd-accent: #5aa2ff;--fd-accent-text: #0b1220;--fd-accent-soft: rgba(90, 162, 255, .16);--fd-focus: #5aa2ff;--fd-error: #ff8a7a;--fd-error-soft: rgba(255, 138, 122, .13);--fd-success: #6fd08e;--fd-success-soft: rgba(111, 208, 142, .14);--fd-warning: #f2b55c;--fd-warning-soft: rgba(242, 181, 92, .13);--fd-info: #7db7ff;--fd-info-soft: rgba(90, 162, 255, .14)}}:is(.fd-form,.fd-form-dialog)[data-accent]{--fd-accent: var(--fd-look-accent);--fd-accent-text: var(--fd-look-accent-text);--fd-focus: var(--fd-look-accent);--fd-accent-soft: color-mix(in srgb, var(--fd-accent) 12%, var(--fd-surface));--fd-accent-hover: color-mix(in srgb, var(--fd-accent) 84%, var(--fd-text))}:is(.fd-form,.fd-form-dialog)[data-scheme=dark][data-accent]{--fd-accent: var(--fd-look-accent-dark);--fd-accent-text: var(--fd-look-accent-dark-text);--fd-focus: var(--fd-look-accent-dark)}@media(prefers-color-scheme:dark){:is(.fd-form,.fd-form-dialog)[data-scheme=auto][data-accent]{--fd-accent: var(--fd-look-accent-dark);--fd-accent-text: var(--fd-look-accent-dark-text);--fd-focus: var(--fd-look-accent-dark)}}:is(.fd-form,.fd-form-dialog)[data-fd-skin=outlined][data-accent]{--fd-focus-ring: 0 0 0 2px color-mix(in srgb, var(--fd-accent) 22%, transparent)}:is(.fd-form,.fd-form-dialog)[data-accent] .fd-button-primary:hover{filter:none;background:var(--fd-accent-hover);border-color:var(--fd-accent-hover)}.fd-form[data-accent] .fd-page-head{border-block-end:3px solid var(--fd-accent);padding-block-end:14px}`;\n", "import { KINDS_CSS } from './styles-kinds';\nimport { CHOICES_CSS } from './styles-choices';\nimport { INPUTS_CSS } from './styles-inputs';\n\n/**\n * Fieldia's stylesheet: two skins and the layout chrome, all scoped to the\n * form's own root (`.fd-form[data-fd-skin=\u2026]`), so two forms on one page can\n * wear different skins and the host page's own controls are never touched.\n *\n * underline \u2014 the Flectra and Odoo style: flat inputs on a single line, labels\n * beside the field, navy accents.\n * outlined \u2014 the Ant Design style: boxed inputs with rounded corners, labels\n * above the field, a blue focus glow.\n *\n * Written with logical properties (inline/block, start/end), so a right-to-left\n * form mirrors without a second stylesheet.\n */\nimport { LAYOUT_CSS } from './layout-styles';\n\n/** The skins and the parts' chrome. One literal, so the script bundle can minify it as CSS. */\nconst SKINS_CSS = /* css */ `.fd-form,.fd-theme:is([data-fd-skin],:not(.fd-form *)){--fd-font: system-ui, -apple-system, \"Segoe UI\", Roboto, \"Noto Sans\", \"Noto Sans Arabic\", sans-serif;--fd-text: #212529;--fd-muted: #636976;--fd-page: #f2f3f5;--fd-surface: #ffffff;--fd-border: #cfd4da;--fd-border-strong: #9aa3ad;--fd-accent: #002855;--fd-accent-text: #ffffff;--fd-accent-soft: #e6ebf2;--fd-focus: #002855;--fd-focus-ring: none;--fd-error: #c62828;--fd-error-soft: #fdecea;--fd-success: #2e7d32;--fd-success-soft: #e8f5e9;--fd-warning: #8a5300;--fd-warning-soft: #fff4e0;--fd-info: #0b5cad;--fd-info-soft: #e7f0fb;--fd-radius: 0px;--fd-control-radius: 0px;--fd-pad-y: 3px;--fd-pad-x: 4px;--fd-input-border: 0 0 1px 0;--fd-label-weight: 600;--fd-gap-x: 32px;--fd-gap-y: 14px;container-type:inline-size;font-family:var(--fd-font);font-size:14px;line-height:1.45;color:var(--fd-text);-webkit-text-size-adjust:100%}.fd-form[data-fd-skin=outlined],.fd-theme[data-fd-skin=outlined]{--fd-text: rgba(0, 0, 0, .88);--fd-muted: rgba(0, 0, 0, .55);--fd-page: #f5f5f5;--fd-border: #d9d9d9;--fd-border-strong: #bfbfbf;--fd-accent: #1365d9;--fd-accent-soft: #e6f4ff;--fd-focus: #1365d9;--fd-focus-ring: 0 0 0 2px rgba(5, 145, 255, .12);--fd-error: #c63c3d;--fd-error-soft: #fff2f0;--fd-radius: 8px;--fd-control-radius: 6px;--fd-pad-y: 4px;--fd-pad-x: 11px;--fd-input-border: 1px;--fd-label-weight: 400;--fd-gap-x: 24px;--fd-gap-y: 18px}.fd-form *,.fd-form *:before,.fd-form *:after{box-sizing:border-box}.fd-form [hidden]{display:none!important}.fd-page-head{display:grid;gap:4px;margin-block-end:20px}.fd-page-title{font-size:22px;font-weight:650;margin:0;line-height:1.25}.fd-page-description{color:var(--fd-muted);margin:0}.fd-form[data-max-width=narrow]{--fd-page-max: 640px}.fd-form[data-max-width=medium]{--fd-page-max: 900px}.fd-form[data-max-width=wide]{--fd-page-max: 1180px}.fd-form[data-max-width=full]{--fd-page-max: none}.fd-form[data-max-width]>.fd-content:not(:has(>.fd-sheet-page)){max-width:var(--fd-page-max);margin-inline:auto}.fd-actions.fd-actions-top{margin-block-start:0;padding-block-end:14px;margin-block-end:18px;border-block-end:1px solid var(--fd-border)}.fd-icon{width:1.15em;height:1.15em;flex:none;vertical-align:-.2em}.fd-section-title .fd-icon,.fd-tab .fd-icon,.fd-button .fd-icon,.fd-step-title .fd-icon{margin-inline-end:.4em}.fd-section-title .fd-icon{color:var(--fd-muted)}.fd-grid{--fd-cols: var(--fd-columns, 1);--fd-span: 1;display:grid;grid-template-columns:repeat(var(--fd-cols),minmax(0,1fr));gap:var(--fd-gap-y) var(--fd-gap-x);align-items:start}.fd-grid>*{grid-column:span min(var(--fd-span, 1),var(--fd-cols))}.fd-field{display:grid;gap:4px;min-width:0}.fd-label{font-weight:var(--fd-label-weight);color:var(--fd-text)}.fd-valid-mark{color:var(--fd-success);width:1em;height:1em;margin-inline-start:6px;vertical-align:-.15em;stroke-width:2.4}.fd-field.fd-required>.fd-label:after{content:\" *\";color:var(--fd-error)}.fd-form[data-fd-skin=outlined] .fd-field.fd-required>.fd-label:after{content:\"\"}.fd-form[data-fd-skin=outlined] .fd-field.fd-required>.fd-label:before{content:\"* \";color:var(--fd-error)}.fd-help{color:var(--fd-muted);font-size:12.5px}.fd-page-title,.fd-page-description,.fd-section-description,.fd-label,.fd-help,.fd-text-heading,.fd-text-paragraph,.fd-text-note,.fd-choice>span{unicode-bidi:plaintext;text-align:match-parent;text-align:-webkit-match-parent}.fd-error{color:var(--fd-error);font-size:12.5px}.fd-warning{color:var(--fd-warning);background:var(--fd-warning-soft);font-size:12.5px;padding:3px 8px;border-radius:var(--fd-control-radius);justify-self:start}.fd-form[data-fd-skin=underline] .fd-field:where(:not([data-labels])){grid-template-columns:var(--fd-label-width, 11em) minmax(0,1fr);column-gap:12px;align-items:baseline}.fd-form[data-fd-skin=underline] .fd-field:where(:not([data-labels]))>.fd-label{grid-column:1}.fd-form[data-fd-skin=underline] .fd-field[data-type=one2many]{grid-template-columns:minmax(0,1fr)}.fd-form[data-fd-skin=underline] .fd-field[data-type=one2many]>*{grid-column:1!important}.fd-form[data-fd-skin=underline] .fd-field:where(:not([data-labels]))>:not(.fd-label){grid-column:2}@container (max-width: 760px){.fd-form[data-fd-skin=underline] .fd-grid{--fd-cols: 1}.fd-form .fd-grid[data-columns-medium]{--fd-cols: var(--fd-columns-medium)}.fd-form[data-fd-skin=underline] .fd-grid[data-columns-medium]:not([data-columns-medium=\"1\"]) .fd-field:where(:not([data-labels])){grid-template-columns:minmax(0,1fr)}.fd-form[data-fd-skin=underline] .fd-grid[data-columns-medium]:not([data-columns-medium=\"1\"]) .fd-field:where(:not([data-labels]))>*{grid-column:1!important}}@container (max-width: 520px){.fd-grid{--fd-cols: 1}.fd-form[data-fd-skin=underline] .fd-field:where(:not([data-labels])){grid-template-columns:minmax(0,1fr)}.fd-form[data-fd-skin=underline] .fd-field:where(:not([data-labels]))>*{grid-column:1!important}.fd-form .fd-grid[data-columns-medium],.fd-form .fd-grid[data-columns-narrow]{--fd-cols: var(--fd-columns-narrow, 1)}.fd-form .fd-file-viewer>:first-child{padding-inline-end:16px}.fd-form .fd-file-viewer h2{flex-basis:100%;margin-inline-end:36px}}.fd-input{width:100%;min-width:0;font:inherit;color:inherit;background:var(--fd-surface);border:solid var(--fd-border);border-width:var(--fd-input-border);border-radius:var(--fd-control-radius);padding:var(--fd-pad-y) var(--fd-pad-x);min-height:var(--fd-control-height, 30px);transition:border-color .15s ease,box-shadow .15s ease}.fd-input::placeholder{color:var(--fd-muted);opacity:.8}.fd-input:hover{border-color:var(--fd-border-strong)}.fd-input:focus{outline:none;border-color:var(--fd-focus);box-shadow:var(--fd-focus-ring)}.fd-form[data-fd-skin=underline] .fd-input{background:transparent}.fd-form[data-fd-skin=underline] .fd-input:focus{box-shadow:0 1px 0 0 var(--fd-focus)}.fd-form[data-fd-skin=underline] .fd-field.fd-required .fd-input{border-color:var(--fd-accent)}.fd-input[readonly]{background:transparent;border-color:transparent;padding-inline:0}.fd-form[data-fd-skin=outlined] .fd-input[readonly]{background:#0000000a;border-color:var(--fd-border);padding-inline:var(--fd-pad-x);color:var(--fd-muted)}.fd-form[data-readonly] .fd-input[readonly]{background:transparent;border-color:transparent;padding-inline:0;color:var(--fd-text)}.fd-form[data-readonly] .fd-input::placeholder{color:transparent}.fd-form[data-readonly] select.fd-input:disabled{appearance:none;background:transparent;border-color:transparent;padding-inline:0;color:var(--fd-text);opacity:1}.fd-input[aria-invalid=true]{border-color:var(--fd-error)}.fd-form[data-fd-skin=outlined] .fd-input[aria-invalid=true]:focus{box-shadow:0 0 0 2px #ff26050f}.fd-textarea{resize:vertical;min-height:64px}.fd-select{appearance:auto}.fd-number{display:flex;align-items:baseline;gap:6px}.fd-number-input{font-variant-numeric:tabular-nums}.fd-currency{color:var(--fd-muted);font-size:12.5px;font-weight:600}.fd-currency-after>.fd-number-input{text-align:end}.fd-currency-picked{align-items:center}.fd-currency-picked>:not(.fd-number-input){flex:0 0 104px;min-width:0}.fd-currency-picked>.fd-number-input{flex:1 1 auto;min-width:0}.fd-pending{color:var(--fd-muted);font-style:italic}.fd-pending:empty:before{content:\"\u2014\"}.fd-checkbox,.fd-choice input{width:16px;height:16px;accent-color:var(--fd-accent);margin:0}.fd-switch{appearance:none;width:34px;height:20px;margin:0;border-radius:999px;position:relative;background:var(--fd-border-strong);cursor:pointer;transition:background .2s ease}.fd-switch:after{content:\"\";position:absolute;inset-block-start:2px;inset-inline-start:2px;width:16px;height:16px;border-radius:50%;background:#fff;transition:transform .2s ease;box-shadow:0 1px 2px #00000040}.fd-switch:checked{background:var(--fd-accent)}.fd-switch:checked:after{transform:translate(14px)}[dir=rtl] .fd-switch:checked:after{transform:translate(-14px)}.fd-choices{display:flex;flex-wrap:wrap;gap:6px 18px}.fd-choice{display:inline-flex;align-items:center;gap:8px;cursor:pointer}.fd-choice-other{cursor:default;flex:1 1 260px;max-width:420px;min-width:0}.fd-choice-other-pick{display:inline-flex;align-items:center;gap:8px;cursor:pointer;flex:none}.fd-choice-other .fd-other-input{flex:1;min-width:6em;width:auto;min-height:30px;padding-block:2px}.fd-scale-box{display:inline-grid;gap:4px;max-width:100%}.fd-scale-ends{display:flex;justify-content:space-between;gap:16px;font-size:12.5px;color:var(--fd-muted)}.fd-choices-box{display:grid;gap:6px;min-width:0}.fd-choice-clear{justify-self:end;font:inherit;font-size:13px;color:var(--fd-muted);background:none;border:0;padding:2px 4px;border-radius:4px;cursor:pointer}.fd-choice-clear:hover{color:var(--fd-text);text-decoration:underline;text-underline-offset:3px}.fd-lines-table .fd-choice-clear,.fd-grid-editor .fd-choice-clear{display:none}.fd-points{display:flex;flex-wrap:wrap;gap:6px}.fd-points button{font:inherit;cursor:pointer;border:1px solid var(--fd-border);background:var(--fd-surface);color:var(--fd-text);border-radius:var(--fd-control-radius);min-width:34px;height:34px;padding:0 8px}.fd-points button.fd-on{background:var(--fd-accent);color:var(--fd-accent-text);border-color:var(--fd-accent)}.fd-rating button{border:none;background:none;font-size:24px;color:var(--fd-border-strong);padding:0 2px;min-width:0}.fd-rating button.fd-on{background:none;color:#f5a623}.fd-points button:disabled,.fd-choice input:disabled{cursor:default}.fd-form :focus-visible{outline:2px solid var(--fd-focus);outline-offset:2px}.fd-form .fd-input:focus-visible{outline:none}.fd-combo{position:relative;display:flex;align-items:center;min-width:0}.fd-combo-input{padding-inline-end:30px}.fd-combo-clear{position:absolute;inset-inline-end:3px;border:none;background:none;cursor:pointer;color:var(--fd-muted);font-size:16px;line-height:1;padding:0 4px;border-radius:4px;min-width:24px;min-height:24px;display:inline-grid;place-items:center}.fd-combo-clear:hover{color:var(--fd-text);background:var(--fd-page)}.fd-combo:has(>.fd-combo-open:not([hidden])) .fd-combo-input{padding-inline-end:56px}.fd-combo-open{position:absolute;inset-inline-end:29px;border:none;background:none;cursor:pointer;color:var(--fd-accent);font-size:14px;line-height:1;padding:0 4px;border-radius:4px;min-width:24px;min-height:24px;display:inline-grid;place-items:center}.fd-combo-open:hover{background:var(--fd-page)}.fd-listbox{position:absolute;inset-inline:0;inset-block-start:calc(100% + 2px);z-index:20;margin:0;padding:4px 0;list-style:none;background:var(--fd-surface);border:1px solid var(--fd-border);border-radius:max(var(--fd-control-radius),4px);box-shadow:0 8px 24px #0f14191f;max-height:240px;overflow-y:auto}.fd-option{padding:6px 12px;cursor:pointer}.fd-option:hover,.fd-option.fd-active{background:var(--fd-accent-soft)}.fd-option-create{color:var(--fd-accent);border-block-start:1px solid var(--fd-border)}.fd-empty{padding:6px 12px;color:var(--fd-muted);font-style:italic}.fd-tags{display:flex;flex-wrap:wrap;gap:6px;align-items:center;min-width:0}.fd-chips{display:contents;list-style:none;margin:0;padding:0}.fd-chip{display:inline-flex;align-items:center;gap:4px;padding:1px 4px 1px 10px;border-radius:999px;background:var(--fd-accent-soft);color:var(--fd-text);font-size:13px;line-height:22px}button.fd-chip-label{border:none;padding:0;background:none;font:inherit;color:inherit;cursor:pointer}button.fd-chip-label:hover{text-decoration:underline}.fd-chip-remove{border:none;background:none;cursor:pointer;color:var(--fd-muted);font-size:15px;line-height:1;padding:0 4px;border-radius:999px}.fd-chip-remove:hover{color:var(--fd-error)}.fd-tags .fd-combo{flex:1 1 140px}.fd-reference{display:grid;grid-template-columns:minmax(7em,34%) minmax(0,1fr);gap:8px}.fd-lines{display:grid;grid-template-columns:minmax(0,1fr);gap:6px;min-width:0}.fd-lines-scroll{overflow-x:auto;min-width:0;position:relative}.fd-lines-table{width:100%;border-collapse:collapse;font-size:13.5px}.fd-lines-table th{text-align:start;font-weight:600;color:var(--fd-muted);font-size:12.5px;padding:6px 8px;border-block-end:1px solid var(--fd-border);white-space:nowrap}.fd-lines-table td{padding:4px 8px;border-block-end:1px solid var(--fd-border);vertical-align:top;min-width:7em}.fd-lines-table td.fd-lines-tools,.fd-lines-table th.fd-lines-tools{width:32px;min-width:32px;padding-inline:0;text-align:center}.fd-lines-table .fd-input{min-height:28px}.fd-lines-table td>.fd-checkbox,.fd-lines-table td>.fd-switch{margin-block-start:6px}.fd-lines-table .fd-lines-grip{width:1px;min-width:0;padding-inline:6px 2px}.fd-line-grip{display:block;margin-block-start:7px;cursor:grab}.fd-line-delete{border:none;background:none;cursor:pointer;color:var(--fd-muted);font-size:16px;line-height:1;padding:4px 6px;border-radius:4px}.fd-line-delete:hover{color:var(--fd-error);background:var(--fd-error-soft)}.fd-lines-totals td{padding:8px;font-weight:600;border-block-start:1px solid var(--fd-border);font-variant-numeric:tabular-nums}.fd-lines-adds{display:flex;flex-wrap:wrap;gap:4px 16px;justify-self:start}.fd-line-section td{background:var(--fd-page)}.fd-line-section .fd-input{font-weight:600}.fd-line-note .fd-input{font-style:italic}.fd-cell-error{color:var(--fd-error);font-size:12px}.fd-sr-only{position:absolute;width:1px;height:1px;overflow:hidden;clip:rect(0 0 0 0);white-space:nowrap}.fd-file{display:grid;gap:8px;justify-items:start;padding:6px 0;border-radius:var(--fd-control-radius);min-width:0}.fd-file.fd-dragging{outline:2px dashed var(--fd-accent);outline-offset:4px}.fd-file-pick{display:flex;flex-wrap:wrap;gap:4px 8px;align-items:center;cursor:pointer}.fd-file input:focus-visible+.fd-file-pick{outline:2px solid var(--fd-focus);outline-offset:2px}.fd-files-list .fd-file-pick{justify-self:stretch;padding:10px 14px;border:1px dashed var(--fd-border-strong);border-radius:var(--fd-control-radius);background:var(--fd-page)}.fd-file-pick:hover,.fd-dragging .fd-file-pick{border-color:var(--fd-accent)}.fd-files{list-style:none;margin:0;padding:0;display:grid;gap:6px;justify-self:stretch;min-width:0}.fd-files:empty{display:none}.fd-file-item{position:relative;display:flex;align-items:center;gap:2px;min-width:0}.fd-file-open{flex:1;min-width:0;display:flex;align-items:center;gap:10px;padding:5px 8px;font:inherit;color:inherit;text-align:start;cursor:pointer;background:var(--fd-surface);border:1px solid var(--fd-border);border-radius:var(--fd-control-radius)}.fd-file-open:hover{border-color:var(--fd-accent)}.fd-file-thumb,.fd-file-icon{flex:none;width:36px;height:36px;border-radius:3px;object-fit:cover}.fd-file-icon{display:grid;place-items:end center;padding-block-end:4px;font-size:9px;font-weight:700;color:#fff;background:var(--fd-kind, #5b6573);clip-path:polygon(0 0,68% 0,100% 28%,100% 100%,0 100%)}.fd-file-icon[data-kind=pdf]{--fd-kind: #c62828}.fd-file-icon[data-kind=doc]{--fd-kind: #1f5fbf}.fd-file-icon[data-kind=sheet]{--fd-kind: #1d7a3e}.fd-file-icon[data-kind=zip]{--fd-kind: #8a5300}.fd-file-name{flex:1;display:flex;min-width:0;white-space:pre}.fd-file-name>span{overflow:hidden;text-overflow:ellipsis}.fd-file-size{color:var(--fd-muted);font-size:12.5px;font-variant-numeric:tabular-nums;unicode-bidi:plaintext}.fd-file-remove{flex:none;width:32px;height:32px;border:none;border-radius:999px;background:none;color:var(--fd-muted);font-size:20px;line-height:1;cursor:pointer}.fd-file-remove:hover{color:var(--fd-error);background:var(--fd-error-soft)}.fd-file-confirm:not([hidden]){display:flex;flex-wrap:wrap;align-items:center;gap:4px 14px}.fd-file-note:empty{display:none}.fd-file-note{color:var(--fd-warning)}.fd-files-thumbs{display:flex;flex-wrap:wrap;align-items:flex-start}.fd-files-thumbs>*{flex-basis:100%;order:2}.fd-files-thumbs>.fd-files{display:contents}.fd-files-thumbs .fd-file-item,.fd-image-pick{flex:none;width:96px;height:96px;order:0}.fd-files-thumbs>.fd-file-count{order:-1}.fd-files-thumbs .fd-file-open{height:100%;padding:6px;flex-direction:column;justify-content:center;gap:4px;overflow:hidden;font-size:12px}.fd-files-thumbs .fd-file-thumb{position:absolute;inset:0;width:100%;height:100%;border-radius:inherit}.fd-files-thumbs .fd-file-name{flex:none;max-width:100%}.fd-files-thumbs .fd-file-size,.fd-files-thumbs .fd-file-thumb~*{display:none}.fd-files-thumbs .fd-file-remove{position:absolute;inset-block-start:4px;inset-inline-end:4px;width:26px;height:26px;font-size:17px;background:#0f14199e;color:#fff;opacity:0}.fd-file-item:is(:hover,:focus-within) .fd-file-remove{opacity:1}.fd-image-pick{order:1;display:grid;place-content:center;justify-items:center;gap:2px;padding:6px;text-align:center;font-size:12px;border:1px dashed var(--fd-border-strong);border-radius:var(--fd-control-radius);background:var(--fd-page)}.fd-image-pick .fd-button{border:none;background:none;color:var(--fd-accent);padding:0;min-height:0;font-size:13px}.fd-file-viewer{max-width:1000px;height:min(88vh,100%);background:var(--fd-surface)}.fd-file-viewer>:first-child{position:relative;flex-wrap:wrap;justify-content:start;gap:6px 10px;padding-block:8px;padding-inline-end:52px}.fd-file-viewer .fd-dialog-close{position:absolute;inset-block-start:10px;inset-inline-end:10px}.fd-file-viewer h2{flex:1 1 10em;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.fd-file-step{font-size:18px;line-height:1;min-width:34px}.fd-file-viewer a{text-decoration:none}.fd-file-viewer-body{flex:1;min-height:0;display:flex;align-items:center;justify-content:center;overflow:auto;background:var(--fd-page)}.fd-file-viewer-body img{max-width:100%;max-height:100%;object-fit:contain}.fd-file-viewer-body :is(iframe,pre){flex:1;align-self:stretch;margin:0;border:0;background:var(--fd-surface)}.fd-file-viewer-body pre{padding:14px 16px;overflow:auto;font:13px/1.5 monospace;white-space:pre-wrap;overflow-wrap:anywhere}.fd-file-none{display:grid;justify-items:center;gap:4px;padding:24px;text-align:center;color:var(--fd-muted)}.fd-file-none strong{color:var(--fd-text);overflow-wrap:anywhere}.fd-file-none .fd-file-icon{width:64px;height:64px;font-size:14px;padding-block-end:8px}.fd-richtext{min-height:96px;line-height:1.5;overflow-wrap:anywhere}.fd-richtext-box{display:grid;gap:0;min-width:0}.fd-richtext-box>.fd-richtext{border-start-start-radius:0;border-start-end-radius:0}.fd-richtext-bar{display:flex;flex-wrap:wrap;align-items:center;gap:2px;padding:4px;min-width:0;border:1px solid var(--fd-border);border-block-end:none;border-start-start-radius:var(--fd-control-radius);border-start-end-radius:var(--fd-control-radius);background:var(--fd-page)}.fd-richtext-style{font:inherit;font-size:12.5px;padding:3px 6px;margin-inline-end:4px;border:1px solid var(--fd-border);border-radius:4px;background:var(--fd-surface);color:var(--fd-text)}.fd-richtext-tool{display:grid;place-items:center;width:28px;height:28px;padding:0;border:none;border-radius:4px;background:none;cursor:pointer;color:var(--fd-text);font:inherit;font-size:14px}.fd-richtext-tool:hover{background:var(--fd-surface)}.fd-richtext-tool[aria-pressed=true]{background:var(--fd-accent-soft);color:var(--fd-accent)}.fd-richtext-tool svg{width:16px;height:16px;fill:none;stroke:currentColor;stroke-width:1.3;stroke-linecap:round}.fd-richtext-tool svg circle{fill:currentColor;stroke:none}.fd-link-row{display:flex;flex-wrap:wrap;gap:6px;align-items:center;padding:6px;border:1px solid var(--fd-border);border-block-end:none;background:var(--fd-surface)}.fd-link-row>.fd-input{flex:1 1 200px;min-width:0}.fd-richtext[contenteditable=false]{background:transparent;border-color:transparent;padding-inline:0;min-height:0}.fd-richtext p{margin:0 0 6px}.fd-code{font-family:ui-monospace,SF Mono,Menlo,Consolas,monospace;font-size:12.5px;min-height:96px}.fd-sections{display:grid;gap:var(--fd-gap-block, 24px)}.fd-section{border:0;margin:0;padding:0;min-width:0;display:grid;gap:14px}.fd-section-title{font-size:15px;font-weight:650;padding:0;margin:0;float:inline-start;width:100%}.fd-section-title+*{clear:both}.fd-form[data-fd-skin=underline] .fd-section-title{text-transform:uppercase;letter-spacing:.05em;font-size:12.5px;color:var(--fd-muted);border-block-end:1px solid var(--fd-border);padding-block-end:6px;width:100%}.fd-section-description{color:var(--fd-muted);margin:0}.fd-section-toggle{font:inherit;color:inherit;background:none;border:0;padding:0;margin:0;cursor:pointer;display:inline-flex;align-items:center;gap:8px;text-align:start}.fd-section-toggle:focus-visible{outline:2px solid var(--fd-focus);outline-offset:2px;border-radius:2px}.fd-section-chevron{width:.5em;height:.5em;border:solid currentColor;border-width:0 2px 2px 0;transform:rotate(45deg);margin-block-start:-.2em;transition:transform .15s ease;flex:none}.fd-section-folded .fd-section-chevron{transform:rotate(-45deg);margin-block-start:0}[dir=rtl] .fd-section-folded .fd-section-chevron{transform:rotate(135deg)}.fd-form[data-fd-skin=outlined] :is(.fd-sections>.fd-section:not([data-style]),.fd-section[data-style=card][data-on-page]){background:var(--fd-surface);border:1px solid var(--fd-border);border-radius:var(--fd-radius);padding:var(--fd-group-pad, 20px 24px)}.fd-tablist{display:flex;gap:2px;border-block-end:1px solid var(--fd-border);overflow-x:auto}.fd-tab{font:inherit;background:none;border:none;cursor:pointer;padding:8px 14px;color:var(--fd-muted);border-block-end:2px solid transparent;margin-block-end:-1px;white-space:nowrap}.fd-tab[aria-selected=true]{color:var(--fd-accent);border-block-end-color:var(--fd-accent);font-weight:600}.fd-tabpanel{padding-block:16px;display:grid;gap:16px}.fd-button{font:inherit;cursor:pointer;display:inline-flex;align-items:center;gap:6px;justify-content:center;min-height:var(--fd-control-height, 32px);padding:4px 14px;border-radius:var(--fd-control-radius);border:1px solid var(--fd-border);background:var(--fd-surface);color:var(--fd-text)}.fd-button:hover{border-color:var(--fd-accent);color:var(--fd-accent)}.fd-button-primary{background:var(--fd-accent);border-color:var(--fd-accent);color:var(--fd-accent-text)}.fd-button-primary:hover{color:var(--fd-accent-text);filter:brightness(1.12)}.fd-button-danger{color:var(--fd-error);border-color:var(--fd-error)}.fd-button-danger:hover{background:var(--fd-error);color:#fff}.fd-button-link{border-color:transparent;background:none;color:var(--fd-accent);padding-inline:4px}.fd-form[data-fd-skin=underline] .fd-button{border-radius:3px}.fd-actions{display:flex;flex-wrap:wrap;gap:8px;align-items:center}.fd-actions-end{justify-content:flex-end;margin-block-start:24px}.fd-sheet-page{background:var(--fd-page);padding:0 0 32px;min-width:0}.fd-header{display:flex;flex-wrap:wrap;gap:10px 16px;align-items:center;justify-content:space-between;background:var(--fd-surface);border-block-end:1px solid var(--fd-border);padding:8px 16px}.fd-statusbar{display:flex;list-style:none;margin:0;padding:0;overflow-x:auto}.fd-statusbar li{display:flex}.fd-statusbar li>*{font:inherit;font-size:13px;border:none;background:var(--fd-page);color:var(--fd-muted);padding:5px 18px 5px 22px;margin-inline-start:-6px;white-space:nowrap;clip-path:polygon(0 0,calc(100% - 10px) 0,100% 50%,calc(100% - 10px) 100%,0 100%,10px 50%)}.fd-statusbar li:first-child>*{margin-inline-start:0;padding-inline-start:14px;clip-path:polygon(0 0,calc(100% - 10px) 0,100% 50%,calc(100% - 10px) 100%,0 100%)}.fd-statusbar li>button{cursor:pointer}.fd-statusbar li>[aria-current=step]{background:var(--fd-accent);color:var(--fd-accent-text);font-weight:600}[dir=rtl] .fd-statusbar li>*{transform:scaleX(-1)}[dir=rtl] .fd-statusbar li>*>*{display:inline-block;transform:scaleX(-1)}.fd-sheet-layout{display:grid;grid-template-columns:minmax(0,1fr);gap:16px;max-width:var(--fd-page-max, 1180px);margin:16px auto 0;padding-inline:16px}.fd-sheet-layout{align-items:start}.fd-sheet-foot{margin:4px -28px -28px;padding:12px 28px;border-block-start:1px solid var(--fd-border);border-end-start-radius:inherit;border-end-end-radius:inherit}.fd-sheet-layout.fd-has-side{grid-template-columns:minmax(0,1fr) minmax(260px,360px)}@container (max-width: 1000px){.fd-sheet-layout.fd-has-side{grid-template-columns:minmax(0,1fr)}}.fd-card{position:relative;background:var(--fd-surface);border:1px solid var(--fd-border);border-radius:var(--fd-radius);padding:24px 28px 28px;display:grid;gap:18px;min-width:0;container-type:inline-size}.fd-ribbon-frame{position:absolute;inset:0;overflow:hidden;border-radius:inherit;pointer-events:none}.fd-ribbon{position:absolute;inset-block-start:18px;inset-inline-end:-42px;transform:rotate(45deg);width:160px;text-align:center;font-size:12px;font-weight:700;padding:4px 0;color:#fff;background:var(--fd-muted);text-transform:uppercase;letter-spacing:.06em;pointer-events:none}[dir=rtl] .fd-ribbon{transform:rotate(-45deg)}.fd-ribbon.fd-tone-danger{background:var(--fd-error)}.fd-ribbon.fd-tone-success{background:var(--fd-success)}.fd-ribbon.fd-tone-warning{background:#d97706}.fd-ribbon.fd-tone-info{background:var(--fd-info)}.fd-alert{padding:10px 14px;border-radius:var(--fd-control-radius);border:1px solid;font-size:13.5px;display:flex;align-items:flex-start;gap:10px}.fd-alert-message{flex:1 1 auto;min-width:0}.fd-alert-close{border:none;background:none;color:inherit;cursor:pointer;font:inherit;font-size:18px;line-height:1;padding:0 4px;border-radius:4px;opacity:.75}.fd-alert-close:hover{opacity:1}.fd-alert-close:focus-visible{outline:2px solid var(--fd-focus);opacity:1}.fd-alert.fd-tone-warning{background:var(--fd-warning-soft);border-color:#f0c47a;color:var(--fd-warning)}.fd-alert.fd-tone-danger{background:var(--fd-error-soft);border-color:#f1a7a7;color:var(--fd-error)}.fd-alert.fd-tone-success{background:var(--fd-success-soft);border-color:#a7d7ab;color:var(--fd-success)}.fd-alert.fd-tone-info,.fd-alert:not([class*=fd-tone-]){background:var(--fd-info-soft);border-color:#a9c8ef;color:var(--fd-info)}.fd-stats{display:flex;flex-wrap:wrap;justify-content:flex-end;gap:0;margin:-24px -28px 0;border-block-end:1px solid var(--fd-border)}.fd-stats:empty{display:none}.fd-card:has(>.fd-ribbon-frame>.fd-ribbon:not([hidden])) .fd-stats{padding-inline-end:104px}.fd-stat{font:inherit;background:none;border:none;border-inline-start:1px solid var(--fd-border);cursor:pointer;padding:8px 18px;display:grid;justify-items:start;line-height:1.2;color:var(--fd-text);min-width:120px}.fd-stat:hover{background:var(--fd-page)}.fd-stat:has(>.fd-icon){grid-template-columns:auto minmax(0,1fr);align-items:center;column-gap:10px}.fd-stat>.fd-icon{width:22px;height:22px;color:var(--fd-muted)}.fd-stat-words{display:grid;justify-items:start}.fd-stat-value{font-weight:700;font-size:15px;color:var(--fd-accent);font-variant-numeric:tabular-nums}.fd-stat-label{font-size:12.5px;color:var(--fd-muted)}.fd-title-row{display:flex;gap:16px;align-items:flex-start;justify-content:space-between}.fd-title{display:grid;gap:4px;flex:1 1 auto;min-width:0}.fd-avatar{flex:none}.fd-avatar>.fd-label{position:absolute;width:1px;height:1px;overflow:hidden;clip:rect(0 0 0 0);white-space:nowrap}.fd-form[data-fd-skin=underline] .fd-avatar{grid-template-columns:minmax(0,1fr)}.fd-form[data-fd-skin=underline] .fd-avatar>*{grid-column:1!important}.fd-avatar .fd-file{justify-items:center;gap:4px 8px;padding:0;justify-content:center}.fd-avatar :is(.fd-file-item,.fd-image-pick){width:88px;height:88px}.fd-avatar :is(.fd-image-pick .fd-help,.fd-file-limits){display:none}.fd-avatar .fd-button-link{flex-basis:auto;font-size:12.5px}.fd-title>.fd-field .fd-input{font-size:24px;font-weight:600;min-height:40px}.fd-form[data-fd-skin=underline] .fd-title>.fd-field{grid-template-columns:minmax(0,1fr)}.fd-form[data-fd-skin=underline] .fd-title>.fd-field>*{grid-column:1}.fd-title>.fd-field>.fd-label{position:absolute;width:1px;height:1px;overflow:hidden;clip:rect(0 0 0 0);white-space:nowrap}.fd-title-above,.fd-title-below{display:flex;flex-wrap:wrap;align-items:center;gap:6px 24px}.fd-title-above{margin-block-end:4px}.fd-title-below{margin-block-start:6px}.fd-form .fd-title-above>.fd-field,.fd-form .fd-title-below>.fd-field{display:flex;align-items:center;gap:8px;grid-template-columns:none}.fd-form .fd-title-above>.fd-field>*,.fd-form .fd-title-below>.fd-field>*{grid-column:auto!important}.fd-title-above .fd-label:empty,.fd-title-below .fd-label:empty{display:none}.fd-title-above>.fd-field>.fd-label{position:absolute;width:1px;height:1px;overflow:hidden;clip:rect(0 0 0 0);white-space:nowrap}.fd-title-statusbar{display:flex}.fd-badges{display:flex;flex-wrap:wrap;gap:6px}.fd-badge{display:inline-flex;align-items:center;gap:5px;font-size:12px;font-weight:600;line-height:1;padding:5px 10px;border-radius:999px;border:1px solid var(--fd-border);background:var(--fd-page);color:var(--fd-muted)}.fd-badge .fd-icon{width:13px;height:13px}.fd-badge.fd-tone-info{background:var(--fd-info-soft);border-color:#a9c8ef;color:var(--fd-info)}.fd-badge.fd-tone-success{background:var(--fd-success-soft);border-color:#a7d7ab;color:var(--fd-success)}.fd-badge.fd-tone-warning{background:var(--fd-warning-soft);border-color:#f0c47a;color:var(--fd-warning)}.fd-badge.fd-tone-danger{background:var(--fd-error-soft);border-color:#f1a7a7;color:var(--fd-error)}.fd-side{display:grid;gap:12px;align-content:start;min-width:0}.fd-wizard{display:grid;gap:20px}.fd-progress{display:grid;gap:8px}.fd-progress-text{color:var(--fd-muted);font-size:13px}.fd-value-text{display:block;padding-block:6px;font-variant-numeric:tabular-nums}.fd-date-pick{position:relative;display:flex;align-items:center;gap:6px;min-width:0}.fd-date-pick>.fd-input{flex:1 1 auto;min-width:0}.fd-calendar-button{flex:0 0 auto;display:grid;place-items:center;width:32px;height:32px;padding:0;cursor:pointer;border:1px solid var(--fd-border);border-radius:var(--fd-control-radius);background:var(--fd-surface);color:var(--fd-muted)}.fd-calendar-button:hover,.fd-calendar-button[aria-expanded=true]{color:var(--fd-text);background:var(--fd-page)}.fd-calendar-button svg{width:16px;height:16px;fill:none;stroke:currentColor;stroke-width:1.4;stroke-linecap:round}.fd-calendar{position:absolute;inset-block-start:calc(100% + 4px);inset-inline-end:0;z-index:30;padding:8px;background:var(--fd-surface);border:1px solid var(--fd-border);border-radius:max(var(--fd-control-radius),6px);box-shadow:0 8px 24px #0f141924}.fd-calendar-head{display:flex;align-items:center;justify-content:space-between;gap:8px;padding:2px 4px 6px}.fd-calendar-head button{border:none;background:none;cursor:pointer;font-size:18px;line-height:1;padding:4px 8px;border-radius:4px;color:var(--fd-text)}.fd-calendar-head button:hover{background:var(--fd-page)}.fd-calendar-title{font-weight:600}.fd-calendar-grid{border-collapse:collapse;font-variant-numeric:tabular-nums}.fd-calendar-grid th{font-size:11.5px;font-weight:600;color:var(--fd-muted);padding:4px 0;width:34px;text-align:center}.fd-calendar-grid .fd-week{color:var(--fd-accent);font-weight:600;border-inline-end:1px solid var(--fd-border)}.fd-calendar-grid td{padding:1px}.fd-calendar-grid td button{width:32px;height:30px;border:none;border-radius:4px;background:none;cursor:pointer;color:var(--fd-text);font:inherit;font-size:13px}.fd-calendar-grid td button:hover{background:var(--fd-accent-soft)}.fd-calendar-grid td button.fd-outside{color:var(--fd-muted);opacity:.6}.fd-calendar-grid td button[aria-current=date]{box-shadow:inset 0 0 0 1px var(--fd-accent)}.fd-calendar-grid td button[aria-selected=true]{background:var(--fd-accent);color:var(--fd-accent-text);font-weight:600}.fd-calendar-grid td button:focus-visible{outline:2px solid var(--fd-focus);outline-offset:1px}.fd-properties{display:grid;gap:8px;min-width:0}.fd-property{display:grid;grid-template-columns:minmax(120px,30%) minmax(0,1fr);align-items:center;gap:12px;min-width:0}.fd-property>label{color:var(--fd-muted);font-size:13px}.fd-property[data-type=boolean]>:last-child{justify-self:start}@container (max-width: 520px){.fd-property{grid-template-columns:minmax(0,1fr);gap:4px}}.fd-progressbar{position:relative;height:22px;min-width:120px;border-radius:999px;overflow:hidden;background:var(--fd-page);border:1px solid var(--fd-border);font-variant-numeric:tabular-nums}.fd-progressbar-fill{height:100%;background:var(--fd-success);transition:width .2s ease}.fd-progressbar[data-tone=warning] .fd-progressbar-fill{background:#d97706}.fd-progressbar[data-tone=danger] .fd-progressbar-fill{background:var(--fd-error)}.fd-progressbar[data-tone=info] .fd-progressbar-fill{background:var(--fd-info)}.fd-progressbar-text{position:absolute;inset-block:2px;left:50%;translate:-50% 0;display:grid;place-items:center;padding-inline:7px;border-radius:999px;background:var(--fd-surface);font-size:12px;line-height:1;font-weight:600;color:var(--fd-text)}.fd-progressbar-text:empty{display:none}.fd-progressbar-edit{display:flex;align-items:center;gap:12px;min-width:0}.fd-progressbar-edit>.fd-progressbar{flex:1 1 auto}.fd-progressbar-edit>.fd-input{flex:0 0 96px}.fd-progress-bar{height:4px;background:var(--fd-border);border-radius:999px;overflow:hidden}.fd-progress-bar>span{display:block;height:100%;background:var(--fd-accent);transition:width .25s ease}.fd-step{display:grid;gap:18px}.fd-step-title{font-size:18px;font-weight:650;margin:0}.fd-wizard-nav{display:flex;gap:8px;justify-content:space-between}.fd-steps-list{display:flex;flex-wrap:wrap;gap:8px;list-style:none;margin:0;padding:0;counter-reset:fd-step}.fd-steps-list>li{counter-increment:fd-step}.fd-step-link{font:inherit;font-size:13.5px;display:inline-flex;align-items:center;gap:6px;cursor:pointer;border:1px solid var(--fd-border);background:var(--fd-surface);color:var(--fd-muted);border-radius:999px;padding:4px 12px 4px 6px}.fd-step-link:before{content:counter(fd-step);display:inline-grid;place-items:center;width:20px;height:20px;border-radius:50%;background:var(--fd-page);color:var(--fd-muted);font-size:12px;font-weight:600;font-variant-numeric:tabular-nums}.fd-step-link:hover{border-color:var(--fd-accent);color:var(--fd-text)}.fd-step-link:focus-visible{outline:2px solid var(--fd-focus);outline-offset:2px}.fd-step-link.fd-step-done{color:var(--fd-text)}.fd-step-link.fd-step-done:before{content:\"\u2713\";background:var(--fd-accent-soft);color:var(--fd-accent)}.fd-step-link.fd-step-skipped{border-style:dashed;color:var(--fd-muted)}.fd-step-link.fd-step-skipped:before{content:\"\u2013\";background:var(--fd-page);color:var(--fd-muted)}.fd-step-link[aria-current=step]{border-color:var(--fd-accent);color:var(--fd-accent);font-weight:600}.fd-step-link[aria-current=step]:before{content:counter(fd-step);background:var(--fd-accent);color:var(--fd-accent-text)}.fd-wizard-nav .fd-spacer{flex:1}.fd-text-heading{font-size:16px;font-weight:650;margin:0}.fd-matrix{overflow-x:auto;max-width:100%}.fd-matrix-table{border-collapse:collapse;min-width:100%}.fd-matrix-table th,.fd-matrix-table td{padding:6px 10px;text-align:center;border-bottom:1px solid var(--fd-border)}.fd-matrix-table thead th{font-weight:500;font-size:13px;color:var(--fd-muted)}.fd-matrix-table tbody th{text-align:start;font-weight:500}.fd-matrix-table input{accent-color:var(--fd-accent);width:16px;height:16px;margin:0}.fd-divider{grid-column:1 / -1;width:100%;border:0;border-top:1px solid var(--fd-border);margin:4px 0}.fd-block{min-width:0}.fd-spacer{min-height:24px}.fd-image{display:block;max-width:100%;height:auto;border-radius:var(--fd-radius)}.fd-figure{display:grid;justify-items:start;gap:6px;margin:0}.fd-figure[data-align=center]{justify-items:center}.fd-figure[data-align=end]{justify-items:end}.fd-figure>a,.fd-figure .fd-image{width:var(--fd-image-width, auto);max-width:100%}.fd-figure>a{display:block;border-radius:var(--fd-radius)}.fd-caption{font-size:13px;color:var(--fd-muted)}.fd-text-paragraph{margin:0}.fd-text-note{margin:0;color:var(--fd-muted);font-size:13px}.fd-status{min-height:1.4em;color:var(--fd-muted);font-size:13px}.fd-status-box{display:inline-flex;align-items:center;gap:6px;min-width:0}.fd-status-box .fd-retry{font-size:13px}.fd-announce{position:absolute;width:1px;height:1px;overflow:hidden;clip:rect(0 0 0 0);white-space:nowrap}.fd-banner{display:flex;flex-wrap:wrap;align-items:center;gap:8px 14px;padding:10px 14px;margin-block-end:16px;border:1px solid #f0c47a;border-radius:var(--fd-control-radius);background:var(--fd-warning-soft);color:var(--fd-warning);font-size:13.5px}.fd-banner-text{flex:1 1 16em;min-width:0}.fd-content>.fd-banner:has(+.fd-draft+.fd-sheet-page),.fd-content>.fd-banner:has(+.fd-sheet-page){margin:12px 16px 0}.fd-status-box.fd-toast{position:fixed;inset-block-end:max(20px,env(safe-area-inset-bottom,0px));inset-inline-end:20px;z-index:900;padding:10px 16px;border-radius:8px;background:var(--fd-text);box-shadow:0 8px 24px #0f141940}.fd-toast .fd-status,.fd-toast .fd-status.fd-status-saved,.fd-toast .fd-status.fd-status-error{color:var(--fd-surface);font-size:13.5px;min-height:0}.fd-toast .fd-retry{color:var(--fd-surface);text-decoration:underline}.fd-toast:has(.fd-status-error){background:var(--fd-error)}.fd-status-box.fd-status-bar{display:flex;justify-content:center;min-height:32px;padding:6px 16px;background:var(--fd-surface);border-block-end:1px solid var(--fd-border)}.fd-status-bar .fd-status-error,.fd-status.fd-status-error{color:var(--fd-error)}.fd-status.fd-status-saved{color:var(--fd-success)}.fd-draft{display:flex;flex-wrap:wrap;gap:8px 12px;align-items:center;padding:10px 14px;margin-block-end:16px;background:var(--fd-info-soft);border:1px solid #a9c8ef;border-radius:var(--fd-control-radius)}.fd-done{padding:40px 0;text-align:center;display:grid;gap:12px;justify-items:center}.fd-done-title{font-size:20px;font-weight:650;margin:0}.fd-dialog-backdrop{position:fixed;inset:0;background:#0f141973;display:grid;place-items:center;z-index:1000;padding:16px}.fd-dialog{background:var(--fd-surface);color:var(--fd-text);border-radius:max(var(--fd-radius),6px);max-width:420px;width:100%;padding:20px 22px;display:grid;gap:16px;box-shadow:0 10px 30px #0003;font-family:var(--fd-font)}.fd-dialog p{margin:0}.fd-form-dialog{display:flex;flex-direction:column;width:100%;max-height:min(90vh,100%);min-height:0;background:var(--fd-page);color:var(--fd-text);border-radius:max(var(--fd-radius),8px);box-shadow:0 24px 64px #0f14194d;overflow:hidden}.fd-form-dialog:focus{outline:none}.fd-form-dialog.fd-size-small{max-width:440px}.fd-form-dialog.fd-size-medium{max-width:760px}.fd-form-dialog.fd-size-large{max-width:1080px}.fd-form-dialog-backdrop:has(>.fd-size-full){padding:0}.fd-form-dialog.fd-size-full{max-width:none;max-height:none;height:100%;border-radius:0}.fd-form-dialog-head{display:flex;align-items:center;justify-content:space-between;gap:12px;padding:12px 16px;border-block-end:1px solid var(--fd-border);background:var(--fd-surface)}.fd-form-dialog-title{margin:0;font-size:16px;font-weight:600}.fd-dialog-close{border:none;background:none;cursor:pointer;font-size:22px;line-height:1;padding:2px 8px;border-radius:4px;color:var(--fd-muted)}.fd-dialog-close:hover{background:var(--fd-page);color:var(--fd-text)}.fd-form-dialog-body{flex:1 1 auto;min-height:0;overflow:auto;container-type:inline-size}.fd-form-dialog-body .fd-sheet-layout{margin-block-start:12px}.fd-form-dialog-body .fd-page-title{display:none}.fd-form-dialog-body .fd-page-head:not(:has(.fd-page-description)){display:none}.fd-form-dialog-body .fd-sheet-layout.fd-has-side{grid-template-columns:minmax(0,1fr)}.fd-form-dialog-body .fd-side{display:none}.fd-search-body{display:grid;gap:12px;align-content:start}.fd-search-list{list-style:none;margin:0;padding:0;border:1px solid var(--fd-border);border-radius:var(--fd-control-radius);overflow:auto;max-height:min(60vh,520px)}.fd-search-list .fd-option{padding:8px 12px}.fd-search-list .fd-option+.fd-option{border-block-start:1px solid var(--fd-border)}.fd-search-list .fd-empty{padding:10px 12px;color:var(--fd-muted)}.fd-form-dialog-body:not(:has(.fd-sheet-layout)){background:var(--fd-surface);padding:16px 20px 20px}.fd-form-dialog-foot{padding:12px 16px;border-block-start:1px solid var(--fd-border);background:var(--fd-surface);margin:0}@media(prefers-reduced-motion:reduce){.fd-form *,.fd-form *:before,.fd-form *:after{transition:none!important}}`;\n\n/** Fieldia's whole stylesheet: the skins, then the layout over them, the inputs' details, the question kinds and the choices' details. */\nexport const FIELDIA_CSS = SKINS_CSS + LAYOUT_CSS + INPUTS_CSS + KINDS_CSS + CHOICES_CSS;\n\nconst STYLE_ID = 'fieldia-styles';\n\n/** Add Fieldia's stylesheet to a document, once. */\nexport function installStyles(document: Document): void {\n if (document.getElementById(STYLE_ID)) return;\n const style = document.createElement('style');\n style.id = STYLE_ID;\n style.textContent = FIELDIA_CSS;\n (document.head ?? document.documentElement).append(style);\n}\n", "import type { JsonValue } from '@fieldia/core';\n\n/**\n * Where a person's choices about how a page looks are kept between visits:\n * a table's column widths, their order, which columns show. Never data, and\n * never anything a page needs to work: a store that forgets is fine.\n */\nexport interface PreferenceStore {\n get(key: string): JsonValue | null;\n set(key: string, value: JsonValue): void;\n}\n\n/** Preferences in the browser's local storage, under `fieldia:`. A browser that refuses storage just forgets. */\nexport function browserPreferences(storage?: Storage): PreferenceStore {\n const area = () => {\n try {\n return storage ?? globalThis.localStorage ?? null;\n } catch {\n return null; // reading localStorage itself throws where site data is blocked\n }\n };\n return {\n get(key) {\n try {\n const text = area()?.getItem(`fieldia:${key}`);\n return text == null ? null : (JSON.parse(text) as JsonValue);\n } catch {\n return null;\n }\n },\n set(key, value) {\n try {\n area()?.setItem(`fieldia:${key}`, JSON.stringify(value));\n } catch {\n // Full, private or blocked: the choice lasts until the page closes.\n }\n },\n };\n}\n\n/** Preferences that last as long as the page: for tests, and apps that keep nothing. */\nexport function memoryPreferences(): PreferenceStore {\n const values = new Map<string, JsonValue>();\n return {\n get: (key) => (values.has(key) ? structuredCloneSafe(values.get(key) as JsonValue) : null),\n set: (key, value) => void values.set(key, structuredCloneSafe(value)),\n };\n}\n\nconst structuredCloneSafe = (value: JsonValue): JsonValue => JSON.parse(JSON.stringify(value)) as JsonValue;\n", "export const LANGUAGES = {};", "import type { Locale } from '@fieldia/core';\nimport { LANGUAGES } from './locales/all';\n\n/** Every word the viewer shows, so a page can be translated. `{n}`, `{total}` and `{time}` are filled in. */\nexport interface ViewerLabels {\n save: string;\n /** Switching a read-only form to editing, and back. */\n edit: string;\n done: string;\n discard: string;\n saving: string;\n saved: string;\n submit: string;\n next: string;\n back: string;\n /** Passing over an optional step. */\n skip: string;\n /** The list of a wizard's steps, for screen readers. */\n steps: string;\n stepOf: string;\n submitted: string;\n submitAnother: string;\n draftFound: string;\n restore: string;\n discardDraft: string;\n ok: string;\n cancel: string;\n loading: string;\n /** A form in a dialog: the button that saves it and closes the dialog, and the \u00D7 that closes it. */\n saveClose: string;\n close: string;\n /** The \u00D7 on an alert that may be dismissed. */\n dismiss: string;\n /** Saving again after a save failed. */\n retry: string;\n notSaved: string;\n notSent: string;\n /** What was not saved or sent, and the fields to look at. */\n checkFields: string;\n /** The banner when the server cannot be reached. */\n offline: string;\n /** A list: its pages (`{from}`, `{to}`, `{total}`), what is chosen in it, and an empty one. */\n previousPage: string;\n nextPage: string;\n range: string;\n selected: string;\n clearSelection: string;\n selectAll: string;\n selectRecord: string;\n noRecords: string;\n loadFailed: string;\n /**\n * A list's search bar: the box (`{field}` and `{text}` in a suggestion), its\n * chips (`{label}`), the Filters, Group By and Favourites menu (`{name}`),\n * and the conditions a custom filter offers.\n */\n search: string;\n searchLabel: string;\n searchFor: string;\n searchOptions: string;\n filters: string;\n groupBy: string;\n favourites: string;\n or: string;\n removeFacet: string;\n addCustomFilter: string;\n field: string;\n condition: string;\n value: string;\n apply: string;\n saveSearch: string;\n searchName: string;\n useByDefault: string;\n deleteFavourite: string;\n noFavourites: string;\n opIs: string;\n opIsNot: string;\n opContains: string;\n opGreater: string;\n opLess: string;\n opSet: string;\n opNotSet: string;\n yes: string;\n no: string;\n /** A list's groups: the one of records with no value, and the rest of a group's records (`{n}`). */\n none: string;\n loadMore: string;\n}\n\n/** English: always here, and the words a language leaves out. */\nconst en: ViewerLabels = {\n save: 'Save',\n edit: 'Edit',\n done: 'Done',\n discard: 'Discard',\n saving: 'Saving\u2026',\n saved: 'Saved',\n submit: 'Submit',\n next: 'Next',\n back: 'Back',\n skip: 'Skip',\n steps: 'Steps',\n stepOf: 'Step {n} of {total}',\n submitted: 'Thank you. Your answers were sent.',\n submitAnother: 'Submit another response',\n draftFound: 'You have unsaved answers from {time}.',\n restore: 'Restore',\n discardDraft: 'Discard',\n ok: 'OK',\n cancel: 'Cancel',\n loading: 'Loading\u2026',\n saveClose: 'Save & Close',\n close: 'Close',\n dismiss: 'Dismiss',\n retry: 'Retry',\n notSaved: 'Not saved',\n notSent: 'Not sent',\n checkFields: '{what}. Check: {fields}',\n offline: 'Could not reach the server. Your changes are still here.',\n previousPage: 'Previous page',\n nextPage: 'Next page',\n range: '{from}\u2013{to} / {total}',\n selected: '{n} selected',\n clearSelection: 'Clear',\n selectAll: 'Select all',\n selectRecord: 'Select {name}',\n noRecords: 'No records match.',\n loadFailed: 'Could not load the records.',\n search: 'Search\u2026',\n searchLabel: 'Search',\n searchFor: 'Search {field} for: {text}',\n searchOptions: 'Search options',\n filters: 'Filters',\n groupBy: 'Group By',\n favourites: 'Favourites',\n or: 'or',\n removeFacet: 'Remove {label}',\n addCustomFilter: 'Add a custom filter',\n field: 'Field',\n condition: 'Condition',\n value: 'Value',\n apply: 'Apply',\n saveSearch: 'Save current search',\n searchName: 'Name of the search',\n useByDefault: 'Use by default',\n deleteFavourite: 'Delete {name}',\n noFavourites: 'No saved searches yet.',\n opIs: 'is',\n opIsNot: 'is not',\n opContains: 'contains',\n opGreater: 'greater than',\n opLess: 'less than',\n opSet: 'is set',\n opNotSet: 'is not set',\n yes: 'Yes',\n no: 'No',\n none: 'None',\n loadMore: 'Show {n} more',\n};\n\n/**\n * The viewer's words in every language Fieldia has. This package holds all\n * four; the one-tag script holds English alone, and a page adds another\n * language with that language's script (fieldia.ar.js, \u2026), through\n * `addLanguage`.\n */\nexport const VIEWER_LABELS: Record<Locale, ViewerLabels> = { en, ...LANGUAGES };\n\n/** English, kept under its old name. */\nexport const DEFAULT_LABELS: ViewerLabels = VIEWER_LABELS.en;\n\n/** The languages with a script of their own beside the one-tag script, by name. */\nconst ADD_ONS = new Map([\n ['ar', 'Arabic'],\n ['de', 'German'],\n ['fr', 'French'],\n]);\nconst missing = new Set<string>();\n\n/**\n * The language of the viewer's own words for a language tag: its own, its\n * base language's (`ar` for `ar-EG`), or English. A language the one-tag\n * script was not given is English, and the console says once which script\n * to add.\n */\nexport function ownLocale(tag = 'en'): Locale {\n const base = tag.split('-')[0];\n if (Object.prototype.hasOwnProperty.call(VIEWER_LABELS, base)) return base as Locale;\n const name = ADD_ONS.get(base);\n if (name && !missing.has(base)) {\n missing.add(base);\n console.warn(\n `Fieldia: this page is in ${name}, but only English words are loaded, so Fieldia's own words show in English. ` +\n `Load the ${name} ones after fieldia.js: <script src=\"https://cdn.jsdelivr.net/npm/@fieldia/viewer/bundle/fieldia.${base}.js\"></script>`\n );\n }\n return 'en';\n}\n", "import type { PageLook } from '@fieldia/core';\n\n/**\n * The page's look, worn by the form: what the page says about its accent,\n * font, room, corners, labels and colour scheme becomes attributes and tokens\n * on the form's root, and the stylesheet turns them into the form's own\n * colours and sizes \u2014 so every widget follows, in either skin, light or dark.\n * A page with no look is left exactly as its skin draws it.\n */\n\n/** Words written on a light accent, and on the dark page's accent. */\nconst INK = '#111418';\n/** The dark scheme's surface, which the dark page's accent has to read on. */\nconst DARK_SURFACE = '#1f2329';\n/** The darkest ground of a light page (the underline skin's), which the light page's accent has to read on. */\nconst LIGHT_GROUND = '#f2f3f5';\n/** WCAG's contrast for normal text (1.4.3, AA): the accent is words on the page, and has words on it. */\nconst READABLE = 4.5;\n\nconst channels = (hex: string) => [1, 3, 5].map((at) => parseInt(hex.slice(at, at + 2), 16));\nconst toHex = (rgb: number[]) => `#${rgb.map((c) => Math.round(c).toString(16).padStart(2, '0')).join('')}`;\n\n/** How bright a colour looks, as WCAG measures it: 0 for black, 1 for white. */\nfunction luminance(hex: string): number {\n const [r, g, b] = channels(hex).map((c) => {\n const s = c / 255;\n return s <= 0.03928 ? s / 12.92 : ((s + 0.055) / 1.055) ** 2.4;\n });\n return 0.2126 * r + 0.7152 * g + 0.0722 * b;\n}\n\n/** How well one colour reads on another: 1 (not at all) to 21 (black on white). */\nexport function contrast(a: string, b: string): number {\n const [light, dark] = [luminance(a), luminance(b)].sort((x, y) => y - x);\n return (light + 0.05) / (dark + 0.05);\n}\n\n/** White on a colour, as buttons are usually written; ink where white would read poorly. */\nconst textOn = (hex: string) => (contrast(hex, '#ffffff') >= READABLE ? '#ffffff' : INK);\n/** On a dark page the accent is light: whichever of ink or white reads better on it. */\nconst textOnDark = (hex: string) => (contrast(hex, INK) >= contrast(hex, '#ffffff') ? INK : '#ffffff');\n\n/** A colour taken towards white by `amount` (0 to 1). */\nconst lighten = (hex: string, amount: number) => toHex(channels(hex).map((c) => c + (255 - c) * amount));\n/** A colour taken towards black by `amount` (0 to 1). */\nconst darken = (hex: string, amount: number) => toHex(channels(hex).map((c) => c * (1 - amount)));\n/** The accent's softer shade on a surface, as the stylesheet mixes it: 12% of the accent. */\nconst softOn = (hex: string, surface: string) => toHex(channels(hex).map((c, i) => c * 0.12 + channels(surface)[i] * 0.88));\n/** Reads as words on a surface, on the lightest ground there, and on its own softer shade (a picked tab, a chip). */\nconst readsOn = (hex: string, grounds: string[]) => [...grounds, softOn(hex, grounds[0])].every((ground) => contrast(hex, ground) >= READABLE);\n\nexport interface AccentShades {\n /** The accent on a light page: as the page gives it, or darkened, when it has to be, until it reads there. */\n accent: string;\n /** What is written on it: a primary button's words. */\n accentText: string;\n /** The accent on a dark page: lightened, when it has to be, until it reads there. */\n dark: string;\n darkText: string;\n}\n\n/**\n * The accent, and what goes with it in either scheme. Each is moved, in small\n * steps and only as far as it has to be, until words in it and on it read at\n * 4.5:1 \u2014 darker on a light page, lighter on a dark one. The softer and hover\n * shades are mixed from these by the stylesheet.\n */\nexport function accentShades(hex: string): AccentShades {\n const given = hex.toLowerCase();\n let accent = given;\n for (let step = 1; step <= 40 && !readsOn(accent, ['#ffffff', LIGHT_GROUND]); step++) accent = darken(given, step / 40);\n let dark = given;\n for (let step = 1; step <= 40 && !readsOn(dark, [DARK_SURFACE]); step++) dark = lighten(given, step / 40);\n return { accent, accentText: textOn(accent), dark, darkText: textOnDark(dark) };\n}\n\n/** Put the page's look on the form's root. */\nexport function applyLook(root: HTMLElement, look: PageLook | undefined): void {\n if (!look) return;\n for (const name of ['font', 'density', 'corners', 'scheme'] as const) {\n const value = look[name];\n if (value) root.setAttribute(`data-${name}`, value);\n }\n if (look.labelWidth) root.style.setProperty('--fd-label-width', `${look.labelWidth}px`);\n if (look.accent) {\n const shades = accentShades(look.accent);\n root.setAttribute('data-accent', '');\n root.style.setProperty('--fd-look-accent', shades.accent);\n root.style.setProperty('--fd-look-accent-text', shades.accentText);\n root.style.setProperty('--fd-look-accent-dark', shades.dark);\n root.style.setProperty('--fd-look-accent-dark-text', shades.darkText);\n }\n}\n", "import type { PageLook, RecordId, RelatedRecord, Values } from '@fieldia/core';\nimport { WIDGET_LABELS } from '@fieldia/widgets';\nimport { ownLocale } from './labels';\nimport { keepTabIn } from './focus-trap';\nimport { applyLook } from './look';\nimport { mountViewer, VIEWER_LABELS, type Skin, type ViewerHandle, type ViewerOptions } from './viewer';\n\n/**\n * A page in a dialog: a new related record, a line to edit, a quick task. The\n * dialog saves (Save & Close) or closes without saving (Discard, \u00D7, Escape);\n * the page's own Save and Discard stay hidden. The focus moves into the dialog,\n * Tab stays inside it, and the focus goes back where it was when it closes.\n */\n\nexport interface FormDialogOptions extends ViewerOptions {\n title: string;\n size?: 'small' | 'medium' | 'large' | 'full';\n /**\n * \"save\" (the default) saves the record through the data source. \"values\"\n * only checks the form and hands its values back, for something saved with\n * a bigger record, such as a line.\n */\n mode?: 'save' | 'values';\n /**\n * Recalculates the values as they change, for a dialog with no data source of\n * its own: a line's subtotal following its quantity. What comes back is shown.\n */\n recompute?: (values: Values) => Promise<Values>;\n /** Where the dialog goes: the document's body by default. */\n container?: HTMLElement;\n /** The look of the page that opened it, worn by the dialog and the page in it, unless that page has a look of its own. */\n look?: PageLook;\n}\n\nexport interface FormDialogResult {\n /** True when Save & Close was pressed and the form accepted. */\n saved: boolean;\n recordId: RecordId | null;\n values: Values;\n}\n\nlet dialogs = 0;\n\nexport function openFormDialog(options: FormDialogOptions): Promise<FormDialogResult> {\n const doc = options.container?.ownerDocument ?? document;\n const container = options.container ?? doc.body;\n const opener = doc.activeElement instanceof doc.defaultView!.HTMLElement ? (doc.activeElement as HTMLElement) : null;\n const labels = { ...VIEWER_LABELS[ownLocale(options.locale)], ...options.labels };\n const id = `fd-dialog-${++dialogs}`;\n const make = <K extends keyof HTMLElementTagNameMap>(tag: K, attrs: Record<string, string> = {}, text?: string) => {\n const element = doc.createElement(tag);\n for (const [name, value] of Object.entries(attrs)) element.setAttribute(name, value);\n if (text !== undefined) element.textContent = text;\n return element;\n };\n\n const title = make('h2', { id: `${id}-title`, class: 'fd-form-dialog-title' }, options.title);\n const closeButton = make('button', { type: 'button', class: 'fd-dialog-close', 'aria-label': labels.close }, '\u00D7');\n const body = make('div', { class: 'fd-form-dialog-body' });\n const discard = make('button', { type: 'button', class: 'fd-button' }, labels.discard);\n const saveClose = make('button', { type: 'button', class: 'fd-button fd-button-primary' }, labels.saveClose);\n const box = make('div', {\n // Its own tokens and skin: the dialog sits outside the page that opened it.\n class: `fd-theme fd-form-dialog fd-size-${options.size ?? 'medium'}`,\n 'data-fd-skin': options.skin ?? 'underline',\n role: 'dialog',\n 'aria-modal': 'true',\n 'aria-labelledby': title.id,\n tabindex: '-1',\n });\n if (options.dir) box.setAttribute('dir', options.dir);\n // One look for the box and the page in it: the page's own, else the opener's.\n const look = options.page.look ?? options.look;\n applyLook(box, look);\n box.append(make('div', { class: 'fd-form-dialog-head' }), body, make('div', { class: 'fd-actions fd-actions-end fd-form-dialog-foot' }));\n box.firstElementChild?.append(title, closeButton);\n box.lastElementChild?.append(discard, saveClose);\n const backdrop = make('div', { class: 'fd-dialog-backdrop fd-form-dialog-backdrop' });\n backdrop.append(box);\n container.append(backdrop);\n\n const handle = mountViewer(body, { ...options, page: look && !options.page.look ? { ...options.page, look } : options.page, showActions: false });\n let done = false;\n if (options.recompute) recalculate(handle.form, options.page.fields, options.recompute, () => done);\n\n // Into the dialog: its first field, once the record is in, or the dialog itself meanwhile.\n const firstField = () => body.querySelector<HTMLElement>('input:not([type=\"hidden\"]), select, textarea, [contenteditable=\"true\"]');\n (firstField() ?? box).focus();\n void handle.form.settled().then(() => {\n if (doc.activeElement === box || !box.contains(doc.activeElement)) firstField()?.focus();\n });\n\n return new Promise((resolve) => {\n const close = (saved: boolean) => {\n if (done) return;\n done = true;\n const state = handle.form.getState();\n // The form never changes its values in place, so these are safe to hand back.\n const result: FormDialogResult = { saved, recordId: state.recordId ?? null, values: state.values as Values };\n handle.destroy();\n backdrop.remove();\n opener?.focus();\n resolve(result);\n };\n saveClose.addEventListener('click', async () => {\n saveClose.disabled = true;\n const accepted = options.mode === 'values' ? handle.check() : await handle.save();\n saveClose.disabled = false;\n if (accepted) close(true);\n });\n discard.addEventListener('click', () => close(false));\n closeButton.addEventListener('click', () => close(false));\n box.addEventListener('keydown', (event) => {\n // Ctrl+Enter is Save & Close from wherever the cursor is, even after a field used the Enter\n // (a tag box adding its tag), taking what is still being typed. The grid keeps its own keys.\n if (event.key === 'Enter' && (event.ctrlKey || event.metaKey) && !event.isComposing) {\n if ((event.target as Element).closest('.ag-root-wrapper')) return;\n event.preventDefault();\n doc.activeElement?.dispatchEvent(new Event('change', { bubbles: true }));\n saveClose.click();\n return;\n }\n // A key a field used itself (Escape closing a list) is not the dialog's.\n if (event.defaultPrevented) return;\n if (event.key === 'Escape') {\n event.preventDefault();\n close(false);\n } else keepTabIn(box, event);\n });\n });\n}\n\n/** Each change of the values asks for them recalculated, and shows the answer unless they changed again meanwhile. */\nfunction recalculate(form: ViewerHandle['form'], fields: Record<string, unknown>, recompute: (values: Values) => Promise<Values>, closed: () => boolean) {\n let seen = JSON.stringify(form.getState().values);\n let writing = false;\n form.subscribe(() => {\n const values = form.getState().values as Values;\n const now = JSON.stringify(values);\n if (writing || now === seen) return;\n seen = now;\n recompute(values).then(\n (next) => {\n if (closed() || JSON.stringify(form.getState().values) !== now) return; // a newer answer is on its way\n writing = true;\n for (const [name, value] of Object.entries(next)) {\n if (name in fields && JSON.stringify(values[name] ?? null) !== JSON.stringify(value ?? null)) form.setValue(name, value);\n }\n writing = false;\n seen = JSON.stringify(form.getState().values);\n },\n () => undefined\n );\n });\n}\n\nexport interface SearchDialogOptions {\n title: string;\n /** Finds records for what is typed: the field's own search, filter and all. */\n search(query: string, limit: number): Promise<RelatedRecord[]>;\n /** A language tag; the dialog's words are in it when Fieldia has them, English otherwise. */\n locale?: string;\n skin?: Skin;\n dir?: 'ltr' | 'rtl';\n /** Where the dialog goes: the document's body by default. */\n container?: HTMLElement;\n /** The look of the page that opened it: its accent, scheme, font, room and corners. */\n look?: PageLook;\n}\n\n/**\n * A searchable list in a dialog, for \"Search more\u2026\": every record the field may\n * point to, narrowed as the person types, picked with a click or the keyboard.\n * Resolves with the record picked, or null when closed.\n */\nexport function openSearchDialog(options: SearchDialogOptions): Promise<RelatedRecord | null> {\n const doc = options.container?.ownerDocument ?? document;\n const container = options.container ?? doc.body;\n const opener = doc.activeElement instanceof doc.defaultView!.HTMLElement ? (doc.activeElement as HTMLElement) : null;\n const locale = ownLocale(options.locale);\n const labels = VIEWER_LABELS[locale];\n const words = WIDGET_LABELS[locale];\n const id = `fd-dialog-${++dialogs}`;\n const make = <K extends keyof HTMLElementTagNameMap>(tag: K, attrs: Record<string, string> = {}, text?: string) => {\n const element = doc.createElement(tag);\n for (const [name, value] of Object.entries(attrs)) element.setAttribute(name, value);\n if (text !== undefined) element.textContent = text;\n return element;\n };\n const title = make('h2', { id: `${id}-title`, class: 'fd-form-dialog-title' }, options.title);\n const closeButton = make('button', { type: 'button', class: 'fd-dialog-close', 'aria-label': labels.close }, '\u00D7');\n const query = make('input', { type: 'search', class: 'fd-input', 'aria-label': words.search, placeholder: words.search, 'aria-controls': `${id}-list`, autocomplete: 'off' });\n const list = make('ul', { id: `${id}-list`, class: 'fd-search-list', role: 'listbox', 'aria-labelledby': title.id });\n const cancel = make('button', { type: 'button', class: 'fd-button' }, labels.cancel);\n const box = make('div', {\n class: `fd-theme fd-form-dialog fd-search-dialog fd-size-small`,\n 'data-fd-skin': options.skin ?? 'underline',\n role: 'dialog',\n 'aria-modal': 'true',\n 'aria-labelledby': title.id,\n });\n if (options.dir) box.setAttribute('dir', options.dir);\n applyLook(box, options.look);\n const head = make('div', { class: 'fd-form-dialog-head' });\n head.append(title, closeButton);\n const body = make('div', { class: 'fd-form-dialog-body fd-search-body' });\n body.append(query, list);\n const foot = make('div', { class: 'fd-actions fd-actions-end fd-form-dialog-foot' });\n foot.append(cancel);\n box.append(head, body, foot);\n const backdrop = make('div', { class: 'fd-dialog-backdrop fd-form-dialog-backdrop' });\n backdrop.append(box);\n container.append(backdrop);\n query.focus();\n\n return new Promise((resolve) => {\n let found: RelatedRecord[] = [];\n let active = -1;\n let asked = 0;\n let timer: ReturnType<typeof setTimeout> | undefined;\n const close = (picked: RelatedRecord | null) => {\n clearTimeout(timer);\n asked++;\n backdrop.remove();\n opener?.focus();\n resolve(picked);\n };\n const draw = () => {\n list.replaceChildren(\n ...found.map((record, i) => {\n const option = make('li', { id: `${id}-option-${i}`, role: 'option', class: `fd-option${i === active ? ' fd-active' : ''}`, 'aria-selected': String(i === active) }, record.label);\n option.addEventListener('click', () => close(record));\n return option;\n })\n );\n if (!found.length) list.append(make('li', { class: 'fd-empty' }, words.noResults));\n if (active >= 0) query.setAttribute('aria-activedescendant', `${id}-option-${active}`);\n else query.removeAttribute('aria-activedescendant');\n };\n const look = () => {\n clearTimeout(timer);\n const mine = ++asked;\n timer = setTimeout(async () => {\n const records = await options.search(query.value, 80).catch(() => [] as RelatedRecord[]);\n if (mine !== asked) return; // a newer search, or the dialog closed\n found = records;\n active = -1;\n draw();\n }, 180);\n };\n query.addEventListener('input', look);\n query.addEventListener('keydown', (event) => {\n if (event.key === 'ArrowDown' || event.key === 'ArrowUp') {\n event.preventDefault();\n if (!found.length) return;\n active = (active + (event.key === 'ArrowDown' ? 1 : -1) + found.length) % found.length;\n draw();\n list.children[active]?.scrollIntoView?.({ block: 'nearest' });\n } else if (event.key === 'Enter' && active >= 0) {\n event.preventDefault();\n close(found[active]);\n }\n });\n cancel.addEventListener('click', () => close(null));\n closeButton.addEventListener('click', () => close(null));\n box.addEventListener('keydown', (event) => {\n if (event.key === 'Escape') {\n event.preventDefault();\n close(null);\n } else keepTabIn(box, event);\n });\n look();\n });\n}\n", "import type { CreateRequest, DataSource, Field, Page, SearchRequest } from '@fieldia/core';\nimport type { WidgetDialogs } from '@fieldia/widgets';\nimport { openFormDialog, openSearchDialog } from './dialog';\nimport type { ViewerOptions } from './viewer';\n\n/** The field a page's records are named by: its title, or \"name\", or its first line of text. */\nexport function nameFieldOf(page: Page): string | null {\n if (page.layout.type === 'sheet' && page.layout.title?.field) return page.layout.title.field;\n if (page.fields['name']) return 'name';\n return Object.entries(page.fields).find(([, def]) => def.type === 'char')?.[0] ?? null;\n}\n\n\n\n/** A form made of fields, for values edited in a dialog (a line, for one). */\nfunction valuesPage(fields: Record<string, Field>, title: string, readonly: boolean): Page {\n const shown = Object.fromEntries(Object.entries(fields).map(([name, def]) => [name, readonly ? { ...def, readonly: true } : def])) as Page['fields'];\n return {\n fieldia: '0.1',\n id: 'values',\n title,\n data: { kind: 'record', model: 'values' },\n fields: shown,\n layout: {\n type: 'sections',\n id: 'values',\n children: [{ type: 'section', id: 'values-section', columns: 2, children: Object.keys(shown).map((name) => ({ type: 'field' as const, id: `values-${name}`, field: name })) }],\n },\n };\n}\n\n/** Only finding and making linked records: values edited in a dialog are no record of the source's to load, save or recalculate. */\nfunction lookupsOf(source: DataSource | undefined): DataSource | undefined {\n if (!source) return undefined;\n return {\n ...(source.search ? { search: (request: SearchRequest) => source.search!(request) } : {}),\n ...(source.create ? { create: (request: CreateRequest) => source.create!(request) } : {}),\n };\n}\n\n/** The dialogs a page's widgets may open, made from the viewer's own options. */\nexport function pageDialogs(options: ViewerOptions): WidgetDialogs {\n const pageFor = (model: string) =>\n (typeof options.relatedPages === 'function' ? options.relatedPages(model) : options.relatedPages?.[model]) ?? null;\n // A dialog's page looks and reads like the page that opened it, and can open dialogs of its own.\n const shared = {\n locale: options.locale,\n skin: options.skin,\n dir: options.dir,\n widgets: options.widgets,\n preferences: options.preferences,\n relatedPages: options.relatedPages,\n translate: options.translate,\n look: options.page.look,\n };\n return {\n canOpen: (model) => pageFor(model) !== null,\n async openRecord(model, request) {\n const related = pageFor(model);\n if (!related) return null;\n const nameField = nameFieldOf(related);\n const result = await openFormDialog({\n ...shared,\n page: related,\n dataSource: options.dataSource,\n recordId: request.recordId ?? null,\n values: request.name && nameField ? { [nameField]: request.name } : undefined,\n title: request.title,\n size: 'large',\n });\n if (!result.saved || result.recordId === null) return null;\n const name = nameField ? result.values[nameField] : null;\n return { id: result.recordId, label: typeof name === 'string' && name ? name : request.name ?? request.title };\n },\n searchMore: (request) => openSearchDialog({ title: request.title, search: request.search, locale: options.locale, skin: options.skin, dir: options.dir, look: options.page.look }),\n async editValues(request) {\n const result = await openFormDialog({\n ...shared,\n page: valuesPage(request.fields, request.title, request.readonly === true),\n dataSource: lookupsOf(options.dataSource),\n values: request.values,\n title: request.title,\n mode: 'values',\n ...(request.recompute ? { recompute: request.recompute } : {}),\n });\n return result.saved ? result.values : null;\n },\n };\n}\n", "import type { Facet, JsonValue, ListNode, Page } from '@fieldia/core';\nimport type { PreferenceStore } from '@fieldia/widgets';\nimport type { El } from './dom';\nimport type { ViewerLabels } from './labels';\n\n/** A search a person kept, by its name; the one used by default opens the list. */\nexport interface Favourite {\n name: string;\n facets: Facet[];\n isDefault?: boolean;\n}\n\nconst key = (page: Page) => `favourites:${page.id}`;\n\nexport function readFavourites(preferences: PreferenceStore, page: Page): Favourite[] {\n const kept = preferences.get(key(page));\n return Array.isArray(kept) ? (kept as unknown as Favourite[]) : [];\n}\n\n/** What a list starts with: the favourite used by default, or else the list's own default filters. */\nexport function startingFacets(node: ListNode, preferences: PreferenceStore, page: Page): Facet[] {\n const chosen = readFavourites(preferences, page).find((favourite) => favourite.isDefault);\n if (chosen) return chosen.facets;\n if (!node.defaultFilters?.length) return [];\n return [{ kind: 'filters', ids: [...node.defaultFilters], labels: node.defaultFilters.map((id) => node.filters?.find((f) => f.id === id)?.label ?? id) }];\n}\n\n/**\n * The Favourites of the search menu: searches kept by name, each one put back\n * with a click or deleted, and the search on screen kept as a new one, used by\n * default if the person says so. Kept where the page keeps its preferences.\n */\nexport function favouritesPart(context: { page: Page; el: El; labels: ViewerLabels; fill: (template: string, values: Record<string, string>) => string; preferences: PreferenceStore; current: () => Facet[]; apply: (facets: Facet[]) => void }) {\n const { page, el, labels, fill, preferences } = context;\n const list = el('ul', { class: 'fd-favourite-list' });\n const none = el('p', { class: 'fd-favourites-none' }, labels.noFavourites);\n const name = el('input', { class: 'fd-input', 'aria-label': labels.searchName, placeholder: labels.searchName });\n const byDefault = el('input', { type: 'checkbox' });\n const save = el('button', { type: 'button', class: 'fd-button fd-button-primary' }, labels.save);\n const form = el('div', { class: 'fd-favourite-form', hidden: '' }, name, el('label', { class: 'fd-favourite-default' }, byDefault, labels.useByDefault), save);\n const open = el('button', { type: 'button', class: 'fd-search-option fd-search-add', 'aria-expanded': 'false' }, labels.saveSearch);\n\n const write = (favourites: Favourite[]) => preferences.set(key(page), favourites as unknown as JsonValue);\n\n function draw() {\n const favourites = readFavourites(preferences, page);\n none.hidden = favourites.length > 0;\n list.replaceChildren(\n ...favourites.map((favourite) => {\n const use = el('button', { type: 'button', class: 'fd-search-option', 'data-default': favourite.isDefault ? 'true' : undefined }, favourite.name);\n use.addEventListener('click', () => context.apply(favourite.facets));\n const remove = el('button', { type: 'button', class: 'fd-favourite-remove', 'aria-label': fill(labels.deleteFavourite, { name: favourite.name }) }, '\u00D7');\n remove.addEventListener('click', () => {\n write(readFavourites(preferences, page).filter((f) => f.name !== favourite.name));\n draw();\n });\n return el('li', { class: 'fd-favourite' }, use, remove);\n })\n );\n }\n\n open.addEventListener('click', () => {\n form.hidden = !form.hidden;\n open.setAttribute('aria-expanded', String(!form.hidden));\n if (!form.hidden) name.focus();\n });\n save.addEventListener('click', () => {\n const named = name.value.trim();\n if (!named) return name.focus();\n const kept: Favourite = { name: named, facets: context.current(), ...(byDefault.checked ? { isDefault: true } : {}) };\n // A name kept again replaces the old search; one default at a time.\n const others = readFavourites(preferences, page)\n .filter((f) => f.name !== named)\n .map((f) => (byDefault.checked ? { name: f.name, facets: f.facets } : f));\n write([...others, kept]);\n name.value = '';\n byDefault.checked = false;\n form.hidden = true;\n open.setAttribute('aria-expanded', 'false');\n draw();\n });\n\n draw();\n return { list, none, open, form };\n}\n", "import type { DataSource, Group, Page, RecordId, ResolvedFilter, SortOrder, Value } from '@fieldia/core';\nimport type { El } from './dom';\nimport type { ViewerLabels } from './labels';\n\nexport type Row = { id: RecordId; values: Record<string, Value> };\n\nexport interface GroupContext {\n page: Page;\n el: El;\n labels: ViewerLabels;\n fill: (template: string, values: Record<string, string | number>) => string;\n dataSource: DataSource;\n model: string;\n fields: string[];\n columns: number;\n pageSize: number;\n sort: () => SortOrder[];\n /** A record's row, at a depth under its groups. */\n recordRow: (record: Row, level: number) => HTMLTableRowElement;\n /** Rows came or went. */\n changed: () => void;\n}\n\n/** A group's name as a person reads it: the choice's label, yes or no, the linked record's name, or None. */\nfunction groupName(context: GroupContext, field: string, group: Group): string {\n const def = context.page.fields[field];\n if (group.value === null) return context.labels.none;\n if (def.type === 'selection') return def.options.find((o) => o.value === group.value)?.label ?? group.label;\n if (def.type === 'boolean') return group.value ? context.labels.yes : context.labels.no;\n return group.label || String(group.value);\n}\n\n/** Take away every row under a group: its records, its groups and theirs. */\nfunction closeUnder(tr: HTMLElement) {\n const level = Number(tr.dataset['level']);\n let next = tr.nextElementSibling as HTMLElement | null;\n while (next && Number(next.dataset['level'] ?? 0) > level) {\n const after = next.nextElementSibling as HTMLElement | null;\n next.remove();\n next = after;\n }\n}\n\n/**\n * A group's row: its name and how many records it holds. Opened, it shows\n * the next field's groups under it, or at the last field its records, a page\n * at a time; closed, everything under it goes.\n */\nexport function groupRow(context: GroupContext, group: Group, level: number, within: ResolvedFilter[], grouping: string[]): HTMLTableRowElement {\n const { el, labels } = context;\n const field = grouping[level];\n const filter: ResolvedFilter[] = [...within, group.value === null ? { field, op: 'notset', value: null } : { field, op: '=', value: group.value }];\n const toggle = el(\n 'button',\n { type: 'button', class: 'fd-group-toggle', 'aria-expanded': 'false' },\n el('span', { class: 'fd-group-label' }, groupName(context, field, group)),\n ' ',\n el('span', { class: 'fd-group-count' }, `(${group.count})`)\n );\n const tr = el('tr', { class: 'fd-list-group', 'data-level': String(level), 'aria-level': String(level + 1) }, el('td', { colspan: String(context.columns) }, toggle));\n tr.style.setProperty('--fd-level', String(level));\n let opening = false;\n\n async function open() {\n opening = true;\n try {\n const rows =\n level + 1 < grouping.length\n ? (await context.dataSource.groups?.({ model: context.model, field: grouping[level + 1], filter }))?.map((inner) => groupRow(context, inner, level + 1, filter, grouping)) ?? []\n : await recordsFrom(0);\n // Closed, or the list drawn again, while the answer was on its way.\n if (!tr.isConnected || toggle.getAttribute('aria-expanded') !== 'true') return;\n tr.after(...rows);\n context.changed();\n } finally {\n opening = false;\n }\n }\n\n /** A page of the group's records, from `offset`, and a row for the rest when there are more. */\n async function recordsFrom(offset: number): Promise<HTMLTableRowElement[]> {\n const answer = await context.dataSource.list!({ model: context.model, fields: context.fields, filter, sort: context.sort(), offset, limit: context.pageSize });\n const rows = answer.records.map((record) => context.recordRow(record, level + 1));\n const left = answer.total - offset - answer.records.length;\n if (left <= 0) return rows;\n const more = el('button', { type: 'button', class: 'fd-button fd-button-link' }, context.fill(labels.loadMore, { n: left }));\n const moreRow = el('tr', { class: 'fd-list-more', 'data-level': String(level + 1) }, el('td', { colspan: String(context.columns) }, more));\n moreRow.style.setProperty('--fd-level', String(level));\n more.addEventListener('click', async () => {\n more.disabled = true;\n const next = await recordsFrom(offset + answer.records.length);\n if (!moreRow.isConnected) return;\n moreRow.replaceWith(...next);\n context.changed();\n });\n return [...rows, moreRow];\n }\n\n toggle.addEventListener('click', () => {\n const opened = toggle.getAttribute('aria-expanded') === 'true';\n toggle.setAttribute('aria-expanded', String(!opened));\n if (opened) {\n closeUnder(tr);\n context.changed();\n } else if (!opening) void open();\n });\n return tr;\n}\n", "/** The list's look, on the same tokens as the forms it opens. */\nexport const LIST_STYLES = `.fd-list{display:grid;gap:10px;min-width:0}.fd-list [hidden]{display:none!important}.fd-list-bar{display:flex;flex-wrap:wrap;align-items:center;gap:8px 12px;min-height:34px}.fd-search{position:relative;flex:1 1 360px;max-width:680px;min-width:0;container:fd-search / inline-size}.fd-search-field{display:flex;flex-wrap:wrap;align-items:center;gap:4px;min-height:34px;box-sizing:border-box;padding:2px 2px 2px 8px;padding-inline:8px 2px;border:1px solid var(--fd-border);border-radius:var(--fd-control-radius);background:var(--fd-surface)}.fd-search-field:focus-within{border-color:var(--fd-focus);box-shadow:var(--fd-focus-ring)}.fd-search-field>.fd-icon,.fd-search-field>svg{width:16px;height:16px;color:var(--fd-muted);flex:none}.fd-facets{display:contents}.fd-facet{display:inline-flex;align-items:center;gap:4px;max-width:100%;min-width:0;min-height:24px;padding-block:0;padding-inline:6px 0;border-radius:3px;background:var(--fd-accent-soft);color:var(--fd-accent);font-size:13px;line-height:18px}.fd-facet svg{width:13px;height:13px;flex:none}.fd-facet[data-kind=groupBy]{background:var(--fd-success-soft);color:var(--fd-success)}.fd-facet-text{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.fd-facet-remove{all:unset;cursor:pointer;display:grid;place-items:center;width:24px;height:24px;border-radius:2px;font-size:15px;line-height:1;opacity:.7}.fd-facet-remove:hover,.fd-facet-remove:focus-visible{opacity:1;background:var(--fd-surface)}.fd-search-input{flex:1 1 140px;min-width:100px;border:none;outline:none;background:none;font:inherit;font-size:14px;color:var(--fd-text);padding:5px 4px}.fd-form .fd-search-input:focus-visible{outline:none}.fd-search-toggle{all:unset;cursor:pointer;display:grid;place-items:center;width:30px;height:28px;border-radius:3px;color:var(--fd-muted)}.fd-search-toggle:before{content:\"\";width:7px;height:7px;border-right:1.5px solid currentColor;border-bottom:1.5px solid currentColor;transform:translateY(-2px) rotate(45deg)}.fd-search-toggle[aria-expanded=true]:before{transform:translateY(2px) rotate(-135deg)}.fd-search-toggle:hover,.fd-search-toggle[aria-expanded=true]{background:var(--fd-page);color:var(--fd-text)}.fd-search-toggle:focus-visible{outline:2px solid var(--fd-focus)}.fd-search-suggestions,.fd-search-panel{position:absolute;z-index:30;inset-inline:0;top:calc(100% + 4px);box-sizing:border-box;background:var(--fd-surface);border:1px solid var(--fd-border);border-radius:var(--fd-radius);box-shadow:0 10px 28px #0f172a24}.fd-search-suggestions{list-style:none;margin:0;padding:4px 0}.fd-search-suggestions [role=option]{padding:7px 12px;cursor:pointer;font-size:14px}.fd-search-suggestions [role=option][aria-selected=true]{background:var(--fd-accent-soft)}.fd-search-panel{display:grid;grid-auto-flow:column;grid-auto-columns:minmax(0,1fr);padding-block:6px}.fd-search-group{display:flex;flex-direction:column;align-items:stretch;gap:1px;padding:4px 10px 8px;min-width:0}.fd-search-group+.fd-search-group{border-inline-start:1px solid var(--fd-border)}@container fd-search (max-width: 540px){.fd-search-panel{grid-auto-flow:row}.fd-search-group+.fd-search-group{border-inline-start:none;border-block-start:1px solid var(--fd-border);padding-block-start:8px}}.fd-search-heading{display:flex;align-items:center;gap:6px;font-weight:600;font-size:13.5px;padding:4px 6px 6px}.fd-search-heading svg{width:15px;height:15px}.fd-search-group[data-group-kind=filters] .fd-search-heading svg{color:var(--fd-accent)}.fd-search-group[data-group-kind=groupBy] .fd-search-heading svg{color:var(--fd-success)}.fd-search-group[data-group-kind=favourites] .fd-search-heading svg{color:var(--fd-warning)}.fd-search-option{all:unset;box-sizing:border-box;cursor:pointer;display:flex;align-items:center;gap:6px;padding:5px 6px;border-radius:4px;font-size:14px;color:var(--fd-text)}.fd-search-option:before{content:\"\";width:14px;flex:none;text-align:center;color:var(--fd-accent);font-weight:700}.fd-search-option[aria-pressed=true]:before{content:\"\u2713\"}.fd-search-option:hover,.fd-search-option:focus-visible{background:var(--fd-page)}.fd-search-add{color:var(--fd-muted);margin-block-start:4px}.fd-search-add:before{content:\"+\";color:var(--fd-muted);font-weight:400}.fd-custom-filter,.fd-favourite-form{display:grid;gap:6px;padding:6px}.fd-custom-filter .fd-input,.fd-favourite-form .fd-input{width:100%;box-sizing:border-box;min-height:30px;border:1px solid var(--fd-border);border-radius:var(--fd-control-radius);padding:3px 6px;font:inherit;font-size:13.5px;background:var(--fd-surface);color:var(--fd-text)}.fd-favourite-default{display:flex;align-items:center;gap:6px;font-size:13.5px}.fd-favourite-list{list-style:none;margin:0;padding:0}.fd-favourite{display:flex;align-items:center}.fd-favourite .fd-search-option{flex:1;min-width:0}.fd-favourite .fd-search-option[data-default=true]:before{content:\"\u2605\";color:var(--fd-warning)}.fd-favourite-remove{all:unset;cursor:pointer;width:24px;height:24px;display:grid;place-items:center;border-radius:4px;color:var(--fd-muted)}.fd-favourite-remove:hover{background:var(--fd-page);color:var(--fd-error)}.fd-favourites-none{margin:0;padding:4px 6px;color:var(--fd-muted);font-size:13px}.fd-list-selection{display:flex;flex-wrap:wrap;align-items:center;gap:8px;padding:3px 4px 3px 10px;border-radius:var(--fd-control-radius);background:var(--fd-accent-soft)}.fd-list-count{font-weight:600;font-size:13.5px;color:var(--fd-accent);font-variant-numeric:tabular-nums}.fd-pager{display:flex;align-items:center;gap:4px;margin-inline-start:auto}.fd-pager-text{color:var(--fd-muted);font-size:13.5px;font-variant-numeric:tabular-nums;margin-inline-end:6px;white-space:nowrap}.fd-pager-button{min-width:32px;padding-inline:0;font-size:18px;line-height:1}.fd-list-scroll{overflow-x:auto;background:var(--fd-surface);border:1px solid var(--fd-border);border-radius:var(--fd-radius)}.fd-list-table{width:100%;border-collapse:collapse;font-size:14px}.fd-list-table th{text-align:start;font-weight:600;font-size:13px;color:var(--fd-text);padding:8px 10px;border-block-end:1px solid var(--fd-border-strong);white-space:nowrap;background:var(--fd-surface)}.fd-list-table td{padding:7px 10px;border-block-end:1px solid var(--fd-border);max-width:28em;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.fd-list-table tbody tr:last-child td{border-block-end:none}.fd-list-table .fd-num{text-align:end;font-variant-numeric:tabular-nums}.fd-list-table th.fd-list-check,.fd-list-table td.fd-list-check{width:36px;padding-inline:10px 0}.fd-list-checkbox{width:16px;height:16px;margin:0;vertical-align:middle;accent-color:var(--fd-accent);cursor:pointer}.fd-list-sort{all:unset;box-sizing:border-box;width:100%;cursor:pointer;display:flex;align-items:center;gap:4px;font:inherit;color:inherit}.fd-list-sort:after{content:\"\";width:0;height:0;border-inline:4px solid transparent;opacity:0}.fd-list-sort:hover:after{opacity:.35;border-block-start:5px solid currentColor}.fd-list-table th[aria-sort=ascending] .fd-list-sort:after{opacity:1;border-block-start:none;border-block-end:5px solid currentColor}.fd-list-table th[aria-sort=descending] .fd-list-sort:after{opacity:1;border-block-end:none;border-block-start:5px solid currentColor}.fd-list-table th.fd-num .fd-list-sort{justify-content:flex-end}.fd-list-table th.fd-num .fd-list-sort:after{order:-1}.fd-list-sort:focus-visible{outline:2px solid var(--fd-focus);outline-offset:2px}.fd-list-row:hover td{background:var(--fd-page)}.fd-list-openable{cursor:pointer}.fd-list-row[aria-selected=true] td{background:var(--fd-accent-soft)}.fd-list-row:focus-visible{outline:2px solid var(--fd-focus);outline-offset:-2px}.fd-list-table[aria-busy=true] tbody{opacity:.6;transition:opacity .2s .15s}.fd-list-group td{padding:0;background:var(--fd-page)}.fd-group-toggle{all:unset;box-sizing:border-box;cursor:pointer;display:flex;align-items:center;gap:8px;width:100%;padding:8px 10px;padding-inline-start:calc(12px + var(--fd-level, 0) * 22px);font-weight:600;font-size:13.5px;color:var(--fd-text)}.fd-group-toggle:before{content:\"\";flex:none;width:6px;height:6px;border-top:1.5px solid currentColor;border-right:1.5px solid currentColor;transform:rotate(45deg);transition:transform .12s}.fd-group-toggle:dir(rtl):before{transform:rotate(-135deg)}.fd-group-toggle[aria-expanded=true]:before{transform:rotate(135deg)}.fd-group-toggle:hover{background:var(--fd-accent-soft)}.fd-group-toggle:focus-visible{outline:2px solid var(--fd-focus);outline-offset:-2px}.fd-group-count{color:var(--fd-muted);font-weight:400;font-variant-numeric:tabular-nums}.fd-list-more td{padding:4px 10px;padding-inline-start:calc(46px + var(--fd-level, 0) * 22px)}.fd-list-empty,.fd-list-failed{margin:0;padding:28px 12px;text-align:center;color:var(--fd-muted)}.fd-list-failed{color:var(--fd-error)}`;\n\n/** Puts the list's look in the document once. */\nexport function installListStyles(doc: Document): void {\n if (doc.getElementById('fd-list-styles')) return;\n const style = doc.createElement('style');\n style.id = 'fd-list-styles';\n style.textContent = LIST_STYLES;\n doc.head.append(style);\n}\n", "import type { Facet, Field, JsonValue, Page, ResolvedFilterCondition } from '@fieldia/core';\nimport type { El } from './dom';\nimport type { ViewerLabels } from './labels';\n\ntype Op = ResolvedFilterCondition['op'];\ntype Words = Pick<ViewerLabels, 'opIs' | 'opIsNot' | 'opContains' | 'opGreater' | 'opLess' | 'opSet' | 'opNotSet'>;\n\nconst TEXT: [Op, keyof Words][] = [['ilike', 'opContains'], ['=', 'opIs'], ['!=', 'opIsNot'], ['set', 'opSet'], ['notset', 'opNotSet']];\nconst LINK: [Op, keyof Words][] = [['ilike', 'opContains'], ['set', 'opSet'], ['notset', 'opNotSet']];\nconst CHOICE: [Op, keyof Words][] = [['=', 'opIs'], ['!=', 'opIsNot'], ['set', 'opSet'], ['notset', 'opNotSet']];\nconst NUMBER: [Op, keyof Words][] = [['=', 'opIs'], ['!=', 'opIsNot'], ['>', 'opGreater'], ['<', 'opLess'], ['set', 'opSet'], ['notset', 'opNotSet']];\nconst DATE: [Op, keyof Words][] = [['=', 'opIs'], ['>', 'opGreater'], ['<', 'opLess'], ['set', 'opSet'], ['notset', 'opNotSet']];\n\n/** The conditions that suit a field, or none for a field a custom filter cannot look at. */\nfunction conditionsFor(def: Field): [Op, keyof Words][] {\n switch (def.type) {\n case 'char':\n case 'text':\n case 'html':\n return TEXT;\n case 'many2one':\n case 'many2many':\n return LINK;\n case 'selection':\n return CHOICE;\n case 'integer':\n case 'float':\n case 'monetary':\n return NUMBER;\n case 'date':\n case 'datetime':\n return DATE;\n case 'boolean':\n return [['=', 'opIs']];\n default:\n return [];\n }\n}\n\n/**\n * A filter of a person's own, under the list's filters: a field, a condition\n * that suits it, and a value of its kind. Applied, it becomes a chip.\n */\nexport function customFilterPart(context: { page: Page; el: El; labels: ViewerLabels; add: (facet: Facet) => void }) {\n const { page, el, labels } = context;\n const fields = Object.entries(page.fields).filter(([, def]) => conditionsFor(def).length);\n const field = el('select', { class: 'fd-input', 'aria-label': labels.field }, ...fields.map(([name, def]) => el('option', { value: name }, def.label)));\n const condition = el('select', { class: 'fd-input', 'aria-label': labels.condition });\n const valueBox = el('span', { class: 'fd-custom-filter-value' });\n const apply = el('button', { type: 'button', class: 'fd-button fd-button-primary' }, labels.apply);\n const form = el('div', { class: 'fd-custom-filter', hidden: '' }, field, condition, valueBox, apply);\n const button = el('button', { type: 'button', class: 'fd-search-option fd-search-add', 'aria-expanded': 'false' }, labels.addCustomFilter);\n let value: HTMLInputElement | HTMLSelectElement = el('input', { class: 'fd-input', 'aria-label': labels.value });\n\n const def = () => page.fields[field.value];\n\n function drawConditions() {\n condition.replaceChildren(...conditionsFor(def()).map(([op, word]) => el('option', { value: op }, labels[word])));\n drawValue();\n }\n\n /** A box of the field's kind: its choices, yes or no, a number, a day, or text. */\n function drawValue() {\n const current = def();\n if (current.type === 'selection') value = el('select', { class: 'fd-input', 'aria-label': labels.value }, ...current.options.map((o) => el('option', { value: String(o.value) }, o.label)));\n else if (current.type === 'boolean') value = el('select', { class: 'fd-input', 'aria-label': labels.value }, el('option', { value: 'true' }, labels.yes), el('option', { value: 'false' }, labels.no));\n else {\n const type = ['integer', 'float', 'monetary'].includes(current.type) ? 'number' : current.type === 'date' ? 'date' : current.type === 'datetime' ? 'datetime-local' : 'text';\n value = el('input', { class: 'fd-input', type, 'aria-label': labels.value });\n }\n valueBox.replaceChildren(value);\n valueBox.hidden = condition.value === 'set' || condition.value === 'notset';\n }\n\n field.addEventListener('change', drawConditions);\n condition.addEventListener('change', () => (valueBox.hidden = condition.value === 'set' || condition.value === 'notset'));\n button.addEventListener('click', () => {\n form.hidden = !form.hidden;\n button.setAttribute('aria-expanded', String(!form.hidden));\n if (!form.hidden) field.focus();\n });\n\n apply.addEventListener('click', () => {\n const current = def();\n const op = condition.value as Op;\n const word = labels[conditionsFor(current).find(([o]) => o === op)?.[1] ?? 'opIs'];\n let wanted: JsonValue = null;\n let shown = '';\n if (!valueBox.hidden) {\n const text = value.value.trim();\n if (!text) return value.focus();\n if (current.type === 'selection') {\n const option = current.options.find((o) => String(o.value) === text);\n wanted = option?.value ?? text;\n shown = option?.label ?? text;\n } else if (current.type === 'boolean') {\n wanted = text === 'true';\n shown = wanted ? labels.yes : labels.no;\n } else if (['integer', 'float', 'monetary'].includes(current.type)) {\n wanted = Number(text);\n if (!Number.isFinite(wanted)) return value.focus();\n shown = text;\n } else {\n wanted = text;\n shown = text;\n }\n }\n context.add({ kind: 'custom', label: [current.label, word, shown].filter(Boolean).join(' '), filter: [{ field: field.value, op, value: wanted }] });\n form.hidden = true;\n button.setAttribute('aria-expanded', 'false');\n });\n\n drawConditions();\n return { button, form };\n}\n", "import { suggestions, type Facet, type ListNode, type Page, type Suggestion } from '@fieldia/core';\nimport { drawIcon, type IconSet, type PreferenceStore } from '@fieldia/widgets';\nimport { customFilterPart } from './custom-filter';\nimport type { El } from './dom';\nimport { favouritesPart } from './favourites';\nimport type { ViewerLabels } from './labels';\n\ntype FieldFacet = Extract<Facet, { kind: 'field' }>;\n\nexport interface SearchContext {\n page: Page;\n node: ListNode;\n doc: Document;\n el: El;\n labels: ViewerLabels;\n fill: (template: string, values: Record<string, string | number>) => string;\n uid: (id: string) => string;\n icons?: IconSet;\n preferences: PreferenceStore;\n /** What the list starts with. */\n facets: Facet[];\n onChange: (facets: Facet[]) => void;\n}\n\n/** A chip's words: a field and the values looked for in it, filters any of which apply, or the fields grouped by. */\nexport function facetText(facet: Facet, labels: Pick<ViewerLabels, 'or'>): string {\n const or = ` ${labels.or} `;\n switch (facet.kind) {\n case 'field':\n return `${facet.label}: ${facet.values.map((v) => v.label).join(or)}`;\n case 'filters':\n return facet.labels.join(or);\n case 'groupBy':\n return facet.labels.join(' > ');\n case 'custom':\n return facet.label;\n }\n}\n\n/**\n * A list's search bar: what is typed becomes a search in one of the list's\n * fields, chosen from suggestions; the menu turns the list's filters on and\n * off, groups by its fields, builds a filter, and keeps searches as\n * favourites. Everything chosen shows as a chip, and all of it applies.\n */\nexport function searchBar(context: SearchContext) {\n const { page, node, doc, el, labels, fill, uid } = context;\n let facets = context.facets;\n const icon = (name: string) => {\n const drawn = drawIcon(doc, name, context.icons);\n drawn?.setAttribute('aria-hidden', 'true');\n return drawn ? [drawn] : [];\n };\n\n function change(next: Facet[]) {\n facets = next;\n drawChips();\n drawPanel();\n context.onChange(facets);\n }\n\n // ---- the box, its chips and its suggestions -----------------------------------------\n\n const listId = uid(`${node.id}-suggestions`);\n const panelId = uid(`${node.id}-search-panel`);\n const input = el('input', {\n class: 'fd-search-input',\n role: 'combobox',\n autocomplete: 'off',\n placeholder: labels.search,\n 'aria-label': labels.searchLabel,\n 'aria-autocomplete': 'list',\n 'aria-expanded': 'false',\n 'aria-controls': listId,\n });\n const chips = el('div', { class: 'fd-facets' });\n const offeredList = el('ul', { class: 'fd-search-suggestions', role: 'listbox', id: listId, 'aria-label': labels.searchLabel, hidden: '' });\n const toggle = el('button', { type: 'button', class: 'fd-search-toggle', 'aria-label': labels.searchOptions, 'aria-expanded': 'false', 'aria-controls': panelId });\n let offered: Suggestion[] = [];\n let active = 0;\n\n function drawChips() {\n chips.replaceChildren(\n ...facets.map((facet, index) => {\n const text = facetText(facet, labels);\n const remove = el('button', { type: 'button', class: 'fd-facet-remove', 'aria-label': fill(labels.removeFacet, { label: text }) }, '\u00D7');\n remove.addEventListener('click', () => {\n change(facets.filter((_, i) => i !== index));\n input.focus();\n });\n const kind = facet.kind === 'groupBy' ? 'layers' : facet.kind === 'field' ? '' : 'filter';\n return el('span', { class: 'fd-facet', 'data-kind': facet.kind }, ...(kind ? icon(kind) : []), el('span', { class: 'fd-facet-text' }, text), remove);\n })\n );\n }\n\n function drawOffered() {\n offeredList.replaceChildren(\n ...offered.map((suggestion, index) => {\n const option = el('li', { role: 'option', id: `${listId}-${index}`, 'aria-selected': String(index === active) }, suggestion.label);\n // The box keeps the focus while a suggestion is clicked.\n option.addEventListener('mousedown', (event) => event.preventDefault());\n option.addEventListener('click', () => pick(suggestion));\n return option;\n })\n );\n offeredList.hidden = offered.length === 0;\n input.setAttribute('aria-expanded', String(!offeredList.hidden));\n if (offeredList.hidden) input.removeAttribute('aria-activedescendant');\n else input.setAttribute('aria-activedescendant', `${listId}-${active}`);\n }\n\n function closeOffered() {\n offered = [];\n drawOffered();\n }\n\n /** A search in a field joins the field's chip, any of its values; the same value twice is once. */\n function pick(suggestion: Suggestion) {\n const value = { op: suggestion.op, value: suggestion.value, label: suggestion.valueLabel };\n const at = facets.findIndex((f) => f.kind === 'field' && f.field === suggestion.field);\n const next = [...facets];\n if (at < 0) next.push({ kind: 'field', field: suggestion.field, label: suggestion.fieldLabel, values: [value] });\n else {\n const facet = next[at] as FieldFacet;\n const known = facet.values.some((v) => v.op === value.op && JSON.stringify(v.value) === JSON.stringify(value.value));\n if (!known) next[at] = { ...facet, values: [...facet.values, value] };\n }\n input.value = '';\n closeOffered();\n change(next);\n }\n\n input.addEventListener('input', () => {\n offered = suggestions(input.value, page, node, { searchFor: labels.searchFor });\n active = 0;\n drawOffered();\n });\n input.addEventListener('blur', closeOffered);\n input.addEventListener('keydown', (event) => {\n if (event.isComposing) return;\n if ((event.key === 'ArrowDown' || event.key === 'ArrowUp') && offered.length) {\n event.preventDefault();\n active = (active + (event.key === 'ArrowDown' ? 1 : offered.length - 1)) % offered.length;\n drawOffered();\n } else if (event.key === 'Enter') {\n // Never the form's Enter: a list has nothing to send.\n event.preventDefault();\n if (offered.length) pick(offered[active]);\n } else if (event.key === 'Backspace' && !input.value && facets.length) {\n change(facets.slice(0, -1));\n } else if (event.key === 'Escape' && !offeredList.hidden) {\n event.preventDefault();\n closeOffered();\n }\n });\n\n // ---- the menu: filters, group by, favourites ---------------------------------------\n\n const heading = (iconName: string, text: string, id: string) => el('div', { class: 'fd-search-heading', id }, ...icon(iconName), text);\n const toggleIn = (kind: 'filters' | 'groupBy', key: string) => {\n const at = facets.findIndex((f) => f.kind === kind);\n const now = at < 0 ? [] : kind === 'filters' ? (facets[at] as Extract<Facet, { kind: 'filters' }>).ids : (facets[at] as Extract<Facet, { kind: 'groupBy' }>).fields;\n const keys = now.includes(key) ? now.filter((k) => k !== key) : [...now, key];\n const facet: Facet =\n kind === 'filters'\n ? { kind, ids: keys, labels: keys.map((id) => node.filters?.find((f) => f.id === id)?.label ?? id) }\n : { kind, fields: keys, labels: keys.map((field) => page.fields[field]?.label ?? field) };\n const next = [...facets];\n if (at < 0) next.push(facet);\n else if (keys.length) next[at] = facet;\n else next.splice(at, 1);\n change(next);\n };\n\n const filterButtons = (node.filters ?? []).map((filter) => {\n const button = el('button', { type: 'button', class: 'fd-search-option', 'aria-pressed': 'false', 'data-filter': filter.id }, filter.label);\n button.addEventListener('click', () => toggleIn('filters', filter.id));\n return button;\n });\n const groupButtons = (node.groupBy ?? []).map((field) => {\n const button = el('button', { type: 'button', class: 'fd-search-option', 'aria-pressed': 'false', 'data-group': field }, page.fields[field].label);\n button.addEventListener('click', () => toggleIn('groupBy', field));\n return button;\n });\n const custom = customFilterPart({ page, el, labels, add: (facet) => change([...facets, facet]) });\n const favourites = favouritesPart({ page, el, labels, fill, preferences: context.preferences, current: () => facets, apply: change });\n\n const group = (kind: string, iconName: string, title: string, ...parts: HTMLElement[]) =>\n el('div', { class: 'fd-search-group', 'data-group-kind': kind, role: 'group', 'aria-labelledby': `${panelId}-${kind}` }, heading(iconName, title, `${panelId}-${kind}`), ...parts);\n const panel = el(\n 'div',\n { class: 'fd-search-panel', id: panelId, hidden: '' },\n group('filters', 'filter', labels.filters, ...filterButtons, custom.button, custom.form),\n ...(groupButtons.length ? [group('groupBy', 'layers', labels.groupBy, ...groupButtons)] : []),\n group('favourites', 'star', labels.favourites, favourites.list, favourites.none, favourites.open, favourites.form)\n );\n\n function drawPanel() {\n const ids = (facets.find((f) => f.kind === 'filters') as Extract<Facet, { kind: 'filters' }> | undefined)?.ids ?? [];\n const fields = (facets.find((f) => f.kind === 'groupBy') as Extract<Facet, { kind: 'groupBy' }> | undefined)?.fields ?? [];\n for (const button of filterButtons) button.setAttribute('aria-pressed', String(ids.includes(button.dataset['filter'] ?? '')));\n for (const button of groupButtons) button.setAttribute('aria-pressed', String(fields.includes(button.dataset['group'] ?? '')));\n }\n\n function showPanel(open: boolean) {\n panel.hidden = !open;\n toggle.setAttribute('aria-expanded', String(open));\n if (open) closeOffered();\n }\n toggle.addEventListener('click', () => showPanel(panel.hidden));\n panel.addEventListener('keydown', (event) => {\n if (event.key !== 'Escape') return;\n event.preventDefault();\n showPanel(false);\n toggle.focus();\n });\n const element = el('div', { class: 'fd-search' }, el('div', { class: 'fd-search-field' }, ...icon('search'), chips, input, toggle), offeredList, panel);\n // A press anywhere else closes the menu.\n const outside = (event: Event) => {\n if (!panel.hidden && !element.contains(event.target as Node)) showPanel(false);\n };\n doc.addEventListener('pointerdown', outside);\n\n drawChips();\n drawPanel();\n return {\n element,\n destroy: () => doc.removeEventListener('pointerdown', outside),\n };\n}\n", "import {\n facetsToFilter,\n groupByFields,\n type ButtonNode,\n type DataSource,\n type Facet,\n type Form,\n type LineField,\n type ListNode,\n type Locale,\n type Page,\n type RecordId,\n type SortOrder,\n type Value,\n} from '@fieldia/core';\nimport { displayValue, type IconSet, type PreferenceStore } from '@fieldia/widgets';\nimport type { El } from './dom';\nimport { startingFacets } from './favourites';\nimport type { ViewerLabels } from './labels';\nimport { groupRow, type GroupContext, type Row } from './list-groups';\nimport { installListStyles } from './list-styles';\nimport { searchBar } from './search-bar';\n\nexport interface ListContext {\n page: Page;\n node: ListNode;\n form: Form;\n dataSource: DataSource | undefined;\n doc: Document;\n el: El;\n labels: ViewerLabels;\n locale: Locale;\n fill: (template: string, values: Record<string, string | number>) => string;\n confirm: (message: string) => Promise<boolean>;\n withIcon: (icon: string | undefined, text: string) => (Node | string)[];\n uid: (id: string) => string;\n icons?: IconSet;\n /** Where the list's favourite searches are kept. */\n preferences: PreferenceStore;\n onOpenRecord?: (id: RecordId) => void;\n}\n\nexport interface ListView {\n element: HTMLElement;\n /** Ask for the records again, keeping the page, the order and what is chosen where it still applies. */\n reload(): Promise<void>;\n destroy(): void;\n}\n\n/** Numbers line up on the end of their column. */\nconst NUMBERS = new Set(['integer', 'float', 'monetary']);\n/** Fields no list can put in order. */\nconst UNSORTABLE = new Set(['one2many', 'many2many', 'binary', 'image', 'html', 'json', 'properties']);\n\n/**\n * Records as a table: one page at a time, in the order a header asks for, each\n * row opening its record. Chosen rows get the list's buttons, which hand the\n * app their ids. A plain table, so it reads the same in every binding.\n */\nexport function listView(context: ListContext): ListView {\n const { page, node, form, el, labels, fill, locale, doc } = context;\n installListStyles(doc);\n const pageSize = node.pageSize ?? 40;\n const defaultSort = node.sort ?? [];\n let sort: SortOrder[] = defaultSort;\n let offset = 0;\n let total = 0;\n /** The page of records, when the list is not grouped. */\n let rows: Row[] = [];\n /** Each record's row, for the records on show however they are grouped. */\n const recordOf = new WeakMap<Element, Row>();\n const visible = () => [...body.querySelectorAll('.fd-list-row')].map((tr) => recordOf.get(tr) as Row);\n // Only a page of records gets this far: the page check refuses a list of anything else.\n const model = page.data.kind === 'record' ? page.data.model : '';\n let facets: Facet[] = startingFacets(node, context.preferences, page);\n /** In the order they were chosen, which is the order the app gets them. */\n const chosen = new Set<RecordId>();\n let asking = 0;\n let destroyed = false;\n\n // The columns, and what an amount needs to be read: its currency, from the record.\n const fields = [...new Set(node.columns.flatMap((name) => {\n const def = page.fields[name];\n return def.type === 'monetary' && def.currencyField ? [name, def.currencyField] : [name];\n }))];\n const show = (name: string, values: Record<string, Value>) => displayValue(page.fields[name] as LineField, values[name], values, locale);\n\n // ---- the table ---------------------------------------------------------------\n\n const chooseAll = el('input', { type: 'checkbox', class: 'fd-list-checkbox', 'aria-label': labels.selectAll });\n const headers = node.columns.map((name) => {\n const def = page.fields[name];\n const th = el('th', { scope: 'col', 'data-field': name, class: NUMBERS.has(def.type) ? 'fd-num' : undefined });\n if (UNSORTABLE.has(def.type)) th.append(def.label);\n else {\n const button = el('button', { type: 'button', class: 'fd-list-sort' }, def.label);\n button.addEventListener('click', () => {\n // The header's field leads; the list's own order breaks the ties.\n const desc = sort[0]?.field === name ? !sort[0].desc : false;\n sort = [{ field: name, ...(desc ? { desc } : {}) }, ...defaultSort.filter((order) => order.field !== name)];\n offset = 0;\n void load();\n });\n th.append(button);\n }\n return th;\n });\n const body = el('tbody');\n const table = el(\n 'table',\n { class: 'fd-list-table', 'aria-label': page.title },\n el('thead', {}, el('tr', {}, el('th', { class: 'fd-list-check', scope: 'col' }, chooseAll), ...headers)),\n body\n );\n const empty = el('p', { class: 'fd-list-empty', hidden: '' }, labels.noRecords);\n const retry = el('button', { type: 'button', class: 'fd-button fd-button-link' }, labels.retry);\n const failed = el('p', { class: 'fd-list-failed', role: 'alert', hidden: '' }, labels.loadFailed, ' ', retry);\n retry.addEventListener('click', () => void load());\n\n function row(record: Row, level = 0): HTMLTableRowElement {\n const name = show(node.columns[0], record.values) || String(record.id);\n const box = el('input', { type: 'checkbox', class: 'fd-list-checkbox', 'aria-label': fill(labels.selectRecord, { name }) });\n box.checked = chosen.has(record.id);\n box.addEventListener('change', () => {\n if (box.checked) chosen.add(record.id);\n else chosen.delete(record.id);\n drawChoice();\n });\n const tr = el(\n 'tr',\n { class: context.onOpenRecord ? 'fd-list-row fd-list-openable' : 'fd-list-row', tabindex: '0', 'data-id': String(record.id), 'data-level': level ? String(level) : undefined },\n el('td', { class: 'fd-list-check' }, box),\n // Each value in its own direction: a phone number or an amount reads left to right on a right-to-left page.\n ...node.columns.map((name) => el('td', { class: NUMBERS.has(page.fields[name].type) ? 'fd-num' : undefined }, el('bdi', {}, show(name, record.values))))\n );\n tr.addEventListener('click', (event) => {\n const cell = (event.target as Element).closest('td');\n // The box's own cell is a bigger target for the box.\n if (cell?.classList.contains('fd-list-check')) {\n if (event.target === cell) box.click();\n return;\n }\n context.onOpenRecord?.(record.id);\n });\n tr.addEventListener('keydown', (event) => {\n if (event.target !== tr) return;\n if (event.key === 'Enter') {\n event.preventDefault();\n context.onOpenRecord?.(record.id);\n } else if (event.key === ' ') {\n event.preventDefault();\n box.click();\n } else if (event.key === 'ArrowDown' || event.key === 'ArrowUp') {\n event.preventDefault();\n const next = event.key === 'ArrowDown' ? tr.nextElementSibling : tr.previousElementSibling;\n (next as HTMLElement | null)?.focus();\n }\n });\n recordOf.set(tr, record);\n return tr;\n }\n\n // ---- what is chosen, and the buttons for it --------------------------------------\n\n const count = el('span', { class: 'fd-list-count', role: 'status' });\n const clear = el('button', { type: 'button', class: 'fd-button fd-button-link' }, labels.clearSelection);\n const buttons = (node.actions ?? []).map((action: ButtonNode) => {\n const button = el('button', { type: 'button', class: `fd-button fd-button-${action.style ?? 'secondary'}`, 'data-node': action.id }, ...context.withIcon(action.icon, action.label));\n button.addEventListener('click', async () => {\n if (action.confirm && !(await context.confirm(action.confirm))) return;\n await form.runAction(action.id, { recordIds: [...chosen] });\n await load();\n });\n return button;\n });\n const selection = el('div', { class: 'fd-list-selection', hidden: '' }, count, ...buttons, clear);\n clear.addEventListener('click', () => {\n chosen.clear();\n for (const box of body.querySelectorAll<HTMLInputElement>('.fd-list-checkbox')) box.checked = false;\n drawChoice();\n });\n chooseAll.addEventListener('change', () => {\n for (const record of visible()) {\n if (chooseAll.checked) chosen.add(record.id);\n else chosen.delete(record.id);\n }\n for (const box of body.querySelectorAll<HTMLInputElement>('.fd-list-checkbox')) box.checked = chooseAll.checked;\n drawChoice();\n });\n\n function drawChoice() {\n const shown = visible();\n const onPage = shown.filter((record) => chosen.has(record.id)).length;\n chooseAll.checked = shown.length > 0 && onPage === shown.length;\n chooseAll.indeterminate = onPage > 0 && onPage < shown.length;\n selection.hidden = chosen.size === 0;\n count.textContent = fill(labels.selected, { n: chosen.size });\n for (const tr of body.querySelectorAll<HTMLElement>('.fd-list-row')) {\n tr.setAttribute('aria-selected', String([...chosen].some((id) => String(id) === tr.dataset['id'])));\n }\n }\n\n // ---- pages -------------------------------------------------------------------\n\n const range = el('span', { class: 'fd-pager-text' });\n const previous = el('button', { type: 'button', class: 'fd-button fd-pager-button', 'aria-label': labels.previousPage }, '\u2039');\n const next = el('button', { type: 'button', class: 'fd-button fd-pager-button', 'aria-label': labels.nextPage }, '\u203A');\n const pager = el('div', { class: 'fd-pager', role: 'group' }, range, previous, next);\n previous.addEventListener('click', () => {\n offset = Math.max(0, offset - pageSize);\n void load();\n });\n next.addEventListener('click', () => {\n offset += pageSize;\n void load();\n });\n\n function drawPager() {\n pager.hidden = total === 0;\n range.textContent = fill(labels.range, { from: offset + 1, to: Math.min(offset + rows.length, total), total });\n previous.disabled = offset === 0;\n next.disabled = offset + pageSize >= total;\n }\n\n function drawSort() {\n for (const th of headers) {\n const order = sort[0]?.field === th.dataset['field'] ? sort[0] : null;\n if (order) th.setAttribute('aria-sort', order.desc ? 'descending' : 'ascending');\n else th.removeAttribute('aria-sort');\n }\n }\n\n // ---- asking for the records ------------------------------------------------------\n\n /** Rows came or went: what is chosen keeps to the records on show. */\n function changed() {\n const shown = new Set(visible().map((record) => record.id));\n for (const id of [...chosen]) if (!shown.has(id)) chosen.delete(id);\n drawChoice();\n }\n\n const grouped = (source: DataSource): GroupContext => ({\n page,\n el,\n labels,\n fill,\n dataSource: source,\n model,\n fields,\n columns: node.columns.length + 1,\n pageSize,\n sort: () => sort,\n recordRow: row,\n changed,\n });\n\n async function load(): Promise<void> {\n const mine = ++asking;\n drawSort();\n table.setAttribute('aria-busy', 'true');\n let drawn: HTMLTableRowElement[] = [];\n try {\n const filter = facetsToFilter(facets, node);\n const grouping = groupByFields(facets);\n const source = context.dataSource;\n if (grouping.length && source?.groups && source.list) {\n // Grouped: a row for each value of the first field, each opening into the rest.\n const groups = await source.groups({ model, field: grouping[0], filter });\n if (mine !== asking || destroyed) return;\n rows = [];\n total = 0;\n drawn = groups.map((group) => groupRow(grouped(source), group, 0, filter, grouping));\n } else {\n const answer = source?.list ? await source.list({ model, fields, filter, sort, offset, limit: pageSize }) : { records: [], total: 0 };\n if (mine !== asking || destroyed) return;\n // Past the end, as when the last record of the last page went: back to the page that is left.\n if (!answer.records.length && answer.total > 0 && offset > 0) {\n offset = Math.floor((answer.total - 1) / pageSize) * pageSize;\n return load();\n }\n rows = answer.records;\n total = answer.total;\n drawn = rows.map((record) => row(record));\n }\n failed.hidden = true;\n } catch {\n if (mine !== asking || destroyed) return;\n rows = [];\n total = 0;\n failed.hidden = false;\n }\n body.replaceChildren(...drawn);\n empty.hidden = drawn.length > 0 || !failed.hidden;\n table.removeAttribute('aria-busy');\n drawPager();\n changed();\n }\n\n const search = searchBar({\n page,\n node,\n doc,\n el,\n labels,\n fill,\n uid: context.uid,\n icons: context.icons,\n preferences: context.preferences,\n facets,\n onChange(next) {\n facets = next;\n offset = 0;\n void load();\n },\n });\n const element = el(\n 'div',\n { class: 'fd-list', 'data-node': node.id },\n el('div', { class: 'fd-list-bar' }, search.element, pager),\n selection,\n el('div', { class: 'fd-list-scroll' }, table),\n empty,\n failed\n );\n void load();\n\n return {\n element,\n reload: load,\n destroy() {\n destroyed = true;\n search.destroy();\n },\n };\n}\n", "import { wideColumns, type FieldNode, type FieldType, type LabelPlace, type SectionNode } from '@fieldia/core';\n\n/**\n * Where a part sits, as the viewer lays a page out: how many columns the grid\n * round it has, whether anything is drawn round it yet, and where labels go\n * there. Worked out once, top down, so the stylesheet is handed plain facts.\n */\nexport interface Place {\n /** The columns of the grid it sits in, at full width: one on the page, in a tab or in a step. */\n columns: number;\n /** Nothing is drawn round it yet: a card here is a box of its own. */\n onPage: boolean;\n /** Where labels sit here, as the page or a group round it says; undefined leaves them to the skin. */\n labels?: LabelPlace;\n}\n\nexport type SectionStyle = NonNullable<SectionNode['style']>;\n\nexport interface SectionPlan {\n style: SectionStyle;\n /**\n * An arrangement: untitled and plain, it only holds parts side by side or\n * one under another. In a grid with columns it lays them on the `tracks` it\n * covers there; one column wide with columns of its own, they share that\n * one cell (`shared`). Anywhere else it has a grid of its own.\n */\n arrangement: boolean;\n at?: 'tracks' | 'shared';\n /** Where the parts inside it sit. */\n inner: Place;\n}\n\n/** How a section is drawn where it sits, and where that leaves the parts inside it. */\nexport function planSection(node: SectionNode, place: Place): SectionPlan {\n const style = node.style ?? 'card';\n const arrangement = style === 'plain' && !node.title;\n const own = wideColumns(node.columns);\n const span = node.colspan ?? 1;\n const at = arrangement && place.columns > 1 ? (span === 1 && own > 1 ? 'shared' : 'tracks') : undefined;\n return {\n style,\n arrangement,\n at,\n inner: {\n columns: at === 'tracks' ? Math.min(span, place.columns) : own,\n // A line under a title and a plain group draw no box: what is inside them still sits on the page.\n onPage: place.onPage && (style === 'plain' || style === 'line'),\n labels: node.labels ?? place.labels,\n },\n };\n}\n\n/** Kinds shown as a table: no room beside them for a label, which goes above. */\nconst TABLES = new Set<FieldType>(['one2many', 'matrix']);\n\n/**\n * Where a field's label sits: its own place, else where it is put; a table's label beside it goes above.\n * A tick box's words always come after the box: they are all it says, and beside or out of sight would part them from it.\n */\nexport function labelPlace(node: FieldNode, type: FieldType, place: LabelPlace | undefined): LabelPlace | 'after' | undefined {\n if (type === 'boolean' && node.widget === 'tick') return 'after';\n const chosen = node.labels ?? place;\n return chosen === 'beside' && TABLES.has(type) ? 'above' : chosen;\n}\n", "/** The viewer's way to make an element: a tag, its attributes (left out when undefined), and what goes in it. */\nexport type El = <K extends keyof HTMLElementTagNameMap>(tag: K, attrs?: Record<string, string | undefined>, ...children: (Node | string)[]) => HTMLElementTagNameMap[K];\n\n/**\n * Shown or hidden, written only when that changes. Every part of a form is\n * brought up to date at each change; writing what is there already still has\n * the browser look at the page anew, which on a big page is most of a key's time.\n */\nexport function setHidden(element: HTMLElement, hidden: boolean): void {\n if (element.hidden !== hidden) element.hidden = hidden;\n}\n\n/** Words written only when they change. */\nexport function setText(element: Node, text: string): void {\n if (element.textContent !== text) element.textContent = text;\n}\n\n/** An attribute, written only when it changes; `null` takes it away. */\nexport function setAttr(element: Element, name: string, value: string | null): void {\n if (element.getAttribute(name) === value) return;\n if (value === null) element.removeAttribute(name);\n else element.setAttribute(name, value);\n}\n", "import {\n createForm,\n checkPage,\n isRightToLeft,\n localizePage,\n translatePage,\n wideColumns,\n type ButtonNode,\n type FieldNode,\n type Form,\n type FormOptions,\n type FormState,\n type JsonValue,\n type LayoutNode,\n type Page,\n type RecordId,\n type SectionNode,\n type SheetNode,\n type SlotNode,\n type TabsNode,\n type TextNode,\n type DividerNode,\n type SpacerNode,\n type ImageNode,\n type WizardNode,\n type LabelPlace,\n type Locale,\n MESSAGES,\n} from '@fieldia/core';\nimport { browserPreferences, createWidget, drawIcon, installStyles, WIDGET_LABELS, type IconSet, type PreferenceStore, type WidgetFactory } from '@fieldia/widgets';\nimport { pageDialogs } from './related';\nimport { listView } from './list';\nimport { applyLook } from './look';\nimport { labelPlace, planSection, type Place } from './place';\nimport { setAttr, setHidden, setText } from './dom';\n\nexport type Skin = 'underline' | 'outlined';\n\nimport { ownLocale, VIEWER_LABELS, type ViewerLabels } from './labels';\nimport { keepTabIn } from './focus-trap';\nexport { VIEWER_LABELS, DEFAULT_LABELS, type ViewerLabels } from './labels';\n\n/** Fill a slot with the app's own content. Return a function to clean up. */\nexport type SlotRenderer = (element: HTMLElement, context: { form: Form; name: string }) => void | (() => void);\n\nexport interface ViewerOptions extends Omit<FormOptions, 'page'> {\n page: Page;\n /** A form made elsewhere, to share one record between two views. */\n form?: Form;\n skin?: Skin;\n /** Widgets that replace or add to the built-in ones, by `type` or `type.widget`. */\n widgets?: Record<string, WidgetFactory>;\n slots?: Record<string, SlotRenderer>;\n /**\n * The page's language, as a language tag (`ar`, `es`, `pt-BR`): the page's\n * own words in it when the page keeps them, and the viewer's labels,\n * validation messages and widget words in it when Fieldia has them (English,\n * Arabic, German, French; English otherwise \u2014 and in the one-tag script,\n * English until the language's own script is loaded: `fieldia.ar.js`, \u2026).\n * A language written right to left runs right to left. The language the\n * page is written in unless said.\n */\n locale?: Locale | (string & {});\n /** Labels that win over the language's defaults. */\n labels?: Partial<ViewerLabels>;\n dir?: 'ltr' | 'rtl';\n /** How to ask before a button with `confirm` runs. Defaults to a small dialog. */\n confirm?: (message: string) => Promise<boolean>;\n /** Where a person's choices about the page's look are kept, such as a table's columns. The browser's storage by default. */\n preferences?: PreferenceStore;\n /** False when something around the page saves it, such as a dialog: the page's own Save, Discard and Submit stay hidden. */\n showActions?: boolean;\n /**\n * Pages for the models links point to, so a link can show its record in a\n * dialog: Create and edit\u2026, and the button that opens the linked record.\n */\n relatedPages?: Record<string, Page> | ((model: string) => Page | null | undefined);\n /**\n * The app's own icons, or replacements for Fieldia's, by the name a page\n * gives them: the inside of a 24\u00D724 SVG, drawn with lines in the text colour.\n */\n icons?: IconSet;\n /**\n * Keys around the fields. Ctrl+Enter (Cmd+Enter on a Mac) saves, from\n * wherever the cursor is, unless `saveWithCtrlEnter` is false. With\n * `enterMovesToNext`, Enter moves to the next field instead of sending the form.\n */\n keys?: { saveWithCtrlEnter?: boolean; enterMovesToNext?: boolean };\n /** A \u2713 by a field's label once someone has filled it in and it would pass its checks. */\n showValid?: boolean;\n /** Where a save's progress shows: beside Save (the default), as a toast in a corner, or as a bar across the top. */\n saveStatus?: 'inline' | 'toast' | 'bar';\n /** Show the whole form read-only: every field locked, no Save. Buttons still run. */\n readonly?: boolean;\n /** An Edit button that unlocks a read-only form, and a Done that saves and locks it again. */\n editSwitch?: boolean;\n /**\n * The app's own translator, for apps that keep translations by text or by\n * key: every word of the page goes through it. Record data never does.\n */\n translate?: (text: string) => string;\n /** A list page: a row was opened, by a click or by Enter. The app shows the record. */\n onOpenRecord?: (id: RecordId) => void;\n}\n\nexport interface ViewerHandle {\n readonly form: Form;\n readonly element: HTMLElement;\n setSkin(skin: Skin): void;\n /** Save the record, or take the focus to the first problem when the form refuses. */\n save(): Promise<boolean>;\n /** Check the form without saving, taking the focus to the first problem. */\n check(): boolean;\n /** Lock or unlock the whole form. */\n setReadonly(readonly: boolean): void;\n isReadonly(): boolean;\n destroy(): void;\n}\n\ntype Updater = (state: FormState) => void;\n\nlet mounts = 0;\n\n/**\n * Render a page into `host` and keep it in step with its form. Plain DOM: the\n * React, Angular and Vue bindings are thin shells around this function.\n * Throws when the page does not validate, listing every problem.\n */\nexport function mountViewer(host: HTMLElement, options: ViewerOptions): ViewerHandle {\n const doc = host.ownerDocument;\n // The quick check of names and conditions: the full one, with its validation library, belongs where pages are made.\n const checked = checkPage(options.page);\n if (!checked.ok) {\n throw new Error(`This page cannot be shown:\\n${checked.issues.map((i) => ` ${i.path}: ${i.message}`).join('\\n')}`);\n }\n // The page's own words in its language first; the app's translator over what is left.\n const tag = options.locale ?? checked.page.language;\n const localized = tag ? localizePage(checked.page, tag) : checked.page;\n const page = options.translate ? translatePage(localized, options.translate) : localized;\n const locale = ownLocale(tag);\n const preferences = options.preferences ?? browserPreferences();\n const dialogs = pageDialogs(options);\n const ownsForm = !options.form;\n const form = options.form ?? createForm({ ...options, page, messages: options.messages ?? MESSAGES[locale] });\n const labels: ViewerLabels = { ...VIEWER_LABELS[locale], ...options.labels };\n const widgetLabels = WIDGET_LABELS[locale];\n const dir = options.dir ?? (tag && isRightToLeft(tag) ? 'rtl' : undefined);\n const prefix = `fd${++mounts}`;\n const updaters: Updater[] = [];\n const cleanups: (() => void)[] = [];\n const uid = (id: string) => `${prefix}-${id.replace(/[^A-Za-z0-9_-]/g, '_')}`;\n const fill = (template: string, values: Record<string, string | number>) =>\n template.replace(/\\{(\\w+)\\}/g, (_, key: string) => String(values[key] ?? ''));\n\n installStyles(doc);\n\n function el<K extends keyof HTMLElementTagNameMap>(tag: K, attrs: Record<string, string | undefined> = {}, ...children: (Node | string)[]) {\n const node = doc.createElement(tag);\n for (const [name, value] of Object.entries(attrs)) if (value !== undefined) node.setAttribute(name, value);\n node.append(...children);\n return node;\n }\n\n /**\n * Words with the icon a page names before them, when there is such an icon.\n * The words sit in a <bdi>: left as written on a page of the other direction,\n * they still run their own way, the icon still before them.\n */\n function withIcon(name: string | undefined, text: string): (Node | string)[] {\n const icon = drawIcon(doc, name, options.icons);\n const words = el('bdi', {}, text);\n return icon ? [icon, words] : [words];\n }\n\n const root = el('form', { class: 'fd-form', novalidate: '', 'data-fd-skin': options.skin ?? 'underline', dir, lang: tag, 'data-max-width': page.maxWidth });\n applyLook(root, page.look);\n const confirm = options.confirm ?? dialogConfirm;\n\n // ---- the parts -------------------------------------------------------\n\n /** A field with its label, help and messages. `labels` is where labels sit where it is put; the title's own fields take none. */\n function fieldItem(node: FieldNode, labels?: LabelPlace): HTMLElement {\n const def = page.fields[node.field];\n const id = uid(node.id);\n const labelsAt = labelPlace(node, def.type, labels);\n const wrapper = el('div', { class: 'fd-field', 'data-node': node.id, 'data-field': node.field, 'data-type': def.type, 'data-labels': labelsAt });\n if (node.colspan) wrapper.style.setProperty('--fd-span', String(node.colspan));\n const labelText = node.label ?? def.label;\n const label = el('label', { class: 'fd-label', id: `${id}-label`, for: id }, labelText);\n // The \u2713 of a field filled in right; never on a yes/no box, a table or a file, where it would say nothing.\n const mark = options.showValid && !NO_VALID_MARK.has(def.type) ? drawIcon(doc, 'check') : null;\n if (mark) {\n mark.classList.add('fd-valid-mark');\n label.append(mark);\n }\n const widget = createWidget({ form, name: node.field, field: def, node, id, document: doc, labels: widgetLabels, preferences, locale, dialogs }, options.widgets);\n // A label kept out of sight still names the box; the empty box shows it instead, unless the page gives it words of its own.\n if (labelsAt === 'hidden' && !node.placeholder) {\n const box = widget.element.matches(TEXT_BOX) ? widget.element : widget.element.querySelector(TEXT_BOX);\n box?.setAttribute('placeholder', labelText);\n }\n if (!['INPUT', 'SELECT', 'TEXTAREA'].includes(widget.element.tagName)) {\n // `for` stays: a custom field that puts the id on its own input is\n // labelled natively. Only a wrapper with a role (a radio group, say) may\n // carry a name; ARIA forbids naming a plain div or span.\n // A group inside a box of its own (a radio group with \"Clear selection\" under it) is named too.\n const named = widget.element.getAttribute('role') ? widget.element : widget.element.querySelector(`[id=\"${id}\"][role]`);\n named?.setAttribute('aria-labelledby', label.id);\n label.addEventListener('click', () => widget.focus());\n }\n const helpText = node.help ?? def.help;\n const help = helpText ? el('div', { class: 'fd-help', id: `${id}-help` }, helpText) : null;\n // Not an alert of its own: a refused save is announced once, naming every field to look at.\n const error = el('div', { class: 'fd-error', id: `${id}-error`, hidden: '' });\n // A warning from an answer rule, and one from the data source's onchange beside the field whose change brought it.\n const warning = el('div', { class: 'fd-warning', id: `${id}-warning`, role: 'status', hidden: '' });\n wrapper.append(...(labelsAt === 'after' ? [widget.element, label] : [label, widget.element]), ...(help ? [help] : []), error, warning);\n if (widget.destroy) cleanups.push(() => widget.destroy?.());\n // An answer rule's warning waits until the person leaves the field: no advice\n // mid-word. One already shown stays while they put it right, and goes once they have.\n let typing = false;\n let advice = '';\n wrapper.addEventListener('focusin', () => (typing = true));\n wrapper.addEventListener('focusout', (event) => {\n if (wrapper.contains(event.relatedTarget as Node | null)) return;\n typing = false;\n // Not at once: focus also leaves when a redraw removes the focused part\n // (a deleted line's button), and that redraw must finish first.\n queueMicrotask(() => update(form.getState()));\n });\n\n const update = (state: FormState) => {\n const shown = form.node(node.id);\n setHidden(wrapper, shown.invisible);\n wrapper.classList.toggle('fd-required', shown.required);\n const message = state.errors[node.field];\n setHidden(error, !message);\n setText(error, message ?? '');\n const now = state.warnings[node.field] ?? '';\n if (!typing || !now) advice = now;\n // An error shown says enough: the rule's warning gives way to it.\n const warned = [message ? '' : advice, state.warning && state.warningField === node.field ? state.warning : ''].filter(Boolean).join(' ');\n setHidden(warning, !warned);\n setText(warning, warned);\n if (mark) {\n const value = state.values[node.field];\n const filled = value !== null && value !== undefined && value !== '' && !(Array.isArray(value) && !value.length);\n const valid = !shown.readonly && !message && filled && state.dirty.includes(node.field) && form.problem(node.field) === null;\n wrapper.classList.toggle('fd-valid', valid);\n mark.toggleAttribute('hidden', !valid);\n }\n widget.update({\n value: state.values[node.field],\n values: state.values,\n readonly: shown.readonly || locked,\n required: shown.required,\n invalid: !!message,\n describedBy: [help?.id, message ? error.id : undefined, warned ? warning.id : undefined].filter(Boolean).join(' ') || undefined,\n });\n };\n updaters.push(update);\n return wrapper;\n }\n\n function hideWhen(element: HTMLElement, id: string) {\n updaters.push(() => setHidden(element, form.node(id).invisible));\n }\n\n function buttonItem(node: ButtonNode): HTMLElement {\n const button = el('button', { type: 'button', class: `fd-button fd-button-${node.style ?? 'secondary'}`, 'data-node': node.id }, ...withIcon(node.icon, node.label));\n spans(button, node.colspan);\n button.addEventListener('click', async () => {\n if (node.confirm && !(await confirm(node.confirm))) return;\n await form.runAction(node.id);\n });\n hideWhen(button, node.id);\n return button;\n }\n\n function textItem(node: TextNode): HTMLElement {\n const style = node.style ?? 'paragraph';\n const element = el(style === 'heading' ? 'h3' : 'p', { class: `fd-text-${style}`, 'data-node': node.id }, node.text);\n spans(element, node.colspan);\n hideWhen(element, node.id);\n return element;\n }\n\n function slotItem(node: SlotNode): HTMLElement {\n const element = el('div', { class: 'fd-slot', 'data-slot': node.name, 'data-node': node.id });\n const cleanup = options.slots?.[node.name]?.(element, { form, name: node.name });\n if (cleanup) cleanups.push(cleanup);\n hideWhen(element, node.id);\n return element;\n }\n\n /** The columns a part spans in the grid it sits in; the stylesheet keeps it within the columns there at each width. */\n function spans(element: HTMLElement, colspan: number | undefined) {\n if (colspan) element.style.setProperty('--fd-span', String(colspan));\n }\n\n /**\n * A grid of parts. With `columns` null, it has none of its own: it lays its\n * parts on the columns of the grid round it (an arrangement on its tracks).\n */\n function grid(children: LayoutNode[], columns: SectionNode['columns'] | null, place: Place): HTMLElement {\n const box = el('div', { class: 'fd-grid' });\n if (columns !== null) {\n box.style.setProperty('--fd-columns', String(wideColumns(columns)));\n // Counts given for the narrower widths replace the skin's own stacking there.\n if (typeof columns === 'object') {\n for (const width of ['medium', 'narrow'] as const) {\n const count = columns[width];\n if (count === undefined) continue;\n box.setAttribute(`data-columns-${width}`, String(count));\n box.style.setProperty(`--fd-columns-${width}`, String(count));\n }\n }\n }\n box.append(...children.map((child) => item(child, place)));\n return box;\n }\n\n /** Where the parts of a page, a tab or a step sit: one column, the page's labels. */\n const top = (onPage: boolean): Place => ({ columns: 1, onPage, labels: page.look?.labels });\n\n /** Folded sections, and how to open each: a problem inside one has to be seen. */\n const folds = new Map<HTMLElement, () => void>();\n\n function sectionItem(node: SectionNode, place: Place): HTMLElement {\n const plan = planSection(node, place);\n // An arrangement is no group to name, and a fieldset cannot lay its parts on the columns round it.\n const section = el(plan.arrangement ? 'div' : 'fieldset', {\n class: 'fd-section',\n 'data-node': node.id,\n 'data-style': plan.style,\n 'data-place': plan.at,\n 'data-on-page': plan.style === 'card' && place.onPage ? '' : undefined,\n });\n spans(section, node.colspan);\n if (node.labelWidth) section.style.setProperty('--fd-label-width', `${node.labelWidth}px`);\n const description = node.description ? el('p', { class: 'fd-section-description' }, node.description) : null;\n const content = grid(node.children, plan.at === 'tracks' ? null : node.columns, plan.inner);\n if (node.title && node.collapsible) {\n content.id = uid(`${node.id}-content`);\n const toggle = el(\n 'button',\n { type: 'button', class: 'fd-section-toggle', 'aria-controls': content.id },\n el('span', { class: 'fd-section-chevron', 'aria-hidden': 'true' }),\n ...withIcon(node.icon, node.title)\n );\n let open = node.collapsed !== true;\n const show = (next: boolean) => {\n open = next;\n toggle.setAttribute('aria-expanded', String(open));\n content.hidden = !open;\n if (description) description.hidden = !open;\n section.classList.toggle('fd-section-folded', !open);\n };\n toggle.addEventListener('click', () => show(!open));\n folds.set(section, () => show(true));\n show(open);\n section.append(el('legend', { class: 'fd-section-title' }, toggle));\n } else if (node.title) {\n section.append(el('legend', { class: 'fd-section-title' }, ...withIcon(node.icon, node.title)));\n }\n if (description) section.append(description);\n section.append(content);\n hideWhen(section, node.id);\n return section;\n }\n\n function tabsItem(node: TabsNode, place: Place): HTMLElement {\n const box = el('div', { class: 'fd-tabs', 'data-node': node.id });\n spans(box, node.colspan);\n const list = el('div', { class: 'fd-tablist', role: 'tablist' });\n // The tab someone picked. Until they pick, the first visible tab is open \u2014\n // a tab hidden while the record loads must not leave its neighbour open.\n let picked: string | null = null;\n let active = node.children[0].id;\n const parts = node.children.map((tab) => {\n const tabId = uid(`${tab.id}-tab`);\n const panelId = uid(`${tab.id}-panel`);\n const button = el('button', { type: 'button', class: 'fd-tab', role: 'tab', id: tabId, 'aria-controls': panelId, 'data-node': tab.id }, ...withIcon(tab.icon, tab.label));\n // A tab's parts sit where the tabs do: on the page, or in the box round them.\n const panel = el('div', { class: 'fd-tabpanel', role: 'tabpanel', id: panelId, 'aria-labelledby': tabId }, grid(tab.children, 1, { columns: 1, onPage: place.onPage, labels: place.labels }));\n button.addEventListener('click', () => {\n picked = active = tab.id;\n render(form.getState());\n });\n list.append(button);\n return { tab, button, panel };\n });\n list.addEventListener('keydown', (event) => {\n const shown = parts.filter((p) => !p.button.hidden);\n const at = shown.findIndex((p) => p.tab.id === active);\n const move = { ArrowRight: 1, ArrowLeft: -1, Home: -at, End: shown.length - 1 - at }[event.key];\n if (move === undefined || at === -1) return;\n event.preventDefault();\n const rtl = root.getAttribute('dir') === 'rtl' && (event.key === 'ArrowRight' || event.key === 'ArrowLeft');\n const next = shown[(at + (rtl ? -move : move) + shown.length) % shown.length];\n picked = active = next.tab.id;\n render(form.getState());\n next.button.focus();\n });\n box.append(list, ...parts.map((p) => p.panel));\n updaters.push(() => {\n box.hidden = form.node(node.id).invisible;\n const shown = parts.filter((p) => !form.node(p.tab.id).invisible);\n const keep = picked !== null && shown.some((p) => p.tab.id === picked);\n if (keep) active = picked as string;\n else if (shown.length) active = shown[0].tab.id;\n for (const p of parts) {\n const selected = p.tab.id === active;\n p.button.hidden = !shown.includes(p);\n p.button.setAttribute('aria-selected', String(selected));\n p.button.tabIndex = selected ? 0 : -1;\n p.panel.hidden = !selected;\n }\n });\n return box;\n }\n\n function item(node: LayoutNode, place: Place): HTMLElement {\n switch (node.type) {\n case 'field':\n return fieldItem(node, place.labels);\n case 'button':\n return buttonItem(node);\n case 'text':\n return textItem(node);\n case 'slot':\n return slotItem(node);\n case 'section':\n return sectionItem(node, place);\n case 'tabs':\n return tabsItem(node, place);\n case 'divider':\n case 'spacer':\n case 'image':\n return blockItem(node);\n }\n }\n\n /** A line across the row, empty room, or a picture: shown and hidden by its rule like any part. */\n function blockItem(node: DividerNode | SpacerNode | ImageNode): HTMLElement {\n const element =\n node.type === 'divider' ? el('hr', { class: 'fd-divider', 'data-node': node.id })\n : node.type === 'spacer' ? el('div', { class: 'fd-block fd-spacer', 'aria-hidden': 'true', 'data-node': node.id })\n : figure(node);\n if (node.type !== 'divider' && node.colspan) element.style.setProperty('--fd-span', String(node.colspan));\n hideWhen(element, node.id);\n return element;\n }\n\n /** A picture as wide and where its page says, opening its link in a new tab \u2014 a web or mail address only \u2014 its caption under it. */\n function figure(node: ImageNode): HTMLElement {\n const image = el('img', { class: 'fd-image', src: node.src, alt: node.alt, loading: 'lazy' });\n const href = node.href && /^(https?:\\/\\/|mailto:)/i.test(node.href) ? node.href : undefined;\n const element = el(\n 'figure',\n { class: 'fd-block fd-figure', 'data-node': node.id, 'data-align': node.align },\n href ? el('a', { href, target: '_blank', rel: 'noopener noreferrer' }, image) : image,\n ...(node.caption ? [el('figcaption', { class: 'fd-caption' }, node.caption)] : [])\n );\n const width = typeof node.width === 'number' ? `${node.width}px` : node.width && { small: '160px', medium: '320px', large: '480px', full: '100%' }[node.width];\n if (width) element.style.setProperty('--fd-image-width', width);\n return element;\n }\n\n // ---- shared chrome ----------------------------------------------------------\n\n /** The whole form locked: every field read-only, no Save; buttons still run. */\n let locked = options.readonly === true;\n // Edit unlocks; Done saves what changed first, and locks only once that is saved.\n const editSwitch = options.editSwitch ? el('button', { type: 'button', class: 'fd-button fd-edit-switch' }) : null;\n editSwitch?.addEventListener('click', async () => {\n if (!locked) {\n if (form.getState().dirty.length) {\n const saved = await form.save();\n if (!saved) {\n if (!form.getState().saveProblem) announce(checkText(form.getState()));\n focusFirstProblem();\n return;\n }\n }\n locked = true;\n } else locked = false;\n root.toggleAttribute('data-readonly', locked);\n render(form.getState());\n });\n root.toggleAttribute('data-readonly', locked);\n updaters.push(() => {\n if (!editSwitch) return;\n editSwitch.textContent = locked ? labels.edit : labels.done;\n editSwitch.classList.toggle('fd-button-primary', locked);\n });\n\n // The status says its words alone, so a screen reader hears them; Retry sits beside it.\n const statusText = el('div', { class: 'fd-status', role: 'status', 'aria-live': 'polite' });\n const retry = el('button', { type: 'button', class: 'fd-button fd-button-link fd-retry', hidden: '' }, labels.retry);\n retry.addEventListener('click', () => void submitOrSave());\n const status = el('div', { class: 'fd-status-box' }, statusText, retry);\n const notDone = () => (page.data.kind === 'responses' ? labels.notSent : labels.notSaved);\n /** \"Not saved. Check: Email, Phone\": the fields with a problem, in the order they show. */\n function checkText(state: FormState): string {\n const names: string[] = [];\n for (const key of Object.keys(state.errors)) {\n const field = key.split('.')[0];\n const shown = root.querySelector(`.fd-field[data-field=\"${field}\"]:not([hidden]) > .fd-label`);\n const name = shown?.firstChild?.textContent ?? page.fields[field]?.label ?? field;\n if (!names.includes(name)) names.push(name);\n }\n const inOrder = [...root.querySelectorAll('.fd-field[data-field] > .fd-label')].map((label) => label.firstChild?.textContent ?? '');\n names.sort((a, b) => (inOrder.indexOf(a) + 1 || Infinity) - (inOrder.indexOf(b) + 1 || Infinity));\n return names.length ? fill(labels.checkFields, { what: notDone(), fields: names.join(', ') }) : notDone();\n }\n let quietTimer: ReturnType<typeof setTimeout> | undefined;\n updaters.push((state) => {\n const problem = state.saveProblem;\n const text =\n state.status === 'saving' ? labels.saving\n : state.status === 'saved' ? labels.saved\n : state.status === 'loading' ? labels.loading\n : state.status === 'error' && problem ? (problem.kind === 'fields' ? checkText(state) : problem.kind === 'other' ? problem.message : notDone())\n : state.status === 'error' ? state.error ?? ''\n : '';\n // A problem is said once, at once, by the announcer (or the banner, or a dialog): the status shows it and keeps quiet.\n setAttr(statusText, 'aria-live', state.status === 'error' && problem ? 'off' : 'polite');\n setText(statusText, text);\n setHidden(retry, !(state.status === 'error' && problem?.kind === 'other'));\n statusText.classList.toggle('fd-status-error', state.status === 'error');\n statusText.classList.toggle('fd-status-saved', state.status === 'saved');\n // A toast shows while there is something to say, and lets \"Saved\" go after a moment.\n if (options.saveStatus === 'toast') {\n clearTimeout(quietTimer);\n status.hidden = !text;\n if (state.status === 'saved') quietTimer = setTimeout(() => (status.hidden = true), 2500);\n }\n });\n\n // A save the network failed: a banner over the page, with Retry.\n const bannerRetry = el('button', { type: 'button', class: 'fd-button fd-retry' }, labels.retry);\n bannerRetry.addEventListener('click', () => void submitOrSave());\n const banner = el('div', { class: 'fd-banner fd-tone-warning', role: 'alert', hidden: '' }, el('span', { class: 'fd-banner-text' }, labels.offline), bannerRetry);\n /** Said at once to a screen reader: why a save or send did not go through. */\n const announcer = el('div', { class: 'fd-announce', role: 'alert', 'aria-live': 'assertive' });\n function announce(text: string) {\n announcer.textContent = '';\n setTimeout(() => (announcer.textContent = text), 0);\n }\n // Each new reason a save was refused, from Save or from autosave, is shown where it belongs.\n let seenProblem: FormState['saveProblem'] = null;\n updaters.push((state) => {\n if (state.saveProblem === seenProblem) return;\n seenProblem = state.saveProblem;\n banner.hidden = seenProblem?.kind !== 'network';\n if (!seenProblem) return;\n if (seenProblem.kind === 'rule') void dialogConfirm(seenProblem.message, false);\n else if (seenProblem.kind === 'fields') announce(checkText(state));\n else if (seenProblem.kind === 'other') announce(seenProblem.message);\n });\n\n const draft = el('div', { class: 'fd-draft', hidden: '' });\n const draftText = el('span');\n const restore = el('button', { type: 'button', class: 'fd-button fd-button-primary' }, labels.restore);\n const discardDraft = el('button', { type: 'button', class: 'fd-button fd-button-link' }, labels.discardDraft);\n restore.addEventListener('click', () => form.restoreDraft());\n discardDraft.addEventListener('click', () => form.discardDraft());\n draft.append(draftText, restore, discardDraft);\n updaters.push((state) => {\n setHidden(draft, !state.draft);\n if (state.draft) draftText.textContent = fill(labels.draftFound, { time: new Date(state.draft.savedAt).toLocaleString() });\n });\n\n function focusFirstProblem() {\n const invalid = root.querySelector<HTMLElement>('[aria-invalid=\"true\"]');\n if (!invalid) return;\n for (let folded = invalid.closest<HTMLElement>('.fd-section-folded'); folded; folded = folded.parentElement?.closest<HTMLElement>('.fd-section-folded') ?? null) {\n folds.get(folded)?.();\n }\n // A widget that knows where its problem is (a cell of a grid) takes the focus there itself.\n if (!invalid.dispatchEvent(new CustomEvent('fd-focus-problem', { cancelable: true }))) return;\n const target = invalid.matches('input, select, textarea, button') ? invalid : invalid.querySelector<HTMLElement>('input, select, textarea, button');\n target?.focus();\n }\n\n const done = el('div', { class: 'fd-done', hidden: '' }, el('p', { class: 'fd-done-title' }, labels.submitted));\n const again = el('button', { type: 'button', class: 'fd-button' }, labels.submitAnother);\n done.append(again);\n const content = el('div', { class: 'fd-content' });\n\n async function submitOrSave() {\n const saved = await form.save();\n if (!saved) {\n // Stopped by the page's own checks: say which fields; a refused save says so above.\n if (!form.getState().saveProblem) announce(checkText(form.getState()));\n focusFirstProblem();\n return;\n }\n if (page.data.kind === 'responses') {\n content.hidden = true;\n done.hidden = false;\n }\n }\n again.addEventListener('click', () => {\n form.reset();\n content.hidden = false;\n done.hidden = true;\n });\n\n function pageHead(): HTMLElement | null {\n if (!page.title && !page.description) return null;\n const head = el('header', { class: 'fd-page-head' });\n if (page.title) head.append(el('h1', { class: 'fd-page-title' }, page.title));\n if (page.description) head.append(el('p', { class: 'fd-page-description' }, page.description));\n return head;\n }\n\n // ---- the four page layouts ---------------------------------------------------\n\n function sectionsLayout(node: { id: string; children: LayoutNode[] }): HTMLElement {\n const box = el('div', { class: 'fd-sections', 'data-node': node.id }, ...node.children.map((child) => item(child, top(true))));\n const action = el('button', { type: 'submit', class: 'fd-button fd-button-primary' }, page.data.kind === 'responses' ? labels.submit : labels.save);\n const actions = el('div', { class: 'fd-actions fd-actions-end' }, status, action);\n if (page.data.kind === 'record') {\n // A record offers Save and Discard once something changes, the same as on a sheet.\n const discard = el('button', { type: 'button', class: 'fd-button' }, labels.discard);\n discard.addEventListener('click', () => form.reset());\n actions.insertBefore(discard, action);\n updaters.push((state) => {\n const dirty = state.dirty.length > 0 && state.status !== 'saving' && !locked;\n setHidden(action, !dirty);\n setHidden(discard, !dirty);\n });\n } else updaters.push(() => setHidden(action, locked));\n if (editSwitch) actions.prepend(editSwitch);\n if (options.showActions === false) return el('div', {}, box);\n if (page.actionsPosition === 'top') {\n actions.classList.add('fd-actions-top');\n return el('div', {}, actions, box);\n }\n return el('div', {}, box, actions);\n }\n\n function wizardLayout(node: WizardNode): HTMLElement {\n const box = el('div', { class: 'fd-wizard', 'data-node': node.id });\n const progressText = el('div', { class: 'fd-progress-text' });\n const bar = el('span');\n box.append(el('div', { class: 'fd-progress' }, progressText, el('div', { class: 'fd-progress-bar' }, bar)));\n // A clickable wizard lists its steps: back to any, forward past those that are complete.\n const list = node.clickable ? el('ol', { class: 'fd-steps-list' }) : null;\n const stepButtons = new Map<string, HTMLButtonElement>();\n if (list) {\n for (const step of node.children) {\n const go = el('button', { type: 'button', class: 'fd-step-link' }, ...withIcon(step.icon, step.label));\n go.addEventListener('click', () => {\n if (form.goTo(step.id)) focusStep();\n else focusFirstProblem();\n });\n stepButtons.set(step.id, go);\n list.append(el('li', {}, go));\n }\n box.append(el('nav', { class: 'fd-steps', 'aria-label': labels.steps }, list));\n }\n const panels = node.children.map((step) => {\n const panel = el('section', { class: 'fd-step', 'data-node': step.id, 'aria-labelledby': uid(`${step.id}-title`) });\n panel.append(el('h2', { class: 'fd-step-title', id: uid(`${step.id}-title`) }, ...withIcon(step.icon, step.label)));\n if (step.description) panel.append(el('p', { class: 'fd-section-description' }, step.description));\n // The step is the box: a card in it draws none of its own.\n panel.append(grid(step.children, 1, top(false)));\n box.append(panel);\n return { step, panel };\n });\n const back = el('button', { type: 'button', class: 'fd-button' }, node.backLabel ?? labels.back);\n const skip = el('button', { type: 'button', class: 'fd-button fd-button-link' }, labels.skip);\n const forward = el('button', { type: 'submit', class: 'fd-button fd-button-primary' });\n box.append(el('div', { class: 'fd-wizard-nav' }, back, el('span', { class: 'fd-spacer' }), status, skip, forward));\n back.addEventListener('click', () => {\n if (form.back()) focusStep();\n });\n skip.addEventListener('click', () => {\n if (form.skip()) focusStep();\n });\n const isLast = () => {\n const steps = form.steps();\n return steps.indexOf(form.getState().step ?? '') === steps.length - 1;\n };\n wizardForward = async () => {\n if (isLast()) return submitOrSave();\n if (form.next()) focusStep();\n else focusFirstProblem();\n };\n function focusStep() {\n const current = panels.find((p) => p.step.id === form.getState().step);\n current?.panel.querySelector<HTMLElement>('input, select, textarea, [role=radio]')?.focus();\n }\n updaters.push((state) => {\n const steps = form.steps();\n const index = Math.max(0, steps.indexOf(state.step ?? ''));\n progressText.textContent = fill(labels.stepOf, { n: index + 1, total: steps.length });\n bar.style.width = `${((index + 1) / Math.max(1, steps.length)) * 100}%`;\n for (const { step, panel } of panels) panel.hidden = step.id !== state.step;\n const last = index === steps.length - 1;\n back.hidden = index === 0;\n skip.hidden = last || !node.children.find((step) => step.id === state.step)?.optional;\n forward.textContent = last ? node.finishLabel ?? labels.submit : node.nextLabel ?? labels.next;\n for (const [id, go] of stepButtons) {\n const at = steps.indexOf(id);\n (go.parentElement as HTMLElement).hidden = at === -1;\n go.classList.toggle('fd-step-done', at !== -1 && at < index);\n go.classList.toggle('fd-step-skipped', state.skipped.includes(id));\n if (id === state.step) go.setAttribute('aria-current', 'step');\n else go.removeAttribute('aria-current');\n }\n });\n return box;\n }\n\n function sheetLayout(node: SheetNode): HTMLElement {\n const pageBox = el('div', { class: 'fd-sheet-page', 'data-node': node.id });\n const actions = el('div', { class: 'fd-actions' });\n const save = el('button', { type: 'submit', class: 'fd-button fd-button-primary' }, labels.save);\n const discard = el('button', { type: 'button', class: 'fd-button' }, labels.discard);\n discard.addEventListener('click', () => form.reset());\n // Save and Discard lead the header bar, or close the sheet when the page puts them at its foot.\n const atFoot = page.actionsPosition === 'bottom';\n const foot = el('div', { class: 'fd-actions fd-actions-end fd-sheet-foot' });\n if (options.showActions === false) actions.append(...(node.buttons ?? []).map(buttonItem));\n else if (atFoot) {\n actions.append(...(node.buttons ?? []).map(buttonItem));\n foot.append(status, discard, save);\n } else actions.append(save, discard, ...(node.buttons ?? []).map(buttonItem), status);\n // The Edit switch leads the header bar, before Save and the record's own buttons.\n if (editSwitch && options.showActions !== false) actions.prepend(editSwitch);\n updaters.push((state) => {\n const dirty = state.dirty.length > 0 && state.status !== 'saving' && !locked;\n save.hidden = !dirty;\n discard.hidden = !dirty;\n });\n const header = el('div', { class: 'fd-header' }, actions);\n const underTitle = node.statusbar?.position === 'title';\n if (node.statusbar && !underTitle) header.append(statusbar(node.statusbar));\n\n const card = el('div', { class: 'fd-card' });\n if (node.ribbon) {\n const ribbon = el('div', { class: `fd-ribbon fd-tone-${node.ribbon.tone ?? 'muted'}`, 'data-node': node.ribbon.id }, node.ribbon.label);\n hideWhen(ribbon, node.ribbon.id);\n // The ribbon is clipped to the card's corner by its own frame, so the card itself never clips: lists open past it.\n card.append(el('div', { class: 'fd-ribbon-frame' }, ribbon));\n }\n if (node.statButtons?.length) {\n const stats = el('div', { class: 'fd-stats' });\n for (const stat of node.statButtons) {\n const value = el('span', { class: 'fd-stat-value' });\n const icon = drawIcon(doc, stat.icon, options.icons);\n const words = el('span', { class: 'fd-stat-words' }, value, el('span', { class: 'fd-stat-label' }, stat.label));\n const button = el('button', { type: 'button', class: 'fd-stat', 'data-node': stat.id }, ...(icon ? [icon, words] : [words]));\n button.addEventListener('click', () => void form.runAction(stat.id));\n updaters.push((state) => {\n button.hidden = form.node(stat.id).invisible;\n const count = stat.field ? state.values[stat.field] : null;\n value.textContent = count === null || count === undefined ? '' : String(count);\n });\n stats.append(button);\n }\n card.append(stats);\n }\n for (const alert of node.alerts ?? []) {\n const box = el('div', { class: `fd-alert fd-tone-${alert.tone ?? 'info'}`, role: 'status', 'data-node': alert.id }, el('span', { class: 'fd-alert-message' }, alert.message));\n if (alert.dismissible) {\n // Closed, it stays closed while the page is open, whatever its condition does.\n let dismissed = false;\n const close = el('button', { type: 'button', class: 'fd-alert-close', 'aria-label': labels.dismiss }, '\u00D7');\n close.addEventListener('click', () => {\n dismissed = true;\n box.hidden = true;\n });\n box.append(close);\n updaters.push(() => {\n box.hidden = dismissed || form.node(alert.id).invisible;\n });\n } else hideWhen(box, alert.id);\n card.append(box);\n }\n if (node.badges?.length) {\n const badges = el('div', { class: 'fd-badges' });\n for (const badge of node.badges) {\n const chip = el('span', { class: `fd-badge fd-tone-${badge.tone ?? 'muted'}`, 'data-node': badge.id }, ...withIcon(badge.icon, badge.label));\n hideWhen(chip, badge.id);\n badges.append(chip);\n }\n updaters.push(() => {\n badges.hidden = [...badges.children].every((chip) => (chip as HTMLElement).hidden);\n });\n card.append(badges);\n }\n if (node.title) {\n const title = el('div', { class: 'fd-title' });\n if (node.title.above?.length) title.append(el('div', { class: 'fd-title-above' }, ...node.title.above.map((part) => fieldItem(part))));\n title.append(fieldItem({ type: 'field', id: '#title', field: node.title.field, placeholder: node.title.placeholder }));\n if (node.title.subtitleField) title.append(fieldItem({ type: 'field', id: '#subtitle', field: node.title.subtitleField }));\n if (node.title.below?.length) title.append(el('div', { class: 'fd-title-below' }, ...node.title.below.map((part) => fieldItem(part))));\n const row = el('div', { class: 'fd-title-row' }, title);\n if (node.title.avatarField) {\n const avatar = fieldItem({ type: 'field', id: '#avatar', field: node.title.avatarField });\n avatar.classList.add('fd-avatar');\n row.append(avatar);\n }\n card.append(row);\n }\n if (node.statusbar && underTitle) card.append(el('div', { class: 'fd-title-statusbar' }, statusbar(node.statusbar)));\n card.append(grid(node.children, 1, top(false)));\n if (atFoot && options.showActions !== false) {\n card.append(foot);\n updaters.push((state) => {\n foot.hidden = state.dirty.length === 0 && !statusText.textContent;\n });\n }\n\n const layout = el('div', { class: 'fd-sheet-layout' }, card);\n if (node.sidePanel) {\n layout.classList.add('fd-has-side');\n layout.append(el('aside', { class: 'fd-side' }, slotItem(node.sidePanel)));\n }\n pageBox.append(header, layout);\n return pageBox;\n }\n\n /** The sheet header's statusbar: the same widget a form can place anywhere. */\n function statusbar(config: NonNullable<SheetNode['statusbar']>): HTMLElement {\n const def = page.fields[config.field];\n const barOptions: { [key: string]: JsonValue } = { clickable: config.clickable === true };\n if (config.visibleStates) barOptions['visibleStates'] = config.visibleStates;\n const node: FieldNode = { type: 'field', id: '#statusbar', field: config.field, widget: 'statusbar', options: barOptions };\n const widget = createWidget(\n { form, name: config.field, field: def, node, id: uid('statusbar'), document: doc, labels: widgetLabels, preferences, locale, dialogs },\n options.widgets\n );\n updaters.push((state) =>\n widget.update({ value: state.values[config.field], values: state.values, readonly: form.node('#statusbar').readonly || locked, required: false, invalid: false })\n );\n return widget.element;\n }\n\n let wizardForward: (() => Promise<void>) | null = null;\n\n const layout = page.layout;\n let body: HTMLElement;\n if (layout.type === 'sheet') body = sheetLayout(layout);\n else if (layout.type === 'wizard') body = wizardLayout(layout);\n else if (layout.type === 'tabs') body = sectionsLayout({ id: `${layout.id}-page`, children: [layout] });\n else if (layout.type === 'list') {\n const list = listView({\n page,\n node: layout,\n form,\n dataSource: options.dataSource,\n doc,\n el,\n labels,\n locale,\n fill,\n confirm,\n withIcon,\n uid,\n icons: options.icons,\n preferences,\n onOpenRecord: options.onOpenRecord,\n });\n cleanups.push(list.destroy);\n body = list.element;\n }\n else body = sectionsLayout(layout);\n\n const head = layout.type === 'sheet' ? null : pageHead();\n content.append(...(head ? [head] : []), banner, draft, body);\n root.append(content, done, announcer);\n // The status leaves its place beside Save when the page wants it in a corner or across the top.\n if (options.saveStatus === 'toast') {\n status.classList.add('fd-toast');\n root.append(status);\n } else if (options.saveStatus === 'bar') {\n status.classList.add('fd-status-bar');\n content.prepend(status);\n }\n\n root.addEventListener('submit', (event) => {\n event.preventDefault();\n if (layout.type === 'list') return;\n if (wizardForward) void wizardForward();\n else void submitOrSave();\n });\n\n // ---- keys -------------------------------------------------------------------\n\n /** Text typed and not yet taken, such as a tag without its Enter, is taken now. */\n function commitTyping() {\n const active = doc.activeElement;\n if (active && root.contains(active) && (active.tagName === 'INPUT' || active.tagName === 'TEXTAREA')) {\n active.dispatchEvent(new Event('change', { bubbles: true }));\n }\n }\n\n /** The fields Enter can move between: on this page, shown, with a box to type or choose in, outside tables of lines. */\n function nextField(from: HTMLElement): HTMLElement | null {\n const fields = [...root.querySelectorAll<HTMLElement>('.fd-field')].filter(\n (field) => !field.closest('[hidden], [data-type=\"one2many\"] .fd-field, .fd-form-dialog') && !field.parentElement?.closest('[data-type=\"one2many\"]')\n );\n const here = from.closest('.fd-field');\n const after = fields.slice(fields.indexOf(here as HTMLElement) + 1);\n for (const field of after) {\n const control = field.querySelector<HTMLElement>('input:not([type=\"hidden\"]):not([readonly]):not([disabled]), select:not([disabled]), textarea:not([readonly]), [contenteditable=\"true\"]');\n if (control) return control;\n }\n return null;\n }\n\n root.addEventListener('keydown', (event) => {\n // A list has nothing to save, and its rows keep their own keys.\n if (event.isComposing || event.key !== 'Enter' || layout.type === 'list') return;\n // An app's own content in a slot, such as a chatter's composer, keeps its keys.\n if ((event.target as Element).closest('.fd-slot')) return;\n const keys = options.keys ?? {};\n if (event.ctrlKey || event.metaKey) {\n // Saves even after a field used the Enter (a tag box adding its tag); the grid keeps its own keys.\n if (keys.saveWithCtrlEnter === false || options.showActions === false) return;\n if ((event.target as Element).closest('.ag-root-wrapper')) return;\n event.preventDefault();\n commitTyping();\n if (wizardForward) void wizardForward();\n else void submitOrSave();\n return;\n }\n // A plain Enter a field used itself, such as picking from an open list, is the field's.\n if (event.defaultPrevented || !keys.enterMovesToNext || event.shiftKey || event.altKey) return;\n const from = event.target as HTMLElement;\n if (from.tagName !== 'INPUT' && from.tagName !== 'SELECT') return;\n if (from.closest('[data-type=\"one2many\"]')) return;\n if (['button', 'submit', 'reset', 'file'].includes((from as HTMLInputElement).type)) return;\n event.preventDefault();\n nextField(from)?.focus();\n });\n\n // ---- confirmation dialog -----------------------------------------------------\n\n /** A question with Cancel and OK, or with `withCancel` false a notice with OK alone. */\n function dialogConfirm(message: string, withCancel = true): Promise<boolean> {\n return new Promise((resolve) => {\n const text = el('p', { id: `${prefix}-confirm` }, message);\n const cancel = el('button', { type: 'button', class: 'fd-button' }, labels.cancel);\n const ok = el('button', { type: 'button', class: 'fd-button fd-button-primary' }, labels.ok);\n const dialog = el('div', { class: 'fd-dialog', role: 'alertdialog', 'aria-modal': 'true', 'aria-labelledby': text.id }, text, el('div', { class: 'fd-actions fd-actions-end' }, ...(withCancel ? [cancel, ok] : [ok])));\n const backdrop = el('div', { class: 'fd-dialog-backdrop' }, dialog);\n const doc = root.ownerDocument;\n const opener = doc.activeElement as HTMLElement | null;\n const close = (answer: boolean) => {\n backdrop.remove();\n // Back to what had focus when it asked; or, when that let go of it \u2014 Save hides while it saves \u2014 to Save, shown again.\n const shown = (e: HTMLElement | null) => !!e && e !== doc.body && e.isConnected && !e.closest('[hidden]');\n const back = shown(opener) ? opener : root.querySelector<HTMLElement>('button[type=\"submit\"]:not([hidden])');\n back?.focus();\n resolve(answer);\n };\n cancel.addEventListener('click', () => close(false));\n ok.addEventListener('click', () => close(true));\n backdrop.addEventListener('keydown', (event) => {\n if (event.key === 'Escape') close(false);\n else keepTabIn(dialog, event);\n });\n root.append(backdrop);\n ok.focus();\n });\n }\n\n // ---- go -------------------------------------------------------------------\n\n function render(state: FormState) {\n for (const update of updaters) update(state);\n }\n\n host.append(root);\n const unsubscribe = form.subscribe(render);\n render(form.getState());\n if (form.getState().status === 'idle') void form.load();\n\n return {\n form,\n element: root,\n setSkin(skin) {\n root.setAttribute('data-fd-skin', skin);\n },\n async save() {\n const saved = await form.save();\n if (!saved) focusFirstProblem();\n return saved;\n },\n check() {\n const valid = form.validate();\n if (!valid) focusFirstProblem();\n return valid;\n },\n setReadonly(readonly) {\n locked = readonly;\n root.toggleAttribute('data-readonly', locked);\n render(form.getState());\n },\n isReadonly: () => locked,\n destroy() {\n unsubscribe();\n for (const cleanup of cleanups) cleanup();\n root.remove();\n if (ownsForm) form.dispose();\n },\n };\n}\n\n/** The boxes a label can be shown in, as the words of an empty box. */\nconst TEXT_BOX = 'input:not([type=\"checkbox\"]):not([type=\"radio\"]):not([type=\"file\"]):not([type=\"hidden\"]), textarea';\n\n/** Fields whose \u2713 would say nothing: a yes/no box is never wrong, a table or a file has its own look. */\nconst NO_VALID_MARK = new Set(['boolean', 'one2many', 'binary', 'image', 'html', 'json', 'properties']);\n", "import { MESSAGES, type Locale, type Messages } from '@fieldia/core';\nimport { WIDGET_LABELS, type WidgetLabels } from '@fieldia/widgets';\nimport { VIEWER_LABELS, type ViewerLabels } from './labels';\n\n/** A language's own words, in the three places Fieldia keeps them. A word left out shows in English. */\nexport interface LanguageWords {\n /** The validation messages (`MESSAGES`). */\n messages?: Partial<Messages>;\n /** The widgets' own words (`WIDGET_LABELS`). */\n widgets?: Partial<WidgetLabels>;\n /** The viewer's own words (`VIEWER_LABELS`). */\n viewer?: Partial<ViewerLabels>;\n}\n\n/**\n * Give Fieldia a language's own words, for every page shown in it from then\n * on. The packages have English, Arabic, German and French already; the\n * one-tag script has English alone, and its add-on scripts \u2014 `fieldia.ar.js`,\n * `fieldia.de.js`, `fieldia.fr.js` \u2014 call this with theirs. A language given\n * again takes the new words.\n */\nexport function addLanguage(locale: Locale, words: LanguageWords): void {\n MESSAGES[locale] = { ...MESSAGES.en, ...words.messages };\n WIDGET_LABELS[locale] = { ...WIDGET_LABELS.en, ...words.widgets };\n VIEWER_LABELS[locale] = { ...VIEWER_LABELS.en, ...words.viewer };\n}\n"],
5
+ "mappings": ";qlBAAA,IAAAA,GAAA,GAAAC,GAAAD,GAAA,mBAAAE,GAAA,mBAAAC,GAAA,gBAAAC,GAAA,eAAAC,GAAA,gBAAAC,GAAA,mBAAAC,GAAA,UAAAC,GAAA,aAAAC,GAAA,YAAAC,GAAA,kBAAAC,GAAA,kBAAAC,GAAA,iBAAAC,GAAA,gBAAAC,GAAA,cAAAC,GAAA,iBAAAC,GAAA,uBAAAC,GAAA,mBAAAC,GAAA,mBAAAC,GAAA,cAAAC,GAAA,eAAAC,GAAA,oBAAAC,GAAA,aAAAC,GAAA,gBAAAC,GAAA,eAAAC,GAAA,2BAAAC,GAAA,iBAAAC,GAAA,UAAAC,GAAA,kBAAAC,GAAA,iBAAAC,GAAA,aAAAC,GAAA,eAAAC,GAAA,qBAAAC,GAAA,sBAAAC,GAAA,mBAAAC,GAAA,gBAAAC,GAAA,SAAAC,GAAA,gBAAAC,GAAA,gBAAAC,GAAA,iBAAAC,GAAA,kBAAAC,GAAA,kBAAAC,GAAA,eAAAC,GAAA,gBAAAC,GAAA,kBAAAC,GAAA,sBAAAC,GAAA,kBAAAC,GAAA,YAAAC,GAAA,oBAAAC,GAAA,kBAAAC,GAAA,YAAAC,GAAA,eAAAC,GAAA,cAAAC,GAAA,kBAAAC,GAAA,eAAAC,GAAA,gBAAAC,GAAA,aAAAC,GAAA,aAAAC,GAAA,gBAAAC,GAAA,gBAAAC,GAAA,yBAAAC,GAAA,iBAAAC,GAAA,mBAAAC,GAAA,kBAAAC,GAAA,sBAAAC,GAAA,gBAAAC,GAAA,oBAAAC,GAAA,mBAAAC,GAAA,qBAAAC,GAAA,cAAAC,GAAA,gBAAAC,GAAA,sBAAAC,GAAA,qBAAAC,GAAA,aAAAC,GAAA,oBAAAC,GAAA,iBAAAC,GAAA,kBAAAC,GAAA,gBAAAC,GAAA,YAAAC,GAAA,oBAAAC,GAAA,gBAAAC,GAAA,YAAAC,GAAA,eAAAC,GAAA,kBAAAC,GAAA,SAAAC,GAAA,gBAAAC,GAAA,iBAAAC,KCGO,IAAMC,GAAa,2BAEbC,GAAc,CACzB,OACA,OACA,OACA,UACA,QACA,WACA,UACA,OACA,WACA,YACA,SACA,QACA,WACA,YACA,WACA,YACA,aACA,OACA,QACF,ECtBO,SAASC,GAAYC,EAAgE,CAC1F,OAAO,OAAOA,GAAY,SAAWA,EAAQ,KAAOA,GAAW,CACjE,CCJO,IAAMC,GAAiB,MCOvB,IAAMC,GAAYC,GAAoC,OAAOA,GAAU,UAAY,OAAO,SAASA,CAAK,EAMxG,SAASC,GAAKD,EAA8B,CACjD,OAAO,OAAO,SAASA,CAAK,EAAI,OAAOA,EAAM,YAAY,EAAE,CAAC,EAAI,IAClE,CAGO,SAASE,GAAWC,EAAkBC,EAAeC,EAAyB,CACnF,GAAIF,IAAa,MAAQ,OAAOC,GAAS,UAAY,OAAOC,GAAU,UAAW,CAC/E,IAAMC,EAAIC,GAASH,CAAI,EACjBI,EAAID,GAASF,CAAK,EACxB,OAAOC,IAAM,MAAQE,IAAM,KAAO,KAAOF,EAAIE,CAC/C,CACA,GAAI,CAACT,GAASK,CAAI,GAAK,CAACL,GAASM,CAAK,EAAG,OAAO,KAChD,OAAQF,EAAU,CAChB,IAAK,IACH,OAAOF,GAAKG,EAAOC,CAAK,EAC1B,IAAK,IACH,OAAOJ,GAAKG,EAAOC,CAAK,EAC1B,IAAK,IACH,OAAOJ,GAAKG,EAAOC,CAAK,EAC1B,IAAK,IACH,OAAOJ,GAAKG,EAAOC,CAAK,EAC1B,IAAK,IAEH,OAAOJ,GAAKG,EAAOC,EAAQ,KAAK,MAAMD,EAAOC,CAAK,CAAC,EACrD,QACE,OAAO,IACX,CACF,CAGA,SAASE,GAASP,EAA+B,CAC/C,OAAIA,GAAU,KAAoC,GAC9C,OAAOA,GAAU,SAAiBA,EAC/BD,GAASC,CAAK,EAAI,OAAOA,CAAK,EAAI,IAC3C,CAGO,SAASS,GAAOT,EAA+B,CACpD,OAAOD,GAASC,CAAK,EAAIC,GAAK,CAACD,CAAK,EAAI,IAC1C,CAGO,SAASU,GAAOV,EAAyB,CAC9C,OAAI,MAAM,QAAQA,CAAK,EAAUA,EAAM,OAAS,EAC5CA,IAAU,MAAQ,OAAOA,GAAU,SAAiB,OAAO,KAAKA,CAAK,EAAE,OAAS,EAC7E,EAAQA,CACjB,CAOO,SAASW,GAAQX,EAAeY,EAA+B,CACpE,IAAMC,EAAQ,IAAM,KAAK,MAAMD,CAAM,EAE/BE,EAAS,QAAQ,KAAK,IAAId,CAAK,EAAIa,GAAO,YAAY,EAAE,CAAC,EAC/D,OAAOZ,GAAM,KAAK,KAAKD,CAAK,EAAI,KAAK,MAAMc,CAAM,EAAKD,CAAK,CAC7D,CCpCO,SAASE,GAASC,EAAoB,CAC3C,IAAMC,EAAO,GAAc,OAAO,CAAC,EAAE,SAAS,EAAG,GAAG,EACpD,MAAO,GAAGD,EAAK,YAAY,CAAC,IAAIC,EAAID,EAAK,SAAS,EAAI,CAAC,CAAC,IAAIC,EAAID,EAAK,QAAQ,CAAC,CAAC,EACjF,CAGA,SAASE,GAAOC,EAAqB,CACnC,IAAMC,EAAQD,EAAK,KAAK,CAAC,EAEzB,OADaC,EAAM,OAAS,aAAeD,EAAK,IAAI,QAAQC,EAAM,IAAI,EAAI,SAC3DD,EAAK,MAAMC,CAAK,CACjC,CAGA,SAASC,GAAQF,EAAYG,EAA2B,CACtD,IAAMC,EAAQJ,EAAK,KAChB,QAASK,GAAQ,CAChB,IAAMC,EAAQN,EAAK,MAAMK,CAAG,EAC5B,OAAO,MAAM,QAAQC,CAAK,EAAIA,EAAQ,CAACA,CAAK,CAC9C,CAAC,EACA,OAAQA,GAAUA,GAAU,IAA2B,EAE1D,MADI,CAACF,EAAM,QACP,CAACA,EAAM,MAAMG,EAAQ,GAAK,CAACH,EAAM,MAAOE,GAAU,OAAOA,GAAU,QAAQ,EAAU,KACzEF,EACD,OAAO,CAACI,EAAMF,KAAYH,EAAUG,EAAQE,EAAOF,EAAQE,GAAQF,EAAQE,CAAK,CACjG,CAEO,IAAMC,GAAqD,IAAI,IAAgC,CACpG,CACE,QACA,CACE,MAAO,CAAC,EAAG,CAAC,EACZ,KAAK,CAAE,KAAAC,EAAM,MAAAJ,CAAM,EAAG,CACpB,IAAMK,EAAIL,EAAMI,EAAK,CAAC,CAAC,EACjBE,EAASF,EAAK,OAAS,EAAIJ,EAAMI,EAAK,CAAC,CAAC,EAAI,EAClD,OAAOH,GAASI,CAAC,GAAKJ,GAASK,CAAM,EAAIC,GAAQF,EAAGC,CAAM,EAAI,IAChE,CACF,CACF,EACA,CACE,MACA,CACE,MAAO,CAAC,EAAG,CAAC,EACZ,KAAK,CAAE,KAAAF,EAAM,MAAAJ,CAAM,EAAG,CACpB,IAAMK,EAAIL,EAAMI,EAAK,CAAC,CAAC,EACvB,OAAOH,GAASI,CAAC,EAAI,KAAK,IAAIA,CAAC,EAAI,IACrC,CACF,CACF,EACA,CAAC,MAAO,CAAE,MAAO,CAAC,EAAG,GAAQ,EAAG,KAAOX,GAASE,GAAQF,EAAM,EAAI,CAAE,CAAC,EACrE,CAAC,MAAO,CAAE,MAAO,CAAC,EAAG,GAAQ,EAAG,KAAOA,GAASE,GAAQF,EAAM,EAAK,CAAE,CAAC,EACtE,CACE,MACA,CACE,MAAO,CAAC,EAAG,CAAC,EACZ,KAAK,CAAE,KAAAU,EAAM,MAAAJ,CAAM,EAAG,CACpB,IAAMK,EAAIL,EAAMI,EAAK,CAAC,CAAC,EACvB,OAAIC,GAAM,KAAgC,EACnC,OAAOA,GAAM,UAAY,MAAM,QAAQA,CAAC,EAAIA,EAAE,OAAS,IAChE,CACF,CACF,EACA,CAAC,QAAS,CAAE,MAAO,CAAC,EAAG,CAAC,EAAG,KAAM,CAAC,CAAE,IAAAG,CAAI,IAAMA,EAAI,QAAQ,GAAKlB,GAAS,IAAI,IAAM,CAAE,CAAC,EACrF,CACE,MACA,CACE,MAAO,CAAC,EAAG,CAAC,EACZ,MAAMc,EAAM,CACV,IAAMK,EAAQL,EAAK,CAAC,EACpB,GAAIK,GAAS,EAAEA,EAAM,OAAS,WAAa,OAAOA,EAAM,OAAU,UAChE,MAAO,mFAGX,EACA,KAAKf,EAAM,CACT,IAAMgB,EAAOjB,GAAOC,CAAI,EACxB,GAAIgB,GAAS,KAA4B,MAAO,GAChD,GAAI,CAAC,MAAM,QAAQA,CAAI,EAAG,OAAO,KACjC,IAAMD,EAAQf,EAAK,KAAK,CAAC,GAAG,OAAS,UAAaA,EAAK,KAAK,CAAC,EAAE,MAAmB,OAC9EiB,EAAQ,EACZ,QAAWC,KAAQF,EAAM,CACvB,IAAMG,EAAIJ,IAAU,OAAYG,EAAQA,IAA0CH,CAAK,EACnFR,GAASY,CAAC,IAAGF,GAASE,EAC5B,CACA,OAAOC,GAAKH,CAAK,CACnB,CACF,CACF,EACA,CACE,QACA,CACE,MAAO,CAAC,EAAG,CAAC,EACZ,KAAKjB,EAAM,CACT,IAAMgB,EAAOjB,GAAOC,CAAI,EACxB,OAAIgB,GAAS,KAAmC,EACzC,MAAM,QAAQA,CAAI,EAAIA,EAAK,OAAS,IAC7C,CACF,CACF,EACA,CACE,KACA,CACE,MAAO,CAAC,EAAG,CAAC,EAEZ,KAAM,CAAC,CAAE,KAAAN,EAAM,MAAAJ,CAAM,IAAOe,GAAOf,EAAMI,EAAK,CAAC,CAAC,CAAC,EAAIJ,EAAMI,EAAK,CAAC,CAAC,EAAIJ,EAAMI,EAAK,CAAC,CAAC,CACrF,CACF,CACF,CAAC,EAGM,SAASY,GAAaC,EAAc,CAACC,EAAOC,CAAI,EAAsC,CAC3F,OAAIA,IAAS,EAAU,GAAGF,CAAI,mBAC1BC,IAAUC,EAAa,GAAGF,CAAI,UAAUC,CAAK,SAASA,IAAU,EAAI,GAAK,GAAG,GAC5EC,IAAS,IAAiB,GAAGF,CAAI,UAAUC,CAAK,kBAC7C,GAAGD,CAAI,UAAUC,CAAK,OAAOC,CAAI,SAC1C,CC3HO,SAASC,GAASC,EAAcC,EAAkCC,EAAqB,CAAC,EAAY,CACzG,OAAQF,EAAI,KAAM,CAChB,IAAK,WACH,OAAOG,GAAiBH,EAAKC,EAASC,CAAG,EAE3C,IAAK,UACH,OAAOE,GAAgBJ,EAAKC,EAASC,CAAG,EAE1C,IAAK,OACH,OAAOG,GAAaL,EAAKC,EAASC,CAAG,EAEvC,IAAK,UACH,OAAOF,EAAI,MAEb,IAAK,aACH,OAAOM,GAAeL,EAASD,EAAI,IAAI,EAEzC,QACE,MAAM,IAAI,MAAM,0BAA2BA,EAAyB,IAAI,EAAE,CAC9E,CACF,CAKA,SAASG,GAAiBI,EAAoBN,EAAkCC,EAA6B,CAC3G,IAAMM,EAAOC,GAAUV,GAASQ,EAAK,KAAMN,EAASC,CAAG,CAAC,EAClDQ,EAAQD,GAAUV,GAASQ,EAAK,MAAON,EAASC,CAAG,CAAC,EACpDS,EAAWJ,EAAK,SAAS,YAAY,EACrCK,EAAUJ,IAAS,MAAQE,IAAU,KAE3C,OAAQC,EAAU,CAEhB,IAAK,KACH,OAAOH,IAASE,EAElB,IAAK,KACL,IAAK,KACH,OAAOF,IAASE,EAElB,IAAK,IACH,OAAOE,GAAYJ,EAAuBE,EAE5C,IAAK,IACH,OAAOE,GAAYJ,EAAuBE,EAE5C,IAAK,KACH,OAAOE,GAAYJ,GAAwBE,EAE7C,IAAK,KACH,OAAOE,GAAYJ,GAAwBE,EAG7C,IAAK,KACH,OAAO,MAAM,QAAQA,CAAK,GAAKA,EAAM,SAASF,CAAI,EAEpD,IAAK,SACH,OAAO,MAAM,QAAQE,CAAK,GAAK,CAACA,EAAM,SAASF,CAAI,EAGrD,IAAK,IACL,IAAK,IACL,IAAK,IACL,IAAK,IACL,IAAK,IACH,OAAOK,GAAWF,EAAUH,EAAME,CAAK,EAGzC,IAAK,MACH,OAAOI,GAAON,CAAI,GAAKM,GAAOJ,CAAK,EAErC,IAAK,KACH,OAAOI,GAAON,CAAI,GAAKM,GAAOJ,CAAK,EAErC,QACE,MAAM,IAAI,MAAM,4BAA4BH,EAAK,QAAQ,EAAE,CAC/D,CACF,CAKA,SAASH,GAAgBG,EAAmBN,EAAkCC,EAA6B,CACzG,IAAMa,EAAUhB,GAASQ,EAAK,QAASN,EAASC,CAAG,EAGnD,OAFiBK,EAAK,SAAS,YAAY,EAEzB,CAChB,IAAK,MACH,MAAO,CAACO,GAAOC,CAAO,EAExB,IAAK,IACH,OAAOC,GAAOD,CAAO,EAEvB,QACE,MAAM,IAAI,MAAM,2BAA2BR,EAAK,QAAQ,EAAE,CAC9D,CACF,CAGA,SAASF,GAAaE,EAAgBN,EAAkCC,EAA6B,CACnG,IAAMe,EAAKC,GAAU,IAAIX,EAAK,IAAI,EAClC,GAAI,CAACU,EAAI,MAAM,IAAI,MAAM,qBAAqBV,EAAK,IAAI,EAAE,EACzD,OAAOU,EAAG,KAAK,CAAE,KAAMV,EAAK,KAAM,MAAQY,GAAQpB,GAASoB,EAAKlB,EAASC,CAAG,EAAG,IAAAA,CAAI,CAAC,CACtF,CAMA,SAASO,GAAUW,EAAyB,CAC1C,OAAOA,IAAU,OAAY,KAAOA,CACtC,CAaA,SAASd,GAAee,EAAcC,EAAuB,CAC3D,IAAMC,EAAQD,EAAK,MAAM,GAAG,EACxBE,EAAmBH,EAEvB,QAAWI,KAAQF,EAAO,CACxB,GAAIC,GAAY,KACd,OAEFA,EAAWA,EAAoCC,CAAI,CACrD,CAEA,OAAOD,CACT,CCtIO,IAAME,GAAiD,IAAI,IAA4B,CAC5F,CAAC,OAAQ,EAAI,EACb,CAAC,QAAS,EAAK,EACf,CAAC,OAAQ,IAAI,EACb,CAAC,OAAQ,EAAI,EACb,CAAC,QAAS,EAAK,EACf,CAAC,OAAQ,IAAI,CACf,CAAC,EAGKC,GAAa,IAAI,IAAI,CAAC,IAAK,IAAK,IAAK,IAAK,GAAG,CAAC,EAgB7C,SAASC,GAASC,EAAuB,CAC9C,IAAMC,EAAkB,CAAC,EACzB,GAAI,CAACD,EAAM,OAAOC,EAMlB,IAAMC,EACJ,6HACIC,EAAQ,OACVC,EAAK,EAET,OAAS,CAIP,GAHAD,EAAM,UAAYC,EAClBD,EAAM,KAAKH,CAAI,EACfI,EAAKD,EAAM,UACPC,GAAMJ,EAAK,OAAQ,OAAOC,EAE9BC,EAAM,UAAYE,EAClB,IAAMC,EAAQH,EAAM,KAAKF,CAAI,EAC7B,GAAI,CAACK,EACH,MAAM,IAAI,MAAM,eAAeL,EAAKI,CAAE,CAAC,kBAAkBA,EAAK,CAAC,QAAQJ,CAAI,EAAE,EAE/EC,EAAO,KAAK,CAAE,KAAMK,GAAaD,EAAM,CAAC,CAAC,EAAG,MAAOA,EAAM,CAAC,EAAG,SAAUJ,EAAO,MAAO,CAAC,EACtFG,EAAKF,EAAM,SACb,CACF,CAKA,SAASI,GAAaC,EAAyB,CAC7C,IAAMC,EAAYD,EAAK,YAAY,EAAE,KAAK,EAG1C,OAAIV,GAAU,IAAIU,CAAI,EACb,WAILC,IAAc,OAASA,IAAc,MAAQA,IAAc,MACtD,UAKP,CAAC,KAAM,KAAM,KAAM,IAAK,IAAK,KAAM,IAAI,EAAE,SAASD,CAAI,GACtDC,IAAc,MACdA,IAAc,SAEP,WAILD,IAAS,KAAOA,IAAS,IACpB,QAILT,GAAW,IAAIS,CAAI,EACd,aAELA,IAAS,IACJ,QAILA,EAAK,WAAW,GAAG,EACd,OAILA,EAAK,WAAW,GAAG,GAAKA,EAAK,WAAW,GAAG,EACtC,SAIL,cAAc,KAAKA,CAAI,EAClB,SAIF,YACT,CClFO,IAAME,GAAN,KAAuB,CAI5B,YAAYC,EAAiB,CAH7BC,GAAA,KAAQ,UACRA,GAAA,KAAQ,WAAmB,GAGzB,KAAK,OAASD,CAChB,CAKA,OAAiB,CACf,GAAI,KAAK,OAAO,SAAW,EACzB,MAAM,IAAI,MAAM,+BAA+B,EAGjD,IAAME,EAAM,KAAK,QAAQ,EAGzB,GAAI,CAAC,KAAK,QAAQ,EAChB,MAAM,IAAI,MAAM,gCAAgC,KAAK,QAAQ,KAAK,KAAK,KAAK,GAAG,KAAK,EAAE,EAGxF,OAAOA,CACT,CAMQ,SAAmB,CACzB,IAAIC,EAAO,KAAK,SAAS,EAEzB,KAAO,KAAK,aAAa,IAAI,GAAG,CAC9B,IAAMC,EAAW,KAAK,SAAS,EAAE,MAC3BC,EAAQ,KAAK,SAAS,EAC5BF,EAAO,CACL,KAAM,WACN,SAAUC,EAAS,YAAY,EAC/B,KAAAD,EACA,MAAAE,CACF,CACF,CAEA,OAAOF,CACT,CAMQ,UAAoB,CAC1B,IAAIA,EAAO,KAAK,SAAS,EAEzB,KAAO,KAAK,aAAa,KAAK,GAAG,CAC/B,IAAMC,EAAW,KAAK,SAAS,EAAE,MAC3BC,EAAQ,KAAK,SAAS,EAC5BF,EAAO,CACL,KAAM,WACN,SAAUC,EAAS,YAAY,EAC/B,KAAAD,EACA,MAAAE,CACF,CACF,CAEA,OAAOF,CACT,CAMQ,UAAoB,CAC1B,GAAI,KAAK,aAAa,KAAK,EAAG,CAC5B,IAAMC,EAAW,KAAK,SAAS,EAAE,MAC3BE,EAAU,KAAK,gBAAgB,EACrC,MAAO,CACL,KAAM,UACN,SAAUF,EAAS,YAAY,EAC/B,QAAAE,CACF,CACF,CAEA,OAAO,KAAK,gBAAgB,CAC9B,CAOQ,iBAA2B,CACjC,IAAMH,EAAO,KAAK,SAAS,EAErBI,EAAgB,CAAC,KAAM,KAAM,KAAM,IAAK,IAAK,KAAM,KAAM,KAAM,QAAQ,EAC7E,GAAI,KAAK,cAAc,GAAGA,CAAa,EAAG,CACxC,IAAMH,EAAW,KAAK,SAAS,EAAE,MAC3BC,EAAQ,KAAK,SAAS,EAC5B,MAAO,CACL,KAAM,WACN,SAAUD,EAAS,YAAY,EAC/B,KAAAD,EACA,MAAAE,CACF,CACF,CAGA,OAAOF,CACT,CAMQ,UAAoB,CAC1B,IAAIA,EAAO,KAAK,aAAa,EAC7B,KAAO,KAAK,MAAM,aAAc,IAAK,GAAG,GAEtCA,EAAO,CAAE,KAAM,WAAY,SADV,KAAK,SAAS,EAAE,MACI,KAAAA,EAAM,MAAO,KAAK,aAAa,CAAE,EAExE,OAAOA,CACT,CAMQ,cAAwB,CAC9B,IAAIA,EAAO,KAAK,WAAW,EAC3B,KAAO,KAAK,MAAM,aAAc,IAAK,IAAK,GAAG,GAE3CA,EAAO,CAAE,KAAM,WAAY,SADV,KAAK,SAAS,EAAE,MACI,KAAAA,EAAM,MAAO,KAAK,WAAW,CAAE,EAEtE,OAAOA,CACT,CAMQ,YAAsB,CAC5B,OAAI,KAAK,MAAM,aAAc,GAAG,EACvB,CAAE,KAAM,UAAW,SAAU,IAAK,QAAS,KAAK,WAAW,CAAE,EAE/D,KAAK,WAAW,CACzB,CAMQ,UAAUK,EAAuB,CACvC,IAAMC,EAAKC,GAAU,IAAIF,CAAI,EAC7B,GAAI,CAACC,EAAI,MAAM,IAAI,MAAM,gBAAgBD,CAAI,wBAAwB,CAAC,GAAGE,GAAU,KAAK,CAAC,EAAE,KAAK,IAAI,CAAC,EAAE,EACvG,KAAK,QAAQ,EACb,IAAMC,EAAkB,CAAC,EACzB,GAAI,CAAC,KAAK,MAAM,QAAS,GAAG,EAAG,CAC7B,GACEA,EAAK,KAAK,KAAK,QAAQ,CAAC,QACjB,KAAK,MAAM,OAAO,GAC3B,KAAK,QAAQ,QAAS,IAAK,wCAAwCH,CAAI,UAAK,CAC9E,CACA,GAAM,CAACI,EAAOC,CAAI,EAAIJ,EAAG,MACzB,GAAIE,EAAK,OAASC,GAASD,EAAK,OAASE,EAAM,MAAM,IAAI,MAAMC,GAAaN,EAAMC,EAAG,KAAK,CAAC,EAC3F,IAAMM,EAAUN,EAAG,QAAQE,CAAI,EAC/B,GAAII,EAAS,MAAM,IAAI,MAAMA,CAAO,EACpC,MAAO,CAAE,KAAM,OAAQ,KAAAP,EAAM,KAAAG,CAAK,CACpC,CAMQ,YAAsB,CAE5B,GAAI,KAAK,MAAM,QAAS,GAAG,EAAG,CAC5B,IAAMK,EAAO,KAAK,QAAQ,EAC1B,YAAK,QAAQ,QAAS,IAAK,8BAA8B,EAClDA,CACT,CAGA,GAAI,KAAK,MAAM,QAAQ,EAIrB,MAAO,CAAE,KAAM,UAAW,MAHZ,KAAK,QAAQ,EAEP,MAAM,MAAM,EAAG,EAAE,CACL,EAIlC,GAAI,KAAK,MAAM,UAAU,EAAG,CAC1B,IAAMC,EAAQ,KAAK,QAAQ,EAC3B,MAAO,CAAE,KAAM,UAAW,MAAOC,GAAU,IAAID,EAAM,KAAK,GAAK,IAAK,CACtE,CAGA,GAAI,KAAK,MAAM,QAAQ,EAAG,CACxB,IAAMA,EAAQ,KAAK,QAAQ,EAC3B,MAAO,CAAE,KAAM,UAAW,MAAO,OAAOA,EAAM,KAAK,CAAE,CACvD,CAGA,GAAI,KAAK,MAAM,MAAM,EAAG,CACtB,IAAMA,EAAQ,KAAK,QAAQ,EAE3B,MAAO,CAAE,KAAM,UAAW,MADZE,GAAiBF,EAAM,KAAK,CACV,CAClC,CAGA,GAAI,KAAK,MAAM,YAAY,EAAG,CAC5B,IAAMA,EAAQ,KAAK,QAAQ,EACrBG,EAAO,KAAK,KAAK,EACvB,OAAIA,GAAM,OAAS,SAAWA,EAAK,QAAU,IAAY,KAAK,UAAUH,EAAM,KAAK,EAC5E,CAAE,KAAM,aAAc,KAAMA,EAAM,KAAM,CACjD,CAEA,MAAM,IAAI,MAAM,qBAAqB,KAAK,KAAK,GAAG,OAAS,KAAK,EAAE,CACpE,CAOQ,MAAMI,KAAiBC,EAA2B,CACxD,GAAI,KAAK,MAAMD,CAAI,EAAG,CACpB,GAAIC,EAAO,SAAW,EACpB,YAAK,QAAQ,EACN,GAET,IAAML,EAAQ,KAAK,KAAK,EACxB,GAAIA,GAASK,EAAO,SAASL,EAAM,KAAK,EACtC,YAAK,QAAQ,EACN,EAEX,CACA,MAAO,EACT,CAKQ,gBAAgBM,EAA8B,CACpD,IAAMN,EAAQ,KAAK,KAAK,EACxB,GAAIA,GAASA,EAAM,OAAS,UAAW,CACrC,IAAMO,EAAaP,EAAM,MAAM,YAAY,EAC3C,GAAIM,EAAU,IAAIE,GAAMA,EAAG,YAAY,CAAC,EAAE,SAASD,CAAU,EAC3D,YAAK,QAAQ,EACN,EAEX,CACA,MAAO,EACT,CAKQ,iBAAiBD,EAA8B,CACrD,IAAMN,EAAQ,KAAK,KAAK,EACxB,GAAIA,GAASA,EAAM,OAAS,WAAY,CACtC,IAAMO,EAAaP,EAAM,MAAM,YAAY,EAC3C,GAAIM,EAAU,IAAIE,GAAMA,EAAG,YAAY,CAAC,EAAE,SAASD,CAAU,EAC3D,YAAK,QAAQ,EACN,EAEX,CACA,MAAO,EACT,CAKQ,MAAMH,EAAuB,CAEnC,OADc,KAAK,KAAK,GACV,OAASA,CACzB,CAKQ,SAAiB,CACvB,OAAK,KAAK,QAAQ,GAChB,KAAK,WAEA,KAAK,SAAS,CACvB,CAKQ,MAAqB,CAC3B,OAAI,KAAK,QAAQ,EACR,KAEF,KAAK,OAAO,KAAK,QAAQ,CAClC,CAKQ,UAAkB,CACxB,OAAO,KAAK,OAAO,KAAK,SAAW,CAAC,CACtC,CAKQ,SAAmB,CACzB,OAAO,KAAK,UAAY,KAAK,OAAO,MACtC,CAKQ,QAAQA,EAAcK,EAAeC,EAAwB,CACnE,GAAI,KAAK,MAAMN,CAAI,EAAG,CACpB,IAAMJ,EAAQ,KAAK,KAAK,EACxB,GAAIA,GAASA,EAAM,QAAUS,EAC3B,OAAO,KAAK,QAAQ,CAExB,CACA,MAAM,IAAI,MAAMC,CAAO,CACzB,CACF,EAMA,SAASR,GAAiBS,EAA4B,CACpD,GAAI,CAEF,IAAMC,EAAUD,EAAQ,MAAM,EAAG,EAAE,EAAE,KAAK,EAC1C,GAAI,CAACC,EACH,MAAO,CAAC,EAIV,IAAMC,EAAsB,CAAC,EACzBC,EAAU,GACVC,EAAW,GACXC,EAAa,GAEjB,QAASC,EAAI,EAAGA,EAAIL,EAAQ,OAAQK,IAAK,CACvC,IAAMC,EAAON,EAAQK,CAAC,GAEjBC,IAAS,KAAOA,IAAS,OAASD,IAAM,GAAKL,EAAQK,EAAI,CAAC,IAAM,QAC9DF,EAGMG,IAASF,IAClBD,EAAW,GACXC,EAAa,KAJbD,EAAW,GACXC,EAAaE,IAObA,IAAS,KAAO,CAACH,GACnBF,EAAS,KAAKM,GAAaL,EAAQ,KAAK,CAAC,CAAC,EAC1CA,EAAU,IAEVA,GAAWI,CAEf,CAEA,OAAIJ,EAAQ,KAAK,GACfD,EAAS,KAAKM,GAAaL,EAAQ,KAAK,CAAC,CAAC,EAGrCD,CACT,OAASO,EAAO,CAEd,MAAM,IAAI,MAAM,wBAAwBT,CAAO,GAAI,CAAE,MAAOS,CAAM,CAAC,CACrE,CACF,CAKA,SAASD,GAAaE,EAA0B,CAE9C,OAAKA,EAAQ,WAAW,GAAG,GAAKA,EAAQ,SAAS,GAAG,GAC/CA,EAAQ,WAAW,GAAG,GAAKA,EAAQ,SAAS,GAAG,EAC3CA,EAAQ,MAAM,EAAG,EAAE,EAIvB,MAAM,OAAOA,CAAO,CAAC,EAKtBA,EAAQ,YAAY,IAAM,OAAe,GACzCA,EAAQ,YAAY,IAAM,QAAgB,GAGvCA,EARE,OAAOA,CAAO,CASzB,CClcA,SAASC,GAAKC,EAAcC,EAAsC,CAEhE,OADAA,EAAMD,CAAG,EACDA,EAAI,KAAM,CAChB,IAAK,WACHD,GAAKC,EAAI,KAAMC,CAAK,EACpBF,GAAKC,EAAI,MAAOC,CAAK,EACrB,OACF,IAAK,UACHF,GAAKC,EAAI,QAASC,CAAK,EACvB,OACF,IAAK,OACH,QAAWC,KAAOF,EAAI,KAAMD,GAAKG,EAAKD,CAAK,EAC3C,OACF,QACE,MACJ,CACF,CAGO,SAASE,GAAWH,EAAwB,CACjD,IAAMI,EAAkB,CAAC,EACzB,OAAAL,GAAKC,EAAMK,GAAS,CAClB,GAAIA,EAAK,OAAS,aAAc,OAChC,IAAMC,EAAOD,EAAK,KAAK,MAAM,GAAG,EAAE,CAAC,EAC9BD,EAAM,SAASE,CAAI,GAAGF,EAAM,KAAKE,CAAI,CAC5C,CAAC,EACMF,CACT,CAGO,SAASG,GAASP,EAAkD,CACzE,IAAMQ,EAA2C,CAAC,EAClD,OAAAT,GAAKC,EAAMK,GAAS,CAClB,GAAIA,EAAK,OAAS,QAAUA,EAAK,OAAS,MAAO,OACjD,GAAM,CAACI,EAAOC,CAAK,EAAIL,EAAK,KACxBI,EAAM,OAAS,cAAgBC,GAAO,OAAS,WAAWF,EAAK,KAAK,CAAE,MAAOC,EAAM,KAAM,MAAOC,EAAM,KAAgB,CAAC,CAC7H,CAAC,EACMF,CACT,CCpBO,SAASG,GAAgBC,EAAkD,CAChF,GAAI,OAAOA,GAAa,SAAU,CAChC,IAAMC,EAAQD,IAAa,GAC3B,MAAO,CAAE,OAAQA,EAAU,OAAQ,CAAC,EAAG,SAAU,IAAMC,CAAM,CAC/D,CACA,IAAMC,EAAM,IAAIC,GAAiBC,GAASJ,CAAQ,CAAC,EAAE,MAAM,EAC3D,MAAO,CACL,OAAQA,EACR,OAAQK,GAAWH,CAAG,EACtB,SAASI,EAAQC,EAAK,CACpB,GAAI,CACF,OAAOC,GAAOC,GAASP,EAAKI,EAAQC,CAAG,CAAC,CAC1C,MAAQ,CACN,MAAO,EACT,CACF,CACF,CACF,CCdO,SAASG,GAAkBC,EAAoC,CACpE,IAAMC,EAAM,IAAIC,GAAiBC,GAASH,CAAM,CAAC,EAAE,MAAM,EACzD,MAAO,CACL,OAAAA,EACA,OAAQI,GAAWH,CAAG,EACtB,KAAMI,GAASJ,CAAG,EAClB,SAASK,EAAQC,EAAM,CAAC,EAAG,CACzB,GAAI,CACF,OAAOC,GAASP,EAAKK,EAAmCC,CAAG,GAAK,IAClE,MAAQ,CACN,OAAO,IACT,CACF,CACF,CACF,CC/BO,SAASE,GAAgBC,EAAwF,CACtH,IAAMC,EAAkB,CAAC,EACnBC,EAAqB,CAAC,EACtBC,EAAO,IAAI,IACXC,EAAiB,CAAC,EAClBC,EAASC,GAAuB,CACpC,GAAIH,EAAK,IAAIG,CAAI,EAAG,OACpB,IAAMC,EAAKH,EAAK,QAAQE,CAAI,EAC5B,GAAIC,IAAO,GAAI,CACbL,EAAO,KAAK,CAAC,GAAGE,EAAK,MAAMG,CAAE,EAAGD,CAAI,CAAC,EACrC,MACF,CACAF,EAAK,KAAKE,CAAI,EACd,QAAWE,KAAQR,EAAM,IAAIM,CAAI,GAAK,CAAC,EAAON,EAAM,IAAIQ,CAAI,GAAGH,EAAMG,CAAI,EACzEJ,EAAK,IAAI,EACTD,EAAK,IAAIG,CAAI,EACbL,EAAM,KAAKK,CAAI,CACjB,EACA,QAAWA,KAAQN,EAAM,KAAK,EAAGK,EAAMC,CAAI,EAC3C,MAAO,CAAE,MAAAL,EAAO,OAAAC,CAAO,CACzB,CCZA,IAAMO,GAAM,CAACC,EAAgBC,IAAgB,OAAO,UAAU,eAAe,KAAKD,EAAQC,CAAG,EAGvFC,GAAc,IAAI,IAAI,CAAC,OAAQ,OAAQ,OAAQ,UAAW,QAAS,WAAY,UAAW,OAAQ,WAAY,YAAa,MAAM,CAAC,EAClIC,GAAoB,wDAUpBC,GAAUC,GAAoB,CAClC,IAAMC,EAASD,EAAM,IAAKE,GAAS,IAAIA,CAAI,GAAG,EAC9C,OAAOD,EAAO,OAAS,EAAIA,EAAO,KAAK,EAAE,EAAI,GAAGA,EAAO,MAAM,EAAG,EAAE,EAAE,KAAK,IAAI,CAAC,QAAQA,EAAOA,EAAO,OAAS,CAAC,CAAC,EACjH,EAGaE,GAAN,KAAqB,CAI1B,YAA6BC,EAAY,CAAZC,GAAA,YAAAD,GAH7BC,GAAA,KAAiB,SAAsB,CAAC,GACxCA,GAAA,KAAiB,MAAM,IAAI,IAEe,CAE1C,KAAmB,CACjB,YAAK,YAAY,KAAK,KAAK,OAAQ,QAAQ,EAC3C,KAAK,SAAS,KAAK,KAAK,OAAQ,QAAQ,EACjC,KAAK,MACd,CAEQ,OAAOC,EAAcC,EAAiB,CAC5C,KAAK,OAAO,KAAK,CAAE,KAAAD,EAAM,QAAAC,CAAQ,CAAC,CACpC,CAEQ,MAAMC,EAAYF,EAAc,CACtC,IAAMG,EAAQ,KAAK,IAAI,IAAID,CAAE,EACzBC,IAAU,OAAW,KAAK,OAAOH,EAAM,iBAAiBE,CAAE,mBAAmBC,CAAK,EAAE,EACnF,KAAK,IAAI,IAAID,EAAIF,CAAI,CAC5B,CAGQ,KAAKJ,EAAcI,EAAcI,EAA2C,KAAK,KAAK,OAAQ,CACpG,GAAIhB,GAAIgB,EAAOR,CAAI,EAAG,OAAOQ,EAAMR,CAAI,EACvC,KAAK,OAAOI,EAAM,aAAaJ,CAAI,GAAG,CAExC,CAGQ,eAAeS,EAAeL,EAAcM,EAA0B,CAAC,WAAW,EAAGF,EAAe,CAAE,OAAQ,KAAK,KAAK,MAAO,EAAG,CACxI,QAAWd,KAAOgB,EAAM,CACtB,IAAMC,EAASF,EAAkCf,CAAG,EACpD,GAAI,OAAOiB,GAAU,SAAU,SAC/B,IAAIC,EACJ,GAAI,CACFA,EAASC,GAAgBF,CAAK,EAAE,MAClC,OAASG,EAAO,CACd,KAAK,OAAO,GAAGV,CAAI,IAAIV,CAAG,GAAI,gBAAgBiB,CAAK,MAAOG,EAAgB,OAAO,EAAE,EACnF,QACF,CACA,KAAK,WAAWH,EAAOC,EAAQ,GAAGR,CAAI,IAAIV,CAAG,GAAIc,CAAK,CACxD,CACF,CAGQ,WAAWO,EAAgBH,EAA2BR,EAAcI,EAAc,CACxF,QAAWR,KAAQY,EAAQ,CACzB,GAAIpB,GAAIgB,EAAM,OAAQR,CAAI,EAAG,SAC7B,IAAMgB,EAAQR,EAAM,QAAU,OAAY,eAAiB,oBAAoBA,EAAM,KAAK,IAC1F,KAAK,OAAOJ,EAAM,IAAIW,CAAM,YAAYf,CAAI,2BAA2BgB,CAAK,EAAE,CAChF,CACF,CAOQ,gBAAgBD,EAAgBX,EAAcI,EAAwC,CAC5F,IAAIS,EACJ,GAAI,CACFA,EAAWC,GAAkBH,CAAM,CACrC,OAASD,EAAO,CACd,YAAK,OAAOV,EAAM,gBAAgBW,CAAM,MAAOD,EAAgB,OAAO,EAAE,EACjE,IACT,CACA,KAAK,WAAWC,EAAQE,EAAS,OAAQb,EAAMI,CAAK,EACpD,QAAWW,KAAOF,EAAS,KAAM,CAC/B,GAAI,CAACzB,GAAIgB,EAAM,OAAQW,EAAI,KAAK,EAAG,SACnC,IAAMC,EAAQZ,EAAM,OAAOW,EAAI,KAAK,EAChCC,EAAM,OAAS,WAAY,KAAK,OAAOhB,EAAM,yCAAyCe,EAAI,KAAK,UAAUC,EAAM,IAAI,EAAE,EAC/G5B,GAAI4B,EAAM,OAAQD,EAAI,KAAK,GAAG,KAAK,OAAOf,EAAM,IAAIe,EAAI,KAAK,qCAAqCA,EAAI,KAAK,GAAG,CAC1H,CACA,OAAOF,EAAS,MAClB,CAMQ,eAAeL,EAA2CS,EAAcb,EAAc,CAC5F,IAAMc,EAAQ,IAAI,IAClB,OAAW,CAACtB,EAAMuB,CAAG,IAAK,OAAO,QAAQX,CAAM,EAAG,CAChD,IAAMR,EAAO,GAAGiB,CAAI,IAAIrB,CAAI,GAC5B,IAAKuB,EAAI,UAAY,QAAaA,EAAI,UAAY,CAAC5B,GAAY,IAAI4B,EAAI,IAAI,EAAG,CACxEA,EAAI,UAAY,QAAW,KAAK,OAAO,GAAGnB,CAAI,WAAY,KAAKmB,EAAI,IAAI,0BAA0B3B,EAAiB,EAAE,EACpH2B,EAAI,SAAS,KAAK,OAAO,GAAGnB,CAAI,WAAY,KAAKmB,EAAI,IAAI,kCAAkC3B,EAAiB,EAAE,EAClH,QACF,CACA,GAAI2B,EAAI,UAAY,OAAW,CAC7B,IAAMC,EAAO,KAAK,gBAAgBD,EAAI,QAAS,GAAGnB,CAAI,WAAYI,CAAK,EACnEgB,GAAMF,EAAM,IAAItB,EAAMwB,CAAI,CAChC,CACAD,EAAI,SAAS,QAAQ,CAACE,EAAMC,IAAM,CAChC,KAAK,eAAeD,EAAM,GAAGrB,CAAI,YAAYsB,CAAC,IAAK,CAAC,MAAM,EAAGlB,CAAK,EAClE,KAAK,gBAAgBiB,EAAK,MAAO,GAAGrB,CAAI,YAAYsB,CAAC,UAAWlB,CAAK,CACvE,CAAC,CACH,CACA,QAAWmB,KAASC,GAAgBN,CAAK,EAAE,OAAQ,CACjD,IAAMxB,EAAQ6B,EAAM,MAAM,EAAG,EAAE,EACzBtB,EAAUP,EAAM,SAAW,EAAI,IAAIA,EAAM,CAAC,CAAC,8BAAgC,GAAGD,GAAOC,CAAK,CAAC,oCAAoC6B,EAAM,KAAK,UAAK,CAAC,GACtJ,KAAK,OAAO,GAAGN,CAAI,IAAIM,EAAM,CAAC,CAAC,WAAYtB,CAAO,CACpD,CACF,CAEQ,YAAYO,EAA4CS,EAAcD,EAAgB,CAC5F,KAAK,eAAeR,EAAQS,EAAM,CAAE,OAAAT,EAAQ,MAAAQ,CAAM,CAAC,EACnD,OAAW,CAACpB,EAAMuB,CAAG,IAAK,OAAO,QAAQX,CAAM,EAAG,CAChD,IAAMR,EAAO,GAAGiB,CAAI,IAAIrB,CAAI,GAC5B,GAAIuB,EAAI,OAAS,YAAcA,EAAI,gBAAkB,OAAW,CAC9D,IAAMM,EAAW,KAAK,KAAKN,EAAI,cAAe,GAAGnB,CAAI,iBAAkBQ,CAAM,EACzEiB,GAAY,CAAC,CAAC,WAAY,YAAa,MAAM,EAAE,SAASA,EAAS,IAAI,GACvE,KAAK,OACH,GAAGzB,CAAI,iBACP,IAAImB,EAAI,aAAa,UAAUM,EAAS,IAAI,0DAC9C,CAEJ,CACA,IAAKN,EAAI,OAAS,YAAcA,EAAI,OAAS,cAAgBA,EAAI,OAAQ,CAEvE,IAAMO,EAAO,CAACL,EAAkBM,IAAqB,CACnD,GAAI,QAASN,EAAM,OAAOA,EAAK,IAAI,QAAQ,CAACO,EAAON,IAAMI,EAAKE,EAAO,GAAGD,CAAE,QAAQL,CAAC,GAAG,CAAC,EACvF,GAAI,QAASD,EAAM,OAAOA,EAAK,IAAI,QAAQ,CAACO,EAAON,IAAMI,EAAKE,EAAO,GAAGD,CAAE,QAAQL,CAAC,GAAG,CAAC,EACnFD,EAAK,YAAc,QAAW,KAAK,KAAKA,EAAK,UAAW,GAAGM,CAAE,aAAcnB,CAAM,CACvF,EACAW,EAAI,OAAO,QAAQ,CAACE,EAAMC,IAAM,CAC9BI,EAAKL,EAAM,GAAGrB,CAAI,WAAWsB,CAAC,GAAG,CACnC,CAAC,CACH,CAEA,GADIH,EAAI,OAAS,aAAaA,EAAI,aAAa,WAAW,QAAQ,CAACU,EAAOP,IAAM,KAAK,KAAKO,EAAO,GAAG7B,CAAI,0BAA0BsB,CAAC,IAAKd,CAAM,CAAC,EAC3IW,EAAI,OAAS,cAAgBA,EAAI,YAAa,CAChD,IAAMW,EAAO,IAAI,IACjBX,EAAI,YAAY,QAAQ,CAACY,EAAUT,IAAM,CACnCS,EAAS,OAAS,aAAe,CAACA,EAAS,SAC7C,KAAK,OAAO,GAAG/B,CAAI,gBAAgBsB,CAAC,YAAa,qCAAqC,EAEpFQ,EAAK,IAAIC,EAAS,IAAI,GAAG,KAAK,OAAO,GAAG/B,CAAI,gBAAgBsB,CAAC,SAAU,IAAIS,EAAS,IAAI,kBAAkB,EAC9GD,EAAK,IAAIC,EAAS,IAAI,CACxB,CAAC,CACH,CACA,GAAIZ,EAAI,OAAS,aACf,KAAK,YAAYA,EAAI,OAAQ,GAAGnB,CAAI,UAAWJ,CAAI,EAC/CuB,EAAI,WAAW,KAAK,eAAevB,EAAMuB,EAAI,UAAWA,EAAI,OAAQ,GAAGnB,CAAI,YAAY,EACvFmB,EAAI,gBAAkB,QAAW,CACnC,IAAMa,EAAWb,EAAI,OAAOA,EAAI,aAAa,EACxCa,EACIA,EAAS,OAAS,WACzB,KAAK,OAAO,GAAGhC,CAAI,iBAAkB,IAAImB,EAAI,aAAa,UAAUa,EAAS,IAAI,8DAA8D,EAFlI,KAAK,OAAO,GAAGhC,CAAI,iBAAkB,IAAImB,EAAI,aAAa,qCAAqCvB,CAAI,GAAG,CAIvH,CAEJ,CACF,CAEQ,eAAeqC,EAAeC,EAAkBC,EAAuCnC,EAAc,CAC3G,IAAMoC,EAAYD,EAAWD,EAAM,KAAK,EACxC,GAAI,CAACE,EAAW,KAAK,OAAO,GAAGpC,CAAI,SAAU,IAAIkC,EAAM,KAAK,qCAAqCD,CAAK,GAAG,UAChGG,EAAU,OAAS,aAAeA,EAAU,OAAS,OAC5D,KAAK,OAAO,GAAGpC,CAAI,SAAU,IAAIkC,EAAM,KAAK,UAAUE,EAAU,IAAI,kEAAkE,UAC7HA,EAAU,OAAS,YAC5B,QAAWC,IAAS,CAAC,UAAW,MAAM,EAAY,CAChD,IAAM9B,EAAQ2B,EAAMG,CAAK,GAAKA,EACzBD,EAAU,QAAQ,KAAME,GAAMA,EAAE,QAAU/B,CAAK,GAAG,KAAK,OAAO,GAAGP,CAAI,IAAIqC,CAAK,GAAI,IAAIH,EAAM,KAAK,oBAAoB3B,CAAK,GAAG,CACpI,CAEF,IAAMgC,EAAOJ,EAAWD,EAAM,IAAI,EAC7BK,EACIA,EAAK,OAAS,QAAUA,EAAK,OAAS,QAC7C,KAAK,OAAO,GAAGvC,CAAI,QAAS,IAAIkC,EAAM,IAAI,UAAUK,EAAK,IAAI,2DAA2D,EAF/G,KAAK,OAAO,GAAGvC,CAAI,QAAS,IAAIkC,EAAM,IAAI,qCAAqCD,CAAK,GAAG,CAIpG,CAEQ,SAASO,EAAkBxC,EAAc,CAC/C,GAAIwC,EAAK,OAAS,OAAQ,OAAO,KAAK,SAASA,EAAMxC,CAAI,EAEzD,GADA,KAAK,MAAMwC,EAAK,GAAIxC,CAAI,EACpBwC,EAAK,OAAS,QAAS,OAAO,KAAK,UAAUA,EAAMxC,CAAI,EAC3D,GAAIwC,EAAK,OAAS,WAAY,OAAO,KAAK,aAAaA,EAAK,SAAUxC,CAAI,EAC1E,GAAIwC,EAAK,OAAS,OAAQ,OAAO,KAAK,SAASA,EAAMxC,CAAI,EACzDwC,EAAK,SAAS,QAAQ,CAACC,EAAM,IAAM,CACjC,IAAMC,EAAW,GAAG1C,CAAI,aAAa,CAAC,IACtC,KAAK,MAAMyC,EAAK,GAAIC,CAAQ,EAC5B,KAAK,eAAeD,EAAMC,CAAQ,EAClC,KAAK,aAAaD,EAAK,SAAUC,CAAQ,CAC3C,CAAC,CACH,CAEQ,SAASC,EAAgB3C,EAAc,CACzC,KAAK,KAAK,KAAK,OAAS,UAAU,KAAK,OAAO,OAAQ,gEAAgE,EAC1H2C,EAAK,QAAQ,QAAQ,CAAC/C,EAAM0B,IAAM,KAAK,KAAK1B,EAAM,GAAGI,CAAI,YAAYsB,CAAC,GAAG,CAAC,EAC1EqB,EAAK,MAAM,QAAQ,CAACC,EAAOtB,IAAM,KAAK,KAAKsB,EAAM,MAAO,GAAG5C,CAAI,SAASsB,CAAC,SAAS,CAAC,EACnFqB,EAAK,cAAc,QAAQ,CAAC/C,EAAM0B,IAAM,KAAK,KAAK1B,EAAM,GAAGI,CAAI,iBAAiBsB,CAAC,GAAG,CAAC,EACrFqB,EAAK,SAAS,QAAQ,CAAC/C,EAAM0B,IAAM,KAAK,KAAK1B,EAAM,GAAGI,CAAI,YAAYsB,CAAC,GAAG,CAAC,EAE3E,IAAMI,EAAO,CAACL,EAAkBM,IAAqB,CACnD,GAAI,QAASN,EAAM,OAAOA,EAAK,IAAI,QAAQ,CAACO,EAAON,IAAMI,EAAKE,EAAO,GAAGD,CAAE,QAAQL,CAAC,GAAG,CAAC,EACvF,GAAI,QAASD,EAAM,OAAOA,EAAK,IAAI,QAAQ,CAACO,EAAON,IAAMI,EAAKE,EAAO,GAAGD,CAAE,QAAQL,CAAC,GAAG,CAAC,EACvF,KAAK,KAAKD,EAAK,MAAO,GAAGM,CAAE,QAAQ,EAC/BN,EAAK,YAAc,QAAW,KAAK,OAAO,GAAGM,CAAE,aAAc,8DAA8D,CACjI,EACMkB,EAAQ,IAAI,IAClBF,EAAK,SAAS,QAAQ,CAACG,EAAQxB,IAAM,CACnC,KAAK,MAAMwB,EAAO,GAAI,GAAG9C,CAAI,YAAYsB,CAAC,GAAG,EAC7CuB,EAAM,IAAIC,EAAO,EAAE,EACnBA,EAAO,OAAO,QAAQ,CAACzB,EAAM0B,IAAMrB,EAAKL,EAAM,GAAGrB,CAAI,YAAYsB,CAAC,YAAYyB,CAAC,GAAG,CAAC,CACrF,CAAC,EACDJ,EAAK,gBAAgB,QAAQ,CAACzC,EAAIoB,IAAM,CACjCuB,EAAM,IAAI3C,CAAE,GAAG,KAAK,OAAO,GAAGF,CAAI,mBAAmBsB,CAAC,IAAK,cAAcpB,CAAE,gBAAgB,CAClG,CAAC,EACDyC,EAAK,SAAS,QAAQ,CAACK,EAAQ1B,IAAM,KAAK,MAAM0B,EAAO,GAAI,GAAGhD,CAAI,YAAYsB,CAAC,GAAG,CAAC,CACrF,CAEQ,aAAa2B,EAAwBjD,EAAc,CACzDiD,EAAS,QAAQ,CAACC,EAAO,IAAM,KAAK,SAASA,EAAO,GAAGlD,CAAI,aAAa,CAAC,GAAG,CAAC,CAC/E,CAEQ,SAASmD,EAAkBnD,EAAc,CAG/C,OAFA,KAAK,MAAMmD,EAAK,GAAInD,CAAI,EACxB,KAAK,eAAemD,EAAMnD,EAAMmD,EAAK,OAAS,QAAU,CAAC,YAAa,WAAY,UAAU,EAAIA,EAAK,OAAS,UAAY,CAAC,YAAa,UAAU,EAAI,CAAC,WAAW,CAAC,EAC3JA,EAAK,KAAM,CACjB,IAAK,QACH,OAAO,KAAK,eAAeA,EAAMnD,CAAI,EACvC,IAAK,UACH,OAAImD,EAAK,aAAe,CAACA,EAAK,OAAO,KAAK,OAAOnD,EAAM,mDAAmD,EACtGmD,EAAK,WAAa,CAACA,EAAK,aAAa,KAAK,OAAOnD,EAAM,mCAAmC,EACvF,KAAK,aAAamD,EAAK,SAAUnD,CAAI,EAC9C,IAAK,OACH,OAAO,KAAK,SAASmD,EAAMnD,CAAI,EACjC,QACE,MACJ,CACF,CAEQ,SAASmD,EAAgBnD,EAAc,CAC7CmD,EAAK,SAAS,QAAQ,CAACC,EAAK,IAAM,CAChC,IAAMC,EAAU,GAAGrD,CAAI,aAAa,CAAC,IACrC,KAAK,MAAMoD,EAAI,GAAIC,CAAO,EAC1B,KAAK,eAAeD,EAAKC,CAAO,EAChC,KAAK,aAAaD,EAAI,SAAUC,CAAO,CACzC,CAAC,CACH,CAEQ,UAAUC,EAAkBtD,EAAc,CAMhD,GALIsD,EAAM,QACR,KAAK,KAAKA,EAAM,MAAM,MAAO,GAAGtD,CAAI,cAAc,EAC9CsD,EAAM,MAAM,gBAAkB,QAAW,KAAK,KAAKA,EAAM,MAAM,cAAe,GAAGtD,CAAI,sBAAsB,EAC3GsD,EAAM,MAAM,cAAgB,QAAW,KAAK,KAAKA,EAAM,MAAM,YAAa,GAAGtD,CAAI,oBAAoB,GAEvGsD,EAAM,UAAW,CACnB,GAAM,CAAE,MAAArB,EAAO,cAAAsB,CAAc,EAAID,EAAM,UACjCnC,EAAM,KAAK,KAAKc,EAAO,GAAGjC,CAAI,kBAAkB,EAItD,GAHImB,GAAOA,EAAI,OAAS,aAAeA,EAAI,OAAS,YAClD,KAAK,OAAO,GAAGnB,CAAI,mBAAoB,IAAIiC,CAAK,UAAUd,EAAI,IAAI,6CAA6C,EAE7GA,GAAK,OAAS,aAAeoC,EAAe,CAC9C,IAAMC,EAAS,IAAI,IAAIrC,EAAI,QAAQ,IAAKmB,GAAMA,EAAE,KAAK,CAAC,EACtDiB,EAAc,QAAQ,CAACE,EAAOnC,IAAM,CAC7BkC,EAAO,IAAIC,CAAK,GACnB,KAAK,OAAO,GAAGzD,CAAI,4BAA4BsB,CAAC,IAAK,IAAImC,CAAK,0BAA0BxB,CAAK,GAAG,CAEpG,CAAC,CACH,CACF,CACAqB,EAAM,SAAS,QAAQ,CAACN,EAAQ,IAAM,CACpC,KAAK,MAAMA,EAAO,GAAI,GAAGhD,CAAI,YAAY,CAAC,GAAG,EAC7C,KAAK,eAAegD,EAAQ,GAAGhD,CAAI,YAAY,CAAC,GAAG,CACrD,CAAC,EACDsD,EAAM,aAAa,QAAQ,CAACI,EAAM,IAAM,CACtC,KAAK,MAAMA,EAAK,GAAI,GAAG1D,CAAI,gBAAgB,CAAC,GAAG,EAC/C,KAAK,eAAe0D,EAAM,GAAG1D,CAAI,gBAAgB,CAAC,GAAG,EACjD0D,EAAK,QAAU,QAAW,KAAK,KAAKA,EAAK,MAAO,GAAG1D,CAAI,gBAAgB,CAAC,SAAS,CACvF,CAAC,EACGsD,EAAM,SACR,KAAK,MAAMA,EAAM,OAAO,GAAI,GAAGtD,CAAI,SAAS,EAC5C,KAAK,eAAesD,EAAM,OAAQ,GAAGtD,CAAI,SAAS,GAEpDsD,EAAM,QAAQ,QAAQ,CAACK,EAAO,IAAM,CAClC,KAAK,MAAMA,EAAM,GAAI,GAAG3D,CAAI,WAAW,CAAC,GAAG,EAC3C,KAAK,eAAe2D,EAAO,GAAG3D,CAAI,WAAW,CAAC,GAAG,CACnD,CAAC,EACD,QAAW4D,IAAS,CAAC,QAAS,OAAO,EACnCN,EAAM,QAAQM,CAAK,GAAG,QAAQ,CAACT,EAAM7B,IAAM,KAAK,SAAS6B,EAAM,GAAGnD,CAAI,UAAU4D,CAAK,IAAItC,CAAC,GAAG,CAAC,EAEhGgC,EAAM,QAAQ,QAAQ,CAACO,EAAO,IAAM,CAClC,KAAK,MAAMA,EAAM,GAAI,GAAG7D,CAAI,WAAW,CAAC,GAAG,EAC3C,KAAK,eAAe6D,EAAO,GAAG7D,CAAI,WAAW,CAAC,GAAG,CACnD,CAAC,EACD,KAAK,aAAasD,EAAM,SAAUtD,CAAI,EAClCsD,EAAM,YACR,KAAK,MAAMA,EAAM,UAAU,GAAI,GAAGtD,CAAI,YAAY,EAClD,KAAK,eAAesD,EAAM,UAAW,GAAGtD,CAAI,YAAY,EAE5D,CAEQ,eAAemD,EAAiBnD,EAAc,CACpD,IAAMmB,EAAM,KAAK,KAAKgC,EAAK,MAAO,GAAGnD,CAAI,QAAQ,EAEjDmD,EAAK,UAAU,QAAQ,CAACW,EAAMxC,IAAM,CAClC,IAAMK,EAAK,GAAG3B,CAAI,aAAasB,CAAC,IAEhC,GADA,KAAK,eAAewC,EAAMnC,EAAI,CAAC,OAAQ,OAAO,CAAC,EAC3CmC,EAAK,UAAY,OACrB,GAAI,CACF,IAAI,OAAOA,EAAK,OAAO,CACzB,MAAQ,CACN,KAAK,OAAO,GAAGnC,CAAE,WAAY,IAAImC,EAAK,OAAO,+BAA+B,CAC9E,CACF,CAAC,EACG3C,GAAOgC,EAAK,SACVhC,EAAI,OAAS,WACf,KAAK,OAAO,GAAGnB,CAAI,UAAW,0CAA0CmD,EAAK,KAAK,UAAUhC,EAAI,IAAI,EAAE,EAEtGgC,EAAK,OAAO,QAAQ,CAACY,EAAQzC,IAAM,CACjC,IAAM0C,EAAM5E,GAAI+B,EAAI,OAAQ4C,CAAM,EAAI5C,EAAI,OAAO4C,CAAM,EAAI,OACtDC,EACK,CAAC,UAAW,QAAS,UAAU,EAAE,SAASA,EAAI,IAAI,GAC1D,KAAK,OAAO,GAAGhE,CAAI,WAAWsB,CAAC,IAAK,IAAIyC,CAAM,UAAUC,EAAI,IAAI,mDAAmD,EAF3G,KAAK,OAAO,GAAGhE,CAAI,WAAWsB,CAAC,IAAK,IAAIyC,CAAM,qCAAqCZ,EAAK,KAAK,GAAG,CAI5G,CAAC,GAIL,OAAW,CAAC7D,EAAKiB,CAAK,IAAK,OAAO,QAAQ4C,EAAK,SAAW,CAAC,CAAC,EACtD7D,EAAI,SAAS,OAAO,GAAK,OAAOiB,GAAU,UAAU,KAAK,KAAKA,EAAO,GAAGP,CAAI,YAAYV,CAAG,EAAE,EAKnG,GAHI6B,GAAOgC,EAAK,UAAYhC,EAAI,OAAS,YACvC,KAAK,OAAO,GAAGnB,CAAI,YAAa,8CAA8CmD,EAAK,KAAK,UAAUhC,EAAI,IAAI,EAAE,EAE1GA,GAAOgC,EAAK,gBACd,GAAIhC,EAAI,OAAS,WACf,KAAK,OAAO,GAAGnB,CAAI,mBAAoB,oDAAoDmD,EAAK,KAAK,UAAUhC,EAAI,IAAI,EAAE,MACpH,CAEL,IAAM8C,EAAQd,EAAK,SAAW,OAAO,KAAKhC,EAAI,MAAM,EAAE,OAAQ+C,GAAMA,IAAM/C,EAAI,WAAW,OAAS+C,IAAM/C,EAAI,aAAa,EACzH,QAAW4C,KAAU,OAAO,KAAKZ,EAAK,eAAe,EAC9Cc,EAAM,SAASF,CAAM,GAAG,KAAK,OAAO,GAAG/D,CAAI,oBAAoB+D,CAAM,GAAI,IAAIA,CAAM,yBAAyBZ,EAAK,KAAK,GAAG,CAElI,CAEE,CAAChC,GAAO,CAACgC,EAAK,UACdhC,EAAI,OAAS,WACfgC,EAAK,QAAQ,QAAQ,CAACY,EAAQzC,IAAM,CAC7BlC,GAAI+B,EAAI,OAAQ4C,CAAM,GACzB,KAAK,OAAO,GAAG/D,CAAI,YAAYsB,CAAC,IAAK,IAAIyC,CAAM,qCAAqCZ,EAAK,KAAK,GAAG,CAErG,CAAC,EACQhC,EAAI,OAAS,aACtB,KAAK,OAAO,GAAGnB,CAAI,WAAY,yDAAyDmD,EAAK,KAAK,UAAUhC,EAAI,IAAI,EAAE,EAE1H,CACF,EC3XA,IAAMgD,GAAYC,GAAqDA,IAAU,MAAQ,OAAOA,GAAU,UAAY,CAAC,MAAM,QAAQA,CAAK,EACpIC,GAAU,CAAC,QAAS,WAAY,OAAQ,QAAQ,EAS/C,SAASC,GAAUC,EAAgC,CACxD,GAAI,CAACJ,GAASI,CAAK,EAAG,MAAO,CAAE,GAAI,GAAO,OAAQ,CAAC,CAAE,KAAM,SAAU,QAAS,yBAA0B,CAAC,CAAE,EAC3G,IAAMC,EAAsB,CAAC,EACvBC,EAAM,CAACC,EAAcC,IAAoBH,EAAO,KAAK,CAAE,KAAAE,EAAM,QAAAC,CAAQ,CAAC,EACxEJ,EAAM,UAAe,OAAgBE,EAAI,UAAW,2BAA2B,KAAc,EAAE,GAC/F,OAAOF,EAAM,IAAU,UAAY,CAACA,EAAM,KAAOE,EAAI,KAAM,oBAAoB,EACnF,IAAMG,EAAOL,EAAM,MACf,CAACJ,GAASS,CAAI,GAAK,EAAEA,EAAK,OAAY,aAAgBA,EAAK,OAAY,UAAY,OAAOA,EAAK,OAAa,UAAYA,EAAK,SAC/HH,EAAI,OAAQ,0EAAqE,EAEnF,IAAMI,EAASN,EAAM,OACrB,GAAI,CAACJ,GAASU,CAAM,EAAGJ,EAAI,SAAU,mDAAmD,MAEtF,QAAW,CAACK,EAAMC,CAAG,IAAK,OAAO,QAAQF,CAAM,GACzC,CAACV,GAASY,CAAG,GAAK,CAAEC,GAAmC,SAASD,EAAI,IAAO,GAAK,OAAOA,EAAI,OAAa,WAC1GN,EAAI,UAAUK,CAAI,GAAI,gDAAgD,EAI5E,IAAMG,EAASV,EAAM,OACfW,EAASf,GAASc,CAAM,GAAKA,EAAO,OAAY,OAItD,IAHI,CAACd,GAASc,CAAM,IAAMC,EAAS,CAAC,MAAM,QAAQD,EAAO,OAAU,EAAI,CAACZ,GAAQ,SAASY,EAAO,IAAiB,GAAK,CAAC,MAAM,QAAQA,EAAO,QAAW,KACrJR,EAAI,SAAU,wFAAwF,EAEpGD,EAAO,OAAQ,MAAO,CAAE,GAAI,GAAO,OAAAA,CAAO,EAC9C,IAAMW,EAAOZ,EACb,GAAI,CACF,IAAMa,EAAQ,IAAIC,GAAeF,CAAI,EAAE,IAAI,EAC3C,OAAOC,EAAM,OAAS,CAAE,GAAI,GAAO,OAAQA,CAAM,EAAI,CAAE,GAAI,GAAM,KAAAD,CAAK,CACxE,OAASG,EAAO,CACd,MAAO,CAAE,GAAI,GAAO,OAAQ,CAAC,CAAE,KAAM,SAAU,QAAS,uCAAwCA,EAAgB,OAAO,EAAG,CAAC,CAAE,CAC/H,CACF,CCxCA,IAAMC,GAAY,IAAI,IAAI,CAAC,QAAS,cAAe,QAAS,OAAQ,cAAe,UAAW,OAAQ,UAAW,MAAO,SAAS,CAAC,EAO5HC,GAAW,IAAI,IAAI,CAAC,YAAa,SAAU,UAAW,OAAQ,cAAc,CAAC,EAOnF,SAASC,GAAKC,EAAgBC,EAAoBC,EAAiCC,EAAiDC,EAAS,GAAgB,CAC3J,GAAI,OAAOJ,GAAU,SAAU,OAAOC,IAAQ,OAASA,EAAI,SAAS,OAAO,GAAM,CAACG,GAAUP,GAAU,IAAII,CAAG,GAAMC,EAAKF,CAAK,EAAIA,EACjI,GAAI,MAAM,QAAQA,CAAK,EAAG,OAAOA,EAAM,IAAKK,GAASN,GAAKM,EAAM,KAAMH,EAAMC,EAAOC,CAAM,CAAC,EAC1F,GAAIJ,IAAU,MAAQ,OAAOA,GAAU,SAAU,OAAOA,EACxDG,IAAQH,CAAgC,EACxC,IAAMM,EAA+B,CAAC,EACtC,OAAW,CAACC,EAAMC,CAAK,IAAK,OAAO,QAAQR,CAAK,EAE9CM,EAAIC,CAAI,EAAIT,GAAS,IAAIS,CAAI,EAAIC,EAAQT,GAAKS,EAAOD,EAAML,EAAMC,EAAOC,GAAWG,IAAS,WAAa,CAAC,MAAM,QAAQC,CAAK,CAAE,EAEjI,OAAOF,CACT,CAQO,SAASG,GAAcC,EAAYC,EAA2C,CACnF,OAAOZ,GAAKW,EAAM,KAAMC,CAAS,CACnC,CAUO,SAASC,GAAUF,EAAsB,CAC9C,IAAMG,EAAQ,IAAI,IACZC,EAASJ,EAAK,OACdK,EAAQ,CAACf,EAAgBC,EAAqB,OAClDF,GACEC,EACAC,EACCC,IAAUA,EAAK,KAAK,GAAKW,EAAM,IAAIX,CAAI,EAAGA,GAC1Cc,GAAS,CAEJA,EAAK,OAAY,UAAUD,EAAMC,EAAK,QAAW,EACrD,IAAMC,EAAMD,EAAK,OAAY,QAAUF,EAAOE,EAAK,KAAkB,EAAI,OACzE,GAAKC,EACL,QAAW,CAACC,EAAMX,CAAI,GAAK,CAAC,CAACS,EAAM,OAAO,EAAG,CAACC,EAAK,OAAO,EAAG,CAACD,EAAM,aAAa,EAAG,CAACA,EAAM,MAAM,EAAG,CAACC,EAAK,MAAM,CAAC,EAAYF,EAAMG,EAAKX,CAAI,EAAGA,CAAI,EACnJQ,EAAME,CAAG,EACX,CACF,EACF,OAAAF,EAAM,CAAE,MAAOL,EAAK,MAAO,YAAaA,EAAK,YAAa,OAAQA,EAAK,MAAO,CAAC,EAC/EK,EAAML,CAAI,EACH,CAAC,GAAGG,CAAK,CAClB,CAOO,SAASM,GAAaT,EAAYU,EAAsB,CAC7D,IAAMP,EAAQH,EAAK,eAAeU,CAAM,GAAKV,EAAK,eAAeU,EAAO,MAAM,GAAG,EAAE,CAAC,CAAC,EACrF,OAAKP,EACEJ,GAAcC,EAAOR,GAASW,EAAMX,CAAI,GAAKA,CAAI,EADrCQ,CAErB,CAMO,SAASW,GAAcC,EAAsB,CAClD,GAAM,CAACC,EAAU,GAAGC,CAAI,EAAIF,EAAI,YAAY,EAAE,MAAM,GAAG,EACjDG,EAASD,EAAK,KAAMN,GAASA,EAAK,SAAW,GAAK,CAAC,KAAK,KAAKA,CAAI,CAAC,EACxE,OAAOO,EAAS,yCAAyC,KAAKA,CAAM,EAAI,2DAA2D,KAAKF,CAAQ,CAClJ,CCzCO,SAASG,GACdC,EACAC,EACS,CAET,GAAID,IAAe,OACjB,MAAO,GAIT,GAAI,OAAOA,GAAe,UACxB,OAAOA,EAIT,GAAIA,IAAe,KAAOA,IAAe,QAAUA,IAAe,OAChE,MAAO,GAQT,GALIA,IAAe,KAAOA,IAAe,SAAWA,IAAe,SAK/DA,IAAe,GACjB,MAAO,GAIT,GAAI,CACF,IAAME,EAASC,GAASH,CAAU,EAGlC,GAAIE,EAAO,SAAW,EACpB,MAAO,GAIT,IAAME,EADS,IAAIC,GAAiBH,CAAM,EACvB,MAAM,EACnBI,EAASC,GAASH,EAAKH,CAAO,EAGpC,OAAOO,GAAOF,CAAM,CACtB,MAAQ,CAIN,MAAO,EACT,CACF,CAQO,SAASG,GAAgBT,EAAmD,CAKjF,GAJIA,IAAe,QAAa,OAAOA,GAAe,WAIlDA,IAAe,GACjB,MAAO,GAGT,GAAI,CACF,IAAME,EAASC,GAASH,CAAU,EAClC,OAAIE,EAAO,SAAW,GAGP,IAAIG,GAAiBH,CAAM,EACnC,MAAM,EACN,EACT,MAAQ,CACN,MAAO,EACT,CACF,CCjIO,IAAMQ,GAAY,CAAC,EC6E1B,IAAMC,GAAe,CACnB,SAAU,sBACV,UAAW,mCACX,QAAS,wCACT,KAAM,uBACN,OAAQ,2BACR,QAAS,iCACT,IAAK,iCACL,IAAK,gCACL,SAAU,0CACV,QAAS,4BACT,WAAY,4CACZ,YAAa,wCACb,eAAgB,8DAChB,gBAAiB,2CACjB,OAAQ,4BACR,cAAe,qDACf,OAAQ,uCACR,UAAW,mBACX,WAAY,8BACZ,QAAS,oCACT,OAAQ,2BACR,QAAS,oCACT,UAAW,kCACX,KAAM,yBACN,SAAU,gCACV,SAAU,gCACV,SAAU,sCACV,SAAU,4CACV,UAAW,4CACX,SAAU,iCACV,QAAS,oCACT,OAAQ,mCACR,SAAU,8BACV,WAAY,gCACZ,MAAO,gDACP,GAAI,KACJ,KAAM,yBACN,MAAO,gDACP,IAAK,wCACL,MAAO,8CACP,KAAM,2BACN,OAAQ,qCACR,MAAO,oCACP,QAAS,oCACT,SAAU,gCACV,SAAU,qCACV,aAAc,sEACd,OAAQ,IACV,EAQaC,GAAqC,CAAE,GAAAD,GAAI,GAAGE,EAAU,EAG9D,SAASC,GAAKC,EAAkBC,EAAiD,CACtF,OAAOD,EAAS,QAAQ,aAAc,CAACE,EAAOC,IAAkBA,KAAQF,EAAS,OAAOA,EAAOE,CAAI,CAAC,EAAID,CAAM,CAChH,CC9HO,SAASE,GAAMC,EAAeC,EAAQC,GAAS,IAAI,IAAM,EAAW,CACzE,IAAMC,EAAU,oBAAoB,KAAKH,CAAK,EAC9C,GAAI,CAACG,EAAS,OAAOH,EACrB,GAAM,CAACI,EAAGC,EAAGC,CAAC,EAAIL,EAAM,MAAM,GAAG,EAAE,IAAI,MAAM,EAC7C,OAAO,IAAI,KAAK,KAAK,IAAIG,EAAGC,EAAI,EAAGC,EAAI,OAAOH,EAAQ,CAAC,GAAK,CAAC,CAAC,CAAC,EAAE,YAAY,EAAE,MAAM,EAAG,EAAE,CAC5F,CAGA,IAAMI,GAAU,CAACC,EAAqCC,EAAoBC,IACxE,IAAI,KAAK,eAAeD,EAAS,OAAQ,CAAE,GAAGD,EAAS,SAAU,MAAO,gBAAiB,MAAO,CAAC,EAAE,OAAOE,CAAE,EAGvG,SAASC,GAASC,EAA0BC,EAAeZ,EAA2BQ,EAAwC,CACnI,GAAIG,EAAM,OAAS,QAAUA,EAAM,OAAS,WAAY,OACxD,IAAME,EAAMF,EAAM,OAAS,OAASC,EAAQX,GAAS,IAAI,KAAKW,CAAK,CAAC,EAC9DE,EAAM,CAACC,EAAqChB,IAAkBiB,GAAKR,EAASO,CAAG,EAAG,CAAE,MAAOJ,EAAM,MAAO,IAAKZ,EAAO,IAAKA,EAAO,KAAMA,CAAM,CAAC,EAC7IkB,EAASlB,GAAkBO,GAAQ,CAAE,IAAK,UAAW,MAAO,OAAQ,KAAM,SAAU,EAAGE,EAAU,KAAK,MAAMT,CAAK,CAAC,EAClHmB,EAAMP,EAAM,KAAOb,GAAMa,EAAM,IAAKX,CAAK,EACzCmB,EAAMR,EAAM,KAAOb,GAAMa,EAAM,IAAKX,CAAK,EAC/C,GAAIkB,GAAOL,EAAMK,EAAK,OAAOJ,EAAI,SAAUG,EAAMC,CAAG,CAAC,EACrD,GAAIC,GAAON,EAAMM,EAAK,OAAOL,EAAI,QAASG,EAAME,CAAG,CAAC,EACpD,IAAMC,EAAOT,EAAM,KAEnB,GAAIS,GAAQ,CAACA,EAAK,SAAS,IAAI,KAAK,KAAK,MAAMP,CAAG,CAAC,EAAE,UAAU,GAAK,CAAC,EAAG,CACtE,IAAMQ,EAAM,CAAC,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,CAAC,EAAE,OAAQC,GAAM,CAACF,EAAK,SAASE,CAAC,CAAC,EAAE,IAAKA,GAAMhB,GAAQ,CAAE,QAAS,MAAO,EAAGE,EAAU,KAAK,IAAI,KAAM,EAAGc,CAAC,CAAC,CAAC,EAC1I,OAAOR,EAAI,UAAWO,EAAI,OAAS,EAAI,GAAGA,EAAI,MAAM,EAAG,EAAE,EAAE,KAAK,IAAI,CAAC,IAAIb,EAAS,EAAE,IAAIa,EAAIA,EAAI,OAAS,CAAC,CAAC,GAAKA,EAAI,CAAC,CAAC,CACxH,CAEF,CCmBO,SAASE,GAAWC,EAAwB,CACjD,OAAQA,EAAM,KAAM,CAClB,IAAK,UACH,MAAO,GACT,IAAK,YACL,IAAK,WACH,MAAO,CAAC,EACV,IAAK,YACL,IAAK,SACL,IAAK,QACH,OAAOA,EAAM,SAAW,CAAC,EAAI,KAC/B,QACE,OAAO,IACX,CACF,CAGO,SAASC,GAAcC,EAAkCC,EAAwB,CACtF,IAAMC,EAAiB,CAAC,EACxB,OAAW,CAACC,EAAML,CAAK,IAAK,OAAO,QAAQE,CAAM,EAAG,CAClD,IAAMI,EAAQN,EAAM,QACpBI,EAAOC,CAAI,EAAIC,IAAU,OAAYP,GAAWC,CAAK,EAAIA,EAAM,OAAS,QAAU,OAAOM,GAAU,UAAYA,EAAM,WAAW,OAAO,EAAIC,GAAMD,EAAOH,CAAK,EAAIK,GAAeF,CAAK,CACvL,CACA,OAAOF,CACT,CAGO,SAASK,GAAQT,EAAiBU,EAAmC,CAC1E,OAAIA,GAAU,KAAoC,GAC9C,OAAOA,GAAU,SAAiBA,EAAM,KAAK,IAAM,GACnD,MAAM,QAAQA,CAAK,EAAUA,EAAM,SAAW,EAE9CV,EAAM,OAAS,UAAY,OAAOU,GAAU,SACvC,OAAO,OAAOA,CAAgC,EAAE,MAAOC,GAAMA,GAAM,MAA4B,MAAM,QAAQA,CAAC,GAAK,CAACA,EAAE,MAAO,EAE/H,EACT,CAQO,SAASC,GAAkBR,EAAgBF,EAA2D,CAC3G,IAAMW,EAAmC,CAAC,EAC1C,OAAW,CAACR,EAAMK,CAAK,IAAK,OAAO,QAAQN,CAAM,EAAG,CAClD,IAAMJ,EAAQE,EAAOG,CAAI,EACzBQ,EAAQR,CAAI,EAAIL,EAAQc,GAAed,EAAOU,CAAK,EAAIA,CACzD,CACA,OAAOG,CACT,CAEA,SAASC,GAAed,EAAiBU,EAAuB,CAC9D,GAAIA,GAAU,KAA6B,OAAO,KAClD,OAAQV,EAAM,KAAM,CAClB,IAAK,WACH,OAAQU,EAAwB,GAClC,IAAK,YACH,OAAQA,EAA0B,IAAKK,GAAWA,EAAO,EAAE,EAC7D,IAAK,WACH,OAAQL,EAAiB,IAAKM,GAASA,EAAK,GAAG,EACjD,IAAK,YAAa,CAChB,IAAMC,EAAMP,EACZ,MAAO,GAAGO,EAAI,KAAK,IAAIA,EAAI,EAAE,EAC/B,CACA,IAAK,SACL,IAAK,QACH,OAAO,MAAM,QAAQP,CAAK,EAAKA,EAAsB,IAAKQ,GAASA,EAAK,IAAI,EAAKR,EAAoB,KACvG,QACE,OAAOA,CACX,CACF,CAMO,SAASS,GAASnB,EAA6CI,EAA2C,CAC/G,IAAMgB,EAAQpB,EAAM,UACpB,GAAI,CAACoB,EAAO,OAAO,KACnB,IAAMV,EAAQN,EAAOgB,EAAM,KAAK,EAChC,OAAIV,KAAWU,EAAM,SAAW,WAAmB,UAC/CV,KAAWU,EAAM,MAAQ,QAAgB,OACtC,IACT,CAGO,SAASC,GAAUV,EAAsBW,EAA+B,CAC7E,OAAO,KAAK,UAAUX,GAAK,IAAI,IAAM,KAAK,UAAUW,GAAK,IAAI,CAC/D,CAGO,SAASd,GAAkBE,EAAa,CAC7C,OAAOA,IAAU,OAAYA,EAAS,KAAK,MAAM,KAAK,UAAUA,CAAK,CAAC,CACxE,CC9IO,SAASa,GACdC,EACAC,EACAC,EACAC,EAAqBC,GAAS,GAE9BC,EACoB,CACpB,IAAMC,EAAQN,EAAM,OAAS,aACvBO,EAAM,CAACC,EAAqBC,EAA0C,CAAC,IAAMC,GAAKP,EAASK,CAAG,EAAG,CAAE,MAAAF,EAAO,GAAGG,CAAO,CAAC,EAC3H,GAAIE,GAAQX,EAAOC,CAAK,EAAG,OAAOC,EAAWK,EAAI,UAAU,EAAI,OAC/D,GAAIP,EAAM,OAAS,SAAU,OAAOY,GAAYZ,EAAOC,EAAOC,EAAUK,CAAG,EAE3E,OAAQP,EAAM,KAAM,CAClB,IAAK,OACL,IAAK,OACL,IAAK,OACH,OAAI,OAAOC,GAAU,SAAiBM,EAAI,MAAM,GAC3CP,EAAM,OAAS,QAAUA,EAAM,OAAS,SAAWA,EAAM,OAAS,QAAaC,EAAM,OAASD,EAAM,KAChGO,EAAI,YAAa,CAAE,IAAKP,EAAM,IAAK,CAAC,EAEzCA,EAAM,OAAS,QAAUA,EAAM,UAAY,QAAa,CAAC,IAAI,OAAOA,EAAM,OAAO,EAAE,KAAKC,CAAK,EACxFM,EAAI,SAAS,EAEtB,OAEF,IAAK,UACL,IAAK,QACL,IAAK,WACH,OAAI,OAAON,GAAU,UAAY,CAAC,OAAO,SAASA,CAAK,EAAUM,EAAI,QAAQ,EACzEP,EAAM,OAAS,WAAa,CAAC,OAAO,UAAUC,CAAK,EAAUM,EAAI,SAAS,EAC1EP,EAAM,MAAQ,QAAaC,EAAQD,EAAM,IAAYO,EAAI,MAAO,CAAE,IAAKP,EAAM,GAAI,CAAC,EAClFA,EAAM,MAAQ,QAAaC,EAAQD,EAAM,IAAYO,EAAI,MAAO,CAAE,IAAKP,EAAM,GAAI,CAAC,EAClFA,EAAM,OAAS,WAAaA,EAAM,QAAUa,GAASZ,CAAK,EAAID,EAAM,OAAO,CAAC,EACvEO,EAAI,WAAY,CAAE,OAAQP,EAAM,OAAO,CAAC,CAAE,CAAC,EAEpD,OAEF,IAAK,UACH,OAAO,OAAOC,GAAU,UAAY,OAAYM,EAAI,SAAS,EAC/D,IAAK,OACH,OAAOO,GAAUb,EAAOM,CAAG,GAAKQ,GAASf,EAAOC,EAAiBI,EAAOF,CAAQ,EAClF,IAAK,WACH,OAAOa,GAAcf,EAAOM,CAAG,GAAKQ,GAASf,EAAOC,EAAiBI,EAAOF,CAAQ,EACtF,IAAK,YAAa,CAEhB,GAAIH,EAAM,YAAa,OACvB,IAAMiB,EAAU,IAAI,IAAIjB,EAAM,QAAQ,IAAKkB,GAAMA,EAAE,KAAK,CAAC,EACnDC,EAAUZ,EAAIP,EAAM,MAAQ,gBAAkB,SAAU,CAAE,QAASA,EAAM,QAAQ,IAAKkB,GAAMA,EAAE,KAAK,EAAE,KAAK,IAAI,CAAE,CAAC,EAEjHE,EAAOC,IAAgBrB,EAAM,QAAU,IAAQA,EAAM,aAAe,KAAS,OAAOqB,GAAM,UAAYA,EAAE,KAAK,IAAM,IAAM,CAACJ,EAAQ,IAAII,CAAC,EAC7I,OAAIrB,EAAM,SACH,MAAM,QAAQC,CAAK,GACVA,EAAM,OAAQoB,GAAM,CAACJ,EAAQ,IAAII,CAAoB,CAAC,EAAE,QAErD,GAAKrB,EAAM,aAAeC,EAAM,MAAOoB,GAAMJ,EAAQ,IAAII,CAAoB,GAAKD,EAAIC,CAAC,CAAC,EAAI,OAAYF,EAHvFZ,EAAI,SAAS,EAK1CU,EAAQ,IAAIhB,CAAwB,GAAKmB,EAAInB,CAAK,EAAI,OAAYkB,CAC3E,CACA,IAAK,WACH,OAAOG,GAASrB,CAAK,EAAI,OAAYM,EAAI,QAAQ,EACnD,IAAK,YACH,OAAO,MAAM,QAAQN,CAAK,GAAKA,EAAM,MAAMqB,EAAQ,EAAI,OAAYf,EAAI,SAAS,EAClF,IAAK,YAAa,CAChB,IAAMgB,EAAMtB,EACZ,GAAI,CAACqB,GAASrB,CAAK,GAAK,OAAOsB,EAAI,OAAU,SAAU,OAAOhB,EAAI,QAAQ,EAC1E,GAAI,CAACP,EAAM,OAAO,KAAMwB,GAAMA,EAAE,QAAUD,EAAI,KAAK,EAAG,CACpD,IAAME,EAASC,GAAO1B,EAAM,OAAO,IAAKwB,GAAMA,EAAE,KAAK,EAAGrB,EAAS,EAAE,EACnE,OAAOI,EAAI,YAAa,CAAE,OAAAkB,EAAQ,QAASE,GAAQF,CAAM,CAAE,CAAC,CAC9D,CACA,MACF,CACA,IAAK,SACL,IAAK,QACH,OAAOG,GAAW5B,EAAOC,EAAOM,EAAKJ,CAAQ,EAC/C,QACE,MACJ,CACF,CAGA,SAASS,GACPZ,EACAC,EACAC,EACAK,EACoB,CACpB,GAAIN,IAAU,MAAQ,OAAOA,GAAU,UAAY,MAAM,QAAQA,CAAK,EAAG,OAAOM,EAAI,QAAQ,EAC5F,IAAMsB,EAAO,IAAI,IAAI7B,EAAM,KAAK,IAAK8B,GAAM,OAAOA,EAAE,KAAK,CAAC,CAAC,EACrDC,EAAU,IAAI,IAAI/B,EAAM,QAAQ,IAAKgC,GAAMA,EAAE,KAAgB,CAAC,EAC9Db,EAAUZ,EAAI,SAAU,CAAE,QAASP,EAAM,QAAQ,IAAKgC,GAAMA,EAAE,KAAK,EAAE,KAAK,IAAI,CAAE,CAAC,EACvF,OAAW,CAACC,EAAKC,CAAM,IAAK,OAAO,QAAQjC,CAAgC,EAAG,CAC5E,GAAI,CAAC4B,EAAK,IAAII,CAAG,EAAG,OAAO1B,EAAI,YAAa,CAAE,KAAMP,EAAM,KAAK,IAAK8B,GAAMA,EAAE,KAAK,EAAE,KAAK,IAAI,CAAE,CAAC,EAC/F,IAAMK,EAASnC,EAAM,UAAY,MAAM,QAAQkC,CAAM,EAAIA,EAAS,CAACA,CAAM,EAEzE,GADI,CAAClC,EAAM,UAAY,MAAM,QAAQkC,CAAM,GACvCC,EAAO,KAAMC,GAAMA,GAAM,MAA2B,CAACL,EAAQ,IAAIK,CAAC,CAAC,EAAG,OAAOjB,CACnF,CACA,IAAMkB,EAAYJ,GAAgB,CAChC,IAAMG,EAAKnC,EAAkCgC,CAAG,EAChD,OAAOG,GAAM,MAA2B,EAAE,MAAM,QAAQA,CAAC,GAAK,CAACA,EAAE,OACnE,EACA,GAAIlC,GAAYF,EAAM,KAAK,KAAM8B,GAAM,CAACO,EAAS,OAAOP,EAAE,KAAK,CAAC,CAAC,EAAG,OAAOvB,EAAI,YAAY,CAE7F,CAEA,SAASM,GAASZ,EAAuB,CACvC,IAAMqC,EAAO,OAAOrC,CAAK,EACzB,GAAIqC,EAAK,SAAS,IAAI,EAAG,OAAO,OAAOA,EAAK,MAAM,IAAI,EAAE,CAAC,CAAC,EAC1D,IAAMC,EAAMD,EAAK,QAAQ,GAAG,EAC5B,OAAOC,IAAQ,GAAK,EAAID,EAAK,OAASC,EAAM,CAC9C,CAEA,SAASjB,GAASrB,EAAwC,CACxD,OACEA,IAAU,MACV,OAAOA,GAAU,UACjB,CAAC,MAAM,QAAQA,CAAK,IACnB,OAAQA,EAAwB,IAAO,UAAY,OAAQA,EAAwB,IAAO,WAC3F,OAAQA,EAAwB,OAAU,QAE9C,CAIA,SAASa,GAAUb,EAA0BM,EAA8B,CACzE,GAAI,OAAON,GAAU,UAAY,CAAC,sBAAsB,KAAKA,CAAK,EAAG,OAAOM,EAAI,YAAY,EAC5F,GAAM,CAACiC,EAAGhB,EAAGiB,CAAC,EAAIxC,EAAM,MAAM,GAAG,EAAE,IAAI,MAAM,EAC7C,OAAOyC,GAAQF,EAAGhB,EAAGiB,CAAC,EAAI,OAAYlC,EAAI,aAAa,CACzD,CAEA,IAAMoC,GAAe,6FAErB,SAAS3B,GAAcf,EAA0BM,EAA8B,CAC7E,IAAMqC,EAAQ,OAAO3C,GAAU,SAAW0C,GAAa,KAAK1C,CAAK,EAAI,KACrE,GAAI,CAAC2C,EAAO,OAAOrC,EAAI,gBAAgB,EACvC,GAAM,CAACiC,EAAGK,EAAIJ,EAAGK,EAAGC,EAAIC,CAAC,EAAIJ,EAAM,MAAM,CAAC,EAAE,IAAKK,GAAS,OAAOA,GAAQ,CAAC,CAAC,EAC3E,OAAOP,GAAQF,EAAGK,EAAIJ,CAAC,GAAKK,EAAI,IAAMC,EAAK,IAAMC,EAAI,GAAK,OAAYzC,EAAI,iBAAiB,CAC7F,CAEA,SAASmC,GAAQQ,EAAcC,EAAeC,EAAsB,CAClE,GAAID,EAAQ,GAAKA,EAAQ,IAAMC,EAAM,EAAG,MAAO,GAC/C,IAAMC,EAAU,CAAC,GAAIH,EAAO,IAAM,IAAMA,EAAO,MAAQ,GAAKA,EAAO,MAAQ,GAAK,GAAK,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,EAAE,EAC/H,OAAOE,GAAOC,EAAQF,EAAQ,CAAC,CACjC,CAKA,SAASvB,GAAW5B,EAAkBC,EAA0BM,EAAUJ,EAAwC,CAEhH,IAAMmD,EAAQtD,EAAM,SAAY,MAAM,QAAQC,CAAK,EAAIA,EAAQ,CAACA,CAAK,EAAK,CAACA,CAAK,EAChF,GAAID,EAAM,UAAYA,EAAM,WAAa,QAAasD,EAAM,OAAStD,EAAM,SAAU,OAAOO,EAAI,WAAY,CAAE,IAAKP,EAAM,QAAS,CAAC,EACnI,GAAIA,EAAM,UAAYA,EAAM,WAAa,QAAasD,EAAM,OAAStD,EAAM,SAAU,OAAOO,EAAI,WAAY,CAAE,IAAKP,EAAM,QAAS,CAAC,EACnI,QAAWuD,KAAQD,EAAO,CACxB,GAAI,CAACE,GAAOD,CAAI,EAAG,OAAOhD,EAAI,MAAM,EACpC,IAAMkD,EAAUC,GAAY1D,EAAOuD,EAAMpD,EAAUH,EAAM,SAAWuD,EAAK,KAAOvD,EAAM,OAAS,YAAY,EAC3G,GAAIyD,EAAS,OAAOA,CACtB,CAEF,CAOO,SAASC,GAAY1D,EAAkBuD,EAAoDpD,EAAqBC,GAAS,GAAIE,EAAQiD,EAAK,KAA0B,CACzK,GAAIvD,EAAM,UAAY,QAAauD,EAAK,KAAOvD,EAAM,QAAS,OAAOU,GAAKP,EAAS,SAAU,CAAE,MAAAG,EAAO,KAAMqD,GAAY3D,EAAM,OAAO,CAAE,CAAC,EACxI,IAAM4D,EAAS5D,EAAM,OAAS,QAAU,CAAC,SAAS,EAAIA,EAAM,OAC5D,GAAI4D,GAAU,CAACC,GAAQD,EAAQL,EAAK,IAAI,EAAG,CACzC,IAAMO,EAAQC,GAAcH,EAAQzD,EAAS,EAAE,EAC/C,OAAOO,GAAKP,EAAS,SAAU,CAAE,MAAAG,EAAO,MAAAwD,EAAO,OAAQnC,GAAQmC,CAAK,CAAE,CAAC,CACzE,CAEF,CAEA,SAASN,GAAOvD,EAAoC,CAClD,IAAMsD,EAAOtD,EACb,OAAOA,IAAU,MAAQ,OAAOA,GAAU,UAAY,OAAOsD,EAAK,MAAS,UAAY,OAAOA,EAAK,MAAS,QAC9G,CAGA,SAASM,GAAQG,EAA6BC,EAAuB,CACnE,OAAOD,EAAS,KAAME,GAAaA,EAAQ,SAAS,IAAI,EAAID,EAAK,WAAWC,EAAQ,MAAM,EAAG,EAAE,CAAC,EAAIA,IAAYD,CAAK,CACvH,CAGA,IAAME,GAAa,oNAAoN,MAAM,GAAG,EAAE,IAAKC,GAASA,EAAK,MAAM,GAAG,CAAC,EAE/Q,SAASC,GAAaH,EAAyB,CAC7C,GAAIA,EAAQ,SAAS,IAAI,EAAG,OAAOA,EAAQ,MAAM,EAAG,EAAE,EACtD,IAAMI,EAAMJ,EAAQ,MAAM,GAAG,EAAE,CAAC,GAAKA,EACrC,OAAOC,GAAW,KAAK,CAAC,CAACI,CAAI,IAAMD,EAAI,SAASC,CAAI,CAAC,IAAI,CAAC,GAAKD,EAAI,YAAY,CACjF,CAGO,SAASP,GAAcC,EAA6BQ,EAAoB,CAC7E,OAAO9C,GAAO,CAAC,GAAG,IAAI,IAAIsC,EAAS,IAAIK,EAAY,CAAC,CAAC,EAAGG,CAAE,CAC5D,CAEA,SAAS9C,GAAO+C,EAAiBD,EAAoB,CACnD,OAAIC,EAAM,QAAU,EAAUA,EAAM,KAAK,EAAE,EACpC,GAAGA,EAAM,MAAM,EAAG,EAAE,EAAE,KAAK,IAAI,CAAC,IAAID,CAAE,IAAIC,EAAMA,EAAM,OAAS,CAAC,CAAC,EAC1E,CAEA,SAAS9C,GAAQ+C,EAAwB,CACvC,MAAO,YAAY,KAAKA,CAAM,EAAI,MAAMA,CAAM,GAAK,KAAKA,CAAM,EAChE,CAGO,SAASf,GAAYgB,EAAuB,CACjD,IAAMC,EAAQ,CAAC,QAAS,KAAM,KAAM,IAAI,EACpCC,EAAOF,EACPG,EAAO,EACX,KAAOD,GAAQ,MAAQC,EAAOF,EAAM,OAAS,GAC3CC,GAAQ,KACRC,IAEF,MAAO,GAAG,OAAOD,EAAK,QAAQ,CAAC,CAAC,CAAC,IAAID,EAAME,CAAI,CAAC,EAClD,CCpNA,IAAMC,GAAQC,GAAc,KAAK,MAAMA,EAAI,GAAG,EAAI,IAE5CC,GAAW,CAACC,EAA4BC,IAAmBD,EAAQ,KAAME,GAAMA,EAAE,QAAUD,CAAK,GAAG,OAAS,EAC5GE,GAAQH,GAA+BA,EAAQ,OAAO,CAACI,EAAMF,IAAM,KAAK,IAAIE,EAAMF,EAAE,OAAS,CAAC,EAAG,CAAC,EAClGG,GAAYL,GAA+BA,EAAQ,OAAO,CAACM,EAAKJ,IAAMI,EAAM,KAAK,IAAI,EAAGJ,EAAE,OAAS,CAAC,EAAG,CAAC,EAExGK,GAAS,CAACP,EAA4BQ,EAAiBC,IAC3DA,EAAW,MAAM,QAAQD,CAAM,EAAIA,EAAO,OAAO,CAACF,EAAaI,IAAMJ,EAAMP,GAASC,EAASU,CAAC,EAAG,CAAC,EAAI,EAAKX,GAASC,EAASQ,CAAM,EAE9H,SAASG,GAAQC,EAAYC,EAA8B,CAChE,IAAIC,EAAQ,EACRC,EAAM,EACNC,EAAS,GACb,OAAW,CAACC,EAAMC,CAAK,IAAK,OAAO,QAAQN,EAAK,MAAM,EACpD,GAAIM,EAAM,OAAS,aAAeA,EAAM,QAAQ,KAAMhB,GAAMA,EAAE,QAAU,MAAS,EAAG,CAClFc,EAAS,GACT,IAAMP,EAAUS,EAAM,WAAa,GACnCJ,GAASP,GAAOW,EAAM,QAASL,EAAOI,CAAI,EAAGR,CAAO,EACpDM,GAAON,EAAUJ,GAASa,EAAM,OAAO,EAAIf,GAAKe,EAAM,OAAO,CAC/D,SAAWA,EAAM,OAAS,UAAYA,EAAM,QAAQ,KAAMC,GAAMA,EAAE,QAAU,MAAS,EAAG,CACtFH,EAAS,GACT,IAAMP,EAAUS,EAAM,WAAa,GAC7BE,EAAUP,EAAOI,CAAI,EACrBI,EAAQD,GAAW,OAAOA,GAAY,UAAY,CAAC,MAAM,QAAQA,CAAO,EAAKA,EAAsC,CAAC,EAC1H,QAAWE,KAAOJ,EAAM,KACtBJ,GAASP,GAAOW,EAAM,QAASG,EAAM,OAAOC,EAAI,KAAK,CAAC,EAAGb,CAAO,EAChEM,GAAON,EAAUJ,GAASa,EAAM,OAAO,EAAIf,GAAKe,EAAM,OAAO,CAEjE,CAEF,OAAOF,EAAS,CAAE,MAAOnB,GAAKiB,CAAK,EAAG,IAAKjB,GAAKkB,CAAG,CAAE,EAAI,IAC3D,CCmIO,SAASQ,GAAYC,EAAwD,CAClF,OAAO,OAAO,OAAO,IAAI,MAAMA,EAAQ,OAAO,EAAG,CAAE,QAAAA,CAAQ,CAAC,CAC9D,CAGO,SAASC,GAAcC,EAA6B,CACzD,IAAMC,EAAWD,GAA4C,QAC7D,GAAIC,GAAW,OAAOA,EAAQ,MAAS,SAAU,OAAOA,EACxD,IAAMC,EAAUF,aAAiB,MAAQA,EAAM,QAAU,OAAOA,CAAK,EACrE,OAAIA,aAAiB,WAAa,6BAA6B,KAAKE,CAAO,EAAU,CAAE,KAAM,UAAW,QAAAA,CAAQ,EACzG,CAAE,KAAM,QAAS,QAAAA,CAAQ,CAClC,CCxLO,SAASC,GAAcC,EAAgBC,EAA4C,CACxF,OAAOA,EAAO,MAAOC,GAASC,GAAMH,EAAQE,CAAI,CAAC,CACnD,CAEA,SAASC,GAAMH,EAAgBE,EAA+B,CAC5D,MAAI,QAASA,EAAaA,EAAK,IAAI,KAAME,GAAUD,GAAMH,EAAQI,CAAK,CAAC,EACnE,QAASF,EAAaA,EAAK,IAAI,MAAOE,GAAUD,GAAMH,EAAQI,CAAK,CAAC,EACjEC,GAAML,EAAQE,CAAI,CAC3B,CAGA,SAASI,GAAMC,EAAyB,CACtC,OAAOA,GAAU,MAA+BA,IAAU,IAAMA,IAAU,IAAS,EAAE,MAAM,QAAQA,CAAK,GAAK,CAACA,EAAM,OACtH,CAEA,SAASF,GAAML,EAAgBQ,EAA6C,CAC1E,IAAMC,EAAMT,EAAOQ,EAAU,KAAK,EAE5BE,EAASD,IAAQ,MAAQ,OAAOA,GAAQ,UAAY,CAAC,MAAM,QAAQA,CAAG,GAAK,OAAQA,EAAOA,EAAsB,GAAMA,EACtHE,EAAWH,EAAU,MAErBI,EAAOH,IAAQ,MAAQ,OAAOA,GAAQ,UAAY,CAAC,MAAM,QAAQA,CAAG,GAAK,UAAWA,EAAM,OAAQA,EAAsB,KAAK,EAAI,OAAOC,GAAU,EAAE,EAC1J,OAAQF,EAAU,GAAI,CACpB,IAAK,IACH,OAAOE,IAAWC,EACpB,IAAK,KACH,OAAOD,IAAWC,EACpB,IAAK,IACH,OAAOL,GAAMI,CAAM,GAAMA,EAAqBC,EAChD,IAAK,IACH,OAAOL,GAAMI,CAAM,GAAMA,EAAqBC,EAChD,IAAK,KACH,OAAOL,GAAMI,CAAM,GAAMA,GAAsBC,EACjD,IAAK,KACH,OAAOL,GAAMI,CAAM,GAAMA,GAAsBC,EACjD,IAAK,KACH,OAAO,MAAM,QAAQA,CAAQ,GAAKA,EAAS,SAASD,CAAmB,EACzE,IAAK,SACH,OAAO,MAAM,QAAQC,CAAQ,GAAK,CAACA,EAAS,SAASD,CAAmB,EAC1E,IAAK,OACH,OAAOE,EAAK,SAAS,OAAOD,CAAQ,CAAC,EACvC,IAAK,QACH,OAAOC,EAAK,YAAY,EAAE,SAAS,OAAOD,CAAQ,EAAE,YAAY,CAAC,EACnE,IAAK,aACH,OAAOC,EAAK,YAAY,EAAE,WAAW,OAAOD,CAAQ,EAAE,YAAY,CAAC,EACrE,IAAK,WACH,OAAOC,EAAK,YAAY,EAAE,SAAS,OAAOD,CAAQ,EAAE,YAAY,CAAC,EACnE,IAAK,MACH,OAAOL,GAAMG,CAAG,EAClB,IAAK,SACH,MAAO,CAACH,GAAMG,CAAG,EACnB,IAAK,UAAW,CACd,GAAI,CAACH,GAAMI,CAAM,GAAK,CAAC,MAAM,QAAQC,CAAQ,EAAG,MAAO,GACvD,GAAM,CAACE,EAAKC,CAAI,EAAIH,EACpB,OAAQD,GAA8BG,GAAQH,GAA8BI,CAC9E,CACF,CACF,CCvCA,IAAMC,GAAO,IAAI,IAAI,CAAC,OAAQ,OAAQ,MAAM,CAAC,EACvCC,GAAS,IAAI,IAAI,CAAC,UAAW,QAAS,UAAU,CAAC,EACjDC,GAAO,IAAI,IAAI,CAAC,WAAY,WAAW,CAAC,EAOvC,SAASC,GAAYC,EAAeC,EAAYC,EAAgBC,EAA+B,CAAE,UAAW,4BAA6B,EAAiB,CAC/J,IAAMC,EAAOJ,EAAM,KAAK,EACxB,GAAI,CAACI,EAAM,MAAO,CAAC,EACnB,IAAMC,EAAsB,CAAC,EAC7B,QAAWC,KAASJ,EAAK,cAAgBA,EAAK,QAAS,CACrD,IAAMK,EAAMN,EAAK,OAAOK,CAAK,EAC7B,GAAI,CAACC,EAAK,SACV,IAAMC,EAAM,CAACC,EAAsBC,EAAkBC,EAAoBC,IACvEP,EAAM,KAAK,CAAE,MAAAC,EAAO,WAAYC,EAAI,MAAO,GAAAE,EAAI,MAAAC,EAAO,WAAAC,EAAY,MAAOC,GAASC,GAAKV,EAAM,UAAW,CAAE,MAAOI,EAAI,MAAO,KAAAH,CAAK,CAAC,CAAE,CAAC,EACvI,GAAIR,GAAK,IAAIW,EAAI,IAAI,GAAKT,GAAK,IAAIS,EAAI,IAAI,EAAGC,EAAI,QAASJ,EAAMA,CAAI,UAC5DG,EAAI,OAAS,YAAa,CACjC,IAAMO,EAAQV,EAAK,YAAY,EAC/B,QAAWW,KAAUR,EAAI,QAAaQ,EAAO,MAAM,YAAY,EAAE,SAASD,CAAK,GAAGN,EAAI,IAAKO,EAAO,MAAOA,EAAO,MAAO,GAAGR,EAAI,KAAK,KAAKQ,EAAO,KAAK,EAAE,CACxJ,SAAWlB,GAAO,IAAIU,EAAI,IAAI,EAAG,CAC/B,IAAMS,EAAS,OAAOZ,EAAK,QAAQ,SAAU,EAAE,CAAC,EAC5CA,GAAQ,OAAO,SAASY,CAAM,GAAGR,EAAI,IAAKQ,EAAQZ,CAAI,CAC5D,CACF,CAEA,IAAMa,EAAQ,GAAkB,CAC9B,IAAMC,EAAOjB,EAAK,OAAO,EAAE,KAAK,GAAG,MAAQ,GAC3C,OAAOL,GAAK,IAAIsB,CAAI,EAAI,EAAIA,IAAS,YAAc,EAAIrB,GAAO,IAAIqB,CAAI,EAAI,EAAI,CAChF,EACA,OAAOb,EAAM,IAAI,CAAC,EAAGc,KAAO,CAAE,EAAG,EAAAA,CAAE,EAAE,EAAE,KAAK,CAACC,EAAGC,IAAMJ,EAAKG,EAAE,CAAC,EAAIH,EAAKI,EAAE,CAAC,GAAKD,EAAE,EAAIC,EAAE,CAAC,EAAE,IAAI,CAAC,CAAE,CAAE,IAAM,CAAC,CAC5G,CAGO,SAASC,GAAeC,EAA0BrB,EAAkC,CACzF,IAAMsB,EAA2B,CAAC,EAClC,QAAWC,KAASF,EAClB,GAAIE,EAAM,OAAS,QAAS,CAC1B,IAAMC,EAAaD,EAAM,OAAO,IAAKE,IAAO,CAAE,MAAOF,EAAM,MAAO,GAAIE,EAAE,GAAI,MAAOA,EAAE,KAAM,EAAE,EAC7FH,EAAO,KAAKE,EAAW,SAAW,EAAIA,EAAW,CAAC,EAAI,CAAE,IAAKA,CAAW,CAAC,CAC3E,SAAWD,EAAM,OAAS,UAAW,CAEnC,IAAMG,EAASH,EAAM,IAAI,IAAKI,GAAQ3B,EAAK,SAAS,KAAM4B,GAAMA,EAAE,KAAOD,CAAE,GAAG,QAAU,CAAC,CAAsB,EAAE,OAAQE,GAAUA,EAAM,MAAM,EAC3IH,EAAO,SAAW,EAAGJ,EAAO,KAAK,GAAGI,EAAO,CAAC,CAAC,EACxCA,EAAO,OAAS,GAAGJ,EAAO,KAAK,CAAE,IAAKI,EAAO,IAAKG,GAAWA,EAAM,SAAW,EAAIA,EAAM,CAAC,EAAI,CAAE,IAAKA,CAAM,CAAE,CAAE,CAAC,CAC1H,MAAWN,EAAM,OAAS,UACxBD,EAAO,KAAK,GAAGC,EAAM,MAAM,EAG/B,OAAOD,CACT,CAGO,SAASQ,GAAcT,EAAoC,CAChE,OAAOA,EAAO,KAAMO,GAAgDA,EAAE,OAAS,SAAS,GAAG,QAAU,CAAC,CACxG,CCrEO,IAAMG,GAA2B,CACtC,WAAY,CAACC,EAAUC,IAAQ,WAAqC,WAAWD,EAAUC,CAAE,EAC3F,aAAeC,GAAY,WAAqC,aAAaA,CAAM,CACrF,EAGO,SAASC,GAAKF,EAAYG,EAAuBL,GAA8B,CACpF,OAAO,IAAI,QAASM,GAAY,CAC9BD,EAAU,WAAWC,EAASJ,CAAE,CAClC,CAAC,CACH,CC2BO,SAASK,GAAuBC,EAAmC,CAAC,EAAqB,CAC9F,IAAMC,EAAUC,GAAeF,EAAQ,SAAW,CAAC,CAAC,EAC9CG,EAA6B,CAAC,EAC9BC,EAAmC,CAAC,EACtCC,EAAU,IAERC,EAAQ,IAAON,EAAQ,QAAUO,GAAKP,EAAQ,QAASA,EAAQ,SAAS,EAAI,QAAQ,QAAQ,EAC5FQ,EAASC,GAAmBR,EAAAQ,KAAAR,EAAAQ,GAAmB,CAAC,GAChDC,EAAU,CAACD,EAAeE,IAAiB,CAC/C,IAAMC,EAAQJ,EAAMC,CAAK,EAAE,OAAOE,CAAE,CAAC,IAAIX,EAAQ,aAAaS,CAAK,GAAK,MAAM,EAC9E,OAAO,OAAOG,GAAU,SAAWA,EAAQ,OAAOD,CAAE,CACtD,EACME,EAAUJ,GAAkB,KAAK,IAAI,EAAG,GAAG,OAAO,KAAKD,EAAMC,CAAK,CAAC,EAAE,IAAI,MAAM,EAAE,OAAO,OAAO,QAAQ,CAAC,EAAI,EAC5GK,EAAQC,GAA2B,OAAO,SAAS,OAAOA,CAAG,CAAC,EAAI,OAAOA,CAAG,EAAIA,EAEtF,SAASC,EAAWC,EAAiBC,EAAuB,CAC1D,IAAIC,EAAQ,CAAC,GAAGF,CAAO,EACvB,QAAWG,KAAMF,EACXE,EAAG,KAAO,SAAUD,EAAM,KAAK,CAAE,IAAKC,EAAG,IAAK,GAAI,EAAEf,EAAS,OAAQH,GAAekB,EAAG,MAAM,CAAE,CAAC,EAC3FA,EAAG,KAAO,SAAUD,EAAQA,EAAM,IAAKE,GAAOA,EAAE,KAAOD,EAAG,GAAK,CAAE,GAAGC,EAAG,OAAQ,CAAE,GAAGA,EAAE,OAAQ,GAAGnB,GAAekB,EAAG,MAAM,CAAE,CAAE,EAAIC,CAAE,EACvIF,EAAQA,EAAM,OAAQE,GAAMA,EAAE,KAAOD,EAAG,EAAE,EAEjD,OAAOD,CACT,CAEA,SAASG,EAAWL,EAA0BC,EAAeT,EAAgC,CAC3F,IAAIc,EAAQ,CAAC,GAAGN,CAAO,EACjBO,EAAWb,IAAiC,CAAE,GAAAA,EAAI,MAAOD,EAAQD,EAAOE,CAAE,CAAE,GAClF,QAAWS,KAAMF,EACXE,EAAG,KAAO,QAAU,CAACG,EAAM,KAAME,GAAMA,EAAE,KAAOL,EAAG,EAAE,EAAGG,EAAM,KAAKC,EAAQJ,EAAG,EAAE,CAAC,EAC5EA,EAAG,KAAO,SAAUG,EAAQA,EAAM,OAAQE,GAAMA,EAAE,KAAOL,EAAG,EAAE,EAC9DA,EAAG,KAAO,MAAOG,EAAQH,EAAG,IAAI,IAAII,CAAO,EAC3CJ,EAAG,KAAO,UAASG,EAAQ,CAAC,GAEvC,OAAOA,CACT,CAEA,SAASG,EAAWC,EAAgBC,EAAsB,CACxD,IAAMC,EAA2BF,EAAOC,CAAI,EAC5C,OAAOC,GAAS,aAAcA,EAAQA,EAAM,SAAWD,CACzD,CAEA,MAAO,CACL,QAAA3B,EACA,UAAAE,EACA,MAAAC,EAEA,MAAM,KAAK0B,EAAuC,CAChD1B,EAAM,KAAK,CAAE,OAAQ,OAAQ,QAAA0B,CAAQ,CAAC,EACtC,MAAMxB,EAAM,EACZ,IAAMyB,EAASvB,EAAMsB,EAAQ,KAAK,EAAE,OAAOA,EAAQ,EAAE,CAAC,EACtD,GAAI,CAACC,EAAQ,MAAM,IAAI,MAAM,MAAMD,EAAQ,KAAK,mBAAmBA,EAAQ,EAAE,EAAE,EAC/E,OAAO5B,GAAe6B,CAAM,CAC9B,EAEA,MAAM,KAAKD,EAA2C,CACpD1B,EAAM,KAAK,CAAE,OAAQ,OAAQ,QAAA0B,CAAQ,CAAC,EACtC,MAAMxB,EAAM,EACZ,IAAMK,EAAKmB,EAAQ,IAAMjB,EAAOiB,EAAQ,KAAK,EACvCC,EAAiB,CAAE,GAAIvB,EAAMsB,EAAQ,KAAK,EAAE,OAAOnB,CAAE,CAAC,GAAK,CAAC,EAAI,GAAGT,GAAe4B,EAAQ,QAAQ,MAAM,CAAE,EAChH,OAAW,CAACF,EAAMV,CAAG,IAAK,OAAO,QAAQY,EAAQ,QAAQ,KAAK,EAC5DC,EAAOH,CAAI,EAAIZ,EAAYe,EAAOH,CAAI,GAA4B,CAAC,EAAGV,CAAG,EAE3E,OAAW,CAACU,EAAMV,CAAG,IAAK,OAAO,QAAQY,EAAQ,QAAQ,KAAK,EAC5DC,EAAOH,CAAI,EAAIN,EAAYS,EAAOH,CAAI,GAAqC,CAAC,EAAGV,EAAKQ,EAAWI,EAAQ,OAAQF,CAAI,CAAC,EAEtH,OAAApB,EAAMsB,EAAQ,KAAK,EAAE,OAAOnB,CAAE,CAAC,EAAIoB,EAC5B,CAAE,GAAApB,EAAI,OAAQT,GAAe6B,CAAM,CAAE,CAC9C,EAEA,MAAM,SAASD,EAAmD,CAChE1B,EAAM,KAAK,CAAE,OAAQ,WAAY,QAAA0B,CAAQ,CAAC,EAC1C,MAAMxB,EAAM,EACZ,IAAM0B,EAAOhC,EAAQ,WAAW8B,EAAQ,KAAK,IAAIA,EAAQ,OAAO,EAC1DG,EAAOjC,EAAQ,WAAW8B,EAAQ,KAAK,IAAIA,EAAQ,OAAO,EAC1DI,EAAyBF,EAAO,CAAE,OAAQA,EAAK9B,GAAe4B,EAAQ,MAAM,CAAC,CAAE,EAAI,CAAC,EACpFK,EAAUF,IAAO/B,GAAe4B,EAAQ,MAAM,CAAC,EACrD,OAAOK,EAAU,CAAE,GAAGD,EAAQ,QAAAC,CAAQ,EAAID,CAC5C,EAEA,MAAM,OAAOJ,EAAkD,CAC7D1B,EAAM,KAAK,CAAE,OAAQ,SAAU,QAAA0B,CAAQ,CAAC,EACxC,MAAMxB,EAAM,EACZ,IAAM8B,EAAQN,EAAQ,MAAM,KAAK,EAAE,YAAY,EAC/C,OAAO,OAAO,QAAQtB,EAAMsB,EAAQ,KAAK,CAAC,EACvC,OAAO,CAAC,CAAC,CAAEO,CAAM,IAAMC,GAAcD,EAAQP,EAAQ,QAAU,CAAC,CAAC,CAAC,EAClE,IAAI,CAAC,CAACf,CAAG,KAAO,CAAE,GAAID,EAAKC,CAAG,EAAG,MAAOL,EAAQoB,EAAQ,MAAOhB,EAAKC,CAAG,CAAC,CAAE,EAAE,EAC5E,OAAQwB,GAAWA,EAAO,MAAM,YAAY,EAAE,SAASH,CAAK,CAAC,EAC7D,MAAM,EAAGN,EAAQ,OAAS,CAAC,CAChC,EAEA,MAAM,KAAKA,EAA2C,CACpD1B,EAAM,KAAK,CAAE,OAAQ,OAAQ,QAAA0B,CAAQ,CAAC,EACtC,MAAMxB,EAAM,EACZ,IAAMkC,EAAW,OAAO,QAAQhC,EAAMsB,EAAQ,KAAK,CAAC,EACjD,OAAO,CAAC,CAAC,CAAEO,CAAM,IAAMC,GAAcD,EAAQP,EAAQ,MAAM,CAAC,EAC5D,IAAI,CAAC,CAACf,EAAKsB,CAAM,KAAO,CAAE,GAAIvB,EAAKC,CAAG,EAAG,OAAAsB,CAAO,EAAE,EACrD,OAAAG,EAAS,KAAK,CAACC,EAAGC,IAAM,CACtB,QAAWC,KAASb,EAAQ,KAAM,CAChC,IAAMc,EAAWC,GAAcJ,EAAE,OAAOE,EAAM,KAAK,EAAGD,EAAE,OAAOC,EAAM,KAAK,CAAC,EAE3E,GAAIC,EAAS,MAAO,OAAOA,EAAS,OACpC,GAAIA,EAAS,OAAQ,OAAOD,EAAM,KAAO,CAACC,EAAS,OAASA,EAAS,MACvE,CACA,MAAO,EACT,CAAC,EACM,CACL,MAAOJ,EAAS,OAChB,QAASA,EAAS,MAAMV,EAAQ,OAAQA,EAAQ,OAASA,EAAQ,KAAK,EAAE,IAAI,CAAC,CAAE,GAAAnB,EAAI,OAAA0B,CAAO,KAAO,CAC/F,GAAA1B,EACA,OAAQ,OAAO,YAAYmB,EAAQ,OAAO,IAAKD,GAAU,CAACA,EAAO3B,GAAemC,EAAOR,CAAK,GAAK,IAAI,CAAU,CAAC,CAAC,CACnH,EAAE,CACJ,CACF,EAEA,MAAM,OAAOC,EAAyC,CACpD1B,EAAM,KAAK,CAAE,OAAQ,SAAU,QAAA0B,CAAQ,CAAC,EACxC,MAAMxB,EAAM,EACZ,IAAMwC,EAAU,IAAI,IACpB,QAAWT,KAAU,OAAO,OAAO7B,EAAMsB,EAAQ,KAAK,CAAC,EAAG,CACxD,GAAI,CAACQ,GAAcD,EAAQP,EAAQ,MAAM,EAAG,SAC5C,IAAMiB,EAAMV,EAAOP,EAAQ,KAAK,GAAK,KAC/BkB,EAAOD,IAAQ,MAAQ,OAAOA,GAAQ,UAAY,CAAC,MAAM,QAAQA,CAAG,GAAK,OAAQA,EAAOA,EAAwB,KAChHnC,EAASoC,EAAOA,EAAK,GAAKD,EAC1BhC,EAAM,KAAK,UAAUH,CAAK,EAC1BqC,EAAQH,EAAQ,IAAI/B,CAAG,GAAK,CAAE,MAAAH,EAAO,MAAOoC,EAAOA,EAAK,MAAQD,IAAQ,MAAQA,IAAQ,GAAK,GAAK,OAAOA,CAAG,EAAG,MAAO,CAAE,EAC9HE,EAAM,QACNH,EAAQ,IAAI/B,EAAKkC,CAAK,CACxB,CACA,MAAO,CAAC,GAAGH,EAAQ,OAAO,CAAC,EAAE,KAAK,CAACL,EAAGC,IAAOD,EAAE,QAAU,OAAWC,EAAE,QAAU,MAAQD,EAAE,MAAM,cAAcC,EAAE,KAAK,EAAID,EAAE,QAAU,KAAO,EAAI,EAAE,CACpJ,EAEA,MAAM,OAAOX,EAAgD,CAC3D1B,EAAM,KAAK,CAAE,OAAQ,SAAU,QAAA0B,CAAQ,CAAC,EACxC,MAAMxB,EAAM,EACZ,IAAM4C,EAAO1C,EAAMsB,EAAQ,KAAK,EAC1BnB,EAAK,OAAO,KAAKuC,CAAI,EAAE,OAAO,CAACC,EAAKpC,IAAQ,KAAK,IAAIoC,EAAK,OAAOpC,CAAG,GAAK,CAAC,EAAG,CAAC,EAAI,EACxF,OAAAmC,EAAK,OAAOvC,CAAE,CAAC,EAAI,CAAE,KAAMmB,EAAQ,IAAK,EACjC,CAAE,GAAAnB,EAAI,MAAOmB,EAAQ,IAAK,CACnC,EAEA,MAAM,OAAOA,EAA+C,CAC1D,OAAA1B,EAAM,KAAK,CAAE,OAAQ,SAAU,QAAA0B,CAAQ,CAAC,EACxC,MAAMxB,EAAM,EACZH,EAAU,KAAKD,GAAe4B,CAAO,CAAC,EAC/B,CAAE,GAAI3B,EAAU,MAAO,CAChC,EAEA,MAAM,QAAQ2B,EAA4C,CACxD1B,EAAM,KAAK,CAAE,OAAQ,UAAW,QAAA0B,CAAQ,CAAC,EACzC,MAAMxB,EAAM,EACZ,IAAM8C,EAAOpD,EAAQ,QAAQ8B,EAAQ,IAAI,EACzC,GAAI,CAACsB,EAAM,MAAM,IAAI,MAAM,YAAYtB,EAAQ,IAAI,GAAG,EACtD,OAAO5B,GAAe,OAAOkD,GAAS,WAAa,MAAMA,EAAKtB,EAAQ,MAAM,EAAIsB,CAAI,CACtF,CACF,CACF,CAGA,SAASP,GAAcJ,EAAYC,EAAgD,CACjF,IAAMW,EAASC,GAAeA,GAAM,MAA2BA,IAAM,GACrE,GAAID,EAAMZ,CAAC,GAAKY,EAAMX,CAAC,EAAG,MAAO,CAAE,OAAQW,EAAMZ,CAAC,IAAMY,EAAMX,CAAC,EAAI,EAAIW,EAAMZ,CAAC,EAAI,EAAI,GAAI,MAAOY,EAAMZ,CAAC,IAAMY,EAAMX,CAAC,CAAE,EACvH,IAAMa,EAASD,GAAgB,OAAOA,GAAM,UAAYA,IAAM,MAAQ,UAAWA,EAAKA,EAAoB,MAAQA,EAC5G,CAACE,EAAGC,CAAC,EAAI,CAACF,EAAMd,CAAC,EAAGc,EAAMb,CAAC,CAAC,EAClC,OAAI,OAAOc,GAAM,UAAY,OAAOC,GAAM,SAAiB,CAAE,OAAQD,EAAIC,EAAG,MAAO,EAAM,EAClF,CAAE,OAAQ,OAAOD,CAAC,EAAE,cAAc,OAAOC,CAAC,CAAC,EAAG,MAAO,EAAM,CACpE,CC5MO,IAAMC,GAAgB,CAAC,SAAU,QAAS,OAAQ,SAAU,WAAY,SAAS,EAEjF,SAASC,GAAeC,EAAcC,EAAiBC,EAA0BC,EAAwC,CAC9H,IAAMC,EAAUH,EAAK,SAAW,CAAC,EAC3BI,EAAQJ,EAAK,OAASD,EAAM,MAClC,GAAIA,EAAM,OAAS,YAAc,MAAM,QAAQE,CAAK,GAAKA,EAAM,OAAQ,CACrE,GAAI,OAAOE,EAAQ,KAAW,UAAYF,EAAM,OAASE,EAAQ,IAAQ,OAAOE,GAAKH,EAAS,SAAU,CAAE,MAAAE,EAAO,IAAKD,EAAQ,GAAO,CAAC,EACtI,GAAI,OAAOA,EAAQ,KAAW,UAAYF,EAAM,OAASE,EAAQ,IAAQ,OAAOE,GAAKH,EAAS,SAAU,CAAE,MAAAE,EAAO,IAAKD,EAAQ,GAAO,CAAC,CACxI,CACA,IAAMG,EAASH,EAAQ,cACvB,GAAIH,EAAK,SAAW,WAAa,CAAC,MAAM,QAAQM,CAAM,GAAK,CAACL,GAAS,OAAOA,GAAU,UAAY,MAAM,QAAQA,CAAK,EAAG,OACxH,IAAMM,EAAQ,MAAM,QAAQJ,EAAQ,KAAQ,EAAIA,EAAQ,MAAWN,GAC7DW,EAAQP,EACRQ,EAAUZ,GAAc,UAAWa,GAASJ,EAAO,SAASI,CAAI,GAAKH,EAAM,SAASG,CAAI,GAAK,CAAC,OAAOF,EAAME,CAAI,GAAK,EAAE,EAAE,KAAK,CAAC,EACpI,OAAOD,EAAU,EAAI,OAAYJ,GAAKH,EAAS,SAAU,CAAE,MAAOA,EAAS,aAAa,MAAM,GAAG,EAAEO,CAAO,CAAE,CAAC,CAC/G,CCdA,IAAME,GAAkC,CACtC,MAAO,6BACP,IAAK,mEACL,MAAO,wBACP,KAAM,2BACR,EAEO,SAASC,GAAWC,EAAcC,EAAiBC,EAA0BC,EAAwC,CAC1H,IAAMC,EAASH,EAAK,QAAU,GAC9B,GAAID,EAAM,OAAS,OAAQ,OAAOK,GAAeL,EAAOC,EAAMC,EAAOC,CAAQ,EAC7E,GAAI,OAAOD,GAAU,UAAY,CAACA,EAAM,KAAK,EAAG,OAChD,IAAMI,EAAOJ,EAAM,KAAK,EAClBK,EAAUN,EAAK,SAAW,CAAC,EAC3BO,EAAQP,EAAK,OAASD,EAAM,MAC5BS,EAASX,GAAQM,CAAM,EACvBM,EAASJ,EAAK,MAAM,UAAU,GAAG,QAAU,EACjD,GAAIG,IAAW,CAACA,EAAO,KAAKH,CAAI,GAAMF,IAAW,UAAYM,EAAS,GAAKA,EAAS,KAAO,OAAOP,EAASC,CAAiB,EAC5H,GAAIA,IAAW,OAAQ,CACrB,GAAI,OAAOG,EAAQ,KAAW,UAAYD,EAAOC,EAAQ,IAAQ,OAAOI,GAAKR,EAAS,OAAQ,CAAE,MAAAK,EAAO,IAAKD,EAAQ,GAAO,CAAC,EAC5H,GAAI,OAAOA,EAAQ,KAAW,UAAYD,EAAOC,EAAQ,IAAQ,OAAOI,GAAKR,EAAS,MAAO,CAAE,MAAAK,EAAO,IAAKD,EAAQ,GAAO,CAAC,CAC7H,CACA,GAAIH,IAAW,QAAU,OAAOG,EAAQ,KAAW,UACnCD,EAAK,MAAM,OAAOC,EAAQ,WAAiB,UAAYA,EAAQ,UAAeA,EAAQ,UAAe,GAAG,EAAE,OAAQK,GAAMA,EAAE,KAAK,CAAC,EAAE,OACpIL,EAAQ,IAAQ,OAAOI,GAAKR,EAAS,OAAQ,CAAE,MAAAK,EAAO,IAAKD,EAAQ,GAAO,CAAC,CAG3F,CChCO,SAASM,GAAcC,EAAgBC,EAA2CC,EAAoC,CAC3H,IAAMC,EAAO,IAAI,IACjB,MAAO,CACL,MAAAD,EACA,MAAME,EAAM,CACV,IAAMC,EAAMJ,EAAOG,CAAI,EACvB,GAAIC,GAAK,OAAS,WAAY,OAC9B,IAAIC,EAAQH,EAAK,IAAIC,CAAI,EACzB,OAAKE,IAEHA,GADgBN,EAAOI,CAAI,GAAuB,CAAC,GAAG,OAAQG,GAASC,GAASH,EAAKE,EAAK,MAAM,IAAM,IAAI,EAC5F,IAAKA,GAASE,GAAkBF,EAAK,OAAQF,EAAI,MAAM,CAAC,EACtEF,EAAK,IAAIC,EAAME,CAAK,GAEfA,CACT,CACF,CACF,CCAA,SAASI,GAAMC,EAAmD,CAChE,IAAMC,EAAW,IAAI,IACrB,OAAW,CAACC,EAAMC,CAAG,IAAK,OAAO,QAAQH,CAAM,EAAOG,EAAI,UAAY,QAAWF,EAAS,IAAIC,EAAME,GAAkBD,EAAI,OAAO,CAAC,EAClI,GAAM,CAAE,MAAAE,CAAM,EAAIC,GAAgB,IAAI,IAAI,CAAC,GAAGL,CAAQ,EAAE,IAAI,CAAC,CAACC,EAAMK,CAAU,IAAM,CAACL,EAAMK,EAAW,MAAM,CAAC,CAAC,CAAC,EAC/G,OAAOF,EAAM,IAAKH,GAAS,CAACA,EAAMD,EAAS,IAAIC,CAAI,EAAyBF,EAAOE,CAAI,CAAC,CAAC,CAC3F,CAOO,SAASM,GAAML,EAAwBM,EAAuB,CACnE,GAAIN,EAAI,OAAS,UAAW,OAAOO,GAAOD,CAAK,EAC/C,GAAIA,GAAU,KAA6B,OAAO,KAClD,OAAQN,EAAI,KAAM,CAChB,IAAK,UACH,OAAOQ,GAASF,CAAK,EAAIG,GAAQH,EAAO,CAAC,EAAI,KAC/C,IAAK,QACL,IAAK,WACH,OAAKE,GAASF,CAAK,EACZN,EAAI,OAASS,GAAQH,EAAON,EAAI,OAAO,CAAC,CAAC,EAAIM,EADvB,KAE/B,IAAK,OACL,IAAK,OACL,IAAK,OACH,OAAO,OAAOA,GAAU,SAAWA,EAAQE,GAASF,CAAK,EAAI,OAAOA,CAAK,EAAI,KAC/E,IAAK,OACL,IAAK,WACH,OAAO,OAAOA,GAAU,SAAWA,EAAQ,KAC7C,QACE,OAAOA,CACX,CACF,CAGO,SAASI,GAAgBC,EAAYC,EAA+B,CACzE,IAAMC,EAAMjB,GAAMe,EAAK,MAAM,EACvBG,EAAY,IAAI,IACtB,OAAW,CAACf,EAAMC,CAAG,IAAK,OAAO,QAAQW,EAAK,MAAM,EAAG,CACrD,GAAIX,EAAI,OAAS,WAAY,SAC7B,IAAMe,EAAQnB,GAAMI,EAAI,MAAM,EAC1Be,EAAM,QAAQD,EAAU,IAAIf,EAAM,CAAE,IAAAC,EAAK,MAAOe,CAAM,CAAC,CAC7D,CAEA,IAAMC,EAAyB,CAAE,MAAAJ,CAAM,EAGvC,SAASK,EAAIC,EAAgBC,EAActB,EAA2CuB,EAA4B,CAChH,IAAIC,EAAOH,EACLI,EAAUC,GAAkBL,EAAQrB,CAAM,EAChD,OAAW,CAACE,EAAMK,EAAYJ,CAAG,IAAKmB,EAAM,CAC1C,IAAMb,EAAQD,GAAML,EAAKI,EAAW,SAASkB,EAASF,CAAG,CAAC,EACtDI,GAAUlB,EAAOe,EAAKtB,CAAI,CAAC,IAC/BsB,EAAO,CAAE,GAAGA,EAAM,CAACtB,CAAI,EAAGO,CAAM,EAEhC,OAAO,OAAOgB,EAASC,GAAkB,CAAE,CAACxB,CAAI,EAAGO,CAAM,EAAGT,CAAM,CAAC,EACrE,CACA,OAAOwB,CACT,CAEA,SAASI,EAAKC,EAAeR,EAAwB,CACnD,IAAMH,EAAQD,EAAU,IAAIY,CAAK,EAEjC,MAAI,CAACX,GAASY,GAASZ,EAAM,IAAKG,CAAM,IAAM,KAAaA,EACpDD,EAAIC,EAAQH,EAAM,MAAOA,EAAM,IAAI,OAAQC,CAAO,CAC3D,CAEA,MAAO,CACL,KAAAS,EACA,MAAMP,EAAQ,CACZ,IAAIG,EAAOH,EACX,QAAWQ,KAASZ,EAAU,KAAK,EAAG,CACpC,IAAMc,EAAUP,EAAKK,CAAK,EAC1B,GAAI,CAAC,MAAM,QAAQE,CAAO,EAAG,SAC7B,IAAIC,EAAU,GACRC,EAAWF,EAAmB,IAAKG,GAAM,CAC7C,IAAMC,EAASP,EAAKC,EAAOK,EAAE,MAAM,EACnC,OAAIC,IAAWD,EAAE,OAAeA,GAChCF,EAAU,GACH,CAAE,GAAGE,EAAG,OAAQC,CAAO,EAChC,CAAC,EACGH,IAASR,EAAO,CAAE,GAAGA,EAAM,CAACK,CAAK,EAAGI,CAAQ,EAClD,CACA,OAAKjB,EAAI,OACFI,EAAII,EAAMR,EAAKF,EAAK,OAAQsB,GAAcZ,EAAMV,EAAK,OAAQC,CAAK,CAAC,EADlDS,CAE1B,CACF,CACF,CC9EA,SAASa,GAAMC,EAAmD,CAChE,OAAO,OAAO,QAAQA,CAAM,EAAE,QAAQ,CAAC,CAACC,EAAMC,CAAG,KAC9CA,EAAI,SAAW,CAAC,GAAG,IAAI,CAACC,EAAe,KAAa,CAAE,IAAK,GAAGF,CAAI,IAAI,CAAC,GAAI,KAAAA,EAAM,IAAAC,EAAK,KAAME,GAAgBD,EAAK,IAAI,EAAG,MAAOE,GAAkBF,EAAK,KAAK,CAAE,EAAE,CAClK,CACF,CAGA,IAAMG,GAAkC,CAAE,IAAK,IAAM,EAAK,EAGnD,SAASC,GAAeC,EAAYC,EAAmC,CAC5E,IAAMC,EAAMX,GAAMS,EAAK,MAAM,EACvBG,EAAY,IAAI,IACtB,OAAW,CAACV,EAAMC,CAAG,IAAK,OAAO,QAAQM,EAAK,MAAM,EAAG,CACrD,GAAIN,EAAI,OAAS,WAAY,SAC7B,IAAMU,EAAQb,GAAMG,EAAI,MAAM,EAC1BU,EAAM,QAAQD,EAAU,IAAIV,EAAM,CAAE,IAAAC,EAAK,MAAOU,CAAM,CAAC,CAC7D,CACA,IAAMC,EAAyB,CAAE,MAAAJ,CAAM,EAGvC,SAASK,EAAIC,EAAgBC,EAAchB,EAA2CiB,EAAoBC,EAAgBC,EAA6BC,EAA0B,CAC/K,IAAIC,EAAON,EACLO,EAAUC,GAAkBR,EAAQf,CAAM,EAChD,QAAWG,KAAQa,EAAM,CACvB,GAAI,CAACb,EAAK,KAAK,SAASmB,EAASL,CAAG,EAAG,SACvC,IAAMO,EAAMN,EAASf,EAAK,IAE1B,GADAiB,EAAI,IAAII,CAAG,EACPL,EAAO,IAAIK,CAAG,EAAG,SACrB,IAAMC,EAAQC,GAAMvB,EAAK,IAAKA,EAAK,MAAM,SAASmB,EAASL,CAAG,CAAC,EAC1DU,GAAUF,EAAOJ,EAAKlB,EAAK,IAAI,CAAC,IAAGkB,EAAO,CAAE,GAAGA,EAAM,CAAClB,EAAK,IAAI,EAAGsB,CAAM,EAC/E,CACA,OAAOJ,CACT,CAEA,SAASO,EAAMb,EAAgBI,EAA6B,CAC1D,IAAMC,EAAM,IAAI,IACZC,EAAOX,EAAI,OAASI,EAAIC,EAAQL,EAAKF,EAAK,OAAQqB,GAAcd,EAAQP,EAAK,OAAQC,CAAK,EAAG,GAAIU,EAAQC,CAAG,EAAIL,EACpH,OAAW,CAACe,EAAO,CAAE,IAAA5B,EAAK,MAAOc,CAAK,CAAC,IAAKL,EAAW,CACrD,IAAMoB,EAAUhB,EAAOe,CAAK,EAC5B,GAAI,CAAC,MAAM,QAAQC,CAAO,EAAG,SAC7B,IAAIC,EAAU,GACRC,EAAWF,EAAmB,IAAKG,GAAS,CAEhD,GAAIC,GAASjC,EAAKgC,EAAK,MAAM,IAAM,KAAM,OAAOA,EAChD,IAAME,EAAMtB,EAAIoB,EAAK,OAAQlB,EAAMd,EAAI,OAAQW,EAAS,GAAGiB,CAAK,IAAII,EAAK,GAAG,IAAKf,EAAQC,CAAG,EAC5F,OAAIgB,IAAQF,EAAK,OAAeA,GAChCF,EAAU,GACH,CAAE,GAAGE,EAAM,OAAQE,CAAI,EAChC,CAAC,EACGJ,IAASX,EAAO,CAAE,GAAGA,EAAM,CAACS,CAAK,EAAGG,CAAQ,EAClD,CACA,MAAO,CAAE,OAAQZ,EAAM,QAASD,CAAI,CACtC,CAEA,MAAO,CAAE,MAAAQ,EAAO,QAAUb,GAAWa,EAAMb,EAAQT,EAAU,EAAE,OAAQ,CACzE,CCjEO,SAAS+B,GAAaC,EAA0D,CACrF,OAAQA,GAAS,CAAC,GAAG,IAAKC,IAAU,CAClC,KAAAA,EACA,KAAMC,GAAgBD,EAAK,MAAQ,EAAI,EAEvC,QAASA,EAAK,UAAY,OAAY,KAAO,IAAI,OAAO,OAAOA,EAAK,OAAO,IAAI,EAC/E,MAAOA,EAAK,QAAU,OAAY,KAAOC,GAAgBD,EAAK,KAAK,CACrE,EAAE,CACJ,CAWO,SAASE,GACdC,EACAC,EACAC,EACAN,EACAO,EACsC,CACtC,IAAMC,EAA8C,CAAC,EACrD,GAAI,CAACR,EAAM,QAAUS,GAAQL,EAAOE,CAAK,EAAG,OAAOE,EACnD,QAAWE,KAAYV,EAAO,CAC5B,IAAMW,EAAQD,EAAS,KAAK,OAAS,QACrC,GAAIF,EAAMG,CAAK,IAAM,QAAa,CAACD,EAAS,KAAK,SAASH,EAAG,QAASA,EAAG,GAAG,EAAG,SAC/E,IAAMK,EAASC,GAAUH,EAAUN,EAAOE,EAAgBC,EAAG,GAAG,GAAKO,GAAaJ,EAAUH,CAAE,EAC1FK,IAAQJ,EAAMG,CAAK,EAAID,EAAS,KAAK,SAAWK,GAAKR,EAAG,SAASK,EAAO,GAAG,EAAG,CAAE,MAAAP,EAAO,GAAGO,EAAO,MAAO,CAAC,EAC/G,CACA,OAAOJ,CACT,CAKA,SAASK,GAAU,CAAE,KAAAZ,EAAM,QAAAe,CAAQ,EAAiBZ,EAAcE,EAAcW,EAA+B,CAC7G,IAAMC,EAAO,OAAOZ,GAAU,SAAWA,EAAQ,KACjD,GAAIY,IAAS,MAAQjB,EAAK,YAAc,QAAaiB,EAAK,OAASjB,EAAK,UAAW,MAAO,CAAE,IAAK,YAAa,OAAQ,CAAE,IAAKA,EAAK,SAAU,CAAE,EAC9I,GAAIiB,IAAS,MAAQjB,EAAK,YAAc,QAAaiB,EAAK,OAASjB,EAAK,UAAW,MAAO,CAAE,IAAK,YAAa,OAAQ,CAAE,IAAKA,EAAK,SAAU,CAAE,EAC9I,GAAIe,IAAYE,IAAS,MAAQC,GAASb,CAAK,IAAM,CAACU,EAAQ,KAAK,OAAOV,CAAK,CAAC,EAAG,MAAO,CAAE,IAAK,SAAU,EAC3G,GAAIY,IAAS,MAAQjB,EAAK,WAAa,QAAa,CAACiB,EAAK,KAAK,EAAE,YAAY,EAAE,SAASjB,EAAK,SAAS,YAAY,CAAC,EACjH,MAAO,CAAE,IAAK,WAAY,OAAQ,CAAE,OAAQA,EAAK,QAAS,CAAE,EAE9D,GAAIkB,GAASb,CAAK,GAAKL,EAAK,MAAQ,QAAaK,EAAQL,EAAK,IAAK,MAAO,CAAE,IAAK,MAAO,OAAQ,CAAE,IAAKA,EAAK,GAAI,CAAE,EAClH,GAAIkB,GAASb,CAAK,GAAKL,EAAK,MAAQ,QAAaK,EAAQL,EAAK,IAAK,MAAO,CAAE,IAAK,MAAO,OAAQ,CAAE,IAAKA,EAAK,GAAI,CAAE,EAClH,IAAMmB,EAAQ,MAAM,QAAQd,CAAK,EAAIA,EAAM,OAAS,KACpD,GAAIc,IAAU,MAAQnB,EAAK,UAAY,QAAamB,EAAQnB,EAAK,QAAS,MAAO,CAAE,IAAK,UAAW,OAAQ,CAAE,IAAKA,EAAK,OAAQ,CAAE,EACjI,GAAImB,IAAU,MAAQnB,EAAK,SAAW,QAAamB,EAAQnB,EAAK,OAAQ,MAAO,CAAE,IAAK,SAAU,OAAQ,CAAE,IAAKA,EAAK,MAAO,CAAE,EAC7H,GAAIiB,IAAS,MAAQjB,EAAK,OAAS,OAAW,CAC5C,IAAMoB,EAAOC,GAAOlB,EAAOc,EAAMD,CAAG,EACpC,GAAIhB,EAAK,OAAS,QAAUoB,GAAQ,EAAG,MAAO,CAAE,IAAK,UAAW,EAChE,GAAIpB,EAAK,OAAS,UAAYoB,GAAQ,EAAG,MAAO,CAAE,IAAK,YAAa,CACtE,CAEF,CAGA,IAAME,GAASjB,GAAmBA,GAAU,MAAgC,OAAOA,GAAU,UAAY,CAACA,EAAM,KAAK,GAAO,MAAM,QAAQA,CAAK,GAAK,CAACA,EAAM,OAG3J,SAASQ,GAAa,CAAE,MAAAU,CAAM,EAAiBjB,EAAqC,CAClF,GAAI,GAACiB,GAASA,EAAM,OAAO,KAAMC,GAASF,GAAMhB,EAAG,QAAQkB,CAAI,CAAC,CAAC,GACjE,OAAOD,EAAM,SAASjB,EAAG,QAASA,EAAG,GAAG,EAAI,OAAY,CAAE,IAAK,OAAQ,CACzE,CAOA,SAASe,GAAOlB,EAAcc,EAAcD,EAAmB,CAC7D,GAAIb,EAAM,OAAS,WAAY,OAAO,KAAK,KAAK,KAAK,MAAMc,CAAI,EAAID,EAAI,QAAQ,CAAC,EAChF,IAAMS,EAAQC,GAASV,CAAG,EAC1B,OAAOC,EAAOQ,EAAQ,GAAKR,EAAOQ,EAAQ,EAAI,CAChD,CCyFO,SAASE,GAAWC,EAA4B,CACrD,GAAM,CAAE,KAAAC,CAAK,EAAID,EACXE,EAAYF,EAAQ,WAAaG,GACjCC,EAAWJ,EAAQ,UAAYK,GAAS,GACxCC,EAAQC,GAAYN,EAAK,MAAM,EAE/BO,EAAY,IAAI,IACtB,QAAWC,KAAQH,EAAM,OAAO,EAAG,CACjC,IAAMI,EAASD,EAAK,OAAgD,SAChEA,EAAK,OAAS,SAAWC,GAAOF,EAAU,IAAIC,EAAK,GAAIE,GAAaD,CAAK,CAAC,CAChF,CAEA,IAAME,EAAQ,CAAC,GAAGJ,EAAU,OAAO,CAAC,EAAE,KAAME,GAAUA,EAAM,KAAMG,GAAaA,EAAS,KAAK,QAAU,SAAS,CAAC,EAC3GC,EAAQb,EAAK,OAAO,OAAS,SAAWA,EAAK,OAAO,SAAS,IAAKc,GAASA,EAAK,EAAE,EAAI,CAAC,EACvFC,EAAW,IAAM,iBAAiBf,EAAK,EAAE,IAAIgB,EAAM,UAAY,KAAK,GACpEC,EAAQ,IAAMC,GAASnB,EAAQ,MAAM,GAAK,IAAI,IAAM,EACpDoB,EAAWC,GAAgBpB,EAAMiB,CAAK,EACtCI,EAAUC,GAAetB,EAAMiB,CAAK,EAEtCM,EAAmBJ,EAAS,MAAM,CAAE,GAAGK,GAAcxB,EAAK,OAAQiB,EAAM,CAAC,EAAG,GAAGQ,GAAe1B,EAAQ,QAAU,CAAC,CAAC,CAAE,CAAC,EAErH2B,EAAUL,EAAQ,QAAQE,CAAQ,EAClCP,EAAmB,CACrB,OAAQjB,EAAQ,UAAY,KAAO,OAAS,QAC5C,SAAUA,EAAQ,UAAY,KAC9B,OAAQ0B,GAAeF,CAAQ,EAC/B,OAAQ,CAAC,EACT,MAAO,CAAC,EACR,SAAU,CAAC,EACX,QAAS,KACT,aAAc,KACd,MAAO,KACP,MAAO,KACP,KAAMV,EAAM,CAAC,GAAK,KAClB,QAAS,CAAC,EACV,YAAa,KACb,QAAS,CAAC,CACZ,EAEIc,EAAmE,CAAC,EACpEC,EAAW,EACXC,EAAc,EACdC,EAAsB,KACtBC,EAAyB,KACvBC,EAAU,IAAI,IACdC,EAAY,IAAI,IAClBC,EAAgG,KAG9FC,EAAsC,CAAC,EAE7C,SAASC,EAAIC,EAA2B,CACtC,IAAMC,EAAMtB,EAAM,OAClBA,EAAQ,CAAE,GAAGA,EAAO,GAAGqB,CAAM,EAC7B,QAAWE,IAAY,CAAC,GAAGN,CAAS,EAAGM,EAASvB,CAAK,EAErD,GAAIA,EAAM,SAAWsB,EACnB,QAAWE,KAAQxB,EAAM,QAAayB,EAASD,CAAI,EAAE,WAAW,KAAME,GAAUJ,EAAII,CAAK,IAAM1B,EAAM,OAAO0B,CAAK,CAAC,GAAGC,EAAYH,CAAI,CAEzI,CAEA,IAAMC,EAAYD,GAAkBxC,EAAK,OAAOwC,CAAI,EAA4C,YAEhG,SAASG,EAAYH,EAAc,CACjC,GAAM,CAAE,KAAAI,CAAK,EAAIH,EAASD,CAAI,EACxBK,EAAQV,EAAYK,CAAI,GAAKL,EAAYK,CAAI,GAAK,GAAK,EACvDM,EAAOC,IAAqBF,IAASV,EAAYK,CAAI,GAAKJ,EAAI,CAAE,QAAS,CAAE,GAAGpB,EAAM,QAAS,CAACwB,CAAI,EAAGO,EAAQ,CAAE,CAAC,EAEhHC,EAAQhC,EAAM,QAAQwB,CAAI,GAAG,SAAW,KAC9CM,EAAI,CAAE,QAASE,EAAO,QAAS,EAAK,CAAC,EACrC,IAAMC,GAASlD,EAAQ,WAClBmD,GACFD,IAAQ,QAAUA,GAAO,QAAQ,CAAE,KAAAL,EAAM,OAAQnB,GAAeT,EAAM,MAAgB,CAAE,CAAC,EAAI,QAAQ,OAAO,IAAI,MAAM,YAAY4B,CAAI,GAAG,CAAC,GAAG,KAC3IO,IAAWL,EAAI,CAAE,QAASK,EAAO,CAAC,EAClCC,IAAUN,EAAI,CAAE,QAASE,EAAO,MAAQI,GAAgB,SAAW,OAAOA,EAAK,CAAE,CAAC,CACrF,CACF,CACF,CAGA,SAASC,EAAQb,EAAqB,CACpC,IAAMc,EAAMtD,EAAK,OAAOwC,CAAI,EACtBW,EAASnC,EAAM,QAAQwB,CAAI,GAAG,QACpC,OAAOc,EAAI,OAAS,aAAeA,EAAI,aAAeH,EAAS,CAAE,GAAGG,EAAK,QAASH,EAAQ,YAAa,MAAU,EAAIG,CACvH,CAEA,SAASJ,EAASK,EAAiC,CACjDvB,EAAQ,IAAIuB,CAAO,EACnB,IAAMC,EAAO,IAAMxB,EAAQ,OAAOuB,CAAO,EACzC,OAAAA,EAAQ,KAAKC,EAAMA,CAAI,EAChBD,CACT,CAGA,SAASE,GAAoE,CAC3E,GAAIvB,GAAc,SAAWlB,EAAM,OAAQ,CACzC,IAAM0C,EAAS1C,EAAM,OACrBkB,EAAe,CAAE,OAAAwB,EAAQ,QAASC,GAAkBD,EAAQ1D,EAAK,MAAM,EAAG,IAAK4D,GAAcF,EAAQ1D,EAAK,OAAQiB,CAAK,CAAE,CAC3H,CACA,OAAOiB,CACT,CAEA,IAAM2B,EAAU,IAAMJ,EAAQ,EAAE,QAEhC,SAASK,EAAStB,EAAqB,CACrC,IAAMc,EAAMtD,EAAK,OAAOwC,CAAI,EAC5B,GAAI,CAACc,EAAK,MAAM,IAAI,MAAM,0BAA0Bd,CAAI,GAAG,EAC3D,OAAOc,CACT,CAEA,SAASS,EAAYL,EAA0B,CAC7C,OAAO,OAAO,KAAK1D,EAAK,MAAM,EAAE,OAAQwC,GAAS,KAAK,UAAUkB,EAAOlB,CAAI,GAAK,IAAI,IAAM,KAAK,UAAUjB,EAASiB,CAAI,GAAK,IAAI,CAAC,CAClI,CAEA,SAASwB,EAAUC,EAAuB,CACxC,IAAMzD,EAAOH,EAAM,IAAI4D,CAAE,EACzB,GAAI,CAACzD,EAAM,MAAM,IAAI,MAAM,4BAA4ByD,CAAE,GAAG,EAC5D,GAAM,CAAE,QAASC,EAAK,IAAAC,CAAI,EAAIV,EAAQ,EAClCW,EAAY5D,EAAK,UAAU,SAAS0D,EAAKC,CAAG,EAChD,QAASE,GAAS7D,EAAK,OAAQ,CAAC4D,GAAaC,GAAQA,GAAShE,EAAM,IAAIgE,EAAM,GAAG,QAAU,KACzFD,EAAY/D,EAAM,IAAIgE,EAAM,GAAG,UAAU,SAASH,EAAKC,CAAG,GAAK,GAGjE,IAAIG,GAAW9D,EAAK,SAAS,SAAS0D,EAAKC,CAAG,EAC9C,QAASE,GAAS7D,EAAK,OAAQ,CAAC8D,IAAYD,GAAQA,GAAShE,EAAM,IAAIgE,EAAM,GAAG,QAAU,KACxFC,GAAWjE,EAAM,IAAIgE,EAAM,GAAG,SAAS,SAASH,EAAKC,CAAG,GAAK,GAE/D,IAAMb,GAAM9C,EAAK,MAAQR,EAAK,OAAOQ,EAAK,KAAK,EAAI,OACnD,MAAO,CACL,UAAA4D,EACA,SAAUE,IAAahB,KAAQ,QAAaiB,GAAYjB,EAAG,EAC3D,SAAU9C,EAAK,SAAS,SAAS0D,EAAKC,CAAG,GAAKb,IAAK,WAAa,EAClE,CACF,CAGA,SAASkB,EAAkBC,EAA8B,CACvD,IAAMC,EAAUlE,GAAsB,CACpC,GAAI,CAACiE,EAAM,MAAO,GAClB,QAASE,EAAoBnE,EAAK,GAAImE,EAAIA,EAAKtE,EAAM,IAAIsE,CAAE,GAAG,QAAU,KAAM,GAAIA,IAAOF,EAAM,MAAO,GACtG,MAAO,EACT,EAEMG,EAAWpE,GAAsB,CACrC,GAAIiE,GAAQ,CAACzD,EAAM,QAAQ,OAAQ,MAAO,GAC1C,QAAS2D,EAAoBnE,EAAK,GAAImE,EAAIA,EAAKtE,EAAM,IAAIsE,CAAE,GAAG,QAAU,KAAM,GAAI3D,EAAM,QAAQ,SAAS2D,CAAE,EAAG,MAAO,GACrH,MAAO,EACT,EACA,MAAO,CAAC,GAAGtE,EAAM,OAAO,CAAC,EAAE,OAAQG,GAASA,EAAK,OAAS,SAAWkE,EAAOlE,CAAI,GAAK,CAACoE,EAAQpE,CAAI,GAAK,CAACwD,EAAUxD,EAAK,EAAE,EAAE,SAAS,CACtI,CAGA,SAASqE,EAAUrE,EAAyD,CAC1E,IAAMC,EAAQF,EAAU,IAAIC,EAAK,EAAE,EACnC,GAAI,CAACC,EAAO,MAAO,CAAC,EACpB,IAAM+B,EAAOhC,EAAK,MACZ8C,EAAMtD,EAAK,OAAOwC,CAAI,EACtBsC,EAAStE,EAAK,OAAqB,OAAS8C,EAAI,MAChD,CAAE,QAASY,GAAK,IAAAC,EAAI,EAAIV,EAAQ,EACtC,OAAOsB,GAAWzB,EAAKwB,EAAO9D,EAAM,OAAOwB,CAAI,EAAG/B,EAAO,CAAE,QAASyD,GAAK,IAAAC,GAAK,IAAKpE,EAAQ,MAAM,GAAK,IAAI,KAAQ,SAAAI,CAAS,CAAC,CAC9H,CAGA,SAAS6E,EAASxE,EAAuC,CACvD,IAAMgC,EAAOhC,EAAK,MAElB,OADeA,EAAK,OAAqB,SAAW,QAAUR,EAAK,OAAOwC,CAAI,EAAE,OAAS,WACzExB,EAAM,OAAOwB,CAAI,IAAM,IAAQwB,EAAUxD,EAAK,EAAE,EAAE,SAAWL,EAAS,KAAO,MAC/F,CAGA,SAAS8E,EAAUzE,EAAuC,CACxD,IAAMgC,EAAOhC,EAAK,MAClB,OAAOwE,EAASxE,CAAI,GAAK0E,GAAWlF,EAAK,OAAOwC,CAAI,EAAGhC,EAAK,OAAqBQ,EAAM,OAAOwB,CAAI,EAAGrC,CAAQ,GAAKgF,GAAW9B,EAAQb,CAAI,EAAGxB,EAAM,OAAOwB,CAAI,EAAGwB,EAAUxD,EAAK,EAAE,EAAE,SAAUL,EAAUc,EAAM,CAAC,GAAK4D,EAAUrE,CAAI,EAAE,KACrO,CAGA,SAAS4E,GAA0C,CAjXrD,IAAAC,EAkXI,IAAMC,EAAmC,CAAC,EAC1C,GAAI,CAAC3E,EAAO,OAAO2E,EACnB,QAAW9E,KAAQgE,EAAkB,EAAG,CACtC,IAAMe,EAAUhF,EAAU,IAAIC,EAAK,EAAE,EAAIqE,EAAUrE,CAAI,EAAE,QAAU,OAC/D+E,IAASD,EAAAD,EAAS7E,EAAK,SAAd8E,EAAAD,GAAmCE,GAClD,CACA,OAAOD,CACT,CAGA,SAASE,EAAc9B,EAAgB+B,EAAkB,CACvD,IAAMC,EAAW1E,EACjBA,EAAQ,CAAE,GAAGA,EAAO,OAAA0C,CAAO,EAC3B,GAAI,CACF,OAAO+B,EAAK,CACd,QAAE,CACAzE,EAAQ0E,CACV,CACF,CAGA,SAASC,EAAclB,EAAuC,CAC5D,IAAMmB,EAAiC,CAAC,EACxC,QAAWpF,KAAQgE,EAAkBC,CAAI,EAAG,CAC1C,IAAMjC,EAAOhC,EAAK,MAClB,GAAIoF,EAAOpD,CAAI,EAAG,SAClB,IAAMc,EAAMtD,EAAK,OAAOwC,CAAI,EACtBqD,GAAUZ,EAAUzE,CAAI,EAE9B,GADIqF,KAASD,EAAOpD,CAAI,EAAIqD,IACxBvC,EAAI,OAAS,WACf,QAAWwC,MAAS9E,EAAM,OAAOwB,CAAI,GAAuB,CAAC,EAAG,CAE9D,IAAMuD,GAAOC,GAAS1C,EAAKwC,GAAK,MAAM,EACtC,OAAW,CAACG,GAAKC,EAAM,IAAK,OAAO,QAAQ5C,EAAI,MAAM,EAAG,CACtD,GAAIyC,IAAQE,KAAQ3C,EAAI,WAAW,KAAM,SACzC,IAAM6C,GAAchB,GAAWe,GAAQJ,GAAK,OAAOG,EAAG,EAAGC,GAAO,WAAa,GAAM/F,EAAUc,EAAM,CAAC,EAChGkF,KAAaP,EAAO,GAAGpD,CAAI,IAAIsD,GAAK,GAAG,IAAIG,EAAG,EAAE,EAAIE,GAC1D,CACF,CAEJ,CACA,OAAOP,CACT,CAOA,SAASQ,EAAOC,EAAyB,CACvC,IAAI3C,EAASvC,EAAS,MAAMkF,CAAO,EACnC,QAASC,EAAQ,EAAGA,EAAQ,EAAGA,IAAS,CACtC,IAAMC,EAASlF,EAAQ,MAAMqC,EAAQhC,CAAO,EAE5C,GADAA,EAAU6E,EAAO,QACbA,EAAO,SAAW7C,EAAQ,MAC9BA,EAASvC,EAAS,MAAMoF,EAAO,MAAM,CACvC,CACA,OAAO7C,CACT,CAGA,SAAS8C,EAAU9C,EAAwB,CACzC,IAAM+C,EAAStF,EAAS,MAAMuC,CAAM,EACpC,OAAAhC,EAAUL,EAAQ,QAAQoF,CAAM,EACzBA,CACT,CAGA,SAASC,EAAYL,EAAiBM,EAA4B,CAAC,EAAGC,EAAQ,GAAO,CACnF,IAAMlD,EAASkD,EAAQJ,EAAUH,CAAO,EAAID,EAAOC,CAAO,EACpDT,EAAS,OAAO,KAAK5E,EAAM,MAAM,EAAE,OAAS6F,GAAgBnD,CAAM,EAAI1C,EAAM,OAClFoB,EAAI,CAAE,OAAAsB,EAAQ,MAAOK,EAAYL,CAAM,EAAG,OAAAkC,EAAQ,SAAUJ,EAAW9B,EAAQ0B,CAAe,EAAG,GAAGuB,CAAM,CAAC,CAC7G,CAGA,SAASE,GAAgBnD,EAAwC,CAC/D,IAAMkD,EAAQpB,EAAW9B,EAAQ,IAAMiC,EAAc3E,EAAM,MAAQ,MAAS,CAAC,EACvE8F,EAA+B,CAAC,EACtC,QAAWC,KAAO,OAAO,KAAK/F,EAAM,MAAM,EAAO4F,EAAMG,CAAG,IAAGD,EAAKC,CAAG,EAAIH,EAAMG,CAAG,GAClF,OAAW,CAACvE,EAAMwE,CAAO,IAAK,OAAO,QAAQrF,CAAY,EACnD,KAAK,UAAU+B,EAAOlB,CAAI,GAAK,IAAI,IAAMwE,EAAQ,MAAOF,EAAAtE,KAAAsE,EAAAtE,GAAewE,EAAQ,SAC9E,OAAOrF,EAAaa,CAAI,EAE/B,OAAOsE,CACT,CAEA,SAASG,IAAgB,CACvB,IAAMC,EAASnH,EAAQ,OAClBmH,IACDpF,IAAe,MAAM7B,EAAU,aAAa6B,CAAU,EAC1DA,EAAa7B,EAAU,WAAW,IAAM,CACtC6B,EAAa,KACboF,EAAO,MAAM,QAAQnG,EAAS,EAAG,KAAK,UAAU,CAAE,QAAS,IAAI,KAAK,EAAE,YAAY,EAAG,OAAQC,EAAM,MAAO,CAAC,CAAC,CAC9G,EAAGkG,EAAO,SAAW,GAAG,EAC1B,CAEA,SAASC,IAAc,CACjBrF,IAAe,MAAM7B,EAAU,aAAa6B,CAAU,EAC1DA,EAAa,KACb/B,EAAQ,QAAQ,MAAM,WAAWgB,EAAS,CAAC,CAC7C,CAEA,SAASqG,IAAa,CACpB,IAAMF,EAASnH,EAAQ,OACvB,GAAI,CAACmH,EAAQ,OACb,IAAMG,EAAMH,EAAO,MAAM,QAAQnG,EAAS,CAAC,EAC3C,GAAI,CAACsG,EAAK,OACV,IAAIC,EACJ,GAAI,CACFA,EAAQ,KAAK,MAAMD,CAAG,CACxB,MAAQ,CACNH,EAAO,MAAM,WAAWnG,EAAS,CAAC,EAClC,MACF,CACImG,EAAO,UAAY,OAAQR,EAAY,CAAE,GAAG1F,EAAM,OAAQ,GAAGsG,EAAM,MAAO,EAAG,CAAE,MAAO,IAAK,EAAG,EAAI,EACjGlF,EAAI,CAAE,MAAO,CAAE,QAASkF,EAAM,OAAQ,CAAE,CAAC,CAChD,CAEA,SAASC,GAAmB,CAC1B,IAAMC,EAAWzH,EAAQ,SACrB,CAACyH,GAAYxH,EAAK,KAAK,OAAS,WAChC+B,IAAkB,MAAM9B,EAAU,aAAa8B,CAAa,EAChEA,EAAgB9B,EAAU,WAAW,IAAM,CACzC8B,EAAgB,KACZf,EAAM,MAAM,QAAU,OAAO,KAAK2E,EAAc,CAAC,EAAE,SAAW,GAAQzC,EAAMuE,GAAK,CAAC,CACxF,EAAGD,EAAS,OAAO,EACrB,CAEA,SAASE,GAAYC,EAAiB,CACpC,IAAM1E,EAASlD,EAAQ,WACvB,GAAI,CAACkD,GAAQ,UAAYjD,EAAK,KAAK,OAAS,SAAU,OACtD,IAAM4H,EAAM,EAAE/F,EACRgG,EAAU,CAAE,MAAO7H,EAAK,KAAK,MAAO,GAAIgB,EAAM,SAAU,QAAA2G,EAAS,OAAQlG,GAAeT,EAAM,MAAgB,CAAE,EACjHkC,EACHD,EAAO,SAAS4E,CAAO,EAAE,KACtBtB,GAAW,CACV,GAAIqB,IAAQ/F,EAAa,OACzB,IAAM6B,GAAS,CAAE,GAAI1C,EAAM,OAAmB,GAAIuF,EAAO,QAAU,CAAC,CAAG,EACvEG,EAAYhD,GAAQ,CAAE,QAAS6C,EAAO,SAAW,KAAM,aAAcA,EAAO,QAAUoB,EAAU,IAAK,CAAC,CACxG,EACA,IAAG,EACL,CACF,CACF,CAEA,SAASG,GAAUH,EAAiB,CAClCV,GAAc,EACdM,EAAiB,EACjBG,GAAYC,CAAO,CACrB,CAEA,SAASI,IAAyB,CAChC,IAAMxB,EAAwB,CAAE,OAAQ,CAAC,EAAG,MAAO,CAAC,EAAG,MAAO,CAAC,CAAE,EAG3DyB,EAAWhH,EAAM,WAAa,MAAQA,EAAM,WAAa,OACzDiH,EAAQD,EACV,OAAO,KAAKhI,EAAK,MAAM,EAAE,OAAQwC,GAASxB,EAAM,MAAM,SAASwB,CAAI,GAAK,CAAC0F,GAAQlI,EAAK,OAAOwC,CAAI,EAAGxB,EAAM,OAAOwB,CAAI,CAAC,CAAC,EACvHxB,EAAM,MACV,QAAWwB,KAAQyF,EAAO,CACxB,IAAM3E,EAAMtD,EAAK,OAAOwC,CAAI,EACtB2F,GAAMnH,EAAM,OAAOwB,CAAI,EACvB4F,GAASJ,EAAWK,GAAW/E,CAAG,EAAI/B,EAASiB,CAAI,EACrDc,EAAI,OAAS,WAAYiD,EAAO,MAAM/D,CAAI,EAAI8F,GAASF,IAA4B,CAAC,EAAID,IAAyB,CAAC,CAAC,EAC9G7E,EAAI,OAAS,YAAaiD,EAAO,MAAM/D,CAAI,EAAI+F,GAASH,IAAqC,CAAC,EAAID,IAAkC,CAAC,CAAC,EAC1I5B,EAAO,OAAO/D,CAAI,EAAIf,GAAe0G,EAAG,CAC/C,CACA,OAAO5B,CACT,CAGA,SAASiC,IAAsB,CAC7B,IAAMxF,EAAgB,CAAC,EACvB,QAAWxC,KAAQgE,EAAkB,EAAG,CACtC,IAAMhC,EAAOhC,EAAK,MAClBwC,EAAMR,CAAI,EAAIf,GAAeT,EAAM,OAAOwB,CAAI,CAAC,CACjD,CACA,OAAOQ,CACT,CAEA,eAAeyE,IAAyB,CACtC,IAAM7B,EAASD,EAAc,EAC7B,GAAI,OAAO,KAAKC,CAAM,EAAE,OACtB,OAAAxD,EAAI,CAAE,OAAAwD,CAAO,CAAC,EACP,GAET,IAAM3C,EAASlD,EAAQ,WACvB4B,EAAe,CAAC,EAChBS,EAAI,CAAE,OAAQ,SAAU,OAAQ,CAAC,EAAG,MAAO,KAAM,YAAa,IAAK,CAAC,EACpE,GAAI,CACF,GAAIpC,EAAK,KAAK,OAAS,YAAa,CAClC,GAAI,CAACiD,GAAQ,OAAQ,MAAM,IAAI,MAAM,qDAAqD,EAC1F,aAAMA,EAAO,OAAO,CAAE,OAAQjD,EAAK,GAAI,OAAQwI,GAAY,CAAE,CAAC,EAC9DrB,GAAY,EACZ/E,EAAI,CAAE,OAAQ,OAAQ,CAAC,EAChB,EACT,CACA,GAAI,CAACa,GAAQ,KAAM,MAAM,IAAI,MAAM,yCAAyC,EAC5E,IAAMsD,EAAS,MAAMtD,EAAO,KAAK,CAC/B,MAAOjD,EAAK,KAAK,MACjB,GAAIgB,EAAM,SACV,OAAQhB,EAAK,OACb,QAAS+H,GAAQ,EACjB,OAAQtG,GAAeT,EAAM,MAAgB,CAC/C,CAAC,EACDmG,GAAY,EACZ,IAAMzD,EAAS8C,EAAUD,EAAO,OAAS,CAAE,GAAIvF,EAAM,OAAmB,GAAGuF,EAAO,MAAO,EAAKvF,EAAM,MAAiB,EACrH,OAAAO,EAAWE,GAAeiC,CAAM,EAChCtB,EAAI,CAAE,OAAQ,QAAS,SAAUmE,EAAO,GAAI,OAAA7C,EAAQ,MAAO,CAAC,EAAG,SAAU8B,EAAW9B,EAAQ0B,CAAe,CAAE,CAAC,EACvG,EACT,OAAShC,EAAO,CACd,IAAMqF,EAAUC,GAActF,CAAK,EAC7BuF,EAASF,EAAQ,OAAS,SAAWA,EAAQ,QAAU,CAAC,EAAI,CAAC,EACnE,OAAA9G,EAAe,OAAO,YAAY,OAAO,QAAQgH,CAAM,EAAE,IAAI,CAAC,CAACnG,GAAMqD,EAAO,IAAM,CAACrD,GAAM,CAAE,QAAAqD,GAAS,MAAO,KAAK,UAAU7E,EAAM,OAAOwB,EAAI,GAAK,IAAI,CAAE,CAAC,CAAC,CAAC,EACzJJ,EAAI,CAAE,OAAQ,QAAS,MAAOqG,EAAQ,QAAS,YAAaA,EAAS,OAAQ,CAAE,GAAGE,CAAO,CAAE,CAAC,EACrF,EACT,CACF,CAGA,SAASC,GAAUtF,EAAmD,CACpE,MAAI,CAACvD,EAAQ,YAAY,QAAU,CAACuD,GAAOA,EAAI,SAAiB,KACzDA,EAAI,OAAS,YAAcA,EAAI,OAAS,YAAcA,EAAI,SAAW,IAC9E,CAEA,eAAeuF,GAAUvF,EAAoCd,EAAcsG,EAAuC,CAChH,IAAMC,EAAQH,GAAUtF,CAAG,EACrBL,EAASlD,EAAQ,WACvB,GAAI,CAACgJ,GAAS,CAAC9F,GAAQ,OAAQ,MAAM,IAAI,MAAM,IAAIT,CAAI,2EAA2E,EAClI,OAAOU,EAAMD,EAAO,OAAO,CAAE,MAAA8F,EAAO,KAAMD,EAAM,KAAK,CAAE,CAAC,CAAC,CAC3D,CAEA,eAAeE,GACb1F,EACAd,EACA0B,EACA+E,EACAC,EACAH,GAC0B,CAC1B,GAAIzF,EAAI,OAAS,YAAcA,EAAI,OAAS,aAAeA,EAAI,OAAS,YACtE,MAAM,IAAI,MAAM,IAAId,CAAI,6CAA6C,EAEvE,GAAIc,EAAI,OAAS,aAAe,CAACyF,GAAO,MAAM,IAAI,MAAM,cAAcvG,CAAI,iBAAiB,EAC3F,IAAMS,GAASlD,EAAQ,WACvB,GAAI,CAACkD,IAAQ,OAAQ,MAAO,CAAC,EAE7B,IAAMkG,GAAWC,IACf,QAASA,GACL,CAAE,IAAKA,GAAK,IAAI,IAAID,EAAO,CAAE,EAC7B,QAASC,GACP,CAAE,IAAKA,GAAK,IAAI,IAAID,EAAO,CAAE,EAC7B,CAAE,MAAOC,GAAK,MAAO,GAAIA,GAAK,GAAI,MAAQA,GAAK,YAAc,OAAYlF,EAAIkF,GAAK,SAAS,GAAK,KAAOA,GAAK,OAAS,IAAmB,EAC1IC,GAAuC/F,EAAI,OAAS,YAAc,OAAYA,EAAI,QAAQ,IAAI6F,EAAO,EACrGG,GAAWhG,EAAI,OAAS,YAAeyF,GAAmBzF,EAAI,SACpE,OAAOJ,EAAMD,GAAO,OAAO,CAAE,MAAOqG,GAAU,MAAAL,EAAO,GAAII,GAAS,CAAE,OAAAA,EAAO,EAAI,CAAC,EAAI,MAAAH,CAAM,CAAC,CAAC,CAC9F,CAEA,SAASK,GAAUC,EAAe,CAChC,IAAMlG,EAAMQ,EAAS0F,CAAK,EAC1B,GAAIlG,EAAI,OAAS,WAAY,MAAM,IAAI,MAAM,IAAIkG,CAAK,UAAUlG,EAAI,IAAI,kBAAkB,EAC1F,OAAOA,CACT,CAEA,SAASmG,IAAoB,CAC3B,OAAOzI,EAAM,KAAOH,EAAM,QAAQG,EAAM,IAAI,EAAI,EAClD,CAGA,SAAS0I,GAAazF,EAAqB,CACzC,OAAQ5D,EAAM,IAAI4D,CAAE,GAAG,QAA+C,WAAa,EACrF,CAEA,eAAepB,IAAsB,CACnC,IAAMI,EAASlD,EAAQ,WACvB,GAAI,EAAAiB,EAAM,UAAY,MAAQhB,EAAK,KAAK,OAAS,UACjD,IAAI,CAACiD,GAAQ,KAAM,CACjBb,EAAI,CAAE,OAAQ,QAAS,MAAO,2CAA4C,CAAC,EAC3E,MACF,CACAA,EAAI,CAAE,OAAQ,UAAW,MAAO,IAAK,CAAC,EACtC,GAAI,CACF,IAAMe,EAAS,MAAMF,EAAO,KAAK,CAAE,MAAOjD,EAAK,KAAK,MAAO,GAAIgB,EAAM,SAAU,OAAQhB,EAAK,MAAO,CAAC,EACpGuB,EAAWiF,EAAU,CAAE,GAAGhF,GAAcxB,EAAK,OAAQiB,EAAM,CAAC,EAAG,GAAGkC,CAAO,CAAC,EAC1Ef,EAAI,CAAE,OAAQ,QAAS,OAAQX,GAAeF,CAAQ,EAAG,MAAO,CAAC,EAAG,OAAQ,CAAC,EAAG,SAAUiE,EAAWjE,EAAU6D,CAAe,CAAE,CAAC,EACjIgC,GAAW,CACb,OAAShE,EAAO,CACdhB,EAAI,CAAE,OAAQ,QAAS,MAAQgB,EAAgB,OAAQ,CAAC,CAC1D,EACF,CAEA,IAAMuG,GAAa,CACjB,KAAA3J,EACA,SAAU,IAAMgB,EAEhB,UAAUuB,EAAU,CAClB,OAAAN,EAAU,IAAIM,CAAQ,EACf,IAAMN,EAAU,OAAOM,CAAQ,CACxC,EAEA,KAAM,IAAMW,EAAML,GAAK,CAAC,EAExB,SAASL,EAAMoH,EAAO,CACpB9F,EAAStB,CAAI,EACbkE,EAAY,CAAE,GAAI1F,EAAM,OAAmB,CAACwB,CAAI,EAAGf,GAAemI,CAAK,CAAE,CAAC,EAC1E9B,GAAUtF,CAAI,CAChB,EAEA,KAAMwB,EAEN,cAAgBxB,GAAS+B,GAAYT,EAAStB,CAAI,CAAC,EAEnD,YAAAG,EAEA,QAAQH,EAAM,CACZsB,EAAStB,CAAI,EAEb,IAAMQ,EAAQwB,EAAkB,EAAE,OAAQhE,GAASA,EAAK,QAAUgC,CAAI,EACtE,OAAKQ,EAAM,OAETA,EAAM,IAAIgC,CAAQ,EAAE,KAAK,OAAO,GAChChC,EAAM,IAAKxC,GAAS0E,GAAWlF,EAAK,OAAOwC,CAAI,EAAGhC,EAAK,OAAqBQ,EAAM,OAAOwB,CAAI,EAAGrC,CAAQ,CAAC,EAAE,KAAK,OAAO,GACvHgF,GAAW9B,EAAQb,CAAI,EAAGxB,EAAM,OAAOwB,CAAI,EAAGQ,EAAM,KAAMxC,GAASwD,EAAUxD,EAAK,EAAE,EAAE,QAAQ,EAAGL,EAAUc,EAAM,CAAC,GACtG+B,EAAM,IAAKxC,GAASqE,EAAUrE,CAAI,EAAE,KAAK,EAAE,KAAM4C,GAAUA,IAAU,MAAS,GAAK,KALvE,IAM5B,EAEA,UAAW,CACT,IAAMwC,EAASD,EAAc,EAC7B,OAAAvD,EAAI,CAAE,OAAAwD,CAAO,CAAC,EACP,OAAO,KAAKA,CAAM,EAAE,SAAW,CACxC,EAEA,KAAM,IAAM1C,EAAMuE,GAAK,CAAC,EAExB,OAAQ,CACNN,GAAY,EACZxF,EAAe,CAAC,EAChBD,EAAUL,EAAQ,QAAQE,CAAQ,EAClCa,EAAI,CAAE,OAAQX,GAAeF,CAAQ,EAAG,MAAO,CAAC,EAAG,OAAQ,CAAC,EAAG,SAAUiE,EAAWjE,EAAU6D,CAAe,EAAG,QAAS,KAAM,aAAc,KAAM,MAAO,KAAM,KAAMvE,EAAM,CAAC,GAAK,KAAM,QAAS,CAAC,EAAG,YAAa,IAAK,CAAC,CAC1N,EAEA,QAAAkH,GAEA,QAAQyB,EAAO9F,EAAS,CAAC,EAAG,CAC1B,IAAMJ,EAAMiG,GAAUC,CAAK,EACrBzC,EAAM,OAAO,EAAEnF,CAAQ,GACvBiI,EAAW7I,EAAM,OAAOwI,CAAK,GAAuB,CAAC,EACrD1D,GAAa,CAAE,IAAAiB,EAAK,OAAQ,CAAE,GAAGvF,GAAc8B,EAAI,OAAqCrC,EAAM,CAAC,EAAG,GAAGQ,GAAeiC,CAAM,CAAE,CAAE,EAEpI,GAAIJ,EAAI,eAAiBwC,GAAK,OAAOxC,EAAI,aAAa,GAAK,KAAM,CAC/D,IAAMwG,GAAUD,EAAQ,IAAKE,IAAMA,GAAE,OAAOzG,EAAI,aAAuB,CAAC,EAAE,OAAQ0G,IAAmB,OAAOA,IAAM,QAAQ,EAC1HlE,GAAK,OAAOxC,EAAI,aAAa,EAAIwG,GAAQ,OAAS,KAAK,IAAI,GAAGA,EAAO,EAAI,EAAI,CAC/E,CACA,IAAMG,GAAQ,CAAC,GAAGJ,EAAS/D,EAAI,EAC/B,OAAAY,EAAY,CAAE,GAAI1F,EAAM,OAAmB,CAACwI,CAAK,EAAGS,EAAM,CAAC,EAC3DnC,GAAU0B,CAAK,EACRzC,CACT,EAEA,WAAWyC,EAAOzC,EAAKvE,EAAMoH,EAAO,CAElC,GAAI,CADQL,GAAUC,CAAK,EAClB,OAAOhH,CAAI,EAAG,MAAM,IAAI,MAAM,iBAAiBgH,CAAK,oBAAoBhH,CAAI,GAAG,EACxF,IAAMyH,IAAUjJ,EAAM,OAAOwI,CAAK,GAAuB,CAAC,GAAG,IAAK1D,IAChEA,GAAK,MAAQiB,EAAM,CAAE,GAAGjB,GAAM,OAAQ,CAAE,GAAGA,GAAK,OAAQ,CAACtD,CAAI,EAAGf,GAAemI,CAAK,CAAE,CAAE,EAAI9D,EAC9F,EACAY,EAAY,CAAE,GAAI1F,EAAM,OAAmB,CAACwI,CAAK,EAAGS,EAAM,CAAC,EAC3DnC,GAAU0B,CAAK,CACjB,EAEA,SAASA,EAAOzC,EAAKmD,EAAI,CAEvB,IAAMC,EADMZ,GAAUC,CAAK,EACN,cACrB,GAAI,CAACW,EAAU,MAAM,IAAI,MAAM,iBAAiBX,CAAK,iDAAiD,EACtG,IAAMS,GAAQ,CAAC,GAAKjJ,EAAM,OAAOwI,CAAK,GAAuB,CAAC,CAAE,EAC1DY,GAAOH,GAAM,UAAWnE,GAASA,EAAK,MAAQiB,CAAG,EACvD,GAAIqD,GAAO,EAAG,MAAM,IAAI,MAAM,IAAIZ,CAAK,kBAAkBzC,CAAG,GAAG,EAC/D,IAAMsD,GAAS,KAAK,IAAI,EAAG,KAAK,IAAIH,EAAID,GAAM,OAAS,CAAC,CAAC,EACzD,GAAII,KAAWD,GAAM,OAErB,IAAMhC,GAAS6B,GAAM,IAAKnE,GAASA,EAAK,OAAOqE,CAAQ,CAAC,EAClDG,GAAUlC,GAAO,MAAM,CAAC4B,EAAGO,IAAM,OAAOP,GAAM,WAAaO,IAAM,GAAKP,EAAK5B,GAAOmC,EAAI,CAAC,EAAa,EAC1GN,GAAM,OAAOI,GAAQ,EAAG,GAAGJ,GAAM,OAAOG,GAAM,CAAC,CAAC,EAIhD,IAAMI,GAAM,KAAK,IAAIJ,GAAMC,EAAM,EAC3BI,GAAO,KAAK,IAAIL,GAAMC,EAAM,EAC5BK,EAAOJ,GAAWlC,GAAO,MAAMoC,GAAKC,GAAO,CAAC,EAAiB,CAAC,EAC9DE,EAAaV,GAAM,IAAI,CAACnE,EAAMyE,IAAM,CACxC,IAAMX,GAAQU,GAAWC,GAAKC,IAAOD,GAAKE,GAAOC,EAAKH,EAAIC,EAAG,EAAI1E,EAAK,OAAOqE,CAAQ,EAAKI,EAAI,EAC9F,OAAOX,KAAU9D,EAAK,OAAOqE,CAAQ,EAAIrE,EAAO,CAAE,GAAGA,EAAM,OAAQ,CAAE,GAAGA,EAAK,OAAQ,CAACqE,CAAQ,EAAGP,EAAM,CAAE,CAC3G,CAAC,EACDlD,EAAY,CAAE,GAAI1F,EAAM,OAAmB,CAACwI,CAAK,EAAGmB,CAAW,CAAC,EAChE7C,GAAU0B,CAAK,CACjB,EAEA,WAAWA,EAAOzC,EAAK,CACrBwC,GAAUC,CAAK,EACf,IAAMS,GAAUjJ,EAAM,OAAOwI,CAAK,GAAuB,CAAC,GAAG,OAAQ1D,GAASA,EAAK,MAAQiB,CAAG,EAC9FL,EAAY,CAAE,GAAI1F,EAAM,OAAmB,CAACwI,CAAK,EAAGS,CAAM,CAAC,EAC3DnC,GAAU0B,CAAK,CACjB,EAEA,MAAM,OAAOA,EAAOP,EAAOC,EAAQ,EAAGnJ,EAAU,CAAC,EAAG,CAClD,OAAOiJ,GAAUlF,EAAS0F,CAAK,EAAGA,EAAO3F,EAAQ,EAAGoF,EAAOC,EAAOnJ,EAAQ,KAAK,CACjF,EAEA,MAAM,YAAYyJ,EAAOzC,EAAKrD,EAAQ,CACpC6F,GAAUC,CAAK,EACf,IAAMS,EAASjJ,EAAM,OAAOwI,CAAK,GAAuB,CAAC,EACnD1D,EAAOmE,EAAM,KAAMF,IAAMA,GAAE,MAAQhD,CAAG,EAC5C,GAAI,CAACjB,EAAM,MAAM,IAAI,MAAM,IAAI0D,CAAK,kBAAkBzC,CAAG,GAAG,EAC5D,IAAM6D,GAASzJ,EAAS,KAAKqI,EAAO,CAAE,GAAG1D,EAAK,OAAQ,GAAGpC,CAAO,CAAC,EAC3DT,GAASlD,EAAQ,WACvB,GAAI,CAACkD,IAAQ,UAAYjD,EAAK,KAAK,OAAS,SAAU,OAAO4K,GAC7D,IAAMjD,GAAUsC,EAAM,IAAKF,IAAOA,GAAE,MAAQhD,EAAM,CAAE,GAAGgD,GAAG,OAAQa,EAAO,EAAIb,EAAE,EAEzEc,KADS,MAAM5H,GAAO,SAAS,CAAE,MAAOjD,EAAK,KAAK,MAAO,GAAIgB,EAAM,SAAU,QAASwI,EAAO,OAAQ/H,GAAe,CAAE,GAAIT,EAAM,OAAmB,CAACwI,CAAK,EAAG7B,EAAQ,CAAC,CAAE,CAAC,GACvJ,SAAS6B,CAAK,GAA4B,CAAC,GAAG,KAAMO,IAAMA,GAAE,MAAQhD,CAAG,EAC9F,OAAO8D,GAAQ1J,EAAS,KAAKqI,EAAO,CAAE,GAAGoB,GAAQ,GAAGC,GAAM,MAAO,CAAC,EAAID,EACxE,EAEA,MAAM,WAAWpB,EAAOzC,EAAK+D,EAAU7B,EAAOC,EAAQ,EAAG,CACvD,IAAM5F,GAAMiG,GAAUC,CAAK,EACrBvD,GAAM3C,GAAI,OAAOwH,CAAQ,EAC/B,GAAI,CAAC7E,GAAK,MAAM,IAAI,MAAM,iBAAiBuD,CAAK,oBAAoBsB,CAAQ,GAAG,EAC/E,IAAMhF,IAAS9E,EAAM,OAAOwI,CAAK,GAAuB,CAAC,GAAG,KAAMO,IAAMA,GAAE,MAAQhD,CAAG,EACrF,GAAI,CAACjB,GAAM,MAAM,IAAI,MAAM,IAAI0D,CAAK,kBAAkBzC,CAAG,GAAG,EAC5D,OAAOiC,GAAU/C,GAAK6E,EAAUnH,GAAkBmC,GAAK,OAAQxC,GAAI,MAAmC,EAAG2F,EAAOC,CAAK,CACvH,EAEA,UAAYM,GAAUZ,GAAU5I,EAAK,OAAOwJ,CAAK,CAAC,IAAM,KACxD,YAAa,CAACA,EAAOV,IAAUD,GAAU7I,EAAK,OAAOwJ,CAAK,EAAGA,EAAOV,CAAK,EACzE,cAAe,CAACU,EAAOsB,IAAalC,GAAUW,GAAUC,CAAK,EAAE,OAAOsB,CAAQ,CAAC,IAAM,KACrF,gBAAiB,CAACtB,EAAOsB,EAAUhC,IAAUD,GAAUU,GAAUC,CAAK,EAAE,OAAOsB,CAAQ,EAAGA,EAAUhC,CAAK,EAEzG,MAAO,IAAMjI,EAAM,OAAQoD,GAAO,CAACD,EAAUC,CAAE,EAAE,SAAS,EAE1D,MAAO,CACL,GAAI,CAACjD,EAAM,KAAM,MAAO,GAEpBA,EAAM,QAAQ,SAASA,EAAM,IAAI,GAAGoB,EAAI,CAAE,QAASpB,EAAM,QAAQ,OAAQiD,GAAOA,IAAOjD,EAAM,IAAI,CAAE,CAAC,EACxG,IAAM4E,EAASD,EAAc3E,EAAM,IAAI,EACvC,GAAI,OAAO,KAAK4E,CAAM,EAAE,OACtB,OAAAxD,EAAI,CAAE,OAAAwD,CAAO,CAAC,EACP,GAET,IAAMmF,EAAUpB,GAAK,MAAM,EACrBqB,EAAYnK,EAAM,MAAM4I,GAAU,EAAI,CAAC,EAAE,KAAMxF,GAAO8G,EAAQ,SAAS9G,CAAE,CAAC,EAChF,OAAK+G,GACL5I,EAAI,CAAE,KAAM4I,EAAW,OAAQ,CAAC,CAAE,CAAC,EAC5B,IAFgB,EAGzB,EAEA,MAAO,CACL,GAAI,CAAChK,EAAM,KAAM,MAAO,GACxB,IAAM+J,EAAUpB,GAAK,MAAM,EACrBjE,EAAW7E,EAAM,MAAM,EAAG4I,GAAU,CAAC,EAAE,QAAQ,EAAE,KAAMxF,GAAO8G,EAAQ,SAAS9G,CAAE,CAAC,EACxF,OAAKyB,GACLtD,EAAI,CAAE,KAAMsD,EAAU,OAAQ,CAAC,CAAE,CAAC,EAC3B,IAFe,EAGxB,EAEA,MAAO,CACL,IAAMmE,EAAU7I,EAAM,KACtB,GAAI,CAAC6I,GAAW,CAACH,GAAaG,CAAO,EAAG,MAAO,GAC/C,IAAMkB,EAAUpB,GAAK,MAAM,EACrBqB,EAAYD,EAAQA,EAAQ,QAAQlB,CAAO,EAAI,CAAC,EACtD,OAAKmB,GACL5I,EAAI,CAAE,KAAM4I,EAAW,OAAQ,CAAC,EAAG,QAAS,CAAC,GAAGhK,EAAM,QAAQ,OAAQiD,GAAOA,IAAO4F,CAAO,EAAGA,CAAO,CAAE,CAAC,EACjG,IAFgB,EAGzB,EAEA,KAAKQ,EAAQ,CACX,IAAMU,EAAUpB,GAAK,MAAM,EACrBO,EAAKa,EAAQ,QAAQV,CAAM,EAC3B1F,EAAK3D,EAAM,KAAO+J,EAAQ,QAAQ/J,EAAM,IAAI,EAAI,GACtD,GAAIkJ,IAAO,IAAMvF,IAAO,GAAI,MAAO,GACnC,GAAIuF,GAAMvF,EACR,OAAAvC,EAAI,CAAE,KAAMiI,EAAQ,OAAQ,CAAC,CAAE,CAAC,EACzB,GAET,IAAMzF,EAAU,CAAC,GAAG5D,EAAM,OAAO,EACjC,QAAWiD,MAAM8G,EAAQ,MAAMpG,EAAIuF,CAAE,EAAG,CACtC,GAAItF,EAAQ,SAASX,EAAE,EAAG,SAC1B,IAAM2B,GAASD,EAAc1B,EAAE,EAC/B,GAAK,OAAO,KAAK2B,EAAM,EAAE,OACzB,IAAI8D,GAAazF,EAAE,EAAG,CACpBW,EAAQ,KAAKX,EAAE,EACf,QACF,CACA,OAAA7B,EAAI,CAAE,KAAM6B,GAAI,OAAA2B,GAAQ,QAAAhB,CAAQ,CAAC,EAC1B,GACT,CACA,OAAAxC,EAAI,CAAE,KAAMiI,EAAQ,OAAQ,CAAC,EAAG,QAAAzF,CAAQ,CAAC,EAClC,EACT,EAEA,MAAM,UAAUX,EAAIgH,EAAQ,CAC1B,IAAMzK,EAAOH,EAAM,IAAI4D,CAAE,EACzB,GAAI,CAACzD,GAASA,EAAK,OAAS,UAAYA,EAAK,OAAS,OAAS,MAAM,IAAI,MAAM,2BAA2ByD,CAAE,GAAG,EAC/G,GAAID,EAAUC,CAAE,EAAE,UAAW,OAC7B,IAAMhB,EAASzC,EAAK,OACpB,MAAM0C,EACJ,QAAQ,QACNnD,EAAQ,WAAW,CACjB,GAAAkE,EACA,OAAQhB,EAAO,OACf,GAAI,WAAYA,GAAUA,EAAO,OAAS,CAAE,OAAQA,EAAO,MAAO,EAAI,CAAC,EACvE,SAAUjC,EAAM,SAChB,OAAQS,GAAeT,EAAM,MAAgB,EAC7C,GAAIiK,EAAS,CAAE,UAAW,CAAC,GAAGA,EAAO,SAAS,CAAE,EAAI,CAAC,CACvD,CAAC,CACH,CACF,CACF,EAEA,cAAe,CACb,IAAM5D,EAAMtH,EAAQ,QAAQ,MAAM,QAAQgB,EAAS,CAAC,EACpD,GAAI,CAACsG,EAAK,OACV,IAAMC,EAAQ,KAAK,MAAMD,CAAG,EAC5BX,EAAY,CAAE,GAAI1F,EAAM,OAAmB,GAAGsG,EAAM,MAAO,EAAG,CAAE,MAAO,IAAK,EAAG,EAAI,CACrF,EAEA,cAAe,CACbH,GAAY,EACZ/E,EAAI,CAAE,MAAO,IAAK,CAAC,CACrB,EAEA,MAAM,SAAU,CACd,KAAOJ,EAAQ,MAAM,MAAM,QAAQ,WAAW,CAAC,GAAGA,CAAO,CAAC,CAC5D,EAEA,SAAU,CACJF,IAAe,MAAM7B,EAAU,aAAa6B,CAAU,EACtDC,IAAkB,MAAM9B,EAAU,aAAa8B,CAAa,EAChEE,EAAU,MAAM,CAClB,CACF,EAGA,OAAAjB,EAAQ,CAAE,GAAGA,EAAO,SAAUoE,EAAgB,CAAE,EAC5CpE,EAAM,UAAY,MAAMoG,GAAW,EAChCuC,EACT,CAGA,SAASpF,GAAYjB,EAAqB,CACxC,OAAOA,EAAI,WAAa,IAAQA,EAAI,UAAY,MAClD,CAEA,SAASgF,GAAQF,EAAgBD,EAAuB,CACtD,IAAM+C,EAAgB,CAAC,EACjBC,EAAM,IAAI,IAAI/C,EAAO,OAAQtC,GAASA,EAAK,KAAO,MAAS,EAAE,IAAKA,GAAS,CAACA,EAAK,IAAKA,CAAI,CAAC,CAAC,EAClG,QAAWA,KAAQqC,EAAK,CACtB,IAAMzC,EAAWyF,EAAI,IAAIrF,EAAK,GAAG,EACjC,GAAIA,EAAK,KAAO,QAAa,CAACJ,EAAU,CACtCwF,EAAI,KAAK,CAAE,GAAI,SAAU,IAAKpF,EAAK,IAAK,OAAQrE,GAAeqE,EAAK,MAAM,CAAE,CAAC,EAC7E,QACF,CACA,IAAM6B,EAAkB,CAAC,EACzB,OAAW,CAACnF,EAAMoH,CAAK,IAAK,OAAO,QAAQ9D,EAAK,MAAM,EAChD,KAAK,UAAU8D,CAAK,IAAM,KAAK,UAAUlE,EAAS,OAAOlD,CAAI,CAAC,IAAGmF,EAAQnF,CAAI,EAAIf,GAAemI,CAAK,GAEvG,OAAO,KAAKjC,CAAO,EAAE,QAAQuD,EAAI,KAAK,CAAE,GAAI,SAAU,GAAIpF,EAAK,GAAI,OAAQ6B,CAAQ,CAAC,CAC1F,CACA,IAAMb,EAAO,IAAI,IAAIqB,EAAI,IAAKrC,GAASA,EAAK,GAAG,CAAC,EAChD,QAAWA,KAAQsC,EAAYtC,EAAK,KAAO,QAAa,CAACgB,EAAK,IAAIhB,EAAK,GAAG,GAAGoF,EAAI,KAAK,CAAE,GAAI,SAAU,GAAIpF,EAAK,EAAG,CAAC,EACnH,OAAOoF,CACT,CAEA,SAAS3C,GAAQH,EAAyBD,EAAgC,CACxE,IAAMiD,EAAM,IAAI,IAAIhD,EAAO,IAAKiD,GAAMA,EAAE,EAAE,CAAC,EACrCC,EAAM,IAAI,IAAInD,EAAI,IAAKkD,GAAMA,EAAE,EAAE,CAAC,EACxC,MAAO,CACL,GAAGlD,EAAI,OAAQkD,GAAM,CAACD,EAAI,IAAIC,EAAE,EAAE,CAAC,EAAE,IAAKA,IAAe,CAAE,GAAI,OAAQ,GAAIA,EAAE,EAAG,EAAE,EAClF,GAAGjD,EAAO,OAAQiD,GAAM,CAACC,EAAI,IAAID,EAAE,EAAE,CAAC,EAAE,IAAKA,IAAe,CAAE,GAAI,SAAU,GAAIA,EAAE,EAAG,EAAE,CACzF,CACF,CAEA,SAAS/K,GAAYmE,EAA4C,CAC/D,IAAMpE,EAAQ,IAAI,IACZkL,EAAM,CACVtI,EACAoB,EACA0B,EACAyF,IACG,CACHnL,EAAM,IAAI4C,EAAO,GAAI,CACnB,GAAIA,EAAO,GACX,OAAAoB,EACA,KAAA0B,EACA,MAAOyF,EAAU,MACjB,UAAWC,GAAgBD,EAAU,SAAS,EAC9C,SAAUC,GAAgBD,EAAU,QAAQ,EAC5C,SAAUC,GAAgBD,EAAU,QAAQ,EAC5C,OAAAvI,CACF,CAAC,CACH,EACMyI,EAAO,CAACC,EAAqBtH,IAAmB,CACpD,QAAW7D,KAAQmL,EACjB,GAAInL,EAAK,OAAS,QAChB+K,EAAI/K,EAAM6D,EAAQ,QAAS,CAAE,UAAW7D,EAAK,UAAW,SAAUA,EAAK,SAAU,SAAUA,EAAK,SAAU,MAAOA,EAAK,KAAM,CAAC,UACpHA,EAAK,OAAS,SACvB+K,EAAI/K,EAAM6D,EAAQ,SAAU,CAAE,UAAW7D,EAAK,SAAU,CAAC,UAChDA,EAAK,OAAS,OAAQ,CAC/B+K,EAAI/K,EAAM6D,EAAQ,QAAS,CAAE,UAAW7D,EAAK,SAAU,CAAC,EACxD,QAAWoL,KAAOpL,EAAK,SACrB+K,EAAIK,EAAKpL,EAAK,GAAI,QAAS,CAAE,UAAWoL,EAAI,SAAU,CAAC,EACvDF,EAAKE,EAAI,SAAUA,EAAI,EAAE,CAE7B,MAAWpL,EAAK,OAAS,WACvB+K,EAAI/K,EAAM6D,EAAQ,QAAS,CAAE,UAAW7D,EAAK,UAAW,SAAUA,EAAK,QAAS,CAAC,EACjFkL,EAAKlL,EAAK,SAAUA,EAAK,EAAE,GAE3B+K,EAAI/K,EAAM6D,EAAQ,QAAS,CAAE,UAAW7D,EAAK,SAAU,CAAC,CAG9D,EAEA,GAAIiE,EAAK,OAAS,OAChB,OAAAiH,EAAK,CAACjH,CAAI,EAAG,EAAE,EACfpE,EAAM,IAAIoE,EAAK,EAAE,EAAG,OAAS,KACtBpE,EAGT,GADAkL,EAAI9G,EAAM,KAAM,QAAS,CAAC,CAAC,EACvBA,EAAK,OAAS,SAChB,QAAW3D,KAAQ2D,EAAK,SACtB8G,EAAIzK,EAAM2D,EAAK,GAAI,OAAQ,CAAE,UAAW3D,EAAK,SAAU,CAAC,EACxD4K,EAAK5K,EAAK,SAAUA,EAAK,EAAE,UAEpB2D,EAAK,OAAS,WACvBiH,EAAKjH,EAAK,SAAUA,EAAK,EAAE,UAClBA,EAAK,OAAS,OAEvB,QAAWoH,KAAUpH,EAAK,SAAW,CAAC,EAAG8G,EAAIM,EAAQpH,EAAK,GAAI,SAAU,CAAE,UAAWoH,EAAO,SAAU,CAAC,MAClG,CAGL,IAAM7I,EAAQ,CAACiB,EAAYuF,IAA8B,CACnDA,GAAO+B,EAAI,CAAE,GAAAtH,CAAG,EAAGQ,EAAK,GAAI,QAAS,CAAE,MAAA+E,CAAM,CAAC,CACpD,EACAxG,EAAM,SAAUyB,EAAK,OAAO,KAAK,EACjCzB,EAAM,YAAayB,EAAK,OAAO,aAAa,EAC5CzB,EAAM,UAAWyB,EAAK,OAAO,WAAW,EACxCzB,EAAM,aAAcyB,EAAK,WAAW,KAAK,EACzC,QAAWoH,KAAUpH,EAAK,SAAW,CAAC,EAAG8G,EAAIM,EAAQpH,EAAK,GAAI,SAAU,CAAE,UAAWoH,EAAO,SAAU,CAAC,EACvG,QAAWC,KAAQrH,EAAK,aAAe,CAAC,EAAG8G,EAAIO,EAAMrH,EAAK,GAAI,OAAQ,CAAE,UAAWqH,EAAK,SAAU,CAAC,EAC/FrH,EAAK,QAAQ8G,EAAI9G,EAAK,OAAQA,EAAK,GAAI,QAAS,CAAE,UAAWA,EAAK,OAAO,SAAU,CAAC,EACxF,QAAWsH,KAAStH,EAAK,QAAU,CAAC,EAAG8G,EAAIQ,EAAOtH,EAAK,GAAI,QAAS,CAAE,UAAWsH,EAAM,SAAU,CAAC,EAClG,QAAWC,KAASvH,EAAK,QAAU,CAAC,EAAG8G,EAAIS,EAAOvH,EAAK,GAAI,QAAS,CAAE,UAAWuH,EAAM,SAAU,CAAC,EAElGN,EAAK,CAAC,GAAIjH,EAAK,OAAO,OAAS,CAAC,EAAI,GAAIA,EAAK,OAAO,OAAS,CAAC,CAAE,EAAGA,EAAK,EAAE,EAC1EiH,EAAKjH,EAAK,SAAUA,EAAK,EAAE,EACvBA,EAAK,WAAW8G,EAAI9G,EAAK,UAAWA,EAAK,GAAI,QAAS,CAAE,UAAWA,EAAK,UAAU,SAAU,CAAC,CACnG,CACA,OAAOpE,CACT,CCz/BA,IAAM4L,GAAU,IAAI,IACpB,SAASC,GAAOC,EAAgBC,EAAqC,CACnE,IAAMC,EAAM,GAAGF,CAAM,IAAIC,CAAQ,GAC7BE,EAAQL,GAAQ,IAAII,CAAG,EAC3B,OAAKC,IACHA,EAAQ,IAAI,KAAK,aAAaH,EAAQ,CAAE,gBAAiB,OAAQ,sBAAuBC,EAAU,sBAAuBA,CAAS,CAAC,EACnIH,GAAQ,IAAII,EAAKC,CAAK,GAEjBA,CACT,CAQO,SAASC,GAAYC,EAAeC,EAAkBL,EAAkBD,EAAiB,KAAc,CAC5G,GAAI,CACF,OAAO,IAAI,KAAK,aAAaA,EAAQ,CAAE,MAAO,WAAY,SAAAM,EAAU,gBAAiB,eAAgB,gBAAiB,OAAQ,sBAAuBL,EAAU,sBAAuBA,CAAS,CAAC,EAAE,OAAOI,CAAK,CAChN,MAAQ,CACN,MAAO,GAAGC,CAAQ,IAAIC,GAAaF,EAAOJ,EAAUD,CAAM,CAAC,EAC7D,CACF,CAGA,SAASQ,GAAMR,EAAoD,CACjE,IAAMS,EAAQV,GAAOC,EAAQ,CAAC,EAAE,cAAc,OAAO,EACrD,MAAO,CAAE,MAAOS,EAAM,KAAMC,GAAMA,EAAE,OAAS,OAAO,GAAG,OAAS,IAAK,QAASD,EAAM,KAAMC,GAAMA,EAAE,OAAS,SAAS,GAAG,OAAS,GAAI,CACtI,CAGO,SAASH,GAAaF,EAAeJ,EAAkBD,EAAiB,KAAc,CAC3F,OAAOD,GAAOC,EAAQC,CAAQ,EAAE,OAAOI,CAAK,CAC9C,CAMO,SAASM,GAAgBC,EAAcZ,EAAiB,KAAc,CAC3E,GAAM,CAAE,MAAAa,EAAO,QAAAC,CAAQ,EAAIN,GAAMR,CAAM,EACnCe,EAAMH,EACP,QAAQ,SAAWI,GAAM,OAAOA,EAAE,WAAW,CAAC,EAAI,IAAM,CAAC,EACzD,QAAQ,SAAWA,GAAM,OAAOA,EAAE,WAAW,CAAC,EAAI,IAAM,CAAC,EACzD,QAAQ,KAAMF,CAAO,EACrB,QAAQ,KAAMD,CAAK,EAEtB,OAAAE,EAAMA,EAAI,QAAQ,oBAAqB,EAAE,EACrCF,EAAM,KAAK,IAAGE,EAAMA,EAAI,MAAMF,CAAK,EAAE,KAAK,EAAE,GACzCC,IAAY,IAAMC,EAAMA,EAAI,MAAMD,CAAO,EAAE,KAAK,GAAG,CAC5D,CC5DO,IAAMG,GAAY,CAAC,ECyI1B,IAAMC,GAAmB,CACvB,OAAQ,eACR,UAAW,aACX,OAAQ,gBACR,MAAO,gBACP,QAAS,aACT,WAAY,gBACZ,QAAS,aACT,WAAY,cACZ,MAAO,WACP,MAAO,QACP,YAAa,sBACb,aAAc,eACd,cAAe,iBACf,YAAa,4BACb,cAAe,wBACf,WAAY,oBACZ,UAAW,cACX,SAAU,YACV,WAAY,gBACZ,MAAO,SACP,YAAa,kBACb,eAAgB,kBAChB,cAAe,iBACf,UAAW,aACX,UAAW,KACX,KAAM,OACN,WAAY,aACZ,KAAM,OACN,OAAQ,SACR,UAAW,YACX,UAAW,aACX,UAAW,YACX,QAAS,UACT,WAAY,aACZ,WAAY,gBACZ,WAAY,gBACZ,UAAW,aACX,YAAa,eACb,WAAY,cACZ,KAAM,OACN,YAAa,eACb,UAAW,QACX,WAAY,cACZ,OAAQ,gBACR,YAAa,cACb,QAAS,UACT,WAAY,SACZ,SAAU,kBACV,SAAU,YACV,UAAW,aACX,SAAU,oBACV,SAAU,eACV,SAAU,oBACV,UAAW,oBACX,UAAW,YACX,QAAS,SACT,YAAa,qBACb,QAAS,mCACT,aAAc,wBACd,UAAW,iBACX,KAAM,OACN,SAAU,WACV,KAAM,OACN,SAAU,WACV,MAAO,QACP,OAAQ,iBACR,UAAW,mCACX,YAAa,iBACb,aAAc,qCACd,SAAU,YACV,cAAe,oBACf,aAAc,QACd,KAAM,OACN,gBAAiB,mBACjB,YAAa,eACb,OAAQ,kBACR,SAAU,oBACV,QAAS,wCACT,cAAe,iBACf,YAAa,OACb,aAAc,iBACd,cAAe,kBACf,gBAAiB,WACjB,eAAgB,UAChB,MAAO,YACP,WAAY,cACZ,KAAM,cACN,QAAS,iBACT,eAAgB,wBAChB,cAAe,yBACf,WAAY,4BACZ,IAAK,MACL,GAAI,KACJ,KAAM,YACN,UAAW,kBACX,MAAO,eACP,eAAgB,sBAClB,EAQaC,GAA8C,CAAE,GAAAD,GAAI,GAAGE,EAAU,ECvOvE,SAASC,GAAMC,EAA0B,CAC9C,MAAO,CAACC,EAAKC,EAAQ,CAAC,KAAMC,IAAa,CACvC,IAAMC,EAAUJ,EAAS,cAAcC,CAAG,EAC1C,OAAW,CAACI,EAAMC,CAAK,IAAK,OAAO,QAAQJ,CAAK,EAAOI,IAAU,QAAWF,EAAQ,aAAaC,EAAMC,CAAK,EAC5G,OAAAF,EAAQ,OAAO,GAAGD,CAAQ,EACnBC,CACT,CACF,CAGO,IAAMG,GAAW,CAACC,EAAkCC,IAA6CD,GAAUE,GAAcD,GAAU,IAAI,GAAKC,GAAc,GAGpJC,GAAS,CAACC,EAAkBC,IACvCD,EAAS,QAAQ,aAAc,CAACE,EAAOC,IAAiBA,KAAOF,EAAS,OAAOA,EAAOE,CAAG,CAAC,EAAID,CAAM,EAQ/F,SAASE,GAAQZ,EAAkBC,EAAcC,EAA4B,CAC9EF,EAAQ,aAAaC,CAAI,IAAMC,IAC/BA,IAAU,KAAMF,EAAQ,gBAAgBC,CAAI,EAC3CD,EAAQ,aAAaC,EAAMC,CAAK,EACvC,CAGO,SAASW,GAAUb,EAAsBc,EAAuB,CACjEd,EAAQ,SAAWc,IAAQd,EAAQ,OAASc,EAClD,CAGO,SAASC,GAAQf,EAAegB,EAAoB,CACrDhB,EAAQ,cAAgBgB,IAAMhB,EAAQ,YAAcgB,EAC1D,CAGO,SAASC,GAAcjB,EAAsBkB,EAAmD,CACrGN,GAAQZ,EAAS,eAAgB,OAAOkB,EAAM,OAAO,CAAC,EACtDN,GAAQZ,EAAS,mBAAoBkB,EAAM,aAAe,IAAI,CAChE,CAGO,SAASC,GAAUC,EAAY,CACpC,IAAMpB,EAAUoB,EAAK,MAAO,CAAE,MAAO,cAAe,KAAM,SAAU,YAAa,QAAS,CAAC,EAC3F,MAAO,CACL,QAAApB,EACA,IAAIgB,EAAc,CAEhBhB,EAAQ,YAAc,GACtBA,EAAQ,YAAcgB,CACxB,CACF,CACF,CAGO,IAAMK,GAAerB,GAAqBA,EAAQ,QAAQ,OAAO,GAAG,aAAa,KAAK,IAAM,MAM5F,SAASsB,GAAe1B,EAAoB2B,EAAqBC,EAAmB,CACzF,IAAMC,EAAS9B,GAAMC,CAAQ,EAAE,SAAU,CAAE,KAAM,SAAU,MAAO,kBAAmB,OAAQ,EAAG,EAAG2B,EAAM,cAAc,EACvHE,EAAO,iBAAiB,QAASD,CAAK,EACtC,IAAIE,EAAO,GACX,MAAO,CACL,OAAAD,EAEA,MAAMP,EAAoB,CACxBQ,EAAO,CAACR,EAAM,UAAY,CAACA,EAAM,QACnC,EACA,KAAKS,EAAiB,CACpBd,GAAUY,EAAQ,EAAEC,GAAQC,EAAO,CACrC,CACF,CACF,CAOO,SAASC,GAASR,EAAYG,EAAqB,CACxD,IAAMM,EAAWT,EAAK,MAAM,EACtBU,EAAMV,EAAK,SAAU,CAAE,KAAM,SAAU,MAAO,0BAA2B,EAAGG,EAAM,UAAU,EAC5FQ,EAAKX,EAAK,SAAU,CAAE,KAAM,SAAU,MAAO,0BAA2B,EAAGG,EAAM,IAAI,EACrFvB,EAAUoB,EAAK,MAAO,CAAE,MAAO,kBAAmB,OAAQ,EAAG,EAAGS,EAAUC,EAAKC,CAAE,EACnFC,EAAQC,GAAkB,GACxBC,EAAYC,GAAoB,CACpCnC,EAAQ,OAAS,GACjBgC,EAAKG,CAAM,CACb,EACA,OAAAL,EAAI,iBAAiB,QAAS,IAAMI,EAAS,EAAI,CAAC,EAClDH,EAAG,iBAAiB,QAAS,IAAMG,EAAS,EAAK,CAAC,EAClDlC,EAAQ,iBAAiB,UAAYoC,GAAUA,EAAM,MAAQ,UAAYF,EAAS,EAAK,CAAC,EACjF,CACL,QAAAlC,EACA,IAAIgB,EAAcqB,EAAmC,CACnDR,EAAS,YAAcb,EACvBgB,EAAOK,EACPrC,EAAQ,OAAS,GACjB+B,EAAG,MAAM,CACX,CACF,CACF,CC5GA,IAAMO,GAAc,IAEdC,GAAQ,EAEd,SAASC,GAAKC,EAAkBC,EAAgC,CAC9D,OAAOD,EAAS,QAAQ,aAAc,CAACE,EAAOC,IAAiBF,EAAOE,CAAI,GAAKD,CAAK,CACtF,CAeA,SAASE,GAASC,EAeL,CACX,GAAM,CAAE,SAAUC,EAAK,GAAAC,EAAI,OAAAC,CAAO,EAAIH,EAChCI,EAAS,GAAGF,CAAE,QACdG,EAAQJ,EAAI,cAAc,OAAO,EACvC,OAAO,OAAOI,EAAO,CAAE,GAAAH,EAAI,UAAW,0BAA2B,aAAc,KAAM,CAAC,EACtFG,EAAM,aAAa,OAAQ,UAAU,EACrCA,EAAM,aAAa,oBAAqB,MAAM,EAC9CA,EAAM,aAAa,gBAAiB,OAAO,EAC3CA,EAAM,aAAa,gBAAiBD,CAAM,EAC1CC,EAAM,YAAcF,EAAO,OAC3B,IAAMG,EAAOL,EAAI,cAAc,IAAI,EACnCK,EAAK,GAAKF,EACVE,EAAK,UAAY,aACjBA,EAAK,aAAa,OAAQ,SAAS,EACnCA,EAAK,OAAS,GACd,IAAMC,EAAUN,EAAI,cAAc,KAAK,EACvCM,EAAQ,UAAY,WACpBA,EAAQ,OAAOF,EAAOC,CAAI,EAE1B,IAAIE,EAAQ,GAERC,EAAiC,KACjCC,EAAe,GAEfC,EAAS,IAAI,IAEbC,EAAU,GACVC,EAA2B,CAAC,EAC5BC,EAAS,GACTC,EAAM,EACNC,EACAC,EAAW,GAEf,SAASC,GAAS,CAahB,GAZAZ,EAAK,gBAAgB,EACrBO,EAAQ,QAAQ,CAACM,EAAQC,IAAM,CAC7B,IAAMC,EAASpB,EAAI,cAAc,IAAI,EACrCoB,EAAO,GAAK,GAAGjB,CAAM,IAAIgB,CAAC,GAC1BC,EAAO,aAAa,OAAQ,QAAQ,EACpCA,EAAO,aAAa,gBAAiB,OAAOD,IAAMN,CAAM,CAAC,EACzDO,EAAO,UAAY,YAAYD,IAAMN,EAAS,aAAe,EAAE,GAAGK,IAAWV,GAAYE,EAAO,IAAIQ,CAAM,EAAI,oBAAsB,EAAE,GACtIE,EAAO,YAAcF,EAAO,MAC5BE,EAAO,iBAAiB,YAAcC,GAAUA,EAAM,eAAe,CAAC,EACtED,EAAO,iBAAiB,QAAS,IAAME,EAAOH,CAAC,CAAC,EAChDd,EAAK,OAAOe,CAAM,CACpB,CAAC,EACG,CAACR,EAAQ,OAAQ,CACnB,IAAMW,EAAQvB,EAAI,cAAc,IAAI,EACpCuB,EAAM,UAAY,WAClBA,EAAM,YAAcrB,EAAO,UAC3BG,EAAK,OAAOkB,CAAK,CACnB,CACIV,GAAU,EAAGT,EAAM,aAAa,wBAAyB,GAAGD,CAAM,IAAIU,CAAM,EAAE,EAC7ET,EAAM,gBAAgB,uBAAuB,CACpD,CAEA,SAASoB,GAAO,CACdnB,EAAK,OAAS,GACdD,EAAM,aAAa,gBAAiB,MAAM,CAC5C,CAEA,SAASqB,GAAQ,CAEf,aAAaV,CAAK,EAClBD,IACAT,EAAK,OAAS,GACdD,EAAM,aAAa,gBAAiB,OAAO,EAC3CA,EAAM,gBAAgB,uBAAuB,EAC7CS,EAAS,EACX,CAEA,SAASS,EAAOI,EAAe,CAC7B,IAAMR,EAASN,EAAQc,CAAK,EAC5B,GAAI,CAACR,EAAQ,OACb,IAAMS,EAAQlB,EAGd,GAFAgB,EAAM,EACNd,EAAU,GACNO,IAAWV,GAAYT,EAAQ,OAAQ,CACpCA,EAAQ,OAAO4B,CAAK,EAAE,KAAK5B,EAAQ,KAAM,IAAG,EAAY,EAC7D,MACF,CACA,IAAM6B,EAAMlB,EAAO,IAAIQ,CAAM,EAC7B,GAAIU,EAAK,CACFA,EAAID,CAAK,EAAE,KAAME,GAAWA,GAAU9B,EAAQ,KAAK8B,CAAM,EAAG,IAAG,EAAY,EAChF,MACF,CACA9B,EAAQ,KAAKmB,CAAM,CACrB,CAEA,SAASY,EAAOC,EAAe,CAC7B,aAAahB,CAAK,EAClB,IAAMiB,EAAO,EAAElB,EACfC,EAAQ,WAAW,SAAY,CAC7B,IAAMkB,EAAQ,MAAMlC,EAAQ,OAAOgC,CAAK,EAAE,MAAM,IAAM,CAAC,CAAoB,EAC3E,GAAIC,IAASlB,GAAOd,EAAI,gBAAkBI,EAAO,OAEjD,IAAM8B,EAAUtB,EAAQC,CAAM,EACxBsB,EAAOD,GAAWA,IAAY1B,GAAY,CAACE,EAAO,IAAIwB,CAAO,EAAIA,EAAQ,GAAK,OAC9EE,EAASrC,EAAQ,UAAU,GAAK,IAAI,IACpCsC,EAAOJ,EAAM,OAAQf,GAAW,CAACkB,EAAO,IAAIlB,EAAO,EAAE,CAAC,EACtDoB,EAAWvC,EAAQ,QAAU,QAAasC,EAAK,OAAStC,EAAQ,MACtEa,EAAU0B,EAAWD,EAAK,MAAM,EAAGtC,EAAQ,KAAK,EAAIsC,EAEpD,IAAMV,EAAQI,EAAM,KAAK,EACzBvB,EAAW,KACPT,EAAQ,QAAU4B,GAAS,CAACM,EAAM,KAAMf,GAAWA,EAAO,MAAM,KAAK,EAAE,YAAY,IAAMS,EAAM,YAAY,CAAC,IAC9GlB,EAAekB,EACfnB,EAAW,CAAE,GAAI,aAAc,MAAOf,GAAKS,EAAO,YAAa,CAAE,KAAMyB,CAAM,CAAC,CAAE,EAChFf,EAAU,CAAC,GAAGA,EAASJ,CAAQ,GAEjCC,EAAekB,EACfjB,EAAS,IAAI,KAAKX,EAAQ,OAAO4B,EAAOW,CAAQ,GAAK,CAAC,GAAG,IAAI,CAACC,EAAOpB,IAAM,CAAC,CAAE,GAAI,UAAUA,CAAC,KAAM,MAAOoB,EAAM,KAAM,EAAGA,EAAM,GAAG,CAAC,CAAC,EACpI3B,EAAU,CAAC,GAAGA,EAAS,GAAGF,EAAO,KAAK,CAAC,EACvCG,EAASsB,IAAS,OAAY,GAAKvB,EAAQ,UAAWM,GAAWA,EAAO,KAAOiB,CAAI,EACnFlB,EAAO,EACPO,EAAK,CACP,EAAGjC,EAAW,CAChB,CAEA,OAAAa,EAAM,iBAAiB,QAAS,IAAM,CACpCO,EAAU,GACLK,GAAUc,EAAO1B,EAAM,KAAK,CACnC,CAAC,EACDA,EAAM,iBAAiB,QAAS,IAAM,CAC/BY,GAAUc,EAAO,EAAE,CAC1B,CAAC,EACD1B,EAAM,iBAAiB,UAAYiB,GAAU,CAC3C,GAAI,CAAAL,EACJ,OAAQK,EAAM,IAAK,CACjB,IAAK,YACL,IAAK,UAAW,CAEd,GADAA,EAAM,eAAe,EACjBhB,EAAK,OAAQ,OAAOyB,EAAO1B,EAAM,KAAK,EAC1C,GAAI,CAACQ,EAAQ,OAAQ,OACrBC,GAAUA,GAAUQ,EAAM,MAAQ,YAAc,EAAI,IAAMT,EAAQ,QAAUA,EAAQ,OACpFK,EAAO,EACPZ,EAAK,SAASQ,CAAM,GAAG,iBAAiB,CAAE,MAAO,SAAU,CAAC,EAC5D,MACF,CACA,IAAK,QACC,CAACR,EAAK,QAAUQ,GAAU,IAC5BQ,EAAM,eAAe,EACrBC,EAAOT,CAAM,GAEf,OACF,IAAK,SACER,EAAK,QAAQgB,EAAM,eAAe,EACvCI,EAAM,EACNd,EAAU,GACVP,EAAM,MAAQG,EACd,OACF,IAAK,YACCH,EAAM,QAAU,IAAIL,EAAQ,mBAAmB,EACnD,MACJ,CACF,CAAC,EACDK,EAAM,iBAAiB,OAAQ,IAAM,CACnCU,IACA,aAAaC,CAAK,EAClBU,EAAM,EACN,IAAMe,EAAU7B,GAAWP,EAAM,MAAM,KAAK,IAAM,IAAMG,IAAU,GAClEI,EAAU,GACN6B,EAASzC,EAAQ,gBAAgB,EAChCK,EAAM,MAAQG,CACrB,CAAC,EAEM,CACL,QAAAD,EACA,MAAAF,EACA,QAAQqC,EAAM,CACZlC,EAAQkC,EACJ,CAAC9B,GAAWP,EAAM,QAAUqC,IAAMrC,EAAM,MAAQqC,EACtD,EACA,YAAYC,EAAM,CAChB1B,EAAW0B,EACPtC,EAAM,WAAasC,IAAMtC,EAAM,SAAWsC,GAC1CA,GAAMjB,EAAM,CAClB,EACA,MAAAA,CACF,CACF,CAGA,SAASkB,GAAQC,EAAY/C,EAAcgD,EAAyE,CAClH,OAAOA,EAAK,SAAU,SAAc,IAASD,EAAK,UAAU/C,CAAI,EAAK4C,GAASG,EAAK,YAAY/C,EAAM4C,CAAI,EAAI,MAC/G,CAEO,IAAMK,GAAgC,CAAC,CAAE,KAAAF,EAAM,KAAA/C,EAAM,MAAAkD,EAAO,KAAAF,EAAM,GAAA5C,EAAI,SAAA+C,EAAU,OAAA9C,EAAS+C,GAAc,GAAI,QAAAC,CAAQ,IAAM,CAC9H,IAAMC,EAAWJ,EAAM,OAAS,WAAaA,EAAM,SAAW,GACxDK,EAAU,CAAC,CAACF,GAAWA,EAAQ,QAAQC,CAAQ,EACjDnC,EAAW,GACTqC,EAAMvD,GAAS,CACnB,SAAAkD,EACA,GAAA/C,EACA,OAAAC,EAEA,OAAS6B,GAAUa,EAAK,OAAO/C,EAAMkC,EAAOvC,GAAQ,CAAC,EACrD,MAAOA,GACP,KAAO0B,GAAW0B,EAAK,SAAS/C,EAAMqB,CAAM,EAC5C,cAAe,IAAM0B,EAAK,SAAS/C,EAAM,IAAI,EAC7C,OAAQ8C,GAAQC,EAAM/C,EAAMgD,CAAI,EAEhC,KAAM,CAAClB,EAAOW,IAAa,CACzB,GAAI,CAACY,GAAWlC,EAAU,MAAO,CAAC,EAClC,IAAMsC,EAAqF,CAAC,EAC5F,OAAI3B,GAASyB,GAAWP,EAAK,SAAU,SAAc,IACnDS,EAAQ,KAAK,CAAE,MAAOpD,EAAO,cAAe,IAAMuC,GAASS,EAAQ,WAAWC,EAAU,CAAE,KAAMV,EAAM,MAAOM,EAAM,KAAM,CAAC,CAAE,CAAC,EAE3HT,GAAUgB,EAAQ,KAAK,CAAE,MAAOpD,EAAO,WAAY,IAAK,IAAMgD,EAAQ,WAAW,CAAE,MAAOH,EAAM,MAAO,OAAQ,CAAChB,EAAOwB,IAAUX,EAAK,OAAO/C,EAAMkC,EAAOwB,CAAK,CAAE,CAAC,CAAE,CAAC,EAClKD,CACT,CACF,CAAC,EAEK9B,EAAO4B,EAAUJ,EAAS,cAAc,QAAQ,EAAI,KACtDxB,IACFA,EAAK,KAAO,SACZA,EAAK,UAAY,gBACjBA,EAAK,YAAc,SACnBA,EAAK,OAAS,GACdA,EAAK,iBAAiB,QAAS,SAAY,CACzC,IAAMgC,EAAUZ,EAAK,SAAS,EAAE,OAAO/C,CAAI,EAC3C,GAAI,CAAC2D,GAAW,CAACN,EAAS,OAC1B,IAAMO,EAAQ,MAAMP,EAAQ,WAAWC,EAAU,CAAE,SAAUK,EAAQ,GAAI,MAAOA,EAAQ,KAAM,CAAC,EAC3FC,GAASA,EAAM,QAAUD,EAAQ,OAAOZ,EAAK,SAAS/C,EAAM4D,CAAK,CACvE,CAAC,GAEH,IAAMC,EAAQV,EAAS,cAAc,QAAQ,EAC7C,OAAAU,EAAM,KAAO,SACbA,EAAM,UAAY,iBAClBA,EAAM,YAAc,OACpBA,EAAM,aAAa,aAAcjE,GAAKS,EAAO,MAAO,CAAE,MAAO6C,EAAM,KAAM,CAAC,CAAC,EAC3EW,EAAM,iBAAiB,QAAS,IAAM,CACpCd,EAAK,SAAS/C,EAAM,IAAI,EACxBwD,EAAI,MAAM,MAAM,CAClB,CAAC,EACDA,EAAI,QAAQ,OAAOK,EAAO,GAAIlC,EAAO,CAACA,CAAI,EAAI,CAAC,CAAE,EAC1C,CACL,QAAS6B,EAAI,QACb,MAAO,IAAMA,EAAI,MAAM,MAAM,EAC7B,OAAOM,EAAO,CACZ,IAAMzC,EAASyC,EAAM,MACrB3C,EAAW2C,EAAM,SACjBN,EAAI,QAAQnC,GAAQ,OAAS,EAAE,EAC/BmC,EAAI,YAAYM,EAAM,QAAQ,EAC9BC,GAAUF,EAAO,CAACxC,GAAUyC,EAAM,QAAQ,EACtCnC,IACFoC,GAAUpC,EAAM,CAACN,CAAM,EACnBA,GAAQ2C,GAAQrC,EAAM,aAAc/B,GAAKS,EAAO,UAAW,CAAE,KAAMgB,EAAO,KAAM,CAAC,CAAC,GAExF2C,GAAQR,EAAI,MAAO,eAAgB,OAAOM,EAAM,OAAO,CAAC,EACxDE,GAAQR,EAAI,MAAO,gBAAiB,OAAOM,EAAM,QAAQ,CAAC,EACtDA,EAAM,aAAaE,GAAQR,EAAI,MAAO,mBAAoBM,EAAM,WAAW,CACjF,CACF,CACF,EAEaG,GAA4B,CAAC,CAAE,KAAAlB,EAAM,KAAA/C,EAAM,MAAAkD,EAAO,KAAAF,EAAM,GAAA5C,EAAI,SAAA+C,EAAU,OAAA9C,EAAS+C,GAAc,GAAI,QAAAC,CAAQ,IAAM,CAC1H,IAAMC,EAAWJ,EAAM,OAAS,YAAcA,EAAM,SAAW,GACzDS,EAAU,IAAOZ,EAAK,SAAS,EAAE,OAAO/C,CAAI,GAAgC,CAAC,EAC7ES,EAAU0C,EAAS,cAAc,KAAK,EAC5C1C,EAAQ,UAAY,UACpBA,EAAQ,aAAa,OAAQ,OAAO,EACpC,IAAMyD,EAAQf,EAAS,cAAc,IAAI,EACzCe,EAAM,UAAY,WAClB,IAAMV,EAAMvD,GAAS,CACnB,SAAAkD,EACA,GAAA/C,EACA,OAAAC,EAEA,OAAS6B,GAAUa,EAAK,OAAO/C,EAAMkC,EAAOvC,GAAQ,EAAIgE,EAAQ,EAAE,MAAM,EACxE,MAAOhE,GACP,KAAO0B,GAAW,CACXsC,EAAQ,EAAE,KAAMQ,GAAMA,EAAE,KAAO9C,EAAO,EAAE,GAAG0B,EAAK,SAAS/C,EAAM,CAAC,GAAG2D,EAAQ,EAAGtC,CAAM,CAAC,EAC1FmC,EAAI,MAAM,MAAQ,EACpB,EACA,QAAS,IAAM,IAAI,IAAIG,EAAQ,EAAE,IAAKtC,GAAWA,EAAO,EAAE,CAAC,EAC3D,iBAAkB,IAAM,CACtB,IAAM+C,EAAUT,EAAQ,EACpBS,EAAQ,QAAQrB,EAAK,SAAS/C,EAAMoE,EAAQ,MAAM,EAAG,EAAE,CAAC,CAC9D,EACA,OAAQtB,GAAQC,EAAM/C,EAAMgD,CAAI,EAEhC,KAAM,CAACqB,EAAQ5B,IAAcY,GAAWZ,EAAW,CAAC,CAAE,MAAOpC,EAAO,WAAY,IAAK,IAAMgD,EAAQ,WAAW,CAAE,MAAOH,EAAM,MAAO,OAAQ,CAAChB,EAAOwB,IAAUX,EAAK,OAAO/C,EAAMkC,EAAOwB,CAAK,CAAE,CAAC,CAAE,CAAC,EAAI,CAAC,CACzM,CAAC,EAEK/B,EACJ0B,GAAWA,EAAQ,QAAQC,CAAQ,EAC/B,MAAOjC,GAA0B,CAC/B,IAAMuC,EAAQ,MAAMP,EAAQ,WAAWC,EAAU,CAAE,SAAUjC,EAAO,GAAI,MAAOA,EAAO,KAAM,CAAC,EACzFuC,GAASA,EAAM,QAAUvC,EAAO,OAAO0B,EAAK,SAAS/C,EAAM2D,EAAQ,EAAE,IAAKQ,GAAOA,EAAE,KAAO9C,EAAO,GAAKuC,EAAQO,CAAE,CAAC,CACvH,EACA,OACN1D,EAAQ,OAAOyD,EAAOV,EAAI,OAAO,EACjC,IAAIrC,EAAW,GACXmD,EAAQ,GACZ,MAAO,CACL,QAAA7D,EACA,MAAO,IAAM+C,EAAI,MAAM,MAAM,EAC7B,OAAOM,EAAO,CACZ,IAAMM,EAAWN,EAAM,OAAoC,CAAC,EAEtDS,EAAM,KAAK,UAAU,CAACT,EAAM,SAAUM,CAAO,CAAC,EACpDjD,EAAW2C,EAAM,SACjBN,EAAI,YAAYrC,CAAQ,EACxBqC,EAAI,QAAQ,OAASrC,EACrBqC,EAAI,MAAM,aAAa,eAAgB,OAAOM,EAAM,OAAO,CAAC,EACxDA,EAAM,aAAaN,EAAI,MAAM,aAAa,mBAAoBM,EAAM,WAAW,EAC/ES,IAAQD,IACZA,EAAQC,EACRC,GAAUN,EAAOE,EAASjD,EAAUd,EAASgB,GAAW0B,EAAK,SAAS/C,EAAM2D,EAAQ,EAAE,OAAQQ,GAAMA,EAAE,KAAO9C,EAAO,EAAE,CAAC,EAAGM,CAAI,EAC9H6B,EAAI,QAAQ,EAAE,EAChB,CACF,CACF,EAGA,SAASgB,GAAUN,EAAoBE,EAA0BjD,EAAmBd,EAAsBoE,EAAyC9C,EAAwC,CACzL,IAAMxB,EAAM+D,EAAM,cAClBA,EAAM,gBACJ,GAAGE,EAAQ,IAAK/C,GAAW,CACzB,IAAMqD,EAAOvE,EAAI,cAAc,IAAI,EACnCuE,EAAK,UAAY,UACjB,IAAM9B,EAAOzC,EAAI,cAAcwB,EAAO,SAAW,MAAM,EASvD,GARAiB,EAAK,UAAY,gBACjBA,EAAK,YAAcvB,EAAO,MACtBM,IACDiB,EAA2B,KAAO,SACnCA,EAAK,aAAa,aAAchD,GAAKS,EAAO,UAAW,CAAE,KAAMgB,EAAO,KAAM,CAAC,CAAC,EAC9EuB,EAAK,iBAAiB,QAAS,IAAMjB,EAAKN,CAAM,CAAC,GAEnDqD,EAAK,OAAO9B,CAAI,EACZ,CAACzB,EAAU,CACb,IAAMwD,EAASxE,EAAI,cAAc,QAAQ,EACzCwE,EAAO,KAAO,SACdA,EAAO,UAAY,iBACnBA,EAAO,YAAc,OACrBA,EAAO,aAAa,aAAc/E,GAAKS,EAAO,OAAQ,CAAE,KAAMgB,EAAO,KAAM,CAAC,CAAC,EAC7EsD,EAAO,iBAAiB,QAAS,IAAMF,EAAOpD,CAAM,CAAC,EACrDqD,EAAK,OAAOC,CAAM,CACpB,CACA,OAAOD,CACT,CAAC,CACH,CACF,CAQO,IAAME,GAAgC,CAAC,CAAE,KAAA7B,EAAM,KAAA/C,EAAM,KAAAgD,EAAM,GAAA5C,EAAI,SAAA+C,EAAU,OAAA9C,EAAS+C,GAAc,EAAG,IAAM,CAC9G,IAAMlD,EAAU8C,EAAK,SAAW,CAAC,EAC3B6B,EAAY,OAAO3E,EAAQ,WAAiB,UAAYA,EAAQ,UAAeA,EAAQ,UAAe,IACtG4E,EAAc,MAAM,QAAQ5E,EAAQ,WAAc,EAAIA,EAAQ,YAAe,OAAQ6E,GAAmB,OAAOA,GAAM,QAAQ,EAAI,CAAC,EAClIC,EAASpC,GACb,OAAOA,GAAS,SAAWA,EAAK,MAAMiC,CAAS,EAAE,IAAKI,GAAMA,EAAE,KAAK,CAAC,EAAE,OAAQA,GAAMA,IAAM,EAAE,EAAI,CAAC,EAC7FtB,EAAU,IAAMqB,EAAMjC,EAAK,SAAS,EAAE,OAAO/C,CAAI,CAAC,EAClDkF,EAASC,GAAmBpC,EAAK,SAAS/C,EAAMmF,EAAK,OAASA,EAAK,KAAK,GAAGN,CAAS,GAAG,EAAI,IAAI,EAC/FO,EAAOC,GAAgB,CAC3B,IAAMC,EAAMD,EAAI,KAAK,EACfF,EAAOxB,EAAQ,EACjB2B,GAAO,CAACH,EAAK,KAAMF,GAAMA,EAAE,YAAY,IAAMK,EAAI,YAAY,CAAC,GAAK,EAAEH,EAAK,QAAWjF,EAAQ,MAAoBgF,EAAM,CAAC,GAAGC,EAAMG,CAAG,CAAC,CAC3I,EAEM7E,EAAU0C,EAAS,cAAc,KAAK,EAC5C1C,EAAQ,UAAY,UACpBA,EAAQ,aAAa,OAAQ,OAAO,EACpC,IAAMyD,EAAQf,EAAS,cAAc,IAAI,EACzCe,EAAM,UAAY,WAClB,IAAMV,EAAMvD,GAAS,CACnB,SAAAkD,EACA,GAAA/C,EACA,OAAAC,EACA,OAAQ,MAAO6B,GAAU,CACvB,IAAMqD,EAAQ,IAAI,IAAI5B,EAAQ,EAAE,IAAKsB,GAAMA,EAAE,YAAY,CAAC,CAAC,EACrDO,EAAStD,EAAM,KAAK,EAAE,YAAY,EACxC,OAAO4C,EACJ,OAAQC,GAAM,CAACQ,EAAM,IAAIR,EAAE,YAAY,CAAC,GAAKA,EAAE,YAAY,EAAE,SAASS,CAAM,CAAC,EAC7E,IAAKT,IAAO,CAAE,GAAIA,EAAG,MAAOA,CAAE,EAAE,CACrC,EACA,KAAO1D,GAAW,CAChB+D,EAAI/D,EAAO,KAAK,EAChBmC,EAAI,MAAM,MAAQ,EACpB,EACA,iBAAkB,IAAM,CACtB,IAAM2B,EAAOxB,EAAQ,EACjBwB,EAAK,QAAQD,EAAMC,EAAK,MAAM,EAAG,EAAE,CAAC,CAC1C,CACF,CAAC,EAED3B,EAAI,MAAM,iBAAiB,UAAYhC,GAAU,CAC3CA,EAAM,MAAQ,SAAWA,EAAM,kBAAoBgC,EAAI,MAAM,MAAM,KAAK,IAAM,KAClFhC,EAAM,eAAe,EACrB4D,EAAI5B,EAAI,MAAM,KAAK,EACnBA,EAAI,MAAM,MAAQ,GAClBA,EAAI,MAAM,EACZ,CAAC,EAEDA,EAAI,MAAM,iBAAiB,QAAS,IAAM,CACxC,IAAMiC,EAAQjC,EAAI,MAAM,MAAM,MAAMqB,CAAS,EAC7C,GAAI,EAAAY,EAAM,OAAS,GACnB,SAAWC,KAAQD,EAAM,MAAM,EAAG,EAAE,EAAGL,EAAIM,CAAI,EAC/ClC,EAAI,MAAM,MAAQiC,EAAMA,EAAM,OAAS,CAAC,EAAE,UAAU,EACtD,CAAC,EAEDjC,EAAI,MAAM,iBAAiB,SAAU,IAAM,CACrCA,EAAI,MAAM,MAAM,KAAK,GAAG4B,EAAI5B,EAAI,MAAM,KAAK,CACjD,CAAC,EACD/C,EAAQ,OAAOyD,EAAOV,EAAI,OAAO,EACjC,IAAIc,EAAQ,GACZ,MAAO,CACL,QAAA7D,EACA,MAAO,IAAM+C,EAAI,MAAM,MAAM,EAC7B,OAAOM,EAAO,CACZ,IAAMqB,EAAOH,EAAMlB,EAAM,KAAK,EAC9BN,EAAI,YAAYM,EAAM,QAAQ,EAC9BN,EAAI,QAAQ,OAASM,EAAM,UAAYqB,EAAK,QAAWjF,EAAQ,IAC/DsD,EAAI,MAAM,aAAa,eAAgB,OAAOM,EAAM,OAAO,CAAC,EACxDA,EAAM,aAAaN,EAAI,MAAM,aAAa,mBAAoBM,EAAM,WAAW,EACnF,IAAMS,EAAM,KAAK,UAAU,CAACT,EAAM,SAAUqB,CAAI,CAAC,EACjD,GAAIZ,IAAQD,EAAO,OACnBA,EAAQC,EACR,IAAMoB,EAASxC,EAAS,gBAAkBK,EAAI,MAC9CgB,GAAUN,EAAOiB,EAAK,IAAKF,IAAO,CAAE,GAAIA,EAAG,MAAOA,CAAE,EAAE,EAAGnB,EAAM,SAAUzD,EAASgB,GAAW6D,EAAMvB,EAAQ,EAAE,OAAQsB,GAAMA,IAAM5D,EAAO,KAAK,CAAC,CAAC,EAC/ImC,EAAI,QAAQ,EAAE,EAEVmC,GAAUnC,EAAI,QAAQ,QAAQU,EAAM,cAAiC,sBAAsB,GAAG,MAAM,CAC1G,CACF,CACF,EAGa0B,GAAsC,CAAC,CAAE,KAAA7C,EAAM,KAAA/C,EAAM,GAAAI,EAAI,SAAA+C,CAAS,IAAM,CACnF,IAAM1C,EAAU0C,EAAS,cAAc,KAAK,EAC5C1C,EAAQ,GAAKL,EACbK,EAAQ,UAAY,iCACpBA,EAAQ,aAAa,OAAQ,OAAO,EACpC,IAAIoF,EAA4D,CAAC,EAC7DC,EAAS,CAAE,SAAU,GAAO,MAAO,CAAC,CAAqB,EAEvDC,EAAO,IAAM,CACjB,IAAMC,EAAS,IAAI,IAAIF,EAAO,MAAM,IAAK3B,GAAMA,EAAE,EAAE,CAAC,EACpD,OAAW,CAAE,OAAA9C,EAAQ,IAAAmC,CAAI,IAAKqC,EAC5BrC,EAAI,QAAUwC,EAAO,IAAI3E,EAAO,EAAE,EAClCmC,EAAI,SAAWsC,EAAO,QAE1B,EACA,OAAK/C,EAAK,OAAO/C,EAAM,GAAI,EAAE,EAAE,KAAMoE,GAAY,CAC/CyB,EAAQzB,EAAQ,IAAI,CAAC/C,EAAQC,IAAM,CACjC,IAAMkC,EAAML,EAAS,cAAc,OAAO,EAC1CK,EAAI,KAAO,WACXA,EAAI,GAAK,GAAGpD,CAAE,IAAIkB,CAAC,GACnBkC,EAAI,iBAAiB,SAAU,IAAM,CACnC,IAAMyC,EAAOlD,EAAK,SAAS,EAAE,OAAO/C,CAAI,GAAgC,CAAC,EACzE+C,EAAK,SAAS/C,EAAMwD,EAAI,QAAU,CAAC,GAAGyC,EAAK5E,CAAM,EAAI4E,EAAI,OAAQ9B,GAAMA,EAAE,KAAO9C,EAAO,EAAE,CAAC,CAC5F,CAAC,EACD,IAAM6E,EAAQ/C,EAAS,cAAc,OAAO,EAC5C+C,EAAM,UAAY,YAClBA,EAAM,QAAU1C,EAAI,GACpB,IAAMZ,EAAOO,EAAS,cAAc,MAAM,EAC1C,OAAAP,EAAK,YAAcvB,EAAO,MAC1B6E,EAAM,OAAO1C,EAAKZ,CAAI,EACtBnC,EAAQ,OAAOyF,CAAK,EACb,CAAE,OAAA7E,EAAQ,IAAAmC,CAAI,CACvB,CAAC,EACDuC,EAAK,CACP,CAAC,EACM,CACL,QAAAtF,EACA,MAAO,IAAMA,EAAQ,cAAc,OAAO,GAAG,MAAM,EACnD,OAAOqD,EAAO,CACZgC,EAAS,CAAE,SAAUhC,EAAM,SAAU,MAAQA,EAAM,OAAoC,CAAC,CAAE,EAC1FiC,EAAK,CACP,CACF,CACF,EAEaI,GAAkCC,GAA2B,CACxE,GAAM,CAAE,KAAArD,EAAM,KAAA/C,EAAM,MAAAkD,EAAO,GAAA9C,EAAI,SAAA+C,EAAU,OAAA9C,EAAS+C,GAAc,EAAG,EAAIgD,EACjEC,EAASnD,EAAM,OAAS,YAAcA,EAAM,OAAS,CAAC,EACtDzC,EAAU0C,EAAS,cAAc,KAAK,EAC5C1C,EAAQ,UAAY,eACpB,IAAM6F,EAASnD,EAAS,cAAc,QAAQ,EAC9CmD,EAAO,UAAY,qBACnBA,EAAO,aAAa,aAAcpD,EAAM,KAAK,EAC7CoD,EAAO,OAAOnD,EAAS,cAAc,QAAQ,CAAC,EAC9C,QAAWoD,KAASF,EAAQ,CAC1B,IAAM9E,EAAS4B,EAAS,cAAc,QAAQ,EAC9C5B,EAAO,MAAQ,OAAOgF,EAAM,KAAK,EACjChF,EAAO,YAAcgF,EAAM,MAC3BD,EAAO,OAAO/E,CAAM,CACtB,CACA,IAAIgF,EAAQ,GACZD,EAAO,iBAAiB,SAAU,IAAM,CACtCC,EAAQD,EAAO,MACfvD,EAAK,SAAS/C,EAAM,IAAI,CAC1B,CAAC,EACD,IAAMwD,EAAMvD,GAAS,CACnB,SAAAkD,EACA,GAAA/C,EACA,OAAAC,EACA,OAAS6B,GAAWqE,EAAQxD,EAAK,OAAO/C,EAAMkC,EAAO,EAAG,CAAE,MAAAqE,CAAM,CAAC,EAAI,QAAQ,QAAQ,CAAC,CAAC,EACvF,KAAOlF,GAAW0B,EAAK,SAAS/C,EAAM,CAAE,MAAAuG,EAAO,GAAIlF,EAAO,GAAI,MAAOA,EAAO,KAAM,CAAC,EACnF,cAAe,IAAM0B,EAAK,SAAS/C,EAAM,IAAI,CAC/C,CAAC,EACD,OAAAS,EAAQ,OAAO6F,EAAQ9C,EAAI,OAAO,EAC3B,CACL,QAAA/C,EACA,MAAO,IAAO8F,EAAQ/C,EAAI,MAAM,MAAM,EAAI8C,EAAO,MAAM,EACvD,OAAOxC,EAAO,CACZ,IAAM0C,EAAQ1C,EAAM,MAChB0C,IAAOD,EAAQC,EAAM,OACzBF,EAAO,MAAQC,EACfD,EAAO,SAAWxC,EAAM,SACxBN,EAAI,QAAQgD,GAAO,OAAS,EAAE,EAC9BhD,EAAI,YAAYM,EAAM,UAAY,CAACyC,CAAK,CAC1C,CACF,CACF,ECljBA,SAASE,GAAUC,EAA2B,CAC5C,IAAMC,EAAQ,mDAAmD,KAAKD,CAAI,EAC1E,GAAI,CAACC,EAAO,OAAO,KACnB,GAAM,CAAC,CAAEC,EAAGC,EAAGC,EAAGC,EAAIC,CAAE,EAAIL,EAC5B,OAAO,IAAI,KAAK,OAAOC,CAAC,EAAG,OAAOC,CAAC,EAAI,EAAG,OAAOC,CAAC,EAAG,OAAOC,GAAM,CAAC,EAAG,OAAOC,GAAM,CAAC,CAAC,CACvF,CAMO,SAASC,GAAaC,EAAgBC,EAA0BC,EAAgC,CAAC,EAAGC,EAAiB,KAAc,CACxI,IAAMC,EAAS,CAACC,EAAWC,IAAmBC,GAAaF,EAAGC,EAAQH,CAAM,EAC5E,GAAIF,GAAU,MAA+BA,IAAU,GAAI,MAAO,GAClE,OAAQD,EAAI,KAAM,CAChB,IAAK,WACL,IAAK,YACH,OAAQC,EAA6B,OAAS,GAChD,IAAK,YACH,OAASA,GAAiC,CAAC,GAAG,IAAKO,GAAMA,EAAE,KAAK,EAAE,KAAK,IAAI,EAC7E,IAAK,YAAa,CAChB,IAAMC,EAASC,GAAeV,EAAI,QAAQ,KAAMW,GAAMA,EAAE,QAAUD,CAAC,GAAG,OAAS,OAAOA,CAAC,EACvF,OAAO,MAAM,QAAQT,CAAK,EAAIA,EAAM,IAAIQ,CAAK,EAAE,KAAK,IAAI,EAAIA,EAAMR,CAAK,CACzE,CACA,IAAK,UACH,OAAOG,EAAO,OAAOH,CAAK,EAAG,CAAC,EAChC,IAAK,QACH,OAAOG,EAAO,OAAOH,CAAK,EAAGD,EAAI,SAAS,CAAC,GAAK,CAAC,EACnD,IAAK,WAAY,CACf,IAAMY,EAAWZ,EAAI,WAAaA,EAAI,cAAiBE,EAAOF,EAAI,aAAa,GAAiC,MAAQ,QAExH,OAAOY,EAAWC,GAAY,OAAOZ,CAAK,EAAGW,EAAUZ,EAAI,SAAS,CAAC,GAAK,EAAGG,CAAM,EAAIC,EAAO,OAAOH,CAAK,EAAGD,EAAI,SAAS,CAAC,GAAK,CAAC,CACnI,CACA,IAAK,OAAQ,CACX,IAAMc,EAAOvB,GAAU,OAAOU,CAAK,CAAC,EACpC,OAAOa,EAAO,IAAI,KAAK,eAAeX,IAAW,KAAO,QAAUA,EAAQ,CAAE,IAAK,UAAW,MAAO,QAAS,KAAM,UAAW,gBAAiB,MAAO,CAAC,EAAE,OAAOW,CAAI,EAAI,OAAOb,CAAK,CACrL,CACA,IAAK,WAAY,CACf,IAAMa,EAAOvB,GAAU,OAAOU,CAAK,CAAC,EACpC,OAAOa,EACH,IAAI,KAAK,eAAeX,IAAW,KAAO,QAAUA,EAAQ,CAAE,IAAK,UAAW,MAAO,QAAS,KAAM,UAAW,KAAM,UAAW,OAAQ,UAAW,gBAAiB,MAAO,CAAC,EAAE,OAAOW,CAAI,EACzL,OAAOb,CAAK,CAClB,CACA,IAAK,OACH,OAAO,OAAOA,CAAK,EAAE,QAAQ,WAAY,GAAG,EAAE,QAAQ,OAAQ,GAAG,EAAE,KAAK,EAC1E,IAAK,SACL,IAAK,QAEH,MAAO,CAACA,CAAK,EAAE,KAAK,EAAE,IAAKc,GAAUA,EAA2B,MAAQ,EAAE,EAAE,KAAK,IAAI,EACvF,IAAK,UACH,OAAOd,EAAQ,SAAM,GACvB,QACE,OAAO,OAAOA,CAAK,CACvB,CACF,CClDO,SAASe,GAAWC,EAAYC,EAAcC,EAAcC,EAAaC,EAAkB,CAChG,GAAIF,EAAM,OAAS,YAAcA,EAAM,cAAe,OAAOF,EAAK,SAASC,EAAME,EAAKC,CAAE,EACxF,IAAMC,EAAQ,CAAC,GAAKL,EAAK,SAAS,EAAE,OAAOC,CAAI,GAAuB,CAAC,CAAE,EACnEK,EAAOD,EAAM,UAAWE,GAASA,EAAK,MAAQJ,CAAG,EACnDG,EAAO,GAAKF,EAAK,GAAKA,GAAMC,EAAM,QAAUD,IAAOE,IACvDD,EAAM,OAAOD,EAAI,EAAG,GAAGC,EAAM,OAAOC,EAAM,CAAC,CAAC,EAC5CN,EAAK,SAASC,EAAMI,CAAK,EAC3B,CCeA,IAAMG,GAASC,GAAoB,OAAOA,GAAU,UAAY,OAAO,UAAUA,CAAK,GAAKA,GAAS,EAAIA,EAAQ,OAGzG,SAASC,GAAcC,EAAgBC,EAAqC,CACjF,OAAOA,IAAS,UAAa,CAAE,GAAGD,EAAK,KAAM,MAAO,EAAmB,CAAE,GAAGA,EAAK,KAAM,MAAO,CAChG,CAGO,SAASE,GAASC,EAAYC,EAAeC,EAAmB,CACrE,IAAMC,EAAS,KAASH,EAAK,SAAS,EAAE,OAAOC,CAAK,GAAuB,CAAC,GAAG,KAAMG,GAAMA,EAAE,MAAQF,CAAG,GAAG,QAAU,CAAC,EACtH,MAAO,CACL,GAAGF,EACH,SAAU,KAAkB,CAAE,GAAGA,EAAK,SAAS,EAAG,OAAQG,EAAO,CAAE,GACnE,SAAU,CAACE,EAAcV,IAAiBK,EAAK,WAAWC,EAAOC,EAAKG,EAAMV,CAAK,EACjF,OAAQ,CAACU,EAAcC,EAAeC,IAAmBP,EAAK,WAAWC,EAAOC,EAAKG,EAAMC,EAAOC,CAAK,EACvG,UAAYF,GAAiBL,EAAK,cAAcC,EAAOI,CAAI,EAC3D,YAAa,CAACA,EAAcG,IAAiBR,EAAK,gBAAgBC,EAAOI,EAAMG,CAAI,CACrF,CACF,CAEO,IAAMC,GAA6B,CAAC,CAAE,KAAAT,EAAM,KAAAK,EAAM,MAAAJ,EAAO,KAAAS,EAAM,GAAAC,EAAI,SAAAC,EAAU,OAAAC,EAASC,GAAc,GAAI,OAAAC,EAAQ,QAAAC,CAAQ,IAAM,CACnI,IAAMnB,EAAMI,EACNgB,EAAQpB,EAAI,UACZqB,EAAOC,GAAMP,CAAQ,EACrBQ,EAAUV,EAAK,SAAW,CAAC,EAC3BW,EAAM3B,GAAM0B,EAAQ,GAAM,GAAK,EAC/BE,EAAM5B,GAAM0B,EAAQ,GAAM,GAAK,IAC/BG,EAASrB,GAAiB,OAAOkB,EAAQlB,CAAG,GAAM,UAAakB,EAAQlB,CAAG,EAAa,KAAK,EAAKkB,EAAQlB,CAAG,EAAe,KAG3HsB,GAAWd,EAAK,SAAW,OAAO,KAAKb,EAAI,MAAM,GAAG,OACvD4B,GAAW5B,EAAI,OAAO4B,CAAM,GAAKA,IAAWR,GAAO,OAASQ,IAAW5B,EAAI,eAAiBa,EAAK,kBAAkBe,CAAM,IAAM,MAClI,EACMC,EAAUd,EAAS,cAAc,KAAK,EAC5Cc,EAAQ,UAAY,WACpBA,EAAQ,GAAKf,EACbe,EAAQ,aAAa,OAAQ,OAAO,EACpC,IAAMC,EAAWf,EAAS,cAAc,KAAK,EAC7Ce,EAAS,UAAY,kBACrB,IAAMC,EAAQhB,EAAS,cAAc,OAAO,EAC5CgB,EAAM,UAAY,iBAClB,IAAMC,EAAOjB,EAAS,cAAc,OAAO,EACrCkB,EAAUlB,EAAS,cAAc,IAAI,EAC3CkB,EAAQ,OAAOZ,EAAK,KAAM,CAAE,MAAO,eAAgB,CAAC,CAAC,EACrD,QAAWO,KAAUD,EAAS,CAC5B,IAAMO,EAAKnB,EAAS,cAAc,IAAI,EACtCmB,EAAG,MAAQ,MACXA,EAAG,YAAclC,EAAI,OAAO4B,CAAM,EAAE,MACpCK,EAAQ,OAAOC,CAAE,CACnB,CACA,IAAMC,EAASpB,EAAS,cAAc,IAAI,EAC1CoB,EAAO,UAAY,iBACnBF,EAAQ,OAAOE,CAAM,EACrBH,EAAK,OAAOC,CAAO,EACnB,IAAMG,EAAOrB,EAAS,cAAc,OAAO,EAC3CgB,EAAM,OAAOC,EAAMI,CAAI,EAEvB,IAAMC,GAAUxB,EAAK,QAAU,CAAC,GAAG,OAAQe,GAAWD,EAAQ,SAASC,CAAM,CAAC,EACxEU,EAAO,IAAI,IACjB,GAAID,EAAO,OAAQ,CACjB,IAAME,EAAOxB,EAAS,cAAc,OAAO,EACrCyB,EAAMzB,EAAS,cAAc,IAAI,EACvCyB,EAAI,UAAY,kBAChBA,EAAI,OAAOzB,EAAS,cAAc,IAAI,CAAC,EACvCY,EAAQ,QAAQ,CAACC,EAAQa,IAAM,CAC7B,IAAMC,EAAK3B,EAAS,cAAc,IAAI,EAClCsB,EAAO,SAAST,CAAM,EAAGU,EAAK,IAAIV,EAAQc,CAAE,EACvCD,IAAM,IAAGC,EAAG,YAAc1B,EAAO,OAC1CwB,EAAI,OAAOE,CAAE,CACf,CAAC,EACDF,EAAI,OAAOzB,EAAS,cAAc,IAAI,CAAC,EACvCwB,EAAK,OAAOC,CAAG,EACfT,EAAM,OAAOQ,CAAI,CACnB,CACAT,EAAS,OAAOC,CAAK,EACrB,IAAMY,EAAO5B,EAAS,cAAc,KAAK,EACzC4B,EAAK,UAAY,gBACjB,IAAMC,EAAY,CAACjC,EAAcL,EAA+BL,IAAiB,CAC/E,IAAM4C,EAAS9B,EAAS,cAAc,QAAQ,EAC9C8B,EAAO,KAAO,SACdA,EAAO,UAAY,wCACnBA,EAAO,QAAQ,IAAS5C,EACxB4C,EAAO,YAAc,KAAKlC,CAAI,GAC9BkC,EAAO,iBAAiB,QAAS,IAAM,CACrCC,EAAW3C,EAAK,QAAQK,EAAMF,CAAM,EACpC,IAAMkC,EAAMO,EAAK,IAAID,CAAQ,EACzBN,IACFA,EAAI,MAAM,CAAC,GAAG,OAAO,MAAM,EAC3BM,EAAW,KAEf,CAAC,EACDH,EAAK,OAAOE,CAAM,CACpB,EACAD,EAAUlB,EAAM,UAAU,GAAKV,EAAO,QAAS,CAAC,EAAG,MAAM,EACrDI,IACFwB,EAAU5B,EAAO,WAAY,CAAE,CAACI,EAAM,KAAK,EAAGA,EAAM,SAAW,SAAU,EAAG,SAAS,EACrFwB,EAAU5B,EAAO,QAAS,CAAE,CAACI,EAAM,KAAK,EAAGA,EAAM,MAAQ,MAAO,EAAG,MAAM,GAE3E,IAAM4B,EAAatB,EAAM,YAAY,EAC/BuB,EAAQD,EAAa3B,EAAK,MAAO,CAAE,MAAO,wBAAyB,EAAG2B,CAAU,EAAI,KAEpFE,EAAUC,GAAS9B,EAAML,CAAM,EAE/BoC,EAAQ/B,EAAK,MAAO,CAAE,MAAO,aAAc,KAAM,QAAS,CAAC,EACjEQ,EAAQ,OAAOC,EAAU,GAAImB,EAAQ,CAACA,CAAK,EAAI,CAAC,EAAIN,EAAMO,EAAQ,QAASE,CAAK,EAEhF,IAAML,EAAO,IAAI,IACbD,EAA0B,KAC1BO,EAAW,GACTC,EAAU,IAAOnD,EAAK,SAAS,EAAE,OAAOK,CAAI,GAAuB,CAAC,EAE1E,QAAS+C,EAAOD,EAAQ,EAAE,OAAQC,EAAO/B,EAAK+B,IAAQpD,EAAK,QAAQK,CAAI,EAGvE,SAASgD,EAAKnD,EAAaoD,EAAY,CACrC,IAAMC,EAAOJ,EAAQ,EAAE,UAAWK,IAASA,GAAK,MAAQtD,CAAG,EAC3D,GAAIgD,GAAYI,IAAOC,GAAQD,EAAK,GAAKA,GAAMH,EAAQ,EAAE,OAAQ,OACjE,IAAMM,EAAU7C,EAAS,cAEnB8C,EAAQP,EAAQ,EAAEI,CAAI,EAAE,OAAO/B,EAAQ,CAAC,CAAC,EAC/CmC,GAAW3D,EAAMK,EAAMR,EAAKK,EAAKoD,CAAE,EAC/BG,GAAWA,IAAY7C,EAAS,eAAe6C,EAAQ,MAAM,EACjER,EAAM,YAAcW,GAAO/C,EAAO,QAAS,CAAE,MAAO,OAAO6C,GAAU,UAAYA,EAAM,KAAK,EAAIA,EAAQE,GAAO/C,EAAO,MAAO,CAAE,EAAG0C,EAAO,CAAE,CAAC,EAAG,EAAGD,EAAK,EAAG,MAAOH,EAAQ,EAAE,MAAO,CAAC,CACrL,CACAlB,EAAK,iBAAiB,UAAY4B,GAAU,CAC1C,IAAM3D,EAAO2D,EAAM,OAAmB,QAAQ,IAAI,GAAG,QAAQ,KACzD,CAAC3D,GAAO,CAAC2D,EAAM,QAAWA,EAAM,MAAQ,WAAaA,EAAM,MAAQ,cACvEA,EAAM,eAAe,EACrBR,EAAKnD,EAAKiD,EAAQ,EAAE,UAAWK,GAASA,EAAK,MAAQtD,CAAG,GAAK2D,EAAM,MAAQ,UAAY,GAAK,EAAE,EAChG,CAAC,EACD,SAASC,EAASC,EAAyBP,EAAY/B,EAAgBuC,EAAgBC,EAAO,EAAG,CAC/F,IAAMC,GAAS,GAAGvD,CAAE,IAAI6C,EAAK,GAAG,IAAI/B,CAAM,GACpC0C,GAAqB,CAAE,KAAM,QAAS,GAAI,GAAGzD,EAAK,EAAE,IAAI8C,EAAK,GAAG,IAAI/B,CAAM,GAAI,MAAOA,CAAO,EAC5F2C,GAASC,GAAa,CAAE,KAAMtE,GAASC,EAAMK,EAAMmD,EAAK,GAAG,EAAG,KAAM/B,EAAQ,MAAOuC,EAAc,KAAMG,GAAS,GAAID,GAAQ,SAAAtD,EAAU,OAAAC,EAAQ,OAAAE,EAAQ,QAAAC,CAAQ,CAAC,EAC/JuB,GAAK3B,EAAS,cAAc,IAAI,EACtC2B,GAAG,QAAU0B,EACb,IAAMK,EAAQ1D,EAAS,cAAc,OAAO,EAC5C0D,EAAM,UAAY,aAClBA,EAAM,QAAUJ,GAChBI,EAAM,YAAcN,EAAI,MACxB,IAAMO,GAAQ3D,EAAS,cAAc,KAAK,EAC1C,OAAA2D,GAAM,UAAY,gBAClBA,GAAM,OAAS,GACfhC,GAAG,OAAO+B,EAAOF,GAAO,QAASG,EAAK,EACtCR,EAAG,OAAOxB,EAAE,EACL,CAAE,KAAMd,EAAQ,IAAKuC,EAAK,OAAAI,GAAQ,MAAAG,EAAM,CACjD,CAEA,SAASC,EAAQhB,EAAiB,CAChC,IAAMO,EAAKnD,EAAS,cAAc,IAAI,EACtCmD,EAAG,QAAQ,KAAUP,EAAK,IAC1B,IAAM1D,EAAO2E,GAAS5E,EAAK2D,EAAK,MAAM,EAClC1D,IAAMiE,EAAG,UAAY,WAAWjE,CAAI,IAExC,IAAM4E,EAAOxD,EAAK,OAAQ,CAAE,MAAO,4BAA6B,cAAe,MAAO,CAAC,EACnFyD,EAAW,GACfD,EAAK,iBAAiB,cAAgBb,IAAU,CAC1CX,GAAYW,GAAM,SAAW,IACjCA,GAAM,eAAe,EACrBa,EAAK,oBAAoBb,GAAM,SAAS,EACxCc,EAAW,GACb,CAAC,EACDD,EAAK,iBAAiB,cAAgBb,IAAU,CACzCc,GAELtB,EAAKG,EAAK,IAAK,CAAC,GAAGvB,EAAK,QAAQ,EAAE,OAAQI,GAAQA,IAAQ0B,GAAM1B,EAAI,sBAAsB,EAAE,IAAMA,EAAI,sBAAsB,EAAE,OAAS,EAAIwB,GAAM,OAAO,EAAE,MAAM,CAClK,CAAC,EACD,QAAWe,KAAO,CAAC,YAAa,eAAe,EAAGF,EAAK,iBAAiBE,GAAK,IAAOD,EAAW,EAAM,EACrGZ,EAAG,OAAO7C,EAAK,KAAM,CAAE,MAAO,eAAgB,EAAGwD,CAAI,CAAC,EACtD,IAAMG,GACJ/E,GAAQmB,EACJ,CAAC6C,EAASC,EAAIP,EAAMvC,EAAM,KAAMrB,GAAcC,EAAI,OAAOoB,EAAM,IAAI,EAAGnB,CAAI,EAAG0B,EAAQ,MAAM,CAAC,EAC5FA,EAAQ,IAAKC,IAAWqC,EAASC,EAAIP,EAAM/B,GAAQ5B,EAAI,OAAO4B,EAAM,CAAC,CAAC,EACtEqD,GAAQlE,EAAS,cAAc,IAAI,EACzCkE,GAAM,UAAY,iBAClB,IAAMC,GAASnE,EAAS,cAAc,QAAQ,EAC9C,OAAAmE,GAAO,KAAO,SACdA,GAAO,UAAY,iBACnBA,GAAO,YAAc,OACrBA,GAAO,aAAa,aAAclE,EAAO,UAAU,EACnDkE,GAAO,iBAAiB,QAAS,IAAM,CACrC,IAAMC,GAAK7B,EAAQ,EAAE,UAAW/C,IAAMA,GAAE,MAAQoD,EAAK,GAAG,EAClDrD,EAASgD,EAAQ,EAAE6B,EAAE,GAAG,QAAU,CAAC,EACzC,GAAI5D,EAAQ,gBAAqB,IAAQyD,GAAM,MAAOI,IAASC,GAAQD,GAAK,IAAK9E,EAAO8E,GAAK,IAAI,CAAC,GAAK9E,EAAO8E,GAAK,IAAI,IAAM,EAAK,EAAG,OAAOjF,EAAK,WAAWK,EAAMmD,EAAK,GAAG,EAC1KT,EAAQ,IAAIa,GAAO/C,EAAO,UAAW,CAAE,KAAM+C,GAAO/C,EAAO,MAAO,CAAE,EAAGmE,GAAK,CAAE,CAAC,CAAE,CAAC,EAAIG,IAAS,CACzFA,IAAMnF,EAAK,WAAWK,EAAMmD,EAAK,GAAG,EAExC,IAAM4B,GAAOjC,EAAQ,EACfkC,GAAOD,GAAKD,GAAO,KAAK,IAAIH,GAAII,GAAK,OAAS,CAAC,EAAIJ,EAAE,GAC1DK,GAAOzC,EAAK,IAAIyC,GAAK,GAAG,GAAG,OAAS7C,EAAK,cAAc,QAAQ,IAAI,MAAM,CAC5E,CAAC,CACH,CAAC,EACDsC,GAAM,OAAOC,EAAM,EACnBhB,EAAG,OAAOe,EAAK,EACR,CAAE,QAASf,EAAI,KAAAjE,EAAM,MAAA+E,GAAO,OAAAE,GAAQ,KAAAL,CAAK,CAClD,CAEA,MAAO,CACL,QAAAhD,EACA,MAAO,KAAOO,EAAK,cAA2B,yBAAyB,GAAKO,EAAK,cAAc,QAAQ,IAAI,MAAM,EACjH,OAAO8C,EAAO,CACZpC,EAAWoC,EAAM,SACjB,IAAMnC,EAAWmC,EAAM,OAA2B,CAAC,EACnD9C,EAAK,OAASU,GAAYC,EAAQ,QAAU7B,EACxC4B,IAAUH,EAAQ,QAAQ,OAAS,IACnCD,IAAOA,EAAM,OAASK,EAAQ,OAAS,GAC3C,IAAMoC,EAASvF,EAAK,SAAS,EAAE,OACzBwF,EAAO,IAAI,IAAIrC,EAAQ,IAAKK,GAASA,EAAK,GAAG,CAAC,EACpD,OAAW,CAACtD,EAAKmC,EAAG,IAAKO,EAClB4C,EAAK,IAAItF,CAAG,IACfmC,GAAI,QAAQ,OAAO,EACnBO,EAAK,OAAO1C,CAAG,GAGnBiD,EAAQ,QAAQ,CAACK,EAAMiC,KAAU,CAC/B,IAAIpD,GAAMO,EAAK,IAAIY,EAAK,GAAG,EAEvBnB,IAAOA,GAAI,OAASoC,GAAS5E,EAAK2D,EAAK,MAAM,IAC/CnB,GAAI,QAAQ,OAAO,EACnBA,GAAM,QAEHA,KACHA,GAAMmC,EAAQhB,CAAI,EAClBZ,EAAK,IAAIY,EAAK,IAAKnB,EAAG,GAEpBJ,EAAK,SAASwD,EAAK,IAAMpD,GAAI,SAASJ,EAAK,aAAaI,GAAI,QAASJ,EAAK,SAASwD,EAAK,GAAK,IAAI,EACrGpD,GAAI,OAAO,OAASa,GAAYC,EAAQ,QAAU9B,EAClDgB,GAAI,KAAK,OAASa,EACdA,EAAUb,GAAI,OAAO,OAAO,EACtBA,GAAI,OAAO,aAAaA,GAAI,QAAQ,kBAAkB,OAAOA,GAAI,MAAM,EACjF,QAAW4C,MAAQ5C,GAAI,MAAO,CAC5B,IAAMqD,GAAUH,EAAO,GAAGlF,CAAI,IAAImD,EAAK,GAAG,IAAIyB,GAAK,IAAI,EAAE,EACzDA,GAAK,MAAM,OAAS,CAACS,GACrBT,GAAK,MAAM,YAAcS,IAAW,GACpCT,GAAK,OAAO,OAAO,CACjB,MAAOzB,EAAK,OAAOyB,GAAK,IAAI,EAC5B,OAAQzB,EAAK,OAEb,SAAUN,GAAY+B,GAAK,IAAI,WAAa,IAAQA,GAAK,IAAI,UAAY,OACzE,SAAUA,GAAK,IAAI,WAAa,GAChC,QAAS,CAAC,CAACS,EACb,CAAC,CACH,CACF,CAAC,EACD,OAAW,CAACjE,EAAQc,EAAE,IAAKJ,EAAM,CAC/B,IAAMwD,GAAMxC,EAAQ,OAAQK,IAAS,CAACiB,GAAS5E,EAAK2D,GAAK,MAAM,CAAC,EAAE,OAAO,CAACoC,GAAOpC,KAASoC,GAAQ,OAAOpC,GAAK,OAAO/B,CAAM,GAAK,CAAC,EAAG,CAAC,EACrIc,GAAG,YAAcsD,GAAahG,EAAI,OAAO4B,CAAM,EAAGkE,GAAKxC,EAAQ,CAAC,GAAG,QAAU,CAAC,EAAGpC,CAAM,CACzF,CACI4B,GAAYC,EAAK,IAAID,CAAQ,IAC/BC,EAAK,IAAID,CAAQ,GAAG,MAAM,CAAC,GAAG,OAAO,MAAM,EAC3CA,EAAW,KAEf,CACF,CACF,EC3RA,IAAMmD,GAAY,2HAQX,SAASC,GAAUC,EAAkBC,EAA4B,CACtE,GAAIA,EAAM,MAAQ,MAAO,OACzB,IAAMC,EAAM,CAAC,GAAGF,EAAI,iBAA8BF,EAAS,CAAC,EAAE,OAAQK,GAAM,CAACA,EAAE,QAAQ,mBAAmB,GAAK,CAAEA,EAAwB,QAAQ,EACjJ,GAAI,CAACD,EAAI,OAAQ,OACjB,IAAME,EAAQF,EAAI,CAAC,EACbG,EAAOH,EAAIA,EAAI,OAAS,CAAC,EACzBI,EAAKN,EAAI,cAAc,eACzBC,EAAM,SAAWK,IAAOF,GAAS,CAACJ,EAAI,SAASM,CAAE,EAAIA,IAAOD,KAC9DJ,EAAM,eAAe,GACpBA,EAAM,SAAWI,EAAOD,GAAO,MAAM,EAE1C,CCDO,IAAMG,GAAYC,GACvB,IAAI,QAAmB,CAACC,EAASC,IAAW,CAC1C,IAAMC,EAAS,IAAI,WACnBA,EAAO,OAAS,IAAM,CACpB,IAAMC,EAAM,OAAOD,EAAO,QAAU,EAAE,EACtCF,EAAQ,CAAE,KAAMD,EAAK,KAAM,KAAMA,EAAK,KAAM,KAAMA,EAAK,KAAM,KAAMI,EAAI,MAAMA,EAAI,QAAQ,GAAG,EAAI,CAAC,CAAE,CAAC,CACtG,EACAD,EAAO,QAAU,IAAMD,EAAOC,EAAO,KAAK,EAC1CA,EAAO,cAAcH,CAAI,CAC3B,CAAC,EAEGK,GAAaC,IAAkB,eAAe,KAAKA,CAAI,IAAI,CAAC,GAAK,IAAI,YAAY,EAEvF,SAASC,GAAOP,EAAyB,CACvC,IAAMQ,EAAK,GAAGR,EAAK,IAAI,IAAIK,GAAUL,EAAK,IAAI,CAAC,GAAG,YAAY,EAC9D,MAAO,WAAW,KAAKQ,CAAE,EAAI,QAAU,MAAM,KAAKA,CAAE,EAAI,MAAQ,8BAA8B,KAAKA,CAAE,EAAI,QAAU,oBAAoB,KAAKA,CAAE,EAAI,MAAQ,2CAA2C,KAAKA,CAAE,EAAI,MAAQ,MAC1N,CACA,IAAMC,GAAUT,GAAoB,uBAAuB,KAAKA,EAAK,IAAI,EAEnEU,GAAUV,GAAqBA,EAAK,KAAO,QAAQA,EAAK,IAAI,WAAWA,EAAK,IAAI,GAAMA,EAAK,KAAO,GAClGW,GAASC,GAAiB,WAAW,KAAK,KAAKA,CAAI,EAAIC,GAAMA,EAAE,WAAW,CAAC,CAAC,EAC5EC,GAAO,CAACC,EAAYf,IAAoBe,EAAK,OAAQ,CAAE,MAAO,eAAgB,YAAaR,GAAOP,CAAI,EAAG,cAAe,MAAO,EAAGK,GAAUL,EAAK,IAAI,GAAK,GAAG,EAE7JgB,GAAQ,CAACD,EAAYT,IAAiBS,EAAK,OAAQ,CAAE,MAAO,eAAgB,IAAK,OAAQ,MAAOT,CAAK,EAAGS,EAAK,OAAQ,CAAC,EAAGT,EAAK,MAAM,EAAG,EAAE,CAAC,EAAGA,EAAK,MAAM,EAAE,CAAC,EAEjK,SAASW,GAAWC,EAAyC,CAC3D,MAAO,CAAC,CAAE,KAAAC,EAAM,KAAAb,EAAM,MAAOc,EAAK,KAAAC,EAAM,GAAAC,EAAI,SAAUC,EAAK,OAAAC,EAAQ,OAAAC,EAAS,IAAK,IAAM,CACrF,IAAMC,EAAQN,EACRO,EAAQC,GAASJ,EAAQC,CAAM,EAC/BI,EAAWC,GAASL,CAAM,GAAKK,GAAS,GACxCf,EAAOgB,GAAMR,CAAG,EAChBS,EAAUN,EAAM,WAAa,GAC7BO,EAAOD,EAAWN,EAAM,UAAY,IAAY,EAChDQ,EAAQhB,IAAS,QACjBiB,GAAUd,EAAK,SAAU,QAAaa,EAAQ,aAAe,WAAa,aAC1EE,EAASf,EAAK,SAAU,OACxBgB,EAASX,EAAM,OAAS,SAAWA,EAAM,OAAS,CAAC,SAAS,EAC5DY,EAAUvB,EAAK,MAAO,CAAE,MAAO,mBAAmBG,CAAI,aAAaiB,EAAS,SAAW,MAAM,EAAG,CAAC,EACjGI,EAAQxB,EAAK,QAAS,CAAE,KAAM,OAAQ,GAAAO,EAAI,MAAO,aAAc,OAAQe,GAAQ,KAAK,GAAG,EAAG,QAASD,EAAUA,IAAW,OAAS,OAAS,cAAiB,MAAU,CAAC,EAC5KG,EAAM,SAAWP,EAGjB,IAAMQ,EAAS,CACb,CAACN,GAASG,EAASI,GAAcJ,EAAQR,EAAS,EAAE,EAAI,GACxDH,EAAM,QAAUgB,GAAKV,EAAUL,EAAM,SAAWA,EAAM,SAAU,CAAE,KAAMgB,GAAYjB,EAAM,OAAO,CAAE,CAAC,EAAI,GACxGM,GAAWN,EAAM,SAAWgB,GAAKf,EAAM,UAAW,CAAE,IAAKD,EAAM,QAAS,CAAC,EAAI,EAC/E,EAAE,OAAO,OAAO,EAEVkB,EAAO7B,EACX,QACA,CAAE,MAAO,eAAeoB,EAAS,iBAAmB,EAAE,GAAI,IAAKb,CAAG,EAClEP,EAAK,OAAQ,CAAE,MAAO,WAAY,EAAGiB,EAAWE,EAAQP,EAAM,UAAYA,EAAM,SAAYO,EAAQP,EAAM,YAAcA,EAAM,MAAM,EACpIZ,EAAK,OAAQ,CAAE,MAAO,SAAU,EAAGiB,EAAUL,EAAM,SAAWA,EAAM,QAAQ,CAC9E,EACMkB,EAAU9B,EAAK,OAAQ,CAAE,MAAO,wBAAyB,EAAGyB,EAAO,KAAK,QAAK,CAAC,EAC9EM,EAAQd,EAAUjB,EAAK,OAAQ,CAAE,MAAO,uBAAwB,CAAC,EAAI,KACrEgC,EAAOhC,EAAK,KAAM,CAAE,MAAO,WAAY,KAAM,MAAO,CAAC,EACrDiC,EAAUjC,EAAK,SAAU,CAAE,KAAM,SAAU,MAAO,0BAA2B,EAAGY,EAAM,OAAO,EACnGqB,EAAQ,iBAAiB,QAAS,IAAMT,EAAM,MAAM,CAAC,EAErD,IAAMU,EAAUC,GAASnC,EAAMY,CAAK,EAE9BwB,EAAOpC,EAAK,MAAO,CAAE,MAAO,uBAAwB,KAAM,QAAS,CAAC,EAC1EuB,EAAQ,OAAOC,EAAOK,EAAM,GAAIJ,EAAO,OAAS,CAACK,CAAO,EAAI,CAAC,EAAI,GAAIC,EAAQ,CAACA,CAAK,EAAI,CAAC,EAAIC,EAAMC,EAASC,EAAQ,QAASE,CAAI,EAEhI,IAAIC,EAAW,GACXC,EAAqB,CAAC,EACtBC,EACEC,EAAOC,GAAoBL,EAAK,gBAAgB,GAAGK,EAAM,IAAKC,GAAS1C,EAAK,MAAO,CAAC,EAAG0C,CAAI,CAAC,CAAC,EAE7FC,EAAO,MAAOC,GAAmB,CACrC,GAAIP,GAAY,CAACO,EAAO,OAAQ,OAChC,IAAMC,EAAe,CAAC,EAChBJ,EAAkB,CAAC,EACrBK,EAAO,EACX,QAAW7D,KAAQ2D,EAAQ,CACzB,IAAMG,EAAUC,GAAYrC,EAAO1B,EAAM6B,CAAQ,IAAMG,GAAW,CAAC,GAAGqB,EAAO,GAAGO,CAAI,EAAE,KAAMI,GAAMA,EAAE,OAAShE,EAAK,IAAI,EAAI0C,GAAKf,EAAM,aAAc,CAAE,KAAM3B,EAAK,IAAK,CAAC,EAAI,QACtK8D,EAASN,EAAM,KAAKM,CAAO,GACrB9B,EAAUqB,EAAM,OAAS,GAAKO,EAAK,OAAS3B,EAAM2B,EAAK,KAAK5D,CAAI,EACrE6D,GACP,CAGA,GAFIA,GAAQ7B,GAASwB,EAAM,KAAKd,GAAKf,EAAM,QAAS,CAAE,IAAKM,EAAM,EAAG4B,CAAK,CAAC,CAAC,EAC3EN,EAAIC,CAAK,EACL,CAACI,EAAK,OAAQ,OAClB,IAAMK,EAAQ,MAAM,QAAQ,IAAIL,EAAK,IAAI7D,EAAQ,CAAC,EAClDoB,EAAK,SAASb,EAAM0B,EAAU,CAAC,GAAGqB,EAAO,GAAGY,CAAK,EAAIA,EAAM,CAAC,CAAC,CAC/D,EACA1B,EAAM,iBAAiB,SAAU,IAAM,CAChCmB,EAAK,CAAC,GAAInB,EAAM,OAAS,CAAC,CAAE,CAAC,EAClCA,EAAM,MAAQ,EAChB,CAAC,EACDD,EAAQ,iBAAiB,WAAa4B,GAAU,CAC1Cd,IACJc,EAAM,eAAe,EACrB5B,EAAQ,UAAU,IAAI,aAAa,EACrC,CAAC,EACDA,EAAQ,iBAAiB,YAAa,IAAMA,EAAQ,UAAU,OAAO,aAAa,CAAC,EACnFA,EAAQ,iBAAiB,OAAS4B,GAAU,CAC1CA,EAAM,eAAe,EACrB5B,EAAQ,UAAU,OAAO,aAAa,EACjCoB,EAAK,CAAC,GAAKQ,EAAoB,cAAc,OAAS,CAAC,CAAE,CAAC,CACjE,CAAC,EAEDnB,EAAK,iBAAiB,QAAUmB,GAAU,CACxC,IAAMC,EAAUD,EAAM,OAAmB,QAAQ,QAAQ,EACnDE,EAAK,OAAOD,GAAQ,QAAQ,EAAK,EACvC,GAAKA,EACL,IAAIA,EAAO,UAAU,SAAS,cAAc,EAAG,OAAOE,EAAKD,EAAID,CAAM,EACrElB,EAAQ,IAAIP,GAAKf,EAAM,UAAW,CAAE,KAAM0B,EAAMe,CAAE,EAAE,IAAK,CAAC,EAAIE,GAAW,CACvE,IAAMC,EAAOlB,EAAMe,CAAE,EACjBE,IACFnD,EAAK,SAASb,EAAM0B,EAAUqB,EAAM,OAAO,CAACmB,EAAGC,IAAMA,IAAML,CAAE,EAAI,IAAI,EACrEb,EAAI,CAACb,GAAKf,EAAM,QAAS,CAAE,KAAM4C,EAAK,IAAK,CAAC,CAAC,CAAC,IAE/CxB,EAAK,iBAA8B,iBAAiB,EAAEuB,EAAS,KAAK,IAAIF,EAAIf,EAAM,OAAS,CAAC,EAAIe,CAAE,IAAMxB,EAAK,OAASI,EAAUT,IAAQ,MAAM,CACjJ,CAAC,EACH,CAAC,EAGD,SAAS8B,EAAKD,EAAYM,EAAqB,CAC7C,IAAMC,EAAMtB,EACRjD,EAAM,GACJwE,EAAQ7D,EAAK,KAAM,CAAE,GAAI,GAAGO,CAAE,QAAS,MAAO,sBAAuB,CAAC,EACtEuD,EAAO9D,EAAK,OAAQ,CAAE,MAAO,SAAU,CAAC,EACxC+D,EAAO,CAACC,GAAYpD,GAAeqD,KAAkB,CACzD,IAAMb,GAASpD,EAAK,SAAU,CAAE,KAAM,SAAU,MAAO,yBAA0B,aAAcY,EAAM,EAAGqD,EAAK,EAC7G,OAAAb,GAAO,OAASQ,EAAI,OAAS,EAC7BR,GAAO,iBAAiB,QAAS,IAAMc,GAAKb,EAAKW,EAAE,CAAC,EAC7CZ,EACT,EACMe,EAAWnE,EAAK,IAAK,CAAE,MAAO,WAAY,EAAGY,EAAM,QAAQ,EAC3DwD,EAAQpE,EAAK,SAAU,CAAE,KAAM,SAAU,MAAO,kBAAmB,aAAcY,EAAM,KAAM,EAAG,MAAG,EACnGyD,GAAOrE,EAAK,MAAO,CAAE,MAAO,qBAAsB,CAAC,EACnDsE,GAAMtE,EACV,MAEA,CAAE,MAAO,gCAAiC,KAAM,SAAU,aAAc,OAAQ,kBAAmB6D,EAAM,GAAI,SAAU,IAAK,EAC5H7D,EAAK,MAAO,CAAE,MAAO,qBAAsB,EAAG6D,EAAOC,EAAMC,EAAK,GAAInD,EAAM,SAAU,QAAG,EAAGmD,EAAK,EAAGnD,EAAM,KAAM,QAAG,EAAGuD,EAAUC,CAAK,EACnIC,EACF,EACME,GAAWvE,EAAK,MAAO,CAAE,MAAO,oBAAqB,EAAGsE,EAAG,EAC3DE,GAAO,IAAMnF,EAAI,WAAW,OAAO,GAAK,IAAI,gBAAgBA,CAAG,EAC/DoF,EAAQxF,IAAoBe,EAAK,MAAO,CAAE,MAAO,cAAe,EAAGD,GAAKC,EAAMf,EAAI,EAAGe,EAAK,SAAU,CAAC,EAAGf,GAAK,IAAI,EAAG2C,GAAY3C,GAAK,IAAI,EAAGe,EAAK,IAAK,CAAC,EAAGY,EAAM,SAAS,CAAC,EAChL,SAASsD,GAAKQ,GAAY,CACxBrB,GAAMqB,GAAKd,EAAI,QAAUA,EAAI,OAC7B,IAAM3E,GAAO2E,EAAIP,CAAE,EACnBmB,GAAK,EACL,IAAM3E,GAAOZ,GAAK,KAAOW,GAAMX,GAAK,IAAI,EAAI,KAC5CI,EAAMQ,GAAO,IAAI,gBAAgB,IAAI,KAAK,CAACA,EAAI,EAAG,CAAE,KAAMZ,GAAK,IAAK,CAAC,CAAC,EAAKA,GAAK,KAAO,GACvF4E,EAAM,YAAc5E,GAAK,KACzB6E,EAAK,gBAAgB9D,EAAK,OAAQ,CAAE,MAAO,cAAe,EAAG4B,GAAY3C,GAAK,IAAI,CAAC,EAAG2E,EAAI,OAAS,EAAI,SAAMjC,GAAKf,EAAM,OAAQ,CAAE,EAAGyC,EAAK,EAAG,MAAOO,EAAI,MAAO,CAAC,CAAC,GAAK,EAAE,EACxKO,EAAS,KAAO9E,EAChB8E,EAAS,SAAWlF,GAAK,KACzB,IAAMkB,GAAOX,GAAOP,EAAI,EACxB,GAAIkB,KAAS,QAAS,OAAOkE,GAAK,gBAAgBrE,EAAK,MAAO,CAAE,IAAKX,EAAK,IAAKJ,GAAK,IAAK,CAAC,CAAC,EAC3F,GAAIkB,KAAS,MAAO,OAAOkE,GAAK,gBAAgBrE,EAAK,SAAU,CAAE,IAAKX,EAAK,MAAOJ,GAAK,IAAK,CAAC,CAAC,EAC9F,GAAI,CAACS,GAAOT,EAAI,EAAG,OAAOoF,GAAK,gBAAgBI,EAAKxF,EAAI,CAAC,EACzD,IAAM0F,GAAM3E,EAAK,MAAO,CAAE,SAAU,GAAI,CAAC,EACzCqE,GAAK,gBAAgBM,EAAG,GAEvB9E,GAAO,QAAQ,QAAQ,IAAI,YAAY,EAAE,OAAOA,GAAK,SAAS,EAAG,GAAG,CAAC,CAAC,EAAI,MAAMR,CAAG,EAAE,KAAMuF,IAAMA,GAAE,KAAK,CAAC,GAAG,KAC1GhE,IAAW+D,GAAI,YAAc/D,GAAM,MAAM,EAAG,GAAG,EAChD,IAAM+D,GAAI,YAAYF,EAAKxF,EAAI,CAAC,CAClC,CACF,CACA,IAAM4F,GAAO,IAAM,CACjBL,GAAK,EACLD,GAAS,OAAO,GACfZ,EAAO,YAAcA,EAAS3B,EAAK,iBAA8B,eAAe,EAAEqB,CAAE,IAAI,MAAM,CACjG,EACAe,EAAM,iBAAiB,QAASS,EAAI,EACpCN,GAAS,iBAAiB,QAAUpB,IAAUA,GAAM,SAAWoB,IAAYM,GAAK,CAAC,EACjFP,GAAI,iBAAiB,UAAYnB,IAAU,CACzC,IAAMa,GAAM,CAAE,UAAW,GAAI,WAAY,CAAE,EAA6Bb,GAAM,GAAG,EAC7EA,GAAM,MAAQ,SAAU0B,GAAK,EACxBb,IAAMJ,EAAI,OAAS,GAAMT,GAAM,OAAmB,UAAY,MAAOe,GAAKb,GAAMyB,GAAYvD,CAAO,EAAI,CAACyC,GAAKA,GAAG,EACpHe,GAAUT,GAAKnB,EAAK,CAC3B,CAAC,EACDe,GAAKb,CAAE,GAEN9B,EAAQ,QAAQ,UAAU,GAAKf,EAAI,MAAM,OAAO+D,EAAQ,EACzDD,GAAI,MAAM,CACZ,CAEA,MAAO,CACL,QAAA/C,EACA,MAAO,KAAOS,EAAK,cAAc,QAAQ,IAAMH,EAAK,OAASI,EAAUT,IAAQ,MAAM,EACrF,OAAOwD,EAAO,CACZ3C,EAAW2C,EAAM,SACjB,IAAMC,EAAQD,EAAM,MACpB1C,EAAQ,MAAM,QAAQ2C,CAAK,EAAIA,EAAQA,EAAQ,CAACA,CAAK,EAAI,CAAC,EAC1D,IAAMC,EAAO5C,EAAM,QAAUpB,EAC7BiE,GAAUtD,EAAMqD,GAAQ7C,CAAQ,EAChC8C,GAAUrD,EAASO,CAAQ,EAC3Bb,EAAM,SAAWa,EACjBb,EAAM,OAASK,EAAK,OACpBsD,GAAUlD,EAAShB,GAAW,CAACqB,EAAM,QAAUD,CAAQ,EACnDN,GAAOqD,GAAQrD,EAAQO,EAAM,OAAcrB,GAAWN,EAAM,SAAWgB,GAAKf,EAAM,YAAa,CAAE,EAAG0B,EAAM,OAAQ,IAAK3B,EAAM,QAAS,CAAC,EAAI2B,EAAM,SAAW,EAAI1B,EAAM,QAAUe,GAAKf,EAAM,UAAW,CAAE,EAAG0B,EAAM,MAAO,CAAC,EAAnL,EAAoL,EAC9N+C,GAAc7D,EAAOwD,CAAK,EACtB,EAAAzC,IAAU0C,GAASjD,EAAK,QAAQ,WAAgB,OAAOK,CAAQ,KACnEE,EAAQ0C,EACRjD,EAAK,QAAQ,SAAc,OAAOK,CAAQ,EAC1CL,EAAK,gBACH,GAAGM,EAAM,IAAI,CAACrD,EAAMoE,IAClBrD,EACE,KACA,CAAE,MAAO,cAAe,EACxBA,EACE,SAEA,CAAE,KAAM,SAAU,MAAO,eAAgB,UAAW,OAAOqD,CAAE,EAAG,gBAAiB,SAAU,aAAc,GAAGpE,EAAK,IAAI,KAAK2C,GAAY3C,EAAK,IAAI,CAAC,EAAG,EACnJO,GAAOP,CAAI,IAAM,SAAWU,GAAOV,CAAI,EAAIe,EAAK,MAAO,CAAE,MAAO,gBAAiB,IAAKL,GAAOV,CAAI,EAAG,IAAK,EAAG,CAAC,EAAIc,GAAKC,EAAMf,CAAI,EAChIgB,GAAMD,EAAMf,EAAK,IAAI,EACrBe,EAAK,OAAQ,CAAE,MAAO,cAAe,EAAG4B,GAAY3C,EAAK,IAAI,CAAC,CAChE,EACA,GAAIoD,EAAW,CAAC,EAAI,CAACrC,EAAK,SAAU,CAAE,KAAM,SAAU,MAAO,iBAAkB,UAAW,OAAOqD,CAAE,EAAG,aAAc1B,GAAKf,EAAM,OAAQ,CAAE,KAAM3B,EAAK,IAAK,CAAC,CAAE,EAAG,MAAG,CAAC,CACrK,CACF,CACF,EACF,CACF,CACF,CACF,CAEO,IAAMqG,GAAepF,GAAW,QAAQ,EAClCqF,GAAcrF,GAAW,OAAO,ECtO7C,IAAMsF,GAAW,IAAI,IACrB,SAASC,GAAQC,EAAeC,EAAgB,CAC9C,IAAIC,EAASJ,GAAS,IAAIG,CAAM,EAChC,OAAKC,IACHA,EAAS,IAAI,KAAK,aAAaD,EAAQ,CAAE,MAAO,UAAW,sBAAuB,EAAG,gBAAiB,MAAO,CAAC,EAC9GH,GAAS,IAAIG,EAAQC,CAAM,GAEtBA,EAAO,OAAOF,EAAQ,GAAG,CAClC,CAEO,IAAMG,GAAoCC,GAAY,CAC3D,GAAM,CAAE,MAAAC,EAAO,KAAAC,EAAM,GAAAC,EAAI,SAAAC,EAAU,OAAAP,EAAS,IAAK,EAAIG,EAC/CK,EAAUH,EAAK,SAAW,CAAC,EAC3BI,EAAQ,CAACC,EAAoBC,IAAkB,CACnD,IAAMC,EAAMJ,EAAQE,CAAG,GAAMN,EAAkCM,CAAG,EAClE,OAAO,OAAOE,GAAQ,SAAWA,EAAMD,CACzC,EACME,EAAMJ,EAAM,MAAO,CAAC,EACpBK,EAAWL,EAAM,MAAO,GAAG,EAC3BM,EAAW,OAAOP,EAAQ,UAAgB,SAAWA,EAAQ,SAAc,KAC3EQ,EAAQ,OAAOR,EAAQ,OAAa,SAAWA,EAAQ,MAAW,OAClES,EAAcT,EAAQ,cAAmB,GAEzCU,EAAMX,EAAS,cAAc,KAAK,EACxCW,EAAI,UAAY,iBAChBA,EAAI,aAAa,OAAQ,aAAa,EACtC,IAAMC,EAAOZ,EAAS,cAAc,KAAK,EACzCY,EAAK,UAAY,sBACjB,IAAMC,EAAOb,EAAS,cAAc,MAAM,EAC1Ca,EAAK,UAAY,sBACjBF,EAAI,OAAOC,EAAMC,CAAI,EAGrB,IAAIC,EAAqB,KACrBC,EAAuBJ,EAC3B,OAAIV,EAAQ,WAAgB,IAC1Ba,EAAME,GAAa,CAAE,GAAGpB,EAAS,KAAM,CAAE,GAAGE,EAAM,OAAQ,MAAU,CAAE,CAAC,EACvEa,EAAI,aAAa,cAAe,MAAM,EACtCI,EAAUf,EAAS,cAAc,KAAK,EACtCe,EAAQ,UAAY,sBACpBA,EAAQ,OAAOJ,EAAKG,EAAI,OAAO,GAE/BH,EAAI,GAAKZ,EAGJ,CACL,QAAAgB,EACA,MAAO,IAAMD,GAAK,MAAM,EACxB,OAAOG,EAAO,CACZ,IAAMzB,EAAQ,OAAOyB,EAAM,OAAU,SAAWA,EAAM,MAAQ,EACxDC,EAAMV,EAAW,OAAOS,EAAM,OAAOT,CAAQ,GAAK,CAAC,EAAID,EACvDY,EAAQD,EAAMZ,EAAM,KAAK,IAAI,IAAK,KAAK,IAAI,GAAKd,EAAQc,IAAQY,EAAMZ,GAAQ,GAAG,CAAC,EAAI,EACtFc,EAAU,KAAK,MAAMD,EAAQ,EAAE,EAAI,GACzCP,EAAK,MAAM,MAAQ,GAAGQ,CAAO,IAC7BT,EAAI,aAAa,gBAAiB,OAAOnB,CAAK,CAAC,EAC/CmB,EAAI,aAAa,gBAAiB,OAAOL,CAAG,CAAC,EAC7CK,EAAI,aAAa,gBAAiB,OAAOO,CAAG,CAAC,EAC7CP,EAAI,aAAa,iBAAkBpB,GAAQ4B,EAAO1B,CAAM,CAAC,EACzDoB,EAAK,YAAcH,EAAcnB,GAAQ4B,EAAO1B,CAAM,EAAI,GAC1DkB,EAAI,QAAQ,KAAUF,IAAU,OAASA,EAAQU,EAAQ,GAAK,SAAWA,EAAQ,GAAK,UAAY,UAClGL,GAAK,OAAOG,CAAK,CACnB,CACF,CACF,EChEA,SAASI,GAAMC,EAAkC,CAC/C,OAAIA,GAAU,KAAoC,GAC9C,OAAOA,GAAU,UAAY,UAAYA,EAA0BA,EAAwB,MACxF,OAAOA,CAAK,CACrB,CAEO,IAAMC,GAA6B,CAAC,CAAE,MAAAC,EAAO,KAAAC,EAAM,GAAAC,EAAI,SAAAC,EAAU,OAAAC,EAAS,IAAe,IAAM,CACpG,IAAMC,EAAUJ,EAAK,SAAW,CAAC,EAC3BK,EAAQC,GAA8B,OAAOF,EAAQE,CAAG,GAAM,SAAYF,EAAQE,CAAG,EAAe,GACpGC,EAAQD,GAAwC,OAAOF,EAAQE,CAAG,GAAM,SAAYF,EAAQE,CAAG,EAAe,KAC9GE,EACJT,EAAM,OAAS,UAAY,EAAIA,EAAM,OAAS,SAAWA,EAAM,OAAS,WAAcA,EAAM,SAAS,CAAC,GAAK,EAAK,KAE5GU,EAASP,EAAS,cAAc,QAAQ,EAC9C,OAAAO,EAAO,GAAKR,EACZQ,EAAO,UAAY,gBACZ,CACL,QAASA,EACT,MAAO,IAAG,GACV,OAAO,CAAE,MAAAZ,EAAO,OAAAa,CAAO,EAAG,CACxB,GAAIb,GAAU,MAA+BA,IAAU,GAAI,CACzDY,EAAO,YAAc,GACrB,MACF,CACA,IAAME,EAAQH,IAAa,MAAQ,OAAOX,GAAU,SAAWe,GAAaf,EAAOW,EAAUL,CAAM,EAAIU,GAAQhB,EAAOE,CAAK,EACrHe,EAAcP,EAAK,aAAa,EAChCQ,EAAcR,EAAK,aAAa,EAChCS,EAASF,EAAclB,GAAMc,EAAOI,CAAW,CAAC,EAAIT,EAAK,QAAQ,EACjEY,EAASF,EAAcnB,GAAMc,EAAOK,CAAW,CAAC,EAAIV,EAAK,QAAQ,EACvEI,EAAO,YAAc,CAACO,EAAQL,EAAOM,CAAM,EAAE,OAAQC,GAASA,IAAS,EAAE,EAAE,KAAK,GAAG,CACrF,CACF,CACF,EC3BO,IAAMC,GAAiC,CAAC,CAAE,KAAAC,EAAM,KAAAC,EAAM,MAAAC,EAAO,KAAAC,EAAM,GAAAC,EAAI,SAAAC,CAAS,IAAM,CAC3F,IAAMC,EAAUH,EAAK,SAAW,CAAC,EAC3BI,EAAYD,EAAQ,YAAiB,GACrCE,EAAU,MAAM,QAAQF,EAAQ,aAAgB,EAAIA,EAAQ,cAAmB,KAC/EG,EAAOJ,EAAS,cAAc,IAAI,EACxCI,EAAK,UAAY,eACjBA,EAAK,GAAKL,EACVK,EAAK,aAAa,aAAcP,EAAM,KAAK,EAE3C,IAAMQ,EAASC,GACbA,GAAS,OAAOA,GAAU,UAAY,OAAQA,EAAQ,MAAM,OAAQA,EAAwB,EAAE,CAAC,GAAK,KAAK,OAAOA,CAAK,CAAC,GAEpHC,EACFV,EAAM,OAAS,YAAcA,EAAM,QAAQ,IAAKW,IAAO,CAAE,IAAKH,EAAMG,EAAE,KAAK,EAAG,MAAOA,EAAE,MAAO,MAAOA,EAAE,KAAM,EAAE,EAAI,CAAC,EAClHC,EAAWZ,EAAM,OAAS,YAC1Ba,EAA8C,CAAE,MAAO,OAAW,SAAU,EAAM,EAEtF,SAASC,GAAO,CACd,GAAM,CAAE,MAAAL,EAAO,SAAAM,CAAS,EAAIF,EACtBG,EAAaP,GAAU,KAA8B,KAAOD,EAAMC,CAAK,EACzEQ,EAAQP,EAAM,OAAQQ,GAAM,CAACZ,GAAWA,EAAQ,KAAMa,GAAMX,EAAMW,CAAC,IAAMD,EAAE,GAAG,GAAKA,EAAE,MAAQF,CAAU,EACvGA,GAAc,CAACC,EAAM,KAAMC,GAAMA,EAAE,MAAQF,CAAU,GAAKP,GAAS,OAAOA,GAAU,WACtFQ,EAAQ,CAAC,GAAGA,EAAO,CAAE,IAAKD,EAAY,MAAQP,EAAwB,MAAO,MAAAA,CAAM,CAAC,GAEtFF,EAAK,gBACH,GAAGU,EAAM,IAAKG,GAAS,CACrB,IAAMC,EAAQlB,EAAS,cAAc,MAAM,EAC3CkB,EAAM,YAAcD,EAAK,MACzB,IAAME,EAAQnB,EAAS,cAAcE,EAAY,SAAW,MAAM,EAC9DiB,aAAiB,oBACnBA,EAAM,KAAO,SACbA,EAAM,SAAWP,EACjBO,EAAM,iBAAiB,QAAS,IAAMxB,EAAK,SAASC,EAAMqB,EAAK,KAAc,CAAC,GAEhFE,EAAM,OAAOD,CAAK,EACdD,EAAK,MAAQJ,GAAYM,EAAM,aAAa,eAAgB,MAAM,EACtE,IAAMC,EAAOpB,EAAS,cAAc,IAAI,EACxC,OAAAoB,EAAK,OAAOD,CAAK,EACVC,CACT,CAAC,CACH,CACF,CAEA,MAAO,CACL,QAAShB,EACT,MAAO,IAAMA,EAAK,cAA2B,wBAAwB,GAAG,MAAM,EAC9E,OAAOiB,EAAO,CACZX,EAAO,CAAE,MAAOW,EAAM,MAAO,SAAUA,EAAM,QAAS,EACtDV,EAAK,EACAF,IACHA,EAAW,GACNd,EACF,OAAOC,EAAM,GAAI,EAAE,EACnB,KAAM0B,GAAY,CACjBf,EAAQe,EAAQ,IAAKC,IAAO,CAAE,IAAKlB,EAAMkB,CAAC,EAAG,MAAOA,EAAE,MAAO,MAAOA,CAAE,EAAE,EACxEZ,EAAK,CACP,CAAC,EACA,MAAM,IAAG,EAAY,EAE5B,CACF,CACF,EClEO,SAASa,GAAQC,EAAmB,CACzC,IAAM,EAAI,IAAI,KAAK,KAAK,IAAIA,EAAI,YAAY,EAAGA,EAAI,SAAS,EAAGA,EAAI,QAAQ,CAAC,CAAC,EAC7E,EAAE,WAAW,EAAE,WAAW,EAAI,GAAK,EAAE,UAAU,GAAK,EAAE,EACtD,IAAMC,EAAY,KAAK,IAAI,EAAE,eAAe,EAAG,EAAG,CAAC,EACnD,OAAO,KAAK,OAAO,EAAE,QAAQ,EAAIA,GAAa,MAAW,GAAK,CAAC,CACjE,CAEA,IAAMC,GAAOC,GAAc,OAAOA,CAAC,EAAE,SAAS,EAAG,GAAG,EAC9CC,GAAU,CAACC,EAASC,IAAYD,EAAE,YAAY,IAAMC,EAAE,YAAY,GAAKD,EAAE,SAAS,IAAMC,EAAE,SAAS,GAAKD,EAAE,QAAQ,IAAMC,EAAE,QAAQ,EAClIC,GAAU,CAACC,EAASL,IAAc,IAAI,KAAKK,EAAE,YAAY,EAAGA,EAAE,SAAS,EAAGA,EAAE,QAAQ,EAAIL,CAAC,EAE/F,SAASM,GAAUD,EAASL,EAAW,CACrC,IAAMO,EAAO,IAAI,KAAKF,EAAE,YAAY,EAAGA,EAAE,SAAS,EAAIL,EAAI,EAAG,CAAC,EAAE,QAAQ,EACxE,OAAO,IAAI,KAAKK,EAAE,YAAY,EAAGA,EAAE,SAAS,EAAIL,EAAG,KAAK,IAAIK,EAAE,QAAQ,EAAGE,CAAI,CAAC,CAChF,CAGA,SAASC,GAAMC,EAA2BC,EAAuC,CAC/E,GAAI,OAAOA,GAAU,UAAY,CAACA,EAAO,OAAO,KAChD,GAAID,IAAS,OAAQ,CACnB,IAAME,EAAI,2BAA2B,KAAKD,CAAK,EAC/C,OAAOC,EAAI,IAAI,KAAK,OAAOA,EAAE,CAAC,CAAC,EAAG,OAAOA,EAAE,CAAC,CAAC,EAAI,EAAG,OAAOA,EAAE,CAAC,CAAC,CAAC,EAAI,IACtE,CACA,IAAMN,EAAI,IAAI,KAAKK,CAAK,EACxB,OAAO,OAAO,MAAML,EAAE,QAAQ,CAAC,EAAI,KAAOA,CAC5C,CAEO,SAASO,GAAaC,EAAeC,EAAwBL,EAAmC,CACrG,GAAM,CAAE,KAAAM,EAAM,KAAAC,EAAM,GAAAC,EAAI,SAAUC,EAAK,OAAAC,EAAS,IAAe,EAAIL,EAC7DM,EAAuBN,EAAQ,QAAUO,GAAc,GACvDC,EAAOH,IAAW,KAAO,QAAUA,EACnCI,EAAY,IAAI,KAAK,eAAeD,EAAM,CAAE,MAAO,OAAQ,KAAM,UAAW,gBAAiB,MAAO,CAAC,EACrGE,EAAU,IAAI,KAAK,eAAeF,EAAM,CAAE,QAAS,OAAQ,IAAK,UAAW,MAAO,OAAQ,KAAM,UAAW,gBAAiB,MAAO,CAAC,EACpIG,EAAe,IAAI,KAAK,eAAeH,EAAM,CAAE,QAAS,OAAQ,CAAC,EACjEI,EAAc,IAAI,KAAK,eAAeJ,EAAM,CAAE,QAAS,MAAO,CAAC,EAE/DK,EAAST,EAAI,cAAc,QAAQ,EACzCS,EAAO,KAAO,SACdA,EAAO,UAAY,qBAEnB,IAAMC,EAAM,6BACNC,EAAOX,EAAI,gBAAgBU,EAAK,KAAK,EAC3CC,EAAK,aAAa,UAAW,WAAW,EACxCA,EAAK,aAAa,cAAe,MAAM,EACvC,OAAW,CAACC,EAAKC,CAAK,GAAK,CACzB,CAAC,OAAQ,CAAE,EAAG,IAAK,EAAG,IAAK,MAAO,KAAM,OAAQ,KAAM,GAAI,KAAM,CAAC,EACjE,CAAC,OAAQ,CAAE,EAAG,4BAA6B,CAAC,CAC9C,EAAY,CACV,IAAMC,EAAQd,EAAI,gBAAgBU,EAAKE,CAAG,EAC1C,OAAW,CAACG,EAAGC,CAAC,IAAK,OAAO,QAAQH,CAAK,EAAGC,EAAM,aAAaC,EAAGC,CAAC,EACnEL,EAAK,OAAOG,CAAK,CACnB,CACAL,EAAO,OAAOE,CAAI,EAClBF,EAAO,aAAa,aAAcP,EAAO,UAAU,EACnDO,EAAO,aAAa,gBAAiB,QAAQ,EAC7CA,EAAO,aAAa,gBAAiB,OAAO,EAC5CA,EAAO,aAAa,gBAAiB,GAAGV,CAAE,WAAW,EAErD,IAAMkB,EAASjB,EAAI,cAAc,KAAK,EACtCiB,EAAO,UAAY,cACnBA,EAAO,GAAK,GAAGlB,CAAE,YACjBkB,EAAO,aAAa,OAAQ,QAAQ,EACpCA,EAAO,OAAS,GAChB,IAAMC,EAAOlB,EAAI,cAAc,KAAK,EACpCkB,EAAK,UAAY,mBACjB,IAAMC,EAAOnB,EAAI,cAAc,QAAQ,EACvCmB,EAAK,KAAO,SACZA,EAAK,YAAc,SACnBA,EAAK,aAAa,aAAcjB,EAAO,aAAa,EACpD,IAAMkB,EAAQpB,EAAI,cAAc,MAAM,EACtCoB,EAAM,UAAY,oBAClBA,EAAM,aAAa,YAAa,QAAQ,EACxC,IAAMC,EAAOrB,EAAI,cAAc,QAAQ,EACvCqB,EAAK,KAAO,SACZA,EAAK,YAAc,SACnBA,EAAK,aAAa,aAAcnB,EAAO,SAAS,EAChDgB,EAAK,OAAOC,EAAMC,EAAOC,CAAI,EAC7B,IAAMC,EAAOtB,EAAI,cAAc,OAAO,EACtCsB,EAAK,UAAY,mBACjBA,EAAK,aAAa,OAAQ,MAAM,EAChCL,EAAO,OAAOC,EAAMI,CAAI,EAExB,IAAMC,EAAUvB,EAAI,cAAc,MAAM,EACxCuB,EAAQ,UAAY,eACpBA,EAAQ,OAAO5B,EAAM,QAASc,EAAQQ,CAAM,EAE5C,IAAIO,EAAU,IAAI,KACdC,EAAW,GAEf,SAASC,EAAK/C,EAAW,CACvB,GAAIY,IAAS,OACXM,EAAK,SAASC,EAAM,GAAGnB,EAAI,YAAY,CAAC,IAAIE,GAAIF,EAAI,SAAS,EAAI,CAAC,CAAC,IAAIE,GAAIF,EAAI,QAAQ,CAAC,CAAC,EAAE,MACtF,CACL,IAAMgD,EAAMrC,GAAM,WAAYO,EAAK,SAAS,EAAE,OAAOC,CAAI,CAAC,EACpD8B,EAAK,IAAI,KAAKjD,EAAI,YAAY,EAAGA,EAAI,SAAS,EAAGA,EAAI,QAAQ,EAAGgD,GAAK,SAAS,GAAK,EAAGA,GAAK,WAAW,GAAK,CAAC,EAClH9B,EAAK,SAASC,EAAM8B,EAAG,YAAY,CAAC,CACtC,CACAC,EAAM,CACR,CAEA,SAASC,EAAKC,EAAgB,CAC5B,IAAMC,EAAS1C,GAAMC,EAAMM,EAAK,SAAS,EAAE,OAAOC,CAAI,CAAC,EACjDmC,EAAQ,IAAI,KACZC,EAAQ7B,EAAU,OAAOmB,CAAO,EACtCJ,EAAM,YAAcc,EACpBjB,EAAO,aAAa,aAAciB,CAAK,EACvC,IAAMC,EAAQ,IAAI,KAAKX,EAAQ,YAAY,EAAGA,EAAQ,SAAS,EAAG,CAAC,EAC7DY,EAAQlD,GAAQiD,EAAO,GAAGA,EAAM,OAAO,EAAI,GAAK,EAAE,EAClDE,EAAUrC,EAAI,cAAc,IAAI,EAChCsC,EAAWtC,EAAI,cAAc,IAAI,EACvCsC,EAAS,MAAQ,MACjBA,EAAS,YAAcpC,EAAO,UAC9BoC,EAAS,aAAa,OAAQpC,EAAO,IAAI,EACzCmC,EAAQ,OAAOC,CAAQ,EACvB,QAASC,EAAI,EAAGA,EAAI,EAAGA,IAAK,CAC1B,IAAMpD,GAAID,GAAQkD,EAAOG,CAAC,EACpBC,GAAKxC,EAAI,cAAc,IAAI,EACjCwC,GAAG,MAAQ,MACXA,GAAG,YAAcjC,EAAa,OAAOpB,EAAC,EAAE,QAAQ,MAAO,EAAE,EACzDqD,GAAG,aAAa,OAAQhC,EAAY,OAAOrB,EAAC,CAAC,EAC7CkD,EAAQ,OAAOG,EAAE,CACnB,CACA,IAAMC,EAAQzC,EAAI,cAAc,OAAO,EACvCyC,EAAM,OAAOJ,CAAO,EACpB,IAAMK,EAAQ1C,EAAI,cAAc,OAAO,EACvC,QAAS2C,EAAMP,EAAOO,GAAO,IAAI,KAAKnB,EAAQ,YAAY,EAAGA,EAAQ,SAAS,EAAI,EAAG,CAAC,EAAGmB,EAAMzD,GAAQyD,EAAK,CAAC,EAAG,CAC9G,IAAMC,GAAK5C,EAAI,cAAc,IAAI,EAC3B6C,GAAO7C,EAAI,cAAc,IAAI,EACnC6C,GAAK,MAAQ,MACbA,GAAK,UAAY,UACjBA,GAAK,YAAc,OAAOnE,GAAQiE,CAAG,CAAC,EACtCC,GAAG,OAAOC,EAAI,EACd,QAASN,GAAI,EAAGA,GAAI,EAAGA,KAAK,CAC1B,IAAMpD,GAAID,GAAQyD,EAAKJ,EAAC,EAClBO,EAAO9C,EAAI,cAAc,IAAI,EAC7BrB,GAAMqB,EAAI,cAAc,QAAQ,EACtCrB,GAAI,KAAO,SACXA,GAAI,YAAc,OAAOQ,GAAE,QAAQ,CAAC,EACpCR,GAAI,aAAa,aAAc2B,EAAQ,OAAOnB,EAAC,CAAC,EAChDR,GAAI,SAAWI,GAAQI,GAAGqC,CAAO,EAAI,EAAI,GACrCrC,GAAE,SAAS,IAAMqC,EAAQ,SAAS,GAAG7C,GAAI,UAAU,IAAI,YAAY,EACnEqD,GAAUjD,GAAQI,GAAG6C,CAAM,GAAGrD,GAAI,aAAa,gBAAiB,MAAM,EACtEI,GAAQI,GAAG8C,CAAK,GAAGtD,GAAI,aAAa,eAAgB,MAAM,EAC9DA,GAAI,SAAW8C,EACf9C,GAAI,iBAAiB,QAAS,IAAM+C,EAAKvC,EAAC,CAAC,EAC3CR,GAAI,iBAAiB,UAAYoE,IAAUC,EAAMD,GAAO5D,EAAC,CAAC,EAC1D2D,EAAK,OAAOnE,EAAG,EACfiE,GAAG,OAAOE,CAAI,CAChB,CACAJ,EAAM,OAAOE,EAAE,CACjB,CACAtB,EAAK,gBAAgBmB,EAAOC,CAAK,EAC7BX,GAAOT,EAAK,cAAiC,sBAAsB,GAAG,MAAM,CAClF,CAEA,SAAS2B,EAAKC,EAAU,CACtB1B,EAAU0B,EACVpB,EAAK,EAAI,CACX,CAEA,SAASkB,EAAMD,EAAsBpE,EAAW,CAC9C,IAAMwE,EAAoC,CACxC,UAAW,IAAMjE,GAAQP,EAAK,EAAE,EAChC,WAAY,IAAMO,GAAQP,EAAK,CAAC,EAChC,QAAS,IAAMO,GAAQP,EAAK,EAAE,EAC9B,UAAW,IAAMO,GAAQP,EAAK,CAAC,EAC/B,OAAQ,IAAMS,GAAUT,EAAK,EAAE,EAC/B,SAAU,IAAMS,GAAUT,EAAK,CAAC,EAChC,KAAM,IAAMO,GAAQP,EAAK,GAAGA,EAAI,OAAO,EAAI,GAAK,EAAE,EAClD,IAAK,IAAMO,GAAQP,EAAK,GAAMA,EAAI,OAAO,EAAI,GAAK,CAAE,CACtD,EACIwE,EAAMJ,EAAM,GAAG,GACjBA,EAAM,eAAe,EACrBE,EAAKE,EAAMJ,EAAM,GAAG,EAAE,CAAC,IACdA,EAAM,MAAQ,SAAWA,EAAM,MAAQ,OAChDA,EAAM,eAAe,EACrBrB,EAAK/C,CAAG,EAEZ,CAEA,SAASyE,GAAO,CACd5B,EAAUlC,GAAMC,EAAMM,EAAK,SAAS,EAAE,OAAOC,CAAI,CAAC,GAAK,IAAI,KAC3DmB,EAAO,OAAS,GAChBR,EAAO,aAAa,gBAAiB,MAAM,EAC3CqB,EAAK,EAAI,CACX,CAEA,SAASD,GAAQ,CACXZ,EAAO,SACXA,EAAO,OAAS,GAChBR,EAAO,aAAa,gBAAiB,OAAO,EAC5CA,EAAO,MAAM,EACf,CAEAA,EAAO,iBAAiB,QAAS,IAAOQ,EAAO,OAASmC,EAAK,EAAIvB,EAAM,CAAE,EACzEV,EAAK,iBAAiB,QAAS,IAAM,CACnCK,EAAUpC,GAAUoC,EAAS,EAAE,EAC/BM,EAAK,EAAK,CACZ,CAAC,EACDT,EAAK,iBAAiB,QAAS,IAAM,CACnCG,EAAUpC,GAAUoC,EAAS,CAAC,EAC9BM,EAAK,EAAK,CACZ,CAAC,EACDb,EAAO,iBAAiB,UAAY8B,GAAU,CACxCA,EAAM,MAAQ,WAChBA,EAAM,eAAe,EACrBA,EAAM,gBAAgB,EACtBlB,EAAM,EAEV,CAAC,EACD,IAAMwB,EAAWN,GAAiB,CAC5B,CAAC9B,EAAO,QAAU,CAACM,EAAQ,SAASwB,EAAM,MAAc,IAC1D9B,EAAO,OAAS,GAChBR,EAAO,aAAa,gBAAiB,OAAO,EAEhD,EACA,OAAAT,EAAI,iBAAiB,YAAaqD,CAAO,EAElC,CACL,QAAA9B,EACA,MAAO,IAAM5B,EAAM,MAAM,EACzB,OAAO2D,EAAO,CACZ7B,EAAW6B,EAAM,SACjB7C,EAAO,OAAS6C,EAAM,SAClBA,EAAM,WAAUrC,EAAO,OAAS,IACpCtB,EAAM,OAAO2D,CAAK,CACpB,EACA,SAAU,CACRtD,EAAI,oBAAoB,YAAaqD,CAAO,EAC5C1D,EAAM,UAAU,CAClB,CACF,CACF,CC1OA,IAAM4D,GAAYC,GAAiB,CACjC,IAAMC,EAAQD,EAAK,QAAQ,KAAM,GAAG,EAAE,KAAK,EAC3C,OAAOC,EAAM,OAAO,CAAC,EAAE,YAAY,EAAIA,EAAM,MAAM,CAAC,CACtD,EAGA,SAASC,GAAMF,EAAcG,EAA8C,CACzE,IAAMC,EAAQL,GAASC,CAAI,EAC3B,OAAI,OAAOG,GAAU,UAAkB,CAAE,KAAAH,EAAM,MAAAI,EAAO,KAAM,SAAU,EAClE,OAAOD,GAAU,SAAiB,CAAE,KAAAH,EAAM,MAAAI,EAAO,KAAM,OAAO,UAAUD,CAAK,EAAI,UAAY,OAAQ,EACrG,OAAOA,GAAU,UAAY,sBAAsB,KAAKA,CAAK,EAAU,CAAE,KAAAH,EAAM,MAAAI,EAAO,KAAM,MAAO,EAChG,CAAE,KAAAJ,EAAM,MAAAI,EAAO,KAAM,MAAO,CACrC,CAEO,IAAMC,GAAmCC,GAAY,CAC1D,GAAM,CAAE,KAAAC,EAAM,KAAAP,EAAM,MAAAQ,EAAO,KAAAC,EAAM,GAAAC,EAAI,SAAAC,CAAS,EAAIL,EAC5CM,EAAWJ,EAAM,OAAS,aAAeA,EAAM,YAAc,OAC7DK,EAAU,IAAM,CACpB,IAAMV,EAAQI,EAAK,SAAS,EAAE,OAAOP,CAAI,EACzC,OAAOG,GAAS,OAAOA,GAAU,UAAY,CAAC,MAAM,QAAQA,CAAK,EAAKA,EAAkC,CAAC,CAC3G,EAEMW,EAAmB,CACvB,GAAGP,EACH,SAAU,KAAkB,CAAE,GAAGA,EAAK,SAAS,EAAG,OAAQM,EAAQ,CAAE,GAEpE,SAAU,CAACE,EAAkBZ,IAAiBI,EAAK,SAASP,EAAM,CAAE,GAAGa,EAAQ,EAAG,CAACE,CAAQ,EAAGZ,CAAM,CAAc,CACpH,EAEMa,EAAUL,EAAS,cAAc,KAAK,EAC5CK,EAAQ,UAAY,gBACpBA,EAAQ,aAAa,OAAQ,OAAO,EACpC,IAAIC,EAA6D,CAAC,EAC9DC,EAAQ,GAEZ,SAASC,EAAKC,EAAmC,CAC/C,QAAWC,KAAOJ,EAAMI,EAAI,OAAO,UAAU,EAC7CJ,EAAOG,EAAY,IAAKE,GAAe,CACrC,IAAMC,EAAQ,GAAGb,CAAE,IAAIY,EAAW,IAAI,GAChCE,EAAgB,CAAE,KAAMF,EAAW,KAAM,MAAOA,EAAW,MAAO,GAAIA,EAAW,QAAU,CAAE,QAASA,EAAW,OAAQ,EAAI,CAAC,CAAG,EACjIG,EAA0B,CAAE,KAAM,QAAS,GAAI,GAAGhB,EAAK,EAAE,IAAIa,EAAW,IAAI,GAAI,MAAOA,EAAW,IAAK,EACvGI,EAASC,GAAa,CAAE,GAAGrB,EAAS,KAAMQ,EAAY,KAAMQ,EAAW,KAAM,MAAOE,EAAe,KAAMC,EAAc,GAAIF,CAAM,CAAC,EACxI,MAAO,CAAE,WAAAD,EAAY,OAAAI,CAAO,CAC9B,CAAC,EACDV,EAAQ,gBACN,GAAGC,EAAK,IAAI,CAAC,CAAE,WAAAK,EAAY,OAAAI,CAAO,IAAM,CACtC,IAAML,EAAMV,EAAS,cAAc,KAAK,EACxCU,EAAI,UAAY,cAChBA,EAAI,QAAQ,KAAUC,EAAW,KACjC,IAAMlB,EAAQO,EAAS,cAAc,OAAO,EAC5C,OAAAP,EAAM,QAAU,GAAGM,CAAE,IAAIY,EAAW,IAAI,GACxClB,EAAM,YAAckB,EAAW,MAC/BD,EAAI,OAAOjB,EAAOsB,EAAO,OAAO,EACzBL,CACT,CAAC,CACH,CACF,CAEA,MAAO,CACL,QAAAL,EACA,MAAO,IAAMC,EAAK,CAAC,GAAG,OAAO,MAAM,EACnC,QAAS,IAAMA,EAAK,QAASI,GAAQA,EAAI,OAAO,UAAU,CAAC,EAC3D,OAAOO,EAAO,CACZ,IAAMC,EAAShB,EAAQ,EACjBO,EAAcR,GAAY,OAAO,KAAKiB,CAAM,EAAE,IAAKC,GAAQ5B,GAAM4B,EAAKD,EAAOC,CAAG,CAAC,CAAC,EAClFA,EAAM,KAAK,UAAUV,CAAW,EAClCU,IAAQZ,IACVA,EAAQY,EACRX,EAAKC,CAAW,GAElB,OAAW,CAAE,WAAAE,EAAY,OAAAI,CAAO,IAAKT,EACnCS,EAAO,OAAO,CAAE,MAAOG,EAAOP,EAAW,IAAI,GAAK,KAAM,OAAAO,EAAQ,SAAUD,EAAM,SAAU,SAAU,GAAO,QAAS,EAAM,CAAC,CAE/H,CACF,CACF,EC3EA,IAAMG,GAAU,IAAI,IAAI,CACtB,IAAK,KAAM,IAAK,SAAU,IAAK,KAAM,IAAK,IAAK,KAAM,KAAM,KAAM,IAAK,KAAM,KAAM,KAAM,KACxF,aAAc,OAAQ,MAAO,OAAQ,KACvC,CAAC,EACKC,GAAuB,IAAI,IAAI,CAAC,SAAU,QAAS,SAAU,SAAU,QAAS,WAAY,WAAY,MAAO,MAAM,CAAC,EAEtHC,GAAY,IAAI,IAAI,CAAC,IAAK,MAAO,KAAM,KAAM,KAAM,KAAM,KAAM,aAAc,KAAK,CAAC,EACnFC,GAAa,IAAI,IAAI,CAAC,OAAQ,SAAU,QAAS,UAAW,QAAS,KAAK,CAAC,EAG1E,SAASC,GAAaC,EAAcC,EAAqB,WAAW,SAAkB,CAC3F,IAAMC,EAAMD,EAAS,cAAc,UAAU,EAC7CC,EAAI,UAAYF,EAChB,IAAMG,EAASC,GAAuB,CACpC,QAAWC,IAAQ,CAAC,GAAGD,EAAO,UAAU,EAAG,CACzC,GAAIC,EAAK,WAAa,KAAK,UAAW,SACtC,GAAIA,EAAK,WAAa,KAAK,aAAc,CACvCA,EAAK,OAAO,EACZ,QACF,CACA,IAAMC,EAAUD,EAChB,GAAIT,GAAqB,IAAIU,EAAQ,OAAO,EAAG,CAC7CA,EAAQ,OAAO,EACf,QACF,CAEA,GADAH,EAAMG,CAAO,EACT,CAACX,GAAQ,IAAIW,EAAQ,OAAO,EAAG,CACjCA,EAAQ,YAAY,GAAGA,EAAQ,UAAU,EACzC,QACF,CACA,IAAMC,EAAOD,EAAQ,UAAY,IAAMA,EAAQ,aAAa,MAAM,EAAI,KAChEE,EAAQX,GAAU,IAAIS,EAAQ,OAAO,EAAKA,EAAwB,OAAO,WAAW,KAAK,EAAE,YAAY,EAAI,GACjH,QAAWG,IAAa,CAAC,GAAGH,EAAQ,UAAU,EAAGA,EAAQ,gBAAgBG,EAAU,IAAI,EACnFF,GAAQ,sBAAsB,KAAKA,EAAK,KAAK,CAAC,GAAGD,EAAQ,aAAa,OAAQC,EAAK,KAAK,CAAC,EACzFC,GAASV,GAAW,IAAIU,CAAK,GAAGF,EAAQ,aAAa,QAAS,eAAeE,CAAK,GAAG,CAC3F,CACF,EACAL,EAAMD,EAAI,OAAO,EACjB,IAAMQ,EAAMT,EAAS,cAAc,KAAK,EACxC,OAAAS,EAAI,OAAOR,EAAI,OAAO,EACfQ,EAAI,SACb,CAGO,SAASC,GAAYC,EAA8B,CACxD,IAAMC,EAAOD,EAAM,KAAK,EACxB,MAAI,8BAA8B,KAAKC,CAAI,EAAUA,EACjD,mCAAmC,KAAKA,CAAI,EAAU,UAAUA,CAAI,GACpE,iCAAiC,KAAKA,CAAI,EAAU,WAAWA,CAAI,GAChE,IACT,CAGA,IAAMC,GAAgD,CACpD,CAAC,OAAQ,OAAQ,UAAU,EAC3B,CAAC,SAAU,SAAU,UAAU,EAC/B,CAAC,YAAa,YAAa,UAAU,EAErC,CAAC,UAAW,UAAW,UAAU,EACjC,CAAC,aAAc,sBAAuB,8JAA8J,EACpM,CAAC,aAAc,oBAAqB,oHAAoH,EACxJ,CAAC,YAAa,cAAe,gFAAgF,EAC7G,CAAC,cAAe,gBAAiB,gFAAgF,EACjH,CAAC,aAAc,eAAgB,gFAAgF,EAC/G,CAAC,OAAQ,aAAc,yJAAyJ,CAClL,EAEaC,GAA4B,CAAC,CAAE,KAAAC,EAAM,KAAAC,EAAM,KAAAZ,EAAM,GAAAa,EAAI,SAAAjB,EAAU,OAAAkB,EAASC,GAAc,EAAG,IAAM,CAC1G,IAAMC,EAAOpB,EAAS,cAAc,KAAK,EACzCoB,EAAK,GAAKH,EACVG,EAAK,UAAY,uBACjBA,EAAK,aAAa,OAAQ,SAAS,EACnCA,EAAK,aAAa,iBAAkB,MAAM,EAC1CA,EAAK,aAAa,kBAAmB,MAAM,EAC3C,IAAMC,EAAcjB,EAAK,SAAU,UAAe,GAC9CkB,EAAO,GACXF,EAAK,iBAAiB,QAAS,IAAM,CACnC,IAAMlB,EAAQJ,GAAasB,EAAK,UAAWpB,CAAQ,EACnDsB,EAAOpB,EACPa,EAAK,SAASC,EAAMd,EAAM,KAAK,IAAM,GAAK,KAAOA,CAAK,CACxD,CAAC,EACDkB,EAAK,iBAAiB,OAAQ,IAAM,CAE9BA,EAAK,YAAcE,IAAMF,EAAK,UAAYE,EAChD,CAAC,EACD,IAAMC,EAAUF,EAAcG,GAAkBJ,EAAMpB,EAAUkB,CAAM,EAAI,KACtEb,EAAuBe,EAC3B,OAAIG,IAEFlB,EAAUL,EAAS,cAAc,KAAK,EACtCK,EAAQ,UAAY,kBACpBA,EAAQ,aAAa,OAAQ,OAAO,EACpCe,EAAK,aAAa,kBAAmB,GAAGH,CAAE,QAAQ,EAClDZ,EAAQ,OAAOkB,EAAQ,IAAKA,EAAQ,QAASH,CAAI,GAE5C,CACL,QAAAf,EACA,MAAO,IAAMe,EAAK,MAAM,EACxB,QAAS,IAAMG,GAAS,QAAQ,EAChC,OAAOE,EAAO,CACRF,IACFA,EAAQ,IAAI,OAASE,EAAM,SACvBA,EAAM,WAAUF,EAAQ,QAAQ,OAAS,KAE/C,IAAMrB,EAAQJ,GAAa,OAAO2B,EAAM,OAAU,SAAWA,EAAM,MAAQ,GAAIzB,CAAQ,GACnFE,IAAUoB,GAAQtB,EAAS,gBAAkBoB,KAC3CA,EAAK,YAAclB,IAAOkB,EAAK,UAAYlB,GAC/CoB,EAAOpB,GAETkB,EAAK,aAAa,kBAAmB,OAAO,CAACK,EAAM,QAAQ,CAAC,EAC5DL,EAAK,aAAa,gBAAiB,OAAOK,EAAM,QAAQ,CAAC,EACzDL,EAAK,aAAa,eAAgB,OAAOK,EAAM,OAAO,CAAC,EACnDA,EAAM,aAAaL,EAAK,aAAa,mBAAoBK,EAAM,WAAW,CAChF,CACF,CACF,EAOA,SAASD,GAAkBJ,EAAmBM,EAAeR,EAAsB,CACjF,IAAMS,EAAMD,EAAI,cAAc,KAAK,EACnCC,EAAI,UAAY,kBAChBA,EAAI,aAAa,OAAQ,SAAS,EAClCA,EAAI,aAAa,aAAcT,EAAO,UAAU,EAGhD,IAAIU,EAA0B,KACxBC,EAAU,IAAM,CACpBT,EAAK,MAAM,EACX,IAAMU,EAAYJ,EAAI,aAAa,EAC/BE,GAAaE,IACfA,EAAU,gBAAgB,EAC1BA,EAAU,SAASF,CAAS,EAEhC,EACMG,EAAM,CAACC,EAAiBC,IAAmB,CAC/CJ,EAAQ,EACRH,EAAI,cAAcM,EAAS,GAAOC,CAAK,CACzC,EAEMC,EAAQR,EAAI,cAAc,QAAQ,EACxCQ,EAAM,UAAY,oBAClBA,EAAM,aAAa,aAAchB,EAAO,SAAS,EACjD,OAAW,CAACe,EAAOE,CAAG,GAAK,CAAC,CAAC,IAAK,WAAW,EAAG,CAAC,KAAM,SAAS,EAAG,CAAC,KAAM,YAAY,CAAC,EAAY,CACjG,IAAMC,EAASV,EAAI,cAAc,QAAQ,EACzCU,EAAO,MAAQH,EACfG,EAAO,YAAclB,EAAOiB,CAAG,EAC/BD,EAAM,OAAOE,CAAM,CACrB,CACAF,EAAM,iBAAiB,SAAU,IAAMH,EAAI,cAAe,IAAIG,EAAM,KAAK,GAAG,CAAC,EAE7E,IAAMG,EAAUX,EAAI,cAAc,KAAK,EACvCW,EAAQ,UAAY,cACpBA,EAAQ,OAAS,GACjB,IAAMC,EAAUZ,EAAI,cAAc,OAAO,EACzCY,EAAQ,UAAY,WACpBA,EAAQ,KAAO,MACfA,EAAQ,YAAc,WACtBA,EAAQ,aAAa,aAAcpB,EAAO,WAAW,EACrD,IAAMqB,EAAQb,EAAI,cAAc,QAAQ,EACxCa,EAAM,KAAO,SACbA,EAAM,UAAY,0BAClBA,EAAM,YAAcrB,EAAO,UAC3B,IAAMsB,EAASd,EAAI,cAAc,QAAQ,EACzCc,EAAO,KAAO,SACdA,EAAO,UAAY,0CACnBA,EAAO,YAActB,EAAO,WAC5BmB,EAAQ,OAAOC,EAASC,EAAOC,CAAM,EACrCD,EAAM,iBAAiB,QAAS,IAAM,CACpC,IAAME,EAAM/B,GAAY4B,EAAQ,KAAK,EACrC,GAAI,CAACG,EAAK,CACRH,EAAQ,aAAa,eAAgB,MAAM,EAC3C,MACF,CACAA,EAAQ,aAAa,eAAgB,OAAO,EAC5CT,EAAQ,EACRH,EAAI,cAAc,aAAc,GAAOe,CAAG,EAC1CJ,EAAQ,OAAS,EACnB,CAAC,EACDG,EAAO,iBAAiB,QAAS,IAAM,CACrCX,EAAQ,EACRH,EAAI,cAAc,SAAU,EAAK,EACjCW,EAAQ,OAAS,EACnB,CAAC,EACDC,EAAQ,iBAAiB,UAAYI,GAAU,CACzCA,EAAM,MAAQ,SAChBA,EAAM,eAAe,EACrBH,EAAM,MAAM,GACHG,EAAM,MAAQ,WACvBA,EAAM,eAAe,EACrBL,EAAQ,OAAS,GACjBR,EAAQ,EAEZ,CAAC,EAED,IAAMc,EAAU9B,GAAM,IAAI,CAAC,CAACsB,EAAKH,EAASY,CAAI,IAAM,CAClD,IAAMC,EAASnB,EAAI,cAAc,QAAQ,EACzC,OAAAmB,EAAO,KAAO,SACdA,EAAO,UAAY,mBACnBA,EAAO,aAAa,aAAc3B,EAAOiB,CAAG,CAAC,EAC7CU,EAAO,MAAQ3B,EAAOiB,CAAG,EACzBU,EAAO,UAAYD,EACnBC,EAAO,cAAc,KAAK,GAAG,aAAa,cAAe,MAAM,EAC3D,CAAC,OAAQ,SAAU,YAAa,SAAS,EAAE,SAASb,CAAO,GAAGa,EAAO,aAAa,eAAgB,OAAO,EAE7GA,EAAO,iBAAiB,YAAcH,GAAUA,EAAM,eAAe,CAAC,EACtEG,EAAO,iBAAiB,QAAS,IAAM,CACrC,GAAIb,IAAY,UAAW,OAAOD,EAAI,cAAeG,EAAM,QAAU,KAAO,MAAQ,MAAM,EAC1F,GAAIF,IAAY,aAAc,OAAOD,EAAIC,CAAO,EAChDK,EAAQ,OAAS,GACjBC,EAAQ,MAAQ,GAChBA,EAAQ,MAAM,CAChB,CAAC,EACMO,CACT,CAAC,EACDlB,EAAI,OAAOO,EAAO,GAAGS,CAAO,EAG5B,IAAMG,EAAQ,CAACZ,EAAO,GAAGS,CAAO,EAChCG,EAAM,QAAQ,CAACC,EAAMC,IAAOD,EAAK,SAAWC,IAAM,EAAI,EAAI,EAAG,EAC7DrB,EAAI,iBAAiB,UAAYe,GAAU,CACzC,GAAIA,EAAM,MAAQ,cAAgBA,EAAM,MAAQ,YAAa,OAC7D,IAAMO,EAAKH,EAAM,QAAQpB,EAAI,aAAkC,EAC/D,GAAIuB,EAAK,EAAG,OACZ,IAAMC,EAAM,iBAAiBvB,CAAG,EAAE,YAAc,MAC1CwB,EAAQT,EAAM,MAAQ,eAAkBQ,EAAM,EAAI,GAClDE,EAAON,GAAOG,EAAKE,EAAOL,EAAM,QAAUA,EAAM,MAAM,EAC5DJ,EAAM,eAAe,EACrBI,EAAM,QAASC,GAAUA,EAAK,SAAWA,IAASK,EAAO,EAAI,EAAG,EAChEA,EAAK,MAAM,CACb,CAAC,EAGD,IAAMC,EAAU,IAAM,CACpB,IAAMvB,EAAYJ,EAAI,aAAa,EACnC,GAAI,CAACI,GAAa,CAACA,EAAU,YAAc,CAACV,EAAK,SAASU,EAAU,UAAU,EAAG,OACjFF,EAAYE,EAAU,WAAW,CAAC,EAAE,WAAW,EAC/C,IAAMwB,EAAQ,OAAO5B,EAAI,oBAAoB,aAAa,GAAK,EAAE,EAAE,YAAY,EAAE,QAAQ,QAAS,EAAE,EACpGQ,EAAM,MAAQoB,IAAU,MAAQA,IAAU,KAAOA,EAAQ,IACzD,QAAWT,KAAUF,EAAS,CAC5B,IAAMX,EAAUnB,GAAM8B,EAAQ,QAAQE,CAAM,CAAC,EAAE,CAAC,EAC5CA,EAAO,aAAa,cAAc,GAAGA,EAAO,aAAa,eAAgB,OAAOb,IAAY,UAAYsB,IAAU,KAAQ5B,EAAI,oBAAoBM,CAAO,GAAK,EAAM,CAAC,CAC3K,CACF,EACA,OAAAN,EAAI,iBAAiB,kBAAmB2B,CAAO,EACxC,CAAE,IAAA1B,EAAK,QAAAU,EAAS,QAAS,IAAMX,EAAI,oBAAoB,kBAAmB2B,CAAO,CAAE,CAC5F,CAEO,IAAME,GAA4B,CAAC,CAAE,KAAAxC,EAAM,KAAAC,EAAM,GAAAC,EAAI,SAAAjB,EAAU,OAAAkB,EAASC,GAAc,EAAG,IAAM,CACpG,IAAMd,EAAUL,EAAS,cAAc,KAAK,EAC5CK,EAAQ,UAAY,UACpB,IAAMe,EAAOpB,EAAS,cAAc,UAAU,EAC9CoB,EAAK,GAAKH,EACVG,EAAK,UAAY,+BACjBA,EAAK,WAAa,GAClB,IAAMoC,EAAQxD,EAAS,cAAc,KAAK,EAC1C,OAAAwD,EAAM,UAAY,gBAClBA,EAAM,OAAS,GACfnD,EAAQ,OAAOe,EAAMoC,CAAK,EAC1BpC,EAAK,iBAAiB,QAAS,IAAM,CACnC,GAAIA,EAAK,MAAM,KAAK,IAAM,GAAI,CAC5BoC,EAAM,OAAS,GACfzC,EAAK,SAASC,EAAM,IAAI,EACxB,MACF,CACA,GAAI,CACF,IAAMyC,EAAS,KAAK,MAAMrC,EAAK,KAAK,EACpCoC,EAAM,OAAS,GACfzC,EAAK,SAASC,EAAMyC,CAAM,CAC5B,MAAQ,CACND,EAAM,OAAS,GACfA,EAAM,YAActC,EAAO,WAC7B,CACF,CAAC,EACM,CACL,QAAAb,EACA,MAAO,IAAMe,EAAK,MAAM,EACxB,OAAOK,EAAO,CACZ,GAAIzB,EAAS,gBAAkBoB,EAAM,CACnC,IAAMR,EAAOa,EAAM,QAAU,MAAQA,EAAM,QAAU,OAAY,GAAK,KAAK,UAAUA,EAAM,MAAO,KAAM,CAAC,EACrGL,EAAK,QAAUR,IAAMQ,EAAK,MAAQR,EACxC,CACAQ,EAAK,SAAWK,EAAM,SACtBL,EAAK,aAAa,eAAgB,OAAOK,EAAM,SAAW,CAAC+B,EAAM,MAAM,CAAC,CAC1E,CACF,CACF,ECjSA,IAAME,GAAQ,IAAI,QAGlB,SAASC,GAAOC,EAAsB,CACpC,IAAIC,EAAOH,GAAM,IAAIE,CAAI,EACzB,OAAIC,IAAS,SACXA,EAAO,KAAK,MAAM,KAAK,OAAO,EAAI,UAAW,IAAM,EACnDH,GAAM,IAAIE,EAAMC,CAAI,GAEfA,CACT,CAGA,SAASC,GAAKD,EAAcE,EAAsB,CAChD,IAAIC,EAAIH,EAAO,WACf,QAASI,EAAI,EAAGA,EAAIF,EAAK,OAAQE,IAC/BD,EAAI,KAAK,KAAKA,EAAID,EAAK,WAAWE,CAAC,EAAG,UAAU,EAChDD,GAAKA,IAAM,GAEb,OAAOA,IAAM,CACf,CAGA,SAASE,GAAQL,EAA4B,CAC3C,IAAIM,EAAIN,EACR,MAAO,IAAM,CACXM,EAAKA,EAAI,WAAc,EACvB,IAAIC,EAAI,KAAK,KAAKD,EAAKA,IAAM,GAAK,EAAIA,CAAC,EACvC,OAAAC,EAAKA,EAAI,KAAK,KAAKA,EAAKA,IAAM,EAAI,GAAKA,CAAC,EAAKA,IACpCA,EAAKA,IAAM,MAAS,GAAK,UACpC,CACF,CAOO,SAASC,GAAgBC,EAAuBV,EAAcG,EAAcQ,EAAuC,CACxH,GAAIA,EAAK,SAAU,UAAe,GAAM,MAAO,CAAC,GAAGD,CAAO,EAC1D,IAAME,EAAK,CAACC,EAAWC,IAAkBD,EAAmCC,CAAI,IAAM,GAChFC,EAAQL,EAAQ,OAAQM,GAAM,CAACJ,EAAGI,EAAG,OAAO,GAAK,CAACJ,EAAGI,EAAG,WAAW,CAAC,EACpEC,EAAOX,GAAQJ,GAAKH,GAAOC,CAAI,EAAGG,CAAI,CAAC,EAE7C,QAASE,EAAIU,EAAM,OAAS,EAAGV,EAAI,EAAGA,IAAK,CACzC,IAAMa,EAAI,KAAK,MAAMD,EAAK,GAAKZ,EAAI,EAAE,EACrC,CAACU,EAAMV,CAAC,EAAGU,EAAMG,CAAC,CAAC,EAAI,CAACH,EAAMG,CAAC,EAAGH,EAAMV,CAAC,CAAC,CAC5C,CACA,OAAAU,EAAM,KAAK,GAAGL,EAAQ,OAAQM,GAAM,CAACJ,EAAGI,EAAG,OAAO,GAAKJ,EAAGI,EAAG,WAAW,CAAC,CAAC,EACnEN,EAAQ,IAAKM,GAAOJ,EAAGI,EAAG,OAAO,EAAIA,EAAKD,EAAM,MAAM,CAAQ,CACvE,CChDO,IAAMI,GAA8B,CAAC,CAAE,KAAAC,EAAM,KAAAC,EAAM,MAAAC,EAAO,KAAAC,EAAM,GAAAC,EAAI,SAAAC,CAAS,IAAM,CACxF,IAAMC,EAAMJ,EACNK,EAAOD,EAAI,SAAW,WAAa,QACnCE,EAAO,CAAwCC,EAAQC,EAAgC,CAAC,KAAMC,IAAgC,CAClI,IAAMC,EAAUP,EAAS,cAAcI,CAAG,EAC1C,OAAW,CAACI,EAAKC,CAAK,IAAK,OAAO,QAAQJ,CAAK,EAAGE,EAAQ,aAAaC,EAAKC,CAAK,EACjF,OAAAF,EAAQ,OAAO,GAAGD,CAAQ,EACnBC,CACT,EACMG,EAAQP,EAAK,QAAS,CAAE,GAAAJ,EAAI,MAAO,iBAAkB,CAAC,EAC5DW,EAAM,OAAOP,EAAK,QAAS,CAAC,EAAGA,EAAK,KAAM,CAAC,EAAGA,EAAK,KAAM,CAAE,MAAO,KAAM,CAAC,EAAG,GAAGF,EAAI,QAAQ,IAAKU,GAAMR,EAAK,KAAM,CAAE,MAAO,KAAM,EAAGQ,EAAE,KAAK,CAAC,CAAC,CAAC,CAAC,EAC9I,IAAMC,EAAOT,EAAK,OAAO,EACnBU,EAA6B,CAAC,EAC9BC,EAAsB,CAAC,EAC7B,QAAWC,KAAOC,GAAaf,EAAI,KAAMN,EAAMC,EAAME,CAAI,EAAG,CAC1D,IAAMmB,EAAKd,EAAK,KAAM,CAAE,KAAMD,IAAS,QAAU,aAAe,QAAS,aAAca,EAAI,KAAM,CAAC,EAClGD,EAAK,KAAKG,CAAE,EACZA,EAAG,OAAOd,EAAK,KAAM,CAAE,MAAO,KAAM,EAAGY,EAAI,KAAK,CAAC,EACjD,QAAWG,KAAUjB,EAAI,QAAS,CAChC,IAAMkB,EAAQhB,EAAK,QAAS,CAAE,KAAMD,EAAM,KAAM,GAAGH,CAAE,IAAIgB,EAAI,KAAK,GAAI,MAAO,OAAOG,EAAO,KAAK,EAAG,WAAY,OAAOH,EAAI,KAAK,EAAG,aAAc,GAAGA,EAAI,KAAK,KAAKG,EAAO,KAAK,EAAG,CAAC,EACjLC,EAAM,iBAAiB,SAAU,IAAM,CACrC,GAAIlB,EAAI,cAAgBkB,EAAM,QAAS,QAAWC,KAASP,EAAYO,EAAM,QAAUD,EAAM,OAASC,IAAUD,IAAOC,EAAM,QAAU,IACvIC,EAAK,CACP,CAAC,EACDR,EAAO,KAAKM,CAAK,EAEjBF,EAAG,OAAOd,EAAK,KAAM,CAAC,EAAGA,EAAK,QAAS,CAAE,MAAO,gBAAiB,EAAGgB,EAAOhB,EAAK,OAAQ,CAAE,MAAO,kBAAmB,EAAGe,EAAO,KAAK,CAAC,CAAC,CAAC,CACxI,CACAN,EAAK,OAAOK,CAAE,CAChB,CACAP,EAAM,OAAOE,CAAI,EACjB,IAAML,EAAUJ,EAAK,MAAO,CAAE,MAAO,WAAY,EAAGO,CAAK,EAGnDY,EAAeC,GAAiBtB,EAAI,QAAQ,KAAMU,GAAM,OAAOA,EAAE,KAAK,IAAMY,CAAI,GAAG,OAASA,EAClG,SAASF,GAAO,CACd,IAAMZ,EAA+B,CAAC,EACtC,QAAWM,KAAOd,EAAI,KAAM,CAC1B,IAAMuB,EAASX,EAAO,OAAQY,GAAMA,EAAE,QAAQ,MAAW,OAAOV,EAAI,KAAK,GAAKU,EAAE,OAAO,EAAE,IAAKA,GAAMH,EAAYG,EAAE,KAAK,CAAC,GACpHxB,EAAI,SAAWuB,EAAO,OAASA,EAAO,SAAW,KAAGf,EAAM,OAAOM,EAAI,KAAK,CAAC,EAAKd,EAAI,SAAWuB,EAASA,EAAO,CAAC,EACtH,CACA7B,EAAK,SAASC,EAAM,OAAO,KAAKa,CAAK,EAAE,OAAUA,EAAkB,IAAI,CACzE,CAEA,MAAO,CACL,QAAAF,EACA,MAAO,KAAOM,EAAO,KAAMY,GAAMA,EAAE,OAAO,GAAKZ,EAAO,CAAC,IAAI,MAAM,EACjE,OAAOa,EAAO,CACZ,IAAMjB,EAAQiB,EAAM,OAAS,OAAOA,EAAM,OAAU,UAAY,CAAC,MAAM,QAAQA,EAAM,KAAK,EAAKA,EAAM,MAAoC,CAAC,EAC1I,QAAWP,KAASN,EAAQ,CAC1B,IAAMc,EAASlB,EAAMU,EAAM,QAAQ,KAAU,EAAE,EACzCS,EAAS,MAAM,QAAQD,CAAM,EAAIA,EAAO,IAAI,MAAM,EAA4BA,GAAW,KAAO,CAAC,EAAI,CAAC,OAAOA,CAAM,CAAC,EAC1HR,EAAM,QAAUS,EAAO,SAAST,EAAM,KAAK,EAC3CA,EAAM,SAAWO,EAAM,QACzB,CAGA,GAFAhB,EAAM,aAAa,eAAgB,OAAOgB,EAAM,OAAO,CAAC,EAEpDxB,IAAS,QAAS,QAAWe,KAAMH,EAAMe,GAAQZ,EAAI,gBAAiB,OAAOS,EAAM,QAAQ,CAAC,EAE5FA,EAAM,YAAahB,EAAM,aAAa,mBAAoBgB,EAAM,WAAW,EAC1EhB,EAAM,gBAAgB,kBAAkB,CAC/C,CACF,CACF,ECzDA,IAAMoB,GAAQ,IACRC,GAAS,IAETC,GAAM,UACNC,GAAS,kFAGTC,GAAWC,GAAmB,KAAK,MAAOA,EAAO,OAAS,EAAK,CAAC,GAAKA,EAAO,SAAS,IAAI,EAAI,EAAIA,EAAO,SAAS,GAAG,EAAI,EAAI,GAC5HC,GAASC,GAAoBA,EAAK,MAAQA,EAAK,KAAO,GAG/CC,GAAiC,CAAC,CAAE,KAAAC,EAAM,KAAAC,EAAM,MAAAC,EAAO,KAAAC,EAAM,GAAAC,EAAI,SAAAC,EAAU,OAAAC,EAAQ,OAAAC,CAAO,IAAM,CAC3G,IAAMC,EAAQC,GAASH,EAAQC,CAAM,EAC/BG,EAAOC,GAAMN,CAAQ,EACrBO,EAAUT,EAAK,SAAW,CAAC,EAC3BU,EAAQD,EAAQ,MAChBE,EAAM,OAAOD,GAAU,UAAY,iBAAiB,KAAKA,CAAK,EAAIA,EAAQpB,GAC1EsB,EAAWH,EAAQ,SACnBI,EAAQ,OAAOD,GAAa,UAAYA,EAAW,EAAIA,EAAW,EAClEE,EAAcL,EAAQ,YACtBM,EAASR,EAAK,SAAU,CAAE,MAAO,mBAAoB,MAAO,OAAOnB,EAAK,EAAG,OAAQ,OAAOC,EAAM,EAAG,KAAM,MAAO,aAAcgB,EAAM,YAAa,CAAC,EAClJW,EAAOT,EAAK,OAAQ,CAAE,MAAO,oBAAqB,cAAe,MAAO,EAAGP,EAAK,aAAeK,EAAM,QAAQ,EAC7GY,EAAQV,EAAK,MAAO,CAAE,MAAO,qBAAsB,IAAKR,EAAM,MAAO,OAAQ,EAAG,CAAC,EACjFmB,EAAQX,EAAK,QAAS,CAAE,KAAM,OAAQ,MAAO,8BAA+B,aAAcF,EAAM,cAAe,YAAaA,EAAM,cAAe,aAAc,MAAO,CAAC,EACvKc,EAAUd,GAAkBE,EAAK,SAAU,CAAE,KAAM,SAAU,MAAO,2BAA4B,OAAQ,EAAG,EAAGF,CAAK,EACnHe,EAAOD,EAAOd,EAAM,IAAI,EACxBgB,EAAQF,EAAOd,EAAM,YAAY,EACvCgB,EAAM,UAAU,IAAI,oBAAoB,EAExC,IAAMC,EAASb,EAAQ,SAAc,GAAOU,EAAOd,EAAM,eAAe,EAAI,KACtEV,EAAOY,EAAK,QAAS,CAAE,KAAM,OAAQ,OAAQ,UAAW,MAAO,aAAc,SAAU,KAAM,cAAe,MAAO,CAAC,EACpHgB,EAAUhB,EACd,MACA,CAAE,GAAAN,EAAI,MAAO,eAAgB,KAAM,OAAQ,EAC3CM,EAAK,MAAO,CAAE,MAAO,kBAAmB,EAAGQ,EAAQE,EAAOD,CAAI,EAC9D,GAAI,OAAOF,GAAgB,UAAYA,EAAc,CAACP,EAAK,OAAQ,CAAE,MAAO,qBAAsB,EAAGO,CAAW,CAAC,EAAI,CAAC,EACtHP,EAAK,MAAO,CAAE,MAAO,oBAAqB,EAAGW,EAAOE,EAAM,GAAIE,EAAS,CAACA,EAAQ3B,CAAI,EAAI,CAAC,EAAI0B,CAAK,CACpG,EAEMG,EAAM,IAAM,CAChB,IAAMC,EAAUV,EAAO,WAAW,IAAI,EACtC,OAAIU,IACFA,EAAQ,YAAcA,EAAQ,UAAYd,EAC1Cc,EAAQ,UAAYZ,EACpBY,EAAQ,QAAUA,EAAQ,SAAW,SAEhCA,CACT,EAEIC,EAAsB,KACtBC,EAAW,GAEXC,EAA2B,KAC3BC,EAAqB,CAAC,EACtBC,EAAqB,KAEnBC,EAAQ,IAAM,CAACF,EAAQ,QAAU,CAACD,EAExC,SAASI,GAAS,CAChB,IAAMP,EAAUD,EAAI,EACpB,GAAKC,EACL,CAAAA,EAAQ,UAAU,EAAG,EAAGrC,GAAOC,EAAM,EACjCuC,IACFH,EAAQ,KAAO,eAAelC,EAAM,GACpCkC,EAAQ,UAAY,SACpBA,EAAQ,aAAe,SACvBA,EAAQ,SAASG,EAAWxC,GAAQ,EAAGC,GAAS,EAAGD,GAAQ,EAAE,GAE/D,QAAW6C,KAAUJ,EAAS,CAC5BJ,EAAQ,UAAU,EAClBA,EAAQ,IAAIQ,EAAO,CAAC,EAAE,EAAGA,EAAO,CAAC,EAAE,EAAGpB,EAAQ,EAAG,EAAG,KAAK,GAAK,CAAC,EAC/DY,EAAQ,KAAK,EACb,QAASS,EAAI,EAAGA,EAAID,EAAO,OAAQC,IAAKC,EAAKF,EAAOC,EAAI,CAAC,EAAGD,EAAOC,CAAC,CAAC,CACvE,EACF,CACA,SAASC,EAAKC,EAAaC,EAAW,CACpC,IAAMZ,EAAUD,EAAI,EACpBC,GAAS,UAAU,EACnBA,GAAS,OAAOW,EAAK,EAAGA,EAAK,CAAC,EAC9BX,GAAS,OAAOY,EAAG,EAAGA,EAAG,CAAC,EAC1BZ,GAAS,OAAO,CAClB,CACA,SAASa,GAAO,CACdT,EAAU,CAAC,EACXD,EAAY,KACZI,EAAO,CACT,CAEA,SAASO,GAAO,CAEd,GADAvB,EAAK,OAAS,CAACe,EAAM,EACjBA,EAAM,EACR,OAAAL,EAAO,KACA7B,EAAK,SAASC,EAAM,IAAI,EAEjC,IAAI0C,EACJ,GAAI,CACFA,EAAMzB,EAAO,UAAU,WAAW,CACpC,MAAQ,CACN,MACF,CACA,GAAI,CAACyB,EAAK,OACV,IAAMC,EAAOD,EAAI,MAAMA,EAAI,QAAQ,GAAG,EAAI,CAAC,EAC3Cd,EAAOe,EACP5C,EAAK,SAASC,EAAM,CAAE,KAAM,gBAAiB,KAAM,YAAa,KAAMN,GAAQiD,CAAI,EAAG,KAAAA,EAAM,GAAIb,GAAa,CAACC,EAAQ,OAAS,CAAE,KAAMD,CAAU,EAAI,CAAC,CAAG,CAAC,CAC3J,CAEA,SAASc,EAAGC,EAAqB,CAC/B,IAAMC,EAAM7B,EAAO,sBAAsB,EACzC,MAAO,CAAE,GAAK4B,EAAM,QAAUC,EAAI,MAAQxD,IAAUwD,EAAI,OAASxD,IAAQ,GAAKuD,EAAM,QAAUC,EAAI,KAAOvD,IAAWuD,EAAI,QAAUvD,GAAQ,CAC5I,CAEA0B,EAAO,iBAAiB,cAAgB4B,GAAU,CAC5ChB,GAAYgB,EAAM,SAAW,IACjCA,EAAM,eAAe,EACrB5B,EAAO,oBAAoB4B,EAAM,SAAS,EAC1Cb,EAAOY,EAAGC,CAAK,EACfd,EAAQ,KAAK,CAACC,CAAI,CAAC,EACnBd,EAAK,OAAS,GACdgB,EAAO,EACT,CAAC,EACDjB,EAAO,iBAAiB,cAAgB4B,GAAU,CAChD,GAAI,CAACb,EAAM,OACX,IAAMe,EAAOH,EAAGC,CAAK,EACrBR,EAAKL,EAAMe,CAAI,EACfhB,EAAQA,EAAQ,OAAS,CAAC,EAAE,KAAKgB,CAAI,EACrCf,EAAOe,CACT,CAAC,EACD,IAAMC,EAAM,IAAM,CACXhB,IACLA,EAAO,KACPS,EAAK,EACP,EACAxB,EAAO,iBAAiB,YAAa+B,CAAG,EACxC/B,EAAO,iBAAiB,gBAAiB+B,CAAG,EAG5C5B,EAAM,iBAAiB,QAAS,IAAM,CACpC6B,EAAQ,EACRlB,EAAU,CAAC,EACXD,EAAYV,EAAM,MAAM,KAAK,GAAK,KAClCc,EAAO,EACPO,EAAK,CACP,CAAC,EAEDnB,EAAK,iBAAiB,QAAS,IAAM,CACnCS,EAAQ,IAAI,EACZG,EAAO,EACPO,EAAK,CACP,CAAC,EAEDjB,GAAQ,iBAAiB,QAAS,IAAM3B,EAAK,MAAM,CAAC,EACpDA,EAAK,iBAAiB,SAAU,IAAM,CACpC,IAAMqD,EAASrD,EAAK,QAAQ,CAAC,EAC7BA,EAAK,MAAQ,GACTqD,GAAaC,GAASD,CAAM,EAAE,KAAME,GAAUrD,EAAK,SAASC,EAAMoD,CAAK,CAAC,CAC9E,CAAC,EAED7B,EAAM,iBAAiB,QAAS,IAAM,CACpCiB,EAAK,EACLZ,EAAO,KACPR,EAAM,MAAQ,GACd6B,EAAQ,EACRlD,EAAK,SAASC,EAAM,IAAI,EACxBoB,EAAM,MAAM,CACd,CAAC,EAED,SAAS6B,GAAU,CACjB9B,EAAM,OAAS,GACfF,EAAO,OAAS,EAClB,CAEA,MAAO,CACL,QAAAQ,EACA,MAAO,KAAOL,EAAM,OAASG,EAAQH,GAAO,MAAM,EAClD,OAAOiC,EAAO,CACZxB,EAAWwB,EAAM,SACjB,IAAMD,EAAQC,EAAM,OAAS,OAAOA,EAAM,OAAU,UAAY,CAAC,MAAM,QAAQA,EAAM,KAAK,EAAKA,EAAM,MAAsB,KACrHC,EAAOlD,EAAS,gBAAkBgB,EACxC,GAAIgC,GAASxD,GAAMwD,CAAK,IAAMxB,EAAM,CAElC,IAAM2B,EAAMH,EAAM,KAAO,QAAQA,EAAM,IAAI,WAAWA,EAAM,IAAI,GAAMA,EAAM,KAAO,GAC/EjC,EAAM,aAAa,KAAK,IAAMoC,IAAKpC,EAAM,IAAMoC,GACnDpC,EAAM,OAAS,GACfF,EAAO,OAAS,GAChBW,EAAO,KACPY,EAAK,EACDc,IAAMlC,EAAM,MAAQgC,EAAM,MAAQ,GACxC,MAAYA,KACNxB,IAAS,MAAQ,CAACT,EAAM,UAE1BS,EAAO,KACPY,EAAK,EACDc,IAAMlC,EAAM,MAAQ,KAE1B6B,EAAQ,GAEV/B,EAAK,OAASW,GAAY,CAACI,EAAM,GAAK,CAACd,EAAM,OAC7CC,EAAM,OAASS,EACfT,EAAM,SAAWS,EACjBN,EAAM,OAASM,GAAY,CAACuB,EAC5B9B,EAAK,OAASO,GAAY,CAACE,EAAQ,QAAU,CAACZ,EAAM,OAChDK,IAAQA,EAAO,OAASK,GAC5BZ,EAAO,UAAU,OAAO,sBAAuBY,CAAQ,EACvD2B,GAAc/B,EAAS4B,CAAK,EAC5BjC,EAAM,aAAa,eAAgB,OAAOiC,EAAM,OAAO,CAAC,CAC1D,CACF,CACF,ECtNO,IAAMI,GAA8B,CAAC,CAAE,KAAAC,EAAM,KAAAC,EAAM,MAAAC,EAAO,KAAAC,EAAM,GAAAC,EAAI,SAAAC,EAAU,OAAAC,EAAQ,OAAAC,EAAS,IAAK,IAAM,CAC/G,IAAMC,EAAQC,GAASH,EAAQC,CAAM,EAC/BG,EAAOC,GAAMN,CAAQ,EACrBO,EAAOC,GAAwBA,KAAOX,GAAS,OAAQA,EAAkCW,CAAG,GAAM,SAAaX,EAAkCW,CAAG,EAAe,OACnKC,EAAMF,EAAI,KAAK,GAAK,EACpBG,EAAMH,EAAI,KAAK,GAAK,IACpBI,EAAO,OAAOb,EAAK,SAAU,MAAY,UAAYA,EAAK,QAAQ,KAAU,EAAIA,EAAK,QAAQ,KAAU,EACvGc,EAAWf,EAAM,OAAS,UAAY,EAAIA,EAAM,OAAS,SAAWA,EAAM,OAASA,EAAM,OAAO,CAAC,EAAI,KAAK,IAAI,EAAG,CAAC,KAAK,MAAM,KAAK,MAAMc,CAAI,CAAC,CAAC,EAC9IE,EAAWC,GAAcC,GAAaD,EAAGF,EAAUV,CAAM,EAEzDc,EAAQX,EAAK,QAAS,CAAE,GAAAN,EAAI,KAAM,QAAS,MAAO,kBAAmB,IAAK,OAAOU,CAAG,EAAG,IAAK,OAAOC,CAAG,EAAG,KAAM,OAAOC,CAAI,CAAE,CAAC,EAC7HM,EAASZ,EAAK,SAAU,CAAE,MAAO,kBAAmB,IAAKN,EAAI,cAAe,MAAO,CAAC,EAEpFmB,EAAW,CAACpB,EAAK,SAAU,WAAeA,EAAK,SAAU,QAAW,EAAE,IAAKqB,GAAO,OAAOA,GAAM,SAAWA,EAAI,EAAG,EACjHC,EAAM,CAACN,EAAWO,IAAchB,EAAK,OAAQ,CAAE,MAAOgB,EAAI,iBAAmB,MAAU,EAAGR,EAAQC,CAAC,EAAG,GAAII,EAASG,CAAC,EAAI,CAAChB,EAAK,OAAQ,CAAE,MAAO,gBAAiB,EAAGa,EAASG,CAAC,CAAC,CAAC,EAAI,CAAC,CAAE,EACtLC,EAAOjB,EAAK,MAAO,CAAE,MAAO,iBAAkB,cAAe,MAAO,EAAGe,EAAIX,EAAK,CAAC,EAAGW,EAAIV,EAAK,CAAC,CAAC,EAC/Fa,EAAQC,GAAexB,EAAUG,EAAO,IAAM,CAClDR,EAAK,SAASC,EAAM,IAAI,EACxBoB,EAAM,MAAM,CACd,CAAC,EACKS,EAAUpB,EAAK,MAAO,CAAE,MAAO,WAAY,EAAGA,EAAK,MAAO,CAAE,MAAO,iBAAkB,EAAGW,EAAOC,CAAM,EAAGK,EAAMC,EAAM,MAAM,EAChI,OAAIL,EAAS,KAAK,OAAO,GAAGF,EAAM,aAAa,mBAAoBE,EAAS,OAAO,OAAO,EAAE,KAAK,UAAK,CAAC,EACvGF,EAAM,iBAAiB,QAAS,IAAMrB,EAAK,SAASC,EAAM,OAAOoB,EAAM,KAAK,CAAC,CAAC,EAEvE,CACL,QAAAS,EACA,MAAO,IAAMT,EAAM,MAAM,EACzB,OAAOU,EAAO,CACZ,IAAMC,EAAQ,OAAOD,EAAM,OAAU,SAAWA,EAAM,MAAQ,KAC9DD,EAAQ,UAAU,OAAO,kBAAmBE,IAAU,IAAI,EAE1D,IAAMC,EAAK,OAAOD,IAAUlB,EAAMC,GAAO,CAAC,EACtCM,EAAM,QAAUY,IAAIZ,EAAM,MAAQY,GACtCX,EAAO,YAAcU,IAAU,KAAO,SAAMd,EAAQc,CAAK,EACzDX,EAAM,aAAa,iBAAkBW,IAAU,KAAOxB,EAAM,YAAcU,EAAQc,CAAK,CAAC,EACxFX,EAAM,SAAWU,EAAM,SACvBH,EAAM,MAAMG,CAAK,EACjBH,EAAM,KAAKI,IAAU,IAAI,EACzBE,GAAcb,EAAOU,CAAK,CAC5B,CACF,CACF,EC1CO,SAASI,GAAUC,EAA4BC,EAAyBC,EAA2B,CACxG,IAAMC,EAASC,GAAeJ,EAAQ,KAAM,GAAM,EAAE,WAAa,EAAE,QAAUI,CAAC,EAC9E,OAAOD,EAAMD,CAAK,EAAI,CAACA,CAAK,EAAI,CAAC,GAAGD,EAAI,OAAQG,GAAM,CAACD,EAAMC,CAAC,CAAC,EAAGF,CAAK,CACzE,CAOO,SAASG,GAAQC,EAAYC,EAAqBC,EAAiB,CACxE,IAAMC,EAAOD,EAAK,UAAU,KAAME,GAAMA,EAAE,SAAW,SAAcA,EAAE,MAAQ,MAAU,IAAQA,EAAE,QAAU,SAAS,GAAG,OACjHC,EAAUF,EAAOH,EAAK,OAAQ,CAAE,MAAO,kBAAmB,KAAM,QAAS,CAAC,EAAI,KACpF,MAAO,CACL,QAAAK,EAEA,KAAKC,EAAe,CAClB,IAAMC,EAAO,CAAC,CAACJ,GAAQG,GAASH,EAChC,OAAIE,GAASG,GAAQH,EAASE,EAAOE,GAAOR,EAAM,KAAM,CAAE,EAAGE,CAAe,CAAC,EAAI,EAAE,EAC5EI,CACT,CACF,CACF,CAGO,SAASG,GAAOC,EAAoBT,EAAiB,CAC1D,IAAMU,EAAUV,EAAK,SAAU,QAC3BU,IAAY,MAAOD,EAAM,UAAU,IAAI,gBAAgB,EAClD,OAAOC,GAAY,UAAYA,GAAW,IACjDD,EAAM,UAAU,IAAI,oBAAoB,EACxCA,EAAM,MAAM,YAAY,sBAAuB,OAAO,KAAK,IAAI,EAAG,KAAK,MAAMC,CAAO,CAAC,CAAC,CAAC,EAE3F,CCxBO,IAAMC,GAAmCC,GAAYC,GAAMD,EAAS,EAAK,EACnEE,GAA+BF,GAAYC,GAAMD,EAAS,EAAI,EAE3E,SAASC,GAAM,CAAE,KAAAE,EAAM,KAAAC,EAAM,MAAAC,EAAO,GAAAC,EAAI,SAAAC,EAAU,OAAAC,EAAQ,OAAAC,CAAO,EAAkBC,EAAiB,CAClG,IAAMC,EAAQC,GAASJ,EAAQC,CAAM,EAC/BI,EAAOC,GAAMP,CAAQ,EACrBQ,EAAoBV,EAAM,OAAS,YAAcA,EAAM,QAAU,CAAC,EAClEW,EAAMX,EAAM,OAAS,aAAeA,EAAM,aAAe,IAAQ,CAACK,EAClEO,EAAS,GAAGX,CAAE,QACdY,EAAQL,EAAK,QAAS,CAC1B,GAAAP,EACA,KAAM,OACN,MAAO,0BACP,KAAM,WACN,oBAAqB,OACrB,gBAAiB,QACjB,gBAAiBW,EACjB,aAAc,MACd,YAAaN,EAAM,MACrB,CAAC,EACKQ,EAAON,EAAK,KAAM,CAAE,GAAII,EAAQ,MAAO,aAAc,KAAM,UAAW,OAAQ,EAAG,CAAC,EAClFG,EAAQP,EAAK,KAAM,CAAE,MAAO,UAAW,CAAC,EACxCQ,EAAMR,EAAK,MAAO,CAAE,MAAO,UAAW,EAAGK,EAAOC,CAAI,EACpDG,EAAUZ,EAASG,EAAK,MAAO,CAAE,MAAO,kBAAmB,EAAGQ,CAAG,EAAIR,EAAK,MAAO,CAAE,MAAO,wBAAyB,EAAGO,EAAOC,CAAG,EAEhIE,EAAU,IAAMpB,EAAK,SAAS,EAAE,OAAOC,CAAI,EAC3CoB,EAAS,IAA4B,MAAM,QAAQD,EAAQ,CAAC,EAAKA,EAAQ,EAA4B,CAAC,EACtGE,EAASC,GAAgCvB,EAAK,SAASC,EAAMsB,CAAe,EAC5EC,EAAWC,GAAmBb,EAAQ,KAAMc,GAAMA,EAAE,QAAUD,CAAK,GAAG,QAAUA,GAAU,KAA8B,GAAK,OAAOA,CAAK,GAG3IE,EAAkB,CAAC,EACnBC,EAAS,GACTC,EAAW,GAEf,SAASC,GAAO,CACdd,EAAK,gBACH,GAAGW,EAAM,IAAI,CAACI,EAAQC,IAAM,CAC1B,IAAMC,EAAOvB,EAAK,KAAM,CAAE,GAAI,GAAGI,CAAM,IAAIkB,CAAC,GAAI,KAAM,SAAU,MAAO,YAAYA,IAAMJ,EAAS,aAAe,EAAE,GAAI,gBAAiB,OAAOI,IAAMJ,CAAM,CAAE,EAAGG,EAAO,KAAK,EAE5K,OAAAE,EAAK,iBAAiB,YAAcC,GAAUA,EAAM,eAAe,CAAC,EACpED,EAAK,iBAAiB,QAAS,IAAME,EAAIJ,CAAM,CAAC,EACzCE,CACT,CAAC,CACH,EACKN,EAAM,QAAQX,EAAK,OAAON,EAAK,KAAM,CAAE,MAAO,UAAW,EAAGF,EAAM,SAAS,CAAC,EACjF4B,GAAQrB,EAAO,wBAAyBa,GAAU,EAAI,GAAGd,CAAM,IAAIc,CAAM,GAAK,IAAI,CACpF,CACA,SAASS,GAAO,CACd,IAAMC,EAAUvB,EAAM,MAAM,KAAK,EAE3BwB,EAAQhC,GAAU+B,IAAYd,EAAQJ,EAAQ,CAAC,EAAI,GAAKkB,EAAQ,YAAY,EAC5EE,EAAQ,IAAI,IAAInB,EAAO,CAAC,EAC9BM,EAAQf,EAAQ,OAAQc,GAAM,CAACc,EAAM,IAAId,EAAE,KAAK,GAAKA,EAAE,MAAM,YAAY,EAAE,SAASa,CAAK,CAAC,EAEtF1B,GAAO0B,GAAS,CAACC,EAAM,IAAIF,CAAO,GAAK,CAAC1B,EAAQ,KAAMc,GAAMA,EAAE,MAAM,YAAY,IAAMa,CAAK,GAAGZ,EAAM,KAAK,CAAE,MAAOW,EAAS,MAAOG,GAAOjC,EAAM,YAAa,CAAE,KAAM8B,CAAQ,CAAC,CAAE,CAAC,EACpLV,EAAS,GACTE,EAAK,EACLd,EAAK,OAAS,GACdD,EAAM,aAAa,gBAAiB,MAAM,CAC5C,CACA,SAAS2B,GAAQ,CACf1B,EAAK,OAAS,GACdY,EAAS,GACTb,EAAM,aAAa,gBAAiB,OAAO,EAC3CA,EAAM,gBAAgB,uBAAuB,CAC/C,CACA,SAASoB,EAAIJ,EAAgB,CAC3B,GAAIxB,EACF,OAAAQ,EAAM,MAAQgB,EAAO,MACrBT,EAAMS,EAAO,KAAK,EACXW,EAAM,EAEf3B,EAAM,MAAQ,GACdO,EAAMqB,GAAU/B,EAASS,EAAO,EAAGU,EAAO,KAAK,CAAC,EAC5C3B,EAAS,gBAAkBW,EAAOsB,EAAK,EACtCK,EAAM,CACb,CAEKnC,GAAQQ,EAAM,iBAAiB,QAAS,IAAM,CAACc,GAAYQ,EAAK,CAAC,EACtEtB,EAAM,iBAAiB,QAAS,IAAM,CAACc,GAAYb,EAAK,QAAUqB,EAAK,CAAC,EACxEtB,EAAM,iBAAiB,QAAS,IAAM,CAACc,GAAYQ,EAAK,CAAC,EACzDtB,EAAM,iBAAiB,OAAQ,IAAM,CACnC2B,EAAM,EAEFnC,GAAU,CAACsB,IACRd,EAAM,MAAM,KAAK,EACjBA,EAAM,MAAQS,EAAQJ,EAAQ,CAAC,EADXE,EAAM,IAAI,EAGvC,CAAC,EACDP,EAAM,iBAAiB,UAAYmB,GAAU,CAC3C,GAAI,CAAAL,EACJ,OAAQK,EAAM,IAAK,CACjB,IAAK,YACL,IAAK,UAAW,CAEd,GADAA,EAAM,eAAe,EACjBlB,EAAK,OAAQ,OAAOqB,EAAK,EAC7B,GAAI,CAACV,EAAM,OAAQ,OACnB,IAAMiB,EAAOV,EAAM,MAAQ,YAE3BN,EAASA,IAAW,GAAMgB,EAAO,EAAIjB,EAAM,OAAS,GAAMC,GAAUgB,EAAO,EAAI,IAAMjB,EAAM,QAAUA,EAAM,OAC3GG,EAAK,EACLd,EAAK,SAASY,CAAM,GAAG,iBAAiB,CAAE,MAAO,SAAU,CAAC,EAC5D,MACF,CACA,IAAK,QAAS,CACZ,IAAMiB,EAAOlB,EAAMC,CAAM,IAAMb,EAAM,MAAM,KAAK,EAAIY,EAAM,CAAC,EAAI,QAC/D,GAAIX,EAAK,QAAU,CAAC6B,EAAM,OAC1BX,EAAM,eAAe,EACrBC,EAAIU,CAAI,EACR,MACF,CACA,IAAK,SACE7B,EAAK,QAAQkB,EAAM,eAAe,EACvCQ,EAAM,EACN,OACF,IAAK,YACC,CAACnC,GAAUQ,EAAM,QAAU,IAAMM,EAAO,EAAE,QAAQC,EAAMD,EAAO,EAAE,MAAM,EAAG,EAAE,CAAC,EACjF,MACJ,CACF,CAAC,EAED,IAAIyB,EAAQ,GACZ,MAAO,CACL,QAAA3B,EACA,MAAO,IAAMJ,EAAM,MAAM,EACzB,OAAOgC,EAAO,CAKZ,GAJAlB,EAAWkB,EAAM,SACblB,GAAUa,EAAM,EACpBM,GAAcjC,EAAOgC,CAAK,EAC1BX,GAAQrB,EAAO,gBAAiB,OAAOgC,EAAM,QAAQ,CAAC,EAClDxC,EAAQ,CACVQ,EAAM,SAAWc,EACbzB,EAAS,gBAAkBW,IAAOA,EAAM,MAAQS,EAAQuB,EAAM,KAAK,GACvE,MACF,CACA,IAAMxB,EAAS,MAAM,QAAQwB,EAAM,KAAK,EAAKA,EAAM,MAAsB,CAAC,EAC1EhC,EAAM,OAASc,EACf,IAAMoB,EAAM,KAAK,UAAU,CAACpB,EAAUN,CAAM,CAAC,EACzC0B,IAAQH,IACZA,EAAQG,EACRhC,EAAM,gBACJ,GAAGM,EAAO,IAAKE,GAAU,CACvB,IAAMyB,EAAQ1B,EAAQC,CAAK,EACrB0B,EAAOzC,EAAK,KAAM,CAAE,MAAO,SAAU,EAAGA,EAAK,OAAQ,CAAE,MAAO,eAAgB,EAAGwC,CAAK,CAAC,EAC7F,GAAI,CAACrB,EAAU,CACb,IAAMuB,EAAS1C,EAAK,SAAU,CAAE,KAAM,SAAU,MAAO,iBAAkB,aAAc+B,GAAOjC,EAAM,OAAQ,CAAE,KAAM0C,CAAM,CAAC,CAAE,EAAG,MAAG,EACnIE,EAAO,iBAAiB,QAAS,IAAM9B,EAAMD,EAAO,EAAE,OAAQgC,GAAMA,IAAM5B,CAAK,CAAC,CAAC,EACjF0B,EAAK,OAAOC,CAAM,CACpB,CACA,OAAOD,CACT,CAAC,CACH,EAEKnC,EAAK,QAAQqB,EAAK,EACzB,CACF,CACF,CC1JA,IAAMiB,GAAQ,iLAEDC,GAAmC,CAAC,CAAE,KAAAC,EAAM,KAAAC,EAAM,MAAAC,EAAO,KAAAC,EAAM,GAAAC,EAAI,SAAAC,EAAU,OAAAC,EAAQ,OAAAC,CAAO,IAAM,CAC7G,IAAMC,EAAQC,GAASH,EAAQC,CAAM,EAC/BG,EAAOC,GAAMN,CAAQ,EACrBO,EAAWV,EAAM,OAAS,aAAeA,EAAM,WAAa,GAC5DW,EAAoBX,EAAM,OAAS,YAAcA,EAAM,QAAU,CAAC,EAClEY,EAAUC,GAAaF,EAASb,EAAMC,EAAME,CAAI,EAChDa,EAAOb,EAAK,SAAW,CAAC,EACxBc,EAAOD,EAAK,aAAkB,GAC9BE,EAAQR,EAAK,MAAO,CAAE,GAAAN,EAAI,MAAO,mBAAmBa,EAAO,yBAA2B,EAAE,GAAI,KAAML,EAAW,QAAU,aAAc,YAAaI,EAAK,UAAwB,WAAYA,EAAK,QAAsB,CAAC,EAC7NG,GAAOD,EAAOf,CAAI,EAClB,IAAMiB,EAAQR,EAAWS,GAAQX,EAAMF,EAAOL,CAAI,EAAI,KAChDmB,EAAQR,EAAQ,IAAKS,GAAW,CACpC,IAAMC,EAAUD,EAAO,MAAQb,EAAK,MAAO,CAAE,IAAKa,EAAO,MAAO,IAAKA,EAAO,KAAO,GAAI,QAAS,OAAQ,UAAW,OAAQ,CAAC,EAAIb,EAAK,OAAQ,CAAE,MAAO,qBAAsB,CAAC,EACxKa,EAAO,QAAOC,EAAQ,UAAY1B,IACvC,IAAM2B,EAAOf,EACX,SACA,CAAE,KAAM,SAAU,MAAO,gBAAiB,KAAME,EAAW,WAAa,QAAS,eAAgB,QAAS,aAAcK,EAAOM,EAAO,MAAQ,MAAU,EACxJb,EAAK,OAAQ,CAAE,MAAO,uBAAwB,EAAGc,CAAO,EACxDd,EAAK,OAAQ,CAAE,MAAO,qBAAsB,EAAGa,EAAO,KAAK,CAC7D,EACA,OAAAE,EAAK,iBAAiB,QAAS,IAAMC,EAAKH,CAAM,CAAC,EACjDL,EAAM,OAAOO,CAAI,EACVA,CACT,CAAC,EAEKE,EAAU,IAAM3B,EAAK,SAAS,EAAE,OAAOC,CAAI,EACjD,SAASyB,EAAKH,EAAgB,CAC5B,GAAI,CAACX,EAAU,OAAOZ,EAAK,SAASC,EAAMsB,EAAO,KAAK,EACtD,IAAMK,EAAM,MAAM,QAAQD,EAAQ,CAAC,EAAKA,EAAQ,EAAkB,CAAC,EAC7DE,EAAK,IAAI,IAAID,EAAI,SAASL,EAAO,KAAK,EAAIK,EAAI,OAAQE,GAAMA,IAAMP,EAAO,KAAK,EAAIQ,GAAUlB,EAASe,EAAKL,EAAO,KAAK,CAAC,EAE7HvB,EAAK,SAASC,EAAMY,EAAQ,OAAQmB,GAAMH,EAAG,IAAIG,EAAE,KAAK,CAAC,EAAE,IAAKA,GAAMA,EAAE,KAAK,CAAC,CAChF,CAEA,IAAIC,EAAW,GACVrB,GACHM,EAAM,iBAAiB,UAAYgB,GAAU,CAC3C,GAAID,EAAU,OACd,IAAME,EAAKb,EAAM,QAAQY,EAAM,MAA2B,EAC1D,GAAIC,IAAO,GAAI,OACf,IAAMC,EAAOC,GAAYnB,CAAK,EACxBoB,EAAgC,CAAE,UAAW,EAAG,QAAS,GAAI,WAAYF,EAAO,GAAK,EAAG,UAAWA,EAAO,EAAI,EAAG,EACjHG,EAAKL,EAAM,MAAQ,OAAS,EAAIA,EAAM,MAAQ,MAAQZ,EAAM,OAAS,EAAIY,EAAM,OAAOI,GAASH,EAAKG,EAAMJ,EAAM,GAAG,EAAIZ,EAAM,QAAUA,EAAM,OAAS,GACxJiB,IAAO,KACXL,EAAM,eAAe,EACrBR,EAAKZ,EAAQyB,CAAE,CAAC,EAChBjB,EAAMiB,CAAE,EAAE,MAAM,EAClB,CAAC,EAEH,IAAMC,EAAQ5B,EACV,KACA6B,GAAepC,EAAUG,EAAO,IAAM,CACpCR,EAAK,SAASC,EAAM,IAAI,EACxBqB,EAAM,CAAC,GAAG,MAAM,CAClB,CAAC,EAEL,OAAIF,GAAO,SAASF,EAAM,OAAOE,EAAM,OAAO,EACvC,CACL,QAASoB,EAAQ9B,EAAK,MAAO,CAAE,MAAO,gBAAiB,EAAGQ,EAAOsB,EAAM,MAAM,EAAItB,EACjF,MAAO,KAAOI,EAAM,KAAMoB,GAAMA,EAAE,aAAa,cAAc,IAAM,MAAM,GAAKpB,EAAM,CAAC,IAAI,MAAM,EAC/F,OAAOqB,EAAO,CACZV,EAAWU,EAAM,SACjB,IAAMC,EAAS,IAAI,IAAa,MAAM,QAAQD,EAAM,KAAK,EAAIA,EAAM,MAAQ,CAACA,EAAM,KAAK,CAAC,EAClFE,EAAOjC,EAAW,GAAK,KAAK,IAAI,EAAGE,EAAQ,UAAWkB,GAAMY,EAAO,IAAIZ,EAAE,KAAK,CAAC,CAAC,EAChFc,EAAO,CAAC,CAAC1B,GAAO,KAAK,MAAM,QAAQuB,EAAM,KAAK,EAAIA,EAAM,MAAM,OAAS,CAAC,EAC9ErB,EAAM,QAAQ,CAACG,EAAMsB,IAAM,CACzB,IAAMlB,EAAKe,EAAO,IAAI9B,EAAQiC,CAAC,EAAE,KAAK,EACtCtB,EAAK,aAAa,eAAgB,OAAOI,CAAE,CAAC,EAC5CJ,EAAK,SAAWb,GAAYmC,IAAMF,EAAO,EAAI,GAC7CpB,EAAK,SAAWQ,GAAaa,GAAQ,CAACjB,GAAM,CAACf,EAAQiC,CAAC,EAAE,SAC1D,CAAC,EACDP,GAAO,MAAMG,CAAK,EAClBH,GAAO,KAAK1B,EAAQ,KAAMkB,GAAMY,EAAO,IAAIZ,EAAE,KAAK,CAAC,CAAC,EACpDgB,GAAc9B,EAAOyB,CAAK,CAC5B,CACF,CACF,ECvEA,IAAMM,GAAO,EAEAC,GAA+B,CAAC,CAAE,KAAAC,EAAM,KAAAC,EAAM,MAAAC,EAAO,KAAAC,EAAM,GAAAC,EAAI,SAAAC,EAAU,OAAAC,EAAQ,OAAAC,CAAO,IAAM,CACzG,IAAMC,EAAQC,GAASH,EAAQC,CAAM,EAC/BG,EAAOC,GAAMN,CAAQ,EACrBO,EAAoBC,GAAaX,EAAM,OAAS,YAAcA,EAAM,QAAU,CAAC,EAAGF,EAAMC,EAAME,CAAI,EAClGW,EAAOJ,EAAK,KAAM,CAAE,MAAO,cAAe,CAAC,EAC3CK,EAAQC,GAAUN,CAAI,EACtBO,EAAOd,EAAK,SAAU,IACtBe,EAAM,OAAOD,GAAS,UAAYA,GAAQ,GAAKA,EAAOL,EAAQ,OAAS,KAAK,MAAMK,CAAI,EAAI,EAC1FE,EAAOT,EAAK,MAAO,CAAE,MAAO,cAAe,CAAC,EAC5CU,EAAcV,EAAK,SAAU,CAAE,KAAM,SAAU,MAAO,wBAAyB,EAAGF,EAAM,SAAS,EACvGY,EAAY,iBAAiB,QAAS,IAAMpB,EAAK,SAASC,EAAMoB,EAAM,IAAKC,GAASA,EAAK,OAAO,KAAK,CAAC,CAAC,EACvG,IAAMC,EAAUb,EACd,MACA,CAAE,GAAAN,EAAI,MAAO,aAAc,KAAM,OAAQ,EACzC,GAAIc,EAAM,CAACR,EAAK,MAAO,CAAE,MAAO,iBAAkB,EAAGc,GAAOhB,EAAM,KAAM,CAAE,EAAGU,CAAI,CAAC,CAAC,EAAGC,EAAML,CAAI,EAAI,CAACA,EAAMM,CAAW,EACtHL,EAAM,OACR,EAEMU,EAAgBb,EAAQ,IAAKc,GAAW,CAC5C,IAAMC,EAAQD,EAAO,MACfE,EAAQlB,EAAK,OAAQ,CAAE,MAAO,gBAAiB,cAAe,MAAO,CAAC,EACtEmB,EAAKnB,EAAK,SAAU,CAAE,KAAM,SAAU,MAAO,0BAA2B,aAAcc,GAAOhB,EAAM,OAAQ,CAAE,MAAAmB,CAAM,CAAC,CAAE,EAAG,QAAG,EAC5HG,EAAOpB,EAAK,SAAU,CAAE,KAAM,SAAU,MAAO,4BAA6B,aAAcc,GAAOhB,EAAM,SAAU,CAAE,MAAAmB,CAAM,CAAC,CAAE,EAAG,QAAG,EAClII,EAAOrB,EAAK,OAAQ,CAAE,MAAO,eAAgB,cAAe,MAAO,CAAC,EACpEsB,EAAQtB,EAAK,OAAQ,CAAE,MAAO,eAAgB,EAAGmB,EAAIC,CAAI,EACzDG,EAAKvB,EAAK,KAAM,CAAE,MAAO,eAAgB,aAAc,OAAOgB,EAAO,KAAK,CAAE,EAAGK,EAAMH,EAAOlB,EAAK,OAAQ,CAAE,MAAO,eAAgB,EAAGiB,CAAK,EAAGK,CAAK,EAClJV,EAAa,CAAE,OAAAI,EAAQ,QAASO,EAAI,MAAAL,EAAO,GAAAC,EAAI,KAAAC,CAAK,EAC1D,GAAIZ,EAAK,CAEP,IAAMgB,EAAOxB,EAAK,SAAU,CAAE,KAAM,SAAU,MAAO,cAAe,EAAGiB,CAAK,EAC5EO,EAAK,iBAAiB,QAAS,IAAM,CAACC,GAAYd,EAAM,OAASH,GAAOkB,EAAK,CAAC,GAAGf,EAAOC,CAAI,EAAGA,CAAI,CAAC,EACpG,IAAMe,EAAM3B,EAAK,SAAU,CAAE,KAAM,SAAU,MAAO,2BAA4B,aAAcc,GAAOhB,EAAM,OAAQ,CAAE,KAAMmB,CAAM,CAAC,CAAE,EAAG,MAAG,EAC1IU,EAAI,iBAAiB,QAAS,IAAM,CAClCtB,EAAM,IAAIS,GAAOhB,EAAM,QAAS,CAAE,KAAMmB,CAAM,CAAC,CAAC,EAChD3B,EAAK,SAASC,EAAMoB,EAAM,OAAQiB,GAAUA,IAAUhB,CAAI,EAAE,IAAKgB,GAAUA,EAAM,OAAO,KAAK,CAAC,CAChG,CAAC,EACDN,EAAM,OAAOK,CAAG,EAChBlB,EAAK,OAAOe,CAAI,EAChBZ,EAAK,KAAOY,CACd,CACA,OAAAL,EAAG,iBAAiB,QAAS,IAAMU,EAAKjB,EAAM,GAAI,IAAI,CAAC,EACvDQ,EAAK,iBAAiB,QAAS,IAAMS,EAAKjB,EAAM,EAAG,MAAM,CAAC,EAC1DW,EAAG,iBAAiB,cAAgBO,GAAUC,EAAMnB,EAAMkB,CAAK,CAAC,EACzDlB,CACT,CAAC,EAEGa,EAAW,GAEXd,EAAgB,CAAC,GAAGI,CAAK,EAEzBiB,EAAuD,KAE3D,SAASC,EAAKC,EAAc,CAS1B,IARAvB,EAAQuB,EACRA,EAAK,QAAQ,CAACtB,EAAMuB,IAAM,CACpB/B,EAAK,SAAS+B,CAAC,IAAMvB,EAAK,SAASR,EAAK,aAAaQ,EAAK,QAASR,EAAK,SAAS+B,CAAC,GAAK,IAAI,EAC/FvB,EAAK,MAAM,YAAc,OAAOuB,EAAI,CAAC,EACrCvB,EAAK,GAAG,SAAWuB,IAAM,EACzBvB,EAAK,KAAK,SAAWuB,IAAMD,EAAK,OAAS,CAC3C,CAAC,EAEM9B,EAAK,SAAS,OAAS8B,EAAK,QAAQ9B,EAAK,kBAAkB,OAAO,CAC3E,CAEA,SAASsB,EAAKQ,EAAcE,EAAa,CACvC/B,EAAM,IAAIS,GAAOhB,EAAM,QAAS,CAAE,MAAOsC,EAAM,OAAO,MAAO,EAAGF,EAAK,QAAQE,CAAK,EAAI,EAAG,MAAOF,EAAK,MAAO,CAAC,CAAC,EAC9G5C,EAAK,SAASC,EAAM2C,EAAK,IAAKtB,GAASA,EAAK,OAAO,KAAK,CAAC,CAC3D,CACA,SAASiB,EAAKjB,EAAYyB,EAAcC,EAAsB,CAC5D,IAAMC,EAAO5B,EAAM,QAAQC,CAAI,EACzB4B,EAAKD,EAAOF,EAClB,GAAIZ,GAAYe,EAAK,GAAKA,GAAM7B,EAAM,OAAQ,OAC9C,IAAMuB,EAAO,CAAC,GAAGvB,CAAK,EACtBuB,EAAK,OAAOK,EAAM,CAAC,EACnBL,EAAK,OAAOM,EAAI,EAAG5B,CAAI,EAGvBoB,EAFgBpB,EAAK,QAAQ,SAASjB,EAAS,aAAa,EAExC,CAAE,KAAAiB,EAAM,MAAQ0B,IAAU,MAAQE,IAAO,GAAOF,IAAU,QAAUE,IAAON,EAAK,OAAS,EAAMI,IAAU,KAAO,OAAS,KAAQA,CAAM,EAAI,KAC/JZ,EAAKQ,EAAMtB,CAAI,EACf6B,EAAc,CAChB,CACA,SAASA,GAAgB,CACvB,GAAI,CAACT,EAAS,OACd,GAAM,CAAE,KAAApB,EAAM,MAAA0B,CAAM,EAAIN,EACxBA,EAAU,KACVpB,EAAK0B,CAAK,EAAE,MAAM,CACpB,CAEAlC,EAAK,iBAAiB,UAAY0B,GAAU,CAC1C,GAAIL,GAAY,CAACK,EAAM,QAAWA,EAAM,MAAQ,WAAaA,EAAM,MAAQ,YAAc,OACzF,IAAMlB,EAAOG,EAAM,KAAMoB,GAAMA,EAAE,QAAQ,SAASL,EAAM,MAAc,CAAC,EAClElB,IACLkB,EAAM,eAAe,EACrBD,EAAKjB,EAAMkB,EAAM,MAAQ,UAAY,GAAK,EAAGA,EAAM,MAAQ,UAAY,KAAO,MAAM,EACtF,CAAC,EAGD,SAASC,EAAMnB,EAAYkB,EAAqB,CAG9C,GAFIL,GAAYK,EAAM,SAAW,GAAMA,EAAM,OAAmB,QAAQ,QAAQ,GAE5EA,EAAM,cAAgB,SAAW,CAAEA,EAAM,OAAmB,QAAQ,eAAe,EAAG,OAC1F,IAAMY,EAASZ,EAAM,QACfa,EAAS,CAAC,GAAGhC,CAAK,EACpBiC,EAAS,GACbhC,EAAK,QAAQ,oBAAoBkB,EAAM,SAAS,EAChD,IAAMe,EAAUC,GAAoB,CAClC,GAAI,CAACF,GAAU,KAAK,IAAIE,EAAE,QAAUJ,CAAM,EAAItD,GAAM,OAC/CwD,IACHA,EAAS,GACThC,EAAK,QAAQ,UAAU,IAAI,gBAAgB,GAE7CkC,EAAE,eAAe,EAEjB,IAAMC,EAASpC,EAAM,OAAQiB,GAAUA,IAAUhB,CAAI,EAC/CoC,EAAKD,EAAO,OAAQnB,GAAU,CAClC,IAAMqB,EAAMrB,EAAM,QAAQ,sBAAsB,EAChD,OAAOqB,EAAI,IAAMA,EAAI,OAAS,EAAIH,EAAE,OACtC,CAAC,EAAE,OACCnC,EAAM,QAAQC,CAAI,IAAMoC,GAAIf,EAAK,CAAC,GAAGc,EAAO,MAAM,EAAGC,CAAE,EAAGpC,EAAM,GAAGmC,EAAO,MAAMC,CAAE,CAAC,CAAC,CAC1F,EACME,EAAQ,IAAM,CAClBtC,EAAK,QAAQ,oBAAoB,cAAeiC,CAAM,EACtDjC,EAAK,QAAQ,oBAAoB,YAAasC,CAAK,EACnDtC,EAAK,QAAQ,oBAAoB,gBAAiBsC,CAAK,EACvDtC,EAAK,QAAQ,UAAU,OAAO,gBAAgB,EAC1CD,EAAM,KAAK,CAACiB,EAAOO,IAAMP,IAAUe,EAAOR,CAAC,CAAC,GAAGT,EAAKf,EAAOC,CAAI,CACrE,EACAA,EAAK,QAAQ,iBAAiB,cAAeiC,CAAM,EACnDjC,EAAK,QAAQ,iBAAiB,YAAasC,CAAK,EAChDtC,EAAK,QAAQ,iBAAiB,gBAAiBsC,CAAK,CACtD,CAGA,SAASC,EAAQC,EAAwB,CACvC,IAAMC,GAAS,MAAM,QAAQD,CAAK,EAAIA,EAAQ,CAAC,GAAG,IAAKE,GAAMvC,EAAM,KAAMH,GAASA,EAAK,OAAO,QAAU0C,CAAC,CAAC,EAAE,OAAQ1C,GAAuB,CAAC,CAACA,CAAI,EACjJ,OAAIJ,EAAY6C,EAAM,MAAM,EAAG7C,CAAG,EAC3B,MAAM,QAAQ4C,CAAK,EAAI,CAAC,GAAG,IAAI,IAAI,CAAC,GAAGC,EAAO,GAAG1C,CAAK,CAAC,CAAC,EAAIA,CACrE,CAEA,OAAAsB,EAAKzB,EAAM,CAAC,EAAIG,CAAK,EACd,CACL,QAAAE,EACA,MAAO,KAAOE,EAAM,KAAMH,GAASA,EAAK,MAAQ,CAACA,EAAK,KAAK,QAAU,CAACA,EAAK,KAAK,QAAQ,GAAG,OAASD,EAAM,CAAC,GAAG,KAAK,SAAWA,EAAM,CAAC,GAAG,GAAKA,EAAM,CAAC,GAAG,QAAQ,MAAM,EACrK,OAAO4C,EAAO,CACZ9B,EAAW8B,EAAM,SACjB1C,EAAQ,UAAU,OAAO,oBAAqBY,CAAQ,EACtD,IAAMS,EAAOiB,EAAQI,EAAM,KAAK,GAC5BrB,EAAK,SAAWvB,EAAM,QAAUuB,EAAK,KAAK,CAACtB,EAAMuB,IAAMvB,IAASD,EAAMwB,CAAC,CAAC,GAAM,CAAC3B,GAAO,CAACJ,EAAK,SAAS,SAAS6B,EAAKC,CAAI,EAC3H,QAAWtB,KAAQG,EACjBH,EAAK,GAAG,OAASA,EAAK,KAAK,OAASa,EAChCb,EAAK,OACPA,EAAK,KAAK,OAASD,EAAM,SAASC,CAAI,EACtCA,EAAK,KAAK,SAAWa,GAAYd,EAAM,QAAUH,EAChDI,EAAK,QAAQ,cAAc,cAAc,EAAkB,OAASa,GAGzEf,EAAY,OAASe,GAAa,MAAM,QAAQ8B,EAAM,KAAK,GAAKA,EAAM,MAAM,OAAS,EACrFd,EAAc,EACde,GAAc3C,EAAS0C,CAAK,CAC9B,CACF,CACF,EC/KA,IAAME,GAA8E,CAClF,OAAQ,CAAC,gBAAiB,gBAAgB,EAC1C,MAAO,CAAC,eAAgB,eAAe,EACvC,KAAM,CAAC,cAAe,gBAAgB,EACtC,OAAQ,CAAC,gBAAiB,gBAAgB,EAC1C,SAAU,CAAC,kBAAmB,aAAa,EAC3C,QAAS,CAAC,iBAAkB,SAAS,CACvC,EAEMC,GAAUC,GAAgC,OAAOA,GAAS,UAAYA,KAAQF,GAG9EG,GAAgB,4FAChBC,GAAgD,CAAC,EAEhD,SAASC,GAAYC,EAAoC,CAC9D,GAAI,CAACF,GAAUE,CAAM,EAAG,CACtB,IAAMC,EAAQ,IAAI,KAAK,aAAa,CAACD,CAAM,EAAG,CAAE,KAAM,SAAU,SAAU,MAAO,CAAC,EAC5EE,EAA4B,CAAC,EACnC,QAASC,EAAI,GAAIA,EAAI,GAAIA,IACvB,QAASC,EAAI,GAAIA,EAAI,GAAIA,IAAK,CAC5B,IAAMC,EAAO,OAAO,aAAaF,EAAGC,CAAC,EAC/BR,EAAO,CAACC,GAAc,SAASQ,CAAI,GAAKJ,EAAM,GAAGI,CAAI,EACvDT,GAAMM,EAAM,KAAK,CAACG,EAAMT,CAAI,CAAC,CACnC,CACFE,GAAUE,CAAM,EAAIE,EAAM,KAAK,CAACI,EAAGC,IAAMD,EAAE,CAAC,EAAE,cAAcC,EAAE,CAAC,EAAGP,CAAM,CAAC,CAC3E,CACA,OAAOF,GAAUE,CAAM,CACzB,CAEO,IAAMQ,GAA+B,CAAC,CAAE,KAAAC,EAAM,KAAAb,EAAM,KAAAc,EAAM,GAAAC,EAAI,SAAAC,EAAU,OAAAC,EAAQ,OAAAb,EAAS,IAAK,IAAM,CACzG,IAAMc,EAAQC,GAASF,EAAQb,CAAM,EAC/BgB,EAAOC,GAAML,CAAQ,EACrBM,EAAUR,EAAK,SAAW,CAAC,EAC3BS,EAAQD,EAAQ,MAChBE,EAAgB,MAAM,QAAQD,CAAK,EAAIA,EAAM,OAAOxB,EAAM,EAAI,CAAC,SAAU,OAAQ,WAAY,SAAS,EACtG0B,EAAS,MAAM,QAAQH,EAAQ,aAAgB,EAAIA,EAAQ,cAAmB,CAAC,EAC/EI,EAAQ,OAAOJ,EAAQ,SAAe,SAAWA,EAAQ,QAAa,GACtEK,EAAUP,EAAK,MAAO,CAAE,GAAAL,EAAI,MAAO,aAAc,KAAM,OAAQ,CAAC,EAEhEa,EAAQ,CAACC,EAAYC,IAAiB,CAC1C,IAAMC,EAAMlB,EAAK,SAAS,EAAE,OAAOb,CAAI,EACjCgC,EAAgCD,GAAO,OAAOA,GAAQ,UAAY,CAAC,MAAM,QAAQA,CAAG,EAAI,CAAE,GAAIA,CAAgC,EAAI,CAAC,EACzIC,EAAKH,CAAI,EAAIC,EAETJ,GAASF,EAAM,SAAS,SAAS,GAAKQ,EAAK,UAAe,SAAWA,EAAK,QAAaN,GAE3F,IAAMO,EAAS,OAAO,YAAY,OAAO,QAAQD,CAAI,EAAE,OAAO,CAAC,CAAC,CAAEE,CAAC,IAAM,OAAOA,GAAM,UAAYA,EAAE,KAAK,IAAM,EAAE,CAAC,EAC5GC,EAAO,OAAO,KAAKF,CAAM,EAC/BpB,EAAK,SAASb,EAAMmC,EAAK,SAAWN,IAAS,WAAaM,EAAK,KAAK,IAAM,WAAaF,EAAO,UAAeP,GAAUO,EAAmB,IAAI,CAChJ,EACMG,EAAQZ,EAAM,IAAKK,GAAS,CAChC,GAAM,CAACQ,EAAOC,CAAY,EAAIxC,GAAM+B,CAAI,EAClCU,EAAQ,CAAE,GAAI,GAAGxB,CAAE,IAAIc,CAAI,GAAI,MAAO,WAAY,YAAaA,EAAM,aAAcA,IAAS,UAAYL,EAAM,SAAS,OAAO,EAAI,gBAAkBc,EAAc,gBAAiBb,EAAO,SAASI,CAAI,EAAI,OAAS,MAAU,EAC9NW,EACJX,IAAS,UACLT,EAAK,SAAUmB,EAAOnB,EAAK,SAAU,CAAE,MAAO,EAAG,CAAC,EAAG,GAAGjB,GAAYC,CAAM,EAAE,IAAI,CAAC,CAACK,EAAMgC,CAAO,IAAMrB,EAAK,SAAU,CAAE,MAAOX,CAAK,EAAGgC,CAAO,CAAC,CAAC,EAC9IrB,EAAK,QAAS,CAAE,KAAM,OAAQ,GAAGmB,CAAM,CAAC,EAC9C,OAAAC,EAAM,iBAAiBX,IAAS,UAAY,SAAW,QAAS,IAAMD,EAAMC,EAAMW,EAAM,KAAK,CAAC,EAC1FX,IAAS,WAAWW,EAAM,UAAU,IAAI,WAAW,EACvDb,EAAQ,OAAOP,EAAK,MAAO,CAAE,MAAO,8BAA8BS,CAAI,GAAGJ,EAAO,SAASI,CAAI,EAAI,eAAiB,EAAE,EAAG,EAAGT,EAAK,QAAS,CAAE,MAAO,mBAAoB,IAAKoB,EAAM,EAAG,EAAGtB,EAAMmB,CAAK,CAAC,EAAGG,CAAK,CAAC,EACpM,CAAE,KAAAX,EAAM,MAAAW,CAAM,CACvB,CAAC,EAED,MAAO,CACL,QAAAb,EACA,MAAO,IAAMS,EAAM,CAAC,GAAG,MAAM,MAAM,EACnC,OAAOM,EAAO,CACZ,IAAMC,EAAQD,EAAM,OAAS,OAAOA,EAAM,OAAU,UAAY,CAAC,MAAM,QAAQA,EAAM,KAAK,EAAKA,EAAM,MAAoC,CAAC,EAC1I,OAAW,CAAE,KAAAb,EAAM,MAAAW,CAAM,IAAKJ,EAAO,CACnC,IAAMN,EAAO,OAAOa,EAAMd,CAAI,GAAM,SAAYc,EAAMd,CAAI,EAAeA,IAAS,WAAac,EAAM,UAAe,OAAYjB,EAAQ,GACpIc,aAAiB,mBAEfV,GAAQ,CAAC,CAAC,GAAGU,EAAM,OAAO,EAAE,KAAMI,GAAMA,EAAE,QAAUd,CAAI,GAAGU,EAAM,OAAOpB,EAAK,SAAU,CAAE,MAAOU,CAAK,EAAGA,CAAI,CAAC,EACjHU,EAAM,SAAWE,EAAM,UAClBF,EAAM,SAAWE,EAAM,SAE1B1B,EAAS,gBAAkBwB,GAASA,EAAM,QAAUV,IAAMU,EAAM,MAAQV,GAE5EU,EAAM,aAAa,eAAgB,OAAOE,EAAM,UAAY,CAACjB,EAAO,QAAWA,EAAO,SAASI,CAAI,GAAK,CAACC,EAAK,KAAK,EAAG,CAAC,CACzH,CACAe,GAAclB,EAASe,CAAK,CAC9B,CACF,CACF,EC3EA,IAAMI,GAASC,GAAoB,OAAOA,GAAU,UAAY,OAAO,UAAUA,CAAK,GAAKA,GAAS,EAAIA,EAAQ,OAEnGC,GAA6B,CAAC,CAAE,KAAAC,EAAM,KAAAC,EAAM,MAAAC,EAAO,KAAAC,EAAM,GAAAC,EAAI,SAAAC,EAAU,OAAAC,EAAQ,OAAAC,EAAQ,QAAAC,CAAQ,IAAM,CAChH,IAAMC,EAAQC,GAASJ,EAAQC,CAAM,EAC/BI,EAAOC,GAAMP,CAAQ,EACrBQ,EAAMX,EACNY,EAAUX,EAAK,SAAW,CAAC,EAC3BY,EAAMlB,GAAMiB,EAAQ,GAAM,GAAK,EAC/BE,EAAMnB,GAAMiB,EAAQ,GAAM,GAAK,IAC/BG,EAAY,OAAOH,EAAQ,WAAiB,UAAYA,EAAQ,UAAa,KAAK,EAAIA,EAAQ,UAAa,KAAK,EAAI,KACpHI,EAAWC,GAAeF,EAAY,GAAGA,CAAS,IAAIE,CAAC,GAAKC,GAAOX,EAAM,MAAO,CAAE,EAAAU,CAAE,CAAC,EAErFE,GAASlB,EAAK,SAAW,OAAO,KAAKU,EAAI,MAAM,GAAG,OAAQS,GAAMT,EAAI,OAAOS,CAAC,GAAKA,IAAMT,EAAI,eAAiBS,IAAMT,EAAI,WAAW,KAAK,EAEtIU,EAAOZ,EAAK,MAAO,CAAE,MAAO,gBAAiB,CAAC,EAC9Ca,EAAYb,EAAK,SAAU,CAAE,KAAM,SAAU,MAAO,yBAA0B,EAAG,OAAOG,EAAQ,UAAgB,UAAYA,EAAQ,SAAcA,EAAQ,SAAcL,EAAM,UAAU,EACxLgB,EAAQC,GAAUf,CAAI,EACtBgB,EAAUhB,EAAK,MAAO,CAAE,GAAAP,EAAI,MAAO,YAAa,KAAM,OAAQ,EAAGmB,EAAMC,EAAWC,EAAM,OAAO,EAE/FG,EAAQ,IAAI,IACZC,EAAQ,IAAO7B,EAAK,SAAS,EAAE,OAAOC,CAAI,GAAuB,CAAC,EACpE6B,EAAW,GAEXC,EAAiC,KAGrC,QAASC,EAAOH,EAAM,EAAE,OAAQG,EAAOjB,EAAKiB,IAAQhC,EAAK,QAAQC,CAAI,EAErEuB,EAAU,iBAAiB,QAAS,IAAM,CACxC,GAAIM,GAAYD,EAAM,EAAE,QAAUb,EAAK,OACvC,IAAMiB,EAAMjC,EAAK,QAAQC,CAAI,EAC7B8B,EAAY,IAAMH,EAAM,IAAIK,CAAG,GAAG,OAAO,CAAC,GAAG,OAAO,MAAM,EAC1DC,EAAO,CACT,CAAC,EAED,SAASC,EAASC,EAAkB,CAClC,IAAMC,EAAU,GAAGjC,CAAE,IAAIgC,EAAK,GAAG,SAC3BE,EAAQ3B,EAAK,OAAQ,CAAE,GAAI0B,EAAS,MAAO,iBAAkB,CAAC,EAC9DE,EAAS5B,EAAK,SAAU,CAAE,KAAM,SAAU,MAAO,kBAAmB,EAAG,MAAG,EAC1E6B,EAAO,CAACC,EAAcC,EAAsCC,IAAsD,CACtH,IAAMC,EAASjC,EAAK,SAAU,CAAE,KAAM,SAAU,MAAO,gBAAiB,EAAG8B,CAAI,EAC/E,OAAAG,EAAO,iBAAiB,QAASD,CAAG,EAC7B,CAACC,EAAQF,CAAI,CACtB,EACMG,EAAK,IAAMhB,EAAM,EAAE,UAAWiB,GAAMA,EAAE,MAAQV,EAAK,GAAG,EACtDW,EAAQ,CAACP,EAAK,SAAK,SAAU,IAAMQ,EAAKZ,EAAK,IAAKS,EAAG,EAAI,CAAC,CAAC,EAAGL,EAAK,SAAK,WAAY,IAAMQ,EAAKZ,EAAK,IAAKS,EAAG,EAAI,CAAC,CAAC,EAAGL,EAAK,SAAK,OAAQ,IAAMS,EAAKb,EAAK,GAAG,CAAC,CAAC,EAC5Jc,EAAOvC,EAAK,MAAO,CAAE,MAAO,kBAAmB,CAAC,EAChDwC,EAAcxC,EAAK,MAAO,CAAE,MAAO,iBAAkB,KAAM,QAAS,kBAAmB0B,EAAS,YAAaD,EAAK,GAAI,EAAGzB,EAAK,MAAO,CAAE,MAAO,gBAAiB,EAAG2B,EAAO,GAAGS,EAAM,IAAI,CAAC,CAACK,CAAC,IAAMA,CAAC,EAAGb,CAAM,EAAGW,CAAI,EAChNG,EAAShC,EAAM,IAAKiC,GAAW,CACnC,IAAMC,EAAM1C,EAAI,OAAOyC,CAAM,EACvBE,EAAS,GAAGpD,CAAE,IAAIgC,EAAK,GAAG,IAAIkB,CAAM,GACpCG,EAAqB,CAAE,KAAM,QAAS,GAAI,GAAGtD,EAAK,EAAE,IAAIiC,EAAK,GAAG,IAAIkB,CAAM,GAAI,MAAOA,CAAO,EAC5FI,GAASC,GAAa,CAAE,KAAMC,GAAS5D,EAAMC,EAAMmC,EAAK,GAAG,EAAG,KAAMkB,EAAQ,MAAOC,EAAc,KAAME,EAAS,GAAID,EAAQ,SAAAnD,EAAU,OAAAC,EAAQ,OAAAC,EAAQ,QAAAC,CAAQ,CAAC,EAC/JqD,GAAQlD,EAAK,QAAS,CAAE,MAAO,kBAAmB,IAAK6C,CAAO,EAAGD,EAAI,KAAK,EAC3E,CAAC,QAAS,SAAU,UAAU,EAAE,SAASG,GAAO,QAAQ,OAAO,GAAGG,GAAM,iBAAiB,QAAS,IAAMH,GAAO,MAAM,CAAC,EAC3H,IAAMI,GAAQnD,EAAK,MAAO,CAAE,MAAO,gBAAiB,OAAQ,EAAG,CAAC,EAChE,OAAAuC,EAAK,OAAOvC,EAAK,MAAO,CAAE,MAAO,iBAAkB,EAAGkD,GAAOH,GAAO,QAASI,EAAK,CAAC,EAC5E,CAAE,KAAMR,EAAQ,IAAKC,EAAK,OAAAG,GAAQ,MAAAI,EAAM,CACjD,CAAC,EACD,OAAAvB,EAAO,iBAAiB,QAAS,IAAM,CACrC,IAAMwB,EAAMlC,EAAM,EACZgB,EAAKkB,EAAI,UAAWjB,IAAMA,GAAE,MAAQV,EAAK,GAAG,EAClD,GAAIN,GAAYe,IAAO,IAAMkB,EAAI,QAAUhD,EAAK,OAChD,IAAMiD,EAAO1B,EAAM,aAAe,GAClCtC,EAAK,WAAWC,EAAMmC,EAAK,GAAG,EAC9BX,EAAM,IAAIL,GAAOX,EAAM,QAAS,CAAE,KAAMuD,CAAK,CAAC,CAAC,EAE/C,IAAMC,EAAQpC,EAAM,EACdqC,GAAOD,EAAM,KAAK,IAAIpB,EAAIoB,EAAM,OAAS,CAAC,CAAC,EACjDlC,EAAY,IAAOmC,GAAOtC,EAAM,IAAIsC,GAAK,GAAG,GAAG,OAAO,CAAC,GAAG,OAAO,MAAM,EAAI1C,EAAU,MAAM,EAC3FU,EAAO,CACT,CAAC,EACM,CAAE,QAASiB,EAAa,MAAAb,EAAO,OAAAC,EAAQ,MAAAQ,EAAO,OAAAM,CAAO,CAC9D,CAGA,SAASL,EAAKf,EAAakC,EAAY,CACrC,IAAMC,EAAOvC,EAAM,EAAE,UAAWiB,GAAMA,EAAE,MAAQb,CAAG,EACnD,GAAIH,GAAYqC,EAAK,GAAKA,GAAMtC,EAAM,EAAE,QAAUsC,IAAOC,EAAM,OAC/D,IAAMJ,EAAOpC,EAAM,IAAIK,CAAG,GAAG,MAAM,aAAe,GAClDoC,GAAWrE,EAAMC,EAAMY,EAAKoB,EAAKkC,CAAE,EAEnC,IAAMG,EAAOF,EAAOD,GAAMA,EAAK,GAAMA,IAAOtC,EAAM,EAAE,OAAS,EAAI,EAAI,EACrED,EAAM,IAAIK,CAAG,GAAG,MAAMqC,CAAG,EAAE,CAAC,EAAE,MAAM,EACpC7C,EAAM,IAAIL,GAAOX,EAAM,QAAS,CAAE,MAAOuD,EAAM,EAAGG,EAAK,EAAG,MAAOtC,EAAM,EAAE,MAAO,CAAC,CAAC,CACpF,CAGA,SAASoB,EAAKhB,EAAa,CACzB,IAAM8B,EAAMlC,EAAM,EACZgB,EAAKkB,EAAI,UAAWjB,GAAMA,EAAE,MAAQb,CAAG,EAC7C,GAAIH,GAAYe,EAAK,GAAKkB,EAAI,QAAU/C,EAAK,OAC7C,IAAMuD,EAAS,CAAE,GAAGR,EAAIlB,CAAE,EAAE,MAAO,EAC/BhC,EAAI,eAAe,OAAO0D,EAAO1D,EAAI,aAAa,EACtD,IAAM2D,EAAOxE,EAAK,QAAQC,EAAMsE,CAAM,EACtCF,GAAWrE,EAAMC,EAAMY,EAAK2D,EAAM3B,EAAK,CAAC,EACxCjB,EAAM,IAAI4C,CAAI,GAAG,OAAO,CAAC,GAAG,OAAO,MAAM,CAC3C,CAEA,SAAStC,GAAS,CAChB,IAAMuC,EAAM1C,EACZA,EAAY,KACZ0C,IAAM,CACR,CAEA,MAAO,CACL,QAAA9C,EACA,MAAO,KAAO,CAAC,GAAGC,EAAM,OAAO,CAAC,EAAE,KAAM8C,GAASA,EAAK,UAAYnD,EAAK,iBAAiB,GAAG,OAAO,CAAC,GAAG,QAAUC,GAAW,MAAM,EACjI,OAAOmD,EAAO,CACZ7C,EAAW6C,EAAM,SACjB,IAAMC,EAAWD,EAAM,OAA2B,CAAC,EAC7CE,EAAS7E,EAAK,SAAS,EAAE,OACzB8E,EAAO,IAAI,IAAIF,EAAQ,IAAK9B,GAAMA,EAAE,GAAG,CAAC,EAC9C,OAAW,CAACb,EAAKyC,CAAI,IAAK9C,EACxB,GAAI,CAAAkD,EAAK,IAAI7C,CAAG,EAChB,CAAAyC,EAAK,QAAQ,OAAO,EACpB,QAAWpD,KAAKoD,EAAK,OAAQpD,EAAE,OAAO,UAAU,EAChDM,EAAM,OAAOK,CAAG,EAElB2C,EAAQ,QAAQ,CAACxC,EAAM2C,IAAU,CAC/B,IAAIL,EAAO9C,EAAM,IAAIQ,EAAK,GAAG,EACxBsC,GAAM9C,EAAM,IAAIQ,EAAK,IAAMsC,EAAOvC,EAASC,CAAI,CAAE,EAClDb,EAAK,SAASwD,CAAK,IAAML,EAAK,SAASnD,EAAK,aAAamD,EAAK,QAASnD,EAAK,SAASwD,CAAK,GAAK,IAAI,EACvGL,EAAK,MAAM,YAAcxD,EAAQ6D,EAAQ,CAAC,EAC1CL,EAAK,OAAO,aAAa,aAActD,GAAOX,EAAM,OAAQ,CAAE,KAAMiE,EAAK,MAAM,WAAY,CAAC,CAAC,EAC7FA,EAAK,OAAO,OAAS5C,GAAY8C,EAAQ,QAAU7D,EACnD,OAAW,CAAC6B,EAAQF,CAAI,IAAKgC,EAAK,MAChC9B,EAAO,aAAa,aAAcxB,GAAOX,EAAMiC,CAAI,EAAG,CAAE,MAAOgC,EAAK,MAAM,YAAa,KAAMA,EAAK,MAAM,WAAY,CAAC,CAAC,EACtH9B,EAAO,OAASd,IAAaY,IAAS,SAAWqC,IAAU,EAAIrC,IAAS,WAAaqC,IAAUH,EAAQ,OAAS,EAAIA,EAAQ,QAAU5D,GAExI,QAAWM,KAAKoD,EAAK,OAAQ,CAC3B,IAAMM,EAAUH,EAAO,GAAG5E,CAAI,IAAImC,EAAK,GAAG,IAAId,EAAE,IAAI,EAAE,EACtDA,EAAE,MAAM,OAAS,CAAC0D,EAClB1D,EAAE,MAAM,YAAc0D,GAAW,GACjC1D,EAAE,OAAO,OAAO,CAAE,MAAOc,EAAK,OAAOd,EAAE,IAAI,EAAG,OAAQc,EAAK,OAAQ,SAAUN,GAAYR,EAAE,IAAI,WAAa,GAAM,SAAUA,EAAE,IAAI,WAAa,GAAM,QAAS,CAAC,CAAC0D,CAAQ,CAAC,CAC3K,CACF,CAAC,EACDxD,EAAU,OAASM,GAAY8C,EAAQ,QAAU5D,EACjDiE,GAActD,EAASgD,CAAK,CAC9B,CACF,CACF,EC3JO,SAASO,GAAQC,EAAgB,CAAE,KAAAC,EAAM,KAAAC,EAAM,MAAAC,EAAO,SAAAC,EAAU,OAAAC,EAAQ,OAAAC,CAAO,EAAkBC,EAAqD,CAC3J,IAAMC,EAAOL,EAAM,OAAS,QAAUA,EAAM,OAAS,OAASA,EAAM,KAAO,OAC3E,GAAI,CAACK,GAAQP,EAAK,KAAK,OAAOC,CAAI,IAAMC,EAAO,OAAOH,EACtD,IAAMS,EAAOC,GAAMN,CAAQ,EACrBO,EAAQF,EAAK,MAAO,CAAE,MAAO,WAAY,cAAe,MAAO,CAAC,EAChEG,EAAOH,EAAK,MAAO,CAAE,MAAO,aAAc,YAAa,QAAS,CAAC,EACnEI,EACJ,MAAO,CACL,GAAGb,EACH,QAASS,EAAK,MAAO,CAAE,MAAO,YAAa,EAAGT,EAAO,QAASW,EAAOC,CAAI,EACzE,OAAOE,EAAO,CACZd,EAAO,OAAOc,CAAK,EACnB,IAAMC,EAAIR,EAAI,MAAM,OACpBS,GAAQL,EAAO,GAAGI,CAAC,MAAMP,CAAI,EAAE,EAC/BG,EAAM,UAAU,OAAO,gBAAiBI,GAAKP,EAAO,EAAG,EACvDS,GAAUN,EAAOG,EAAM,QAAQ,EAC3BV,EAAS,gBAAkBG,IAC/B,aAAaM,CAAK,EAClBA,EAAQ,WAAW,IAAMG,GAAQJ,EAAMM,GAAOC,GAASd,EAAQC,CAAM,EAAE,eAAgB,CAAE,EAAGE,EAAOO,CAAE,CAAC,CAAC,EAAG,GAAG,EAC/G,CACF,CACF,CAGO,SAASK,GAAOC,EAA2BC,EAA6B,CAC7E,IAAMC,EAAOD,EAAK,SAAU,KAE5B,OADI,OAAOC,GAAS,WAAUF,EAAK,KAAOE,GACtCD,EAAK,SAAU,WAAgB,GAAc,IAAG,GAC7C,IAAM,CACXD,EAAK,MAAM,OAAS,GAEhBA,EAAK,eAAcA,EAAK,MAAM,OAAS,GAAGA,EAAK,aAAeA,EAAK,aAAeA,EAAK,YAAY,KACzG,CACF,CAQO,SAASG,GAAOC,EAAyBtB,EAAcmB,EAAuB,CACnF,IAAMI,EAAUJ,EAAK,SAAW,CAAC,EAC3BK,EAAOxB,EAAM,OAAS,QACbwB,EAAO,CAACD,EAAQ,IAAQA,EAAQ,GAAM,EAAI,QAASvB,EAAQ,CAACA,EAAM,IAAKA,EAAM,GAAG,EAAI,CAAC,GAC7F,QAAQ,CAACyB,EAAOC,IAAM,CACvB,OAAOD,GAAU,WAAUH,EAAMI,EAAI,MAAQ,KAAK,EAAIF,EAAOC,EAAQE,GAAMF,CAAK,GAAKzB,EAAM,OAAS,WAAc0B,EAAI,SAAW,SAAY,IACnJ,CAAC,EACG,OAAOH,EAAQ,MAAY,WAAUD,EAAM,KAAO,OAAOC,EAAQ,KAAU,EAAE,EACnF,CCtDO,SAASK,GAAeC,EAAcC,EAAkD,CAC7F,GAAI,CACF,IAAMC,EAAQ,IAAI,KAAK,aAAaD,EAAQ,CAAE,MAAO,WAAY,SAAUD,EAAM,gBAAiB,cAAe,CAAC,EAAE,cAAc,CAAC,EAC7HG,EAAKD,EAAM,UAAWE,GAASA,EAAK,OAAS,UAAU,EAC7D,MAAO,CAAE,KAAMF,EAAMC,CAAE,EAAE,MAAO,MAAOA,EAAKD,EAAM,UAAWE,GAASA,EAAK,OAAS,SAAS,CAAE,CACjG,MAAQ,CACN,MAAO,CAAE,KAAMJ,EAAM,MAAO,EAAM,CACpC,CACF,CCPA,IAAMK,GAAM,6BAECC,GAAiB,CAC5B,KAAM,wEACN,MAAO,yJACP,SAAU,wGACV,KAAM,+EACN,MAAO,wEACP,KAAM,4EACN,IAAK,iGACL,MAAO,qGACP,SAAU,qFACV,MAAO,yDACP,MAAO,iHACP,KAAM,6GACN,IAAK,mFACL,MAAO,sHACP,QAAS,oEACT,KAAM,kEACN,KAAM,+DACN,IAAK,oEACL,KAAM,oFACN,KAAM,wFACN,MAAO,qCACP,KAAM,+DACN,QAAS,yDACT,SAAU,sJACV,MAAO,gDACP,KAAM,6HACN,KAAM,0DACN,KAAM,iCACN,OAAQ,0DACR,OAAQ,2CACR,OAAQ,0DACR,MAAO,sHACT,EAGO,SAASC,GAASC,EAAeC,EAA0BC,EAAqC,CACrG,IAAMC,EAASF,EAAOC,IAAMD,CAAI,GAAKH,GAAMG,CAAI,EAAI,OACnD,GAAIE,IAAW,OAAW,OAAO,KACjC,IAAMC,EAAMJ,EAAI,gBAAgBH,GAAK,KAAK,EAC1C,OAAW,CAACQ,EAAKC,CAAK,IAAK,OAAO,QAAQ,CACxC,QAAS,YACT,KAAM,OACN,OAAQ,eACR,eAAgB,MAChB,iBAAkB,QAClB,kBAAmB,QACnB,cAAe,OACf,UAAW,QACX,MAAO,UACP,YAAaL,CACf,CAAC,EACCG,EAAI,aAAaC,EAAKC,CAAK,EAE7B,OAAAF,EAAI,UAAYD,EACTC,CACT,CCxDO,SAASG,GAAYC,EAAwBC,EAAgC,CAClF,GAAM,CAAE,KAAAC,EAAM,KAAAC,EAAM,SAAUC,CAAI,EAAIH,EAChCI,EAAQC,GAASL,EAAQ,OAAQA,EAAQ,MAAM,EAC/CM,EAAMH,EAAI,cAAc,KAAK,EAC7BI,EAAOJ,EAAI,cAAc,KAAK,EAC9BK,EAAQL,EAAI,cAAc,QAAQ,EACxCK,EAAM,KAAO,SACbA,EAAM,UAAY,2BAClBA,EAAM,YAAcJ,EAAM,cAC1BI,EAAM,QAAU,IAAMP,EAAK,YAAYC,CAAI,EAC3CK,EAAK,aAAa,OAAQ,QAAQ,EAElCD,EAAI,MAAM,QAAU,uBAEpB,IAAMG,EAAQ,IAAI,IACdC,EACAC,EAAyB,KACvBC,EAAQC,GAAsB,CAClCH,GAAO,UAAU,EACjBA,EAAQX,EAAQ,CAAE,GAAGC,EAAS,MAAO,CAAE,GAAGA,EAAQ,MAAO,QAAAa,CAAQ,CAAW,CAAC,EAEzEH,EAAM,QAAQ,aAAa,MAAM,GAAGA,EAAM,QAAQ,aAAa,kBAAmB,GAAGV,EAAQ,EAAE,QAAQ,EAC3GM,EAAI,gBAAgBI,EAAM,QAASH,EAAMC,CAAK,CAChD,EACA,OAAAI,EAAK,CAAC,CAAC,EACFX,EAAK,SAAS,EAAE,QAAQC,CAAI,GAAGD,EAAK,YAAYC,CAAI,EAClD,CACL,QAASI,EACT,MAAO,IAAMI,EAAM,MAAM,EACzB,QAAS,IAAMA,EAAM,UAAU,EAC/B,OAAOI,EAAO,CACZ,IAAMC,EAAUd,EAAK,SAAS,EAAE,QAAQC,CAAI,EAC5C,GAAIa,GAAS,SAAWA,EAAQ,UAAYJ,EAAO,CACjDA,EAAQI,EAAQ,QAChB,QAAWC,KAAUL,EAAOF,EAAM,IAAIO,EAAO,MAAOA,EAAO,KAAK,EAChEJ,EAAKD,CAAK,CACZ,CACAD,EAAM,OAAOI,CAAK,EAElB,IAAMG,EAAON,GAAS,CAAEX,EAAQ,MAA8B,MAAQ,CAACc,EAAM,KAAK,EAAE,KAAK,EAAE,OAAQI,GAAMA,GAAK,MAAQ,CAACP,GAAO,KAAMQ,GAAMA,EAAE,QAAUD,CAAC,CAAC,EAAI,CAAC,EAC7JX,EAAK,UAAYQ,GAAS,QAAU,UAAY,aAChDR,EAAK,YAAcQ,GAAS,QAAUX,EAAM,eAAiBa,EAAK,OAASG,GAAKhB,EAAM,WAAY,CAAE,KAAMa,EAAK,IAAKC,GAAMT,EAAM,IAAIS,CAAC,GAAK,OAAOA,CAAC,CAAC,EAAE,KAAK,IAAI,CAAE,CAAC,EAAI,GACrKX,EAAK,OAAS,CAACA,EAAK,YAEpBC,EAAM,OAAS,CAACO,GAAS,KAC3B,CACF,CACF,CC/CO,IAAMM,GAA6B,CAAC,CAAE,KAAAC,EAAM,KAAAC,EAAM,KAAAC,EAAM,GAAAC,EAAI,SAAAC,EAAU,OAAAC,EAAQ,OAAAC,CAAO,IAAM,CAChG,IAAMC,EAAQC,GAASH,EAAQC,CAAM,EAC/BG,EAAOC,GAAMN,CAAQ,EAErBO,EAAQF,EAAK,MAAO,CAAE,GAAAN,EAAI,MAAO,sBAAuB,KAAM,YAAa,CAAC,EAC9ES,EAAW,GACTC,EAAU,CAAC,GAAM,EAAK,EAAE,IAAKC,GAAU,CAC3C,IAAMC,EAAMb,EAAK,UAAUY,EAAQ,WAAa,SAAS,EACnDE,EAASP,EAAK,SAAU,CAAE,KAAM,SAAU,KAAM,OAAQ,EAAG,OAAOM,GAAQ,UAAYA,EAAMA,EAAMD,EAAQP,EAAM,IAAMA,EAAM,EAAE,EACpI,OAAAS,EAAO,iBAAiB,QAAS,IAAMhB,EAAK,SAASC,EAAMa,CAAK,CAAC,EACjEH,EAAM,OAAOK,CAAM,EACZA,CACT,CAAC,EAEDL,EAAM,iBAAiB,UAAYM,GAAU,CAC3C,IAAMC,EAAKL,EAAQ,QAAQI,EAAM,MAA2B,EACxDL,GAAYM,IAAO,IAAM,CAACD,EAAM,IAAI,WAAW,OAAO,IAC1DA,EAAM,eAAe,EACrBjB,EAAK,SAASC,EAAMiB,IAAO,CAAC,EAC5BL,EAAQ,EAAIK,CAAE,EAAE,MAAM,EACxB,CAAC,EACD,IAAMC,EAAQC,GAAehB,EAAUG,EAAO,IAAM,CAClDP,EAAK,SAASC,EAAM,IAAI,EACxBY,EAAQ,CAAC,EAAE,MAAM,CACnB,CAAC,EACD,MAAO,CACL,QAASJ,EAAK,MAAO,CAAE,MAAO,gBAAiB,EAAGE,EAAOQ,EAAM,MAAM,EACrE,MAAO,KAAON,EAAQ,KAAMQ,GAAMA,EAAE,aAAa,cAAc,IAAM,MAAM,GAAKR,EAAQ,CAAC,GAAG,MAAM,EAClG,OAAOS,EAAO,CACZV,EAAWU,EAAM,SACjB,IAAMC,EAASD,EAAM,QAAU,GAAO,EAAIA,EAAM,QAAU,GAAQ,EAAI,GACtET,EAAQ,QAAQ,CAACG,EAAQQ,IAAM,CAC7BC,GAAQT,EAAQ,eAAgB,OAAOQ,IAAMD,CAAM,CAAC,EACpDP,EAAO,UAAU,OAAO,QAASQ,IAAMD,CAAM,EAC7CP,EAAO,SAAWQ,IAAM,KAAK,IAAI,EAAGD,CAAM,EAAI,EAAI,GAClDP,EAAO,SAAWJ,CACpB,CAAC,EACDa,GAAQd,EAAO,gBAAiB,OAAOW,EAAM,QAAQ,CAAC,EACtDH,EAAM,MAAMG,CAAK,EACjBH,EAAM,KAAKI,IAAW,EAAE,EACxBG,GAAcf,EAAOW,CAAK,CAC5B,CACF,CACF,ECyDO,SAASK,GAAaC,EAAwBC,EAA0C,CAAC,EAAW,CACzG,GAAM,CAAE,MAAAC,EAAO,KAAAC,CAAK,EAAIH,EAClBI,EAAO,CACXD,EAAK,OAAS,GAAGD,EAAM,IAAI,IAAIC,EAAK,MAAM,GAAK,KAC/CD,EAAM,OAAS,aAAeA,EAAM,SAAW,uBAAyB,KACxEA,EAAM,IACR,EAAE,OAAQG,GAAuBA,IAAQ,IAAI,EAC7C,QAAWA,KAAOD,EAAM,CACtB,IAAME,EAAUL,EAASI,CAAG,GAAKE,GAAeF,CAAG,EAEnD,GAAIC,EAAS,OAAOJ,EAAM,OAAS,aAAeA,EAAM,YAAcM,GAAYF,EAASN,CAAO,EAAIM,EAAQN,CAAO,CACvH,CACA,OAAOS,GAAcT,CAAO,CAC9B,CAIA,SAASU,GACPC,EACAC,EACAC,EAAyC,CAAC,KACvCC,EACuB,CAC1B,IAAMC,EAAUJ,EAAI,cAAcC,CAAG,EACrC,OAAW,CAACI,EAAMC,CAAK,IAAK,OAAO,QAAQJ,CAAK,EAAOI,IAAU,QAAWF,EAAQ,aAAaC,EAAMC,CAAK,EAC5G,OAAAF,EAAQ,OAAO,GAAGD,CAAQ,EACnBC,CACT,CAEA,SAASG,GAASH,EAAsBI,EAAoB,CAC1DC,GAAQL,EAAS,eAAgB,OAAOI,EAAM,OAAO,CAAC,EAEtDC,GAAQL,EAAS,gBAAiBA,EAAQ,aAAa,MAAM,IAAM,QAAU,KAAO,OAAOI,EAAM,QAAQ,CAAC,EAC1GC,GAAQL,EAAS,mBAAoBI,EAAM,aAAe,IAAI,CAChE,CAEA,IAAME,GAAUJ,GAA8BA,GAAU,KAA8B,GAAK,OAAOA,CAAK,EAEvG,SAASK,GAAWC,EAAkC,CACpD,OAAQvB,GAAY,CAClB,GAAM,CAAE,KAAAwB,EAAM,KAAAR,EAAM,MAAAd,EAAO,KAAAC,EAAM,GAAAsB,EAAI,SAAAC,CAAS,EAAI1B,EAE5C2B,EAAQjB,GAAKgB,EAAU,QAAS,CAAE,GAAAD,EAAI,KAAMF,EAAW,MAAO,WAAY,aAAc,oBAAoB,KAAKA,CAAS,EAAIA,EAAY,KAAM,CAAC,EACvJ,OAAIrB,EAAM,OAAS,QAAUA,EAAM,OAAS,SAAWyB,EAAM,UAAYzB,EAAM,MAC3EqB,IAAc,QAAQK,GAAOD,EAAOzB,EAAOC,CAAI,EAC/CA,EAAK,cAAawB,EAAM,YAAcxB,EAAK,aAC/CwB,EAAM,iBAAiB,QAAS,IAAMH,EAAK,SAASR,EAAMW,EAAM,QAAU,GAAK,KAAOA,EAAM,KAAK,CAAC,EAC3FE,GAAQ,CACb,QAASF,EACT,MAAO,IAAMA,EAAM,MAAM,EACzB,OAAOR,EAAO,CACZ,IAAMW,EAAOT,GAAOF,EAAM,KAAK,EAC3BQ,EAAM,QAAUG,IAAMH,EAAM,MAAQG,GACpCH,EAAM,WAAaR,EAAM,WAAUQ,EAAM,SAAWR,EAAM,UAC9DD,GAASS,EAAOR,CAAK,CACvB,CACF,EAAGnB,EAAS2B,CAAK,CACnB,CACF,CAEA,IAAMI,GAAiC/B,GAAY,CACjD,GAAM,CAAE,KAAAwB,EAAM,KAAAR,EAAM,MAAAd,EAAO,KAAAC,EAAM,GAAAsB,EAAI,SAAAC,CAAS,EAAI1B,EAC5CgC,EAAOtB,GAAKgB,EAAU,WAAY,CAAE,GAAAD,EAAI,MAAO,uBAAwB,KAAM,GAAI,CAAC,EACpFvB,EAAM,OAAS,QAAUA,EAAM,OAAS,SAAW8B,EAAK,UAAY9B,EAAM,MAC1EC,EAAK,cAAa6B,EAAK,YAAc7B,EAAK,aAC9C,IAAM8B,EAAOC,GAAOF,EAAM7B,CAAI,EAC9B,OAAA6B,EAAK,iBAAiB,QAAS,IAAM,CACnCC,EAAK,EACLT,EAAK,SAASR,EAAMgB,EAAK,QAAU,GAAK,KAAOA,EAAK,KAAK,CAC3D,CAAC,EACMH,GAAQ,CACb,QAASG,EACT,MAAO,IAAMA,EAAK,MAAM,EACxB,OAAOb,EAAO,CACZ,IAAMW,EAAOT,GAAOF,EAAM,KAAK,EAC3Ba,EAAK,QAAUF,IACjBE,EAAK,MAAQF,EACbG,EAAK,GAEHD,EAAK,WAAab,EAAM,WAAUa,EAAK,SAAWb,EAAM,UAC5DD,GAASc,EAAMb,CAAK,CACtB,CACF,EAAGnB,EAASgC,CAAI,CAClB,EAEMG,GAAS,wBACTC,GAAa,UAQbC,GAA+BrC,GAAY,CAC/C,GAAM,CAAE,KAAAwB,EAAM,KAAAR,EAAM,MAAAd,EAAO,KAAAC,EAAM,GAAAsB,EAAI,SAAAC,EAAU,OAAAY,EAAS,IAAK,EAAItC,EAC3DuC,EAAUrC,EAAM,OAAS,UACzBsC,EAAWD,EAAU,GAAKrC,EAAM,OAAS,SAAWA,EAAM,OAAS,WAAaA,EAAM,SAAS,CAAC,EAAI,SAAc,EAClHuC,EAASxB,GAA8B,OAAOA,GAAU,SAAWyB,GAAazB,EAAOuB,EAAUF,CAAM,EAAIjB,GAAOJ,CAAK,EACvHU,EAAQjB,GAAKgB,EAAU,QAAS,CAAE,GAAAD,EAAI,KAAM,OAAQ,MAAO,2BAA4B,aAAc,KAAM,CAAC,EAClHE,EAAM,UAAYY,EAAU,UAAY,UACpCpC,EAAK,cAAawB,EAAM,YAAcxB,EAAK,aAE/C,IAAMwC,EAASC,GAAmC,CAChD,IAAMd,EAAOe,GAAgBD,EAAI,KAAK,EAAGN,CAAM,EAC/C,GAAIR,IAAS,GAAI,OAAO,KACxB,GAAIK,GAAO,KAAKL,CAAI,EAAG,OAAO,OAAOA,CAAI,EACzC,GAAI,CAAAM,GAAW,KAAKN,CAAI,EACxB,OAAOA,CACT,EACAH,EAAM,iBAAiB,QAAS,IAAM,CACpC,IAAMV,EAAQ0B,EAAMhB,EAAM,KAAK,EAC3BV,IAAU,QAAWO,EAAK,SAASR,EAAMC,CAAK,CACpD,CAAC,EACDU,EAAM,iBAAiB,OAAQ,IAAM,CACnCA,EAAM,MAAQc,EAAMjB,EAAK,SAAS,EAAE,OAAOR,CAAI,CAAC,CAClD,CAAC,EAID,IAAM8B,EAAU3C,EAAK,SAAW,CAAC,EAC3B4C,EAAgB7C,EAAM,OAAS,WAAaA,EAAM,cAAgB,OAClE8C,EAAcD,EAAgBvB,EAAK,KAAK,OAAOuB,CAAa,EAAI,OAChEE,EACJF,GAAiBC,GAAeF,EAAQ,eAAoB,GACxD/C,GAAa,CAAE,GAAGC,EAAS,KAAM+C,EAAe,MAAOC,EAAa,KAAM,CAAE,KAAM,QAAS,GAAI,GAAG7C,EAAK,EAAE,YAAa,MAAO4C,CAAc,EAAG,GAAI,GAAGtB,CAAE,WAAY,CAAC,EACpK,KACFwB,GAAUD,GAAaC,EAAO,QAAQ,cAAc,eAAe,GAAG,aAAa,aAAcD,EAAY,KAAK,EAClHC,GAAQ,QAAQ,QAAQ,eAAe,GAAKD,GAAaC,EAAO,QAAQ,aAAa,aAAcD,EAAY,KAAK,EAExH,IAAME,EAAQJ,EAAQ,OAAYA,EAAQ,SAAc,QAAU5C,EAAM,OAAS,YAAciD,GAAejD,EAAM,UAAY,MAAOoC,CAAM,EAAE,MACzIc,EAAO,CAACtB,EAAcuB,IAAc3C,GAAKgB,EAAU,OAAQ,CAAE,MAAO,UAAUxB,EAAM,OAAS,WAAa,eAAiB,EAAE,GAAI,GAAI,GAAGuB,CAAE,QAAQ4B,CAAC,EAAG,EAAGvB,CAAI,EAC7JwB,EAAWpD,EAAM,OAAS,YAAc,CAAC+C,EAASG,EAAK,GAAI,CAAC,EAAI,KAChE,CAACG,EAAQC,CAAM,EAAI,CAAC,SAAU,QAAQ,EAAE,IAAI,CAACnD,EAAKgD,IAAO,OAAOP,EAAQzC,CAAG,GAAM,UAAYyC,EAAQzC,CAAG,EAAI+C,EAAKN,EAAQzC,CAAG,EAAagD,EAAI,CAAC,EAAI,IAAK,EACvJI,GAASP,EAAQ,KAAQD,GAAQ,SAAWK,IAAcC,EAC1DG,GAAQR,EAASD,GAAQ,SAAWK,EAAY,OAASE,EACzDG,EAAQ,CAACF,EAAOC,CAAI,EAAE,OAAQE,GAAwB,CAAC,CAACA,GAAKA,IAAMX,GAAQ,OAAO,EAMxF,MAAO,CACL,QALAQ,GAASC,EACLhD,GAAKgB,EAAU,OAAQ,CAAE,MAAO,YAAYwB,EAAQ,qBAAuB,EAAE,GAAGD,EAAS,sBAAwB,EAAE,EAAG,EAAG,GAAG,CAACQ,EAAO9B,EAAO+B,CAAI,EAAE,OAAQE,GAAwB,CAAC,CAACA,CAAC,CAAC,EACrLjC,EAIJ,MAAO,IAAMA,EAAM,MAAM,EACzB,OAAOR,EAAO,CACZ,IAAM0C,EAASnC,EAAS,gBAAkBC,EACpCmC,EAASnB,EAAMhB,EAAM,KAAK,EAC1BoC,EAAYD,IAAW,QAAaA,IAAW3C,EAAM,MAC3D,GAAI,EAAE0C,GAAUE,GAAY,CAC1B,IAAMjC,EAAOW,EAAMtB,EAAM,KAAK,EAC1BQ,EAAM,QAAUG,IAAMH,EAAM,MAAQG,EAC1C,CAMA,GALIH,EAAM,WAAaR,EAAM,WAAUQ,EAAM,SAAWR,EAAM,UAC9DD,GAASS,EAAO,CAAE,GAAGR,EAAO,YAAa,CAACA,EAAM,YAAa,GAAGwC,EAAM,IAAKC,GAAMA,EAAE,EAAE,CAAC,EAAE,OAAO,OAAO,EAAE,KAAK,GAAG,CAAE,CAAC,EAC/GX,GAAUF,GACZE,EAAO,OAAO,CAAE,MAAO9B,EAAM,OAAO4B,CAAa,EAAG,OAAQ5B,EAAM,OAAQ,SAAUA,EAAM,SAAU,SAAU,GAAO,QAAS,EAAM,CAAC,EAEnImC,GAAYpD,EAAM,OAAS,WAAY,CACzC,IAAM8D,EAAS9D,EAAM,cAAgBiB,EAAM,OAAOjB,EAAM,aAAa,EAAI,KACnE+D,EAAOD,GAAU,OAAOA,GAAW,UAAY,UAAWA,EAAUA,EAAyB,MAAS,OAAOA,GAAW,SAAWA,EAAS9D,EAAM,UAAY,GACpKgE,GAAQZ,EAAU,aAAa,KAAKW,CAAI,EAAId,GAAec,EAAM3B,CAAM,EAAE,KAAO2B,CAAI,CACtF,CAEA,OAAW,CAACL,EAAGO,CAAI,GAAK,CAAC,CAACV,EAAO,OAAO,EAAG,CAACC,EAAM,KAAK,CAAC,EAAgBE,GAAKD,EAAM,SAASC,CAAC,GAAGjC,EAAM,MAAM,YAAY,kBAAkBwC,CAAI,GAAI,0BAA0BP,EAAE,aAAa,QAAU,CAAC,WAAW,CACnN,CACF,CACF,EAGA,SAASQ,GAAeC,EAAkC,MAAsB,CAC9E,IAAMC,EAAQD,IAAS,SAAW,CAAE,MAAO,YAAa,KAAM,QAAS,EAAI,CAAE,MAAOA,IAAS,OAAS,sBAAwB,aAAc,EAC5I,MAAO,CAAC,CAAE,KAAA7C,EAAM,KAAAR,EAAM,GAAAS,EAAI,SAAAC,CAAS,IAAM,CACvC,IAAM6C,EAAM7D,GAAKgB,EAAU,QAAS,CAAE,GAAAD,EAAI,KAAM,WAAY,GAAG6C,CAAM,CAAC,EACtE,OAAAC,EAAI,iBAAiB,SAAU,IAAM/C,EAAK,SAASR,EAAMuD,EAAI,OAAO,CAAC,EAC9D,CACL,QAASA,EACT,MAAO,IAAMA,EAAI,MAAM,EACvB,OAAOpD,EAAO,CACZoD,EAAI,QAAUpD,EAAM,QAAU,GAC1BoD,EAAI,WAAapD,EAAM,WAAUoD,EAAI,SAAWpD,EAAM,UAC1DD,GAASqD,EAAKpD,CAAK,CACrB,CACF,CACF,CACF,CAEA,SAAS2B,GAAQ5C,EAAc,CAC7B,OAAOA,EAAM,OAAS,YAAcA,EAAM,QAAU,CAAC,CACvD,CAEA,IAAMsE,GAA+BxE,GAAY,CAC/C,GAAM,CAAE,KAAAwB,EAAM,KAAAR,EAAM,MAAAd,EAAO,KAAAC,EAAM,GAAAsB,EAAI,SAAAC,CAAS,EAAI1B,EAE5CyE,EAAStE,EAAK,SAAU,OAC9B,GAAIsE,IAAW,IAASA,IAAW,IAAS3B,GAAQ5C,CAAK,EAAE,OAAS,GAAK,OAAOwE,GAAa1E,CAAO,EACpG,IAAM2E,EAAUC,GAAa9B,GAAQ5C,CAAK,EAAGsB,EAAMR,EAAMb,CAAI,EACvD0E,EAASnE,GAAKgB,EAAU,SAAU,CAAE,GAAAD,EAAI,MAAO,oBAAqB,EAAGf,GAAKgB,EAAU,SAAU,CAAE,MAAO,EAAG,CAAC,CAAC,EACpH,OAAAiD,EAAQ,QAAQ,CAACG,EAAQC,IAAMF,EAAO,OAAOnE,GAAKgB,EAAU,SAAU,CAAE,MAAO,OAAOqD,CAAC,CAAE,EAAGD,EAAO,KAAK,CAAC,CAAC,EAC1GD,EAAO,iBAAiB,SAAU,IAAMrD,EAAK,SAASR,EAAM6D,EAAO,QAAU,GAAK,KAAOF,EAAQ,OAAOE,EAAO,KAAK,CAAC,EAAE,KAAK,CAAC,EACtH,CACL,QAASA,EACT,MAAO,IAAMA,EAAO,MAAM,EAC1B,OAAO1D,EAAO,CACZ,IAAM6D,EAAQL,EAAQ,UAAWG,GAAWA,EAAO,QAAU3D,EAAM,KAAK,EACxE0D,EAAO,MAAQG,IAAU,GAAK,GAAK,OAAOA,CAAK,EAC3CH,EAAO,WAAa1D,EAAM,WAAU0D,EAAO,SAAW1D,EAAM,UAChED,GAAS2D,EAAQ1D,CAAK,CACxB,CACF,CACF,EAEA,SAAS8D,GAAYC,EAA2C,CAC9D,MAAO,CAAC,CAAE,KAAA1D,EAAM,KAAAR,EAAM,MAAAd,EAAO,KAAAC,EAAM,GAAAsB,EAAI,SAAAC,EAAU,OAAAyD,EAAQ,OAAA7C,CAAO,IAAM,CAEpE,IAAMqC,EAAUC,GAAa9B,GAAQ5C,CAAK,EAAGsB,EAAMR,EAAMb,CAAI,EACvDiF,EAAQC,GAASF,EAAQ7C,CAAM,EAC/BgD,EAAQ5E,GAAKgB,EAAU,MAAO,CAAE,GAAAD,EAAI,MAAO,yBAAyByD,CAAI,GAAI,KAAMA,IAAS,QAAU,aAAe,OAAQ,CAAC,EACnIK,GAAOD,EAAOnF,CAAI,EAClB,IAAMqF,EAAQN,IAAS,WAAaO,GAAQC,GAAMhE,CAAQ,EAAG0D,EAAOjF,CAAI,EAAI,KACtEwF,EAAShB,EAAQ,IAAI,CAACG,EAAQC,IAAM,CACxC,IAAMpD,EAAQjB,GAAKgB,EAAU,QAAS,CAAE,KAAMwD,EAAM,KAAMzD,EAAI,MAAO,OAAOsD,CAAC,EAAG,GAAI,GAAGtD,CAAE,IAAIsD,CAAC,EAAG,CAAC,EAClG,OAAAO,EAAM,OAAO5E,GAAKgB,EAAU,QAAS,CAAE,MAAO,YAAa,IAAK,GAAGD,CAAE,IAAIsD,CAAC,EAAG,EAAGpD,EAAOjB,GAAKgB,EAAU,OAAQ,CAAC,EAAGoD,EAAO,KAAK,CAAC,CAAC,EACzHnD,CACT,CAAC,EAEKiE,EAAQ1F,EAAM,OAAS,aAAeA,EAAM,QAAU,GACtD2F,EAAcD,EAAQlF,GAAKgB,EAAU,QAAS,CAAE,KAAMwD,EAAM,KAAMzD,EAAI,MAAO,QAAS,GAAI,GAAGA,CAAE,QAAS,CAAC,EAAI,KAC7GqE,EAAWF,EAAQlF,GAAKgB,EAAU,QAAS,CAAE,KAAM,OAAQ,MAAO,0BAA2B,aAAc0D,EAAM,YAAa,aAAc,KAAM,CAAC,EAAI,KACzJS,GAAeC,IACjBR,EAAM,OAAO5E,GAAKgB,EAAU,MAAO,CAAE,MAAO,2BAA4B,EAAGhB,GAAKgB,EAAU,QAAS,CAAE,MAAO,uBAAwB,IAAK,GAAGD,CAAE,QAAS,EAAGoE,EAAanF,GAAKgB,EAAU,OAAQ,CAAC,EAAG0D,EAAM,KAAK,CAAC,EAAGU,CAAQ,CAAC,EAE1NA,EAAS,iBAAiB,QAAS,IAAM,CAClCD,EAAY,UAASA,EAAY,QAAU,IAChDE,EAAKF,CAAW,CAClB,CAAC,EACDA,EAAY,iBAAiB,SAAU,IAAM,CACvCA,EAAY,SAASC,EAAS,MAAM,CAC1C,CAAC,GAECN,GAAO,SAASF,EAAM,OAAOE,EAAM,OAAO,EAE9C,SAASO,EAAKC,EAA6B,CAEzC,GAAId,IAAS,YAAcc,aAAkB,kBAAoBA,EAAO,QAAS,CAC/E,IAAMC,EAAQtB,EAAQgB,EAAO,QAAQK,CAAM,CAAC,GAAG,YAAc,GAC7DL,EAAO,QAAQ,CAAChE,EAAOoD,IAAMpD,IAAUqE,IAAWC,GAAStB,EAAQI,CAAC,EAAE,aAAepD,EAAM,QAAU,GAAM,EACvGsE,GAASJ,IAAaA,EAAY,QAAU,GAClD,CACA,IAAMK,EAAML,GAAa,SAAWC,GAAYA,EAAS,MAAM,KAAK,EAAIA,EAAS,MAAQ,KACzF,GAAIZ,IAAS,QAAS,CACpB,IAAMiB,EAASR,EAAO,UAAWhE,GAAUA,EAAM,OAAO,EACxDH,EAAK,SAASR,EAAMmF,IAAW,GAAKxB,EAAQwB,CAAM,EAAE,MAAQD,CAAG,CACjE,KAAO,CAEL,IAAMF,EAAS,IAAI,IAAIrB,EAAQ,OAAO,CAACyB,EAAGrB,IAAMY,EAAOZ,CAAC,EAAE,OAAO,CAAC,EAClEvD,EAAK,SAASR,EAAM,CAAC,GAAG8B,GAAQ5C,CAAK,EAAE,OAAQ4E,GAAWkB,EAAO,IAAIlB,CAAM,CAAC,EAAE,IAAKA,GAAWA,EAAO,KAAK,EAAG,GAAIoB,IAAQ,KAAO,CAACA,CAAG,EAAI,CAAC,CAAE,CAAC,CAC9I,CACF,CACAZ,EAAM,iBAAiB,SAAWe,GAAU,CACtCA,EAAM,SAAWP,GAAUC,EAAKM,EAAM,MAAM,CAClD,CAAC,EACD,IAAMC,EAAQ,IAAI,IAAI3B,EAAQ,IAAK4B,GAAMA,EAAE,KAAgB,CAAC,EACtDC,EAAS,IAAMb,EAAO,KAAMhE,GAAUA,EAAM,OAAO,GAAKkE,GAAa,UAAY,GACjFY,EACJvB,IAAS,QACLwB,GAAehF,EAAU0D,EAAO,IAAM,CACpC,QAAWzD,IAAS,CAAC,GAAGgE,EAAQE,CAAW,EAAOlE,IAAOA,EAAM,QAAU,IACzEH,EAAK,SAASR,EAAM,IAAI,GAEvB2E,EAAO,CAAC,GAAKE,IAAc,MAAM,CACpC,CAAC,EACD,KACN,MAAO,CACL,QAASY,EAAQ/F,GAAKgB,EAAU,MAAO,CAAE,MAAO,gBAAiB,EAAG4D,EAAOmB,EAAM,MAAM,EAAInB,EAC3F,MAAO,KAAOK,EAAO,KAAMhE,GAAUA,EAAM,OAAO,IAAMkE,GAAa,QAAUC,EAAW,OAASH,EAAO,CAAC,IAAI,MAAM,EACrH,OAAOxE,EAAO,CACZ,IAAMgF,EAAS,MAAM,QAAQhF,EAAM,KAAK,EAAIA,EAAM,MAAQ,CAACA,EAAM,KAAK,EAEhEwF,EAAO,CAAC,CAACnB,GAAO,KAAK,MAAM,QAAQrE,EAAM,KAAK,EAAIA,EAAM,MAAM,OAAS,CAAC,EAM9E,GALAwE,EAAO,QAAQ,CAAChE,EAAOoD,IAAM,CAC3BpD,EAAM,QAAUwE,EAAO,SAASxB,EAAQI,CAAC,EAAE,KAAc,EACzD,IAAM6B,EAAMzF,EAAM,UAAawF,GAAQ,CAAChF,EAAM,SAAW,CAACgD,EAAQI,CAAC,EAAE,UACjEpD,EAAM,WAAaiF,IAAKjF,EAAM,SAAWiF,EAC/C,CAAC,EACGf,GAAeC,EAAU,CAE3B,IAAMI,EAAMC,EAAO,KAAMU,GAAM,OAAOA,GAAM,UAAY,CAACP,EAAM,IAAIO,CAAC,CAAC,EAE/DC,EAAUjB,EAAY,SAAW,CAACC,EAAS,MAAM,KAAK,IAAMZ,IAAS,YAAciB,EAAO,MAAOU,GAAMA,GAAM,IAAuB,GAC1IhB,EAAY,QAAUK,IAAQ,QAAaY,EACvCZ,IAAQ,QAAaxE,EAAS,gBAAkBoE,IAAUA,EAAS,MAAQI,GAC/E,IAAMU,EAAMzF,EAAM,UAAawF,GAAQ,CAACd,EAAY,QAChDA,EAAY,WAAae,IAAKf,EAAY,SAAWC,EAAS,SAAWc,EAC/E,CACAH,GAAO,MAAMtF,CAAK,EAClBsF,GAAO,KAAKD,EAAO,CAAC,EACpBtF,GAASoE,EAAOnE,CAAK,CACvB,CACF,CACF,CACF,CAOA,SAAS4F,GAAaC,EAA0C,CAC9D,MAAO,CAAC,CAAE,KAAAxF,EAAM,KAAAR,EAAM,MAAAd,EAAO,KAAAC,EAAM,GAAAsB,EAAI,SAAAC,EAAU,OAAAyD,EAAQ,OAAA7C,CAAO,IAAM,CACpE,IAAM8C,EAAQC,GAASF,EAAQ7C,CAAM,EAC/B2E,EAAM,QAAS/G,GAAS,OAAOA,EAAM,KAAQ,SAAWA,EAAM,IAAM8G,IAAU,SAAW,EAAI,EAC7FE,EAAM,QAAShH,GAAS,OAAOA,EAAM,KAAQ,SAAWA,EAAM,IAAM8G,IAAU,SAAW,EAAI,GAC7FG,EAAOH,IAAU,SAAW7G,EAAK,SAAU,KAAU,SACrDiH,EAAUD,IAAS,SAEnBE,EAAML,IAAU,SAAW7G,EAAK,SAAU,MAAW,IAAQ8G,IAAQ,GAAKC,IAAQ,GAClF5B,EAAQ5E,GAAKgB,EAAU,MAAO,CAAE,GAAAD,EAAI,MAAO,gBAAgB2F,EAAU,SAAW,OAAO,GAAGA,EAAU,cAAcD,GAAQ,MAAM,GAAK,EAAE,GAAGE,EAAM,UAAY,EAAE,GAAI,KAAM,YAAa,CAAC,EACtLC,EAA8B,CAAC,EACrC,QAASjE,EAAI4D,EAAK5D,GAAK6D,EAAK7D,IAAK,CAC/B,IAAMkE,EAAQ7G,GAAKgB,EAAU,SAAU,CAAE,KAAM,SAAU,KAAM,QAAS,aAAc8F,GAAOpC,EAAM,MAAO,CAAE,EAAA/B,EAAG,IAAA6D,CAAI,CAAC,EAAG,aAAc,OAAO7D,CAAC,CAAE,EAAG8D,IAAS,QAAWM,GAAS/F,EAAU,OAAO,EAAsByF,IAAS,QAAU,SAAMC,EAAU,SAAM,OAAO/D,CAAC,CAAC,EACpQ2D,IAAU,SAASO,EAAM,gBAAgB,YAAY,EACrDF,IAAKE,EAAM,QAAQ,KAAUlE,EAAI,EAAI,MAAQA,EAAI,EAAI,MAAQ,QACjEkE,EAAM,iBAAiB,QAAS,IAAM/F,EAAK,SAASR,EAAMqC,CAAC,CAAC,EAC5DiE,EAAO,KAAKC,CAAK,EACjBjC,EAAM,OAAOiC,CAAK,CACpB,CACAjC,EAAM,iBAAiB,UAAYe,GAAU,CAC3C,IAAMqB,EAAUlG,EAAK,SAAS,EAAE,OAAOR,CAAI,EACrCC,EAAQ,OAAOyG,GAAY,SAAWA,EAAUT,EAAM,EACtDU,EAAOtB,EAAM,MAAQ,cAAgBA,EAAM,MAAQ,UAAY,EAAIA,EAAM,MAAQ,aAAeA,EAAM,MAAQ,YAAc,GAAK,EACvI,GAAI,CAACsB,EAAM,OACXtB,EAAM,eAAe,EACrB,IAAMuB,EAAO,KAAK,IAAIV,EAAK,KAAK,IAAID,EAAKhG,EAAQ0G,CAAI,CAAC,EACtDnG,EAAK,SAASR,EAAM4G,CAAI,EACxBN,EAAOM,EAAOX,CAAG,GAAG,MAAM,CAC5B,CAAC,EAED,IAAMY,EAAO,CAAC1H,EAAK,SAAU,WAAeA,EAAK,SAAU,QAAW,EAAE,IAAK0G,GAAO,OAAOA,GAAM,SAAWA,EAAI,EAAG,EAC7GJ,EAAQC,GAAehF,EAAU0D,EAAO,IAAM,CAClD5D,EAAK,SAASR,EAAM,IAAI,EACxBsG,EAAO,CAAC,GAAG,MAAM,CACnB,CAAC,EACK7E,EAAQoF,EAAK,KAAK,OAAO,EAC3BnH,GAAKgB,EAAU,MAAO,CAAE,MAAO,cAAe,EAAG4D,EAAO5E,GAAKgB,EAAU,MAAO,CAAE,MAAO,gBAAiB,cAAe,MAAO,EAAGhB,GAAKgB,EAAU,OAAQ,CAAC,EAAGmG,EAAK,CAAC,CAAC,EAAGnH,GAAKgB,EAAU,OAAQ,CAAC,EAAGmG,EAAK,CAAC,CAAC,CAAC,CAAC,EAC1MvC,EACJ,OAAIuC,EAAK,KAAK,OAAO,GAAGvC,EAAM,aAAa,mBAAoBuC,EAAK,OAAO,OAAO,EAAE,KAAK,UAAK,CAAC,EACxF,CACL,QAASnH,GAAKgB,EAAU,MAAO,CAAE,MAAO,gBAAiB,EAAGe,EAAOgE,EAAM,MAAM,EAC/E,MAAO,KAAOa,EAAO,KAAMQ,GAAMA,EAAE,aAAa,cAAc,IAAM,MAAM,GAAKR,EAAO,CAAC,IAAI,MAAM,EACjG,OAAOnG,EAAO,CACZ,IAAMF,EAAQ,OAAOE,EAAM,OAAU,SAAWA,EAAM,MAAQ,KAC9DmG,EAAO,QAAQ,CAACC,EAAOxC,IAAM,CAC3B,IAAM1B,EAAI4D,EAAMlC,EAChB3D,GAAQmG,EAAO,eAAgB,OAAOlE,IAAMpC,CAAK,CAAC,EAClDsG,EAAM,UAAU,OAAO,QAASH,EAAUnG,IAAU,MAAQoC,GAAKpC,EAAQoC,IAAMpC,CAAK,EACpF,IAAM8G,EAAM1E,IAAMpC,GAAUA,IAAU,MAAQ8D,IAAM,EAAK,EAAI,GACzDwC,EAAM,WAAaQ,IAAKR,EAAM,SAAWQ,GACzCR,EAAM,WAAapG,EAAM,WAAUoG,EAAM,SAAWpG,EAAM,SAChE,CAAC,EACDsF,EAAM,MAAMtF,CAAK,EACjBsF,EAAM,KAAKxF,IAAU,IAAI,EACzBC,GAASoE,EAAOnE,CAAK,CACvB,CACF,CACF,CACF,CAEA,IAAM6G,GAA6BhI,GAAY,CAC7C,GAAM,CAAE,KAAAwB,EAAM,KAAAR,EAAM,MAAAd,EAAO,GAAAuB,EAAI,SAAAC,EAAU,KAAAvB,CAAK,EAAIH,EAC5C2B,EAAQjB,GAAKgB,EAAU,QAAS,CAAE,GAAAD,EAAI,KAAM,OAAQ,MAAO,kBAAmB,CAAC,EACrFG,GAAOD,EAAOzB,EAAOC,CAAI,EACzBwB,EAAM,iBAAiB,QAAS,IAAMH,EAAK,SAASR,EAAMW,EAAM,OAAS,IAAI,CAAC,EAC9E,IAAMsG,EAAiB,CACrB,QAAStG,EACT,MAAO,IAAMA,EAAM,MAAM,EACzB,OAAOR,EAAO,CACZ,IAAMW,EAAOT,GAAOF,EAAM,KAAK,EAC3BQ,EAAM,QAAUG,IAAMH,EAAM,MAAQG,GACpCH,EAAM,WAAaR,EAAM,WAAUQ,EAAM,SAAWR,EAAM,UAC9DD,GAASS,EAAOR,CAAK,CACvB,CACF,EACA,OAAOhB,EAAK,SAAU,cAAmB,GAAO+H,GAAaD,EAAQjI,EAAS,MAAM,EAAIiI,CAC1F,EAEME,GAAO9E,GAAc,OAAOA,CAAC,EAAE,SAAS,EAAG,GAAG,EAG9C+E,GAAiCpI,GAAY,CACjD,GAAM,CAAE,KAAAwB,EAAM,KAAAR,EAAM,MAAAd,EAAO,GAAAuB,EAAI,SAAAC,EAAU,KAAAvB,CAAK,EAAIH,EAC5C2B,EAAQjB,GAAKgB,EAAU,QAAS,CAAE,GAAAD,EAAI,KAAM,iBAAkB,MAAO,sBAAuB,CAAC,EACnGG,GAAOD,EAAOzB,EAAOC,CAAI,EACzB,IAAMkI,EAASC,GAA2B,CACxC,GAAI,OAAOA,GAAQ,UAAY,CAACA,EAAK,MAAO,GAC5C,IAAMC,EAAI,IAAI,KAAKD,CAAG,EACtB,OAAO,OAAO,MAAMC,EAAE,QAAQ,CAAC,EAAI,GAAK,GAAGA,EAAE,YAAY,CAAC,IAAIJ,GAAII,EAAE,SAAS,EAAI,CAAC,CAAC,IAAIJ,GAAII,EAAE,QAAQ,CAAC,CAAC,IAAIJ,GAAII,EAAE,SAAS,CAAC,CAAC,IAAIJ,GAAII,EAAE,WAAW,CAAC,CAAC,EACrJ,EACA5G,EAAM,iBAAiB,QAAS,IAAM,CACpC,GAAI,CAACA,EAAM,MAAO,OAAOH,EAAK,SAASR,EAAM,IAAI,EACjD,IAAMuH,EAAI,IAAI,KAAK5G,EAAM,KAAK,EACzB,OAAO,MAAM4G,EAAE,QAAQ,CAAC,GAAG/G,EAAK,SAASR,EAAMuH,EAAE,YAAY,CAAC,CACrE,CAAC,EACD,IAAMN,EAAiB,CACrB,QAAStG,EACT,MAAO,IAAMA,EAAM,MAAM,EACzB,OAAOR,EAAO,CACZ,IAAMW,EAAOuG,EAAMlH,EAAM,KAAK,EAC1BQ,EAAM,QAAUG,IAAMH,EAAM,MAAQG,GACpCH,EAAM,WAAaR,EAAM,WAAUQ,EAAM,SAAWR,EAAM,UAC9DD,GAASS,EAAOR,CAAK,CACvB,CACF,EACA,OAAOhB,EAAK,SAAU,cAAmB,GAAO+H,GAAaD,EAAQjI,EAAS,UAAU,EAAIiI,CAC9F,EAGA,SAASxH,GAAc,CAAE,MAAAP,EAAO,GAAAuB,EAAI,SAAAC,CAAS,EAA0B,CACrE,IAAM8G,EAAO9H,GAAKgB,EAAU,OAAQ,CAAE,GAAAD,EAAI,MAAO,aAAc,kBAAmBvB,EAAM,IAAK,CAAC,EAC9F,MAAO,CACL,QAASsI,EACT,MAAO,IAAG,GACV,OAAOrH,EAAO,CACZqH,EAAK,YAAcC,GAAQtH,EAAM,MAAOjB,CAAK,CAC/C,CACF,CACF,CAEO,SAASuI,GAAQxH,EAA0Bf,EAAsB,CACtE,GAAIe,GAAU,KAA6B,MAAO,GAClD,OAAQf,EAAM,KAAM,CAClB,IAAK,WACL,IAAK,YACH,OAAQe,EAAyC,MACnD,IAAK,YACH,OAAQA,EAA0B,IAAKyH,GAAWA,EAAO,KAAK,EAAE,KAAK,IAAI,EAC3E,IAAK,WAAY,CACf,IAAMC,EAAS1H,EAAiB,OAChC,MAAO,GAAG0H,CAAK,IAAIA,IAAU,EAAI,OAAS,OAAO,EACnD,CACA,IAAK,SACL,IAAK,QACH,MAAO,CAAC1H,CAAgC,EAAE,KAAK,EAAE,IAAK2H,GAASA,EAAK,IAAI,EAAE,KAAK,IAAI,EACrF,IAAK,OACH,OAAO,OAAO3H,CAAK,EAAE,QAAQ,WAAY,GAAG,EAAE,QAAQ,OAAQ,GAAG,EAAE,KAAK,EAC1E,QACE,OAAO,OAAOA,GAAU,SAAW,KAAK,UAAUA,CAAK,EAAI,OAAOA,CAAK,CAC3E,CACF,CAEO,IAAMV,GAAgD,CAC3D,KAAMe,GAAW,MAAM,EACvB,aAAcA,GAAW,OAAO,EAChC,aAAcA,GAAW,KAAK,EAC9B,WAAYA,GAAW,KAAK,EAC5B,gBAAiBA,GAAW,UAAU,EACtC,YAAaA,GAAW,MAAM,EAC9B,YAAauH,GACb,KAAM9G,GACN,QAASM,GACT,MAAOA,GACP,SAAUA,GACV,iBAAkB0E,GAAa,QAAQ,EACvC,gBAAiBA,GAAa,OAAO,EACrC,iBAAkB+B,GAClB,eAAgBA,GAChB,sBAAuBC,GACvB,gBAAiBC,GACjB,cAAeA,GACf,iBAAkBA,GAClB,oBAAqBD,GACrB,uBAAwBA,GACxB,QAAS3E,GAAe,EACxB,iBAAkBA,GAAe,QAAQ,EACzC,eAAgBA,GAAe,MAAM,EACrC,kBAAmB6E,GACnB,UAAWzE,GACX,kBAAmBS,GAAY,OAAO,EACtC,uBAAwBA,GAAY,UAAU,EAC9C,iBAAkBiE,GAClB,yBAA0BC,GAC1B,oBAAqBC,GACrB,sBAAuBC,GACvB,KAAMrB,GACN,SAAUI,GACV,SAAUkB,GACV,qBAAsBD,GACtB,UAAWE,GACX,iBAAkBA,GAClB,uBAAwBC,GACxB,UAAWC,GACX,SAAUC,GACV,iBAAkBC,GAClB,OAAQC,GACR,mBAAoBC,GACpB,MAAOC,GACP,KAAMC,GACN,KAAMC,GACN,eAAgBC,GAChB,WAAYC,GACZ,OAAQC,EACV,EC7lBO,IAAMC,GAAsB,i6NCA5B,IAAMC,GAAwB,g/DCE9B,IAAMC,GAAuB,g6CCE7B,IAAMC,GAAuB,o8MCUpC,IAAMC,GAAsB,6tuCAGfC,GAAcD,GAAYE,GAAaC,GAAaC,GAAYC,GAEvEC,GAAW,iBAGV,SAASC,GAAcC,EAA0B,CACtD,GAAIA,EAAS,eAAeF,EAAQ,EAAG,OACvC,IAAMG,EAAQD,EAAS,cAAc,OAAO,EAC5CC,EAAM,GAAKH,GACXG,EAAM,YAAcR,IACnBO,EAAS,MAAQA,EAAS,iBAAiB,OAAOC,CAAK,CAC1D,CCrBO,SAASC,GAAmBC,EAAoC,CACrE,IAAMC,EAAO,IAAM,CACjB,GAAI,CACF,OAAOD,GAAW,WAAW,cAAgB,IAC/C,MAAQ,CACN,OAAO,IACT,CACF,EACA,MAAO,CACL,IAAIE,EAAK,CACP,GAAI,CACF,IAAMC,EAAOF,EAAK,GAAG,QAAQ,WAAWC,CAAG,EAAE,EAC7C,OAAOC,GAAQ,KAAO,KAAQ,KAAK,MAAMA,CAAI,CAC/C,MAAQ,CACN,OAAO,IACT,CACF,EACA,IAAID,EAAKE,EAAO,CACd,GAAI,CACFH,EAAK,GAAG,QAAQ,WAAWC,CAAG,GAAI,KAAK,UAAUE,CAAK,CAAC,CACzD,MAAQ,CAER,CACF,CACF,CACF,CAGO,SAASC,IAAqC,CACnD,IAAMC,EAAS,IAAI,IACnB,MAAO,CACL,IAAMJ,GAASI,EAAO,IAAIJ,CAAG,EAAIK,GAAoBD,EAAO,IAAIJ,CAAG,CAAc,EAAI,KACrF,IAAK,CAACA,EAAKE,IAAO,CAAQE,EAAO,IAAIJ,EAAKK,GAAoBH,CAAK,CAAC,EACtE,CACF,CAEA,IAAMG,GAAuBH,GAAgC,KAAK,MAAM,KAAK,UAAUA,CAAK,CAAC,ECjDtF,IAAMI,GAAY,CAAC,EC0F1B,IAAMC,GAAmB,CACvB,KAAM,OACN,KAAM,OACN,KAAM,OACN,QAAS,UACT,OAAQ,eACR,MAAO,QACP,OAAQ,SACR,KAAM,OACN,KAAM,OACN,KAAM,OACN,MAAO,QACP,OAAQ,sBACR,UAAW,qCACX,cAAe,0BACf,WAAY,wCACZ,QAAS,UACT,aAAc,UACd,GAAI,KACJ,OAAQ,SACR,QAAS,gBACT,UAAW,eACX,MAAO,QACP,QAAS,UACT,MAAO,QACP,SAAU,YACV,QAAS,WACT,YAAa,0BACb,QAAS,2DACT,aAAc,gBACd,SAAU,YACV,MAAO,6BACP,SAAU,eACV,eAAgB,QAChB,UAAW,aACX,aAAc,gBACd,UAAW,oBACX,WAAY,8BACZ,OAAQ,eACR,YAAa,SACb,UAAW,6BACX,cAAe,iBACf,QAAS,UACT,QAAS,WACT,WAAY,aACZ,GAAI,KACJ,YAAa,iBACb,gBAAiB,sBACjB,MAAO,QACP,UAAW,YACX,MAAO,QACP,MAAO,QACP,WAAY,sBACZ,WAAY,qBACZ,aAAc,iBACd,gBAAiB,gBACjB,aAAc,yBACd,KAAM,KACN,QAAS,SACT,WAAY,WACZ,UAAW,eACX,OAAQ,YACR,MAAO,SACP,SAAU,aACV,IAAK,MACL,GAAI,KACJ,KAAM,OACN,SAAU,eACZ,EAQaC,GAA8C,CAAE,GAAAD,GAAI,GAAGE,EAAU,EAGjEC,GAA+BF,GAAc,GAGpDG,GAAU,IAAI,IAAI,CACtB,CAAC,KAAM,QAAQ,EACf,CAAC,KAAM,QAAQ,EACf,CAAC,KAAM,QAAQ,CACjB,CAAC,EACKC,GAAU,IAAI,IAQb,SAASC,GAAUC,EAAM,KAAc,CAC5C,IAAMC,EAAOD,EAAI,MAAM,GAAG,EAAE,CAAC,EAC7B,GAAI,OAAO,UAAU,eAAe,KAAKN,GAAeO,CAAI,EAAG,OAAOA,EACtE,IAAMC,EAAOL,GAAQ,IAAII,CAAI,EAC7B,OAAIC,GAAQ,CAACJ,GAAQ,IAAIG,CAAI,IAC3BH,GAAQ,IAAIG,CAAI,EAChB,QAAQ,KACN,4BAA4BC,CAAI,yFAClBA,CAAI,oGAAoGD,CAAI,iBAC5H,GAEK,IACT,CC1LA,IAAME,GAAM,UAENC,GAAe,UAEfC,GAAe,UAIrB,IAAMC,GAAYC,GAAgB,CAAC,EAAG,EAAG,CAAC,EAAE,IAAKC,GAAO,SAASD,EAAI,MAAMC,EAAIA,EAAK,CAAC,EAAG,EAAE,CAAC,EACrFC,GAASC,GAAkB,IAAIA,EAAI,IAAKC,GAAM,KAAK,MAAMA,CAAC,EAAE,SAAS,EAAE,EAAE,SAAS,EAAG,GAAG,CAAC,EAAE,KAAK,EAAE,CAAC,GAGzG,SAASC,GAAUL,EAAqB,CACtC,GAAM,CAACM,EAAGC,EAAGC,CAAC,EAAIT,GAASC,CAAG,EAAE,IAAKI,GAAM,CACzC,IAAMK,EAAIL,EAAI,IACd,OAAOK,GAAK,OAAUA,EAAI,QAAUA,EAAI,MAAS,QAAU,GAC7D,CAAC,EACD,MAAO,OAASH,EAAI,MAASC,EAAI,MAASC,CAC5C,CAGO,SAASE,GAASC,EAAWH,EAAmB,CACrD,GAAM,CAACI,EAAOC,CAAI,EAAI,CAACR,GAAUM,CAAC,EAAGN,GAAUG,CAAC,CAAC,EAAE,KAAK,CAACM,EAAGC,IAAMA,EAAID,CAAC,EACvE,OAAQF,EAAQ,MAASC,EAAO,IAClC,CAGA,IAAMG,GAAUhB,GAAiBU,GAASV,EAAK,SAAS,GAAK,IAAW,UAAYiB,GAE9EC,GAAclB,GAAiBU,GAASV,EAAKiB,EAAG,GAAKP,GAASV,EAAK,SAAS,EAAIiB,GAAM,UAGtFE,GAAU,CAACnB,EAAaoB,IAAmBlB,GAAMH,GAASC,CAAG,EAAE,IAAKI,GAAMA,GAAK,IAAMA,GAAKgB,CAAM,CAAC,EAEjGC,GAAS,CAACrB,EAAaoB,IAAmBlB,GAAMH,GAASC,CAAG,EAAE,IAAKI,GAAMA,GAAK,EAAIgB,EAAO,CAAC,EAE1FE,GAAS,CAACtB,EAAauB,IAAoBrB,GAAMH,GAASC,CAAG,EAAE,IAAI,CAACI,EAAGoB,IAAMpB,EAAI,IAAOL,GAASwB,CAAO,EAAEC,CAAC,EAAI,GAAI,CAAC,EAEpHC,GAAU,CAACzB,EAAa0B,IAAsB,CAAC,GAAGA,EAASJ,GAAOtB,EAAK0B,EAAQ,CAAC,CAAC,CAAC,EAAE,MAAOC,GAAWjB,GAASV,EAAK2B,CAAM,GAAK,GAAQ,EAkBtI,SAASC,GAAa5B,EAA2B,CACtD,IAAM6B,EAAQ7B,EAAI,YAAY,EAC1B8B,EAASD,EACb,QAASE,EAAO,EAAGA,GAAQ,IAAM,CAACN,GAAQK,EAAQ,CAAC,UAAWE,EAAY,CAAC,EAAGD,IAAQD,EAAST,GAAOQ,EAAOE,EAAO,EAAE,EACtH,IAAIlB,EAAOgB,EACX,QAASE,EAAO,EAAGA,GAAQ,IAAM,CAACN,GAAQZ,EAAM,CAACoB,EAAY,CAAC,EAAGF,IAAQlB,EAAOM,GAAQU,EAAOE,EAAO,EAAE,EACxG,MAAO,CAAE,OAAAD,EAAQ,WAAYd,GAAOc,CAAM,EAAG,KAAAjB,EAAM,SAAUK,GAAWL,CAAI,CAAE,CAChF,CAGO,SAASqB,GAAUC,EAAmBC,EAAkC,CAC7E,GAAKA,EACL,SAAWC,IAAQ,CAAC,OAAQ,UAAW,UAAW,QAAQ,EAAY,CACpE,IAAMC,EAAQF,EAAKC,CAAI,EACnBC,GAAOH,EAAK,aAAa,QAAQE,CAAI,GAAIC,CAAK,CACpD,CAEA,GADIF,EAAK,YAAYD,EAAK,MAAM,YAAY,mBAAoB,GAAGC,EAAK,UAAU,IAAI,EAClFA,EAAK,OAAQ,CACf,IAAMG,EAASX,GAAaQ,EAAK,MAAM,EACvCD,EAAK,aAAa,cAAe,EAAE,EACnCA,EAAK,MAAM,YAAY,mBAAoBI,EAAO,MAAM,EACxDJ,EAAK,MAAM,YAAY,wBAAyBI,EAAO,UAAU,EACjEJ,EAAK,MAAM,YAAY,wBAAyBI,EAAO,IAAI,EAC3DJ,EAAK,MAAM,YAAY,6BAA8BI,EAAO,QAAQ,CACtE,EACF,CCnDA,IAAIC,GAAU,EAEP,SAASC,GAAeC,EAAuD,CACpF,IAAMC,EAAMD,EAAQ,WAAW,eAAiB,SAC1CE,EAAYF,EAAQ,WAAaC,EAAI,KACrCE,EAASF,EAAI,yBAAyBA,EAAI,YAAa,YAAeA,EAAI,cAAgC,KAC1GG,EAAS,CAAE,GAAGC,GAAcC,GAAUN,EAAQ,MAAM,CAAC,EAAG,GAAGA,EAAQ,MAAO,EAC1EO,EAAK,aAAa,EAAET,EAAO,GAC3BU,EAAO,CAAwCC,EAAQC,EAAgC,CAAC,EAAGC,IAAkB,CACjH,IAAMC,EAAUX,EAAI,cAAcQ,CAAG,EACrC,OAAW,CAACI,EAAMC,CAAK,IAAK,OAAO,QAAQJ,CAAK,EAAGE,EAAQ,aAAaC,EAAMC,CAAK,EACnF,OAAIH,IAAS,SAAWC,EAAQ,YAAcD,GACvCC,CACT,EAEMG,EAAQP,EAAK,KAAM,CAAE,GAAI,GAAGD,CAAE,SAAU,MAAO,sBAAuB,EAAGP,EAAQ,KAAK,EACtFgB,EAAcR,EAAK,SAAU,CAAE,KAAM,SAAU,MAAO,kBAAmB,aAAcJ,EAAO,KAAM,EAAG,MAAG,EAC1Ga,EAAOT,EAAK,MAAO,CAAE,MAAO,qBAAsB,CAAC,EACnDU,EAAUV,EAAK,SAAU,CAAE,KAAM,SAAU,MAAO,WAAY,EAAGJ,EAAO,OAAO,EAC/Ee,EAAYX,EAAK,SAAU,CAAE,KAAM,SAAU,MAAO,6BAA8B,EAAGJ,EAAO,SAAS,EACrGgB,EAAMZ,EAAK,MAAO,CAEtB,MAAO,mCAAmCR,EAAQ,MAAQ,QAAQ,GAClE,eAAgBA,EAAQ,MAAQ,YAChC,KAAM,SACN,aAAc,OACd,kBAAmBe,EAAM,GACzB,SAAU,IACZ,CAAC,EACGf,EAAQ,KAAKoB,EAAI,aAAa,MAAOpB,EAAQ,GAAG,EAEpD,IAAMqB,EAAOrB,EAAQ,KAAK,MAAQA,EAAQ,KAC1CsB,GAAUF,EAAKC,CAAI,EACnBD,EAAI,OAAOZ,EAAK,MAAO,CAAE,MAAO,qBAAsB,CAAC,EAAGS,EAAMT,EAAK,MAAO,CAAE,MAAO,+CAAgD,CAAC,CAAC,EACvIY,EAAI,mBAAmB,OAAOL,EAAOC,CAAW,EAChDI,EAAI,kBAAkB,OAAOF,EAASC,CAAS,EAC/C,IAAMI,EAAWf,EAAK,MAAO,CAAE,MAAO,4CAA6C,CAAC,EACpFe,EAAS,OAAOH,CAAG,EACnBlB,EAAU,OAAOqB,CAAQ,EAEzB,IAAMC,EAASC,GAAYR,EAAM,CAAE,GAAGjB,EAAS,KAAMqB,GAAQ,CAACrB,EAAQ,KAAK,KAAO,CAAE,GAAGA,EAAQ,KAAM,KAAAqB,CAAK,EAAIrB,EAAQ,KAAM,YAAa,EAAM,CAAC,EAC5I0B,EAAO,GACP1B,EAAQ,WAAW2B,GAAYH,EAAO,KAAMxB,EAAQ,KAAK,OAAQA,EAAQ,UAAW,IAAM0B,CAAI,EAGlG,IAAME,EAAa,IAAMX,EAAK,cAA2B,wEAAwE,EACjI,OAACW,EAAW,GAAKR,GAAK,MAAM,EACvBI,EAAO,KAAK,QAAQ,EAAE,KAAK,IAAM,EAChCvB,EAAI,gBAAkBmB,GAAO,CAACA,EAAI,SAASnB,EAAI,aAAa,IAAG2B,EAAW,GAAG,MAAM,CACzF,CAAC,EAEM,IAAI,QAASC,GAAY,CAC9B,IAAMC,EAASC,GAAmB,CAChC,GAAIL,EAAM,OACVA,EAAO,GACP,IAAMM,EAAQR,EAAO,KAAK,SAAS,EAE7BS,EAA2B,CAAE,MAAAF,EAAO,SAAUC,EAAM,UAAY,KAAM,OAAQA,EAAM,MAAiB,EAC3GR,EAAO,QAAQ,EACfD,EAAS,OAAO,EAChBpB,GAAQ,MAAM,EACd0B,EAAQI,CAAM,CAChB,EACAd,EAAU,iBAAiB,QAAS,SAAY,CAC9CA,EAAU,SAAW,GACrB,IAAMe,EAAWlC,EAAQ,OAAS,SAAWwB,EAAO,MAAM,EAAI,MAAMA,EAAO,KAAK,EAChFL,EAAU,SAAW,GACjBe,GAAUJ,EAAM,EAAI,CAC1B,CAAC,EACDZ,EAAQ,iBAAiB,QAAS,IAAMY,EAAM,EAAK,CAAC,EACpDd,EAAY,iBAAiB,QAAS,IAAMc,EAAM,EAAK,CAAC,EACxDV,EAAI,iBAAiB,UAAYe,GAAU,CAGzC,GAAIA,EAAM,MAAQ,UAAYA,EAAM,SAAWA,EAAM,UAAY,CAACA,EAAM,YAAa,CACnF,GAAKA,EAAM,OAAmB,QAAQ,kBAAkB,EAAG,OAC3DA,EAAM,eAAe,EACrBlC,EAAI,eAAe,cAAc,IAAI,MAAM,SAAU,CAAE,QAAS,EAAK,CAAC,CAAC,EACvEkB,EAAU,MAAM,EAChB,MACF,CAEIgB,EAAM,mBACNA,EAAM,MAAQ,UAChBA,EAAM,eAAe,EACrBL,EAAM,EAAK,GACNM,GAAUhB,EAAKe,CAAK,EAC7B,CAAC,CACH,CAAC,CACH,CAGA,SAASR,GAAYU,EAA4BC,EAAiCC,EAAgDC,EAAuB,CACvJ,IAAIC,EAAO,KAAK,UAAUJ,EAAK,SAAS,EAAE,MAAM,EAC5CK,EAAU,GACdL,EAAK,UAAU,IAAM,CACnB,IAAMM,EAASN,EAAK,SAAS,EAAE,OACzBO,EAAM,KAAK,UAAUD,CAAM,EAC7BD,GAAWE,IAAQH,IACvBA,EAAOG,EACPL,EAAUI,CAAM,EAAE,KACfE,GAAS,CACR,GAAI,EAAAL,EAAO,GAAK,KAAK,UAAUH,EAAK,SAAS,EAAE,MAAM,IAAMO,GAC3D,CAAAF,EAAU,GACV,OAAW,CAAC7B,EAAMC,CAAK,IAAK,OAAO,QAAQ+B,CAAI,EACzChC,KAAQyB,GAAU,KAAK,UAAUK,EAAO9B,CAAI,GAAK,IAAI,IAAM,KAAK,UAAUC,GAAS,IAAI,GAAGuB,EAAK,SAASxB,EAAMC,CAAK,EAEzH4B,EAAU,GACVD,EAAO,KAAK,UAAUJ,EAAK,SAAS,EAAE,MAAM,EAC9C,EACA,IAAG,EACL,EACF,CAAC,CACH,CAqBO,SAASS,GAAiB9C,EAA6D,CAC5F,IAAMC,EAAMD,EAAQ,WAAW,eAAiB,SAC1CE,EAAYF,EAAQ,WAAaC,EAAI,KACrCE,EAASF,EAAI,yBAAyBA,EAAI,YAAa,YAAeA,EAAI,cAAgC,KAC1G8C,EAASzC,GAAUN,EAAQ,MAAM,EACjCI,EAASC,GAAc0C,CAAM,EAC7BC,EAAQC,GAAcF,CAAM,EAC5BxC,EAAK,aAAa,EAAET,EAAO,GAC3BU,EAAO,CAAwCC,EAAQC,EAAgC,CAAC,EAAGC,IAAkB,CACjH,IAAMC,EAAUX,EAAI,cAAcQ,CAAG,EACrC,OAAW,CAACI,EAAMC,CAAK,IAAK,OAAO,QAAQJ,CAAK,EAAGE,EAAQ,aAAaC,EAAMC,CAAK,EACnF,OAAIH,IAAS,SAAWC,EAAQ,YAAcD,GACvCC,CACT,EACMG,EAAQP,EAAK,KAAM,CAAE,GAAI,GAAGD,CAAE,SAAU,MAAO,sBAAuB,EAAGP,EAAQ,KAAK,EACtFgB,EAAcR,EAAK,SAAU,CAAE,KAAM,SAAU,MAAO,kBAAmB,aAAcJ,EAAO,KAAM,EAAG,MAAG,EAC1G8C,EAAQ1C,EAAK,QAAS,CAAE,KAAM,SAAU,MAAO,WAAY,aAAcwC,EAAM,OAAQ,YAAaA,EAAM,OAAQ,gBAAiB,GAAGzC,CAAE,QAAS,aAAc,KAAM,CAAC,EACtK4C,EAAO3C,EAAK,KAAM,CAAE,GAAI,GAAGD,CAAE,QAAS,MAAO,iBAAkB,KAAM,UAAW,kBAAmBQ,EAAM,EAAG,CAAC,EAC7GqC,EAAS5C,EAAK,SAAU,CAAE,KAAM,SAAU,MAAO,WAAY,EAAGJ,EAAO,MAAM,EAC7EgB,EAAMZ,EAAK,MAAO,CACtB,MAAO,yDACP,eAAgBR,EAAQ,MAAQ,YAChC,KAAM,SACN,aAAc,OACd,kBAAmBe,EAAM,EAC3B,CAAC,EACGf,EAAQ,KAAKoB,EAAI,aAAa,MAAOpB,EAAQ,GAAG,EACpDsB,GAAUF,EAAKpB,EAAQ,IAAI,EAC3B,IAAMqD,EAAO7C,EAAK,MAAO,CAAE,MAAO,qBAAsB,CAAC,EACzD6C,EAAK,OAAOtC,EAAOC,CAAW,EAC9B,IAAMC,EAAOT,EAAK,MAAO,CAAE,MAAO,oCAAqC,CAAC,EACxES,EAAK,OAAOiC,EAAOC,CAAI,EACvB,IAAMG,EAAO9C,EAAK,MAAO,CAAE,MAAO,+CAAgD,CAAC,EACnF8C,EAAK,OAAOF,CAAM,EAClBhC,EAAI,OAAOiC,EAAMpC,EAAMqC,CAAI,EAC3B,IAAM/B,EAAWf,EAAK,MAAO,CAAE,MAAO,4CAA6C,CAAC,EACpF,OAAAe,EAAS,OAAOH,CAAG,EACnBlB,EAAU,OAAOqB,CAAQ,EACzB2B,EAAM,MAAM,EAEL,IAAI,QAASrB,GAAY,CAC9B,IAAI0B,EAAyB,CAAC,EAC1BC,EAAS,GACTC,EAAQ,EACRC,EACE5B,EAAS6B,GAAiC,CAC9C,aAAaD,CAAK,EAClBD,IACAlC,EAAS,OAAO,EAChBpB,GAAQ,MAAM,EACd0B,EAAQ8B,CAAM,CAChB,EACMC,EAAO,IAAM,CACjBT,EAAK,gBACH,GAAGI,EAAM,IAAI,CAACM,EAAQC,IAAM,CAC1B,IAAMC,EAASvD,EAAK,KAAM,CAAE,GAAI,GAAGD,CAAE,WAAWuD,CAAC,GAAI,KAAM,SAAU,MAAO,YAAYA,IAAMN,EAAS,aAAe,EAAE,GAAI,gBAAiB,OAAOM,IAAMN,CAAM,CAAE,EAAGK,EAAO,KAAK,EACjL,OAAAE,EAAO,iBAAiB,QAAS,IAAMjC,EAAM+B,CAAM,CAAC,EAC7CE,CACT,CAAC,CACH,EACKR,EAAM,QAAQJ,EAAK,OAAO3C,EAAK,KAAM,CAAE,MAAO,UAAW,EAAGwC,EAAM,SAAS,CAAC,EAC7EQ,GAAU,EAAGN,EAAM,aAAa,wBAAyB,GAAG3C,CAAE,WAAWiD,CAAM,EAAE,EAChFN,EAAM,gBAAgB,uBAAuB,CACpD,EACM7B,EAAO,IAAM,CACjB,aAAaqC,CAAK,EAClB,IAAMM,EAAO,EAAEP,EACfC,EAAQ,WAAW,SAAY,CAC7B,IAAMO,EAAU,MAAMjE,EAAQ,OAAOkD,EAAM,MAAO,EAAE,EAAE,MAAM,IAAM,CAAC,CAAoB,EACnFc,IAASP,IACbF,EAAQU,EACRT,EAAS,GACTI,EAAK,EACP,EAAG,GAAG,CACR,EACAV,EAAM,iBAAiB,QAAS7B,CAAI,EACpC6B,EAAM,iBAAiB,UAAYf,GAAU,CAC3C,GAAIA,EAAM,MAAQ,aAAeA,EAAM,MAAQ,UAAW,CAExD,GADAA,EAAM,eAAe,EACjB,CAACoB,EAAM,OAAQ,OACnBC,GAAUA,GAAUrB,EAAM,MAAQ,YAAc,EAAI,IAAMoB,EAAM,QAAUA,EAAM,OAChFK,EAAK,EACLT,EAAK,SAASK,CAAM,GAAG,iBAAiB,CAAE,MAAO,SAAU,CAAC,CAC9D,MAAWrB,EAAM,MAAQ,SAAWqB,GAAU,IAC5CrB,EAAM,eAAe,EACrBL,EAAMyB,EAAMC,CAAM,CAAC,EAEvB,CAAC,EACDJ,EAAO,iBAAiB,QAAS,IAAMtB,EAAM,IAAI,CAAC,EAClDd,EAAY,iBAAiB,QAAS,IAAMc,EAAM,IAAI,CAAC,EACvDV,EAAI,iBAAiB,UAAYe,GAAU,CACrCA,EAAM,MAAQ,UAChBA,EAAM,eAAe,EACrBL,EAAM,IAAI,GACLM,GAAUhB,EAAKe,CAAK,CAC7B,CAAC,EACDd,EAAK,CACP,CAAC,CACH,CC3QO,SAAS6C,GAAYC,EAA2B,CACrD,OAAIA,EAAK,OAAO,OAAS,SAAWA,EAAK,OAAO,OAAO,MAAcA,EAAK,OAAO,MAAM,MACnFA,EAAK,OAAO,KAAgB,OACzB,OAAO,QAAQA,EAAK,MAAM,EAAE,KAAK,CAAC,CAAC,CAAEC,CAAG,IAAMA,EAAI,OAAS,MAAM,IAAI,CAAC,GAAK,IACpF,CAKA,SAASC,GAAWC,EAA+BC,EAAeC,EAAyB,CACzF,IAAMC,EAAQ,OAAO,YAAY,OAAO,QAAQH,CAAM,EAAE,IAAI,CAAC,CAACI,EAAMN,CAAG,IAAM,CAACM,EAAMF,EAAW,CAAE,GAAGJ,EAAK,SAAU,EAAK,EAAIA,CAAG,CAAC,CAAC,EACjI,MAAO,CACL,QAAS,MACT,GAAI,SACJ,MAAAG,EACA,KAAM,CAAE,KAAM,SAAU,MAAO,QAAS,EACxC,OAAQE,EACR,OAAQ,CACN,KAAM,WACN,GAAI,SACJ,SAAU,CAAC,CAAE,KAAM,UAAW,GAAI,iBAAkB,QAAS,EAAG,SAAU,OAAO,KAAKA,CAAK,EAAE,IAAKC,IAAU,CAAE,KAAM,QAAkB,GAAI,UAAUA,CAAI,GAAI,MAAOA,CAAK,EAAE,CAAE,CAAC,CAC/K,CACF,CACF,CAGA,SAASC,GAAUC,EAAwD,CACzE,GAAKA,EACL,MAAO,CACL,GAAIA,EAAO,OAAS,CAAE,OAASC,GAA2BD,EAAO,OAAQC,CAAO,CAAE,EAAI,CAAC,EACvF,GAAID,EAAO,OAAS,CAAE,OAASC,GAA2BD,EAAO,OAAQC,CAAO,CAAE,EAAI,CAAC,CACzF,CACF,CAGO,SAASC,GAAYC,EAAuC,CACjE,IAAMC,EAAWC,IACd,OAAOF,EAAQ,cAAiB,WAAaA,EAAQ,aAAaE,CAAK,EAAIF,EAAQ,eAAeE,CAAK,IAAM,KAE1GC,EAAS,CACb,OAAQH,EAAQ,OAChB,KAAMA,EAAQ,KACd,IAAKA,EAAQ,IACb,QAASA,EAAQ,QACjB,YAAaA,EAAQ,YACrB,aAAcA,EAAQ,aACtB,UAAWA,EAAQ,UACnB,KAAMA,EAAQ,KAAK,IACrB,EACA,MAAO,CACL,QAAUE,GAAUD,EAAQC,CAAK,IAAM,KACvC,MAAM,WAAWA,EAAOJ,EAAS,CAC/B,IAAMM,EAAUH,EAAQC,CAAK,EAC7B,GAAI,CAACE,EAAS,OAAO,KACrB,IAAMC,EAAYlB,GAAYiB,CAAO,EAC/BE,EAAS,MAAMC,GAAe,CAClC,GAAGJ,EACH,KAAMC,EACN,WAAYJ,EAAQ,WACpB,SAAUF,EAAQ,UAAY,KAC9B,OAAQA,EAAQ,MAAQO,EAAY,CAAE,CAACA,CAAS,EAAGP,EAAQ,IAAK,EAAI,OACpE,MAAOA,EAAQ,MACf,KAAM,OACR,CAAC,EACD,GAAI,CAACQ,EAAO,OAASA,EAAO,WAAa,KAAM,OAAO,KACtD,IAAMX,EAAOU,EAAYC,EAAO,OAAOD,CAAS,EAAI,KACpD,MAAO,CAAE,GAAIC,EAAO,SAAU,MAAO,OAAOX,GAAS,UAAYA,EAAOA,EAAOG,EAAQ,MAAQA,EAAQ,KAAM,CAC/G,EACA,WAAaA,GAAYU,GAAiB,CAAE,MAAOV,EAAQ,MAAO,OAAQA,EAAQ,OAAQ,OAAQE,EAAQ,OAAQ,KAAMA,EAAQ,KAAM,IAAKA,EAAQ,IAAK,KAAMA,EAAQ,KAAK,IAAK,CAAC,EACjL,MAAM,WAAWF,EAAS,CACxB,IAAMQ,EAAS,MAAMC,GAAe,CAClC,GAAGJ,EACH,KAAMb,GAAWQ,EAAQ,OAAQA,EAAQ,MAAOA,EAAQ,WAAa,EAAI,EACzE,WAAYF,GAAUI,EAAQ,UAAU,EACxC,OAAQF,EAAQ,OAChB,MAAOA,EAAQ,MACf,KAAM,SACN,GAAIA,EAAQ,UAAY,CAAE,UAAWA,EAAQ,SAAU,EAAI,CAAC,CAC9D,CAAC,EACD,OAAOQ,EAAO,MAAQA,EAAO,OAAS,IACxC,CACF,CACF,CC5EA,IAAMG,GAAOC,GAAe,cAAcA,EAAK,EAAE,GAE1C,SAASC,GAAeC,EAA8BF,EAAyB,CACpF,IAAMG,EAAOD,EAAY,IAAIH,GAAIC,CAAI,CAAC,EACtC,OAAO,MAAM,QAAQG,CAAI,EAAKA,EAAkC,CAAC,CACnE,CAGO,SAASC,GAAeC,EAAgBH,EAA8BF,EAAqB,CAChG,IAAMM,EAASL,GAAeC,EAAaF,CAAI,EAAE,KAAMO,GAAcA,EAAU,SAAS,EACxF,OAAID,EAAeA,EAAO,OACrBD,EAAK,gBAAgB,OACnB,CAAC,CAAE,KAAM,UAAW,IAAK,CAAC,GAAGA,EAAK,cAAc,EAAG,OAAQA,EAAK,eAAe,IAAKG,GAAOH,EAAK,SAAS,KAAMI,GAAMA,EAAE,KAAOD,CAAE,GAAG,OAASA,CAAE,CAAE,CAAC,EAD/G,CAAC,CAE5C,CAOO,SAASE,GAAeC,EAAmN,CAChP,GAAM,CAAE,KAAAX,EAAM,GAAAY,EAAI,OAAAC,EAAQ,KAAAC,EAAM,YAAAZ,CAAY,EAAIS,EAC1CI,EAAOH,EAAG,KAAM,CAAE,MAAO,mBAAoB,CAAC,EAC9CI,EAAOJ,EAAG,IAAK,CAAE,MAAO,oBAAqB,EAAGC,EAAO,YAAY,EACnEI,EAAOL,EAAG,QAAS,CAAE,MAAO,WAAY,aAAcC,EAAO,WAAY,YAAaA,EAAO,UAAW,CAAC,EACzGK,EAAYN,EAAG,QAAS,CAAE,KAAM,UAAW,CAAC,EAC5CO,EAAOP,EAAG,SAAU,CAAE,KAAM,SAAU,MAAO,6BAA8B,EAAGC,EAAO,IAAI,EACzFO,EAAOR,EAAG,MAAO,CAAE,MAAO,oBAAqB,OAAQ,EAAG,EAAGK,EAAML,EAAG,QAAS,CAAE,MAAO,sBAAuB,EAAGM,EAAWL,EAAO,YAAY,EAAGM,CAAI,EACvJE,EAAOT,EAAG,SAAU,CAAE,KAAM,SAAU,MAAO,iCAAkC,gBAAiB,OAAQ,EAAGC,EAAO,UAAU,EAE5HS,EAASC,GAA4BrB,EAAY,IAAIH,GAAIC,CAAI,EAAGuB,CAAkC,EAExG,SAASC,GAAO,CACd,IAAMD,EAAatB,GAAeC,EAAaF,CAAI,EACnDgB,EAAK,OAASO,EAAW,OAAS,EAClCR,EAAK,gBACH,GAAGQ,EAAW,IAAKhB,GAAc,CAC/B,IAAMkB,EAAMb,EAAG,SAAU,CAAE,KAAM,SAAU,MAAO,mBAAoB,eAAgBL,EAAU,UAAY,OAAS,MAAU,EAAGA,EAAU,IAAI,EAChJkB,EAAI,iBAAiB,QAAS,IAAMd,EAAQ,MAAMJ,EAAU,MAAM,CAAC,EACnE,IAAMmB,EAASd,EAAG,SAAU,CAAE,KAAM,SAAU,MAAO,sBAAuB,aAAcE,EAAKD,EAAO,gBAAiB,CAAE,KAAMN,EAAU,IAAK,CAAC,CAAE,EAAG,MAAG,EACvJ,OAAAmB,EAAO,iBAAiB,QAAS,IAAM,CACrCJ,EAAMrB,GAAeC,EAAaF,CAAI,EAAE,OAAQS,GAAMA,EAAE,OAASF,EAAU,IAAI,CAAC,EAChFiB,EAAK,CACP,CAAC,EACMZ,EAAG,KAAM,CAAE,MAAO,cAAe,EAAGa,EAAKC,CAAM,CACxD,CAAC,CACH,CACF,CAEA,OAAAL,EAAK,iBAAiB,QAAS,IAAM,CACnCD,EAAK,OAAS,CAACA,EAAK,OACpBC,EAAK,aAAa,gBAAiB,OAAO,CAACD,EAAK,MAAM,CAAC,EAClDA,EAAK,QAAQH,EAAK,MAAM,CAC/B,CAAC,EACDE,EAAK,iBAAiB,QAAS,IAAM,CACnC,IAAMQ,EAAQV,EAAK,MAAM,KAAK,EAC9B,GAAI,CAACU,EAAO,OAAOV,EAAK,MAAM,EAC9B,IAAMd,EAAkB,CAAE,KAAMwB,EAAO,OAAQhB,EAAQ,QAAQ,EAAG,GAAIO,EAAU,QAAU,CAAE,UAAW,EAAK,EAAI,CAAC,CAAG,EAE9GU,EAAS3B,GAAeC,EAAaF,CAAI,EAC5C,OAAQS,GAAMA,EAAE,OAASkB,CAAK,EAC9B,IAAKlB,GAAOS,EAAU,QAAU,CAAE,KAAMT,EAAE,KAAM,OAAQA,EAAE,MAAO,EAAIA,CAAE,EAC1Ea,EAAM,CAAC,GAAGM,EAAQzB,CAAI,CAAC,EACvBc,EAAK,MAAQ,GACbC,EAAU,QAAU,GACpBE,EAAK,OAAS,GACdC,EAAK,aAAa,gBAAiB,OAAO,EAC1CG,EAAK,CACP,CAAC,EAEDA,EAAK,EACE,CAAE,KAAAT,EAAM,KAAAC,EAAM,KAAAK,EAAM,KAAAD,CAAK,CAClC,CC5DA,SAASS,GAAUC,EAAuBC,EAAeC,EAAsB,CAC7E,IAAMC,EAAMH,EAAQ,KAAK,OAAOC,CAAK,EACrC,OAAIC,EAAM,QAAU,KAAaF,EAAQ,OAAO,KAC5CG,EAAI,OAAS,YAAoBA,EAAI,QAAQ,KAAMC,GAAMA,EAAE,QAAUF,EAAM,KAAK,GAAG,OAASA,EAAM,MAClGC,EAAI,OAAS,UAAkBD,EAAM,MAAQF,EAAQ,OAAO,IAAMA,EAAQ,OAAO,GAC9EE,EAAM,OAAS,OAAOA,EAAM,KAAK,CAC1C,CAGA,SAASG,GAAWC,EAAiB,CACnC,IAAMC,EAAQ,OAAOD,EAAG,QAAQ,KAAQ,EACpCE,EAAOF,EAAG,mBACd,KAAOE,GAAQ,OAAOA,EAAK,QAAQ,OAAY,CAAC,EAAID,GAAO,CACzD,IAAME,EAAQD,EAAK,mBACnBA,EAAK,OAAO,EACZA,EAAOC,CACT,CACF,CAOO,SAASC,GAASV,EAAuBE,EAAcK,EAAeI,EAA0BC,EAAyC,CAC9I,GAAM,CAAE,GAAAC,EAAI,OAAAC,CAAO,EAAId,EACjBC,EAAQW,EAASL,CAAK,EACtBQ,EAA2B,CAAC,GAAGJ,EAAQT,EAAM,QAAU,KAAO,CAAE,MAAAD,EAAO,GAAI,SAAU,MAAO,IAAK,EAAI,CAAE,MAAAA,EAAO,GAAI,IAAK,MAAOC,EAAM,KAAM,CAAC,EAC3Ic,EAASH,EACb,SACA,CAAE,KAAM,SAAU,MAAO,kBAAmB,gBAAiB,OAAQ,EACrEA,EAAG,OAAQ,CAAE,MAAO,gBAAiB,EAAGd,GAAUC,EAASC,EAAOC,CAAK,CAAC,EACxE,IACAW,EAAG,OAAQ,CAAE,MAAO,gBAAiB,EAAG,IAAIX,EAAM,KAAK,GAAG,CAC5D,EACMI,EAAKO,EAAG,KAAM,CAAE,MAAO,gBAAiB,aAAc,OAAON,CAAK,EAAG,aAAc,OAAOA,EAAQ,CAAC,CAAE,EAAGM,EAAG,KAAM,CAAE,QAAS,OAAOb,EAAQ,OAAO,CAAE,EAAGgB,CAAM,CAAC,EACpKV,EAAG,MAAM,YAAY,aAAc,OAAOC,CAAK,CAAC,EAChD,IAAIU,EAAU,GAEd,eAAeC,GAAO,CACpBD,EAAU,GACV,GAAI,CACF,IAAME,EACJZ,EAAQ,EAAIK,EAAS,QAChB,MAAMZ,EAAQ,WAAW,SAAS,CAAE,MAAOA,EAAQ,MAAO,MAAOY,EAASL,EAAQ,CAAC,EAAG,OAAAQ,CAAO,CAAC,IAAI,IAAKK,GAAUV,GAASV,EAASoB,EAAOb,EAAQ,EAAGQ,EAAQH,CAAQ,CAAC,GAAK,CAAC,EAC7K,MAAMS,EAAY,CAAC,EAEzB,GAAI,CAACf,EAAG,aAAeU,EAAO,aAAa,eAAe,IAAM,OAAQ,OACxEV,EAAG,MAAM,GAAGa,CAAI,EAChBnB,EAAQ,QAAQ,CAClB,QAAE,CACAiB,EAAU,EACZ,CACF,CAGA,eAAeI,EAAYC,EAAgD,CACzE,IAAMC,EAAS,MAAMvB,EAAQ,WAAW,KAAM,CAAE,MAAOA,EAAQ,MAAO,OAAQA,EAAQ,OAAQ,OAAAe,EAAQ,KAAMf,EAAQ,KAAK,EAAG,OAAAsB,EAAQ,MAAOtB,EAAQ,QAAS,CAAC,EACvJmB,EAAOI,EAAO,QAAQ,IAAKC,GAAWxB,EAAQ,UAAUwB,EAAQjB,EAAQ,CAAC,CAAC,EAC1EkB,EAAOF,EAAO,MAAQD,EAASC,EAAO,QAAQ,OACpD,GAAIE,GAAQ,EAAG,OAAON,EACtB,IAAMO,EAAOb,EAAG,SAAU,CAAE,KAAM,SAAU,MAAO,0BAA2B,EAAGb,EAAQ,KAAKc,EAAO,SAAU,CAAE,EAAGW,CAAK,CAAC,CAAC,EACrHE,EAAUd,EAAG,KAAM,CAAE,MAAO,eAAgB,aAAc,OAAON,EAAQ,CAAC,CAAE,EAAGM,EAAG,KAAM,CAAE,QAAS,OAAOb,EAAQ,OAAO,CAAE,EAAG0B,CAAI,CAAC,EACzI,OAAAC,EAAQ,MAAM,YAAY,aAAc,OAAOpB,CAAK,CAAC,EACrDmB,EAAK,iBAAiB,QAAS,SAAY,CACzCA,EAAK,SAAW,GAChB,IAAMlB,EAAO,MAAMa,EAAYC,EAASC,EAAO,QAAQ,MAAM,EACxDI,EAAQ,cACbA,EAAQ,YAAY,GAAGnB,CAAI,EAC3BR,EAAQ,QAAQ,EAClB,CAAC,EACM,CAAC,GAAGmB,EAAMQ,CAAO,CAC1B,CAEA,OAAAX,EAAO,iBAAiB,QAAS,IAAM,CACrC,IAAMY,EAASZ,EAAO,aAAa,eAAe,IAAM,OACxDA,EAAO,aAAa,gBAAiB,OAAO,CAACY,CAAM,CAAC,EAChDA,GACFvB,GAAWC,CAAE,EACbN,EAAQ,QAAQ,GACNiB,GAAcC,EAAK,CACjC,CAAC,EACMZ,CACT,CC1GO,IAAMuB,GAAc,2mRAGpB,SAASC,GAAkBC,EAAqB,CACrD,GAAIA,EAAI,eAAe,gBAAgB,EAAG,OAC1C,IAAMC,EAAQD,EAAI,cAAc,OAAO,EACvCC,EAAM,GAAK,iBACXA,EAAM,YAAcH,GACpBE,EAAI,KAAK,OAAOC,CAAK,CACvB,CCHA,IAAMC,GAA4B,CAAC,CAAC,QAAS,YAAY,EAAG,CAAC,IAAK,MAAM,EAAG,CAAC,KAAM,SAAS,EAAG,CAAC,MAAO,OAAO,EAAG,CAAC,SAAU,UAAU,CAAC,EAChIC,GAA4B,CAAC,CAAC,QAAS,YAAY,EAAG,CAAC,MAAO,OAAO,EAAG,CAAC,SAAU,UAAU,CAAC,EAC9FC,GAA8B,CAAC,CAAC,IAAK,MAAM,EAAG,CAAC,KAAM,SAAS,EAAG,CAAC,MAAO,OAAO,EAAG,CAAC,SAAU,UAAU,CAAC,EACzGC,GAA8B,CAAC,CAAC,IAAK,MAAM,EAAG,CAAC,KAAM,SAAS,EAAG,CAAC,IAAK,WAAW,EAAG,CAAC,IAAK,QAAQ,EAAG,CAAC,MAAO,OAAO,EAAG,CAAC,SAAU,UAAU,CAAC,EAC9IC,GAA4B,CAAC,CAAC,IAAK,MAAM,EAAG,CAAC,IAAK,WAAW,EAAG,CAAC,IAAK,QAAQ,EAAG,CAAC,MAAO,OAAO,EAAG,CAAC,SAAU,UAAU,CAAC,EAG/H,SAASC,GAAcC,EAAiC,CACtD,OAAQA,EAAI,KAAM,CAChB,IAAK,OACL,IAAK,OACL,IAAK,OACH,OAAON,GACT,IAAK,WACL,IAAK,YACH,OAAOC,GACT,IAAK,YACH,OAAOC,GACT,IAAK,UACL,IAAK,QACL,IAAK,WACH,OAAOC,GACT,IAAK,OACL,IAAK,WACH,OAAOC,GACT,IAAK,UACH,MAAO,CAAC,CAAC,IAAK,MAAM,CAAC,EACvB,QACE,MAAO,CAAC,CACZ,CACF,CAMO,SAASG,GAAiBC,EAAoF,CACnH,GAAM,CAAE,KAAAC,EAAM,GAAAC,EAAI,OAAAC,CAAO,EAAIH,EACvBI,EAAS,OAAO,QAAQH,EAAK,MAAM,EAAE,OAAO,CAAC,CAAC,CAAEH,CAAG,IAAMD,GAAcC,CAAG,EAAE,MAAM,EAClFO,EAAQH,EAAG,SAAU,CAAE,MAAO,WAAY,aAAcC,EAAO,KAAM,EAAG,GAAGC,EAAO,IAAI,CAAC,CAACE,EAAMR,CAAG,IAAMI,EAAG,SAAU,CAAE,MAAOI,CAAK,EAAGR,EAAI,KAAK,CAAC,CAAC,EAChJS,EAAYL,EAAG,SAAU,CAAE,MAAO,WAAY,aAAcC,EAAO,SAAU,CAAC,EAC9EK,EAAWN,EAAG,OAAQ,CAAE,MAAO,wBAAyB,CAAC,EACzDO,EAAQP,EAAG,SAAU,CAAE,KAAM,SAAU,MAAO,6BAA8B,EAAGC,EAAO,KAAK,EAC3FO,EAAOR,EAAG,MAAO,CAAE,MAAO,mBAAoB,OAAQ,EAAG,EAAGG,EAAOE,EAAWC,EAAUC,CAAK,EAC7FE,EAAST,EAAG,SAAU,CAAE,KAAM,SAAU,MAAO,iCAAkC,gBAAiB,OAAQ,EAAGC,EAAO,eAAe,EACrIS,EAA8CV,EAAG,QAAS,CAAE,MAAO,WAAY,aAAcC,EAAO,KAAM,CAAC,EAEzGL,EAAM,IAAMG,EAAK,OAAOI,EAAM,KAAK,EAEzC,SAASQ,GAAiB,CACxBN,EAAU,gBAAgB,GAAGV,GAAcC,EAAI,CAAC,EAAE,IAAI,CAAC,CAACgB,EAAIC,CAAI,IAAMb,EAAG,SAAU,CAAE,MAAOY,CAAG,EAAGX,EAAOY,CAAI,CAAC,CAAC,CAAC,EAChHC,EAAU,CACZ,CAGA,SAASA,GAAY,CACnB,IAAMC,EAAUnB,EAAI,EACpB,GAAImB,EAAQ,OAAS,YAAaL,EAAQV,EAAG,SAAU,CAAE,MAAO,WAAY,aAAcC,EAAO,KAAM,EAAG,GAAGc,EAAQ,QAAQ,IAAKC,GAAMhB,EAAG,SAAU,CAAE,MAAO,OAAOgB,EAAE,KAAK,CAAE,EAAGA,EAAE,KAAK,CAAC,CAAC,UACjLD,EAAQ,OAAS,UAAWL,EAAQV,EAAG,SAAU,CAAE,MAAO,WAAY,aAAcC,EAAO,KAAM,EAAGD,EAAG,SAAU,CAAE,MAAO,MAAO,EAAGC,EAAO,GAAG,EAAGD,EAAG,SAAU,CAAE,MAAO,OAAQ,EAAGC,EAAO,EAAE,CAAC,MAChM,CACH,IAAMgB,EAAO,CAAC,UAAW,QAAS,UAAU,EAAE,SAASF,EAAQ,IAAI,EAAI,SAAWA,EAAQ,OAAS,OAAS,OAASA,EAAQ,OAAS,WAAa,iBAAmB,OACtKL,EAAQV,EAAG,QAAS,CAAE,MAAO,WAAY,KAAAiB,EAAM,aAAchB,EAAO,KAAM,CAAC,CAC7E,CACAK,EAAS,gBAAgBI,CAAK,EAC9BJ,EAAS,OAASD,EAAU,QAAU,OAASA,EAAU,QAAU,QACrE,CAEA,OAAAF,EAAM,iBAAiB,SAAUQ,CAAc,EAC/CN,EAAU,iBAAiB,SAAU,IAAOC,EAAS,OAASD,EAAU,QAAU,OAASA,EAAU,QAAU,QAAS,EACxHI,EAAO,iBAAiB,QAAS,IAAM,CACrCD,EAAK,OAAS,CAACA,EAAK,OACpBC,EAAO,aAAa,gBAAiB,OAAO,CAACD,EAAK,MAAM,CAAC,EACpDA,EAAK,QAAQL,EAAM,MAAM,CAChC,CAAC,EAEDI,EAAM,iBAAiB,QAAS,IAAM,CACpC,IAAMQ,EAAUnB,EAAI,EACdgB,EAAKP,EAAU,MACfQ,EAAOZ,EAAON,GAAcoB,CAAO,EAAE,KAAK,CAAC,CAACC,CAAC,IAAMA,IAAMJ,CAAE,IAAI,CAAC,GAAK,MAAM,EAC7EM,EAAoB,KACpBC,EAAQ,GACZ,GAAI,CAACb,EAAS,OAAQ,CACpB,IAAMc,EAAOV,EAAM,MAAM,KAAK,EAC9B,GAAI,CAACU,EAAM,OAAOV,EAAM,MAAM,EAC9B,GAAIK,EAAQ,OAAS,YAAa,CAChC,IAAMM,EAASN,EAAQ,QAAQ,KAAMC,GAAM,OAAOA,EAAE,KAAK,IAAMI,CAAI,EACnEF,EAASG,GAAQ,OAASD,EAC1BD,EAAQE,GAAQ,OAASD,CAC3B,SAAWL,EAAQ,OAAS,UAC1BG,EAASE,IAAS,OAClBD,EAAQD,EAASjB,EAAO,IAAMA,EAAO,WAC5B,CAAC,UAAW,QAAS,UAAU,EAAE,SAASc,EAAQ,IAAI,EAAG,CAElE,GADAG,EAAS,OAAOE,CAAI,EAChB,CAAC,OAAO,SAASF,CAAM,EAAG,OAAOR,EAAM,MAAM,EACjDS,EAAQC,CACV,MACEF,EAASE,EACTD,EAAQC,CAEZ,CACAtB,EAAQ,IAAI,CAAE,KAAM,SAAU,MAAO,CAACiB,EAAQ,MAAOF,EAAMM,CAAK,EAAE,OAAO,OAAO,EAAE,KAAK,GAAG,EAAG,OAAQ,CAAC,CAAE,MAAOhB,EAAM,MAAO,GAAAS,EAAI,MAAOM,CAAO,CAAC,CAAE,CAAC,EAClJV,EAAK,OAAS,GACdC,EAAO,aAAa,gBAAiB,OAAO,CAC9C,CAAC,EAEDE,EAAe,EACR,CAAE,OAAAF,EAAQ,KAAAD,CAAK,CACxB,CCzFO,SAASc,GAAUC,EAAcC,EAA0C,CAChF,IAAMC,EAAK,IAAID,EAAO,EAAE,IACxB,OAAQD,EAAM,KAAM,CAClB,IAAK,QACH,MAAO,GAAGA,EAAM,KAAK,KAAKA,EAAM,OAAO,IAAKG,GAAMA,EAAE,KAAK,EAAE,KAAKD,CAAE,CAAC,GACrE,IAAK,UACH,OAAOF,EAAM,OAAO,KAAKE,CAAE,EAC7B,IAAK,UACH,OAAOF,EAAM,OAAO,KAAK,KAAK,EAChC,IAAK,SACH,OAAOA,EAAM,KACjB,CACF,CAQO,SAASI,GAAUC,EAAwB,CAChD,GAAM,CAAE,KAAAC,EAAM,KAAAC,EAAM,IAAAC,EAAK,GAAAC,EAAI,OAAAR,EAAQ,KAAAS,EAAM,IAAAC,CAAI,EAAIN,EAC/CO,EAASP,EAAQ,OACfQ,EAAQC,GAAiB,CAC7B,IAAMC,EAAQC,GAASR,EAAKM,EAAMT,EAAQ,KAAK,EAC/C,OAAAU,GAAO,aAAa,cAAe,MAAM,EAClCA,EAAQ,CAACA,CAAK,EAAI,CAAC,CAC5B,EAEA,SAASE,EAAOC,EAAe,CAC7BN,EAASM,EACTC,EAAU,EACVC,EAAU,EACVf,EAAQ,SAASO,CAAM,CACzB,CAIA,IAAMS,EAASV,EAAI,GAAGJ,EAAK,EAAE,cAAc,EACrCe,EAAUX,EAAI,GAAGJ,EAAK,EAAE,eAAe,EACvCgB,EAAQd,EAAG,QAAS,CACxB,MAAO,kBACP,KAAM,WACN,aAAc,MACd,YAAaR,EAAO,OACpB,aAAcA,EAAO,YACrB,oBAAqB,OACrB,gBAAiB,QACjB,gBAAiBoB,CACnB,CAAC,EACKG,EAAQf,EAAG,MAAO,CAAE,MAAO,WAAY,CAAC,EACxCgB,EAAchB,EAAG,KAAM,CAAE,MAAO,wBAAyB,KAAM,UAAW,GAAIY,EAAQ,aAAcpB,EAAO,YAAa,OAAQ,EAAG,CAAC,EACpIyB,EAASjB,EAAG,SAAU,CAAE,KAAM,SAAU,MAAO,mBAAoB,aAAcR,EAAO,cAAe,gBAAiB,QAAS,gBAAiBqB,CAAQ,CAAC,EAC7JK,EAAwB,CAAC,EACzBC,EAAS,EAEb,SAAST,GAAY,CACnBK,EAAM,gBACJ,GAAGZ,EAAO,IAAI,CAACZ,EAAO6B,IAAU,CAC9B,IAAMC,EAAO/B,GAAUC,EAAOC,CAAM,EAC9B8B,EAAStB,EAAG,SAAU,CAAE,KAAM,SAAU,MAAO,kBAAmB,aAAcC,EAAKT,EAAO,YAAa,CAAE,MAAO6B,CAAK,CAAC,CAAE,EAAG,MAAG,EACtIC,EAAO,iBAAiB,QAAS,IAAM,CACrCd,EAAOL,EAAO,OAAO,CAACoB,EAAGC,IAAMA,IAAMJ,CAAK,CAAC,EAC3CN,EAAM,MAAM,CACd,CAAC,EACD,IAAMW,EAAOlC,EAAM,OAAS,UAAY,SAAWA,EAAM,OAAS,QAAU,GAAK,SACjF,OAAOS,EAAG,OAAQ,CAAE,MAAO,WAAY,YAAaT,EAAM,IAAK,EAAG,GAAIkC,EAAOrB,EAAKqB,CAAI,EAAI,CAAC,EAAIzB,EAAG,OAAQ,CAAE,MAAO,eAAgB,EAAGqB,CAAI,EAAGC,CAAM,CACrJ,CAAC,CACH,CACF,CAEA,SAASI,GAAc,CACrBV,EAAY,gBACV,GAAGE,EAAQ,IAAI,CAACS,EAAYP,IAAU,CACpC,IAAMQ,EAAS5B,EAAG,KAAM,CAAE,KAAM,SAAU,GAAI,GAAGY,CAAM,IAAIQ,CAAK,GAAI,gBAAiB,OAAOA,IAAUD,CAAM,CAAE,EAAGQ,EAAW,KAAK,EAEjI,OAAAC,EAAO,iBAAiB,YAAcC,GAAUA,EAAM,eAAe,CAAC,EACtED,EAAO,iBAAiB,QAAS,IAAME,EAAKH,CAAU,CAAC,EAChDC,CACT,CAAC,CACH,EACAZ,EAAY,OAASE,EAAQ,SAAW,EACxCJ,EAAM,aAAa,gBAAiB,OAAO,CAACE,EAAY,MAAM,CAAC,EAC3DA,EAAY,OAAQF,EAAM,gBAAgB,uBAAuB,EAChEA,EAAM,aAAa,wBAAyB,GAAGF,CAAM,IAAIO,CAAM,EAAE,CACxE,CAEA,SAASY,GAAe,CACtBb,EAAU,CAAC,EACXQ,EAAY,CACd,CAGA,SAASI,EAAKH,EAAwB,CACpC,IAAMK,EAAQ,CAAE,GAAIL,EAAW,GAAI,MAAOA,EAAW,MAAO,MAAOA,EAAW,UAAW,EACnFM,EAAK9B,EAAO,UAAW+B,GAAMA,EAAE,OAAS,SAAWA,EAAE,QAAUP,EAAW,KAAK,EAC/ElB,EAAO,CAAC,GAAGN,CAAM,EACvB,GAAI8B,EAAK,EAAGxB,EAAK,KAAK,CAAE,KAAM,QAAS,MAAOkB,EAAW,MAAO,MAAOA,EAAW,WAAY,OAAQ,CAACK,CAAK,CAAE,CAAC,MAC1G,CACH,IAAMzC,EAAQkB,EAAKwB,CAAE,EACP1C,EAAM,OAAO,KAAMG,GAAMA,EAAE,KAAOsC,EAAM,IAAM,KAAK,UAAUtC,EAAE,KAAK,IAAM,KAAK,UAAUsC,EAAM,KAAK,CAAC,IACvGvB,EAAKwB,CAAE,EAAI,CAAE,GAAG1C,EAAO,OAAQ,CAAC,GAAGA,EAAM,OAAQyC,CAAK,CAAE,EACtE,CACAlB,EAAM,MAAQ,GACdiB,EAAa,EACbvB,EAAOC,CAAI,CACb,CAEAK,EAAM,iBAAiB,QAAS,IAAM,CACpCI,EAAUiB,GAAYrB,EAAM,MAAOjB,EAAMC,EAAM,CAAE,UAAWN,EAAO,SAAU,CAAC,EAC9E2B,EAAS,EACTO,EAAY,CACd,CAAC,EACDZ,EAAM,iBAAiB,OAAQiB,CAAY,EAC3CjB,EAAM,iBAAiB,UAAYe,GAAU,CACvCA,EAAM,eACLA,EAAM,MAAQ,aAAeA,EAAM,MAAQ,YAAcX,EAAQ,QACpEW,EAAM,eAAe,EACrBV,GAAUA,GAAUU,EAAM,MAAQ,YAAc,EAAIX,EAAQ,OAAS,IAAMA,EAAQ,OACnFQ,EAAY,GACHG,EAAM,MAAQ,SAEvBA,EAAM,eAAe,EACjBX,EAAQ,QAAQY,EAAKZ,EAAQC,CAAM,CAAC,GAC/BU,EAAM,MAAQ,aAAe,CAACf,EAAM,OAASX,EAAO,OAC7DK,EAAOL,EAAO,MAAM,EAAG,EAAE,CAAC,EACjB0B,EAAM,MAAQ,UAAY,CAACb,EAAY,SAChDa,EAAM,eAAe,EACrBE,EAAa,GAEjB,CAAC,EAID,IAAMK,EAAU,CAACC,EAAkBhB,EAAciB,IAAetC,EAAG,MAAO,CAAE,MAAO,oBAAqB,GAAAsC,CAAG,EAAG,GAAGlC,EAAKiC,CAAQ,EAAGhB,CAAI,EAC/HkB,EAAW,CAACd,EAA6Be,IAAgB,CAC7D,IAAMP,EAAK9B,EAAO,UAAW+B,GAAMA,EAAE,OAAST,CAAI,EAC5CgB,EAAMR,EAAK,EAAI,CAAC,EAAIR,IAAS,UAAatB,EAAO8B,CAAE,EAA0C,IAAO9B,EAAO8B,CAAE,EAA0C,OACvJS,EAAOD,EAAI,SAASD,CAAG,EAAIC,EAAI,OAAQE,GAAMA,IAAMH,CAAG,EAAI,CAAC,GAAGC,EAAKD,CAAG,EACtEjD,EACJkC,IAAS,UACL,CAAE,KAAAA,EAAM,IAAKiB,EAAM,OAAQA,EAAK,IAAKJ,GAAOxC,EAAK,SAAS,KAAMoC,GAAMA,EAAE,KAAOI,CAAE,GAAG,OAASA,CAAE,CAAE,EACjG,CAAE,KAAAb,EAAM,OAAQiB,EAAM,OAAQA,EAAK,IAAKE,GAAU/C,EAAK,OAAO+C,CAAK,GAAG,OAASA,CAAK,CAAE,EACtFnC,EAAO,CAAC,GAAGN,CAAM,EACnB8B,EAAK,EAAGxB,EAAK,KAAKlB,CAAK,EAClBmD,EAAK,OAAQjC,EAAKwB,CAAE,EAAI1C,EAC5BkB,EAAK,OAAOwB,EAAI,CAAC,EACtBzB,EAAOC,CAAI,CACb,EAEMoC,GAAiB/C,EAAK,SAAW,CAAC,GAAG,IAAKgD,GAAW,CACzD,IAAMC,EAAS/C,EAAG,SAAU,CAAE,KAAM,SAAU,MAAO,mBAAoB,eAAgB,QAAS,cAAe8C,EAAO,EAAG,EAAGA,EAAO,KAAK,EAC1I,OAAAC,EAAO,iBAAiB,QAAS,IAAMR,EAAS,UAAWO,EAAO,EAAE,CAAC,EAC9DC,CACT,CAAC,EACKC,GAAgBlD,EAAK,SAAW,CAAC,GAAG,IAAK8C,GAAU,CACvD,IAAMG,EAAS/C,EAAG,SAAU,CAAE,KAAM,SAAU,MAAO,mBAAoB,eAAgB,QAAS,aAAc4C,CAAM,EAAG/C,EAAK,OAAO+C,CAAK,EAAE,KAAK,EACjJ,OAAAG,EAAO,iBAAiB,QAAS,IAAMR,EAAS,UAAWK,CAAK,CAAC,EAC1DG,CACT,CAAC,EACKE,EAASC,GAAiB,CAAE,KAAArD,EAAM,GAAAG,EAAI,OAAAR,EAAQ,IAAMD,GAAUiB,EAAO,CAAC,GAAGL,EAAQZ,CAAK,CAAC,CAAE,CAAC,EAC1F4D,EAAaC,GAAe,CAAE,KAAAvD,EAAM,GAAAG,EAAI,OAAAR,EAAQ,KAAAS,EAAM,YAAaL,EAAQ,YAAa,QAAS,IAAMO,EAAQ,MAAOK,CAAO,CAAC,EAE9H6C,EAAQ,CAAC5B,EAAcY,EAAkBiB,KAAkBC,IAC/DvD,EAAG,MAAO,CAAE,MAAO,kBAAmB,kBAAmByB,EAAM,KAAM,QAAS,kBAAmB,GAAGZ,CAAO,IAAIY,CAAI,EAAG,EAAGW,EAAQC,EAAUiB,EAAO,GAAGzC,CAAO,IAAIY,CAAI,EAAE,EAAG,GAAG8B,CAAK,EAC7KC,EAAQxD,EACZ,MACA,CAAE,MAAO,kBAAmB,GAAIa,EAAS,OAAQ,EAAG,EACpDwC,EAAM,UAAW,SAAU7D,EAAO,QAAS,GAAGqD,EAAeI,EAAO,OAAQA,EAAO,IAAI,EACvF,GAAID,EAAa,OAAS,CAACK,EAAM,UAAW,SAAU7D,EAAO,QAAS,GAAGwD,CAAY,CAAC,EAAI,CAAC,EAC3FK,EAAM,aAAc,OAAQ7D,EAAO,WAAY2D,EAAW,KAAMA,EAAW,KAAMA,EAAW,KAAMA,EAAW,IAAI,CACnH,EAEA,SAASxC,GAAY,CACnB,IAAM8C,EAAOtD,EAAO,KAAM+B,GAAMA,EAAE,OAAS,SAAS,GAAuD,KAAO,CAAC,EAC7GwB,EAAUvD,EAAO,KAAM+B,GAAMA,EAAE,OAAS,SAAS,GAAuD,QAAU,CAAC,EACzH,QAAWa,KAAUF,EAAeE,EAAO,aAAa,eAAgB,OAAOU,EAAI,SAASV,EAAO,QAAQ,QAAa,EAAE,CAAC,CAAC,EAC5H,QAAWA,KAAUC,EAAcD,EAAO,aAAa,eAAgB,OAAOW,EAAO,SAASX,EAAO,QAAQ,OAAY,EAAE,CAAC,CAAC,CAC/H,CAEA,SAASY,EAAUC,EAAe,CAChCJ,EAAM,OAAS,CAACI,EAChB3C,EAAO,aAAa,gBAAiB,OAAO2C,CAAI,CAAC,EAC7CA,GAAM7B,EAAa,CACzB,CACAd,EAAO,iBAAiB,QAAS,IAAM0C,EAAUH,EAAM,MAAM,CAAC,EAC9DA,EAAM,iBAAiB,UAAY3B,GAAU,CACvCA,EAAM,MAAQ,WAClBA,EAAM,eAAe,EACrB8B,EAAU,EAAK,EACf1C,EAAO,MAAM,EACf,CAAC,EACD,IAAM4C,EAAU7D,EAAG,MAAO,CAAE,MAAO,WAAY,EAAGA,EAAG,MAAO,CAAE,MAAO,iBAAkB,EAAG,GAAGI,EAAK,QAAQ,EAAGW,EAAOD,EAAOG,CAAM,EAAGD,EAAawC,CAAK,EAEhJM,EAAWjC,GAAiB,CAC5B,CAAC2B,EAAM,QAAU,CAACK,EAAQ,SAAShC,EAAM,MAAc,GAAG8B,EAAU,EAAK,CAC/E,EACA,OAAA5D,EAAI,iBAAiB,cAAe+D,CAAO,EAE3CpD,EAAU,EACVC,EAAU,EACH,CACL,QAAAkD,EACA,QAAS,IAAM9D,EAAI,oBAAoB,cAAe+D,CAAO,CAC/D,CACF,CCpLA,IAAMC,GAAU,IAAI,IAAI,CAAC,UAAW,QAAS,UAAU,CAAC,EAElDC,GAAa,IAAI,IAAI,CAAC,WAAY,YAAa,SAAU,QAAS,OAAQ,OAAQ,YAAY,CAAC,EAO9F,SAASC,GAASC,EAAgC,CACvD,GAAM,CAAE,KAAAC,EAAM,KAAAC,EAAM,KAAAC,EAAM,GAAAC,EAAI,OAAAC,EAAQ,KAAAC,EAAM,OAAAC,EAAQ,IAAAC,CAAI,EAAIR,EAC5DS,GAAkBD,CAAG,EACrB,IAAME,EAAWR,EAAK,UAAY,GAC5BS,EAAcT,EAAK,MAAQ,CAAC,EAC9BU,EAAoBD,EACpBE,EAAS,EACTC,EAAQ,EAERC,EAAc,CAAC,EAEbC,EAAW,IAAI,QACfC,EAAU,IAAM,CAAC,GAAGC,EAAK,iBAAiB,cAAc,CAAC,EAAE,IAAKC,GAAOH,EAAS,IAAIG,CAAE,CAAQ,EAE9FC,EAAQnB,EAAK,KAAK,OAAS,SAAWA,EAAK,KAAK,MAAQ,GAC1DoB,EAAkBC,GAAepB,EAAMF,EAAQ,YAAaC,CAAI,EAE9DsB,EAAS,IAAI,IACfC,EAAS,EACTC,EAAY,GAGVC,EAAS,CAAC,GAAG,IAAI,IAAIxB,EAAK,QAAQ,QAASyB,GAAS,CACxD,IAAMC,GAAM3B,EAAK,OAAO0B,CAAI,EAC5B,OAAOC,GAAI,OAAS,YAAcA,GAAI,cAAgB,CAACD,EAAMC,GAAI,aAAa,EAAI,CAACD,CAAI,CACzF,CAAC,CAAC,CAAC,EACGE,EAAO,CAACF,EAAcG,KAAkCC,GAAa9B,EAAK,OAAO0B,CAAI,EAAgBG,GAAOH,CAAI,EAAGG,GAAQvB,CAAM,EAIjIyB,EAAY5B,EAAG,QAAS,CAAE,KAAM,WAAY,MAAO,mBAAoB,aAAcC,EAAO,SAAU,CAAC,EACvG4B,EAAU/B,EAAK,QAAQ,IAAKyB,GAAS,CACzC,IAAMC,GAAM3B,EAAK,OAAO0B,CAAI,EACtBO,GAAK9B,EAAG,KAAM,CAAE,MAAO,MAAO,aAAcuB,EAAM,MAAO9B,GAAQ,IAAI+B,GAAI,IAAI,EAAI,SAAW,MAAU,CAAC,EAC7G,GAAI9B,GAAW,IAAI8B,GAAI,IAAI,EAAGM,GAAG,OAAON,GAAI,KAAK,MAC5C,CACH,IAAMO,GAAS/B,EAAG,SAAU,CAAE,KAAM,SAAU,MAAO,cAAe,EAAGwB,GAAI,KAAK,EAChFO,GAAO,iBAAiB,QAAS,IAAM,CAErC,IAAMC,GAAOxB,EAAK,CAAC,GAAG,QAAUe,EAAO,CAACf,EAAK,CAAC,EAAE,KAAO,GACvDA,EAAO,CAAC,CAAE,MAAOe,EAAM,GAAIS,GAAO,CAAE,KAAAA,EAAK,EAAI,CAAC,CAAG,EAAG,GAAGzB,EAAY,OAAQ0B,IAAUA,GAAM,QAAUV,CAAI,CAAC,EAC1Gd,EAAS,EACJyB,GAAK,CACZ,CAAC,EACDJ,GAAG,OAAOC,EAAM,CAClB,CACA,OAAOD,EACT,CAAC,EACKhB,EAAOd,EAAG,OAAO,EACjBmC,EAAQnC,EACZ,QACA,CAAE,MAAO,gBAAiB,aAAcH,EAAK,KAAM,EACnDG,EAAG,QAAS,CAAC,EAAGA,EAAG,KAAM,CAAC,EAAGA,EAAG,KAAM,CAAE,MAAO,gBAAiB,MAAO,KAAM,EAAG4B,CAAS,EAAG,GAAGC,CAAO,CAAC,EACvGf,CACF,EACMsB,EAAQpC,EAAG,IAAK,CAAE,MAAO,gBAAiB,OAAQ,EAAG,EAAGC,EAAO,SAAS,EACxEoC,EAAQrC,EAAG,SAAU,CAAE,KAAM,SAAU,MAAO,0BAA2B,EAAGC,EAAO,KAAK,EACxFqC,EAAStC,EAAG,IAAK,CAAE,MAAO,iBAAkB,KAAM,QAAS,OAAQ,EAAG,EAAGC,EAAO,WAAY,IAAKoC,CAAK,EAC5GA,EAAM,iBAAiB,QAAS,IAAG,CAAQH,GAAK,EAAC,EAEjD,SAASK,EAAIC,EAAaC,GAAQ,EAAwB,CACxD,IAAMlB,GAAOE,EAAK3B,EAAK,QAAQ,CAAC,EAAG0C,EAAO,MAAM,GAAK,OAAOA,EAAO,EAAE,EAC/DE,GAAM1C,EAAG,QAAS,CAAE,KAAM,WAAY,MAAO,mBAAoB,aAAcE,EAAKD,EAAO,aAAc,CAAE,KAAAsB,EAAK,CAAC,CAAE,CAAC,EAC1HmB,GAAI,QAAUvB,EAAO,IAAIqB,EAAO,EAAE,EAClCE,GAAI,iBAAiB,SAAU,IAAM,CAC/BA,GAAI,QAASvB,EAAO,IAAIqB,EAAO,EAAE,EAChCrB,EAAO,OAAOqB,EAAO,EAAE,EAC5BG,EAAW,CACb,CAAC,EACD,IAAM5B,GAAKf,EACT,KACA,CAAE,MAAOJ,EAAQ,aAAe,+BAAiC,cAAe,SAAU,IAAK,UAAW,OAAO4C,EAAO,EAAE,EAAG,aAAcC,GAAQ,OAAOA,EAAK,EAAI,MAAU,EAC7KzC,EAAG,KAAM,CAAE,MAAO,eAAgB,EAAG0C,EAAG,EAExC,GAAG5C,EAAK,QAAQ,IAAKyB,IAASvB,EAAG,KAAM,CAAE,MAAOP,GAAQ,IAAII,EAAK,OAAO0B,EAAI,EAAE,IAAI,EAAI,SAAW,MAAU,EAAGvB,EAAG,MAAO,CAAC,EAAGyB,EAAKF,GAAMiB,EAAO,MAAM,CAAC,CAAC,CAAC,CACzJ,EACA,OAAAzB,GAAG,iBAAiB,QAAU6B,IAAU,CACtC,IAAMC,GAAQD,GAAM,OAAmB,QAAQ,IAAI,EAEnD,GAAIC,IAAM,UAAU,SAAS,eAAe,EAAG,CACzCD,GAAM,SAAWC,IAAMH,GAAI,MAAM,EACrC,MACF,CACA9C,EAAQ,eAAe4C,EAAO,EAAE,CAClC,CAAC,EACDzB,GAAG,iBAAiB,UAAY6B,IAAU,CACpCA,GAAM,SAAW7B,KACjB6B,GAAM,MAAQ,SAChBA,GAAM,eAAe,EACrBhD,EAAQ,eAAe4C,EAAO,EAAE,GACvBI,GAAM,MAAQ,KACvBA,GAAM,eAAe,EACrBF,GAAI,MAAM,IACDE,GAAM,MAAQ,aAAeA,GAAM,MAAQ,aACpDA,GAAM,eAAe,GACRA,GAAM,MAAQ,YAAc7B,GAAG,mBAAqBA,GAAG,yBACtC,MAAM,GAExC,CAAC,EACDH,EAAS,IAAIG,GAAIyB,CAAM,EAChBzB,EACT,CAIA,IAAM+B,EAAQ9C,EAAG,OAAQ,CAAE,MAAO,gBAAiB,KAAM,QAAS,CAAC,EAC7D+C,EAAQ/C,EAAG,SAAU,CAAE,KAAM,SAAU,MAAO,0BAA2B,EAAGC,EAAO,cAAc,EACjG+C,GAAWlD,EAAK,SAAW,CAAC,GAAG,IAAKmD,GAAuB,CAC/D,IAAMlB,GAAS/B,EAAG,SAAU,CAAE,KAAM,SAAU,MAAO,uBAAuBiD,EAAO,OAAS,WAAW,GAAI,YAAaA,EAAO,EAAG,EAAG,GAAGrD,EAAQ,SAASqD,EAAO,KAAMA,EAAO,KAAK,CAAC,EACnL,OAAAlB,GAAO,iBAAiB,QAAS,SAAY,CACvCkB,EAAO,SAAW,CAAE,MAAMrD,EAAQ,QAAQqD,EAAO,OAAO,IAC5D,MAAMlD,EAAK,UAAUkD,EAAO,GAAI,CAAE,UAAW,CAAC,GAAG9B,CAAM,CAAE,CAAC,EAC1D,MAAMe,GAAK,EACb,CAAC,EACMH,EACT,CAAC,EACKmB,EAAYlD,EAAG,MAAO,CAAE,MAAO,oBAAqB,OAAQ,EAAG,EAAG8C,EAAO,GAAGE,EAASD,CAAK,EAChGA,EAAM,iBAAiB,QAAS,IAAM,CACpC5B,EAAO,MAAM,EACb,QAAWuB,KAAO5B,EAAK,iBAAmC,mBAAmB,EAAG4B,EAAI,QAAU,GAC9FC,EAAW,CACb,CAAC,EACDf,EAAU,iBAAiB,SAAU,IAAM,CACzC,QAAWY,KAAU3B,EAAQ,EACvBe,EAAU,QAAST,EAAO,IAAIqB,EAAO,EAAE,EACtCrB,EAAO,OAAOqB,EAAO,EAAE,EAE9B,QAAWE,KAAO5B,EAAK,iBAAmC,mBAAmB,EAAG4B,EAAI,QAAUd,EAAU,QACxGe,EAAW,CACb,CAAC,EAED,SAASA,GAAa,CACpB,IAAMQ,EAAQtC,EAAQ,EAChBuC,GAASD,EAAM,OAAQX,IAAWrB,EAAO,IAAIqB,GAAO,EAAE,CAAC,EAAE,OAC/DZ,EAAU,QAAUuB,EAAM,OAAS,GAAKC,KAAWD,EAAM,OACzDvB,EAAU,cAAgBwB,GAAS,GAAKA,GAASD,EAAM,OACvDD,EAAU,OAAS/B,EAAO,OAAS,EACnC2B,EAAM,YAAc5C,EAAKD,EAAO,SAAU,CAAE,EAAGkB,EAAO,IAAK,CAAC,EAC5D,QAAWJ,MAAMD,EAAK,iBAA8B,cAAc,EAChEC,GAAG,aAAa,gBAAiB,OAAO,CAAC,GAAGI,CAAM,EAAE,KAAMkC,IAAO,OAAOA,EAAE,IAAMtC,GAAG,QAAQ,EAAK,CAAC,CAAC,CAEtG,CAIA,IAAMuC,EAAQtD,EAAG,OAAQ,CAAE,MAAO,eAAgB,CAAC,EAC7CuD,EAAWvD,EAAG,SAAU,CAAE,KAAM,SAAU,MAAO,4BAA6B,aAAcC,EAAO,YAAa,EAAG,QAAG,EACtHuD,EAAOxD,EAAG,SAAU,CAAE,KAAM,SAAU,MAAO,4BAA6B,aAAcC,EAAO,QAAS,EAAG,QAAG,EAC9GwD,EAAQzD,EAAG,MAAO,CAAE,MAAO,WAAY,KAAM,OAAQ,EAAGsD,EAAOC,EAAUC,CAAI,EACnFD,EAAS,iBAAiB,QAAS,IAAM,CACvC9C,EAAS,KAAK,IAAI,EAAGA,EAASH,CAAQ,EACjC4B,GAAK,CACZ,CAAC,EACDsB,EAAK,iBAAiB,QAAS,IAAM,CACnC/C,GAAUH,EACL4B,GAAK,CACZ,CAAC,EAED,SAASwB,GAAY,CACnBD,EAAM,OAAS/C,IAAU,EACzB4C,EAAM,YAAcpD,EAAKD,EAAO,MAAO,CAAE,KAAMQ,EAAS,EAAG,GAAI,KAAK,IAAIA,EAASE,EAAK,OAAQD,CAAK,EAAG,MAAAA,CAAM,CAAC,EAC7G6C,EAAS,SAAW9C,IAAW,EAC/B+C,EAAK,SAAW/C,EAASH,GAAYI,CACvC,CAEA,SAASiD,GAAW,CAClB,QAAW7B,KAAMD,EAAS,CACxB,IAAMI,GAAQzB,EAAK,CAAC,GAAG,QAAUsB,EAAG,QAAQ,MAAWtB,EAAK,CAAC,EAAI,KAC7DyB,GAAOH,EAAG,aAAa,YAAaG,GAAM,KAAO,aAAe,WAAW,EAC1EH,EAAG,gBAAgB,WAAW,CACrC,CACF,CAKA,SAAS8B,GAAU,CACjB,IAAMT,EAAQ,IAAI,IAAItC,EAAQ,EAAE,IAAK2B,IAAWA,GAAO,EAAE,CAAC,EAC1D,QAAWa,KAAM,CAAC,GAAGlC,CAAM,EAAQgC,EAAM,IAAIE,EAAE,GAAGlC,EAAO,OAAOkC,EAAE,EAClEV,EAAW,CACb,CAEA,IAAMkB,GAAWC,IAAsC,CACrD,KAAAjE,EACA,GAAAG,EACA,OAAAC,EACA,KAAAC,EACA,WAAY4D,EACZ,MAAA9C,EACA,OAAAM,EACA,QAASxB,EAAK,QAAQ,OAAS,EAC/B,SAAAQ,EACA,KAAM,IAAME,EACZ,UAAW+B,EACX,QAAAqB,CACF,GAEA,eAAe1B,IAAsB,CACnC,IAAM6B,EAAO,EAAE3C,EACfuC,EAAS,EACTxB,EAAM,aAAa,YAAa,MAAM,EACtC,IAAI6B,GAA+B,CAAC,EACpC,GAAI,CACF,IAAMC,GAASC,GAAejD,EAAQnB,CAAI,EACpCqE,GAAWC,GAAcnD,CAAM,EAC/B6C,GAASlE,EAAQ,WACvB,GAAIuE,GAAS,QAAUL,IAAQ,QAAUA,GAAO,KAAM,CAEpD,IAAMO,GAAS,MAAMP,GAAO,OAAO,CAAE,MAAA9C,EAAO,MAAOmD,GAAS,CAAC,EAAG,OAAAF,EAAO,CAAC,EACxE,GAAIF,IAAS3C,GAAUC,EAAW,OAClCV,EAAO,CAAC,EACRD,EAAQ,EACRsD,GAAQK,GAAO,IAAKC,IAAUC,GAASV,GAAQC,EAAM,EAAGQ,GAAO,EAAGL,GAAQE,EAAQ,CAAC,CACrF,KAAO,CACL,IAAMK,GAASV,IAAQ,KAAO,MAAMA,GAAO,KAAK,CAAE,MAAA9C,EAAO,OAAAM,EAAQ,OAAA2C,GAAQ,KAAAzD,EAAM,OAAAC,EAAQ,MAAOH,CAAS,CAAC,EAAI,CAAE,QAAS,CAAC,EAAG,MAAO,CAAE,EACpI,GAAIyD,IAAS3C,GAAUC,EAAW,OAElC,GAAI,CAACmD,GAAO,QAAQ,QAAUA,GAAO,MAAQ,GAAK/D,EAAS,EACzD,OAAAA,EAAS,KAAK,OAAO+D,GAAO,MAAQ,GAAKlE,CAAQ,EAAIA,EAC9C4B,GAAK,EAEdvB,EAAO6D,GAAO,QACd9D,EAAQ8D,GAAO,MACfR,GAAQrD,EAAK,IAAK6B,IAAWD,EAAIC,EAAM,CAAC,CAC1C,CACAF,EAAO,OAAS,EAClB,MAAQ,CACN,GAAIyB,IAAS3C,GAAUC,EAAW,OAClCV,EAAO,CAAC,EACRD,EAAQ,EACR4B,EAAO,OAAS,EAClB,CACAxB,EAAK,gBAAgB,GAAGkD,EAAK,EAC7B5B,EAAM,OAAS4B,GAAM,OAAS,GAAK,CAAC1B,EAAO,OAC3CH,EAAM,gBAAgB,WAAW,EACjCuB,EAAU,EACVE,EAAQ,CACV,CAEA,IAAMa,GAASC,GAAU,CACvB,KAAA7E,EACA,KAAAC,EACA,IAAAM,EACA,GAAAJ,EACA,OAAAC,EACA,KAAAC,EACA,IAAKN,EAAQ,IACb,MAAOA,EAAQ,MACf,YAAaA,EAAQ,YACrB,OAAAqB,EACA,SAASuC,EAAM,CACbvC,EAASuC,EACT/C,EAAS,EACJyB,GAAK,CACZ,CACF,CAAC,EACKyC,GAAU3E,EACd,MACA,CAAE,MAAO,UAAW,YAAaF,EAAK,EAAG,EACzCE,EAAG,MAAO,CAAE,MAAO,aAAc,EAAGyE,GAAO,QAAShB,CAAK,EACzDP,EACAlD,EAAG,MAAO,CAAE,MAAO,gBAAiB,EAAGmC,CAAK,EAC5CC,EACAE,CACF,EACA,OAAKJ,GAAK,EAEH,CACL,QAAAyC,GACA,OAAQzC,GACR,SAAU,CACRb,EAAY,GACZoD,GAAO,QAAQ,CACjB,CACF,CACF,CC7SO,SAASG,GAAYC,EAAmBC,EAA2B,CACxE,IAAMC,EAAQF,EAAK,OAAS,OACtBG,EAAcD,IAAU,SAAW,CAACF,EAAK,MACzCI,EAAMC,GAAYL,EAAK,OAAO,EAC9BM,EAAON,EAAK,SAAW,EACvBO,EAAKJ,GAAeF,EAAM,QAAU,EAAKK,IAAS,GAAKF,EAAM,EAAI,SAAW,SAAY,OAC9F,MAAO,CACL,MAAAF,EACA,YAAAC,EACA,GAAAI,EACA,MAAO,CACL,QAASA,IAAO,SAAW,KAAK,IAAID,EAAML,EAAM,OAAO,EAAIG,EAE3D,OAAQH,EAAM,SAAWC,IAAU,SAAWA,IAAU,QACxD,OAAQF,EAAK,QAAUC,EAAM,MAC/B,CACF,CACF,CAGA,IAAMO,GAAS,IAAI,IAAe,CAAC,WAAY,QAAQ,CAAC,EAMjD,SAASC,GAAWT,EAAiBU,EAAiBT,EAAiE,CAC5H,GAAIS,IAAS,WAAaV,EAAK,SAAW,OAAQ,MAAO,QACzD,IAAMW,EAASX,EAAK,QAAUC,EAC9B,OAAOU,IAAW,UAAYH,GAAO,IAAIE,CAAI,EAAI,QAAUC,CAC7D,CCvDO,SAASC,GAAUC,EAAsBC,EAAuB,CACjED,EAAQ,SAAWC,IAAQD,EAAQ,OAASC,EAClD,CAGO,SAASC,GAAQF,EAAeG,EAAoB,CACrDH,EAAQ,cAAgBG,IAAMH,EAAQ,YAAcG,EAC1D,CAGO,SAASC,GAAQJ,EAAkBK,EAAcC,EAA4B,CAC9EN,EAAQ,aAAaK,CAAI,IAAMC,IAC/BA,IAAU,KAAMN,EAAQ,gBAAgBK,CAAI,EAC3CL,EAAQ,aAAaK,EAAMC,CAAK,EACvC,CCmGA,IAAIC,GAAS,EAON,SAASC,GAAYC,EAAmBC,EAAsC,CACnF,IAAMC,EAAMF,EAAK,cAEXG,EAAUC,GAAUH,EAAQ,IAAI,EACtC,GAAI,CAACE,EAAQ,GACX,MAAM,IAAI,MAAM;AAAA,EAA+BA,EAAQ,OAAO,IAAKE,GAAM,KAAKA,EAAE,IAAI,KAAKA,EAAE,OAAO,EAAE,EAAE,KAAK;AAAA,CAAI,CAAC,EAAE,EAGpH,IAAMC,EAAML,EAAQ,QAAUE,EAAQ,KAAK,SACrCI,EAAYD,EAAME,GAAaL,EAAQ,KAAMG,CAAG,EAAIH,EAAQ,KAC5DM,EAAOR,EAAQ,UAAYS,GAAcH,EAAWN,EAAQ,SAAS,EAAIM,EACzEI,EAASC,GAAUN,CAAG,EACtBO,EAAcZ,EAAQ,aAAea,GAAmB,EACxDC,EAAUC,GAAYf,CAAO,EAC7BgB,EAAW,CAAChB,EAAQ,KACpBiB,EAAOjB,EAAQ,MAAQkB,GAAW,CAAE,GAAGlB,EAAS,KAAAQ,EAAM,SAAUR,EAAQ,UAAYmB,GAAST,CAAM,CAAE,CAAC,EACtGU,EAAuB,CAAE,GAAGC,GAAcX,CAAM,EAAG,GAAGV,EAAQ,MAAO,EACrEsB,EAAeC,GAAcb,CAAM,EACnCc,EAAMxB,EAAQ,MAAQK,GAAOoB,GAAcpB,CAAG,EAAI,MAAQ,QAC1DqB,EAAS,KAAK,EAAE7B,EAAM,GACtB8B,EAAsB,CAAC,EACvBC,EAA2B,CAAC,EAC5BC,EAAOC,GAAe,GAAGJ,CAAM,IAAII,EAAG,QAAQ,kBAAmB,GAAG,CAAC,GACrEC,EAAO,CAACC,EAAkBC,IAC9BD,EAAS,QAAQ,aAAc,CAAC,EAAGE,IAAgB,OAAOD,EAAOC,CAAG,GAAK,EAAE,CAAC,EAE9EC,GAAclC,CAAG,EAEjB,SAASmC,EAA0C/B,EAAQgC,EAA4C,CAAC,KAAMC,EAA6B,CACzI,IAAMC,EAAOtC,EAAI,cAAcI,CAAG,EAClC,OAAW,CAACmC,GAAMC,EAAK,IAAK,OAAO,QAAQJ,CAAK,EAAOI,KAAU,QAAWF,EAAK,aAAaC,GAAMC,EAAK,EACzG,OAAAF,EAAK,OAAO,GAAGD,CAAQ,EAChBC,CACT,CAOA,SAASG,EAASF,EAA0BG,EAAiC,CAC3E,IAAMC,EAAOC,GAAS5C,EAAKuC,EAAMxC,EAAQ,KAAK,EACxC8C,EAAQV,EAAG,MAAO,CAAC,EAAGO,CAAI,EAChC,OAAOC,EAAO,CAACA,EAAME,CAAK,EAAI,CAACA,CAAK,CACtC,CAEA,IAAMC,EAAOX,EAAG,OAAQ,CAAE,MAAO,UAAW,WAAY,GAAI,eAAgBpC,EAAQ,MAAQ,YAAa,IAAAwB,EAAK,KAAMnB,EAAK,iBAAkBG,EAAK,QAAS,CAAC,EAC1JwC,GAAUD,EAAMvC,EAAK,IAAI,EACzB,IAAMyC,EAAUjD,EAAQ,SAAWkD,GAKnC,SAASC,EAAUZ,EAAiBnB,EAAkC,CACpE,IAAMgC,EAAM5C,EAAK,OAAO+B,EAAK,KAAK,EAC5BT,EAAKD,EAAIU,EAAK,EAAE,EAChBc,GAAWC,GAAWf,EAAMa,EAAI,KAAMhC,CAAM,EAC5CmC,GAAUnB,EAAG,MAAO,CAAE,MAAO,WAAY,YAAaG,EAAK,GAAI,aAAcA,EAAK,MAAO,YAAaa,EAAI,KAAM,cAAeC,EAAS,CAAC,EAC3Id,EAAK,SAASgB,GAAQ,MAAM,YAAY,YAAa,OAAOhB,EAAK,OAAO,CAAC,EAC7E,IAAMiB,GAAYjB,EAAK,OAASa,EAAI,MAC9BK,GAAQrB,EAAG,QAAS,CAAE,MAAO,WAAY,GAAI,GAAGN,CAAE,SAAU,IAAKA,CAAG,EAAG0B,EAAS,EAEhFE,GAAO1D,EAAQ,WAAa,CAAC2D,GAAc,IAAIP,EAAI,IAAI,EAAIP,GAAS5C,EAAK,OAAO,EAAI,KACtFyD,KACFA,GAAK,UAAU,IAAI,eAAe,EAClCD,GAAM,OAAOC,EAAI,GAEnB,IAAME,GAASC,GAAa,CAAE,KAAA5C,EAAM,KAAMsB,EAAK,MAAO,MAAOa,EAAK,KAAAb,EAAM,GAAAT,EAAI,SAAU7B,EAAK,OAAQqB,EAAc,YAAAV,EAAa,OAAAF,EAAQ,QAAAI,CAAQ,EAAGd,EAAQ,OAAO,EAE5JqD,KAAa,UAAY,CAACd,EAAK,cACrBqB,GAAO,QAAQ,QAAQE,EAAQ,EAAIF,GAAO,QAAUA,GAAO,QAAQ,cAAcE,EAAQ,IAChG,aAAa,cAAeN,EAAS,EAEvC,CAAC,QAAS,SAAU,UAAU,EAAE,SAASI,GAAO,QAAQ,OAAO,KAKpDA,GAAO,QAAQ,aAAa,MAAM,EAAIA,GAAO,QAAUA,GAAO,QAAQ,cAAc,QAAQ9B,CAAE,UAAU,IAC/G,aAAa,kBAAmB2B,GAAM,EAAE,EAC/CA,GAAM,iBAAiB,QAAS,IAAMG,GAAO,MAAM,CAAC,GAEtD,IAAMG,GAAWxB,EAAK,MAAQa,EAAI,KAC5BY,GAAOD,GAAW3B,EAAG,MAAO,CAAE,MAAO,UAAW,GAAI,GAAGN,CAAE,OAAQ,EAAGiC,EAAQ,EAAI,KAEhFE,GAAQ7B,EAAG,MAAO,CAAE,MAAO,WAAY,GAAI,GAAGN,CAAE,SAAU,OAAQ,EAAG,CAAC,EAEtEoC,GAAU9B,EAAG,MAAO,CAAE,MAAO,aAAc,GAAI,GAAGN,CAAE,WAAY,KAAM,SAAU,OAAQ,EAAG,CAAC,EAClGyB,GAAQ,OAAO,GAAIF,KAAa,QAAU,CAACO,GAAO,QAASH,EAAK,EAAI,CAACA,GAAOG,GAAO,OAAO,EAAI,GAAII,GAAO,CAACA,EAAI,EAAI,CAAC,EAAIC,GAAOC,EAAO,EACjIN,GAAO,SAAShC,EAAS,KAAK,IAAMgC,GAAO,UAAU,CAAC,EAG1D,IAAIO,GAAS,GACTC,GAAS,GACbb,GAAQ,iBAAiB,UAAW,IAAOY,GAAS,EAAK,EACzDZ,GAAQ,iBAAiB,WAAac,IAAU,CAC1Cd,GAAQ,SAASc,GAAM,aAA4B,IACvDF,GAAS,GAGT,eAAe,IAAMG,GAAOrD,EAAK,SAAS,CAAC,CAAC,EAC9C,CAAC,EAED,IAAMqD,GAAUC,IAAqB,CACnC,IAAMC,GAAQvD,EAAK,KAAKsB,EAAK,EAAE,EAC/BkC,GAAUlB,GAASiB,GAAM,SAAS,EAClCjB,GAAQ,UAAU,OAAO,cAAeiB,GAAM,QAAQ,EACtD,IAAME,GAAUH,GAAM,OAAOhC,EAAK,KAAK,EACvCkC,GAAUR,GAAO,CAACS,EAAO,EACzBC,GAAQV,GAAOS,IAAW,EAAE,EAC5B,IAAME,GAAML,GAAM,SAAShC,EAAK,KAAK,GAAK,IACtC,CAAC4B,IAAU,CAACS,MAAKR,GAASQ,IAE9B,IAAMC,GAAS,CAACH,GAAU,GAAKN,GAAQG,GAAM,SAAWA,GAAM,eAAiBhC,EAAK,MAAQgC,GAAM,QAAU,EAAE,EAAE,OAAO,OAAO,EAAE,KAAK,GAAG,EAGxI,GAFAE,GAAUP,GAAS,CAACW,EAAM,EAC1BF,GAAQT,GAASW,EAAM,EACnBnB,GAAM,CACR,IAAMjB,GAAQ8B,GAAM,OAAOhC,EAAK,KAAK,EAC/BuC,GAASrC,IAAU,MAA+BA,KAAU,IAAM,EAAE,MAAM,QAAQA,EAAK,GAAK,CAACA,GAAM,QACnGsC,GAAQ,CAACP,GAAM,UAAY,CAACE,IAAWI,IAAUP,GAAM,MAAM,SAAShC,EAAK,KAAK,GAAKtB,EAAK,QAAQsB,EAAK,KAAK,IAAM,KACxHgB,GAAQ,UAAU,OAAO,WAAYwB,EAAK,EAC1CrB,GAAK,gBAAgB,SAAU,CAACqB,EAAK,CACvC,CACAnB,GAAO,OAAO,CACZ,MAAOW,GAAM,OAAOhC,EAAK,KAAK,EAC9B,OAAQgC,GAAM,OACd,SAAUC,GAAM,UAAYQ,EAC5B,SAAUR,GAAM,SAChB,QAAS,CAAC,CAACE,GACX,YAAa,CAACV,IAAM,GAAIU,GAAUT,GAAM,GAAK,OAAWY,GAASX,GAAQ,GAAK,MAAS,EAAE,OAAO,OAAO,EAAE,KAAK,GAAG,GAAK,MACxH,CAAC,CACH,EACA,OAAAvC,EAAS,KAAK2C,EAAM,EACbf,EACT,CAEA,SAAS0B,EAASC,EAAsBpD,EAAY,CAClDH,EAAS,KAAK,IAAM8C,GAAUS,EAASjE,EAAK,KAAKa,CAAE,EAAE,SAAS,CAAC,CACjE,CAEA,SAASqD,EAAW5C,EAA+B,CACjD,IAAM6C,EAAShD,EAAG,SAAU,CAAE,KAAM,SAAU,MAAO,uBAAuBG,EAAK,OAAS,WAAW,GAAI,YAAaA,EAAK,EAAG,EAAG,GAAGG,EAASH,EAAK,KAAMA,EAAK,KAAK,CAAC,EACnK,OAAA8C,EAAMD,EAAQ7C,EAAK,OAAO,EAC1B6C,EAAO,iBAAiB,QAAS,SAAY,CACvC7C,EAAK,SAAW,CAAE,MAAMU,EAAQV,EAAK,OAAO,GAChD,MAAMtB,EAAK,UAAUsB,EAAK,EAAE,CAC9B,CAAC,EACD0C,EAASG,EAAQ7C,EAAK,EAAE,EACjB6C,CACT,CAEA,SAASE,EAAS/C,EAA6B,CAC7C,IAAMgD,EAAQhD,EAAK,OAAS,YACtB2C,EAAU9C,EAAGmD,IAAU,UAAY,KAAO,IAAK,CAAE,MAAO,WAAWA,CAAK,GAAI,YAAahD,EAAK,EAAG,EAAGA,EAAK,IAAI,EACnH,OAAA8C,EAAMH,EAAS3C,EAAK,OAAO,EAC3B0C,EAASC,EAAS3C,EAAK,EAAE,EAClB2C,CACT,CAEA,SAASM,EAASjD,EAA6B,CAC7C,IAAM2C,EAAU9C,EAAG,MAAO,CAAE,MAAO,UAAW,YAAaG,EAAK,KAAM,YAAaA,EAAK,EAAG,CAAC,EACtFkD,EAAUzF,EAAQ,QAAQuC,EAAK,IAAI,IAAI2C,EAAS,CAAE,KAAAjE,EAAM,KAAMsB,EAAK,IAAK,CAAC,EAC/E,OAAIkD,GAAS7D,EAAS,KAAK6D,CAAO,EAClCR,EAASC,EAAS3C,EAAK,EAAE,EAClB2C,CACT,CAGA,SAASG,EAAMH,EAAsBQ,EAA6B,CAC5DA,GAASR,EAAQ,MAAM,YAAY,YAAa,OAAOQ,CAAO,CAAC,CACrE,CAMA,SAASC,EAAKrD,EAAwBsD,EAAwCC,EAA2B,CACvG,IAAMC,EAAM1D,EAAG,MAAO,CAAE,MAAO,SAAU,CAAC,EAC1C,GAAIwD,IAAY,OACdE,EAAI,MAAM,YAAY,eAAgB,OAAOC,GAAYH,CAAO,CAAC,CAAC,EAE9D,OAAOA,GAAY,UACrB,QAAWI,KAAS,CAAC,SAAU,QAAQ,EAAY,CACjD,IAAMC,GAAQL,EAAQI,EAAK,EACvBC,KAAU,SACdH,EAAI,aAAa,gBAAgBE,EAAK,GAAI,OAAOC,EAAK,CAAC,EACvDH,EAAI,MAAM,YAAY,gBAAgBE,EAAK,GAAI,OAAOC,EAAK,CAAC,EAC9D,CAGJ,OAAAH,EAAI,OAAO,GAAGxD,EAAS,IAAK4D,IAAUC,EAAKD,GAAOL,CAAK,CAAC,CAAC,EAClDC,CACT,CAGA,IAAMM,EAAOC,IAA4B,CAAE,QAAS,EAAG,OAAAA,EAAQ,OAAQ7F,EAAK,MAAM,MAAO,GAGnF8F,EAAQ,IAAI,IAElB,SAASC,EAAYhE,EAAmBsD,EAA2B,CACjE,IAAMW,EAAOC,GAAYlE,EAAMsD,CAAK,EAE9Ba,EAAUtE,EAAGoE,EAAK,YAAc,MAAQ,WAAY,CACxD,MAAO,aACP,YAAajE,EAAK,GAClB,aAAciE,EAAK,MACnB,aAAcA,EAAK,GACnB,eAAgBA,EAAK,QAAU,QAAUX,EAAM,OAAS,GAAK,MAC/D,CAAC,EACDR,EAAMqB,EAASnE,EAAK,OAAO,EACvBA,EAAK,YAAYmE,EAAQ,MAAM,YAAY,mBAAoB,GAAGnE,EAAK,UAAU,IAAI,EACzF,IAAMoE,GAAcpE,EAAK,YAAcH,EAAG,IAAK,CAAE,MAAO,wBAAyB,EAAGG,EAAK,WAAW,EAAI,KAClGqE,GAAUjB,EAAKpD,EAAK,SAAUiE,EAAK,KAAO,SAAW,KAAOjE,EAAK,QAASiE,EAAK,KAAK,EAC1F,GAAIjE,EAAK,OAASA,EAAK,YAAa,CAClCqE,GAAQ,GAAK/E,EAAI,GAAGU,EAAK,EAAE,UAAU,EACrC,IAAMsE,GAASzE,EACb,SACA,CAAE,KAAM,SAAU,MAAO,oBAAqB,gBAAiBwE,GAAQ,EAAG,EAC1ExE,EAAG,OAAQ,CAAE,MAAO,qBAAsB,cAAe,MAAO,CAAC,EACjE,GAAGM,EAASH,EAAK,KAAMA,EAAK,KAAK,CACnC,EACIuE,GAAOvE,EAAK,YAAc,GACxBwE,GAAQC,IAAkB,CAC9BF,GAAOE,GACPH,GAAO,aAAa,gBAAiB,OAAOC,EAAI,CAAC,EACjDF,GAAQ,OAAS,CAACE,GACdH,KAAaA,GAAY,OAAS,CAACG,IACvCJ,EAAQ,UAAU,OAAO,oBAAqB,CAACI,EAAI,CACrD,EACAD,GAAO,iBAAiB,QAAS,IAAME,GAAK,CAACD,EAAI,CAAC,EAClDR,EAAM,IAAII,EAAS,IAAMK,GAAK,EAAI,CAAC,EACnCA,GAAKD,EAAI,EACTJ,EAAQ,OAAOtE,EAAG,SAAU,CAAE,MAAO,kBAAmB,EAAGyE,EAAM,CAAC,CACpE,MAAWtE,EAAK,OACdmE,EAAQ,OAAOtE,EAAG,SAAU,CAAE,MAAO,kBAAmB,EAAG,GAAGM,EAASH,EAAK,KAAMA,EAAK,KAAK,CAAC,CAAC,EAEhG,OAAIoE,IAAaD,EAAQ,OAAOC,EAAW,EAC3CD,EAAQ,OAAOE,EAAO,EACtB3B,EAASyB,EAASnE,EAAK,EAAE,EAClBmE,CACT,CAEA,SAASO,EAAS1E,EAAgBsD,EAA2B,CAC3D,IAAMC,EAAM1D,EAAG,MAAO,CAAE,MAAO,UAAW,YAAaG,EAAK,EAAG,CAAC,EAChE8C,EAAMS,EAAKvD,EAAK,OAAO,EACvB,IAAM2E,EAAO9E,EAAG,MAAO,CAAE,MAAO,aAAc,KAAM,SAAU,CAAC,EAG3D+E,GAAwB,KACxBC,GAAS7E,EAAK,SAAS,CAAC,EAAE,GACxB8E,GAAQ9E,EAAK,SAAS,IAAK+E,IAAQ,CACvC,IAAMC,GAAQ1F,EAAI,GAAGyF,GAAI,EAAE,MAAM,EAC3BE,GAAU3F,EAAI,GAAGyF,GAAI,EAAE,QAAQ,EAC/BlC,GAAShD,EAAG,SAAU,CAAE,KAAM,SAAU,MAAO,SAAU,KAAM,MAAO,GAAImF,GAAO,gBAAiBC,GAAS,YAAaF,GAAI,EAAG,EAAG,GAAG5E,EAAS4E,GAAI,KAAMA,GAAI,KAAK,CAAC,EAElKG,GAAQrF,EAAG,MAAO,CAAE,MAAO,cAAe,KAAM,WAAY,GAAIoF,GAAS,kBAAmBD,EAAM,EAAG5B,EAAK2B,GAAI,SAAU,EAAG,CAAE,QAAS,EAAG,OAAQzB,EAAM,OAAQ,OAAQA,EAAM,MAAO,CAAC,CAAC,EAC5L,OAAAT,GAAO,iBAAiB,QAAS,IAAM,CACrC+B,GAASC,GAASE,GAAI,GACtBI,GAAOzG,EAAK,SAAS,CAAC,CACxB,CAAC,EACDiG,EAAK,OAAO9B,EAAM,EACX,CAAE,IAAAkC,GAAK,OAAAlC,GAAQ,MAAAqC,EAAM,CAC9B,CAAC,EACD,OAAAP,EAAK,iBAAiB,UAAY7C,IAAU,CAC1C,IAAMG,GAAQ6C,GAAM,OAAQM,IAAM,CAACA,GAAE,OAAO,MAAM,EAC5CC,GAAKpD,GAAM,UAAWmD,IAAMA,GAAE,IAAI,KAAOP,EAAM,EAC/CS,GAAO,CAAE,WAAY,EAAG,UAAW,GAAI,KAAM,CAACD,GAAI,IAAKpD,GAAM,OAAS,EAAIoD,EAAG,EAAEvD,GAAM,GAAG,EAC9F,GAAIwD,KAAS,QAAaD,KAAO,GAAI,OACrCvD,GAAM,eAAe,EACrB,IAAMyD,GAAM/E,EAAK,aAAa,KAAK,IAAM,QAAUsB,GAAM,MAAQ,cAAgBA,GAAM,MAAQ,aACzF2C,GAAOxC,IAAOoD,IAAME,GAAM,CAACD,GAAOA,IAAQrD,GAAM,QAAUA,GAAM,MAAM,EAC5E2C,GAASC,GAASJ,GAAK,IAAI,GAC3BU,GAAOzG,EAAK,SAAS,CAAC,EACtB+F,GAAK,OAAO,MAAM,CACpB,CAAC,EACDlB,EAAI,OAAOoB,EAAM,GAAGG,GAAM,IAAKM,IAAMA,GAAE,KAAK,CAAC,EAC7ChG,EAAS,KAAK,IAAM,CAClBmE,EAAI,OAAS7E,EAAK,KAAKsB,EAAK,EAAE,EAAE,UAChC,IAAMiC,GAAQ6C,GAAM,OAAQM,IAAM,CAAC1G,EAAK,KAAK0G,GAAE,IAAI,EAAE,EAAE,SAAS,EACnDR,KAAW,MAAQ3C,GAAM,KAAMmD,IAAMA,GAAE,IAAI,KAAOR,EAAM,EAC3DC,GAASD,GACV3C,GAAM,SAAQ4C,GAAS5C,GAAM,CAAC,EAAE,IAAI,IAC7C,QAAWmD,MAAKN,GAAO,CACrB,IAAMU,GAAWJ,GAAE,IAAI,KAAOP,GAC9BO,GAAE,OAAO,OAAS,CAACnD,GAAM,SAASmD,EAAC,EACnCA,GAAE,OAAO,aAAa,gBAAiB,OAAOI,EAAQ,CAAC,EACvDJ,GAAE,OAAO,SAAWI,GAAW,EAAI,GACnCJ,GAAE,MAAM,OAAS,CAACI,EACpB,CACF,CAAC,EACMjC,CACT,CAEA,SAASK,EAAK5D,EAAkBsD,EAA2B,CACzD,OAAQtD,EAAK,KAAM,CACjB,IAAK,QACH,OAAOY,EAAUZ,EAAMsD,EAAM,MAAM,EACrC,IAAK,SACH,OAAOV,EAAW5C,CAAI,EACxB,IAAK,OACH,OAAO+C,EAAS/C,CAAI,EACtB,IAAK,OACH,OAAOiD,EAASjD,CAAI,EACtB,IAAK,UACH,OAAOgE,EAAYhE,EAAMsD,CAAK,EAChC,IAAK,OACH,OAAOoB,EAAS1E,EAAMsD,CAAK,EAC7B,IAAK,UACL,IAAK,SACL,IAAK,QACH,OAAOmC,EAAUzF,CAAI,CACzB,CACF,CAGA,SAASyF,EAAUzF,EAAyD,CAC1E,IAAM2C,EACJ3C,EAAK,OAAS,UAAYH,EAAG,KAAM,CAAE,MAAO,aAAc,YAAaG,EAAK,EAAG,CAAC,EAC9EA,EAAK,OAAS,SAAWH,EAAG,MAAO,CAAE,MAAO,qBAAsB,cAAe,OAAQ,YAAaG,EAAK,EAAG,CAAC,EAC/G0F,EAAO1F,CAAI,EACf,OAAIA,EAAK,OAAS,WAAaA,EAAK,SAAS2C,EAAQ,MAAM,YAAY,YAAa,OAAO3C,EAAK,OAAO,CAAC,EACxG0C,EAASC,EAAS3C,EAAK,EAAE,EAClB2C,CACT,CAGA,SAAS+C,EAAO1F,EAA8B,CAC5C,IAAM2F,EAAQ9F,EAAG,MAAO,CAAE,MAAO,WAAY,IAAKG,EAAK,IAAK,IAAKA,EAAK,IAAK,QAAS,MAAO,CAAC,EACtF4F,EAAO5F,EAAK,MAAQ,0BAA0B,KAAKA,EAAK,IAAI,EAAIA,EAAK,KAAO,OAC5E2C,EAAU9C,EACd,SACA,CAAE,MAAO,qBAAsB,YAAaG,EAAK,GAAI,aAAcA,EAAK,KAAM,EAC9E4F,EAAO/F,EAAG,IAAK,CAAE,KAAA+F,EAAM,OAAQ,SAAU,IAAK,qBAAsB,EAAGD,CAAK,EAAIA,EAChF,GAAI3F,EAAK,QAAU,CAACH,EAAG,aAAc,CAAE,MAAO,YAAa,EAAGG,EAAK,OAAO,CAAC,EAAI,CAAC,CAClF,EACMyD,GAAQ,OAAOzD,EAAK,OAAU,SAAW,GAAGA,EAAK,KAAK,KAAOA,EAAK,OAAS,CAAE,MAAO,QAAS,OAAQ,QAAS,MAAO,QAAS,KAAM,MAAO,EAAEA,EAAK,KAAK,EAC7J,OAAIyD,IAAOd,EAAQ,MAAM,YAAY,mBAAoBc,EAAK,EACvDd,CACT,CAKA,IAAIF,EAAShF,EAAQ,WAAa,GAE5BoI,EAAapI,EAAQ,WAAaoC,EAAG,SAAU,CAAE,KAAM,SAAU,MAAO,0BAA2B,CAAC,EAAI,KAC9GgG,GAAY,iBAAiB,QAAS,SAAY,CAChD,GAAKpD,EAUEA,EAAS,OAVH,CACX,GAAI/D,EAAK,SAAS,EAAE,MAAM,QAEpB,CADU,MAAMA,EAAK,KAAK,EAClB,CACLA,EAAK,SAAS,EAAE,aAAaoH,GAASC,GAAUrH,EAAK,SAAS,CAAC,CAAC,EACrEsH,GAAkB,EAClB,MACF,CAEFvD,EAAS,EACX,CACAjC,EAAK,gBAAgB,gBAAiBiC,CAAM,EAC5C0C,GAAOzG,EAAK,SAAS,CAAC,CACxB,CAAC,EACD8B,EAAK,gBAAgB,gBAAiBiC,CAAM,EAC5CrD,EAAS,KAAK,IAAM,CACbyG,IACLA,EAAW,YAAcpD,EAAS5D,EAAO,KAAOA,EAAO,KACvDgH,EAAW,UAAU,OAAO,oBAAqBpD,CAAM,EACzD,CAAC,EAGD,IAAMwD,EAAapG,EAAG,MAAO,CAAE,MAAO,YAAa,KAAM,SAAU,YAAa,QAAS,CAAC,EACpFqG,EAAQrG,EAAG,SAAU,CAAE,KAAM,SAAU,MAAO,oCAAqC,OAAQ,EAAG,EAAGhB,EAAO,KAAK,EACnHqH,EAAM,iBAAiB,QAAS,IAAG,CAAQC,GAAa,EAAC,EACzD,IAAMC,EAASvG,EAAG,MAAO,CAAE,MAAO,eAAgB,EAAGoG,EAAYC,CAAK,EAChEG,EAAU,IAAOpI,EAAK,KAAK,OAAS,YAAcY,EAAO,QAAUA,EAAO,SAEhF,SAASkH,GAAU/D,EAA0B,CAC3C,IAAMsE,EAAkB,CAAC,EACzB,QAAW3G,KAAO,OAAO,KAAKqC,EAAM,MAAM,EAAG,CAC3C,IAAMuE,GAAQ5G,EAAI,MAAM,GAAG,EAAE,CAAC,EAExBM,GADQO,EAAK,cAAc,yBAAyB+F,EAAK,8BAA8B,GACzE,YAAY,aAAetI,EAAK,OAAOsI,EAAK,GAAG,OAASA,GACvED,EAAM,SAASrG,EAAI,GAAGqG,EAAM,KAAKrG,EAAI,CAC5C,CACA,IAAMuG,EAAU,CAAC,GAAGhG,EAAK,iBAAiB,mCAAmC,CAAC,EAAE,IAAKU,GAAUA,EAAM,YAAY,aAAe,EAAE,EAClI,OAAAoF,EAAM,KAAK,CAACG,EAAGC,MAAOF,EAAQ,QAAQC,CAAC,EAAI,GAAK,MAAaD,EAAQ,QAAQE,EAAC,EAAI,GAAK,IAAS,EACzFJ,EAAM,OAAS9G,EAAKX,EAAO,YAAa,CAAE,KAAMwH,EAAQ,EAAG,OAAQC,EAAM,KAAK,IAAI,CAAE,CAAC,EAAID,EAAQ,CAC1G,CACA,IAAIM,GACJvH,EAAS,KAAM4C,GAAU,CACvB,IAAM4E,EAAU5E,EAAM,YAChB5B,EACJ4B,EAAM,SAAW,SAAWnD,EAAO,OACjCmD,EAAM,SAAW,QAAUnD,EAAO,MAClCmD,EAAM,SAAW,UAAYnD,EAAO,QACpCmD,EAAM,SAAW,SAAW4E,EAAWA,EAAQ,OAAS,SAAWb,GAAU/D,CAAK,EAAI4E,EAAQ,OAAS,QAAUA,EAAQ,QAAUP,EAAQ,EAC3IrE,EAAM,SAAW,QAAUA,EAAM,OAAS,GAC1C,GAEJ6E,GAAQZ,EAAY,YAAajE,EAAM,SAAW,SAAW4E,EAAU,MAAQ,QAAQ,EACvFxE,GAAQ6D,EAAY7F,CAAI,EACxB8B,GAAUgE,EAAO,EAAElE,EAAM,SAAW,SAAW4E,GAAS,OAAS,QAAQ,EACzEX,EAAW,UAAU,OAAO,kBAAmBjE,EAAM,SAAW,OAAO,EACvEiE,EAAW,UAAU,OAAO,kBAAmBjE,EAAM,SAAW,OAAO,EAEnEvE,EAAQ,aAAe,UACzB,aAAakJ,EAAU,EACvBP,EAAO,OAAS,CAAChG,EACb4B,EAAM,SAAW,UAAS2E,GAAa,WAAW,IAAOP,EAAO,OAAS,GAAO,IAAI,GAE5F,CAAC,EAGD,IAAMU,GAAcjH,EAAG,SAAU,CAAE,KAAM,SAAU,MAAO,oBAAqB,EAAGhB,EAAO,KAAK,EAC9FiI,GAAY,iBAAiB,QAAS,IAAG,CAAQX,GAAa,EAAC,EAC/D,IAAMY,GAASlH,EAAG,MAAO,CAAE,MAAO,4BAA6B,KAAM,QAAS,OAAQ,EAAG,EAAGA,EAAG,OAAQ,CAAE,MAAO,gBAAiB,EAAGhB,EAAO,OAAO,EAAGiI,EAAW,EAE1JE,EAAYnH,EAAG,MAAO,CAAE,MAAO,cAAe,KAAM,QAAS,YAAa,WAAY,CAAC,EAC7F,SAASiG,GAAS1F,EAAc,CAC9B4G,EAAU,YAAc,GACxB,WAAW,IAAOA,EAAU,YAAc5G,EAAO,CAAC,CACpD,CAEA,IAAI6G,GAAwC,KAC5C7H,EAAS,KAAM4C,GAAU,CACnBA,EAAM,cAAgBiF,KAC1BA,GAAcjF,EAAM,YACpB+E,GAAO,OAASE,IAAa,OAAS,UACjCA,KACDA,GAAY,OAAS,OAAatG,GAAcsG,GAAY,QAAS,EAAK,EACrEA,GAAY,OAAS,SAAUnB,GAASC,GAAU/D,CAAK,CAAC,EACxDiF,GAAY,OAAS,SAASnB,GAASmB,GAAY,OAAO,GACrE,CAAC,EAED,IAAMC,GAAQrH,EAAG,MAAO,CAAE,MAAO,WAAY,OAAQ,EAAG,CAAC,EACnDsH,GAAYtH,EAAG,MAAM,EACrBuH,GAAUvH,EAAG,SAAU,CAAE,KAAM,SAAU,MAAO,6BAA8B,EAAGhB,EAAO,OAAO,EAC/FwI,GAAexH,EAAG,SAAU,CAAE,KAAM,SAAU,MAAO,0BAA2B,EAAGhB,EAAO,YAAY,EAC5GuI,GAAQ,iBAAiB,QAAS,IAAM1I,EAAK,aAAa,CAAC,EAC3D2I,GAAa,iBAAiB,QAAS,IAAM3I,EAAK,aAAa,CAAC,EAChEwI,GAAM,OAAOC,GAAWC,GAASC,EAAY,EAC7CjI,EAAS,KAAM4C,GAAU,CACvBE,GAAUgF,GAAO,CAAClF,EAAM,KAAK,EACzBA,EAAM,QAAOmF,GAAU,YAAc3H,EAAKX,EAAO,WAAY,CAAE,KAAM,IAAI,KAAKmD,EAAM,MAAM,OAAO,EAAE,eAAe,CAAE,CAAC,EAC3H,CAAC,EAED,SAASgE,IAAoB,CAC3B,IAAMsB,EAAU9G,EAAK,cAA2B,uBAAuB,EACvE,GAAI,CAAC8G,EAAS,OACd,QAASC,EAASD,EAAQ,QAAqB,oBAAoB,EAAGC,EAAQA,EAASA,EAAO,eAAe,QAAqB,oBAAoB,GAAK,KACzJxD,EAAM,IAAIwD,CAAM,IAAI,EAGtB,GAAI,CAACD,EAAQ,cAAc,IAAI,YAAY,mBAAoB,CAAE,WAAY,EAAK,CAAC,CAAC,EAAG,QACxEA,EAAQ,QAAQ,iCAAiC,EAAIA,EAAUA,EAAQ,cAA2B,iCAAiC,IAC1I,MAAM,CAChB,CAEA,IAAME,GAAO3H,EAAG,MAAO,CAAE,MAAO,UAAW,OAAQ,EAAG,EAAGA,EAAG,IAAK,CAAE,MAAO,eAAgB,EAAGhB,EAAO,SAAS,CAAC,EACxG4I,GAAQ5H,EAAG,SAAU,CAAE,KAAM,SAAU,MAAO,WAAY,EAAGhB,EAAO,aAAa,EACvF2I,GAAK,OAAOC,EAAK,EACjB,IAAMpD,GAAUxE,EAAG,MAAO,CAAE,MAAO,YAAa,CAAC,EAEjD,eAAesG,IAAe,CAE5B,GAAI,CADU,MAAMzH,EAAK,KAAK,EAClB,CAELA,EAAK,SAAS,EAAE,aAAaoH,GAASC,GAAUrH,EAAK,SAAS,CAAC,CAAC,EACrEsH,GAAkB,EAClB,MACF,CACI/H,EAAK,KAAK,OAAS,cACrBoG,GAAQ,OAAS,GACjBmD,GAAK,OAAS,GAElB,CACAC,GAAM,iBAAiB,QAAS,IAAM,CACpC/I,EAAK,MAAM,EACX2F,GAAQ,OAAS,GACjBmD,GAAK,OAAS,EAChB,CAAC,EAED,SAASE,IAA+B,CACtC,GAAI,CAACzJ,EAAK,OAAS,CAACA,EAAK,YAAa,OAAO,KAC7C,IAAM0J,EAAO9H,EAAG,SAAU,CAAE,MAAO,cAAe,CAAC,EACnD,OAAI5B,EAAK,OAAO0J,EAAK,OAAO9H,EAAG,KAAM,CAAE,MAAO,eAAgB,EAAG5B,EAAK,KAAK,CAAC,EACxEA,EAAK,aAAa0J,EAAK,OAAO9H,EAAG,IAAK,CAAE,MAAO,qBAAsB,EAAG5B,EAAK,WAAW,CAAC,EACtF0J,CACT,CAIA,SAASC,GAAe5H,EAA2D,CACjF,IAAMuD,EAAM1D,EAAG,MAAO,CAAE,MAAO,cAAe,YAAaG,EAAK,EAAG,EAAG,GAAGA,EAAK,SAAS,IAAK2D,IAAUC,EAAKD,GAAOE,EAAI,EAAI,CAAC,CAAC,CAAC,EACvHgE,EAAShI,EAAG,SAAU,CAAE,KAAM,SAAU,MAAO,6BAA8B,EAAG5B,EAAK,KAAK,OAAS,YAAcY,EAAO,OAASA,EAAO,IAAI,EAC5IiJ,EAAUjI,EAAG,MAAO,CAAE,MAAO,2BAA4B,EAAGuG,EAAQyB,CAAM,EAChF,GAAI5J,EAAK,KAAK,OAAS,SAAU,CAE/B,IAAM8J,GAAUlI,EAAG,SAAU,CAAE,KAAM,SAAU,MAAO,WAAY,EAAGhB,EAAO,OAAO,EACnFkJ,GAAQ,iBAAiB,QAAS,IAAMrJ,EAAK,MAAM,CAAC,EACpDoJ,EAAQ,aAAaC,GAASF,CAAM,EACpCzI,EAAS,KAAM4C,IAAU,CACvB,IAAMgG,GAAQhG,GAAM,MAAM,OAAS,GAAKA,GAAM,SAAW,UAAY,CAACS,EACtEP,GAAU2F,EAAQ,CAACG,EAAK,EACxB9F,GAAU6F,GAAS,CAACC,EAAK,CAC3B,CAAC,CACH,MAAO5I,EAAS,KAAK,IAAM8C,GAAU2F,EAAQpF,CAAM,CAAC,EAEpD,OADIoD,GAAYiC,EAAQ,QAAQjC,CAAU,EACtCpI,EAAQ,cAAgB,GAAcoC,EAAG,MAAO,CAAC,EAAG0D,CAAG,EACvDtF,EAAK,kBAAoB,OAC3B6J,EAAQ,UAAU,IAAI,gBAAgB,EAC/BjI,EAAG,MAAO,CAAC,EAAGiI,EAASvE,CAAG,GAE5B1D,EAAG,MAAO,CAAC,EAAG0D,EAAKuE,CAAO,CACnC,CAEA,SAASG,EAAajI,EAA+B,CACnD,IAAMuD,EAAM1D,EAAG,MAAO,CAAE,MAAO,YAAa,YAAaG,EAAK,EAAG,CAAC,EAC5DkI,EAAerI,EAAG,MAAO,CAAE,MAAO,kBAAmB,CAAC,EACtDsI,EAAMtI,EAAG,MAAM,EACrB0D,EAAI,OAAO1D,EAAG,MAAO,CAAE,MAAO,aAAc,EAAGqI,EAAcrI,EAAG,MAAO,CAAE,MAAO,iBAAkB,EAAGsI,CAAG,CAAC,CAAC,EAE1G,IAAMxD,GAAO3E,EAAK,UAAYH,EAAG,KAAM,CAAE,MAAO,eAAgB,CAAC,EAAI,KAC/DuI,GAAc,IAAI,IACxB,GAAIzD,GAAM,CACR,QAAW0D,MAAQrI,EAAK,SAAU,CAChC,IAAMsI,GAAKzI,EAAG,SAAU,CAAE,KAAM,SAAU,MAAO,cAAe,EAAG,GAAGM,EAASkI,GAAK,KAAMA,GAAK,KAAK,CAAC,EACrGC,GAAG,iBAAiB,QAAS,IAAM,CAC7B5J,EAAK,KAAK2J,GAAK,EAAE,EAAGE,GAAU,EAC7BvC,GAAkB,CACzB,CAAC,EACDoC,GAAY,IAAIC,GAAK,GAAIC,EAAE,EAC3B3D,GAAK,OAAO9E,EAAG,KAAM,CAAC,EAAGyI,EAAE,CAAC,CAC9B,CACA/E,EAAI,OAAO1D,EAAG,MAAO,CAAE,MAAO,WAAY,aAAchB,EAAO,KAAM,EAAG8F,EAAI,CAAC,CAC/E,CACA,IAAM6D,GAASxI,EAAK,SAAS,IAAKqI,IAAS,CACzC,IAAMnD,GAAQrF,EAAG,UAAW,CAAE,MAAO,UAAW,YAAawI,GAAK,GAAI,kBAAmB/I,EAAI,GAAG+I,GAAK,EAAE,QAAQ,CAAE,CAAC,EAClH,OAAAnD,GAAM,OAAOrF,EAAG,KAAM,CAAE,MAAO,gBAAiB,GAAIP,EAAI,GAAG+I,GAAK,EAAE,QAAQ,CAAE,EAAG,GAAGlI,EAASkI,GAAK,KAAMA,GAAK,KAAK,CAAC,CAAC,EAC9GA,GAAK,aAAanD,GAAM,OAAOrF,EAAG,IAAK,CAAE,MAAO,wBAAyB,EAAGwI,GAAK,WAAW,CAAC,EAEjGnD,GAAM,OAAO9B,EAAKiF,GAAK,SAAU,EAAGxE,EAAI,EAAK,CAAC,CAAC,EAC/CN,EAAI,OAAO2B,EAAK,EACT,CAAE,KAAAmD,GAAM,MAAAnD,EAAM,CACvB,CAAC,EACKuD,GAAO5I,EAAG,SAAU,CAAE,KAAM,SAAU,MAAO,WAAY,EAAGG,EAAK,WAAanB,EAAO,IAAI,EACzF6J,GAAO7I,EAAG,SAAU,CAAE,KAAM,SAAU,MAAO,0BAA2B,EAAGhB,EAAO,IAAI,EACtF8J,GAAU9I,EAAG,SAAU,CAAE,KAAM,SAAU,MAAO,6BAA8B,CAAC,EACrF0D,EAAI,OAAO1D,EAAG,MAAO,CAAE,MAAO,eAAgB,EAAG4I,GAAM5I,EAAG,OAAQ,CAAE,MAAO,WAAY,CAAC,EAAGuG,EAAQsC,GAAMC,EAAO,CAAC,EACjHF,GAAK,iBAAiB,QAAS,IAAM,CAC/B/J,EAAK,KAAK,GAAG6J,GAAU,CAC7B,CAAC,EACDG,GAAK,iBAAiB,QAAS,IAAM,CAC/BhK,EAAK,KAAK,GAAG6J,GAAU,CAC7B,CAAC,EACD,IAAMK,GAAS,IAAM,CACnB,IAAMC,GAAQnK,EAAK,MAAM,EACzB,OAAOmK,GAAM,QAAQnK,EAAK,SAAS,EAAE,MAAQ,EAAE,IAAMmK,GAAM,OAAS,CACtE,EACAC,EAAgB,SAAY,CAC1B,GAAIF,GAAO,EAAG,OAAOzC,GAAa,EAC9BzH,EAAK,KAAK,EAAG6J,GAAU,EACtBvC,GAAkB,CACzB,EACA,SAASuC,IAAY,CACHC,GAAO,KAAMpD,IAAMA,GAAE,KAAK,KAAO1G,EAAK,SAAS,EAAE,IAAI,GAC5D,MAAM,cAA2B,uCAAuC,GAAG,MAAM,CAC5F,CACA,OAAAU,EAAS,KAAM4C,IAAU,CACvB,IAAM6G,GAAQnK,EAAK,MAAM,EACnBqK,GAAQ,KAAK,IAAI,EAAGF,GAAM,QAAQ7G,GAAM,MAAQ,EAAE,CAAC,EACzDkG,EAAa,YAAc1I,EAAKX,EAAO,OAAQ,CAAE,EAAGkK,GAAQ,EAAG,MAAOF,GAAM,MAAO,CAAC,EACpFV,EAAI,MAAM,MAAQ,IAAKY,GAAQ,GAAK,KAAK,IAAI,EAAGF,GAAM,MAAM,EAAK,GAAG,IACpE,OAAW,CAAE,KAAAR,GAAM,MAAAnD,EAAM,IAAKsD,GAAQtD,GAAM,OAASmD,GAAK,KAAOrG,GAAM,KACvE,IAAMgH,GAAOD,KAAUF,GAAM,OAAS,EACtCJ,GAAK,OAASM,KAAU,EACxBL,GAAK,OAASM,IAAQ,CAAChJ,EAAK,SAAS,KAAMqI,IAASA,GAAK,KAAOrG,GAAM,IAAI,GAAG,SAC7E2G,GAAQ,YAAcK,GAAOhJ,EAAK,aAAenB,EAAO,OAASmB,EAAK,WAAanB,EAAO,KAC1F,OAAW,CAACU,GAAI+I,EAAE,IAAKF,GAAa,CAClC,IAAM/C,GAAKwD,GAAM,QAAQtJ,EAAE,EAC1B+I,GAAG,cAA8B,OAASjD,KAAO,GAClDiD,GAAG,UAAU,OAAO,eAAgBjD,KAAO,IAAMA,GAAK0D,EAAK,EAC3DT,GAAG,UAAU,OAAO,kBAAmBtG,GAAM,QAAQ,SAASzC,EAAE,CAAC,EAC7DA,KAAOyC,GAAM,KAAMsG,GAAG,aAAa,eAAgB,MAAM,EACxDA,GAAG,gBAAgB,cAAc,CACxC,CACF,CAAC,EACM/E,CACT,CAEA,SAAS0F,EAAYjJ,EAA8B,CACjD,IAAMkJ,EAAUrJ,EAAG,MAAO,CAAE,MAAO,gBAAiB,YAAaG,EAAK,EAAG,CAAC,EACpE8H,EAAUjI,EAAG,MAAO,CAAE,MAAO,YAAa,CAAC,EAC3CsJ,EAAOtJ,EAAG,SAAU,CAAE,KAAM,SAAU,MAAO,6BAA8B,EAAGhB,EAAO,IAAI,EACzFkJ,GAAUlI,EAAG,SAAU,CAAE,KAAM,SAAU,MAAO,WAAY,EAAGhB,EAAO,OAAO,EACnFkJ,GAAQ,iBAAiB,QAAS,IAAMrJ,EAAK,MAAM,CAAC,EAEpD,IAAM0K,GAASnL,EAAK,kBAAoB,SAClCoL,GAAOxJ,EAAG,MAAO,CAAE,MAAO,yCAA0C,CAAC,EACvEpC,EAAQ,cAAgB,GAAOqK,EAAQ,OAAO,IAAI9H,EAAK,SAAW,CAAC,GAAG,IAAI4C,CAAU,CAAC,EAChFwG,IACPtB,EAAQ,OAAO,IAAI9H,EAAK,SAAW,CAAC,GAAG,IAAI4C,CAAU,CAAC,EACtDyG,GAAK,OAAOjD,EAAQ2B,GAASoB,CAAI,GAC5BrB,EAAQ,OAAOqB,EAAMpB,GAAS,IAAI/H,EAAK,SAAW,CAAC,GAAG,IAAI4C,CAAU,EAAGwD,CAAM,EAEhFP,GAAcpI,EAAQ,cAAgB,IAAOqK,EAAQ,QAAQjC,CAAU,EAC3EzG,EAAS,KAAM4C,IAAU,CACvB,IAAMgG,GAAQhG,GAAM,MAAM,OAAS,GAAKA,GAAM,SAAW,UAAY,CAACS,EACtE0G,EAAK,OAAS,CAACnB,GACfD,GAAQ,OAAS,CAACC,EACpB,CAAC,EACD,IAAMsB,GAASzJ,EAAG,MAAO,CAAE,MAAO,WAAY,EAAGiI,CAAO,EAClDyB,GAAavJ,EAAK,WAAW,WAAa,QAC5CA,EAAK,WAAa,CAACuJ,IAAYD,GAAO,OAAOE,EAAUxJ,EAAK,SAAS,CAAC,EAE1E,IAAMyJ,GAAO5J,EAAG,MAAO,CAAE,MAAO,SAAU,CAAC,EAC3C,GAAIG,EAAK,OAAQ,CACf,IAAM0J,GAAS7J,EAAG,MAAO,CAAE,MAAO,qBAAqBG,EAAK,OAAO,MAAQ,OAAO,GAAI,YAAaA,EAAK,OAAO,EAAG,EAAGA,EAAK,OAAO,KAAK,EACtI0C,EAASgH,GAAQ1J,EAAK,OAAO,EAAE,EAE/ByJ,GAAK,OAAO5J,EAAG,MAAO,CAAE,MAAO,iBAAkB,EAAG6J,EAAM,CAAC,CAC7D,CACA,GAAI1J,EAAK,aAAa,OAAQ,CAC5B,IAAM2J,GAAQ9J,EAAG,MAAO,CAAE,MAAO,UAAW,CAAC,EAC7C,QAAW+J,MAAQ5J,EAAK,YAAa,CACnC,IAAME,GAAQL,EAAG,OAAQ,CAAE,MAAO,eAAgB,CAAC,EAC7CQ,GAAOC,GAAS5C,EAAKkM,GAAK,KAAMnM,EAAQ,KAAK,EAC7C8C,GAAQV,EAAG,OAAQ,CAAE,MAAO,eAAgB,EAAGK,GAAOL,EAAG,OAAQ,CAAE,MAAO,eAAgB,EAAG+J,GAAK,KAAK,CAAC,EACxG/G,GAAShD,EAAG,SAAU,CAAE,KAAM,SAAU,MAAO,UAAW,YAAa+J,GAAK,EAAG,EAAG,GAAIvJ,GAAO,CAACA,GAAME,EAAK,EAAI,CAACA,EAAK,CAAE,EAC3HsC,GAAO,iBAAiB,QAAS,IAAG,CAAQnE,EAAK,UAAUkL,GAAK,EAAE,EAAC,EACnExK,EAAS,KAAM4C,IAAU,CACvBa,GAAO,OAASnE,EAAK,KAAKkL,GAAK,EAAE,EAAE,UACnC,IAAMlG,GAAQkG,GAAK,MAAQ5H,GAAM,OAAO4H,GAAK,KAAK,EAAI,KACtD1J,GAAM,YAAcwD,IAAU,KAA8B,GAAK,OAAOA,EAAK,CAC/E,CAAC,EACDiG,GAAM,OAAO9G,EAAM,CACrB,CACA4G,GAAK,OAAOE,EAAK,CACnB,CACA,QAAWE,MAAS7J,EAAK,QAAU,CAAC,EAAG,CACrC,IAAMuD,GAAM1D,EAAG,MAAO,CAAE,MAAO,oBAAoBgK,GAAM,MAAQ,MAAM,GAAI,KAAM,SAAU,YAAaA,GAAM,EAAG,EAAGhK,EAAG,OAAQ,CAAE,MAAO,kBAAmB,EAAGgK,GAAM,OAAO,CAAC,EAC5K,GAAIA,GAAM,YAAa,CAErB,IAAIC,GAAY,GACVC,GAAQlK,EAAG,SAAU,CAAE,KAAM,SAAU,MAAO,iBAAkB,aAAchB,EAAO,OAAQ,EAAG,MAAG,EACzGkL,GAAM,iBAAiB,QAAS,IAAM,CACpCD,GAAY,GACZvG,GAAI,OAAS,EACf,CAAC,EACDA,GAAI,OAAOwG,EAAK,EAChB3K,EAAS,KAAK,IAAM,CAClBmE,GAAI,OAASuG,IAAapL,EAAK,KAAKmL,GAAM,EAAE,EAAE,SAChD,CAAC,CACH,MAAOnH,EAASa,GAAKsG,GAAM,EAAE,EAC7BJ,GAAK,OAAOlG,EAAG,CACjB,CACA,GAAIvD,EAAK,QAAQ,OAAQ,CACvB,IAAMgK,GAASnK,EAAG,MAAO,CAAE,MAAO,WAAY,CAAC,EAC/C,QAAWoK,MAASjK,EAAK,OAAQ,CAC/B,IAAMkK,GAAOrK,EAAG,OAAQ,CAAE,MAAO,oBAAoBoK,GAAM,MAAQ,OAAO,GAAI,YAAaA,GAAM,EAAG,EAAG,GAAG9J,EAAS8J,GAAM,KAAMA,GAAM,KAAK,CAAC,EAC3IvH,EAASwH,GAAMD,GAAM,EAAE,EACvBD,GAAO,OAAOE,EAAI,CACpB,CACA9K,EAAS,KAAK,IAAM,CAClB4K,GAAO,OAAS,CAAC,GAAGA,GAAO,QAAQ,EAAE,MAAOE,IAAUA,GAAqB,MAAM,CACnF,CAAC,EACDT,GAAK,OAAOO,EAAM,CACpB,CACA,GAAIhK,EAAK,MAAO,CACd,IAAMmK,GAAQtK,EAAG,MAAO,CAAE,MAAO,UAAW,CAAC,EACzCG,EAAK,MAAM,OAAO,QAAQmK,GAAM,OAAOtK,EAAG,MAAO,CAAE,MAAO,gBAAiB,EAAG,GAAGG,EAAK,MAAM,MAAM,IAAKoK,IAASxJ,EAAUwJ,EAAI,CAAC,CAAC,CAAC,EACrID,GAAM,OAAOvJ,EAAU,CAAE,KAAM,QAAS,GAAI,SAAU,MAAOZ,EAAK,MAAM,MAAO,YAAaA,EAAK,MAAM,WAAY,CAAC,CAAC,EACjHA,EAAK,MAAM,eAAemK,GAAM,OAAOvJ,EAAU,CAAE,KAAM,QAAS,GAAI,YAAa,MAAOZ,EAAK,MAAM,aAAc,CAAC,CAAC,EACrHA,EAAK,MAAM,OAAO,QAAQmK,GAAM,OAAOtK,EAAG,MAAO,CAAE,MAAO,gBAAiB,EAAG,GAAGG,EAAK,MAAM,MAAM,IAAKoK,IAASxJ,EAAUwJ,EAAI,CAAC,CAAC,CAAC,EACrI,IAAMC,GAAMxK,EAAG,MAAO,CAAE,MAAO,cAAe,EAAGsK,EAAK,EACtD,GAAInK,EAAK,MAAM,YAAa,CAC1B,IAAMsK,GAAS1J,EAAU,CAAE,KAAM,QAAS,GAAI,UAAW,MAAOZ,EAAK,MAAM,WAAY,CAAC,EACxFsK,GAAO,UAAU,IAAI,WAAW,EAChCD,GAAI,OAAOC,EAAM,CACnB,CACAb,GAAK,OAAOY,EAAG,CACjB,CACIrK,EAAK,WAAauJ,IAAYE,GAAK,OAAO5J,EAAG,MAAO,CAAE,MAAO,oBAAqB,EAAG2J,EAAUxJ,EAAK,SAAS,CAAC,CAAC,EACnHyJ,GAAK,OAAOrG,EAAKpD,EAAK,SAAU,EAAG6D,EAAI,EAAK,CAAC,CAAC,EAC1CuF,IAAU3L,EAAQ,cAAgB,KACpCgM,GAAK,OAAOJ,EAAI,EAChBjK,EAAS,KAAM4C,IAAU,CACvBqH,GAAK,OAASrH,GAAM,MAAM,SAAW,GAAK,CAACiE,EAAW,WACxD,CAAC,GAGH,IAAMsE,GAAS1K,EAAG,MAAO,CAAE,MAAO,iBAAkB,EAAG4J,EAAI,EAC3D,OAAIzJ,EAAK,YACPuK,GAAO,UAAU,IAAI,aAAa,EAClCA,GAAO,OAAO1K,EAAG,QAAS,CAAE,MAAO,SAAU,EAAGoD,EAASjD,EAAK,SAAS,CAAC,CAAC,GAE3EkJ,EAAQ,OAAOI,GAAQiB,EAAM,EACtBrB,CACT,CAGA,SAASM,EAAUgB,EAA0D,CAC3E,IAAM3J,EAAM5C,EAAK,OAAOuM,EAAO,KAAK,EAC9BC,EAA2C,CAAE,UAAWD,EAAO,YAAc,EAAK,EACpFA,EAAO,gBAAeC,EAAW,cAAmBD,EAAO,eAC/D,IAAMxK,EAAkB,CAAE,KAAM,QAAS,GAAI,aAAc,MAAOwK,EAAO,MAAO,OAAQ,YAAa,QAASC,CAAW,EACnHpJ,GAASC,GACb,CAAE,KAAA5C,EAAM,KAAM8L,EAAO,MAAO,MAAO3J,EAAK,KAAAb,EAAM,GAAIV,EAAI,WAAW,EAAG,SAAU5B,EAAK,OAAQqB,EAAc,YAAAV,EAAa,OAAAF,EAAQ,QAAAI,CAAQ,EACtId,EAAQ,OACV,EACA,OAAA2B,EAAS,KAAM4C,IACbX,GAAO,OAAO,CAAE,MAAOW,GAAM,OAAOwI,EAAO,KAAK,EAAG,OAAQxI,GAAM,OAAQ,SAAUtD,EAAK,KAAK,YAAY,EAAE,UAAY+D,EAAQ,SAAU,GAAO,QAAS,EAAM,CAAC,CAClK,EACOpB,GAAO,OAChB,CAEA,IAAIyH,EAA8C,KAE5CyB,EAAStM,EAAK,OAChByM,GACJ,GAAIH,EAAO,OAAS,QAASG,GAAOzB,EAAYsB,CAAM,UAC7CA,EAAO,OAAS,SAAUG,GAAOzC,EAAasC,CAAM,UACpDA,EAAO,OAAS,OAAQG,GAAO9C,GAAe,CAAE,GAAI,GAAG2C,EAAO,EAAE,QAAS,SAAU,CAACA,CAAM,CAAE,CAAC,UAC7FA,EAAO,OAAS,OAAQ,CAC/B,IAAM5F,EAAOgG,GAAS,CACpB,KAAA1M,EACA,KAAMsM,EACN,KAAA7L,EACA,WAAYjB,EAAQ,WACpB,IAAAC,EACA,GAAAmC,EACA,OAAAhB,EACA,OAAAV,EACA,KAAAqB,EACA,QAAAkB,EACA,SAAAP,EACA,IAAAb,EACA,MAAO7B,EAAQ,MACf,YAAAY,EACA,aAAcZ,EAAQ,YACxB,CAAC,EACD4B,EAAS,KAAKsF,EAAK,OAAO,EAC1B+F,GAAO/F,EAAK,OACd,MACK+F,GAAO9C,GAAe2C,CAAM,EAEjC,IAAM5C,GAAO4C,EAAO,OAAS,QAAU,KAAO7C,GAAS,EACvDrD,GAAQ,OAAO,GAAIsD,GAAO,CAACA,EAAI,EAAI,CAAC,EAAIZ,GAAQG,GAAOwD,EAAI,EAC3DlK,EAAK,OAAO6D,GAASmD,GAAMR,CAAS,EAEhCvJ,EAAQ,aAAe,SACzB2I,EAAO,UAAU,IAAI,UAAU,EAC/B5F,EAAK,OAAO4F,CAAM,GACT3I,EAAQ,aAAe,QAChC2I,EAAO,UAAU,IAAI,eAAe,EACpC/B,GAAQ,QAAQ+B,CAAM,GAGxB5F,EAAK,iBAAiB,SAAWsB,GAAU,CACzCA,EAAM,eAAe,EACjByI,EAAO,OAAS,SAChBzB,EAAoBA,EAAc,EAC5B3C,GAAa,EACzB,CAAC,EAKD,SAASyE,IAAe,CACtB,IAAM/F,EAASnH,EAAI,cACfmH,GAAUrE,EAAK,SAASqE,CAAM,IAAMA,EAAO,UAAY,SAAWA,EAAO,UAAY,aACvFA,EAAO,cAAc,IAAI,MAAM,SAAU,CAAE,QAAS,EAAK,CAAC,CAAC,CAE/D,CAGA,SAASgG,GAAUC,EAAuC,CACxD,IAAMC,EAAS,CAAC,GAAGvK,EAAK,iBAA8B,WAAW,CAAC,EAAE,OACjE+F,IAAU,CAACA,GAAM,QAAQ,6DAA6D,GAAK,CAACA,GAAM,eAAe,QAAQ,wBAAwB,CACpJ,EACMyE,EAAOF,EAAK,QAAQ,WAAW,EAC/BG,EAAQF,EAAO,MAAMA,EAAO,QAAQC,CAAmB,EAAI,CAAC,EAClE,QAAWzE,MAAS0E,EAAO,CACzB,IAAMC,GAAU3E,GAAM,cAA2B,wIAAwI,EACzL,GAAI2E,GAAS,OAAOA,EACtB,CACA,OAAO,IACT,CAEA1K,EAAK,iBAAiB,UAAYsB,GAAU,CAI1C,GAFIA,EAAM,aAAeA,EAAM,MAAQ,SAAWyI,EAAO,OAAS,QAE7DzI,EAAM,OAAmB,QAAQ,UAAU,EAAG,OACnD,IAAMqJ,EAAO1N,EAAQ,MAAQ,CAAC,EAC9B,GAAIqE,EAAM,SAAWA,EAAM,QAAS,CAGlC,GADIqJ,EAAK,oBAAsB,IAAS1N,EAAQ,cAAgB,IAC3DqE,EAAM,OAAmB,QAAQ,kBAAkB,EAAG,OAC3DA,EAAM,eAAe,EACrB8I,GAAa,EACT9B,EAAoBA,EAAc,EAC5B3C,GAAa,EACvB,MACF,CAEA,GAAIrE,EAAM,kBAAoB,CAACqJ,EAAK,kBAAoBrJ,EAAM,UAAYA,EAAM,OAAQ,OACxF,IAAMgJ,EAAOhJ,EAAM,OACfgJ,EAAK,UAAY,SAAWA,EAAK,UAAY,UAC7CA,EAAK,QAAQ,wBAAwB,GACrC,CAAC,SAAU,SAAU,QAAS,MAAM,EAAE,SAAUA,EAA0B,IAAI,IAClFhJ,EAAM,eAAe,EACrB+I,GAAUC,CAAI,GAAG,MAAM,EACzB,CAAC,EAKD,SAASnK,GAAcwB,EAAiBiJ,EAAa,GAAwB,CAC3E,OAAO,IAAI,QAASC,GAAY,CAC9B,IAAMjL,EAAOP,EAAG,IAAK,CAAE,GAAI,GAAGV,CAAM,UAAW,EAAGgD,CAAO,EACnDmJ,GAASzL,EAAG,SAAU,CAAE,KAAM,SAAU,MAAO,WAAY,EAAGhB,EAAO,MAAM,EAC3E0M,GAAK1L,EAAG,SAAU,CAAE,KAAM,SAAU,MAAO,6BAA8B,EAAGhB,EAAO,EAAE,EACrF2M,GAAS3L,EAAG,MAAO,CAAE,MAAO,YAAa,KAAM,cAAe,aAAc,OAAQ,kBAAmBO,EAAK,EAAG,EAAGA,EAAMP,EAAG,MAAO,CAAE,MAAO,2BAA4B,EAAG,GAAIuL,EAAa,CAACE,GAAQC,EAAE,EAAI,CAACA,EAAE,CAAE,CAAC,EAChNE,GAAW5L,EAAG,MAAO,CAAE,MAAO,oBAAqB,EAAG2L,EAAM,EAC5D9N,GAAM8C,EAAK,cACXkL,GAAShO,GAAI,cACbqM,GAAS4B,IAAoB,CACjCF,GAAS,OAAO,IAEDG,IAA0B,CAAC,CAACA,IAAKA,KAAMlO,GAAI,MAAQkO,GAAE,aAAe,CAACA,GAAE,QAAQ,UAAU,GACrFF,EAAM,EAAIA,GAASlL,EAAK,cAA2B,qCAAqC,IACrG,MAAM,EACZ6K,EAAQM,EAAM,CAChB,EACAL,GAAO,iBAAiB,QAAS,IAAMvB,GAAM,EAAK,CAAC,EACnDwB,GAAG,iBAAiB,QAAS,IAAMxB,GAAM,EAAI,CAAC,EAC9C0B,GAAS,iBAAiB,UAAY3J,IAAU,CAC1CA,GAAM,MAAQ,SAAUiI,GAAM,EAAK,EAClC8B,GAAUL,GAAQ1J,EAAK,CAC9B,CAAC,EACDtB,EAAK,OAAOiL,EAAQ,EACpBF,GAAG,MAAM,CACX,CAAC,CACH,CAIA,SAASpG,GAAOnD,EAAkB,CAChC,QAAWD,KAAU3C,EAAU2C,EAAOC,CAAK,CAC7C,CAEAxE,EAAK,OAAOgD,CAAI,EAChB,IAAMsL,GAAcpN,EAAK,UAAUyG,EAAM,EACzC,OAAAA,GAAOzG,EAAK,SAAS,CAAC,EAClBA,EAAK,SAAS,EAAE,SAAW,QAAaA,EAAK,KAAK,EAE/C,CACL,KAAAA,EACA,QAAS8B,EACT,QAAQuL,EAAM,CACZvL,EAAK,aAAa,eAAgBuL,CAAI,CACxC,EACA,MAAM,MAAO,CACX,IAAMC,EAAQ,MAAMtN,EAAK,KAAK,EAC9B,OAAKsN,GAAOhG,GAAkB,EACvBgG,CACT,EACA,OAAQ,CACN,IAAMxJ,EAAQ9D,EAAK,SAAS,EAC5B,OAAK8D,GAAOwD,GAAkB,EACvBxD,CACT,EACA,YAAYyJ,EAAU,CACpBxJ,EAASwJ,EACTzL,EAAK,gBAAgB,gBAAiBiC,CAAM,EAC5C0C,GAAOzG,EAAK,SAAS,CAAC,CACxB,EACA,WAAY,IAAM+D,EAClB,SAAU,CACRqJ,GAAY,EACZ,QAAW5I,KAAW7D,EAAU6D,EAAQ,EACxC1C,EAAK,OAAO,EACR/B,GAAUC,EAAK,QAAQ,CAC7B,CACF,CACF,CAGA,IAAM6C,GAAW,qGAGXH,GAAgB,IAAI,IAAI,CAAC,UAAW,WAAY,SAAU,QAAS,OAAQ,OAAQ,YAAY,CAAC,ECv+B/F,SAAS8K,GAAYC,EAAgBC,EAA4B,CACtEC,GAASF,CAAM,EAAI,CAAE,GAAGE,GAAS,GAAI,GAAGD,EAAM,QAAS,EACvDE,GAAcH,CAAM,EAAI,CAAE,GAAGG,GAAc,GAAI,GAAGF,EAAM,OAAQ,EAChEG,GAAcJ,CAAM,EAAI,CAAE,GAAGI,GAAc,GAAI,GAAGH,EAAM,MAAO,CACjE,CvFTO,IAAMI,GAAkB,SAGzBC,GAAO,WACb,OAAW,CAACC,EAAQC,CAAK,IAAKF,GAAK,kBAAoB,CAAC,EAAGG,GAAYF,EAAQC,CAAK,EACpF,OAAOF,GAAK",
6
+ "names": ["script_entry_exports", "__export", "ADDRESS_PARTS", "DEFAULT_LABELS", "FIELDIA_CSS", "FIELD_NAME", "FIELD_TYPES", "FORMAT_VERSION", "ICONS", "MESSAGES", "VERSION", "VIEWER_LABELS", "WIDGET_LABELS", "accentShades", "addLanguage", "applyLook", "binaryWidget", "browserPreferences", "builtInWidgets", "charTagsWidget", "checkPage", "checkValue", "compileModifier", "contrast", "countriesIn", "createForm", "createMemoryDataSource", "createWidget", "dayOf", "describeTypes", "displayValue", "drawIcon", "emptyValue", "evaluateModifier", "expressionContext", "facetsToFilter", "fileProblem", "fill", "formatBytes", "formatMoney", "formatNumber", "groupByFields", "hostScheduler", "htmlWidget", "imageWidget", "initialValues", "installListStyles", "installStyles", "isEmpty", "isModifierValid", "isRightToLeft", "isoWeek", "jsonWidget", "keepTabIn", "kindTextField", "labelPlace", "labelWidget", "lineForm", "lineKind", "linesWidget", "linkAddress", "linkCheckboxesWidget", "localizePage", "many2oneWidget", "matchesFilter", "memoryPreferences", "mountViewer", "normalizeNumber", "openFormDialog", "openSearchDialog", "pageWords", "planSection", "progressbarWidget", "propertiesWidget", "readFile", "referenceWidget", "sanitizeHtml", "saveProblemOf", "saveRefused", "scoreOf", "statusbarWidget", "suggestions", "summary", "tagsWidget", "translatePage", "wait", "wideColumns", "withCalendar", "FIELD_NAME", "FIELD_TYPES", "wideColumns", "columns", "FORMAT_VERSION", "isNumber", "value", "tidy", "arithmetic", "operator", "left", "right", "l", "joinable", "r", "negate", "truthy", "roundTo", "digits", "scale", "scaled", "localDay", "date", "pad", "listOf", "call", "first", "extreme", "smaller", "items", "arg", "value", "isNumber", "best", "FUNCTIONS", "args", "x", "digits", "roundTo", "env", "field", "list", "total", "item", "n", "tidy", "truthy", "takesInWords", "name", "least", "most", "evaluate", "ast", "context", "env", "evaluateBinaryOp", "evaluateUnaryOp", "evaluateCall", "getNestedValue", "node", "left", "normalize", "right", "operator", "ordered", "arithmetic", "truthy", "operand", "negate", "fn", "FUNCTIONS", "arg", "value", "obj", "path", "parts", "current", "part", "CONSTANTS", "ARITHMETIC", "tokenize", "expr", "tokens", "token", "space", "at", "match", "getTokenType", "text", "lowerText", "ExpressionParser", "tokens", "__publicField", "ast", "left", "operator", "right", "operand", "compOperators", "name", "fn", "FUNCTIONS", "args", "least", "most", "takesInWords", "problem", "expr", "token", "CONSTANTS", "parseListLiteral", "next", "type", "values", "operators", "lowerValue", "op", "value", "message", "listStr", "content", "elements", "current", "inString", "stringChar", "i", "char", "parseElement", "error", "element", "walk", "ast", "visit", "arg", "fieldsRead", "names", "node", "root", "sumsRead", "sums", "lines", "field", "compileModifier", "modifier", "value", "ast", "ExpressionParser", "tokenize", "fieldsRead", "values", "env", "truthy", "evaluate", "compileExpression", "source", "ast", "ExpressionParser", "tokenize", "fieldsRead", "sumsRead", "values", "env", "evaluate", "dependencyOrder", "reads", "order", "cycles", "done", "path", "visit", "name", "at", "read", "has", "record", "key", "EXPRESSIBLE", "EXPRESSIBLE_WORDS", "listed", "names", "quoted", "name", "ReferenceCheck", "page", "__publicField", "path", "message", "id", "first", "scope", "owner", "keys", "value", "fields", "compileModifier", "error", "source", "where", "compiled", "compileExpression", "sum", "lines", "base", "reads", "def", "read", "item", "i", "cycle", "dependencyOrder", "currency", "walk", "at", "inner", "other", "seen", "property", "sequence", "field", "kinds", "lineFields", "kindField", "which", "o", "text", "root", "step", "stepPath", "list", "order", "named", "filter", "j", "button", "children", "child", "node", "tab", "tabPath", "sheet", "visibleStates", "values", "state", "stat", "badge", "place", "alert", "rule", "column", "sub", "shown", "c", "isObject", "value", "LAYOUTS", "checkPage", "input", "issues", "say", "path", "message", "data", "fields", "name", "def", "FIELD_TYPES", "layout", "isList", "page", "found", "ReferenceCheck", "error", "TEXT_KEYS", "NOT_TEXT", "walk", "value", "key", "text", "enter", "widget", "item", "out", "name", "inner", "translatePage", "page", "translate", "pageWords", "words", "fields", "visit", "node", "def", "part", "localizePage", "locale", "isRightToLeft", "tag", "language", "rest", "script", "evaluateModifier", "expression", "context", "tokens", "tokenize", "ast", "ExpressionParser", "result", "evaluate", "truthy", "isModifierValid", "LANGUAGES", "en", "MESSAGES", "LANGUAGES", "fill", "template", "values", "match", "name", "dayOf", "limit", "today", "localDay", "counted", "y", "m", "d", "written", "options", "messages", "at", "checkDay", "field", "value", "day", "say", "key", "fill", "words", "min", "max", "days", "not", "n", "emptyValue", "field", "initialValues", "fields", "today", "values", "name", "start", "dayOf", "structuredCopy", "isEmpty", "value", "a", "expressionContext", "context", "forExpressions", "record", "line", "ref", "file", "lineKind", "kinds", "sameValue", "b", "checkValue", "field", "value", "required", "messages", "MESSAGES", "today", "label", "say", "key", "values", "fill", "isEmpty", "checkMatrix", "decimals", "checkDate", "checkDay", "checkDateTime", "allowed", "o", "listing", "own", "v", "isRecord", "ref", "m", "models", "listOr", "article", "checkFiles", "rows", "r", "columns", "c", "row", "answer", "picked", "a", "answered", "text", "dot", "y", "d", "realDay", "ISO_DATETIME", "match", "mo", "h", "mi", "s", "part", "year", "month", "day", "lengths", "files", "file", "isFile", "problem", "fileProblem", "formatBytes", "accept", "accepts", "types", "describeTypes", "patterns", "type", "pattern", "EXTENSIONS", "pair", "describeType", "sub", "word", "or", "items", "phrase", "bytes", "units", "size", "unit", "tidy", "n", "pointsOf", "options", "value", "o", "best", "most", "allWorth", "sum", "earned", "answer", "several", "v", "scoreOf", "page", "values", "score", "max", "scored", "name", "field", "c", "answers", "byRow", "row", "saveRefused", "problem", "saveProblemOf", "error", "carried", "message", "matchesFilter", "values", "filter", "item", "holds", "inner", "meets", "isSet", "value", "condition", "raw", "actual", "expected", "text", "low", "high", "TEXT", "NUMBER", "LINK", "suggestions", "typed", "page", "list", "words", "text", "found", "field", "def", "say", "op", "value", "valueLabel", "label", "fill", "lower", "option", "number", "rank", "type", "i", "a", "b", "facetsToFilter", "facets", "filter", "facet", "conditions", "v", "chosen", "id", "f", "items", "groupByFields", "hostScheduler", "callback", "ms", "handle", "wait", "scheduler", "resolve", "createMemoryDataSource", "options", "records", "structuredCopy", "responses", "calls", "lineIds", "pause", "wait", "table", "model", "labelOf", "id", "value", "nextId", "asId", "key", "applyLines", "current", "ops", "lines", "op", "l", "applyLinks", "links", "related", "r", "relationOf", "fields", "name", "field", "request", "stored", "rule", "warn", "result", "warning", "query", "values", "matchesFilter", "record", "matching", "a", "b", "order", "compared", "compareValues", "counted", "raw", "link", "group", "rows", "top", "list", "blank", "v", "label", "x", "y", "ADDRESS_PARTS", "checkStructure", "field", "node", "value", "messages", "options", "label", "fill", "needed", "asked", "parts", "missing", "part", "FORMATS", "checkInput", "field", "node", "value", "messages", "widget", "checkStructure", "text", "options", "label", "format", "digits", "fill", "t", "expressionEnv", "values", "fields", "today", "rows", "name", "def", "found", "line", "lineKind", "expressionContext", "steps", "fields", "compiled", "name", "def", "compileExpression", "order", "dependencyOrder", "expression", "fitTo", "value", "truthy", "isNumber", "roundTo", "compileComputed", "page", "today", "own", "lineSteps", "found", "lineEnv", "run", "values", "list", "env", "next", "context", "expressionContext", "sameValue", "line", "field", "lineKind", "current", "changed", "updated", "l", "worked", "expressionEnv", "rules", "fields", "name", "def", "rule", "compileModifier", "compileExpression", "EVERYTHING", "compileSetWhen", "page", "today", "own", "lineRules", "found", "lineEnv", "run", "values", "list", "env", "prefix", "before", "now", "next", "context", "expressionContext", "key", "value", "fitTo", "sameValue", "apply", "expressionEnv", "field", "current", "changed", "updated", "line", "lineKind", "set", "compileRules", "rules", "rule", "compileModifier", "checkRules", "field", "label", "value", "at", "found", "isEmpty", "compiled", "level", "broken", "brokenAsk", "brokenAcross", "fill", "pattern", "now", "text", "isNumber", "count", "side", "whenIs", "blank", "holds", "name", "today", "localDay", "createForm", "options", "page", "scheduler", "hostScheduler", "messages", "MESSAGES", "index", "indexLayout", "nodeRules", "node", "rules", "compileRules", "warns", "compiled", "steps", "step", "draftKey", "state", "today", "localDay", "computed", "compileComputed", "setWhen", "compileSetWhen", "baseline", "initialValues", "structuredCopy", "holding", "serverErrors", "lineKeys", "onchangeSeq", "draftTimer", "autosaveTimer", "pending", "listeners", "contextCache", "choiceLoads", "set", "patch", "was", "listener", "name", "fromList", "other", "loadChoices", "list", "load", "put", "choices", "shown", "source", "track", "loaded", "error", "checked", "def", "promise", "done", "reading", "values", "expressionContext", "expressionEnv", "context", "fieldDef", "dirtyFields", "nodeState", "id", "ctx", "env", "invisible", "parent", "readonly", "lockedField", "visibleFieldNodes", "root", "inside", "at", "skipped", "ruleCheck", "label", "checkRules", "unticked", "nodeError", "checkInput", "checkValue", "collectWarnings", "_a", "warnings", "warning", "withValues", "find", "previous", "collectErrors", "errors", "message", "line", "kind", "lineKind", "sub", "subDef", "lineMessage", "settle", "written", "round", "result", "startFrom", "worked", "writeValues", "extra", "fresh", "revalidateShown", "kept", "key", "refused", "scheduleDraft", "drafts", "forgetDraft", "offerDraft", "raw", "draft", "scheduleAutosave", "autosave", "save", "runOnchange", "changed", "seq", "request", "afterEdit", "changes", "creating", "names", "isEmpty", "now", "before", "emptyValue", "lineOps", "linkOps", "shownValues", "problem", "saveProblemOf", "fields", "creatable", "runCreate", "typed", "model", "runSearch", "query", "limit", "resolve", "item", "filter", "relation", "lineField", "field", "stepIndex", "optionalStep", "form", "value", "current", "numbers", "l", "n", "lines", "to", "sequence", "from", "target", "trusted", "i", "low", "high", "pool", "renumbered", "merged", "after", "subfield", "visible", "following", "chosen", "ops", "old", "had", "r", "has", "add", "modifiers", "compileModifier", "walk", "nodes", "tab", "button", "stat", "alert", "badge", "formats", "format", "locale", "decimals", "key", "found", "formatMoney", "value", "currency", "formatNumber", "marks", "parts", "p", "normalizeNumber", "text", "group", "decimal", "out", "d", "LANGUAGES", "en", "WIDGET_LABELS", "LANGUAGES", "maker", "document", "tag", "attrs", "children", "element", "name", "value", "wordsFor", "labels", "locale", "WIDGET_LABELS", "fillIn", "template", "values", "match", "key", "setAttr", "setHidden", "hidden", "setText", "text", "describeState", "state", "announcer", "make", "rightToLeft", "clearSelection", "words", "clear", "button", "open", "picked", "askFirst", "question", "yes", "no", "then", "_remove", "answered", "remove", "event", "answer", "DEBOUNCE_MS", "SHOWN", "fill", "template", "values", "match", "name", "combobox", "options", "doc", "id", "labels", "listId", "input", "list", "element", "shown", "creating", "creatingText", "extras", "editing", "results", "active", "seq", "timer", "readonly", "render", "record", "i", "option", "event", "choose", "empty", "open", "close", "index", "typed", "act", "picked", "lookUp", "query", "mine", "found", "reached", "held", "hidden", "kept", "overflow", "extra", "emptied", "text", "next", "creator", "form", "node", "many2oneWidget", "field", "document", "WIDGET_LABELS", "dialogs", "relation", "canOpen", "box", "choices", "limit", "current", "saved", "clear", "state", "setHidden", "setAttr", "tagsWidget", "chips", "r", "records", "_typed", "drawn", "key", "drawChips", "remove", "chip", "button", "charTagsWidget", "separator", "suggestions", "s", "split", "t", "write", "tags", "add", "raw", "tag", "taken", "wanted", "parts", "part", "typing", "linkCheckboxesWidget", "boxes", "latest", "sync", "chosen", "now", "label", "referenceWidget", "context", "models", "select", "model", "value", "localDate", "text", "match", "y", "m", "d", "hh", "mm", "displayValue", "def", "value", "values", "locale", "number", "n", "digits", "formatNumber", "r", "label", "v", "o", "currency", "formatMoney", "date", "file", "moveLineTo", "form", "name", "field", "key", "to", "lines", "from", "line", "count", "value", "kindTextField", "def", "kind", "lineForm", "form", "field", "key", "values", "l", "name", "query", "limit", "text", "linesWidget", "node", "id", "document", "labels", "WIDGET_LABELS", "locale", "dialogs", "kinds", "make", "maker", "options", "min", "max", "words", "columns", "column", "element", "scroller", "table", "head", "headRow", "th", "lastTh", "body", "totals", "sums", "foot", "row", "i", "td", "adds", "addButton", "button", "focusNew", "rows", "emptyWords", "empty", "confirm", "askFirst", "voice", "readonly", "current", "have", "move", "to", "from", "line", "focused", "first", "moveLineTo", "fillIn", "event", "makeCell", "tr", "sub", "span", "cellId", "subNode", "widget", "createWidget", "label", "error", "makeRow", "lineKind", "grip", "dragging", "end", "cells", "tools", "remove", "at", "cell", "isEmpty", "gone", "left", "next", "state", "errors", "keep", "index", "message", "sum", "total", "displayValue", "FOCUSABLE", "keepTabIn", "box", "event", "all", "e", "first", "last", "at", "readFile", "file", "resolve", "reject", "reader", "url", "extension", "name", "kindOf", "of", "asText", "source", "bytes", "data", "c", "icon", "make", "named", "fileWidget", "kind", "form", "def", "node", "id", "doc", "labels", "locale", "field", "words", "wordsFor", "messages", "MESSAGES", "maker", "several", "most", "image", "thumbs", "camera", "accept", "element", "input", "limits", "describeTypes", "fill", "formatBytes", "pick", "limited", "count", "list", "replace", "confirm", "askFirst", "note", "readonly", "files", "shown", "say", "lines", "line", "take", "chosen", "kept", "over", "problem", "fileProblem", "f", "added", "event", "button", "at", "view", "remove", "gone", "_", "i", "opener", "all", "title", "meta", "step", "by", "arrow", "show", "download", "close", "body", "box", "backdrop", "free", "none", "to", "pre", "r", "done", "rightToLeft", "keepTabIn", "state", "value", "full", "setHidden", "setText", "describeState", "binaryWidget", "imageWidget", "percents", "percent", "value", "locale", "format", "progressbarWidget", "context", "field", "node", "id", "document", "options", "range", "key", "usual", "set", "min", "fixedMax", "maxField", "color", "showPercent", "bar", "fill", "text", "box", "element", "createWidget", "state", "max", "share", "rounded", "words", "value", "labelWidget", "field", "node", "id", "document", "locale", "options", "text", "key", "from", "decimals", "output", "values", "shown", "formatNumber", "summary", "prefixField", "suffixField", "prefix", "suffix", "part", "statusbarWidget", "form", "name", "field", "node", "id", "document", "options", "clickable", "visible", "list", "keyOf", "value", "steps", "o", "lookedUp", "last", "draw", "readonly", "currentKey", "shown", "s", "v", "step", "label", "inner", "item", "state", "records", "r", "isoWeek", "day", "yearStart", "pad", "n", "sameDay", "a", "b", "addDays", "d", "addMonths", "last", "dayOf", "kind", "value", "m", "withCalendar", "inner", "context", "form", "name", "id", "doc", "locale", "labels", "WIDGET_LABELS", "lang", "monthName", "dayName", "weekdayShort", "weekdayLong", "button", "svg", "icon", "tag", "attrs", "shape", "k", "v", "dialog", "head", "prev", "title", "next", "grid", "element", "focused", "readonly", "pick", "was", "at", "close", "draw", "focus", "chosen", "today", "label", "first", "start", "headRow", "weekHead", "i", "th", "thead", "tbody", "row", "tr", "week", "cell", "event", "onKey", "move", "to", "moves", "open", "outside", "state", "humanize", "name", "words", "guess", "value", "label", "propertiesWidget", "context", "form", "field", "node", "id", "document", "declared", "current", "properties", "property", "element", "rows", "drawn", "draw", "definitions", "row", "definition", "rowId", "propertyField", "propertyNode", "widget", "createWidget", "state", "values", "key", "ALLOWED", "DROPPED_WITH_CONTENT", "ALIGNABLE", "ALIGNMENTS", "sanitizeHtml", "html", "document", "box", "clean", "parent", "node", "element", "href", "align", "attribute", "out", "linkAddress", "typed", "text", "TOOLS", "htmlWidget", "form", "name", "id", "labels", "WIDGET_LABELS", "area", "withToolbar", "last", "toolbar", "formattingToolbar", "state", "doc", "bar", "lastRange", "restore", "selection", "run", "command", "value", "style", "key", "option", "linkRow", "address", "apply", "unlink", "url", "event", "buttons", "icon", "button", "stops", "stop", "i", "at", "rtl", "step", "next", "reflect", "block", "jsonWidget", "error", "parsed", "seeds", "seedOf", "form", "seed", "stir", "name", "h", "i", "numbers", "a", "t", "shownOptions", "options", "node", "is", "option", "flag", "shown", "o", "next", "j", "matrixWidget", "form", "name", "field", "node", "id", "document", "def", "kind", "make", "tag", "attrs", "children", "element", "key", "value", "table", "c", "body", "inputs", "rows", "row", "shownOptions", "tr", "column", "input", "other", "save", "columnValue", "text", "picked", "i", "state", "answer", "chosen", "setAttr", "WIDTH", "HEIGHT", "INK", "SCRIPT", "bytesOf", "base64", "keyOf", "file", "signatureWidget", "form", "name", "field", "node", "id", "document", "labels", "locale", "words", "wordsFor", "make", "maker", "options", "color", "ink", "penWidth", "width", "footerWords", "canvas", "hint", "image", "typed", "button", "undo", "clear", "upload", "element", "pen", "context", "mine", "readonly", "typedName", "strokes", "last", "blank", "redraw", "stroke", "i", "line", "from", "to", "wipe", "keep", "url", "data", "at", "event", "box", "next", "end", "showPad", "chosen", "readFile", "value", "state", "away", "src", "describeState", "sliderWidget", "form", "name", "field", "node", "id", "document", "labels", "locale", "words", "wordsFor", "make", "maker", "has", "key", "min", "max", "step", "decimals", "written", "n", "formatNumber", "input", "output", "endWords", "v", "end", "i", "ends", "clear", "clearSelection", "element", "state", "value", "at", "describeState", "withAlone", "options", "now", "value", "alone", "v", "limiter", "make", "words", "node", "most", "r", "element", "count", "full", "setText", "fillIn", "layOut", "group", "columns", "choiceTagsWidget", "context", "combo", "searchWidget", "form", "name", "field", "id", "document", "labels", "locale", "single", "words", "wordsFor", "make", "maker", "options", "own", "listId", "input", "list", "chips", "box", "element", "current", "chosen", "write", "values", "labelOf", "value", "o", "found", "active", "readonly", "draw", "option", "i", "item", "event", "add", "setAttr", "open", "written", "typed", "taken", "fillIn", "close", "withAlone", "down", "pick", "drawn", "state", "describeState", "key", "label", "chip", "remove", "v", "BLANK", "imageChoiceWidget", "form", "name", "field", "node", "id", "document", "labels", "locale", "words", "wordsFor", "make", "maker", "multiple", "written", "options", "shownOptions", "look", "bare", "group", "layOut", "limit", "limiter", "cards", "option", "picture", "card", "pick", "current", "now", "on", "v", "withAlone", "o", "readonly", "event", "at", "back", "rightToLeft", "steps", "to", "clear", "clearSelection", "c", "state", "chosen", "stop", "full", "i", "describeState", "SLOP", "rankingWidget", "form", "name", "field", "node", "id", "document", "labels", "locale", "words", "wordsFor", "make", "maker", "options", "shownOptions", "list", "voice", "announcer", "most", "top", "pool", "keepAsShown", "shown", "item", "element", "fillIn", "items", "option", "label", "place", "up", "down", "grip", "tools", "li", "pick", "readonly", "keep", "out", "other", "move", "event", "press", "refocus", "draw", "next", "i", "moved", "step", "which", "from", "to", "giveBackFocus", "startY", "before", "lifted", "onMove", "e", "others", "at", "box", "onEnd", "orderOf", "value", "named", "v", "state", "describeState", "PARTS", "isPart", "name", "NOT_COUNTRIES", "countries", "countriesIn", "locale", "names", "found", "a", "b", "code", "x", "y", "addressWidget", "form", "node", "id", "document", "labels", "words", "wordsFor", "make", "maker", "options", "asked", "parts", "needed", "start", "element", "write", "part", "text", "now", "kept", "filled", "v", "keys", "boxes", "label", "autocomplete", "attrs", "input", "country", "state", "value", "o", "describeState", "count", "value", "cardsWidget", "form", "name", "field", "node", "id", "document", "labels", "locale", "dialogs", "words", "wordsFor", "make", "maker", "def", "options", "min", "max", "itemLabel", "titleOf", "n", "fillIn", "names", "f", "list", "addButton", "voice", "announcer", "element", "cards", "lines", "readonly", "focusNext", "have", "key", "settle", "makeCard", "line", "titleId", "title", "remove", "tool", "text", "word", "act", "button", "at", "l", "tools", "move", "copy", "body", "cardElement", "b", "fields", "column", "sub", "cellId", "subNode", "widget", "createWidget", "lineForm", "label", "error", "all", "gone", "after", "next", "to", "from", "moveLineTo", "way", "values", "made", "run", "card", "state", "current", "errors", "keep", "index", "message", "describeState", "counted", "widget", "form", "name", "field", "document", "labels", "locale", "box", "size", "make", "maker", "shown", "said", "pause", "state", "n", "setText", "setHidden", "fillIn", "wordsFor", "grower", "area", "node", "rows", "bounds", "input", "options", "time", "limit", "i", "dayOf", "currencySymbol", "code", "locale", "parts", "at", "part", "SVG", "ICONS", "drawIcon", "doc", "name", "own", "inside", "svg", "key", "value", "listChoices", "factory", "context", "form", "name", "doc", "words", "wordsFor", "box", "note", "retry", "named", "inner", "shown", "draw", "options", "state", "choices", "option", "lost", "v", "o", "fill", "yesNoWidget", "form", "name", "node", "id", "document", "labels", "locale", "words", "wordsFor", "make", "maker", "group", "readonly", "buttons", "value", "own", "button", "event", "at", "clear", "clearSelection", "b", "state", "picked", "i", "setAttr", "describeState", "createWidget", "context", "registry", "field", "node", "keys", "key", "factory", "builtInWidgets", "listChoices", "pendingWidget", "make", "doc", "tag", "props", "children", "element", "name", "value", "describe", "state", "setAttr", "textOf", "textWidget", "inputType", "form", "id", "document", "input", "bounds", "counted", "text", "textareaWidget", "area", "grow", "grower", "NUMBER", "UNFINISHED", "numberWidget", "locale", "integer", "decimals", "shown", "formatNumber", "parse", "raw", "normalizeNumber", "options", "currencyField", "currencyDef", "picker", "after", "currencySymbol", "unit", "n", "currency", "prefix", "suffix", "first", "last", "units", "u", "typing", "parsed", "showsSame", "holder", "code", "setText", "side", "checkboxWidget", "look", "attrs", "box", "selectWidget", "search", "searchWidget", "choices", "shownOptions", "select", "option", "i", "index", "choiceGroup", "kind", "labels", "words", "wordsFor", "group", "layOut", "limit", "limiter", "maker", "inputs", "other", "otherChoice", "otherBox", "save", "ticked", "alone", "own", "chosen", "_", "event", "known", "o", "picked", "clear", "clearSelection", "full", "off", "v", "waiting", "pointsWidget", "style", "min", "max", "icon", "filling", "nps", "points", "point", "fillIn", "drawIcon", "current", "step", "next", "ends", "p", "tab", "dateWidget", "widget", "withCalendar", "pad", "dateTimeWidget", "local", "iso", "d", "span", "summary", "record", "count", "file", "charTagsWidget", "sliderWidget", "progressbarWidget", "labelWidget", "yesNoWidget", "choiceTagsWidget", "imageChoiceWidget", "rankingWidget", "statusbarWidget", "many2oneWidget", "tagsWidget", "linkCheckboxesWidget", "referenceWidget", "linesWidget", "cardsWidget", "binaryWidget", "signatureWidget", "imageWidget", "htmlWidget", "jsonWidget", "addressWidget", "propertiesWidget", "matrixWidget", "KINDS_CSS", "CHOICES_CSS", "INPUTS_CSS", "LAYOUT_CSS", "SKINS_CSS", "FIELDIA_CSS", "LAYOUT_CSS", "INPUTS_CSS", "KINDS_CSS", "CHOICES_CSS", "STYLE_ID", "installStyles", "document", "style", "browserPreferences", "storage", "area", "key", "text", "value", "memoryPreferences", "values", "structuredCloneSafe", "LANGUAGES", "en", "VIEWER_LABELS", "LANGUAGES", "DEFAULT_LABELS", "ADD_ONS", "missing", "ownLocale", "tag", "base", "name", "INK", "DARK_SURFACE", "LIGHT_GROUND", "channels", "hex", "at", "toHex", "rgb", "c", "luminance", "r", "g", "b", "s", "contrast", "a", "light", "dark", "x", "y", "textOn", "INK", "textOnDark", "lighten", "amount", "darken", "softOn", "surface", "i", "readsOn", "grounds", "ground", "accentShades", "given", "accent", "step", "LIGHT_GROUND", "DARK_SURFACE", "applyLook", "root", "look", "name", "value", "shades", "dialogs", "openFormDialog", "options", "doc", "container", "opener", "labels", "VIEWER_LABELS", "ownLocale", "id", "make", "tag", "attrs", "text", "element", "name", "value", "title", "closeButton", "body", "discard", "saveClose", "box", "look", "applyLook", "backdrop", "handle", "mountViewer", "done", "recalculate", "firstField", "resolve", "close", "saved", "state", "result", "accepted", "event", "keepTabIn", "form", "fields", "recompute", "closed", "seen", "writing", "values", "now", "next", "openSearchDialog", "locale", "words", "WIDGET_LABELS", "query", "list", "cancel", "head", "foot", "found", "active", "asked", "timer", "picked", "draw", "record", "i", "option", "mine", "records", "nameFieldOf", "page", "def", "valuesPage", "fields", "title", "readonly", "shown", "name", "lookupsOf", "source", "request", "pageDialogs", "options", "pageFor", "model", "shared", "related", "nameField", "result", "openFormDialog", "openSearchDialog", "key", "page", "readFavourites", "preferences", "kept", "startingFacets", "node", "chosen", "favourite", "id", "f", "favouritesPart", "context", "el", "labels", "fill", "list", "none", "name", "byDefault", "save", "form", "open", "write", "favourites", "draw", "use", "remove", "named", "others", "groupName", "context", "field", "group", "def", "o", "closeUnder", "tr", "level", "next", "after", "groupRow", "within", "grouping", "el", "labels", "filter", "toggle", "opening", "open", "rows", "inner", "recordsFrom", "offset", "answer", "record", "left", "more", "moreRow", "opened", "LIST_STYLES", "installListStyles", "doc", "style", "TEXT", "LINK", "CHOICE", "NUMBER", "DATE", "conditionsFor", "def", "customFilterPart", "context", "page", "el", "labels", "fields", "field", "name", "condition", "valueBox", "apply", "form", "button", "value", "drawConditions", "op", "word", "drawValue", "current", "o", "type", "wanted", "shown", "text", "option", "facetText", "facet", "labels", "or", "v", "searchBar", "context", "page", "node", "doc", "el", "fill", "uid", "facets", "icon", "name", "drawn", "drawIcon", "change", "next", "drawChips", "drawPanel", "listId", "panelId", "input", "chips", "offeredList", "toggle", "offered", "active", "index", "text", "remove", "_", "i", "kind", "drawOffered", "suggestion", "option", "event", "pick", "closeOffered", "value", "at", "f", "suggestions", "heading", "iconName", "id", "toggleIn", "key", "now", "keys", "k", "field", "filterButtons", "filter", "button", "groupButtons", "custom", "customFilterPart", "favourites", "favouritesPart", "group", "title", "parts", "panel", "ids", "fields", "showPanel", "open", "element", "outside", "NUMBERS", "UNSORTABLE", "listView", "context", "page", "node", "form", "el", "labels", "fill", "locale", "doc", "installListStyles", "pageSize", "defaultSort", "sort", "offset", "total", "rows", "recordOf", "visible", "body", "tr", "model", "facets", "startingFacets", "chosen", "asking", "destroyed", "fields", "name", "def", "show", "values", "displayValue", "chooseAll", "headers", "th", "button", "desc", "order", "load", "table", "empty", "retry", "failed", "row", "record", "level", "box", "drawChoice", "event", "cell", "count", "clear", "buttons", "action", "selection", "shown", "onPage", "id", "range", "previous", "next", "pager", "drawPager", "drawSort", "changed", "grouped", "source", "mine", "drawn", "filter", "facetsToFilter", "grouping", "groupByFields", "groups", "group", "groupRow", "answer", "search", "searchBar", "element", "planSection", "node", "place", "style", "arrangement", "own", "wideColumns", "span", "at", "TABLES", "labelPlace", "type", "chosen", "setHidden", "element", "hidden", "setText", "text", "setAttr", "name", "value", "mounts", "mountViewer", "host", "options", "doc", "checked", "checkPage", "i", "tag", "localized", "localizePage", "page", "translatePage", "locale", "ownLocale", "preferences", "browserPreferences", "dialogs", "pageDialogs", "ownsForm", "form", "createForm", "MESSAGES", "labels", "VIEWER_LABELS", "widgetLabels", "WIDGET_LABELS", "dir", "isRightToLeft", "prefix", "updaters", "cleanups", "uid", "id", "fill", "template", "values", "key", "installStyles", "el", "attrs", "children", "node", "name", "value", "withIcon", "text", "icon", "drawIcon", "words", "root", "applyLook", "confirm", "dialogConfirm", "fieldItem", "def", "labelsAt", "labelPlace", "wrapper", "labelText", "label", "mark", "NO_VALID_MARK", "widget", "createWidget", "TEXT_BOX", "helpText", "help", "error", "warning", "typing", "advice", "event", "update", "state", "shown", "setHidden", "message", "setText", "now", "warned", "filled", "valid", "locked", "hideWhen", "element", "buttonItem", "button", "spans", "textItem", "style", "slotItem", "cleanup", "colspan", "grid", "columns", "place", "box", "wideColumns", "width", "count", "child", "item", "top", "onPage", "folds", "sectionItem", "plan", "planSection", "section", "description", "content", "toggle", "open", "show", "next", "tabsItem", "list", "picked", "active", "parts", "tab", "tabId", "panelId", "panel", "render", "p", "at", "move", "rtl", "selected", "blockItem", "figure", "image", "href", "editSwitch", "announce", "checkText", "focusFirstProblem", "statusText", "retry", "submitOrSave", "status", "notDone", "names", "field", "inOrder", "a", "b", "quietTimer", "problem", "setAttr", "bannerRetry", "banner", "announcer", "seenProblem", "draft", "draftText", "restore", "discardDraft", "invalid", "folded", "done", "again", "pageHead", "head", "sectionsLayout", "action", "actions", "discard", "dirty", "wizardLayout", "progressText", "bar", "stepButtons", "step", "go", "focusStep", "panels", "back", "skip", "forward", "isLast", "steps", "wizardForward", "index", "last", "sheetLayout", "pageBox", "save", "atFoot", "foot", "header", "underTitle", "statusbar", "card", "ribbon", "stats", "stat", "alert", "dismissed", "close", "badges", "badge", "chip", "title", "part", "row", "avatar", "layout", "config", "barOptions", "body", "listView", "commitTyping", "nextField", "from", "fields", "here", "after", "control", "keys", "withCancel", "resolve", "cancel", "ok", "dialog", "backdrop", "opener", "answer", "e", "keepTabIn", "unsubscribe", "skin", "saved", "readonly", "addLanguage", "locale", "words", "MESSAGES", "WIDGET_LABELS", "VIEWER_LABELS", "VERSION", "host", "locale", "words", "addLanguage"]
7
7
  }