{"version":3,"sources":["../src/format.ts","../src/temporalProvider.ts","../src/errors.ts","../src/localeVocab.ts","../src/isoWeek.ts","../src/tokens.ts","../src/tokenize.ts","../src/constants.ts","../src/numbering.ts"],"sourcesContent":["/*\n * Copyright 2026 DirazCoder\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { TOKENS, DEFAULT_LOCALE, getEffectiveTokens, onTokenTableChange, type TemporalLike, type FormatOptions } from './tokens.js';\nimport { tokenize, type Piece } from './tokenize.js';\nimport { MAX_FORMAT_LENGTH } from './constants.js';\nimport { applyNumbering, type NumberingFormatOptions } from './numbering.js';\nimport { FormatSyntaxError, UnknownTokenError } from './errors.js';\n\n// `let`, not `const` — rebuilt below whenever a mod registers a format\n// token, same reasoning as tokenize.ts's SORTED_TOKEN_STRINGS. Every\n// read site in this file reads the live binding at call time (none of\n// them capture it into a closure at import time), so reassigning here\n// is enough; nothing needs to hold a reference to the Map itself.\nlet HANDLER_BY_TOKEN = new Map(TOKENS.map(([tok, fn, field]) => [tok, { fn, field }]));\n\n// Pre-tokenized format strings, keyed by (formatStr) — locale doesn't\n// change the tokenization step, only the per-token rendering, so the\n// piece list is shared across locales. Same eviction shape as the\n// other caches in this library.\nconst tokenizeCache = new Map<string, Piece[]>();\nconst MAX_TOKENIZE_CACHE_SIZE = 500;\n\n// A mod's registerFormatToken() rebuilds both HANDLER_BY_TOKEN here and\n// tokenize.ts's own token-string list in the same synchronous listener\n// pass (tokens.ts's registerToken() calls every subscriber in turn) —\n// see the comment on tokens.ts's rebuildListeners for why the two can\n// never be allowed to drift apart. The tokenizeCache also has to be\n// cleared here: if some format string was already tokenized (and\n// cached) before this registration, the newly-registered token's\n// characters would be stuck as cached literal text forever otherwise —\n// this is the fix for exactly that staleness.\nonTokenTableChange(() => {\n  HANDLER_BY_TOKEN = new Map(getEffectiveTokens().map(([tok, fn, field]) => [tok, { fn, field }]));\n  tokenizeCache.clear();\n});\n\nfunction getPieces(formatStr: string): Piece[] {\n  let pieces = tokenizeCache.get(formatStr);\n  if (pieces) return pieces;\n  if (tokenizeCache.size >= MAX_TOKENIZE_CACHE_SIZE) {\n    const oldestKey = tokenizeCache.keys().next().value;\n    if (oldestKey !== undefined) tokenizeCache.delete(oldestKey);\n  }\n  pieces = tokenize(formatStr);\n  // Deep-freeze before caching: the SAME array instance is handed out\n  // by compileFormat().pieces and _getPieces() (documented as readonly\n  // inspection surface). Read-only at the type level alone didn't stop\n  // runtime mutation — a caller writing pieces[0].value used to poison\n  // the shared cache and corrupt every subsequent format() for that\n  // string process-wide. Frozen objects make the mutation attempt\n  // throw (ESM is strict mode) instead of silently corrupting state.\n  for (const piece of pieces) Object.freeze(piece);\n  Object.freeze(pieces);\n  tokenizeCache.set(formatStr, pieces);\n  return pieces;\n}\n\n/**\n * Format a Temporal.PlainDate, PlainTime, PlainDateTime, or ZonedDateTime\n * using a date-fns-style token string.\n *\n * @example\n * format(Temporal.Now.plainDateISO(), 'yyyy-MM-dd') // \"2026-08-04\"\n * format(zdt, \"MMM d, yyyy 'at' h:mm a\") // \"Aug 4, 2026 at 3:45 PM\"\n * format(zdt, 'MMMM d, yyyy', { locale: 'fr-FR' }) // \"août 4, 2026\"\n *\n * Throws on a token the input type doesn't support (e.g. 'HH' on a PlainDate).\n */\nexport function format(temporal: TemporalLike, formatStr: string, options: NumberingFormatOptions = {}): string {\n  if (formatStr.length > MAX_FORMAT_LENGTH) {\n    throw new FormatSyntaxError({\n      format: formatStr,\n      message:\n        `temporal-fmt: format string exceeds maximum length of ${MAX_FORMAT_LENGTH} characters ` +\n        `(got ${formatStr.length}).`,\n    });\n  }\n  // Null/undefined input used to leak a raw V8 TypeError from the\n  // first field read (\"Cannot read properties of null (reading 'year')\")\n  // — every other entry point validates its input with a typed error,\n  // and null/undefined is by far the most common wrong input. A null\n  // `options` object hits the same class (the default parameter only\n  // covers undefined).\n  if (temporal === null || temporal === undefined) {\n    throw new FormatSyntaxError({\n      input: String(temporal),\n      reason: `format() expected a Temporal.PlainDate / PlainTime / PlainDateTime / ZonedDateTime (or a TemporalLike field bag), got ${String(temporal)}`,\n    });\n  }\n  const opts = options ?? {};\n\n  const locale = opts.locale ?? DEFAULT_LOCALE;\n  const pieces = getPieces(formatStr);\n  let result = '';\n\n  for (const piece of pieces) {\n    if (piece.kind === 'literal') {\n      result += piece.value;\n      continue;\n    }\n\n    const handler = HANDLER_BY_TOKEN.get(piece.value);\n    /* c8 ignore start @preserve -- unreachable: tokenize() only ever emits\n       tokens present in TOKENS, and HANDLER_BY_TOKEN is built from that\n       same list, so every token piece.value can hold already has an entry\n       here. Same defensive-guard category as the twin checks in\n       analyze.ts/formatDuration.ts. */\n    if (!handler) {\n      throw new UnknownTokenError({ token: piece.value, format: formatStr, message: `temporal-fmt: unknown token \"${piece.value}\"` });\n    }\n    /* c8 ignore stop @preserve */\n\n    if (temporal[handler.field] === undefined) {\n      throw new FormatSyntaxError({\n        format: formatStr,\n        token: piece.value,\n        message:\n          `temporal-fmt: token \"${piece.value}\" requires \"${handler.field}\", ` +\n          `which this Temporal object doesn't have. ` +\n          `(e.g. PlainDate has no time fields, PlainTime has no date fields)`,\n      });\n    }\n\n    result += handler.fn(temporal, locale);\n  }\n\n  // Numeral transliteration happens last and only on request — every\n  // upstream token handler still emits plain ASCII digits, so this is\n  // the single place output digits can diverge from that default.\n  return applyNumbering(result, opts);\n}\n\n// Shape mirrors Intl.DateTimeFormat.formatToParts: each entry is either\n// a literal (carrying no token info) or a token piece (carrying the\n// token string and the formatted value). Letting callers iterate parts\n// means they can build custom output — strip a token, swap a separator,\n// render each token to its own DOM node — without re-implementing the\n// tokenizer or the field-check logic.\nexport interface FormattedPart {\n  type: 'literal' | 'token';\n  value: string;\n  // Present when `type === 'token'`. Carries the token string (e.g. \"yyyy\")\n  // so a caller can look up its metadata via tokenInfo() from analyze.ts.\n  token?: string;\n}\n\nexport function formatToParts(temporal: TemporalLike, formatStr: string, options: NumberingFormatOptions = {}): FormattedPart[] {\n  if (formatStr.length > MAX_FORMAT_LENGTH) {\n    throw new FormatSyntaxError({\n      format: formatStr,\n      message:\n        `temporal-fmt: format string exceeds maximum length of ${MAX_FORMAT_LENGTH} characters ` +\n        `(got ${formatStr.length}).`,\n    });\n  }\n  const locale = options.locale ?? DEFAULT_LOCALE;\n  const pieces = getPieces(formatStr);\n  const result: FormattedPart[] = [];\n  for (const piece of pieces) {\n    if (piece.kind === 'literal') {\n      // Collapse adjacent literals so formatToParts stays consistent with\n      // how format() walks pieces — a multi-char literal \"at \" is one\n      // entry, not one per character. Same merge logic as appendLiteral\n      // in tokenize.ts.\n      const last = result[result.length - 1];\n      /* c8 ignore start @preserve -- unreachable through tokenize()'s own\n         output: appendLiteral() in tokenize.ts already merges every\n         adjacent literal character before pieces ever reaches here, so\n         two 'literal' pieces never sit back-to-back in the array this\n         loop walks. Kept as defense-in-depth in case that invariant ever\n         changes upstream. */\n      if (last && last.type === 'literal') {\n        last.value += piece.value;\n      } else {\n        /* c8 ignore stop @preserve */\n        result.push({ type: 'literal', value: piece.value });\n      }\n      continue;\n    }\n    const handler = HANDLER_BY_TOKEN.get(piece.value);\n    /* c8 ignore start @preserve -- unreachable, see the note in format() above */\n    if (!handler) {\n      throw new UnknownTokenError({ token: piece.value, format: formatStr, message: `temporal-fmt: unknown token \"${piece.value}\"` });\n    }\n    /* c8 ignore stop @preserve */\n    if (temporal[handler.field] === undefined) {\n      throw new FormatSyntaxError({\n        format: formatStr,\n        token: piece.value,\n        message:\n          `temporal-fmt: token \"${piece.value}\" requires \"${handler.field}\", ` +\n          `which this Temporal object doesn't have. ` +\n          `(e.g. PlainDate has no time fields, PlainTime has no date fields)`,\n      });\n    }\n    // Numeral transliteration applies per-token-part here, rather than\n    // once at the end like format() does, so a caller styling individual\n    // parts (e.g. one <span> per token) still gets correctly-transliterated\n    // digits in each part instead of plain ASCII.\n    result.push({ type: 'token', value: applyNumbering(handler.fn(temporal, locale), options), token: piece.value });\n  }\n  return result;\n}\n\n// Pre-compiles a format string into an object whose format()/formatToParts()\n// methods skip the tokenization step on every call. The tokenizeCache in\n// this module means a plain format(temporal, fmt) call already pays only\n// a Map lookup for tokenization after the first call, so compileFormat()\n// is mostly a typing/ergonomics affordance — useful for callers who want\n// to hold onto a compiled form explicitly (e.g. to inspect the pieces\n// via the .pieces property, or to pass the compiled object around\n// instead of the string).\nexport interface CompiledFormat {\n  format(temporal: TemporalLike, options?: NumberingFormatOptions): string;\n  formatToParts(temporal: TemporalLike, options?: NumberingFormatOptions): FormattedPart[];\n  readonly pieces: ReadonlyArray<Piece>;\n  readonly formatStr: string;\n}\n\nexport function compileFormat(formatStr: string): CompiledFormat {\n  if (formatStr.length > MAX_FORMAT_LENGTH) {\n    throw new FormatSyntaxError({\n      format: formatStr,\n      message:\n        `temporal-fmt: format string exceeds maximum length of ${MAX_FORMAT_LENGTH} characters ` +\n        `(got ${formatStr.length}).`,\n    });\n  }\n  // Pre-tokenize once. Validation (unknown tokens, unterminated quotes)\n  // happens here, not lazily on first format() call — surfaces a bad\n  // format string at compile time rather than at first use, which is\n  // the point of compiling up front.\n  const pieces = getPieces(formatStr);\n  return {\n    formatStr,\n    pieces,\n    format(temporal: TemporalLike, options: NumberingFormatOptions = {}) {\n      const locale = options.locale ?? DEFAULT_LOCALE;\n      let result = '';\n      for (const piece of pieces) {\n        if (piece.kind === 'literal') {\n          result += piece.value;\n          continue;\n        }\n        const handler = HANDLER_BY_TOKEN.get(piece.value);\n        /* c8 ignore next -- unreachable, see the note in format() above */\n        if (!handler) throw new UnknownTokenError({ token: piece.value, format: formatStr, message: `temporal-fmt: unknown token \"${piece.value}\"` });\n        if (temporal[handler.field] === undefined) {\n          throw new FormatSyntaxError({\n            format: formatStr,\n            token: piece.value,\n            message:\n              `temporal-fmt: token \"${piece.value}\" requires \"${handler.field}\", ` +\n              `which this Temporal object doesn't have. ` +\n              `(e.g. PlainDate has no time fields, PlainTime has no date fields)`,\n          });\n        }\n        result += handler.fn(temporal, locale);\n      }\n      return applyNumbering(result, options);\n    },\n    formatToParts(temporal: TemporalLike, options: NumberingFormatOptions = {}) {\n      const locale = options.locale ?? DEFAULT_LOCALE;\n      const out: FormattedPart[] = [];\n      for (const piece of pieces) {\n        if (piece.kind === 'literal') {\n          const last = out[out.length - 1];\n          /* c8 ignore next -- unreachable, see the note in formatToParts() above */\n          if (last && last.type === 'literal') last.value += piece.value;\n          else out.push({ type: 'literal', value: piece.value });\n          continue;\n        }\n        const handler = HANDLER_BY_TOKEN.get(piece.value);\n        /* c8 ignore next -- unreachable, see the note in format() above */\n        if (!handler) throw new UnknownTokenError({ token: piece.value, format: formatStr, message: `temporal-fmt: unknown token \"${piece.value}\"` });\n        if (temporal[handler.field] === undefined) {\n          throw new FormatSyntaxError({\n            format: formatStr,\n            token: piece.value,\n            message:\n              `temporal-fmt: token \"${piece.value}\" requires \"${handler.field}\", ` +\n              `which this Temporal object doesn't have. ` +\n              `(e.g. PlainDate has no time fields, PlainTime has no date fields)`,\n          });\n        }\n        out.push({ type: 'token', value: applyNumbering(handler.fn(temporal, locale), options), token: piece.value });\n      }\n      return out;\n    },\n  };\n}\n\n// Exported so analyze.ts can reuse the same tokenization cache rather\n// than re-tokenizing when a caller asks for both a format() and an\n// analyzeFormat() on the same string.\nexport function _getPieces(formatStr: string): Piece[] {\n  return getPieces(formatStr);\n}\n\n// Exported for analyze.ts — same reason as above. The handler map is\n// the source of truth for \"what field does this token need\" — analyze\n// consumes it to compute requiredFields and compatibleTypes.\nexport function _handlerFor(token: string): { fn: (t: TemporalLike, locale: string) => string; field: keyof TemporalLike } | undefined {\n  return HANDLER_BY_TOKEN.get(token);\n}","/*\n * Copyright 2026 DirazCoder\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n// tsconfig here is lib: [\"ESNext\"] only, so there's no ambient Temporal\n// namespace type to lean on. everywhere else in the codebase we just read\n// fields off whatever Temporal-like object gets passed in (see TemporalLike\n// in tokens.ts) but this file is the one place that actually touches the\n// Temporal namespace itself — PlainDate.from and friends. parse() uses it\n// to build results, tokens.ts uses it to check native Intl<->Temporal\n// support. you can hand us your own implementation via setTemporal(), or\n// we just grab globalThis.Temporal if there is one\ninterface TemporalFactory {\n  from(fields: Record<string, number | string | undefined>, options?: { overflow?: 'constrain' | 'reject'; disambiguation?: 'compatible' | 'earlier' | 'later' | 'reject'; offset?: 'use' | 'ignore' | 'prefer' | 'reject' }): unknown;\n  // compare() is on the namespace, not instances (Temporal.PlainDate.compare).\n  // made optional since someone might hand us a stripped-down shim that\n  // doesn't bother implementing it\n  compare?(one: unknown, two: unknown): number;\n}\n\n// Instant doesn't use from(fields) like the others, it's\n// fromEpochMilliseconds / fromEpochNanoseconds. needs its own shape.\ninterface InstantFactory {\n  from(iso: string): unknown;\n  fromEpochMilliseconds(ms: number): unknown;\n  fromEpochMicroseconds(µs: number): unknown;\n  fromEpochNanoseconds(ns: bigint): unknown;\n}\n\n// Duration uses from(fields) too, but also has round() and compare()\ninterface DurationFactory extends TemporalFactory {\n  compare?(one: unknown, two: unknown): number;\n  prototype?: { round(options: unknown): unknown };\n}\n\n// PlainYearMonth / PlainMonthDay also just use from(fields) — same shape\n// as TemporalFactory really, kept as its own type so callers can narrow\nexport interface TemporalNamespace {\n  PlainDate: TemporalFactory;\n  PlainTime: TemporalFactory;\n  PlainDateTime: TemporalFactory;\n  ZonedDateTime: TemporalFactory;\n  Instant?: InstantFactory;\n  Duration?: DurationFactory;\n  PlainYearMonth?: TemporalFactory;\n  PlainMonthDay?: TemporalFactory;\n}\n\nlet injectedTemporal: TemporalNamespace | undefined;\n\n// anything caching something tied to WHICH Temporal impl is active\n// (right now just tokens.ts's native-Intl probe) registers a listener\n// here so it knows to invalidate when setTemporal() swaps things out —\n// see setTemporal() below for why that matters. kept this as a plain\n// array instead of a full event emitter since all we need is \"call\n// everyone back, in order, no payload\" — didn't need unsubscribe either\nconst onTemporalChanged: Array<() => void> = [];\n\nexport function subscribeToTemporalChanges(listener: () => void): void {\n  onTemporalChanged.push(listener);\n}\n\n/**\n * Explicitly hand temporal-fmt the Temporal implementation to use, instead\n * of relying on a global `Temporal`. Call this once, before your first\n * `format()`/`parse()`/`parseISO()`/etc.\n *\n * Call with no argument (or `undefined`) to clear the override and fall\n * back to `globalThis.Temporal` again.\n *\n * @example\n * import { Temporal } from 'temporal-polyfill';\n * import { setTemporal } from 'temporal-fmt';\n * setTemporal(Temporal);\n */\nexport function setTemporal(temporal?: TemporalNamespace): void {\n  injectedTemporal = temporal;\n  // tokens.ts caches its native-Intl probe result based on whatever\n  // Temporal was active the first time it ran. if that changes later\n  // (native -> polyfill, say) the cached result goes stale. so just reset\n  // everyone on any setTemporal() call — costs one extra probe re-run,\n  // worth it to not silently use a stale answer\n  for (const listener of onTemporalChanged) listener();\n}\n\nfunction resolveTemporal(): TemporalNamespace | undefined {\n  return injectedTemporal ?? (globalThis as unknown as { Temporal?: TemporalNamespace }).Temporal;\n}\n\nexport function getTemporal(): TemporalNamespace {\n  const temporal = resolveTemporal();\n  if (!temporal) {\n    throw new Error(\n      'temporal-fmt: parse() needs a Temporal implementation to construct its result. ' +\n      'Call setTemporal(Temporal) once at startup, or assign one to globalThis.Temporal ' +\n      '(native on Node 26+, or a polyfill like temporal-polyfill).'\n    );\n  }\n  return temporal;\n}\n","/*\n * Copyright 2026 DirazCoder\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n// structured error classes for parse()/format() failures.\n//\n// as of 0.9.0 every throw site on the parse/format data path —\n// tokenize.ts, pattern.ts, format.ts, parse.ts (parse/safeParse/tryParse/\n// parseToParts/compileParser), plus the two data-path throws in\n// localeVocab.ts (partValue/assertNoCollision on the getLocaleVocab side)\n// — throws one of these typed classes directly instead of a plain\n// `new Error(message)`. every site we migrated kept its exact pre-0.9.0\n// message text, and since subclasses of TemporalFmtError still pass\n// `instanceof Error` and match the same message regexes (e.g.\n// `/token \"HH\" requires/`), this didn't need a semver-major bump for\n// either of those checks. what DOES break in 0.9.0: if anyone was\n// specifically checking `err.constructor === Error` or `err.name ===\n// 'Error'`, that'll now see a different name (e.g. 'FormatSyntaxError').\n// noted in the 0.9.0 changelog.\n//\n// deliberately did NOT migrate:\n//  - localeVocab.ts's registration-time throws (assertValidVocab,\n//    registerLocaleVocab itself) — these are config-time API-misuse\n//    errors on data a developer hands in once at startup, not runtime\n//    parse/format failures, so they don't really fit this module's\n//    TemporalFmtErrorCode taxonomy as-is. assertNoCollision is shared\n//    between the registration path and the data path (getLocaleVocab)\n//    though, so its throw stays a plain Error for both until that gets\n//    split apart — see the tracking note where it's called.\n//\n// wrapUntypedError() below is still around for localeVocab.ts's\n// registration throws, and for anything a caller passes into\n// safeParse()/tryParse() from outside this package. on the data path\n// itself, safeParse's `if (err instanceof TemporalFmtError) return { ok:\n// false, error: err }` catches everything before it'd even reach the\n// classifier here, so honestly the regex branches below are dead for\n// parse/format/tokenize/pattern at this point — kept as the fallback for\n// whatever hasn't been migrated to a typed throw site yet\n\nexport type TemporalFmtErrorCode =\n  | 'FORMAT_SYNTAX_ERROR'\n  | 'UNKNOWN_TOKEN'\n  | 'PARSE_MISMATCH'\n  | 'INVALID_DATE'\n  | 'INVALID_TIME'\n  | 'INVALID_OFFSET'\n  | 'INVALID_TIME_ZONE'\n  | 'INVALID_CALENDAR'\n  | 'AMBIGUOUS_INPUT'\n  | 'INVALID_LOCALE'\n  | 'INVALID_DURATION';\n\nexport interface TemporalFmtErrorFields {\n  code: TemporalFmtErrorCode;\n  input?: string;\n  format?: string;\n  token?: string;\n  position?: number;\n  expected?: string;\n  actual?: string;\n  reason?: string;\n}\n\n// base class. `message` is the human-readable summary, the structured\n// fields are the machine-readable bits a linter or codemod would report\n// on. calling Error.captureStackTrace manually (where it exists) so the\n// stack points at wherever this got thrown from, not at this constructor\n// — same trick Node uses for its own error classes\nexport class TemporalFmtError extends Error {\n  readonly code: TemporalFmtErrorCode;\n  readonly input?: string;\n  readonly format?: string;\n  readonly token?: string;\n  readonly position?: number;\n  readonly expected?: string;\n  readonly actual?: string;\n  readonly reason?: string;\n\n  constructor(message: string, fields: TemporalFmtErrorFields) {\n    super(message);\n    this.name = 'TemporalFmtError';\n    this.code = fields.code;\n    this.input = fields.input;\n    this.format = fields.format;\n    this.token = fields.token;\n    this.position = fields.position;\n    this.expected = fields.expected;\n    this.actual = fields.actual;\n    this.reason = fields.reason;\n    // don't want the stack pointing at this constructor line — captureStackTrace\n    // is V8-only though, so on other engines callers just get the default\n    // stack (pointing here) since there's nothing better to do about it\n    const capture = (Error as unknown as { captureStackTrace?: (target: Error, ctor?: Function) => void }).captureStackTrace;\n    if (typeof capture === 'function') {\n      capture(this, this.constructor);\n    }\n  }\n\n  // lets callers just call err.toJSON() for logging. plain Error doesn't\n  // serialize its non-enumerable fields on its own, so this picks them\n  // up explicitly\n  toJSON(): TemporalFmtErrorFields & { name: string; message: string } {\n    return {\n      name: this.name,\n      message: this.message,\n      code: this.code,\n      input: this.input,\n      format: this.format,\n      token: this.token,\n      position: this.position,\n      expected: this.expected,\n      actual: this.actual,\n      reason: this.reason,\n    };\n  }\n}\n\n// each subclass just fixes `code` so callers can switch on it without\n// having to re-check message text. the constructor only takes the\n// fields that actually vary per call; `code` and the default message\n// template come from the subclass itself\n\nexport class FormatSyntaxError extends TemporalFmtError {\n  constructor(fields: Omit<TemporalFmtErrorFields, 'code'> & { message?: string }) {\n    const { message, ...rest } = fields;\n    super(\n      message ?? `format string \"${fields.format ?? ''}\" has a syntax error${fields.reason ? `: ${fields.reason}` : ''}.`,\n      { code: 'FORMAT_SYNTAX_ERROR', ...rest },\n    );\n    this.name = 'FormatSyntaxError';\n  }\n}\n\nexport class UnknownTokenError extends TemporalFmtError {\n  constructor(fields: Omit<TemporalFmtErrorFields, 'code'> & { message?: string }) {\n    const { message, ...rest } = fields;\n    super(\n      message ?? `token \"${fields.token ?? ''}\" is not a recognized temporal-fmt token${fields.format ? ` in format string \"${fields.format}\"` : ''}.`,\n      { code: 'UNKNOWN_TOKEN', ...rest },\n    );\n    this.name = 'UnknownTokenError';\n  }\n}\n\nexport class ParseMismatchError extends TemporalFmtError {\n  constructor(fields: Omit<TemporalFmtErrorFields, 'code'> & { message?: string }) {\n    const { message, ...rest } = fields;\n    super(\n      message ?? `input \"${fields.input ?? ''}\" does not match format \"${fields.format ?? ''}\"${fields.reason ? `: ${fields.reason}` : ''}.`,\n      { code: 'PARSE_MISMATCH', ...rest },\n    );\n    this.name = 'ParseMismatchError';\n  }\n}\n\nexport class InvalidDateError extends TemporalFmtError {\n  constructor(fields: Omit<TemporalFmtErrorFields, 'code'> & { message?: string }) {\n    const { message, ...rest } = fields;\n    super(\n      message ?? `input \"${fields.input ?? ''}\" does not describe a valid date${fields.reason ? `: ${fields.reason}` : ''}.`,\n      { code: 'INVALID_DATE', ...rest },\n    );\n    this.name = 'InvalidDateError';\n  }\n}\n\n/* c8 ignore start @preserve -- InvalidTimeError is part of the public\n   error-class surface (exported from index.ts, code 'INVALID_TIME') but\n   nothing in this package actually constructs one. went and checked\n   whether it could get wired in the same way InvalidTimeZoneError just\n   was (see parse.ts's zzz-validation loop) — does hour/minute/second have\n   a post-match semantic range check the way zone ids do? nope.\n   pattern.ts's regex fragments for HH/H/hh/h/mm/m/ss/s already enforce\n   their valid ranges right at the regex level (e.g. HH is\n   '(?:[01]\\d|2[0-3])', which literally can't match \"99\"), so an\n   out-of-range time just gets rejected as a plain shape mismatch before\n   any semantic check would even run. no live gap to hook this into\n   without inventing a redundant check purely to give this class a body.\n   leaving it unconstructed until the library actually hits a real\n   invalid-time case worth reporting */\nexport class InvalidTimeError extends TemporalFmtError {\n  constructor(fields: Omit<TemporalFmtErrorFields, 'code'> & { message?: string }) {\n    const { message, ...rest } = fields;\n    super(\n      message ?? `input \"${fields.input ?? ''}\" does not describe a valid time${fields.reason ? `: ${fields.reason}` : ''}.`,\n      { code: 'INVALID_TIME', ...rest },\n    );\n    this.name = 'InvalidTimeError';\n  }\n}\n/* c8 ignore stop @preserve */\n\nexport class InvalidOffsetError extends TemporalFmtError {\n  constructor(fields: Omit<TemporalFmtErrorFields, 'code'> & { message?: string }) {\n    const { message, ...rest } = fields;\n    super(\n      message ?? `offset \"${fields.actual ?? ''}\" is invalid${fields.reason ? `: ${fields.reason}` : ''}.`,\n      { code: 'INVALID_OFFSET', ...rest },\n    );\n    this.name = 'InvalidOffsetError';\n  }\n}\n\nexport class InvalidTimeZoneError extends TemporalFmtError {\n  constructor(fields: Omit<TemporalFmtErrorFields, 'code'> & { message?: string }) {\n    const { message, ...rest } = fields;\n    super(\n      message ?? `time zone \"${fields.actual ?? ''}\" is not a recognized IANA time zone or fixed offset${fields.reason ? `: ${fields.reason}` : ''}.`,\n      { code: 'INVALID_TIME_ZONE', ...rest },\n    );\n    this.name = 'InvalidTimeZoneError';\n  }\n}\n\n/* c8 ignore start @preserve -- InvalidCalendarError is part of the\n   public error-class surface (exported from index.ts, code\n   'INVALID_CALENDAR') but same story as InvalidTimeError above — nothing\n   in this package constructs one. checked for a wiring opportunity the\n   same way: there's no user-supplied calendar identifier anywhere in the\n   library that we'd validate against a supported list. resolveCalendar()\n   in parse.ts derives the calendar entirely from Intl's own resolution\n   of the locale string — it's never handed an arbitrary \"calendar\" value\n   a caller could actually get wrong. no live input to reject here.\n   leaving it unconstructed until the library accepts an actual calendar\n   parameter that could be invalid */\nexport class InvalidCalendarError extends TemporalFmtError {\n  constructor(fields: Omit<TemporalFmtErrorFields, 'code'> & { message?: string }) {\n    const { message, ...rest } = fields;\n    super(\n      message ?? `calendar \"${fields.actual ?? ''}\" is not supported${fields.reason ? `: ${fields.reason}` : ''}.`,\n      { code: 'INVALID_CALENDAR', ...rest },\n    );\n    this.name = 'InvalidCalendarError';\n  }\n}\n/* c8 ignore stop @preserve */\n\nexport class AmbiguousInputError extends TemporalFmtError {\n  constructor(fields: Omit<TemporalFmtErrorFields, 'code'> & { message?: string }) {\n    const { message, ...rest } = fields;\n    super(\n      message ?? `input \"${fields.input ?? ''}\" is ambiguous${fields.reason ? `: ${fields.reason}` : ''}.`,\n      { code: 'AMBIGUOUS_INPUT', ...rest },\n    );\n    this.name = 'AmbiguousInputError';\n  }\n}\n\nexport class InvalidLocaleError extends TemporalFmtError {\n  constructor(fields: Omit<TemporalFmtErrorFields, 'code'> & { message?: string }) {\n    const { message, ...rest } = fields;\n    super(\n      message ?? `locale \"${fields.actual ?? ''}\" is not a valid BCP-47 tag${fields.reason ? `: ${fields.reason}` : ''}.`,\n      { code: 'INVALID_LOCALE', ...rest },\n    );\n    this.name = 'InvalidLocaleError';\n  }\n}\n\nexport class InvalidDurationError extends TemporalFmtError {\n  constructor(fields: Omit<TemporalFmtErrorFields, 'code'> & { message?: string }) {\n    const { message, ...rest } = fields;\n    super(\n      message ?? `duration is invalid${fields.reason ? `: ${fields.reason}` : ''}.`,\n      { code: 'INVALID_DURATION', ...rest },\n    );\n    this.name = 'InvalidDurationError';\n  }\n}\n\n// wraps a plain Error thrown from a code path that hasn't been migrated\n// to typed errors yet. keeps the original message around in `reason` so\n// callers reading the typed surface still see what actually failed.\n// used by safeParse() in parse.ts.\n//\n// after the 0.9.0 migration, every throw site on the parse/format data\n// path throws a TemporalFmtError directly, so safeParse's `instanceof\n// TemporalFmtError` check always passes before this function would even\n// get called — nothing in the current test suite actually reaches any\n// branch below. kept as the safety net for whenever someone adds an\n// unmigrated throw site down the line (see the c8-ignored call in\n// parse.ts's safeParse) — same reasoning as that call site: removing\n// this would silently break the \"safeParse always returns a\n// TemporalFmtError\" contract the moment anyone adds a bare\n// `throw new Error(...)` without wiring up a typed class for it\n/* c8 ignore start @preserve -- unreachable from the current test suite,\n   see rationale above */\nexport function wrapUntypedError(err: Error, context: { input?: string; format?: string }): TemporalFmtError {\n  // try to classify by looking at the message — covers the existing\n  // parse()/format() throw sites without having to touch them. anything\n  // that doesn't match a known pattern falls through to a generic\n  // ParseMismatchError, still with the structured fields intact\n  const msg = err.message;\n  if (/unknown token|isn't a recognized token/.test(msg)) {\n    return new UnknownTokenError({ input: context.input, format: context.format, reason: msg });\n  }\n  if (/ambiguous/i.test(msg)) {\n    return new AmbiguousInputError({ input: context.input, format: context.format, reason: msg });\n  }\n  if (/offset/.test(msg) && /out of range|exceeds|doesn't match the shape/i.test(msg)) {\n    return new InvalidOffsetError({ input: context.input, format: context.format, reason: msg });\n  }\n  if (/no valid pattern matches/i.test(msg)) {\n    return new ParseMismatchError({ input: context.input, format: context.format, reason: msg });\n  }\n  if (/doesn't describe a valid date\\/time|incomplete date|weekday token|quarter token/.test(msg)) {\n    return new InvalidDateError({ input: context.input, format: context.format, reason: msg });\n  }\n  const lowerMsg = msg.toLowerCase();\n  const mentionsLocale = lowerMsg.includes('locale');\n  if (\n    (mentionsLocale && (lowerMsg.includes('produced no') || lowerMsg.includes('not a valid'))) ||\n    lowerMsg.includes('cutoffs must be')\n  ) {\n    return new InvalidLocaleError({ input: context.input, format: context.format, reason: msg });\n  }\n  if (/format string exceeds maximum length|input exceeds maximum length|unterminated quote|isn't a recognized token/i.test(msg)) {\n    return new FormatSyntaxError({ input: context.input, format: context.format, reason: msg });\n  }\n  return new ParseMismatchError({ input: context.input, format: context.format, reason: msg });\n}\n/* c8 ignore stop @preserve */","/*\n * Copyright 2026 DirazCoder\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n// Name lists for the locale-aware tokens (MMMM, MMM, EEEE, EEE, a). Each\n// list is small and fixed (12 months, 7 weekdays, 2 day periods), so we\n// generate the real Intl strings for a locale once and cache them.\n\nimport { InvalidLocaleError } from './errors.js';\n\nexport interface LocaleVocab {\n  monthLong: string[]; // index 0 = January\n  monthShort: string[];\n  weekdayLong: string[]; // index 0 = Monday, per Temporal's dayOfWeek numbering\n  weekdayShort: string[];\n  dayPeriod: string[]; // typically [AM-ish, PM-ish], deduped\n}\n\n// Custom vocabs registered by callers for locales Intl doesn't cover well\n// (e.g. a 13-month Hebrew leap year, where Intl's 12-month vocabulary\n// silently loses a whole month). Keyed by canonical cache key so the\n// same locale string spelling variants fold together — same convention\n// as the Intl-derived vocab cache above.\nconst customVocabs = new Map<string, LocaleVocab>();\nconst MAX_CUSTOM_VOCABS = 500;\nconst MAX_LOCALE_TAG_LENGTH = 256;\nconst MAX_VOCAB_ENTRY_LENGTH = 256;\n\nfunction assertValidVocab(vocab: Partial<LocaleVocab>, locale: string): void {\n  // Strict shape validation at registration time, not lazily on first\n  // use — the README's promise is that a malformed registration throws\n  // descriptively here, rather than failing later inside format()/parse()\n  // with a confusing \"no month part\" or wrong-month error the caller\n  // can't trace back to the bad registration.\n  const required: Array<{ key: keyof LocaleVocab; length: number; label: string }> = [\n    { key: 'monthLong', length: 12, label: 'long month names' },\n    { key: 'monthShort', length: 12, label: 'short month names' },\n    { key: 'weekdayLong', length: 7, label: 'long weekday names' },\n    { key: 'weekdayShort', length: 7, label: 'short weekday names' },\n    { key: 'dayPeriod', length: 2, label: 'day period markers (AM/PM-equivalent)' },\n  ];\n\n  for (const { key, length, label } of required) {\n    const value = vocab[key];\n    if (value === undefined) {\n      throw new Error(\n        `temporal-fmt: registerLocaleVocab for locale \"${locale}\" is missing required field \"${key}\" (${label}).`\n      );\n    }\n    if (!Array.isArray(value)) {\n      throw new Error(\n        `temporal-fmt: registerLocaleVocab for locale \"${locale}\": \"${key}\" must be an array, got ${typeof value}.`\n      );\n    }\n    if (value.length !== length) {\n      throw new Error(\n        `temporal-fmt: registerLocaleVocab for locale \"${locale}\": \"${key}\" must have exactly ${length} entries (got ${value.length}) — ${label}.`\n      );\n    }\n    value.forEach((entry, i) => {\n      if (typeof entry !== 'string' || entry.length === 0) {\n        throw new Error(\n          `temporal-fmt: registerLocaleVocab for locale \"${locale}\": \"${key}[${i}]\" must be a non-empty string, got ${String(entry)}.`\n        );\n      }\n      if (entry.length > MAX_VOCAB_ENTRY_LENGTH) {\n        throw new RangeError(\n          `temporal-fmt: registerLocaleVocab for locale \"${locale}\": \"${key}[${i}]\" is too long (maximum ${MAX_VOCAB_ENTRY_LENGTH} characters).`\n        );\n      }\n    });\n  }\n\n  // Reuse the same collision check the Intl-derived path uses — a\n  // duplicate month name is just as ambiguous when supplied by a caller\n  // as when produced by Intl.\n  assertNoCollision(vocab.monthLong!, 'MMMM month', locale);\n  assertNoCollision(vocab.monthShort!, 'MMM month', locale);\n  assertNoCollision(vocab.weekdayLong!, 'EEEE weekday', locale);\n  assertNoCollision(vocab.weekdayShort!, 'EEE weekday', locale);\n\n  // dayPeriod entries must differ from each other, or parse()'s\n  // isPM check (raw === vocab.dayPeriod[1]) can never return true and\n  // every 12-hour parse silently resolves to AM. The Intl-derived path\n  // dedupes a same-AM/PM collision to length 1, but a caller passing\n  // both entries identical is a real bug to surface — not something to\n  // dedupe around.\n  if (vocab.dayPeriod![0] === vocab.dayPeriod![1]) {\n    throw new Error(\n      `temporal-fmt: registerLocaleVocab for locale \"${locale}\": dayPeriod entries must differ ` +\n      `(both are \"${vocab.dayPeriod![0]}\"); otherwise parse() can't tell AM from PM.`\n    );\n  }\n}\n\n// Anything that caches a result derived from *which* vocabulary is\n// active for a locale (right now: parse.ts's compiled pattern cache,\n// whose MMMM/MMM/EEEE/EEE/a fragments embed the vocab's alternations)\n// subscribes here so it gets invalidated when a registration swaps the\n// vocab — mirrors temporalProvider.ts's subscribeToTemporalChanges.\nconst onVocabChanged: Array<() => void> = [];\n\nexport function subscribeToVocabChanges(listener: () => void): void {\n  onVocabChanged.push(listener);\n}\n\n/**\n * Supply a custom month/weekday/day-period vocabulary for a locale key,\n * overriding the Intl-derived vocab this library would otherwise build\n * for that key. Useful for locales Intl doesn't cover well — the\n * Parsing section of the README (\"MMMM/MMM assume a 12-month calendar\")\n * calls out the Hebrew leap-month gap as a specific case this addresses.\n *\n * Throws descriptively on malformed input (wrong array lengths, empty\n * strings, duplicate entries, missing fields) rather than failing later\n * during format/parse.\n *\n * Registered vocab takes precedence over the Intl-derived vocab for that\n * locale key, including for already-cached entries — registering\n * invalidates the prior cache entry for that locale so the next call\n * picks up the new vocab.\n *\n * @example\n * registerLocaleVocab('en-u-ca-hebrew-leap', {\n *   monthLong: ['Nisan','Iyar','Sivan','Tammuz','Av','Elul','Tishrei','Marcheshvan','Kislev','Tevet','Shevat','Adar I','Adar II'],\n *   monthShort: ['Nis','Iyy','Siv','Tam','Av','Elu','Tish','Chesh','Kis','Tev','Shv','Ad1','Ad2'],\n *   weekdayLong: ['Monday','Tuesday','Wednesday','Thursday','Friday','Saturday','Sunday'],\n *   weekdayShort: ['Mon','Tue','Wed','Thu','Fri','Sat','Sun'],\n *   dayPeriod: ['AM','PM'],\n * });\n */\nexport function registerLocaleVocab(locale: string, vocab: Partial<LocaleVocab>): void {\n  if (typeof locale !== 'string' || locale.length === 0) {\n    throw new Error(`temporal-fmt: registerLocaleVocab requires a non-empty locale string, got ${String(locale)}.`);\n  }\n  if (locale.length > MAX_LOCALE_TAG_LENGTH) {\n    throw new RangeError(`temporal-fmt: registerLocaleVocab locale is too long (maximum ${MAX_LOCALE_TAG_LENGTH} characters).`);\n  }\n  assertValidVocab(vocab, locale);\n\n  const cacheKey = canonicalCacheKey(locale);\n  if (!customVocabs.has(cacheKey) && customVocabs.size >= MAX_CUSTOM_VOCABS) {\n    throw new RangeError(`temporal-fmt: registerLocaleVocab reached the ${MAX_CUSTOM_VOCABS}-locale limit.`);\n  }\n  customVocabs.set(cacheKey, {\n    monthLong: [...vocab.monthLong!],\n    monthShort: [...vocab.monthShort!],\n    weekdayLong: [...vocab.weekdayLong!],\n    weekdayShort: [...vocab.weekdayShort!],\n    dayPeriod: [...vocab.dayPeriod!],\n  });\n  // Invalidate the Intl-derived cache entry so any prior format/parse\n  // result cached for this locale is rebuilt against the new vocab. Not\n  // strictly necessary (getLocaleVocab checks customVocabs first), but\n  // cheap and keeps the two caches from drifting out of sync.\n  vocabCache.delete(cacheKey);\n  // Also invalidate downstream caches that baked the previous vocab in\n  // at build time (parse.ts's pattern cache is the one that matters:\n  // without this, a cached pattern would keep matching the OLD month /\n  // weekday names while format() renders the new ones, so the library's\n  // own format() output would fail to parse back).\n  for (const listener of onVocabChanged) listener();\n}\n\n// Every locale-keyed cache in this library (this one, formatterCache in\n// tokens.ts, patternCache/calendarCache in parse.ts) used to key on the\n// exact locale string a caller passed in. Intl treats spelling variants of\n// the same locale as equivalent ('en-US' / 'en-us' / 'en_US' all resolve\n// the same way), but a plain string-keyed Map doesn't — so callers mixing\n// spellings for what's really one locale would silently fragment across\n// separate cache entries instead of sharing one, making the bounded\n// eviction limits (MAX_*_CACHE_SIZE) less effective than they look. This\n// doesn't change any cache's *correctness* (each entry is still built from\n// -- and valid for -- whatever locale string produced it), only how many\n// distinct entries equivalent spellings end up costing. Falls back to the\n// original string on a malformed/unrecognized tag rather than throwing —\n// cache-key normalization shouldn't be where a bad locale first surfaces\n// as an error; whatever actually calls `new Intl.DateTimeFormat(locale)`\n// downstream is the right place for that.\n// Intl constructors (DateTimeFormat/NumberFormat/RelativeTimeFormat)\n// reject underscore-separated tags like 'en_US' outright, while\n// canonicalCacheKey and every locale-parsing path in this library\n// tolerates them by normalizing to BCP-47 hyphens. Centralize that\n// normalization so every `new Intl.*(locale)` construction site\n// accepts the same spellings the cache keys do. Genuinely malformed\n// tags still throw downstream, unchanged.\nexport function normalizeLocaleTag(locale: string): string {\n  return locale.replace(/_/g, '-');\n}\n\n// Memoized so hot paths (parse()'s resolveCalendar keys off this on\n// every call, and every locale-keyed cache re-derives it) don't build a\n// fresh Intl.Locale per invocation — construction is comparatively\n// expensive. Bounded like every other cache in this library.\nconst canonicalKeyCache = new Map<string, string>();\nconst MAX_CANONICAL_KEY_CACHE = 500;\n\nexport function canonicalCacheKey(locale: string): string {\n  const hit = canonicalKeyCache.get(locale);\n  if (hit !== undefined) return hit;\n  let key: string;\n  try {\n    // Intl.Locale requires BCP-47 hyphens and rejects underscore-separated\n    // tags like 'en_US' outright (RangeError), rather than normalizing\n    // them — so without this replace, that spelling would just fall\n    // through to the catch below and never fold with 'en-US'.\n    key = new Intl.Locale(locale.replace(/_/g, '-')).toString().toLowerCase();\n  } catch {\n    // Malformed tag: key on the raw string. Callers that must reject\n    // malformed tags do it via assertValidLocaleTag() before/instead of\n    // relying on this function — cache-key normalization isn't where a\n    // bad locale should surface as an error (unchanged behavior).\n    key = locale;\n  }\n  if (canonicalKeyCache.size >= MAX_CANONICAL_KEY_CACHE) {\n    const oldestKey = canonicalKeyCache.keys().next().value;\n    if (oldestKey !== undefined) canonicalKeyCache.delete(oldestKey);\n  }\n  canonicalKeyCache.set(locale, key);\n  return key;\n}\n\n// Single validation choke point for locale tags at public boundaries.\n// Intl constructors reject malformed tags with a bare engine RangeError\n// (\"Incorrect locale information provided\") that carries none of the\n// library's structured error context; this rethrows as the typed\n// InvalidLocaleError with the offending tag in its fields. Accepts the\n// same spellings as canonicalCacheKey (underscore tags normalized).\nexport function assertValidLocaleTag(locale: string): void {\n  try {\n    new Intl.Locale(normalizeLocaleTag(locale));\n  } catch {\n    throw new InvalidLocaleError({\n      actual: locale,\n      reason: 'not a valid BCP-47 locale tag',\n    });\n  }\n}\n\nconst vocabCache = new Map<string, LocaleVocab>();\nconst MAX_VOCAB_CACHE_SIZE = 500;\n\n// Some locales (ja-JP) split a field across two parts — month \"8\" plus a\n// counter suffix \"月\" as a separate sibling \"literal\" — while format()'s\n// post-1582 tokens go through toLocaleString(), which concatenates\n// everything into \"8月\", and the pre-1582 path in tokens.ts\n// (preCutoverGregorianName) formats one field at a time the same way this\n// does. Reading only the type-tagged part used to drop that suffix, so\n// this locale's vocab never matched what format() actually produced.\n// Only merges *adjacent* literals, not the whole string, since the\n// dayPeriod/weekday formatters below carry an extra hour part that a\n// join-everything approach would wrongly absorb.\nexport function partValue(formatter: Intl.DateTimeFormat, date: Date, type: Intl.DateTimeFormatPartTypes): string {\n  const parts = formatter.formatToParts(date);\n  const index = parts.findIndex((p) => p.type === type);\n  /* c8 ignore start @preserve -- defensive guard against a real but\n     unreproducible failure mode: an Intl implementation that omits the\n     requested part type entirely for some locale. Checked every locale\n     with unusual dayPeriod/weekday/month rendering available in this\n     runtime's ICU data (ja-JP, zh-CN, th-TH, he-IL, ar-SA, ko-KR, fa-IR)\n     against the exact formatter options getLocaleVocab uses (notably\n     hour12: true for the dayPeriod formatter, which is what makes every\n     locale here actually emit a dayPeriod part — omitting it is what\n     produced a false \"gap\" during investigation). None omit their part\n     on this runtime. A different ICU version or a non-Node Intl\n     implementation could plausibly behave differently, so this stays a\n     real check rather than an assertion. */\n  /* c8 ignore start @preserve */\n  if (index === -1) {\n    throw new InvalidLocaleError({\n      message: `temporal-fmt: locale produced no \"${type}\" part while building match vocabulary.`,\n    });\n  }\n  /* c8 ignore stop @preserve */\n  let value = parts[index]!.value;\n  const prev = parts[index - 1];\n  const next = parts[index + 1];\n  // skip whitespace literals (the separator before \"AM\") — only a\n  // no-space suffix like ja-JP's \"月\" should get folded in\n  if (prev?.type === 'literal' && !/\\s/.test(prev.value)) value = prev.value + value;\n  if (next?.type === 'literal' && !/\\s/.test(next.value)) value = value + next.value;\n  return value;\n}\n\n// Two entries rendering identically means parse()'s reverse lookup\n// (indexOf) can never tell them apart. Weekday collisions already surface\n// via parse()'s dayOfWeek cross-check, but with a confusing same-string\n// error; months have no equivalent cross-check, so a collision there would\n// otherwise resolve silently to the wrong month. Catching both here, once\n// at build time, gives one clear error instead.\nfunction assertNoCollision(names: string[], label: string, locale: string): void {\n  const seen = new Map<string, number>();\n  for (let i = 0; i < names.length; i++) {\n    const prior = seen.get(names[i]!);\n    if (prior !== undefined) {\n      // Not migrated to a typed error: this function is shared between\n      // getLocaleVocab's Intl-derived path (data-path error, would be a\n      // good InvalidLocaleError candidate) and assertValidVocab's\n      // registration-time check (out of scope for this pass — see the\n      // localeVocab.ts registration-error follow-up). Splitting this into\n      // two near-duplicate functions just to route error types\n      // differently isn't worth it for one throw; revisit together with\n      // the registration-error work instead.\n      throw new Error(\n        `temporal-fmt: locale \"${locale}\" renders ${label} index ${prior} and ${i} identically ` +\n        `(\"${names[i]}\"). parse() can't reliably tell these apart for this locale/token, so this ` +\n        `combination isn't supported.`\n      );\n    }\n    seen.set(names[i]!, i);\n  }\n}\n\n// Exposed for tokens.ts: when a custom vocab is registered for this\n// locale, format()'s locale-aware tokens (MMMM/MMM/EEEE/EEE/a) read\n// straight from the registered array instead of going through\n// Intl.DateTimeFormat. Without this override, format() would silently\n// keep producing Intl's strings while parse() matched against the\n// registered vocab — the two would round-trip-fail.\nexport function getCustomVocab(locale: string): LocaleVocab | undefined {\n  const cacheKey = canonicalCacheKey(locale);\n  return customVocabs.get(cacheKey);\n}\n\nexport function getLocaleVocab(locale: string): LocaleVocab {\n  // Validate before building vocab: a malformed tag used to surface as a\n  // raw RangeError from the first new Intl.DateTimeFormat below.\n  assertValidLocaleTag(locale);\n  const cacheKey = canonicalCacheKey(locale);\n  // Registered vocabs take precedence over the Intl-derived one — this\n  // is the override mechanism registerLocaleVocab() promises. Checking\n  // here, before the Intl cache lookup, means a registration that\n  // happens *after* the first Intl-derived vocab was built still takes\n  // effect on the next call.\n  const custom = customVocabs.get(cacheKey);\n  if (custom) {\n    return custom;\n  }\n  const cached = vocabCache.get(cacheKey);\n  if (cached) {\n    return cached;\n  }\n\n  const intlLocale = normalizeLocaleTag(locale);\n  const monthLongFmt = new Intl.DateTimeFormat(intlLocale, { month: 'long', timeZone: 'UTC' });\n  const monthShortFmt = new Intl.DateTimeFormat(intlLocale, { month: 'short', timeZone: 'UTC' });\n  const monthLong: string[] = [];\n  const monthShort: string[] = [];\n  for (let m = 0; m < 12; m++) {\n    const date = new Date(Date.UTC(2020, m, 1));\n    monthLong.push(partValue(monthLongFmt, date, 'month'));\n    monthShort.push(partValue(monthShortFmt, date, 'month'));\n  }\n  assertNoCollision(monthLong, 'MMMM month', locale);\n  assertNoCollision(monthShort, 'MMM month', locale);\n\n  const weekdayLongFmt = new Intl.DateTimeFormat(intlLocale, { weekday: 'long', timeZone: 'UTC' });\n  const weekdayShortFmt = new Intl.DateTimeFormat(intlLocale, { weekday: 'short', timeZone: 'UTC' });\n  const weekdayLong: string[] = [];\n  const weekdayShort: string[] = [];\n  // 2024-01-01 is a Monday (UTC) — walk 7 days from there for weekday names\n  for (let d = 0; d < 7; d++) {\n    const date = new Date(Date.UTC(2024, 0, 1 + d));\n    weekdayLong.push(partValue(weekdayLongFmt, date, 'weekday'));\n    weekdayShort.push(partValue(weekdayShortFmt, date, 'weekday'));\n  }\n  // redundant with parse()'s dayOfWeek cross-check, but gives a clearer error\n  assertNoCollision(weekdayLong, 'EEEE weekday', locale);\n  assertNoCollision(weekdayShort, 'EEE weekday', locale);\n\n  const dayPeriodFmt = new Intl.DateTimeFormat(intlLocale, { hour: 'numeric', hour12: true, timeZone: 'UTC' });\n  const am = partValue(dayPeriodFmt, new Date(Date.UTC(2020, 0, 1, 1)), 'dayPeriod');\n  const pm = partValue(dayPeriodFmt, new Date(Date.UTC(2020, 0, 1, 13)), 'dayPeriod');\n  const dayPeriod = [...new Set([am, pm])];\n\n  const vocab: LocaleVocab = { monthLong, monthShort, weekdayLong, weekdayShort, dayPeriod };\n  if (vocabCache.size >= MAX_VOCAB_CACHE_SIZE) {\n    const oldestKey = vocabCache.keys().next().value;\n    if (oldestKey !== undefined) vocabCache.delete(oldestKey);\n  }\n  vocabCache.set(cacheKey, vocab);\n  return vocab;\n}","/*\n * Copyright 2026 DirazCoder\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n// ISO week stuff. week runs Mon-Sun, and week 1 is whichever week has\n// the year's first Thursday in it (same as saying \"the week with Jan 4\").\n// took me a minute to wrap my head around this but the upshot is late-Dec\n// dates can land in week 1 of NEXT year, and early-Jan dates can land in\n// week 52/53 of the PREVIOUS year. that adjacent year is what RRRR prints,\n// not the plain calendar year.\n//\n// doing this with plain year/month/day + dayOfWeek math instead of asking\n// Temporal for it, since format() only has whatever fields got handed in\n// and dragging in a whole Temporal implementation just for week numbers\n// felt like overkill (also breaks for people not on setTemporal()).\n\nconst DAYS_IN_MONTH = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31];\nconst CUMULATIVE_DAYS_BY_MONTH = [0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334];\n\nexport function isGregorianLeapYear(year: number): boolean {\n  // divisible by 4, unless it's a century, then it also needs /400.\n  // Temporal's iso8601 calendar never switches to Julian, so this rule\n  // just applies all the way back, even for BCE years.\n  return (year % 4 === 0 && year % 100 !== 0) || year % 400 === 0;\n}\n\nfunction daysInYear(year: number): 365 | 366 {\n  return isGregorianLeapYear(year) ? 366 : 365;\n}\n\nexport function dayOfYear(year: number, month: number, day: number): number {\n  let doy = CUMULATIVE_DAYS_BY_MONTH[month - 1]! + day;\n  if (month > 2 && isGregorianLeapYear(year)) doy += 1;\n  return doy;\n}\n\n// Jan 1 2000 was a Saturday (ISO dow 6). picked this as an anchor point\n// since it's easier than reaching for Zeller's congruence every time,\n// and obviously this fact about Jan 1 2000 isn't going to change on us\nconst REFERENCE_YEAR = 2000;\nconst REFERENCE_JAN1_DAY_OF_WEEK = 6;\n\n// Howard Hinnant's days_from_civil: O(1) day count for a proleptic\n// Gregorian y/m/d, correct for negative years and year 0 (the (y2>=0?\n// y2 : y2-399)/400 offset form relies on truncating division, which JS\n// doesn't have — Math.floor on the *un-offset* numerator is the exact\n// JS equivalent, see the matching formulas in arithmetic.ts). Shared by\n// dayOfWeekOfJan1 and any caller needing days between two arbitrary\n// dates without a year-by-year walk (those walks were O(|year − 2000|)\n// per call — a field bag claiming year 2e8 hung formatDistance for\n// ~400ms per call and worse for bigger values).\nexport function daysFromCivil(year: number, month: number, day: number): number {\n  const y2 = month <= 2 ? year - 1 : year;\n  const era = Math.floor(y2 / 400);\n  const yoe = y2 - era * 400; // [0, 399]\n  const m2 = month > 2 ? month - 3 : month + 9; // [0, 11]\n  const doy = Math.floor((153 * m2 + 2) / 5) + day - 1; // [0, 365]\n  const doe = yoe * 365 + Math.floor(yoe / 4) - Math.floor(yoe / 100) + doy; // [0, 146096]\n  return era * 146097 + doe - 719468;\n}\n\n// Day of week (ISO, 1=Mon..7=Sun) for a proleptic Gregorian y/m/d, in\n// O(1). 1970-01-01 was a Thursday (dow 4), so dow = (days + 3) mod 7\n// shifted to 1..7. Replaces the Date.UTC(year, month-1, day) idiom used\n// elsewhere in this library, which silently remaps years 0-99 to\n// 1900-1999 per the ECMAScript spec and produces the wrong weekday for\n// first-century dates.\nexport function dayOfWeekFromCivil(year: number, month: number, day: number): number {\n  const days = daysFromCivil(year, month, day);\n  // days=0 is 1970-01-01 (Thursday, dow 4): (0 + 3) % 7 = 3 → 4 ✓\n  return (((days + 3) % 7) + 7) % 7 + 1;\n}\n\nfunction dayOfWeekOfJan1(year: number): number {\n  // O(1) via daysFromCivil: Jan 1 of `year` is `days` after Jan 1 2000\n  // (a Saturday, dow 6), so dow = (6 - 1 + days) mod 7, bumped to 1-indexed.\n  // The old year-by-year walk from 2000 was O(|year − 2000|) — correct\n  // but linear, and unbounded for hostile field-bag years.\n  const days = daysFromCivil(year, 1, 1) - daysFromCivil(REFERENCE_YEAR, 1, 1);\n  const zeroIndexed = (((REFERENCE_JAN1_DAY_OF_WEEK - 1 + days) % 7) + 7) % 7;\n  return zeroIndexed + 1;\n}\n\nexport interface IsoWeekDate {\n  isoYear: number;\n  week: number; // goes 1 to 53\n}\n\nexport function isoWeekYearAndWeek(year: number, month: number, day: number, dayOfWeek: number): IsoWeekDate {\n  // step 1: figure out the Thursday of this week — whatever calendar year\n  // that Thursday's in IS the ISO week-numbering year. doing this with\n  // day-of-year offsets so we don't need an actual Temporal.PlainDate here\n  const doy = dayOfYear(year, month, day);\n  const thursdayDoyRelative = doy + (4 - dayOfWeek); // can go negative or past daysInYear, that's fine\n\n  let isoYear: number;\n  let thursdayDoy: number;\n  if (thursdayDoyRelative < 1) {\n    isoYear = year - 1;\n    thursdayDoy = thursdayDoyRelative + daysInYear(isoYear);\n  } else if (thursdayDoyRelative > daysInYear(year)) {\n    isoYear = year + 1;\n    thursdayDoy = thursdayDoyRelative - daysInYear(year);\n  } else {\n    isoYear = year;\n    thursdayDoy = thursdayDoyRelative;\n  }\n\n  // step 2: find the first Thursday of isoYear, that one's week 1 by definition.\n  // depends entirely on which weekday Jan 1 lands on\n  const jan1Dow = dayOfWeekOfJan1(isoYear);\n  const firstThursdayDoy = 1 + ((4 - jan1Dow + 7) % 7); // always lands somewhere 1-7\n\n  // step 3: just count how many full weeks between the two Thursdays\n  const week = 1 + Math.floor((thursdayDoy - firstThursdayDoy) / 7);\n  return { isoYear, week };\n}\n","/*\n * Copyright 2026 DirazCoder\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { getTemporal, subscribeToTemporalChanges } from './temporalProvider.js';\nimport { canonicalCacheKey, getCustomVocab, normalizeLocaleTag, partValue } from './localeVocab.js';\nimport { InvalidLocaleError, FormatSyntaxError } from './errors.js';\nimport { isoWeekYearAndWeek, dayOfYear } from './isoWeek.js';\n\n// Throws the library's standard typed missing-field error for tokens\n// that READ more fields than their TOKENS-table `field` entry declares\n// (the table only drives format()'s single-field precheck). ww/RRRR read\n// year/month/day/dayOfWeek but precheck only dayOfWeek; D/DD/DDD read\n// year/month/day but precheck only day. Without this, a bag carrying the\n// declared field but missing the rest fed undefined into the math and\n// produced literal \"NaN\" output instead of the descriptive error every\n// other token throws.\nfunction requireFields(t: TemporalLike, token: string, ...fields: Array<keyof TemporalLike>): void {\n  for (const field of fields) {\n    if (t[field] === undefined) {\n      throw new FormatSyntaxError({\n        token,\n        message:\n          `temporal-fmt: token \"${token}\" requires \"${field}\", ` +\n          `which this Temporal object doesn't have. ` +\n          `(e.g. PlainDate has no time fields, PlainTime has no date fields)`,\n      });\n    }\n  }\n}\n\nexport function pad(n: number, len: number): string {\n  // padStart pads the whole string, sign included, so pad(-45, 4) used to\n  // come out \"0-45\" instead of \"-045\" — split the sign off first.\n  const negative = n < 0;\n  const digits = String(Math.abs(n)).padStart(len, '0');\n  return negative ? '-' + digits : digits;\n}\n\n// Combines the three sub-second fields Temporal exposes into one 9-digit\n// nanosecond-of-second value, then truncates (never rounds) to the\n// requested width. Truncating matches what every digit-width token in\n// this library already does elsewhere (yy, MM, dd, ...) — the token\n// asked for N digits of precision, not a rounded N-digit approximation.\n// A caller asking for SSS on a value with nanosecond precision gets the\n// leading 3 digits of it, same as they'd get the leading 3 digits of any\n// other multi-digit field this library formats.\n//\n// Attached to pad() rather than declared standalone: the bundler's\n// per-function coverage instrumentation attributes hits to each of the\n// 9 fraction-token arrow functions individually but not to a shared\n// helper they all close over, so a correctly-exercised helper still\n// shows as 0 hits under c8. pad() itself is called directly all over\n// this file and is reliably attributed — routing through it here keeps\n// the coverage numbers honest without duplicating the slice logic\n// across every token entry below.\npad.fraction = function formatFraction(t: TemporalLike, width: number): string {\n  const nanoOfSecond = t.millisecond! * 1_000_000 + (t.microsecond ?? 0) * 1_000 + (t.nanosecond ?? 0);\n  return pad(nanoOfSecond, 9).slice(0, width);\n};\n\n// Not every field exists on every Temporal type (PlainDate has no .hour,\n// etc). Callers check for undefined before formatting a token.\nexport interface TemporalLike {\n  year?: number;\n  month?: number;\n  day?: number;\n  hour?: number;\n  minute?: number;\n  second?: number;\n  millisecond?: number;\n  microsecond?: number;\n  nanosecond?: number;\n  timeZoneId?: string;\n  // ZonedDateTime.prototype.offset — `±HH:MM` (6 chars) for any modern\n  // date, but pre-1900 local-mean-time zones (e.g. America/New_York\n  // before 1883) surface a seconds component too: `±HH:MM:SS` (9\n  // chars). Format-side offset tokens must check the length rather\n  // than assume 6. Parse-side writes a canonicalized `+HH:MM` here\n  // before handing it to Temporal.ZonedDateTime.from as the\n  // `timeZone` value.\n  offset?: string;\n  dayOfWeek?: number; // 1=Mon, 7=Sun, per Temporal spec\n  calendarId?: string;\n  toInstant?: () => unknown;\n  toLocaleString?: (locale: string, options: Intl.DateTimeFormatOptions) => string;\n}\n\nexport interface FormatOptions {\n  /** BCP 47 locale tag, e.g. 'en-US', 'fr-FR', 'ar-EG'. Defaults to 'en-US'. */\n  locale?: string;\n  /**\n   * When set on parse(), opts into the lenient split heuristic for ambiguous\n   * glued numeric runs (e.g. \"121\" against \"Md\"). Default (false) keeps\n   * parse()'s strict behavior — throw on ambiguity rather than guess.\n   * See README \"Lenient parse mode\" for the heuristic and why it's opt-in.\n   */\n  lenient?: boolean;\n}\n\nexport const DEFAULT_LOCALE = 'en-US';\n\n// Intl.DateTimeFormat is expensive to construct and format() can run in a\n// loop (rendering a table of dates), so cache by (locale, options).\nconst formatterCache = new Map<string, Intl.DateTimeFormat>();\nconst MAX_CACHE_SIZE = 500;\n\nfunction getFormatter(locale: string, options: Intl.DateTimeFormatOptions): Intl.DateTimeFormat {\n  const key = JSON.stringify([canonicalCacheKey(locale), options]);\n  let formatter = formatterCache.get(key);\n  if (formatter) {\n    return formatter;\n  }\n  if (formatterCache.size >= MAX_CACHE_SIZE) {\n    // not real LRU, just evicts oldest insertion — fine for this key space\n    const oldestKey = formatterCache.keys().next().value;\n    if (oldestKey !== undefined) formatterCache.delete(oldestKey);\n  }\n  try {\n    formatter = new Intl.DateTimeFormat(normalizeLocaleTag(locale), options);\n  } catch (err) {\n    // Malformed locale tags reach Intl as a bare RangeError; surface the\n    // library's typed error instead (reached via dayPeriodPart — the\n    // 'a' token — on any runtime, and the native-Intl path for the rest).\n    // Every failure mode of this constructor with a string locale is a\n    // RangeError, so converting unconditionally preserves the original\n    // message in `reason` either way.\n    throw new InvalidLocaleError({ actual: locale, reason: (err as Error).message });\n  }\n  formatterCache.set(key, formatter);\n  return formatter;\n}\n\n// Passing a Temporal object straight into `new Intl.DateTimeFormat().formatToParts()`\n// only works when the engine's Intl implementation has special-cased support for\n// *native* Temporal instances (checked via internal slots and/or gated behind a V8 flag,\n// not tied to a specific Node version).\n//\n// A Temporal polyfill's instances don't have those slots, so the engine falls back to ToNumber() -> .valueOf(),\n// which the polyfill deliberately throws on (\"Cannot use valueOf\").\n// Probed once and memoized and only from intlPart(), so it never\n// runs unless a format string actually uses a locale-aware token.\nlet nativeSupport: boolean | undefined;\n// Invalidate the memoized probe whenever setTemporal() swaps the active\n// implementation — otherwise a probe result from \"is native Temporal\n// supported\" could keep being used after the active implementation is\n// no longer the one that was probed. See setTemporal() in\n// temporalProvider.ts for the other half of this.\nsubscribeToTemporalChanges(() => { nativeSupport = undefined; });\n\nfunction intlSupportsNativeTemporal(): boolean {\n  if (nativeSupport === undefined) {\n    nativeSupport = false;\n      try {\n        const temporal = getTemporal();\n        new Intl.DateTimeFormat('en-US', { day: 'numeric' })\n          .formatToParts(temporal.PlainDate.from({ year: 1970, month: 1, day: 1 }) as Date);\n        // Version-gated, not dead — see the matching note on the\n        // !intlSupportsNativeTemporal() branch in intlPart() below for\n        // why this can't be exercised from this environment.\n        /* c8 ignore next */\n        nativeSupport = true;\n      /* c8 ignore start */\n      } catch {\n        // native Temporal absent, or present but not recognized by Intl — fall back.\n        // Version-gated, not dead: this catch only fires on runtimes where the\n        // probe above throws (no native Temporal, or Intl doesn't recognize it).\n        // On a runtime with full native support (e.g. Node builds where Intl\n        // accepts native Temporal instances directly) the try succeeds and this\n        // branch is unreachable — mirror case of the block below.\n      }\n      /* c8 ignore stop */\n  }\n  return nativeSupport;\n}\n\n// The Julian → Gregorian cutover, as ICU applies it. ICU's gregory\n// calendar (unlike Temporal's, which is proleptic Gregorian throughout)\n// treats every date before October 15, 1582 as a Julian-calendar date:\n// the Julian calendar ran ~10 days behind proleptic Gregorian in that\n// era, so a date Temporal correctly calls 1500-07-05 gets silently\n// reinterpreted by Intl as Julian 1500-06-25 — the wrong month near\n// boundaries, and a weekday shifted by 10 mod 7 = 3 slots everywhere.\n// See tc39/ecma402#1003. Whether the cutover is even observable varies\n// by engine and entry point (V8's plain-Date path disables it; the\n// native-Temporal formatToParts path on some Node 26 builds does not),\n// so this can't be probed reliably at runtime — pre-cutover dates have\n// to be routed around Intl's calendar math entirely.\nconst GREGORIAN_CUTOVER_YEAR = 1582;\nconst GREGORIAN_CUTOVER_MONTH = 10;\nconst GREGORIAN_CUTOVER_DAY = 15;\n\n// True when the Temporal object's own (proleptic-Gregorian, hence\n// trustworthy) fields place it before the ICU cutover. Deliberately\n// NaN-tolerant rather than undefined-checking: a Temporal type that\n// lacks one of these fields (PlainMonthDay has no year, PlainYearMonth\n// no day) feeds undefined into Number(), every NaN comparison is false,\n// and the object falls out as \"not before the cutover\" onto its existing\n// formatting path — no undefined-specific branches to keep covered, and\n// no behavior change for field-partial types.\nfunction isBeforeGregorianCutover(t: TemporalLike): boolean {\n  if (t.year !== GREGORIAN_CUTOVER_YEAR) return Number(t.year) < GREGORIAN_CUTOVER_YEAR;\n  if (t.month !== GREGORIAN_CUTOVER_MONTH) return Number(t.month) < GREGORIAN_CUTOVER_MONTH;\n  return Number(t.day) < GREGORIAN_CUTOVER_DAY;\n}\n\n// Renders a locale-aware month/weekday name for a pre-cutover date\n// WITHOUT ever handing the date itself to Intl. Intl is used purely as a\n// name lookup table indexed by month/weekday number — never as the thing\n// that computes which month/weekday a historical date falls on, which is\n// the computation the Julian cutover corrupts. The number comes straight\n// off the Temporal object's own fields (proleptic-Gregorian-correct by\n// construction, since that's what Temporal is), and the name comes from\n// formatting a safe modern reference date carrying that same number.\n//\n// The reference dates are deliberately the same ones getLocaleVocab()\n// (localeVocab.ts) uses to build the parse-side vocabulary — 2020-mm-01\n// for months, the Monday-anchored 2024-01-01..07 week for weekdays — so\n// format() output for a pre-cutover date is byte-identical to what\n// parse() matches against, and round-trips keep working. partValue()\n// gives us the same adjacent-literal merging (ja-JP's \"8月\") the vocab\n// builder uses, for the same reason.\nfunction preCutoverGregorianName(\n  temporal: TemporalLike,\n  locale: string,\n  formatterOptions: Intl.DateTimeFormatOptions,\n  partType: 'month' | 'weekday'\n): string {\n  // timeZone: 'UTC' matters: the references are built via Date.UTC\n  // (midnight UTC), and without pinning the formatter's zone a host\n  // timezone behind UTC would shift them to the previous local day.\n  // month/dayOfWeek are guaranteed present — format()'s field precheck\n  // for MMMM/MMM ('month') and EEEE/EEE ('dayOfWeek') ran before the\n  // token handler was invoked at all.\n  const reference = partType === 'month'\n    ? new Date(Date.UTC(2020, temporal.month! - 1, 1))\n    : new Date(Date.UTC(2024, 0, temporal.dayOfWeek!));\n  const formatter = getFormatter(locale, { ...formatterOptions, timeZone: 'UTC' });\n  return partValue(formatter, reference, partType);\n}\n\nfunction intlPart(\n  temporal: TemporalLike,\n  locale: string,\n  options: Intl.DateTimeFormatOptions,\n  partType: Intl.DateTimeFormatPartTypes\n): string {\n  // Intl throws \"Mismatching Calendars\" if the formatter's calendar doesn't\n  // match the object's own (e.g. en-US formatter defaults to gregory, but\n  // a hebrew/islamic PlainDate needs its own calendar passed through).\n  //\n  // For iso8601 specifically, force 'gregory' rather than leaving calendar\n  // unset: numeric fields (yyyy/dd, see tokens' pad()-based handlers) are\n  // always pulled straight off the object's own ISO fields — so if the\n  // *locale* carries a `-u-ca-*` extension (e.g. 'en-u-ca-hebrew') and this\n  // step left calendar unset, the formatter would resolve its own default\n  // calendar from the locale and format MMMM/EEEE in that calendar while\n  // yyyy/dd stay ISO, producing a date that looks internally consistent\n  // (a real Hebrew month name next to a real-looking day/year) but names a\n  // completely different day than the object actually represents. Forcing\n  // 'gregory' here keeps every field of an ISO object's output anchored to\n  // the same (ISO/Gregorian) calendar — a locale's calendar extension only\n  // takes effect when the object itself already carries a non-ISO calendar\n  // (via `.withCalendar()`), matching what the README documents.\n  //\n  // 'gregory' specifically, not 'iso8601' — passing `calendar: 'iso8601'`\n  // explicitly alongside a single-field options object makes\n  // formatToParts() come back empty for some reason, but 'gregory' doesn't\n  // have that problem and Temporal's iso8601 calendar is Gregorian-shaped\n  // (proleptic Gregorian throughout, no Julian cutover) so the two agree\n  // on every numeric field this library ever reads.\n  const calendar = temporal?.calendarId;\n  const formatterOptions: Intl.DateTimeFormatOptions = {\n    ...options,\n    calendar: calendar && calendar !== 'iso8601' ? calendar : 'gregory',\n  };\n\n  // Field-bag guard: a plain { year, month, day } object only has\n  // Object.prototype.toLocaleString, which ignores both arguments and\n  // returns \"[object Object]\". On engines without native Temporal\n  // support in Intl this used to be caught below, but on engines where\n  // Intl *does* recognize native Temporal instances (Node 26+), a bag\n  // skips that branch entirely and reaches formatToParts() directly —\n  // which doesn't throw \"[object Object]\", it throws a bare\n  // \"RangeError: Invalid time value\" once the bag fails ToNumber()\n  // coercion. Neither failure mode is useful to a caller, so check for\n  // a real toLocaleString up front, before branching on native support,\n  // so the descriptive error fires on every engine.\n  const ls = temporal.toLocaleString;\n  if (typeof ls !== 'function' || ls === Object.prototype.toLocaleString) {\n    throw new Error(\n      `temporal-fmt: locale-aware part \"${partType}\" needs a value that implements ` +\n      `toLocaleString (a real Temporal object). A plain field bag cannot render ` +\n      `locale-aware names — pass a Temporal.PlainDate/PlainDateTime/ZonedDateTime.`\n    );\n  }\n\n  // Pre-1582 cutover guard. ICU's gregory calendar reinterprets dates\n  // before October 15, 1582 under Julian-calendar rules (see the long\n  // comment on isBeforeGregorianCutover above for the why), so for those\n  // dates Intl must never be handed the Temporal object itself — neither\n  // through formatToParts() below nor through toLocaleString() in the\n  // polyfill branch — since either route lets ICU's calendar math decide\n  // which month/weekday the date falls on, and that's exactly what the\n  // cutover corrupts. Route month/weekday name lookups through a safe\n  // modern reference date instead (preCutoverGregorianName above). Only\n  // month/weekday parts are affected: era is AD/CE either way for CE\n  // dates, and timeZoneName depends on the instant, not the calendar.\n  // Only Gregorian-shaped objects take this path — a Temporal object\n  // carrying a non-Gregorian calendar (hebrew, islamic, ...) has its\n  // month/weekday fields in that calendar already, and ICU's\n  // non-Gregorian calendars don't apply the Julian cutover at all, so\n  // feeding one through a gregory-keyed reference lookup would index the\n  // wrong month number into the wrong calendar. Custom vocabs never\n  // reach here (localeAwareName resolves them before calling intlPart).\n  if (\n    (partType === 'month' || partType === 'weekday') &&\n    formatterOptions.calendar === 'gregory' &&\n    isBeforeGregorianCutover(temporal)\n  ) {\n    return preCutoverGregorianName(temporal, locale, formatterOptions, partType);\n  }\n\n  // Temporal.prototype.toLocaleString() is part of the Temporal spec itself:\n  // polyfills implement the ICU formatting internally without needing the\n  // engine to recognize the object, so it works without native Intl support.\n  //\n  // Everything from here to the end of this function is genuinely\n  // reachable — NOT dead code — but only on a Node build where a global\n  // `Temporal` exists AND Intl.DateTimeFormat.formatToParts() recognizes\n  // native Temporal instances directly (this is real, observed to vary\n  // across Node versions: absent on the Node 22/24 builds this suite has\n  // been run against, present on at least one Node 26 build). This\n  // environment has no native Temporal (`typeof globalThis.Temporal ===\n  // 'undefined'`), so intlSupportsNativeTemporal() always returns false\n  // here and this branch can't be exercised from this test suite without\n  // faking native-instance recognition, which turned out to be\n  // impractical (Intl's native-Temporal detection isn't spoofable via a\n  // Proxy or valueOf() shim — see the M-02 regression test in\n  // temporalProvider.test.js for the same conclusion reached about the\n  // sibling probe function). Coverage numbers for this block will differ\n  // between Node versions for that reason; that's expected, not a\n  // regression.\n  /* c8 ignore start */\n  if (!intlSupportsNativeTemporal()) {\n    // normalizeLocaleTag: the active Temporal implementation's\n    // toLocaleString forwards the locale to Intl.DateTimeFormat, which\n    // (unlike this library's cache keys) rejects underscore-separated\n    // tags like 'en_US' outright.\n    // (Field-bag guard now runs unconditionally above, before this\n    // native-support branch, so it's not repeated here.)\n    try {\n      return ls.call(temporal, normalizeLocaleTag(locale), formatterOptions);\n    } catch (err) {\n      // The active Temporal implementation forwards the tag to Intl, which\n      // throws a bare RangeError for a malformed one — rethrow typed.\n      if (err instanceof RangeError) {\n        throw new InvalidLocaleError({ actual: locale, reason: err.message });\n      }\n      throw err;\n    }\n  }\n\n  // formatToParts() throws on ZonedDateTime directly (per spec), so convert\n  // to Instant and pass the zone via `timeZone` instead. Don't convert to\n  // PlainDateTime — that drops the zone, which breaks 'MMMM' + 'zzz' combos.\n  const { toInstant, timeZoneId } = temporal;\n  const isZoned = typeof toInstant === 'function' && typeof timeZoneId === 'string';\n  // has to be called as temporal.toInstant() because destructuring it off breaks\n  // the receiver and throws\n  const intlSafeTemporal = isZoned ? temporal.toInstant!() : temporal;\n  const nativeOptions: Intl.DateTimeFormatOptions = {\n    ...formatterOptions,\n    ...(isZoned ? { timeZone: timeZoneId } : {}),\n  };\n\n  const formatter = getFormatter(locale, nativeOptions);\n  const parts = formatter.formatToParts(intlSafeTemporal as Date | number);\n  const index = parts.findIndex((p) => p.type === partType);\n  if (index === -1) {\n    throw new Error(\n      `temporal-fmt: locale \"${locale}\" produced no \"${partType}\" part for this token. ` +\n      `This usually means the Temporal object is missing the field the token needs.`\n    );\n  }\n  // some locales (ja-JP) split a field across two parts — e.g. month \"8\"\n  // plus a counter suffix \"月\" as a separate sibling literal part. Merge in\n  // an adjacent literal only if it has no whitespace, so a genuine suffix\n  // gets folded in but an ordinary separator (the space before \"AM\") stays\n  // a separator. Mirrors partValue() in localeVocab.ts, which builds the\n  // vocab this token's output needs to match for parse() to round-trip.\n  let value = parts[index]!.value;\n  const prev = parts[index - 1];\n  const next = parts[index + 1];\n  if (prev?.type === 'literal' && !/\\s/.test(prev.value)) value = prev.value + value;\n  if (next?.type === 'literal' && !/\\s/.test(next.value)) value = value + next.value;\n  return value;\n}\n/* c8 ignore stop */\n\n// Temporal.prototype.toLocaleString() can't isolate a single field the way\n// formatToParts() can — asking for `hour` + `dayPeriod` together returns one\n// joined string (e.g. \"3 in the afternoon\"), and `dayPeriod` alone resolves\n// against a different, non-hour-anchored set of periods (\"in the\n// afternoon\"/\"昼\" instead of \"PM\"/\"午後\"). Day period only depends on the\n// hour anyway, so route it through a plain UTC Date and Intl.DateTimeFormat\n// instead — that's worked the same on every engine regardless of whether\n// Temporal itself is native or polyfilled.\nfunction dayPeriodPart(hour: number, locale: string): string {\n  // Custom vocab (when registered) takes precedence over Intl — same\n  // contract as the other locale-aware tokens. Intl won't know about a\n  // caller-supplied AM/PM string for a made-up locale key, so going\n  // through Intl would produce something other than what the caller\n  // registered.\n  const custom = getCustomVocab(locale);\n  if (custom) {\n    return hour < 12 ? custom.dayPeriod[0]! : custom.dayPeriod[1]!;\n  }\n  const date = new Date(Date.UTC(1970, 0, 1, hour));\n  const formatter = getFormatter(locale, { hour: 'numeric', hour12: true, timeZone: 'UTC' });\n  const part = formatter.formatToParts(date).find((p) => p.type === 'dayPeriod');\n  // Defensive guard, confirmed unreachable on this ICU build: forcing\n  // hour12: true (as this call always does) produces a dayPeriod part\n  // for every locale checked, including 24-hour-clock locales (ja-JP,\n  // zh-CN, th-TH, he-IL) and a wide sweep of less-common tags (dz-BT,\n  // bo-CN, am-ET, etc.). Same finding as partValue()'s twin guard in\n  // localeVocab.ts. Kept in case a future ICU/locale-data update\n  // produces a locale that genuinely omits it.\n  /* c8 ignore start */\n  if (!part) {\n    throw new Error(`temporal-fmt: locale \"${locale}\" produced no \"dayPeriod\" part for token \"a\".`);\n  }\n  /* c8 ignore stop */\n  return part.value;\n}\n\n// Resolves a locale-aware month/weekday name from the registered custom\n// vocab when one exists for this locale, falling through to Intl otherwise.\n// Without this, format() would silently keep producing Intl's strings while\n// parse() matched against the registered vocab — the two would round-trip-fail\n// against each other.\nfunction localeAwareName(\n  temporal: TemporalLike,\n  locale: string,\n  options: Intl.DateTimeFormatOptions,\n  partType: Intl.DateTimeFormatPartTypes,\n  customArray: string[] | undefined,\n  customIndex: number | undefined,\n): string {\n  if (customArray && customIndex !== undefined && customIndex >= 0 && customIndex < customArray.length) {\n    return customArray[customIndex]!;\n  }\n  return intlPart(temporal, locale, options, partType);\n}\n\n// Formats a `±HH:MM` offset string (the shape Temporal exposes on\n// ZonedDateTime.prototype.offset) into one of the six offset-token widths.\n// Width and Z-handling come from the variant letter+case:\n//\n//   X / x   — short form: minutes omitted when zero, no colon otherwise\n//   XX / xx — hours + minutes, no colon\n//   XXX / xxx — hours + minutes, with colon\n//\n// Uppercase (X) collapses +00:00 to \"Z\"; lowercase (x) always emits a\n// numeric offset, even for UTC. Mirrors the date-fns/Unicode-LDML offset\n// family — see README for the full variant table.\nfunction formatOffset(offset: string, variant: 'X' | 'XX' | 'XXX' | 'x' | 'xx' | 'xxx'): string {\n  if (offset === '+00:00' && (variant === 'X' || variant === 'XX' || variant === 'XXX')) {\n    return 'Z';\n  }\n  // Most offsets are 6 chars: sign + HH + ':' + MM. Pre-1900 local-mean-time\n  // zones can surface a seconds component too, 9 chars: sign + HH + ':' +\n  // MM + ':' + SS. \"xxx\" is the one variant with a always-signed,\n  // never-\"Z\" colon-separated shape wide enough to carry that unchanged,\n  // so it passes a sub-minute offset through verbatim. Every other\n  // variant has no seconds slot and must throw rather than silently\n  // truncate them away.\n  if (offset.length > 6) {\n    if (variant === 'xxx') {\n      return offset;\n    }\n    throw new Error(\n      `temporal-fmt: token \"${variant}\" cannot represent the offset \"${offset}\", ` +\n      `which has a seconds component. None of the X/XX/XXX/x/xx tokens ` +\n      `support offset seconds; use \"xxx\" instead, which formats the full ` +\n      `offset unchanged.`\n    );\n  }\n  const sign = offset[0]!;\n  const hours = offset.slice(1, 3);\n  const minutes = offset.slice(4, 6);\n  switch (variant) {\n    case 'X': case 'x':\n      // minutes only matter when they're non-zero — otherwise drop them\n      // entirely. Matches LDML: \"With a single X, the hours field is\n      // required. The minutes field is optional, but only if the\n      // minutes value is 0.\"\n      return minutes === '00' ? `${sign}${hours}` : `${sign}${hours}${minutes}`;\n    case 'XX': case 'xx':\n      return `${sign}${hours}${minutes}`;\n    case 'XXX': case 'xxx':\n      return `${sign}${hours}:${minutes}`;\n  }\n}\n\ntype TokenHandler = (t: TemporalLike, locale: string) => string;\n\n// Longest-first — tokenizer is greedy, \"yyyy\" has to be tried before \"yy\".\n//\n// Numeric tokens always render in ASCII digits, never locale-native\n// (Arabic-Indic, Devanagari, etc). Padding non-ASCII digits isn't as simple\n// as padding \"3\", and most consumers parsing these back out want plain\n// digits anyway.\nexport const TOKENS: Array<[string, TokenHandler, keyof TemporalLike]> = [\n  ['yyyy', (t) => pad(t.year!, 4), 'year'],\n  ['yy', (t) => {\n    // -45 % 100 === -45, so truncating negative years to 2 digits doesn't\n    // work and Math.abs() would make 45 CE and 45 BCE render the same.\n    if (t.year! < 0) {\n      throw new Error(\n        `temporal-fmt: token \"yy\" doesn't support negative years (got ${t.year}), ` +\n        `since truncating to 2 digits would make it indistinguishable from a ` +\n        `positive year. Use \"yyyy\" instead.`\n      );\n    }\n    return pad(t.year! % 100, 2);\n  }, 'year'],\n  // Unpadded year — no minimum width, unlike yyyy's fixed 4 digits.\n  // pad(n, 0) still does the right thing here: Math.abs(n) with no\n  // padStart floor just yields the plain digit string, and the sign\n  // handling (split off before padding) already covers negative years,\n  // so this doesn't need its own sign branch the way \"yy\" does.\n  ['y', (t) => pad(t.year!, 0), 'year'],\n  ['MMMM', (t, locale) => {\n    const custom = getCustomVocab(locale);\n    return localeAwareName(t, locale, { month: 'long' }, 'month', custom?.monthLong, t.month! - 1);\n  }, 'month'],\n  ['MMM', (t, locale) => {\n    const custom = getCustomVocab(locale);\n    return localeAwareName(t, locale, { month: 'short' }, 'month', custom?.monthShort, t.month! - 1);\n  }, 'month'],\n  ['MM', (t) => pad(t.month!, 2), 'month'],\n  ['M', (t) => String(t.month!), 'month'],\n  ['dd', (t) => pad(t.day!, 2), 'day'],\n  ['d', (t) => String(t.day!), 'day'],\n  ['EEEE', (t, locale) => {\n    const custom = getCustomVocab(locale);\n    return localeAwareName(t, locale, { weekday: 'long' }, 'weekday', custom?.weekdayLong, t.dayOfWeek! - 1);\n  }, 'dayOfWeek'],\n  ['EEE', (t, locale) => {\n    const custom = getCustomVocab(locale);\n    return localeAwareName(t, locale, { weekday: 'short' }, 'weekday', custom?.weekdayShort, t.dayOfWeek! - 1);\n  }, 'dayOfWeek'],\n  ['HH', (t) => pad(t.hour!, 2), 'hour'],\n  ['H', (t) => String(t.hour!), 'hour'],\n  ['hh', (t) => pad(t.hour! % 12 || 12, 2), 'hour'],\n  ['h', (t) => String(t.hour! % 12 || 12), 'hour'],\n  ['mm', (t) => pad(t.minute!, 2), 'minute'],\n  ['m', (t) => String(t.minute!), 'minute'],\n  ['ss', (t) => pad(t.second!, 2), 'second'],\n  ['s', (t) => String(t.second!), 'second'],\n  // Fractional-second tokens, S through SSSSSSSSS (1-9 digits). Each token\n  // formats a slice of the same underlying nanosecond-of-second value —\n  // combining millisecond/microsecond/nanosecond into one 9-digit number\n  // and truncating to the token's width — so \"SSS\" keeps meaning exactly\n  // what it always meant (3-digit milliseconds) while wider tokens expose\n  // the precision Temporal actually carries. formatFraction below is the\n  // shared implementation; see its comment for the truncate-not-round\n  // rule and why.\n  ['SSSSSSSSS', (t) => pad.fraction(t, 9), 'millisecond'],\n  ['SSSSSSSS', (t) => pad.fraction(t, 8), 'millisecond'],\n  ['SSSSSSS', (t) => pad.fraction(t, 7), 'millisecond'],\n  ['SSSSSS', (t) => pad.fraction(t, 6), 'millisecond'],\n  ['SSSSS', (t) => pad.fraction(t, 5), 'millisecond'],\n  ['SSSS', (t) => pad.fraction(t, 4), 'millisecond'],\n  ['SSS', (t) => pad.fraction(t, 3), 'millisecond'],\n  ['SS', (t) => pad.fraction(t, 2), 'millisecond'],\n  ['S', (t) => pad.fraction(t, 1), 'millisecond'],\n  // dayPeriod text is locale-specific (AM/PM in en-US, م/ص in ar-EG) but\n  // still needs .hour on the input to compute which period it is\n  ['a', (t, locale) => dayPeriodPart(t.hour!, locale), 'hour'],\n  ['zzz', (t) => t.timeZoneId!, 'timeZoneId'],\n  // Numeric UTC offset tokens (date-fns/Unicode-LDML family). Only\n  // ZonedDateTime carries an offset, so the field check in format() throws\n  // the same \"requires offset, which this Temporal object doesn't have\"\n  // error zzz throws on PlainDate/PlainTime/PlainDateTime — same\n  // validation path, just a different field name. See formatOffset above\n  // for the per-variant width and Z/numeric distinction.\n  ['xxx', (t) => formatOffset(t.offset!, 'xxx'), 'offset'],\n  ['xx', (t) => formatOffset(t.offset!, 'xx'), 'offset'],\n  ['X', (t) => formatOffset(t.offset!, 'X'), 'offset'],\n  ['XX', (t) => formatOffset(t.offset!, 'XX'), 'offset'],\n  ['XXX', (t) => formatOffset(t.offset!, 'XXX'), 'offset'],\n  ['x', (t) => formatOffset(t.offset!, 'x'), 'offset'],\n\n  // Ordinal day (1st, 2nd, 3rd, ... 21st). English suffix rules only —\n  // locale-aware ordinals (\"2.\" in de-DE, \"2日\" in ja-JP) are out of scope,\n  // since the rest of this library routes locale-specific names through\n  // Intl.DateTimeFormat, and Intl has no part type for ordinals. Format-only:\n  // the suffix isn't structurally distinguishable from a literal in a parse\n  // context (a \"st\"/\"nd\"/\"rd\"/\"th\" suffix isn't a digit and would collide\n  // with any adjacent literal text), so there's no good way to read it back.\n  ['do', (t) => {\n    const day = t.day!;\n    const lastDigit = day % 10;\n    // 11, 12, 13 are the exception — they'd otherwise match the 1/2/3 rule\n    // and produce \"11st\"/\"12nd\"/\"13rd\", which is wrong. They always take \"th\".\n    const lastTwoDigits = day % 100;\n    if (lastTwoDigits >= 11 && lastTwoDigits <= 13) {\n      return day + 'th';\n    }\n    if (lastDigit === 1) return day + 'st';\n    if (lastDigit === 2) return day + 'nd';\n    if (lastDigit === 3) return day + 'rd';\n    return day + 'th';\n  }, 'day'],\n\n  // Quarter computed from month: 1-3=Q1, 4-6=Q2, 7-9=Q3, 10-12=Q4.\n  // `Q` is plain numeric, `QQQ` renders as \"Q3\" — same convention as\n  // date-fns's `Q` and `QQQ` for parity with the most common prior art.\n  // Both format and parse; parse() cross-checks Q/QQQ against the parsed\n  // month in the same spirit as the EEEE-vs-date cross-check.\n  ['Q', (t) => String(Math.ceil(t.month! / 3)), 'month'],\n  ['QQQ', (t) => 'Q' + Math.ceil(t.month! / 3), 'month'],\n\n  // ISO 8601 week and week-numbering year. Both are format-only — parsing\n  // \"ww\"/\"RRRR\" back into a real date requires resolving an ISO week + a\n  // weekday (or some other disambiguator) to a specific date, which is a\n  // different parsing surface than the token-based parse() here. The\n  // ISO-week year (RRRR) can differ from the calendar year at the boundary:\n  // Dec 29-31 often belong to week 1 of the *next* year; Jan 1-3 often\n  // belong to week 52/53 of the *previous* year. See isoWeekYearAndWeek().\n  ['ww', (t) => {\n    requireFields(t, 'ww', 'year', 'month', 'day');\n    const { week } = isoWeekYearAndWeek(t.year!, t.month!, t.day!, t.dayOfWeek!);\n    return pad(week, 2);\n  }, 'dayOfWeek'],\n  ['RRRR', (t) => {\n    requireFields(t, 'RRRR', 'year', 'month', 'day');\n    const { isoYear } = isoWeekYearAndWeek(t.year!, t.month!, t.day!, t.dayOfWeek!);\n    return pad(isoYear, 4);\n  }, 'dayOfWeek'],\n\n  // Day of year — number of days since Jan 1 (1-366). Three widths:\n  //   D    — unpadded (1, 2, 366)\n  //   DD   — 2-digit minimum (zero-padded if <100)\n  //   DDD  — 3-digit zero-padded (001, 002, 366)\n  // Format-only — parsing day-of-year requires resolving against a year,\n  // which is a different shape from the token-based parse() surface.\n  // The dayOfYearHelper() in calendarUtils.ts covers the same field for\n  // callers who need the numeric value.\n  ['D', (t) => {\n    requireFields(t, 'D', 'year', 'month');\n    return String(dayOfYear(t.year!, t.month!, t.day!));\n  }, 'day'],\n  ['DD', (t) => {\n    requireFields(t, 'DD', 'year', 'month');\n    return pad(dayOfYear(t.year!, t.month!, t.day!), 2);\n  }, 'day'],\n  ['DDD', (t) => {\n    requireFields(t, 'DDD', 'year', 'month');\n    return pad(dayOfYear(t.year!, t.month!, t.day!), 3);\n  }, 'day'],\n\n  // Stand-alone month — uses Intl's stand-alone form. In most locales\n  // (en, fr, de, es) this is identical to MMMM/MMM. In Slavic/Baltic\n  // locales (cs, sk, pl, ru) the stand-alone form differs from the\n  // format form (nominative vs genitive case). LLLL = long, LLL = short.\n  ['LLLL', (t, locale) => {\n    const custom = getCustomVocab(locale);\n    return localeAwareName(t, locale, { month: 'long' }, 'month', custom?.monthLong, t.month! - 1);\n  }, 'month'],\n  ['LLL', (t, locale) => {\n    const custom = getCustomVocab(locale);\n    return localeAwareName(t, locale, { month: 'short' }, 'month', custom?.monthShort, t.month! - 1);\n  }, 'month'],\n\n  // Stand-alone weekday — same pattern as stand-alone month but for\n  // weekday names. cccc = long, ccc = short.\n  ['cccc', (t, locale) => {\n    const custom = getCustomVocab(locale);\n    return localeAwareName(t, locale, { weekday: 'long' }, 'weekday', custom?.weekdayLong, t.dayOfWeek! - 1);\n  }, 'dayOfWeek'],\n  ['ccc', (t, locale) => {\n    const custom = getCustomVocab(locale);\n    return localeAwareName(t, locale, { weekday: 'short' }, 'weekday', custom?.weekdayShort, t.dayOfWeek! - 1);\n  }, 'dayOfWeek'],\n\n  // Era — locale-aware (\"AD\"/\"BC\" in en, \"ap. J.-C.\"/\"av. J.-C.\" in fr).\n  // GGGG = long, G = short. Format-only.\n  ['GGGG', (t, locale) => {\n    return intlPart(t, locale, { era: 'long' }, 'era');\n  }, 'year'],\n  ['G', (t, locale) => {\n    return intlPart(t, locale, { era: 'short' }, 'era');\n  }, 'year'],\n\n  // Localized timezone name — uses Intl's longLocalized/short timezone\n  // name option. Format-only — these names are locale-dependent and\n  // vary by season (EST vs EDT), so parsing them back requires a\n  // lookup table that isn't practical to ship.\n  ['zzzz', (t, locale) => {\n    return intlPart(t, locale, { timeZoneName: 'longGeneric' as Intl.DateTimeFormatOptions['timeZoneName'] }, 'timeZoneName' as Intl.DateTimeFormatPartTypes);\n  }, 'timeZoneId'],\n  ['z', (t, locale) => {\n    return intlPart(t, locale, { timeZoneName: 'short' as Intl.DateTimeFormatOptions['timeZoneName'] }, 'timeZoneName' as Intl.DateTimeFormatPartTypes);\n  }, 'timeZoneId'],\n\n];\n\n// Mod-registered tokens, layered on top of the static TOKENS above.\n// Last-write-wins by name (same rule as registerLocale and\n// createFormatter's own token merging) — a second registerFormatToken()\n// call for a name already claimed, whether that name came from another\n// mod or from TOKENS itself, replaces the earlier entry. See\n// registerFormatToken() in runtime.ts for why this beats a hard error:\n// Mod.priority exists precisely so an author can control who wins a\n// shared key, and that only means something if collisions actually\n// resolve instead of throwing.\nconst registeredTokens = new Map<string, [string, TokenHandler, keyof TemporalLike]>();\n\n// tokenize.ts and format.ts each derive a lookup table from TOKENS at\n// import time (SORTED_TOKEN_STRINGS, HANDLER_BY_TOKEN). Once mods can\n// add tokens after those tables are built, something has to tell both\n// modules to rebuild — this is that hook. Both subscribers rebuild in\n// the same call so the tokenizer's idea of \"is this a token\" and\n// format()'s idea of \"what does this token do\" can never drift apart\n// (the c8-ignored \"impossible\" branches in format.ts assume exactly\n// that they can't).\nconst rebuildListeners: Array<() => void> = [];\n\nexport function onTokenTableChange(listener: () => void): void {\n  rebuildListeners.push(listener);\n}\n\n// All tokens currently in effect: built-ins plus mod-registered,\n// mod-registered winning on a name clash. Recomputed on every call\n// rather than cached here — registration only happens at mod-load\n// time, so there's no hot-path cost to paying for the rebuild each time\n// a listener fires.\nexport function getEffectiveTokens(): Array<[string, TokenHandler, keyof TemporalLike]> {\n  const merged = new Map(TOKENS.map((t) => [t[0], t] as const));\n  for (const [name, entry] of registeredTokens) merged.set(name, entry);\n  return [...merged.values()];\n}\n\nexport function registerToken(token: [string, TokenHandler, keyof TemporalLike]): void {\n  registeredTokens.set(token[0], token);\n  for (const listener of rebuildListeners) listener();\n}\n\n// Test-only: clears mod-registered tokens and notifies subscribers, so\n// one test file's registerFormatToken() call can't leak into the next.\n// Mirrors _resetOverridesForTesting() in runtime.ts.\nexport function _resetRegisteredTokensForTesting(): void {\n  registeredTokens.clear();\n  for (const listener of rebuildListeners) listener();\n}","/*\n * Copyright 2026 DirazCoder\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { TOKENS, getEffectiveTokens, onTokenTableChange } from './tokens.js';\nimport { FormatSyntaxError, UnknownTokenError } from './errors.js';\n\nexport type Piece =\n  | { kind: 'token'; value: string }\n  | { kind: 'literal'; value: string };\n\n// A piece plus its exact source span in the ORIGINAL format string.\n// `start`/`end` are UTF-16 code-unit indices, half-open [start, end).\n// Decoded literals can be shorter than their span ('' is 2 source\n// chars → 1 decoded quote), which is exactly why positions computed\n// from decoded lengths (the old approach in analyze.ts) drifted after\n// any quoted text.\nexport interface SpannedPiece {\n  kind: 'token' | 'literal';\n  value: string;\n  start: number;\n  end: number;\n}\n\n// gotta sort longest-first or the greedy scan grabs \"M\" when \"MMMM\" was actually there.\n// Starts from the static TOKENS (so this module works before any mod has\n// registered anything) and rebuilds from tokens.ts's getEffectiveTokens()\n// whenever a mod calls registerFormatToken — otherwise a token registered\n// after this module loaded would never be recognized here, and format()\n// would tokenize it as literal text even though HANDLER_BY_TOKEN in\n// format.ts knows about it. `let`, not `const`, precisely so the rebuild\n// below can replace the binding rather than mutate a shared array in place.\nlet SORTED_TOKEN_STRINGS = TOKENS.map(([tok]) => tok).sort((a, b) => b.length - a.length);\n\nonTokenTableChange(() => {\n  SORTED_TOKEN_STRINGS = getEffectiveTokens()\n    .map(([tok]) => tok)\n    .sort((a, b) => b.length - a.length);\n});\n\n/**\n * Splits a format string like `\"yyyy-MM-dd 'at' HH:mm\"` into token/literal\n * pieces, each with its exact source span. Text in single quotes is always\n * literal (e.g. write 'rd' in \"3rd\" so it's not read as the day token). A\n * doubled quote ('') means a literal quote character, both inside a quoted\n * span and standalone.\n */\nexport function tokenizeWithSpans(format: string): SpannedPiece[] {\n  const pieces: SpannedPiece[] = [];\n  let i = 0;\n\n  while (i < format.length) {\n    const ch = format[i];\n\n    if (ch === \"'\") {\n      // gotta check the doubled-quote case first, otherwise \"''best''\" parses wrong\n      if (format[i + 1] === \"'\") {\n        appendLiteral(pieces, \"'\", i, i + 2);\n        i += 2;\n        continue;\n      }\n\n      let j = i + 1;\n      let literal = '';\n      let closed = false;\n      while (j < format.length) {\n        if (format[j] === \"'\") {\n          if (format[j + 1] === \"'\") {\n            literal += \"'\";\n            j += 2;\n            continue;\n          }\n          closed = true;\n          j += 1;\n          break;\n        }\n        literal += format[j];\n        j += 1;\n      }\n\n      if (!closed) {\n        throw new FormatSyntaxError({\n          format,\n          message: `temporal-fmt: unterminated quote in format string \"${format}\"`,\n        });\n      }\n\n      appendLiteral(pieces, literal, i, j);\n      i = j;\n      continue;\n    }\n\n    const match = SORTED_TOKEN_STRINGS.find((tok) => format.startsWith(tok, i));\n    if (match) {\n      // this is already the longest token that starts here, so if there's\n      // one more of the same char after it, that's not a real token — it'd\n      // just silently fall through to whatever handles that next char and\n      // get glued onto this one. found this the hard way: \"zzzz\" was\n      // parsing as zzz + literal \"z\", \"MMMMM\" as MMMM + the M token. so now\n      // we just treat the whole overlong run as one bad token instead\n      const runChar = match[match.length - 1];\n      if (format[i + match.length] === runChar) {\n        let end = i + match.length;\n        while (format[end] === runChar) end += 1;\n        // UnknownTokenError, not FormatSyntaxError: wrapUntypedError's\n        // classifier already treats this exact message (\"isn't a\n        // recognized token\") as UNKNOWN_TOKEN (see errors.test.js's\n        // \"overlong token run classifies as UnknownTokenError\"), and a\n        // direct throw here needs to agree with what safeParse's fallback\n        // path would have classified it as.\n        throw new UnknownTokenError({\n          format,\n          token: format.slice(i, end),\n          message:\n            `temporal-fmt: \"${format.slice(i, end)}\" in format string \"${format}\" isn't a recognized token — ` +\n            `did you mean \"${match}\"?`,\n        });\n      }\n      pieces.push({ kind: 'token', value: match, start: i, end: i + match.length });\n      i += match.length;\n      continue;\n    }\n\n    // not a token or quote — pass through as-is\n    appendLiteral(pieces, ch, i, i + 1);\n    i += 1;\n  }\n\n  return pieces;\n}\n\n/**\n * Splits a format string like `\"yyyy-MM-dd 'at' HH:mm\"` into token/literal\n * pieces. Text in single quotes is always literal (e.g. write 'rd' in\n * \"3rd\" so it's not read as the day token). A doubled quote ('') means a\n * literal quote character, both inside a quoted span and standalone.\n */\nexport function tokenize(format: string): Piece[] {\n  return tokenizeWithSpans(format).map(({ kind, value }) => ({ kind, value }));\n}\n\n// merges into the previous piece if it's also a literal, so \"---\" is one\n// piece instead of three (spans track the full merged range)\nfunction appendLiteral(pieces: SpannedPiece[], value: string, start: number, end: number): void {\n  const last = pieces[pieces.length - 1];\n  if (last && last.kind === 'literal' && last.end === start) {\n    last.value += value;\n    last.end = end;\n  } else {\n    pieces.push({ kind: 'literal', value, start, end });\n  }\n}\n","/*\n * Copyright 2026 DirazCoder\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n// format strings are basically always short hand-written stuff like \"yyyy-MM-dd\"\n// so if something's way longer than that, cap it before tokenize() chokes on it\nexport const MAX_FORMAT_LENGTH = 1000;\nexport const MAX_INPUT_LENGTH = 100_000;","/*\n * Copyright 2026 DirazCoder\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n// numbering systems. latn (ASCII digits) is the default, but arab, deva,\n// beng, etc are all options, configurable per format call.\n//\n// the tokens in this lib always spit out ASCII digits normally (check\n// tokens.ts's pad() — just String(n), which is ASCII). this module bolts\n// on the ability to convert that output to a locale's native digits via\n// Intl.NumberFormat, since that's the standard way JS does digit\n// transliteration anyway.\n//\n// parse side is stricter: parse() only accepts ASCII digits, matches how\n// NUMERIC_FRAGMENTS is already built. parseNumberingSystem converts\n// input digits to ASCII first — an explicit opt-in per call, never\n// silently accepting any numeral system that shows up.\n//\n// both directions also accept 'auto': instead of requiring the caller to\n// know the ICU numbering-system code for their locale, ask\n// Intl.NumberFormat(locale).resolvedOptions().numberingSystem what the\n// locale itself uses and transliterate with that.\n\nimport { DEFAULT_LOCALE, type FormatOptions } from './tokens.js';\nimport { InvalidLocaleError } from './errors.js';\nimport { canonicalCacheKey, normalizeLocaleTag } from './localeVocab.js';\n\nexport type NumberingSystem = 'latn' | 'arab' | 'deva' | 'beng' | 'guru' | 'gujr' | 'orya' | 'tamldec' | 'telu' | 'knda' | 'mlym' | 'fullwide' | 'hanidec';\n\n// What a caller may pass as numberingSystem / parseNumberingSystem: an\n// explicit system name, or 'auto' to derive the system from the call's\n// locale. The `(string & {})` keeps arbitrary strings compiling (the\n// runtime still validates them against SUPPORTED_NUMBERING_SYSTEMS and\n// throws on unknown names, unchanged) while editors still offer the\n// known literals — 'latn', 'arab', ..., 'auto' — as completions.\nexport type NumberingSystemOption = NumberingSystem | 'auto' | (string & {});\n\n// every NumberingSystem value we support. latn's the default and\n// what the rest of this lib naturally produces\nexport const SUPPORTED_NUMBERING_SYSTEMS: ReadonlySet<string> = new Set([\n  'latn', 'arab', 'deva', 'beng', 'guru', 'gujr', 'orya', 'tamldec',\n  'telu', 'knda', 'mlym', 'fullwide', 'hanidec',\n]);\n\nconst digitMapCache = new Map<string, Record<string, string>>();\n\n// 'auto' resolutions, keyed by canonical locale tag (same key discipline\n// as every other locale-keyed cache in this library — 'ar_EG' and 'ar-EG'\n// fold together instead of costing two entries). Intl.NumberFormat\n// construction isn't free and format() runs in loops (a table of dates, one\n// row per record), so resolve each locale once. Bounded, evicting the\n// oldest insertion, mirroring formatterCache in tokens.ts.\nconst autoNumberingCache = new Map<string, string>();\nconst MAX_AUTO_NUMBERING_CACHE = 500;\n\n// Turns 'auto' into a concrete system by asking Intl what the locale\n// itself defaults to (ar-EG -> arab, bn-BD -> beng, en-US -> latn). When\n// the locale's native system isn't one this library can transliterate\n// (thai, laoo, mymr, ... — anything outside SUPPORTED_NUMBERING_SYSTEMS),\n// fall back to 'latn' rather than throwing: 'auto' means \"use whatever\n// this locale naturally uses, if you can\", not \"throw on locales with\n// numerals this library doesn't cover\". A malformed locale tag DOES\n// throw — typed InvalidLocaleError, matching getFormatter() in tokens.ts —\n// since asking to derive from a locale that doesn't exist is a caller bug,\n// not a data condition to paper over.\nfunction resolveAutoNumberingSystem(locale: string): string {\n  const key = canonicalCacheKey(locale);\n  const cached = autoNumberingCache.get(key);\n  if (cached !== undefined) return cached;\n  let resolved: string;\n  try {\n    resolved = new Intl.NumberFormat(normalizeLocaleTag(locale)).resolvedOptions().numberingSystem;\n  } catch (err) {\n    throw new InvalidLocaleError({ actual: locale, reason: (err as Error).message });\n  }\n  const system = SUPPORTED_NUMBERING_SYSTEMS.has(resolved) ? resolved : 'latn';\n  if (autoNumberingCache.size >= MAX_AUTO_NUMBERING_CACHE) {\n    // not real LRU, just evicts oldest insertion — fine for this key space\n    const oldestKey = autoNumberingCache.keys().next().value;\n    if (oldestKey !== undefined) autoNumberingCache.delete(oldestKey);\n  }\n  autoNumberingCache.set(key, system);\n  return system;\n}\n\n// Shared front door for both option names. undefined stays 'latn' — the\n// default is unchanged; 'auto' is an opt-in, not a new default. Anything\n// else passes through untouched for convertDigits/convertDigitsToAscii\n// to validate against the supported set (they throw on unknown names).\nfunction resolveRequestedSystem(requested: string | undefined, locale: string | undefined): string {\n  if (requested === undefined) return 'latn';\n  if (requested === 'auto') return resolveAutoNumberingSystem(locale ?? DEFAULT_LOCALE);\n  return requested;\n}\n\n// builds a digit-transliteration map per numbering system. renders 0-9\n// through Intl.NumberFormat in the target system, then builds the lookup\n// table from that. caching it since spinning up a formatter isn't free\n// and we reuse the same map for every digit we convert\nfunction getDigitMap(system: string): Record<string, string> {\n  let map = digitMapCache.get(system);\n  if (map) return map;\n  /* c8 ignore start @preserve -- this branch is dead by construction, not\n     just untested: both callers (convertDigits, convertDigitsToAscii)\n     already bail out early on system === 'latn' before ever calling\n     getDigitMap, so it never actually gets invoked with 'latn'. keeping\n     it anyway as a defensive fallback rather than betting that stays\n     true forever */\n  if (system === 'latn') {\n    map = {};\n    for (let i = 0; i < 10; i++) map[String(i)] = String(i);\n  } else {\n    /* c8 ignore stop @preserve */\n    const fmt = new Intl.NumberFormat('en-US-u-nu-' + system, { useGrouping: false });\n    map = {};\n    for (let i = 0; i < 10; i++) {\n      map[String(i)] = fmt.format(i);\n    }\n  }\n  digitMapCache.set(system, map);\n  return map;\n}\n\n// swaps every ASCII digit in `s` for its equivalent in the target\n// numbering system. anything that's not a digit passes through untouched\nexport function convertDigits(s: string, system: string): string {\n  if (system === 'latn') return s;\n  if (!SUPPORTED_NUMBERING_SYSTEMS.has(system)) {\n    throw new InvalidLocaleError({ actual: system, reason: `numbering system \"${system}\" is not supported. Supported: ${[...SUPPORTED_NUMBERING_SYSTEMS].join(', ')}.` });\n  }\n  const map = getDigitMap(system);\n  let result = '';\n  for (const ch of s) {\n    if (ch >= '0' && ch <= '9') {\n      // map[ch] is always populated for 0-9 — getDigitMap builds all ten\n      // keys for every system we support, and ch is already range-checked\n      // above. the ?? ch is really just there to satisfy TS about Record's\n      // implicit undefined, not because this path is actually reachable\n      /* c8 ignore next */\n      result += map[ch] ?? ch;\n    } else {\n      result += ch;\n    }\n  }\n  return result;\n}\n\n// inverse of convertDigits — takes non-ASCII digits back to ASCII. used\n// by parse() when someone passes an explicit numberingSystem option.\n// throws on anything unsupported\nexport function convertDigitsToAscii(s: string, system: string): string {\n  // same dead-by-construction thing as the 'latn' guard above —\n  // applyParseNumbering (the only caller) already returns early on\n  // 'latn' before this ever gets called, so system's never actually\n  // 'latn' here in practice. leaving the guard anyway in case someone\n  // calls this directly someday without going through that guard\n  /* c8 ignore next */\n  if (system === 'latn') return s;\n  if (!SUPPORTED_NUMBERING_SYSTEMS.has(system)) {\n    throw new InvalidLocaleError({ actual: system, reason: `numbering system \"${system}\" is not supported.` });\n  }\n  const map = getDigitMap(system);\n  // just flip the map around\n  const reverse: Record<string, string> = {};\n  for (const k of Object.keys(map)) reverse[map[k]!] = k;\n  let result = '';\n  for (const ch of s) {\n    result += reverse[ch] ?? ch;\n  }\n  return result;\n}\n\n// FormatOptions plus a numberingSystem field. pass { numberingSystem: 'arab' }\n// to format() to get Arabic-Indic digits out, or { numberingSystem: 'auto' }\n// to use whichever numeral system the call's locale itself defaults to\n// (ar-EG -> arab, bn-BD -> beng, en-US -> latn), resolved via\n// Intl.NumberFormat(locale).resolvedOptions().numberingSystem with a\n// 'latn' fallback for locales whose native system isn't supported here.\n// Unset still means 'latn' — 'auto' is an opt-in, not a default change.\nexport interface NumberingFormatOptions extends FormatOptions {\n  numberingSystem?: NumberingSystemOption;\n}\n\n// same idea but for the parse side. called parseNumberingSystem instead of\n// just numberingSystem so someone mixing format() and parse() options in\n// one config object can set both independently — the two directions\n// aren't always symmetric (you might want native digits out without\n// wanting to accept them back in, or vice versa). 'auto' works here too,\n// resolving from the parse call's own locale the same way the format\n// side does.\nexport interface NumberingParseOptions extends FormatOptions {\n  parseNumberingSystem?: NumberingSystemOption;\n}\n\n// format-path helper: takes format()'s ASCII output and converts digits\n// if numberingSystem was asked for. lives here so format.ts doesn't need\n// to know anything about numbering systems\nexport function applyNumbering(s: string, options: NumberingFormatOptions): string {\n  const system = resolveRequestedSystem(options.numberingSystem, options.locale);\n  if (system === 'latn') return s;\n  return convertDigits(s, system);\n}\n\n// parse-path helper: converts input digits to ASCII before matching, if\n// parseNumberingSystem got set. kept as a separate option name from the\n// format side so callers can be explicit about which direction they\n// actually want transliterated\nexport function applyParseNumbering(s: string, options: { parseNumberingSystem?: string; locale?: string }): string {\n  // both call sites for this (both in parse.ts) already guard with\n  // `if (options.parseNumberingSystem)` before calling, so an undefined\n  // parseNumberingSystem never actually reaches here from parse() itself —\n  // the undefined handling inside resolveRequestedSystem is dead by\n  // construction from that direction. leaving it in as a safety net\n  // rather than betting every future caller replicates the same guard\n  // (this is a public export; direct calls don't come pre-guarded).\n  const system = resolveRequestedSystem(options.parseNumberingSystem, options.locale);\n  if (system === 'latn') return s;\n  return convertDigitsToAscii(s, system);\n}"],"mappings":";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;;AC4DA,IAAI;AAQJ,IAAM,oBAAuC,CAAC;AAEvC,SAAS,2BAA2B,UAA4B;AACrE,oBAAkB,KAAK,QAAQ;AACjC;AAyBA,SAAS,kBAAiD;AACxD,SAAO,oBAAqB,WAA2D;AACzF;AAEO,SAAS,cAAiC;AAC/C,QAAM,WAAW,gBAAgB;AACjC,MAAI,CAAC,UAAU;AACb,UAAM,IAAI;AAAA,MACR;AAAA,IAGF;AAAA,EACF;AACA,SAAO;AACT;;;AC/BO,IAAM,mBAAN,cAA+B,MAAM;AAAA,EACjC;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EAET,YAAY,SAAiB,QAAgC;AAC3D,UAAM,OAAO;AACb,SAAK,OAAO;AACZ,SAAK,OAAO,OAAO;AACnB,SAAK,QAAQ,OAAO;AACpB,SAAK,SAAS,OAAO;AACrB,SAAK,QAAQ,OAAO;AACpB,SAAK,WAAW,OAAO;AACvB,SAAK,WAAW,OAAO;AACvB,SAAK,SAAS,OAAO;AACrB,SAAK,SAAS,OAAO;AAIrB,UAAM,UAAW,MAAsF;AACvG,QAAI,OAAO,YAAY,YAAY;AACjC,cAAQ,MAAM,KAAK,WAAW;AAAA,IAChC;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKA,SAAqE;AACnE,WAAO;AAAA,MACL,MAAM,KAAK;AAAA,MACX,SAAS,KAAK;AAAA,MACd,MAAM,KAAK;AAAA,MACX,OAAO,KAAK;AAAA,MACZ,QAAQ,KAAK;AAAA,MACb,OAAO,KAAK;AAAA,MACZ,UAAU,KAAK;AAAA,MACf,UAAU,KAAK;AAAA,MACf,QAAQ,KAAK;AAAA,MACb,QAAQ,KAAK;AAAA,IACf;AAAA,EACF;AACF;AAOO,IAAM,oBAAN,cAAgC,iBAAiB;AAAA,EACtD,YAAY,QAAqE;AAC/E,UAAM,EAAE,SAAS,GAAG,KAAK,IAAI;AAC7B;AAAA,MACE,WAAW,kBAAkB,OAAO,UAAU,EAAE,uBAAuB,OAAO,SAAS,KAAK,OAAO,MAAM,KAAK,EAAE;AAAA,MAChH,EAAE,MAAM,uBAAuB,GAAG,KAAK;AAAA,IACzC;AACA,SAAK,OAAO;AAAA,EACd;AACF;AAEO,IAAM,oBAAN,cAAgC,iBAAiB;AAAA,EACtD,YAAY,QAAqE;AAC/E,UAAM,EAAE,SAAS,GAAG,KAAK,IAAI;AAC7B;AAAA,MACE,WAAW,UAAU,OAAO,SAAS,EAAE,2CAA2C,OAAO,SAAS,sBAAsB,OAAO,MAAM,MAAM,EAAE;AAAA,MAC7I,EAAE,MAAM,iBAAiB,GAAG,KAAK;AAAA,IACnC;AACA,SAAK,OAAO;AAAA,EACd;AACF;AAwBA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAwBA;AAwBA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAqBA;AAaO,IAAM,qBAAN,cAAiC,iBAAiB;AAAA,EACvD,YAAY,QAAqE;AAC/E,UAAM,EAAE,SAAS,GAAG,KAAK,IAAI;AAC7B;AAAA,MACE,WAAW,WAAW,OAAO,UAAU,EAAE,8BAA8B,OAAO,SAAS,KAAK,OAAO,MAAM,KAAK,EAAE;AAAA,MAChH,EAAE,MAAM,kBAAkB,GAAG,KAAK;AAAA,IACpC;AACA,SAAK,OAAO;AAAA,EACd;AACF;AA4BA;AAAA;AAoCA;;;AC1SA,IAAM,eAAe,oBAAI,IAAyB;AAmK3C,SAAS,mBAAmB,QAAwB;AACzD,SAAO,OAAO,QAAQ,MAAM,GAAG;AACjC;AAMA,IAAM,oBAAoB,oBAAI,IAAoB;AAClD,IAAM,0BAA0B;AAEzB,SAAS,kBAAkB,QAAwB;AACxD,QAAM,MAAM,kBAAkB,IAAI,MAAM;AACxC,MAAI,QAAQ,OAAW,QAAO;AAC9B,MAAI;AACJ,MAAI;AAKF,UAAM,IAAI,KAAK,OAAO,OAAO,QAAQ,MAAM,GAAG,CAAC,EAAE,SAAS,EAAE,YAAY;AAAA,EAC1E,QAAQ;AAKN,UAAM;AAAA,EACR;AACA,MAAI,kBAAkB,QAAQ,yBAAyB;AACrD,UAAM,YAAY,kBAAkB,KAAK,EAAE,KAAK,EAAE;AAClD,QAAI,cAAc,OAAW,mBAAkB,OAAO,SAAS;AAAA,EACjE;AACA,oBAAkB,IAAI,QAAQ,GAAG;AACjC,SAAO;AACT;AAgCO,SAAS,UAAU,WAAgC,MAAY,MAA4C;AAChH,QAAM,QAAQ,UAAU,cAAc,IAAI;AAC1C,QAAM,QAAQ,MAAM,UAAU,CAAC,MAAM,EAAE,SAAS,IAAI;AAAA,EACpD;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAYA;AACA,MAAI,UAAU,IAAI;AAChB,UAAM,IAAI,mBAAmB;AAAA,MAC3B,SAAS,qCAAqC,IAAI;AAAA,IACpD,CAAC;AAAA,EACH;AAAA,EACA;AACA,MAAI,QAAQ,MAAM,KAAK,EAAG;AAC1B,QAAM,OAAO,MAAM,QAAQ,CAAC;AAC5B,QAAM,OAAO,MAAM,QAAQ,CAAC;AAG5B,MAAI,MAAM,SAAS,aAAa,CAAC,KAAK,KAAK,KAAK,KAAK,EAAG,SAAQ,KAAK,QAAQ;AAC7E,MAAI,MAAM,SAAS,aAAa,CAAC,KAAK,KAAK,KAAK,KAAK,EAAG,SAAQ,QAAQ,KAAK;AAC7E,SAAO;AACT;AAqCO,SAAS,eAAe,QAAyC;AACtE,QAAM,WAAW,kBAAkB,MAAM;AACzC,SAAO,aAAa,IAAI,QAAQ;AAClC;;;ACjTA,IAAM,2BAA2B,CAAC,GAAG,IAAI,IAAI,IAAI,KAAK,KAAK,KAAK,KAAK,KAAK,KAAK,KAAK,GAAG;AAEhF,SAAS,oBAAoB,MAAuB;AAIzD,SAAQ,OAAO,MAAM,KAAK,OAAO,QAAQ,KAAM,OAAO,QAAQ;AAChE;AAEA,SAAS,WAAW,MAAyB;AAC3C,SAAO,oBAAoB,IAAI,IAAI,MAAM;AAC3C;AAEO,SAAS,UAAU,MAAc,OAAe,KAAqB;AAC1E,MAAI,MAAM,yBAAyB,QAAQ,CAAC,IAAK;AACjD,MAAI,QAAQ,KAAK,oBAAoB,IAAI,EAAG,QAAO;AACnD,SAAO;AACT;AAKA,IAAM,iBAAiB;AACvB,IAAM,6BAA6B;AAW5B,SAAS,cAAc,MAAc,OAAe,KAAqB;AAC9E,QAAM,KAAK,SAAS,IAAI,OAAO,IAAI;AACnC,QAAM,MAAM,KAAK,MAAM,KAAK,GAAG;AAC/B,QAAM,MAAM,KAAK,MAAM;AACvB,QAAM,KAAK,QAAQ,IAAI,QAAQ,IAAI,QAAQ;AAC3C,QAAM,MAAM,KAAK,OAAO,MAAM,KAAK,KAAK,CAAC,IAAI,MAAM;AACnD,QAAM,MAAM,MAAM,MAAM,KAAK,MAAM,MAAM,CAAC,IAAI,KAAK,MAAM,MAAM,GAAG,IAAI;AACtE,SAAO,MAAM,SAAS,MAAM;AAC9B;AAcA,SAAS,gBAAgB,MAAsB;AAK7C,QAAM,OAAO,cAAc,MAAM,GAAG,CAAC,IAAI,cAAc,gBAAgB,GAAG,CAAC;AAC3E,QAAM,gBAAiB,6BAA6B,IAAI,QAAQ,IAAK,KAAK;AAC1E,SAAO,cAAc;AACvB;AAOO,SAAS,mBAAmB,MAAc,OAAe,KAAa,WAAgC;AAI3G,QAAM,MAAM,UAAU,MAAM,OAAO,GAAG;AACtC,QAAM,sBAAsB,OAAO,IAAI;AAEvC,MAAI;AACJ,MAAI;AACJ,MAAI,sBAAsB,GAAG;AAC3B,cAAU,OAAO;AACjB,kBAAc,sBAAsB,WAAW,OAAO;AAAA,EACxD,WAAW,sBAAsB,WAAW,IAAI,GAAG;AACjD,cAAU,OAAO;AACjB,kBAAc,sBAAsB,WAAW,IAAI;AAAA,EACrD,OAAO;AACL,cAAU;AACV,kBAAc;AAAA,EAChB;AAIA,QAAM,UAAU,gBAAgB,OAAO;AACvC,QAAM,mBAAmB,KAAM,IAAI,UAAU,KAAK;AAGlD,QAAM,OAAO,IAAI,KAAK,OAAO,cAAc,oBAAoB,CAAC;AAChE,SAAO,EAAE,SAAS,KAAK;AACzB;;;ACnGA,SAAS,cAAc,GAAiB,UAAkB,QAAyC;AACjG,aAAW,SAAS,QAAQ;AAC1B,QAAI,EAAE,KAAK,MAAM,QAAW;AAC1B,YAAM,IAAI,kBAAkB;AAAA,QAC1B;AAAA,QACA,SACE,wBAAwB,KAAK,eAAe,KAAK;AAAA,MAGrD,CAAC;AAAA,IACH;AAAA,EACF;AACF;AAEO,SAAS,IAAI,GAAW,KAAqB;AAGlD,QAAM,WAAW,IAAI;AACrB,QAAM,SAAS,OAAO,KAAK,IAAI,CAAC,CAAC,EAAE,SAAS,KAAK,GAAG;AACpD,SAAO,WAAW,MAAM,SAAS;AACnC;AAmBA,IAAI,WAAW,SAAS,eAAe,GAAiB,OAAuB;AAC7E,QAAM,eAAe,EAAE,cAAe,OAAa,EAAE,eAAe,KAAK,OAAS,EAAE,cAAc;AAClG,SAAO,IAAI,cAAc,CAAC,EAAE,MAAM,GAAG,KAAK;AAC5C;AAyCO,IAAM,iBAAiB;AAI9B,IAAM,iBAAiB,oBAAI,IAAiC;AAC5D,IAAM,iBAAiB;AAEvB,SAAS,aAAa,QAAgB,SAA0D;AAC9F,QAAM,MAAM,KAAK,UAAU,CAAC,kBAAkB,MAAM,GAAG,OAAO,CAAC;AAC/D,MAAI,YAAY,eAAe,IAAI,GAAG;AACtC,MAAI,WAAW;AACb,WAAO;AAAA,EACT;AACA,MAAI,eAAe,QAAQ,gBAAgB;AAEzC,UAAM,YAAY,eAAe,KAAK,EAAE,KAAK,EAAE;AAC/C,QAAI,cAAc,OAAW,gBAAe,OAAO,SAAS;AAAA,EAC9D;AACA,MAAI;AACF,gBAAY,IAAI,KAAK,eAAe,mBAAmB,MAAM,GAAG,OAAO;AAAA,EACzE,SAAS,KAAK;AAOZ,UAAM,IAAI,mBAAmB,EAAE,QAAQ,QAAQ,QAAS,IAAc,QAAQ,CAAC;AAAA,EACjF;AACA,iBAAe,IAAI,KAAK,SAAS;AACjC,SAAO;AACT;AAWA,IAAI;AAMJ,2BAA2B,MAAM;AAAE,kBAAgB;AAAW,CAAC;AAE/D,SAAS,6BAAsC;AAC7C,MAAI,kBAAkB,QAAW;AAC/B,oBAAgB;AACd,QAAI;AACF,YAAM,WAAW,YAAY;AAC7B,UAAI,KAAK,eAAe,SAAS,EAAE,KAAK,UAAU,CAAC,EAChD,cAAc,SAAS,UAAU,KAAK,EAAE,MAAM,MAAM,OAAO,GAAG,KAAK,EAAE,CAAC,CAAS;AAKlF,sBAAgB;AAAA,IAElB,QAAQ;AAAA,IAOR;AAAA,EAEJ;AACA,SAAO;AACT;AAcA,IAAM,yBAAyB;AAC/B,IAAM,0BAA0B;AAChC,IAAM,wBAAwB;AAU9B,SAAS,yBAAyB,GAA0B;AAC1D,MAAI,EAAE,SAAS,uBAAwB,QAAO,OAAO,EAAE,IAAI,IAAI;AAC/D,MAAI,EAAE,UAAU,wBAAyB,QAAO,OAAO,EAAE,KAAK,IAAI;AAClE,SAAO,OAAO,EAAE,GAAG,IAAI;AACzB;AAkBA,SAAS,wBACP,UACA,QACA,kBACA,UACQ;AAOR,QAAM,YAAY,aAAa,UAC3B,IAAI,KAAK,KAAK,IAAI,MAAM,SAAS,QAAS,GAAG,CAAC,CAAC,IAC/C,IAAI,KAAK,KAAK,IAAI,MAAM,GAAG,SAAS,SAAU,CAAC;AACnD,QAAM,YAAY,aAAa,QAAQ,EAAE,GAAG,kBAAkB,UAAU,MAAM,CAAC;AAC/E,SAAO,UAAU,WAAW,WAAW,QAAQ;AACjD;AAEA,SAAS,SACP,UACA,QACA,SACA,UACQ;AAyBR,QAAM,WAAW,UAAU;AAC3B,QAAM,mBAA+C;AAAA,IACnD,GAAG;AAAA,IACH,UAAU,YAAY,aAAa,YAAY,WAAW;AAAA,EAC5D;AAaA,QAAM,KAAK,SAAS;AACpB,MAAI,OAAO,OAAO,cAAc,OAAO,OAAO,UAAU,gBAAgB;AACtE,UAAM,IAAI;AAAA,MACR,oCAAoC,QAAQ;AAAA,IAG9C;AAAA,EACF;AAoBA,OACG,aAAa,WAAW,aAAa,cACtC,iBAAiB,aAAa,aAC9B,yBAAyB,QAAQ,GACjC;AACA,WAAO,wBAAwB,UAAU,QAAQ,kBAAkB,QAAQ;AAAA,EAC7E;AAuBA,MAAI,CAAC,2BAA2B,GAAG;AAOjC,QAAI;AACF,aAAO,GAAG,KAAK,UAAU,mBAAmB,MAAM,GAAG,gBAAgB;AAAA,IACvE,SAAS,KAAK;AAGZ,UAAI,eAAe,YAAY;AAC7B,cAAM,IAAI,mBAAmB,EAAE,QAAQ,QAAQ,QAAQ,IAAI,QAAQ,CAAC;AAAA,MACtE;AACA,YAAM;AAAA,IACR;AAAA,EACF;AAKA,QAAM,EAAE,WAAW,WAAW,IAAI;AAClC,QAAM,UAAU,OAAO,cAAc,cAAc,OAAO,eAAe;AAGzE,QAAM,mBAAmB,UAAU,SAAS,UAAW,IAAI;AAC3D,QAAM,gBAA4C;AAAA,IAChD,GAAG;AAAA,IACH,GAAI,UAAU,EAAE,UAAU,WAAW,IAAI,CAAC;AAAA,EAC5C;AAEA,QAAM,YAAY,aAAa,QAAQ,aAAa;AACpD,QAAM,QAAQ,UAAU,cAAc,gBAAiC;AACvE,QAAM,QAAQ,MAAM,UAAU,CAAC,MAAM,EAAE,SAAS,QAAQ;AACxD,MAAI,UAAU,IAAI;AAChB,UAAM,IAAI;AAAA,MACR,yBAAyB,MAAM,kBAAkB,QAAQ;AAAA,IAE3D;AAAA,EACF;AAOA,MAAI,QAAQ,MAAM,KAAK,EAAG;AAC1B,QAAM,OAAO,MAAM,QAAQ,CAAC;AAC5B,QAAM,OAAO,MAAM,QAAQ,CAAC;AAC5B,MAAI,MAAM,SAAS,aAAa,CAAC,KAAK,KAAK,KAAK,KAAK,EAAG,SAAQ,KAAK,QAAQ;AAC7E,MAAI,MAAM,SAAS,aAAa,CAAC,KAAK,KAAK,KAAK,KAAK,EAAG,SAAQ,QAAQ,KAAK;AAC7E,SAAO;AACT;AAWA,SAAS,cAAc,MAAc,QAAwB;AAM3D,QAAM,SAAS,eAAe,MAAM;AACpC,MAAI,QAAQ;AACV,WAAO,OAAO,KAAK,OAAO,UAAU,CAAC,IAAK,OAAO,UAAU,CAAC;AAAA,EAC9D;AACA,QAAM,OAAO,IAAI,KAAK,KAAK,IAAI,MAAM,GAAG,GAAG,IAAI,CAAC;AAChD,QAAM,YAAY,aAAa,QAAQ,EAAE,MAAM,WAAW,QAAQ,MAAM,UAAU,MAAM,CAAC;AACzF,QAAM,OAAO,UAAU,cAAc,IAAI,EAAE,KAAK,CAAC,MAAM,EAAE,SAAS,WAAW;AAS7E,MAAI,CAAC,MAAM;AACT,UAAM,IAAI,MAAM,yBAAyB,MAAM,+CAA+C;AAAA,EAChG;AAEA,SAAO,KAAK;AACd;AAOA,SAAS,gBACP,UACA,QACA,SACA,UACA,aACA,aACQ;AACR,MAAI,eAAe,gBAAgB,UAAa,eAAe,KAAK,cAAc,YAAY,QAAQ;AACpG,WAAO,YAAY,WAAW;AAAA,EAChC;AACA,SAAO,SAAS,UAAU,QAAQ,SAAS,QAAQ;AACrD;AAaA,SAAS,aAAa,QAAgB,SAA0D;AAC9F,MAAI,WAAW,aAAa,YAAY,OAAO,YAAY,QAAQ,YAAY,QAAQ;AACrF,WAAO;AAAA,EACT;AAQA,MAAI,OAAO,SAAS,GAAG;AACrB,QAAI,YAAY,OAAO;AACrB,aAAO;AAAA,IACT;AACA,UAAM,IAAI;AAAA,MACR,wBAAwB,OAAO,kCAAkC,MAAM;AAAA,IAIzE;AAAA,EACF;AACA,QAAM,OAAO,OAAO,CAAC;AACrB,QAAM,QAAQ,OAAO,MAAM,GAAG,CAAC;AAC/B,QAAM,UAAU,OAAO,MAAM,GAAG,CAAC;AACjC,UAAQ,SAAS;AAAA,IACf,KAAK;AAAA,IAAK,KAAK;AAKb,aAAO,YAAY,OAAO,GAAG,IAAI,GAAG,KAAK,KAAK,GAAG,IAAI,GAAG,KAAK,GAAG,OAAO;AAAA,IACzE,KAAK;AAAA,IAAM,KAAK;AACd,aAAO,GAAG,IAAI,GAAG,KAAK,GAAG,OAAO;AAAA,IAClC,KAAK;AAAA,IAAO,KAAK;AACf,aAAO,GAAG,IAAI,GAAG,KAAK,IAAI,OAAO;AAAA,EACrC;AACF;AAUO,IAAM,SAA4D;AAAA,EACvE,CAAC,QAAQ,CAAC,MAAM,IAAI,EAAE,MAAO,CAAC,GAAG,MAAM;AAAA,EACvC,CAAC,MAAM,CAAC,MAAM;AAGZ,QAAI,EAAE,OAAQ,GAAG;AACf,YAAM,IAAI;AAAA,QACR,gEAAgE,EAAE,IAAI;AAAA,MAGxE;AAAA,IACF;AACA,WAAO,IAAI,EAAE,OAAQ,KAAK,CAAC;AAAA,EAC7B,GAAG,MAAM;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAMT,CAAC,KAAK,CAAC,MAAM,IAAI,EAAE,MAAO,CAAC,GAAG,MAAM;AAAA,EACpC,CAAC,QAAQ,CAAC,GAAG,WAAW;AACtB,UAAM,SAAS,eAAe,MAAM;AACpC,WAAO,gBAAgB,GAAG,QAAQ,EAAE,OAAO,OAAO,GAAG,SAAS,QAAQ,WAAW,EAAE,QAAS,CAAC;AAAA,EAC/F,GAAG,OAAO;AAAA,EACV,CAAC,OAAO,CAAC,GAAG,WAAW;AACrB,UAAM,SAAS,eAAe,MAAM;AACpC,WAAO,gBAAgB,GAAG,QAAQ,EAAE,OAAO,QAAQ,GAAG,SAAS,QAAQ,YAAY,EAAE,QAAS,CAAC;AAAA,EACjG,GAAG,OAAO;AAAA,EACV,CAAC,MAAM,CAAC,MAAM,IAAI,EAAE,OAAQ,CAAC,GAAG,OAAO;AAAA,EACvC,CAAC,KAAK,CAAC,MAAM,OAAO,EAAE,KAAM,GAAG,OAAO;AAAA,EACtC,CAAC,MAAM,CAAC,MAAM,IAAI,EAAE,KAAM,CAAC,GAAG,KAAK;AAAA,EACnC,CAAC,KAAK,CAAC,MAAM,OAAO,EAAE,GAAI,GAAG,KAAK;AAAA,EAClC,CAAC,QAAQ,CAAC,GAAG,WAAW;AACtB,UAAM,SAAS,eAAe,MAAM;AACpC,WAAO,gBAAgB,GAAG,QAAQ,EAAE,SAAS,OAAO,GAAG,WAAW,QAAQ,aAAa,EAAE,YAAa,CAAC;AAAA,EACzG,GAAG,WAAW;AAAA,EACd,CAAC,OAAO,CAAC,GAAG,WAAW;AACrB,UAAM,SAAS,eAAe,MAAM;AACpC,WAAO,gBAAgB,GAAG,QAAQ,EAAE,SAAS,QAAQ,GAAG,WAAW,QAAQ,cAAc,EAAE,YAAa,CAAC;AAAA,EAC3G,GAAG,WAAW;AAAA,EACd,CAAC,MAAM,CAAC,MAAM,IAAI,EAAE,MAAO,CAAC,GAAG,MAAM;AAAA,EACrC,CAAC,KAAK,CAAC,MAAM,OAAO,EAAE,IAAK,GAAG,MAAM;AAAA,EACpC,CAAC,MAAM,CAAC,MAAM,IAAI,EAAE,OAAQ,MAAM,IAAI,CAAC,GAAG,MAAM;AAAA,EAChD,CAAC,KAAK,CAAC,MAAM,OAAO,EAAE,OAAQ,MAAM,EAAE,GAAG,MAAM;AAAA,EAC/C,CAAC,MAAM,CAAC,MAAM,IAAI,EAAE,QAAS,CAAC,GAAG,QAAQ;AAAA,EACzC,CAAC,KAAK,CAAC,MAAM,OAAO,EAAE,MAAO,GAAG,QAAQ;AAAA,EACxC,CAAC,MAAM,CAAC,MAAM,IAAI,EAAE,QAAS,CAAC,GAAG,QAAQ;AAAA,EACzC,CAAC,KAAK,CAAC,MAAM,OAAO,EAAE,MAAO,GAAG,QAAQ;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASxC,CAAC,aAAa,CAAC,MAAM,IAAI,SAAS,GAAG,CAAC,GAAG,aAAa;AAAA,EACtD,CAAC,YAAY,CAAC,MAAM,IAAI,SAAS,GAAG,CAAC,GAAG,aAAa;AAAA,EACrD,CAAC,WAAW,CAAC,MAAM,IAAI,SAAS,GAAG,CAAC,GAAG,aAAa;AAAA,EACpD,CAAC,UAAU,CAAC,MAAM,IAAI,SAAS,GAAG,CAAC,GAAG,aAAa;AAAA,EACnD,CAAC,SAAS,CAAC,MAAM,IAAI,SAAS,GAAG,CAAC,GAAG,aAAa;AAAA,EAClD,CAAC,QAAQ,CAAC,MAAM,IAAI,SAAS,GAAG,CAAC,GAAG,aAAa;AAAA,EACjD,CAAC,OAAO,CAAC,MAAM,IAAI,SAAS,GAAG,CAAC,GAAG,aAAa;AAAA,EAChD,CAAC,MAAM,CAAC,MAAM,IAAI,SAAS,GAAG,CAAC,GAAG,aAAa;AAAA,EAC/C,CAAC,KAAK,CAAC,MAAM,IAAI,SAAS,GAAG,CAAC,GAAG,aAAa;AAAA;AAAA;AAAA,EAG9C,CAAC,KAAK,CAAC,GAAG,WAAW,cAAc,EAAE,MAAO,MAAM,GAAG,MAAM;AAAA,EAC3D,CAAC,OAAO,CAAC,MAAM,EAAE,YAAa,YAAY;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAO1C,CAAC,OAAO,CAAC,MAAM,aAAa,EAAE,QAAS,KAAK,GAAG,QAAQ;AAAA,EACvD,CAAC,MAAM,CAAC,MAAM,aAAa,EAAE,QAAS,IAAI,GAAG,QAAQ;AAAA,EACrD,CAAC,KAAK,CAAC,MAAM,aAAa,EAAE,QAAS,GAAG,GAAG,QAAQ;AAAA,EACnD,CAAC,MAAM,CAAC,MAAM,aAAa,EAAE,QAAS,IAAI,GAAG,QAAQ;AAAA,EACrD,CAAC,OAAO,CAAC,MAAM,aAAa,EAAE,QAAS,KAAK,GAAG,QAAQ;AAAA,EACvD,CAAC,KAAK,CAAC,MAAM,aAAa,EAAE,QAAS,GAAG,GAAG,QAAQ;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASnD,CAAC,MAAM,CAAC,MAAM;AACZ,UAAM,MAAM,EAAE;AACd,UAAM,YAAY,MAAM;AAGxB,UAAM,gBAAgB,MAAM;AAC5B,QAAI,iBAAiB,MAAM,iBAAiB,IAAI;AAC9C,aAAO,MAAM;AAAA,IACf;AACA,QAAI,cAAc,EAAG,QAAO,MAAM;AAClC,QAAI,cAAc,EAAG,QAAO,MAAM;AAClC,QAAI,cAAc,EAAG,QAAO,MAAM;AAClC,WAAO,MAAM;AAAA,EACf,GAAG,KAAK;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOR,CAAC,KAAK,CAAC,MAAM,OAAO,KAAK,KAAK,EAAE,QAAS,CAAC,CAAC,GAAG,OAAO;AAAA,EACrD,CAAC,OAAO,CAAC,MAAM,MAAM,KAAK,KAAK,EAAE,QAAS,CAAC,GAAG,OAAO;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASrD,CAAC,MAAM,CAAC,MAAM;AACZ,kBAAc,GAAG,MAAM,QAAQ,SAAS,KAAK;AAC7C,UAAM,EAAE,KAAK,IAAI,mBAAmB,EAAE,MAAO,EAAE,OAAQ,EAAE,KAAM,EAAE,SAAU;AAC3E,WAAO,IAAI,MAAM,CAAC;AAAA,EACpB,GAAG,WAAW;AAAA,EACd,CAAC,QAAQ,CAAC,MAAM;AACd,kBAAc,GAAG,QAAQ,QAAQ,SAAS,KAAK;AAC/C,UAAM,EAAE,QAAQ,IAAI,mBAAmB,EAAE,MAAO,EAAE,OAAQ,EAAE,KAAM,EAAE,SAAU;AAC9E,WAAO,IAAI,SAAS,CAAC;AAAA,EACvB,GAAG,WAAW;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAUd,CAAC,KAAK,CAAC,MAAM;AACX,kBAAc,GAAG,KAAK,QAAQ,OAAO;AACrC,WAAO,OAAO,UAAU,EAAE,MAAO,EAAE,OAAQ,EAAE,GAAI,CAAC;AAAA,EACpD,GAAG,KAAK;AAAA,EACR,CAAC,MAAM,CAAC,MAAM;AACZ,kBAAc,GAAG,MAAM,QAAQ,OAAO;AACtC,WAAO,IAAI,UAAU,EAAE,MAAO,EAAE,OAAQ,EAAE,GAAI,GAAG,CAAC;AAAA,EACpD,GAAG,KAAK;AAAA,EACR,CAAC,OAAO,CAAC,MAAM;AACb,kBAAc,GAAG,OAAO,QAAQ,OAAO;AACvC,WAAO,IAAI,UAAU,EAAE,MAAO,EAAE,OAAQ,EAAE,GAAI,GAAG,CAAC;AAAA,EACpD,GAAG,KAAK;AAAA;AAAA;AAAA;AAAA;AAAA,EAMR,CAAC,QAAQ,CAAC,GAAG,WAAW;AACtB,UAAM,SAAS,eAAe,MAAM;AACpC,WAAO,gBAAgB,GAAG,QAAQ,EAAE,OAAO,OAAO,GAAG,SAAS,QAAQ,WAAW,EAAE,QAAS,CAAC;AAAA,EAC/F,GAAG,OAAO;AAAA,EACV,CAAC,OAAO,CAAC,GAAG,WAAW;AACrB,UAAM,SAAS,eAAe,MAAM;AACpC,WAAO,gBAAgB,GAAG,QAAQ,EAAE,OAAO,QAAQ,GAAG,SAAS,QAAQ,YAAY,EAAE,QAAS,CAAC;AAAA,EACjG,GAAG,OAAO;AAAA;AAAA;AAAA,EAIV,CAAC,QAAQ,CAAC,GAAG,WAAW;AACtB,UAAM,SAAS,eAAe,MAAM;AACpC,WAAO,gBAAgB,GAAG,QAAQ,EAAE,SAAS,OAAO,GAAG,WAAW,QAAQ,aAAa,EAAE,YAAa,CAAC;AAAA,EACzG,GAAG,WAAW;AAAA,EACd,CAAC,OAAO,CAAC,GAAG,WAAW;AACrB,UAAM,SAAS,eAAe,MAAM;AACpC,WAAO,gBAAgB,GAAG,QAAQ,EAAE,SAAS,QAAQ,GAAG,WAAW,QAAQ,cAAc,EAAE,YAAa,CAAC;AAAA,EAC3G,GAAG,WAAW;AAAA;AAAA;AAAA,EAId,CAAC,QAAQ,CAAC,GAAG,WAAW;AACtB,WAAO,SAAS,GAAG,QAAQ,EAAE,KAAK,OAAO,GAAG,KAAK;AAAA,EACnD,GAAG,MAAM;AAAA,EACT,CAAC,KAAK,CAAC,GAAG,WAAW;AACnB,WAAO,SAAS,GAAG,QAAQ,EAAE,KAAK,QAAQ,GAAG,KAAK;AAAA,EACpD,GAAG,MAAM;AAAA;AAAA;AAAA;AAAA;AAAA,EAMT,CAAC,QAAQ,CAAC,GAAG,WAAW;AACtB,WAAO,SAAS,GAAG,QAAQ,EAAE,cAAc,cAA4D,GAAG,cAA8C;AAAA,EAC1J,GAAG,YAAY;AAAA,EACf,CAAC,KAAK,CAAC,GAAG,WAAW;AACnB,WAAO,SAAS,GAAG,QAAQ,EAAE,cAAc,QAAsD,GAAG,cAA8C;AAAA,EACpJ,GAAG,YAAY;AAEjB;AAWA,IAAM,mBAAmB,oBAAI,IAAwD;AAUrF,IAAM,mBAAsC,CAAC;AAEtC,SAAS,mBAAmB,UAA4B;AAC7D,mBAAiB,KAAK,QAAQ;AAChC;AAOO,SAAS,qBAAwE;AACtF,QAAM,SAAS,IAAI,IAAI,OAAO,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC,GAAG,CAAC,CAAU,CAAC;AAC5D,aAAW,CAAC,MAAM,KAAK,KAAK,iBAAkB,QAAO,IAAI,MAAM,KAAK;AACpE,SAAO,CAAC,GAAG,OAAO,OAAO,CAAC;AAC5B;;;ACxsBA,IAAI,uBAAuB,OAAO,IAAI,CAAC,CAAC,GAAG,MAAM,GAAG,EAAE,KAAK,CAAC,GAAG,MAAM,EAAE,SAAS,EAAE,MAAM;AAExF,mBAAmB,MAAM;AACvB,yBAAuB,mBAAmB,EACvC,IAAI,CAAC,CAAC,GAAG,MAAM,GAAG,EAClB,KAAK,CAAC,GAAG,MAAM,EAAE,SAAS,EAAE,MAAM;AACvC,CAAC;AASM,SAAS,kBAAkBA,SAAgC;AAChE,QAAM,SAAyB,CAAC;AAChC,MAAI,IAAI;AAER,SAAO,IAAIA,QAAO,QAAQ;AACxB,UAAM,KAAKA,QAAO,CAAC;AAEnB,QAAI,OAAO,KAAK;AAEd,UAAIA,QAAO,IAAI,CAAC,MAAM,KAAK;AACzB,sBAAc,QAAQ,KAAK,GAAG,IAAI,CAAC;AACnC,aAAK;AACL;AAAA,MACF;AAEA,UAAI,IAAI,IAAI;AACZ,UAAI,UAAU;AACd,UAAI,SAAS;AACb,aAAO,IAAIA,QAAO,QAAQ;AACxB,YAAIA,QAAO,CAAC,MAAM,KAAK;AACrB,cAAIA,QAAO,IAAI,CAAC,MAAM,KAAK;AACzB,uBAAW;AACX,iBAAK;AACL;AAAA,UACF;AACA,mBAAS;AACT,eAAK;AACL;AAAA,QACF;AACA,mBAAWA,QAAO,CAAC;AACnB,aAAK;AAAA,MACP;AAEA,UAAI,CAAC,QAAQ;AACX,cAAM,IAAI,kBAAkB;AAAA,UAC1B,QAAAA;AAAA,UACA,SAAS,sDAAsDA,OAAM;AAAA,QACvE,CAAC;AAAA,MACH;AAEA,oBAAc,QAAQ,SAAS,GAAG,CAAC;AACnC,UAAI;AACJ;AAAA,IACF;AAEA,UAAM,QAAQ,qBAAqB,KAAK,CAAC,QAAQA,QAAO,WAAW,KAAK,CAAC,CAAC;AAC1E,QAAI,OAAO;AAOT,YAAM,UAAU,MAAM,MAAM,SAAS,CAAC;AACtC,UAAIA,QAAO,IAAI,MAAM,MAAM,MAAM,SAAS;AACxC,YAAI,MAAM,IAAI,MAAM;AACpB,eAAOA,QAAO,GAAG,MAAM,QAAS,QAAO;AAOvC,cAAM,IAAI,kBAAkB;AAAA,UAC1B,QAAAA;AAAA,UACA,OAAOA,QAAO,MAAM,GAAG,GAAG;AAAA,UAC1B,SACE,kBAAkBA,QAAO,MAAM,GAAG,GAAG,CAAC,uBAAuBA,OAAM,mDAClD,KAAK;AAAA,QAC1B,CAAC;AAAA,MACH;AACA,aAAO,KAAK,EAAE,MAAM,SAAS,OAAO,OAAO,OAAO,GAAG,KAAK,IAAI,MAAM,OAAO,CAAC;AAC5E,WAAK,MAAM;AACX;AAAA,IACF;AAGA,kBAAc,QAAQ,IAAI,GAAG,IAAI,CAAC;AAClC,SAAK;AAAA,EACP;AAEA,SAAO;AACT;AAQO,SAAS,SAASA,SAAyB;AAChD,SAAO,kBAAkBA,OAAM,EAAE,IAAI,CAAC,EAAE,MAAM,MAAM,OAAO,EAAE,MAAM,MAAM,EAAE;AAC7E;AAIA,SAAS,cAAc,QAAwB,OAAe,OAAe,KAAmB;AAC9F,QAAM,OAAO,OAAO,OAAO,SAAS,CAAC;AACrC,MAAI,QAAQ,KAAK,SAAS,aAAa,KAAK,QAAQ,OAAO;AACzD,SAAK,SAAS;AACd,SAAK,MAAM;AAAA,EACb,OAAO;AACL,WAAO,KAAK,EAAE,MAAM,WAAW,OAAO,OAAO,IAAI,CAAC;AAAA,EACpD;AACF;;;ACjJO,IAAM,oBAAoB;;;ACiC1B,IAAM,8BAAmD,oBAAI,IAAI;AAAA,EACtE;AAAA,EAAQ;AAAA,EAAQ;AAAA,EAAQ;AAAA,EAAQ;AAAA,EAAQ;AAAA,EAAQ;AAAA,EAAQ;AAAA,EACxD;AAAA,EAAQ;AAAA,EAAQ;AAAA,EAAQ;AAAA,EAAY;AACtC,CAAC;AAED,IAAM,gBAAgB,oBAAI,IAAoC;AAQ9D,IAAM,qBAAqB,oBAAI,IAAoB;AACnD,IAAM,2BAA2B;AAYjC,SAAS,2BAA2B,QAAwB;AAC1D,QAAM,MAAM,kBAAkB,MAAM;AACpC,QAAM,SAAS,mBAAmB,IAAI,GAAG;AACzC,MAAI,WAAW,OAAW,QAAO;AACjC,MAAI;AACJ,MAAI;AACF,eAAW,IAAI,KAAK,aAAa,mBAAmB,MAAM,CAAC,EAAE,gBAAgB,EAAE;AAAA,EACjF,SAAS,KAAK;AACZ,UAAM,IAAI,mBAAmB,EAAE,QAAQ,QAAQ,QAAS,IAAc,QAAQ,CAAC;AAAA,EACjF;AACA,QAAM,SAAS,4BAA4B,IAAI,QAAQ,IAAI,WAAW;AACtE,MAAI,mBAAmB,QAAQ,0BAA0B;AAEvD,UAAM,YAAY,mBAAmB,KAAK,EAAE,KAAK,EAAE;AACnD,QAAI,cAAc,OAAW,oBAAmB,OAAO,SAAS;AAAA,EAClE;AACA,qBAAmB,IAAI,KAAK,MAAM;AAClC,SAAO;AACT;AAMA,SAAS,uBAAuB,WAA+B,QAAoC;AACjG,MAAI,cAAc,OAAW,QAAO;AACpC,MAAI,cAAc,OAAQ,QAAO,2BAA2B,UAAU,cAAc;AACpF,SAAO;AACT;AAMA,SAAS,YAAY,QAAwC;AAC3D,MAAI,MAAM,cAAc,IAAI,MAAM;AAClC,MAAI,IAAK,QAAO;AAAA,EAChB;AAAA;AAAA;AAAA;AAAA;AAAA;AAMA,MAAI,WAAW,QAAQ;AACrB,UAAM,CAAC;AACP,aAAS,IAAI,GAAG,IAAI,IAAI,IAAK,KAAI,OAAO,CAAC,CAAC,IAAI,OAAO,CAAC;AAAA,EACxD,OAAO;AAAA,IACL;AACA,UAAM,MAAM,IAAI,KAAK,aAAa,gBAAgB,QAAQ,EAAE,aAAa,MAAM,CAAC;AAChF,UAAM,CAAC;AACP,aAAS,IAAI,GAAG,IAAI,IAAI,KAAK;AAC3B,UAAI,OAAO,CAAC,CAAC,IAAI,IAAI,OAAO,CAAC;AAAA,IAC/B;AAAA,EACF;AACA,gBAAc,IAAI,QAAQ,GAAG;AAC7B,SAAO;AACT;AAIO,SAAS,cAAc,GAAW,QAAwB;AAC/D,MAAI,WAAW,OAAQ,QAAO;AAC9B,MAAI,CAAC,4BAA4B,IAAI,MAAM,GAAG;AAC5C,UAAM,IAAI,mBAAmB,EAAE,QAAQ,QAAQ,QAAQ,qBAAqB,MAAM,kCAAkC,CAAC,GAAG,2BAA2B,EAAE,KAAK,IAAI,CAAC,IAAI,CAAC;AAAA,EACtK;AACA,QAAM,MAAM,YAAY,MAAM;AAC9B,MAAI,SAAS;AACb,aAAW,MAAM,GAAG;AAClB,QAAI,MAAM,OAAO,MAAM,KAAK;AAM1B,gBAAU,IAAI,EAAE,KAAK;AAAA,IACvB,OAAO;AACL,gBAAU;AAAA,IACZ;AAAA,EACF;AACA,SAAO;AACT;AAoDO,SAAS,eAAe,GAAW,SAAyC;AACjF,QAAM,SAAS,uBAAuB,QAAQ,iBAAiB,QAAQ,MAAM;AAC7E,MAAI,WAAW,OAAQ,QAAO;AAC9B,SAAO,cAAc,GAAG,MAAM;AAChC;;;AR1LA,IAAI,mBAAmB,IAAI,IAAI,OAAO,IAAI,CAAC,CAAC,KAAK,IAAI,KAAK,MAAM,CAAC,KAAK,EAAE,IAAI,MAAM,CAAC,CAAC,CAAC;AAMrF,IAAM,gBAAgB,oBAAI,IAAqB;AAC/C,IAAM,0BAA0B;AAWhC,mBAAmB,MAAM;AACvB,qBAAmB,IAAI,IAAI,mBAAmB,EAAE,IAAI,CAAC,CAAC,KAAK,IAAI,KAAK,MAAM,CAAC,KAAK,EAAE,IAAI,MAAM,CAAC,CAAC,CAAC;AAC/F,gBAAc,MAAM;AACtB,CAAC;AAED,SAAS,UAAU,WAA4B;AAC7C,MAAI,SAAS,cAAc,IAAI,SAAS;AACxC,MAAI,OAAQ,QAAO;AACnB,MAAI,cAAc,QAAQ,yBAAyB;AACjD,UAAM,YAAY,cAAc,KAAK,EAAE,KAAK,EAAE;AAC9C,QAAI,cAAc,OAAW,eAAc,OAAO,SAAS;AAAA,EAC7D;AACA,WAAS,SAAS,SAAS;AAQ3B,aAAW,SAAS,OAAQ,QAAO,OAAO,KAAK;AAC/C,SAAO,OAAO,MAAM;AACpB,gBAAc,IAAI,WAAW,MAAM;AACnC,SAAO;AACT;AAaO,SAAS,OAAO,UAAwB,WAAmB,UAAkC,CAAC,GAAW;AAC9G,MAAI,UAAU,SAAS,mBAAmB;AACxC,UAAM,IAAI,kBAAkB;AAAA,MAC1B,QAAQ;AAAA,MACR,SACE,yDAAyD,iBAAiB,oBAClE,UAAU,MAAM;AAAA,IAC5B,CAAC;AAAA,EACH;AAOA,MAAI,aAAa,QAAQ,aAAa,QAAW;AAC/C,UAAM,IAAI,kBAAkB;AAAA,MAC1B,OAAO,OAAO,QAAQ;AAAA,MACtB,QAAQ,yHAAyH,OAAO,QAAQ,CAAC;AAAA,IACnJ,CAAC;AAAA,EACH;AACA,QAAM,OAAO,WAAW,CAAC;AAEzB,QAAM,SAAS,KAAK,UAAU;AAC9B,QAAM,SAAS,UAAU,SAAS;AAClC,MAAI,SAAS;AAEb,aAAW,SAAS,QAAQ;AAC1B,QAAI,MAAM,SAAS,WAAW;AAC5B,gBAAU,MAAM;AAChB;AAAA,IACF;AAEA,UAAM,UAAU,iBAAiB,IAAI,MAAM,KAAK;AAAA,IAChD;AAAA;AAAA;AAAA;AAAA;AAKA,QAAI,CAAC,SAAS;AACZ,YAAM,IAAI,kBAAkB,EAAE,OAAO,MAAM,OAAO,QAAQ,WAAW,SAAS,gCAAgC,MAAM,KAAK,IAAI,CAAC;AAAA,IAChI;AAAA,IACA;AAEA,QAAI,SAAS,QAAQ,KAAK,MAAM,QAAW;AACzC,YAAM,IAAI,kBAAkB;AAAA,QAC1B,QAAQ;AAAA,QACR,OAAO,MAAM;AAAA,QACb,SACE,wBAAwB,MAAM,KAAK,eAAe,QAAQ,KAAK;AAAA,MAGnE,CAAC;AAAA,IACH;AAEA,cAAU,QAAQ,GAAG,UAAU,MAAM;AAAA,EACvC;AAKA,SAAO,eAAe,QAAQ,IAAI;AACpC;AAgBO,SAAS,cAAc,UAAwB,WAAmB,UAAkC,CAAC,GAAoB;AAC9H,MAAI,UAAU,SAAS,mBAAmB;AACxC,UAAM,IAAI,kBAAkB;AAAA,MAC1B,QAAQ;AAAA,MACR,SACE,yDAAyD,iBAAiB,oBAClE,UAAU,MAAM;AAAA,IAC5B,CAAC;AAAA,EACH;AACA,QAAM,SAAS,QAAQ,UAAU;AACjC,QAAM,SAAS,UAAU,SAAS;AAClC,QAAM,SAA0B,CAAC;AACjC,aAAW,SAAS,QAAQ;AAC1B,QAAI,MAAM,SAAS,WAAW;AAK5B,YAAM,OAAO,OAAO,OAAO,SAAS,CAAC;AAAA,MACrC;AAAA;AAAA;AAAA;AAAA;AAAA;AAMA,UAAI,QAAQ,KAAK,SAAS,WAAW;AACnC,aAAK,SAAS,MAAM;AAAA,MACtB,OAAO;AAAA,QACL;AACA,eAAO,KAAK,EAAE,MAAM,WAAW,OAAO,MAAM,MAAM,CAAC;AAAA,MACrD;AACA;AAAA,IACF;AACA,UAAM,UAAU,iBAAiB,IAAI,MAAM,KAAK;AAAA,IAChD;AACA,QAAI,CAAC,SAAS;AACZ,YAAM,IAAI,kBAAkB,EAAE,OAAO,MAAM,OAAO,QAAQ,WAAW,SAAS,gCAAgC,MAAM,KAAK,IAAI,CAAC;AAAA,IAChI;AAAA,IACA;AACA,QAAI,SAAS,QAAQ,KAAK,MAAM,QAAW;AACzC,YAAM,IAAI,kBAAkB;AAAA,QAC1B,QAAQ;AAAA,QACR,OAAO,MAAM;AAAA,QACb,SACE,wBAAwB,MAAM,KAAK,eAAe,QAAQ,KAAK;AAAA,MAGnE,CAAC;AAAA,IACH;AAKA,WAAO,KAAK,EAAE,MAAM,SAAS,OAAO,eAAe,QAAQ,GAAG,UAAU,MAAM,GAAG,OAAO,GAAG,OAAO,MAAM,MAAM,CAAC;AAAA,EACjH;AACA,SAAO;AACT;AAiBO,SAAS,cAAc,WAAmC;AAC/D,MAAI,UAAU,SAAS,mBAAmB;AACxC,UAAM,IAAI,kBAAkB;AAAA,MAC1B,QAAQ;AAAA,MACR,SACE,yDAAyD,iBAAiB,oBAClE,UAAU,MAAM;AAAA,IAC5B,CAAC;AAAA,EACH;AAKA,QAAM,SAAS,UAAU,SAAS;AAClC,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA,OAAO,UAAwB,UAAkC,CAAC,GAAG;AACnE,YAAM,SAAS,QAAQ,UAAU;AACjC,UAAI,SAAS;AACb,iBAAW,SAAS,QAAQ;AAC1B,YAAI,MAAM,SAAS,WAAW;AAC5B,oBAAU,MAAM;AAChB;AAAA,QACF;AACA,cAAM,UAAU,iBAAiB,IAAI,MAAM,KAAK;AAEhD,YAAI,CAAC,QAAS,OAAM,IAAI,kBAAkB,EAAE,OAAO,MAAM,OAAO,QAAQ,WAAW,SAAS,gCAAgC,MAAM,KAAK,IAAI,CAAC;AAC5I,YAAI,SAAS,QAAQ,KAAK,MAAM,QAAW;AACzC,gBAAM,IAAI,kBAAkB;AAAA,YAC1B,QAAQ;AAAA,YACR,OAAO,MAAM;AAAA,YACb,SACE,wBAAwB,MAAM,KAAK,eAAe,QAAQ,KAAK;AAAA,UAGnE,CAAC;AAAA,QACH;AACA,kBAAU,QAAQ,GAAG,UAAU,MAAM;AAAA,MACvC;AACA,aAAO,eAAe,QAAQ,OAAO;AAAA,IACvC;AAAA,IACA,cAAc,UAAwB,UAAkC,CAAC,GAAG;AAC1E,YAAM,SAAS,QAAQ,UAAU;AACjC,YAAM,MAAuB,CAAC;AAC9B,iBAAW,SAAS,QAAQ;AAC1B,YAAI,MAAM,SAAS,WAAW;AAC5B,gBAAM,OAAO,IAAI,IAAI,SAAS,CAAC;AAE/B,cAAI,QAAQ,KAAK,SAAS,UAAW,MAAK,SAAS,MAAM;AAAA,cACpD,KAAI,KAAK,EAAE,MAAM,WAAW,OAAO,MAAM,MAAM,CAAC;AACrD;AAAA,QACF;AACA,cAAM,UAAU,iBAAiB,IAAI,MAAM,KAAK;AAEhD,YAAI,CAAC,QAAS,OAAM,IAAI,kBAAkB,EAAE,OAAO,MAAM,OAAO,QAAQ,WAAW,SAAS,gCAAgC,MAAM,KAAK,IAAI,CAAC;AAC5I,YAAI,SAAS,QAAQ,KAAK,MAAM,QAAW;AACzC,gBAAM,IAAI,kBAAkB;AAAA,YAC1B,QAAQ;AAAA,YACR,OAAO,MAAM;AAAA,YACb,SACE,wBAAwB,MAAM,KAAK,eAAe,QAAQ,KAAK;AAAA,UAGnE,CAAC;AAAA,QACH;AACA,YAAI,KAAK,EAAE,MAAM,SAAS,OAAO,eAAe,QAAQ,GAAG,UAAU,MAAM,GAAG,OAAO,GAAG,OAAO,MAAM,MAAM,CAAC;AAAA,MAC9G;AACA,aAAO;AAAA,IACT;AAAA,EACF;AACF;AAKO,SAAS,WAAW,WAA4B;AACrD,SAAO,UAAU,SAAS;AAC5B;AAKO,SAAS,YAAY,OAA2G;AACrI,SAAO,iBAAiB,IAAI,KAAK;AACnC;","names":["format"]}