spamscanner 6.0.0 → 6.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../replacement-words.json", "../../replacements.js", "../../get-classifier.js", "../../src/enhanced-idn-detector.js", "../../src/index.js"],
4
- "sourcesContent": ["[\n \"url\",\n \"email\",\n \"number\",\n \"currency\",\n \"initialism\",\n \"abbreviation\",\n \"emoji\",\n \"hexa\",\n \"mac\",\n \"phone\",\n \"bitcoin\",\n \"cc\"\n]\n", "import {debuglog} from 'node:util';\nimport {readFileSync} from 'node:fs';\nimport cryptoRandomString from 'crypto-random-string';\nimport REPLACEMENT_WORDS from './replacement-words.json' with { type: 'json' };\n\nconst debug = debuglog('spamscanner');\n\nconst randomOptions = {\n\tlength: 10,\n\tcharacters: 'abcdefghijklmnopqrstuvwxyz',\n};\n\n// Simply delete the replacements.json to generate new replacements\nlet replacements = {};\ntry {\n\treplacements = JSON.parse(readFileSync('./replacements.json', 'utf8'));\n} catch (error) {\n\tdebug(error);\n\tfor (const replacement of REPLACEMENT_WORDS) {\n\t\treplacements[replacement] = `${replacement}${cryptoRandomString(randomOptions)}`;\n\t}\n}\n\nexport default replacements;\n", "import {debuglog} from 'node:util';\nimport {readFileSync} from 'node:fs';\nimport NaiveBayes from '@ladjs/naivebayes';\n\nconst debug = debuglog('spamscanner');\n\nlet classifier = new NaiveBayes().toJsonObject();\n\ntry {\n\tclassifier = JSON.parse(readFileSync('./classifier.json', 'utf8'));\n} catch (error) {\n\tdebug(error);\n}\n\nexport default classifier;\n", "#!/usr/bin/env node\n/**\n * Enhanced IDN Homograph Attack Detection\n * Based on comprehensive research and best practices\n */\n\nimport {createHash} from 'node:crypto';\nimport confusables from 'confusables';\n\n// Unicode confusable character mappings (subset for demonstration)\nconst CONFUSABLE_CHARS = new Map([\n\t// Cyrillic to Latin confusables\n\t['\u0430', 'a'],\n\t['\u0435', 'e'],\n\t['\u043E', 'o'],\n\t['\u0440', 'p'],\n\t['\u0441', 'c'],\n\t['\u0445', 'x'],\n\t['\u0443', 'y'],\n\t['\u0410', 'A'],\n\t['\u0412', 'B'],\n\t['\u0415', 'E'],\n\t['\u041A', 'K'],\n\t['\u041C', 'M'],\n\t['\u041D', 'H'],\n\t['\u041E', 'O'],\n\t['\u0420', 'P'],\n\t['\u0421', 'C'],\n\t['\u0422', 'T'],\n\t['\u0425', 'X'],\n\t['\u0423', 'Y'],\n\n\t// Greek to Latin confusables\n\t['\u03B1', 'a'],\n\t['\u03BF', 'o'],\n\t['\u03C1', 'p'],\n\t['\u03C5', 'u'],\n\t['\u03BD', 'v'],\n\t['\u03B9', 'i'],\n\t['\u0391', 'A'],\n\t['\u0392', 'B'],\n\t['\u0395', 'E'],\n\t['\u0396', 'Z'],\n\t['\u0397', 'H'],\n\t['\u0399', 'I'],\n\t['\u039A', 'K'],\n\t['\u039C', 'M'],\n\t['\u039D', 'N'],\n\t['\u039F', 'O'],\n\t['\u03A1', 'P'],\n\t['\u03A4', 'T'],\n\t['\u03A5', 'Y'],\n\n\t// Mathematical symbols\n\t['\uD835\uDC1A', 'a'],\n\t['\uD835\uDC1B', 'b'],\n\t['\uD835\uDC1C', 'c'],\n\t['\uD835\uDC1D', 'd'],\n\t['\uD835\uDC1E', 'e'],\n\t['\uD835\uDFCE', '0'],\n\t['\uD835\uDFCF', '1'],\n\t['\uD835\uDFD0', '2'],\n\t['\uD835\uDFD1', '3'],\n\t['\uD835\uDFD2', '4'],\n\n\t// Other common confusables\n\t['\u212F', 'e'],\n\t['\u210A', 'g'],\n\t['\u210E', 'h'],\n\t['\u2113', 'l'],\n\t['\u2134', 'o'],\n\t['\u212F', 'e'],\n\t['\u2170', 'i'],\n\t['\u2171', 'ii'],\n\t['\u2172', 'iii'],\n\t['\u2173', 'iv'],\n\t['\u2174', 'v'],\n]);\n\n// Known legitimate international domains (whitelist approach)\nconst LEGITIMATE_IDN_DOMAINS = new Set([\n\t'xn--fsq.xn--0zwm56d', // \u4E2D\u56FD\n\t'xn--fiqs8s', // \u4E2D\u56FD\n\t'xn--fiqz9s', // \u4E2D\u56EF\n\t'xn--j6w193g', // \u9999\u6E2F\n\t'xn--55qx5d', // \u516C\u53F8\n\t'xn--io0a7i', // \u7F51\u7EDC\n\t// Add more legitimate domains as needed\n]);\n\n// Popular brand domains for comparison\nconst POPULAR_BRANDS = [\n\t'google',\n\t'facebook',\n\t'amazon',\n\t'apple',\n\t'microsoft',\n\t'twitter',\n\t'instagram',\n\t'linkedin',\n\t'youtube',\n\t'netflix',\n\t'paypal',\n\t'ebay',\n\t'yahoo',\n\t'adobe',\n\t'salesforce',\n\t'oracle',\n\t'ibm',\n\t'cisco',\n\t'intel',\n\t'nvidia',\n\t'tesla',\n\t'citibank',\n\t'bankofamerica',\n\t'wellsfargo',\n\t'chase',\n\t'americanexpress',\n];\n\nclass EnhancedIDNDetector {\n\tconstructor(options = {}) {\n\t\tthis.options = {\n\t\t\tstrictMode: false,\n\t\t\tenableWhitelist: true,\n\t\t\tenableBrandProtection: true,\n\t\t\tenableContextAnalysis: true,\n\t\t\tmaxSimilarityThreshold: 0.8,\n\t\t\tminDomainAge: 30, // Days\n\t\t\t...options,\n\t\t};\n\n\t\tthis.cache = new Map();\n\t}\n\n\t/**\n\t * Main detection method with comprehensive analysis\n\t */\n\tdetectHomographAttack(domain, context = {}) {\n\t\tconst cacheKey = this.getCacheKey(domain, context);\n\t\tif (this.cache.has(cacheKey)) {\n\t\t\treturn this.cache.get(cacheKey);\n\t\t}\n\n\t\tconst result = this.analyzeComprehensive(domain, context);\n\t\tthis.cache.set(cacheKey, result);\n\t\treturn result;\n\t}\n\n\t/**\n\t * Comprehensive analysis combining multiple detection methods\n\t */\n\tanalyzeComprehensive(domain, context) {\n\t\tconst analysis = {\n\t\t\tdomain,\n\t\t\tisIDN: this.isIDNDomain(domain),\n\t\t\triskScore: 0,\n\t\t\triskFactors: [],\n\t\t\trecommendations: [],\n\t\t\tconfidence: 0,\n\t\t};\n\n\t\t// Skip analysis for whitelisted domains\n\t\tif (this.options.enableWhitelist && this.isWhitelisted(domain)) {\n\t\t\tanalysis.riskScore = 0;\n\t\t\tanalysis.confidence = 1;\n\t\t\tanalysis.recommendations.push('Domain is whitelisted as legitimate');\n\t\t\treturn analysis;\n\t\t}\n\n\t\t// Basic IDN detection\n\t\tif (analysis.isIDN) {\n\t\t\tanalysis.riskScore += 0.3;\n\t\t\tanalysis.riskFactors.push('Contains non-ASCII characters');\n\t\t}\n\n\t\t// Confusable character analysis\n\t\tconst confusableAnalysis = this.analyzeConfusableCharacters(domain);\n\t\tanalysis.riskScore += confusableAnalysis.score;\n\t\tanalysis.riskFactors.push(...confusableAnalysis.factors);\n\n\t\t// Brand similarity analysis\n\t\tif (this.options.enableBrandProtection) {\n\t\t\tconst brandAnalysis = this.analyzeBrandSimilarity(domain);\n\t\t\tanalysis.riskScore += brandAnalysis.score;\n\t\t\tanalysis.riskFactors.push(...brandAnalysis.factors);\n\t\t}\n\n\t\t// Script mixing analysis\n\t\tconst scriptAnalysis = this.analyzeScriptMixing(domain);\n\t\tanalysis.riskScore += scriptAnalysis.score;\n\t\tanalysis.riskFactors.push(...scriptAnalysis.factors);\n\n\t\t// Context analysis\n\t\tif (this.options.enableContextAnalysis && context) {\n\t\t\tconst contextAnalysis = this.analyzeContext(domain, context);\n\t\t\tanalysis.riskScore += contextAnalysis.score;\n\t\t\tanalysis.riskFactors.push(...contextAnalysis.factors);\n\t\t}\n\n\t\t// Punycode analysis\n\t\tif (domain.includes('xn--')) {\n\t\t\tconst punycodeAnalysis = this.analyzePunycode(domain);\n\t\t\tanalysis.riskScore += punycodeAnalysis.score;\n\t\t\tanalysis.riskFactors.push(...punycodeAnalysis.factors);\n\t\t}\n\n\t\t// Calculate final confidence and recommendations\n\t\tanalysis.confidence = Math.min(analysis.riskScore, 1);\n\t\tanalysis.recommendations = this.generateRecommendations(analysis);\n\n\t\treturn analysis;\n\t}\n\n\t/**\n\t * Detect if domain contains IDN characters\n\t */\n\tisIDNDomain(domain) {\n\t\t// eslint-disable-next-line no-control-regex\n\t\treturn domain.includes('xn--') || /[^\\u0000-\\u007F]/.test(domain);\n\t}\n\n\t/**\n\t * Check if domain is in whitelist\n\t */\n\tisWhitelisted(domain) {\n\t\tconst normalized = domain.toLowerCase();\n\t\treturn LEGITIMATE_IDN_DOMAINS.has(normalized);\n\t}\n\n\t/**\n\t * Analyze confusable characters\n\t */\n\tanalyzeConfusableCharacters(domain) {\n\t\tconst analysis = {score: 0, factors: []};\n\t\tlet confusableCount = 0;\n\t\tlet totalChars = 0;\n\n\t\t// Use confusables library to detect and normalize\n\t\ttry {\n\t\t\tconst normalized = confusables(domain);\n\t\t\tif (normalized !== domain) {\n\t\t\t\t// Domain contains confusable characters\n\t\t\t\tfor (const char of domain) {\n\t\t\t\t\ttotalChars++;\n\t\t\t\t\tconst normalizedChar = confusables(char);\n\t\t\t\t\tif (normalizedChar !== char) {\n\t\t\t\t\t\tconfusableCount++;\n\t\t\t\t\t\tanalysis.factors.push(`Confusable character: ${char} \u2192 ${normalizedChar}`);\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tif (confusableCount > 0) {\n\t\t\t\t\tconst ratio = confusableCount / totalChars;\n\t\t\t\t\tanalysis.score = Math.min(ratio * 0.8, 0.6);\n\t\t\t\t\tanalysis.factors.push(`${confusableCount}/${totalChars} characters are confusable`, `Normalized domain: ${normalized}`);\n\t\t\t\t}\n\t\t\t}\n\t\t} catch {\n\t\t\t// Fallback to manual detection\n\t\t\tfor (const char of domain) {\n\t\t\t\ttotalChars++;\n\t\t\t\tif (CONFUSABLE_CHARS.has(char)) {\n\t\t\t\t\tconfusableCount++;\n\t\t\t\t\tanalysis.factors.push(`Confusable character: ${char} \u2192 ${CONFUSABLE_CHARS.get(char)}`);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (confusableCount > 0) {\n\t\t\t\tconst ratio = confusableCount / totalChars;\n\t\t\t\tanalysis.score = Math.min(ratio * 0.8, 0.6);\n\t\t\t\tanalysis.factors.push(`${confusableCount}/${totalChars} characters are confusable`);\n\t\t\t}\n\t\t}\n\n\t\treturn analysis;\n\t}\n\n\t/**\n\t * Analyze similarity to popular brands\n\t */\n\tanalyzeBrandSimilarity(domain) {\n\t\tconst analysis = {score: 0, factors: []};\n\t\tconst cleanDomain = this.normalizeDomain(domain);\n\n\t\tfor (const brand of POPULAR_BRANDS) {\n\t\t\tconst similarity = this.calculateSimilarity(cleanDomain, brand);\n\t\t\tif (similarity > this.options.maxSimilarityThreshold) {\n\t\t\t\tanalysis.score = Math.max(analysis.score, similarity * 0.7);\n\t\t\t\tanalysis.factors.push(`High similarity to ${brand}: ${(similarity * 100).toFixed(1)}%`);\n\t\t\t}\n\t\t}\n\n\t\treturn analysis;\n\t}\n\n\t/**\n\t * Analyze script mixing patterns\n\t */\n\tanalyzeScriptMixing(domain) {\n\t\tconst analysis = {score: 0, factors: []};\n\t\tconst scripts = this.detectScripts(domain);\n\n\t\tif (scripts.size > 1) {\n\t\t\t// Mixed scripts can be suspicious\n\t\t\tconst scriptList = [...scripts].join(', ');\n\t\t\tanalysis.factors.push(`Mixed scripts detected: ${scriptList}`);\n\n\t\t\t// Higher risk for certain combinations\n\t\t\tif (scripts.has('Latin') && (scripts.has('Cyrillic') || scripts.has('Greek'))) {\n\t\t\t\tanalysis.score += 0.4;\n\t\t\t\tanalysis.factors.push('Suspicious Latin/Cyrillic or Latin/Greek mixing');\n\t\t\t} else {\n\t\t\t\tanalysis.score += 0.2;\n\t\t\t}\n\t\t}\n\n\t\treturn analysis;\n\t}\n\n\t/**\n\t * Analyze context (email headers, content, etc.)\n\t */\n\tanalyzeContext(domain, context) {\n\t\tconst analysis = {score: 0, factors: []};\n\n\t\t// Check if display text differs from actual domain\n\t\tif (context.displayText && context.displayText !== domain) {\n\t\t\tanalysis.score += 0.3;\n\t\t\tanalysis.factors.push('Display text differs from actual domain');\n\t\t}\n\n\t\t// Check sender reputation\n\t\tif (context.senderReputation && context.senderReputation < 0.5) {\n\t\t\tanalysis.score += 0.2;\n\t\t\tanalysis.factors.push('Low sender reputation');\n\t\t}\n\n\t\t// Check for suspicious email patterns\n\t\tif (context.emailContent) {\n\t\t\tconst suspiciousPatterns = [\n\t\t\t\t/urgent/i,\n\t\t\t\t/verify.*account/i,\n\t\t\t\t/suspended/i,\n\t\t\t\t/click.*here/i,\n\t\t\t\t/limited.*time/i,\n\t\t\t\t/act.*now/i,\n\t\t\t\t/confirm.*identity/i,\n\t\t\t];\n\n\t\t\tfor (const pattern of suspiciousPatterns) {\n\t\t\t\tif (pattern.test(context.emailContent)) {\n\t\t\t\t\tanalysis.score += 0.1;\n\t\t\t\t\tanalysis.factors.push(`Suspicious email pattern: ${pattern.source}`);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn analysis;\n\t}\n\n\t/**\n\t * Analyze punycode domains\n\t */\n\tanalyzePunycode(domain) {\n\t\tconst analysis = {score: 0, factors: []};\n\n\t\ttry {\n\t\t\t// Decode punycode to see actual characters\n\t\t\tconst decoded = this.decodePunycode(domain);\n\t\t\tanalysis.factors.push(`Punycode decoded: ${decoded}`);\n\n\t\t\t// Check if decoded version looks suspicious\n\t\t\tconst decodedAnalysis = this.analyzeConfusableCharacters(decoded);\n\t\t\tanalysis.score += decodedAnalysis.score * 0.8;\n\t\t\tanalysis.factors.push(...decodedAnalysis.factors);\n\t\t} catch {\n\t\t\tanalysis.score += 0.2;\n\t\t\tanalysis.factors.push('Invalid punycode encoding');\n\t\t}\n\n\t\treturn analysis;\n\t}\n\n\t/**\n\t * Normalize domain for comparison\n\t */\n\tnormalizeDomain(domain) {\n\t\tlet normalized = domain.toLowerCase();\n\n\t\t// Use confusables library to remove confusable characters\n\t\ttry {\n\t\t\tnormalized = confusables(normalized);\n\t\t} catch {\n\t\t\t// Fallback to manual replacement if confusables fails\n\t\t\tfor (const [confusable, latin] of CONFUSABLE_CHARS) {\n\t\t\t\tnormalized = normalized.replaceAll(confusable, latin);\n\t\t\t}\n\t\t}\n\n\t\t// Remove common TLD for comparison\n\t\tnormalized = normalized.replace(/\\.(com|org|net|edu|gov)$/, '');\n\n\t\treturn normalized;\n\t}\n\n\t/**\n\t * Calculate string similarity using Levenshtein distance\n\t */\n\tcalculateSimilarity(string1, string2) {\n\t\tconst matrix = [];\n\t\tconst length1 = string1.length;\n\t\tconst length2 = string2.length;\n\n\t\tfor (let i = 0; i <= length2; i++) {\n\t\t\tmatrix[i] = [i];\n\t\t}\n\n\t\tfor (let j = 0; j <= length1; j++) {\n\t\t\tmatrix[0][j] = j;\n\t\t}\n\n\t\tfor (let i = 1; i <= length2; i++) {\n\t\t\tfor (let j = 1; j <= length1; j++) {\n\t\t\t\tif (string2.charAt(i - 1) === string1.charAt(j - 1)) {\n\t\t\t\t\tmatrix[i][j] = matrix[i - 1][j - 1];\n\t\t\t\t} else {\n\t\t\t\t\tmatrix[i][j] = Math.min(\n\t\t\t\t\t\tmatrix[i - 1][j - 1] + 1,\n\t\t\t\t\t\tmatrix[i][j - 1] + 1,\n\t\t\t\t\t\tmatrix[i - 1][j] + 1,\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tconst maxLength = Math.max(length1, length2);\n\t\treturn maxLength === 0 ? 1 : (maxLength - matrix[length2][length1]) / maxLength;\n\t}\n\n\t/**\n\t * Detect scripts used in domain\n\t */\n\tdetectScripts(domain) {\n\t\tconst scripts = new Set();\n\n\t\tfor (const char of domain) {\n\t\t\tconst code = char.codePointAt(0);\n\n\t\t\tif ((code >= 0x00_41 && code <= 0x00_5A) || (code >= 0x00_61 && code <= 0x00_7A)) {\n\t\t\t\tscripts.add('Latin');\n\t\t\t} else if (code >= 0x04_00 && code <= 0x04_FF) {\n\t\t\t\tscripts.add('Cyrillic');\n\t\t\t} else if (code >= 0x03_70 && code <= 0x03_FF) {\n\t\t\t\tscripts.add('Greek');\n\t\t\t} else if (code >= 0x4E_00 && code <= 0x9F_FF) {\n\t\t\t\tscripts.add('CJK');\n\t\t\t} else if (code >= 0x05_90 && code <= 0x05_FF) {\n\t\t\t\tscripts.add('Hebrew');\n\t\t\t} else if (code >= 0x06_00 && code <= 0x06_FF) {\n\t\t\t\tscripts.add('Arabic');\n\t\t\t}\n\t\t}\n\n\t\treturn scripts;\n\t}\n\n\t/**\n\t * Simple punycode decoder (basic implementation)\n\t */\n\tdecodePunycode(domain) {\n\t\t// This is a simplified implementation\n\t\t// In production, use a proper punycode library\n\t\ttry {\n\t\t\tconst url = new URL(`http://${domain}`);\n\t\t\treturn url.hostname;\n\t\t} catch {\n\t\t\treturn domain;\n\t\t}\n\t}\n\n\t/**\n\t * Generate recommendations based on analysis\n\t */\n\tgenerateRecommendations(analysis) {\n\t\tconst recommendations = [];\n\n\t\tif (analysis.riskScore > 0.8) {\n\t\t\trecommendations.push('HIGH RISK: Likely homograph attack - block or quarantine');\n\t\t} else if (analysis.riskScore > 0.6) {\n\t\t\trecommendations.push('MEDIUM RISK: Suspicious domain - flag for review');\n\t\t} else if (analysis.riskScore > 0.3) {\n\t\t\trecommendations.push('LOW RISK: Monitor domain activity');\n\t\t} else {\n\t\t\trecommendations.push('SAFE: Domain appears legitimate');\n\t\t}\n\n\t\tif (analysis.isIDN) {\n\t\t\trecommendations.push('Consider displaying punycode representation to users');\n\t\t}\n\n\t\tif (analysis.riskFactors.some(f => f.includes('brand'))) {\n\t\t\trecommendations.push('Verify domain authenticity through official channels');\n\t\t}\n\n\t\treturn recommendations;\n\t}\n\n\t/**\n\t * Generate cache key\n\t */\n\tgetCacheKey(domain, context) {\n\t\tconst contextHash = createHash('md5')\n\t\t\t.update(JSON.stringify(context))\n\t\t\t.digest('hex')\n\t\t\t.slice(0, 8);\n\t\treturn `${domain}:${contextHash}`;\n\t}\n}\n\nexport default EnhancedIDNDetector;\n\n", "import fs from 'node:fs';\nimport path from 'node:path';\nimport process from 'node:process';\nimport {createHash} from 'node:crypto';\nimport {debuglog} from 'node:util';\nimport {fileURLToPath} from 'node:url';\nimport autoBind from 'auto-bind';\nimport AFHConvert from 'ascii-fullwidth-halfwidth-convert';\nimport ClamScan from 'clamscan';\nimport NaiveBayes from '@ladjs/naivebayes';\nimport arrayJoinConjunction from 'array-join-conjunction';\nimport bitcoinRegex from 'bitcoin-regex';\nimport creditCardRegex from 'credit-card-regex';\nimport emailRegexSafe from 'email-regex-safe';\nimport escapeStringRegexp from 'escape-string-regexp';\nimport expandContractions from '@stdlib/nlp-expand-contractions';\nimport fileExtension from 'file-extension';\nimport floatingPointRegex from 'floating-point-regex';\nimport lande from 'lande'; // Replaced franc with lande as per TODO\nimport hexaColorRegex from 'hexa-color-regex';\nimport {parse as parseTldts} from 'tldts';\nimport ipRegex from 'ip-regex';\nimport isBuffer from 'is-buffer';\nimport isSANB from 'is-string-and-not-blank';\nimport macRegex from 'mac-regex';\nimport natural from 'natural';\nimport normalizeUrl from 'normalize-url';\nimport phoneRegex from 'phone-regex';\nimport snowball from 'node-snowball';\nimport striptags from 'striptags';\nimport superagent from 'superagent';\nimport sw from 'stopword';\nimport urlRegexSafe from 'url-regex-safe';\nimport {simpleParser} from 'mailparser';\nimport {fileTypeFromBuffer} from 'file-type';\n\n// ES module compatibility\nconst __filename = fileURLToPath(import.meta.url);\nconst __dirname = path.dirname(__filename);\n\n// Load JSON data\nconst executablesData = JSON.parse(fs.readFileSync(path.join(__dirname, '..', 'executables.json'), 'utf8'));\n\nconst EXECUTABLES = new Set(executablesData);\n\n// Dynamic imports for modules that need to be loaded conditionally\nconst getReplacements = async () => {\n\tconst {default: replacements} = await import('../replacements.js');\n\treturn replacements;\n};\n\nconst getClassifier = async () => {\n\tconst {default: classifier} = await import('../get-classifier.js');\n\treturn classifier;\n};\n\nconst debug = debuglog('spamscanner');\n\n// All tokenizers combined - improved regex pattern\nconst GENERIC_TOKENIZER\n = /[^a-z\u00E1-\u00FA\u00C1-\u00DA\u00E0-\u00FA\u00C0-\u00DA\u00F1\u00FC\\d\u0430-\u044F\u0451\u00E6\u00F8\u00E5\u00E0\u00E1\u1EA3\u00E3\u1EA1\u0103\u1EAF\u1EB1\u1EB3\u1EB5\u1EB7\u00E2\u1EA5\u1EA7\u1EA9\u1EAB\u1EAD\u00E9\u00E8\u1EBB\u1EBD\u1EB9\u00EA\u1EBF\u1EC1\u1EC3\u1EC5\u1EC7\u00ED\u00EC\u1EC9\u0129\u1ECB\u00F3\u00F2\u1ECF\u00F5\u1ECD\u00F4\u1ED1\u1ED3\u1ED5\u1ED7\u1ED9\u01A1\u1EDB\u1EDD\u1EDF\u1EE1\u1EE3\u00FA\u00F9\u1EE7\u0169\u1EE5\u01B0\u1EE9\u1EEB\u1EED\u1EEF\u1EF1\u00FD\u1EF3\u1EF7\u1EF9\u1EF5\u0111\u00E4\u00F6\u00EB\u00EF\u00EE\u00FB\u0153\u00E7\u0105\u017C\u015B\u017A\u0119\u0107\u0144\u0142-]+/i;\n\nconst converter = new AFHConvert();\n\n// Chinese tokenizer setup with proper path resolution\nconst chineseTokenizer = {tokenize: text => text.split(/\\s+/)};\n\n// Enhanced stopwords with fallback for missing language-specific stopwords\nconst stopwordsMap = new Map([\n\t['ar', new Set([...(natural.stopwords || []), ...(sw.ar || [])])],\n\t['bg', new Set([...(natural.stopwords || []), ...(sw.bg || [])])],\n\t['bn', new Set([...(natural.stopwords || []), ...(sw.bn || [])])],\n\t['ca', new Set([...(natural.stopwords || []), ...(sw.ca || [])])],\n\t['cs', new Set([...(natural.stopwords || []), ...(sw.cs || [])])],\n\t['da', new Set([...(natural.stopwords || []), ...(sw.da || [])])],\n\t['de', new Set([...(natural.stopwords || []), ...(sw.de || [])])],\n\t['el', new Set([...(natural.stopwords || []), ...(sw.el || [])])],\n\t['en', new Set([...(natural.stopwords || []), ...(sw.en || [])])],\n\t['es', new Set([...(natural.stopwords || []), ...(sw.es || [])])],\n\t['fa', new Set([...(natural.stopwords || []), ...(sw.fa || [])])],\n\t['fi', new Set([...(natural.stopwords || []), ...(sw.fi || [])])],\n\t['fr', new Set([...(natural.stopwords || []), ...(sw.fr || [])])],\n\t['ga', new Set([...(natural.stopwords || []), ...(sw.ga || [])])],\n\t['gl', new Set([...(natural.stopwords || []), ...(sw.gl || [])])],\n\t['gu', new Set([...(natural.stopwords || []), ...(sw.gu || [])])],\n\t['he', new Set([...(natural.stopwords || []), ...(sw.he || [])])],\n\t['hi', new Set([...(natural.stopwords || []), ...(sw.hi || [])])],\n\t['hr', new Set([...(natural.stopwords || []), ...(sw.hr || [])])],\n\t['hu', new Set([...(natural.stopwords || []), ...(sw.hu || [])])],\n\t['hy', new Set([...(natural.stopwords || []), ...(sw.hy || [])])],\n\t['it', new Set([...(natural.stopwords || []), ...(sw.it || [])])],\n\t['ja', new Set([...(natural.stopwords || []), ...(sw.ja || [])])],\n\t['ko', new Set([...(natural.stopwords || []), ...(sw.ko || [])])],\n\t['la', new Set([...(natural.stopwords || []), ...(sw.la || [])])],\n\t['lt', new Set([...(natural.stopwords || []), ...(sw.lt || [])])],\n\t['lv', new Set([...(natural.stopwords || []), ...(sw.lv || [])])],\n\t['mr', new Set([...(natural.stopwords || []), ...(sw.mr || [])])],\n\t['nl', new Set([...(natural.stopwords || []), ...(sw.nl || [])])],\n\t['no', new Set([...(natural.stopwords || []), ...(sw.nob || [])])],\n\t['pl', new Set([...(natural.stopwords || []), ...(sw.pl || [])])],\n\t['pt', new Set([...(natural.stopwords || []), ...(sw.pt || [])])],\n\t['ro', new Set([...(natural.stopwords || []), ...(sw.ro || [])])],\n\t['ru', new Set([...(natural.stopwords || []), ...(sw.ru || [])])],\n\t['sk', new Set([...(natural.stopwords || []), ...(sw.sk || [])])],\n\t['sl', new Set([...(natural.stopwords || []), ...(sw.sl || [])])],\n\t['sv', new Set([...(natural.stopwords || []), ...(sw.sv || [])])],\n\t['th', new Set([...(natural.stopwords || []), ...(sw.th || [])])],\n\t['tr', new Set([...(natural.stopwords || []), ...(sw.tr || [])])],\n\t['uk', new Set([...(natural.stopwords || []), ...(sw.uk || [])])],\n\t['vi', new Set([...(natural.stopwords || []), ...(sw.vi || [])])],\n\t['zh', new Set([...(natural.stopwords || []), ...(sw.zh || [])])],\n]);\n\n// URL ending reserved characters\nconst URL_ENDING_RESERVED_CHARS = /[).,;!?]+$/;\n\n// Date pattern detection (DONE)\nconst DATE_PATTERNS = [\n\t/\\b(?:\\d{1,2}[/-]){2}\\d{2,4}\\b/g, // MM/DD/YYYY or DD/MM/YYYY\n\t/\\b\\d{4}(?:[/-]\\d{1,2}){2}\\b/g, // YYYY/MM/DD\n\t/\\b\\d{1,2}\\s+(jan|feb|mar|apr|may|jun|jul|aug|sep|oct|nov|dec)\\s+\\d{2,4}\\b/gi, // DD MMM YYYY\n\t/\\b(jan|feb|mar|apr|may|jun|jul|aug|sep|oct|nov|dec)\\s+\\d{1,2},?\\s+\\d{2,4}\\b/gi, // MMM DD, YYYY\n];\n\n// File path detection (DONE)\nconst FILE_PATH_PATTERNS = [\n\t/[a-z]:\\\\\\\\[^\\\\s<>:\"|?*]+/gi, // Windows paths\n\t/\\/[^\\\\s<>:\"|?*]+/g, // Unix paths\n\t/~\\/[^\\\\s<>:\"|?*]+/g, // Home directory paths\n];\n\n// Additional regex patterns\nconst CREDIT_CARD_PATTERN = creditCardRegex({exact: false});\nconst PHONE_PATTERN = phoneRegex({exact: false});\nconst EMAIL_PATTERN = emailRegexSafe({exact: false});\nconst IP_PATTERN = ipRegex({exact: false});\nconst URL_PATTERN = urlRegexSafe({exact: false});\nconst BITCOIN_PATTERN = bitcoinRegex({exact: false});\nconst MAC_PATTERN = macRegex({exact: false});\nconst HEX_COLOR_PATTERN = hexaColorRegex({exact: false});\nconst FLOATING_POINT_PATTERN = floatingPointRegex;\n\nclass SpamScanner {\n\tconstructor(options = {}) {\n\t\tthis.config = {\n\t\t\t// Enhanced configuration options\n\t\t\tenableMacroDetection: true,\n\t\t\tenablePerformanceMetrics: false,\n\t\t\ttimeout: 30_000,\n\t\t\tsupportedLanguages: ['en'],\n\t\t\tenableMixedLanguageDetection: false,\n\t\t\tenableAdvancedPatternRecognition: true,\n\n\t\t\t// Existing options\n\t\t\tdebug: false,\n\t\t\tlogger: console,\n\t\t\tclamscan: {\n\t\t\t\tremoveInfected: false,\n\t\t\t\tquarantineInfected: false,\n\t\t\t\tscanLog: null,\n\t\t\t\tdebugMode: false,\n\t\t\t\tfileList: null,\n\t\t\t\tscanRecursively: true,\n\t\t\t\tclamscanPath: '/usr/bin/clamscan',\n\t\t\t\tclamdscanPath: '/usr/bin/clamdscan',\n\t\t\t\tpreference: 'clamdscan',\n\t\t\t},\n\t\t\tclassifier: null,\n\t\t\treplacements: null,\n\t\t\t...options,\n\t\t};\n\n\t\t// Async loading of replacements and classifier\n\t\tthis.classifier = null;\n\t\tthis.clamscan = null;\n\t\tthis.isInitialized = false;\n\n\t\t// Initialize replacements as empty Map\n\t\tthis.replacements = new Map();\n\n\t\t// Performance metrics\n\t\tthis.metrics = {\n\t\t\ttotalScans: 0,\n\t\t\taverageTime: 0,\n\t\t\tlastScanTime: 0,\n\t\t};\n\n\t\t// Bind methods\n\t\tautoBind(this);\n\t}\n\n\tasync initializeClassifier() {\n\t\tif (this.classifier) {\n\t\t\treturn;\n\t\t}\n\n\t\ttry {\n\t\t\tif (this.config.classifier) {\n\t\t\t\tthis.classifier = new NaiveBayes(this.config.classifier);\n\t\t\t} else {\n\t\t\t\tconst classifierData = await getClassifier();\n\t\t\t\tthis.classifier = new NaiveBayes(classifierData);\n\t\t\t}\n\n\t\t\t// Custom tokenizer - we handle tokenization ourselves\n\t\t\tthis.classifier.tokenizer = function (tokens) {\n\t\t\t\tif (typeof tokens === 'string') {\n\t\t\t\t\treturn tokens.split(/\\s+/);\n\t\t\t\t}\n\n\t\t\t\treturn Array.isArray(tokens) ? tokens : [];\n\t\t\t};\n\t\t} catch (error) {\n\t\t\tdebug('Failed to initialize classifier:', error);\n\t\t\t// Create a fallback classifier\n\t\t\tthis.classifier = new NaiveBayes();\n\t\t}\n\t}\n\n\t// Initialize replacements\n\tasync initializeReplacements() {\n\t\tif (this.replacements && this.replacements.size > 0) {\n\t\t\treturn;\n\t\t}\n\n\t\ttry {\n\t\t\tconst replacements = this.config.replacements || await getReplacements();\n\n\t\t\t// Ensure replacements is a Map\n\t\t\tif (replacements instanceof Map) {\n\t\t\t\tthis.replacements = replacements;\n\t\t\t} else if (typeof replacements === 'object' && replacements !== null) {\n\t\t\t\tthis.replacements = new Map(Object.entries(replacements));\n\t\t\t} else {\n\t\t\t\tthrow new Error('Invalid replacements format');\n\t\t\t}\n\t\t} catch (error) {\n\t\t\tdebug('Failed to initialize replacements:', error);\n\t\t\t// Generate fallback replacements\n\t\t\tthis.replacements = new Map();\n\n\t\t\t// Add some basic replacements\n\t\t\tconst basicReplacements = {\n\t\t\t\tu: 'you',\n\t\t\t\tur: 'your',\n\t\t\t\tr: 'are',\n\t\t\t\tn: 'and',\n\t\t\t\t'w/': 'with',\n\t\t\t\tb4: 'before',\n\t\t\t\t2: 'to',\n\t\t\t\t4: 'for',\n\t\t\t};\n\n\t\t\tfor (const [word, replacement] of Object.entries(basicReplacements)) {\n\t\t\t\tthis.replacements.set(word, replacement);\n\t\t\t}\n\t\t}\n\t}\n\n\t// Initialize regex helpers\n\tinitializeRegex() {\n\t\tthis.regexCache = new Map();\n\t\tthis.urlCache = new Map();\n\t}\n\n\t// Enhanced virus scanning with timeout protection\n\tasync getVirusResults(mail) {\n\t\tif (!this.clamscan) {\n\t\t\ttry {\n\t\t\t\tthis.clamscan = await new ClamScan().init(this.config.clamscan);\n\t\t\t} catch (error) {\n\t\t\t\tdebug('ClamScan initialization failed:', error);\n\t\t\t\treturn [];\n\t\t\t}\n\t\t}\n\n\t\tconst results = [];\n\t\tconst attachments = mail.attachments || [];\n\n\t\tfor (const attachment of attachments) {\n\t\t\ttry {\n\t\t\t\tif (attachment.content && isBuffer(attachment.content)) {\n\t\t\t\t\t// eslint-disable-next-line no-await-in-loop\n\t\t\t\t\tconst scanResult = await Promise.race([\n\t\t\t\t\t\tthis.clamscan.scanBuffer(attachment.content),\n\t\t\t\t\t\tnew Promise((_resolve, reject) => {\n\t\t\t\t\t\t\tsetTimeout(() => reject(new Error('Virus scan timeout')), this.config.timeout);\n\t\t\t\t\t\t}),\n\t\t\t\t\t]);\n\n\t\t\t\t\tif (scanResult.isInfected) {\n\t\t\t\t\t\tresults.push({\n\t\t\t\t\t\t\tfilename: attachment.filename || 'unknown',\n\t\t\t\t\t\t\tvirus: scanResult.viruses || ['Unknown virus'],\n\t\t\t\t\t\t\ttype: 'virus',\n\t\t\t\t\t\t});\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t} catch (error) {\n\t\t\t\tdebug('Virus scan error:', error);\n\t\t\t}\n\t\t}\n\n\t\treturn results;\n\t}\n\n\t// Macro detection (DONE)\n\tasync getMacroResults(mail) {\n\t\tconst results = [];\n\t\tconst attachments = mail.attachments || [];\n\t\tconst textContent = mail.text || '';\n\t\tconst htmlContent = mail.html || '';\n\n\t\t// VBA Macro detection\n\t\tconst vbaPatterns = [\n\t\t\t/sub\\s+\\w+\\s*\\(/gi,\n\t\t\t/function\\s+\\w+\\s*\\(/gi,\n\t\t\t/dim\\s+\\w+\\s+as\\s+\\w+/gi,\n\t\t\t/application\\.run/gi,\n\t\t\t/shell\\s*\\(/gi,\n\t\t];\n\n\t\t// PowerShell detection\n\t\tconst powershellPatterns = [\n\t\t\t/powershell/gi,\n\t\t\t/invoke-expression/gi,\n\t\t\t/iex\\s*\\(/gi,\n\t\t\t/start-process/gi,\n\t\t\t/new-object\\s+system\\./gi,\n\t\t];\n\n\t\t// JavaScript macro detection\n\t\tconst jsPatterns = [\n\t\t\t/eval\\s*\\(/gi,\n\t\t\t/document\\.write/gi,\n\t\t\t/activexobject/gi,\n\t\t\t/wscript\\./gi,\n\t\t\t/new\\s+activexobject/gi,\n\t\t];\n\n\t\t// Batch file detection\n\t\tconst batchPatterns = [/@echo\\s+off/gi, /cmd\\s*\\/c/gi, /start\\s+\\/b/gi, /for\\s+\\/[lrf]/gi];\n\n\t\t// Get content from text, html, and header lines\n\t\tlet allContent = textContent + ' ' + htmlContent;\n\n\t\t// Also check header lines for content (like macro code in raw emails)\n\t\tif (mail.headerLines && Array.isArray(mail.headerLines)) {\n\t\t\tfor (const headerLine of mail.headerLines) {\n\t\t\t\tif (headerLine.line) {\n\t\t\t\t\tallContent += ' ' + headerLine.line;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t// Check for VBA macros\n\t\tfor (const pattern of vbaPatterns) {\n\t\t\tif (pattern.test(allContent)) {\n\t\t\t\tresults.push({\n\t\t\t\t\ttype: 'macro',\n\t\t\t\t\tsubtype: 'vba',\n\t\t\t\t\tdescription: 'VBA macro detected',\n\t\t\t\t});\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\n\t\t// Check for PowerShell\n\t\tfor (const pattern of powershellPatterns) {\n\t\t\tif (pattern.test(allContent)) {\n\t\t\t\tresults.push({\n\t\t\t\t\ttype: 'macro',\n\t\t\t\t\tsubtype: 'powershell',\n\t\t\t\t\tdescription: 'PowerShell script detected',\n\t\t\t\t});\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\n\t\t// Check for JavaScript macros\n\t\tfor (const pattern of jsPatterns) {\n\t\t\tif (pattern.test(allContent)) {\n\t\t\t\tresults.push({\n\t\t\t\t\ttype: 'macro',\n\t\t\t\t\tsubtype: 'javascript',\n\t\t\t\t\tdescription: 'JavaScript macro detected',\n\t\t\t\t});\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\n\t\t// Check for batch files\n\t\tfor (const pattern of batchPatterns) {\n\t\t\tif (pattern.test(allContent)) {\n\t\t\t\tresults.push({\n\t\t\t\t\ttype: 'macro',\n\t\t\t\t\tsubtype: 'batch',\n\t\t\t\t\tdescription: 'Batch script detected',\n\t\t\t\t});\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\n\t\t// Check attachments for macro content\n\t\tfor (const attachment of attachments) {\n\t\t\tif (attachment.filename) {\n\t\t\t\tconst extension = fileExtension(attachment.filename).toLowerCase();\n\n\t\t\t\t// Standalone macro files\n\t\t\t\tconst macroExtensions = ['vbs', 'vba', 'ps1', 'bat', 'cmd', 'scr', 'pif'];\n\n\t\t\t\t// Office documents with macros (OOXML format)\n\t\t\t\tconst officeMacroExtensions = ['docm', 'xlsm', 'pptm', 'xlam', 'dotm', 'xltm', 'potm'];\n\n\t\t\t\t// Legacy Office formats (always have macro capability)\n\t\t\t\tconst legacyOfficeExtensions = ['doc', 'xls', 'ppt', 'dot', 'xlt', 'pot', 'xla', 'ppa'];\n\n\t\t\t\tif (macroExtensions.includes(extension)) {\n\t\t\t\t\tresults.push({\n\t\t\t\t\t\ttype: 'macro',\n\t\t\t\t\t\tsubtype: 'script',\n\t\t\t\t\t\tfilename: attachment.filename,\n\t\t\t\t\t\tdescription: `Macro script attachment detected: ${extension}`,\n\t\t\t\t\t});\n\t\t\t\t} else if (officeMacroExtensions.includes(extension)) {\n\t\t\t\t\tresults.push({\n\t\t\t\t\t\ttype: 'macro',\n\t\t\t\t\t\tsubtype: 'office_document',\n\t\t\t\t\t\tfilename: attachment.filename,\n\t\t\t\t\t\tdescription: `Office document with macro capability: ${extension}`,\n\t\t\t\t\t});\n\t\t\t\t} else if (legacyOfficeExtensions.includes(extension)) {\n\t\t\t\t\tresults.push({\n\t\t\t\t\t\ttype: 'macro',\n\t\t\t\t\t\tsubtype: 'legacy_office',\n\t\t\t\t\t\tfilename: attachment.filename,\n\t\t\t\t\t\tdescription: `Legacy Office document (macro-capable): ${extension}`,\n\t\t\t\t\t\trisk: 'high',\n\t\t\t\t\t});\n\t\t\t\t}\n\n\t\t\t\t// Check PDF attachments for JavaScript\n\t\t\t\tif (extension === 'pdf' && attachment.content && isBuffer(attachment.content)) {\n\t\t\t\t\ttry {\n\t\t\t\t\t\tconst pdfContent = attachment.content.toString('latin1');\n\t\t\t\t\t\t// Check for JavaScript in PDF\n\t\t\t\t\t\tif (pdfContent.includes('/JavaScript') || pdfContent.includes('/JS')) {\n\t\t\t\t\t\t\tresults.push({\n\t\t\t\t\t\t\t\ttype: 'macro',\n\t\t\t\t\t\t\t\tsubtype: 'pdf_javascript',\n\t\t\t\t\t\t\t\tfilename: attachment.filename,\n\t\t\t\t\t\t\t\tdescription: 'PDF with embedded JavaScript detected',\n\t\t\t\t\t\t\t\trisk: 'medium',\n\t\t\t\t\t\t\t});\n\t\t\t\t\t\t}\n\t\t\t\t\t} catch (error) {\n\t\t\t\t\t\tdebug('PDF JavaScript detection error:', error);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn results;\n\t}\n\n\t// File path detection (DONE)\n\tasync getFilePathResults(mail) {\n\t\tconst results = [];\n\t\tconst textContent = mail.text || '';\n\t\tconst htmlContent = mail.html || '';\n\t\tconst allContent = textContent + ' ' + htmlContent;\n\n\t\tfor (const pattern of FILE_PATH_PATTERNS) {\n\t\t\tconst matches = allContent.match(pattern);\n\t\t\tif (matches) {\n\t\t\t\tfor (const match of matches) {\n\t\t\t\t\t// Skip HTML tags and common false positives\n\t\t\t\t\tif (this.isValidFilePath(match)) {\n\t\t\t\t\t\tresults.push({\n\t\t\t\t\t\t\ttype: 'file_path',\n\t\t\t\t\t\t\tpath: match,\n\t\t\t\t\t\t\tdescription: 'Suspicious file path detected',\n\t\t\t\t\t\t});\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn results;\n\t}\n\n\t// Check if a path is a valid file path (not HTML tag or false positive)\n\tisValidFilePath(path) {\n\t\t// Skip HTML tags (common HTML elements)\n\t\tconst htmlTags = [\n\t\t\t'a',\n\t\t\t'abbr',\n\t\t\t'address',\n\t\t\t'area',\n\t\t\t'article',\n\t\t\t'aside',\n\t\t\t'audio',\n\t\t\t'b',\n\t\t\t'base',\n\t\t\t'bdi',\n\t\t\t'bdo',\n\t\t\t'blockquote',\n\t\t\t'body',\n\t\t\t'br',\n\t\t\t'button',\n\t\t\t'canvas',\n\t\t\t'caption',\n\t\t\t'cite',\n\t\t\t'code',\n\t\t\t'col',\n\t\t\t'colgroup',\n\t\t\t'data',\n\t\t\t'datalist',\n\t\t\t'dd',\n\t\t\t'del',\n\t\t\t'details',\n\t\t\t'dfn',\n\t\t\t'dialog',\n\t\t\t'div',\n\t\t\t'dl',\n\t\t\t'dt',\n\t\t\t'em',\n\t\t\t'embed',\n\t\t\t'fieldset',\n\t\t\t'figcaption',\n\t\t\t'figure',\n\t\t\t'footer',\n\t\t\t'form',\n\t\t\t'h1',\n\t\t\t'h2',\n\t\t\t'h3',\n\t\t\t'h4',\n\t\t\t'h5',\n\t\t\t'h6',\n\t\t\t'head',\n\t\t\t'header',\n\t\t\t'hr',\n\t\t\t'html',\n\t\t\t'i',\n\t\t\t'iframe',\n\t\t\t'img',\n\t\t\t'input',\n\t\t\t'ins',\n\t\t\t'kbd',\n\t\t\t'label',\n\t\t\t'legend',\n\t\t\t'li',\n\t\t\t'link',\n\t\t\t'main',\n\t\t\t'map',\n\t\t\t'mark',\n\t\t\t'meta',\n\t\t\t'meter',\n\t\t\t'nav',\n\t\t\t'noscript',\n\t\t\t'object',\n\t\t\t'ol',\n\t\t\t'optgroup',\n\t\t\t'option',\n\t\t\t'output',\n\t\t\t'p',\n\t\t\t'param',\n\t\t\t'picture',\n\t\t\t'pre',\n\t\t\t'progress',\n\t\t\t'q',\n\t\t\t'rp',\n\t\t\t'rt',\n\t\t\t'ruby',\n\t\t\t's',\n\t\t\t'samp',\n\t\t\t'script',\n\t\t\t'section',\n\t\t\t'select',\n\t\t\t'small',\n\t\t\t'source',\n\t\t\t'span',\n\t\t\t'strong',\n\t\t\t'style',\n\t\t\t'sub',\n\t\t\t'summary',\n\t\t\t'sup',\n\t\t\t'svg',\n\t\t\t'table',\n\t\t\t'tbody',\n\t\t\t'td',\n\t\t\t'template',\n\t\t\t'textarea',\n\t\t\t'tfoot',\n\t\t\t'th',\n\t\t\t'thead',\n\t\t\t'time',\n\t\t\t'title',\n\t\t\t'tr',\n\t\t\t'track',\n\t\t\t'u',\n\t\t\t'ul',\n\t\t\t'var',\n\t\t\t'video',\n\t\t\t'wbr',\n\t\t];\n\n\t\t// Check if it's an HTML tag\n\t\tconst tagMatch = path.match(/^\\/([a-z\\d]+)$/i);\n\t\tif (tagMatch && htmlTags.includes(tagMatch[1].toLowerCase())) {\n\t\t\treturn false;\n\t\t}\n\n\t\t// Skip very short paths that are likely false positives\n\t\tif (path.length < 4) {\n\t\t\treturn false;\n\t\t}\n\n\t\t// Skip paths that are just domain names\n\t\tif (/^\\/\\/[a-z\\d.-]+$/i.test(path)) {\n\t\t\treturn false;\n\t\t}\n\n\t\t// Must have a file extension or be a directory with multiple segments\n\t\tif (!path.includes('.') && !path.includes('/')) {\n\t\t\treturn false;\n\t\t}\n\n\t\treturn true;\n\t}\n\n\t// Optimize URL parsing with timeout protection (DONE)\n\tasync optimizeUrlParsing(url) {\n\t\ttry {\n\t\t\treturn await Promise.race([\n\t\t\t\tnormalizeUrl(url, {\n\t\t\t\t\tstripHash: true,\n\t\t\t\t\tstripWWW: false,\n\t\t\t\t\tremoveQueryParameters: false,\n\t\t\t\t}),\n\t\t\t\tnew Promise((_resolve, reject) => {\n\t\t\t\t\tsetTimeout(() => reject(new Error('URL parsing timeout')), 5000);\n\t\t\t\t}),\n\t\t\t]);\n\t\t} catch {\n\t\t\treturn url;\n\t\t}\n\t}\n\n\t// Enhanced Cloudflare blocked domain checking with timeout\n\tasync isCloudflareBlocked(hostname) {\n\t\ttry {\n\t\t\tconst response = await Promise.race([\n\t\t\t\tsuperagent\n\t\t\t\t\t.get(`https://1.1.1.3/dns-query?name=${hostname}&type=A`)\n\t\t\t\t\t.set('Accept', 'application/dns-json')\n\t\t\t\t\t.timeout(5000),\n\t\t\t\tnew Promise((_resolve, reject) => {\n\t\t\t\t\tsetTimeout(() => reject(new Error('DNS timeout')), 5000);\n\t\t\t\t}),\n\t\t\t]);\n\n\t\t\treturn response.body?.Status === 3; // NXDOMAIN indicates blocked\n\t\t} catch {\n\t\t\treturn false;\n\t\t}\n\t}\n\n\t// Extract URLs from all possible sources\n\textractAllUrls(mail, originalSource) {\n\t\tlet allText = '';\n\n\t\t// Add mail text and html\n\t\tallText += (mail.text || '') + ' ' + (mail.html || '');\n\n\t\t// Add header lines content\n\t\tif (mail.headerLines && Array.isArray(mail.headerLines)) {\n\t\t\tfor (const headerLine of mail.headerLines) {\n\t\t\t\tif (headerLine.line) {\n\t\t\t\t\tallText += ' ' + headerLine.line;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t// Also check original source if it's a simple string\n\t\tif (typeof originalSource === 'string') {\n\t\t\tallText += ' ' + originalSource;\n\t\t}\n\n\t\treturn this.getUrls(allText);\n\t}\n\n\t// Enhanced URL extraction with improved parsing using tldts\n\tgetUrls(string_) {\n\t\tif (!isSANB(string_)) {\n\t\t\treturn [];\n\t\t}\n\n\t\tconst urls = [];\n\t\tconst matches = string_.match(URL_PATTERN);\n\n\t\tif (matches) {\n\t\t\tfor (let url of matches) {\n\t\t\t\t// Clean up URL ending characters\n\t\t\t\turl = url.replace(URL_ENDING_RESERVED_CHARS, '');\n\n\t\t\t\t// Validate and normalize URL\n\t\t\t\ttry {\n\t\t\t\t\tconst normalizedUrl = normalizeUrl(url, {\n\t\t\t\t\t\tstripHash: false,\n\t\t\t\t\t\tstripWWW: false,\n\t\t\t\t\t});\n\t\t\t\t\turls.push(normalizedUrl);\n\t\t\t\t} catch {\n\t\t\t\t\t// If normalization fails, keep original\n\t\t\t\t\turls.push(url);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn [...new Set(urls)]; // Remove duplicates\n\t}\n\n\t// Parse URL using tldts for accurate domain extraction\n\tparseUrlWithTldts(url) {\n\t\ttry {\n\t\t\tconst parsed = parseTldts(url, {allowPrivateDomains: true});\n\t\t\treturn {\n\t\t\t\tdomain: parsed.domain,\n\t\t\t\tdomainWithoutSuffix: parsed.domainWithoutSuffix,\n\t\t\t\thostname: parsed.hostname,\n\t\t\t\tpublicSuffix: parsed.publicSuffix,\n\t\t\t\tsubdomain: parsed.subdomain,\n\t\t\t\tisIp: parsed.isIp,\n\t\t\t\tisIcann: parsed.isIcann,\n\t\t\t\tisPrivate: parsed.isPrivate,\n\t\t\t};\n\t\t} catch (error) {\n\t\t\tdebug('tldts parsing error:', error);\n\t\t\treturn null;\n\t\t}\n\t}\n\n\t// Enhanced tokenization with language detection\n\tasync getTokens(string_, locale = 'en', isHtml = false) {\n\t\tif (!isSANB(string_)) {\n\t\t\treturn [];\n\t\t}\n\n\t\tlet text = string_;\n\n\t\t// Strip HTML if needed\n\t\tif (isHtml) {\n\t\t\ttext = striptags(text);\n\t\t}\n\n\t\t// Detect language if not provided or if mixed language detection is enabled\n\t\tif (!locale || this.config.enableMixedLanguageDetection) {\n\t\t\ttry {\n\t\t\t\tconst detected = lande(text);\n\t\t\t\tif (detected && detected.length > 0) {\n\t\t\t\t\tlocale = detected[0][0];\n\t\t\t\t}\n\t\t\t} catch {\n\t\t\t\tlocale ||= 'en';\n\t\t\t}\n\t\t}\n\n\t\t// Normalize locale\n\t\tlocale = this.parseLocale(locale);\n\n\t\t// Convert full-width to half-width characters\n\t\ttext = converter.toHalfWidth(text);\n\n\t\t// Expand contractions\n\t\ttry {\n\t\t\ttext = expandContractions(text);\n\t\t} catch {\n\t\t\t// If expansion fails, continue with original text\n\t\t}\n\n\t\t// Tokenize based on language\n\t\tlet tokens = [];\n\n\t\tif (locale === 'ja') {\n\t\t\t// Japanese tokenization\n\t\t\ttry {\n\t\t\t\ttokens = chineseTokenizer.tokenize(text);\n\t\t\t} catch {\n\t\t\t\ttokens = text.split(GENERIC_TOKENIZER);\n\t\t\t}\n\t\t} else if (locale === 'zh') {\n\t\t\t// Chinese tokenization\n\t\t\ttry {\n\t\t\t\ttokens = chineseTokenizer.tokenize(text);\n\t\t\t} catch {\n\t\t\t\ttokens = text.split(GENERIC_TOKENIZER);\n\t\t\t}\n\t\t} else {\n\t\t\t// Generic tokenization for other languages\n\t\t\ttokens = text.split(GENERIC_TOKENIZER);\n\t\t}\n\n\t\t// Process tokens\n\t\tlet processedTokens = tokens\n\t\t\t.map(token => token.toLowerCase().trim())\n\t\t\t.filter(token => token.length > 0 && token.length <= 50); // Reasonable length limit\n\n\t\t// Remove stopwords\n\t\tconst stopwordSet = stopwordsMap.get(locale) || stopwordsMap.get('en');\n\t\tif (stopwordSet) {\n\t\t\tprocessedTokens = processedTokens.filter(token => !stopwordSet.has(token));\n\t\t}\n\n\t\t// Stem words if available for the language\n\t\ttry {\n\t\t\tif (['en', 'es', 'fr', 'de', 'it', 'pt', 'ru'].includes(locale)) {\n\t\t\t\tprocessedTokens = processedTokens.map(token => {\n\t\t\t\t\ttry {\n\t\t\t\t\t\treturn snowball.stemword(token, locale);\n\t\t\t\t\t} catch {\n\t\t\t\t\t\treturn token;\n\t\t\t\t\t}\n\t\t\t\t});\n\t\t\t}\n\t\t} catch {\n\t\t\t// If stemming fails, continue with original tokens\n\t\t}\n\n\t\t// Apply token hashing if enabled\n\t\tif (this.config.hashTokens) {\n\t\t\tprocessedTokens = processedTokens.map(token =>\n\t\t\t\tcreateHash('sha256')\n\t\t\t\t\t.update(token)\n\t\t\t\t\t.digest('hex')\n\t\t\t\t\t.slice(0, 16)); // Use first 16 characters for efficiency\n\t\t}\n\n\t\treturn processedTokens;\n\t}\n\n\t// Enhanced text preprocessing with pattern recognition\n\tasync preprocessText(string_) {\n\t\tif (!isSANB(string_)) {\n\t\t\treturn '';\n\t\t}\n\n\t\tlet text = string_;\n\n\t\t// Apply replacements if available\n\t\tif (this.replacements) {\n\t\t\tfor (const [original, replacement] of this.replacements) {\n\t\t\t\ttext = text.replaceAll(new RegExp(escapeStringRegexp(original), 'gi'), replacement);\n\t\t\t}\n\t\t}\n\n\t\t// Advanced pattern recognition (DONE)\n\t\tif (this.config.enableAdvancedPatternRecognition) {\n\t\t\t// Replace patterns with normalized tokens\n\t\t\ttext = text.replaceAll(DATE_PATTERNS[0], ' DATE_PATTERN ');\n\t\t\ttext = text.replace(CREDIT_CARD_PATTERN, ' CREDIT_CARD ');\n\t\t\ttext = text.replace(PHONE_PATTERN, ' PHONE_NUMBER ');\n\t\t\ttext = text.replace(EMAIL_PATTERN, ' EMAIL_ADDRESS ');\n\t\t\ttext = text.replace(IP_PATTERN, ' IP_ADDRESS ');\n\t\t\ttext = text.replace(URL_PATTERN, ' URL_LINK ');\n\t\t\ttext = text.replace(BITCOIN_PATTERN, ' BITCOIN_ADDRESS ');\n\t\t\ttext = text.replace(MAC_PATTERN, ' MAC_ADDRESS ');\n\t\t\ttext = text.replace(HEX_COLOR_PATTERN, ' HEX_COLOR ');\n\t\t\ttext = text.replace(FLOATING_POINT_PATTERN, ' FLOATING_POINT ');\n\t\t}\n\n\t\treturn text;\n\t}\n\n\t// Main scan method - enhanced with performance metrics and new features\n\tasync scan(source) {\n\t\tconst startTime = Date.now();\n\n\t\ttry {\n\t\t\t// Initialize components if needed\n\t\t\tawait this.initializeClassifier();\n\t\t\tawait this.initializeReplacements();\n\n\t\t\t// Get tokens and mail from source\n\t\t\tconst {tokens, mail} = await this.getTokensAndMailFromSource(source);\n\n\t\t\t// Run all detection methods\n\t\t\tconst [\n\t\t\t\tclassification,\n\t\t\t\tphishing,\n\t\t\t\texecutables,\n\t\t\t\tmacros,\n\t\t\t\tarbitrary,\n\t\t\t\tviruses,\n\t\t\t\tpatterns,\n\t\t\t\tidnHomographAttack,\n\t\t\t\ttoxicity,\n\t\t\t\tnsfw,\n\t\t\t] = await Promise.all([\n\t\t\t\tthis.getClassification(tokens),\n\t\t\t\tthis.getPhishingResults(mail),\n\t\t\t\tthis.getExecutableResults(mail),\n\t\t\t\tthis.config.enableMacroDetection ? this.getMacroResults(mail) : [],\n\t\t\t\tthis.getArbitraryResults(mail),\n\t\t\t\tthis.getVirusResults(mail),\n\t\t\t\tthis.getPatternResults(mail),\n\t\t\t\tthis.getIDNHomographResults(mail),\n\t\t\t\tthis.getToxicityResults(mail),\n\t\t\t\tthis.getNSFWResults(mail),\n\t\t\t]);\n\n\t\t\t// Determine if spam\n\t\t\tconst isSpam\n\t\t\t\t= classification.category === 'spam'\n\t\t\t\t\t|| phishing.length > 0\n\t\t\t\t\t|| executables.length > 0\n\t\t\t\t\t|| macros.length > 0\n\t\t\t\t\t|| arbitrary.length > 0\n\t\t\t\t\t|| viruses.length > 0\n\t\t\t\t\t|| patterns.length > 0\n\t\t\t\t\t|| (idnHomographAttack && idnHomographAttack.detected)\n\t\t\t\t\t|| toxicity.length > 0\n\t\t\t\t\t|| nsfw.length > 0;\n\n\t\t\t// Generate message\n\t\t\tlet message = 'Ham';\n\t\t\tif (isSpam) {\n\t\t\t\tconst reasons = [];\n\t\t\t\tif (classification.category === 'spam') {\n\t\t\t\t\treasons.push('spam classification');\n\t\t\t\t}\n\n\t\t\t\tif (phishing.length > 0) {\n\t\t\t\t\treasons.push('phishing detected');\n\t\t\t\t}\n\n\t\t\t\tif (executables.length > 0) {\n\t\t\t\t\treasons.push('executable content');\n\t\t\t\t}\n\n\t\t\t\tif (macros.length > 0) {\n\t\t\t\t\treasons.push('macro detected');\n\t\t\t\t}\n\n\t\t\t\tif (arbitrary.length > 0) {\n\t\t\t\t\treasons.push('arbitrary patterns');\n\t\t\t\t}\n\n\t\t\t\tif (viruses.length > 0) {\n\t\t\t\t\treasons.push('virus detected');\n\t\t\t\t}\n\n\t\t\t\tif (patterns.length > 0) {\n\t\t\t\t\treasons.push('suspicious patterns');\n\t\t\t\t}\n\n\t\t\t\tif (idnHomographAttack && idnHomographAttack.detected) {\n\t\t\t\t\treasons.push('IDN homograph attack');\n\t\t\t\t}\n\n\t\t\t\tif (toxicity.length > 0) {\n\t\t\t\t\treasons.push('toxic content');\n\t\t\t\t}\n\n\t\t\t\tif (nsfw.length > 0) {\n\t\t\t\t\treasons.push('NSFW content');\n\t\t\t\t}\n\n\t\t\t\tmessage = `Spam (${arrayJoinConjunction(reasons)})`;\n\t\t\t}\n\n\t\t\tconst endTime = Date.now();\n\t\t\tconst processingTime = endTime - startTime;\n\n\t\t\t// Update metrics\n\t\t\tthis.metrics.totalScans++;\n\t\t\tthis.metrics.lastScanTime = processingTime;\n\t\t\tthis.metrics.averageTime\n\t\t\t\t= ((this.metrics.averageTime * (this.metrics.totalScans - 1)) + processingTime)\n\t\t\t\t\t/ this.metrics.totalScans;\n\n\t\t\tconst result = {\n\t\t\t\tisSpam,\n\t\t\t\tmessage,\n\t\t\t\tresults: {\n\t\t\t\t\tclassification,\n\t\t\t\t\tphishing,\n\t\t\t\t\texecutables,\n\t\t\t\t\tmacros,\n\t\t\t\t\tarbitrary,\n\t\t\t\t\tviruses,\n\t\t\t\t\tpatterns,\n\t\t\t\t\tidnHomographAttack,\n\t\t\t\t\ttoxicity,\n\t\t\t\t\tnsfw,\n\t\t\t\t},\n\t\t\t\tlinks: this.extractAllUrls(mail, source),\n\t\t\t\ttokens,\n\t\t\t\tmail,\n\t\t\t};\n\n\t\t\t// Add performance metrics if enabled\n\t\t\tif (this.config.enablePerformanceMetrics) {\n\t\t\t\tresult.metrics = {\n\t\t\t\t\ttotalTime: processingTime,\n\t\t\t\t\tclassificationTime: 0, // Would need to measure individually\n\t\t\t\t\tphishingTime: 0,\n\t\t\t\t\texecutableTime: 0,\n\t\t\t\t\tmacroTime: 0,\n\t\t\t\t\tvirusTime: 0,\n\t\t\t\t\tpatternTime: 0,\n\t\t\t\t\tidnTime: 0,\n\t\t\t\t\tmemoryUsage: process.memoryUsage(),\n\t\t\t\t};\n\t\t\t}\n\n\t\t\treturn result;\n\t\t} catch (error) {\n\t\t\tdebug('Scan error:', error);\n\t\t\tthrow error;\n\t\t}\n\t}\n\n\t// Get pattern recognition results\n\tasync getPatternResults(mail) {\n\t\tconst results = [];\n\t\tconst textContent = mail.text || '';\n\t\tconst htmlContent = mail.html || '';\n\t\tconst allContent = textContent + ' ' + htmlContent;\n\n\t\t// Date pattern detection\n\t\tfor (const pattern of DATE_PATTERNS) {\n\t\t\tconst matches = allContent.match(pattern);\n\t\t\tif (matches && matches.length > 5) {\n\t\t\t\t// Suspicious if many dates\n\t\t\t\tresults.push({\n\t\t\t\t\ttype: 'pattern',\n\t\t\t\t\tsubtype: 'date_spam',\n\t\t\t\t\tcount: matches.length,\n\t\t\t\t\tdescription: 'Excessive date patterns detected',\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\n\t\t// File path detection\n\t\tconst filePathResults = await this.getFilePathResults(mail);\n\t\tresults.push(...filePathResults);\n\n\t\treturn results;\n\t}\n\n\t// Enhanced mail parsing with better error handling\n\tasync getTokensAndMailFromSource(source) {\n\t\tlet mail;\n\n\t\tif (typeof source === 'string' && fs.existsSync(source)) {\n\t\t\t// File path\n\t\t\tsource = fs.readFileSync(source);\n\t\t}\n\n\t\tif (isBuffer(source)) {\n\t\t\tsource = source.toString();\n\t\t}\n\n\t\tif (!source || typeof source !== 'string') {\n\t\t\tsource = '';\n\t\t}\n\n\t\ttry {\n\t\t\tmail = await simpleParser(source);\n\t\t} catch (error) {\n\t\t\tdebug('Mail parsing error:', error);\n\t\t\t// Create minimal mail object\n\t\t\tmail = {\n\t\t\t\ttext: source,\n\t\t\t\thtml: '',\n\t\t\t\tsubject: '',\n\t\t\t\tfrom: {},\n\t\t\t\tto: [],\n\t\t\t\tattachments: [],\n\t\t\t};\n\t\t}\n\n\t\t// Preprocess text content\n\t\tconst textContent = await this.preprocessText(mail.text || '');\n\t\tconst htmlContent = await this.preprocessText(striptags(mail.html || ''));\n\t\tconst subjectContent = await this.preprocessText(mail.subject || '');\n\n\t\t// Get tokens from all content\n\t\tconst allContent = [textContent, htmlContent, subjectContent].join(' ');\n\t\tconst tokens = await this.getTokens(allContent, 'en');\n\n\t\treturn {tokens, mail};\n\t}\n\n\t// Enhanced classification with better error handling\n\tasync getClassification(tokens) {\n\t\tif (!this.classifier) {\n\t\t\tawait this.initializeClassifier();\n\t\t}\n\n\t\ttry {\n\t\t\t// Join tokens into a string for the classifier\n\t\t\tconst text = Array.isArray(tokens) ? tokens.join(' ') : String(tokens);\n\t\t\tconst result = this.classifier.categorize(text);\n\n\t\t\treturn {\n\t\t\t\tcategory: result,\n\t\t\t\tprobability: 0.5, // Default probability\n\t\t\t};\n\t\t} catch (error) {\n\t\t\tdebug('Classification error:', error);\n\t\t\treturn {\n\t\t\t\tcategory: 'ham',\n\t\t\t\tprobability: 0.5,\n\t\t\t};\n\t\t}\n\t}\n\n\t// Enhanced phishing detection\n\tasync getPhishingResults(mail) {\n\t\tconst results = [];\n\t\tconst links = this.getUrls(mail.text || '');\n\n\t\tfor (const url of links) {\n\t\t\ttry {\n\t\t\t\t// eslint-disable-next-line no-await-in-loop\n\t\t\t\tconst normalizedUrl = await this.optimizeUrlParsing(url);\n\t\t\t\tconst parsed = new URL(normalizedUrl);\n\n\t\t\t\t// Check for suspicious domains\n\t\t\t\t// eslint-disable-next-line no-await-in-loop\n\t\t\t\tconst isBlocked = await this.isCloudflareBlocked(parsed.hostname);\n\t\t\t\tif (isBlocked) {\n\t\t\t\t\tresults.push({\n\t\t\t\t\t\ttype: 'phishing',\n\t\t\t\t\t\turl: normalizedUrl,\n\n\t\t\t\t\t\tdescription: 'Blocked by security filters',\n\t\t\t\t\t});\n\t\t\t\t}\n\n\t\t\t\t// Enhanced IDN homograph attack detection\n\t\t\t\t// eslint-disable-next-line no-await-in-loop\n\t\t\t\tconst idnDetector = await this.getIDNDetector();\n\t\t\t\tif (idnDetector && parsed.hostname) {\n\t\t\t\t\tconst context = {\n\t\t\t\t\t\temailContent: mail.text || mail.html || '',\n\t\t\t\t\t\tdisplayText: url === normalizedUrl ? null : url,\n\t\t\t\t\t\tsenderReputation: 0.5, // Default neutral reputation\n\t\t\t\t\t};\n\n\t\t\t\t\tconst idnAnalysis = idnDetector.detectHomographAttack(parsed.hostname, context);\n\n\t\t\t\t\tif (idnAnalysis.riskScore > 0.6) {\n\t\t\t\t\t\tresults.push({\n\t\t\t\t\t\t\ttype: 'phishing',\n\t\t\t\t\t\t\turl: normalizedUrl,\n\t\t\t\t\t\t\tdescription: `IDN homograph attack detected (risk: ${(idnAnalysis.riskScore * 100).toFixed(1)}%)`,\n\t\t\t\t\t\t\tdetails: {\n\t\t\t\t\t\t\t\triskFactors: idnAnalysis.riskFactors,\n\t\t\t\t\t\t\t\trecommendations: idnAnalysis.recommendations,\n\t\t\t\t\t\t\t\tconfidence: idnAnalysis.confidence,\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t});\n\t\t\t\t\t} else if (idnAnalysis.riskScore > 0.3) {\n\t\t\t\t\t\tresults.push({\n\t\t\t\t\t\t\ttype: 'suspicious',\n\t\t\t\t\t\t\turl: normalizedUrl,\n\t\t\t\t\t\t\tdescription: `Suspicious IDN domain (risk: ${(idnAnalysis.riskScore * 100).toFixed(1)}%)`,\n\t\t\t\t\t\t\tdetails: {\n\t\t\t\t\t\t\t\triskFactors: idnAnalysis.riskFactors,\n\t\t\t\t\t\t\t\trecommendations: idnAnalysis.recommendations,\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t});\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t} catch (error) {\n\t\t\t\tdebug('Phishing check error:', error);\n\t\t\t}\n\t\t}\n\n\t\treturn results;\n\t}\n\n\t// Enhanced executable detection\n\tasync getExecutableResults(mail) {\n\t\tconst results = [];\n\t\tconst attachments = mail.attachments || [];\n\n\t\tfor (const attachment of attachments) {\n\t\t\tif (attachment.filename) {\n\t\t\t\tconst extension = fileExtension(attachment.filename).toLowerCase();\n\n\t\t\t\tif (EXECUTABLES.has(extension)) {\n\t\t\t\t\tresults.push({\n\t\t\t\t\t\ttype: 'executable',\n\t\t\t\t\t\tfilename: attachment.filename,\n\t\t\t\t\t\textension,\n\t\t\t\t\t\tdescription: 'Executable file attachment',\n\t\t\t\t\t});\n\t\t\t\t}\n\n\t\t\t\t// Check for archive files (potential evasion technique)\n\t\t\t\tconst archiveExtensions = ['zip', 'rar', '7z', 'tar', 'gz', 'bz2', 'xz', 'arj', 'cab', 'lzh', 'ace', 'iso'];\n\t\t\t\tif (archiveExtensions.includes(extension)) {\n\t\t\t\t\tresults.push({\n\t\t\t\t\t\ttype: 'archive',\n\t\t\t\t\t\tfilename: attachment.filename,\n\t\t\t\t\t\textension,\n\t\t\t\t\t\tdescription: 'Archive attachment (contents not scanned)',\n\t\t\t\t\t\trisk: 'medium',\n\t\t\t\t\t\twarning: 'Archive contents should be extracted and scanned separately',\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Check file content for executable signatures\n\t\t\tif (attachment.content && isBuffer(attachment.content)) {\n\t\t\t\ttry {\n\t\t\t\t\t// eslint-disable-next-line no-await-in-loop\n\t\t\t\t\tconst fileType = await fileTypeFromBuffer(attachment.content);\n\t\t\t\t\tif (fileType && EXECUTABLES.has(fileType.ext)) {\n\t\t\t\t\t\tresults.push({\n\t\t\t\t\t\t\ttype: 'executable',\n\t\t\t\t\t\t\tfilename: attachment.filename || 'unknown',\n\t\t\t\t\t\t\tdetectedType: fileType.ext,\n\t\t\t\t\t\t\tdescription: 'Executable content detected',\n\t\t\t\t\t\t});\n\t\t\t\t\t}\n\t\t\t\t} catch (error) {\n\t\t\t\t\tdebug('File type detection error:', error);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn results;\n\t}\n\n\t// Arbitrary results (GTUBE, etc.)\n\tasync getArbitraryResults(mail) {\n\t\tconst results = [];\n\n\t\t// Get content from text, html, and header lines\n\t\tlet content = (mail.text || '') + (mail.html || '');\n\n\t\t// Also check header lines for content (like GTUBE in raw emails)\n\t\tif (mail.headerLines && Array.isArray(mail.headerLines)) {\n\t\t\tfor (const headerLine of mail.headerLines) {\n\t\t\t\tif (headerLine.line) {\n\t\t\t\t\tcontent += ' ' + headerLine.line;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t// GTUBE test\n\t\tif (content.includes('XJS*C4JDBQADN1.NSBN3*2IDNEN*GTUBE-STANDARD-ANTI-UBE-TEST-EMAIL*C.34X')) {\n\t\t\tresults.push({\n\t\t\t\ttype: 'arbitrary',\n\t\t\t\tdescription: 'GTUBE spam test pattern detected',\n\t\t\t});\n\t\t}\n\n\t\treturn results;\n\t}\n\n\t// Parse and normalize locale\n\tparseLocale(locale) {\n\t\tif (!locale || typeof locale !== 'string') {\n\t\t\treturn 'en';\n\t\t}\n\n\t\t// Handle locale codes like 'en-US' -> 'en'\n\t\tconst normalized = locale.toLowerCase().split('-')[0];\n\t\t// Map some common variations\n\t\tconst localeMap = {\n\t\t\tnb: 'no', // Norwegian Bokm\u00E5l\n\t\t\tnn: 'no', // Norwegian Nynorsk\n\t\t\t'zh-cn': 'zh',\n\t\t\t'zh-tw': 'zh',\n\t\t};\n\t\treturn localeMap[normalized] || normalized;\n\t}\n\n\t// Get IDN homograph attack results\n\tasync getIDNHomographResults(mail) {\n\t\tconst result = {\n\t\t\tdetected: false,\n\t\t\tdomains: [],\n\t\t\triskScore: 0,\n\t\t\tdetails: [],\n\t\t};\n\n\t\ttry {\n\t\t\tconst idnDetector = await this.getIDNDetector();\n\t\t\tif (!idnDetector) {\n\t\t\t\treturn result;\n\t\t\t}\n\n\t\t\t// Extract URLs from email content\n\t\t\tconst textContent = mail.text || '';\n\t\t\tconst htmlContent = mail.html || '';\n\t\t\tconst allContent = textContent + ' ' + htmlContent;\n\t\t\tconst urls = this.getUrls(allContent);\n\n\t\t\t// Analyze each domain\n\t\t\tfor (const url of urls) {\n\t\t\t\ttry {\n\t\t\t\t\t// eslint-disable-next-line no-await-in-loop\n\t\t\t\t\tconst normalizedUrl = await this.optimizeUrlParsing(url);\n\t\t\t\t\tconst parsed = new URL(normalizedUrl);\n\t\t\t\t\tconst domain = parsed.hostname;\n\n\t\t\t\t\tif (!domain) {\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\t}\n\n\t\t\t\t\t// Prepare context for analysis\n\t\t\t\t\tconst context = {\n\t\t\t\t\t\temailContent: allContent,\n\t\t\t\t\t\tdisplayText: url === normalizedUrl ? null : url,\n\t\t\t\t\t\tsenderReputation: 0.5, // Default neutral reputation\n\t\t\t\t\t\temailHeaders: mail.headers || {},\n\t\t\t\t\t};\n\n\t\t\t\t\t// Perform IDN analysis\n\t\t\t\t\tconst analysis = idnDetector.detectHomographAttack(domain, context);\n\n\t\t\t\t\tif (analysis.riskScore > 0.3) {\n\t\t\t\t\t\tresult.detected = true;\n\t\t\t\t\t\tresult.domains.push({\n\t\t\t\t\t\t\tdomain,\n\t\t\t\t\t\t\toriginalUrl: url,\n\t\t\t\t\t\t\tnormalizedUrl,\n\t\t\t\t\t\t\triskScore: analysis.riskScore,\n\t\t\t\t\t\t\triskFactors: analysis.riskFactors,\n\t\t\t\t\t\t\trecommendations: analysis.recommendations,\n\t\t\t\t\t\t\tconfidence: analysis.confidence,\n\t\t\t\t\t\t});\n\n\t\t\t\t\t\t// Update overall risk score to highest found\n\t\t\t\t\t\tresult.riskScore = Math.max(result.riskScore, analysis.riskScore);\n\t\t\t\t\t}\n\t\t\t\t} catch (error) {\n\t\t\t\t\tdebug('IDN analysis error for URL:', url, error);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Add summary details\n\t\t\tif (result.detected) {\n\t\t\t\tresult.details.push(\n\t\t\t\t\t`Found ${result.domains.length} suspicious domain(s)`,\n\t\t\t\t\t`Highest risk score: ${(result.riskScore * 100).toFixed(1)}%`,\n\t\t\t\t);\n\n\t\t\t\t// Add specific risk factors\n\t\t\t\tconst allRiskFactors = new Set();\n\t\t\t\tfor (const domain of result.domains) {\n\t\t\t\t\tfor (const factor of domain.riskFactors) {\n\t\t\t\t\t\tallRiskFactors.add(factor);\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tresult.details.push(...allRiskFactors);\n\t\t\t}\n\t\t} catch (error) {\n\t\t\tdebug('IDN homograph detection error:', error);\n\t\t}\n\n\t\treturn result;\n\t}\n\n\t// Get IDN detector instance\n\tasync getIDNDetector() {\n\t\tif (!this.idnDetector) {\n\t\t\ttry {\n\t\t\t\tconst {default: EnhancedIDNDetector} = await import('./enhanced-idn-detector.js');\n\t\t\t\tthis.idnDetector = new EnhancedIDNDetector({\n\t\t\t\t\tstrictMode: this.config.strictIDNDetection || false,\n\t\t\t\t\tenableWhitelist: true,\n\t\t\t\t\tenableBrandProtection: true,\n\t\t\t\t\tenableContextAnalysis: true,\n\t\t\t\t});\n\t\t\t} catch (error) {\n\t\t\t\tdebug('Failed to load IDN detector:', error);\n\t\t\t\treturn null;\n\t\t\t}\n\t\t}\n\n\t\treturn this.idnDetector;\n\t}\n\n\t// Hybrid language detection using both lande and franc\n\tasync detectLanguageHybrid(text) {\n\t\tif (!text || typeof text !== 'string' || text.length < 3) {\n\t\t\treturn 'en';\n\t\t}\n\n\t\t// Handle edge cases for non-linguistic content\n\t\tconst cleanText = text.trim();\n\t\tif (!cleanText || /^[\\d\\s\\W]+$/.test(cleanText)) {\n\t\t\t// Only numbers, spaces, and special characters\n\t\t\treturn 'en';\n\t\t}\n\n\t\ttry {\n\t\t\t// Use lande for short text (< 50 chars), franc for longer text\n\t\t\tif (text.length < 50) {\n\t\t\t\tconst landeResult = lande(text);\n\t\t\t\tif (landeResult && landeResult.length > 0) {\n\t\t\t\t\t// Convert lande's 3-letter codes to 2-letter codes\n\t\t\t\t\tconst detected = landeResult[0][0];\n\t\t\t\t\tconst normalized = this.normalizeLanguageCode(detected);\n\n\t\t\t\t\t// Additional validation for short text detection\n\t\t\t\t\tif (this.isValidShortTextDetection(text, normalized)) {\n\t\t\t\t\t\t// Filter by supportedLanguages if configured\n\t\t\t\t\t\tif (this.config.supportedLanguages && this.config.supportedLanguages.length > 0) {\n\t\t\t\t\t\t\tif (this.config.supportedLanguages.includes(normalized)) {\n\t\t\t\t\t\t\t\treturn normalized;\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\treturn this.config.supportedLanguages[0];\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\treturn normalized;\n\t\t\t\t\t}\n\n\t\t\t\t\t// Fallback to English for ambiguous short text\n\t\t\t\t\treturn 'en';\n\t\t\t\t}\n\n\t\t\t\treturn 'en';\n\t\t\t}\n\n\t\t\t// Import franc dynamically\n\t\t\tconst {franc} = await import('franc');\n\t\t\tconst francResult = franc(text);\n\t\t\tif (francResult === 'und') {\n\t\t\t\t// Fallback to lande if franc can't detect\n\t\t\t\tconst landeResult = lande(text);\n\t\t\t\tif (landeResult && landeResult.length > 0) {\n\t\t\t\t\treturn this.normalizeLanguageCode(landeResult[0][0]);\n\t\t\t\t}\n\n\t\t\t\treturn 'en';\n\t\t\t}\n\n\t\t\tconst detected = this.normalizeLanguageCode(francResult);\n\n\t\t\t// Filter by supportedLanguages if configured\n\t\t\tif (this.config.supportedLanguages && this.config.supportedLanguages.length > 0) {\n\t\t\t\tif (this.config.supportedLanguages.includes(detected)) {\n\t\t\t\t\treturn detected;\n\t\t\t\t}\n\n\t\t\t\t// If detected language not supported, return first supported language\n\t\t\t\treturn this.config.supportedLanguages[0];\n\t\t\t}\n\n\t\t\treturn detected;\n\t\t} catch (error) {\n\t\t\tdebug('Language detection error:', error);\n\t\t\t// Fallback to lande\n\t\t\ttry {\n\t\t\t\tconst landeResult = lande(text);\n\t\t\t\tif (landeResult && landeResult.length > 0) {\n\t\t\t\t\treturn this.normalizeLanguageCode(landeResult[0][0]);\n\t\t\t\t}\n\n\t\t\t\treturn 'en';\n\t\t\t} catch {\n\t\t\t\treturn 'en';\n\t\t\t}\n\t\t}\n\t}\n\n\t// Validate short text language detection\n\tisValidShortTextDetection(text, detectedLang) {\n\t\t// For non-Latin scripts, always trust the detection\n\t\t// eslint-disable-next-line no-control-regex\n\t\tconst hasNonLatin = /[^\\u0000-\\u024F\\u1E00-\\u1EFF]/.test(text);\n\t\tif (hasNonLatin) {\n\t\t\treturn true;\n\t\t}\n\n\t\t// For very short Latin text (< 7 chars), be conservative\n\t\tif (text.length < 7 && detectedLang !== 'en') {\n\t\t\treturn false;\n\t\t}\n\n\t\t// For longer Latin text, trust the detection\n\t\treturn true;\n\t}\n\n\t// Get toxicity detection results\n\tasync getToxicityResults(mail) {\n\t\tconst results = [];\n\n\t\ttry {\n\t\t\t// Lazy load TensorFlow and toxicity model\n\t\t\tif (!this.toxicityModel) {\n\t\t\t\tconst _tf = await import('@tensorflow/tfjs-node');\n\t\t\t\tconst toxicity = await import('@tensorflow-models/toxicity');\n\n\t\t\t\t// Load model with threshold of 0.7 (higher = more strict)\n\t\t\t\tconst threshold = this.config.toxicityThreshold || 0.7;\n\t\t\t\tthis.toxicityModel = await toxicity.load(threshold);\n\t\t\t}\n\n\t\t\t// Get text content from email\n\t\t\tconst textContent = mail.text || '';\n\t\t\tconst htmlContent = striptags(mail.html || '');\n\t\t\tconst subjectContent = mail.subject || '';\n\n\t\t\t// Combine all content\n\t\t\tconst allContent = [subjectContent, textContent, htmlContent]\n\t\t\t\t.filter(text => text && text.trim().length > 0)\n\t\t\t\t.join(' ')\n\t\t\t\t.slice(0, 5000); // Limit to 5000 chars for performance\n\n\t\t\tif (!allContent || allContent.trim().length < 10) {\n\t\t\t\treturn results;\n\t\t\t}\n\n\t\t\t// Classify text for toxicity\n\t\t\tconst predictions = await Promise.race([\n\t\t\t\tthis.toxicityModel.classify([allContent]),\n\t\t\t\tnew Promise((_resolve, reject) => {\n\t\t\t\t\tsetTimeout(() => reject(new Error('Toxicity detection timeout')), this.config.timeout);\n\t\t\t\t}),\n\t\t\t]);\n\n\t\t\t// Process predictions\n\t\t\tfor (const prediction of predictions) {\n\t\t\t\tconst {label} = prediction;\n\t\t\t\tconst matches = prediction.results[0].match;\n\n\t\t\t\tif (matches) {\n\t\t\t\t\tconst {probabilities} = prediction.results[0];\n\t\t\t\t\tconst toxicProbability = probabilities[1]; // Index 1 is toxic probability\n\n\t\t\t\t\tresults.push({\n\t\t\t\t\t\ttype: 'toxicity',\n\t\t\t\t\t\tcategory: label,\n\t\t\t\t\t\tprobability: toxicProbability,\n\t\t\t\t\t\tdescription: `Toxic content detected: ${label} (${(toxicProbability * 100).toFixed(1)}%)`,\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t}\n\t\t} catch (error) {\n\t\t\tdebug('Toxicity detection error:', error);\n\t\t\t// Don't fail the whole scan if toxicity detection fails\n\t\t}\n\n\t\treturn results;\n\t}\n\n\t// Get NSFW image detection results\n\tasync getNSFWResults(mail) {\n\t\tconst results = [];\n\n\t\ttry {\n\t\t\t// Lazy load TensorFlow and NSFW model\n\t\t\tif (!this.nsfwModel) {\n\t\t\t\tconst _tf = await import('@tensorflow/tfjs-node');\n\t\t\t\tconst nsfw = await import('nsfwjs');\n\n\t\t\t\t// Load model\n\t\t\t\tthis.nsfwModel = await nsfw.load();\n\t\t\t}\n\n\t\t\tconst attachments = mail.attachments || [];\n\n\t\t\t// Process image attachments\n\t\t\tfor (const attachment of attachments) {\n\t\t\t\ttry {\n\t\t\t\t\tif (!attachment.content || !isBuffer(attachment.content)) {\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\t}\n\n\t\t\t\t\t// Check if it's an image\n\t\t\t\t\t// eslint-disable-next-line no-await-in-loop\n\t\t\t\t\tconst fileType = await fileTypeFromBuffer(attachment.content);\n\n\t\t\t\t\tif (!fileType || !fileType.mime.startsWith('image/')) {\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\t}\n\n\t\t\t\t\t// Use sharp to process image for NSFW detection\n\t\t\t\t\t// eslint-disable-next-line no-await-in-loop, unicorn/no-await-expression-member\n\t\t\t\t\tconst sharp = (await import('sharp')).default;\n\t\t\t\t\t// eslint-disable-next-line no-await-in-loop\n\t\t\t\t\tconst processedImage = await sharp(attachment.content)\n\t\t\t\t\t\t.resize(224, 224) // NSFW model expects 224x224\n\t\t\t\t\t\t.raw()\n\t\t\t\t\t\t.toBuffer();\n\n\t\t\t\t\t// Convert to tensor and classify\n\t\t\t\t\t// eslint-disable-next-line no-await-in-loop\n\t\t\t\t\tconst _tf = await import('@tensorflow/tfjs-node');\n\t\t\t\t\tconst imageTensor = _tf.tensor3d(\n\t\t\t\t\t\tnew Uint8Array(processedImage),\n\t\t\t\t\t\t[224, 224, 3],\n\t\t\t\t\t);\n\n\t\t\t\t\t// eslint-disable-next-line no-await-in-loop\n\t\t\t\t\tconst predictions = await Promise.race([\n\t\t\t\t\t\tthis.nsfwModel.classify(imageTensor),\n\t\t\t\t\t\tnew Promise((_resolve, reject) => {\n\t\t\t\t\t\t\tsetTimeout(() => reject(new Error('NSFW detection timeout')), this.config.timeout);\n\t\t\t\t\t\t}),\n\t\t\t\t\t]);\n\n\t\t\t\t\t// Clean up tensor\n\t\t\t\t\timageTensor.dispose();\n\n\t\t\t\t\t// Check predictions\n\t\t\t\t\tconst nsfwThreshold = this.config.nsfwThreshold || 0.6;\n\t\t\t\t\tfor (const prediction of predictions) {\n\t\t\t\t\t\tif (\n\t\t\t\t\t\t\t(prediction.className === 'Porn'\n\t\t\t\t\t\t\t\t|| prediction.className === 'Hentai'\n\t\t\t\t\t\t\t\t|| prediction.className === 'Sexy')\n\t\t\t\t\t\t\t&& prediction.probability > nsfwThreshold\n\t\t\t\t\t\t) {\n\t\t\t\t\t\t\tresults.push({\n\t\t\t\t\t\t\t\ttype: 'nsfw',\n\t\t\t\t\t\t\t\tfilename: attachment.filename || 'unknown',\n\t\t\t\t\t\t\t\tcategory: prediction.className,\n\t\t\t\t\t\t\t\tprobability: prediction.probability,\n\t\t\t\t\t\t\t\tdescription: `NSFW image detected: ${prediction.className} (${(prediction.probability * 100).toFixed(1)}%)`,\n\t\t\t\t\t\t\t});\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t} catch (error) {\n\t\t\t\t\tdebug('NSFW detection error for attachment:', attachment.filename, error);\n\t\t\t\t}\n\t\t\t}\n\t\t} catch (error) {\n\t\t\tdebug('NSFW detection error:', error);\n\t\t\t// Don't fail the whole scan if NSFW detection fails\n\t\t}\n\n\t\treturn results;\n\t}\n\n\t// Normalize language codes from 3-letter to 2-letter format\n\tnormalizeLanguageCode(code) {\n\t\tif (!code || typeof code !== 'string') {\n\t\t\treturn 'en';\n\t\t}\n\n\t\t// If already 2-letter code, return as-is\n\t\tif (code.length === 2) {\n\t\t\treturn code.toLowerCase();\n\t\t}\n\n\t\t// Convert 3-letter ISO 639-2/3 codes to 2-letter ISO 639-1 codes\n\t\tconst codeMap = {\n\t\t\t// Common language mappings\n\t\t\teng: 'en', // English\n\t\t\tfra: 'fr', // French\n\t\t\tfre: 'fr', // French (alternative)\n\t\t\tspa: 'es', // Spanish\n\t\t\tdeu: 'de', // German\n\t\t\tger: 'de', // German (alternative)\n\t\t\tita: 'it', // Italian\n\t\t\tpor: 'pt', // Portuguese\n\t\t\trus: 'ru', // Russian\n\t\t\tjpn: 'ja', // Japanese\n\t\t\tkor: 'ko', // Korean\n\t\t\tcmn: 'zh', // Chinese (Mandarin)\n\t\t\tzho: 'zh', // Chinese\n\t\t\tchi: 'zh', // Chinese (alternative)\n\t\t\tara: 'ar', // Arabic\n\t\t\thin: 'hi', // Hindi\n\t\t\tben: 'bn', // Bengali\n\t\t\turd: 'ur', // Urdu\n\t\t\ttur: 'tr', // Turkish\n\t\t\tpol: 'pl', // Polish\n\t\t\tnld: 'nl', // Dutch\n\t\t\tdut: 'nl', // Dutch (alternative)\n\t\t\tswe: 'sv', // Swedish\n\t\t\tnor: 'no', // Norwegian\n\t\t\tdan: 'da', // Danish\n\t\t\tfin: 'fi', // Finnish\n\t\t\thun: 'hu', // Hungarian\n\t\t\tces: 'cs', // Czech\n\t\t\tcze: 'cs', // Czech (alternative)\n\t\t\tslk: 'sk', // Slovak\n\t\t\tslo: 'sk', // Slovak (alternative)\n\t\t\tslv: 'sl', // Slovenian\n\t\t\thrv: 'hr', // Croatian\n\t\t\tsrp: 'sr', // Serbian\n\t\t\tbul: 'bg', // Bulgarian\n\t\t\tron: 'ro', // Romanian\n\t\t\trum: 'ro', // Romanian (alternative)\n\t\t\tell: 'el', // Greek\n\t\t\tgre: 'el', // Greek (alternative)\n\t\t\theb: 'he', // Hebrew\n\t\t\ttha: 'th', // Thai\n\t\t\tvie: 'vi', // Vietnamese\n\t\t\tind: 'id', // Indonesian\n\t\t\tmsa: 'ms', // Malay\n\t\t\tmay: 'ms', // Malay (alternative)\n\t\t\ttgl: 'tl', // Tagalog\n\t\t\tukr: 'uk', // Ukrainian\n\t\t\tbel: 'be', // Belarusian\n\t\t\tlit: 'lt', // Lithuanian\n\t\t\tlav: 'lv', // Latvian\n\t\t\test: 'et', // Estonian\n\t\t\tcat: 'ca', // Catalan\n\t\t\teus: 'eu', // Basque\n\t\t\tbaq: 'eu', // Basque (alternative)\n\t\t\tglg: 'gl', // Galician\n\t\t\tgle: 'ga', // Irish\n\t\t\tgla: 'gd', // Scottish Gaelic\n\t\t\tcym: 'cy', // Welsh\n\t\t\twel: 'cy', // Welsh (alternative)\n\t\t\tisl: 'is', // Icelandic\n\t\t\tice: 'is', // Icelandic (alternative)\n\t\t\tmlt: 'mt', // Maltese\n\t\t\tafr: 'af', // Afrikaans\n\t\t\tswa: 'sw', // Swahili\n\t\t\tamh: 'am', // Amharic\n\t\t\thau: 'ha', // Hausa\n\t\t\tyor: 'yo', // Yoruba\n\t\t\tibo: 'ig', // Igbo\n\t\t\tsom: 'so', // Somali\n\t\t\torm: 'om', // Oromo\n\t\t\ttig: 'ti', // Tigrinya\n\t\t\tmlg: 'mg', // Malagasy\n\t\t\tnya: 'ny', // Chichewa\n\t\t\tsna: 'sn', // Shona\n\t\t\txho: 'xh', // Xhosa\n\t\t\tzul: 'zu', // Zulu\n\t\t\tnso: 'nso', // Northern Sotho\n\t\t\tsot: 'st', // Southern Sotho\n\t\t\ttsn: 'tn', // Tswana\n\t\t\tven: 've', // Venda\n\t\t\ttso: 'ts', // Tsonga\n\t\t\tssw: 'ss', // Swati\n\t\t\tnde: 'nr', // Southern Ndebele\n\t\t\tnbl: 'nd', // Northern Ndebele\n\t\t};\n\n\t\tconst normalized = code.toLowerCase();\n\t\treturn codeMap[normalized] || 'en';\n\t}\n}\n\nexport default SpamScanner;\n"],
5
- "mappings": ";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA,MACE;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACF;AAAA;AAAA;;;ACbA;AAAA;AAAA;AAAA;AAAA,sBACA,gBACA,6BAGM,OAEA,eAMF,cAUG;AAvBP;AAAA;AAAA,uBAAuB;AACvB,qBAA2B;AAC3B,kCAA+B;AAC/B;AAEA,IAAM,YAAQ,2BAAS,aAAa;AAEpC,IAAM,gBAAgB;AAAA,MACrB,QAAQ;AAAA,MACR,YAAY;AAAA,IACb;AAGA,IAAI,eAAe,CAAC;AACpB,QAAI;AACH,qBAAe,KAAK,UAAM,6BAAa,uBAAuB,MAAM,CAAC;AAAA,IACtE,SAAS,OAAO;AACf,YAAM,KAAK;AACX,iBAAW,eAAe,2BAAmB;AAC5C,qBAAa,WAAW,IAAI,GAAG,WAAW,OAAG,4BAAAA,SAAmB,aAAa,CAAC;AAAA,MAC/E;AAAA,IACD;AAEA,IAAO,uBAAQ;AAAA;AAAA;;;ACvBf;AAAA;AAAA;AAAA;AAAA,IAAAC,mBACAC,iBACA,mBAEMC,QAEF,YAQG;AAdP;AAAA;AAAA,IAAAF,oBAAuB;AACvB,IAAAC,kBAA2B;AAC3B,wBAAuB;AAEvB,IAAMC,aAAQ,4BAAS,aAAa;AAEpC,IAAI,aAAa,IAAI,kBAAAC,QAAW,EAAE,aAAa;AAE/C,QAAI;AACH,mBAAa,KAAK,UAAM,8BAAa,qBAAqB,MAAM,CAAC;AAAA,IAClE,SAAS,OAAO;AACf,MAAAD,OAAM,KAAK;AAAA,IACZ;AAEA,IAAO,yBAAQ;AAAA;AAAA;;;ACdf;AAAA;AAAA;AAAA;AAAA,IAMA,oBACA,oBAGM,kBAsEA,wBAWA,gBA6BA,qBAgZC;AAxgBP;AAAA;AAMA,yBAAyB;AACzB,yBAAwB;AAGxB,IAAM,mBAAmB,oBAAI,IAAI;AAAA;AAAA,MAEhC,CAAC,UAAK,GAAG;AAAA,MACT,CAAC,UAAK,GAAG;AAAA,MACT,CAAC,UAAK,GAAG;AAAA,MACT,CAAC,UAAK,GAAG;AAAA,MACT,CAAC,UAAK,GAAG;AAAA,MACT,CAAC,UAAK,GAAG;AAAA,MACT,CAAC,UAAK,GAAG;AAAA,MACT,CAAC,UAAK,GAAG;AAAA,MACT,CAAC,UAAK,GAAG;AAAA,MACT,CAAC,UAAK,GAAG;AAAA,MACT,CAAC,UAAK,GAAG;AAAA,MACT,CAAC,UAAK,GAAG;AAAA,MACT,CAAC,UAAK,GAAG;AAAA,MACT,CAAC,UAAK,GAAG;AAAA,MACT,CAAC,UAAK,GAAG;AAAA,MACT,CAAC,UAAK,GAAG;AAAA,MACT,CAAC,UAAK,GAAG;AAAA,MACT,CAAC,UAAK,GAAG;AAAA,MACT,CAAC,UAAK,GAAG;AAAA;AAAA,MAGT,CAAC,UAAK,GAAG;AAAA,MACT,CAAC,UAAK,GAAG;AAAA,MACT,CAAC,UAAK,GAAG;AAAA,MACT,CAAC,UAAK,GAAG;AAAA,MACT,CAAC,UAAK,GAAG;AAAA,MACT,CAAC,UAAK,GAAG;AAAA,MACT,CAAC,UAAK,GAAG;AAAA,MACT,CAAC,UAAK,GAAG;AAAA,MACT,CAAC,UAAK,GAAG;AAAA,MACT,CAAC,UAAK,GAAG;AAAA,MACT,CAAC,UAAK,GAAG;AAAA,MACT,CAAC,UAAK,GAAG;AAAA,MACT,CAAC,UAAK,GAAG;AAAA,MACT,CAAC,UAAK,GAAG;AAAA,MACT,CAAC,UAAK,GAAG;AAAA,MACT,CAAC,UAAK,GAAG;AAAA,MACT,CAAC,UAAK,GAAG;AAAA,MACT,CAAC,UAAK,GAAG;AAAA,MACT,CAAC,UAAK,GAAG;AAAA;AAAA,MAGT,CAAC,aAAM,GAAG;AAAA,MACV,CAAC,aAAM,GAAG;AAAA,MACV,CAAC,aAAM,GAAG;AAAA,MACV,CAAC,aAAM,GAAG;AAAA,MACV,CAAC,aAAM,GAAG;AAAA,MACV,CAAC,aAAM,GAAG;AAAA,MACV,CAAC,aAAM,GAAG;AAAA,MACV,CAAC,aAAM,GAAG;AAAA,MACV,CAAC,aAAM,GAAG;AAAA,MACV,CAAC,aAAM,GAAG;AAAA;AAAA,MAGV,CAAC,UAAK,GAAG;AAAA,MACT,CAAC,UAAK,GAAG;AAAA,MACT,CAAC,UAAK,GAAG;AAAA,M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",
6
- "names": ["cryptoRandomString", "import_node_util", "import_node_fs", "debug", "NaiveBayes", "confusables", "import_node_fs", "import_node_crypto", "import_node_util", "import_naivebayes", "path", "fs", "replacements", "classifier", "debug", "AFHConvert", "natural", "sw", "creditCardRegex", "phoneRegex", "emailRegexSafe", "ipRegex", "urlRegexSafe", "bitcoinRegex", "macRegex", "hexaColorRegex", "floatingPointRegex", "autoBind", "NaiveBayes", "ClamScan", "isBuffer", "fileExtension", "normalizeUrl", "superagent", "isSANB", "parseTldts", "striptags", "lande", "expandContractions", "snowball", "escapeStringRegexp", "arrayJoinConjunction", "process", "EnhancedIDNDetector", "detected"]
4
+ "sourcesContent": ["[\n \"url\",\n \"email\",\n \"number\",\n \"currency\",\n \"initialism\",\n \"abbreviation\",\n \"emoji\",\n \"hexa\",\n \"mac\",\n \"phone\",\n \"bitcoin\",\n \"cc\"\n]\n", "import {debuglog} from 'node:util';\nimport {readFileSync} from 'node:fs';\nimport cryptoRandomString from 'crypto-random-string';\nimport REPLACEMENT_WORDS from './replacement-words.json' with { type: 'json' };\n\nconst debug = debuglog('spamscanner');\n\nconst randomOptions = {\n\tlength: 10,\n\tcharacters: 'abcdefghijklmnopqrstuvwxyz',\n};\n\n// Simply delete the replacements.json to generate new replacements\nlet replacements = {};\ntry {\n\treplacements = JSON.parse(readFileSync('./replacements.json', 'utf8'));\n} catch (error) {\n\tdebug(error);\n\tfor (const replacement of REPLACEMENT_WORDS) {\n\t\treplacements[replacement] = `${replacement}${cryptoRandomString(randomOptions)}`;\n\t}\n}\n\nexport default replacements;\n", "import {debuglog} from 'node:util';\nimport {readFileSync} from 'node:fs';\nimport NaiveBayes from '@ladjs/naivebayes';\n\nconst debug = debuglog('spamscanner');\n\nlet classifier = new NaiveBayes().toJsonObject();\n\ntry {\n\tclassifier = JSON.parse(readFileSync('./classifier.json', 'utf8'));\n} catch (error) {\n\tdebug(error);\n}\n\nexport default classifier;\n", "#!/usr/bin/env node\n/**\n * Enhanced IDN Homograph Attack Detection\n * Based on comprehensive research and best practices\n */\n\nimport {createHash} from 'node:crypto';\nimport confusables from 'confusables';\n\n// Unicode confusable character mappings (subset for demonstration)\nconst CONFUSABLE_CHARS = new Map([\n\t// Cyrillic to Latin confusables\n\t['\u0430', 'a'],\n\t['\u0435', 'e'],\n\t['\u043E', 'o'],\n\t['\u0440', 'p'],\n\t['\u0441', 'c'],\n\t['\u0445', 'x'],\n\t['\u0443', 'y'],\n\t['\u0410', 'A'],\n\t['\u0412', 'B'],\n\t['\u0415', 'E'],\n\t['\u041A', 'K'],\n\t['\u041C', 'M'],\n\t['\u041D', 'H'],\n\t['\u041E', 'O'],\n\t['\u0420', 'P'],\n\t['\u0421', 'C'],\n\t['\u0422', 'T'],\n\t['\u0425', 'X'],\n\t['\u0423', 'Y'],\n\n\t// Greek to Latin confusables\n\t['\u03B1', 'a'],\n\t['\u03BF', 'o'],\n\t['\u03C1', 'p'],\n\t['\u03C5', 'u'],\n\t['\u03BD', 'v'],\n\t['\u03B9', 'i'],\n\t['\u0391', 'A'],\n\t['\u0392', 'B'],\n\t['\u0395', 'E'],\n\t['\u0396', 'Z'],\n\t['\u0397', 'H'],\n\t['\u0399', 'I'],\n\t['\u039A', 'K'],\n\t['\u039C', 'M'],\n\t['\u039D', 'N'],\n\t['\u039F', 'O'],\n\t['\u03A1', 'P'],\n\t['\u03A4', 'T'],\n\t['\u03A5', 'Y'],\n\n\t// Mathematical symbols\n\t['\uD835\uDC1A', 'a'],\n\t['\uD835\uDC1B', 'b'],\n\t['\uD835\uDC1C', 'c'],\n\t['\uD835\uDC1D', 'd'],\n\t['\uD835\uDC1E', 'e'],\n\t['\uD835\uDFCE', '0'],\n\t['\uD835\uDFCF', '1'],\n\t['\uD835\uDFD0', '2'],\n\t['\uD835\uDFD1', '3'],\n\t['\uD835\uDFD2', '4'],\n\n\t// Other common confusables\n\t['\u212F', 'e'],\n\t['\u210A', 'g'],\n\t['\u210E', 'h'],\n\t['\u2113', 'l'],\n\t['\u2134', 'o'],\n\t['\u212F', 'e'],\n\t['\u2170', 'i'],\n\t['\u2171', 'ii'],\n\t['\u2172', 'iii'],\n\t['\u2173', 'iv'],\n\t['\u2174', 'v'],\n]);\n\n// Known legitimate international domains (whitelist approach)\nconst LEGITIMATE_IDN_DOMAINS = new Set([\n\t'xn--fsq.xn--0zwm56d', // \u4E2D\u56FD\n\t'xn--fiqs8s', // \u4E2D\u56FD\n\t'xn--fiqz9s', // \u4E2D\u56EF\n\t'xn--j6w193g', // \u9999\u6E2F\n\t'xn--55qx5d', // \u516C\u53F8\n\t'xn--io0a7i', // \u7F51\u7EDC\n\t// Add more legitimate domains as needed\n]);\n\n// Popular brand domains for comparison\nconst POPULAR_BRANDS = [\n\t'google',\n\t'facebook',\n\t'amazon',\n\t'apple',\n\t'microsoft',\n\t'twitter',\n\t'instagram',\n\t'linkedin',\n\t'youtube',\n\t'netflix',\n\t'paypal',\n\t'ebay',\n\t'yahoo',\n\t'adobe',\n\t'salesforce',\n\t'oracle',\n\t'ibm',\n\t'cisco',\n\t'intel',\n\t'nvidia',\n\t'tesla',\n\t'citibank',\n\t'bankofamerica',\n\t'wellsfargo',\n\t'chase',\n\t'americanexpress',\n];\n\nclass EnhancedIDNDetector {\n\tconstructor(options = {}) {\n\t\tthis.options = {\n\t\t\tstrictMode: false,\n\t\t\tenableWhitelist: true,\n\t\t\tenableBrandProtection: true,\n\t\t\tenableContextAnalysis: true,\n\t\t\tmaxSimilarityThreshold: 0.8,\n\t\t\tminDomainAge: 30, // Days\n\t\t\t...options,\n\t\t};\n\n\t\tthis.cache = new Map();\n\t}\n\n\t/**\n\t * Main detection method with comprehensive analysis\n\t */\n\tdetectHomographAttack(domain, context = {}) {\n\t\tconst cacheKey = this.getCacheKey(domain, context);\n\t\tif (this.cache.has(cacheKey)) {\n\t\t\treturn this.cache.get(cacheKey);\n\t\t}\n\n\t\tconst result = this.analyzeComprehensive(domain, context);\n\t\tthis.cache.set(cacheKey, result);\n\t\treturn result;\n\t}\n\n\t/**\n\t * Comprehensive analysis combining multiple detection methods\n\t */\n\tanalyzeComprehensive(domain, context) {\n\t\tconst analysis = {\n\t\t\tdomain,\n\t\t\tisIDN: this.isIDNDomain(domain),\n\t\t\triskScore: 0,\n\t\t\triskFactors: [],\n\t\t\trecommendations: [],\n\t\t\tconfidence: 0,\n\t\t};\n\n\t\t// Skip analysis for whitelisted domains\n\t\tif (this.options.enableWhitelist && this.isWhitelisted(domain)) {\n\t\t\tanalysis.riskScore = 0;\n\t\t\tanalysis.confidence = 1;\n\t\t\tanalysis.recommendations.push('Domain is whitelisted as legitimate');\n\t\t\treturn analysis;\n\t\t}\n\n\t\t// Basic IDN detection\n\t\tif (analysis.isIDN) {\n\t\t\tanalysis.riskScore += 0.3;\n\t\t\tanalysis.riskFactors.push('Contains non-ASCII characters');\n\t\t}\n\n\t\t// Confusable character analysis\n\t\tconst confusableAnalysis = this.analyzeConfusableCharacters(domain);\n\t\tanalysis.riskScore += confusableAnalysis.score;\n\t\tanalysis.riskFactors.push(...confusableAnalysis.factors);\n\n\t\t// Brand similarity analysis\n\t\tif (this.options.enableBrandProtection) {\n\t\t\tconst brandAnalysis = this.analyzeBrandSimilarity(domain);\n\t\t\tanalysis.riskScore += brandAnalysis.score;\n\t\t\tanalysis.riskFactors.push(...brandAnalysis.factors);\n\t\t}\n\n\t\t// Script mixing analysis\n\t\tconst scriptAnalysis = this.analyzeScriptMixing(domain);\n\t\tanalysis.riskScore += scriptAnalysis.score;\n\t\tanalysis.riskFactors.push(...scriptAnalysis.factors);\n\n\t\t// Context analysis\n\t\tif (this.options.enableContextAnalysis && context) {\n\t\t\tconst contextAnalysis = this.analyzeContext(domain, context);\n\t\t\tanalysis.riskScore += contextAnalysis.score;\n\t\t\tanalysis.riskFactors.push(...contextAnalysis.factors);\n\t\t}\n\n\t\t// Punycode analysis\n\t\tif (domain.includes('xn--')) {\n\t\t\tconst punycodeAnalysis = this.analyzePunycode(domain);\n\t\t\tanalysis.riskScore += punycodeAnalysis.score;\n\t\t\tanalysis.riskFactors.push(...punycodeAnalysis.factors);\n\t\t}\n\n\t\t// Calculate final confidence and recommendations\n\t\tanalysis.confidence = Math.min(analysis.riskScore, 1);\n\t\tanalysis.recommendations = this.generateRecommendations(analysis);\n\n\t\treturn analysis;\n\t}\n\n\t/**\n\t * Detect if domain contains IDN characters\n\t */\n\tisIDNDomain(domain) {\n\t\t// eslint-disable-next-line no-control-regex\n\t\treturn domain.includes('xn--') || /[^\\u0000-\\u007F]/.test(domain);\n\t}\n\n\t/**\n\t * Check if domain is in whitelist\n\t */\n\tisWhitelisted(domain) {\n\t\tconst normalized = domain.toLowerCase();\n\t\treturn LEGITIMATE_IDN_DOMAINS.has(normalized);\n\t}\n\n\t/**\n\t * Analyze confusable characters\n\t */\n\tanalyzeConfusableCharacters(domain) {\n\t\tconst analysis = {score: 0, factors: []};\n\t\tlet confusableCount = 0;\n\t\tlet totalChars = 0;\n\n\t\t// Use confusables library to detect and normalize\n\t\ttry {\n\t\t\tconst normalized = confusables(domain);\n\t\t\tif (normalized !== domain) {\n\t\t\t\t// Domain contains confusable characters\n\t\t\t\tfor (const char of domain) {\n\t\t\t\t\ttotalChars++;\n\t\t\t\t\tconst normalizedChar = confusables(char);\n\t\t\t\t\tif (normalizedChar !== char) {\n\t\t\t\t\t\tconfusableCount++;\n\t\t\t\t\t\tanalysis.factors.push(`Confusable character: ${char} \u2192 ${normalizedChar}`);\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tif (confusableCount > 0) {\n\t\t\t\t\tconst ratio = confusableCount / totalChars;\n\t\t\t\t\tanalysis.score = Math.min(ratio * 0.8, 0.6);\n\t\t\t\t\tanalysis.factors.push(`${confusableCount}/${totalChars} characters are confusable`, `Normalized domain: ${normalized}`);\n\t\t\t\t}\n\t\t\t}\n\t\t} catch {\n\t\t\t// Fallback to manual detection\n\t\t\tfor (const char of domain) {\n\t\t\t\ttotalChars++;\n\t\t\t\tif (CONFUSABLE_CHARS.has(char)) {\n\t\t\t\t\tconfusableCount++;\n\t\t\t\t\tanalysis.factors.push(`Confusable character: ${char} \u2192 ${CONFUSABLE_CHARS.get(char)}`);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (confusableCount > 0) {\n\t\t\t\tconst ratio = confusableCount / totalChars;\n\t\t\t\tanalysis.score = Math.min(ratio * 0.8, 0.6);\n\t\t\t\tanalysis.factors.push(`${confusableCount}/${totalChars} characters are confusable`);\n\t\t\t}\n\t\t}\n\n\t\treturn analysis;\n\t}\n\n\t/**\n\t * Analyze similarity to popular brands\n\t */\n\tanalyzeBrandSimilarity(domain) {\n\t\tconst analysis = {score: 0, factors: []};\n\t\tconst cleanDomain = this.normalizeDomain(domain);\n\n\t\tfor (const brand of POPULAR_BRANDS) {\n\t\t\tconst similarity = this.calculateSimilarity(cleanDomain, brand);\n\t\t\tif (similarity > this.options.maxSimilarityThreshold) {\n\t\t\t\tanalysis.score = Math.max(analysis.score, similarity * 0.7);\n\t\t\t\tanalysis.factors.push(`High similarity to ${brand}: ${(similarity * 100).toFixed(1)}%`);\n\t\t\t}\n\t\t}\n\n\t\treturn analysis;\n\t}\n\n\t/**\n\t * Analyze script mixing patterns\n\t */\n\tanalyzeScriptMixing(domain) {\n\t\tconst analysis = {score: 0, factors: []};\n\t\tconst scripts = this.detectScripts(domain);\n\n\t\tif (scripts.size > 1) {\n\t\t\t// Mixed scripts can be suspicious\n\t\t\tconst scriptList = [...scripts].join(', ');\n\t\t\tanalysis.factors.push(`Mixed scripts detected: ${scriptList}`);\n\n\t\t\t// Higher risk for certain combinations\n\t\t\tif (scripts.has('Latin') && (scripts.has('Cyrillic') || scripts.has('Greek'))) {\n\t\t\t\tanalysis.score += 0.4;\n\t\t\t\tanalysis.factors.push('Suspicious Latin/Cyrillic or Latin/Greek mixing');\n\t\t\t} else {\n\t\t\t\tanalysis.score += 0.2;\n\t\t\t}\n\t\t}\n\n\t\treturn analysis;\n\t}\n\n\t/**\n\t * Analyze context (email headers, content, etc.)\n\t */\n\tanalyzeContext(domain, context) {\n\t\tconst analysis = {score: 0, factors: []};\n\n\t\t// Check if display text differs from actual domain\n\t\tif (context.displayText && context.displayText !== domain) {\n\t\t\tanalysis.score += 0.3;\n\t\t\tanalysis.factors.push('Display text differs from actual domain');\n\t\t}\n\n\t\t// Check sender reputation\n\t\tif (context.senderReputation && context.senderReputation < 0.5) {\n\t\t\tanalysis.score += 0.2;\n\t\t\tanalysis.factors.push('Low sender reputation');\n\t\t}\n\n\t\t// Check for suspicious email patterns\n\t\tif (context.emailContent) {\n\t\t\tconst suspiciousPatterns = [\n\t\t\t\t/urgent/i,\n\t\t\t\t/verify.*account/i,\n\t\t\t\t/suspended/i,\n\t\t\t\t/click.*here/i,\n\t\t\t\t/limited.*time/i,\n\t\t\t\t/act.*now/i,\n\t\t\t\t/confirm.*identity/i,\n\t\t\t];\n\n\t\t\tfor (const pattern of suspiciousPatterns) {\n\t\t\t\tif (pattern.test(context.emailContent)) {\n\t\t\t\t\tanalysis.score += 0.1;\n\t\t\t\t\tanalysis.factors.push(`Suspicious email pattern: ${pattern.source}`);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn analysis;\n\t}\n\n\t/**\n\t * Analyze punycode domains\n\t */\n\tanalyzePunycode(domain) {\n\t\tconst analysis = {score: 0, factors: []};\n\n\t\ttry {\n\t\t\t// Decode punycode to see actual characters\n\t\t\tconst decoded = this.decodePunycode(domain);\n\t\t\tanalysis.factors.push(`Punycode decoded: ${decoded}`);\n\n\t\t\t// Check if decoded version looks suspicious\n\t\t\tconst decodedAnalysis = this.analyzeConfusableCharacters(decoded);\n\t\t\tanalysis.score += decodedAnalysis.score * 0.8;\n\t\t\tanalysis.factors.push(...decodedAnalysis.factors);\n\t\t} catch {\n\t\t\tanalysis.score += 0.2;\n\t\t\tanalysis.factors.push('Invalid punycode encoding');\n\t\t}\n\n\t\treturn analysis;\n\t}\n\n\t/**\n\t * Normalize domain for comparison\n\t */\n\tnormalizeDomain(domain) {\n\t\tlet normalized = domain.toLowerCase();\n\n\t\t// Use confusables library to remove confusable characters\n\t\ttry {\n\t\t\tnormalized = confusables(normalized);\n\t\t} catch {\n\t\t\t// Fallback to manual replacement if confusables fails\n\t\t\tfor (const [confusable, latin] of CONFUSABLE_CHARS) {\n\t\t\t\tnormalized = normalized.replaceAll(confusable, latin);\n\t\t\t}\n\t\t}\n\n\t\t// Remove common TLD for comparison\n\t\tnormalized = normalized.replace(/\\.(com|org|net|edu|gov)$/, '');\n\n\t\treturn normalized;\n\t}\n\n\t/**\n\t * Calculate string similarity using Levenshtein distance\n\t */\n\tcalculateSimilarity(string1, string2) {\n\t\tconst matrix = [];\n\t\tconst length1 = string1.length;\n\t\tconst length2 = string2.length;\n\n\t\tfor (let i = 0; i <= length2; i++) {\n\t\t\tmatrix[i] = [i];\n\t\t}\n\n\t\tfor (let j = 0; j <= length1; j++) {\n\t\t\tmatrix[0][j] = j;\n\t\t}\n\n\t\tfor (let i = 1; i <= length2; i++) {\n\t\t\tfor (let j = 1; j <= length1; j++) {\n\t\t\t\tif (string2.charAt(i - 1) === string1.charAt(j - 1)) {\n\t\t\t\t\tmatrix[i][j] = matrix[i - 1][j - 1];\n\t\t\t\t} else {\n\t\t\t\t\tmatrix[i][j] = Math.min(\n\t\t\t\t\t\tmatrix[i - 1][j - 1] + 1,\n\t\t\t\t\t\tmatrix[i][j - 1] + 1,\n\t\t\t\t\t\tmatrix[i - 1][j] + 1,\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tconst maxLength = Math.max(length1, length2);\n\t\treturn maxLength === 0 ? 1 : (maxLength - matrix[length2][length1]) / maxLength;\n\t}\n\n\t/**\n\t * Detect scripts used in domain\n\t */\n\tdetectScripts(domain) {\n\t\tconst scripts = new Set();\n\n\t\tfor (const char of domain) {\n\t\t\tconst code = char.codePointAt(0);\n\n\t\t\tif ((code >= 0x00_41 && code <= 0x00_5A) || (code >= 0x00_61 && code <= 0x00_7A)) {\n\t\t\t\tscripts.add('Latin');\n\t\t\t} else if (code >= 0x04_00 && code <= 0x04_FF) {\n\t\t\t\tscripts.add('Cyrillic');\n\t\t\t} else if (code >= 0x03_70 && code <= 0x03_FF) {\n\t\t\t\tscripts.add('Greek');\n\t\t\t} else if (code >= 0x4E_00 && code <= 0x9F_FF) {\n\t\t\t\tscripts.add('CJK');\n\t\t\t} else if (code >= 0x05_90 && code <= 0x05_FF) {\n\t\t\t\tscripts.add('Hebrew');\n\t\t\t} else if (code >= 0x06_00 && code <= 0x06_FF) {\n\t\t\t\tscripts.add('Arabic');\n\t\t\t}\n\t\t}\n\n\t\treturn scripts;\n\t}\n\n\t/**\n\t * Simple punycode decoder (basic implementation)\n\t */\n\tdecodePunycode(domain) {\n\t\t// This is a simplified implementation\n\t\t// In production, use a proper punycode library\n\t\ttry {\n\t\t\tconst url = new URL(`http://${domain}`);\n\t\t\treturn url.hostname;\n\t\t} catch {\n\t\t\treturn domain;\n\t\t}\n\t}\n\n\t/**\n\t * Generate recommendations based on analysis\n\t */\n\tgenerateRecommendations(analysis) {\n\t\tconst recommendations = [];\n\n\t\tif (analysis.riskScore > 0.8) {\n\t\t\trecommendations.push('HIGH RISK: Likely homograph attack - block or quarantine');\n\t\t} else if (analysis.riskScore > 0.6) {\n\t\t\trecommendations.push('MEDIUM RISK: Suspicious domain - flag for review');\n\t\t} else if (analysis.riskScore > 0.3) {\n\t\t\trecommendations.push('LOW RISK: Monitor domain activity');\n\t\t} else {\n\t\t\trecommendations.push('SAFE: Domain appears legitimate');\n\t\t}\n\n\t\tif (analysis.isIDN) {\n\t\t\trecommendations.push('Consider displaying punycode representation to users');\n\t\t}\n\n\t\tif (analysis.riskFactors.some(f => f.includes('brand'))) {\n\t\t\trecommendations.push('Verify domain authenticity through official channels');\n\t\t}\n\n\t\treturn recommendations;\n\t}\n\n\t/**\n\t * Generate cache key\n\t */\n\tgetCacheKey(domain, context) {\n\t\tconst contextHash = createHash('md5')\n\t\t\t.update(JSON.stringify(context))\n\t\t\t.digest('hex')\n\t\t\t.slice(0, 8);\n\t\treturn `${domain}:${contextHash}`;\n\t}\n}\n\nexport default EnhancedIDNDetector;\n\n", "import fs from 'node:fs';\nimport path from 'node:path';\nimport process from 'node:process';\nimport {createHash} from 'node:crypto';\nimport {debuglog} from 'node:util';\nimport {fileURLToPath} from 'node:url';\nimport autoBind from 'auto-bind';\nimport AFHConvert from 'ascii-fullwidth-halfwidth-convert';\nimport ClamScan from 'clamscan';\nimport NaiveBayes from '@ladjs/naivebayes';\nimport arrayJoinConjunction from 'array-join-conjunction';\nimport bitcoinRegex from 'bitcoin-regex';\nimport creditCardRegex from 'credit-card-regex';\nimport emailRegexSafe from 'email-regex-safe';\nimport escapeStringRegexp from 'escape-string-regexp';\nimport expandContractions from '@stdlib/nlp-expand-contractions';\nimport fileExtension from 'file-extension';\nimport floatingPointRegex from 'floating-point-regex';\nimport lande from 'lande'; // Replaced franc with lande as per TODO\nimport hexaColorRegex from 'hexa-color-regex';\nimport {parse as parseTldts} from 'tldts';\nimport ipRegex from 'ip-regex';\nimport isBuffer from 'is-buffer';\nimport isSANB from 'is-string-and-not-blank';\nimport macRegex from 'mac-regex';\nimport natural from 'natural';\nimport normalizeUrl from 'normalize-url';\nimport phoneRegex from 'phone-regex';\nimport snowball from 'node-snowball';\nimport striptags from 'striptags';\nimport superagent from 'superagent';\nimport sw from 'stopword';\nimport urlRegexSafe from 'url-regex-safe';\nimport {simpleParser} from 'mailparser';\nimport {fileTypeFromBuffer} from 'file-type';\n\n// ES module compatibility - handle both ESM and CJS builds\n// In ESM, import.meta.url is defined; in CJS (via esbuild), it's undefined\nconst __filename = import.meta.url ? fileURLToPath(import.meta.url) : '';\nconst __dirname = __filename ? path.dirname(__filename) : process.cwd();\n\n// Find package root - works from both src/ and dist/esm/ or dist/cjs/\nconst findPackageRoot = startDir => {\n\tlet dir = startDir;\n\twhile (dir !== path.dirname(dir)) {\n\t\tif (fs.existsSync(path.join(dir, 'package.json'))) {\n\t\t\treturn dir;\n\t\t}\n\n\t\tdir = path.dirname(dir);\n\t}\n\n\treturn startDir;\n};\n\nconst packageRoot = findPackageRoot(__dirname);\n\n// Load JSON data\nconst executablesData = JSON.parse(fs.readFileSync(path.join(packageRoot, 'executables.json'), 'utf8'));\n\nconst EXECUTABLES = new Set(executablesData);\n\n// Dynamic imports for modules that need to be loaded conditionally\nconst getReplacements = async () => {\n\tconst {default: replacements} = await import('../replacements.js');\n\treturn replacements;\n};\n\nconst getClassifier = async () => {\n\tconst {default: classifier} = await import('../get-classifier.js');\n\treturn classifier;\n};\n\nconst debug = debuglog('spamscanner');\n\n// All tokenizers combined - improved regex pattern\nconst GENERIC_TOKENIZER\n = /[^a-z\u00E1-\u00FA\u00C1-\u00DA\u00E0-\u00FA\u00C0-\u00DA\u00F1\u00FC\\d\u0430-\u044F\u0451\u00E6\u00F8\u00E5\u00E0\u00E1\u1EA3\u00E3\u1EA1\u0103\u1EAF\u1EB1\u1EB3\u1EB5\u1EB7\u00E2\u1EA5\u1EA7\u1EA9\u1EAB\u1EAD\u00E9\u00E8\u1EBB\u1EBD\u1EB9\u00EA\u1EBF\u1EC1\u1EC3\u1EC5\u1EC7\u00ED\u00EC\u1EC9\u0129\u1ECB\u00F3\u00F2\u1ECF\u00F5\u1ECD\u00F4\u1ED1\u1ED3\u1ED5\u1ED7\u1ED9\u01A1\u1EDB\u1EDD\u1EDF\u1EE1\u1EE3\u00FA\u00F9\u1EE7\u0169\u1EE5\u01B0\u1EE9\u1EEB\u1EED\u1EEF\u1EF1\u00FD\u1EF3\u1EF7\u1EF9\u1EF5\u0111\u00E4\u00F6\u00EB\u00EF\u00EE\u00FB\u0153\u00E7\u0105\u017C\u015B\u017A\u0119\u0107\u0144\u0142-]+/i;\n\nconst converter = new AFHConvert();\n\n// Chinese tokenizer setup with proper path resolution\nconst chineseTokenizer = {tokenize: text => text.split(/\\s+/)};\n\n// Enhanced stopwords with fallback for missing language-specific stopwords\nconst stopwordsMap = new Map([\n\t['ar', new Set([...(natural.stopwords || []), ...(sw.ar || [])])],\n\t['bg', new Set([...(natural.stopwords || []), ...(sw.bg || [])])],\n\t['bn', new Set([...(natural.stopwords || []), ...(sw.bn || [])])],\n\t['ca', new Set([...(natural.stopwords || []), ...(sw.ca || [])])],\n\t['cs', new Set([...(natural.stopwords || []), ...(sw.cs || [])])],\n\t['da', new Set([...(natural.stopwords || []), ...(sw.da || [])])],\n\t['de', new Set([...(natural.stopwords || []), ...(sw.de || [])])],\n\t['el', new Set([...(natural.stopwords || []), ...(sw.el || [])])],\n\t['en', new Set([...(natural.stopwords || []), ...(sw.en || [])])],\n\t['es', new Set([...(natural.stopwords || []), ...(sw.es || [])])],\n\t['fa', new Set([...(natural.stopwords || []), ...(sw.fa || [])])],\n\t['fi', new Set([...(natural.stopwords || []), ...(sw.fi || [])])],\n\t['fr', new Set([...(natural.stopwords || []), ...(sw.fr || [])])],\n\t['ga', new Set([...(natural.stopwords || []), ...(sw.ga || [])])],\n\t['gl', new Set([...(natural.stopwords || []), ...(sw.gl || [])])],\n\t['gu', new Set([...(natural.stopwords || []), ...(sw.gu || [])])],\n\t['he', new Set([...(natural.stopwords || []), ...(sw.he || [])])],\n\t['hi', new Set([...(natural.stopwords || []), ...(sw.hi || [])])],\n\t['hr', new Set([...(natural.stopwords || []), ...(sw.hr || [])])],\n\t['hu', new Set([...(natural.stopwords || []), ...(sw.hu || [])])],\n\t['hy', new Set([...(natural.stopwords || []), ...(sw.hy || [])])],\n\t['it', new Set([...(natural.stopwords || []), ...(sw.it || [])])],\n\t['ja', new Set([...(natural.stopwords || []), ...(sw.ja || [])])],\n\t['ko', new Set([...(natural.stopwords || []), ...(sw.ko || [])])],\n\t['la', new Set([...(natural.stopwords || []), ...(sw.la || [])])],\n\t['lt', new Set([...(natural.stopwords || []), ...(sw.lt || [])])],\n\t['lv', new Set([...(natural.stopwords || []), ...(sw.lv || [])])],\n\t['mr', new Set([...(natural.stopwords || []), ...(sw.mr || [])])],\n\t['nl', new Set([...(natural.stopwords || []), ...(sw.nl || [])])],\n\t['no', new Set([...(natural.stopwords || []), ...(sw.nob || [])])],\n\t['pl', new Set([...(natural.stopwords || []), ...(sw.pl || [])])],\n\t['pt', new Set([...(natural.stopwords || []), ...(sw.pt || [])])],\n\t['ro', new Set([...(natural.stopwords || []), ...(sw.ro || [])])],\n\t['ru', new Set([...(natural.stopwords || []), ...(sw.ru || [])])],\n\t['sk', new Set([...(natural.stopwords || []), ...(sw.sk || [])])],\n\t['sl', new Set([...(natural.stopwords || []), ...(sw.sl || [])])],\n\t['sv', new Set([...(natural.stopwords || []), ...(sw.sv || [])])],\n\t['th', new Set([...(natural.stopwords || []), ...(sw.th || [])])],\n\t['tr', new Set([...(natural.stopwords || []), ...(sw.tr || [])])],\n\t['uk', new Set([...(natural.stopwords || []), ...(sw.uk || [])])],\n\t['vi', new Set([...(natural.stopwords || []), ...(sw.vi || [])])],\n\t['zh', new Set([...(natural.stopwords || []), ...(sw.zh || [])])],\n]);\n\n// URL ending reserved characters\nconst URL_ENDING_RESERVED_CHARS = /[).,;!?]+$/;\n\n// Date pattern detection (DONE)\nconst DATE_PATTERNS = [\n\t/\\b(?:\\d{1,2}[/-]){2}\\d{2,4}\\b/g, // MM/DD/YYYY or DD/MM/YYYY\n\t/\\b\\d{4}(?:[/-]\\d{1,2}){2}\\b/g, // YYYY/MM/DD\n\t/\\b\\d{1,2}\\s+(jan|feb|mar|apr|may|jun|jul|aug|sep|oct|nov|dec)\\s+\\d{2,4}\\b/gi, // DD MMM YYYY\n\t/\\b(jan|feb|mar|apr|may|jun|jul|aug|sep|oct|nov|dec)\\s+\\d{1,2},?\\s+\\d{2,4}\\b/gi, // MMM DD, YYYY\n];\n\n// File path detection (DONE)\nconst FILE_PATH_PATTERNS = [\n\t/[a-z]:\\\\\\\\[^\\\\s<>:\"|?*]+/gi, // Windows paths\n\t/\\/[^\\\\s<>:\"|?*]+/g, // Unix paths\n\t/~\\/[^\\\\s<>:\"|?*]+/g, // Home directory paths\n];\n\n// Additional regex patterns\nconst CREDIT_CARD_PATTERN = creditCardRegex({exact: false});\nconst PHONE_PATTERN = phoneRegex({exact: false});\nconst EMAIL_PATTERN = emailRegexSafe({exact: false});\nconst IP_PATTERN = ipRegex({exact: false});\nconst URL_PATTERN = urlRegexSafe({exact: false});\nconst BITCOIN_PATTERN = bitcoinRegex({exact: false});\nconst MAC_PATTERN = macRegex({exact: false});\nconst HEX_COLOR_PATTERN = hexaColorRegex({exact: false});\nconst FLOATING_POINT_PATTERN = floatingPointRegex;\n\nclass SpamScanner {\n\tconstructor(options = {}) {\n\t\tthis.config = {\n\t\t\t// Enhanced configuration options\n\t\t\tenableMacroDetection: true,\n\t\t\tenablePerformanceMetrics: false,\n\t\t\ttimeout: 30_000,\n\t\t\tsupportedLanguages: ['en'],\n\t\t\tenableMixedLanguageDetection: false,\n\t\t\tenableAdvancedPatternRecognition: true,\n\n\t\t\t// Existing options\n\t\t\tdebug: false,\n\t\t\tlogger: console,\n\t\t\tclamscan: {\n\t\t\t\tremoveInfected: false,\n\t\t\t\tquarantineInfected: false,\n\t\t\t\tscanLog: null,\n\t\t\t\tdebugMode: false,\n\t\t\t\tfileList: null,\n\t\t\t\tscanRecursively: true,\n\t\t\t\tclamscanPath: '/usr/bin/clamscan',\n\t\t\t\tclamdscanPath: '/usr/bin/clamdscan',\n\t\t\t\tpreference: 'clamdscan',\n\t\t\t},\n\t\t\tclassifier: null,\n\t\t\treplacements: null,\n\t\t\t...options,\n\t\t};\n\n\t\t// Async loading of replacements and classifier\n\t\tthis.classifier = null;\n\t\tthis.clamscan = null;\n\t\tthis.isInitialized = false;\n\n\t\t// Initialize replacements as empty Map\n\t\tthis.replacements = new Map();\n\n\t\t// Performance metrics\n\t\tthis.metrics = {\n\t\t\ttotalScans: 0,\n\t\t\taverageTime: 0,\n\t\t\tlastScanTime: 0,\n\t\t};\n\n\t\t// Bind methods\n\t\tautoBind(this);\n\t}\n\n\tasync initializeClassifier() {\n\t\tif (this.classifier) {\n\t\t\treturn;\n\t\t}\n\n\t\ttry {\n\t\t\tif (this.config.classifier) {\n\t\t\t\tthis.classifier = new NaiveBayes(this.config.classifier);\n\t\t\t} else {\n\t\t\t\tconst classifierData = await getClassifier();\n\t\t\t\tthis.classifier = new NaiveBayes(classifierData);\n\t\t\t}\n\n\t\t\t// Custom tokenizer - we handle tokenization ourselves\n\t\t\tthis.classifier.tokenizer = function (tokens) {\n\t\t\t\tif (typeof tokens === 'string') {\n\t\t\t\t\treturn tokens.split(/\\s+/);\n\t\t\t\t}\n\n\t\t\t\treturn Array.isArray(tokens) ? tokens : [];\n\t\t\t};\n\t\t} catch (error) {\n\t\t\tdebug('Failed to initialize classifier:', error);\n\t\t\t// Create a fallback classifier\n\t\t\tthis.classifier = new NaiveBayes();\n\t\t}\n\t}\n\n\t// Initialize replacements\n\tasync initializeReplacements() {\n\t\tif (this.replacements && this.replacements.size > 0) {\n\t\t\treturn;\n\t\t}\n\n\t\ttry {\n\t\t\tconst replacements = this.config.replacements || await getReplacements();\n\n\t\t\t// Ensure replacements is a Map\n\t\t\tif (replacements instanceof Map) {\n\t\t\t\tthis.replacements = replacements;\n\t\t\t} else if (typeof replacements === 'object' && replacements !== null) {\n\t\t\t\tthis.replacements = new Map(Object.entries(replacements));\n\t\t\t} else {\n\t\t\t\tthrow new Error('Invalid replacements format');\n\t\t\t}\n\t\t} catch (error) {\n\t\t\tdebug('Failed to initialize replacements:', error);\n\t\t\t// Generate fallback replacements\n\t\t\tthis.replacements = new Map();\n\n\t\t\t// Add some basic replacements\n\t\t\tconst basicReplacements = {\n\t\t\t\tu: 'you',\n\t\t\t\tur: 'your',\n\t\t\t\tr: 'are',\n\t\t\t\tn: 'and',\n\t\t\t\t'w/': 'with',\n\t\t\t\tb4: 'before',\n\t\t\t\t2: 'to',\n\t\t\t\t4: 'for',\n\t\t\t};\n\n\t\t\tfor (const [word, replacement] of Object.entries(basicReplacements)) {\n\t\t\t\tthis.replacements.set(word, replacement);\n\t\t\t}\n\t\t}\n\t}\n\n\t// Initialize regex helpers\n\tinitializeRegex() {\n\t\tthis.regexCache = new Map();\n\t\tthis.urlCache = new Map();\n\t}\n\n\t// Enhanced virus scanning with timeout protection\n\tasync getVirusResults(mail) {\n\t\tif (!this.clamscan) {\n\t\t\ttry {\n\t\t\t\tthis.clamscan = await new ClamScan().init(this.config.clamscan);\n\t\t\t} catch (error) {\n\t\t\t\tdebug('ClamScan initialization failed:', error);\n\t\t\t\treturn [];\n\t\t\t}\n\t\t}\n\n\t\tconst results = [];\n\t\tconst attachments = mail.attachments || [];\n\n\t\tfor (const attachment of attachments) {\n\t\t\ttry {\n\t\t\t\tif (attachment.content && isBuffer(attachment.content)) {\n\t\t\t\t\t// eslint-disable-next-line no-await-in-loop\n\t\t\t\t\tconst scanResult = await Promise.race([\n\t\t\t\t\t\tthis.clamscan.scanBuffer(attachment.content),\n\t\t\t\t\t\tnew Promise((_resolve, reject) => {\n\t\t\t\t\t\t\tsetTimeout(() => reject(new Error('Virus scan timeout')), this.config.timeout);\n\t\t\t\t\t\t}),\n\t\t\t\t\t]);\n\n\t\t\t\t\tif (scanResult.isInfected) {\n\t\t\t\t\t\tresults.push({\n\t\t\t\t\t\t\tfilename: attachment.filename || 'unknown',\n\t\t\t\t\t\t\tvirus: scanResult.viruses || ['Unknown virus'],\n\t\t\t\t\t\t\ttype: 'virus',\n\t\t\t\t\t\t});\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t} catch (error) {\n\t\t\t\tdebug('Virus scan error:', error);\n\t\t\t}\n\t\t}\n\n\t\treturn results;\n\t}\n\n\t// Macro detection (DONE)\n\tasync getMacroResults(mail) {\n\t\tconst results = [];\n\t\tconst attachments = mail.attachments || [];\n\t\tconst textContent = mail.text || '';\n\t\tconst htmlContent = mail.html || '';\n\n\t\t// VBA Macro detection\n\t\tconst vbaPatterns = [\n\t\t\t/sub\\s+\\w+\\s*\\(/gi,\n\t\t\t/function\\s+\\w+\\s*\\(/gi,\n\t\t\t/dim\\s+\\w+\\s+as\\s+\\w+/gi,\n\t\t\t/application\\.run/gi,\n\t\t\t/shell\\s*\\(/gi,\n\t\t];\n\n\t\t// PowerShell detection\n\t\tconst powershellPatterns = [\n\t\t\t/powershell/gi,\n\t\t\t/invoke-expression/gi,\n\t\t\t/iex\\s*\\(/gi,\n\t\t\t/start-process/gi,\n\t\t\t/new-object\\s+system\\./gi,\n\t\t];\n\n\t\t// JavaScript macro detection\n\t\tconst jsPatterns = [\n\t\t\t/eval\\s*\\(/gi,\n\t\t\t/document\\.write/gi,\n\t\t\t/activexobject/gi,\n\t\t\t/wscript\\./gi,\n\t\t\t/new\\s+activexobject/gi,\n\t\t];\n\n\t\t// Batch file detection\n\t\tconst batchPatterns = [/@echo\\s+off/gi, /cmd\\s*\\/c/gi, /start\\s+\\/b/gi, /for\\s+\\/[lrf]/gi];\n\n\t\t// Get content from text, html, and header lines\n\t\tlet allContent = textContent + ' ' + htmlContent;\n\n\t\t// Also check header lines for content (like macro code in raw emails)\n\t\tif (mail.headerLines && Array.isArray(mail.headerLines)) {\n\t\t\tfor (const headerLine of mail.headerLines) {\n\t\t\t\tif (headerLine.line) {\n\t\t\t\t\tallContent += ' ' + headerLine.line;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t// Check for VBA macros\n\t\tfor (const pattern of vbaPatterns) {\n\t\t\tif (pattern.test(allContent)) {\n\t\t\t\tresults.push({\n\t\t\t\t\ttype: 'macro',\n\t\t\t\t\tsubtype: 'vba',\n\t\t\t\t\tdescription: 'VBA macro detected',\n\t\t\t\t});\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\n\t\t// Check for PowerShell\n\t\tfor (const pattern of powershellPatterns) {\n\t\t\tif (pattern.test(allContent)) {\n\t\t\t\tresults.push({\n\t\t\t\t\ttype: 'macro',\n\t\t\t\t\tsubtype: 'powershell',\n\t\t\t\t\tdescription: 'PowerShell script detected',\n\t\t\t\t});\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\n\t\t// Check for JavaScript macros\n\t\tfor (const pattern of jsPatterns) {\n\t\t\tif (pattern.test(allContent)) {\n\t\t\t\tresults.push({\n\t\t\t\t\ttype: 'macro',\n\t\t\t\t\tsubtype: 'javascript',\n\t\t\t\t\tdescription: 'JavaScript macro detected',\n\t\t\t\t});\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\n\t\t// Check for batch files\n\t\tfor (const pattern of batchPatterns) {\n\t\t\tif (pattern.test(allContent)) {\n\t\t\t\tresults.push({\n\t\t\t\t\ttype: 'macro',\n\t\t\t\t\tsubtype: 'batch',\n\t\t\t\t\tdescription: 'Batch script detected',\n\t\t\t\t});\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\n\t\t// Check attachments for macro content\n\t\tfor (const attachment of attachments) {\n\t\t\tif (attachment.filename) {\n\t\t\t\tconst extension = fileExtension(attachment.filename).toLowerCase();\n\n\t\t\t\t// Standalone macro files\n\t\t\t\tconst macroExtensions = ['vbs', 'vba', 'ps1', 'bat', 'cmd', 'scr', 'pif'];\n\n\t\t\t\t// Office documents with macros (OOXML format)\n\t\t\t\tconst officeMacroExtensions = ['docm', 'xlsm', 'pptm', 'xlam', 'dotm', 'xltm', 'potm'];\n\n\t\t\t\t// Legacy Office formats (always have macro capability)\n\t\t\t\tconst legacyOfficeExtensions = ['doc', 'xls', 'ppt', 'dot', 'xlt', 'pot', 'xla', 'ppa'];\n\n\t\t\t\tif (macroExtensions.includes(extension)) {\n\t\t\t\t\tresults.push({\n\t\t\t\t\t\ttype: 'macro',\n\t\t\t\t\t\tsubtype: 'script',\n\t\t\t\t\t\tfilename: attachment.filename,\n\t\t\t\t\t\tdescription: `Macro script attachment detected: ${extension}`,\n\t\t\t\t\t});\n\t\t\t\t} else if (officeMacroExtensions.includes(extension)) {\n\t\t\t\t\tresults.push({\n\t\t\t\t\t\ttype: 'macro',\n\t\t\t\t\t\tsubtype: 'office_document',\n\t\t\t\t\t\tfilename: attachment.filename,\n\t\t\t\t\t\tdescription: `Office document with macro capability: ${extension}`,\n\t\t\t\t\t});\n\t\t\t\t} else if (legacyOfficeExtensions.includes(extension)) {\n\t\t\t\t\tresults.push({\n\t\t\t\t\t\ttype: 'macro',\n\t\t\t\t\t\tsubtype: 'legacy_office',\n\t\t\t\t\t\tfilename: attachment.filename,\n\t\t\t\t\t\tdescription: `Legacy Office document (macro-capable): ${extension}`,\n\t\t\t\t\t\trisk: 'high',\n\t\t\t\t\t});\n\t\t\t\t}\n\n\t\t\t\t// Check PDF attachments for JavaScript\n\t\t\t\tif (extension === 'pdf' && attachment.content && isBuffer(attachment.content)) {\n\t\t\t\t\ttry {\n\t\t\t\t\t\tconst pdfContent = attachment.content.toString('latin1');\n\t\t\t\t\t\t// Check for JavaScript in PDF\n\t\t\t\t\t\tif (pdfContent.includes('/JavaScript') || pdfContent.includes('/JS')) {\n\t\t\t\t\t\t\tresults.push({\n\t\t\t\t\t\t\t\ttype: 'macro',\n\t\t\t\t\t\t\t\tsubtype: 'pdf_javascript',\n\t\t\t\t\t\t\t\tfilename: attachment.filename,\n\t\t\t\t\t\t\t\tdescription: 'PDF with embedded JavaScript detected',\n\t\t\t\t\t\t\t\trisk: 'medium',\n\t\t\t\t\t\t\t});\n\t\t\t\t\t\t}\n\t\t\t\t\t} catch (error) {\n\t\t\t\t\t\tdebug('PDF JavaScript detection error:', error);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn results;\n\t}\n\n\t// File path detection (DONE)\n\tasync getFilePathResults(mail) {\n\t\tconst results = [];\n\t\tconst textContent = mail.text || '';\n\t\tconst htmlContent = mail.html || '';\n\t\tconst allContent = textContent + ' ' + htmlContent;\n\n\t\tfor (const pattern of FILE_PATH_PATTERNS) {\n\t\t\tconst matches = allContent.match(pattern);\n\t\t\tif (matches) {\n\t\t\t\tfor (const match of matches) {\n\t\t\t\t\t// Skip HTML tags and common false positives\n\t\t\t\t\tif (this.isValidFilePath(match)) {\n\t\t\t\t\t\tresults.push({\n\t\t\t\t\t\t\ttype: 'file_path',\n\t\t\t\t\t\t\tpath: match,\n\t\t\t\t\t\t\tdescription: 'Suspicious file path detected',\n\t\t\t\t\t\t});\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn results;\n\t}\n\n\t// Check if a path is a valid file path (not HTML tag or false positive)\n\tisValidFilePath(path) {\n\t\t// Skip HTML tags (common HTML elements)\n\t\tconst htmlTags = [\n\t\t\t'a',\n\t\t\t'abbr',\n\t\t\t'address',\n\t\t\t'area',\n\t\t\t'article',\n\t\t\t'aside',\n\t\t\t'audio',\n\t\t\t'b',\n\t\t\t'base',\n\t\t\t'bdi',\n\t\t\t'bdo',\n\t\t\t'blockquote',\n\t\t\t'body',\n\t\t\t'br',\n\t\t\t'button',\n\t\t\t'canvas',\n\t\t\t'caption',\n\t\t\t'cite',\n\t\t\t'code',\n\t\t\t'col',\n\t\t\t'colgroup',\n\t\t\t'data',\n\t\t\t'datalist',\n\t\t\t'dd',\n\t\t\t'del',\n\t\t\t'details',\n\t\t\t'dfn',\n\t\t\t'dialog',\n\t\t\t'div',\n\t\t\t'dl',\n\t\t\t'dt',\n\t\t\t'em',\n\t\t\t'embed',\n\t\t\t'fieldset',\n\t\t\t'figcaption',\n\t\t\t'figure',\n\t\t\t'footer',\n\t\t\t'form',\n\t\t\t'h1',\n\t\t\t'h2',\n\t\t\t'h3',\n\t\t\t'h4',\n\t\t\t'h5',\n\t\t\t'h6',\n\t\t\t'head',\n\t\t\t'header',\n\t\t\t'hr',\n\t\t\t'html',\n\t\t\t'i',\n\t\t\t'iframe',\n\t\t\t'img',\n\t\t\t'input',\n\t\t\t'ins',\n\t\t\t'kbd',\n\t\t\t'label',\n\t\t\t'legend',\n\t\t\t'li',\n\t\t\t'link',\n\t\t\t'main',\n\t\t\t'map',\n\t\t\t'mark',\n\t\t\t'meta',\n\t\t\t'meter',\n\t\t\t'nav',\n\t\t\t'noscript',\n\t\t\t'object',\n\t\t\t'ol',\n\t\t\t'optgroup',\n\t\t\t'option',\n\t\t\t'output',\n\t\t\t'p',\n\t\t\t'param',\n\t\t\t'picture',\n\t\t\t'pre',\n\t\t\t'progress',\n\t\t\t'q',\n\t\t\t'rp',\n\t\t\t'rt',\n\t\t\t'ruby',\n\t\t\t's',\n\t\t\t'samp',\n\t\t\t'script',\n\t\t\t'section',\n\t\t\t'select',\n\t\t\t'small',\n\t\t\t'source',\n\t\t\t'span',\n\t\t\t'strong',\n\t\t\t'style',\n\t\t\t'sub',\n\t\t\t'summary',\n\t\t\t'sup',\n\t\t\t'svg',\n\t\t\t'table',\n\t\t\t'tbody',\n\t\t\t'td',\n\t\t\t'template',\n\t\t\t'textarea',\n\t\t\t'tfoot',\n\t\t\t'th',\n\t\t\t'thead',\n\t\t\t'time',\n\t\t\t'title',\n\t\t\t'tr',\n\t\t\t'track',\n\t\t\t'u',\n\t\t\t'ul',\n\t\t\t'var',\n\t\t\t'video',\n\t\t\t'wbr',\n\t\t];\n\n\t\t// Check if it's an HTML tag\n\t\tconst tagMatch = path.match(/^\\/([a-z\\d]+)$/i);\n\t\tif (tagMatch && htmlTags.includes(tagMatch[1].toLowerCase())) {\n\t\t\treturn false;\n\t\t}\n\n\t\t// Skip very short paths that are likely false positives\n\t\tif (path.length < 4) {\n\t\t\treturn false;\n\t\t}\n\n\t\t// Skip paths that are just domain names\n\t\tif (/^\\/\\/[a-z\\d.-]+$/i.test(path)) {\n\t\t\treturn false;\n\t\t}\n\n\t\t// Must have a file extension or be a directory with multiple segments\n\t\tif (!path.includes('.') && !path.includes('/')) {\n\t\t\treturn false;\n\t\t}\n\n\t\treturn true;\n\t}\n\n\t// Optimize URL parsing with timeout protection (DONE)\n\tasync optimizeUrlParsing(url) {\n\t\ttry {\n\t\t\treturn await Promise.race([\n\t\t\t\tnormalizeUrl(url, {\n\t\t\t\t\tstripHash: true,\n\t\t\t\t\tstripWWW: false,\n\t\t\t\t\tremoveQueryParameters: false,\n\t\t\t\t}),\n\t\t\t\tnew Promise((_resolve, reject) => {\n\t\t\t\t\tsetTimeout(() => reject(new Error('URL parsing timeout')), 5000);\n\t\t\t\t}),\n\t\t\t]);\n\t\t} catch {\n\t\t\treturn url;\n\t\t}\n\t}\n\n\t// Enhanced Cloudflare blocked domain checking with timeout\n\tasync isCloudflareBlocked(hostname) {\n\t\ttry {\n\t\t\tconst response = await Promise.race([\n\t\t\t\tsuperagent\n\t\t\t\t\t.get(`https://1.1.1.3/dns-query?name=${hostname}&type=A`)\n\t\t\t\t\t.set('Accept', 'application/dns-json')\n\t\t\t\t\t.timeout(5000),\n\t\t\t\tnew Promise((_resolve, reject) => {\n\t\t\t\t\tsetTimeout(() => reject(new Error('DNS timeout')), 5000);\n\t\t\t\t}),\n\t\t\t]);\n\n\t\t\treturn response.body?.Status === 3; // NXDOMAIN indicates blocked\n\t\t} catch {\n\t\t\treturn false;\n\t\t}\n\t}\n\n\t// Extract URLs from all possible sources\n\textractAllUrls(mail, originalSource) {\n\t\tlet allText = '';\n\n\t\t// Add mail text and html\n\t\tallText += (mail.text || '') + ' ' + (mail.html || '');\n\n\t\t// Add header lines content\n\t\tif (mail.headerLines && Array.isArray(mail.headerLines)) {\n\t\t\tfor (const headerLine of mail.headerLines) {\n\t\t\t\tif (headerLine.line) {\n\t\t\t\t\tallText += ' ' + headerLine.line;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t// Also check original source if it's a simple string\n\t\tif (typeof originalSource === 'string') {\n\t\t\tallText += ' ' + originalSource;\n\t\t}\n\n\t\treturn this.getUrls(allText);\n\t}\n\n\t// Enhanced URL extraction with improved parsing using tldts\n\tgetUrls(string_) {\n\t\tif (!isSANB(string_)) {\n\t\t\treturn [];\n\t\t}\n\n\t\tconst urls = [];\n\t\tconst matches = string_.match(URL_PATTERN);\n\n\t\tif (matches) {\n\t\t\tfor (let url of matches) {\n\t\t\t\t// Clean up URL ending characters\n\t\t\t\turl = url.replace(URL_ENDING_RESERVED_CHARS, '');\n\n\t\t\t\t// Validate and normalize URL\n\t\t\t\ttry {\n\t\t\t\t\tconst normalizedUrl = normalizeUrl(url, {\n\t\t\t\t\t\tstripHash: false,\n\t\t\t\t\t\tstripWWW: false,\n\t\t\t\t\t});\n\t\t\t\t\turls.push(normalizedUrl);\n\t\t\t\t} catch {\n\t\t\t\t\t// If normalization fails, keep original\n\t\t\t\t\turls.push(url);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn [...new Set(urls)]; // Remove duplicates\n\t}\n\n\t// Parse URL using tldts for accurate domain extraction\n\tparseUrlWithTldts(url) {\n\t\ttry {\n\t\t\tconst parsed = parseTldts(url, {allowPrivateDomains: true});\n\t\t\treturn {\n\t\t\t\tdomain: parsed.domain,\n\t\t\t\tdomainWithoutSuffix: parsed.domainWithoutSuffix,\n\t\t\t\thostname: parsed.hostname,\n\t\t\t\tpublicSuffix: parsed.publicSuffix,\n\t\t\t\tsubdomain: parsed.subdomain,\n\t\t\t\tisIp: parsed.isIp,\n\t\t\t\tisIcann: parsed.isIcann,\n\t\t\t\tisPrivate: parsed.isPrivate,\n\t\t\t};\n\t\t} catch (error) {\n\t\t\tdebug('tldts parsing error:', error);\n\t\t\treturn null;\n\t\t}\n\t}\n\n\t// Enhanced tokenization with language detection\n\tasync getTokens(string_, locale = 'en', isHtml = false) {\n\t\tif (!isSANB(string_)) {\n\t\t\treturn [];\n\t\t}\n\n\t\tlet text = string_;\n\n\t\t// Strip HTML if needed\n\t\tif (isHtml) {\n\t\t\ttext = striptags(text);\n\t\t}\n\n\t\t// Detect language if not provided or if mixed language detection is enabled\n\t\tif (!locale || this.config.enableMixedLanguageDetection) {\n\t\t\ttry {\n\t\t\t\tconst detected = lande(text);\n\t\t\t\tif (detected && detected.length > 0) {\n\t\t\t\t\tlocale = detected[0][0];\n\t\t\t\t}\n\t\t\t} catch {\n\t\t\t\tlocale ||= 'en';\n\t\t\t}\n\t\t}\n\n\t\t// Normalize locale\n\t\tlocale = this.parseLocale(locale);\n\n\t\t// Convert full-width to half-width characters\n\t\ttext = converter.toHalfWidth(text);\n\n\t\t// Expand contractions\n\t\ttry {\n\t\t\ttext = expandContractions(text);\n\t\t} catch {\n\t\t\t// If expansion fails, continue with original text\n\t\t}\n\n\t\t// Tokenize based on language\n\t\tlet tokens = [];\n\n\t\tif (locale === 'ja') {\n\t\t\t// Japanese tokenization\n\t\t\ttry {\n\t\t\t\ttokens = chineseTokenizer.tokenize(text);\n\t\t\t} catch {\n\t\t\t\ttokens = text.split(GENERIC_TOKENIZER);\n\t\t\t}\n\t\t} else if (locale === 'zh') {\n\t\t\t// Chinese tokenization\n\t\t\ttry {\n\t\t\t\ttokens = chineseTokenizer.tokenize(text);\n\t\t\t} catch {\n\t\t\t\ttokens = text.split(GENERIC_TOKENIZER);\n\t\t\t}\n\t\t} else {\n\t\t\t// Generic tokenization for other languages\n\t\t\ttokens = text.split(GENERIC_TOKENIZER);\n\t\t}\n\n\t\t// Process tokens\n\t\tlet processedTokens = tokens\n\t\t\t.map(token => token.toLowerCase().trim())\n\t\t\t.filter(token => token.length > 0 && token.length <= 50); // Reasonable length limit\n\n\t\t// Remove stopwords\n\t\tconst stopwordSet = stopwordsMap.get(locale) || stopwordsMap.get('en');\n\t\tif (stopwordSet) {\n\t\t\tprocessedTokens = processedTokens.filter(token => !stopwordSet.has(token));\n\t\t}\n\n\t\t// Stem words if available for the language\n\t\ttry {\n\t\t\tif (['en', 'es', 'fr', 'de', 'it', 'pt', 'ru'].includes(locale)) {\n\t\t\t\tprocessedTokens = processedTokens.map(token => {\n\t\t\t\t\ttry {\n\t\t\t\t\t\treturn snowball.stemword(token, locale);\n\t\t\t\t\t} catch {\n\t\t\t\t\t\treturn token;\n\t\t\t\t\t}\n\t\t\t\t});\n\t\t\t}\n\t\t} catch {\n\t\t\t// If stemming fails, continue with original tokens\n\t\t}\n\n\t\t// Apply token hashing if enabled\n\t\tif (this.config.hashTokens) {\n\t\t\tprocessedTokens = processedTokens.map(token =>\n\t\t\t\tcreateHash('sha256')\n\t\t\t\t\t.update(token)\n\t\t\t\t\t.digest('hex')\n\t\t\t\t\t.slice(0, 16)); // Use first 16 characters for efficiency\n\t\t}\n\n\t\treturn processedTokens;\n\t}\n\n\t// Enhanced text preprocessing with pattern recognition\n\tasync preprocessText(string_) {\n\t\tif (!isSANB(string_)) {\n\t\t\treturn '';\n\t\t}\n\n\t\tlet text = string_;\n\n\t\t// Apply replacements if available\n\t\tif (this.replacements) {\n\t\t\tfor (const [original, replacement] of this.replacements) {\n\t\t\t\ttext = text.replaceAll(new RegExp(escapeStringRegexp(original), 'gi'), replacement);\n\t\t\t}\n\t\t}\n\n\t\t// Advanced pattern recognition (DONE)\n\t\tif (this.config.enableAdvancedPatternRecognition) {\n\t\t\t// Replace patterns with normalized tokens\n\t\t\ttext = text.replaceAll(DATE_PATTERNS[0], ' DATE_PATTERN ');\n\t\t\ttext = text.replace(CREDIT_CARD_PATTERN, ' CREDIT_CARD ');\n\t\t\ttext = text.replace(PHONE_PATTERN, ' PHONE_NUMBER ');\n\t\t\ttext = text.replace(EMAIL_PATTERN, ' EMAIL_ADDRESS ');\n\t\t\ttext = text.replace(IP_PATTERN, ' IP_ADDRESS ');\n\t\t\ttext = text.replace(URL_PATTERN, ' URL_LINK ');\n\t\t\ttext = text.replace(BITCOIN_PATTERN, ' BITCOIN_ADDRESS ');\n\t\t\ttext = text.replace(MAC_PATTERN, ' MAC_ADDRESS ');\n\t\t\ttext = text.replace(HEX_COLOR_PATTERN, ' HEX_COLOR ');\n\t\t\ttext = text.replace(FLOATING_POINT_PATTERN, ' FLOATING_POINT ');\n\t\t}\n\n\t\treturn text;\n\t}\n\n\t// Main scan method - enhanced with performance metrics and new features\n\tasync scan(source) {\n\t\tconst startTime = Date.now();\n\n\t\ttry {\n\t\t\t// Initialize components if needed\n\t\t\tawait this.initializeClassifier();\n\t\t\tawait this.initializeReplacements();\n\n\t\t\t// Get tokens and mail from source\n\t\t\tconst {tokens, mail} = await this.getTokensAndMailFromSource(source);\n\n\t\t\t// Run all detection methods\n\t\t\tconst [\n\t\t\t\tclassification,\n\t\t\t\tphishing,\n\t\t\t\texecutables,\n\t\t\t\tmacros,\n\t\t\t\tarbitrary,\n\t\t\t\tviruses,\n\t\t\t\tpatterns,\n\t\t\t\tidnHomographAttack,\n\t\t\t\ttoxicity,\n\t\t\t\tnsfw,\n\t\t\t] = await Promise.all([\n\t\t\t\tthis.getClassification(tokens),\n\t\t\t\tthis.getPhishingResults(mail),\n\t\t\t\tthis.getExecutableResults(mail),\n\t\t\t\tthis.config.enableMacroDetection ? this.getMacroResults(mail) : [],\n\t\t\t\tthis.getArbitraryResults(mail),\n\t\t\t\tthis.getVirusResults(mail),\n\t\t\t\tthis.getPatternResults(mail),\n\t\t\t\tthis.getIDNHomographResults(mail),\n\t\t\t\tthis.getToxicityResults(mail),\n\t\t\t\tthis.getNSFWResults(mail),\n\t\t\t]);\n\n\t\t\t// Determine if spam\n\t\t\tconst isSpam\n\t\t\t\t= classification.category === 'spam'\n\t\t\t\t\t|| phishing.length > 0\n\t\t\t\t\t|| executables.length > 0\n\t\t\t\t\t|| macros.length > 0\n\t\t\t\t\t|| arbitrary.length > 0\n\t\t\t\t\t|| viruses.length > 0\n\t\t\t\t\t|| patterns.length > 0\n\t\t\t\t\t|| (idnHomographAttack && idnHomographAttack.detected)\n\t\t\t\t\t|| toxicity.length > 0\n\t\t\t\t\t|| nsfw.length > 0;\n\n\t\t\t// Generate message\n\t\t\tlet message = 'Ham';\n\t\t\tif (isSpam) {\n\t\t\t\tconst reasons = [];\n\t\t\t\tif (classification.category === 'spam') {\n\t\t\t\t\treasons.push('spam classification');\n\t\t\t\t}\n\n\t\t\t\tif (phishing.length > 0) {\n\t\t\t\t\treasons.push('phishing detected');\n\t\t\t\t}\n\n\t\t\t\tif (executables.length > 0) {\n\t\t\t\t\treasons.push('executable content');\n\t\t\t\t}\n\n\t\t\t\tif (macros.length > 0) {\n\t\t\t\t\treasons.push('macro detected');\n\t\t\t\t}\n\n\t\t\t\tif (arbitrary.length > 0) {\n\t\t\t\t\treasons.push('arbitrary patterns');\n\t\t\t\t}\n\n\t\t\t\tif (viruses.length > 0) {\n\t\t\t\t\treasons.push('virus detected');\n\t\t\t\t}\n\n\t\t\t\tif (patterns.length > 0) {\n\t\t\t\t\treasons.push('suspicious patterns');\n\t\t\t\t}\n\n\t\t\t\tif (idnHomographAttack && idnHomographAttack.detected) {\n\t\t\t\t\treasons.push('IDN homograph attack');\n\t\t\t\t}\n\n\t\t\t\tif (toxicity.length > 0) {\n\t\t\t\t\treasons.push('toxic content');\n\t\t\t\t}\n\n\t\t\t\tif (nsfw.length > 0) {\n\t\t\t\t\treasons.push('NSFW content');\n\t\t\t\t}\n\n\t\t\t\tmessage = `Spam (${arrayJoinConjunction(reasons)})`;\n\t\t\t}\n\n\t\t\tconst endTime = Date.now();\n\t\t\tconst processingTime = endTime - startTime;\n\n\t\t\t// Update metrics\n\t\t\tthis.metrics.totalScans++;\n\t\t\tthis.metrics.lastScanTime = processingTime;\n\t\t\tthis.metrics.averageTime\n\t\t\t\t= ((this.metrics.averageTime * (this.metrics.totalScans - 1)) + processingTime)\n\t\t\t\t\t/ this.metrics.totalScans;\n\n\t\t\tconst result = {\n\t\t\t\tisSpam,\n\t\t\t\tmessage,\n\t\t\t\tresults: {\n\t\t\t\t\tclassification,\n\t\t\t\t\tphishing,\n\t\t\t\t\texecutables,\n\t\t\t\t\tmacros,\n\t\t\t\t\tarbitrary,\n\t\t\t\t\tviruses,\n\t\t\t\t\tpatterns,\n\t\t\t\t\tidnHomographAttack,\n\t\t\t\t\ttoxicity,\n\t\t\t\t\tnsfw,\n\t\t\t\t},\n\t\t\t\tlinks: this.extractAllUrls(mail, source),\n\t\t\t\ttokens,\n\t\t\t\tmail,\n\t\t\t};\n\n\t\t\t// Add performance metrics if enabled\n\t\t\tif (this.config.enablePerformanceMetrics) {\n\t\t\t\tresult.metrics = {\n\t\t\t\t\ttotalTime: processingTime,\n\t\t\t\t\tclassificationTime: 0, // Would need to measure individually\n\t\t\t\t\tphishingTime: 0,\n\t\t\t\t\texecutableTime: 0,\n\t\t\t\t\tmacroTime: 0,\n\t\t\t\t\tvirusTime: 0,\n\t\t\t\t\tpatternTime: 0,\n\t\t\t\t\tidnTime: 0,\n\t\t\t\t\tmemoryUsage: process.memoryUsage(),\n\t\t\t\t};\n\t\t\t}\n\n\t\t\treturn result;\n\t\t} catch (error) {\n\t\t\tdebug('Scan error:', error);\n\t\t\tthrow error;\n\t\t}\n\t}\n\n\t// Get pattern recognition results\n\tasync getPatternResults(mail) {\n\t\tconst results = [];\n\t\tconst textContent = mail.text || '';\n\t\tconst htmlContent = mail.html || '';\n\t\tconst allContent = textContent + ' ' + htmlContent;\n\n\t\t// Date pattern detection\n\t\tfor (const pattern of DATE_PATTERNS) {\n\t\t\tconst matches = allContent.match(pattern);\n\t\t\tif (matches && matches.length > 5) {\n\t\t\t\t// Suspicious if many dates\n\t\t\t\tresults.push({\n\t\t\t\t\ttype: 'pattern',\n\t\t\t\t\tsubtype: 'date_spam',\n\t\t\t\t\tcount: matches.length,\n\t\t\t\t\tdescription: 'Excessive date patterns detected',\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\n\t\t// File path detection\n\t\tconst filePathResults = await this.getFilePathResults(mail);\n\t\tresults.push(...filePathResults);\n\n\t\treturn results;\n\t}\n\n\t// Enhanced mail parsing with better error handling\n\tasync getTokensAndMailFromSource(source) {\n\t\tlet mail;\n\n\t\tif (typeof source === 'string' && fs.existsSync(source)) {\n\t\t\t// File path\n\t\t\tsource = fs.readFileSync(source);\n\t\t}\n\n\t\tif (isBuffer(source)) {\n\t\t\tsource = source.toString();\n\t\t}\n\n\t\tif (!source || typeof source !== 'string') {\n\t\t\tsource = '';\n\t\t}\n\n\t\ttry {\n\t\t\tmail = await simpleParser(source);\n\t\t} catch (error) {\n\t\t\tdebug('Mail parsing error:', error);\n\t\t\t// Create minimal mail object\n\t\t\tmail = {\n\t\t\t\ttext: source,\n\t\t\t\thtml: '',\n\t\t\t\tsubject: '',\n\t\t\t\tfrom: {},\n\t\t\t\tto: [],\n\t\t\t\tattachments: [],\n\t\t\t};\n\t\t}\n\n\t\t// Preprocess text content\n\t\tconst textContent = await this.preprocessText(mail.text || '');\n\t\tconst htmlContent = await this.preprocessText(striptags(mail.html || ''));\n\t\tconst subjectContent = await this.preprocessText(mail.subject || '');\n\n\t\t// Get tokens from all content\n\t\tconst allContent = [textContent, htmlContent, subjectContent].join(' ');\n\t\tconst tokens = await this.getTokens(allContent, 'en');\n\n\t\treturn {tokens, mail};\n\t}\n\n\t// Enhanced classification with better error handling\n\tasync getClassification(tokens) {\n\t\tif (!this.classifier) {\n\t\t\tawait this.initializeClassifier();\n\t\t}\n\n\t\ttry {\n\t\t\t// Join tokens into a string for the classifier\n\t\t\tconst text = Array.isArray(tokens) ? tokens.join(' ') : String(tokens);\n\t\t\tconst result = this.classifier.categorize(text);\n\n\t\t\treturn {\n\t\t\t\tcategory: result,\n\t\t\t\tprobability: 0.5, // Default probability\n\t\t\t};\n\t\t} catch (error) {\n\t\t\tdebug('Classification error:', error);\n\t\t\treturn {\n\t\t\t\tcategory: 'ham',\n\t\t\t\tprobability: 0.5,\n\t\t\t};\n\t\t}\n\t}\n\n\t// Enhanced phishing detection\n\tasync getPhishingResults(mail) {\n\t\tconst results = [];\n\t\tconst links = this.getUrls(mail.text || '');\n\n\t\tfor (const url of links) {\n\t\t\ttry {\n\t\t\t\t// eslint-disable-next-line no-await-in-loop\n\t\t\t\tconst normalizedUrl = await this.optimizeUrlParsing(url);\n\t\t\t\tconst parsed = new URL(normalizedUrl);\n\n\t\t\t\t// Check for suspicious domains\n\t\t\t\t// eslint-disable-next-line no-await-in-loop\n\t\t\t\tconst isBlocked = await this.isCloudflareBlocked(parsed.hostname);\n\t\t\t\tif (isBlocked) {\n\t\t\t\t\tresults.push({\n\t\t\t\t\t\ttype: 'phishing',\n\t\t\t\t\t\turl: normalizedUrl,\n\n\t\t\t\t\t\tdescription: 'Blocked by security filters',\n\t\t\t\t\t});\n\t\t\t\t}\n\n\t\t\t\t// Enhanced IDN homograph attack detection\n\t\t\t\t// eslint-disable-next-line no-await-in-loop\n\t\t\t\tconst idnDetector = await this.getIDNDetector();\n\t\t\t\tif (idnDetector && parsed.hostname) {\n\t\t\t\t\tconst context = {\n\t\t\t\t\t\temailContent: mail.text || mail.html || '',\n\t\t\t\t\t\tdisplayText: url === normalizedUrl ? null : url,\n\t\t\t\t\t\tsenderReputation: 0.5, // Default neutral reputation\n\t\t\t\t\t};\n\n\t\t\t\t\tconst idnAnalysis = idnDetector.detectHomographAttack(parsed.hostname, context);\n\n\t\t\t\t\tif (idnAnalysis.riskScore > 0.6) {\n\t\t\t\t\t\tresults.push({\n\t\t\t\t\t\t\ttype: 'phishing',\n\t\t\t\t\t\t\turl: normalizedUrl,\n\t\t\t\t\t\t\tdescription: `IDN homograph attack detected (risk: ${(idnAnalysis.riskScore * 100).toFixed(1)}%)`,\n\t\t\t\t\t\t\tdetails: {\n\t\t\t\t\t\t\t\triskFactors: idnAnalysis.riskFactors,\n\t\t\t\t\t\t\t\trecommendations: idnAnalysis.recommendations,\n\t\t\t\t\t\t\t\tconfidence: idnAnalysis.confidence,\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t});\n\t\t\t\t\t} else if (idnAnalysis.riskScore > 0.3) {\n\t\t\t\t\t\tresults.push({\n\t\t\t\t\t\t\ttype: 'suspicious',\n\t\t\t\t\t\t\turl: normalizedUrl,\n\t\t\t\t\t\t\tdescription: `Suspicious IDN domain (risk: ${(idnAnalysis.riskScore * 100).toFixed(1)}%)`,\n\t\t\t\t\t\t\tdetails: {\n\t\t\t\t\t\t\t\triskFactors: idnAnalysis.riskFactors,\n\t\t\t\t\t\t\t\trecommendations: idnAnalysis.recommendations,\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t});\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t} catch (error) {\n\t\t\t\tdebug('Phishing check error:', error);\n\t\t\t}\n\t\t}\n\n\t\treturn results;\n\t}\n\n\t// Enhanced executable detection\n\tasync getExecutableResults(mail) {\n\t\tconst results = [];\n\t\tconst attachments = mail.attachments || [];\n\n\t\tfor (const attachment of attachments) {\n\t\t\tif (attachment.filename) {\n\t\t\t\tconst extension = fileExtension(attachment.filename).toLowerCase();\n\n\t\t\t\tif (EXECUTABLES.has(extension)) {\n\t\t\t\t\tresults.push({\n\t\t\t\t\t\ttype: 'executable',\n\t\t\t\t\t\tfilename: attachment.filename,\n\t\t\t\t\t\textension,\n\t\t\t\t\t\tdescription: 'Executable file attachment',\n\t\t\t\t\t});\n\t\t\t\t}\n\n\t\t\t\t// Check for archive files (potential evasion technique)\n\t\t\t\tconst archiveExtensions = ['zip', 'rar', '7z', 'tar', 'gz', 'bz2', 'xz', 'arj', 'cab', 'lzh', 'ace', 'iso'];\n\t\t\t\tif (archiveExtensions.includes(extension)) {\n\t\t\t\t\tresults.push({\n\t\t\t\t\t\ttype: 'archive',\n\t\t\t\t\t\tfilename: attachment.filename,\n\t\t\t\t\t\textension,\n\t\t\t\t\t\tdescription: 'Archive attachment (contents not scanned)',\n\t\t\t\t\t\trisk: 'medium',\n\t\t\t\t\t\twarning: 'Archive contents should be extracted and scanned separately',\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Check file content for executable signatures\n\t\t\tif (attachment.content && isBuffer(attachment.content)) {\n\t\t\t\ttry {\n\t\t\t\t\t// eslint-disable-next-line no-await-in-loop\n\t\t\t\t\tconst fileType = await fileTypeFromBuffer(attachment.content);\n\t\t\t\t\tif (fileType && EXECUTABLES.has(fileType.ext)) {\n\t\t\t\t\t\tresults.push({\n\t\t\t\t\t\t\ttype: 'executable',\n\t\t\t\t\t\t\tfilename: attachment.filename || 'unknown',\n\t\t\t\t\t\t\tdetectedType: fileType.ext,\n\t\t\t\t\t\t\tdescription: 'Executable content detected',\n\t\t\t\t\t\t});\n\t\t\t\t\t}\n\t\t\t\t} catch (error) {\n\t\t\t\t\tdebug('File type detection error:', error);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn results;\n\t}\n\n\t// Arbitrary results (GTUBE, etc.)\n\tasync getArbitraryResults(mail) {\n\t\tconst results = [];\n\n\t\t// Get content from text, html, and header lines\n\t\tlet content = (mail.text || '') + (mail.html || '');\n\n\t\t// Also check header lines for content (like GTUBE in raw emails)\n\t\tif (mail.headerLines && Array.isArray(mail.headerLines)) {\n\t\t\tfor (const headerLine of mail.headerLines) {\n\t\t\t\tif (headerLine.line) {\n\t\t\t\t\tcontent += ' ' + headerLine.line;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t// GTUBE test\n\t\tif (content.includes('XJS*C4JDBQADN1.NSBN3*2IDNEN*GTUBE-STANDARD-ANTI-UBE-TEST-EMAIL*C.34X')) {\n\t\t\tresults.push({\n\t\t\t\ttype: 'arbitrary',\n\t\t\t\tdescription: 'GTUBE spam test pattern detected',\n\t\t\t});\n\t\t}\n\n\t\treturn results;\n\t}\n\n\t// Parse and normalize locale\n\tparseLocale(locale) {\n\t\tif (!locale || typeof locale !== 'string') {\n\t\t\treturn 'en';\n\t\t}\n\n\t\t// Handle locale codes like 'en-US' -> 'en'\n\t\tconst normalized = locale.toLowerCase().split('-')[0];\n\t\t// Map some common variations\n\t\tconst localeMap = {\n\t\t\tnb: 'no', // Norwegian Bokm\u00E5l\n\t\t\tnn: 'no', // Norwegian Nynorsk\n\t\t\t'zh-cn': 'zh',\n\t\t\t'zh-tw': 'zh',\n\t\t};\n\t\treturn localeMap[normalized] || normalized;\n\t}\n\n\t// Get IDN homograph attack results\n\tasync getIDNHomographResults(mail) {\n\t\tconst result = {\n\t\t\tdetected: false,\n\t\t\tdomains: [],\n\t\t\triskScore: 0,\n\t\t\tdetails: [],\n\t\t};\n\n\t\ttry {\n\t\t\tconst idnDetector = await this.getIDNDetector();\n\t\t\tif (!idnDetector) {\n\t\t\t\treturn result;\n\t\t\t}\n\n\t\t\t// Extract URLs from email content\n\t\t\tconst textContent = mail.text || '';\n\t\t\tconst htmlContent = mail.html || '';\n\t\t\tconst allContent = textContent + ' ' + htmlContent;\n\t\t\tconst urls = this.getUrls(allContent);\n\n\t\t\t// Analyze each domain\n\t\t\tfor (const url of urls) {\n\t\t\t\ttry {\n\t\t\t\t\t// eslint-disable-next-line no-await-in-loop\n\t\t\t\t\tconst normalizedUrl = await this.optimizeUrlParsing(url);\n\t\t\t\t\tconst parsed = new URL(normalizedUrl);\n\t\t\t\t\tconst domain = parsed.hostname;\n\n\t\t\t\t\tif (!domain) {\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\t}\n\n\t\t\t\t\t// Prepare context for analysis\n\t\t\t\t\tconst context = {\n\t\t\t\t\t\temailContent: allContent,\n\t\t\t\t\t\tdisplayText: url === normalizedUrl ? null : url,\n\t\t\t\t\t\tsenderReputation: 0.5, // Default neutral reputation\n\t\t\t\t\t\temailHeaders: mail.headers || {},\n\t\t\t\t\t};\n\n\t\t\t\t\t// Perform IDN analysis\n\t\t\t\t\tconst analysis = idnDetector.detectHomographAttack(domain, context);\n\n\t\t\t\t\tif (analysis.riskScore > 0.3) {\n\t\t\t\t\t\tresult.detected = true;\n\t\t\t\t\t\tresult.domains.push({\n\t\t\t\t\t\t\tdomain,\n\t\t\t\t\t\t\toriginalUrl: url,\n\t\t\t\t\t\t\tnormalizedUrl,\n\t\t\t\t\t\t\triskScore: analysis.riskScore,\n\t\t\t\t\t\t\triskFactors: analysis.riskFactors,\n\t\t\t\t\t\t\trecommendations: analysis.recommendations,\n\t\t\t\t\t\t\tconfidence: analysis.confidence,\n\t\t\t\t\t\t});\n\n\t\t\t\t\t\t// Update overall risk score to highest found\n\t\t\t\t\t\tresult.riskScore = Math.max(result.riskScore, analysis.riskScore);\n\t\t\t\t\t}\n\t\t\t\t} catch (error) {\n\t\t\t\t\tdebug('IDN analysis error for URL:', url, error);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Add summary details\n\t\t\tif (result.detected) {\n\t\t\t\tresult.details.push(\n\t\t\t\t\t`Found ${result.domains.length} suspicious domain(s)`,\n\t\t\t\t\t`Highest risk score: ${(result.riskScore * 100).toFixed(1)}%`,\n\t\t\t\t);\n\n\t\t\t\t// Add specific risk factors\n\t\t\t\tconst allRiskFactors = new Set();\n\t\t\t\tfor (const domain of result.domains) {\n\t\t\t\t\tfor (const factor of domain.riskFactors) {\n\t\t\t\t\t\tallRiskFactors.add(factor);\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tresult.details.push(...allRiskFactors);\n\t\t\t}\n\t\t} catch (error) {\n\t\t\tdebug('IDN homograph detection error:', error);\n\t\t}\n\n\t\treturn result;\n\t}\n\n\t// Get IDN detector instance\n\tasync getIDNDetector() {\n\t\tif (!this.idnDetector) {\n\t\t\ttry {\n\t\t\t\tconst {default: EnhancedIDNDetector} = await import('./enhanced-idn-detector.js');\n\t\t\t\tthis.idnDetector = new EnhancedIDNDetector({\n\t\t\t\t\tstrictMode: this.config.strictIDNDetection || false,\n\t\t\t\t\tenableWhitelist: true,\n\t\t\t\t\tenableBrandProtection: true,\n\t\t\t\t\tenableContextAnalysis: true,\n\t\t\t\t});\n\t\t\t} catch (error) {\n\t\t\t\tdebug('Failed to load IDN detector:', error);\n\t\t\t\treturn null;\n\t\t\t}\n\t\t}\n\n\t\treturn this.idnDetector;\n\t}\n\n\t// Hybrid language detection using both lande and franc\n\tasync detectLanguageHybrid(text) {\n\t\tif (!text || typeof text !== 'string' || text.length < 3) {\n\t\t\treturn 'en';\n\t\t}\n\n\t\t// Handle edge cases for non-linguistic content\n\t\tconst cleanText = text.trim();\n\t\tif (!cleanText || /^[\\d\\s\\W]+$/.test(cleanText)) {\n\t\t\t// Only numbers, spaces, and special characters\n\t\t\treturn 'en';\n\t\t}\n\n\t\ttry {\n\t\t\t// Use lande for short text (< 50 chars), franc for longer text\n\t\t\tif (text.length < 50) {\n\t\t\t\tconst landeResult = lande(text);\n\t\t\t\tif (landeResult && landeResult.length > 0) {\n\t\t\t\t\t// Convert lande's 3-letter codes to 2-letter codes\n\t\t\t\t\tconst detected = landeResult[0][0];\n\t\t\t\t\tconst normalized = this.normalizeLanguageCode(detected);\n\n\t\t\t\t\t// Additional validation for short text detection\n\t\t\t\t\tif (this.isValidShortTextDetection(text, normalized)) {\n\t\t\t\t\t\t// Filter by supportedLanguages if configured\n\t\t\t\t\t\tif (this.config.supportedLanguages && this.config.supportedLanguages.length > 0) {\n\t\t\t\t\t\t\tif (this.config.supportedLanguages.includes(normalized)) {\n\t\t\t\t\t\t\t\treturn normalized;\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\treturn this.config.supportedLanguages[0];\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\treturn normalized;\n\t\t\t\t\t}\n\n\t\t\t\t\t// Fallback to English for ambiguous short text\n\t\t\t\t\treturn 'en';\n\t\t\t\t}\n\n\t\t\t\treturn 'en';\n\t\t\t}\n\n\t\t\t// Import franc dynamically\n\t\t\tconst {franc} = await import('franc');\n\t\t\tconst francResult = franc(text);\n\t\t\tif (francResult === 'und') {\n\t\t\t\t// Fallback to lande if franc can't detect\n\t\t\t\tconst landeResult = lande(text);\n\t\t\t\tif (landeResult && landeResult.length > 0) {\n\t\t\t\t\treturn this.normalizeLanguageCode(landeResult[0][0]);\n\t\t\t\t}\n\n\t\t\t\treturn 'en';\n\t\t\t}\n\n\t\t\tconst detected = this.normalizeLanguageCode(francResult);\n\n\t\t\t// Filter by supportedLanguages if configured\n\t\t\tif (this.config.supportedLanguages && this.config.supportedLanguages.length > 0) {\n\t\t\t\tif (this.config.supportedLanguages.includes(detected)) {\n\t\t\t\t\treturn detected;\n\t\t\t\t}\n\n\t\t\t\t// If detected language not supported, return first supported language\n\t\t\t\treturn this.config.supportedLanguages[0];\n\t\t\t}\n\n\t\t\treturn detected;\n\t\t} catch (error) {\n\t\t\tdebug('Language detection error:', error);\n\t\t\t// Fallback to lande\n\t\t\ttry {\n\t\t\t\tconst landeResult = lande(text);\n\t\t\t\tif (landeResult && landeResult.length > 0) {\n\t\t\t\t\treturn this.normalizeLanguageCode(landeResult[0][0]);\n\t\t\t\t}\n\n\t\t\t\treturn 'en';\n\t\t\t} catch {\n\t\t\t\treturn 'en';\n\t\t\t}\n\t\t}\n\t}\n\n\t// Validate short text language detection\n\tisValidShortTextDetection(text, detectedLang) {\n\t\t// For non-Latin scripts, always trust the detection\n\t\t// eslint-disable-next-line no-control-regex\n\t\tconst hasNonLatin = /[^\\u0000-\\u024F\\u1E00-\\u1EFF]/.test(text);\n\t\tif (hasNonLatin) {\n\t\t\treturn true;\n\t\t}\n\n\t\t// For very short Latin text (< 7 chars), be conservative\n\t\tif (text.length < 7 && detectedLang !== 'en') {\n\t\t\treturn false;\n\t\t}\n\n\t\t// For longer Latin text, trust the detection\n\t\treturn true;\n\t}\n\n\t// Get toxicity detection results\n\tasync getToxicityResults(mail) {\n\t\tconst results = [];\n\n\t\ttry {\n\t\t\t// Lazy load TensorFlow and toxicity model\n\t\t\tif (!this.toxicityModel) {\n\t\t\t\tconst _tf = await import('@tensorflow/tfjs-node');\n\t\t\t\tconst toxicity = await import('@tensorflow-models/toxicity');\n\n\t\t\t\t// Load model with threshold of 0.7 (higher = more strict)\n\t\t\t\tconst threshold = this.config.toxicityThreshold || 0.7;\n\t\t\t\tthis.toxicityModel = await toxicity.load(threshold);\n\t\t\t}\n\n\t\t\t// Get text content from email\n\t\t\tconst textContent = mail.text || '';\n\t\t\tconst htmlContent = striptags(mail.html || '');\n\t\t\tconst subjectContent = mail.subject || '';\n\n\t\t\t// Combine all content\n\t\t\tconst allContent = [subjectContent, textContent, htmlContent]\n\t\t\t\t.filter(text => text && text.trim().length > 0)\n\t\t\t\t.join(' ')\n\t\t\t\t.slice(0, 5000); // Limit to 5000 chars for performance\n\n\t\t\tif (!allContent || allContent.trim().length < 10) {\n\t\t\t\treturn results;\n\t\t\t}\n\n\t\t\t// Classify text for toxicity\n\t\t\tconst predictions = await Promise.race([\n\t\t\t\tthis.toxicityModel.classify([allContent]),\n\t\t\t\tnew Promise((_resolve, reject) => {\n\t\t\t\t\tsetTimeout(() => reject(new Error('Toxicity detection timeout')), this.config.timeout);\n\t\t\t\t}),\n\t\t\t]);\n\n\t\t\t// Process predictions\n\t\t\tfor (const prediction of predictions) {\n\t\t\t\tconst {label} = prediction;\n\t\t\t\tconst matches = prediction.results[0].match;\n\n\t\t\t\tif (matches) {\n\t\t\t\t\tconst {probabilities} = prediction.results[0];\n\t\t\t\t\tconst toxicProbability = probabilities[1]; // Index 1 is toxic probability\n\n\t\t\t\t\tresults.push({\n\t\t\t\t\t\ttype: 'toxicity',\n\t\t\t\t\t\tcategory: label,\n\t\t\t\t\t\tprobability: toxicProbability,\n\t\t\t\t\t\tdescription: `Toxic content detected: ${label} (${(toxicProbability * 100).toFixed(1)}%)`,\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t}\n\t\t} catch (error) {\n\t\t\tdebug('Toxicity detection error:', error);\n\t\t\t// Don't fail the whole scan if toxicity detection fails\n\t\t}\n\n\t\treturn results;\n\t}\n\n\t// Get NSFW image detection results\n\tasync getNSFWResults(mail) {\n\t\tconst results = [];\n\n\t\ttry {\n\t\t\t// Lazy load TensorFlow and NSFW model\n\t\t\tif (!this.nsfwModel) {\n\t\t\t\tconst _tf = await import('@tensorflow/tfjs-node');\n\t\t\t\tconst nsfw = await import('nsfwjs');\n\n\t\t\t\t// Load model\n\t\t\t\tthis.nsfwModel = await nsfw.load();\n\t\t\t}\n\n\t\t\tconst attachments = mail.attachments || [];\n\n\t\t\t// Process image attachments\n\t\t\tfor (const attachment of attachments) {\n\t\t\t\ttry {\n\t\t\t\t\tif (!attachment.content || !isBuffer(attachment.content)) {\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\t}\n\n\t\t\t\t\t// Check if it's an image\n\t\t\t\t\t// eslint-disable-next-line no-await-in-loop\n\t\t\t\t\tconst fileType = await fileTypeFromBuffer(attachment.content);\n\n\t\t\t\t\tif (!fileType || !fileType.mime.startsWith('image/')) {\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\t}\n\n\t\t\t\t\t// Use sharp to process image for NSFW detection\n\t\t\t\t\t// eslint-disable-next-line no-await-in-loop, unicorn/no-await-expression-member\n\t\t\t\t\tconst sharp = (await import('sharp')).default;\n\t\t\t\t\t// eslint-disable-next-line no-await-in-loop\n\t\t\t\t\tconst processedImage = await sharp(attachment.content)\n\t\t\t\t\t\t.resize(224, 224) // NSFW model expects 224x224\n\t\t\t\t\t\t.raw()\n\t\t\t\t\t\t.toBuffer();\n\n\t\t\t\t\t// Convert to tensor and classify\n\t\t\t\t\t// eslint-disable-next-line no-await-in-loop\n\t\t\t\t\tconst _tf = await import('@tensorflow/tfjs-node');\n\t\t\t\t\tconst imageTensor = _tf.tensor3d(\n\t\t\t\t\t\tnew Uint8Array(processedImage),\n\t\t\t\t\t\t[224, 224, 3],\n\t\t\t\t\t);\n\n\t\t\t\t\t// eslint-disable-next-line no-await-in-loop\n\t\t\t\t\tconst predictions = await Promise.race([\n\t\t\t\t\t\tthis.nsfwModel.classify(imageTensor),\n\t\t\t\t\t\tnew Promise((_resolve, reject) => {\n\t\t\t\t\t\t\tsetTimeout(() => reject(new Error('NSFW detection timeout')), this.config.timeout);\n\t\t\t\t\t\t}),\n\t\t\t\t\t]);\n\n\t\t\t\t\t// Clean up tensor\n\t\t\t\t\timageTensor.dispose();\n\n\t\t\t\t\t// Check predictions\n\t\t\t\t\tconst nsfwThreshold = this.config.nsfwThreshold || 0.6;\n\t\t\t\t\tfor (const prediction of predictions) {\n\t\t\t\t\t\tif (\n\t\t\t\t\t\t\t(prediction.className === 'Porn'\n\t\t\t\t\t\t\t\t|| prediction.className === 'Hentai'\n\t\t\t\t\t\t\t\t|| prediction.className === 'Sexy')\n\t\t\t\t\t\t\t&& prediction.probability > nsfwThreshold\n\t\t\t\t\t\t) {\n\t\t\t\t\t\t\tresults.push({\n\t\t\t\t\t\t\t\ttype: 'nsfw',\n\t\t\t\t\t\t\t\tfilename: attachment.filename || 'unknown',\n\t\t\t\t\t\t\t\tcategory: prediction.className,\n\t\t\t\t\t\t\t\tprobability: prediction.probability,\n\t\t\t\t\t\t\t\tdescription: `NSFW image detected: ${prediction.className} (${(prediction.probability * 100).toFixed(1)}%)`,\n\t\t\t\t\t\t\t});\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t} catch (error) {\n\t\t\t\t\tdebug('NSFW detection error for attachment:', attachment.filename, error);\n\t\t\t\t}\n\t\t\t}\n\t\t} catch (error) {\n\t\t\tdebug('NSFW detection error:', error);\n\t\t\t// Don't fail the whole scan if NSFW detection fails\n\t\t}\n\n\t\treturn results;\n\t}\n\n\t// Normalize language codes from 3-letter to 2-letter format\n\tnormalizeLanguageCode(code) {\n\t\tif (!code || typeof code !== 'string') {\n\t\t\treturn 'en';\n\t\t}\n\n\t\t// If already 2-letter code, return as-is\n\t\tif (code.length === 2) {\n\t\t\treturn code.toLowerCase();\n\t\t}\n\n\t\t// Convert 3-letter ISO 639-2/3 codes to 2-letter ISO 639-1 codes\n\t\tconst codeMap = {\n\t\t\t// Common language mappings\n\t\t\teng: 'en', // English\n\t\t\tfra: 'fr', // French\n\t\t\tfre: 'fr', // French (alternative)\n\t\t\tspa: 'es', // Spanish\n\t\t\tdeu: 'de', // German\n\t\t\tger: 'de', // German (alternative)\n\t\t\tita: 'it', // Italian\n\t\t\tpor: 'pt', // Portuguese\n\t\t\trus: 'ru', // Russian\n\t\t\tjpn: 'ja', // Japanese\n\t\t\tkor: 'ko', // Korean\n\t\t\tcmn: 'zh', // Chinese (Mandarin)\n\t\t\tzho: 'zh', // Chinese\n\t\t\tchi: 'zh', // Chinese (alternative)\n\t\t\tara: 'ar', // Arabic\n\t\t\thin: 'hi', // Hindi\n\t\t\tben: 'bn', // Bengali\n\t\t\turd: 'ur', // Urdu\n\t\t\ttur: 'tr', // Turkish\n\t\t\tpol: 'pl', // Polish\n\t\t\tnld: 'nl', // Dutch\n\t\t\tdut: 'nl', // Dutch (alternative)\n\t\t\tswe: 'sv', // Swedish\n\t\t\tnor: 'no', // Norwegian\n\t\t\tdan: 'da', // Danish\n\t\t\tfin: 'fi', // Finnish\n\t\t\thun: 'hu', // Hungarian\n\t\t\tces: 'cs', // Czech\n\t\t\tcze: 'cs', // Czech (alternative)\n\t\t\tslk: 'sk', // Slovak\n\t\t\tslo: 'sk', // Slovak (alternative)\n\t\t\tslv: 'sl', // Slovenian\n\t\t\thrv: 'hr', // Croatian\n\t\t\tsrp: 'sr', // Serbian\n\t\t\tbul: 'bg', // Bulgarian\n\t\t\tron: 'ro', // Romanian\n\t\t\trum: 'ro', // Romanian (alternative)\n\t\t\tell: 'el', // Greek\n\t\t\tgre: 'el', // Greek (alternative)\n\t\t\theb: 'he', // Hebrew\n\t\t\ttha: 'th', // Thai\n\t\t\tvie: 'vi', // Vietnamese\n\t\t\tind: 'id', // Indonesian\n\t\t\tmsa: 'ms', // Malay\n\t\t\tmay: 'ms', // Malay (alternative)\n\t\t\ttgl: 'tl', // Tagalog\n\t\t\tukr: 'uk', // Ukrainian\n\t\t\tbel: 'be', // Belarusian\n\t\t\tlit: 'lt', // Lithuanian\n\t\t\tlav: 'lv', // Latvian\n\t\t\test: 'et', // Estonian\n\t\t\tcat: 'ca', // Catalan\n\t\t\teus: 'eu', // Basque\n\t\t\tbaq: 'eu', // Basque (alternative)\n\t\t\tglg: 'gl', // Galician\n\t\t\tgle: 'ga', // Irish\n\t\t\tgla: 'gd', // Scottish Gaelic\n\t\t\tcym: 'cy', // Welsh\n\t\t\twel: 'cy', // Welsh (alternative)\n\t\t\tisl: 'is', // Icelandic\n\t\t\tice: 'is', // Icelandic (alternative)\n\t\t\tmlt: 'mt', // Maltese\n\t\t\tafr: 'af', // Afrikaans\n\t\t\tswa: 'sw', // Swahili\n\t\t\tamh: 'am', // Amharic\n\t\t\thau: 'ha', // Hausa\n\t\t\tyor: 'yo', // Yoruba\n\t\t\tibo: 'ig', // Igbo\n\t\t\tsom: 'so', // Somali\n\t\t\torm: 'om', // Oromo\n\t\t\ttig: 'ti', // Tigrinya\n\t\t\tmlg: 'mg', // Malagasy\n\t\t\tnya: 'ny', // Chichewa\n\t\t\tsna: 'sn', // Shona\n\t\t\txho: 'xh', // Xhosa\n\t\t\tzul: 'zu', // Zulu\n\t\t\tnso: 'nso', // Northern Sotho\n\t\t\tsot: 'st', // Southern Sotho\n\t\t\ttsn: 'tn', // Tswana\n\t\t\tven: 've', // Venda\n\t\t\ttso: 'ts', // Tsonga\n\t\t\tssw: 'ss', // Swati\n\t\t\tnde: 'nr', // Southern Ndebele\n\t\t\tnbl: 'nd', // Northern Ndebele\n\t\t};\n\n\t\tconst normalized = code.toLowerCase();\n\t\treturn codeMap[normalized] || 'en';\n\t}\n}\n\nexport default SpamScanner;\n"],
5
+ "mappings": ";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA,MACE;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACF;AAAA;AAAA;;;ACbA;AAAA;AAAA;AAAA;AAAA,sBACA,gBACA,6BAGM,OAEA,eAMF,cAUG;AAvBP;AAAA;AAAA,uBAAuB;AACvB,qBAA2B;AAC3B,kCAA+B;AAC/B;AAEA,IAAM,YAAQ,2BAAS,aAAa;AAEpC,IAAM,gBAAgB;AAAA,MACrB,QAAQ;AAAA,MACR,YAAY;AAAA,IACb;AAGA,IAAI,eAAe,CAAC;AACpB,QAAI;AACH,qBAAe,KAAK,UAAM,6BAAa,uBAAuB,MAAM,CAAC;AAAA,IACtE,SAAS,OAAO;AACf,YAAM,KAAK;AACX,iBAAW,eAAe,2BAAmB;AAC5C,qBAAa,WAAW,IAAI,GAAG,WAAW,OAAG,4BAAAA,SAAmB,aAAa,CAAC;AAAA,MAC/E;AAAA,IACD;AAEA,IAAO,uBAAQ;AAAA;AAAA;;;ACvBf;AAAA;AAAA;AAAA;AAAA,IAAAC,mBACAC,iBACA,mBAEMC,QAEF,YAQG;AAdP;AAAA;AAAA,IAAAF,oBAAuB;AACvB,IAAAC,kBAA2B;AAC3B,wBAAuB;AAEvB,IAAMC,aAAQ,4BAAS,aAAa;AAEpC,IAAI,aAAa,IAAI,kBAAAC,QAAW,EAAE,aAAa;AAE/C,QAAI;AACH,mBAAa,KAAK,UAAM,8BAAa,qBAAqB,MAAM,CAAC;AAAA,IAClE,SAAS,OAAO;AACf,MAAAD,OAAM,KAAK;AAAA,IACZ;AAEA,IAAO,yBAAQ;AAAA;AAAA;;;ACdf;AAAA;AAAA;AAAA;AAAA,IAMA,oBACA,oBAGM,kBAsEA,wBAWA,gBA6BA,qBAgZC;AAxgBP;AAAA;AAMA,yBAAyB;AACzB,yBAAwB;AAGxB,IAAM,mBAAmB,oBAAI,IAAI;AAAA;AAAA,MAEhC,CAAC,UAAK,GAAG;AAAA,MACT,CAAC,UAAK,GAAG;AAAA,MACT,CAAC,UAAK,GAAG;AAAA,MACT,CAAC,UAAK,GAAG;AAAA,MACT,CAAC,UAAK,GAAG;AAAA,MACT,CAAC,UAAK,GAAG;AAAA,MACT,CAAC,UAAK,GAAG;AAAA,MACT,CAAC,UAAK,GAAG;AAAA,MACT,CAAC,UAAK,GAAG;AAAA,MACT,CAAC,UAAK,GAAG;AAAA,MACT,CAAC,UAAK,GAAG;AAAA,MACT,CAAC,UAAK,GAAG;AAAA,MACT,CAAC,UAAK,GAAG;AAAA,MACT,CAAC,UAAK,GAAG;AAAA,MACT,CAAC,UAAK,GAAG;AAAA,MACT,CAAC,UAAK,GAAG;AAAA,MACT,CAAC,UAAK,GAAG;AAAA,MACT,CAAC,UAAK,GAAG;AAAA,MACT,CAAC,UAAK,GAAG;AAAA;AAAA,MAGT,CAAC,UAAK,GAAG;AAAA,MACT,CAAC,UAAK,GAAG;AAAA,MACT,CAAC,UAAK,GAAG;AAAA,MACT,CAAC,UAAK,GAAG;AAAA,MACT,CAAC,UAAK,GAAG;AAAA,MACT,CAAC,UAAK,GAAG;AAAA,MACT,CAAC,UAAK,GAAG;AAAA,MACT,CAAC,UAAK,GAAG;AAAA,MACT,CAAC,UAAK,GAAG;AAAA,MACT,CAAC,UAAK,GAAG;AAAA,MACT,CAAC,UAAK,GAAG;AAAA,MACT,CAAC,UAAK,GAAG;AAAA,MACT,CAAC,UAAK,GAAG;AAAA,MACT,CAAC,UAAK,GAAG;AAAA,MACT,CAAC,UAAK,GAAG;AAAA,MACT,CAAC,UAAK,GAAG;AAAA,MACT,CAAC,UAAK,GAAG;AAAA,MACT,CAAC,UAAK,GAAG;AAAA,MACT,CAAC,UAAK,GAAG;AAAA;AAAA,MAGT,CAAC,aAAM,GAAG;AAAA,MACV,CAAC,aAAM,GAAG;AAAA,MACV,CAAC,aAAM,GAAG;AAAA,MACV,CAAC,aAAM,GAAG;AAAA,MACV,CAAC,aAAM,GAAG;AAAA,MACV,CAAC,aAAM,GAAG;AAAA,MACV,CAAC,aAAM,GAAG;AAAA,MACV,CAAC,aAAM,GAAG;AAAA,MACV,CAAC,aAAM,GAAG;AAAA,MACV,CAAC,aAAM,GAAG;AAAA;AAAA,MAGV,CAAC,UAAK,GAAG;AAAA,MACT,CAAC,UAAK,GAAG;AAAA,MACT,CAAC,UAAK,GAAG;AAAA,MACT,CAAC,UAAK,GAAG;AAAA,MACT,CAAC,UAAK,GAAG;AAAA,MACT,CAAC,UAAK,GAAG;AAAA,MACT,CAAC,UAAK,GAAG;AAAA,MACT,CAAC,UAAK,IAAI;AAAA,MACV,CAAC,UAAK,KAAK;AAAA,MACX,CAAC,UAAK,IAAI;AAAA,MACV,CAAC,UAAK,GAAG;AAAA,IACV,CAAC;AAGD,IAAM,yBAAyB,oBAAI,IAAI;AAAA,MACtC;AAAA;AAAA,MACA;AAAA;AAAA,MACA;AAAA;AAAA,MACA;AAAA;AAAA,MACA;AAAA;AAAA,MACA;AAAA;AAAA;AAAA,IAED,CAAC;AAGD,IAAM,iBAAiB;AAAA,MACtB;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACD;AAEA,IAAM,sBAAN,MAA0B;AAAA,MACzB,YAAY,UAAU,CAAC,GAAG;AACzB,aAAK,UAAU;AAAA,UACd,YAAY;AAAA,UACZ,iBAAiB;AAAA,UACjB,uBAAuB;AAAA,UACvB,uBAAuB;AAAA,UACvB,wBAAwB;AAAA,UACxB,cAAc;AAAA;AAAA,UACd,GAAG;AAAA,QACJ;AAEA,aAAK,QAAQ,oBAAI,IAAI;AAAA,MACtB;AAAA;AAAA;AAAA;AAAA,MAKA,sBAAsB,QAAQ,UAAU,CAAC,GAAG;AAC3C,cAAM,WAAW,KAAK,YAAY,QAAQ,OAAO;AACjD,YAAI,KAAK,MAAM,IAAI,QAAQ,GAAG;AAC7B,iBAAO,KAAK,MAAM,IAAI,QAAQ;AAAA,QAC/B;AAEA,cAAM,SAAS,KAAK,qBAAqB,QAAQ,OAAO;AACxD,aAAK,MAAM,IAAI,UAAU,MAAM;AAC/B,eAAO;AAAA,MACR;AAAA;AAAA;AAAA;AAAA,MAKA,qBAAqB,QAAQ,SAAS;AACrC,cAAM,WAAW;AAAA,UAChB;AAAA,UACA,OAAO,KAAK,YAAY,MAAM;AAAA,UAC9B,WAAW;AAAA,UACX,aAAa,CAAC;AAAA,UACd,iBAAiB,CAAC;AAAA,UAClB,YAAY;AAAA,QACb;AAGA,YAAI,KAAK,QAAQ,mBAAmB,KAAK,cAAc,MAAM,GAAG;AAC/D,mBAAS,YAAY;AACrB,mBAAS,aAAa;AACtB,mBAAS,gBAAgB,KAAK,qCAAqC;AACnE,iBAAO;AAAA,QACR;AAGA,YAAI,SAAS,OAAO;AACnB,mBAAS,aAAa;AACtB,mBAAS,YAAY,KAAK,+BAA+B;AAAA,QAC1D;AAGA,cAAM,qBAAqB,KAAK,4BAA4B,MAAM;AAClE,iBAAS,aAAa,mBAAmB;AACzC,iBAAS,YAAY,KAAK,GAAG,mBAAmB,OAAO;AAGvD,YAAI,KAAK,QAAQ,uBAAuB;AACvC,gBAAM,gBAAgB,KAAK,uBAAuB,MAAM;AACxD,mBAAS,aAAa,cAAc;AACpC,mBAAS,YAAY,KAAK,GAAG,cAAc,OAAO;AAAA,QACnD;AAGA,cAAM,iBAAiB,KAAK,oBAAoB,MAAM;AACtD,iBAAS,aAAa,eAAe;AACrC,iBAAS,YAAY,KAAK,GAAG,eAAe,OAAO;AAGnD,YAAI,KAAK,QAAQ,yBAAyB,SAAS;AAClD,gBAAM,kBAAkB,KAAK,eAAe,QAAQ,OAAO;AAC3D,mBAAS,aAAa,gBAAgB;AACtC,mBAAS,YAAY,KAAK,GAAG,gBAAgB,OAAO;AAAA,QACrD;AAGA,YAAI,OAAO,SAAS,MAAM,GAAG;AAC5B,gBAAM,mBAAmB,KAAK,gBAAgB,MAAM;AACpD,mBAAS,aAAa,iBAAiB;AACvC,mBAAS,YAAY,KAAK,GAAG,iBAAiB,OAAO;AAAA,QACtD;AAGA,iBAAS,aAAa,KAAK,IAAI,SAAS,WAAW,CAAC;AACpD,iBAAS,kBAAkB,KAAK,wBAAwB,QAAQ;AAEhE,eAAO;AAAA,MACR;AAAA;AAAA;AAAA;AAAA,MAKA,YAAY,QAAQ;AAEnB,eAAO,OAAO,SAAS,MAAM,KAAK,mBAAmB,KAAK,MAAM;AAAA,MACjE;AAAA;AAAA;AAAA;AAAA,MAKA,cAAc,QAAQ;AACrB,cAAM,aAAa,OAAO,YAAY;AACtC,eAAO,uBAAuB,IAAI,UAAU;AAAA,MAC7C;AAAA;AAAA;AAAA;AAAA,MAKA,4BAA4B,QAAQ;AACnC,cAAM,WAAW,EAAC,OAAO,GAAG,SAAS,CAAC,EAAC;AACvC,YAAI,kBAAkB;AACtB,YAAI,aAAa;AAGjB,YAAI;AACH,gBAAM,iBAAa,mBAAAE,SAAY,MAAM;AACrC,cAAI,eAAe,QAAQ;AAE1B,uBAAW,QAAQ,QAAQ;AAC1B;AACA,oBAAM,qBAAiB,mBAAAA,SAAY,IAAI;AACvC,kBAAI,mBAAmB,MAAM;AAC5B;AACA,yBAAS,QAAQ,KAAK,yBAAyB,IAAI,WAAM,cAAc,EAAE;AAAA,cAC1E;AAAA,YACD;AAEA,gBAAI,kBAAkB,GAAG;AACxB,oBAAM,QAAQ,kBAAkB;AAChC,uBAAS,QAAQ,KAAK,IAAI,QAAQ,KAAK,GAAG;AAC1C,uBAAS,QAAQ,KAAK,GAAG,eAAe,IAAI,UAAU,8BAA8B,sBAAsB,UAAU,EAAE;AAAA,YACvH;AAAA,UACD;AAAA,QACD,QAAQ;AAEP,qBAAW,QAAQ,QAAQ;AAC1B;AACA,gBAAI,iBAAiB,IAAI,IAAI,GAAG;AAC/B;AACA,uBAAS,QAAQ,KAAK,yBAAyB,IAAI,WAAM,iBAAiB,IAAI,IAAI,CAAC,EAAE;AAAA,YACtF;AAAA,UACD;AAEA,cAAI,kBAAkB,GAAG;AACxB,kBAAM,QAAQ,kBAAkB;AAChC,qBAAS,QAAQ,KAAK,IAAI,QAAQ,KAAK,GAAG;AAC1C,qBAAS,QAAQ,KAAK,GAAG,eAAe,IAAI,UAAU,4BAA4B;AAAA,UACnF;AAAA,QACD;AAEA,eAAO;AAAA,MACR;AAAA;AAAA;AAAA;AAAA,MAKA,uBAAuB,QAAQ;AAC9B,cAAM,WAAW,EAAC,OAAO,GAAG,SAAS,CAAC,EAAC;AACvC,cAAM,cAAc,KAAK,gBAAgB,MAAM;AAE/C,mBAAW,SAAS,gBAAgB;AACnC,gBAAM,aAAa,KAAK,oBAAoB,aAAa,KAAK;AAC9D,cAAI,aAAa,KAAK,QAAQ,wBAAwB;AACrD,qBAAS,QAAQ,KAAK,IAAI,SAAS,OAAO,aAAa,GAAG;AAC1D,qBAAS,QAAQ,KAAK,sBAAsB,KAAK,MAAM,aAAa,KAAK,QAAQ,CAAC,CAAC,GAAG;AAAA,UACvF;AAAA,QACD;AAEA,eAAO;AAAA,MACR;AAAA;AAAA;AAAA;AAAA,MAKA,oBAAoB,QAAQ;AAC3B,cAAM,WAAW,EAAC,OAAO,GAAG,SAAS,CAAC,EAAC;AACvC,cAAM,UAAU,KAAK,cAAc,MAAM;AAEzC,YAAI,QAAQ,OAAO,GAAG;AAErB,gBAAM,aAAa,CAAC,GAAG,OAAO,EAAE,KAAK,IAAI;AACzC,mBAAS,QAAQ,KAAK,2BAA2B,UAAU,EAAE;AAG7D,cAAI,QAAQ,IAAI,OAAO,MAAM,QAAQ,IAAI,UAAU,KAAK,QAAQ,IAAI,OAAO,IAAI;AAC9E,qBAAS,SAAS;AAClB,qBAAS,QAAQ,KAAK,iDAAiD;AAAA,UACxE,OAAO;AACN,qBAAS,SAAS;AAAA,UACnB;AAAA,QACD;AAEA,eAAO;AAAA,MACR;AAAA;AAAA;AAAA;AAAA,MAKA,eAAe,QAAQ,SAAS;AAC/B,cAAM,WAAW,EAAC,OAAO,GAAG,SAAS,CAAC,EAAC;AAGvC,YAAI,QAAQ,eAAe,QAAQ,gBAAgB,QAAQ;AAC1D,mBAAS,SAAS;AAClB,mBAAS,QAAQ,KAAK,yCAAyC;AAAA,QAChE;AAGA,YAAI,QAAQ,oBAAoB,QAAQ,mBAAmB,KAAK;AAC/D,mBAAS,SAAS;AAClB,mBAAS,QAAQ,KAAK,uBAAuB;AAAA,QAC9C;AAGA,YAAI,QAAQ,cAAc;AACzB,gBAAM,qBAAqB;AAAA,YAC1B;AAAA,YACA;AAAA,YACA;AAAA,YACA;AAAA,YACA;AAAA,YACA;AAAA,YACA;AAAA,UACD;AAEA,qBAAW,WAAW,oBAAoB;AACzC,gBAAI,QAAQ,KAAK,QAAQ,YAAY,GAAG;AACvC,uBAAS,SAAS;AAClB,uBAAS,QAAQ,KAAK,6BAA6B,QAAQ,MAAM,EAAE;AAAA,YACpE;AAAA,UACD;AAAA,QACD;AAEA,eAAO;AAAA,MACR;AAAA;AAAA;AAAA;AAAA,MAKA,gBAAgB,QAAQ;AACvB,cAAM,WAAW,EAAC,OAAO,GAAG,SAAS,CAAC,EAAC;AAEvC,YAAI;AAEH,gBAAM,UAAU,KAAK,eAAe,MAAM;AAC1C,mBAAS,QAAQ,KAAK,qBAAqB,OAAO,EAAE;AAGpD,gBAAM,kBAAkB,KAAK,4BAA4B,OAAO;AAChE,mBAAS,SAAS,gBAAgB,QAAQ;AAC1C,mBAAS,QAAQ,KAAK,GAAG,gBAAgB,OAAO;AAAA,QACjD,QAAQ;AACP,mBAAS,SAAS;AAClB,mBAAS,QAAQ,KAAK,2BAA2B;AAAA,QAClD;AAEA,eAAO;AAAA,MACR;AAAA;AAAA;AAAA;AAAA,MAKA,gBAAgB,QAAQ;AACvB,YAAI,aAAa,OAAO,YAAY;AAGpC,YAAI;AACH,2BAAa,mBAAAA,SAAY,UAAU;AAAA,QACpC,QAAQ;AAEP,qBAAW,CAAC,YAAY,KAAK,KAAK,kBAAkB;AACnD,yBAAa,WAAW,WAAW,YAAY,KAAK;AAAA,UACrD;AAAA,QACD;AAGA,qBAAa,WAAW,QAAQ,4BAA4B,EAAE;AAE9D,eAAO;AAAA,MACR;AAAA;AAAA;AAAA;AAAA,MAKA,oBAAoB,SAAS,SAAS;AACrC,cAAM,SAAS,CAAC;AAChB,cAAM,UAAU,QAAQ;AACxB,cAAM,UAAU,QAAQ;AAExB,iBAAS,IAAI,GAAG,KAAK,SAAS,KAAK;AAClC,iBAAO,CAAC,IAAI,CAAC,CAAC;AAAA,QACf;AAEA,iBAAS,IAAI,GAAG,KAAK,SAAS,KAAK;AAClC,iBAAO,CAAC,EAAE,CAAC,IAAI;AAAA,QAChB;AAEA,iBAAS,IAAI,GAAG,KAAK,SAAS,KAAK;AAClC,mBAAS,IAAI,GAAG,KAAK,SAAS,KAAK;AAClC,gBAAI,QAAQ,OAAO,IAAI,CAAC,MAAM,QAAQ,OAAO,IAAI,CAAC,GAAG;AACpD,qBAAO,CAAC,EAAE,CAAC,IAAI,OAAO,IAAI,CAAC,EAAE,IAAI,CAAC;AAAA,YACnC,OAAO;AACN,qBAAO,CAAC,EAAE,CAAC,IAAI,KAAK;AAAA,gBACnB,OAAO,IAAI,CAAC,EAAE,IAAI,CAAC,IAAI;AAAA,gBACvB,OAAO,CAAC,EAAE,IAAI,CAAC,IAAI;AAAA,gBACnB,OAAO,IAAI,CAAC,EAAE,CAAC,IAAI;AAAA,cACpB;AAAA,YACD;AAAA,UACD;AAAA,QACD;AAEA,cAAM,YAAY,KAAK,IAAI,SAAS,OAAO;AAC3C,eAAO,cAAc,IAAI,KAAK,YAAY,OAAO,OAAO,EAAE,OAAO,KAAK;AAAA,MACvE;AAAA;AAAA;AAAA;AAAA,MAKA,cAAc,QAAQ;AACrB,cAAM,UAAU,oBAAI,IAAI;AAExB,mBAAW,QAAQ,QAAQ;AAC1B,gBAAM,OAAO,KAAK,YAAY,CAAC;AAE/B,cAAK,QAAQ,MAAW,QAAQ,MAAa,QAAQ,MAAW,QAAQ,KAAU;AACjF,oBAAQ,IAAI,OAAO;AAAA,UACpB,WAAW,QAAQ,QAAW,QAAQ,MAAS;AAC9C,oBAAQ,IAAI,UAAU;AAAA,UACvB,WAAW,QAAQ,OAAW,QAAQ,MAAS;AAC9C,oBAAQ,IAAI,OAAO;AAAA,UACpB,WAAW,QAAQ,SAAW,QAAQ,OAAS;AAC9C,oBAAQ,IAAI,KAAK;AAAA,UAClB,WAAW,QAAQ,QAAW,QAAQ,MAAS;AAC9C,oBAAQ,IAAI,QAAQ;AAAA,UACrB,WAAW,QAAQ,QAAW,QAAQ,MAAS;AAC9C,oBAAQ,IAAI,QAAQ;AAAA,UACrB;AAAA,QACD;AAEA,eAAO;AAAA,MACR;AAAA;AAAA;AAAA;AAAA,MAKA,eAAe,QAAQ;AAGtB,YAAI;AACH,gBAAM,MAAM,IAAI,IAAI,UAAU,MAAM,EAAE;AACtC,iBAAO,IAAI;AAAA,QACZ,QAAQ;AACP,iBAAO;AAAA,QACR;AAAA,MACD;AAAA;AAAA;AAAA;AAAA,MAKA,wBAAwB,UAAU;AACjC,cAAM,kBAAkB,CAAC;AAEzB,YAAI,SAAS,YAAY,KAAK;AAC7B,0BAAgB,KAAK,0DAA0D;AAAA,QAChF,WAAW,SAAS,YAAY,KAAK;AACpC,0BAAgB,KAAK,kDAAkD;AAAA,QACxE,WAAW,SAAS,YAAY,KAAK;AACpC,0BAAgB,KAAK,mCAAmC;AAAA,QACzD,OAAO;AACN,0BAAgB,KAAK,iCAAiC;AAAA,QACvD;AAEA,YAAI,SAAS,OAAO;AACnB,0BAAgB,KAAK,sDAAsD;AAAA,QAC5E;AAEA,YAAI,SAAS,YAAY,KAAK,OAAK,EAAE,SAAS,OAAO,CAAC,GAAG;AACxD,0BAAgB,KAAK,sDAAsD;AAAA,QAC5E;AAEA,eAAO;AAAA,MACR;AAAA;AAAA;AAAA;AAAA,MAKA,YAAY,QAAQ,SAAS;AAC5B,cAAM,kBAAc,+BAAW,KAAK,EAClC,OAAO,KAAK,UAAU,OAAO,CAAC,EAC9B,OAAO,KAAK,EACZ,MAAM,GAAG,CAAC;AACZ,eAAO,GAAG,MAAM,IAAI,WAAW;AAAA,MAChC;AAAA,IACD;AAEA,IAAO,gCAAQ;AAAA;AAAA;;;ACxgBf;AAAA;AAAA;AAAA;AAAA;AAAA,IAAAC,kBAAe;AACf,uBAAiB;AACjB,0BAAoB;AACpB,IAAAC,sBAAyB;AACzB,IAAAC,oBAAuB;AACvB,sBAA4B;AAC5B,uBAAqB;AACrB,+CAAuB;AACvB,sBAAqB;AACrB,IAAAC,qBAAuB;AACvB,oCAAiC;AACjC,2BAAyB;AACzB,+BAA4B;AAC5B,8BAA2B;AAC3B,kCAA+B;AAC/B,qCAA+B;AAC/B,4BAA0B;AAC1B,kCAA+B;AAC/B,mBAAkB;AAClB,8BAA2B;AAC3B,mBAAkC;AAClC,sBAAoB;AACpB,uBAAqB;AACrB,qCAAmB;AACnB,uBAAqB;AACrB,qBAAoB;AACpB,2BAAyB;AACzB,yBAAuB;AACvB,2BAAqB;AACrB,uBAAsB;AACtB,wBAAuB;AACvB,sBAAe;AACf,4BAAyB;AACzB,wBAA2B;AAC3B,uBAAiC;AAlCjC;AAsCA,IAAM,aAAa,YAAY,UAAM,+BAAc,YAAY,GAAG,IAAI;AACtE,IAAM,YAAY,aAAa,iBAAAC,QAAK,QAAQ,UAAU,IAAI,oBAAAC,QAAQ,IAAI;AAGtE,IAAM,kBAAkB,cAAY;AACnC,MAAI,MAAM;AACV,SAAO,QAAQ,iBAAAD,QAAK,QAAQ,GAAG,GAAG;AACjC,QAAI,gBAAAE,QAAG,WAAW,iBAAAF,QAAK,KAAK,KAAK,cAAc,CAAC,GAAG;AAClD,aAAO;AAAA,IACR;AAEA,UAAM,iBAAAA,QAAK,QAAQ,GAAG;AAAA,EACvB;AAEA,SAAO;AACR;AAEA,IAAM,cAAc,gBAAgB,SAAS;AAG7C,IAAM,kBAAkB,KAAK,MAAM,gBAAAE,QAAG,aAAa,iBAAAF,QAAK,KAAK,aAAa,kBAAkB,GAAG,MAAM,CAAC;AAEtG,IAAM,cAAc,IAAI,IAAI,eAAe;AAG3C,IAAM,kBAAkB,YAAY;AACnC,QAAM,EAAC,SAASG,cAAY,IAAI,MAAM;AACtC,SAAOA;AACR;AAEA,IAAM,gBAAgB,YAAY;AACjC,QAAM,EAAC,SAASC,YAAU,IAAI,MAAM;AACpC,SAAOA;AACR;AAEA,IAAMC,aAAQ,4BAAS,aAAa;AAGpC,IAAM,oBACF;AAEJ,IAAM,YAAY,IAAI,yCAAAC,QAAW;AAGjC,IAAM,mBAAmB,EAAC,UAAU,UAAQ,KAAK,MAAM,KAAK,EAAC;AAG7D,IAAM,eAAe,oBAAI,IAAI;AAAA,EAC5B,CAAC,MAAM,oBAAI,IAAI,CAAC,GAAI,eAAAC,QAAQ,aAAa,CAAC,GAAI,GAAI,gBAAAC,QAAG,MAAM,CAAC,CAAE,CAAC,CAAC;AAAA,EAChE,CAAC,MAAM,oBAAI,IAAI,CAAC,GAAI,eAAAD,QAAQ,aAAa,CAAC,GAAI,GAAI,gBAAAC,QAAG,MAAM,CAAC,CAAE,CAAC,CAAC;AAAA,EAChE,CAAC,MAAM,oBAAI,IAAI,CAAC,GAAI,eAAAD,QAAQ,aAAa,CAAC,GAAI,GAAI,gBAAAC,QAAG,MAAM,CAAC,CAAE,CAAC,CAAC;AAAA,EAChE,CAAC,MAAM,oBAAI,IAAI,CAAC,GAAI,eAAAD,QAAQ,aAAa,CAAC,GAAI,GAAI,gBAAAC,QAAG,MAAM,CAAC,CAAE,CAAC,CAAC;AAAA,EAChE,CAAC,MAAM,oBAAI,IAAI,CAAC,GAAI,eAAAD,QAAQ,aAAa,CAAC,GAAI,GAAI,gBAAAC,QAAG,MAAM,CAAC,CAAE,CAAC,CAAC;AAAA,EAChE,CAAC,MAAM,oBAAI,IAAI,CAAC,GAAI,eAAAD,QAAQ,aAAa,CAAC,GAAI,GAAI,gBAAAC,QAAG,MAAM,CAAC,CAAE,CAAC,CAAC;AAAA,EAChE,CAAC,MAAM,oBAAI,IAAI,CAAC,GAAI,eAAAD,QAAQ,aAAa,CAAC,GAAI,GAAI,gBAAAC,QAAG,MAAM,CAAC,CAAE,CAAC,CAAC;AAAA,EAChE,CAAC,MAAM,oBAAI,IAAI,CAAC,GAAI,eAAAD,QAAQ,aAAa,CAAC,GAAI,GAAI,gBAAAC,QAAG,MAAM,CAAC,CAAE,CAAC,CAAC;AAAA,EAChE,CAAC,MAAM,oBAAI,IAAI,CAAC,GAAI,eAAAD,QAAQ,aAAa,CAAC,GAAI,GAAI,gBAAAC,QAAG,MAAM,CAAC,CAAE,CAAC,CAAC;AAAA,EAChE,CAAC,MAAM,oBAAI,IAAI,CAAC,GAAI,eAAAD,QAAQ,aAAa,CAAC,GAAI,GAAI,gBAAAC,QAAG,MAAM,CAAC,CAAE,CAAC,CAAC;AAAA,EAChE,CAAC,MAAM,oBAAI,IAAI,CAAC,GAAI,eAAAD,QAAQ,aAAa,CAAC,GAAI,GAAI,gBAAAC,QAAG,MAAM,CAAC,CAAE,CAAC,CAAC;AAAA,EAChE,CAAC,MAAM,oBAAI,IAAI,CAAC,GAAI,eAAAD,QAAQ,aAAa,CAAC,GAAI,GAAI,gBAAAC,QAAG,MAAM,CAAC,CAAE,CAAC,CAAC;AAAA,EAChE,CAAC,MAAM,oBAAI,IAAI,CAAC,GAAI,eAAAD,QAAQ,aAAa,CAAC,GAAI,GAAI,gBAAAC,QAAG,MAAM,CAAC,CAAE,CAAC,CAAC;AAAA,EAChE,CAAC,MAAM,oBAAI,IAAI,CAAC,GAAI,eAAAD,QAAQ,aAAa,CAAC,GAAI,GAAI,gBAAAC,QAAG,MAAM,CAAC,CAAE,CAAC,CAAC;AAAA,EAChE,CAAC,MAAM,oBAAI,IAAI,CAAC,GAAI,eAAAD,QAAQ,aAAa,CAAC,GAAI,GAAI,gBAAAC,QAAG,MAAM,CAAC,CAAE,CAAC,CAAC;AAAA,EAChE,CAAC,MAAM,oBAAI,IAAI,CAAC,GAAI,eAAAD,QAAQ,aAAa,CAAC,GAAI,GAAI,gBAAAC,QAAG,MAAM,CAAC,CAAE,CAAC,CAAC;AAAA,EAChE,CAAC,MAAM,oBAAI,IAAI,CAAC,GAAI,eAAAD,QAAQ,aAAa,CAAC,GAAI,GAAI,gBAAAC,QAAG,MAAM,CAAC,CAAE,CAAC,CAAC;AAAA,EAChE,CAAC,MAAM,oBAAI,IAAI,CAAC,GAAI,eAAAD,QAAQ,aAAa,CAAC,GAAI,GAAI,gBAAAC,QAAG,MAAM,CAAC,CAAE,CAAC,CAAC;AAAA,EAChE,CAAC,MAAM,oBAAI,IAAI,CAAC,GAAI,eAAAD,QAAQ,aAAa,CAAC,GAAI,GAAI,gBAAAC,QAAG,MAAM,CAAC,CAAE,CAAC,CAAC;AAAA,EAChE,CAAC,MAAM,oBAAI,IAAI,CAAC,GAAI,eAAAD,QAAQ,aAAa,CAAC,GAAI,GAAI,gBAAAC,QAAG,MAAM,CAAC,CAAE,CAAC,CAAC;AAAA,EAChE,CAAC,MAAM,oBAAI,IAAI,CAAC,GAAI,eAAAD,QAAQ,aAAa,CAAC,GAAI,GAAI,gBAAAC,QAAG,MAAM,CAAC,CAAE,CAAC,CAAC;AAAA,EAChE,CAAC,MAAM,oBAAI,IAAI,CAAC,GAAI,eAAAD,QAAQ,aAAa,CAAC,GAAI,GAAI,gBAAAC,QAAG,MAAM,CAAC,CAAE,CAAC,CAAC;AAAA,EAChE,CAAC,MAAM,oBAAI,IAAI,CAAC,GAAI,eAAAD,QAAQ,aAAa,CAAC,GAAI,GAAI,gBAAAC,QAAG,MAAM,CAAC,CAAE,CAAC,CAAC;AAAA,EAChE,CAAC,MAAM,oBAAI,IAAI,CAAC,GAAI,eAAAD,QAAQ,aAAa,CAAC,GAAI,GAAI,gBAAAC,QAAG,MAAM,CAAC,CAAE,CAAC,CAAC;AAAA,EAChE,CAAC,MAAM,oBAAI,IAAI,CAAC,GAAI,eAAAD,QAAQ,aAAa,CAAC,GAAI,GAAI,gBAAAC,QAAG,MAAM,CAAC,CAAE,CAAC,CAAC;AAAA,EAChE,CAAC,MAAM,oBAAI,IAAI,CAAC,GAAI,eAAAD,QAAQ,aAAa,CAAC,GAAI,GAAI,gBAAAC,QAAG,MAAM,CAAC,CAAE,CAAC,CAAC;AAAA,EAChE,CAAC,MAAM,oBAAI,IAAI,CAAC,GAAI,eAAAD,QAAQ,aAAa,CAAC,GAAI,GAAI,gBAAAC,QAAG,MAAM,CAAC,CAAE,CAAC,CAAC;AAAA,EAChE,CAAC,MAAM,oBAAI,IAAI,CAAC,GAAI,eAAAD,QAAQ,aAAa,CAAC,GAAI,GAAI,gBAAAC,QAAG,MAAM,CAAC,CAAE,CAAC,CAAC;AAAA,EAChE,CAAC,MAAM,oBAAI,IAAI,CAAC,GAAI,eAAAD,QAAQ,aAAa,CAAC,GAAI,GAAI,gBAAAC,QAAG,MAAM,CAAC,CAAE,CAAC,CAAC;AAAA,EAChE,CAAC,MAAM,oBAAI,IAAI,CAAC,GAAI,eAAAD,QAAQ,aAAa,CAAC,GAAI,GAAI,gBAAAC,QAAG,OAAO,CAAC,CAAE,CAAC,CAAC;AAAA,EACjE,CAAC,MAAM,oBAAI,IAAI,CAAC,GAAI,eAAAD,QAAQ,aAAa,CAAC,GAAI,GAAI,gBAAAC,QAAG,MAAM,CAAC,CAAE,CAAC,CAAC;AAAA,EAChE,CAAC,MAAM,oBAAI,IAAI,CAAC,GAAI,eAAAD,QAAQ,aAAa,CAAC,GAAI,GAAI,gBAAAC,QAAG,MAAM,CAAC,CAAE,CAAC,CAAC;AAAA,EAChE,CAAC,MAAM,oBAAI,IAAI,CAAC,GAAI,eAAAD,QAAQ,aAAa,CAAC,GAAI,GAAI,gBAAAC,QAAG,MAAM,CAAC,CAAE,CAAC,CAAC;AAAA,EAChE,CAAC,MAAM,oBAAI,IAAI,CAAC,GAAI,eAAAD,QAAQ,aAAa,CAAC,GAAI,GAAI,gBAAAC,QAAG,MAAM,CAAC,CAAE,CAAC,CAAC;AAAA,EAChE,CAAC,MAAM,oBAAI,IAAI,CAAC,GAAI,eAAAD,QAAQ,aAAa,CAAC,GAAI,GAAI,gBAAAC,QAAG,MAAM,CAAC,CAAE,CAAC,CAAC;AAAA,EAChE,CAAC,MAAM,oBAAI,IAAI,CAAC,GAAI,eAAAD,QAAQ,aAAa,CAAC,GAAI,GAAI,gBAAAC,QAAG,MAAM,CAAC,CAAE,CAAC,CAAC;AAAA,EAChE,CAAC,MAAM,oBAAI,IAAI,CAAC,GAAI,eAAAD,QAAQ,aAAa,CAAC,GAAI,GAAI,gBAAAC,QAAG,MAAM,CAAC,CAAE,CAAC,CAAC;AAAA,EAChE,CAAC,MAAM,oBAAI,IAAI,CAAC,GAAI,eAAAD,QAAQ,aAAa,CAAC,GAAI,GAAI,gBAAAC,QAAG,MAAM,CAAC,CAAE,CAAC,CAAC;AAAA,EAChE,CAAC,MAAM,oBAAI,IAAI,CAAC,GAAI,eAAAD,QAAQ,aAAa,CAAC,GAAI,GAAI,gBAAAC,QAAG,MAAM,CAAC,CAAE,CAAC,CAAC;AAAA,EAChE,CAAC,MAAM,oBAAI,IAAI,CAAC,GAAI,eAAAD,QAAQ,aAAa,CAAC,GAAI,GAAI,gBAAAC,QAAG,MAAM,CAAC,CAAE,CAAC,CAAC;AAAA,EAChE,CAAC,MAAM,oBAAI,IAAI,CAAC,GAAI,eAAAD,QAAQ,aAAa,CAAC,GAAI,GAAI,gBAAAC,QAAG,MAAM,CAAC,CAAE,CAAC,CAAC;AAAA,EAChE,CAAC,MAAM,oBAAI,IAAI,CAAC,GAAI,eAAAD,QAAQ,aAAa,CAAC,GAAI,GAAI,gBAAAC,QAAG,MAAM,CAAC,CAAE,CAAC,CAAC;AACjE,CAAC;AAGD,IAAM,4BAA4B;AAGlC,IAAM,gBAAgB;AAAA,EACrB;AAAA;AAAA,EACA;AAAA;AAAA,EACA;AAAA;AAAA,EACA;AAAA;AACD;AAGA,IAAM,qBAAqB;AAAA,EAC1B;AAAA;AAAA,EACA;AAAA;AAAA,EACA;AAAA;AACD;AAGA,IAAM,0BAAsB,yBAAAC,SAAgB,EAAC,OAAO,MAAK,CAAC;AAC1D,IAAM,oBAAgB,mBAAAC,SAAW,EAAC,OAAO,MAAK,CAAC;AAC/C,IAAM,oBAAgB,wBAAAC,SAAe,EAAC,OAAO,MAAK,CAAC;AACnD,IAAM,iBAAa,gBAAAC,SAAQ,EAAC,OAAO,MAAK,CAAC;AACzC,IAAM,kBAAc,sBAAAC,SAAa,EAAC,OAAO,MAAK,CAAC;AAC/C,IAAM,sBAAkB,qBAAAC,SAAa,EAAC,OAAO,MAAK,CAAC;AACnD,IAAM,kBAAc,iBAAAC,SAAS,EAAC,OAAO,MAAK,CAAC;AAC3C,IAAM,wBAAoB,wBAAAC,SAAe,EAAC,OAAO,MAAK,CAAC;AACvD,IAAM,yBAAyB,4BAAAC;AAE/B,IAAM,cAAN,MAAkB;AAAA,EACjB,YAAY,UAAU,CAAC,GAAG;AACzB,SAAK,SAAS;AAAA;AAAA,MAEb,sBAAsB;AAAA,MACtB,0BAA0B;AAAA,MAC1B,SAAS;AAAA,MACT,oBAAoB,CAAC,IAAI;AAAA,MACzB,8BAA8B;AAAA,MAC9B,kCAAkC;AAAA;AAAA,MAGlC,OAAO;AAAA,MACP,QAAQ;AAAA,MACR,UAAU;AAAA,QACT,gBAAgB;AAAA,QAChB,oBAAoB;AAAA,QACpB,SAAS;AAAA,QACT,WAAW;AAAA,QACX,UAAU;AAAA,QACV,iBAAiB;AAAA,QACjB,cAAc;AAAA,QACd,eAAe;AAAA,QACf,YAAY;AAAA,MACb;AAAA,MACA,YAAY;AAAA,MACZ,cAAc;AAAA,MACd,GAAG;AAAA,IACJ;AAGA,SAAK,aAAa;AAClB,SAAK,WAAW;AAChB,SAAK,gBAAgB;AAGrB,SAAK,eAAe,oBAAI,IAAI;AAG5B,SAAK,UAAU;AAAA,MACd,YAAY;AAAA,MACZ,aAAa;AAAA,MACb,cAAc;AAAA,IACf;AAGA,yBAAAC,SAAS,IAAI;AAAA,EACd;AAAA,EAEA,MAAM,uBAAuB;AAC5B,QAAI,KAAK,YAAY;AACpB;AAAA,IACD;AAEA,QAAI;AACH,UAAI,KAAK,OAAO,YAAY;AAC3B,aAAK,aAAa,IAAI,mBAAAC,QAAW,KAAK,OAAO,UAAU;AAAA,MACxD,OAAO;AACN,cAAM,iBAAiB,MAAM,cAAc;AAC3C,aAAK,aAAa,IAAI,mBAAAA,QAAW,cAAc;AAAA,MAChD;AAGA,WAAK,WAAW,YAAY,SAAU,QAAQ;AAC7C,YAAI,OAAO,WAAW,UAAU;AAC/B,iBAAO,OAAO,MAAM,KAAK;AAAA,QAC1B;AAEA,eAAO,MAAM,QAAQ,MAAM,IAAI,SAAS,CAAC;AAAA,MAC1C;AAAA,IACD,SAAS,OAAO;AACf,MAAAd,OAAM,oCAAoC,KAAK;AAE/C,WAAK,aAAa,IAAI,mBAAAc,QAAW;AAAA,IAClC;AAAA,EACD;AAAA;AAAA,EAGA,MAAM,yBAAyB;AAC9B,QAAI,KAAK,gBAAgB,KAAK,aAAa,OAAO,GAAG;AACpD;AAAA,IACD;AAEA,QAAI;AACH,YAAMhB,gBAAe,KAAK,OAAO,gBAAgB,MAAM,gBAAgB;AAGvE,UAAIA,yBAAwB,KAAK;AAChC,aAAK,eAAeA;AAAA,MACrB,WAAW,OAAOA,kBAAiB,YAAYA,kBAAiB,MAAM;AACrE,aAAK,eAAe,IAAI,IAAI,OAAO,QAAQA,aAAY,CAAC;AAAA,MACzD,OAAO;AACN,cAAM,IAAI,MAAM,6BAA6B;AAAA,MAC9C;AAAA,IACD,SAAS,OAAO;AACf,MAAAE,OAAM,sCAAsC,KAAK;AAEjD,WAAK,eAAe,oBAAI,IAAI;AAG5B,YAAM,oBAAoB;AAAA,QACzB,GAAG;AAAA,QACH,IAAI;AAAA,QACJ,GAAG;AAAA,QACH,GAAG;AAAA,QACH,MAAM;AAAA,QACN,IAAI;AAAA,QACJ,GAAG;AAAA,QACH,GAAG;AAAA,MACJ;AAEA,iBAAW,CAAC,MAAM,WAAW,KAAK,OAAO,QAAQ,iBAAiB,GAAG;AACpE,aAAK,aAAa,IAAI,MAAM,WAAW;AAAA,MACxC;AAAA,IACD;AAAA,EACD;AAAA;AAAA,EAGA,kBAAkB;AACjB,SAAK,aAAa,oBAAI,IAAI;AAC1B,SAAK,WAAW,oBAAI,IAAI;AAAA,EACzB;AAAA;AAAA,EAGA,MAAM,gBAAgB,MAAM;AAC3B,QAAI,CAAC,KAAK,UAAU;AACnB,UAAI;AACH,aAAK,WAAW,MAAM,IAAI,gBAAAe,QAAS,EAAE,KAAK,KAAK,OAAO,QAAQ;AAAA,MAC/D,SAAS,OAAO;AACf,QAAAf,OAAM,mCAAmC,KAAK;AAC9C,eAAO,CAAC;AAAA,MACT;AAAA,IACD;AAEA,UAAM,UAAU,CAAC;AACjB,UAAM,cAAc,KAAK,eAAe,CAAC;AAEzC,eAAW,cAAc,aAAa;AACrC,UAAI;AACH,YAAI,WAAW,eAAW,iBAAAgB,SAAS,WAAW,OAAO,GAAG;AAEvD,gBAAM,aAAa,MAAM,QAAQ,KAAK;AAAA,YACrC,KAAK,SAAS,WAAW,WAAW,OAAO;AAAA,YAC3C,IAAI,QAAQ,CAAC,UAAU,WAAW;AACjC,yBAAW,MAAM,OAAO,IAAI,MAAM,oBAAoB,CAAC,GAAG,KAAK,OAAO,OAAO;AAAA,YAC9E,CAAC;AAAA,UACF,CAAC;AAED,cAAI,WAAW,YAAY;AAC1B,oBAAQ,KAAK;AAAA,cACZ,UAAU,WAAW,YAAY;AAAA,cACjC,OAAO,WAAW,WAAW,CAAC,eAAe;AAAA,cAC7C,MAAM;AAAA,YACP,CAAC;AAAA,UACF;AAAA,QACD;AAAA,MACD,SAAS,OAAO;AACf,QAAAhB,OAAM,qBAAqB,KAAK;AAAA,MACjC;AAAA,IACD;AAEA,WAAO;AAAA,EACR;AAAA;AAAA,EAGA,MAAM,gBAAgB,MAAM;AAC3B,UAAM,UAAU,CAAC;AACjB,UAAM,cAAc,KAAK,eAAe,CAAC;AACzC,UAAM,cAAc,KAAK,QAAQ;AACjC,UAAM,cAAc,KAAK,QAAQ;AAGjC,UAAM,cAAc;AAAA,MACnB;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACD;AAGA,UAAM,qBAAqB;AAAA,MAC1B;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACD;AAGA,UAAM,aAAa;AAAA,MAClB;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACD;AAGA,UAAM,gBAAgB,CAAC,iBAAiB,eAAe,iBAAiB,iBAAiB;AAGzF,QAAI,aAAa,cAAc,MAAM;AAGrC,QAAI,KAAK,eAAe,MAAM,QAAQ,KAAK,WAAW,GAAG;AACxD,iBAAW,cAAc,KAAK,aAAa;AAC1C,YAAI,WAAW,MAAM;AACpB,wBAAc,MAAM,WAAW;AAAA,QAChC;AAAA,MACD;AAAA,IACD;AAGA,eAAW,WAAW,aAAa;AAClC,UAAI,QAAQ,KAAK,UAAU,GAAG;AAC7B,gBAAQ,KAAK;AAAA,UACZ,MAAM;AAAA,UACN,SAAS;AAAA,UACT,aAAa;AAAA,QACd,CAAC;AACD;AAAA,MACD;AAAA,IACD;AAGA,eAAW,WAAW,oBAAoB;AACzC,UAAI,QAAQ,KAAK,UAAU,GAAG;AAC7B,gBAAQ,KAAK;AAAA,UACZ,MAAM;AAAA,UACN,SAAS;AAAA,UACT,aAAa;AAAA,QACd,CAAC;AACD;AAAA,MACD;AAAA,IACD;AAGA,eAAW,WAAW,YAAY;AACjC,UAAI,QAAQ,KAAK,UAAU,GAAG;AAC7B,gBAAQ,KAAK;AAAA,UACZ,MAAM;AAAA,UACN,SAAS;AAAA,UACT,aAAa;AAAA,QACd,CAAC;AACD;AAAA,MACD;AAAA,IACD;AAGA,eAAW,WAAW,eAAe;AACpC,UAAI,QAAQ,KAAK,UAAU,GAAG;AAC7B,gBAAQ,KAAK;AAAA,UACZ,MAAM;AAAA,UACN,SAAS;AAAA,UACT,aAAa;AAAA,QACd,CAAC;AACD;AAAA,MACD;AAAA,IACD;AAGA,eAAW,cAAc,aAAa;AACrC,UAAI,WAAW,UAAU;AACxB,cAAM,gBAAY,sBAAAiB,SAAc,WAAW,QAAQ,EAAE,YAAY;AAGjE,cAAM,kBAAkB,CAAC,OAAO,OAAO,OAAO,OAAO,OAAO,OAAO,KAAK;AAGxE,cAAM,wBAAwB,CAAC,QAAQ,QAAQ,QAAQ,QAAQ,QAAQ,QAAQ,MAAM;AAGrF,cAAM,yBAAyB,CAAC,OAAO,OAAO,OAAO,OAAO,OAAO,OAAO,OAAO,KAAK;AAEtF,YAAI,gBAAgB,SAAS,SAAS,GAAG;AACxC,kBAAQ,KAAK;AAAA,YACZ,MAAM;AAAA,YACN,SAAS;AAAA,YACT,UAAU,WAAW;AAAA,YACrB,aAAa,qCAAqC,SAAS;AAAA,UAC5D,CAAC;AAAA,QACF,WAAW,sBAAsB,SAAS,SAAS,GAAG;AACrD,kBAAQ,KAAK;AAAA,YACZ,MAAM;AAAA,YACN,SAAS;AAAA,YACT,UAAU,WAAW;AAAA,YACrB,aAAa,0CAA0C,SAAS;AAAA,UACjE,CAAC;AAAA,QACF,WAAW,uBAAuB,SAAS,SAAS,GAAG;AACtD,kBAAQ,KAAK;AAAA,YACZ,MAAM;AAAA,YACN,SAAS;AAAA,YACT,UAAU,WAAW;AAAA,YACrB,aAAa,2CAA2C,SAAS;AAAA,YACjE,MAAM;AAAA,UACP,CAAC;AAAA,QACF;AAGA,YAAI,cAAc,SAAS,WAAW,eAAW,iBAAAD,SAAS,WAAW,OAAO,GAAG;AAC9E,cAAI;AACH,kBAAM,aAAa,WAAW,QAAQ,SAAS,QAAQ;AAEvD,gBAAI,WAAW,SAAS,aAAa,KAAK,WAAW,SAAS,KAAK,GAAG;AACrE,sBAAQ,KAAK;AAAA,gBACZ,MAAM;AAAA,gBACN,SAAS;AAAA,gBACT,UAAU,WAAW;AAAA,gBACrB,aAAa;AAAA,gBACb,MAAM;AAAA,cACP,CAAC;AAAA,YACF;AAAA,UACD,SAAS,OAAO;AACf,YAAAhB,OAAM,mCAAmC,KAAK;AAAA,UAC/C;AAAA,QACD;AAAA,MACD;AAAA,IACD;AAEA,WAAO;AAAA,EACR;AAAA;AAAA,EAGA,MAAM,mBAAmB,MAAM;AAC9B,UAAM,UAAU,CAAC;AACjB,UAAM,cAAc,KAAK,QAAQ;AACjC,UAAM,cAAc,KAAK,QAAQ;AACjC,UAAM,aAAa,cAAc,MAAM;AAEvC,eAAW,WAAW,oBAAoB;AACzC,YAAM,UAAU,WAAW,MAAM,OAAO;AACxC,UAAI,SAAS;AACZ,mBAAW,SAAS,SAAS;AAE5B,cAAI,KAAK,gBAAgB,KAAK,GAAG;AAChC,oBAAQ,KAAK;AAAA,cACZ,MAAM;AAAA,cACN,MAAM;AAAA,cACN,aAAa;AAAA,YACd,CAAC;AAAA,UACF;AAAA,QACD;AAAA,MACD;AAAA,IACD;AAEA,WAAO;AAAA,EACR;AAAA;AAAA,EAGA,gBAAgBL,OAAM;AAErB,UAAM,WAAW;AAAA,MAChB;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MAC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",
6
+ "names": ["cryptoRandomString", "import_node_util", "import_node_fs", "debug", "NaiveBayes", "confusables", "import_node_fs", "import_node_crypto", "import_node_util", "import_naivebayes", "path", "process", "fs", "replacements", "classifier", "debug", "AFHConvert", "natural", "sw", "creditCardRegex", "phoneRegex", "emailRegexSafe", "ipRegex", "urlRegexSafe", "bitcoinRegex", "macRegex", "hexaColorRegex", "floatingPointRegex", "autoBind", "NaiveBayes", "ClamScan", "isBuffer", "fileExtension", "normalizeUrl", "superagent", "isSANB", "parseTldts", "striptags", "lande", "expandContractions", "snowball", "escapeStringRegexp", "arrayJoinConjunction", "EnhancedIDNDetector", "detected"]
7
7
  }