{"version":3,"sources":["../src/index.ts","../src/types/channel.types.ts","../src/kakao/channel.ts","../src/kakao/sender-number.ts","../src/management/crud.ts","../src/management/permissions.ts","../src/verification/business.verify.ts","../src/verification/number.verify.ts","../src/services/channel.service.ts"],"sourcesContent":["// Types\nexport * from './types/channel.types';\n\n// Kakao Channel Management\nexport { KakaoChannelManager } from './kakao/channel';\nexport { KakaoSenderNumberManager } from './kakao/sender-number';\n\n// Channel Management\nexport { \n  ChannelCRUD,\n  type PaginationOptions,\n  type PaginatedResult,\n  type ChannelCRUDOptions,\n  type AuditLogEntry\n} from './management/crud';\n\nexport { \n  PermissionManager,\n  type User,\n  type Role,\n  type Permission,\n  type AccessContext,\n  type PermissionCheck,\n  type PermissionResult,\n  ResourceType,\n  ActionType,\n  PermissionScope\n} from './management/permissions';\n\n// Verification Systems\nexport { \n  BusinessVerifier,\n  type BusinessInfo,\n  type VerificationRequest,\n  type AutoVerificationResult,\n  type DocumentValidationResult,\n  type BusinessVerifierOptions\n} from './verification/business.verify';\n\nexport { \n  NumberVerifier,\n  type PhoneVerificationRequest,\n  type VerificationAttempt,\n  type PhoneVerificationStatus,\n  type NumberVerifierOptions,\n  type SMSProvider,\n  type VoiceProvider,\n  type PhoneNumberInfo,\n  VerificationType,\n  VerificationMethod\n} from './verification/number.verify';\n\n// Legacy Channel Service (maintained for backward compatibility)\nexport { ChannelService } from './services/channel.service';","import { z } from 'zod';\n\nexport interface Channel {\n  id: string;\n  name: string;\n  provider: string;\n  type: ChannelType;\n  status: ChannelStatus;\n  profileKey: string;\n  senderNumbers: SenderNumber[];\n  metadata: ChannelMetadata;\n  verification: ChannelVerification;\n  createdAt: Date;\n  updatedAt: Date;\n}\n\nexport enum ChannelType {\n  KAKAO_ALIMTALK = 'KAKAO_ALIMTALK',\n  KAKAO_FRIENDTALK = 'KAKAO_FRIENDTALK',\n  SMS = 'SMS',\n  LMS = 'LMS',\n  MMS = 'MMS'\n}\n\nexport enum ChannelStatus {\n  PENDING = 'PENDING',           // 등록 대기\n  VERIFYING = 'VERIFYING',       // 검증 중\n  ACTIVE = 'ACTIVE',             // 활성화\n  SUSPENDED = 'SUSPENDED',       // 일시 정지\n  BLOCKED = 'BLOCKED',           // 차단됨\n  DELETED = 'DELETED'            // 삭제됨\n}\n\nexport interface SenderNumber {\n  id: string;\n  phoneNumber: string;\n  status: SenderNumberStatus;\n  verificationCode?: string;\n  verifiedAt?: Date;\n  category: SenderNumberCategory;\n  metadata: {\n    businessName?: string;\n    businessRegistrationNumber?: string;\n    contactPerson?: string;\n    contactEmail?: string;\n  };\n  createdAt: Date;\n  updatedAt: Date;\n}\n\nexport enum SenderNumberStatus {\n  PENDING = 'PENDING',           // 등록 대기\n  VERIFYING = 'VERIFYING',       // 인증 중\n  VERIFIED = 'VERIFIED',         // 인증 완료\n  REJECTED = 'REJECTED',         // 반려됨\n  BLOCKED = 'BLOCKED'            // 차단됨\n}\n\nexport enum SenderNumberCategory {\n  BUSINESS = 'BUSINESS',         // 사업자\n  PERSONAL = 'PERSONAL',         // 개인\n  GOVERNMENT = 'GOVERNMENT',     // 관공서\n  NON_PROFIT = 'NON_PROFIT'      // 비영리단체\n}\n\nexport interface ChannelMetadata {\n  businessInfo?: {\n    name: string;\n    registrationNumber: string;\n    category: string;\n    contactPerson: string;\n    contactEmail: string;\n    contactPhone: string;\n  };\n  kakaoInfo?: {\n    plusFriendId: string;\n    brandName: string;\n    logoUrl?: string;\n    description?: string;\n  };\n  limits: {\n    dailyMessageLimit: number;\n    monthlyMessageLimit: number;\n    rateLimit: number; // messages per second\n  };\n  features: {\n    supportsBulkSending: boolean;\n    supportsScheduling: boolean;\n    supportsButtons: boolean;\n    maxButtonCount: number;\n  };\n}\n\nexport interface ChannelVerification {\n  status: VerificationStatus;\n  documents: VerificationDocument[];\n  verifiedAt?: Date;\n  rejectedAt?: Date;\n  rejectionReason?: string;\n  verifiedBy?: string;\n}\n\nexport enum VerificationStatus {\n  NOT_REQUIRED = 'NOT_REQUIRED',\n  PENDING = 'PENDING',\n  UNDER_REVIEW = 'UNDER_REVIEW',\n  VERIFIED = 'VERIFIED',\n  REJECTED = 'REJECTED'\n}\n\nexport interface VerificationDocument {\n  id: string;\n  type: DocumentType;\n  fileName: string;\n  fileUrl: string;\n  uploadedAt: Date;\n  status: DocumentStatus;\n}\n\nexport enum DocumentType {\n  BUSINESS_REGISTRATION = 'BUSINESS_REGISTRATION',\n  BUSINESS_LICENSE = 'BUSINESS_LICENSE',\n  ID_CARD = 'ID_CARD',\n  AUTHORIZATION_LETTER = 'AUTHORIZATION_LETTER',\n  OTHER = 'OTHER'\n}\n\nexport enum DocumentStatus {\n  UPLOADED = 'UPLOADED',\n  VERIFIED = 'VERIFIED',\n  REJECTED = 'REJECTED'\n}\n\n// Request/Response types\nexport interface ChannelCreateRequest {\n  name: string;\n  type: ChannelType;\n  provider: string;\n  profileKey: string;\n  businessInfo?: {\n    name: string;\n    registrationNumber: string;\n    category: string;\n    contactPerson: string;\n    contactEmail: string;\n    contactPhone: string;\n  };\n  kakaoInfo?: {\n    plusFriendId: string;\n    brandName: string;\n    logoUrl?: string;\n    description?: string;\n  };\n}\n\nexport interface SenderNumberCreateRequest {\n  phoneNumber: string;\n  category: SenderNumberCategory;\n  businessInfo?: {\n    businessName: string;\n    businessRegistrationNumber: string;\n    contactPerson: string;\n    contactEmail: string;\n  };\n}\n\nexport interface ChannelFilters {\n  provider?: string;\n  type?: ChannelType;\n  status?: ChannelStatus;\n  verified?: boolean;\n  createdAfter?: Date;\n  createdBefore?: Date;\n}\n\nexport interface SenderNumberFilters {\n  channelId?: string;\n  status?: SenderNumberStatus;\n  category?: SenderNumberCategory;\n  verified?: boolean;\n}\n\n// Zod schemas\nexport const ChannelCreateRequestSchema = z.object({\n  name: z.string().min(1).max(100),\n  type: z.nativeEnum(ChannelType),\n  provider: z.string().min(1),\n  profileKey: z.string().min(1),\n  businessInfo: z.object({\n    name: z.string().min(1),\n    registrationNumber: z.string().min(1),\n    category: z.string().min(1),\n    contactPerson: z.string().min(1),\n    contactEmail: z.string().email(),\n    contactPhone: z.string().regex(/^[0-9-+\\s()]+$/),\n  }).optional(),\n  kakaoInfo: z.object({\n    plusFriendId: z.string().min(1),\n    brandName: z.string().min(1),\n    logoUrl: z.string().url().optional(),\n    description: z.string().max(500).optional(),\n  }).optional(),\n});\n\nexport const SenderNumberCreateRequestSchema = z.object({\n  phoneNumber: z.string().regex(/^[0-9]{10,11}$/),\n  category: z.nativeEnum(SenderNumberCategory),\n  businessInfo: z.object({\n    businessName: z.string().min(1),\n    businessRegistrationNumber: z.string().min(1),\n    contactPerson: z.string().min(1),\n    contactEmail: z.string().email(),\n  }).optional(),\n});\n\nexport const ChannelFiltersSchema = z.object({\n  provider: z.string().optional(),\n  type: z.nativeEnum(ChannelType).optional(),\n  status: z.nativeEnum(ChannelStatus).optional(),\n  verified: z.boolean().optional(),\n  createdAfter: z.date().optional(),\n  createdBefore: z.date().optional(),\n});\n\nexport const SenderNumberFiltersSchema = z.object({\n  channelId: z.string().optional(),\n  status: z.nativeEnum(SenderNumberStatus).optional(),\n  category: z.nativeEnum(SenderNumberCategory).optional(),\n  verified: z.boolean().optional(),\n});\n\nexport type ChannelCreateRequestType = z.infer<typeof ChannelCreateRequestSchema>;\nexport type SenderNumberCreateRequestType = z.infer<typeof SenderNumberCreateRequestSchema>;\nexport type ChannelFiltersType = z.infer<typeof ChannelFiltersSchema>;\nexport type SenderNumberFiltersType = z.infer<typeof SenderNumberFiltersSchema>;\n\n// Additional types for service compatibility\nexport interface ChannelConfig {\n  id: string;\n  name: string;\n  type: 'alimtalk' | 'sms' | 'lms' | 'friendtalk';\n  providerId: string;\n  active: boolean;\n  settings: Record<string, any>;\n  createdAt: Date;\n  updatedAt: Date;\n}\n\nexport interface ChannelVerificationResult {\n  success: boolean;\n  status: string;\n  verificationCode?: string;\n  error?: string;\n}","import { \n  Channel, \n  ChannelCreateRequest, \n  ChannelStatus, \n  ChannelType,\n  VerificationStatus \n} from '../types/channel.types';\n\nexport class KakaoChannelManager {\n  private channels: Map<string, Channel> = new Map();\n\n  async createChannel(request: ChannelCreateRequest): Promise<Channel> {\n    // Validate Kakao-specific requirements\n    this.validateKakaoChannelRequest(request);\n\n    const channelId = this.generateChannelId();\n    \n    const channel: Channel = {\n      id: channelId,\n      name: request.name,\n      provider: request.provider,\n      type: request.type,\n      status: ChannelStatus.PENDING,\n      profileKey: request.profileKey,\n      senderNumbers: [],\n      metadata: {\n        businessInfo: request.businessInfo,\n        kakaoInfo: request.kakaoInfo,\n        limits: {\n          dailyMessageLimit: 10000,\n          monthlyMessageLimit: 300000,\n          rateLimit: 10 // 10 messages per second\n        },\n        features: {\n          supportsBulkSending: true,\n          supportsScheduling: true,\n          supportsButtons: true,\n          maxButtonCount: 5\n        }\n      },\n      verification: {\n        status: request.businessInfo ? VerificationStatus.PENDING : VerificationStatus.NOT_REQUIRED,\n        documents: []\n      },\n      createdAt: new Date(),\n      updatedAt: new Date()\n    };\n\n    this.channels.set(channelId, channel);\n\n    // Start verification process if business info is provided\n    if (request.businessInfo) {\n      await this.initiateBusinessVerification(channel);\n    }\n\n    return channel;\n  }\n\n  private validateKakaoChannelRequest(request: ChannelCreateRequest): void {\n    if (request.type !== ChannelType.KAKAO_ALIMTALK && request.type !== ChannelType.KAKAO_FRIENDTALK) {\n      throw new Error('Invalid channel type for Kakao channel');\n    }\n\n    if (!request.kakaoInfo?.plusFriendId) {\n      throw new Error('Plus Friend ID is required for Kakao channels');\n    }\n\n    if (!request.kakaoInfo?.brandName) {\n      throw new Error('Brand name is required for Kakao channels');\n    }\n\n    // Validate Plus Friend ID format\n    if (!this.isValidPlusFriendId(request.kakaoInfo.plusFriendId)) {\n      throw new Error('Invalid Plus Friend ID format');\n    }\n  }\n\n  private isValidPlusFriendId(plusFriendId: string): boolean {\n    // Plus Friend ID should start with @ and contain only allowed characters\n    const regex = /^@[a-zA-Z0-9_-]{3,30}$/;\n    return regex.test(plusFriendId);\n  }\n\n  private async initiateBusinessVerification(channel: Channel): Promise<void> {\n    // In a real implementation, this would integrate with Kakao's verification API\n    // For now, we'll simulate the process\n    \n    channel.verification.status = VerificationStatus.UNDER_REVIEW;\n    channel.status = ChannelStatus.VERIFYING;\n    channel.updatedAt = new Date();\n\n    // Simulate verification process (in real scenario, this would be handled by webhooks)\n    setTimeout(() => {\n      this.completeVerification(channel.id, true);\n    }, 5000); // 5 seconds for demo\n  }\n\n  async completeVerification(channelId: string, approved: boolean, rejectionReason?: string): Promise<void> {\n    const channel = this.channels.get(channelId);\n    if (!channel) {\n      throw new Error('Channel not found');\n    }\n\n    if (approved) {\n      channel.verification.status = VerificationStatus.VERIFIED;\n      channel.verification.verifiedAt = new Date();\n      channel.status = ChannelStatus.ACTIVE;\n    } else {\n      channel.verification.status = VerificationStatus.REJECTED;\n      channel.verification.rejectedAt = new Date();\n      channel.verification.rejectionReason = rejectionReason || 'Verification failed';\n      channel.status = ChannelStatus.SUSPENDED;\n    }\n\n    channel.updatedAt = new Date();\n  }\n\n  async getChannel(channelId: string): Promise<Channel | null> {\n    return this.channels.get(channelId) || null;\n  }\n\n  async updateChannel(channelId: string, updates: Partial<Channel>): Promise<Channel> {\n    const channel = this.channels.get(channelId);\n    if (!channel) {\n      throw new Error('Channel not found');\n    }\n\n    // Validate updates\n    if (updates.metadata?.kakaoInfo?.plusFriendId && !this.isValidPlusFriendId(updates.metadata.kakaoInfo.plusFriendId)) {\n      throw new Error('Invalid Plus Friend ID format');\n    }\n\n    // Apply updates\n    Object.assign(channel, updates, { updatedAt: new Date() });\n\n    return channel;\n  }\n\n  async deleteChannel(channelId: string): Promise<boolean> {\n    const channel = this.channels.get(channelId);\n    if (!channel) {\n      return false;\n    }\n\n    // Soft delete - mark as deleted instead of removing\n    channel.status = ChannelStatus.DELETED;\n    channel.updatedAt = new Date();\n\n    return true;\n  }\n\n  async listChannels(filters?: {\n    status?: ChannelStatus;\n    type?: ChannelType;\n    verified?: boolean;\n  }): Promise<Channel[]> {\n    let channels = Array.from(this.channels.values());\n\n    if (filters) {\n      if (filters.status) {\n        channels = channels.filter(c => c.status === filters.status);\n      }\n      if (filters.type) {\n        channels = channels.filter(c => c.type === filters.type);\n      }\n      if (filters.verified !== undefined) {\n        const verifiedStatus = filters.verified ? VerificationStatus.VERIFIED : VerificationStatus.PENDING;\n        channels = channels.filter(c => c.verification.status === verifiedStatus);\n      }\n    }\n\n    // Exclude deleted channels unless specifically requested\n    return channels.filter(c => c.status !== ChannelStatus.DELETED);\n  }\n\n  async suspendChannel(channelId: string, reason: string): Promise<void> {\n    const channel = this.channels.get(channelId);\n    if (!channel) {\n      throw new Error('Channel not found');\n    }\n\n    channel.status = ChannelStatus.SUSPENDED;\n    channel.updatedAt = new Date();\n    \n    // Log suspension reason (in real implementation, save to audit log)\n    console.log(`Channel ${channelId} suspended: ${reason}`);\n  }\n\n  async reactivateChannel(channelId: string): Promise<void> {\n    const channel = this.channels.get(channelId);\n    if (!channel) {\n      throw new Error('Channel not found');\n    }\n\n    if (channel.verification.status !== VerificationStatus.VERIFIED) {\n      throw new Error('Channel must be verified before reactivation');\n    }\n\n    channel.status = ChannelStatus.ACTIVE;\n    channel.updatedAt = new Date();\n  }\n\n  async checkChannelHealth(channelId: string): Promise<{\n    isHealthy: boolean;\n    issues: string[];\n    recommendations: string[];\n  }> {\n    const channel = this.channels.get(channelId);\n    if (!channel) {\n      throw new Error('Channel not found');\n    }\n\n    const issues: string[] = [];\n    const recommendations: string[] = [];\n\n    // Check channel status\n    if (channel.status !== ChannelStatus.ACTIVE) {\n      issues.push(`Channel status is ${channel.status}`);\n    }\n\n    // Check verification status\n    if (channel.verification.status !== VerificationStatus.VERIFIED && \n        channel.verification.status !== VerificationStatus.NOT_REQUIRED) {\n      issues.push(`Channel verification is ${channel.verification.status}`);\n    }\n\n    // Check if channel has sender numbers\n    if (channel.senderNumbers.length === 0) {\n      recommendations.push('Add at least one verified sender number');\n    }\n\n    // Check business info completeness\n    if (!channel.metadata.businessInfo) {\n      recommendations.push('Complete business information for better deliverability');\n    }\n\n    return {\n      isHealthy: issues.length === 0,\n      issues,\n      recommendations\n    };\n  }\n\n  private generateChannelId(): string {\n    return `kakao_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;\n  }\n}","import { \n  SenderNumber, \n  SenderNumberCreateRequest, \n  SenderNumberStatus, \n  SenderNumberCategory \n} from '../types/channel.types';\n\nexport class KakaoSenderNumberManager {\n  private senderNumbers: Map<string, SenderNumber> = new Map();\n  private verificationCodes: Map<string, { code: string; expiresAt: Date }> = new Map();\n\n  async addSenderNumber(\n    channelId: string, \n    request: SenderNumberCreateRequest\n  ): Promise<SenderNumber> {\n    // Validate phone number format\n    this.validatePhoneNumber(request.phoneNumber);\n\n    // Check if number is already registered\n    const existingNumber = this.findSenderNumberByPhone(request.phoneNumber);\n    if (existingNumber) {\n      throw new Error('Phone number is already registered');\n    }\n\n    const senderNumberId = this.generateSenderNumberId();\n    \n    const senderNumber: SenderNumber = {\n      id: senderNumberId,\n      phoneNumber: request.phoneNumber,\n      status: SenderNumberStatus.PENDING,\n      category: request.category,\n      metadata: {\n        businessName: request.businessInfo?.businessName,\n        businessRegistrationNumber: request.businessInfo?.businessRegistrationNumber,\n        contactPerson: request.businessInfo?.contactPerson,\n        contactEmail: request.businessInfo?.contactEmail,\n      },\n      createdAt: new Date(),\n      updatedAt: new Date()\n    };\n\n    this.senderNumbers.set(senderNumberId, senderNumber);\n\n    // Initiate verification process\n    await this.initiateVerification(senderNumber);\n\n    return senderNumber;\n  }\n\n  private validatePhoneNumber(phoneNumber: string): void {\n    // Korean phone number validation\n    const regex = /^(010|011|016|017|018|019)[0-9]{7,8}$/;\n    if (!regex.test(phoneNumber)) {\n      throw new Error('Invalid Korean phone number format');\n    }\n  }\n\n  private findSenderNumberByPhone(phoneNumber: string): SenderNumber | undefined {\n    return Array.from(this.senderNumbers.values())\n      .find(sn => sn.phoneNumber === phoneNumber);\n  }\n\n  private async initiateVerification(senderNumber: SenderNumber): Promise<void> {\n    // Generate verification code\n    const verificationCode = this.generateVerificationCode();\n    const expiresAt = new Date(Date.now() + 5 * 60 * 1000); // 5 minutes\n\n    // Store verification code\n    this.verificationCodes.set(senderNumber.id, {\n      code: verificationCode,\n      expiresAt\n    });\n\n    // Update sender number status\n    senderNumber.status = SenderNumberStatus.VERIFYING;\n    senderNumber.verificationCode = verificationCode;\n    senderNumber.updatedAt = new Date();\n\n    // In a real implementation, send SMS to the phone number\n    console.log(`Verification code for ${senderNumber.phoneNumber}: ${verificationCode}`);\n    \n    // Simulate SMS sending\n    await this.sendVerificationSMS(senderNumber.phoneNumber, verificationCode);\n  }\n\n  private async sendVerificationSMS(phoneNumber: string, code: string): Promise<void> {\n    // In a real implementation, this would use an SMS provider\n    console.log(`Sending SMS to ${phoneNumber}: Your verification code is ${code}`);\n  }\n\n  async verifySenderNumber(senderNumberId: string, code: string): Promise<boolean> {\n    const senderNumber = this.senderNumbers.get(senderNumberId);\n    if (!senderNumber) {\n      throw new Error('Sender number not found');\n    }\n\n    const verification = this.verificationCodes.get(senderNumberId);\n    if (!verification) {\n      throw new Error('No verification code found');\n    }\n\n    // Check if code is expired\n    if (new Date() > verification.expiresAt) {\n      throw new Error('Verification code has expired');\n    }\n\n    // Check if code matches\n    if (verification.code !== code) {\n      return false;\n    }\n\n    // Mark as verified\n    senderNumber.status = SenderNumberStatus.VERIFIED;\n    senderNumber.verifiedAt = new Date();\n    senderNumber.updatedAt = new Date();\n    delete senderNumber.verificationCode;\n\n    // Clean up verification code\n    this.verificationCodes.delete(senderNumberId);\n\n    return true;\n  }\n\n  async resendVerificationCode(senderNumberId: string): Promise<void> {\n    const senderNumber = this.senderNumbers.get(senderNumberId);\n    if (!senderNumber) {\n      throw new Error('Sender number not found');\n    }\n\n    if (senderNumber.status !== SenderNumberStatus.VERIFYING) {\n      throw new Error('Sender number is not in verifying status');\n    }\n\n    // Check rate limiting (prevent spam)\n    const lastVerification = this.verificationCodes.get(senderNumberId);\n    if (lastVerification) {\n      const timeSinceLastCode = Date.now() - (lastVerification.expiresAt.getTime() - 5 * 60 * 1000);\n      if (timeSinceLastCode < 60 * 1000) { // 1 minute cooldown\n        throw new Error('Please wait before requesting a new verification code');\n      }\n    }\n\n    // Generate new verification code\n    await this.initiateVerification(senderNumber);\n  }\n\n  async getSenderNumber(senderNumberId: string): Promise<SenderNumber | null> {\n    return this.senderNumbers.get(senderNumberId) || null;\n  }\n\n  async listSenderNumbers(filters?: {\n    channelId?: string;\n    status?: SenderNumberStatus;\n    category?: SenderNumberCategory;\n    verified?: boolean;\n  }): Promise<SenderNumber[]> {\n    let senderNumbers = Array.from(this.senderNumbers.values());\n\n    if (filters) {\n      if (filters.status) {\n        senderNumbers = senderNumbers.filter(sn => sn.status === filters.status);\n      }\n      if (filters.category) {\n        senderNumbers = senderNumbers.filter(sn => sn.category === filters.category);\n      }\n      if (filters.verified !== undefined) {\n        if (filters.verified) {\n          senderNumbers = senderNumbers.filter(sn => sn.status === SenderNumberStatus.VERIFIED);\n        } else {\n          senderNumbers = senderNumbers.filter(sn => sn.status !== SenderNumberStatus.VERIFIED);\n        }\n      }\n    }\n\n    return senderNumbers;\n  }\n\n  async updateSenderNumber(\n    senderNumberId: string, \n    updates: Partial<SenderNumber>\n  ): Promise<SenderNumber> {\n    const senderNumber = this.senderNumbers.get(senderNumberId);\n    if (!senderNumber) {\n      throw new Error('Sender number not found');\n    }\n\n    // Prevent updating certain fields\n    const allowedUpdates = { ...updates };\n    delete allowedUpdates.id;\n    delete allowedUpdates.phoneNumber;\n    delete allowedUpdates.verifiedAt;\n    delete allowedUpdates.createdAt;\n\n    Object.assign(senderNumber, allowedUpdates, { updatedAt: new Date() });\n\n    return senderNumber;\n  }\n\n  async deleteSenderNumber(senderNumberId: string): Promise<boolean> {\n    const senderNumber = this.senderNumbers.get(senderNumberId);\n    if (!senderNumber) {\n      return false;\n    }\n\n    // Check if sender number is being used\n    if (await this.isSenderNumberInUse(senderNumberId)) {\n      throw new Error('Cannot delete sender number that is currently in use');\n    }\n\n    this.senderNumbers.delete(senderNumberId);\n    this.verificationCodes.delete(senderNumberId);\n\n    return true;\n  }\n\n  private async isSenderNumberInUse(senderNumberId: string): Promise<boolean> {\n    // In a real implementation, check if any templates or active campaigns use this sender number\n    return false;\n  }\n\n  async blockSenderNumber(senderNumberId: string, reason: string): Promise<void> {\n    const senderNumber = this.senderNumbers.get(senderNumberId);\n    if (!senderNumber) {\n      throw new Error('Sender number not found');\n    }\n\n    senderNumber.status = SenderNumberStatus.BLOCKED;\n    senderNumber.updatedAt = new Date();\n\n    // Log blocking reason (in real implementation, save to audit log)\n    console.log(`Sender number ${senderNumberId} blocked: ${reason}`);\n  }\n\n  async unblockSenderNumber(senderNumberId: string): Promise<void> {\n    const senderNumber = this.senderNumbers.get(senderNumberId);\n    if (!senderNumber) {\n      throw new Error('Sender number not found');\n    }\n\n    if (senderNumber.status !== SenderNumberStatus.BLOCKED) {\n      throw new Error('Sender number is not blocked');\n    }\n\n    // Restore to previous status (assume verified if was blocked)\n    senderNumber.status = senderNumber.verifiedAt ? \n      SenderNumberStatus.VERIFIED : \n      SenderNumberStatus.PENDING;\n    senderNumber.updatedAt = new Date();\n  }\n\n  async validateSenderNumberForSending(senderNumberId: string): Promise<{\n    isValid: boolean;\n    errors: string[];\n  }> {\n    const senderNumber = this.senderNumbers.get(senderNumberId);\n    const errors: string[] = [];\n\n    if (!senderNumber) {\n      errors.push('Sender number not found');\n      return { isValid: false, errors };\n    }\n\n    if (senderNumber.status !== SenderNumberStatus.VERIFIED) {\n      errors.push(`Sender number status is ${senderNumber.status}, must be verified`);\n    }\n\n    if (!senderNumber.verifiedAt) {\n      errors.push('Sender number has not been verified');\n    }\n\n    // Check if verification is recent (within 1 year)\n    if (senderNumber.verifiedAt) {\n      const oneYearAgo = new Date(Date.now() - 365 * 24 * 60 * 60 * 1000);\n      if (senderNumber.verifiedAt < oneYearAgo) {\n        errors.push('Sender number verification has expired');\n      }\n    }\n\n    return {\n      isValid: errors.length === 0,\n      errors\n    };\n  }\n\n  private generateSenderNumberId(): string {\n    return `sn_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;\n  }\n\n  private generateVerificationCode(): string {\n    return Math.floor(100000 + Math.random() * 900000).toString();\n  }\n\n  // Cleanup expired verification codes\n  cleanup(): void {\n    const now = new Date();\n    for (const [id, verification] of this.verificationCodes) {\n      if (now > verification.expiresAt) {\n        this.verificationCodes.delete(id);\n        \n        // Reset sender number status if verification expired\n        const senderNumber = this.senderNumbers.get(id);\n        if (senderNumber && senderNumber.status === SenderNumberStatus.VERIFYING) {\n          senderNumber.status = SenderNumberStatus.PENDING;\n          delete senderNumber.verificationCode;\n          senderNumber.updatedAt = new Date();\n        }\n      }\n    }\n  }\n}","/**\n * Channel CRUD Operations\n * 채널 생성, 조회, 수정, 삭제 통합 관리\n */\n\nimport { EventEmitter } from 'events';\nimport {\n  Channel,\n  SenderNumber,\n  ChannelCreateRequest,\n  SenderNumberCreateRequest,\n  ChannelFilters,\n  SenderNumberFilters,\n  ChannelStatus,\n  SenderNumberStatus,\n  ChannelType,\n  VerificationStatus\n} from '../types/channel.types';\n\nexport interface PaginationOptions {\n  page: number;\n  limit: number;\n  sortBy?: string;\n  sortOrder?: 'asc' | 'desc';\n}\n\nexport interface PaginatedResult<T> {\n  data: T[];\n  total: number;\n  page: number;\n  limit: number;\n  totalPages: number;\n  hasNext: boolean;\n  hasPrev: boolean;\n}\n\nexport interface ChannelCRUDOptions {\n  enableAuditLog: boolean;\n  enableEventEmission: boolean;\n  defaultPageSize: number;\n  maxPageSize: number;\n  enableSoftDelete: boolean;\n  autoCleanup: boolean;\n  cleanupInterval: number; // in milliseconds\n}\n\nexport interface AuditLogEntry {\n  id: string;\n  entityType: 'channel' | 'senderNumber';\n  entityId: string;\n  action: 'create' | 'read' | 'update' | 'delete' | 'verify' | 'suspend' | 'activate';\n  userId?: string;\n  timestamp: Date;\n  changes?: {\n    before: any;\n    after: any;\n  };\n  metadata?: Record<string, any>;\n}\n\nexport class ChannelCRUD extends EventEmitter {\n  private channels = new Map<string, Channel>();\n  private senderNumbers = new Map<string, SenderNumber>();\n  private auditLogs: AuditLogEntry[] = [];\n  private cleanupTimer?: NodeJS.Timeout;\n\n  private defaultOptions: ChannelCRUDOptions = {\n    enableAuditLog: true,\n    enableEventEmission: true,\n    defaultPageSize: 20,\n    maxPageSize: 100,\n    enableSoftDelete: true,\n    autoCleanup: true,\n    cleanupInterval: 3600000 // 1 hour\n  };\n\n  constructor(private options: Partial<ChannelCRUDOptions> = {}) {\n    super();\n    this.options = { ...this.defaultOptions, ...options };\n\n    if (this.options.autoCleanup) {\n      this.startAutoCleanup();\n    }\n  }\n\n  // Channel CRUD Operations\n  async createChannel(request: ChannelCreateRequest, userId?: string): Promise<Channel> {\n    const channelId = this.generateChannelId();\n    \n    const channel: Channel = {\n      id: channelId,\n      name: request.name,\n      provider: request.provider,\n      type: request.type,\n      status: ChannelStatus.PENDING,\n      profileKey: request.profileKey,\n      senderNumbers: [],\n      metadata: {\n        businessInfo: request.businessInfo,\n        kakaoInfo: request.kakaoInfo,\n        limits: this.getDefaultLimits(request.type),\n        features: this.getDefaultFeatures(request.type)\n      },\n      verification: {\n        status: request.businessInfo ? VerificationStatus.PENDING : VerificationStatus.NOT_REQUIRED,\n        documents: []\n      },\n      createdAt: new Date(),\n      updatedAt: new Date()\n    };\n\n    this.channels.set(channelId, channel);\n\n    // Audit log\n    if (this.options.enableAuditLog) {\n      this.addAuditLog('channel', channelId, 'create', userId, undefined, channel);\n    }\n\n    // Event emission\n    if (this.options.enableEventEmission) {\n      this.emit('channel:created', { channel, userId });\n    }\n\n    return channel;\n  }\n\n  async getChannel(channelId: string, userId?: string): Promise<Channel | null> {\n    const channel = this.channels.get(channelId);\n    \n    if (channel && this.options.enableAuditLog) {\n      this.addAuditLog('channel', channelId, 'read', userId);\n    }\n\n    return channel || null;\n  }\n\n  async updateChannel(\n    channelId: string, \n    updates: Partial<Omit<Channel, 'id' | 'createdAt' | 'updatedAt'>>,\n    userId?: string\n  ): Promise<Channel> {\n    const channel = this.channels.get(channelId);\n    if (!channel) {\n      throw new Error(`Channel ${channelId} not found`);\n    }\n\n    const before = this.options.enableAuditLog ? { ...channel } : undefined;\n    \n    // Apply updates\n    const updatedChannel = {\n      ...channel,\n      ...updates,\n      id: channelId, // Ensure ID doesn't change\n      updatedAt: new Date()\n    };\n\n    this.channels.set(channelId, updatedChannel);\n\n    // Audit log\n    if (this.options.enableAuditLog) {\n      this.addAuditLog('channel', channelId, 'update', userId, before, updatedChannel);\n    }\n\n    // Event emission\n    if (this.options.enableEventEmission) {\n      this.emit('channel:updated', { \n        channel: updatedChannel, \n        previousChannel: channel,\n        userId \n      });\n    }\n\n    return updatedChannel;\n  }\n\n  async deleteChannel(channelId: string, userId?: string): Promise<boolean> {\n    const channel = this.channels.get(channelId);\n    if (!channel) {\n      return false;\n    }\n\n    if (this.options.enableSoftDelete) {\n      // Soft delete - mark as deleted\n      channel.status = ChannelStatus.DELETED;\n      channel.updatedAt = new Date();\n    } else {\n      // Hard delete - remove from memory\n      this.channels.delete(channelId);\n      \n      // Also delete associated sender numbers\n      for (const [id, senderNumber] of this.senderNumbers) {\n        // In a real implementation, we'd have a channelId field in SenderNumber\n        // For now, we'll skip this cleanup\n      }\n    }\n\n    // Audit log\n    if (this.options.enableAuditLog) {\n      this.addAuditLog('channel', channelId, 'delete', userId, channel);\n    }\n\n    // Event emission\n    if (this.options.enableEventEmission) {\n      this.emit('channel:deleted', { channel, userId });\n    }\n\n    return true;\n  }\n\n  async listChannels(\n    filters: ChannelFilters = {}, \n    pagination: PaginationOptions = { page: 1, limit: this.options.defaultPageSize! }\n  ): Promise<PaginatedResult<Channel>> {\n    let channels = Array.from(this.channels.values());\n\n    // Apply filters\n    if (filters.provider) {\n      channels = channels.filter(c => c.provider === filters.provider);\n    }\n    if (filters.type) {\n      channels = channels.filter(c => c.type === filters.type);\n    }\n    if (filters.status) {\n      channels = channels.filter(c => c.status === filters.status);\n    }\n    if (filters.verified !== undefined) {\n      const targetStatus = filters.verified ? VerificationStatus.VERIFIED : VerificationStatus.PENDING;\n      channels = channels.filter(c => c.verification.status === targetStatus);\n    }\n    if (filters.createdAfter) {\n      channels = channels.filter(c => c.createdAt >= filters.createdAfter!);\n    }\n    if (filters.createdBefore) {\n      channels = channels.filter(c => c.createdAt <= filters.createdBefore!);\n    }\n\n    // Exclude soft deleted channels unless specifically requested\n    if (!filters.status || filters.status !== ChannelStatus.DELETED) {\n      channels = channels.filter(c => c.status !== ChannelStatus.DELETED);\n    }\n\n    // Apply sorting\n    const sortBy = pagination.sortBy || 'createdAt';\n    const sortOrder = pagination.sortOrder || 'desc';\n    \n    channels.sort((a, b) => {\n      let aValue: any, bValue: any;\n      \n      switch (sortBy) {\n        case 'name':\n          aValue = a.name;\n          bValue = b.name;\n          break;\n        case 'createdAt':\n          aValue = a.createdAt.getTime();\n          bValue = b.createdAt.getTime();\n          break;\n        case 'updatedAt':\n          aValue = a.updatedAt.getTime();\n          bValue = b.updatedAt.getTime();\n          break;\n        default:\n          aValue = a.createdAt.getTime();\n          bValue = b.createdAt.getTime();\n      }\n\n      if (sortOrder === 'asc') {\n        return aValue < bValue ? -1 : aValue > bValue ? 1 : 0;\n      } else {\n        return aValue > bValue ? -1 : aValue < bValue ? 1 : 0;\n      }\n    });\n\n    // Apply pagination\n    const total = channels.length;\n    const limit = Math.min(pagination.limit, this.options.maxPageSize!);\n    const page = Math.max(1, pagination.page);\n    const offset = (page - 1) * limit;\n    const paginatedChannels = channels.slice(offset, offset + limit);\n\n    return {\n      data: paginatedChannels,\n      total,\n      page,\n      limit,\n      totalPages: Math.ceil(total / limit),\n      hasNext: offset + limit < total,\n      hasPrev: page > 1\n    };\n  }\n\n  // Sender Number CRUD Operations\n  async createSenderNumber(\n    channelId: string,\n    request: SenderNumberCreateRequest,\n    userId?: string\n  ): Promise<SenderNumber> {\n    const channel = this.channels.get(channelId);\n    if (!channel) {\n      throw new Error(`Channel ${channelId} not found`);\n    }\n\n    const senderNumberId = this.generateSenderNumberId();\n    \n    const senderNumber: SenderNumber = {\n      id: senderNumberId,\n      phoneNumber: request.phoneNumber,\n      status: SenderNumberStatus.PENDING,\n      category: request.category,\n      metadata: {\n        businessName: request.businessInfo?.businessName,\n        businessRegistrationNumber: request.businessInfo?.businessRegistrationNumber,\n        contactPerson: request.businessInfo?.contactPerson,\n        contactEmail: request.businessInfo?.contactEmail,\n      },\n      createdAt: new Date(),\n      updatedAt: new Date()\n    };\n\n    this.senderNumbers.set(senderNumberId, senderNumber);\n\n    // Add to channel's sender numbers\n    channel.senderNumbers.push(senderNumber);\n    channel.updatedAt = new Date();\n\n    // Audit log\n    if (this.options.enableAuditLog) {\n      this.addAuditLog('senderNumber', senderNumberId, 'create', userId, undefined, senderNumber);\n    }\n\n    // Event emission\n    if (this.options.enableEventEmission) {\n      this.emit('senderNumber:created', { senderNumber, channelId, userId });\n    }\n\n    return senderNumber;\n  }\n\n  async getSenderNumber(senderNumberId: string, userId?: string): Promise<SenderNumber | null> {\n    const senderNumber = this.senderNumbers.get(senderNumberId);\n    \n    if (senderNumber && this.options.enableAuditLog) {\n      this.addAuditLog('senderNumber', senderNumberId, 'read', userId);\n    }\n\n    return senderNumber || null;\n  }\n\n  async updateSenderNumber(\n    senderNumberId: string,\n    updates: Partial<Omit<SenderNumber, 'id' | 'phoneNumber' | 'createdAt' | 'updatedAt'>>,\n    userId?: string\n  ): Promise<SenderNumber> {\n    const senderNumber = this.senderNumbers.get(senderNumberId);\n    if (!senderNumber) {\n      throw new Error(`Sender number ${senderNumberId} not found`);\n    }\n\n    const before = this.options.enableAuditLog ? { ...senderNumber } : undefined;\n    \n    // Apply updates\n    const updatedSenderNumber = {\n      ...senderNumber,\n      ...updates,\n      id: senderNumberId, // Ensure ID doesn't change\n      updatedAt: new Date()\n    };\n\n    this.senderNumbers.set(senderNumberId, updatedSenderNumber);\n\n    // Update in channel's sender numbers array\n    for (const channel of this.channels.values()) {\n      const index = channel.senderNumbers.findIndex(sn => sn.id === senderNumberId);\n      if (index !== -1) {\n        channel.senderNumbers[index] = updatedSenderNumber;\n        channel.updatedAt = new Date();\n        break;\n      }\n    }\n\n    // Audit log\n    if (this.options.enableAuditLog) {\n      this.addAuditLog('senderNumber', senderNumberId, 'update', userId, before, updatedSenderNumber);\n    }\n\n    // Event emission\n    if (this.options.enableEventEmission) {\n      this.emit('senderNumber:updated', { \n        senderNumber: updatedSenderNumber, \n        previousSenderNumber: senderNumber,\n        userId \n      });\n    }\n\n    return updatedSenderNumber;\n  }\n\n  async deleteSenderNumber(senderNumberId: string, userId?: string): Promise<boolean> {\n    const senderNumber = this.senderNumbers.get(senderNumberId);\n    if (!senderNumber) {\n      return false;\n    }\n\n    // Remove from memory\n    this.senderNumbers.delete(senderNumberId);\n\n    // Remove from channel's sender numbers array\n    for (const channel of this.channels.values()) {\n      const index = channel.senderNumbers.findIndex(sn => sn.id === senderNumberId);\n      if (index !== -1) {\n        channel.senderNumbers.splice(index, 1);\n        channel.updatedAt = new Date();\n        break;\n      }\n    }\n\n    // Audit log\n    if (this.options.enableAuditLog) {\n      this.addAuditLog('senderNumber', senderNumberId, 'delete', userId, senderNumber);\n    }\n\n    // Event emission\n    if (this.options.enableEventEmission) {\n      this.emit('senderNumber:deleted', { senderNumber, userId });\n    }\n\n    return true;\n  }\n\n  async listSenderNumbers(\n    filters: SenderNumberFilters = {},\n    pagination: PaginationOptions = { page: 1, limit: this.options.defaultPageSize! }\n  ): Promise<PaginatedResult<SenderNumber>> {\n    let senderNumbers = Array.from(this.senderNumbers.values());\n\n    // Apply filters\n    if (filters.channelId) {\n      const channel = this.channels.get(filters.channelId);\n      if (channel) {\n        senderNumbers = channel.senderNumbers;\n      } else {\n        senderNumbers = [];\n      }\n    }\n    if (filters.status) {\n      senderNumbers = senderNumbers.filter(sn => sn.status === filters.status);\n    }\n    if (filters.category) {\n      senderNumbers = senderNumbers.filter(sn => sn.category === filters.category);\n    }\n    if (filters.verified !== undefined) {\n      if (filters.verified) {\n        senderNumbers = senderNumbers.filter(sn => sn.status === SenderNumberStatus.VERIFIED);\n      } else {\n        senderNumbers = senderNumbers.filter(sn => sn.status !== SenderNumberStatus.VERIFIED);\n      }\n    }\n\n    // Apply sorting\n    const sortBy = pagination.sortBy || 'createdAt';\n    const sortOrder = pagination.sortOrder || 'desc';\n    \n    senderNumbers.sort((a, b) => {\n      let aValue: any, bValue: any;\n      \n      switch (sortBy) {\n        case 'phoneNumber':\n          aValue = a.phoneNumber;\n          bValue = b.phoneNumber;\n          break;\n        case 'createdAt':\n          aValue = a.createdAt.getTime();\n          bValue = b.createdAt.getTime();\n          break;\n        case 'updatedAt':\n          aValue = a.updatedAt.getTime();\n          bValue = b.updatedAt.getTime();\n          break;\n        default:\n          aValue = a.createdAt.getTime();\n          bValue = b.createdAt.getTime();\n      }\n\n      if (sortOrder === 'asc') {\n        return aValue < bValue ? -1 : aValue > bValue ? 1 : 0;\n      } else {\n        return aValue > bValue ? -1 : aValue < bValue ? 1 : 0;\n      }\n    });\n\n    // Apply pagination\n    const total = senderNumbers.length;\n    const limit = Math.min(pagination.limit, this.options.maxPageSize!);\n    const page = Math.max(1, pagination.page);\n    const offset = (page - 1) * limit;\n    const paginatedSenderNumbers = senderNumbers.slice(offset, offset + limit);\n\n    return {\n      data: paginatedSenderNumbers,\n      total,\n      page,\n      limit,\n      totalPages: Math.ceil(total / limit),\n      hasNext: offset + limit < total,\n      hasPrev: page > 1\n    };\n  }\n\n  // Audit and Analytics\n  getAuditLogs(\n    entityType?: 'channel' | 'senderNumber',\n    entityId?: string,\n    limit: number = 100\n  ): AuditLogEntry[] {\n    let logs = [...this.auditLogs];\n\n    if (entityType) {\n      logs = logs.filter(log => log.entityType === entityType);\n    }\n    if (entityId) {\n      logs = logs.filter(log => log.entityId === entityId);\n    }\n\n    return logs\n      .sort((a, b) => b.timestamp.getTime() - a.timestamp.getTime())\n      .slice(0, limit);\n  }\n\n  getStatistics(): {\n    channels: {\n      total: number;\n      byStatus: Record<string, number>;\n      byType: Record<string, number>;\n      byProvider: Record<string, number>;\n    };\n    senderNumbers: {\n      total: number;\n      byStatus: Record<string, number>;\n      byCategory: Record<string, number>;\n    };\n  } {\n    const channels = Array.from(this.channels.values());\n    const senderNumbers = Array.from(this.senderNumbers.values());\n\n    const channelsByStatus: Record<string, number> = {};\n    const channelsByType: Record<string, number> = {};\n    const channelsByProvider: Record<string, number> = {};\n\n    channels.forEach(channel => {\n      channelsByStatus[channel.status] = (channelsByStatus[channel.status] || 0) + 1;\n      channelsByType[channel.type] = (channelsByType[channel.type] || 0) + 1;\n      channelsByProvider[channel.provider] = (channelsByProvider[channel.provider] || 0) + 1;\n    });\n\n    const senderNumbersByStatus: Record<string, number> = {};\n    const senderNumbersByCategory: Record<string, number> = {};\n\n    senderNumbers.forEach(senderNumber => {\n      senderNumbersByStatus[senderNumber.status] = (senderNumbersByStatus[senderNumber.status] || 0) + 1;\n      senderNumbersByCategory[senderNumber.category] = (senderNumbersByCategory[senderNumber.category] || 0) + 1;\n    });\n\n    return {\n      channels: {\n        total: channels.length,\n        byStatus: channelsByStatus,\n        byType: channelsByType,\n        byProvider: channelsByProvider\n      },\n      senderNumbers: {\n        total: senderNumbers.length,\n        byStatus: senderNumbersByStatus,\n        byCategory: senderNumbersByCategory\n      }\n    };\n  }\n\n  // Cleanup and Maintenance\n  cleanup(): {\n    deletedChannels: number;\n    expiredAuditLogs: number;\n  } {\n    let deletedChannels = 0;\n    let expiredAuditLogs = 0;\n\n    // Clean up soft-deleted channels older than 30 days\n    const thirtyDaysAgo = new Date(Date.now() - 30 * 24 * 60 * 60 * 1000);\n    \n    for (const [id, channel] of this.channels) {\n      if (channel.status === ChannelStatus.DELETED && channel.updatedAt < thirtyDaysAgo) {\n        this.channels.delete(id);\n        deletedChannels++;\n      }\n    }\n\n    // Clean up audit logs older than 90 days\n    const ninetyDaysAgo = new Date(Date.now() - 90 * 24 * 60 * 60 * 1000);\n    const originalLogCount = this.auditLogs.length;\n    this.auditLogs = this.auditLogs.filter(log => log.timestamp >= ninetyDaysAgo);\n    expiredAuditLogs = originalLogCount - this.auditLogs.length;\n\n    return { deletedChannels, expiredAuditLogs };\n  }\n\n  destroy(): void {\n    if (this.cleanupTimer) {\n      clearInterval(this.cleanupTimer);\n      this.cleanupTimer = undefined;\n    }\n    \n    this.removeAllListeners();\n    this.channels.clear();\n    this.senderNumbers.clear();\n    this.auditLogs = [];\n  }\n\n  private addAuditLog(\n    entityType: 'channel' | 'senderNumber',\n    entityId: string,\n    action: AuditLogEntry['action'],\n    userId?: string,\n    before?: any,\n    after?: any\n  ): void {\n    const auditLog: AuditLogEntry = {\n      id: this.generateAuditLogId(),\n      entityType,\n      entityId,\n      action,\n      userId,\n      timestamp: new Date(),\n      changes: before || after ? { before, after } : undefined\n    };\n\n    this.auditLogs.push(auditLog);\n\n    // Keep only last 10000 audit logs to prevent memory issues\n    if (this.auditLogs.length > 10000) {\n      this.auditLogs = this.auditLogs.slice(-10000);\n    }\n  }\n\n  private getDefaultLimits(channelType: ChannelType) {\n    switch (channelType) {\n      case ChannelType.KAKAO_ALIMTALK:\n        return {\n          dailyMessageLimit: 10000,\n          monthlyMessageLimit: 300000,\n          rateLimit: 10\n        };\n      case ChannelType.KAKAO_FRIENDTALK:\n        return {\n          dailyMessageLimit: 1000,\n          monthlyMessageLimit: 30000,\n          rateLimit: 5\n        };\n      case ChannelType.SMS:\n      case ChannelType.LMS:\n      case ChannelType.MMS:\n        return {\n          dailyMessageLimit: 1000,\n          monthlyMessageLimit: 30000,\n          rateLimit: 3\n        };\n      default:\n        return {\n          dailyMessageLimit: 1000,\n          monthlyMessageLimit: 30000,\n          rateLimit: 1\n        };\n    }\n  }\n\n  private getDefaultFeatures(channelType: ChannelType) {\n    switch (channelType) {\n      case ChannelType.KAKAO_ALIMTALK:\n        return {\n          supportsBulkSending: true,\n          supportsScheduling: true,\n          supportsButtons: true,\n          maxButtonCount: 5\n        };\n      case ChannelType.KAKAO_FRIENDTALK:\n        return {\n          supportsBulkSending: true,\n          supportsScheduling: true,\n          supportsButtons: false,\n          maxButtonCount: 0\n        };\n      default:\n        return {\n          supportsBulkSending: false,\n          supportsScheduling: false,\n          supportsButtons: false,\n          maxButtonCount: 0\n        };\n    }\n  }\n\n  private startAutoCleanup(): void {\n    this.cleanupTimer = setInterval(() => {\n      this.cleanup();\n    }, this.options.cleanupInterval!);\n  }\n\n  private generateChannelId(): string {\n    return `ch_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;\n  }\n\n  private generateSenderNumberId(): string {\n    return `sn_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;\n  }\n\n  private generateAuditLogId(): string {\n    return `audit_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;\n  }\n}","/**\n * Permission Management System\n * 채널 및 발신번호 액세스 권한 관리\n */\n\nimport { EventEmitter } from 'events';\n\nexport interface User {\n  id: string;\n  email: string;\n  name: string;\n  roles: Role[];\n  isActive: boolean;\n  createdAt: Date;\n  updatedAt: Date;\n}\n\nexport interface Role {\n  id: string;\n  name: string;\n  permissions: Permission[];\n  description?: string;\n  isSystem: boolean;\n  createdAt: Date;\n  updatedAt: Date;\n}\n\nexport interface Permission {\n  id: string;\n  resource: ResourceType;\n  action: ActionType;\n  scope: PermissionScope;\n  conditions?: PermissionCondition[];\n}\n\nexport enum ResourceType {\n  CHANNEL = 'channel',\n  SENDER_NUMBER = 'senderNumber',\n  TEMPLATE = 'template',\n  MESSAGE = 'message',\n  USER = 'user',\n  ROLE = 'role',\n  AUDIT_LOG = 'auditLog',\n  ANALYTICS = 'analytics'\n}\n\nexport enum ActionType {\n  CREATE = 'create',\n  READ = 'read',\n  UPDATE = 'update',\n  DELETE = 'delete',\n  VERIFY = 'verify',\n  SUSPEND = 'suspend',\n  ACTIVATE = 'activate',\n  SEND = 'send',\n  MANAGE = 'manage'\n}\n\nexport enum PermissionScope {\n  GLOBAL = 'global',\n  ORGANIZATION = 'organization',\n  TEAM = 'team',\n  PERSONAL = 'personal'\n}\n\nexport interface PermissionCondition {\n  field: string;\n  operator: 'equals' | 'not_equals' | 'in' | 'not_in' | 'contains' | 'starts_with';\n  value: any;\n}\n\nexport interface AccessContext {\n  userId: string;\n  organizationId?: string;\n  teamId?: string;\n  resourceOwnerId?: string;\n  metadata?: Record<string, any>;\n}\n\nexport interface PermissionCheck {\n  userId: string;\n  resource: ResourceType;\n  action: ActionType;\n  resourceId?: string;\n  context?: AccessContext;\n}\n\nexport interface PermissionResult {\n  granted: boolean;\n  reason?: string;\n  matchedPermissions: Permission[];\n  deniedReasons: string[];\n}\n\nexport class PermissionManager extends EventEmitter {\n  private users = new Map<string, User>();\n  private roles = new Map<string, Role>();\n  private userRoleCache = new Map<string, Set<string>>();\n  private permissionCache = new Map<string, PermissionResult>();\n  private cacheExpiry = new Map<string, number>();\n\n  private readonly CACHE_DURATION = 5 * 60 * 1000; // 5 minutes\n\n  constructor() {\n    super();\n    this.initializeSystemRoles();\n  }\n\n  // User Management\n  async createUser(userData: Omit<User, 'id' | 'createdAt' | 'updatedAt'>): Promise<User> {\n    const userId = this.generateUserId();\n    \n    const user: User = {\n      ...userData,\n      id: userId,\n      createdAt: new Date(),\n      updatedAt: new Date()\n    };\n\n    this.users.set(userId, user);\n    this.updateUserRoleCache(userId, user.roles.map(r => r.id));\n\n    this.emit('user:created', { user });\n    return user;\n  }\n\n  async getUser(userId: string): Promise<User | null> {\n    return this.users.get(userId) || null;\n  }\n\n  async updateUser(userId: string, updates: Partial<User>): Promise<User> {\n    const user = this.users.get(userId);\n    if (!user) {\n      throw new Error('User not found');\n    }\n\n    const updatedUser = {\n      ...user,\n      ...updates,\n      id: userId,\n      updatedAt: new Date()\n    };\n\n    this.users.set(userId, updatedUser);\n\n    // Update role cache if roles changed\n    if (updates.roles) {\n      this.updateUserRoleCache(userId, updates.roles.map(r => r.id));\n    }\n\n    // Clear permission cache for this user\n    this.clearUserPermissionCache(userId);\n\n    this.emit('user:updated', { user: updatedUser, previousUser: user });\n    return updatedUser;\n  }\n\n  async deleteUser(userId: string): Promise<boolean> {\n    const user = this.users.get(userId);\n    if (!user) {\n      return false;\n    }\n\n    this.users.delete(userId);\n    this.userRoleCache.delete(userId);\n    this.clearUserPermissionCache(userId);\n\n    this.emit('user:deleted', { user });\n    return true;\n  }\n\n  // Role Management\n  async createRole(roleData: Omit<Role, 'id' | 'createdAt' | 'updatedAt'>): Promise<Role> {\n    const roleId = this.generateRoleId();\n    \n    const role: Role = {\n      ...roleData,\n      id: roleId,\n      createdAt: new Date(),\n      updatedAt: new Date()\n    };\n\n    this.roles.set(roleId, role);\n\n    this.emit('role:created', { role });\n    return role;\n  }\n\n  async getRole(roleId: string): Promise<Role | null> {\n    return this.roles.get(roleId) || null;\n  }\n\n  async updateRole(roleId: string, updates: Partial<Role>): Promise<Role> {\n    const role = this.roles.get(roleId);\n    if (!role) {\n      throw new Error('Role not found');\n    }\n\n    if (role.isSystem && updates.permissions) {\n      throw new Error('Cannot modify permissions of system roles');\n    }\n\n    const updatedRole = {\n      ...role,\n      ...updates,\n      id: roleId,\n      updatedAt: new Date()\n    };\n\n    this.roles.set(roleId, updatedRole);\n\n    // Clear permission cache for all users with this role\n    this.clearRolePermissionCache(roleId);\n\n    this.emit('role:updated', { role: updatedRole, previousRole: role });\n    return updatedRole;\n  }\n\n  async deleteRole(roleId: string): Promise<boolean> {\n    const role = this.roles.get(roleId);\n    if (!role) {\n      return false;\n    }\n\n    if (role.isSystem) {\n      throw new Error('Cannot delete system roles');\n    }\n\n    // Check if role is assigned to any users\n    const usersWithRole = Array.from(this.users.values())\n      .filter(user => user.roles.some(r => r.id === roleId));\n\n    if (usersWithRole.length > 0) {\n      throw new Error('Cannot delete role that is assigned to users');\n    }\n\n    this.roles.delete(roleId);\n\n    this.emit('role:deleted', { role });\n    return true;\n  }\n\n  // Permission Management\n  async assignRoleToUser(userId: string, roleId: string): Promise<void> {\n    const user = this.users.get(userId);\n    const role = this.roles.get(roleId);\n\n    if (!user) {\n      throw new Error('User not found');\n    }\n    if (!role) {\n      throw new Error('Role not found');\n    }\n\n    // Check if role is already assigned\n    if (user.roles.some(r => r.id === roleId)) {\n      return;\n    }\n\n    user.roles.push(role);\n    user.updatedAt = new Date();\n\n    this.updateUserRoleCache(userId, user.roles.map(r => r.id));\n    this.clearUserPermissionCache(userId);\n\n    this.emit('role:assigned', { userId, roleId });\n  }\n\n  async removeRoleFromUser(userId: string, roleId: string): Promise<void> {\n    const user = this.users.get(userId);\n    if (!user) {\n      throw new Error('User not found');\n    }\n\n    const roleIndex = user.roles.findIndex(r => r.id === roleId);\n    if (roleIndex === -1) {\n      return;\n    }\n\n    user.roles.splice(roleIndex, 1);\n    user.updatedAt = new Date();\n\n    this.updateUserRoleCache(userId, user.roles.map(r => r.id));\n    this.clearUserPermissionCache(userId);\n\n    this.emit('role:removed', { userId, roleId });\n  }\n\n  // Permission Checking\n  async checkPermission(check: PermissionCheck): Promise<PermissionResult> {\n    // Check cache first\n    const cacheKey = this.getCacheKey(check);\n    const cached = this.getFromCache(cacheKey);\n    if (cached) {\n      return cached;\n    }\n\n    const result = await this.performPermissionCheck(check);\n\n    // Cache the result\n    this.setCache(cacheKey, result);\n\n    return result;\n  }\n\n  async hasPermission(\n    userId: string,\n    resource: ResourceType,\n    action: ActionType,\n    resourceId?: string,\n    context?: AccessContext\n  ): Promise<boolean> {\n    const result = await this.checkPermission({\n      userId,\n      resource,\n      action,\n      resourceId,\n      context\n    });\n\n    return result.granted;\n  }\n\n  async requirePermission(\n    userId: string,\n    resource: ResourceType,\n    action: ActionType,\n    resourceId?: string,\n    context?: AccessContext\n  ): Promise<void> {\n    const hasAccess = await this.hasPermission(userId, resource, action, resourceId, context);\n    \n    if (!hasAccess) {\n      throw new Error(`Access denied: ${action} on ${resource}`);\n    }\n  }\n\n  // Utility Methods\n  async getUserPermissions(userId: string): Promise<Permission[]> {\n    const user = this.users.get(userId);\n    if (!user) {\n      return [];\n    }\n\n    const permissions: Permission[] = [];\n    \n    for (const role of user.roles) {\n      permissions.push(...role.permissions);\n    }\n\n    // Remove duplicates\n    const uniquePermissions = permissions.filter((permission, index, self) =>\n      index === self.findIndex(p => p.id === permission.id)\n    );\n\n    return uniquePermissions;\n  }\n\n  async getUserRoles(userId: string): Promise<Role[]> {\n    const user = this.users.get(userId);\n    return user ? user.roles : [];\n  }\n\n  listUsers(filters?: {\n    isActive?: boolean;\n    roleId?: string;\n  }): User[] {\n    let users = Array.from(this.users.values());\n\n    if (filters?.isActive !== undefined) {\n      users = users.filter(u => u.isActive === filters.isActive);\n    }\n\n    if (filters?.roleId) {\n      users = users.filter(u => u.roles.some(r => r.id === filters.roleId));\n    }\n\n    return users;\n  }\n\n  listRoles(): Role[] {\n    return Array.from(this.roles.values());\n  }\n\n  // Private Methods\n  private async performPermissionCheck(check: PermissionCheck): Promise<PermissionResult> {\n    const user = this.users.get(check.userId);\n    if (!user) {\n      return {\n        granted: false,\n        reason: 'User not found',\n        matchedPermissions: [],\n        deniedReasons: ['User not found']\n      };\n    }\n\n    if (!user.isActive) {\n      return {\n        granted: false,\n        reason: 'User is inactive',\n        matchedPermissions: [],\n        deniedReasons: ['User is inactive']\n      };\n    }\n\n    const matchedPermissions: Permission[] = [];\n    const deniedReasons: string[] = [];\n\n    // Check all user's roles\n    for (const role of user.roles) {\n      for (const permission of role.permissions) {\n        if (this.doesPermissionMatch(permission, check)) {\n          // Check conditions\n          if (await this.checkConditions(permission, check)) {\n            matchedPermissions.push(permission);\n          } else {\n            deniedReasons.push(`Conditions not met for permission ${permission.id}`);\n          }\n        }\n      }\n    }\n\n    const granted = matchedPermissions.length > 0;\n\n    return {\n      granted,\n      reason: granted ? undefined : 'No matching permissions found',\n      matchedPermissions,\n      deniedReasons: granted ? [] : deniedReasons\n    };\n  }\n\n  private doesPermissionMatch(permission: Permission, check: PermissionCheck): boolean {\n    return permission.resource === check.resource && permission.action === check.action;\n  }\n\n  private async checkConditions(permission: Permission, check: PermissionCheck): Promise<boolean> {\n    if (!permission.conditions || permission.conditions.length === 0) {\n      return true;\n    }\n\n    // For simplicity, all conditions must be met (AND logic)\n    for (const condition of permission.conditions) {\n      if (!await this.evaluateCondition(condition, check)) {\n        return false;\n      }\n    }\n\n    return true;\n  }\n\n  private async evaluateCondition(condition: PermissionCondition, check: PermissionCheck): Promise<boolean> {\n    let actualValue: any;\n\n    // Get the actual value based on the field\n    switch (condition.field) {\n      case 'userId':\n        actualValue = check.userId;\n        break;\n      case 'organizationId':\n        actualValue = check.context?.organizationId;\n        break;\n      case 'teamId':\n        actualValue = check.context?.teamId;\n        break;\n      case 'resourceOwnerId':\n        actualValue = check.context?.resourceOwnerId;\n        break;\n      default:\n        actualValue = check.context?.metadata?.[condition.field];\n    }\n\n    // Evaluate the condition\n    switch (condition.operator) {\n      case 'equals':\n        return actualValue === condition.value;\n      case 'not_equals':\n        return actualValue !== condition.value;\n      case 'in':\n        return Array.isArray(condition.value) && condition.value.includes(actualValue);\n      case 'not_in':\n        return Array.isArray(condition.value) && !condition.value.includes(actualValue);\n      case 'contains':\n        return String(actualValue).includes(String(condition.value));\n      case 'starts_with':\n        return String(actualValue).startsWith(String(condition.value));\n      default:\n        return false;\n    }\n  }\n\n  private initializeSystemRoles(): void {\n    // Super Admin Role\n    const superAdminRole: Role = {\n      id: 'super-admin',\n      name: 'Super Admin',\n      description: 'Full system access',\n      isSystem: true,\n      permissions: [\n        // Global permissions for all resources and actions\n        ...Object.values(ResourceType).flatMap(resource =>\n          Object.values(ActionType).map(action => ({\n            id: `super-admin-${resource}-${action}`,\n            resource,\n            action,\n            scope: PermissionScope.GLOBAL\n          }))\n        )\n      ],\n      createdAt: new Date(),\n      updatedAt: new Date()\n    };\n\n    // Channel Admin Role\n    const channelAdminRole: Role = {\n      id: 'channel-admin',\n      name: 'Channel Admin',\n      description: 'Manage channels and sender numbers',\n      isSystem: true,\n      permissions: [\n        {\n          id: 'channel-admin-channel-manage',\n          resource: ResourceType.CHANNEL,\n          action: ActionType.MANAGE,\n          scope: PermissionScope.ORGANIZATION\n        },\n        {\n          id: 'channel-admin-sender-manage',\n          resource: ResourceType.SENDER_NUMBER,\n          action: ActionType.MANAGE,\n          scope: PermissionScope.ORGANIZATION\n        }\n      ],\n      createdAt: new Date(),\n      updatedAt: new Date()\n    };\n\n    // Message Sender Role\n    const messageSenderRole: Role = {\n      id: 'message-sender',\n      name: 'Message Sender',\n      description: 'Send messages using configured channels',\n      isSystem: true,\n      permissions: [\n        {\n          id: 'message-sender-channel-read',\n          resource: ResourceType.CHANNEL,\n          action: ActionType.READ,\n          scope: PermissionScope.ORGANIZATION\n        },\n        {\n          id: 'message-sender-message-send',\n          resource: ResourceType.MESSAGE,\n          action: ActionType.SEND,\n          scope: PermissionScope.ORGANIZATION\n        }\n      ],\n      createdAt: new Date(),\n      updatedAt: new Date()\n    };\n\n    // Viewer Role\n    const viewerRole: Role = {\n      id: 'viewer',\n      name: 'Viewer',\n      description: 'Read-only access',\n      isSystem: true,\n      permissions: [\n        {\n          id: 'viewer-channel-read',\n          resource: ResourceType.CHANNEL,\n          action: ActionType.READ,\n          scope: PermissionScope.ORGANIZATION\n        },\n        {\n          id: 'viewer-sender-read',\n          resource: ResourceType.SENDER_NUMBER,\n          action: ActionType.READ,\n          scope: PermissionScope.ORGANIZATION\n        },\n        {\n          id: 'viewer-analytics-read',\n          resource: ResourceType.ANALYTICS,\n          action: ActionType.READ,\n          scope: PermissionScope.ORGANIZATION\n        }\n      ],\n      createdAt: new Date(),\n      updatedAt: new Date()\n    };\n\n    this.roles.set(superAdminRole.id, superAdminRole);\n    this.roles.set(channelAdminRole.id, channelAdminRole);\n    this.roles.set(messageSenderRole.id, messageSenderRole);\n    this.roles.set(viewerRole.id, viewerRole);\n  }\n\n  private updateUserRoleCache(userId: string, roleIds: string[]): void {\n    this.userRoleCache.set(userId, new Set(roleIds));\n  }\n\n  private clearUserPermissionCache(userId: string): void {\n    const keysToDelete: string[] = [];\n    \n    for (const key of this.permissionCache.keys()) {\n      if (key.startsWith(`${userId}:`)) {\n        keysToDelete.push(key);\n      }\n    }\n\n    keysToDelete.forEach(key => {\n      this.permissionCache.delete(key);\n      this.cacheExpiry.delete(key);\n    });\n  }\n\n  private clearRolePermissionCache(roleId: string): void {\n    // Find all users with this role and clear their cache\n    for (const [userId, roleIds] of this.userRoleCache) {\n      if (roleIds.has(roleId)) {\n        this.clearUserPermissionCache(userId);\n      }\n    }\n  }\n\n  private getCacheKey(check: PermissionCheck): string {\n    const contextKey = check.context ? JSON.stringify(check.context) : '';\n    return `${check.userId}:${check.resource}:${check.action}:${check.resourceId || ''}:${contextKey}`;\n  }\n\n  private getFromCache(key: string): PermissionResult | null {\n    const expiry = this.cacheExpiry.get(key);\n    if (!expiry || expiry < Date.now()) {\n      this.permissionCache.delete(key);\n      this.cacheExpiry.delete(key);\n      return null;\n    }\n\n    return this.permissionCache.get(key) || null;\n  }\n\n  private setCache(key: string, result: PermissionResult): void {\n    this.permissionCache.set(key, result);\n    this.cacheExpiry.set(key, Date.now() + this.CACHE_DURATION);\n  }\n\n  private generateUserId(): string {\n    return `user_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;\n  }\n\n  private generateRoleId(): string {\n    return `role_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;\n  }\n}","/**\n * Business Verification System\n * 사업자 정보 및 서류 검증 시스템\n */\n\nimport { EventEmitter } from 'events';\nimport {\n  VerificationDocument,\n  DocumentType,\n  DocumentStatus,\n  VerificationStatus,\n  Channel\n} from '../types/channel.types';\n\nexport interface BusinessInfo {\n  businessName: string;\n  businessRegistrationNumber: string;\n  businessType: 'corporation' | 'individual' | 'partnership' | 'other';\n  industry: string;\n  establishedDate: Date;\n  address: {\n    street: string;\n    city: string;\n    state: string;\n    postalCode: string;\n    country: string;\n  };\n  contactInfo: {\n    phoneNumber: string;\n    email: string;\n    website?: string;\n  };\n  representatives: Array<{\n    name: string;\n    position: string;\n    phoneNumber: string;\n    email: string;\n  }>;\n}\n\nexport interface VerificationRequest {\n  id: string;\n  channelId: string;\n  businessInfo: BusinessInfo;\n  documents: VerificationDocument[];\n  status: VerificationStatus;\n  submittedAt: Date;\n  reviewedAt?: Date;\n  reviewedBy?: string;\n  reviewNotes?: string;\n  autoVerificationResults?: AutoVerificationResult[];\n}\n\nexport interface AutoVerificationResult {\n  checkType: 'business_registry' | 'document_validation' | 'address_verification' | 'phone_verification';\n  status: 'passed' | 'failed' | 'warning';\n  score: number; // 0-100\n  details: string;\n  metadata?: Record<string, any>;\n}\n\nexport interface DocumentValidationResult {\n  isValid: boolean;\n  confidence: number; // 0-100\n  extractedData?: Record<string, any>;\n  issues: Array<{\n    type: 'format' | 'content' | 'quality' | 'authenticity';\n    severity: 'low' | 'medium' | 'high' | 'critical';\n    message: string;\n  }>;\n}\n\nexport interface BusinessVerifierOptions {\n  enableAutoVerification: boolean;\n  requiredDocuments: DocumentType[];\n  autoApprovalThreshold: number; // 0-100\n  requireManualReview: boolean;\n  documentRetentionDays: number;\n  enableExternalAPIs: boolean;\n  externalAPIConfig?: {\n    businessRegistryAPI?: string;\n    addressVerificationAPI?: string;\n    documentOCRAPI?: string;\n  };\n}\n\nexport class BusinessVerifier extends EventEmitter {\n  private verificationRequests = new Map<string, VerificationRequest>();\n  private documentValidators = new Map<DocumentType, (doc: VerificationDocument) => Promise<DocumentValidationResult>>();\n\n  private defaultOptions: BusinessVerifierOptions = {\n    enableAutoVerification: true,\n    requiredDocuments: [DocumentType.BUSINESS_REGISTRATION],\n    autoApprovalThreshold: 80,\n    requireManualReview: false,\n    documentRetentionDays: 365,\n    enableExternalAPIs: false\n  };\n\n  constructor(private options: Partial<BusinessVerifierOptions> = {}) {\n    super();\n    this.options = { ...this.defaultOptions, ...options };\n    this.initializeDocumentValidators();\n  }\n\n  /**\n   * Submit business verification request\n   */\n  async submitVerification(\n    channelId: string,\n    businessInfo: BusinessInfo,\n    documents: VerificationDocument[]\n  ): Promise<VerificationRequest> {\n    const requestId = this.generateRequestId();\n    \n    // Validate required documents\n    this.validateRequiredDocuments(documents);\n\n    const verificationRequest: VerificationRequest = {\n      id: requestId,\n      channelId,\n      businessInfo,\n      documents: documents.map(doc => ({\n        ...doc,\n        status: DocumentStatus.UPLOADED\n      })),\n      status: VerificationStatus.PENDING,\n      submittedAt: new Date()\n    };\n\n    this.verificationRequests.set(requestId, verificationRequest);\n\n    this.emit('verification:submitted', { verificationRequest });\n\n    // Start verification process\n    if (this.options.enableAutoVerification) {\n      await this.processAutoVerification(requestId);\n    }\n\n    return verificationRequest;\n  }\n\n  /**\n   * Get verification request by ID\n   */\n  getVerificationRequest(requestId: string): VerificationRequest | null {\n    return this.verificationRequests.get(requestId) || null;\n  }\n\n  /**\n   * Get verification request by channel ID\n   */\n  getVerificationByChannelId(channelId: string): VerificationRequest | null {\n    for (const request of this.verificationRequests.values()) {\n      if (request.channelId === channelId) {\n        return request;\n      }\n    }\n    return null;\n  }\n\n  /**\n   * Manually approve verification\n   */\n  async approveVerification(\n    requestId: string,\n    reviewerId: string,\n    notes?: string\n  ): Promise<VerificationRequest> {\n    const request = this.verificationRequests.get(requestId);\n    if (!request) {\n      throw new Error('Verification request not found');\n    }\n\n    request.status = VerificationStatus.VERIFIED;\n    request.reviewedAt = new Date();\n    request.reviewedBy = reviewerId;\n    request.reviewNotes = notes;\n\n    // Mark all documents as verified\n    request.documents.forEach(doc => {\n      doc.status = DocumentStatus.VERIFIED;\n    });\n\n    this.emit('verification:approved', { verificationRequest: request, reviewerId });\n\n    return request;\n  }\n\n  /**\n   * Manually reject verification\n   */\n  async rejectVerification(\n    requestId: string,\n    reviewerId: string,\n    reason: string\n  ): Promise<VerificationRequest> {\n    const request = this.verificationRequests.get(requestId);\n    if (!request) {\n      throw new Error('Verification request not found');\n    }\n\n    request.status = VerificationStatus.REJECTED;\n    request.reviewedAt = new Date();\n    request.reviewedBy = reviewerId;\n    request.reviewNotes = reason;\n\n    // Mark problematic documents as rejected\n    request.documents.forEach(doc => {\n      if (doc.status === DocumentStatus.UPLOADED) {\n        doc.status = DocumentStatus.REJECTED;\n      }\n    });\n\n    this.emit('verification:rejected', { verificationRequest: request, reviewerId, reason });\n\n    return request;\n  }\n\n  /**\n   * Update verification request with additional documents\n   */\n  async addDocument(\n    requestId: string,\n    document: VerificationDocument\n  ): Promise<VerificationRequest> {\n    const request = this.verificationRequests.get(requestId);\n    if (!request) {\n      throw new Error('Verification request not found');\n    }\n\n    if (request.status !== VerificationStatus.PENDING && request.status !== VerificationStatus.UNDER_REVIEW) {\n      throw new Error('Cannot add documents to completed verification');\n    }\n\n    document.status = DocumentStatus.UPLOADED;\n    request.documents.push(document);\n\n    // If auto verification is enabled, re-process\n    if (this.options.enableAutoVerification) {\n      await this.processAutoVerification(requestId);\n    }\n\n    this.emit('verification:document_added', { verificationRequest: request, document });\n\n    return request;\n  }\n\n  /**\n   * List verification requests with filters\n   */\n  listVerificationRequests(filters?: {\n    status?: VerificationStatus;\n    channelId?: string;\n    submittedAfter?: Date;\n    submittedBefore?: Date;\n  }): VerificationRequest[] {\n    let requests = Array.from(this.verificationRequests.values());\n\n    if (filters?.status) {\n      requests = requests.filter(r => r.status === filters.status);\n    }\n    if (filters?.channelId) {\n      requests = requests.filter(r => r.channelId === filters.channelId);\n    }\n    if (filters?.submittedAfter) {\n      requests = requests.filter(r => r.submittedAt >= filters.submittedAfter!);\n    }\n    if (filters?.submittedBefore) {\n      requests = requests.filter(r => r.submittedAt <= filters.submittedBefore!);\n    }\n\n    return requests.sort((a, b) => b.submittedAt.getTime() - a.submittedAt.getTime());\n  }\n\n  /**\n   * Get verification statistics\n   */\n  getVerificationStats(): {\n    total: number;\n    byStatus: Record<string, number>;\n    averageProcessingTime: number;\n    autoApprovalRate: number;\n  } {\n    const requests = Array.from(this.verificationRequests.values());\n    \n    const byStatus: Record<string, number> = {};\n    let totalProcessingTime = 0;\n    let processedCount = 0;\n    let autoApprovedCount = 0;\n\n    requests.forEach(request => {\n      byStatus[request.status] = (byStatus[request.status] || 0) + 1;\n\n      if (request.reviewedAt) {\n        const processingTime = request.reviewedAt.getTime() - request.submittedAt.getTime();\n        totalProcessingTime += processingTime;\n        processedCount++;\n\n        // Check if it was auto-approved (no manual reviewer)\n        if (!request.reviewedBy && request.status === VerificationStatus.VERIFIED) {\n          autoApprovedCount++;\n        }\n      }\n    });\n\n    return {\n      total: requests.length,\n      byStatus,\n      averageProcessingTime: processedCount > 0 ? totalProcessingTime / processedCount : 0,\n      autoApprovalRate: processedCount > 0 ? (autoApprovedCount / processedCount) * 100 : 0\n    };\n  }\n\n  // Private Methods\n  private async processAutoVerification(requestId: string): Promise<void> {\n    const request = this.verificationRequests.get(requestId);\n    if (!request) return;\n\n    request.status = VerificationStatus.UNDER_REVIEW;\n    this.emit('verification:auto_processing_started', { verificationRequest: request });\n\n    const autoResults: AutoVerificationResult[] = [];\n\n    try {\n      // 1. Validate business registration\n      const businessCheck = await this.verifyBusinessRegistration(request.businessInfo);\n      autoResults.push(businessCheck);\n\n      // 2. Validate documents\n      for (const document of request.documents) {\n        const docValidation = await this.validateDocument(document);\n        autoResults.push({\n          checkType: 'document_validation',\n          status: docValidation.isValid ? 'passed' : 'failed',\n          score: docValidation.confidence,\n          details: `Document validation: ${docValidation.issues.length} issues found`,\n          metadata: { documentId: document.id, issues: docValidation.issues }\n        });\n      }\n\n      // 3. Verify address\n      const addressCheck = await this.verifyAddress(request.businessInfo.address);\n      autoResults.push(addressCheck);\n\n      // 4. Verify phone number\n      const phoneCheck = await this.verifyPhoneNumber(request.businessInfo.contactInfo.phoneNumber);\n      autoResults.push(phoneCheck);\n\n      request.autoVerificationResults = autoResults;\n\n      // Calculate overall score\n      const overallScore = autoResults.reduce((sum, result) => sum + result.score, 0) / autoResults.length;\n\n      // Auto-approve if score is high enough\n      if (overallScore >= this.options.autoApprovalThreshold! && !this.options.requireManualReview) {\n        request.status = VerificationStatus.VERIFIED;\n        request.reviewedAt = new Date();\n        request.reviewNotes = `Auto-approved with score: ${overallScore.toFixed(1)}`;\n\n        // Mark documents as verified\n        request.documents.forEach(doc => {\n          doc.status = DocumentStatus.VERIFIED;\n        });\n\n        this.emit('verification:auto_approved', { verificationRequest: request, score: overallScore });\n      } else {\n        // Requires manual review\n        this.emit('verification:manual_review_required', { verificationRequest: request, score: overallScore });\n      }\n\n    } catch (error) {\n      request.status = VerificationStatus.PENDING;\n      this.emit('verification:auto_processing_failed', { \n        verificationRequest: request, \n        error: error instanceof Error ? error.message : 'Unknown error' \n      });\n    }\n  }\n\n  private validateRequiredDocuments(documents: VerificationDocument[]): void {\n    const providedTypes = new Set(documents.map(doc => doc.type));\n    const missingTypes = this.options.requiredDocuments!.filter(type => !providedTypes.has(type));\n\n    if (missingTypes.length > 0) {\n      throw new Error(`Missing required documents: ${missingTypes.join(', ')}`);\n    }\n  }\n\n  private async verifyBusinessRegistration(businessInfo: BusinessInfo): Promise<AutoVerificationResult> {\n    // In a real implementation, this would call external business registry APIs\n    // For demo purposes, we'll simulate the verification\n    \n    const score = this.calculateBusinessRegistrationScore(businessInfo);\n    \n    return {\n      checkType: 'business_registry',\n      status: score >= 70 ? 'passed' : score >= 50 ? 'warning' : 'failed',\n      score,\n      details: `Business registration verification completed`,\n      metadata: {\n        businessName: businessInfo.businessName,\n        registrationNumber: businessInfo.businessRegistrationNumber\n      }\n    };\n  }\n\n  private calculateBusinessRegistrationScore(businessInfo: BusinessInfo): number {\n    let score = 0;\n\n    // Check business registration number format (Korean format)\n    if (/^\\d{3}-\\d{2}-\\d{5}$/.test(businessInfo.businessRegistrationNumber)) {\n      score += 30;\n    }\n\n    // Check if business name is reasonable\n    if (businessInfo.businessName.length >= 2 && businessInfo.businessName.length <= 100) {\n      score += 20;\n    }\n\n    // Check if established date is reasonable\n    const now = new Date();\n    const establishedDate = new Date(businessInfo.establishedDate);\n    const yearsOld = (now.getTime() - establishedDate.getTime()) / (1000 * 60 * 60 * 24 * 365);\n    \n    if (yearsOld >= 0 && yearsOld <= 100) {\n      score += 20;\n    }\n\n    // Check contact information completeness\n    if (businessInfo.contactInfo.email && businessInfo.contactInfo.phoneNumber) {\n      score += 15;\n    }\n\n    // Check address completeness\n    if (businessInfo.address.street && businessInfo.address.city && businessInfo.address.postalCode) {\n      score += 15;\n    }\n\n    return Math.min(100, score);\n  }\n\n  private async validateDocument(document: VerificationDocument): Promise<DocumentValidationResult> {\n    const validator = this.documentValidators.get(document.type);\n    if (!validator) {\n      return {\n        isValid: false,\n        confidence: 0,\n        issues: [{\n          type: 'format',\n          severity: 'critical',\n          message: `No validator available for document type: ${document.type}`\n        }]\n      };\n    }\n\n    return await validator(document);\n  }\n\n  private async verifyAddress(address: BusinessInfo['address']): Promise<AutoVerificationResult> {\n    // Simulate address verification\n    let score = 0;\n\n    if (address.street && address.city && address.postalCode) {\n      score += 40;\n    }\n\n    // Check postal code format (Korean format)\n    if (/^\\d{5}$/.test(address.postalCode)) {\n      score += 30;\n    }\n\n    if (address.country === 'KR' || address.country === 'Korea') {\n      score += 30;\n    }\n\n    return {\n      checkType: 'address_verification',\n      status: score >= 70 ? 'passed' : score >= 50 ? 'warning' : 'failed',\n      score,\n      details: 'Address verification completed',\n      metadata: { address }\n    };\n  }\n\n  private async verifyPhoneNumber(phoneNumber: string): Promise<AutoVerificationResult> {\n    // Korean phone number validation\n    const isValidFormat = /^(010|011|016|017|018|019)[0-9]{7,8}$/.test(phoneNumber);\n    \n    const score = isValidFormat ? 100 : 0;\n\n    return {\n      checkType: 'phone_verification',\n      status: isValidFormat ? 'passed' : 'failed',\n      score,\n      details: isValidFormat ? 'Phone number format is valid' : 'Invalid phone number format',\n      metadata: { phoneNumber }\n    };\n  }\n\n  private initializeDocumentValidators(): void {\n    // Business Registration Document Validator\n    this.documentValidators.set(DocumentType.BUSINESS_REGISTRATION, async (doc) => {\n      const issues: DocumentValidationResult['issues'] = [];\n      let confidence = 80; // Base confidence\n\n      // Check file extension\n      if (!doc.fileName.match(/\\.(pdf|jpg|jpeg|png)$/i)) {\n        issues.push({\n          type: 'format',\n          severity: 'medium',\n          message: 'Unsupported file format'\n        });\n        confidence -= 20;\n      }\n\n      // In a real implementation, would use OCR to extract and validate content\n      \n      return {\n        isValid: issues.length === 0 || issues.every(i => i.severity !== 'critical'),\n        confidence: Math.max(0, confidence),\n        issues\n      };\n    });\n\n    // Business License Document Validator\n    this.documentValidators.set(DocumentType.BUSINESS_LICENSE, async (doc) => {\n      const issues: DocumentValidationResult['issues'] = [];\n      let confidence = 75;\n\n      if (!doc.fileName.match(/\\.(pdf|jpg|jpeg|png)$/i)) {\n        issues.push({\n          type: 'format',\n          severity: 'medium',\n          message: 'Unsupported file format'\n        });\n        confidence -= 15;\n      }\n\n      return {\n        isValid: issues.length === 0 || issues.every(i => i.severity !== 'critical'),\n        confidence: Math.max(0, confidence),\n        issues\n      };\n    });\n\n    // ID Card Document Validator\n    this.documentValidators.set(DocumentType.ID_CARD, async (doc) => {\n      const issues: DocumentValidationResult['issues'] = [];\n      let confidence = 70;\n\n      if (!doc.fileName.match(/\\.(jpg|jpeg|png)$/i)) {\n        issues.push({\n          type: 'format',\n          severity: 'high',\n          message: 'ID card should be an image file'\n        });\n        confidence -= 30;\n      }\n\n      return {\n        isValid: issues.length === 0 || issues.every(i => i.severity !== 'critical'),\n        confidence: Math.max(0, confidence),\n        issues\n      };\n    });\n\n    // Default validator for other document types\n    const defaultValidator = async (doc: VerificationDocument): Promise<DocumentValidationResult> => {\n      const issues: DocumentValidationResult['issues'] = [];\n      let confidence = 60; // Lower confidence for unknown document types\n\n      if (!doc.fileName || doc.fileName.length === 0) {\n        issues.push({\n          type: 'format',\n          severity: 'critical',\n          message: 'File name is required'\n        });\n        confidence = 0;\n      }\n\n      return {\n        isValid: issues.length === 0 || issues.every(i => i.severity !== 'critical'),\n        confidence: Math.max(0, confidence),\n        issues\n      };\n    };\n\n    this.documentValidators.set(DocumentType.AUTHORIZATION_LETTER, defaultValidator);\n    this.documentValidators.set(DocumentType.OTHER, defaultValidator);\n  }\n\n  private generateRequestId(): string {\n    return `biz_verify_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;\n  }\n}","/**\n * Phone Number Verification System\n * 발신번호 인증 및 검증 시스템\n */\n\nimport { EventEmitter } from 'events';\nimport { SenderNumber, SenderNumberStatus, SenderNumberCategory } from '../types/channel.types';\n\nexport interface PhoneVerificationRequest {\n  id: string;\n  senderNumberId: string;\n  phoneNumber: string;\n  verificationType: VerificationType;\n  verificationCode: string;\n  status: PhoneVerificationStatus;\n  attempts: VerificationAttempt[];\n  expiresAt: Date;\n  createdAt: Date;\n  completedAt?: Date;\n  metadata: {\n    userAgent?: string;\n    ipAddress?: string;\n    deviceId?: string;\n    smsProvider?: string;\n    callProvider?: string;\n  };\n}\n\nexport interface VerificationAttempt {\n  attemptNumber: number;\n  attemptedAt: Date;\n  method: VerificationMethod;\n  status: 'sent' | 'delivered' | 'failed' | 'verified' | 'expired';\n  failureReason?: string;\n  responseTime?: number; // in milliseconds\n}\n\nexport enum VerificationType {\n  SMS = 'sms',\n  VOICE_CALL = 'voice_call',\n  HYBRID = 'hybrid' // Try SMS first, fallback to voice\n}\n\nexport enum VerificationMethod {\n  SMS = 'sms',\n  VOICE_CALL = 'voice_call',\n  MISSED_CALL = 'missed_call'\n}\n\nexport enum PhoneVerificationStatus {\n  PENDING = 'pending',\n  CODE_SENT = 'code_sent',\n  VERIFIED = 'verified',\n  FAILED = 'failed',\n  EXPIRED = 'expired',\n  BLOCKED = 'blocked'\n}\n\nexport interface NumberVerifierOptions {\n  codeLength: number;\n  codeExpiryMinutes: number;\n  maxAttempts: number;\n  maxDailyAttempts: number;\n  smsTemplate: string;\n  voiceTemplate: string;\n  rateLimitMinutes: number;\n  enableVoiceFallback: boolean;\n  enableMissedCallVerification: boolean;\n  blockedNumbers: string[];\n  allowedCountries: string[];\n  smsProvider?: SMSProvider;\n  voiceProvider?: VoiceProvider;\n}\n\nexport interface SMSProvider {\n  id: string;\n  name: string;\n  sendSMS(phoneNumber: string, message: string, options?: any): Promise<SMSResult>;\n  getDeliveryStatus?(messageId: string): Promise<DeliveryStatus>;\n}\n\nexport interface VoiceProvider {\n  id: string;\n  name: string;\n  makeCall(phoneNumber: string, message: string, options?: any): Promise<VoiceResult>;\n  makeMissedCall?(phoneNumber: string, options?: any): Promise<MissedCallResult>;\n}\n\nexport interface SMSResult {\n  messageId: string;\n  status: 'sent' | 'failed';\n  cost?: number;\n  error?: string;\n}\n\nexport interface VoiceResult {\n  callId: string;\n  status: 'initiated' | 'answered' | 'failed' | 'busy' | 'no_answer';\n  duration?: number;\n  cost?: number;\n  error?: string;\n}\n\nexport interface MissedCallResult {\n  callId: string;\n  status: 'initiated' | 'completed' | 'failed';\n  missedCallNumber?: string;\n  error?: string;\n}\n\nexport interface DeliveryStatus {\n  messageId: string;\n  status: 'pending' | 'delivered' | 'failed' | 'expired';\n  deliveredAt?: Date;\n  failureReason?: string;\n}\n\nexport interface PhoneNumberInfo {\n  phoneNumber: string;\n  countryCode: string;\n  nationalNumber: string;\n  carrier?: string;\n  lineType?: 'mobile' | 'landline' | 'voip' | 'unknown';\n  isValid: boolean;\n  isPossible: boolean;\n  region?: string;\n}\n\nexport class NumberVerifier extends EventEmitter {\n  private verificationRequests = new Map<string, PhoneVerificationRequest>();\n  private phoneNumberCache = new Map<string, PhoneNumberInfo>();\n  private rateLimitTracker = new Map<string, Date[]>();\n  private dailyAttemptTracker = new Map<string, { date: string; count: number }>();\n  private blockedNumbers = new Set<string>();\n\n  private defaultOptions: NumberVerifierOptions = {\n    codeLength: 6,\n    codeExpiryMinutes: 5,\n    maxAttempts: 3,\n    maxDailyAttempts: 10,\n    smsTemplate: '인증번호: {code}. {expiry}분 내에 입력해주세요.',\n    voiceTemplate: '인증번호는 {code}입니다. 다시 한 번, {code}입니다.',\n    rateLimitMinutes: 1,\n    enableVoiceFallback: true,\n    enableMissedCallVerification: false,\n    blockedNumbers: [],\n    allowedCountries: ['KR']\n  };\n\n  constructor(private options: Partial<NumberVerifierOptions> = {}) {\n    super();\n    this.options = { ...this.defaultOptions, ...options };\n    \n    // Initialize blocked numbers\n    this.options.blockedNumbers?.forEach(number => {\n      this.blockedNumbers.add(number);\n    });\n  }\n\n  /**\n   * Start phone number verification process\n   */\n  async startVerification(\n    senderNumberId: string,\n    phoneNumber: string,\n    verificationType: VerificationType = VerificationType.SMS,\n    metadata: PhoneVerificationRequest['metadata'] = {}\n  ): Promise<PhoneVerificationRequest> {\n    // Validate phone number\n    const phoneInfo = await this.getPhoneNumberInfo(phoneNumber);\n    if (!phoneInfo.isValid) {\n      throw new Error('Invalid phone number format');\n    }\n\n    // Check if number is blocked\n    if (this.isNumberBlocked(phoneNumber)) {\n      throw new Error('Phone number is blocked');\n    }\n\n    // Check rate limiting\n    if (this.isRateLimited(phoneNumber)) {\n      throw new Error('Rate limit exceeded. Please try again later.');\n    }\n\n    // Check daily attempt limit\n    if (this.isDailyLimitExceeded(phoneNumber)) {\n      throw new Error('Daily verification attempt limit exceeded');\n    }\n\n    const requestId = this.generateRequestId();\n    const verificationCode = this.generateVerificationCode();\n    const expiresAt = new Date(Date.now() + this.options.codeExpiryMinutes! * 60 * 1000);\n\n    const verificationRequest: PhoneVerificationRequest = {\n      id: requestId,\n      senderNumberId,\n      phoneNumber,\n      verificationType,\n      verificationCode,\n      status: PhoneVerificationStatus.PENDING,\n      attempts: [],\n      expiresAt,\n      createdAt: new Date(),\n      metadata\n    };\n\n    this.verificationRequests.set(requestId, verificationRequest);\n    this.updateRateLimit(phoneNumber);\n    this.updateDailyAttempts(phoneNumber);\n\n    this.emit('verification:started', { verificationRequest, phoneInfo });\n\n    // Send verification code\n    await this.sendVerificationCode(verificationRequest, phoneInfo);\n\n    return verificationRequest;\n  }\n\n  /**\n   * Verify the provided code\n   */\n  async verifyCode(requestId: string, providedCode: string): Promise<{\n    success: boolean;\n    status: PhoneVerificationStatus;\n    message: string;\n  }> {\n    const request = this.verificationRequests.get(requestId);\n    if (!request) {\n      return {\n        success: false,\n        status: PhoneVerificationStatus.FAILED,\n        message: 'Verification request not found'\n      };\n    }\n\n    // Check if already verified\n    if (request.status === PhoneVerificationStatus.VERIFIED) {\n      return {\n        success: true,\n        status: PhoneVerificationStatus.VERIFIED,\n        message: 'Already verified'\n      };\n    }\n\n    // Check if expired\n    if (new Date() > request.expiresAt) {\n      request.status = PhoneVerificationStatus.EXPIRED;\n      this.emit('verification:expired', { verificationRequest: request });\n      \n      return {\n        success: false,\n        status: PhoneVerificationStatus.EXPIRED,\n        message: 'Verification code has expired'\n      };\n    }\n\n    // Check if blocked due to too many attempts\n    if (request.status === PhoneVerificationStatus.BLOCKED) {\n      return {\n        success: false,\n        status: PhoneVerificationStatus.BLOCKED,\n        message: 'Verification blocked due to too many failed attempts'\n      };\n    }\n\n    // Verify code\n    const isCodeValid = this.validateCode(request.verificationCode, providedCode);\n    \n    if (isCodeValid) {\n      request.status = PhoneVerificationStatus.VERIFIED;\n      request.completedAt = new Date();\n\n      this.emit('verification:success', { verificationRequest: request });\n\n      return {\n        success: true,\n        status: PhoneVerificationStatus.VERIFIED,\n        message: 'Phone number verified successfully'\n      };\n    } else {\n      // Add failed verification attempt\n      const failedAttempt: VerificationAttempt = {\n        attemptNumber: request.attempts.length + 1,\n        attemptedAt: new Date(),\n        method: VerificationMethod.SMS, // Assuming SMS for verification attempts\n        status: 'failed'\n      };\n      request.attempts.push(failedAttempt);\n\n      // Handle failed attempt\n      const failedAttempts = request.attempts.filter(a => a.status === 'failed').length;\n      \n      if (failedAttempts >= this.options.maxAttempts!) {\n        request.status = PhoneVerificationStatus.BLOCKED;\n        this.emit('verification:blocked', { verificationRequest: request });\n        \n        return {\n          success: false,\n          status: PhoneVerificationStatus.BLOCKED,\n          message: 'Too many failed attempts. Verification blocked.'\n        };\n      } else {\n        request.status = PhoneVerificationStatus.FAILED;\n        this.emit('verification:failed_attempt', { \n          verificationRequest: request, \n          attemptsRemaining: this.options.maxAttempts! - failedAttempts \n        });\n\n        return {\n          success: false,\n          status: PhoneVerificationStatus.FAILED,\n          message: `Invalid code. ${this.options.maxAttempts! - failedAttempts} attempts remaining.`\n        };\n      }\n    }\n  }\n\n  /**\n   * Resend verification code\n   */\n  async resendCode(requestId: string, method?: VerificationMethod): Promise<PhoneVerificationRequest> {\n    const request = this.verificationRequests.get(requestId);\n    if (!request) {\n      throw new Error('Verification request not found');\n    }\n\n    if (request.status === PhoneVerificationStatus.VERIFIED) {\n      throw new Error('Verification already completed');\n    }\n\n    if (request.status === PhoneVerificationStatus.BLOCKED) {\n      throw new Error('Verification is blocked');\n    }\n\n    // Check rate limiting\n    if (this.isRateLimited(request.phoneNumber)) {\n      throw new Error('Rate limit exceeded. Please wait before requesting a new code.');\n    }\n\n    // Generate new code and extend expiry\n    request.verificationCode = this.generateVerificationCode();\n    request.expiresAt = new Date(Date.now() + this.options.codeExpiryMinutes! * 60 * 1000);\n    request.status = PhoneVerificationStatus.PENDING;\n\n    this.updateRateLimit(request.phoneNumber);\n\n    const phoneInfo = await this.getPhoneNumberInfo(request.phoneNumber);\n    \n    // Send using specified method or fallback logic\n    if (method) {\n      await this.sendVerificationByMethod(request, phoneInfo, method);\n    } else {\n      await this.sendVerificationCode(request, phoneInfo);\n    }\n\n    this.emit('verification:resent', { verificationRequest: request });\n\n    return request;\n  }\n\n  /**\n   * Get verification request status\n   */\n  getVerificationStatus(requestId: string): PhoneVerificationRequest | null {\n    return this.verificationRequests.get(requestId) || null;\n  }\n\n  /**\n   * Cancel verification request\n   */\n  async cancelVerification(requestId: string): Promise<boolean> {\n    const request = this.verificationRequests.get(requestId);\n    if (!request) {\n      return false;\n    }\n\n    if (request.status === PhoneVerificationStatus.VERIFIED) {\n      return false; // Cannot cancel completed verification\n    }\n\n    this.verificationRequests.delete(requestId);\n    this.emit('verification:cancelled', { verificationRequest: request });\n\n    return true;\n  }\n\n  /**\n   * Block a phone number from verification\n   */\n  blockPhoneNumber(phoneNumber: string, reason?: string): void {\n    this.blockedNumbers.add(phoneNumber);\n    \n    // Cancel any pending verifications for this number\n    for (const [requestId, request] of this.verificationRequests) {\n      if (request.phoneNumber === phoneNumber && \n          request.status !== PhoneVerificationStatus.VERIFIED) {\n        request.status = PhoneVerificationStatus.BLOCKED;\n      }\n    }\n\n    this.emit('phone:blocked', { phoneNumber, reason });\n  }\n\n  /**\n   * Unblock a phone number\n   */\n  unblockPhoneNumber(phoneNumber: string): void {\n    this.blockedNumbers.delete(phoneNumber);\n    this.emit('phone:unblocked', { phoneNumber });\n  }\n\n  /**\n   * Get verification statistics\n   */\n  getVerificationStats(): {\n    total: number;\n    byStatus: Record<string, number>;\n    byMethod: Record<string, number>;\n    successRate: number;\n    averageCompletionTime: number;\n  } {\n    const requests = Array.from(this.verificationRequests.values());\n    \n    const byStatus: Record<string, number> = {};\n    const byMethod: Record<string, number> = {};\n    let totalCompletionTime = 0;\n    let completedCount = 0;\n\n    requests.forEach(request => {\n      byStatus[request.status] = (byStatus[request.status] || 0) + 1;\n\n      // Count by primary method used\n      if (request.attempts.length > 0) {\n        const primaryMethod = request.attempts[0].method;\n        byMethod[primaryMethod] = (byMethod[primaryMethod] || 0) + 1;\n      }\n\n      // Calculate completion time for verified requests\n      if (request.completedAt) {\n        const completionTime = request.completedAt.getTime() - request.createdAt.getTime();\n        totalCompletionTime += completionTime;\n        completedCount++;\n      }\n    });\n\n    const successCount = byStatus[PhoneVerificationStatus.VERIFIED] || 0;\n    const successRate = requests.length > 0 ? (successCount / requests.length) * 100 : 0;\n\n    return {\n      total: requests.length,\n      byStatus,\n      byMethod,\n      successRate,\n      averageCompletionTime: completedCount > 0 ? totalCompletionTime / completedCount : 0\n    };\n  }\n\n  /**\n   * Clean up expired verification requests\n   */\n  cleanup(): number {\n    const now = new Date();\n    let cleanedCount = 0;\n\n    for (const [requestId, request] of this.verificationRequests) {\n      if (now > request.expiresAt && request.status !== PhoneVerificationStatus.VERIFIED) {\n        request.status = PhoneVerificationStatus.EXPIRED;\n        this.verificationRequests.delete(requestId);\n        cleanedCount++;\n      }\n    }\n\n    // Clean up old rate limit entries\n    const rateWindow = this.options.rateLimitMinutes! * 60 * 1000;\n    for (const [phoneNumber, timestamps] of this.rateLimitTracker) {\n      const validTimestamps = timestamps.filter(ts => now.getTime() - ts.getTime() < rateWindow);\n      if (validTimestamps.length === 0) {\n        this.rateLimitTracker.delete(phoneNumber);\n      } else {\n        this.rateLimitTracker.set(phoneNumber, validTimestamps);\n      }\n    }\n\n    return cleanedCount;\n  }\n\n  // Private Methods\n  private async sendVerificationCode(\n    request: PhoneVerificationRequest,\n    phoneInfo: PhoneNumberInfo\n  ): Promise<void> {\n    let method: VerificationMethod;\n\n    switch (request.verificationType) {\n      case VerificationType.SMS:\n        method = VerificationMethod.SMS;\n        break;\n      case VerificationType.VOICE_CALL:\n        method = VerificationMethod.VOICE_CALL;\n        break;\n      case VerificationType.HYBRID:\n        // Try SMS first for mobile, voice for landline\n        method = phoneInfo.lineType === 'landline' ? VerificationMethod.VOICE_CALL : VerificationMethod.SMS;\n        break;\n      default:\n        method = VerificationMethod.SMS;\n    }\n\n    await this.sendVerificationByMethod(request, phoneInfo, method);\n  }\n\n  private async sendVerificationByMethod(\n    request: PhoneVerificationRequest,\n    phoneInfo: PhoneNumberInfo,\n    method: VerificationMethod\n  ): Promise<void> {\n    const attempt: VerificationAttempt = {\n      attemptNumber: request.attempts.length + 1,\n      attemptedAt: new Date(),\n      method,\n      status: 'sent'\n    };\n\n    const startTime = Date.now();\n\n    try {\n      switch (method) {\n        case VerificationMethod.SMS:\n          await this.sendSMS(request, phoneInfo);\n          break;\n        case VerificationMethod.VOICE_CALL:\n          await this.sendVoiceCall(request, phoneInfo);\n          break;\n        case VerificationMethod.MISSED_CALL:\n          await this.sendMissedCall(request, phoneInfo);\n          break;\n      }\n\n      attempt.status = 'delivered';\n      attempt.responseTime = Date.now() - startTime;\n      request.status = PhoneVerificationStatus.CODE_SENT;\n\n    } catch (error) {\n      attempt.status = 'failed';\n      attempt.failureReason = error instanceof Error ? error.message : 'Unknown error';\n      attempt.responseTime = Date.now() - startTime;\n\n      // Try fallback method if enabled and this was SMS\n      if (method === VerificationMethod.SMS && \n          this.options.enableVoiceFallback && \n          request.attempts.filter(a => a.method === VerificationMethod.VOICE_CALL).length === 0) {\n        \n        attempt.status = 'failed';\n        request.attempts.push(attempt);\n        \n        // Try voice call as fallback\n        await this.sendVerificationByMethod(request, phoneInfo, VerificationMethod.VOICE_CALL);\n        return;\n      }\n\n      request.status = PhoneVerificationStatus.FAILED;\n      throw error;\n    }\n\n    request.attempts.push(attempt);\n  }\n\n  private async sendSMS(request: PhoneVerificationRequest, phoneInfo: PhoneNumberInfo): Promise<void> {\n    if (!this.options.smsProvider) {\n      throw new Error('SMS provider not configured');\n    }\n\n    const message = this.options.smsTemplate!\n      .replace('{code}', request.verificationCode)\n      .replace('{expiry}', this.options.codeExpiryMinutes!.toString());\n\n    const result = await this.options.smsProvider.sendSMS(request.phoneNumber, message);\n    \n    if (result.status === 'failed') {\n      throw new Error(result.error || 'SMS sending failed');\n    }\n  }\n\n  private async sendVoiceCall(request: PhoneVerificationRequest, phoneInfo: PhoneNumberInfo): Promise<void> {\n    if (!this.options.voiceProvider) {\n      throw new Error('Voice provider not configured');\n    }\n\n    const message = this.options.voiceTemplate!\n      .replace('{code}', request.verificationCode.split('').join(' '));\n\n    const result = await this.options.voiceProvider.makeCall(request.phoneNumber, message);\n    \n    if (result.status === 'failed') {\n      throw new Error(result.error || 'Voice call failed');\n    }\n  }\n\n  private async sendMissedCall(request: PhoneVerificationRequest, phoneInfo: PhoneNumberInfo): Promise<void> {\n    if (!this.options.voiceProvider?.makeMissedCall) {\n      throw new Error('Missed call verification not supported');\n    }\n\n    const result = await this.options.voiceProvider.makeMissedCall(request.phoneNumber);\n    \n    if (result.status === 'failed') {\n      throw new Error(result.error || 'Missed call failed');\n    }\n\n    // For missed call verification, the code is typically the last 4-6 digits of the caller ID\n    if (result.missedCallNumber) {\n      const codeFromNumber = result.missedCallNumber.slice(-this.options.codeLength!);\n      request.verificationCode = codeFromNumber;\n    }\n  }\n\n  private async getPhoneNumberInfo(phoneNumber: string): Promise<PhoneNumberInfo> {\n    // Check cache first\n    if (this.phoneNumberCache.has(phoneNumber)) {\n      return this.phoneNumberCache.get(phoneNumber)!;\n    }\n\n    // Basic Korean phone number validation and parsing\n    const phoneInfo = this.parseKoreanPhoneNumber(phoneNumber);\n    \n    // Cache the result\n    this.phoneNumberCache.set(phoneNumber, phoneInfo);\n    \n    return phoneInfo;\n  }\n\n  private parseKoreanPhoneNumber(phoneNumber: string): PhoneNumberInfo {\n    // Remove any non-digit characters\n    const cleaned = phoneNumber.replace(/\\D/g, '');\n    \n    // Korean phone number patterns\n    const mobilePattern = /^(010|011|016|017|018|019)(\\d{7,8})$/;\n    const landlinePattern = /^(02|031|032|033|041|042|043|044|051|052|053|054|055|061|062|063|064)(\\d{7,8})$/;\n    \n    let isValid = false;\n    let isPossible = false;\n    let lineType: PhoneNumberInfo['lineType'] = 'unknown';\n    let carrier: string | undefined;\n\n    if (mobilePattern.test(cleaned)) {\n      isValid = true;\n      isPossible = true;\n      lineType = 'mobile';\n      \n      const prefix = cleaned.substring(0, 3);\n      switch (prefix) {\n        case '010':\n          carrier = 'Multiple carriers';\n          break;\n        case '011':\n          carrier = 'SK Telecom';\n          break;\n        case '016':\n          carrier = 'KT';\n          break;\n        case '017':\n          carrier = 'LG U+';\n          break;\n        case '018':\n          carrier = 'SK Telecom';\n          break;\n        case '019':\n          carrier = 'LG U+';\n          break;\n      }\n    } else if (landlinePattern.test(cleaned)) {\n      isValid = true;\n      isPossible = true;\n      lineType = 'landline';\n    } else if (cleaned.length >= 10 && cleaned.length <= 11) {\n      isPossible = true;\n    }\n\n    return {\n      phoneNumber: cleaned,\n      countryCode: '82',\n      nationalNumber: cleaned,\n      carrier,\n      lineType,\n      isValid,\n      isPossible,\n      region: 'KR'\n    };\n  }\n\n  private isNumberBlocked(phoneNumber: string): boolean {\n    return this.blockedNumbers.has(phoneNumber);\n  }\n\n  private isRateLimited(phoneNumber: string): boolean {\n    const timestamps = this.rateLimitTracker.get(phoneNumber) || [];\n    const rateWindow = this.options.rateLimitMinutes! * 60 * 1000;\n    const now = new Date();\n    \n    const recentAttempts = timestamps.filter(ts => now.getTime() - ts.getTime() < rateWindow);\n    \n    return recentAttempts.length >= 1; // Allow only 1 attempt per rate limit window\n  }\n\n  private isDailyLimitExceeded(phoneNumber: string): boolean {\n    const today = new Date().toISOString().split('T')[0];\n    const dailyData = this.dailyAttemptTracker.get(phoneNumber);\n    \n    if (!dailyData || dailyData.date !== today) {\n      return false;\n    }\n    \n    return dailyData.count >= this.options.maxDailyAttempts!;\n  }\n\n  private updateRateLimit(phoneNumber: string): void {\n    const timestamps = this.rateLimitTracker.get(phoneNumber) || [];\n    timestamps.push(new Date());\n    this.rateLimitTracker.set(phoneNumber, timestamps);\n  }\n\n  private updateDailyAttempts(phoneNumber: string): void {\n    const today = new Date().toISOString().split('T')[0];\n    const dailyData = this.dailyAttemptTracker.get(phoneNumber);\n    \n    if (!dailyData || dailyData.date !== today) {\n      this.dailyAttemptTracker.set(phoneNumber, { date: today, count: 1 });\n    } else {\n      dailyData.count++;\n    }\n  }\n\n  private validateCode(expected: string, provided: string): boolean {\n    return expected === provided.replace(/\\s/g, ''); // Remove spaces\n  }\n\n  private generateVerificationCode(): string {\n    const length = this.options.codeLength!;\n    let code = '';\n    \n    for (let i = 0; i < length; i++) {\n      code += Math.floor(Math.random() * 10).toString();\n    }\n    \n    return code;\n  }\n\n  private generateRequestId(): string {\n    return `phone_verify_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;\n  }\n}","import type { ChannelConfig, ChannelVerificationResult, SenderNumber } from '../types/channel.types';\nimport { SenderNumberStatus } from '../types/channel.types';\n\n// Define a service-specific SenderNumber interface that extends the types from channel.types\nexport interface ServiceSenderNumber {\n  phoneNumber: string;\n  name?: string;\n  verifiedAt?: Date;\n  status: SenderNumberStatus;\n  channelId: string;\n}\n\nexport class ChannelService {\n  private channels: Map<string, ChannelConfig> = new Map();\n  private senderNumbers: Map<string, ServiceSenderNumber> = new Map();\n\n  async createChannel(channel: Omit<ChannelConfig, 'id' | 'createdAt' | 'updatedAt'>): Promise<ChannelConfig> {\n    const newChannel: ChannelConfig = {\n      ...channel,\n      id: this.generateChannelId(),\n      createdAt: new Date(),\n      updatedAt: new Date(),\n    };\n\n    this.channels.set(newChannel.id, newChannel);\n    return newChannel;\n  }\n\n  async getChannel(channelId: string): Promise<ChannelConfig | null> {\n    return this.channels.get(channelId) || null;\n  }\n\n  async listChannels(providerId?: string): Promise<ChannelConfig[]> {\n    const channels = Array.from(this.channels.values());\n    \n    if (providerId) {\n      return channels.filter(c => c.providerId === providerId);\n    }\n    \n    return channels;\n  }\n\n  async updateChannel(channelId: string, updates: Partial<ChannelConfig>): Promise<ChannelConfig> {\n    const channel = this.channels.get(channelId);\n    if (!channel) {\n      throw new Error(`Channel ${channelId} not found`);\n    }\n\n    const updatedChannel = {\n      ...channel,\n      ...updates,\n      updatedAt: new Date(),\n    };\n\n    this.channels.set(channelId, updatedChannel);\n    return updatedChannel;\n  }\n\n  async deleteChannel(channelId: string): Promise<void> {\n    this.channels.delete(channelId);\n    \n    // 관련 발신번호도 삭제\n    for (const [key, senderNumber] of this.senderNumbers.entries()) {\n      if (senderNumber.channelId === channelId) {\n        this.senderNumbers.delete(key);\n      }\n    }\n  }\n\n  async addSenderNumber(channelId: string, phoneNumber: string, name?: string): Promise<ServiceSenderNumber> {\n    const channel = this.channels.get(channelId);\n    if (!channel) {\n      throw new Error(`Channel ${channelId} not found`);\n    }\n\n    const senderNumber: ServiceSenderNumber = {\n      phoneNumber,\n      name,\n      status: SenderNumberStatus.PENDING,\n      channelId,\n    };\n\n    this.senderNumbers.set(phoneNumber, senderNumber);\n    return senderNumber;\n  }\n\n  async verifySenderNumber(phoneNumber: string): Promise<ChannelVerificationResult> {\n    const senderNumber = this.senderNumbers.get(phoneNumber);\n    if (!senderNumber) {\n      return {\n        success: false,\n        status: 'not_found',\n        error: 'Sender number not found',\n      };\n    }\n\n    // 실제 검증 로직 (API 호출 등)\n    const verificationCode = Math.floor(Math.random() * 900000) + 100000;\n\n    senderNumber.verifiedAt = new Date();\n    senderNumber.status = SenderNumberStatus.VERIFIED;\n\n    this.senderNumbers.set(phoneNumber, senderNumber);\n\n    return {\n      success: true,\n      status: 'verified',\n      verificationCode: verificationCode.toString(),\n    };\n  }\n\n  async getSenderNumbers(channelId?: string): Promise<ServiceSenderNumber[]> {\n    const senderNumbers = Array.from(this.senderNumbers.values());\n    \n    if (channelId) {\n      return senderNumbers.filter(s => s.channelId === channelId);\n    }\n    \n    return senderNumbers;\n  }\n\n  private generateChannelId(): string {\n    return `ch_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;\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;AAAA;;;ACAA,iBAAkB;AAgBX,IAAK,cAAL,kBAAKA,iBAAL;AACL,EAAAA,aAAA,oBAAiB;AACjB,EAAAA,aAAA,sBAAmB;AACnB,EAAAA,aAAA,SAAM;AACN,EAAAA,aAAA,SAAM;AACN,EAAAA,aAAA,SAAM;AALI,SAAAA;AAAA,GAAA;AAQL,IAAK,gBAAL,kBAAKC,mBAAL;AACL,EAAAA,eAAA,aAAU;AACV,EAAAA,eAAA,eAAY;AACZ,EAAAA,eAAA,YAAS;AACT,EAAAA,eAAA,eAAY;AACZ,EAAAA,eAAA,aAAU;AACV,EAAAA,eAAA,aAAU;AANA,SAAAA;AAAA,GAAA;AA0BL,IAAK,qBAAL,kBAAKC,wBAAL;AACL,EAAAA,oBAAA,aAAU;AACV,EAAAA,oBAAA,eAAY;AACZ,EAAAA,oBAAA,cAAW;AACX,EAAAA,oBAAA,cAAW;AACX,EAAAA,oBAAA,aAAU;AALA,SAAAA;AAAA,GAAA;AAQL,IAAK,uBAAL,kBAAKC,0BAAL;AACL,EAAAA,sBAAA,cAAW;AACX,EAAAA,sBAAA,cAAW;AACX,EAAAA,sBAAA,gBAAa;AACb,EAAAA,sBAAA,gBAAa;AAJH,SAAAA;AAAA,GAAA;AA4CL,IAAK,qBAAL,kBAAKC,wBAAL;AACL,EAAAA,oBAAA,kBAAe;AACf,EAAAA,oBAAA,aAAU;AACV,EAAAA,oBAAA,kBAAe;AACf,EAAAA,oBAAA,cAAW;AACX,EAAAA,oBAAA,cAAW;AALD,SAAAA;AAAA,GAAA;AAiBL,IAAK,eAAL,kBAAKC,kBAAL;AACL,EAAAA,cAAA,2BAAwB;AACxB,EAAAA,cAAA,sBAAmB;AACnB,EAAAA,cAAA,aAAU;AACV,EAAAA,cAAA,0BAAuB;AACvB,EAAAA,cAAA,WAAQ;AALE,SAAAA;AAAA,GAAA;AAQL,IAAK,iBAAL,kBAAKC,oBAAL;AACL,EAAAA,gBAAA,cAAW;AACX,EAAAA,gBAAA,cAAW;AACX,EAAAA,gBAAA,cAAW;AAHD,SAAAA;AAAA,GAAA;AAwDL,IAAM,6BAA6B,aAAE,OAAO;AAAA,EACjD,MAAM,aAAE,OAAO,EAAE,IAAI,CAAC,EAAE,IAAI,GAAG;AAAA,EAC/B,MAAM,aAAE,WAAW,WAAW;AAAA,EAC9B,UAAU,aAAE,OAAO,EAAE,IAAI,CAAC;AAAA,EAC1B,YAAY,aAAE,OAAO,EAAE,IAAI,CAAC;AAAA,EAC5B,cAAc,aAAE,OAAO;AAAA,IACrB,MAAM,aAAE,OAAO,EAAE,IAAI,CAAC;AAAA,IACtB,oBAAoB,aAAE,OAAO,EAAE,IAAI,CAAC;AAAA,IACpC,UAAU,aAAE,OAAO,EAAE,IAAI,CAAC;AAAA,IAC1B,eAAe,aAAE,OAAO,EAAE,IAAI,CAAC;AAAA,IAC/B,cAAc,aAAE,OAAO,EAAE,MAAM;AAAA,IAC/B,cAAc,aAAE,OAAO,EAAE,MAAM,gBAAgB;AAAA,EACjD,CAAC,EAAE,SAAS;AAAA,EACZ,WAAW,aAAE,OAAO;AAAA,IAClB,cAAc,aAAE,OAAO,EAAE,IAAI,CAAC;AAAA,IAC9B,WAAW,aAAE,OAAO,EAAE,IAAI,CAAC;AAAA,IAC3B,SAAS,aAAE,OAAO,EAAE,IAAI,EAAE,SAAS;AAAA,IACnC,aAAa,aAAE,OAAO,EAAE,IAAI,GAAG,EAAE,SAAS;AAAA,EAC5C,CAAC,EAAE,SAAS;AACd,CAAC;AAEM,IAAM,kCAAkC,aAAE,OAAO;AAAA,EACtD,aAAa,aAAE,OAAO,EAAE,MAAM,gBAAgB;AAAA,EAC9C,UAAU,aAAE,WAAW,oBAAoB;AAAA,EAC3C,cAAc,aAAE,OAAO;AAAA,IACrB,cAAc,aAAE,OAAO,EAAE,IAAI,CAAC;AAAA,IAC9B,4BAA4B,aAAE,OAAO,EAAE,IAAI,CAAC;AAAA,IAC5C,eAAe,aAAE,OAAO,EAAE,IAAI,CAAC;AAAA,IAC/B,cAAc,aAAE,OAAO,EAAE,MAAM;AAAA,EACjC,CAAC,EAAE,SAAS;AACd,CAAC;AAEM,IAAM,uBAAuB,aAAE,OAAO;AAAA,EAC3C,UAAU,aAAE,OAAO,EAAE,SAAS;AAAA,EAC9B,MAAM,aAAE,WAAW,WAAW,EAAE,SAAS;AAAA,EACzC,QAAQ,aAAE,WAAW,aAAa,EAAE,SAAS;AAAA,EAC7C,UAAU,aAAE,QAAQ,EAAE,SAAS;AAAA,EAC/B,cAAc,aAAE,KAAK,EAAE,SAAS;AAAA,EAChC,eAAe,aAAE,KAAK,EAAE,SAAS;AACnC,CAAC;AAEM,IAAM,4BAA4B,aAAE,OAAO;AAAA,EAChD,WAAW,aAAE,OAAO,EAAE,SAAS;AAAA,EAC/B,QAAQ,aAAE,WAAW,kBAAkB,EAAE,SAAS;AAAA,EAClD,UAAU,aAAE,WAAW,oBAAoB,EAAE,SAAS;AAAA,EACtD,UAAU,aAAE,QAAQ,EAAE,SAAS;AACjC,CAAC;;;AC7NM,IAAM,sBAAN,MAA0B;AAAA,EAA1B;AACL,SAAQ,WAAiC,oBAAI,IAAI;AAAA;AAAA,EAEjD,MAAM,cAAc,SAAiD;AAEnE,SAAK,4BAA4B,OAAO;AAExC,UAAM,YAAY,KAAK,kBAAkB;AAEzC,UAAM,UAAmB;AAAA,MACvB,IAAI;AAAA,MACJ,MAAM,QAAQ;AAAA,MACd,UAAU,QAAQ;AAAA,MAClB,MAAM,QAAQ;AAAA,MACd;AAAA,MACA,YAAY,QAAQ;AAAA,MACpB,eAAe,CAAC;AAAA,MAChB,UAAU;AAAA,QACR,cAAc,QAAQ;AAAA,QACtB,WAAW,QAAQ;AAAA,QACnB,QAAQ;AAAA,UACN,mBAAmB;AAAA,UACnB,qBAAqB;AAAA,UACrB,WAAW;AAAA;AAAA,QACb;AAAA,QACA,UAAU;AAAA,UACR,qBAAqB;AAAA,UACrB,oBAAoB;AAAA,UACpB,iBAAiB;AAAA,UACjB,gBAAgB;AAAA,QAClB;AAAA,MACF;AAAA,MACA,cAAc;AAAA,QACZ,QAAQ,QAAQ;AAAA,QAChB,WAAW,CAAC;AAAA,MACd;AAAA,MACA,WAAW,oBAAI,KAAK;AAAA,MACpB,WAAW,oBAAI,KAAK;AAAA,IACtB;AAEA,SAAK,SAAS,IAAI,WAAW,OAAO;AAGpC,QAAI,QAAQ,cAAc;AACxB,YAAM,KAAK,6BAA6B,OAAO;AAAA,IACjD;AAEA,WAAO;AAAA,EACT;AAAA,EAEQ,4BAA4B,SAAqC;AACvE,QAAI,QAAQ,kDAAuC,QAAQ,oDAAuC;AAChG,YAAM,IAAI,MAAM,wCAAwC;AAAA,IAC1D;AAEA,QAAI,CAAC,QAAQ,WAAW,cAAc;AACpC,YAAM,IAAI,MAAM,+CAA+C;AAAA,IACjE;AAEA,QAAI,CAAC,QAAQ,WAAW,WAAW;AACjC,YAAM,IAAI,MAAM,2CAA2C;AAAA,IAC7D;AAGA,QAAI,CAAC,KAAK,oBAAoB,QAAQ,UAAU,YAAY,GAAG;AAC7D,YAAM,IAAI,MAAM,+BAA+B;AAAA,IACjD;AAAA,EACF;AAAA,EAEQ,oBAAoB,cAA+B;AAEzD,UAAM,QAAQ;AACd,WAAO,MAAM,KAAK,YAAY;AAAA,EAChC;AAAA,EAEA,MAAc,6BAA6B,SAAiC;AAI1E,YAAQ,aAAa;AACrB,YAAQ;AACR,YAAQ,YAAY,oBAAI,KAAK;AAG7B,eAAW,MAAM;AACf,WAAK,qBAAqB,QAAQ,IAAI,IAAI;AAAA,IAC5C,GAAG,GAAI;AAAA,EACT;AAAA,EAEA,MAAM,qBAAqB,WAAmB,UAAmB,iBAAyC;AACxG,UAAM,UAAU,KAAK,SAAS,IAAI,SAAS;AAC3C,QAAI,CAAC,SAAS;AACZ,YAAM,IAAI,MAAM,mBAAmB;AAAA,IACrC;AAEA,QAAI,UAAU;AACZ,cAAQ,aAAa;AACrB,cAAQ,aAAa,aAAa,oBAAI,KAAK;AAC3C,cAAQ;AAAA,IACV,OAAO;AACL,cAAQ,aAAa;AACrB,cAAQ,aAAa,aAAa,oBAAI,KAAK;AAC3C,cAAQ,aAAa,kBAAkB,mBAAmB;AAC1D,cAAQ;AAAA,IACV;AAEA,YAAQ,YAAY,oBAAI,KAAK;AAAA,EAC/B;AAAA,EAEA,MAAM,WAAW,WAA4C;AAC3D,WAAO,KAAK,SAAS,IAAI,SAAS,KAAK;AAAA,EACzC;AAAA,EAEA,MAAM,cAAc,WAAmB,SAA6C;AAClF,UAAM,UAAU,KAAK,SAAS,IAAI,SAAS;AAC3C,QAAI,CAAC,SAAS;AACZ,YAAM,IAAI,MAAM,mBAAmB;AAAA,IACrC;AAGA,QAAI,QAAQ,UAAU,WAAW,gBAAgB,CAAC,KAAK,oBAAoB,QAAQ,SAAS,UAAU,YAAY,GAAG;AACnH,YAAM,IAAI,MAAM,+BAA+B;AAAA,IACjD;AAGA,WAAO,OAAO,SAAS,SAAS,EAAE,WAAW,oBAAI,KAAK,EAAE,CAAC;AAEzD,WAAO;AAAA,EACT;AAAA,EAEA,MAAM,cAAc,WAAqC;AACvD,UAAM,UAAU,KAAK,SAAS,IAAI,SAAS;AAC3C,QAAI,CAAC,SAAS;AACZ,aAAO;AAAA,IACT;AAGA,YAAQ;AACR,YAAQ,YAAY,oBAAI,KAAK;AAE7B,WAAO;AAAA,EACT;AAAA,EAEA,MAAM,aAAa,SAII;AACrB,QAAI,WAAW,MAAM,KAAK,KAAK,SAAS,OAAO,CAAC;AAEhD,QAAI,SAAS;AACX,UAAI,QAAQ,QAAQ;AAClB,mBAAW,SAAS,OAAO,OAAK,EAAE,WAAW,QAAQ,MAAM;AAAA,MAC7D;AACA,UAAI,QAAQ,MAAM;AAChB,mBAAW,SAAS,OAAO,OAAK,EAAE,SAAS,QAAQ,IAAI;AAAA,MACzD;AACA,UAAI,QAAQ,aAAa,QAAW;AAClC,cAAM,iBAAiB,QAAQ;AAC/B,mBAAW,SAAS,OAAO,OAAK,EAAE,aAAa,WAAW,cAAc;AAAA,MAC1E;AAAA,IACF;AAGA,WAAO,SAAS,OAAO,OAAK,EAAE,kCAAgC;AAAA,EAChE;AAAA,EAEA,MAAM,eAAe,WAAmB,QAA+B;AACrE,UAAM,UAAU,KAAK,SAAS,IAAI,SAAS;AAC3C,QAAI,CAAC,SAAS;AACZ,YAAM,IAAI,MAAM,mBAAmB;AAAA,IACrC;AAEA,YAAQ;AACR,YAAQ,YAAY,oBAAI,KAAK;AAG7B,YAAQ,IAAI,WAAW,SAAS,eAAe,MAAM,EAAE;AAAA,EACzD;AAAA,EAEA,MAAM,kBAAkB,WAAkC;AACxD,UAAM,UAAU,KAAK,SAAS,IAAI,SAAS;AAC3C,QAAI,CAAC,SAAS;AACZ,YAAM,IAAI,MAAM,mBAAmB;AAAA,IACrC;AAEA,QAAI,QAAQ,aAAa,sCAAwC;AAC/D,YAAM,IAAI,MAAM,8CAA8C;AAAA,IAChE;AAEA,YAAQ;AACR,YAAQ,YAAY,oBAAI,KAAK;AAAA,EAC/B;AAAA,EAEA,MAAM,mBAAmB,WAItB;AACD,UAAM,UAAU,KAAK,SAAS,IAAI,SAAS;AAC3C,QAAI,CAAC,SAAS;AACZ,YAAM,IAAI,MAAM,mBAAmB;AAAA,IACrC;AAEA,UAAM,SAAmB,CAAC;AAC1B,UAAM,kBAA4B,CAAC;AAGnC,QAAI,QAAQ,kCAAiC;AAC3C,aAAO,KAAK,qBAAqB,QAAQ,MAAM,EAAE;AAAA,IACnD;AAGA,QAAI,QAAQ,aAAa,wCACrB,QAAQ,aAAa,8CAA4C;AACnE,aAAO,KAAK,2BAA2B,QAAQ,aAAa,MAAM,EAAE;AAAA,IACtE;AAGA,QAAI,QAAQ,cAAc,WAAW,GAAG;AACtC,sBAAgB,KAAK,yCAAyC;AAAA,IAChE;AAGA,QAAI,CAAC,QAAQ,SAAS,cAAc;AAClC,sBAAgB,KAAK,yDAAyD;AAAA,IAChF;AAEA,WAAO;AAAA,MACL,WAAW,OAAO,WAAW;AAAA,MAC7B;AAAA,MACA;AAAA,IACF;AAAA,EACF;AAAA,EAEQ,oBAA4B;AAClC,WAAO,SAAS,KAAK,IAAI,CAAC,IAAI,KAAK,OAAO,EAAE,SAAS,EAAE,EAAE,OAAO,GAAG,CAAC,CAAC;AAAA,EACvE;AACF;;;AC/OO,IAAM,2BAAN,MAA+B;AAAA,EAA/B;AACL,SAAQ,gBAA2C,oBAAI,IAAI;AAC3D,SAAQ,oBAAoE,oBAAI,IAAI;AAAA;AAAA,EAEpF,MAAM,gBACJ,WACA,SACuB;AAEvB,SAAK,oBAAoB,QAAQ,WAAW;AAG5C,UAAM,iBAAiB,KAAK,wBAAwB,QAAQ,WAAW;AACvE,QAAI,gBAAgB;AAClB,YAAM,IAAI,MAAM,oCAAoC;AAAA,IACtD;AAEA,UAAM,iBAAiB,KAAK,uBAAuB;AAEnD,UAAM,eAA6B;AAAA,MACjC,IAAI;AAAA,MACJ,aAAa,QAAQ;AAAA,MACrB;AAAA,MACA,UAAU,QAAQ;AAAA,MAClB,UAAU;AAAA,QACR,cAAc,QAAQ,cAAc;AAAA,QACpC,4BAA4B,QAAQ,cAAc;AAAA,QAClD,eAAe,QAAQ,cAAc;AAAA,QACrC,cAAc,QAAQ,cAAc;AAAA,MACtC;AAAA,MACA,WAAW,oBAAI,KAAK;AAAA,MACpB,WAAW,oBAAI,KAAK;AAAA,IACtB;AAEA,SAAK,cAAc,IAAI,gBAAgB,YAAY;AAGnD,UAAM,KAAK,qBAAqB,YAAY;AAE5C,WAAO;AAAA,EACT;AAAA,EAEQ,oBAAoB,aAA2B;AAErD,UAAM,QAAQ;AACd,QAAI,CAAC,MAAM,KAAK,WAAW,GAAG;AAC5B,YAAM,IAAI,MAAM,oCAAoC;AAAA,IACtD;AAAA,EACF;AAAA,EAEQ,wBAAwB,aAA+C;AAC7E,WAAO,MAAM,KAAK,KAAK,cAAc,OAAO,CAAC,EAC1C,KAAK,QAAM,GAAG,gBAAgB,WAAW;AAAA,EAC9C;AAAA,EAEA,MAAc,qBAAqB,cAA2C;AAE5E,UAAM,mBAAmB,KAAK,yBAAyB;AACvD,UAAM,YAAY,IAAI,KAAK,KAAK,IAAI,IAAI,IAAI,KAAK,GAAI;AAGrD,SAAK,kBAAkB,IAAI,aAAa,IAAI;AAAA,MAC1C,MAAM;AAAA,MACN;AAAA,IACF,CAAC;AAGD,iBAAa;AACb,iBAAa,mBAAmB;AAChC,iBAAa,YAAY,oBAAI,KAAK;AAGlC,YAAQ,IAAI,yBAAyB,aAAa,WAAW,KAAK,gBAAgB,EAAE;AAGpF,UAAM,KAAK,oBAAoB,aAAa,aAAa,gBAAgB;AAAA,EAC3E;AAAA,EAEA,MAAc,oBAAoB,aAAqB,MAA6B;AAElF,YAAQ,IAAI,kBAAkB,WAAW,+BAA+B,IAAI,EAAE;AAAA,EAChF;AAAA,EAEA,MAAM,mBAAmB,gBAAwB,MAAgC;AAC/E,UAAM,eAAe,KAAK,cAAc,IAAI,cAAc;AAC1D,QAAI,CAAC,cAAc;AACjB,YAAM,IAAI,MAAM,yBAAyB;AAAA,IAC3C;AAEA,UAAM,eAAe,KAAK,kBAAkB,IAAI,cAAc;AAC9D,QAAI,CAAC,cAAc;AACjB,YAAM,IAAI,MAAM,4BAA4B;AAAA,IAC9C;AAGA,QAAI,oBAAI,KAAK,IAAI,aAAa,WAAW;AACvC,YAAM,IAAI,MAAM,+BAA+B;AAAA,IACjD;AAGA,QAAI,aAAa,SAAS,MAAM;AAC9B,aAAO;AAAA,IACT;AAGA,iBAAa;AACb,iBAAa,aAAa,oBAAI,KAAK;AACnC,iBAAa,YAAY,oBAAI,KAAK;AAClC,WAAO,aAAa;AAGpB,SAAK,kBAAkB,OAAO,cAAc;AAE5C,WAAO;AAAA,EACT;AAAA,EAEA,MAAM,uBAAuB,gBAAuC;AAClE,UAAM,eAAe,KAAK,cAAc,IAAI,cAAc;AAC1D,QAAI,CAAC,cAAc;AACjB,YAAM,IAAI,MAAM,yBAAyB;AAAA,IAC3C;AAEA,QAAI,aAAa,wCAAyC;AACxD,YAAM,IAAI,MAAM,0CAA0C;AAAA,IAC5D;AAGA,UAAM,mBAAmB,KAAK,kBAAkB,IAAI,cAAc;AAClE,QAAI,kBAAkB;AACpB,YAAM,oBAAoB,KAAK,IAAI,KAAK,iBAAiB,UAAU,QAAQ,IAAI,IAAI,KAAK;AACxF,UAAI,oBAAoB,KAAK,KAAM;AACjC,cAAM,IAAI,MAAM,uDAAuD;AAAA,MACzE;AAAA,IACF;AAGA,UAAM,KAAK,qBAAqB,YAAY;AAAA,EAC9C;AAAA,EAEA,MAAM,gBAAgB,gBAAsD;AAC1E,WAAO,KAAK,cAAc,IAAI,cAAc,KAAK;AAAA,EACnD;AAAA,EAEA,MAAM,kBAAkB,SAKI;AAC1B,QAAI,gBAAgB,MAAM,KAAK,KAAK,cAAc,OAAO,CAAC;AAE1D,QAAI,SAAS;AACX,UAAI,QAAQ,QAAQ;AAClB,wBAAgB,cAAc,OAAO,QAAM,GAAG,WAAW,QAAQ,MAAM;AAAA,MACzE;AACA,UAAI,QAAQ,UAAU;AACpB,wBAAgB,cAAc,OAAO,QAAM,GAAG,aAAa,QAAQ,QAAQ;AAAA,MAC7E;AACA,UAAI,QAAQ,aAAa,QAAW;AAClC,YAAI,QAAQ,UAAU;AACpB,0BAAgB,cAAc,OAAO,QAAM,GAAG,oCAAsC;AAAA,QACtF,OAAO;AACL,0BAAgB,cAAc,OAAO,QAAM,GAAG,oCAAsC;AAAA,QACtF;AAAA,MACF;AAAA,IACF;AAEA,WAAO;AAAA,EACT;AAAA,EAEA,MAAM,mBACJ,gBACA,SACuB;AACvB,UAAM,eAAe,KAAK,cAAc,IAAI,cAAc;AAC1D,QAAI,CAAC,cAAc;AACjB,YAAM,IAAI,MAAM,yBAAyB;AAAA,IAC3C;AAGA,UAAM,iBAAiB,EAAE,GAAG,QAAQ;AACpC,WAAO,eAAe;AACtB,WAAO,eAAe;AACtB,WAAO,eAAe;AACtB,WAAO,eAAe;AAEtB,WAAO,OAAO,cAAc,gBAAgB,EAAE,WAAW,oBAAI,KAAK,EAAE,CAAC;AAErE,WAAO;AAAA,EACT;AAAA,EAEA,MAAM,mBAAmB,gBAA0C;AACjE,UAAM,eAAe,KAAK,cAAc,IAAI,cAAc;AAC1D,QAAI,CAAC,cAAc;AACjB,aAAO;AAAA,IACT;AAGA,QAAI,MAAM,KAAK,oBAAoB,cAAc,GAAG;AAClD,YAAM,IAAI,MAAM,sDAAsD;AAAA,IACxE;AAEA,SAAK,cAAc,OAAO,cAAc;AACxC,SAAK,kBAAkB,OAAO,cAAc;AAE5C,WAAO;AAAA,EACT;AAAA,EAEA,MAAc,oBAAoB,gBAA0C;AAE1E,WAAO;AAAA,EACT;AAAA,EAEA,MAAM,kBAAkB,gBAAwB,QAA+B;AAC7E,UAAM,eAAe,KAAK,cAAc,IAAI,cAAc;AAC1D,QAAI,CAAC,cAAc;AACjB,YAAM,IAAI,MAAM,yBAAyB;AAAA,IAC3C;AAEA,iBAAa;AACb,iBAAa,YAAY,oBAAI,KAAK;AAGlC,YAAQ,IAAI,iBAAiB,cAAc,aAAa,MAAM,EAAE;AAAA,EAClE;AAAA,EAEA,MAAM,oBAAoB,gBAAuC;AAC/D,UAAM,eAAe,KAAK,cAAc,IAAI,cAAc;AAC1D,QAAI,CAAC,cAAc;AACjB,YAAM,IAAI,MAAM,yBAAyB;AAAA,IAC3C;AAEA,QAAI,aAAa,oCAAuC;AACtD,YAAM,IAAI,MAAM,8BAA8B;AAAA,IAChD;AAGA,iBAAa,SAAS,aAAa;AAGnC,iBAAa,YAAY,oBAAI,KAAK;AAAA,EACpC;AAAA,EAEA,MAAM,+BAA+B,gBAGlC;AACD,UAAM,eAAe,KAAK,cAAc,IAAI,cAAc;AAC1D,UAAM,SAAmB,CAAC;AAE1B,QAAI,CAAC,cAAc;AACjB,aAAO,KAAK,yBAAyB;AACrC,aAAO,EAAE,SAAS,OAAO,OAAO;AAAA,IAClC;AAEA,QAAI,aAAa,sCAAwC;AACvD,aAAO,KAAK,2BAA2B,aAAa,MAAM,oBAAoB;AAAA,IAChF;AAEA,QAAI,CAAC,aAAa,YAAY;AAC5B,aAAO,KAAK,qCAAqC;AAAA,IACnD;AAGA,QAAI,aAAa,YAAY;AAC3B,YAAM,aAAa,IAAI,KAAK,KAAK,IAAI,IAAI,MAAM,KAAK,KAAK,KAAK,GAAI;AAClE,UAAI,aAAa,aAAa,YAAY;AACxC,eAAO,KAAK,wCAAwC;AAAA,MACtD;AAAA,IACF;AAEA,WAAO;AAAA,MACL,SAAS,OAAO,WAAW;AAAA,MAC3B;AAAA,IACF;AAAA,EACF;AAAA,EAEQ,yBAAiC;AACvC,WAAO,MAAM,KAAK,IAAI,CAAC,IAAI,KAAK,OAAO,EAAE,SAAS,EAAE,EAAE,OAAO,GAAG,CAAC,CAAC;AAAA,EACpE;AAAA,EAEQ,2BAAmC;AACzC,WAAO,KAAK,MAAM,MAAS,KAAK,OAAO,IAAI,GAAM,EAAE,SAAS;AAAA,EAC9D;AAAA;AAAA,EAGA,UAAgB;AACd,UAAM,MAAM,oBAAI,KAAK;AACrB,eAAW,CAAC,IAAI,YAAY,KAAK,KAAK,mBAAmB;AACvD,UAAI,MAAM,aAAa,WAAW;AAChC,aAAK,kBAAkB,OAAO,EAAE;AAGhC,cAAM,eAAe,KAAK,cAAc,IAAI,EAAE;AAC9C,YAAI,gBAAgB,aAAa,wCAAyC;AACxE,uBAAa;AACb,iBAAO,aAAa;AACpB,uBAAa,YAAY,oBAAI,KAAK;AAAA,QACpC;AAAA,MACF;AAAA,IACF;AAAA,EACF;AACF;;;AChTA,oBAA6B;AAuDtB,IAAM,cAAN,cAA0B,2BAAa;AAAA,EAgB5C,YAAoB,UAAuC,CAAC,GAAG;AAC7D,UAAM;AADY;AAfpB,SAAQ,WAAW,oBAAI,IAAqB;AAC5C,SAAQ,gBAAgB,oBAAI,IAA0B;AACtD,SAAQ,YAA6B,CAAC;AAGtC,SAAQ,iBAAqC;AAAA,MAC3C,gBAAgB;AAAA,MAChB,qBAAqB;AAAA,MACrB,iBAAiB;AAAA,MACjB,aAAa;AAAA,MACb,kBAAkB;AAAA,MAClB,aAAa;AAAA,MACb,iBAAiB;AAAA;AAAA,IACnB;AAIE,SAAK,UAAU,EAAE,GAAG,KAAK,gBAAgB,GAAG,QAAQ;AAEpD,QAAI,KAAK,QAAQ,aAAa;AAC5B,WAAK,iBAAiB;AAAA,IACxB;AAAA,EACF;AAAA;AAAA,EAGA,MAAM,cAAc,SAA+B,QAAmC;AACpF,UAAM,YAAY,KAAK,kBAAkB;AAEzC,UAAM,UAAmB;AAAA,MACvB,IAAI;AAAA,MACJ,MAAM,QAAQ;AAAA,MACd,UAAU,QAAQ;AAAA,MAClB,MAAM,QAAQ;AAAA,MACd;AAAA,MACA,YAAY,QAAQ;AAAA,MACpB,eAAe,CAAC;AAAA,MAChB,UAAU;AAAA,QACR,cAAc,QAAQ;AAAA,QACtB,WAAW,QAAQ;AAAA,QACnB,QAAQ,KAAK,iBAAiB,QAAQ,IAAI;AAAA,QAC1C,UAAU,KAAK,mBAAmB,QAAQ,IAAI;AAAA,MAChD;AAAA,MACA,cAAc;AAAA,QACZ,QAAQ,QAAQ;AAAA,QAChB,WAAW,CAAC;AAAA,MACd;AAAA,MACA,WAAW,oBAAI,KAAK;AAAA,MACpB,WAAW,oBAAI,KAAK;AAAA,IACtB;AAEA,SAAK,SAAS,IAAI,WAAW,OAAO;AAGpC,QAAI,KAAK,QAAQ,gBAAgB;AAC/B,WAAK,YAAY,WAAW,WAAW,UAAU,QAAQ,QAAW,OAAO;AAAA,IAC7E;AAGA,QAAI,KAAK,QAAQ,qBAAqB;AACpC,WAAK,KAAK,mBAAmB,EAAE,SAAS,OAAO,CAAC;AAAA,IAClD;AAEA,WAAO;AAAA,EACT;AAAA,EAEA,MAAM,WAAW,WAAmB,QAA0C;AAC5E,UAAM,UAAU,KAAK,SAAS,IAAI,SAAS;AAE3C,QAAI,WAAW,KAAK,QAAQ,gBAAgB;AAC1C,WAAK,YAAY,WAAW,WAAW,QAAQ,MAAM;AAAA,IACvD;AAEA,WAAO,WAAW;AAAA,EACpB;AAAA,EAEA,MAAM,cACJ,WACA,SACA,QACkB;AAClB,UAAM,UAAU,KAAK,SAAS,IAAI,SAAS;AAC3C,QAAI,CAAC,SAAS;AACZ,YAAM,IAAI,MAAM,WAAW,SAAS,YAAY;AAAA,IAClD;AAEA,UAAM,SAAS,KAAK,QAAQ,iBAAiB,EAAE,GAAG,QAAQ,IAAI;AAG9D,UAAM,iBAAiB;AAAA,MACrB,GAAG;AAAA,MACH,GAAG;AAAA,MACH,IAAI;AAAA;AAAA,MACJ,WAAW,oBAAI,KAAK;AAAA,IACtB;AAEA,SAAK,SAAS,IAAI,WAAW,cAAc;AAG3C,QAAI,KAAK,QAAQ,gBAAgB;AAC/B,WAAK,YAAY,WAAW,WAAW,UAAU,QAAQ,QAAQ,cAAc;AAAA,IACjF;AAGA,QAAI,KAAK,QAAQ,qBAAqB;AACpC,WAAK,KAAK,mBAAmB;AAAA,QAC3B,SAAS;AAAA,QACT,iBAAiB;AAAA,QACjB;AAAA,MACF,CAAC;AAAA,IACH;AAEA,WAAO;AAAA,EACT;AAAA,EAEA,MAAM,cAAc,WAAmB,QAAmC;AACxE,UAAM,UAAU,KAAK,SAAS,IAAI,SAAS;AAC3C,QAAI,CAAC,SAAS;AACZ,aAAO;AAAA,IACT;AAEA,QAAI,KAAK,QAAQ,kBAAkB;AAEjC,cAAQ;AACR,cAAQ,YAAY,oBAAI,KAAK;AAAA,IAC/B,OAAO;AAEL,WAAK,SAAS,OAAO,SAAS;AAG9B,iBAAW,CAAC,IAAI,YAAY,KAAK,KAAK,eAAe;AAAA,MAGrD;AAAA,IACF;AAGA,QAAI,KAAK,QAAQ,gBAAgB;AAC/B,WAAK,YAAY,WAAW,WAAW,UAAU,QAAQ,OAAO;AAAA,IAClE;AAGA,QAAI,KAAK,QAAQ,qBAAqB;AACpC,WAAK,KAAK,mBAAmB,EAAE,SAAS,OAAO,CAAC;AAAA,IAClD;AAEA,WAAO;AAAA,EACT;AAAA,EAEA,MAAM,aACJ,UAA0B,CAAC,GAC3B,aAAgC,EAAE,MAAM,GAAG,OAAO,KAAK,QAAQ,gBAAiB,GAC7C;AACnC,QAAI,WAAW,MAAM,KAAK,KAAK,SAAS,OAAO,CAAC;AAGhD,QAAI,QAAQ,UAAU;AACpB,iBAAW,SAAS,OAAO,OAAK,EAAE,aAAa,QAAQ,QAAQ;AAAA,IACjE;AACA,QAAI,QAAQ,MAAM;AAChB,iBAAW,SAAS,OAAO,OAAK,EAAE,SAAS,QAAQ,IAAI;AAAA,IACzD;AACA,QAAI,QAAQ,QAAQ;AAClB,iBAAW,SAAS,OAAO,OAAK,EAAE,WAAW,QAAQ,MAAM;AAAA,IAC7D;AACA,QAAI,QAAQ,aAAa,QAAW;AAClC,YAAM,eAAe,QAAQ;AAC7B,iBAAW,SAAS,OAAO,OAAK,EAAE,aAAa,WAAW,YAAY;AAAA,IACxE;AACA,QAAI,QAAQ,cAAc;AACxB,iBAAW,SAAS,OAAO,OAAK,EAAE,aAAa,QAAQ,YAAa;AAAA,IACtE;AACA,QAAI,QAAQ,eAAe;AACzB,iBAAW,SAAS,OAAO,OAAK,EAAE,aAAa,QAAQ,aAAc;AAAA,IACvE;AAGA,QAAI,CAAC,QAAQ,UAAU,QAAQ,oCAAkC;AAC/D,iBAAW,SAAS,OAAO,OAAK,EAAE,kCAAgC;AAAA,IACpE;AAGA,UAAM,SAAS,WAAW,UAAU;AACpC,UAAM,YAAY,WAAW,aAAa;AAE1C,aAAS,KAAK,CAAC,GAAG,MAAM;AACtB,UAAI,QAAa;AAEjB,cAAQ,QAAQ;AAAA,QACd,KAAK;AACH,mBAAS,EAAE;AACX,mBAAS,EAAE;AACX;AAAA,QACF,KAAK;AACH,mBAAS,EAAE,UAAU,QAAQ;AAC7B,mBAAS,EAAE,UAAU,QAAQ;AAC7B;AAAA,QACF,KAAK;AACH,mBAAS,EAAE,UAAU,QAAQ;AAC7B,mBAAS,EAAE,UAAU,QAAQ;AAC7B;AAAA,QACF;AACE,mBAAS,EAAE,UAAU,QAAQ;AAC7B,mBAAS,EAAE,UAAU,QAAQ;AAAA,MACjC;AAEA,UAAI,cAAc,OAAO;AACvB,eAAO,SAAS,SAAS,KAAK,SAAS,SAAS,IAAI;AAAA,MACtD,OAAO;AACL,eAAO,SAAS,SAAS,KAAK,SAAS,SAAS,IAAI;AAAA,MACtD;AAAA,IACF,CAAC;AAGD,UAAM,QAAQ,SAAS;AACvB,UAAM,QAAQ,KAAK,IAAI,WAAW,OAAO,KAAK,QAAQ,WAAY;AAClE,UAAM,OAAO,KAAK,IAAI,GAAG,WAAW,IAAI;AACxC,UAAM,UAAU,OAAO,KAAK;AAC5B,UAAM,oBAAoB,SAAS,MAAM,QAAQ,SAAS,KAAK;AAE/D,WAAO;AAAA,MACL,MAAM;AAAA,MACN;AAAA,MACA;AAAA,MACA;AAAA,MACA,YAAY,KAAK,KAAK,QAAQ,KAAK;AAAA,MACnC,SAAS,SAAS,QAAQ;AAAA,MAC1B,SAAS,OAAO;AAAA,IAClB;AAAA,EACF;AAAA;AAAA,EAGA,MAAM,mBACJ,WACA,SACA,QACuB;AACvB,UAAM,UAAU,KAAK,SAAS,IAAI,SAAS;AAC3C,QAAI,CAAC,SAAS;AACZ,YAAM,IAAI,MAAM,WAAW,SAAS,YAAY;AAAA,IAClD;AAEA,UAAM,iBAAiB,KAAK,uBAAuB;AAEnD,UAAM,eAA6B;AAAA,MACjC,IAAI;AAAA,MACJ,aAAa,QAAQ;AAAA,MACrB;AAAA,MACA,UAAU,QAAQ;AAAA,MAClB,UAAU;AAAA,QACR,cAAc,QAAQ,cAAc;AAAA,QACpC,4BAA4B,QAAQ,cAAc;AAAA,QAClD,eAAe,QAAQ,cAAc;AAAA,QACrC,cAAc,QAAQ,cAAc;AAAA,MACtC;AAAA,MACA,WAAW,oBAAI,KAAK;AAAA,MACpB,WAAW,oBAAI,KAAK;AAAA,IACtB;AAEA,SAAK,cAAc,IAAI,gBAAgB,YAAY;AAGnD,YAAQ,cAAc,KAAK,YAAY;AACvC,YAAQ,YAAY,oBAAI,KAAK;AAG7B,QAAI,KAAK,QAAQ,gBAAgB;AAC/B,WAAK,YAAY,gBAAgB,gBAAgB,UAAU,QAAQ,QAAW,YAAY;AAAA,IAC5F;AAGA,QAAI,KAAK,QAAQ,qBAAqB;AACpC,WAAK,KAAK,wBAAwB,EAAE,cAAc,WAAW,OAAO,CAAC;AAAA,IACvE;AAEA,WAAO;AAAA,EACT;AAAA,EAEA,MAAM,gBAAgB,gBAAwB,QAA+C;AAC3F,UAAM,eAAe,KAAK,cAAc,IAAI,cAAc;AAE1D,QAAI,gBAAgB,KAAK,QAAQ,gBAAgB;AAC/C,WAAK,YAAY,gBAAgB,gBAAgB,QAAQ,MAAM;AAAA,IACjE;AAEA,WAAO,gBAAgB;AAAA,EACzB;AAAA,EAEA,MAAM,mBACJ,gBACA,SACA,QACuB;AACvB,UAAM,eAAe,KAAK,cAAc,IAAI,cAAc;AAC1D,QAAI,CAAC,cAAc;AACjB,YAAM,IAAI,MAAM,iBAAiB,cAAc,YAAY;AAAA,IAC7D;AAEA,UAAM,SAAS,KAAK,QAAQ,iBAAiB,EAAE,GAAG,aAAa,IAAI;AAGnE,UAAM,sBAAsB;AAAA,MAC1B,GAAG;AAAA,MACH,GAAG;AAAA,MACH,IAAI;AAAA;AAAA,MACJ,WAAW,oBAAI,KAAK;AAAA,IACtB;AAEA,SAAK,cAAc,IAAI,gBAAgB,mBAAmB;AAG1D,eAAW,WAAW,KAAK,SAAS,OAAO,GAAG;AAC5C,YAAM,QAAQ,QAAQ,cAAc,UAAU,QAAM,GAAG,OAAO,cAAc;AAC5E,UAAI,UAAU,IAAI;AAChB,gBAAQ,cAAc,KAAK,IAAI;AAC/B,gBAAQ,YAAY,oBAAI,KAAK;AAC7B;AAAA,MACF;AAAA,IACF;AAGA,QAAI,KAAK,QAAQ,gBAAgB;AAC/B,WAAK,YAAY,gBAAgB,gBAAgB,UAAU,QAAQ,QAAQ,mBAAmB;AAAA,IAChG;AAGA,QAAI,KAAK,QAAQ,qBAAqB;AACpC,WAAK,KAAK,wBAAwB;AAAA,QAChC,cAAc;AAAA,QACd,sBAAsB;AAAA,QACtB;AAAA,MACF,CAAC;AAAA,IACH;AAEA,WAAO;AAAA,EACT;AAAA,EAEA,MAAM,mBAAmB,gBAAwB,QAAmC;AAClF,UAAM,eAAe,KAAK,cAAc,IAAI,cAAc;AAC1D,QAAI,CAAC,cAAc;AACjB,aAAO;AAAA,IACT;AAGA,SAAK,cAAc,OAAO,cAAc;AAGxC,eAAW,WAAW,KAAK,SAAS,OAAO,GAAG;AAC5C,YAAM,QAAQ,QAAQ,cAAc,UAAU,QAAM,GAAG,OAAO,cAAc;AAC5E,UAAI,UAAU,IAAI;AAChB,gBAAQ,cAAc,OAAO,OAAO,CAAC;AACrC,gBAAQ,YAAY,oBAAI,KAAK;AAC7B;AAAA,MACF;AAAA,IACF;AAGA,QAAI,KAAK,QAAQ,gBAAgB;AAC/B,WAAK,YAAY,gBAAgB,gBAAgB,UAAU,QAAQ,YAAY;AAAA,IACjF;AAGA,QAAI,KAAK,QAAQ,qBAAqB;AACpC,WAAK,KAAK,wBAAwB,EAAE,cAAc,OAAO,CAAC;AAAA,IAC5D;AAEA,WAAO;AAAA,EACT;AAAA,EAEA,MAAM,kBACJ,UAA+B,CAAC,GAChC,aAAgC,EAAE,MAAM,GAAG,OAAO,KAAK,QAAQ,gBAAiB,GACxC;AACxC,QAAI,gBAAgB,MAAM,KAAK,KAAK,cAAc,OAAO,CAAC;AAG1D,QAAI,QAAQ,WAAW;AACrB,YAAM,UAAU,KAAK,SAAS,IAAI,QAAQ,SAAS;AACnD,UAAI,SAAS;AACX,wBAAgB,QAAQ;AAAA,MAC1B,OAAO;AACL,wBAAgB,CAAC;AAAA,MACnB;AAAA,IACF;AACA,QAAI,QAAQ,QAAQ;AAClB,sBAAgB,cAAc,OAAO,QAAM,GAAG,WAAW,QAAQ,MAAM;AAAA,IACzE;AACA,QAAI,QAAQ,UAAU;AACpB,sBAAgB,cAAc,OAAO,QAAM,GAAG,aAAa,QAAQ,QAAQ;AAAA,IAC7E;AACA,QAAI,QAAQ,aAAa,QAAW;AAClC,UAAI,QAAQ,UAAU;AACpB,wBAAgB,cAAc,OAAO,QAAM,GAAG,oCAAsC;AAAA,MACtF,OAAO;AACL,wBAAgB,cAAc,OAAO,QAAM,GAAG,oCAAsC;AAAA,MACtF;AAAA,IACF;AAGA,UAAM,SAAS,WAAW,UAAU;AACpC,UAAM,YAAY,WAAW,aAAa;AAE1C,kBAAc,KAAK,CAAC,GAAG,MAAM;AAC3B,UAAI,QAAa;AAEjB,cAAQ,QAAQ;AAAA,QACd,KAAK;AACH,mBAAS,EAAE;AACX,mBAAS,EAAE;AACX;AAAA,QACF,KAAK;AACH,mBAAS,EAAE,UAAU,QAAQ;AAC7B,mBAAS,EAAE,UAAU,QAAQ;AAC7B;AAAA,QACF,KAAK;AACH,mBAAS,EAAE,UAAU,QAAQ;AAC7B,mBAAS,EAAE,UAAU,QAAQ;AAC7B;AAAA,QACF;AACE,mBAAS,EAAE,UAAU,QAAQ;AAC7B,mBAAS,EAAE,UAAU,QAAQ;AAAA,MACjC;AAEA,UAAI,cAAc,OAAO;AACvB,eAAO,SAAS,SAAS,KAAK,SAAS,SAAS,IAAI;AAAA,MACtD,OAAO;AACL,eAAO,SAAS,SAAS,KAAK,SAAS,SAAS,IAAI;AAAA,MACtD;AAAA,IACF,CAAC;AAGD,UAAM,QAAQ,cAAc;AAC5B,UAAM,QAAQ,KAAK,IAAI,WAAW,OAAO,KAAK,QAAQ,WAAY;AAClE,UAAM,OAAO,KAAK,IAAI,GAAG,WAAW,IAAI;AACxC,UAAM,UAAU,OAAO,KAAK;AAC5B,UAAM,yBAAyB,cAAc,MAAM,QAAQ,SAAS,KAAK;AAEzE,WAAO;AAAA,MACL,MAAM;AAAA,MACN;AAAA,MACA;AAAA,MACA;AAAA,MACA,YAAY,KAAK,KAAK,QAAQ,KAAK;AAAA,MACnC,SAAS,SAAS,QAAQ;AAAA,MAC1B,SAAS,OAAO;AAAA,IAClB;AAAA,EACF;AAAA;AAAA,EAGA,aACE,YACA,UACA,QAAgB,KACC;AACjB,QAAI,OAAO,CAAC,GAAG,KAAK,SAAS;AAE7B,QAAI,YAAY;AACd,aAAO,KAAK,OAAO,SAAO,IAAI,eAAe,UAAU;AAAA,IACzD;AACA,QAAI,UAAU;AACZ,aAAO,KAAK,OAAO,SAAO,IAAI,aAAa,QAAQ;AAAA,IACrD;AAEA,WAAO,KACJ,KAAK,CAAC,GAAG,MAAM,EAAE,UAAU,QAAQ,IAAI,EAAE,UAAU,QAAQ,CAAC,EAC5D,MAAM,GAAG,KAAK;AAAA,EACnB;AAAA,EAEA,gBAYE;AACA,UAAM,WAAW,MAAM,KAAK,KAAK,SAAS,OAAO,CAAC;AAClD,UAAM,gBAAgB,MAAM,KAAK,KAAK,cAAc,OAAO,CAAC;AAE5D,UAAM,mBAA2C,CAAC;AAClD,UAAM,iBAAyC,CAAC;AAChD,UAAM,qBAA6C,CAAC;AAEpD,aAAS,QAAQ,aAAW;AAC1B,uBAAiB,QAAQ,MAAM,KAAK,iBAAiB,QAAQ,MAAM,KAAK,KAAK;AAC7E,qBAAe,QAAQ,IAAI,KAAK,eAAe,QAAQ,IAAI,KAAK,KAAK;AACrE,yBAAmB,QAAQ,QAAQ,KAAK,mBAAmB,QAAQ,QAAQ,KAAK,KAAK;AAAA,IACvF,CAAC;AAED,UAAM,wBAAgD,CAAC;AACvD,UAAM,0BAAkD,CAAC;AAEzD,kBAAc,QAAQ,kBAAgB;AACpC,4BAAsB,aAAa,MAAM,KAAK,sBAAsB,aAAa,MAAM,KAAK,KAAK;AACjG,8BAAwB,aAAa,QAAQ,KAAK,wBAAwB,aAAa,QAAQ,KAAK,KAAK;AAAA,IAC3G,CAAC;AAED,WAAO;AAAA,MACL,UAAU;AAAA,QACR,OAAO,SAAS;AAAA,QAChB,UAAU;AAAA,QACV,QAAQ;AAAA,QACR,YAAY;AAAA,MACd;AAAA,MACA,eAAe;AAAA,QACb,OAAO,cAAc;AAAA,QACrB,UAAU;AAAA,QACV,YAAY;AAAA,MACd;AAAA,IACF;AAAA,EACF;AAAA;AAAA,EAGA,UAGE;AACA,QAAI,kBAAkB;AACtB,QAAI,mBAAmB;AAGvB,UAAM,gBAAgB,IAAI,KAAK,KAAK,IAAI,IAAI,KAAK,KAAK,KAAK,KAAK,GAAI;AAEpE,eAAW,CAAC,IAAI,OAAO,KAAK,KAAK,UAAU;AACzC,UAAI,QAAQ,sCAAoC,QAAQ,YAAY,eAAe;AACjF,aAAK,SAAS,OAAO,EAAE;AACvB;AAAA,MACF;AAAA,IACF;AAGA,UAAM,gBAAgB,IAAI,KAAK,KAAK,IAAI,IAAI,KAAK,KAAK,KAAK,KAAK,GAAI;AACpE,UAAM,mBAAmB,KAAK,UAAU;AACxC,SAAK,YAAY,KAAK,UAAU,OAAO,SAAO,IAAI,aAAa,aAAa;AAC5E,uBAAmB,mBAAmB,KAAK,UAAU;AAErD,WAAO,EAAE,iBAAiB,iBAAiB;AAAA,EAC7C;AAAA,EAEA,UAAgB;AACd,QAAI,KAAK,cAAc;AACrB,oBAAc,KAAK,YAAY;AAC/B,WAAK,eAAe;AAAA,IACtB;AAEA,SAAK,mBAAmB;AACxB,SAAK,SAAS,MAAM;AACpB,SAAK,cAAc,MAAM;AACzB,SAAK,YAAY,CAAC;AAAA,EACpB;AAAA,EAEQ,YACN,YACA,UACA,QACA,QACA,QACA,OACM;AACN,UAAM,WAA0B;AAAA,MAC9B,IAAI,KAAK,mBAAmB;AAAA,MAC5B;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA,WAAW,oBAAI,KAAK;AAAA,MACpB,SAAS,UAAU,QAAQ,EAAE,QAAQ,MAAM,IAAI;AAAA,IACjD;AAEA,SAAK,UAAU,KAAK,QAAQ;AAG5B,QAAI,KAAK,UAAU,SAAS,KAAO;AACjC,WAAK,YAAY,KAAK,UAAU,MAAM,IAAM;AAAA,IAC9C;AAAA,EACF;AAAA,EAEQ,iBAAiB,aAA0B;AACjD,YAAQ,aAAa;AAAA,MACnB;AACE,eAAO;AAAA,UACL,mBAAmB;AAAA,UACnB,qBAAqB;AAAA,UACrB,WAAW;AAAA,QACb;AAAA,MACF;AACE,eAAO;AAAA,UACL,mBAAmB;AAAA,UACnB,qBAAqB;AAAA,UACrB,WAAW;AAAA,QACb;AAAA,MACF;AAAA,MACA;AAAA,MACA;AACE,eAAO;AAAA,UACL,mBAAmB;AAAA,UACnB,qBAAqB;AAAA,UACrB,WAAW;AAAA,QACb;AAAA,MACF;AACE,eAAO;AAAA,UACL,mBAAmB;AAAA,UACnB,qBAAqB;AAAA,UACrB,WAAW;AAAA,QACb;AAAA,IACJ;AAAA,EACF;AAAA,EAEQ,mBAAmB,aAA0B;AACnD,YAAQ,aAAa;AAAA,MACnB;AACE,eAAO;AAAA,UACL,qBAAqB;AAAA,UACrB,oBAAoB;AAAA,UACpB,iBAAiB;AAAA,UACjB,gBAAgB;AAAA,QAClB;AAAA,MACF;AACE,eAAO;AAAA,UACL,qBAAqB;AAAA,UACrB,oBAAoB;AAAA,UACpB,iBAAiB;AAAA,UACjB,gBAAgB;AAAA,QAClB;AAAA,MACF;AACE,eAAO;AAAA,UACL,qBAAqB;AAAA,UACrB,oBAAoB;AAAA,UACpB,iBAAiB;AAAA,UACjB,gBAAgB;AAAA,QAClB;AAAA,IACJ;AAAA,EACF;AAAA,EAEQ,mBAAyB;AAC/B,SAAK,eAAe,YAAY,MAAM;AACpC,WAAK,QAAQ;AAAA,IACf,GAAG,KAAK,QAAQ,eAAgB;AAAA,EAClC;AAAA,EAEQ,oBAA4B;AAClC,WAAO,MAAM,KAAK,IAAI,CAAC,IAAI,KAAK,OAAO,EAAE,SAAS,EAAE,EAAE,OAAO,GAAG,CAAC,CAAC;AAAA,EACpE;AAAA,EAEQ,yBAAiC;AACvC,WAAO,MAAM,KAAK,IAAI,CAAC,IAAI,KAAK,OAAO,EAAE,SAAS,EAAE,EAAE,OAAO,GAAG,CAAC,CAAC;AAAA,EACpE;AAAA,EAEQ,qBAA6B;AACnC,WAAO,SAAS,KAAK,IAAI,CAAC,IAAI,KAAK,OAAO,EAAE,SAAS,EAAE,EAAE,OAAO,GAAG,CAAC,CAAC;AAAA,EACvE;AACF;;;ACvsBA,IAAAC,iBAA6B;AA8BtB,IAAK,eAAL,kBAAKC,kBAAL;AACL,EAAAA,cAAA,aAAU;AACV,EAAAA,cAAA,mBAAgB;AAChB,EAAAA,cAAA,cAAW;AACX,EAAAA,cAAA,aAAU;AACV,EAAAA,cAAA,UAAO;AACP,EAAAA,cAAA,UAAO;AACP,EAAAA,cAAA,eAAY;AACZ,EAAAA,cAAA,eAAY;AARF,SAAAA;AAAA,GAAA;AAWL,IAAK,aAAL,kBAAKC,gBAAL;AACL,EAAAA,YAAA,YAAS;AACT,EAAAA,YAAA,UAAO;AACP,EAAAA,YAAA,YAAS;AACT,EAAAA,YAAA,YAAS;AACT,EAAAA,YAAA,YAAS;AACT,EAAAA,YAAA,aAAU;AACV,EAAAA,YAAA,cAAW;AACX,EAAAA,YAAA,UAAO;AACP,EAAAA,YAAA,YAAS;AATC,SAAAA;AAAA,GAAA;AAYL,IAAK,kBAAL,kBAAKC,qBAAL;AACL,EAAAA,iBAAA,YAAS;AACT,EAAAA,iBAAA,kBAAe;AACf,EAAAA,iBAAA,UAAO;AACP,EAAAA,iBAAA,cAAW;AAJD,SAAAA;AAAA,GAAA;AAoCL,IAAM,oBAAN,cAAgC,4BAAa;AAAA;AAAA,EASlD,cAAc;AACZ,UAAM;AATR,SAAQ,QAAQ,oBAAI,IAAkB;AACtC,SAAQ,QAAQ,oBAAI,IAAkB;AACtC,SAAQ,gBAAgB,oBAAI,IAAyB;AACrD,SAAQ,kBAAkB,oBAAI,IAA8B;AAC5D,SAAQ,cAAc,oBAAI,IAAoB;AAE9C,SAAiB,iBAAiB,IAAI,KAAK;AAIzC,SAAK,sBAAsB;AAAA,EAC7B;AAAA;AAAA,EAGA,MAAM,WAAW,UAAuE;AACtF,UAAM,SAAS,KAAK,eAAe;AAEnC,UAAM,OAAa;AAAA,MACjB,GAAG;AAAA,MACH,IAAI;AAAA,MACJ,WAAW,oBAAI,KAAK;AAAA,MACpB,WAAW,oBAAI,KAAK;AAAA,IACtB;AAEA,SAAK,MAAM,IAAI,QAAQ,IAAI;AAC3B,SAAK,oBAAoB,QAAQ,KAAK,MAAM,IAAI,OAAK,EAAE,EAAE,CAAC;AAE1D,SAAK,KAAK,gBAAgB,EAAE,KAAK,CAAC;AAClC,WAAO;AAAA,EACT;AAAA,EAEA,MAAM,QAAQ,QAAsC;AAClD,WAAO,KAAK,MAAM,IAAI,MAAM,KAAK;AAAA,EACnC;AAAA,EAEA,MAAM,WAAW,QAAgB,SAAuC;AACtE,UAAM,OAAO,KAAK,MAAM,IAAI,MAAM;AAClC,QAAI,CAAC,MAAM;AACT,YAAM,IAAI,MAAM,gBAAgB;AAAA,IAClC;AAEA,UAAM,cAAc;AAAA,MAClB,GAAG;AAAA,MACH,GAAG;AAAA,MACH,IAAI;AAAA,MACJ,WAAW,oBAAI,KAAK;AAAA,IACtB;AAEA,SAAK,MAAM,IAAI,QAAQ,WAAW;AAGlC,QAAI,QAAQ,OAAO;AACjB,WAAK,oBAAoB,QAAQ,QAAQ,MAAM,IAAI,OAAK,EAAE,EAAE,CAAC;AAAA,IAC/D;AAGA,SAAK,yBAAyB,MAAM;AAEpC,SAAK,KAAK,gBAAgB,EAAE,MAAM,aAAa,cAAc,KAAK,CAAC;AACnE,WAAO;AAAA,EACT;AAAA,EAEA,MAAM,WAAW,QAAkC;AACjD,UAAM,OAAO,KAAK,MAAM,IAAI,MAAM;AAClC,QAAI,CAAC,MAAM;AACT,aAAO;AAAA,IACT;AAEA,SAAK,MAAM,OAAO,MAAM;AACxB,SAAK,cAAc,OAAO,MAAM;AAChC,SAAK,yBAAyB,MAAM;AAEpC,SAAK,KAAK,gBAAgB,EAAE,KAAK,CAAC;AAClC,WAAO;AAAA,EACT;AAAA;AAAA,EAGA,MAAM,WAAW,UAAuE;AACtF,UAAM,SAAS,KAAK,eAAe;AAEnC,UAAM,OAAa;AAAA,MACjB,GAAG;AAAA,MACH,IAAI;AAAA,MACJ,WAAW,oBAAI,KAAK;AAAA,MACpB,WAAW,oBAAI,KAAK;AAAA,IACtB;AAEA,SAAK,MAAM,IAAI,QAAQ,IAAI;AAE3B,SAAK,KAAK,gBAAgB,EAAE,KAAK,CAAC;AAClC,WAAO;AAAA,EACT;AAAA,EAEA,MAAM,QAAQ,QAAsC;AAClD,WAAO,KAAK,MAAM,IAAI,MAAM,KAAK;AAAA,EACnC;AAAA,EAEA,MAAM,WAAW,QAAgB,SAAuC;AACtE,UAAM,OAAO,KAAK,MAAM,IAAI,MAAM;AAClC,QAAI,CAAC,MAAM;AACT,YAAM,IAAI,MAAM,gBAAgB;AAAA,IAClC;AAEA,QAAI,KAAK,YAAY,QAAQ,aAAa;AACxC,YAAM,IAAI,MAAM,2CAA2C;AAAA,IAC7D;AAEA,UAAM,cAAc;AAAA,MAClB,GAAG;AAAA,MACH,GAAG;AAAA,MACH,IAAI;AAAA,MACJ,WAAW,oBAAI,KAAK;AAAA,IACtB;AAEA,SAAK,MAAM,IAAI,QAAQ,WAAW;AAGlC,SAAK,yBAAyB,MAAM;AAEpC,SAAK,KAAK,gBAAgB,EAAE,MAAM,aAAa,cAAc,KAAK,CAAC;AACnE,WAAO;AAAA,EACT;AAAA,EAEA,MAAM,WAAW,QAAkC;AACjD,UAAM,OAAO,KAAK,MAAM,IAAI,MAAM;AAClC,QAAI,CAAC,MAAM;AACT,aAAO;AAAA,IACT;AAEA,QAAI,KAAK,UAAU;AACjB,YAAM,IAAI,MAAM,4BAA4B;AAAA,IAC9C;AAGA,UAAM,gBAAgB,MAAM,KAAK,KAAK,MAAM,OAAO,CAAC,EACjD,OAAO,UAAQ,KAAK,MAAM,KAAK,OAAK,EAAE,OAAO,MAAM,CAAC;AAEvD,QAAI,cAAc,SAAS,GAAG;AAC5B,YAAM,IAAI,MAAM,8CAA8C;AAAA,IAChE;AAEA,SAAK,MAAM,OAAO,MAAM;AAExB,SAAK,KAAK,gBAAgB,EAAE,KAAK,CAAC;AAClC,WAAO;AAAA,EACT;AAAA;AAAA,EAGA,MAAM,iBAAiB,QAAgB,QAA+B;AACpE,UAAM,OAAO,KAAK,MAAM,IAAI,MAAM;AAClC,UAAM,OAAO,KAAK,MAAM,IAAI,MAAM;AAElC,QAAI,CAAC,MAAM;AACT,YAAM,IAAI,MAAM,gBAAgB;AAAA,IAClC;AACA,QAAI,CAAC,MAAM;AACT,YAAM,IAAI,MAAM,gBAAgB;AAAA,IAClC;AAGA,QAAI,KAAK,MAAM,KAAK,OAAK,EAAE,OAAO,MAAM,GAAG;AACzC;AAAA,IACF;AAEA,SAAK,MAAM,KAAK,IAAI;AACpB,SAAK,YAAY,oBAAI,KAAK;AAE1B,SAAK,oBAAoB,QAAQ,KAAK,MAAM,IAAI,OAAK,EAAE,EAAE,CAAC;AAC1D,SAAK,yBAAyB,MAAM;AAEpC,SAAK,KAAK,iBAAiB,EAAE,QAAQ,OAAO,CAAC;AAAA,EAC/C;AAAA,EAEA,MAAM,mBAAmB,QAAgB,QAA+B;AACtE,UAAM,OAAO,KAAK,MAAM,IAAI,MAAM;AAClC,QAAI,CAAC,MAAM;AACT,YAAM,IAAI,MAAM,gBAAgB;AAAA,IAClC;AAEA,UAAM,YAAY,KAAK,MAAM,UAAU,OAAK,EAAE,OAAO,MAAM;AAC3D,QAAI,cAAc,IAAI;AACpB;AAAA,IACF;AAEA,SAAK,MAAM,OAAO,WAAW,CAAC;AAC9B,SAAK,YAAY,oBAAI,KAAK;AAE1B,SAAK,oBAAoB,QAAQ,KAAK,MAAM,IAAI,OAAK,EAAE,EAAE,CAAC;AAC1D,SAAK,yBAAyB,MAAM;AAEpC,SAAK,KAAK,gBAAgB,EAAE,QAAQ,OAAO,CAAC;AAAA,EAC9C;AAAA;AAAA,EAGA,MAAM,gBAAgB,OAAmD;AAEvE,UAAM,WAAW,KAAK,YAAY,KAAK;AACvC,UAAM,SAAS,KAAK,aAAa,QAAQ;AACzC,QAAI,QAAQ;AACV,aAAO;AAAA,IACT;AAEA,UAAM,SAAS,MAAM,KAAK,uBAAuB,KAAK;AAGtD,SAAK,SAAS,UAAU,MAAM;AAE9B,WAAO;AAAA,EACT;AAAA,EAEA,MAAM,cACJ,QACA,UACA,QACA,YACA,SACkB;AAClB,UAAM,SAAS,MAAM,KAAK,gBAAgB;AAAA,MACxC;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACF,CAAC;AAED,WAAO,OAAO;AAAA,EAChB;AAAA,EAEA,MAAM,kBACJ,QACA,UACA,QACA,YACA,SACe;AACf,UAAM,YAAY,MAAM,KAAK,cAAc,QAAQ,UAAU,QAAQ,YAAY,OAAO;AAExF,QAAI,CAAC,WAAW;AACd,YAAM,IAAI,MAAM,kBAAkB,MAAM,OAAO,QAAQ,EAAE;AAAA,IAC3D;AAAA,EACF;AAAA;AAAA,EAGA,MAAM,mBAAmB,QAAuC;AAC9D,UAAM,OAAO,KAAK,MAAM,IAAI,MAAM;AAClC,QAAI,CAAC,MAAM;AACT,aAAO,CAAC;AAAA,IACV;AAEA,UAAM,cAA4B,CAAC;AAEnC,eAAW,QAAQ,KAAK,OAAO;AAC7B,kBAAY,KAAK,GAAG,KAAK,WAAW;AAAA,IACtC;AAGA,UAAM,oBAAoB,YAAY;AAAA,MAAO,CAAC,YAAY,OAAO,SAC/D,UAAU,KAAK,UAAU,OAAK,EAAE,OAAO,WAAW,EAAE;AAAA,IACtD;AAEA,WAAO;AAAA,EACT;AAAA,EAEA,MAAM,aAAa,QAAiC;AAClD,UAAM,OAAO,KAAK,MAAM,IAAI,MAAM;AAClC,WAAO,OAAO,KAAK,QAAQ,CAAC;AAAA,EAC9B;AAAA,EAEA,UAAU,SAGC;AACT,QAAI,QAAQ,MAAM,KAAK,KAAK,MAAM,OAAO,CAAC;AAE1C,QAAI,SAAS,aAAa,QAAW;AACnC,cAAQ,MAAM,OAAO,OAAK,EAAE,aAAa,QAAQ,QAAQ;AAAA,IAC3D;AAEA,QAAI,SAAS,QAAQ;AACnB,cAAQ,MAAM,OAAO,OAAK,EAAE,MAAM,KAAK,OAAK,EAAE,OAAO,QAAQ,MAAM,CAAC;AAAA,IACtE;AAEA,WAAO;AAAA,EACT;AAAA,EAEA,YAAoB;AAClB,WAAO,MAAM,KAAK,KAAK,MAAM,OAAO,CAAC;AAAA,EACvC;AAAA;AAAA,EAGA,MAAc,uBAAuB,OAAmD;AACtF,UAAM,OAAO,KAAK,MAAM,IAAI,MAAM,MAAM;AACxC,QAAI,CAAC,MAAM;AACT,aAAO;AAAA,QACL,SAAS;AAAA,QACT,QAAQ;AAAA,QACR,oBAAoB,CAAC;AAAA,QACrB,eAAe,CAAC,gBAAgB;AAAA,MAClC;AAAA,IACF;AAEA,QAAI,CAAC,KAAK,UAAU;AAClB,aAAO;AAAA,QACL,SAAS;AAAA,QACT,QAAQ;AAAA,QACR,oBAAoB,CAAC;AAAA,QACrB,eAAe,CAAC,kBAAkB;AAAA,MACpC;AAAA,IACF;AAEA,UAAM,qBAAmC,CAAC;AAC1C,UAAM,gBAA0B,CAAC;AAGjC,eAAW,QAAQ,KAAK,OAAO;AAC7B,iBAAW,cAAc,KAAK,aAAa;AACzC,YAAI,KAAK,oBAAoB,YAAY,KAAK,GAAG;AAE/C,cAAI,MAAM,KAAK,gBAAgB,YAAY,KAAK,GAAG;AACjD,+BAAmB,KAAK,UAAU;AAAA,UACpC,OAAO;AACL,0BAAc,KAAK,qCAAqC,WAAW,EAAE,EAAE;AAAA,UACzE;AAAA,QACF;AAAA,MACF;AAAA,IACF;AAEA,UAAM,UAAU,mBAAmB,SAAS;AAE5C,WAAO;AAAA,MACL;AAAA,MACA,QAAQ,UAAU,SAAY;AAAA,MAC9B;AAAA,MACA,eAAe,UAAU,CAAC,IAAI;AAAA,IAChC;AAAA,EACF;AAAA,EAEQ,oBAAoB,YAAwB,OAAiC;AACnF,WAAO,WAAW,aAAa,MAAM,YAAY,WAAW,WAAW,MAAM;AAAA,EAC/E;AAAA,EAEA,MAAc,gBAAgB,YAAwB,OAA0C;AAC9F,QAAI,CAAC,WAAW,cAAc,WAAW,WAAW,WAAW,GAAG;AAChE,aAAO;AAAA,IACT;AAGA,eAAW,aAAa,WAAW,YAAY;AAC7C,UAAI,CAAC,MAAM,KAAK,kBAAkB,WAAW,KAAK,GAAG;AACnD,eAAO;AAAA,MACT;AAAA,IACF;AAEA,WAAO;AAAA,EACT;AAAA,EAEA,MAAc,kBAAkB,WAAgC,OAA0C;AACxG,QAAI;AAGJ,YAAQ,UAAU,OAAO;AAAA,MACvB,KAAK;AACH,sBAAc,MAAM;AACpB;AAAA,MACF,KAAK;AACH,sBAAc,MAAM,SAAS;AAC7B;AAAA,MACF,KAAK;AACH,sBAAc,MAAM,SAAS;AAC7B;AAAA,MACF,KAAK;AACH,sBAAc,MAAM,SAAS;AAC7B;AAAA,MACF;AACE,sBAAc,MAAM,SAAS,WAAW,UAAU,KAAK;AAAA,IAC3D;AAGA,YAAQ,UAAU,UAAU;AAAA,MAC1B,KAAK;AACH,eAAO,gBAAgB,UAAU;AAAA,MACnC,KAAK;AACH,eAAO,gBAAgB,UAAU;AAAA,MACnC,KAAK;AACH,eAAO,MAAM,QAAQ,UAAU,KAAK,KAAK,UAAU,MAAM,SAAS,WAAW;AAAA,MAC/E,KAAK;AACH,eAAO,MAAM,QAAQ,UAAU,KAAK,KAAK,CAAC,UAAU,MAAM,SAAS,WAAW;AAAA,MAChF,KAAK;AACH,eAAO,OAAO,WAAW,EAAE,SAAS,OAAO,UAAU,KAAK,CAAC;AAAA,MAC7D,KAAK;AACH,eAAO,OAAO,WAAW,EAAE,WAAW,OAAO,UAAU,KAAK,CAAC;AAAA,MAC/D;AACE,eAAO;AAAA,IACX;AAAA,EACF;AAAA,EAEQ,wBAA8B;AAEpC,UAAM,iBAAuB;AAAA,MAC3B,IAAI;AAAA,MACJ,MAAM;AAAA,MACN,aAAa;AAAA,MACb,UAAU;AAAA,MACV,aAAa;AAAA;AAAA,QAEX,GAAG,OAAO,OAAO,YAAY,EAAE;AAAA,UAAQ,cACrC,OAAO,OAAO,UAAU,EAAE,IAAI,aAAW;AAAA,YACvC,IAAI,eAAe,QAAQ,IAAI,MAAM;AAAA,YACrC;AAAA,YACA;AAAA,YACA,OAAO;AAAA,UACT,EAAE;AAAA,QACJ;AAAA,MACF;AAAA,MACA,WAAW,oBAAI,KAAK;AAAA,MACpB,WAAW,oBAAI,KAAK;AAAA,IACtB;AAGA,UAAM,mBAAyB;AAAA,MAC7B,IAAI;AAAA,MACJ,MAAM;AAAA,MACN,aAAa;AAAA,MACb,UAAU;AAAA,MACV,aAAa;AAAA,QACX;AAAA,UACE,IAAI;AAAA,UACJ,UAAU;AAAA,UACV,QAAQ;AAAA,UACR,OAAO;AAAA,QACT;AAAA,QACA;AAAA,UACE,IAAI;AAAA,UACJ,UAAU;AAAA,UACV,QAAQ;AAAA,UACR,OAAO;AAAA,QACT;AAAA,MACF;AAAA,MACA,WAAW,oBAAI,KAAK;AAAA,MACpB,WAAW,oBAAI,KAAK;AAAA,IACtB;AAGA,UAAM,oBAA0B;AAAA,MAC9B,IAAI;AAAA,MACJ,MAAM;AAAA,MACN,aAAa;AAAA,MACb,UAAU;AAAA,MACV,aAAa;AAAA,QACX;AAAA,UACE,IAAI;AAAA,UACJ,UAAU;AAAA,UACV,QAAQ;AAAA,UACR,OAAO;AAAA,QACT;AAAA,QACA;AAAA,UACE,IAAI;AAAA,UACJ,UAAU;AAAA,UACV,QAAQ;AAAA,UACR,OAAO;AAAA,QACT;AAAA,MACF;AAAA,MACA,WAAW,oBAAI,KAAK;AAAA,MACpB,WAAW,oBAAI,KAAK;AAAA,IACtB;AAGA,UAAM,aAAmB;AAAA,MACvB,IAAI;AAAA,MACJ,MAAM;AAAA,MACN,aAAa;AAAA,MACb,UAAU;AAAA,MACV,aAAa;AAAA,QACX;AAAA,UACE,IAAI;AAAA,UACJ,UAAU;AAAA,UACV,QAAQ;AAAA,UACR,OAAO;AAAA,QACT;AAAA,QACA;AAAA,UACE,IAAI;AAAA,UACJ,UAAU;AAAA,UACV,QAAQ;AAAA,UACR,OAAO;AAAA,QACT;AAAA,QACA;AAAA,UACE,IAAI;AAAA,UACJ,UAAU;AAAA,UACV,QAAQ;AAAA,UACR,OAAO;AAAA,QACT;AAAA,MACF;AAAA,MACA,WAAW,oBAAI,KAAK;AAAA,MACpB,WAAW,oBAAI,KAAK;AAAA,IACtB;AAEA,SAAK,MAAM,IAAI,eAAe,IAAI,cAAc;AAChD,SAAK,MAAM,IAAI,iBAAiB,IAAI,gBAAgB;AACpD,SAAK,MAAM,IAAI,kBAAkB,IAAI,iBAAiB;AACtD,SAAK,MAAM,IAAI,WAAW,IAAI,UAAU;AAAA,EAC1C;AAAA,EAEQ,oBAAoB,QAAgB,SAAyB;AACnE,SAAK,cAAc,IAAI,QAAQ,IAAI,IAAI,OAAO,CAAC;AAAA,EACjD;AAAA,EAEQ,yBAAyB,QAAsB;AACrD,UAAM,eAAyB,CAAC;AAEhC,eAAW,OAAO,KAAK,gBAAgB,KAAK,GAAG;AAC7C,UAAI,IAAI,WAAW,GAAG,MAAM,GAAG,GAAG;AAChC,qBAAa,KAAK,GAAG;AAAA,MACvB;AAAA,IACF;AAEA,iBAAa,QAAQ,SAAO;AAC1B,WAAK,gBAAgB,OAAO,GAAG;AAC/B,WAAK,YAAY,OAAO,GAAG;AAAA,IAC7B,CAAC;AAAA,EACH;AAAA,EAEQ,yBAAyB,QAAsB;AAErD,eAAW,CAAC,QAAQ,OAAO,KAAK,KAAK,eAAe;AAClD,UAAI,QAAQ,IAAI,MAAM,GAAG;AACvB,aAAK,yBAAyB,MAAM;AAAA,MACtC;AAAA,IACF;AAAA,EACF;AAAA,EAEQ,YAAY,OAAgC;AAClD,UAAM,aAAa,MAAM,UAAU,KAAK,UAAU,MAAM,OAAO,IAAI;AACnE,WAAO,GAAG,MAAM,MAAM,IAAI,MAAM,QAAQ,IAAI,MAAM,MAAM,IAAI,MAAM,cAAc,EAAE,IAAI,UAAU;AAAA,EAClG;AAAA,EAEQ,aAAa,KAAsC;AACzD,UAAM,SAAS,KAAK,YAAY,IAAI,GAAG;AACvC,QAAI,CAAC,UAAU,SAAS,KAAK,IAAI,GAAG;AAClC,WAAK,gBAAgB,OAAO,GAAG;AAC/B,WAAK,YAAY,OAAO,GAAG;AAC3B,aAAO;AAAA,IACT;AAEA,WAAO,KAAK,gBAAgB,IAAI,GAAG,KAAK;AAAA,EAC1C;AAAA,EAEQ,SAAS,KAAa,QAAgC;AAC5D,SAAK,gBAAgB,IAAI,KAAK,MAAM;AACpC,SAAK,YAAY,IAAI,KAAK,KAAK,IAAI,IAAI,KAAK,cAAc;AAAA,EAC5D;AAAA,EAEQ,iBAAyB;AAC/B,WAAO,QAAQ,KAAK,IAAI,CAAC,IAAI,KAAK,OAAO,EAAE,SAAS,EAAE,EAAE,OAAO,GAAG,CAAC,CAAC;AAAA,EACtE;AAAA,EAEQ,iBAAyB;AAC/B,WAAO,QAAQ,KAAK,IAAI,CAAC,IAAI,KAAK,OAAO,EAAE,SAAS,EAAE,EAAE,OAAO,GAAG,CAAC,CAAC;AAAA,EACtE;AACF;;;ACxoBA,IAAAC,iBAA6B;AAiFtB,IAAM,mBAAN,cAA+B,4BAAa;AAAA,EAajD,YAAoB,UAA4C,CAAC,GAAG;AAClE,UAAM;AADY;AAZpB,SAAQ,uBAAuB,oBAAI,IAAiC;AACpE,SAAQ,qBAAqB,oBAAI,IAAoF;AAErH,SAAQ,iBAA0C;AAAA,MAChD,wBAAwB;AAAA,MACxB,mBAAmB,oDAAmC;AAAA,MACtD,uBAAuB;AAAA,MACvB,qBAAqB;AAAA,MACrB,uBAAuB;AAAA,MACvB,oBAAoB;AAAA,IACtB;AAIE,SAAK,UAAU,EAAE,GAAG,KAAK,gBAAgB,GAAG,QAAQ;AACpD,SAAK,6BAA6B;AAAA,EACpC;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,mBACJ,WACA,cACA,WAC8B;AAC9B,UAAM,YAAY,KAAK,kBAAkB;AAGzC,SAAK,0BAA0B,SAAS;AAExC,UAAM,sBAA2C;AAAA,MAC/C,IAAI;AAAA,MACJ;AAAA,MACA;AAAA,MACA,WAAW,UAAU,IAAI,UAAQ;AAAA,QAC/B,GAAG;AAAA,QACH;AAAA,MACF,EAAE;AAAA,MACF;AAAA,MACA,aAAa,oBAAI,KAAK;AAAA,IACxB;AAEA,SAAK,qBAAqB,IAAI,WAAW,mBAAmB;AAE5D,SAAK,KAAK,0BAA0B,EAAE,oBAAoB,CAAC;AAG3D,QAAI,KAAK,QAAQ,wBAAwB;AACvC,YAAM,KAAK,wBAAwB,SAAS;AAAA,IAC9C;AAEA,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA,EAKA,uBAAuB,WAA+C;AACpE,WAAO,KAAK,qBAAqB,IAAI,SAAS,KAAK;AAAA,EACrD;AAAA;AAAA;AAAA;AAAA,EAKA,2BAA2B,WAA+C;AACxE,eAAW,WAAW,KAAK,qBAAqB,OAAO,GAAG;AACxD,UAAI,QAAQ,cAAc,WAAW;AACnC,eAAO;AAAA,MACT;AAAA,IACF;AACA,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,oBACJ,WACA,YACA,OAC8B;AAC9B,UAAM,UAAU,KAAK,qBAAqB,IAAI,SAAS;AACvD,QAAI,CAAC,SAAS;AACZ,YAAM,IAAI,MAAM,gCAAgC;AAAA,IAClD;AAEA,YAAQ;AACR,YAAQ,aAAa,oBAAI,KAAK;AAC9B,YAAQ,aAAa;AACrB,YAAQ,cAAc;AAGtB,YAAQ,UAAU,QAAQ,SAAO;AAC/B,UAAI;AAAA,IACN,CAAC;AAED,SAAK,KAAK,yBAAyB,EAAE,qBAAqB,SAAS,WAAW,CAAC;AAE/E,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,mBACJ,WACA,YACA,QAC8B;AAC9B,UAAM,UAAU,KAAK,qBAAqB,IAAI,SAAS;AACvD,QAAI,CAAC,SAAS;AACZ,YAAM,IAAI,MAAM,gCAAgC;AAAA,IAClD;AAEA,YAAQ;AACR,YAAQ,aAAa,oBAAI,KAAK;AAC9B,YAAQ,aAAa;AACrB,YAAQ,cAAc;AAGtB,YAAQ,UAAU,QAAQ,SAAO;AAC/B,UAAI,IAAI,sCAAoC;AAC1C,YAAI;AAAA,MACN;AAAA,IACF,CAAC;AAED,SAAK,KAAK,yBAAyB,EAAE,qBAAqB,SAAS,YAAY,OAAO,CAAC;AAEvF,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,YACJ,WACA,UAC8B;AAC9B,UAAM,UAAU,KAAK,qBAAqB,IAAI,SAAS;AACvD,QAAI,CAAC,SAAS;AACZ,YAAM,IAAI,MAAM,gCAAgC;AAAA,IAClD;AAEA,QAAI,QAAQ,sCAAyC,QAAQ,8CAA4C;AACvG,YAAM,IAAI,MAAM,gDAAgD;AAAA,IAClE;AAEA,aAAS;AACT,YAAQ,UAAU,KAAK,QAAQ;AAG/B,QAAI,KAAK,QAAQ,wBAAwB;AACvC,YAAM,KAAK,wBAAwB,SAAS;AAAA,IAC9C;AAEA,SAAK,KAAK,+BAA+B,EAAE,qBAAqB,SAAS,SAAS,CAAC;AAEnF,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA,EAKA,yBAAyB,SAKC;AACxB,QAAI,WAAW,MAAM,KAAK,KAAK,qBAAqB,OAAO,CAAC;AAE5D,QAAI,SAAS,QAAQ;AACnB,iBAAW,SAAS,OAAO,OAAK,EAAE,WAAW,QAAQ,MAAM;AAAA,IAC7D;AACA,QAAI,SAAS,WAAW;AACtB,iBAAW,SAAS,OAAO,OAAK,EAAE,cAAc,QAAQ,SAAS;AAAA,IACnE;AACA,QAAI,SAAS,gBAAgB;AAC3B,iBAAW,SAAS,OAAO,OAAK,EAAE,eAAe,QAAQ,cAAe;AAAA,IAC1E;AACA,QAAI,SAAS,iBAAiB;AAC5B,iBAAW,SAAS,OAAO,OAAK,EAAE,eAAe,QAAQ,eAAgB;AAAA,IAC3E;AAEA,WAAO,SAAS,KAAK,CAAC,GAAG,MAAM,EAAE,YAAY,QAAQ,IAAI,EAAE,YAAY,QAAQ,CAAC;AAAA,EAClF;AAAA;AAAA;AAAA;AAAA,EAKA,uBAKE;AACA,UAAM,WAAW,MAAM,KAAK,KAAK,qBAAqB,OAAO,CAAC;AAE9D,UAAM,WAAmC,CAAC;AAC1C,QAAI,sBAAsB;AAC1B,QAAI,iBAAiB;AACrB,QAAI,oBAAoB;AAExB,aAAS,QAAQ,aAAW;AAC1B,eAAS,QAAQ,MAAM,KAAK,SAAS,QAAQ,MAAM,KAAK,KAAK;AAE7D,UAAI,QAAQ,YAAY;AACtB,cAAM,iBAAiB,QAAQ,WAAW,QAAQ,IAAI,QAAQ,YAAY,QAAQ;AAClF,+BAAuB;AACvB;AAGA,YAAI,CAAC,QAAQ,cAAc,QAAQ,sCAAwC;AACzE;AAAA,QACF;AAAA,MACF;AAAA,IACF,CAAC;AAED,WAAO;AAAA,MACL,OAAO,SAAS;AAAA,MAChB;AAAA,MACA,uBAAuB,iBAAiB,IAAI,sBAAsB,iBAAiB;AAAA,MACnF,kBAAkB,iBAAiB,IAAK,oBAAoB,iBAAkB,MAAM;AAAA,IACtF;AAAA,EACF;AAAA;AAAA,EAGA,MAAc,wBAAwB,WAAkC;AACtE,UAAM,UAAU,KAAK,qBAAqB,IAAI,SAAS;AACvD,QAAI,CAAC,QAAS;AAEd,YAAQ;AACR,SAAK,KAAK,wCAAwC,EAAE,qBAAqB,QAAQ,CAAC;AAElF,UAAM,cAAwC,CAAC;AAE/C,QAAI;AAEF,YAAM,gBAAgB,MAAM,KAAK,2BAA2B,QAAQ,YAAY;AAChF,kBAAY,KAAK,aAAa;AAG9B,iBAAW,YAAY,QAAQ,WAAW;AACxC,cAAM,gBAAgB,MAAM,KAAK,iBAAiB,QAAQ;AAC1D,oBAAY,KAAK;AAAA,UACf,WAAW;AAAA,UACX,QAAQ,cAAc,UAAU,WAAW;AAAA,UAC3C,OAAO,cAAc;AAAA,UACrB,SAAS,wBAAwB,cAAc,OAAO,MAAM;AAAA,UAC5D,UAAU,EAAE,YAAY,SAAS,IAAI,QAAQ,cAAc,OAAO;AAAA,QACpE,CAAC;AAAA,MACH;AAGA,YAAM,eAAe,MAAM,KAAK,cAAc,QAAQ,aAAa,OAAO;AAC1E,kBAAY,KAAK,YAAY;AAG7B,YAAM,aAAa,MAAM,KAAK,kBAAkB,QAAQ,aAAa,YAAY,WAAW;AAC5F,kBAAY,KAAK,UAAU;AAE3B,cAAQ,0BAA0B;AAGlC,YAAM,eAAe,YAAY,OAAO,CAAC,KAAK,WAAW,MAAM,OAAO,OAAO,CAAC,IAAI,YAAY;AAG9F,UAAI,gBAAgB,KAAK,QAAQ,yBAA0B,CAAC,KAAK,QAAQ,qBAAqB;AAC5F,gBAAQ;AACR,gBAAQ,aAAa,oBAAI,KAAK;AAC9B,gBAAQ,cAAc,6BAA6B,aAAa,QAAQ,CAAC,CAAC;AAG1E,gBAAQ,UAAU,QAAQ,SAAO;AAC/B,cAAI;AAAA,QACN,CAAC;AAED,aAAK,KAAK,8BAA8B,EAAE,qBAAqB,SAAS,OAAO,aAAa,CAAC;AAAA,MAC/F,OAAO;AAEL,aAAK,KAAK,uCAAuC,EAAE,qBAAqB,SAAS,OAAO,aAAa,CAAC;AAAA,MACxG;AAAA,IAEF,SAAS,OAAO;AACd,cAAQ;AACR,WAAK,KAAK,uCAAuC;AAAA,QAC/C,qBAAqB;AAAA,QACrB,OAAO,iBAAiB,QAAQ,MAAM,UAAU;AAAA,MAClD,CAAC;AAAA,IACH;AAAA,EACF;AAAA,EAEQ,0BAA0B,WAAyC;AACzE,UAAM,gBAAgB,IAAI,IAAI,UAAU,IAAI,SAAO,IAAI,IAAI,CAAC;AAC5D,UAAM,eAAe,KAAK,QAAQ,kBAAmB,OAAO,UAAQ,CAAC,cAAc,IAAI,IAAI,CAAC;AAE5F,QAAI,aAAa,SAAS,GAAG;AAC3B,YAAM,IAAI,MAAM,+BAA+B,aAAa,KAAK,IAAI,CAAC,EAAE;AAAA,IAC1E;AAAA,EACF;AAAA,EAEA,MAAc,2BAA2B,cAA6D;AAIpG,UAAM,QAAQ,KAAK,mCAAmC,YAAY;AAElE,WAAO;AAAA,MACL,WAAW;AAAA,MACX,QAAQ,SAAS,KAAK,WAAW,SAAS,KAAK,YAAY;AAAA,MAC3D;AAAA,MACA,SAAS;AAAA,MACT,UAAU;AAAA,QACR,cAAc,aAAa;AAAA,QAC3B,oBAAoB,aAAa;AAAA,MACnC;AAAA,IACF;AAAA,EACF;AAAA,EAEQ,mCAAmC,cAAoC;AAC7E,QAAI,QAAQ;AAGZ,QAAI,sBAAsB,KAAK,aAAa,0BAA0B,GAAG;AACvE,eAAS;AAAA,IACX;AAGA,QAAI,aAAa,aAAa,UAAU,KAAK,aAAa,aAAa,UAAU,KAAK;AACpF,eAAS;AAAA,IACX;AAGA,UAAM,MAAM,oBAAI,KAAK;AACrB,UAAM,kBAAkB,IAAI,KAAK,aAAa,eAAe;AAC7D,UAAM,YAAY,IAAI,QAAQ,IAAI,gBAAgB,QAAQ,MAAM,MAAO,KAAK,KAAK,KAAK;AAEtF,QAAI,YAAY,KAAK,YAAY,KAAK;AACpC,eAAS;AAAA,IACX;AAGA,QAAI,aAAa,YAAY,SAAS,aAAa,YAAY,aAAa;AAC1E,eAAS;AAAA,IACX;AAGA,QAAI,aAAa,QAAQ,UAAU,aAAa,QAAQ,QAAQ,aAAa,QAAQ,YAAY;AAC/F,eAAS;AAAA,IACX;AAEA,WAAO,KAAK,IAAI,KAAK,KAAK;AAAA,EAC5B;AAAA,EAEA,MAAc,iBAAiB,UAAmE;AAChG,UAAM,YAAY,KAAK,mBAAmB,IAAI,SAAS,IAAI;AAC3D,QAAI,CAAC,WAAW;AACd,aAAO;AAAA,QACL,SAAS;AAAA,QACT,YAAY;AAAA,QACZ,QAAQ,CAAC;AAAA,UACP,MAAM;AAAA,UACN,UAAU;AAAA,UACV,SAAS,6CAA6C,SAAS,IAAI;AAAA,QACrE,CAAC;AAAA,MACH;AAAA,IACF;AAEA,WAAO,MAAM,UAAU,QAAQ;AAAA,EACjC;AAAA,EAEA,MAAc,cAAc,SAAmE;AAE7F,QAAI,QAAQ;AAEZ,QAAI,QAAQ,UAAU,QAAQ,QAAQ,QAAQ,YAAY;AACxD,eAAS;AAAA,IACX;AAGA,QAAI,UAAU,KAAK,QAAQ,UAAU,GAAG;AACtC,eAAS;AAAA,IACX;AAEA,QAAI,QAAQ,YAAY,QAAQ,QAAQ,YAAY,SAAS;AAC3D,eAAS;AAAA,IACX;AAEA,WAAO;AAAA,MACL,WAAW;AAAA,MACX,QAAQ,SAAS,KAAK,WAAW,SAAS,KAAK,YAAY;AAAA,MAC3D;AAAA,MACA,SAAS;AAAA,MACT,UAAU,EAAE,QAAQ;AAAA,IACtB;AAAA,EACF;AAAA,EAEA,MAAc,kBAAkB,aAAsD;AAEpF,UAAM,gBAAgB,wCAAwC,KAAK,WAAW;AAE9E,UAAM,QAAQ,gBAAgB,MAAM;AAEpC,WAAO;AAAA,MACL,WAAW;AAAA,MACX,QAAQ,gBAAgB,WAAW;AAAA,MACnC;AAAA,MACA,SAAS,gBAAgB,iCAAiC;AAAA,MAC1D,UAAU,EAAE,YAAY;AAAA,IAC1B;AAAA,EACF;AAAA,EAEQ,+BAAqC;AAE3C,SAAK,mBAAmB,yDAAwC,OAAO,QAAQ;AAC7E,YAAM,SAA6C,CAAC;AACpD,UAAI,aAAa;AAGjB,UAAI,CAAC,IAAI,SAAS,MAAM,wBAAwB,GAAG;AACjD,eAAO,KAAK;AAAA,UACV,MAAM;AAAA,UACN,UAAU;AAAA,UACV,SAAS;AAAA,QACX,CAAC;AACD,sBAAc;AAAA,MAChB;AAIA,aAAO;AAAA,QACL,SAAS,OAAO,WAAW,KAAK,OAAO,MAAM,OAAK,EAAE,aAAa,UAAU;AAAA,QAC3E,YAAY,KAAK,IAAI,GAAG,UAAU;AAAA,QAClC;AAAA,MACF;AAAA,IACF,CAAC;AAGD,SAAK,mBAAmB,+CAAmC,OAAO,QAAQ;AACxE,YAAM,SAA6C,CAAC;AACpD,UAAI,aAAa;AAEjB,UAAI,CAAC,IAAI,SAAS,MAAM,wBAAwB,GAAG;AACjD,eAAO,KAAK;AAAA,UACV,MAAM;AAAA,UACN,UAAU;AAAA,UACV,SAAS;AAAA,QACX,CAAC;AACD,sBAAc;AAAA,MAChB;AAEA,aAAO;AAAA,QACL,SAAS,OAAO,WAAW,KAAK,OAAO,MAAM,OAAK,EAAE,aAAa,UAAU;AAAA,QAC3E,YAAY,KAAK,IAAI,GAAG,UAAU;AAAA,QAClC;AAAA,MACF;AAAA,IACF,CAAC;AAGD,SAAK,mBAAmB,6BAA0B,OAAO,QAAQ;AAC/D,YAAM,SAA6C,CAAC;AACpD,UAAI,aAAa;AAEjB,UAAI,CAAC,IAAI,SAAS,MAAM,oBAAoB,GAAG;AAC7C,eAAO,KAAK;AAAA,UACV,MAAM;AAAA,UACN,UAAU;AAAA,UACV,SAAS;AAAA,QACX,CAAC;AACD,sBAAc;AAAA,MAChB;AAEA,aAAO;AAAA,QACL,SAAS,OAAO,WAAW,KAAK,OAAO,MAAM,OAAK,EAAE,aAAa,UAAU;AAAA,QAC3E,YAAY,KAAK,IAAI,GAAG,UAAU;AAAA,QAClC;AAAA,MACF;AAAA,IACF,CAAC;AAGD,UAAM,mBAAmB,OAAO,QAAiE;AAC/F,YAAM,SAA6C,CAAC;AACpD,UAAI,aAAa;AAEjB,UAAI,CAAC,IAAI,YAAY,IAAI,SAAS,WAAW,GAAG;AAC9C,eAAO,KAAK;AAAA,UACV,MAAM;AAAA,UACN,UAAU;AAAA,UACV,SAAS;AAAA,QACX,CAAC;AACD,qBAAa;AAAA,MACf;AAEA,aAAO;AAAA,QACL,SAAS,OAAO,WAAW,KAAK,OAAO,MAAM,OAAK,EAAE,aAAa,UAAU;AAAA,QAC3E,YAAY,KAAK,IAAI,GAAG,UAAU;AAAA,QAClC;AAAA,MACF;AAAA,IACF;AAEA,SAAK,mBAAmB,uDAAuC,gBAAgB;AAC/E,SAAK,mBAAmB,yBAAwB,gBAAgB;AAAA,EAClE;AAAA,EAEQ,oBAA4B;AAClC,WAAO,cAAc,KAAK,IAAI,CAAC,IAAI,KAAK,OAAO,EAAE,SAAS,EAAE,EAAE,OAAO,GAAG,CAAC,CAAC;AAAA,EAC5E;AACF;;;AC9kBA,IAAAC,iBAA6B;AAgCtB,IAAK,mBAAL,kBAAKC,sBAAL;AACL,EAAAA,kBAAA,SAAM;AACN,EAAAA,kBAAA,gBAAa;AACb,EAAAA,kBAAA,YAAS;AAHC,SAAAA;AAAA,GAAA;AAML,IAAK,qBAAL,kBAAKC,wBAAL;AACL,EAAAA,oBAAA,SAAM;AACN,EAAAA,oBAAA,gBAAa;AACb,EAAAA,oBAAA,iBAAc;AAHJ,SAAAA;AAAA,GAAA;AAqFL,IAAM,iBAAN,cAA6B,4BAAa;AAAA,EAqB/C,YAAoB,UAA0C,CAAC,GAAG;AAChE,UAAM;AADY;AApBpB,SAAQ,uBAAuB,oBAAI,IAAsC;AACzE,SAAQ,mBAAmB,oBAAI,IAA6B;AAC5D,SAAQ,mBAAmB,oBAAI,IAAoB;AACnD,SAAQ,sBAAsB,oBAAI,IAA6C;AAC/E,SAAQ,iBAAiB,oBAAI,IAAY;AAEzC,SAAQ,iBAAwC;AAAA,MAC9C,YAAY;AAAA,MACZ,mBAAmB;AAAA,MACnB,aAAa;AAAA,MACb,kBAAkB;AAAA,MAClB,aAAa;AAAA,MACb,eAAe;AAAA,MACf,kBAAkB;AAAA,MAClB,qBAAqB;AAAA,MACrB,8BAA8B;AAAA,MAC9B,gBAAgB,CAAC;AAAA,MACjB,kBAAkB,CAAC,IAAI;AAAA,IACzB;AAIE,SAAK,UAAU,EAAE,GAAG,KAAK,gBAAgB,GAAG,QAAQ;AAGpD,SAAK,QAAQ,gBAAgB,QAAQ,YAAU;AAC7C,WAAK,eAAe,IAAI,MAAM;AAAA,IAChC,CAAC;AAAA,EACH;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,kBACJ,gBACA,aACA,mBAAqC,iBACrC,WAAiD,CAAC,GACf;AAEnC,UAAM,YAAY,MAAM,KAAK,mBAAmB,WAAW;AAC3D,QAAI,CAAC,UAAU,SAAS;AACtB,YAAM,IAAI,MAAM,6BAA6B;AAAA,IAC/C;AAGA,QAAI,KAAK,gBAAgB,WAAW,GAAG;AACrC,YAAM,IAAI,MAAM,yBAAyB;AAAA,IAC3C;AAGA,QAAI,KAAK,cAAc,WAAW,GAAG;AACnC,YAAM,IAAI,MAAM,8CAA8C;AAAA,IAChE;AAGA,QAAI,KAAK,qBAAqB,WAAW,GAAG;AAC1C,YAAM,IAAI,MAAM,2CAA2C;AAAA,IAC7D;AAEA,UAAM,YAAY,KAAK,kBAAkB;AACzC,UAAM,mBAAmB,KAAK,yBAAyB;AACvD,UAAM,YAAY,IAAI,KAAK,KAAK,IAAI,IAAI,KAAK,QAAQ,oBAAqB,KAAK,GAAI;AAEnF,UAAM,sBAAgD;AAAA,MACpD,IAAI;AAAA,MACJ;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA,QAAQ;AAAA,MACR,UAAU,CAAC;AAAA,MACX;AAAA,MACA,WAAW,oBAAI,KAAK;AAAA,MACpB;AAAA,IACF;AAEA,SAAK,qBAAqB,IAAI,WAAW,mBAAmB;AAC5D,SAAK,gBAAgB,WAAW;AAChC,SAAK,oBAAoB,WAAW;AAEpC,SAAK,KAAK,wBAAwB,EAAE,qBAAqB,UAAU,CAAC;AAGpE,UAAM,KAAK,qBAAqB,qBAAqB,SAAS;AAE9D,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,WAAW,WAAmB,cAIjC;AACD,UAAM,UAAU,KAAK,qBAAqB,IAAI,SAAS;AACvD,QAAI,CAAC,SAAS;AACZ,aAAO;AAAA,QACL,SAAS;AAAA,QACT,QAAQ;AAAA,QACR,SAAS;AAAA,MACX;AAAA,IACF;AAGA,QAAI,QAAQ,WAAW,2BAAkC;AACvD,aAAO;AAAA,QACL,SAAS;AAAA,QACT,QAAQ;AAAA,QACR,SAAS;AAAA,MACX;AAAA,IACF;AAGA,QAAI,oBAAI,KAAK,IAAI,QAAQ,WAAW;AAClC,cAAQ,SAAS;AACjB,WAAK,KAAK,wBAAwB,EAAE,qBAAqB,QAAQ,CAAC;AAElE,aAAO;AAAA,QACL,SAAS;AAAA,QACT,QAAQ;AAAA,QACR,SAAS;AAAA,MACX;AAAA,IACF;AAGA,QAAI,QAAQ,WAAW,yBAAiC;AACtD,aAAO;AAAA,QACL,SAAS;AAAA,QACT,QAAQ;AAAA,QACR,SAAS;AAAA,MACX;AAAA,IACF;AAGA,UAAM,cAAc,KAAK,aAAa,QAAQ,kBAAkB,YAAY;AAE5E,QAAI,aAAa;AACf,cAAQ,SAAS;AACjB,cAAQ,cAAc,oBAAI,KAAK;AAE/B,WAAK,KAAK,wBAAwB,EAAE,qBAAqB,QAAQ,CAAC;AAElE,aAAO;AAAA,QACL,SAAS;AAAA,QACT,QAAQ;AAAA,QACR,SAAS;AAAA,MACX;AAAA,IACF,OAAO;AAEL,YAAM,gBAAqC;AAAA,QACzC,eAAe,QAAQ,SAAS,SAAS;AAAA,QACzC,aAAa,oBAAI,KAAK;AAAA,QACtB,QAAQ;AAAA;AAAA,QACR,QAAQ;AAAA,MACV;AACA,cAAQ,SAAS,KAAK,aAAa;AAGnC,YAAM,iBAAiB,QAAQ,SAAS,OAAO,OAAK,EAAE,WAAW,QAAQ,EAAE;AAE3E,UAAI,kBAAkB,KAAK,QAAQ,aAAc;AAC/C,gBAAQ,SAAS;AACjB,aAAK,KAAK,wBAAwB,EAAE,qBAAqB,QAAQ,CAAC;AAElE,eAAO;AAAA,UACL,SAAS;AAAA,UACT,QAAQ;AAAA,UACR,SAAS;AAAA,QACX;AAAA,MACF,OAAO;AACL,gBAAQ,SAAS;AACjB,aAAK,KAAK,+BAA+B;AAAA,UACvC,qBAAqB;AAAA,UACrB,mBAAmB,KAAK,QAAQ,cAAe;AAAA,QACjD,CAAC;AAED,eAAO;AAAA,UACL,SAAS;AAAA,UACT,QAAQ;AAAA,UACR,SAAS,iBAAiB,KAAK,QAAQ,cAAe,cAAc;AAAA,QACtE;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,WAAW,WAAmB,QAAgE;AAClG,UAAM,UAAU,KAAK,qBAAqB,IAAI,SAAS;AACvD,QAAI,CAAC,SAAS;AACZ,YAAM,IAAI,MAAM,gCAAgC;AAAA,IAClD;AAEA,QAAI,QAAQ,WAAW,2BAAkC;AACvD,YAAM,IAAI,MAAM,gCAAgC;AAAA,IAClD;AAEA,QAAI,QAAQ,WAAW,yBAAiC;AACtD,YAAM,IAAI,MAAM,yBAAyB;AAAA,IAC3C;AAGA,QAAI,KAAK,cAAc,QAAQ,WAAW,GAAG;AAC3C,YAAM,IAAI,MAAM,gEAAgE;AAAA,IAClF;AAGA,YAAQ,mBAAmB,KAAK,yBAAyB;AACzD,YAAQ,YAAY,IAAI,KAAK,KAAK,IAAI,IAAI,KAAK,QAAQ,oBAAqB,KAAK,GAAI;AACrF,YAAQ,SAAS;AAEjB,SAAK,gBAAgB,QAAQ,WAAW;AAExC,UAAM,YAAY,MAAM,KAAK,mBAAmB,QAAQ,WAAW;AAGnE,QAAI,QAAQ;AACV,YAAM,KAAK,yBAAyB,SAAS,WAAW,MAAM;AAAA,IAChE,OAAO;AACL,YAAM,KAAK,qBAAqB,SAAS,SAAS;AAAA,IACpD;AAEA,SAAK,KAAK,uBAAuB,EAAE,qBAAqB,QAAQ,CAAC;AAEjE,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA,EAKA,sBAAsB,WAAoD;AACxE,WAAO,KAAK,qBAAqB,IAAI,SAAS,KAAK;AAAA,EACrD;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,mBAAmB,WAAqC;AAC5D,UAAM,UAAU,KAAK,qBAAqB,IAAI,SAAS;AACvD,QAAI,CAAC,SAAS;AACZ,aAAO;AAAA,IACT;AAEA,QAAI,QAAQ,WAAW,2BAAkC;AACvD,aAAO;AAAA,IACT;AAEA,SAAK,qBAAqB,OAAO,SAAS;AAC1C,SAAK,KAAK,0BAA0B,EAAE,qBAAqB,QAAQ,CAAC;AAEpE,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA,EAKA,iBAAiB,aAAqB,QAAuB;AAC3D,SAAK,eAAe,IAAI,WAAW;AAGnC,eAAW,CAAC,WAAW,OAAO,KAAK,KAAK,sBAAsB;AAC5D,UAAI,QAAQ,gBAAgB,eACxB,QAAQ,WAAW,2BAAkC;AACvD,gBAAQ,SAAS;AAAA,MACnB;AAAA,IACF;AAEA,SAAK,KAAK,iBAAiB,EAAE,aAAa,OAAO,CAAC;AAAA,EACpD;AAAA;AAAA;AAAA;AAAA,EAKA,mBAAmB,aAA2B;AAC5C,SAAK,eAAe,OAAO,WAAW;AACtC,SAAK,KAAK,mBAAmB,EAAE,YAAY,CAAC;AAAA,EAC9C;AAAA;AAAA;AAAA;AAAA,EAKA,uBAME;AACA,UAAM,WAAW,MAAM,KAAK,KAAK,qBAAqB,OAAO,CAAC;AAE9D,UAAM,WAAmC,CAAC;AAC1C,UAAM,WAAmC,CAAC;AAC1C,QAAI,sBAAsB;AAC1B,QAAI,iBAAiB;AAErB,aAAS,QAAQ,aAAW;AAC1B,eAAS,QAAQ,MAAM,KAAK,SAAS,QAAQ,MAAM,KAAK,KAAK;AAG7D,UAAI,QAAQ,SAAS,SAAS,GAAG;AAC/B,cAAM,gBAAgB,QAAQ,SAAS,CAAC,EAAE;AAC1C,iBAAS,aAAa,KAAK,SAAS,aAAa,KAAK,KAAK;AAAA,MAC7D;AAGA,UAAI,QAAQ,aAAa;AACvB,cAAM,iBAAiB,QAAQ,YAAY,QAAQ,IAAI,QAAQ,UAAU,QAAQ;AACjF,+BAAuB;AACvB;AAAA,MACF;AAAA,IACF,CAAC;AAED,UAAM,eAAe,SAAS,yBAAgC,KAAK;AACnE,UAAM,cAAc,SAAS,SAAS,IAAK,eAAe,SAAS,SAAU,MAAM;AAEnF,WAAO;AAAA,MACL,OAAO,SAAS;AAAA,MAChB;AAAA,MACA;AAAA,MACA;AAAA,MACA,uBAAuB,iBAAiB,IAAI,sBAAsB,iBAAiB;AAAA,IACrF;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKA,UAAkB;AAChB,UAAM,MAAM,oBAAI,KAAK;AACrB,QAAI,eAAe;AAEnB,eAAW,CAAC,WAAW,OAAO,KAAK,KAAK,sBAAsB;AAC5D,UAAI,MAAM,QAAQ,aAAa,QAAQ,WAAW,2BAAkC;AAClF,gBAAQ,SAAS;AACjB,aAAK,qBAAqB,OAAO,SAAS;AAC1C;AAAA,MACF;AAAA,IACF;AAGA,UAAM,aAAa,KAAK,QAAQ,mBAAoB,KAAK;AACzD,eAAW,CAAC,aAAa,UAAU,KAAK,KAAK,kBAAkB;AAC7D,YAAM,kBAAkB,WAAW,OAAO,QAAM,IAAI,QAAQ,IAAI,GAAG,QAAQ,IAAI,UAAU;AACzF,UAAI,gBAAgB,WAAW,GAAG;AAChC,aAAK,iBAAiB,OAAO,WAAW;AAAA,MAC1C,OAAO;AACL,aAAK,iBAAiB,IAAI,aAAa,eAAe;AAAA,MACxD;AAAA,IACF;AAEA,WAAO;AAAA,EACT;AAAA;AAAA,EAGA,MAAc,qBACZ,SACA,WACe;AACf,QAAI;AAEJ,YAAQ,QAAQ,kBAAkB;AAAA,MAChC,KAAK;AACH,iBAAS;AACT;AAAA,MACF,KAAK;AACH,iBAAS;AACT;AAAA,MACF,KAAK;AAEH,iBAAS,UAAU,aAAa,aAAa,gCAAgC;AAC7E;AAAA,MACF;AACE,iBAAS;AAAA,IACb;AAEA,UAAM,KAAK,yBAAyB,SAAS,WAAW,MAAM;AAAA,EAChE;AAAA,EAEA,MAAc,yBACZ,SACA,WACA,QACe;AACf,UAAM,UAA+B;AAAA,MACnC,eAAe,QAAQ,SAAS,SAAS;AAAA,MACzC,aAAa,oBAAI,KAAK;AAAA,MACtB;AAAA,MACA,QAAQ;AAAA,IACV;AAEA,UAAM,YAAY,KAAK,IAAI;AAE3B,QAAI;AACF,cAAQ,QAAQ;AAAA,QACd,KAAK;AACH,gBAAM,KAAK,QAAQ,SAAS,SAAS;AACrC;AAAA,QACF,KAAK;AACH,gBAAM,KAAK,cAAc,SAAS,SAAS;AAC3C;AAAA,QACF,KAAK;AACH,gBAAM,KAAK,eAAe,SAAS,SAAS;AAC5C;AAAA,MACJ;AAEA,cAAQ,SAAS;AACjB,cAAQ,eAAe,KAAK,IAAI,IAAI;AACpC,cAAQ,SAAS;AAAA,IAEnB,SAAS,OAAO;AACd,cAAQ,SAAS;AACjB,cAAQ,gBAAgB,iBAAiB,QAAQ,MAAM,UAAU;AACjE,cAAQ,eAAe,KAAK,IAAI,IAAI;AAGpC,UAAI,WAAW,mBACX,KAAK,QAAQ,uBACb,QAAQ,SAAS,OAAO,OAAK,EAAE,WAAW,6BAA6B,EAAE,WAAW,GAAG;AAEzF,gBAAQ,SAAS;AACjB,gBAAQ,SAAS,KAAK,OAAO;AAG7B,cAAM,KAAK,yBAAyB,SAAS,WAAW,6BAA6B;AACrF;AAAA,MACF;AAEA,cAAQ,SAAS;AACjB,YAAM;AAAA,IACR;AAEA,YAAQ,SAAS,KAAK,OAAO;AAAA,EAC/B;AAAA,EAEA,MAAc,QAAQ,SAAmC,WAA2C;AAClG,QAAI,CAAC,KAAK,QAAQ,aAAa;AAC7B,YAAM,IAAI,MAAM,6BAA6B;AAAA,IAC/C;AAEA,UAAM,UAAU,KAAK,QAAQ,YAC1B,QAAQ,UAAU,QAAQ,gBAAgB,EAC1C,QAAQ,YAAY,KAAK,QAAQ,kBAAmB,SAAS,CAAC;AAEjE,UAAM,SAAS,MAAM,KAAK,QAAQ,YAAY,QAAQ,QAAQ,aAAa,OAAO;AAElF,QAAI,OAAO,WAAW,UAAU;AAC9B,YAAM,IAAI,MAAM,OAAO,SAAS,oBAAoB;AAAA,IACtD;AAAA,EACF;AAAA,EAEA,MAAc,cAAc,SAAmC,WAA2C;AACxG,QAAI,CAAC,KAAK,QAAQ,eAAe;AAC/B,YAAM,IAAI,MAAM,+BAA+B;AAAA,IACjD;AAEA,UAAM,UAAU,KAAK,QAAQ,cAC1B,QAAQ,UAAU,QAAQ,iBAAiB,MAAM,EAAE,EAAE,KAAK,GAAG,CAAC;AAEjE,UAAM,SAAS,MAAM,KAAK,QAAQ,cAAc,SAAS,QAAQ,aAAa,OAAO;AAErF,QAAI,OAAO,WAAW,UAAU;AAC9B,YAAM,IAAI,MAAM,OAAO,SAAS,mBAAmB;AAAA,IACrD;AAAA,EACF;AAAA,EAEA,MAAc,eAAe,SAAmC,WAA2C;AACzG,QAAI,CAAC,KAAK,QAAQ,eAAe,gBAAgB;AAC/C,YAAM,IAAI,MAAM,wCAAwC;AAAA,IAC1D;AAEA,UAAM,SAAS,MAAM,KAAK,QAAQ,cAAc,eAAe,QAAQ,WAAW;AAElF,QAAI,OAAO,WAAW,UAAU;AAC9B,YAAM,IAAI,MAAM,OAAO,SAAS,oBAAoB;AAAA,IACtD;AAGA,QAAI,OAAO,kBAAkB;AAC3B,YAAM,iBAAiB,OAAO,iBAAiB,MAAM,CAAC,KAAK,QAAQ,UAAW;AAC9E,cAAQ,mBAAmB;AAAA,IAC7B;AAAA,EACF;AAAA,EAEA,MAAc,mBAAmB,aAA+C;AAE9E,QAAI,KAAK,iBAAiB,IAAI,WAAW,GAAG;AAC1C,aAAO,KAAK,iBAAiB,IAAI,WAAW;AAAA,IAC9C;AAGA,UAAM,YAAY,KAAK,uBAAuB,WAAW;AAGzD,SAAK,iBAAiB,IAAI,aAAa,SAAS;AAEhD,WAAO;AAAA,EACT;AAAA,EAEQ,uBAAuB,aAAsC;AAEnE,UAAM,UAAU,YAAY,QAAQ,OAAO,EAAE;AAG7C,UAAM,gBAAgB;AACtB,UAAM,kBAAkB;AAExB,QAAI,UAAU;AACd,QAAI,aAAa;AACjB,QAAI,WAAwC;AAC5C,QAAI;AAEJ,QAAI,cAAc,KAAK,OAAO,GAAG;AAC/B,gBAAU;AACV,mBAAa;AACb,iBAAW;AAEX,YAAM,SAAS,QAAQ,UAAU,GAAG,CAAC;AACrC,cAAQ,QAAQ;AAAA,QACd,KAAK;AACH,oBAAU;AACV;AAAA,QACF,KAAK;AACH,oBAAU;AACV;AAAA,QACF,KAAK;AACH,oBAAU;AACV;AAAA,QACF,KAAK;AACH,oBAAU;AACV;AAAA,QACF,KAAK;AACH,oBAAU;AACV;AAAA,QACF,KAAK;AACH,oBAAU;AACV;AAAA,MACJ;AAAA,IACF,WAAW,gBAAgB,KAAK,OAAO,GAAG;AACxC,gBAAU;AACV,mBAAa;AACb,iBAAW;AAAA,IACb,WAAW,QAAQ,UAAU,MAAM,QAAQ,UAAU,IAAI;AACvD,mBAAa;AAAA,IACf;AAEA,WAAO;AAAA,MACL,aAAa;AAAA,MACb,aAAa;AAAA,MACb,gBAAgB;AAAA,MAChB;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA,QAAQ;AAAA,IACV;AAAA,EACF;AAAA,EAEQ,gBAAgB,aAA8B;AACpD,WAAO,KAAK,eAAe,IAAI,WAAW;AAAA,EAC5C;AAAA,EAEQ,cAAc,aAA8B;AAClD,UAAM,aAAa,KAAK,iBAAiB,IAAI,WAAW,KAAK,CAAC;AAC9D,UAAM,aAAa,KAAK,QAAQ,mBAAoB,KAAK;AACzD,UAAM,MAAM,oBAAI,KAAK;AAErB,UAAM,iBAAiB,WAAW,OAAO,QAAM,IAAI,QAAQ,IAAI,GAAG,QAAQ,IAAI,UAAU;AAExF,WAAO,eAAe,UAAU;AAAA,EAClC;AAAA,EAEQ,qBAAqB,aAA8B;AACzD,UAAM,SAAQ,oBAAI,KAAK,GAAE,YAAY,EAAE,MAAM,GAAG,EAAE,CAAC;AACnD,UAAM,YAAY,KAAK,oBAAoB,IAAI,WAAW;AAE1D,QAAI,CAAC,aAAa,UAAU,SAAS,OAAO;AAC1C,aAAO;AAAA,IACT;AAEA,WAAO,UAAU,SAAS,KAAK,QAAQ;AAAA,EACzC;AAAA,EAEQ,gBAAgB,aAA2B;AACjD,UAAM,aAAa,KAAK,iBAAiB,IAAI,WAAW,KAAK,CAAC;AAC9D,eAAW,KAAK,oBAAI,KAAK,CAAC;AAC1B,SAAK,iBAAiB,IAAI,aAAa,UAAU;AAAA,EACnD;AAAA,EAEQ,oBAAoB,aAA2B;AACrD,UAAM,SAAQ,oBAAI,KAAK,GAAE,YAAY,EAAE,MAAM,GAAG,EAAE,CAAC;AACnD,UAAM,YAAY,KAAK,oBAAoB,IAAI,WAAW;AAE1D,QAAI,CAAC,aAAa,UAAU,SAAS,OAAO;AAC1C,WAAK,oBAAoB,IAAI,aAAa,EAAE,MAAM,OAAO,OAAO,EAAE,CAAC;AAAA,IACrE,OAAO;AACL,gBAAU;AAAA,IACZ;AAAA,EACF;AAAA,EAEQ,aAAa,UAAkB,UAA2B;AAChE,WAAO,aAAa,SAAS,QAAQ,OAAO,EAAE;AAAA,EAChD;AAAA,EAEQ,2BAAmC;AACzC,UAAM,SAAS,KAAK,QAAQ;AAC5B,QAAI,OAAO;AAEX,aAAS,IAAI,GAAG,IAAI,QAAQ,KAAK;AAC/B,cAAQ,KAAK,MAAM,KAAK,OAAO,IAAI,EAAE,EAAE,SAAS;AAAA,IAClD;AAEA,WAAO;AAAA,EACT;AAAA,EAEQ,oBAA4B;AAClC,WAAO,gBAAgB,KAAK,IAAI,CAAC,IAAI,KAAK,OAAO,EAAE,SAAS,EAAE,EAAE,OAAO,GAAG,CAAC,CAAC;AAAA,EAC9E;AACF;;;ACluBO,IAAM,iBAAN,MAAqB;AAAA,EAArB;AACL,SAAQ,WAAuC,oBAAI,IAAI;AACvD,SAAQ,gBAAkD,oBAAI,IAAI;AAAA;AAAA,EAElE,MAAM,cAAc,SAAwF;AAC1G,UAAM,aAA4B;AAAA,MAChC,GAAG;AAAA,MACH,IAAI,KAAK,kBAAkB;AAAA,MAC3B,WAAW,oBAAI,KAAK;AAAA,MACpB,WAAW,oBAAI,KAAK;AAAA,IACtB;AAEA,SAAK,SAAS,IAAI,WAAW,IAAI,UAAU;AAC3C,WAAO;AAAA,EACT;AAAA,EAEA,MAAM,WAAW,WAAkD;AACjE,WAAO,KAAK,SAAS,IAAI,SAAS,KAAK;AAAA,EACzC;AAAA,EAEA,MAAM,aAAa,YAA+C;AAChE,UAAM,WAAW,MAAM,KAAK,KAAK,SAAS,OAAO,CAAC;AAElD,QAAI,YAAY;AACd,aAAO,SAAS,OAAO,OAAK,EAAE,eAAe,UAAU;AAAA,IACzD;AAEA,WAAO;AAAA,EACT;AAAA,EAEA,MAAM,cAAc,WAAmB,SAAyD;AAC9F,UAAM,UAAU,KAAK,SAAS,IAAI,SAAS;AAC3C,QAAI,CAAC,SAAS;AACZ,YAAM,IAAI,MAAM,WAAW,SAAS,YAAY;AAAA,IAClD;AAEA,UAAM,iBAAiB;AAAA,MACrB,GAAG;AAAA,MACH,GAAG;AAAA,MACH,WAAW,oBAAI,KAAK;AAAA,IACtB;AAEA,SAAK,SAAS,IAAI,WAAW,cAAc;AAC3C,WAAO;AAAA,EACT;AAAA,EAEA,MAAM,cAAc,WAAkC;AACpD,SAAK,SAAS,OAAO,SAAS;AAG9B,eAAW,CAAC,KAAK,YAAY,KAAK,KAAK,cAAc,QAAQ,GAAG;AAC9D,UAAI,aAAa,cAAc,WAAW;AACxC,aAAK,cAAc,OAAO,GAAG;AAAA,MAC/B;AAAA,IACF;AAAA,EACF;AAAA,EAEA,MAAM,gBAAgB,WAAmB,aAAqB,MAA6C;AACzG,UAAM,UAAU,KAAK,SAAS,IAAI,SAAS;AAC3C,QAAI,CAAC,SAAS;AACZ,YAAM,IAAI,MAAM,WAAW,SAAS,YAAY;AAAA,IAClD;AAEA,UAAM,eAAoC;AAAA,MACxC;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACF;AAEA,SAAK,cAAc,IAAI,aAAa,YAAY;AAChD,WAAO;AAAA,EACT;AAAA,EAEA,MAAM,mBAAmB,aAAyD;AAChF,UAAM,eAAe,KAAK,cAAc,IAAI,WAAW;AACvD,QAAI,CAAC,cAAc;AACjB,aAAO;AAAA,QACL,SAAS;AAAA,QACT,QAAQ;AAAA,QACR,OAAO;AAAA,MACT;AAAA,IACF;AAGA,UAAM,mBAAmB,KAAK,MAAM,KAAK,OAAO,IAAI,GAAM,IAAI;AAE9D,iBAAa,aAAa,oBAAI,KAAK;AACnC,iBAAa;AAEb,SAAK,cAAc,IAAI,aAAa,YAAY;AAEhD,WAAO;AAAA,MACL,SAAS;AAAA,MACT,QAAQ;AAAA,MACR,kBAAkB,iBAAiB,SAAS;AAAA,IAC9C;AAAA,EACF;AAAA,EAEA,MAAM,iBAAiB,WAAoD;AACzE,UAAM,gBAAgB,MAAM,KAAK,KAAK,cAAc,OAAO,CAAC;AAE5D,QAAI,WAAW;AACb,aAAO,cAAc,OAAO,OAAK,EAAE,cAAc,SAAS;AAAA,IAC5D;AAEA,WAAO;AAAA,EACT;AAAA,EAEQ,oBAA4B;AAClC,WAAO,MAAM,KAAK,IAAI,CAAC,IAAI,KAAK,OAAO,EAAE,SAAS,EAAE,EAAE,OAAO,GAAG,CAAC,CAAC;AAAA,EACpE;AACF;","names":["ChannelType","ChannelStatus","SenderNumberStatus","SenderNumberCategory","VerificationStatus","DocumentType","DocumentStatus","import_events","ResourceType","ActionType","PermissionScope","import_events","import_events","VerificationType","VerificationMethod"]}