{"version":3,"file":"portfolio-snapshot.mjs","names":[],"sources":["../../../src/services/portfolio-snapshot.ts"],"sourcesContent":["/**\n * Portfolio Snapshot Service — multi-chain balance aggregation and analysis.\n *\n * Provides:\n * - Cross-chain portfolio value (Ethereum, Base, Arbitrum, Optimism, Polygon)\n * - Token-by-token breakdown with allocation percentages\n * - Native + ERC-20 balances with USD values\n * - Historical comparison (P&L since last snapshot)\n * - Risk metrics (concentration, stablecoin ratio)\n */\n\nimport { getRpcManager } from './rpc-provider.js';\nimport { getPriceOracle } from './price-oracle.js';\n\n// ── Types ───────────────────────────────────────────────────────────────────\n\nexport interface TokenBalance {\n  symbol: string;\n  address: string;   // '0x0' for native token\n  chain: string;\n  chainId: number;\n  balance: string;    // raw units\n  balanceHuman: number;\n  decimals: number;\n  priceUsd: number;\n  valueUsd: number;\n  allocationPercent: number;  // % of total portfolio\n}\n\nexport interface ChainSummary {\n  chain: string;\n  chainId: number;\n  valueUsd: number;\n  allocationPercent: number;\n  tokenCount: number;\n}\n\nexport interface PortfolioSnapshot {\n  owner: string;\n  totalValueUsd: number;\n  chains: ChainSummary[];\n  tokens: TokenBalance[];\n  stablecoinRatio: number;   // 0-1 (% of portfolio in stablecoins)\n  topConcentration: number;  // 0-1 (% of portfolio in the single largest position)\n  riskLevel: 'conservative' | 'moderate' | 'aggressive';\n  timestamp: number;\n}\n\nexport interface PortfolioChange {\n  current: PortfolioSnapshot;\n  previous: PortfolioSnapshot | null;\n  changeUsd: number;\n  changePercent: number;\n  newPositions: string[];\n  closedPositions: string[];\n}\n\nexport interface PortfolioConfig {\n  /** Chains to scan. Default: all supported. */\n  chainIds?: number[];\n  /** Minimum balance in USD to include a token. Default: 0.01 */\n  minValueUsd?: number;\n  /** Cache TTL for snapshots in ms. Default: 60000 (1 minute). */\n  cacheTtlMs?: number;\n}\n\n// ── ERC-20 ABI (minimal) ────────────────────────────────────────────────────\n\nconst ERC20_ABI = [\n  {\n    inputs: [{ name: 'account', type: 'address' }],\n    name: 'balanceOf',\n    outputs: [{ name: '', type: 'uint256' }],\n    stateMutability: 'view',\n    type: 'function',\n  },\n  {\n    inputs: [],\n    name: 'decimals',\n    outputs: [{ name: '', type: 'uint8' }],\n    stateMutability: 'view',\n    type: 'function',\n  },\n] as const;\n\n// ── Well-Known Tokens Per Chain ─────────────────────────────────────────────\n\nconst TOKENS: Record<number, Array<{ symbol: string; address: string; decimals: number; isStablecoin: boolean }>> = {\n  8453: [\n    { symbol: 'USDC', address: '0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913', decimals: 6, isStablecoin: true },\n    { symbol: 'WETH', address: '0x4200000000000000000000000000000000000006', decimals: 18, isStablecoin: false },\n    { symbol: 'DAI', address: '0x50c5725949A6F0c72E6C4a641F24049A917DB0Cb', decimals: 18, isStablecoin: true },\n    { symbol: 'USDT', address: '0xfde4C96c8593536E31F229EA8f37b2ADa2699bb2', decimals: 6, isStablecoin: true },\n    { symbol: 'cbETH', address: '0x2Ae3F1Ec7F1F5012CFEab0185bfc7aa3cf0DEc22', decimals: 18, isStablecoin: false },\n  ],\n  1: [\n    { symbol: 'USDC', address: '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48', decimals: 6, isStablecoin: true },\n    { symbol: 'WETH', address: '0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2', decimals: 18, isStablecoin: false },\n    { symbol: 'USDT', address: '0xdAC17F958D2ee523a2206206994597C13D831ec7', decimals: 6, isStablecoin: true },\n    { symbol: 'DAI', address: '0x6B175474E89094C44Da98b954EedeAC495271d0F', decimals: 18, isStablecoin: true },\n    { symbol: 'WBTC', address: '0x2260FAC5E5542a773Aa44fBCfeDf7C193bc2C599', decimals: 8, isStablecoin: false },\n    { symbol: 'LINK', address: '0x514910771AF9Ca656af840dff83E8264EcF986CA', decimals: 18, isStablecoin: false },\n    { symbol: 'UNI', address: '0x1f9840a85d5aF5bf1D1762F925BDADdC4201F984', decimals: 18, isStablecoin: false },\n    { symbol: 'AAVE', address: '0x7Fc66500c84A76Ad7e9c93437bFc5Ac33E2DDaE9', decimals: 18, isStablecoin: false },\n  ],\n  42161: [\n    { symbol: 'USDC', address: '0xaf88d065e77c8cC2239327C5EDb3A432268e5831', decimals: 6, isStablecoin: true },\n    { symbol: 'WETH', address: '0x82aF49447D8a07e3bd95BD0d56f35241523fBab1', decimals: 18, isStablecoin: false },\n    { symbol: 'USDT', address: '0xFd086bC7CD5C481DCC9C85ebE478A1C0b69FCbb9', decimals: 6, isStablecoin: true },\n    { symbol: 'ARB', address: '0x912CE59144191C1204E64559FE8253a0e49E6548', decimals: 18, isStablecoin: false },\n    { symbol: 'DAI', address: '0xDA10009cBd5D07dd0CeCc66161FC93D7c9000da1', decimals: 18, isStablecoin: true },\n  ],\n  10: [\n    { symbol: 'USDC', address: '0x0b2C639c533813f4Aa9D7837CAf62653d097Ff85', decimals: 6, isStablecoin: true },\n    { symbol: 'WETH', address: '0x4200000000000000000000000000000000000006', decimals: 18, isStablecoin: false },\n    { symbol: 'USDT', address: '0x94b008aA00579c1307B0EF2c499aD98a8ce58e58', decimals: 6, isStablecoin: true },\n    { symbol: 'OP', address: '0x4200000000000000000000000000000000000042', decimals: 18, isStablecoin: false },\n    { symbol: 'DAI', address: '0xDA10009cBd5D07dd0CeCc66161FC93D7c9000da1', decimals: 18, isStablecoin: true },\n  ],\n  137: [\n    { symbol: 'USDC', address: '0x3c499c542cEF5E3811e1192ce70d8cC03d5c3359', decimals: 6, isStablecoin: true },\n    { symbol: 'WETH', address: '0x7ceB23fD6bC0adD59E62ac25578270cFf1b9f619', decimals: 18, isStablecoin: false },\n    { symbol: 'USDT', address: '0xc2132D05D31c914a87C6611C10748AEb04B58e8F', decimals: 6, isStablecoin: true },\n    { symbol: 'WMATIC', address: '0x0d500B1d8E8eF31E21C99d1Db9A6444d3ADf1270', decimals: 18, isStablecoin: false },\n    { symbol: 'DAI', address: '0x8f3Cf7ad23Cd3CaDbD9735AFf958023239c6A063', decimals: 18, isStablecoin: true },\n  ],\n};\n\nconst CHAIN_NAMES: Record<number, string> = {\n  1: 'ethereum', 8453: 'base', 42161: 'arbitrum', 10: 'optimism', 137: 'polygon',\n};\n\nconst NATIVE_SYMBOL: Record<number, string> = {\n  1: 'ETH', 8453: 'ETH', 42161: 'ETH', 10: 'ETH', 137: 'MATIC',\n};\n\n// ── Service ─────────────────────────────────────────────────────────────────\n\nexport class PortfolioSnapshotService {\n  private config: Required<PortfolioConfig>;\n  private cache: Map<string, { snapshot: PortfolioSnapshot; expiresAt: number }> = new Map();\n  private previousSnapshots: Map<string, PortfolioSnapshot> = new Map();\n  private static readonly MAX_SNAPSHOTS = 100;\n\n  constructor(config: PortfolioConfig = {}) {\n    this.config = {\n      chainIds: config.chainIds ?? [8453, 1, 42161, 10, 137],\n      minValueUsd: config.minValueUsd ?? 0.01,\n      cacheTtlMs: config.cacheTtlMs ?? 60_000,\n    };\n  }\n\n  /**\n   * Take a full portfolio snapshot across all configured chains.\n   */\n  async getSnapshot(ownerAddress: string): Promise<PortfolioSnapshot> {\n    // Check cache\n    const cached = this.cache.get(ownerAddress);\n    if (cached && Date.now() < cached.expiresAt) {\n      return cached.snapshot;\n    }\n\n    const rpcManager = getRpcManager();\n    const oracle = getPriceOracle();\n    const allTokens: TokenBalance[] = [];\n\n    // Scan each chain in parallel\n    const chainResults = await Promise.all(\n      this.config.chainIds.map(async (chainId) => {\n        try {\n          const client = await rpcManager.getClient(chainId);\n          const chain = CHAIN_NAMES[chainId] ?? String(chainId);\n          const nativeSymbol = NATIVE_SYMBOL[chainId] ?? 'ETH';\n\n          // Get native balance\n          const nativeBalance = await client.getBalance({ address: ownerAddress as `0x${string}` });\n          const nativeHuman = Number(nativeBalance) / 1e18;\n\n          // Get native token price\n          const nativePrice = await oracle.getPrice(nativeSymbol, chain).catch(() => ({ priceUsd: 0 }));\n\n          const tokens: TokenBalance[] = [];\n\n          if (nativeHuman > 0) {\n            tokens.push({\n              symbol: nativeSymbol,\n              address: '0x0000000000000000000000000000000000000000',\n              chain,\n              chainId,\n              balance: nativeBalance.toString(),\n              balanceHuman: nativeHuman,\n              decimals: 18,\n              priceUsd: nativePrice.priceUsd,\n              valueUsd: nativeHuman * nativePrice.priceUsd,\n              allocationPercent: 0, // computed later\n            });\n          }\n\n          // Get ERC-20 balances for well-known tokens\n          const chainTokens = TOKENS[chainId] ?? [];\n          const tokenResults = await Promise.all(\n            chainTokens.map(async (tok) => {\n              try {\n                const balance = await client.readContract({\n                  address: tok.address as `0x${string}`,\n                  abi: ERC20_ABI,\n                  functionName: 'balanceOf',\n                  args: [ownerAddress as `0x${string}`],\n                });\n                const raw = balance as bigint;\n                if (raw === 0n) return null;\n\n                const human = Number(raw) / 10 ** tok.decimals;\n                const price = tok.isStablecoin\n                  ? { priceUsd: 1 } // skip price lookup for stablecoins\n                  : await oracle.getPrice(tok.symbol, chain).catch(() => ({ priceUsd: 0 }));\n\n                return {\n                  symbol: tok.symbol,\n                  address: tok.address,\n                  chain,\n                  chainId,\n                  balance: raw.toString(),\n                  balanceHuman: human,\n                  decimals: tok.decimals,\n                  priceUsd: price.priceUsd,\n                  valueUsd: human * price.priceUsd,\n                  allocationPercent: 0,\n                  _isStablecoin: tok.isStablecoin,\n                } as TokenBalance & { _isStablecoin: boolean };\n              } catch {\n                return null;\n              }\n            }),\n          );\n\n          tokens.push(...tokenResults.filter((t): t is TokenBalance & { _isStablecoin: boolean } => t !== null && t.valueUsd >= this.config.minValueUsd));\n          return tokens;\n        } catch {\n          return [];\n        }\n      }),\n    );\n\n    // Flatten all chain results\n    for (const tokens of chainResults) {\n      allTokens.push(...tokens);\n    }\n\n    // Compute total value\n    const totalValueUsd = allTokens.reduce((sum, t) => sum + t.valueUsd, 0);\n\n    // Compute allocation percentages\n    for (const token of allTokens) {\n      token.allocationPercent = totalValueUsd > 0\n        ? Math.round((token.valueUsd / totalValueUsd) * 10000) / 100\n        : 0;\n    }\n\n    // Sort by value descending\n    allTokens.sort((a, b) => b.valueUsd - a.valueUsd);\n\n    // Compute chain summaries\n    const chainMap = new Map<number, ChainSummary>();\n    for (const token of allTokens) {\n      const existing = chainMap.get(token.chainId);\n      if (existing) {\n        existing.valueUsd += token.valueUsd;\n        existing.tokenCount++;\n      } else {\n        chainMap.set(token.chainId, {\n          chain: token.chain,\n          chainId: token.chainId,\n          valueUsd: token.valueUsd,\n          allocationPercent: 0,\n          tokenCount: 1,\n        });\n      }\n    }\n    const chains = Array.from(chainMap.values()).sort((a, b) => b.valueUsd - a.valueUsd);\n    for (const chain of chains) {\n      chain.allocationPercent = totalValueUsd > 0\n        ? Math.round((chain.valueUsd / totalValueUsd) * 10000) / 100\n        : 0;\n    }\n\n    // Risk metrics\n    const stablecoinValue = allTokens\n      .filter((t) => this.isStablecoin(t.symbol))\n      .reduce((sum, t) => sum + t.valueUsd, 0);\n    const stablecoinRatio = totalValueUsd > 0 ? stablecoinValue / totalValueUsd : 0;\n    const topConcentration = allTokens.length > 0 && totalValueUsd > 0\n      ? allTokens[0]!.valueUsd / totalValueUsd\n      : 0;\n\n    let riskLevel: 'conservative' | 'moderate' | 'aggressive';\n    if (stablecoinRatio > 0.6) riskLevel = 'conservative';\n    else if (stablecoinRatio > 0.3 && topConcentration < 0.5) riskLevel = 'moderate';\n    else riskLevel = 'aggressive';\n\n    const snapshot: PortfolioSnapshot = {\n      owner: ownerAddress,\n      totalValueUsd: Math.round(totalValueUsd * 100) / 100,\n      chains,\n      tokens: allTokens,\n      stablecoinRatio: Math.round(stablecoinRatio * 1000) / 1000,\n      topConcentration: Math.round(topConcentration * 1000) / 1000,\n      riskLevel,\n      timestamp: Date.now(),\n    };\n\n    // Cache\n    this.cache.set(ownerAddress, { snapshot, expiresAt: Date.now() + this.config.cacheTtlMs });\n\n    return snapshot;\n  }\n\n  /**\n   * Get portfolio change since last snapshot.\n   */\n  async getChange(ownerAddress: string): Promise<PortfolioChange> {\n    const previous = this.previousSnapshots.get(ownerAddress) ?? null;\n    const current = await this.getSnapshot(ownerAddress);\n\n    // Save current as previous for next comparison (with size cap)\n    this.previousSnapshots.set(ownerAddress, current);\n    if (this.previousSnapshots.size > PortfolioSnapshotService.MAX_SNAPSHOTS) {\n      const first = this.previousSnapshots.keys().next().value;\n      if (first) this.previousSnapshots.delete(first);\n    }\n\n    const changeUsd = previous ? current.totalValueUsd - previous.totalValueUsd : 0;\n    const changePercent = previous && previous.totalValueUsd > 0\n      ? (changeUsd / previous.totalValueUsd) * 100\n      : 0;\n\n    const currentSymbols = new Set(current.tokens.map((t) => `${t.symbol}:${t.chain}`));\n    const previousSymbols = new Set(previous?.tokens.map((t) => `${t.symbol}:${t.chain}`) ?? []);\n\n    const newPositions = [...currentSymbols].filter((s) => !previousSymbols.has(s));\n    const closedPositions = [...previousSymbols].filter((s) => !currentSymbols.has(s));\n\n    return {\n      current,\n      previous,\n      changeUsd: Math.round(changeUsd * 100) / 100,\n      changePercent: Math.round(changePercent * 100) / 100,\n      newPositions,\n      closedPositions,\n    };\n  }\n\n  /**\n   * Get supported chains.\n   */\n  getSupportedChains(): Array<{ chainId: number; name: string }> {\n    return this.config.chainIds.map((id) => ({\n      chainId: id,\n      name: CHAIN_NAMES[id] ?? String(id),\n    }));\n  }\n\n  /** Clear the snapshot cache and previous snapshots. */\n  clearCache(): void {\n    this.cache.clear();\n    this.previousSnapshots.clear();\n  }\n\n  private isStablecoin(symbol: string): boolean {\n    const stables = ['USDC', 'USDT', 'DAI', 'BUSD', 'FRAX', 'LUSD', 'USDbC', 'TUSD'];\n    return stables.includes(symbol.toUpperCase());\n  }\n}\n\n// ── Singleton ───────────────────────────────────────────────────────────────\n\nlet _instance: PortfolioSnapshotService | null = null;\n\nexport function getPortfolioService(config?: PortfolioConfig): PortfolioSnapshotService {\n  if (!_instance) {\n    _instance = new PortfolioSnapshotService(config);\n  }\n  return _instance;\n}\n\nexport function resetPortfolioService(): void {\n  _instance = null;\n}\n"],"mappings":";;;;;;;;;;;;;AAoEA,MAAM,YAAY,CAChB;CACE,QAAQ,CAAC;EAAE,MAAM;EAAW,MAAM;EAAW,CAAC;CAC9C,MAAM;CACN,SAAS,CAAC;EAAE,MAAM;EAAI,MAAM;EAAW,CAAC;CACxC,iBAAiB;CACjB,MAAM;CACP,EACD;CACE,QAAQ,EAAE;CACV,MAAM;CACN,SAAS,CAAC;EAAE,MAAM;EAAI,MAAM;EAAS,CAAC;CACtC,iBAAiB;CACjB,MAAM;CACP,CACF;AAID,MAAM,SAA8G;CAClH,MAAM;EACJ;GAAE,QAAQ;GAAQ,SAAS;GAA8C,UAAU;GAAG,cAAc;GAAM;EAC1G;GAAE,QAAQ;GAAQ,SAAS;GAA8C,UAAU;GAAI,cAAc;GAAO;EAC5G;GAAE,QAAQ;GAAO,SAAS;GAA8C,UAAU;GAAI,cAAc;GAAM;EAC1G;GAAE,QAAQ;GAAQ,SAAS;GAA8C,UAAU;GAAG,cAAc;GAAM;EAC1G;GAAE,QAAQ;GAAS,SAAS;GAA8C,UAAU;GAAI,cAAc;GAAO;EAC9G;CACD,GAAG;EACD;GAAE,QAAQ;GAAQ,SAAS;GAA8C,UAAU;GAAG,cAAc;GAAM;EAC1G;GAAE,QAAQ;GAAQ,SAAS;GAA8C,UAAU;GAAI,cAAc;GAAO;EAC5G;GAAE,QAAQ;GAAQ,SAAS;GAA8C,UAAU;GAAG,cAAc;GAAM;EAC1G;GAAE,QAAQ;GAAO,SAAS;GAA8C,UAAU;GAAI,cAAc;GAAM;EAC1G;GAAE,QAAQ;GAAQ,SAAS;GAA8C,UAAU;GAAG,cAAc;GAAO;EAC3G;GAAE,QAAQ;GAAQ,SAAS;GAA8C,UAAU;GAAI,cAAc;GAAO;EAC5G;GAAE,QAAQ;GAAO,SAAS;GAA8C,UAAU;GAAI,cAAc;GAAO;EAC3G;GAAE,QAAQ;GAAQ,SAAS;GAA8C,UAAU;GAAI,cAAc;GAAO;EAC7G;CACD,OAAO;EACL;GAAE,QAAQ;GAAQ,SAAS;GAA8C,UAAU;GAAG,cAAc;GAAM;EAC1G;GAAE,QAAQ;GAAQ,SAAS;GAA8C,UAAU;GAAI,cAAc;GAAO;EAC5G;GAAE,QAAQ;GAAQ,SAAS;GAA8C,UAAU;GAAG,cAAc;GAAM;EAC1G;GAAE,QAAQ;GAAO,SAAS;GAA8C,UAAU;GAAI,cAAc;GAAO;EAC3G;GAAE,QAAQ;GAAO,SAAS;GAA8C,UAAU;GAAI,cAAc;GAAM;EAC3G;CACD,IAAI;EACF;GAAE,QAAQ;GAAQ,SAAS;GAA8C,UAAU;GAAG,cAAc;GAAM;EAC1G;GAAE,QAAQ;GAAQ,SAAS;GAA8C,UAAU;GAAI,cAAc;GAAO;EAC5G;GAAE,QAAQ;GAAQ,SAAS;GAA8C,UAAU;GAAG,cAAc;GAAM;EAC1G;GAAE,QAAQ;GAAM,SAAS;GAA8C,UAAU;GAAI,cAAc;GAAO;EAC1G;GAAE,QAAQ;GAAO,SAAS;GAA8C,UAAU;GAAI,cAAc;GAAM;EAC3G;CACD,KAAK;EACH;GAAE,QAAQ;GAAQ,SAAS;GAA8C,UAAU;GAAG,cAAc;GAAM;EAC1G;GAAE,QAAQ;GAAQ,SAAS;GAA8C,UAAU;GAAI,cAAc;GAAO;EAC5G;GAAE,QAAQ;GAAQ,SAAS;GAA8C,UAAU;GAAG,cAAc;GAAM;EAC1G;GAAE,QAAQ;GAAU,SAAS;GAA8C,UAAU;GAAI,cAAc;GAAO;EAC9G;GAAE,QAAQ;GAAO,SAAS;GAA8C,UAAU;GAAI,cAAc;GAAM;EAC3G;CACF;AAED,MAAM,cAAsC;CAC1C,GAAG;CAAY,MAAM;CAAQ,OAAO;CAAY,IAAI;CAAY,KAAK;CACtE;AAED,MAAM,gBAAwC;CAC5C,GAAG;CAAO,MAAM;CAAO,OAAO;CAAO,IAAI;CAAO,KAAK;CACtD;AAID,IAAa,2BAAb,MAAa,yBAAyB;CACpC;CACA,wBAAiF,IAAI,KAAK;CAC1F,oCAA4D,IAAI,KAAK;CACrE,OAAwB,gBAAgB;CAExC,YAAY,SAA0B,EAAE,EAAE;AACxC,OAAK,SAAS;GACZ,UAAU,OAAO,YAAY;IAAC;IAAM;IAAG;IAAO;IAAI;IAAI;GACtD,aAAa,OAAO,eAAe;GACnC,YAAY,OAAO,cAAc;GAClC;;;;;CAMH,MAAM,YAAY,cAAkD;EAElE,MAAM,SAAS,KAAK,MAAM,IAAI,aAAa;AAC3C,MAAI,UAAU,KAAK,KAAK,GAAG,OAAO,UAChC,QAAO,OAAO;EAGhB,MAAM,aAAa,eAAe;EAClC,MAAM,SAAS,gBAAgB;EAC/B,MAAM,YAA4B,EAAE;EAGpC,MAAM,eAAe,MAAM,QAAQ,IACjC,KAAK,OAAO,SAAS,IAAI,OAAO,YAAY;AAC1C,OAAI;IACF,MAAM,SAAS,MAAM,WAAW,UAAU,QAAQ;IAClD,MAAM,QAAQ,YAAY,YAAY,OAAO,QAAQ;IACrD,MAAM,eAAe,cAAc,YAAY;IAG/C,MAAM,gBAAgB,MAAM,OAAO,WAAW,EAAE,SAAS,cAA+B,CAAC;IACzF,MAAM,cAAc,OAAO,cAAc,GAAG;IAG5C,MAAM,cAAc,MAAM,OAAO,SAAS,cAAc,MAAM,CAAC,aAAa,EAAE,UAAU,GAAG,EAAE;IAE7F,MAAM,SAAyB,EAAE;AAEjC,QAAI,cAAc,EAChB,QAAO,KAAK;KACV,QAAQ;KACR,SAAS;KACT;KACA;KACA,SAAS,cAAc,UAAU;KACjC,cAAc;KACd,UAAU;KACV,UAAU,YAAY;KACtB,UAAU,cAAc,YAAY;KACpC,mBAAmB;KACpB,CAAC;IAIJ,MAAM,cAAc,OAAO,YAAY,EAAE;IACzC,MAAM,eAAe,MAAM,QAAQ,IACjC,YAAY,IAAI,OAAO,QAAQ;AAC7B,SAAI;MAOF,MAAM,MANU,MAAM,OAAO,aAAa;OACxC,SAAS,IAAI;OACb,KAAK;OACL,cAAc;OACd,MAAM,CAAC,aAA8B;OACtC,CAAC;AAEF,UAAI,QAAQ,GAAI,QAAO;MAEvB,MAAM,QAAQ,OAAO,IAAI,GAAG,MAAM,IAAI;MACtC,MAAM,QAAQ,IAAI,eACd,EAAE,UAAU,GAAG,GACf,MAAM,OAAO,SAAS,IAAI,QAAQ,MAAM,CAAC,aAAa,EAAE,UAAU,GAAG,EAAE;AAE3E,aAAO;OACL,QAAQ,IAAI;OACZ,SAAS,IAAI;OACb;OACA;OACA,SAAS,IAAI,UAAU;OACvB,cAAc;OACd,UAAU,IAAI;OACd,UAAU,MAAM;OAChB,UAAU,QAAQ,MAAM;OACxB,mBAAmB;OACnB,eAAe,IAAI;OACpB;aACK;AACN,aAAO;;MAET,CACH;AAED,WAAO,KAAK,GAAG,aAAa,QAAQ,MAAsD,MAAM,QAAQ,EAAE,YAAY,KAAK,OAAO,YAAY,CAAC;AAC/I,WAAO;WACD;AACN,WAAO,EAAE;;IAEX,CACH;AAGD,OAAK,MAAM,UAAU,aACnB,WAAU,KAAK,GAAG,OAAO;EAI3B,MAAM,gBAAgB,UAAU,QAAQ,KAAK,MAAM,MAAM,EAAE,UAAU,EAAE;AAGvE,OAAK,MAAM,SAAS,UAClB,OAAM,oBAAoB,gBAAgB,IACtC,KAAK,MAAO,MAAM,WAAW,gBAAiB,IAAM,GAAG,MACvD;AAIN,YAAU,MAAM,GAAG,MAAM,EAAE,WAAW,EAAE,SAAS;EAGjD,MAAM,2BAAW,IAAI,KAA2B;AAChD,OAAK,MAAM,SAAS,WAAW;GAC7B,MAAM,WAAW,SAAS,IAAI,MAAM,QAAQ;AAC5C,OAAI,UAAU;AACZ,aAAS,YAAY,MAAM;AAC3B,aAAS;SAET,UAAS,IAAI,MAAM,SAAS;IAC1B,OAAO,MAAM;IACb,SAAS,MAAM;IACf,UAAU,MAAM;IAChB,mBAAmB;IACnB,YAAY;IACb,CAAC;;EAGN,MAAM,SAAS,MAAM,KAAK,SAAS,QAAQ,CAAC,CAAC,MAAM,GAAG,MAAM,EAAE,WAAW,EAAE,SAAS;AACpF,OAAK,MAAM,SAAS,OAClB,OAAM,oBAAoB,gBAAgB,IACtC,KAAK,MAAO,MAAM,WAAW,gBAAiB,IAAM,GAAG,MACvD;EAIN,MAAM,kBAAkB,UACrB,QAAQ,MAAM,KAAK,aAAa,EAAE,OAAO,CAAC,CAC1C,QAAQ,KAAK,MAAM,MAAM,EAAE,UAAU,EAAE;EAC1C,MAAM,kBAAkB,gBAAgB,IAAI,kBAAkB,gBAAgB;EAC9E,MAAM,mBAAmB,UAAU,SAAS,KAAK,gBAAgB,IAC7D,UAAU,GAAI,WAAW,gBACzB;EAEJ,IAAI;AACJ,MAAI,kBAAkB,GAAK,aAAY;WAC9B,kBAAkB,MAAO,mBAAmB,GAAK,aAAY;MACjE,aAAY;EAEjB,MAAM,WAA8B;GAClC,OAAO;GACP,eAAe,KAAK,MAAM,gBAAgB,IAAI,GAAG;GACjD;GACA,QAAQ;GACR,iBAAiB,KAAK,MAAM,kBAAkB,IAAK,GAAG;GACtD,kBAAkB,KAAK,MAAM,mBAAmB,IAAK,GAAG;GACxD;GACA,WAAW,KAAK,KAAK;GACtB;AAGD,OAAK,MAAM,IAAI,cAAc;GAAE;GAAU,WAAW,KAAK,KAAK,GAAG,KAAK,OAAO;GAAY,CAAC;AAE1F,SAAO;;;;;CAMT,MAAM,UAAU,cAAgD;EAC9D,MAAM,WAAW,KAAK,kBAAkB,IAAI,aAAa,IAAI;EAC7D,MAAM,UAAU,MAAM,KAAK,YAAY,aAAa;AAGpD,OAAK,kBAAkB,IAAI,cAAc,QAAQ;AACjD,MAAI,KAAK,kBAAkB,OAAO,yBAAyB,eAAe;GACxE,MAAM,QAAQ,KAAK,kBAAkB,MAAM,CAAC,MAAM,CAAC;AACnD,OAAI,MAAO,MAAK,kBAAkB,OAAO,MAAM;;EAGjD,MAAM,YAAY,WAAW,QAAQ,gBAAgB,SAAS,gBAAgB;EAC9E,MAAM,gBAAgB,YAAY,SAAS,gBAAgB,IACtD,YAAY,SAAS,gBAAiB,MACvC;EAEJ,MAAM,iBAAiB,IAAI,IAAI,QAAQ,OAAO,KAAK,MAAM,GAAG,EAAE,OAAO,GAAG,EAAE,QAAQ,CAAC;EACnF,MAAM,kBAAkB,IAAI,IAAI,UAAU,OAAO,KAAK,MAAM,GAAG,EAAE,OAAO,GAAG,EAAE,QAAQ,IAAI,EAAE,CAAC;EAE5F,MAAM,eAAe,CAAC,GAAG,eAAe,CAAC,QAAQ,MAAM,CAAC,gBAAgB,IAAI,EAAE,CAAC;EAC/E,MAAM,kBAAkB,CAAC,GAAG,gBAAgB,CAAC,QAAQ,MAAM,CAAC,eAAe,IAAI,EAAE,CAAC;AAElF,SAAO;GACL;GACA;GACA,WAAW,KAAK,MAAM,YAAY,IAAI,GAAG;GACzC,eAAe,KAAK,MAAM,gBAAgB,IAAI,GAAG;GACjD;GACA;GACD;;;;;CAMH,qBAA+D;AAC7D,SAAO,KAAK,OAAO,SAAS,KAAK,QAAQ;GACvC,SAAS;GACT,MAAM,YAAY,OAAO,OAAO,GAAG;GACpC,EAAE;;;CAIL,aAAmB;AACjB,OAAK,MAAM,OAAO;AAClB,OAAK,kBAAkB,OAAO;;CAGhC,aAAqB,QAAyB;AAE5C,SADgB;GAAC;GAAQ;GAAQ;GAAO;GAAQ;GAAQ;GAAQ;GAAS;GAAO,CACjE,SAAS,OAAO,aAAa,CAAC;;;AAMjD,IAAI,YAA6C;AAEjD,SAAgB,oBAAoB,QAAoD;AACtF,KAAI,CAAC,UACH,aAAY,IAAI,yBAAyB,OAAO;AAElD,QAAO;;AAGT,SAAgB,wBAA8B;AAC5C,aAAY"}