monetra 2.0.0 → 2.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (59) hide show
  1. package/README.md +177 -160
  2. package/dist/currency/Currency.d.ts +27 -0
  3. package/dist/currency/index.d.ts +4 -0
  4. package/dist/currency/iso4217.d.ts +245 -0
  5. package/dist/currency/precision.d.ts +2 -0
  6. package/dist/currency/registry.d.ts +22 -0
  7. package/dist/errors/BaseError.d.ts +22 -0
  8. package/dist/errors/CurrencyMismatchError.d.ts +12 -0
  9. package/dist/errors/InsufficientFundsError.d.ts +4 -0
  10. package/dist/errors/InvalidArgumentError.d.ts +4 -0
  11. package/dist/errors/InvalidPrecisionError.d.ts +4 -0
  12. package/dist/errors/OverflowError.d.ts +4 -0
  13. package/dist/errors/RoundingRequiredError.d.ts +4 -0
  14. package/dist/errors/index.d.ts +7 -0
  15. package/dist/financial/compound.d.ts +20 -0
  16. package/dist/financial/depreciation.d.ts +30 -0
  17. package/dist/financial/index.d.ts +7 -0
  18. package/dist/financial/index.js +1323 -0
  19. package/dist/financial/index.js.map +1 -0
  20. package/dist/financial/index.mjs +1275 -0
  21. package/dist/financial/index.mjs.map +1 -0
  22. package/dist/financial/investment.d.ts +31 -0
  23. package/dist/financial/leverage.d.ts +66 -0
  24. package/dist/financial/loan.d.ts +67 -0
  25. package/dist/financial/rate.d.ts +169 -0
  26. package/dist/financial/simple.d.ts +60 -0
  27. package/dist/format/formatter.d.ts +42 -0
  28. package/dist/format/parser.d.ts +53 -0
  29. package/dist/index.d.ts +11 -1202
  30. package/dist/index.js +263 -41
  31. package/dist/index.js.map +1 -1
  32. package/dist/index.mjs +248 -41
  33. package/dist/index.mjs.map +1 -1
  34. package/dist/ledger/Ledger.d.ts +65 -0
  35. package/dist/ledger/index.d.ts +3 -0
  36. package/dist/ledger/index.js +1054 -0
  37. package/dist/ledger/index.js.map +1 -0
  38. package/dist/ledger/index.mjs +1029 -0
  39. package/dist/ledger/index.mjs.map +1 -0
  40. package/dist/ledger/types.d.ts +30 -0
  41. package/dist/ledger/verification.d.ts +36 -0
  42. package/dist/money/Converter.d.ts +26 -0
  43. package/dist/money/Money.d.ts +299 -0
  44. package/dist/money/MoneyBag.d.ts +46 -0
  45. package/dist/money/allocation.d.ts +13 -0
  46. package/dist/money/arithmetic.d.ts +32 -0
  47. package/dist/money/guards.d.ts +3 -0
  48. package/dist/money/index.d.ts +4 -0
  49. package/dist/rounding/index.d.ts +3 -0
  50. package/dist/rounding/strategies.d.ts +36 -0
  51. package/dist/tokens/defineToken.d.ts +30 -0
  52. package/dist/tokens/index.d.ts +2 -0
  53. package/dist/tokens/index.js +100 -0
  54. package/dist/tokens/index.js.map +1 -0
  55. package/dist/tokens/index.mjs +69 -0
  56. package/dist/tokens/index.mjs.map +1 -0
  57. package/dist/tokens/types.d.ts +13 -0
  58. package/package.json +34 -14
  59. package/dist/index.d.mts +0 -1211
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/financial/index.ts","../../src/currency/registry.ts","../../src/errors/BaseError.ts","../../src/errors/CurrencyMismatchError.ts","../../src/errors/InvalidPrecisionError.ts","../../src/errors/RoundingRequiredError.ts","../../src/errors/InvalidArgumentError.ts","../../src/money/guards.ts","../../src/rounding/index.ts","../../src/money/arithmetic.ts","../../src/money/allocation.ts","../../src/format/parser.ts","../../src/format/formatter.ts","../../src/money/Money.ts","../../src/financial/loan.ts","../../src/financial/compound.ts","../../src/financial/investment.ts","../../src/financial/rate.ts","../../src/financial/simple.ts","../../src/financial/leverage.ts","../../src/financial/depreciation.ts"],"sourcesContent":["export * from \"./loan\";\nexport * from \"./compound\";\nexport * from \"./investment\";\nexport * from \"./rate\";\nexport * from \"./simple\";\nexport * from \"./leverage\";\nexport * from \"./depreciation\";\n","import { Currency } from \"./Currency\";\n\nconst registry: Map<string, Currency> = new Map();\n\n/**\n * Registers a currency in the global registry.\n * @param currency The currency to register.\n */\nexport function registerCurrency(currency: Currency): void {\n registry.set(currency.code, currency);\n}\n\n/**\n * Retrieves a currency by its code.\n * @param code The currency code (e.g., \"USD\").\n * @returns The Currency object.\n * @throws Error if the currency is not found.\n */\nexport function getCurrency(code: string): Currency {\n const currency = registry.get(code);\n if (!currency) {\n throw new Error(`Currency '${code}' not found in registry.`);\n }\n return currency;\n}\n\n/**\n * Checks if a currency is registered.\n */\nexport function isCurrencyRegistered(code: string): boolean {\n return registry.has(code);\n}\n\n/**\n * Returns all registered currencies as a map.\n * @internal Use for testing only.\n */\nexport function getAllCurrencies(): Record<string, Currency> {\n return Object.fromEntries(registry);\n}\n","/**\n * Error codes for programmatic handling of Monetra errors.\n */\nexport enum MonetraErrorCode {\n CURRENCY_MISMATCH = \"MONETRA_CURRENCY_MISMATCH\",\n INSUFFICIENT_FUNDS = \"MONETRA_INSUFFICIENT_FUNDS\",\n INVALID_ARGUMENT = \"MONETRA_INVALID_ARGUMENT\",\n INVALID_PRECISION = \"MONETRA_INVALID_PRECISION\",\n OVERFLOW = \"MONETRA_OVERFLOW\",\n ROUNDING_REQUIRED = \"MONETRA_ROUNDING_REQUIRED\",\n}\n\n/**\n * Base error class for all Monetra errors.\n * All Monetra errors include an error code for programmatic handling.\n */\nexport class MonetraError extends Error {\n /**\n * A unique error code for programmatic handling.\n */\n readonly code: MonetraErrorCode;\n\n constructor(message: string, code: MonetraErrorCode) {\n super(message);\n this.name = this.constructor.name;\n this.code = code;\n Object.setPrototypeOf(this, new.target.prototype);\n }\n}\n","import { MonetraError, MonetraErrorCode } from \"./BaseError\";\n\nexport class CurrencyMismatchError extends MonetraError {\n /**\n * The expected currency code.\n */\n readonly expected: string;\n\n /**\n * The received currency code.\n */\n readonly received: string;\n\n constructor(expected: string, received: string) {\n super(\n `Currency mismatch: expected ${expected}, received ${received}.\\n` +\n `💡 Tip: Use a Converter to convert between currencies:\\n` +\n ` const converter = new Converter('USD', { ${received}: rate });\\n` +\n ` const converted = converter.convert(money, '${expected}');`,\n MonetraErrorCode.CURRENCY_MISMATCH,\n );\n this.expected = expected;\n this.received = received;\n }\n}\n","import { MonetraError, MonetraErrorCode } from \"./BaseError\";\n\nexport class InvalidPrecisionError extends MonetraError {\n constructor(message: string) {\n super(message, MonetraErrorCode.INVALID_PRECISION);\n }\n}\n","import { MonetraError, MonetraErrorCode } from \"./BaseError\";\n\nexport class RoundingRequiredError extends MonetraError {\n constructor(operation?: string, result?: number) {\n let message =\n \"Rounding is required for this operation but was not provided.\";\n if (operation && result !== undefined) {\n message =\n `Rounding required for ${operation}: result ${result} is not an integer.\\n` +\n `💡 Tip: Provide a rounding mode:\\n` +\n ` money.${operation}(value, { rounding: RoundingMode.HALF_UP })\\n` +\n ` Available modes: HALF_UP, HALF_DOWN, HALF_EVEN, FLOOR, CEIL, TRUNCATE`;\n }\n super(message, MonetraErrorCode.ROUNDING_REQUIRED);\n }\n}\n","import { MonetraError, MonetraErrorCode } from \"./BaseError\";\n\nexport class InvalidArgumentError extends MonetraError {\n constructor(message: string) {\n super(message, MonetraErrorCode.INVALID_ARGUMENT);\n }\n}\n","import { Money } from \"./Money\";\nimport { CurrencyMismatchError, InsufficientFundsError } from \"../errors\";\n\nexport function assertSameCurrency(a: Money, b: Money): void {\n if (a.currency.code !== b.currency.code) {\n throw new CurrencyMismatchError(a.currency.code, b.currency.code);\n }\n}\n\nexport function assertNonNegative(money: Money): void {\n if (money.isNegative()) {\n // Spec doesn't explicitly name a NegativeError, but InsufficientFundsError might fit or just a generic error.\n // Spec lists \"InsufficientFundsError\" in 4.7.\n // But \"assertNonNegative\" is a guard.\n // Let's throw an Error or a specific one if defined.\n // \"Any violation is considered a bug\" -> maybe just Error?\n // But for \"InsufficientFunds\", that's usually when subtracting.\n // Let's use a generic Error for now or create a specific one if needed.\n throw new Error(\"Money value must be non-negative\");\n }\n}\n","import { RoundingMode } from \"./strategies\";\n\nexport * from \"./strategies\";\n\nexport function divideWithRounding(\n numerator: bigint,\n denominator: bigint,\n mode: RoundingMode,\n): bigint {\n if (denominator === 0n) {\n throw new Error(\"Division by zero\");\n }\n\n const quotient = numerator / denominator;\n const remainder = numerator % denominator;\n\n if (remainder === 0n) {\n return quotient;\n }\n\n const isNegativeResult = numerator < 0n !== denominator < 0n;\n const isPositiveResult = !isNegativeResult;\n\n const absRemainder = remainder < 0n ? -remainder : remainder;\n const absDenominator = denominator < 0n ? -denominator : denominator;\n\n // Check for exact half\n const isHalf = absRemainder * 2n === absDenominator;\n const isMoreThanHalf = absRemainder * 2n > absDenominator;\n\n switch (mode) {\n case RoundingMode.FLOOR:\n // If positive, quotient is already floor (truncation).\n // If negative, quotient is ceil (truncation towards zero), so we need to subtract 1.\n return isPositiveResult ? quotient : quotient - 1n;\n case RoundingMode.CEIL:\n // If positive, quotient is floor, so add 1.\n // If negative, quotient is ceil, so keep it.\n return isPositiveResult ? quotient + 1n : quotient;\n case RoundingMode.HALF_UP:\n if (isMoreThanHalf || isHalf) {\n return isPositiveResult ? quotient + 1n : quotient - 1n;\n }\n return quotient;\n case RoundingMode.HALF_DOWN:\n if (isMoreThanHalf) {\n return isPositiveResult ? quotient + 1n : quotient - 1n;\n }\n return quotient;\n case RoundingMode.HALF_EVEN:\n if (isMoreThanHalf) {\n return isPositiveResult ? quotient + 1n : quotient - 1n;\n }\n if (isHalf) {\n // If quotient is odd, round up (away from zero? no, to nearest even).\n // If quotient is even, keep it.\n if (quotient % 2n !== 0n) {\n return isPositiveResult ? quotient + 1n : quotient - 1n;\n }\n }\n return quotient;\n case RoundingMode.TRUNCATE:\n // Truncate towards zero (simply return the quotient without adjustment)\n return quotient;\n default:\n throw new Error(`Unsupported rounding mode: ${mode}`);\n }\n}\n","import { RoundingMode, divideWithRounding } from \"../rounding\";\nimport { RoundingRequiredError } from \"../errors\";\n\n/**\n * Adds two BigInt values.\n */\nexport function add(a: bigint, b: bigint): bigint {\n return a + b;\n}\n\n/**\n * Subtracts two BigInt values.\n */\nexport function subtract(a: bigint, b: bigint): bigint {\n return a - b;\n}\n\n/**\n * Multiplies a BigInt amount by a multiplier.\n *\n * Handles fractional multipliers by converting them to a rational number (numerator/denominator).\n * If the result is not an integer, a rounding mode must be provided.\n *\n * @param amount - The amount to multiply.\n * @param multiplier - The multiplier (number or string).\n * @param rounding - Optional rounding mode.\n * @returns The result as a BigInt.\n * @throws {RoundingRequiredError} If rounding is needed but not provided.\n */\nexport function multiply(\n amount: bigint,\n multiplier: string | number,\n rounding?: RoundingMode,\n): bigint {\n const { numerator, denominator } = parseMultiplier(multiplier);\n\n // result = amount * (numerator / denominator)\n // result = (amount * numerator) / denominator\n\n const product = amount * numerator;\n\n if (product % denominator === 0n) {\n return product / denominator;\n }\n\n if (!rounding) {\n throw new RoundingRequiredError(\n \"multiply\",\n Number(product) / Number(denominator),\n );\n }\n\n return divideWithRounding(product, denominator, rounding);\n}\n\n/**\n * Divides a BigInt amount by a divisor.\n *\n * @param amount - The amount to divide.\n * @param divisor - The divisor (number or string).\n * @param rounding - Optional rounding mode.\n * @returns The result as a BigInt.\n * @throws {RoundingRequiredError} If rounding is needed but not provided.\n */\nexport function divide(\n amount: bigint,\n divisor: string | number,\n rounding?: RoundingMode,\n): bigint {\n const { numerator, denominator } = parseMultiplier(divisor);\n\n // result = amount / (numerator / denominator)\n // result = (amount * denominator) / numerator\n\n const product = amount * denominator;\n\n if (product % numerator === 0n) {\n return product / numerator;\n }\n\n if (!rounding) {\n throw new RoundingRequiredError(\n \"divide\",\n Number(product) / Number(numerator),\n );\n }\n\n return divideWithRounding(product, numerator, rounding);\n}\n\nfunction parseMultiplier(multiplier: string | number): {\n numerator: bigint;\n denominator: bigint;\n} {\n const s = multiplier.toString();\n\n // Check for scientific notation\n if (/[eE]/.test(s)) {\n throw new Error(\"Scientific notation not supported\");\n }\n\n const parts = s.split(\".\");\n if (parts.length > 2) {\n throw new Error(\"Invalid number format\");\n }\n\n const integerPart = parts[0];\n const fractionalPart = parts[1] || \"\";\n\n const denominator = 10n ** BigInt(fractionalPart.length);\n const numerator = BigInt(integerPart + fractionalPart);\n\n return { numerator, denominator };\n}\n","/**\n * Allocates a monetary amount according to a list of ratios.\n *\n * Uses the \"Largest Remainder Method\" to ensure that the sum of the allocated\n * parts equals the original amount. Remainders are distributed to the parts\n * that had the largest fractional remainders during the division.\n *\n * @param amount - The total amount to allocate (in minor units).\n * @param ratios - An array of ratios (e.g., [1, 1] for 50/50 split).\n * @returns An array of allocated amounts (in minor units).\n * @throws {Error} If ratios are empty or total ratio is zero.\n */\nexport function allocate(amount: bigint, ratios: number[]): bigint[] {\n if (ratios.length === 0) {\n throw new Error(\"Cannot allocate to empty ratios\");\n }\n\n // Scale ratios to integers\n const scaledRatios = ratios.map((r) => {\n const s = r.toString();\n if (/[eE]/.test(s)) throw new Error(\"Scientific notation not supported\");\n const parts = s.split(\".\");\n const decimals = parts[1] ? parts[1].length : 0;\n const value = BigInt(parts[0] + (parts[1] || \"\"));\n return { value, decimals };\n });\n\n const maxDecimals = Math.max(...scaledRatios.map((r) => r.decimals));\n\n const normalizedRatios = scaledRatios.map((r) => {\n const factor = 10n ** BigInt(maxDecimals - r.decimals);\n return r.value * factor;\n });\n\n const total = normalizedRatios.reduce((sum, r) => sum + r, 0n);\n\n if (total === 0n) {\n throw new Error(\"Total ratio must be greater than zero\");\n }\n\n const results: { share: bigint; remainder: bigint; index: number }[] = [];\n let allocatedTotal = 0n;\n\n for (let i = 0; i < normalizedRatios.length; i++) {\n const ratio = normalizedRatios[i];\n const share = (amount * ratio) / total;\n const remainder = (amount * ratio) % total;\n\n results.push({ share, remainder, index: i });\n allocatedTotal += share;\n }\n\n let leftOver = amount - allocatedTotal;\n\n // Distribute leftover to those with largest remainder\n // Sort by remainder desc\n results.sort((a, b) => {\n if (b.remainder > a.remainder) return 1;\n if (b.remainder < a.remainder) return -1;\n return 0;\n });\n\n for (let i = 0; i < Number(leftOver); i++) {\n results[i].share += 1n;\n }\n\n // Sort back by index\n results.sort((a, b) => a.index - b.index);\n\n return results.map((r) => r.share);\n}\n","import { Currency } from \"../currency/Currency\";\nimport { InvalidPrecisionError } from \"../errors\";\n\n/**\n * Options for locale-aware parsing.\n */\nexport interface LocaleParseOptions {\n /**\n * The locale to use for parsing (e.g., \"en-US\", \"de-DE\").\n * Used to detect decimal and grouping separators.\n */\n locale: string;\n}\n\n/**\n * Parses a locale-formatted string into a normalized decimal string.\n *\n * Handles locale-specific decimal separators (e.g., comma in German \"1.234,56\")\n * and grouping separators (e.g., period in German \"1.234\").\n *\n * @param amount - The locale-formatted amount string (e.g., \"1,234.56\" or \"1.234,56\").\n * @param options - The locale options.\n * @returns A normalized decimal string (e.g., \"1234.56\").\n * @example\n * parseLocaleString(\"1.234,56\", { locale: \"de-DE\" }); // \"1234.56\"\n * parseLocaleString(\"1,234.56\", { locale: \"en-US\" }); // \"1234.56\"\n */\nexport function parseLocaleString(\n amount: string,\n options: LocaleParseOptions,\n): string {\n // Use Intl.NumberFormat to determine the locale's separators\n const parts = new Intl.NumberFormat(options.locale, {\n style: \"decimal\",\n minimumFractionDigits: 1,\n useGrouping: true,\n }).formatToParts(1234.5);\n\n let decimalSeparator = \".\";\n let groupSeparator = \",\";\n\n for (const part of parts) {\n if (part.type === \"decimal\") {\n decimalSeparator = part.value;\n } else if (part.type === \"group\") {\n groupSeparator = part.value;\n }\n }\n\n // Handle the case where group and decimal separators are the same\n // (shouldn't happen, but be defensive)\n if (groupSeparator === decimalSeparator) {\n throw new Error(\n `Invalid locale configuration: group and decimal separators are the same for locale ${options.locale}`,\n );\n }\n\n // Remove currency symbols and whitespace\n let normalized = amount.replace(/[^\\d.,\\-\\s]/g, \"\").trim();\n\n // Handle negative sign\n const isNegative = normalized.startsWith(\"-\") || amount.includes(\"(\");\n normalized = normalized.replace(/[-()]/g, \"\");\n\n // Remove all grouping separators\n normalized = normalized.split(groupSeparator).join(\"\");\n\n // Replace locale decimal separator with standard period\n normalized = normalized.split(decimalSeparator).join(\".\");\n\n return isNegative ? `-${normalized}` : normalized;\n}\n\n/**\n * Parses a locale-formatted amount string and converts it to Money minor units.\n *\n * This is a convenience function that combines locale parsing with currency validation.\n *\n * @param amount - The locale-formatted amount string.\n * @param currency - The currency to validate against.\n * @param options - The locale options.\n * @returns The amount in minor units as a BigInt.\n * @throws {InvalidPrecisionError} If the precision exceeds the currency's decimals.\n * @example\n * parseLocaleToMinor(\"1.234,56\", EUR, { locale: \"de-DE\" }); // 123456n\n */\nexport function parseLocaleToMinor(\n amount: string,\n currency: Currency,\n options: LocaleParseOptions,\n): bigint {\n const normalized = parseLocaleString(amount, options);\n return parseToMinor(normalized, currency);\n}\n\n/**\n * Parses a string representation of a major unit amount into minor units.\n *\n * Validates the input format to ensure it is a valid decimal number without\n * scientific notation or ambiguous characters. Checks that the precision\n * does not exceed the currency's allowed decimals.\n *\n * @param amount - The amount string (e.g., \"10.50\").\n * @param currency - The currency to validate against.\n * @returns The amount in minor units as a BigInt.\n * @throws {Error} If the format is invalid (scientific notation, non-numeric chars).\n * @throws {InvalidPrecisionError} If the precision exceeds the currency's decimals.\n */\nexport function parseToMinor(amount: string, currency: Currency): bigint {\n // Validate format\n if (/[eE]/.test(amount)) {\n throw new Error(\"Scientific notation not supported\");\n }\n\n // Reject ambiguous separators (commas, spaces, etc.)\n if (/[^0-9.-]/.test(amount)) {\n throw new Error(\"Invalid characters in amount\");\n }\n\n // Reject inputs with no digits (e.g. \"-\" or \"\")\n if (!/[0-9]/.test(amount)) {\n throw new Error(\"Invalid format\");\n }\n\n const parts = amount.split(\".\");\n if (parts.length > 2) {\n throw new Error(\"Invalid format: multiple decimal points\");\n }\n\n const integerPart = parts[0];\n const fractionalPart = parts[1] || \"\";\n\n if (fractionalPart.length > currency.decimals) {\n throw new InvalidPrecisionError(\n `Precision ${fractionalPart.length} exceeds currency decimals ${currency.decimals}`,\n );\n }\n\n // Pad fractional part\n const paddedFractional = fractionalPart.padEnd(currency.decimals, \"0\");\n\n const combined = integerPart + paddedFractional;\n\n return BigInt(combined);\n}\n","import { Money } from \"../money/Money\";\n\n/**\n * Options for formatting Money values.\n */\nexport interface FormatOptions {\n /**\n * The locale to use for formatting (e.g., \"en-US\", \"de-DE\").\n * If not provided, defaults to the currency's default locale or \"en-US\".\n */\n locale?: string;\n\n /**\n * Whether to include the currency symbol in the output.\n * Defaults to true.\n */\n symbol?: boolean;\n\n /**\n * How to display the currency.\n * 'symbol' (default): \"$1.00\"\n * 'code': \"USD 1.00\"\n * 'name': \"1.00 US dollars\"\n */\n display?: \"symbol\" | \"code\" | \"name\";\n\n /**\n * Whether to use accounting format for negative numbers.\n * When true, negative values are wrapped in parentheses instead of using a minus sign.\n * Defaults to false.\n * @example\n * // accounting: false (default): \"-$1.00\"\n * // accounting: true: \"($1.00)\"\n */\n accounting?: boolean;\n}\n\n/**\n * Formats a Money object into a string representation.\n *\n * Uses `Intl.NumberFormat` for locale-aware formatting of numbers and currency symbols.\n *\n * @param money - The Money object to format.\n * @param options - Formatting options.\n * @returns The formatted string.\n */\nexport function format(money: Money, options?: FormatOptions): string {\n const locale = options?.locale || money.currency.locale || \"en-US\";\n const showSymbol = options?.symbol ?? true;\n const display = options?.display || \"symbol\";\n const useAccounting = options?.accounting ?? false;\n\n const decimals = money.currency.decimals;\n const minor = money.minor;\n const isNegative = minor < 0n;\n const absMinor = isNegative ? -minor : minor;\n\n const divisor = 10n ** BigInt(decimals);\n const integerPart = absMinor / divisor;\n const fractionalPart = absMinor % divisor;\n\n // Pad fractional\n const fractionalStr = fractionalPart.toString().padStart(decimals, \"0\");\n\n // Get separators\n // We use a dummy format to extract the decimal separator for the locale\n const parts = new Intl.NumberFormat(locale, {\n style: \"decimal\",\n minimumFractionDigits: 1,\n }).formatToParts(1.1);\n\n const decimalSeparator =\n parts.find((p) => p.type === \"decimal\")?.value || \".\";\n\n // Format integer part with grouping using Intl (supports BigInt)\n const integerFormatted = new Intl.NumberFormat(locale, {\n style: \"decimal\",\n useGrouping: true,\n }).format(integerPart);\n\n const absString =\n decimals > 0\n ? `${integerFormatted}${decimalSeparator}${fractionalStr}`\n : integerFormatted;\n\n if (!showSymbol) {\n if (isNegative) {\n return useAccounting ? `(${absString})` : `-${absString}`;\n }\n return absString;\n }\n\n // Use formatToParts to get the template (sign position, currency position)\n let templateParts: Intl.NumberFormatPart[];\n try {\n templateParts = new Intl.NumberFormat(locale, {\n style: \"currency\",\n currency: money.currency.code,\n currencyDisplay: display,\n }).formatToParts(isNegative ? -1234.5 : 1234.5);\n } catch (e) {\n // Fallback for custom currencies or invalid codes\n const symbol =\n display === \"symbol\" ? money.currency.symbol : money.currency.code;\n if (isNegative) {\n return useAccounting\n ? `(${symbol}${absString})`\n : `-${symbol}${absString}`;\n }\n return `${symbol}${absString}`;\n }\n\n let result = \"\";\n let numberInserted = false;\n\n for (const part of templateParts) {\n switch (part.type) {\n case \"minusSign\": {\n // Skip the minus sign, we'll handle it later for accounting format\n if (!useAccounting) {\n result += part.value;\n }\n break;\n }\n\n case \"integer\": {\n if (!numberInserted) {\n result += absString;\n numberInserted = true;\n }\n break;\n }\n\n // Skip the remaining numeric parts, since we already inserted the full number string.\n case \"group\":\n case \"decimal\":\n case \"fraction\": {\n break;\n }\n\n case \"currency\": {\n if (display === \"symbol\" && money.currency.symbol) {\n result += money.currency.symbol;\n } else {\n result += part.value;\n }\n break;\n }\n\n default: {\n result += part.value; // literals, parentheses, etc.\n break;\n }\n }\n }\n\n // Apply accounting format if negative\n if (useAccounting && isNegative) {\n return `(${result.trim()})`;\n }\n\n return result;\n}\n","import { Currency } from \"../currency/Currency\";\nimport { getCurrency } from \"../currency/registry\";\nimport { RoundingMode } from \"../rounding/strategies\";\n\nimport { assertSameCurrency } from \"./guards\";\nimport { add, subtract, multiply, divide } from \"./arithmetic\";\nimport { allocate } from \"./allocation\";\nimport { parseToMinor } from \"../format/parser\";\nimport { format } from \"../format/formatter\";\n\n/**\n * Represents a monetary value in a specific currency.\n *\n * Money objects are immutable and store values in minor units (e.g., cents) using BigInt\n * to avoid floating-point precision errors.\n */\nexport class Money {\n /**\n * The amount in minor units (e.g., cents).\n */\n readonly minor: bigint;\n\n /**\n * The currency of this money value.\n */\n readonly currency: Currency;\n\n private constructor(minor: bigint, currency: Currency) {\n this.minor = minor;\n this.currency = currency;\n }\n\n private static resolveCurrency(currency: Currency | string): Currency {\n if (typeof currency === \"string\") {\n return getCurrency(currency);\n }\n return currency;\n }\n\n /**\n * Creates a Money instance from minor units (e.g., cents).\n *\n * @param minor - The amount in minor units. Can be a number or BigInt.\n * @param currency - The currency of the money (object or code string).\n * @returns A new Money instance.\n * @example\n * const m = Money.fromMinor(100, USD); // $1.00\n * const m2 = Money.fromMinor(100, 'USD'); // $1.00\n */\n static fromMinor(minor: bigint | number, currency: Currency | string): Money {\n return new Money(BigInt(minor), Money.resolveCurrency(currency));\n }\n\n /**\n * Alias for `fromMinor`. Creates a Money instance from cents/minor units.\n *\n * @param cents - The amount in minor units.\n * @param currency - The currency of the money (object or code string).\n * @returns A new Money instance.\n * @example\n * const m = Money.fromCents(100, 'USD'); // $1.00\n */\n static fromCents(cents: bigint | number, currency: Currency | string): Money {\n return Money.fromMinor(cents, currency);\n }\n\n /**\n * Creates a Money instance from major units (e.g., \"10.50\").\n *\n * @param amount - The amount as a string. Must be a valid decimal number.\n * @param currency - The currency of the money (object or code string).\n * @returns A new Money instance.\n * @throws {InvalidPrecisionError} If the amount has more decimal places than the currency allows.\n * @example\n * const m = Money.fromMajor(\"10.50\", USD); // $10.50\n */\n static fromMajor(amount: string, currency: Currency | string): Money {\n const resolvedCurrency = Money.resolveCurrency(currency);\n const minor = parseToMinor(amount, resolvedCurrency);\n return new Money(minor, resolvedCurrency);\n }\n\n /**\n * Alias for `fromMajor`. Creates a Money instance from a decimal string.\n *\n * @param amount - The amount as a string (e.g., \"10.50\").\n * @param currency - The currency of the money (object or code string).\n * @returns A new Money instance.\n * @throws {InvalidPrecisionError} If the amount has more decimal places than the currency allows.\n * @example\n * const m = Money.fromDecimal(\"10.50\", 'USD'); // $10.50\n */\n static fromDecimal(amount: string, currency: Currency | string): Money {\n return Money.fromMajor(amount, currency);\n }\n\n /**\n * Creates a Money instance from a floating-point number.\n *\n * ⚠️ WARNING: Floating-point numbers can have precision issues.\n * Prefer `Money.fromMajor(\"10.50\", currency)` for exact values.\n *\n * @param amount - The float amount in major units.\n * @param currency - The currency.\n * @param options - Options for handling precision.\n * @returns A new Money instance.\n */\n static fromFloat(\n amount: number,\n currency: Currency | string,\n options?: {\n rounding?: RoundingMode;\n suppressWarning?: boolean;\n },\n ): Money {\n if (!options?.suppressWarning && process.env.NODE_ENV !== \"production\") {\n console.warn(\n \"[monetra] Money.fromFloat() may lose precision. \" +\n 'Consider using Money.fromMajor(\"' +\n amount +\n '\", currency) instead.',\n );\n }\n const resolvedCurrency = Money.resolveCurrency(currency);\n const factor = 10 ** resolvedCurrency.decimals;\n const minorUnits = Math.round(amount * factor);\n return new Money(BigInt(minorUnits), resolvedCurrency);\n }\n\n /**\n * Returns the minimum of the provided Money values.\n * @param values - Money values to compare (must all be same currency).\n * @returns The Money with the smallest amount.\n * @throws {CurrencyMismatchError} If currencies don't match.\n */\n static min(...values: Money[]): Money {\n if (values.length === 0)\n throw new Error(\"At least one Money value required\");\n return values.reduce((min, current) => {\n assertSameCurrency(min, current);\n return current.lessThan(min) ? current : min;\n });\n }\n\n /**\n * Returns the maximum of the provided Money values.\n * @param values - Money values to compare (must all be same currency).\n * @returns The Money with the largest amount.\n * @throws {CurrencyMismatchError} If currencies don't match.\n */\n static max(...values: Money[]): Money {\n if (values.length === 0)\n throw new Error(\"At least one Money value required\");\n return values.reduce((max, current) => {\n assertSameCurrency(max, current);\n return current.greaterThan(max) ? current : max;\n });\n }\n\n /**\n * Creates a Money instance representing zero in the given currency.\n *\n * @param currency - The currency.\n * @returns A new Money instance with value 0.\n */\n static zero(currency: Currency | string): Money {\n return new Money(0n, Money.resolveCurrency(currency));\n }\n\n private resolveOther(other: Money | number | bigint | string): Money {\n if (other instanceof Money) {\n return other;\n }\n if (typeof other === \"string\") {\n return Money.fromMajor(other, this.currency);\n }\n return Money.fromMinor(other, this.currency);\n }\n\n /**\n * Adds another Money value to this one.\n *\n * @param other - The value to add (Money, minor units as number/bigint, or major units as string).\n * @returns A new Money instance representing the sum.\n * @throws {CurrencyMismatchError} If the currencies do not match.\n */\n add(other: Money | number | bigint | string): Money {\n const otherMoney = this.resolveOther(other);\n assertSameCurrency(this, otherMoney);\n return new Money(add(this.minor, otherMoney.minor), this.currency);\n }\n\n /**\n * Subtracts another Money value from this one.\n *\n * @param other - The value to subtract (Money, minor units as number/bigint, or major units as string).\n * @returns A new Money instance representing the difference.\n * @throws {CurrencyMismatchError} If the currencies do not match.\n */\n subtract(other: Money | number | bigint | string): Money {\n const otherMoney = this.resolveOther(other);\n assertSameCurrency(this, otherMoney);\n return new Money(subtract(this.minor, otherMoney.minor), this.currency);\n }\n\n /**\n * Multiplies this Money value by a scalar.\n *\n * @param multiplier - The number to multiply by.\n * @param options - Options for rounding if the result is not an integer.\n * @returns A new Money instance representing the product.\n * @throws {RoundingRequiredError} If the result is fractional and no rounding mode is provided.\n */\n multiply(\n multiplier: string | number,\n options?: { rounding?: RoundingMode },\n ): Money {\n const result = multiply(this.minor, multiplier, options?.rounding);\n return new Money(result, this.currency);\n }\n\n /**\n * Divides this Money value by a divisor.\n *\n * @param divisor - The number to divide by.\n * @param options - Options for rounding if the result is not an integer.\n * @returns A new Money instance representing the quotient.\n * @throws {RoundingRequiredError} If the result is fractional and no rounding mode is provided.\n * @throws {Error} If divisor is zero.\n */\n divide(\n divisor: number | string,\n options?: { rounding?: RoundingMode },\n ): Money {\n if (divisor === 0 || divisor === \"0\") {\n throw new Error(\"Division by zero\");\n }\n const result = divide(this.minor, divisor, options?.rounding);\n return new Money(result, this.currency);\n }\n\n /**\n * Returns the absolute value of this Money.\n * @returns A new Money instance with the absolute value.\n */\n abs(): Money {\n return new Money(this.minor < 0n ? -this.minor : this.minor, this.currency);\n }\n\n /**\n * Returns the negated value of this Money.\n * @returns A new Money instance with the negated value.\n */\n negate(): Money {\n return new Money(-this.minor, this.currency);\n }\n\n /**\n * Allocates (splits) this Money value according to a list of ratios.\n *\n * The sum of the parts will always equal the original amount.\n * Remainders are distributed to the parts with the largest fractional remainders.\n *\n * @param ratios - A list of numbers representing the ratios to split by.\n * @returns An array of Money instances.\n */\n allocate(ratios: number[]): Money[] {\n const shares = allocate(this.minor, ratios);\n return shares.map((share) => new Money(share, this.currency));\n }\n\n /**\n * Formats this Money value as a string.\n *\n * @param options - Formatting options.\n * @returns The formatted string.\n */\n format(options?: {\n locale?: string;\n symbol?: boolean;\n display?: \"symbol\" | \"code\" | \"name\";\n }): string {\n return format(this, options);\n }\n\n /**\n * Checks if this Money value is equal to another.\n *\n * @param other - The other Money value (Money, minor units as number/bigint, or major units as string).\n * @returns True if amounts and currencies are equal.\n */\n equals(other: Money | number | bigint | string): boolean {\n const otherMoney = this.resolveOther(other);\n return (\n this.currency.code === otherMoney.currency.code &&\n this.minor === otherMoney.minor\n );\n }\n\n /**\n * Checks if this Money value is greater than another.\n *\n * @param other - The other Money value (Money, minor units as number/bigint, or major units as string).\n * @returns True if this value is greater.\n * @throws {CurrencyMismatchError} If the currencies do not match.\n */\n greaterThan(other: Money | number | bigint | string): boolean {\n const otherMoney = this.resolveOther(other);\n assertSameCurrency(this, otherMoney);\n return this.minor > otherMoney.minor;\n }\n\n /**\n * Checks if this Money value is less than another.\n *\n * @param other - The other Money value (Money, minor units as number/bigint, or major units as string).\n * @returns True if this value is less.\n * @throws {CurrencyMismatchError} If the currencies do not match.\n */\n lessThan(other: Money | number | bigint | string): boolean {\n const otherMoney = this.resolveOther(other);\n assertSameCurrency(this, otherMoney);\n return this.minor < otherMoney.minor;\n }\n\n /**\n * Checks if this Money value is greater than or equal to another.\n */\n greaterThanOrEqual(other: Money | number | bigint | string): boolean {\n const otherMoney = this.resolveOther(other);\n assertSameCurrency(this, otherMoney);\n return this.minor >= otherMoney.minor;\n }\n\n /**\n * Checks if this Money value is less than or equal to another.\n */\n lessThanOrEqual(other: Money | number | bigint | string): boolean {\n const otherMoney = this.resolveOther(other);\n assertSameCurrency(this, otherMoney);\n return this.minor <= otherMoney.minor;\n }\n\n /**\n * Checks if this Money value is positive (greater than zero).\n */\n isPositive(): boolean {\n return this.minor > 0n;\n }\n\n /**\n * Compares this Money to another, returning -1, 0, or 1.\n * Useful for sorting.\n */\n compare(other: Money | number | bigint | string): -1 | 0 | 1 {\n const otherMoney = this.resolveOther(other);\n assertSameCurrency(this, otherMoney);\n if (this.minor < otherMoney.minor) return -1;\n if (this.minor > otherMoney.minor) return 1;\n return 0;\n }\n\n /**\n * Calculates a percentage of the money.\n * @param percent - The percentage (e.g., 50 for 50%).\n * @param rounding - Rounding mode (defaults to HALF_EVEN).\n */\n percentage(\n percent: number,\n rounding: RoundingMode = RoundingMode.HALF_EVEN,\n ): Money {\n return this.multiply(percent / 100, { rounding });\n }\n\n /**\n * Adds a percentage to the money.\n * @param percent - The percentage to add.\n * @param rounding - Rounding mode.\n */\n addPercent(\n percent: number,\n rounding: RoundingMode = RoundingMode.HALF_EVEN,\n ): Money {\n return this.add(this.percentage(percent, rounding));\n }\n\n /**\n * Subtracts a percentage from the money.\n * @param percent - The percentage to subtract.\n * @param rounding - Rounding mode.\n */\n subtractPercent(\n percent: number,\n rounding: RoundingMode = RoundingMode.HALF_EVEN,\n ): Money {\n return this.subtract(this.percentage(percent, rounding));\n }\n\n /**\n * Splits the money into equal parts.\n * @param parts - Number of parts.\n */\n split(parts: number): Money[] {\n const ratios = Array(parts).fill(1);\n return this.allocate(ratios);\n }\n\n /**\n * Checks if this Money value is zero.\n *\n * @returns True if the amount is zero.\n */\n isZero(): boolean {\n return this.minor === 0n;\n }\n\n /**\n * Checks if this Money value is negative.\n *\n * @returns True if the amount is negative.\n */\n isNegative(): boolean {\n return this.minor < 0n;\n }\n\n /**\n * Clamps this Money value between a minimum and maximum.\n *\n * @param min - The minimum Money value.\n * @param max - The maximum Money value.\n * @returns A new Money instance clamped between min and max.\n * @throws {CurrencyMismatchError} If currencies don't match.\n * @throws {Error} If min is greater than max.\n * @example\n * const price = Money.fromMajor(\"150\", 'USD');\n * const clamped = price.clamp(Money.fromMajor(\"50\", 'USD'), Money.fromMajor(\"100\", 'USD'));\n * // clamped is $100.00\n */\n clamp(min: Money, max: Money): Money {\n assertSameCurrency(this, min);\n assertSameCurrency(this, max);\n\n if (min.greaterThan(max)) {\n throw new Error(\"Clamp min cannot be greater than max\");\n }\n\n if (this.lessThan(min)) {\n return new Money(min.minor, this.currency);\n }\n if (this.greaterThan(max)) {\n return new Money(max.minor, this.currency);\n }\n return this;\n }\n\n /**\n * Returns the value as a decimal string without locale formatting.\n *\n * This returns a raw decimal representation suitable for storage or calculations,\n * without any currency symbols, grouping separators, or locale-specific formatting.\n *\n * @returns The decimal string representation (e.g., \"10.50\", \"-5.25\").\n * @example\n * const m = Money.fromMajor(\"1234.56\", 'USD');\n * m.toDecimalString(); // \"1234.56\"\n */\n toDecimalString(): string {\n const decimals = this.currency.decimals;\n const isNegative = this.minor < 0n;\n const absMinor = isNegative ? -this.minor : this.minor;\n\n if (decimals === 0) {\n return isNegative ? `-${absMinor.toString()}` : absMinor.toString();\n }\n\n const divisor = 10n ** BigInt(decimals);\n const integerPart = absMinor / divisor;\n const fractionalPart = absMinor % divisor;\n\n const fractionalStr = fractionalPart.toString().padStart(decimals, \"0\");\n const result = `${integerPart}.${fractionalStr}`;\n\n return isNegative ? `-${result}` : result;\n }\n\n /**\n * Returns a JSON representation of the Money object.\n *\n * @returns An object with amount (string), currency (code), and precision.\n */\n toJSON(): { amount: string; currency: string; precision: number } {\n return {\n amount: this.minor.toString(),\n currency: this.currency.code,\n precision: this.currency.decimals,\n };\n }\n\n /**\n * JSON reviver function for deserializing Money objects.\n *\n * Use with `JSON.parse()` to automatically reconstruct Money instances:\n *\n * @param key - The JSON key (unused).\n * @param value - The parsed JSON value.\n * @returns A Money instance if value is a serialized Money object, otherwise the original value.\n * @example\n * const json = '{\"amount\": \"1050\", \"currency\": \"USD\", \"precision\": 2}';\n * const money = JSON.parse(json, Money.reviver);\n * // money is Money instance: $10.50\n */\n static reviver(key: string, value: unknown): unknown {\n if (\n value !== null &&\n typeof value === \"object\" &&\n \"amount\" in value &&\n \"currency\" in value &&\n \"precision\" in value &&\n typeof (value as Record<string, unknown>).amount === \"string\" &&\n typeof (value as Record<string, unknown>).currency === \"string\" &&\n typeof (value as Record<string, unknown>).precision === \"number\"\n ) {\n const obj = value as {\n amount: string;\n currency: string;\n precision: number;\n };\n return Money.fromMinor(BigInt(obj.amount), obj.currency);\n }\n return value;\n }\n\n /**\n * Returns a string representation of the Money object (formatted).\n */\n toString(): string {\n return this.format();\n }\n}\n","import { Money } from \"../money/Money\";\nimport { RoundingMode } from \"../rounding/strategies\";\n\nexport interface LoanScheduleEntry {\n period: number;\n payment: Money;\n principal: Money;\n interest: Money;\n balance: Money;\n}\n\nexport interface LoanOptions {\n principal: Money;\n annualRate: number; // e.g., 0.05 for 5%\n periods: number; // Total number of payments\n periodsPerYear?: number; // Default: 12 (monthly)\n rounding?: RoundingMode;\n}\n\nexport interface InterestOnlyOptions {\n principal: Money;\n annualRate: number; // e.g., 0.05 for 5%\n periodsPerYear?: number; // Default: 12 (monthly)\n rounding?: RoundingMode;\n}\n\n/**\n * Calculates loan amortization schedule.\n */\nexport function loan(options: LoanOptions): LoanScheduleEntry[] {\n const {\n principal,\n annualRate,\n periods,\n periodsPerYear = 12,\n rounding = RoundingMode.HALF_EVEN,\n } = options;\n\n const periodicRate = annualRate / periodsPerYear;\n let payment: Money;\n\n if (annualRate === 0) {\n payment = principal.divide(periods, { rounding });\n } else {\n // PMT formula: P * (r(1+r)^n) / ((1+r)^n - 1)\n const r = periodicRate;\n const n = periods;\n const numerator = r * Math.pow(1 + r, n);\n const denominator = Math.pow(1 + r, n) - 1;\n const pmtMultiplier = numerator / denominator;\n payment = principal.multiply(pmtMultiplier, { rounding });\n }\n\n const schedule: LoanScheduleEntry[] = [];\n let balance = principal;\n\n for (let period = 1; period <= periods; period++) {\n const interest =\n annualRate === 0\n ? Money.zero(principal.currency)\n : balance.multiply(periodicRate, { rounding });\n\n let principalPayment = payment.subtract(interest);\n\n // If payment < interest (negative amortization), principal payment is negative.\n // This implementation assumes standard amortization.\n\n balance = balance.subtract(principalPayment);\n\n // Handle final period rounding adjustment\n if (period === periods && !balance.isZero()) {\n const adjustedPrincipal = principalPayment.add(balance);\n schedule.push({\n period,\n payment: interest.add(adjustedPrincipal),\n principal: adjustedPrincipal,\n interest,\n balance: Money.zero(principal.currency),\n });\n } else {\n schedule.push({\n period,\n payment,\n principal: principalPayment,\n interest,\n balance: balance.isNegative()\n ? Money.zero(principal.currency)\n : balance,\n });\n }\n }\n\n return schedule;\n}\n\n/**\n * Calculates monthly payment amount.\n */\nexport function pmt(\n options: Omit<LoanOptions, \"rounding\"> & { rounding?: RoundingMode },\n): Money {\n const schedule = loan(options);\n return schedule[0].payment;\n}\n\n/**\n * Calculates total interest over the life of the loan using the payment formula.\n */\nexport function totalInterest(options: LoanOptions): Money {\n const {\n principal,\n annualRate,\n periods,\n rounding = RoundingMode.HALF_EVEN,\n } = options;\n\n if (annualRate === 0) {\n return Money.zero(principal.currency);\n }\n\n const payment = pmt(options);\n const totalPaid = payment.multiply(periods, { rounding });\n return totalPaid.subtract(principal);\n}\n\n/**\n * Sums the interest column from a loan schedule.\n */\nexport function totalInterestFromSchedule(\n schedule: LoanScheduleEntry[],\n): Money {\n if (schedule.length === 0) {\n throw new Error(\"Schedule must have at least one entry\");\n }\n\n const currency = schedule[0].interest.currency;\n return schedule.reduce(\n (sum, entry) => sum.add(entry.interest),\n Money.zero(currency),\n );\n}\n\n/**\n * Calculates the periodic payment for an interest-only loan.\n *\n * In an interest-only loan, the borrower pays only the interest each period,\n * with the full principal due at maturity or refinancing. This is common in:\n * - Commercial real estate\n * - Construction loans\n * - Home Equity Lines of Credit (HELOCs)\n *\n * Formula: Payment = Principal × Periodic Rate\n * Where Periodic Rate = Annual Rate / Periods Per Year\n *\n * @param options - Interest-only loan configuration\n * @returns The periodic interest payment as a Money object\n *\n * @example\n * ```typescript\n * const principal = Money.fromMajor(\"100000\", USD);\n * const payment = interestOnlyPayment({\n * principal,\n * annualRate: 0.06, // 6% annual\n * periodsPerYear: 12 // Monthly payments\n * });\n * // Returns $500.00 per month\n * ```\n */\nexport function interestOnlyPayment(options: InterestOnlyOptions): Money {\n const {\n principal,\n annualRate,\n periodsPerYear = 12,\n rounding = RoundingMode.HALF_EVEN,\n } = options;\n\n // If rate is zero, interest payment is zero\n if (annualRate === 0) {\n return Money.zero(principal.currency);\n }\n\n const periodicRate = annualRate / periodsPerYear;\n return principal.multiply(periodicRate, { rounding });\n}\n","import { Money } from \"../money/Money\";\nimport { RoundingMode } from \"../rounding/strategies\";\n\nexport interface CompoundOptions {\n rate: number; // Annual rate (e.g., 0.07 for 7%)\n years: number;\n compoundingPerYear?: number; // Default: 12 (monthly)\n rounding?: RoundingMode;\n}\n\n/**\n * Calculates future value with compound interest.\n * FV = PV * (1 + r/n)^(n*t)\n */\nexport function futureValue(\n presentValue: Money,\n options: CompoundOptions,\n): Money {\n const {\n rate,\n years,\n compoundingPerYear = 12,\n rounding = RoundingMode.HALF_EVEN,\n } = options;\n\n const n = compoundingPerYear;\n const t = years;\n const multiplier = Math.pow(1 + rate / n, n * t);\n\n return presentValue.multiply(multiplier, { rounding });\n}\n\n/**\n * Calculates present value (discounting).\n * PV = FV / (1 + r/n)^(n*t)\n */\nexport function presentValue(\n futureVal: Money,\n options: CompoundOptions,\n): Money {\n const {\n rate,\n years,\n compoundingPerYear = 12,\n rounding = RoundingMode.HALF_EVEN,\n } = options;\n\n const n = compoundingPerYear;\n const t = years;\n const divisor = Math.pow(1 + rate / n, n * t);\n\n return futureVal.divide(divisor, { rounding });\n}\n\n// Alias for familiarity\nexport const compound = futureValue;\nexport const discount = presentValue;\n","import { Money } from \"../money/Money\";\nimport { RoundingMode } from \"../rounding/strategies\";\nimport { CurrencyMismatchError } from \"../errors/CurrencyMismatchError\";\nimport { InvalidArgumentError } from \"../errors/InvalidArgumentError\";\n\n/**\n * Calculates Return on Investment (ROI).\n * ROI = (Final Value - Initial Value) / Initial Value\n *\n * @param initialValue - The initial investment cost.\n * @param finalValue - The final value of the investment.\n * @returns The ROI as a decimal (e.g., 0.15 for 15%).\n * @throws {CurrencyMismatchError} If currencies differ.\n */\nexport function roi(initialValue: Money, finalValue: Money): number {\n if (initialValue.currency.code !== finalValue.currency.code) {\n throw new CurrencyMismatchError(\n initialValue.currency.code,\n finalValue.currency.code,\n );\n }\n\n const gain = finalValue.subtract(initialValue);\n return Number(gain.minor) / Number(initialValue.minor);\n}\n\n/**\n * Calculates Net Present Value of cash flows.\n */\nexport function npv(\n discountRate: number,\n cashFlows: Money[], // First is initial investment (usually negative)\n): Money {\n if (cashFlows.length === 0) {\n throw new Error(\"At least one cash flow required\");\n }\n\n const currency = cashFlows[0].currency;\n\n let total = Money.zero(currency);\n\n for (let i = 0; i < cashFlows.length; i++) {\n const discountFactor = Math.pow(1 + discountRate, i);\n const discounted = cashFlows[i].divide(discountFactor, {\n rounding: RoundingMode.HALF_EVEN,\n });\n total = total.add(discounted);\n }\n\n return total;\n}\n\n/**\n * Calculates Internal Rate of Return using Newton-Raphson method.\n * @returns The IRR as a decimal (e.g., 0.12 for 12%)\n */\nexport function irr(cashFlows: Money[], guess: number = 0.1): number {\n const values = cashFlows.map((cf) => Number(cf.minor));\n\n const maxIterations = 100;\n const tolerance = 1e-7;\n let rate = guess;\n\n for (let i = 0; i < maxIterations; i++) {\n let npvValue = 0;\n let derivative = 0;\n\n for (let j = 0; j < values.length; j++) {\n const denominator = Math.pow(1 + rate, j);\n npvValue += values[j] / denominator;\n\n if (j > 0) {\n derivative -= (j * values[j]) / Math.pow(1 + rate, j + 1);\n }\n }\n\n const newRate = rate - npvValue / derivative;\n\n if (Math.abs(newRate - rate) < tolerance) {\n return newRate;\n }\n\n rate = newRate;\n }\n\n throw new Error(\"IRR calculation did not converge\");\n}\n\n/**\n * Calculates the Current Yield of a bond.\n * Current Yield = Annual Coupon Payment / Current Market Price\n *\n * @param annualCoupon - The total annual coupon payment.\n * @param currentPrice - The current market price of the bond.\n * @returns The current yield as a decimal (e.g., 0.05 for 5%).\n * @throws {CurrencyMismatchError} If currencies differ.\n * @throws {InvalidArgumentError} If price is zero or negative.\n */\nexport function currentYield(annualCoupon: Money, currentPrice: Money): number {\n if (annualCoupon.currency.code !== currentPrice.currency.code) {\n throw new CurrencyMismatchError(\n annualCoupon.currency.code,\n currentPrice.currency.code,\n );\n }\n\n if (currentPrice.minor <= 0n) {\n throw new InvalidArgumentError(\"Current price must be positive\");\n }\n\n return Number(annualCoupon.minor) / Number(currentPrice.minor);\n}\n","/**\n * Represents an interest rate or percentage rate with explicit handling\n * to avoid confusion between percentage and decimal forms.\n *\n * @example\n * const rate = Rate.percent(5); // 5% interest rate\n * const rate2 = Rate.decimal(0.05); // Same as 5%\n *\n * rate.toPercent(); // 5\n * rate.toDecimal(); // 0.05\n *\n * // Safe operations\n * rate.add(Rate.percent(2)); // 7%\n * rate.multiply(2); // 10%\n */\nexport class Rate {\n /**\n * Internal storage as a decimal (e.g., 0.05 for 5%).\n * Uses a scaled BigInt internally for precision.\n */\n private readonly decimalValue: bigint;\n\n /**\n * Scale factor for internal precision (1e18 for 18 decimal places).\n */\n private static readonly SCALE = 10n ** 18n;\n\n private constructor(decimalValue: bigint) {\n this.decimalValue = decimalValue;\n }\n\n /**\n * Creates a Rate from a percentage value (e.g., 5 for 5%).\n *\n * @param percent - The percentage value.\n * @returns A new Rate instance.\n * @example\n * const rate = Rate.percent(5.5); // 5.5%\n */\n static percent(percent: number | string): Rate {\n const decimal = typeof percent === \"string\" ? parseFloat(percent) : percent;\n const scaled = BigInt(Math.round((decimal / 100) * Number(Rate.SCALE)));\n return new Rate(scaled);\n }\n\n /**\n * Creates a Rate from a decimal value (e.g., 0.05 for 5%).\n *\n * @param decimal - The decimal value.\n * @returns A new Rate instance.\n * @example\n * const rate = Rate.decimal(0.055); // 5.5%\n */\n static decimal(decimal: number | string): Rate {\n const value = typeof decimal === \"string\" ? parseFloat(decimal) : decimal;\n const scaled = BigInt(Math.round(value * Number(Rate.SCALE)));\n return new Rate(scaled);\n }\n\n /**\n * Creates a Rate representing zero.\n *\n * @returns A Rate of 0%.\n */\n static zero(): Rate {\n return new Rate(0n);\n }\n\n /**\n * Returns the rate as a percentage (e.g., 5 for 5%).\n *\n * @returns The percentage value as a number.\n */\n toPercent(): number {\n return (Number(this.decimalValue) / Number(Rate.SCALE)) * 100;\n }\n\n /**\n * Returns the rate as a decimal (e.g., 0.05 for 5%).\n *\n * @returns The decimal value as a number.\n */\n toDecimal(): number {\n return Number(this.decimalValue) / Number(Rate.SCALE);\n }\n\n /**\n * Adds another rate to this one.\n *\n * @param other - The rate to add.\n * @returns A new Rate representing the sum.\n */\n add(other: Rate): Rate {\n return new Rate(this.decimalValue + other.decimalValue);\n }\n\n /**\n * Subtracts another rate from this one.\n *\n * @param other - The rate to subtract.\n * @returns A new Rate representing the difference.\n */\n subtract(other: Rate): Rate {\n return new Rate(this.decimalValue - other.decimalValue);\n }\n\n /**\n * Multiplies this rate by a scalar.\n *\n * @param multiplier - The number to multiply by.\n * @returns A new Rate representing the product.\n */\n multiply(multiplier: number): Rate {\n const scaled = BigInt(Math.round(multiplier * Number(Rate.SCALE)));\n return new Rate((this.decimalValue * scaled) / Rate.SCALE);\n }\n\n /**\n * Divides this rate by a divisor.\n *\n * @param divisor - The number to divide by.\n * @returns A new Rate representing the quotient.\n */\n divide(divisor: number): Rate {\n const scaled = BigInt(Math.round(divisor * Number(Rate.SCALE)));\n return new Rate((this.decimalValue * Rate.SCALE) / scaled);\n }\n\n /**\n * Checks if this rate equals another.\n *\n * @param other - The rate to compare.\n * @returns True if the rates are equal.\n */\n equals(other: Rate): boolean {\n return this.decimalValue === other.decimalValue;\n }\n\n /**\n * Checks if this rate is greater than another.\n *\n * @param other - The rate to compare.\n * @returns True if this rate is greater.\n */\n greaterThan(other: Rate): boolean {\n return this.decimalValue > other.decimalValue;\n }\n\n /**\n * Checks if this rate is less than another.\n *\n * @param other - The rate to compare.\n * @returns True if this rate is less.\n */\n lessThan(other: Rate): boolean {\n return this.decimalValue < other.decimalValue;\n }\n\n /**\n * Checks if this rate is zero.\n *\n * @returns True if the rate is 0%.\n */\n isZero(): boolean {\n return this.decimalValue === 0n;\n }\n\n /**\n * Checks if this rate is negative.\n *\n * @returns True if the rate is negative.\n */\n isNegative(): boolean {\n return this.decimalValue < 0n;\n }\n\n /**\n * Returns a string representation of the rate as a percentage.\n *\n * @returns The rate as a percentage string (e.g., \"5.5%\").\n */\n toString(): string {\n return `${this.toPercent()}%`;\n }\n\n /**\n * Computes compound factor: (1 + rate)^periods.\n *\n * @param periods - The number of compounding periods.\n * @returns The compound factor as a number.\n * @example\n * Rate.percent(10).compoundFactor(3); // (1.10)^3 = 1.331\n */\n compoundFactor(periods: number): number {\n return Math.pow(1 + this.toDecimal(), periods);\n }\n\n /**\n * Returns the periodic rate for a given frequency.\n *\n * @param periodsPerYear - Number of periods per year (e.g., 12 for monthly).\n * @returns A new Rate representing the periodic rate.\n * @example\n * Rate.percent(12).periodic(12); // 1% monthly\n */\n periodic(periodsPerYear: number): Rate {\n return this.divide(periodsPerYear);\n }\n\n /**\n * Converts an effective rate to a nominal rate.\n *\n * @param periodsPerYear - Number of compounding periods per year.\n * @returns The nominal annual rate.\n */\n toNominal(periodsPerYear: number): Rate {\n const effectiveDecimal = this.toDecimal();\n const nominalDecimal =\n periodsPerYear * (Math.pow(1 + effectiveDecimal, 1 / periodsPerYear) - 1);\n return Rate.decimal(nominalDecimal);\n }\n\n /**\n * Converts a nominal rate to an effective annual rate.\n *\n * @param periodsPerYear - Number of compounding periods per year.\n * @returns The effective annual rate.\n */\n toEffective(periodsPerYear: number): Rate {\n const nominalDecimal = this.toDecimal();\n const effectiveDecimal =\n Math.pow(1 + nominalDecimal / periodsPerYear, periodsPerYear) - 1;\n return Rate.decimal(effectiveDecimal);\n }\n\n /**\n * Returns a JSON representation.\n */\n toJSON(): { percent: number; decimal: number } {\n return {\n percent: this.toPercent(),\n decimal: this.toDecimal(),\n };\n }\n}\n","import { Money } from \"../money/Money\";\nimport { Rate } from \"./rate\";\nimport { RoundingMode } from \"../rounding/strategies\";\n\nexport interface SimpleInterestOptions {\n rate: Rate;\n years: number;\n rounding?: RoundingMode;\n}\n\n/**\n * Calculates simple interest earned on principal.\n *\n * Simple interest is calculated using the formula: Interest = P × r × t\n * Where:\n * - P = Principal amount\n * - r = Annual interest rate (as decimal)\n * - t = Time in years\n *\n * This is commonly used for:\n * - Short-term loans\n * - Accrued interest between bond coupon payments\n * - Basic savings calculations without compounding\n *\n * @param principal - The principal amount as a Money object\n * @param options - Configuration options including rate, years, and rounding\n * @returns The interest amount as a Money object\n *\n * @example\n * ```typescript\n * const principal = Money.fromMajor(\"1000.00\", USD);\n * const rate = Rate.percent(5); // 5% annual rate\n * const interest = simpleInterest(principal, { rate, years: 2 });\n * console.log(interest.format()); // \"$100.00\" (1000 × 0.05 × 2)\n * ```\n */\nexport function simpleInterest(\n principal: Money,\n options: SimpleInterestOptions,\n): Money {\n const { rate, years, rounding = RoundingMode.HALF_EVEN } = options;\n\n // Handle edge cases\n if (rate.isZero() || years === 0) {\n return Money.zero(principal.currency);\n }\n\n // Simple Interest = Principal × Rate × Time\n const interestMultiplier = rate.toDecimal() * years;\n\n return principal.multiply(interestMultiplier, { rounding });\n}\n\n/**\n * Calculates the total amount (principal + simple interest).\n *\n * Uses the formula: Total = P × (1 + r × t)\n * Where:\n * - P = Principal amount\n * - r = Annual interest rate (as decimal)\n * - t = Time in years\n *\n * This represents the final amount you would have after earning\n * simple interest on the principal for the specified time period.\n *\n * @param principal - The principal amount as a Money object\n * @param options - Configuration options including rate, years, and rounding\n * @returns The total amount (principal + interest) as a Money object\n *\n * @example\n * ```typescript\n * const principal = Money.fromMajor(\"1000.00\", USD);\n * const rate = Rate.percent(5); // 5% annual rate\n * const total = simpleInterestTotal(principal, { rate, years: 2 });\n * console.log(total.format()); // \"$1,100.00\" (1000 × (1 + 0.05 × 2))\n * ```\n */\nexport function simpleInterestTotal(\n principal: Money,\n options: SimpleInterestOptions,\n): Money {\n const { rate, years, rounding = RoundingMode.HALF_EVEN } = options;\n\n // Handle edge cases\n if (rate.isZero() || years === 0) {\n return principal;\n }\n\n // Total Amount = Principal × (1 + rate × time)\n const totalMultiplier = 1 + rate.toDecimal() * years;\n\n return principal.multiply(totalMultiplier, { rounding });\n}\n","import { Money } from \"../money/Money\";\nimport { assertSameCurrency } from \"../money/guards\";\n\n/**\n * Input parameters for calculating all leverage ratios\n */\nexport interface LeverageInputs {\n totalDebt: Money;\n totalEquity: Money;\n totalAssets: Money;\n ebit: Money;\n interestExpense: Money;\n}\n\n/**\n * Result of leverage ratio calculations\n */\nexport interface LeverageResult {\n debtToEquity: number;\n debtToAssets: number;\n interestCoverage: number;\n equityMultiplier: number;\n}\n\n/**\n * Calculates the Debt-to-Equity (D/E) ratio,\n * Formula: Total Debt / Total Equity\n *\n * @param totalDebt - Total liabilities\n * @param totalEquity - Total shareholders' equity\n * @returns The D/E ratio as a number\n * @throws {Error} If totalEquity is zero\n */\nexport function debtToEquity(totalDebt: Money, totalEquity: Money): number {\n assertSameCurrency(totalDebt, totalEquity);\n if (totalEquity.isZero()) {\n throw new Error(\"Total equity cannot be zero\");\n }\n return Number(totalDebt.minor) / Number(totalEquity.minor);\n}\n\n/**\n * Calculates the Debt-to-Assets ratio.\n * Formula: Total Debt / Total Assets\n *\n * @param totalDebt - Total liabilities\n * @param totalAssets - Total assets\n * @returns The Debt-to-Assets ratio as a number\n * @throws {Error} If totalAssets is zero\n */\nexport function debtToAssets(totalDebt: Money, totalAssets: Money): number {\n assertSameCurrency(totalDebt, totalAssets);\n if (totalAssets.isZero()) {\n throw new Error(\"Total assets cannot be zero\");\n }\n return Number(totalDebt.minor) / Number(totalAssets.minor);\n}\n\n/**\n * Calculates the Interest Coverage ratio.\n * Formula: EBIT / Interest Expense\n *\n * @param ebit - Earnings Before Interest and Taxes\n * @param interestExpense - Total interest expense\n * @returns The Interest Coverage ratio. Returns Infinity if interest expense is zero\n */\nexport function interestCoverage(ebit: Money, interestExpense: Money): number {\n assertSameCurrency(ebit, interestExpense);\n if (interestExpense.isZero()) {\n return Infinity;\n }\n return Number(ebit.minor) / Number(interestExpense.minor);\n}\n\n/**\n * Calculates the Equity Multiplier\n * Formula: TotalAssets / TotalEquity\n *\n * @param totalAssets - Total assets\n * @param totalEquity - Total shareholders' equity\n * @returns The Equity Multiplier ratio as a number\n * @throws {Error} If total Equity is zero\n */\nexport function equityMultiplier(\n totalAssets: Money,\n totalEquity: Money,\n): number {\n assertSameCurrency(totalAssets, totalEquity);\n if (totalEquity.isZero()) {\n throw new Error(\"Total equity cannot be zero\");\n }\n return Number(totalAssets.minor) / Number(totalEquity.minor);\n}\n\n/**\n * Calculates all leverage ratios at once\n *\n * @param inputs - Object containing all necessary Money values\n * @returns An object with all calculated leverage ratios\n */\nexport function leverageRatios(inputs: LeverageInputs): LeverageResult {\n return {\n debtToEquity: debtToEquity(inputs.totalDebt, inputs.totalEquity),\n debtToAssets: debtToAssets(inputs.totalDebt, inputs.totalAssets),\n interestCoverage: interestCoverage(inputs.ebit, inputs.interestExpense),\n equityMultiplier: equityMultiplier(inputs.totalAssets, inputs.totalEquity),\n };\n}\n","import { Money } from \"../money/Money\";\nimport { RoundingMode } from \"../rounding/strategies\";\nimport { InvalidArgumentError } from \"../errors/InvalidArgumentError\";\nimport { CurrencyMismatchError } from \"../errors/CurrencyMismatchError\";\n\nexport interface DepreciationOptions {\n cost: Money;\n salvageValue: Money;\n usefulLife: number; // in years\n rounding?: RoundingMode;\n}\n\nexport interface DepreciationResult {\n annualDepreciation: Money;\n bookValueAtYear(year: number): Money;\n schedule(): { year: number; depreciation: Money; bookValue: Money }[];\n}\n\n/**\n * Calculates straight-line depreciation for an asset.\n *\n * Formula:\n * Annual Depreciation = (Cost - Salvage Value) / Useful Life\n * Book Value at Year N = Cost - (Annual Depreciation × N)\n *\n * @param options - Configuration for depreciation calculation\n * @returns Object containing annual depreciation, book value calculator, and schedule generator\n * @throws {CurrencyMismatchError} If cost and salvage value currencies differ\n * @throws {InvalidArgumentError} If useful life is not positive or salvage value > cost\n */\nexport function straightLineDepreciation(\n options: DepreciationOptions,\n): DepreciationResult {\n const {\n cost,\n salvageValue,\n usefulLife,\n rounding = RoundingMode.HALF_EVEN,\n } = options;\n\n if (cost.currency.code !== salvageValue.currency.code) {\n throw new CurrencyMismatchError(\n cost.currency.code,\n salvageValue.currency.code,\n );\n }\n\n if (usefulLife <= 0) {\n throw new InvalidArgumentError(\"Useful life must be positive\");\n }\n\n if (salvageValue.greaterThan(cost)) {\n throw new InvalidArgumentError(\"Salvage value cannot be greater than cost\");\n }\n\n const depreciableAmount = cost.subtract(salvageValue);\n const annualDepreciation = depreciableAmount.divide(usefulLife, { rounding });\n\n const result: DepreciationResult = {\n annualDepreciation,\n\n bookValueAtYear(year: number): Money {\n if (year < 0) {\n throw new InvalidArgumentError(\"Year must be non-negative\");\n }\n if (year === 0) return cost;\n\n const totalDepreciation = annualDepreciation.multiply(year);\n const bookValue = cost.subtract(totalDepreciation);\n\n // Ensure book value doesn't drop below salvage value\n if (bookValue.lessThan(salvageValue)) {\n return salvageValue;\n }\n return bookValue;\n },\n\n schedule(): { year: number; depreciation: Money; bookValue: Money }[] {\n const schedule = [];\n let previousBookValue = cost;\n const maxYears = Math.ceil(usefulLife);\n\n for (let year = 1; year <= maxYears; year++) {\n const currentBookValue = result.bookValueAtYear(year);\n const depreciation = previousBookValue.subtract(currentBookValue);\n\n schedule.push({\n year,\n depreciation,\n bookValue: currentBookValue,\n });\n\n previousBookValue = currentBookValue;\n }\n\n return schedule;\n },\n };\n\n return result;\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACEA,IAAM,WAAkC,oBAAI,IAAI;AAgBzC,SAAS,YAAY,MAAwB;AAClD,QAAM,WAAW,SAAS,IAAI,IAAI;AAClC,MAAI,CAAC,UAAU;AACb,UAAM,IAAI,MAAM,aAAa,IAAI,0BAA0B;AAAA,EAC7D;AACA,SAAO;AACT;;;ACRO,IAAM,eAAN,cAA2B,MAAM;AAAA,EAMtC,YAAY,SAAiB,MAAwB;AACnD,UAAM,OAAO;AACb,SAAK,OAAO,KAAK,YAAY;AAC7B,SAAK,OAAO;AACZ,WAAO,eAAe,MAAM,WAAW,SAAS;AAAA,EAClD;AACF;;;AC1BO,IAAM,wBAAN,cAAoC,aAAa;AAAA,EAWtD,YAAY,UAAkB,UAAkB;AAC9C;AAAA,MACE,+BAA+B,QAAQ,cAAc,QAAQ;AAAA;AAAA,8CAEZ,QAAQ;AAAA,iDACL,QAAQ;AAAA;AAAA,IAE9D;AACA,SAAK,WAAW;AAChB,SAAK,WAAW;AAAA,EAClB;AACF;;;ACtBO,IAAM,wBAAN,cAAoC,aAAa;AAAA,EACtD,YAAY,SAAiB;AAC3B,UAAM,4DAA2C;AAAA,EACnD;AACF;;;ACJO,IAAM,wBAAN,cAAoC,aAAa;AAAA,EACtD,YAAY,WAAoB,QAAiB;AAC/C,QAAI,UACF;AACF,QAAI,aAAa,WAAW,QAAW;AACrC,gBACE,yBAAyB,SAAS,YAAY,MAAM;AAAA;AAAA,WAExC,SAAS;AAAA;AAAA,IAEzB;AACA,UAAM,4DAA2C;AAAA,EACnD;AACF;;;ACbO,IAAM,uBAAN,cAAmC,aAAa;AAAA,EACrD,YAAY,SAAiB;AAC3B,UAAM,0DAA0C;AAAA,EAClD;AACF;;;ACHO,SAAS,mBAAmB,GAAU,GAAgB;AAC3D,MAAI,EAAE,SAAS,SAAS,EAAE,SAAS,MAAM;AACvC,UAAM,IAAI,sBAAsB,EAAE,SAAS,MAAM,EAAE,SAAS,IAAI;AAAA,EAClE;AACF;;;ACHO,SAAS,mBACd,WACA,aACA,MACQ;AACR,MAAI,gBAAgB,IAAI;AACtB,UAAM,IAAI,MAAM,kBAAkB;AAAA,EACpC;AAEA,QAAM,WAAW,YAAY;AAC7B,QAAM,YAAY,YAAY;AAE9B,MAAI,cAAc,IAAI;AACpB,WAAO;AAAA,EACT;AAEA,QAAM,mBAAmB,YAAY,OAAO,cAAc;AAC1D,QAAM,mBAAmB,CAAC;AAE1B,QAAM,eAAe,YAAY,KAAK,CAAC,YAAY;AACnD,QAAM,iBAAiB,cAAc,KAAK,CAAC,cAAc;AAGzD,QAAM,SAAS,eAAe,OAAO;AACrC,QAAM,iBAAiB,eAAe,KAAK;AAE3C,UAAQ,MAAM;AAAA,IACZ;AAGE,aAAO,mBAAmB,WAAW,WAAW;AAAA,IAClD;AAGE,aAAO,mBAAmB,WAAW,KAAK;AAAA,IAC5C;AACE,UAAI,kBAAkB,QAAQ;AAC5B,eAAO,mBAAmB,WAAW,KAAK,WAAW;AAAA,MACvD;AACA,aAAO;AAAA,IACT;AACE,UAAI,gBAAgB;AAClB,eAAO,mBAAmB,WAAW,KAAK,WAAW;AAAA,MACvD;AACA,aAAO;AAAA,IACT;AACE,UAAI,gBAAgB;AAClB,eAAO,mBAAmB,WAAW,KAAK,WAAW;AAAA,MACvD;AACA,UAAI,QAAQ;AAGV,YAAI,WAAW,OAAO,IAAI;AACxB,iBAAO,mBAAmB,WAAW,KAAK,WAAW;AAAA,QACvD;AAAA,MACF;AACA,aAAO;AAAA,IACT;AAEE,aAAO;AAAA,IACT;AACE,YAAM,IAAI,MAAM,8BAA8B,IAAI,EAAE;AAAA,EACxD;AACF;;;AC7DO,SAAS,IAAI,GAAW,GAAmB;AAChD,SAAO,IAAI;AACb;AAKO,SAAS,SAAS,GAAW,GAAmB;AACrD,SAAO,IAAI;AACb;AAcO,SAAS,SACd,QACA,YACA,UACQ;AACR,QAAM,EAAE,WAAW,YAAY,IAAI,gBAAgB,UAAU;AAK7D,QAAM,UAAU,SAAS;AAEzB,MAAI,UAAU,gBAAgB,IAAI;AAChC,WAAO,UAAU;AAAA,EACnB;AAEA,MAAI,CAAC,UAAU;AACb,UAAM,IAAI;AAAA,MACR;AAAA,MACA,OAAO,OAAO,IAAI,OAAO,WAAW;AAAA,IACtC;AAAA,EACF;AAEA,SAAO,mBAAmB,SAAS,aAAa,QAAQ;AAC1D;AAWO,SAAS,OACd,QACA,SACA,UACQ;AACR,QAAM,EAAE,WAAW,YAAY,IAAI,gBAAgB,OAAO;AAK1D,QAAM,UAAU,SAAS;AAEzB,MAAI,UAAU,cAAc,IAAI;AAC9B,WAAO,UAAU;AAAA,EACnB;AAEA,MAAI,CAAC,UAAU;AACb,UAAM,IAAI;AAAA,MACR;AAAA,MACA,OAAO,OAAO,IAAI,OAAO,SAAS;AAAA,IACpC;AAAA,EACF;AAEA,SAAO,mBAAmB,SAAS,WAAW,QAAQ;AACxD;AAEA,SAAS,gBAAgB,YAGvB;AACA,QAAM,IAAI,WAAW,SAAS;AAG9B,MAAI,OAAO,KAAK,CAAC,GAAG;AAClB,UAAM,IAAI,MAAM,mCAAmC;AAAA,EACrD;AAEA,QAAM,QAAQ,EAAE,MAAM,GAAG;AACzB,MAAI,MAAM,SAAS,GAAG;AACpB,UAAM,IAAI,MAAM,uBAAuB;AAAA,EACzC;AAEA,QAAM,cAAc,MAAM,CAAC;AAC3B,QAAM,iBAAiB,MAAM,CAAC,KAAK;AAEnC,QAAM,cAAc,OAAO,OAAO,eAAe,MAAM;AACvD,QAAM,YAAY,OAAO,cAAc,cAAc;AAErD,SAAO,EAAE,WAAW,YAAY;AAClC;;;ACrGO,SAAS,SAAS,QAAgB,QAA4B;AACnE,MAAI,OAAO,WAAW,GAAG;AACvB,UAAM,IAAI,MAAM,iCAAiC;AAAA,EACnD;AAGA,QAAM,eAAe,OAAO,IAAI,CAAC,MAAM;AACrC,UAAM,IAAI,EAAE,SAAS;AACrB,QAAI,OAAO,KAAK,CAAC,EAAG,OAAM,IAAI,MAAM,mCAAmC;AACvE,UAAM,QAAQ,EAAE,MAAM,GAAG;AACzB,UAAM,WAAW,MAAM,CAAC,IAAI,MAAM,CAAC,EAAE,SAAS;AAC9C,UAAM,QAAQ,OAAO,MAAM,CAAC,KAAK,MAAM,CAAC,KAAK,GAAG;AAChD,WAAO,EAAE,OAAO,SAAS;AAAA,EAC3B,CAAC;AAED,QAAM,cAAc,KAAK,IAAI,GAAG,aAAa,IAAI,CAAC,MAAM,EAAE,QAAQ,CAAC;AAEnE,QAAM,mBAAmB,aAAa,IAAI,CAAC,MAAM;AAC/C,UAAM,SAAS,OAAO,OAAO,cAAc,EAAE,QAAQ;AACrD,WAAO,EAAE,QAAQ;AAAA,EACnB,CAAC;AAED,QAAM,QAAQ,iBAAiB,OAAO,CAAC,KAAK,MAAM,MAAM,GAAG,EAAE;AAE7D,MAAI,UAAU,IAAI;AAChB,UAAM,IAAI,MAAM,uCAAuC;AAAA,EACzD;AAEA,QAAM,UAAiE,CAAC;AACxE,MAAI,iBAAiB;AAErB,WAAS,IAAI,GAAG,IAAI,iBAAiB,QAAQ,KAAK;AAChD,UAAM,QAAQ,iBAAiB,CAAC;AAChC,UAAM,QAAS,SAAS,QAAS;AACjC,UAAM,YAAa,SAAS,QAAS;AAErC,YAAQ,KAAK,EAAE,OAAO,WAAW,OAAO,EAAE,CAAC;AAC3C,sBAAkB;AAAA,EACpB;AAEA,MAAI,WAAW,SAAS;AAIxB,UAAQ,KAAK,CAAC,GAAG,MAAM;AACrB,QAAI,EAAE,YAAY,EAAE,UAAW,QAAO;AACtC,QAAI,EAAE,YAAY,EAAE,UAAW,QAAO;AACtC,WAAO;AAAA,EACT,CAAC;AAED,WAAS,IAAI,GAAG,IAAI,OAAO,QAAQ,GAAG,KAAK;AACzC,YAAQ,CAAC,EAAE,SAAS;AAAA,EACtB;AAGA,UAAQ,KAAK,CAAC,GAAG,MAAM,EAAE,QAAQ,EAAE,KAAK;AAExC,SAAO,QAAQ,IAAI,CAAC,MAAM,EAAE,KAAK;AACnC;;;ACsCO,SAAS,aAAa,QAAgB,UAA4B;AAEvE,MAAI,OAAO,KAAK,MAAM,GAAG;AACvB,UAAM,IAAI,MAAM,mCAAmC;AAAA,EACrD;AAGA,MAAI,WAAW,KAAK,MAAM,GAAG;AAC3B,UAAM,IAAI,MAAM,8BAA8B;AAAA,EAChD;AAGA,MAAI,CAAC,QAAQ,KAAK,MAAM,GAAG;AACzB,UAAM,IAAI,MAAM,gBAAgB;AAAA,EAClC;AAEA,QAAM,QAAQ,OAAO,MAAM,GAAG;AAC9B,MAAI,MAAM,SAAS,GAAG;AACpB,UAAM,IAAI,MAAM,yCAAyC;AAAA,EAC3D;AAEA,QAAM,cAAc,MAAM,CAAC;AAC3B,QAAM,iBAAiB,MAAM,CAAC,KAAK;AAEnC,MAAI,eAAe,SAAS,SAAS,UAAU;AAC7C,UAAM,IAAI;AAAA,MACR,aAAa,eAAe,MAAM,8BAA8B,SAAS,QAAQ;AAAA,IACnF;AAAA,EACF;AAGA,QAAM,mBAAmB,eAAe,OAAO,SAAS,UAAU,GAAG;AAErE,QAAM,WAAW,cAAc;AAE/B,SAAO,OAAO,QAAQ;AACxB;;;AClGO,SAAS,OAAO,OAAc,SAAiC;AACpE,QAAM,SAAS,SAAS,UAAU,MAAM,SAAS,UAAU;AAC3D,QAAM,aAAa,SAAS,UAAU;AACtC,QAAM,UAAU,SAAS,WAAW;AACpC,QAAM,gBAAgB,SAAS,cAAc;AAE7C,QAAM,WAAW,MAAM,SAAS;AAChC,QAAM,QAAQ,MAAM;AACpB,QAAM,aAAa,QAAQ;AAC3B,QAAM,WAAW,aAAa,CAAC,QAAQ;AAEvC,QAAM,UAAU,OAAO,OAAO,QAAQ;AACtC,QAAM,cAAc,WAAW;AAC/B,QAAM,iBAAiB,WAAW;AAGlC,QAAM,gBAAgB,eAAe,SAAS,EAAE,SAAS,UAAU,GAAG;AAItE,QAAM,QAAQ,IAAI,KAAK,aAAa,QAAQ;AAAA,IAC1C,OAAO;AAAA,IACP,uBAAuB;AAAA,EACzB,CAAC,EAAE,cAAc,GAAG;AAEpB,QAAM,mBACJ,MAAM,KAAK,CAAC,MAAM,EAAE,SAAS,SAAS,GAAG,SAAS;AAGpD,QAAM,mBAAmB,IAAI,KAAK,aAAa,QAAQ;AAAA,IACrD,OAAO;AAAA,IACP,aAAa;AAAA,EACf,CAAC,EAAE,OAAO,WAAW;AAErB,QAAM,YACJ,WAAW,IACP,GAAG,gBAAgB,GAAG,gBAAgB,GAAG,aAAa,KACtD;AAEN,MAAI,CAAC,YAAY;AACf,QAAI,YAAY;AACd,aAAO,gBAAgB,IAAI,SAAS,MAAM,IAAI,SAAS;AAAA,IACzD;AACA,WAAO;AAAA,EACT;AAGA,MAAI;AACJ,MAAI;AACF,oBAAgB,IAAI,KAAK,aAAa,QAAQ;AAAA,MAC5C,OAAO;AAAA,MACP,UAAU,MAAM,SAAS;AAAA,MACzB,iBAAiB;AAAA,IACnB,CAAC,EAAE,cAAc,aAAa,UAAU,MAAM;AAAA,EAChD,SAAS,GAAG;AAEV,UAAM,SACJ,YAAY,WAAW,MAAM,SAAS,SAAS,MAAM,SAAS;AAChE,QAAI,YAAY;AACd,aAAO,gBACH,IAAI,MAAM,GAAG,SAAS,MACtB,IAAI,MAAM,GAAG,SAAS;AAAA,IAC5B;AACA,WAAO,GAAG,MAAM,GAAG,SAAS;AAAA,EAC9B;AAEA,MAAI,SAAS;AACb,MAAI,iBAAiB;AAErB,aAAW,QAAQ,eAAe;AAChC,YAAQ,KAAK,MAAM;AAAA,MACjB,KAAK,aAAa;AAEhB,YAAI,CAAC,eAAe;AAClB,oBAAU,KAAK;AAAA,QACjB;AACA;AAAA,MACF;AAAA,MAEA,KAAK,WAAW;AACd,YAAI,CAAC,gBAAgB;AACnB,oBAAU;AACV,2BAAiB;AAAA,QACnB;AACA;AAAA,MACF;AAAA;AAAA,MAGA,KAAK;AAAA,MACL,KAAK;AAAA,MACL,KAAK,YAAY;AACf;AAAA,MACF;AAAA,MAEA,KAAK,YAAY;AACf,YAAI,YAAY,YAAY,MAAM,SAAS,QAAQ;AACjD,oBAAU,MAAM,SAAS;AAAA,QAC3B,OAAO;AACL,oBAAU,KAAK;AAAA,QACjB;AACA;AAAA,MACF;AAAA,MAEA,SAAS;AACP,kBAAU,KAAK;AACf;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAGA,MAAI,iBAAiB,YAAY;AAC/B,WAAO,IAAI,OAAO,KAAK,CAAC;AAAA,EAC1B;AAEA,SAAO;AACT;;;AClJO,IAAM,QAAN,MAAM,OAAM;AAAA,EAWT,YAAY,OAAe,UAAoB;AACrD,SAAK,QAAQ;AACb,SAAK,WAAW;AAAA,EAClB;AAAA,EAEA,OAAe,gBAAgB,UAAuC;AACpE,QAAI,OAAO,aAAa,UAAU;AAChC,aAAO,YAAY,QAAQ;AAAA,IAC7B;AACA,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAYA,OAAO,UAAU,OAAwB,UAAoC;AAC3E,WAAO,IAAI,OAAM,OAAO,KAAK,GAAG,OAAM,gBAAgB,QAAQ,CAAC;AAAA,EACjE;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAWA,OAAO,UAAU,OAAwB,UAAoC;AAC3E,WAAO,OAAM,UAAU,OAAO,QAAQ;AAAA,EACxC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAYA,OAAO,UAAU,QAAgB,UAAoC;AACnE,UAAM,mBAAmB,OAAM,gBAAgB,QAAQ;AACvD,UAAM,QAAQ,aAAa,QAAQ,gBAAgB;AACnD,WAAO,IAAI,OAAM,OAAO,gBAAgB;AAAA,EAC1C;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAYA,OAAO,YAAY,QAAgB,UAAoC;AACrE,WAAO,OAAM,UAAU,QAAQ,QAAQ;AAAA,EACzC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAaA,OAAO,UACL,QACA,UACA,SAIO;AACP,QAAI,CAAC,SAAS,mBAAmB,QAAQ,IAAI,aAAa,cAAc;AACtE,cAAQ;AAAA,QACN,qFAEE,SACA;AAAA,MACJ;AAAA,IACF;AACA,UAAM,mBAAmB,OAAM,gBAAgB,QAAQ;AACvD,UAAM,SAAS,MAAM,iBAAiB;AACtC,UAAM,aAAa,KAAK,MAAM,SAAS,MAAM;AAC7C,WAAO,IAAI,OAAM,OAAO,UAAU,GAAG,gBAAgB;AAAA,EACvD;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,OAAO,OAAO,QAAwB;AACpC,QAAI,OAAO,WAAW;AACpB,YAAM,IAAI,MAAM,mCAAmC;AACrD,WAAO,OAAO,OAAO,CAAC,KAAK,YAAY;AACrC,yBAAmB,KAAK,OAAO;AAC/B,aAAO,QAAQ,SAAS,GAAG,IAAI,UAAU;AAAA,IAC3C,CAAC;AAAA,EACH;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,OAAO,OAAO,QAAwB;AACpC,QAAI,OAAO,WAAW;AACpB,YAAM,IAAI,MAAM,mCAAmC;AACrD,WAAO,OAAO,OAAO,CAAC,KAAK,YAAY;AACrC,yBAAmB,KAAK,OAAO;AAC/B,aAAO,QAAQ,YAAY,GAAG,IAAI,UAAU;AAAA,IAC9C,CAAC;AAAA,EACH;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,OAAO,KAAK,UAAoC;AAC9C,WAAO,IAAI,OAAM,IAAI,OAAM,gBAAgB,QAAQ,CAAC;AAAA,EACtD;AAAA,EAEQ,aAAa,OAAgD;AACnE,QAAI,iBAAiB,QAAO;AAC1B,aAAO;AAAA,IACT;AACA,QAAI,OAAO,UAAU,UAAU;AAC7B,aAAO,OAAM,UAAU,OAAO,KAAK,QAAQ;AAAA,IAC7C;AACA,WAAO,OAAM,UAAU,OAAO,KAAK,QAAQ;AAAA,EAC7C;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASA,IAAI,OAAgD;AAClD,UAAM,aAAa,KAAK,aAAa,KAAK;AAC1C,uBAAmB,MAAM,UAAU;AACnC,WAAO,IAAI,OAAM,IAAI,KAAK,OAAO,WAAW,KAAK,GAAG,KAAK,QAAQ;AAAA,EACnE;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASA,SAAS,OAAgD;AACvD,UAAM,aAAa,KAAK,aAAa,KAAK;AAC1C,uBAAmB,MAAM,UAAU;AACnC,WAAO,IAAI,OAAM,SAAS,KAAK,OAAO,WAAW,KAAK,GAAG,KAAK,QAAQ;AAAA,EACxE;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAUA,SACE,YACA,SACO;AACP,UAAM,SAAS,SAAS,KAAK,OAAO,YAAY,SAAS,QAAQ;AACjE,WAAO,IAAI,OAAM,QAAQ,KAAK,QAAQ;AAAA,EACxC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAWA,OACE,SACA,SACO;AACP,QAAI,YAAY,KAAK,YAAY,KAAK;AACpC,YAAM,IAAI,MAAM,kBAAkB;AAAA,IACpC;AACA,UAAM,SAAS,OAAO,KAAK,OAAO,SAAS,SAAS,QAAQ;AAC5D,WAAO,IAAI,OAAM,QAAQ,KAAK,QAAQ;AAAA,EACxC;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,MAAa;AACX,WAAO,IAAI,OAAM,KAAK,QAAQ,KAAK,CAAC,KAAK,QAAQ,KAAK,OAAO,KAAK,QAAQ;AAAA,EAC5E;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,SAAgB;AACd,WAAO,IAAI,OAAM,CAAC,KAAK,OAAO,KAAK,QAAQ;AAAA,EAC7C;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAWA,SAAS,QAA2B;AAClC,UAAM,SAAS,SAAS,KAAK,OAAO,MAAM;AAC1C,WAAO,OAAO,IAAI,CAAC,UAAU,IAAI,OAAM,OAAO,KAAK,QAAQ,CAAC;AAAA,EAC9D;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,OAAO,SAII;AACT,WAAO,OAAO,MAAM,OAAO;AAAA,EAC7B;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,OAAO,OAAkD;AACvD,UAAM,aAAa,KAAK,aAAa,KAAK;AAC1C,WACE,KAAK,SAAS,SAAS,WAAW,SAAS,QAC3C,KAAK,UAAU,WAAW;AAAA,EAE9B;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASA,YAAY,OAAkD;AAC5D,UAAM,aAAa,KAAK,aAAa,KAAK;AAC1C,uBAAmB,MAAM,UAAU;AACnC,WAAO,KAAK,QAAQ,WAAW;AAAA,EACjC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASA,SAAS,OAAkD;AACzD,UAAM,aAAa,KAAK,aAAa,KAAK;AAC1C,uBAAmB,MAAM,UAAU;AACnC,WAAO,KAAK,QAAQ,WAAW;AAAA,EACjC;AAAA;AAAA;AAAA;AAAA,EAKA,mBAAmB,OAAkD;AACnE,UAAM,aAAa,KAAK,aAAa,KAAK;AAC1C,uBAAmB,MAAM,UAAU;AACnC,WAAO,KAAK,SAAS,WAAW;AAAA,EAClC;AAAA;AAAA;AAAA;AAAA,EAKA,gBAAgB,OAAkD;AAChE,UAAM,aAAa,KAAK,aAAa,KAAK;AAC1C,uBAAmB,MAAM,UAAU;AACnC,WAAO,KAAK,SAAS,WAAW;AAAA,EAClC;AAAA;AAAA;AAAA;AAAA,EAKA,aAAsB;AACpB,WAAO,KAAK,QAAQ;AAAA,EACtB;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,QAAQ,OAAqD;AAC3D,UAAM,aAAa,KAAK,aAAa,KAAK;AAC1C,uBAAmB,MAAM,UAAU;AACnC,QAAI,KAAK,QAAQ,WAAW,MAAO,QAAO;AAC1C,QAAI,KAAK,QAAQ,WAAW,MAAO,QAAO;AAC1C,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,WACE,SACA,wCACO;AACP,WAAO,KAAK,SAAS,UAAU,KAAK,EAAE,SAAS,CAAC;AAAA,EAClD;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,WACE,SACA,wCACO;AACP,WAAO,KAAK,IAAI,KAAK,WAAW,SAAS,QAAQ,CAAC;AAAA,EACpD;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,gBACE,SACA,wCACO;AACP,WAAO,KAAK,SAAS,KAAK,WAAW,SAAS,QAAQ,CAAC;AAAA,EACzD;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,MAAM,OAAwB;AAC5B,UAAM,SAAS,MAAM,KAAK,EAAE,KAAK,CAAC;AAClC,WAAO,KAAK,SAAS,MAAM;AAAA,EAC7B;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,SAAkB;AAChB,WAAO,KAAK,UAAU;AAAA,EACxB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,aAAsB;AACpB,WAAO,KAAK,QAAQ;AAAA,EACtB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAeA,MAAM,KAAY,KAAmB;AACnC,uBAAmB,MAAM,GAAG;AAC5B,uBAAmB,MAAM,GAAG;AAE5B,QAAI,IAAI,YAAY,GAAG,GAAG;AACxB,YAAM,IAAI,MAAM,sCAAsC;AAAA,IACxD;AAEA,QAAI,KAAK,SAAS,GAAG,GAAG;AACtB,aAAO,IAAI,OAAM,IAAI,OAAO,KAAK,QAAQ;AAAA,IAC3C;AACA,QAAI,KAAK,YAAY,GAAG,GAAG;AACzB,aAAO,IAAI,OAAM,IAAI,OAAO,KAAK,QAAQ;AAAA,IAC3C;AACA,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAaA,kBAA0B;AACxB,UAAM,WAAW,KAAK,SAAS;AAC/B,UAAM,aAAa,KAAK,QAAQ;AAChC,UAAM,WAAW,aAAa,CAAC,KAAK,QAAQ,KAAK;AAEjD,QAAI,aAAa,GAAG;AAClB,aAAO,aAAa,IAAI,SAAS,SAAS,CAAC,KAAK,SAAS,SAAS;AAAA,IACpE;AAEA,UAAM,UAAU,OAAO,OAAO,QAAQ;AACtC,UAAM,cAAc,WAAW;AAC/B,UAAM,iBAAiB,WAAW;AAElC,UAAM,gBAAgB,eAAe,SAAS,EAAE,SAAS,UAAU,GAAG;AACtE,UAAM,SAAS,GAAG,WAAW,IAAI,aAAa;AAE9C,WAAO,aAAa,IAAI,MAAM,KAAK;AAAA,EACrC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,SAAkE;AAChE,WAAO;AAAA,MACL,QAAQ,KAAK,MAAM,SAAS;AAAA,MAC5B,UAAU,KAAK,SAAS;AAAA,MACxB,WAAW,KAAK,SAAS;AAAA,IAC3B;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAeA,OAAO,QAAQ,KAAa,OAAyB;AACnD,QACE,UAAU,QACV,OAAO,UAAU,YACjB,YAAY,SACZ,cAAc,SACd,eAAe,SACf,OAAQ,MAAkC,WAAW,YACrD,OAAQ,MAAkC,aAAa,YACvD,OAAQ,MAAkC,cAAc,UACxD;AACA,YAAM,MAAM;AAKZ,aAAO,OAAM,UAAU,OAAO,IAAI,MAAM,GAAG,IAAI,QAAQ;AAAA,IACzD;AACA,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA,EAKA,WAAmB;AACjB,WAAO,KAAK,OAAO;AAAA,EACrB;AACF;;;AC7fO,SAAS,KAAK,SAA2C;AAC9D,QAAM;AAAA,IACJ;AAAA,IACA;AAAA,IACA;AAAA,IACA,iBAAiB;AAAA,IACjB;AAAA,EACF,IAAI;AAEJ,QAAM,eAAe,aAAa;AAClC,MAAI;AAEJ,MAAI,eAAe,GAAG;AACpB,cAAU,UAAU,OAAO,SAAS,EAAE,SAAS,CAAC;AAAA,EAClD,OAAO;AAEL,UAAM,IAAI;AACV,UAAM,IAAI;AACV,UAAM,YAAY,IAAI,KAAK,IAAI,IAAI,GAAG,CAAC;AACvC,UAAM,cAAc,KAAK,IAAI,IAAI,GAAG,CAAC,IAAI;AACzC,UAAM,gBAAgB,YAAY;AAClC,cAAU,UAAU,SAAS,eAAe,EAAE,SAAS,CAAC;AAAA,EAC1D;AAEA,QAAM,WAAgC,CAAC;AACvC,MAAI,UAAU;AAEd,WAAS,SAAS,GAAG,UAAU,SAAS,UAAU;AAChD,UAAM,WACJ,eAAe,IACX,MAAM,KAAK,UAAU,QAAQ,IAC7B,QAAQ,SAAS,cAAc,EAAE,SAAS,CAAC;AAEjD,QAAI,mBAAmB,QAAQ,SAAS,QAAQ;AAKhD,cAAU,QAAQ,SAAS,gBAAgB;AAG3C,QAAI,WAAW,WAAW,CAAC,QAAQ,OAAO,GAAG;AAC3C,YAAM,oBAAoB,iBAAiB,IAAI,OAAO;AACtD,eAAS,KAAK;AAAA,QACZ;AAAA,QACA,SAAS,SAAS,IAAI,iBAAiB;AAAA,QACvC,WAAW;AAAA,QACX;AAAA,QACA,SAAS,MAAM,KAAK,UAAU,QAAQ;AAAA,MACxC,CAAC;AAAA,IACH,OAAO;AACL,eAAS,KAAK;AAAA,QACZ;AAAA,QACA;AAAA,QACA,WAAW;AAAA,QACX;AAAA,QACA,SAAS,QAAQ,WAAW,IACxB,MAAM,KAAK,UAAU,QAAQ,IAC7B;AAAA,MACN,CAAC;AAAA,IACH;AAAA,EACF;AAEA,SAAO;AACT;AAKO,SAAS,IACd,SACO;AACP,QAAM,WAAW,KAAK,OAAO;AAC7B,SAAO,SAAS,CAAC,EAAE;AACrB;AAKO,SAAS,cAAc,SAA6B;AACzD,QAAM;AAAA,IACJ;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF,IAAI;AAEJ,MAAI,eAAe,GAAG;AACpB,WAAO,MAAM,KAAK,UAAU,QAAQ;AAAA,EACtC;AAEA,QAAM,UAAU,IAAI,OAAO;AAC3B,QAAM,YAAY,QAAQ,SAAS,SAAS,EAAE,SAAS,CAAC;AACxD,SAAO,UAAU,SAAS,SAAS;AACrC;AAKO,SAAS,0BACd,UACO;AACP,MAAI,SAAS,WAAW,GAAG;AACzB,UAAM,IAAI,MAAM,uCAAuC;AAAA,EACzD;AAEA,QAAM,WAAW,SAAS,CAAC,EAAE,SAAS;AACtC,SAAO,SAAS;AAAA,IACd,CAAC,KAAK,UAAU,IAAI,IAAI,MAAM,QAAQ;AAAA,IACtC,MAAM,KAAK,QAAQ;AAAA,EACrB;AACF;AA4BO,SAAS,oBAAoB,SAAqC;AACvE,QAAM;AAAA,IACJ;AAAA,IACA;AAAA,IACA,iBAAiB;AAAA,IACjB;AAAA,EACF,IAAI;AAGJ,MAAI,eAAe,GAAG;AACpB,WAAO,MAAM,KAAK,UAAU,QAAQ;AAAA,EACtC;AAEA,QAAM,eAAe,aAAa;AAClC,SAAO,UAAU,SAAS,cAAc,EAAE,SAAS,CAAC;AACtD;;;ACzKO,SAAS,YACdA,eACA,SACO;AACP,QAAM;AAAA,IACJ;AAAA,IACA;AAAA,IACA,qBAAqB;AAAA,IACrB;AAAA,EACF,IAAI;AAEJ,QAAM,IAAI;AACV,QAAM,IAAI;AACV,QAAM,aAAa,KAAK,IAAI,IAAI,OAAO,GAAG,IAAI,CAAC;AAE/C,SAAOA,cAAa,SAAS,YAAY,EAAE,SAAS,CAAC;AACvD;AAMO,SAAS,aACd,WACA,SACO;AACP,QAAM;AAAA,IACJ;AAAA,IACA;AAAA,IACA,qBAAqB;AAAA,IACrB;AAAA,EACF,IAAI;AAEJ,QAAM,IAAI;AACV,QAAM,IAAI;AACV,QAAM,UAAU,KAAK,IAAI,IAAI,OAAO,GAAG,IAAI,CAAC;AAE5C,SAAO,UAAU,OAAO,SAAS,EAAE,SAAS,CAAC;AAC/C;AAGO,IAAM,WAAW;AACjB,IAAM,WAAW;;;AC1CjB,SAAS,IAAI,cAAqB,YAA2B;AAClE,MAAI,aAAa,SAAS,SAAS,WAAW,SAAS,MAAM;AAC3D,UAAM,IAAI;AAAA,MACR,aAAa,SAAS;AAAA,MACtB,WAAW,SAAS;AAAA,IACtB;AAAA,EACF;AAEA,QAAM,OAAO,WAAW,SAAS,YAAY;AAC7C,SAAO,OAAO,KAAK,KAAK,IAAI,OAAO,aAAa,KAAK;AACvD;AAKO,SAAS,IACd,cACA,WACO;AACP,MAAI,UAAU,WAAW,GAAG;AAC1B,UAAM,IAAI,MAAM,iCAAiC;AAAA,EACnD;AAEA,QAAM,WAAW,UAAU,CAAC,EAAE;AAE9B,MAAI,QAAQ,MAAM,KAAK,QAAQ;AAE/B,WAAS,IAAI,GAAG,IAAI,UAAU,QAAQ,KAAK;AACzC,UAAM,iBAAiB,KAAK,IAAI,IAAI,cAAc,CAAC;AACnD,UAAM,aAAa,UAAU,CAAC,EAAE,OAAO,gBAAgB;AAAA,MACrD;AAAA,IACF,CAAC;AACD,YAAQ,MAAM,IAAI,UAAU;AAAA,EAC9B;AAEA,SAAO;AACT;AAMO,SAAS,IAAI,WAAoB,QAAgB,KAAa;AACnE,QAAM,SAAS,UAAU,IAAI,CAAC,OAAO,OAAO,GAAG,KAAK,CAAC;AAErD,QAAM,gBAAgB;AACtB,QAAM,YAAY;AAClB,MAAI,OAAO;AAEX,WAAS,IAAI,GAAG,IAAI,eAAe,KAAK;AACtC,QAAI,WAAW;AACf,QAAI,aAAa;AAEjB,aAAS,IAAI,GAAG,IAAI,OAAO,QAAQ,KAAK;AACtC,YAAM,cAAc,KAAK,IAAI,IAAI,MAAM,CAAC;AACxC,kBAAY,OAAO,CAAC,IAAI;AAExB,UAAI,IAAI,GAAG;AACT,sBAAe,IAAI,OAAO,CAAC,IAAK,KAAK,IAAI,IAAI,MAAM,IAAI,CAAC;AAAA,MAC1D;AAAA,IACF;AAEA,UAAM,UAAU,OAAO,WAAW;AAElC,QAAI,KAAK,IAAI,UAAU,IAAI,IAAI,WAAW;AACxC,aAAO;AAAA,IACT;AAEA,WAAO;AAAA,EACT;AAEA,QAAM,IAAI,MAAM,kCAAkC;AACpD;AAYO,SAAS,aAAa,cAAqB,cAA6B;AAC7E,MAAI,aAAa,SAAS,SAAS,aAAa,SAAS,MAAM;AAC7D,UAAM,IAAI;AAAA,MACR,aAAa,SAAS;AAAA,MACtB,aAAa,SAAS;AAAA,IACxB;AAAA,EACF;AAEA,MAAI,aAAa,SAAS,IAAI;AAC5B,UAAM,IAAI,qBAAqB,gCAAgC;AAAA,EACjE;AAEA,SAAO,OAAO,aAAa,KAAK,IAAI,OAAO,aAAa,KAAK;AAC/D;;;AChGO,IAAM,QAAN,MAAM,MAAK;AAAA,EAYR,YAAY,cAAsB;AACxC,SAAK,eAAe;AAAA,EACtB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAUA,OAAO,QAAQ,SAAgC;AAC7C,UAAM,UAAU,OAAO,YAAY,WAAW,WAAW,OAAO,IAAI;AACpE,UAAM,SAAS,OAAO,KAAK,MAAO,UAAU,MAAO,OAAO,MAAK,KAAK,CAAC,CAAC;AACtE,WAAO,IAAI,MAAK,MAAM;AAAA,EACxB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAUA,OAAO,QAAQ,SAAgC;AAC7C,UAAM,QAAQ,OAAO,YAAY,WAAW,WAAW,OAAO,IAAI;AAClE,UAAM,SAAS,OAAO,KAAK,MAAM,QAAQ,OAAO,MAAK,KAAK,CAAC,CAAC;AAC5D,WAAO,IAAI,MAAK,MAAM;AAAA,EACxB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,OAAO,OAAa;AAClB,WAAO,IAAI,MAAK,EAAE;AAAA,EACpB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,YAAoB;AAClB,WAAQ,OAAO,KAAK,YAAY,IAAI,OAAO,MAAK,KAAK,IAAK;AAAA,EAC5D;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,YAAoB;AAClB,WAAO,OAAO,KAAK,YAAY,IAAI,OAAO,MAAK,KAAK;AAAA,EACtD;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,IAAI,OAAmB;AACrB,WAAO,IAAI,MAAK,KAAK,eAAe,MAAM,YAAY;AAAA,EACxD;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,SAAS,OAAmB;AAC1B,WAAO,IAAI,MAAK,KAAK,eAAe,MAAM,YAAY;AAAA,EACxD;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,SAAS,YAA0B;AACjC,UAAM,SAAS,OAAO,KAAK,MAAM,aAAa,OAAO,MAAK,KAAK,CAAC,CAAC;AACjE,WAAO,IAAI,MAAM,KAAK,eAAe,SAAU,MAAK,KAAK;AAAA,EAC3D;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,OAAO,SAAuB;AAC5B,UAAM,SAAS,OAAO,KAAK,MAAM,UAAU,OAAO,MAAK,KAAK,CAAC,CAAC;AAC9D,WAAO,IAAI,MAAM,KAAK,eAAe,MAAK,QAAS,MAAM;AAAA,EAC3D;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,OAAO,OAAsB;AAC3B,WAAO,KAAK,iBAAiB,MAAM;AAAA,EACrC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,YAAY,OAAsB;AAChC,WAAO,KAAK,eAAe,MAAM;AAAA,EACnC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,SAAS,OAAsB;AAC7B,WAAO,KAAK,eAAe,MAAM;AAAA,EACnC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,SAAkB;AAChB,WAAO,KAAK,iBAAiB;AAAA,EAC/B;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,aAAsB;AACpB,WAAO,KAAK,eAAe;AAAA,EAC7B;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,WAAmB;AACjB,WAAO,GAAG,KAAK,UAAU,CAAC;AAAA,EAC5B;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAUA,eAAe,SAAyB;AACtC,WAAO,KAAK,IAAI,IAAI,KAAK,UAAU,GAAG,OAAO;AAAA,EAC/C;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAUA,SAAS,gBAA8B;AACrC,WAAO,KAAK,OAAO,cAAc;AAAA,EACnC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,UAAU,gBAA8B;AACtC,UAAM,mBAAmB,KAAK,UAAU;AACxC,UAAM,iBACJ,kBAAkB,KAAK,IAAI,IAAI,kBAAkB,IAAI,cAAc,IAAI;AACzE,WAAO,MAAK,QAAQ,cAAc;AAAA,EACpC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,YAAY,gBAA8B;AACxC,UAAM,iBAAiB,KAAK,UAAU;AACtC,UAAM,mBACJ,KAAK,IAAI,IAAI,iBAAiB,gBAAgB,cAAc,IAAI;AAClE,WAAO,MAAK,QAAQ,gBAAgB;AAAA,EACtC;AAAA;AAAA;AAAA;AAAA,EAKA,SAA+C;AAC7C,WAAO;AAAA,MACL,SAAS,KAAK,UAAU;AAAA,MACxB,SAAS,KAAK,UAAU;AAAA,IAC1B;AAAA,EACF;AACF;AAAA;AAAA;AAAA;AArOa,MAUa,QAAQ,OAAO;AAVlC,IAAM,OAAN;;;ACqBA,SAAS,eACd,WACA,SACO;AACP,QAAM,EAAE,MAAM,OAAO,uCAAkC,IAAI;AAG3D,MAAI,KAAK,OAAO,KAAK,UAAU,GAAG;AAChC,WAAO,MAAM,KAAK,UAAU,QAAQ;AAAA,EACtC;AAGA,QAAM,qBAAqB,KAAK,UAAU,IAAI;AAE9C,SAAO,UAAU,SAAS,oBAAoB,EAAE,SAAS,CAAC;AAC5D;AA0BO,SAAS,oBACd,WACA,SACO;AACP,QAAM,EAAE,MAAM,OAAO,uCAAkC,IAAI;AAG3D,MAAI,KAAK,OAAO,KAAK,UAAU,GAAG;AAChC,WAAO;AAAA,EACT;AAGA,QAAM,kBAAkB,IAAI,KAAK,UAAU,IAAI;AAE/C,SAAO,UAAU,SAAS,iBAAiB,EAAE,SAAS,CAAC;AACzD;;;AC3DO,SAAS,aAAa,WAAkB,aAA4B;AACzE,qBAAmB,WAAW,WAAW;AACzC,MAAI,YAAY,OAAO,GAAG;AACxB,UAAM,IAAI,MAAM,6BAA6B;AAAA,EAC/C;AACA,SAAO,OAAO,UAAU,KAAK,IAAI,OAAO,YAAY,KAAK;AAC3D;AAWO,SAAS,aAAa,WAAkB,aAA4B;AACzE,qBAAmB,WAAW,WAAW;AACzC,MAAI,YAAY,OAAO,GAAG;AACxB,UAAM,IAAI,MAAM,6BAA6B;AAAA,EAC/C;AACA,SAAO,OAAO,UAAU,KAAK,IAAI,OAAO,YAAY,KAAK;AAC3D;AAUO,SAAS,iBAAiB,MAAa,iBAAgC;AAC5E,qBAAmB,MAAM,eAAe;AACxC,MAAI,gBAAgB,OAAO,GAAG;AAC5B,WAAO;AAAA,EACT;AACA,SAAO,OAAO,KAAK,KAAK,IAAI,OAAO,gBAAgB,KAAK;AAC1D;AAWO,SAAS,iBACd,aACA,aACQ;AACR,qBAAmB,aAAa,WAAW;AAC3C,MAAI,YAAY,OAAO,GAAG;AACxB,UAAM,IAAI,MAAM,6BAA6B;AAAA,EAC/C;AACA,SAAO,OAAO,YAAY,KAAK,IAAI,OAAO,YAAY,KAAK;AAC7D;AAQO,SAAS,eAAe,QAAwC;AACrE,SAAO;AAAA,IACL,cAAc,aAAa,OAAO,WAAW,OAAO,WAAW;AAAA,IAC/D,cAAc,aAAa,OAAO,WAAW,OAAO,WAAW;AAAA,IAC/D,kBAAkB,iBAAiB,OAAO,MAAM,OAAO,eAAe;AAAA,IACtE,kBAAkB,iBAAiB,OAAO,aAAa,OAAO,WAAW;AAAA,EAC3E;AACF;;;AC7EO,SAAS,yBACd,SACoB;AACpB,QAAM;AAAA,IACJ;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF,IAAI;AAEJ,MAAI,KAAK,SAAS,SAAS,aAAa,SAAS,MAAM;AACrD,UAAM,IAAI;AAAA,MACR,KAAK,SAAS;AAAA,MACd,aAAa,SAAS;AAAA,IACxB;AAAA,EACF;AAEA,MAAI,cAAc,GAAG;AACnB,UAAM,IAAI,qBAAqB,8BAA8B;AAAA,EAC/D;AAEA,MAAI,aAAa,YAAY,IAAI,GAAG;AAClC,UAAM,IAAI,qBAAqB,2CAA2C;AAAA,EAC5E;AAEA,QAAM,oBAAoB,KAAK,SAAS,YAAY;AACpD,QAAM,qBAAqB,kBAAkB,OAAO,YAAY,EAAE,SAAS,CAAC;AAE5E,QAAM,SAA6B;AAAA,IACjC;AAAA,IAEA,gBAAgB,MAAqB;AACnC,UAAI,OAAO,GAAG;AACZ,cAAM,IAAI,qBAAqB,2BAA2B;AAAA,MAC5D;AACA,UAAI,SAAS,EAAG,QAAO;AAEvB,YAAM,oBAAoB,mBAAmB,SAAS,IAAI;AAC1D,YAAM,YAAY,KAAK,SAAS,iBAAiB;AAGjD,UAAI,UAAU,SAAS,YAAY,GAAG;AACpC,eAAO;AAAA,MACT;AACA,aAAO;AAAA,IACT;AAAA,IAEA,WAAsE;AACpE,YAAM,WAAW,CAAC;AAClB,UAAI,oBAAoB;AACxB,YAAM,WAAW,KAAK,KAAK,UAAU;AAErC,eAAS,OAAO,GAAG,QAAQ,UAAU,QAAQ;AAC3C,cAAM,mBAAmB,OAAO,gBAAgB,IAAI;AACpD,cAAM,eAAe,kBAAkB,SAAS,gBAAgB;AAEhE,iBAAS,KAAK;AAAA,UACZ;AAAA,UACA;AAAA,UACA,WAAW;AAAA,QACb,CAAC;AAED,4BAAoB;AAAA,MACtB;AAEA,aAAO;AAAA,IACT;AAAA,EACF;AAEA,SAAO;AACT;","names":["presentValue"]}