1import { ema, rsi, macd } from "/src/lib/indicators.ts"; 2export const DEFAULT_SETTINGS = { 3 timeframe: "15m", 4 candleLimit: 300, 5 macdFast: 12, 6 macdSlow: 26, 7 macdSignal: 9, 8 useEmaFilter: true, 9 emaPeriod: 200, 10 useRsiFilter: true, 11 rsiPeriod: 14, 12 rsiLongMax: 70, 13 rsiShortMin: 30, 14 useVolumeFilter: false, 15 volumePeriod: 20, 16 minVolumeRatio: 1, 17 confirmClosedCandle: true, 18 minHistogramPercent: 0.05, 19 onlyTradingSymbols: true, 20 min24hVolumeUsdt: 0, 21 maxResults: 0, 22 symbol: "ALL", 23 maxWorkers: 20 24}; 25const BINANCE_BASE_URL = "https://fapi.binance.com"; 26async function fetchJson(url) { 27 const res = await fetch(url); 28 if (!res.ok) throw new Error(`HTTP ${res.status} for ${url}`); 29 return res.json(); 30} 31export async function getUsdtPerpetualSymbols(settings) { 32 const data = await fetchJson(`${BINANCE_BASE_URL}/fapi/v1/exchangeInfo`); 33 const symbols = []; 34 for (const item of data.symbols) { 35 if (item.quoteAsset !== "USDT") continue; 36 if (item.contractType !== "PERPETUAL") continue; 37 if (settings.onlyTradingSymbols && item.status !== "TRADING") continue; 38 symbols.push(item.symbol); 39 } 40 return symbols.sort(); 41} 42export async function get24hVolume() { 43 const data = await fetchJson(`${BINANCE_BASE_URL}/fapi/v1/ticker/24hr`); 44 const result = {}; 45 for (const item of data) { 46 const v = Number(item.quoteVolume); 47 result[item.symbol] = isNaN(v) ? 0 : v; 48 } 49 return result; 50} 51export async function getKlines(symbol, settings) { 52 const url = `${BINANCE_BASE_URL}/fapi/v1/klines?symbol=${symbol}&interval=${settings.timeframe}&limit=${settings.candleLimit}`; 53 const data = await fetchJson(url); 54 return data.map((row) => ({ 55 openTime: row[0], 56 open: Number(row[1]), 57 high: Number(row[2]), 58 low: Number(row[3]), 59 close: Number(row[4]), 60 volume: Number(row[5]), 61 closeTime: row[6], 62 quoteVolume: Number(row[7]) 63 })); 64} 65function histogramState(h) { 66 const h0 = h[h.length - 1]; 67 const h1 = h[h.length - 2]; 68 const h2 = h[h.length - 3]; 69 if (h0 > 0) { 70 if (h0 > h1 && h1 > h2) return "POSITIVE_EXPANDING"; 71 if (h0 < h1 && h1 < h2) return "POSITIVE_CONTRACTING"; 72 return "POSITIVE_MIXED"; 73 } 74 if (h0 < 0) { 75 if (h0 < h1 && h1 < h2) return "NEGATIVE_EXPANDING"; 76 if (h0 > h1 && h1 > h2) return "NEGATIVE_CONTRACTING"; 77 return "NEGATIVE_MIXED"; 78 } 79 return "ZERO"; 80} 81function classifySignal(macdVal, signalVal, prevMacd, prevSignal, histState) { 82 const bullishCross = prevMacd <= prevSignal && macdVal > signalVal; 83 const bearishCross = prevMacd >= prevSignal && macdVal < signalVal; 84 const aboveZero = macdVal > 0; 85 const belowZero = macdVal < 0; 86 if (bullishCross && aboveZero) { 87 return histState === "POSITIVE_EXPANDING" ? "STRONG_LONG" : "LONG"; 88 } 89 if (bullishCross && belowZero) return "EARLY_LONG"; 90 if (bearishCross && belowZero) { 91 return histState === "NEGATIVE_EXPANDING" ? "STRONG_SHORT" : "SHORT"; 92 } 93 if (bearishCross && aboveZero) return "EARLY_SHORT"; 94 if (macdVal > signalVal && aboveZero) { 95 if (histState === "POSITIVE_EXPANDING") return "LONG_MOMENTUM"; 96 if (histState === "POSITIVE_CONTRACTING") return "LONG_WEAKENING"; 97 return "LONG_HOLD"; 98 } 99 if (macdVal < signalVal && belowZero) { 100 if (histState === "NEGATIVE_EXPANDING") return "SHORT_MOMENTUM"; 101 if (histState === "NEGATIVE_CONTRACTING") return "SHORT_WEAKENING"; 102 return "SHORT_HOLD"; 103 } 104 if (macdVal > signalVal) return "BULLISH_TRANSITION"; 105 if (macdVal < signalVal) return "BEARISH_TRANSITION"; 106 return "NEUTRAL"; 107} 108const LONG_SIGNALS = [ 109 "STRONG_LONG", 110 "LONG", 111 "EARLY_LONG", 112 "LONG_MOMENTUM" 113]; 114const SHORT_SIGNALS = [ 115 "STRONG_SHORT", 116 "SHORT", 117 "EARLY_SHORT", 118 "SHORT_MOMENTUM" 119]; 120export const SIGNAL_PRIORITY = { 121 STRONG_LONG: 10, 122 LONG: 9, 123 EARLY_LONG: 8, 124 LONG_MOMENTUM: 7, 125 LONG_HOLD: 6, 126 STRONG_SHORT: 10, 127 SHORT: 9, 128 EARLY_SHORT: 8, 129 SHORT_MOMENTUM: 7, 130 SHORT_HOLD: 6, 131 BULLISH_TRANSITION: 4, 132 BEARISH_TRANSITION: 4, 133 NEUTRAL: 0, 134 LONG_WEAKENING: 2, 135 SHORT_WEAKENING: 2, 136 FILTERED_EMA: 0, 137 FILTERED_RSI: 0, 138 FILTERED_VOLUME: 0, 139 FILTERED_HISTOGRAM: 0 140}; 141export const MEANINGFUL_SIGNALS = [ 142 "STRONG_LONG", 143 "LONG", 144 "EARLY_LONG", 145 "LONG_MOMENTUM", 146 "STRONG_SHORT", 147 "SHORT", 148 "EARLY_SHORT", 149 "SHORT_MOMENTUM" 150]; 151export async function analyzeSymbol(symbol, settings) { 152 try { 153 let klines = await getKlines(symbol, settings); 154 const minCandles = Math.max( 155 settings.macdSlow, 156 settings.emaPeriod, 157 settings.rsiPeriod, 158 50 159 ) + 10; 160 if (klines.length < minCandles) return null; 161 if (settings.confirmClosedCandle) { 162 klines = klines.slice(0, -1); 163 } 164 if (klines.length < 3) return null; 165 const closes = klines.map((k) => k.close); 166 const volumes = klines.map((k) => k.volume); 167 const { macd: macdLine, signal: signalLine, histogram } = macd( 168 closes, 169 settings.macdFast, 170 settings.macdSlow, 171 settings.macdSignal 172 ); 173 const emaArr = ema(closes, settings.emaPeriod); 174 const rsiArr = rsi(closes, settings.rsiPeriod); 175 const i = klines.length - 1; 176 const macdVal = macdLine[i]; 177 const signalVal = signalLine[i]; 178 const prevMacd = macdLine[i - 1]; 179 const prevSignal = signalLine[i - 1]; 180 const hist = histogram[i]; 181 const histPrev = histogram[i - 1]; 182 const price = closes[i]; 183 const rsiVal = rsiArr[i]; 184 const emaVal = emaArr[i]; 185 if ([macdVal, signalVal, prevMacd, prevSignal, hist, histPrev, rsiVal, emaVal].some(isNaN)) return null; 186 const histState = histogramState(histogram.slice(-3)); 187 let signal = classifySignal( 188 macdVal, 189 signalVal, 190 prevMacd, 191 prevSignal, 192 histState 193 ); 194 if (settings.useEmaFilter) { 195 if (LONG_SIGNALS.includes(signal) && !(price > emaVal)) { 196 signal = "FILTERED_EMA"; 197 } else if (SHORT_SIGNALS.includes(signal) && !(price < emaVal)) { 198 signal = "FILTERED_EMA"; 199 } 200 } 201 if (settings.useRsiFilter && signal !== "FILTERED_EMA") { 202 if (LONG_SIGNALS.includes(signal) && rsiVal > settings.rsiLongMax) { 203 signal = "FILTERED_RSI"; 204 } else if (SHORT_SIGNALS.includes(signal) && rsiVal < settings.rsiShortMin) { 205 signal = "FILTERED_RSI"; 206 } 207 } 208 if (settings.useVolumeFilter && !signal.startsWith("FILTERED")) {
209 const recentAvg = volumes.slice(-settings.volumePeriod - 1, -1).reduce((a, b) => a + b, 0) / settings.volumePeriod; 210 if (recentAvg > 0 && volumes[i] / recentAvg < settings.minVolumeRatio) { 211 signal = "FILTERED_VOLUME"; 212 } 213 } 214 if (settings.minHistogramPercent > 0 && !signal.startsWith("FILTERED")) { 215 const pct = Math.abs(hist) / price * 100; 216 if (pct < settings.minHistogramPercent) signal = "FILTERED_HISTOGRAM"; 217 } 218 const macdState = macdVal > signalVal ? "BULLISH" : macdVal < signalVal ? "BEARISH" : "NEUTRAL"; 219 const zeroState = macdVal > 0 ? "ABOVE_ZERO" : macdVal < 0 ? "BELOW_ZERO" : "AT_ZERO"; 220 return { 221 symbol, 222 timeframe: settings.timeframe, 223 candleTime: klines[i].closeTime, 224 price, 225 macd: macdVal, 226 signal: signalVal, 227 histogram: hist, 228 histogramChange: hist - histPrev, 229 histogramPct: hist / price * 100, 230 macdState, 231 zeroState, 232 histogramState: histState, 233 rsi: rsiVal, 234 ema: emaVal, 235 emaTrend: price > emaVal ? "ABOVE_EMA" : "BELOW_EMA", 236 signalType: signal 237 }; 238 } catch { 239 return null; 240 } 241} 242export async function scanAll(settings, onProgress, signal) { 243 let symbols = await getUsdtPerpetualSymbols(settings); 244 if (settings.min24hVolumeUsdt > 0) { 245 const volumes = await get24hVolume(); 246 symbols = symbols.filter((s) => (volumes[s] ?? 0) >= settings.min24hVolumeUsdt); 247 } 248 const total = symbols.length; 249 let completed = 0; 250 const allResults = []; 251 const meaningful = []; 252 const queue = [...symbols]; 253 const workers = []; 254 const concurrency = Math.min(settings.maxWorkers, 15); 255 const runNext = async () => { 256 while (queue.length > 0 && !signal.cancelled) { 257 const sym = queue.shift(); 258 const result = await analyzeSymbol(sym, settings); 259 completed++; 260 if (result) { 261 allResults.push(result); 262 if (MEANINGFUL_SIGNALS.includes(result.signalType)) { 263 meaningful.push(result); 264 meaningful.sort( 265 (a, b) => SIGNAL_PRIORITY[b.signalType] - SIGNAL_PRIORITY[a.signalType] 266 ); 267 } 268 } 269 onProgress({ completed, total, meaningful: [...meaningful] }); 270 } 271 }; 272 for (let i = 0; i < concurrency; i++) workers.push(runNext()); 273 await Promise.all(workers); 274 allResults.sort( 275 (a, b) => SIGNAL_PRIORITY[b.signalType] - SIGNAL_PRIORITY[a.signalType] 276 ); 277 return allResults; 278} 279 280//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIm1hY2RTY2FubmVyLnRzIl0sInNvdXJjZXNDb250ZW50IjpbIi8vIEJpbmFuY2UgVVNEVC1NIHBlcnBldHVhbCBNQUNEIHNjYW5uZXIg4oCUIFR5cGVTY3JpcHQgcG9ydFxuLy8gRmV0Y2hlcyBwdWJsaWMgbWFya2V0IGRhdGEgZnJvbSBCaW5hbmNlIEZ1dHVyZXMgQVBJIChubyBrZXkgcmVxdWlyZWQpXG4vLyBhbmQgY2xhc3NpZmllcyBNQUNEIHNpZ25hbHMgd2l0aCB0aGUgc2FtZSBsb2dpYyBhcyB0aGUgUHl0aG9uIHNjYW5uZXIuXG5cbmltcG9ydCB7IGVtYSwgcnNpLCBtYWNkIH0gZnJvbSAnLi9pbmRpY2F0b3JzJztcblxuZXhwb3J0IGludGVyZmFjZSBTY2FubmVyU2V0dGluZ3Mge1xuICB0aW1lZnJhbWU6IHN0cmluZztcbiAgY2FuZGxlTGltaXQ6IG51bWJlcjtcbiAgbWFjZEZhc3Q6IG51bWJlcjtcbiAgbWFjZFNsb3c6IG51bWJlcjtcbiAgbWFjZFNpZ25hbDogbnVtYmVyO1xuICB1c2VFbWFGaWx0ZXI6IGJvb2xlYW47XG4gIGVtYVBlcmlvZDogbnVtYmVyO1xuICB1c2VSc2lGaWx0ZXI6IGJvb2xlYW47XG4gIHJzaVBlcmlvZDogbnVtYmVyO1xuICByc2lMb25nTWF4OiBudW1iZXI7XG4gIHJzaVNob3J0TWluOiBudW1iZXI7XG4gIHVzZVZvbHVtZUZpbHRlcjogYm9vbGVhbjtcbiAgdm9sdW1lUGVyaW9kOiBudW1iZXI7XG4gIG1pblZvbHVtZVJhdGlvOiBudW1iZXI7XG4gIGNvbmZpcm1DbG9zZWRDYW5kbGU6IGJvb2xlYW47XG4gIG1pbkhpc3RvZ3JhbVBlcmNlbnQ6IG51bWJlcjtcbiAgb25seVRyYWRpbmdTeW1ib2xzOiBib29sZWFuO1xuICBtaW4yNGhWb2x1bWVVc2R0OiBudW1iZXI7XG4gIG1heFJlc3VsdHM6IG51bWJlcjtcbiAgc3ltYm9sOiBzdHJpbmc7IC8vIFwiQUxMXCIgb3IgYSBzaW5nbGUgc3ltYm9sIGxpa2UgXCJCVENVU0RUXCJcbiAgbWF4V29ya2VyczogbnVtYmVyO1xufVxuXG5leHBvcnQgY29uc3QgREVGQVVMVF9TRVRUSU5HUzogU2Nhbm5lclNldHRpbmdzID0ge1xuICB0aW1lZnJhbWU6ICcxNW0nLFxuICBjYW5kbGVMaW1pdDogMzAwLFxuICBtYWNkRmFzdDogMTIsXG4gIG1hY2RTbG93OiAyNixcbiAgbWFjZFNpZ25hbDogOSxcbiAgdXNlRW1hRmlsdGVyOiB0cnVlLFxuICBlbWFQZXJpb2Q6IDIwMCxcbiAgdXNlUnNpRmlsdGVyOiB0cnVlLFxuICByc2lQZXJpb2Q6IDE0LFxuICByc2lMb25nTWF4OiA3MCxcbiAgcnNpU2hvcnRNaW46IDMwLFxuICB1c2VWb2x1bWVGaWx0ZXI6IGZhbHNlLFxuICB2b2x1bWVQZXJpb2Q6IDIwLFxuICBtaW5Wb2x1bWVSYXRpbzogMS4wLFxuICBjb25maXJtQ2xvc2VkQ2FuZGxlOiB0cnVlLFxuICBtaW5IaXN0b2dyYW1QZXJjZW50OiAwLjA1LFxuICBvbmx5VHJhZGluZ1N5bWJvbHM6IHRydWUsXG4gIG1pbjI0aFZvbHVtZVVzZHQ6IDAsXG4gIG1heFJlc3VsdHM6IDAsXG4gIHN5bWJvbDogJ0FMTCcsXG4gIG1heFdvcmtlcnM6IDIwLFxufTtcblxuY29uc3QgQklOQU5DRV9CQVNFX1VSTCA9ICdodHRwczovL2ZhcGkuYmluYW5jZS5jb20nO1xuXG50eXBlIEhpc3RvZ3JhbVN0YXRlID1cbiAgfCAnUE9TSVRJVkVfRVhQQU5ESU5HJ1xuICB8ICdQT1NJVElWRV9DT05UUkFDVElORydcbiAgfCAnUE9TSVRJVkVfTUlYRUQnXG4gIHwgJ05FR0FUSVZFX0VYUEFORElORydcbiAgfCAnTkVHQVRJVkVfQ09OVFJBQ1RJTkcnXG4gIHwgJ05FR0FUSVZFX01JWEVEJ1xuICB8ICdaRVJPJztcblxuZXhwb3J0IHR5cGUgU2lnbmFsVHlwZSA9XG4gIHwgJ1NUUk9OR19MT05HJ1xuICB8ICdMT05HJ1xuICB8ICdFQVJMWV9MT05HJ1xuICB8ICdMT05HX01PTUVOVFVNJ1xuICB8ICdMT05HX0hPTEQnXG4gIHwgJ1NUUk9OR19TSE9SVCdcbiAgfCAnU0hPUlQnXG4gIHwgJ0VBUkxZX1NIT1JUJ1xuICB8ICdTSE9SVF9NT01FTlRVTSdcbiAgfCAnU0hPUlRfSE9MRCdcbiAgfCAnQlVMTElTSF9UUkFOU0lUSU9OJ1xuICB8ICdCRUFSSVNIX1RSQU5TSVRJT04nXG4gIHwgJ05FVVRSQUwnXG4gIHwgJ0xPTkdfV0VBS0VOSU5HJ1xuICB8ICdTSE9SVF9XRUFLRU5JTkcnXG4gIHwgJ0ZJTFRFUkVEX0VNQSdcbiAgfCAnRklMVEVSRURfUlNJJ1xuICB8ICdGSUxURVJFRF9WT0xVTUUnXG4gIHwgJ0ZJTFRFUkVEX0hJU1RPR1JBTSc7XG5cbmV4cG9ydCBpbnRlcmZhY2UgU2NhblJlc3VsdCB7XG4gIHN5bWJvbDogc3RyaW5nO1xuICB0aW1lZnJhbWU6IHN0cmluZztcbiAgY2FuZGxlVGltZTogbnVtYmVyO1xuICBwcmljZTogbnVtYmVyO1xuICBtYWNkOiBudW1iZXI7XG4gIHNpZ25hbDogbnVtYmVyO1xuICBo
280aXN0b2dyYW06IG51bWJlcjtcbiAgaGlzdG9ncmFtQ2hhbmdlOiBudW1iZXI7XG4gIGhpc3RvZ3JhbVBjdDogbnVtYmVyO1xuICBtYWNkU3RhdGU6ICdCVUxMSVNIJyB8ICdCRUFSSVNIJyB8ICdORVVUUkFMJztcbiAgemVyb1N0YXRlOiAnQUJPVkVfWkVSTycgfCAnQkVMT1dfWkVSTycgfCAnQVRfWkVSTyc7XG4gIGhpc3RvZ3JhbVN0YXRlOiBIaXN0b2dyYW1TdGF0ZTtcbiAgcnNpOiBudW1iZXI7XG4gIGVtYTogbnVtYmVyO1xuICBlbWFUcmVuZDogJ0FCT1ZFX0VNQScgfCAnQkVMT1dfRU1BJztcbiAgc2lnbmFsVHlwZTogU2lnbmFsVHlwZTtcbn1cblxuaW50ZXJmYWNlIEtsaW5lIHtcbiAgb3BlblRpbWU6IG51bWJlcjtcbiAgb3BlbjogbnVtYmVyO1xuICBoaWdoOiBudW1iZXI7XG4gIGxvdzogbnVtYmVyO1xuICBjbG9zZTogbnVtYmVyO1xuICB2b2x1bWU6IG51bWJlcjtcbiAgY2xvc2VUaW1lOiBudW1iZXI7XG4gIHF1b3RlVm9sdW1lOiBudW1iZXI7XG59XG5cbmFzeW5jIGZ1bmN0aW9uIGZldGNoSnNvbih1cmw6IHN0cmluZyk6IFByb21pc2U8YW55PiB7XG4gIGNvbnN0IHJlcyA9IGF3YWl0IGZldGNoKHVybCk7XG4gIGlmICghcmVzLm9rKSB0aHJvdyBuZXcgRXJyb3IoYEhUVFAgJHtyZXMuc3RhdHVzfSBmb3IgJHt1cmx9YCk7XG4gIHJldHVybiByZXMuanNvbigpO1xufVxuXG5leHBvcnQgYXN5bmMgZnVuY3Rpb24gZ2V0VXNkdFBlcnBldHVhbFN5bWJvbHMoXG4gIHNldHRpbmdzOiBTY2FubmVyU2V0dGluZ3Ncbik6IFByb21pc2U8c3RyaW5nW10+IHtcbiAgY29uc3QgZGF0YSA9IGF3YWl0IGZldGNoSnNvbihgJHtCSU5BTkNFX0JBU0VfVVJMfS9mYXBpL3YxL2V4Y2hhbmdlSW5mb2ApO1xuICBjb25zdCBzeW1ib2xzOiBzdHJpbmdbXSA9IFtdO1xuICBmb3IgKGNvbnN0IGl0ZW0gb2YgZGF0YS5zeW1ib2xzKSB7XG4gICAgaWYgKGl0ZW0ucXVvdGVBc3NldCAhPT0gJ1VTRFQnKSBjb250aW51ZTtcbiAgICBpZiAoaXRlbS5jb250cmFjdFR5cGUgIT09ICdQRVJQRVRVQUwnKSBjb250aW51ZTtcbiAgICBpZiAoc2V0dGluZ3Mub25seVRyYWRpbmdTeW1ib2xzICYmIGl0ZW0uc3RhdHVzICE9PSAnVFJBRElORycpIGNvbnRpbnVlO1xuICAgIHN5bWJvbHMucHVzaChpdGVtLnN5bWJvbCk7XG4gIH1cbiAgcmV0dXJuIHN5bWJvbHMuc29ydCgpO1xufVxuXG5leHBvcnQgYXN5bmMgZnVuY3Rpb24gZ2V0MjRoVm9sdW1lKCk6IFByb21pc2U8UmVjb3JkPHN0cmluZywgbnVtYmVyPj4ge1xuICBjb25zdCBkYXRhID0gYXdhaXQgZmV0Y2hKc29uKGAke0JJTkFOQ0VfQkFTRV9VUkx9L2ZhcGkvdjEvdGlja2VyLzI0aHJgKTtcbiAgY29uc3QgcmVzdWx0OiBSZWNvcmQ8c3RyaW5nLCBudW1iZXI+ID0ge307XG4gIGZvciAoY29uc3QgaXRlbSBvZiBkYXRhKSB7XG4gICAgY29uc3QgdiA9IE51bWJlcihpdGVtLnF1b3RlVm9sdW1lKTtcbiAgICByZXN1bHRbaXRlbS5zeW1ib2xdID0gaXNOYU4odikgPyAwIDogdjtcbiAgfVxuICByZXR1cm4gcmVzdWx0O1xufVxuXG5leHBvcnQgYXN5bmMgZnVuY3Rpb24gZ2V0S2xpbmVzKFxuICBzeW1ib2w6IHN0cmluZyxcbiAgc2V0dGluZ3M6IFNjYW5uZXJTZXR0aW5nc1xuKTogUHJvbWlzZTxLbGluZVtdPiB7XG4gIGNvbnN0IHVybCA9XG4gICAgYCR7QklOQU5DRV9CQVNFX1VSTH0vZmFwaS92MS9rbGluZXM/c3ltYm9sPSR7c3ltYm9sfWAgK1xuICAgIGAmaW50ZXJ2YWw9JHtzZXR0aW5ncy50aW1lZnJhbWV9JmxpbWl0PSR7c2V0dGluZ3MuY2FuZGxlTGltaXR9YDtcbiAgY29uc3QgZGF0YSA9IGF3YWl0IGZldGNoSnNvbih1cmwpO1xuICByZXR1cm4gZGF0YS5tYXAoKHJvdzogYW55W10pID0+ICh7XG4gICAgb3BlblRpbWU6IHJvd1swXSxcbiAgICBvcGVuOiBOdW1iZXIocm93WzFdKSxcbiAgICBoaWdoOiBOdW1iZXIocm93WzJdKSxcbiAgICBsb3c6IE51bWJlcihyb3dbM10pLFxuICAgIGNsb3NlOiBOdW1iZXIocm93WzRdKSxcbiAgICB2b2x1bWU6IE51bWJlcihyb3dbNV0pLFxuICAgIGNsb3NlVGltZTogcm93WzZdLFxuICAgIHF1b3RlVm9sdW1lOiBOdW1iZXIocm93WzddKSxcbiAgfSkpO1xufVxuXG5mdW5jdGlvbiBoaXN0b2dyYW1TdGF0ZShoOiBudW1iZXJbXSk6IEhpc3RvZ3JhbVN0YXRlIHtcbiAgY29uc3QgaDAgPSBoW2gubGVuZ3RoIC0gMV07XG4gIGNvbnN0IGgxID0gaFtoLmxlbmd0aCAtIDJdO1xuICBjb25zdCBoMiA9IGhbaC5sZW5ndGggLSAzXTtcbiAgaWYgKGgwID4gMCkge1xuICAgIGlmIChoMCA+IGgxICYmIGgxID4gaDIpIHJldHVybiAnUE9TSVRJVkVfRVhQQU5ESU5HJztcbiAgICBpZiAoaDAgPCBoMSAmJiBoMSA8IGgyKSByZXR1cm4gJ1BPU0lUSVZFX0NPTlRSQUNUSU5HJztcbiAgICByZXR1cm4gJ1BPU0lUSVZFX01JWEVEJztcbiAgfVxuICBpZiAoaDAgPCAwKSB7XG4gICAgaWYgKGgwIDwgaDEgJiYgaDEgPCBoMikgcmV0dXJuICdORUdBVElWRV9FWFBBTkRJTkcnO1xuICAgIGlmIChoMCA+IGgxICYmIGgxID4gaDIpIHJldHVybiAnTkVHQVRJVkVfQ09OVFJBQ1RJTkcnO1xuICAgIHJldHVybiAnTkVHQVRJVkVfTUlYRUQnO1xuICB9XG4gIHJldHVybiAnWkVSTyc7XG59XG5cbmZ1bmN0aW9uIGNsYXNzaWZ5U2lnbmFsKFxuICBtYWNkVmFsOiBudW1iZXIsXG4gIHNpZ25hbFZhbDogbnVtYmVyLFxuICBwcmV2TWFjZDogbnVtYmVyLFxuICBwcmV2U2lnbmFsOiBudW1iZXIsXG4gIGhpc3RTdGF0ZTogSGlzdG9ncmFtU3RhdGVcbik6IFNpZ25hbFR5cGUge1xuICBjb25zdCBidWxsaXNoQ3Jvc3MgPSBwcmV2TWFjZCA8PSBwcmV2U2lnbmFsICYmIG1hY2RWYWwgPiBzaWduYWxWYWw7XG4gIGNvbnN0IGJlYXJpc2hDcm9zcyA9IHByZXZNYWNkID49IHByZXZTaWduYWwgJiYgbWFjZFZhbCA8IHNpZ25hbFZhbDtcbiAgY29uc3QgYWJvdmVaZXJvID0gbWFjZFZhbCA+IDA7XG4gIGNvbnN0IGJlbG93WmVybyA9IG1hY2RWYWwgPCAwO1xuXG4gIGlmIChidWxsaXNoQ3Jvc3MgJiYgYWJvdmVaZXJvKSB7XG4gICAgcmV0dXJuIGhpc3RTdGF0ZSA9PT0gJ1BPU0lUSVZFX0VYUEFORElORycgPyAnU1RST05HX0xPTkcnIDogJ0xPTkcnO1xuICB9XG4gIGlmIChidWxsaXNoQ3Jvc3MgJiYgYmVsb3daZXJvKSByZXR1cm4gJ0VBUkxZX0xPT
280kcnO1xuICBpZiAoYmVhcmlzaENyb3NzICYmIGJlbG93WmVybykge1xuICAgIHJldHVybiBoaXN0U3RhdGUgPT09ICdORUdBVElWRV9FWFBBTkRJTkcnID8gJ1NUUk9OR19TSE9SVCcgOiAnU0hPUlQnO1xuICB9XG4gIGlmIChiZWFyaXNoQ3Jvc3MgJiYgYWJvdmVaZXJvKSByZXR1cm4gJ0VBUkxZX1NIT1JUJztcblxuICBpZiAobWFjZFZhbCA+IHNpZ25hbFZhbCAmJiBhYm92ZVplcm8pIHtcbiAgICBpZiAoaGlzdFN0YXRlID09PSAnUE9TSVRJVkVfRVhQQU5ESU5HJykgcmV0dXJuICdMT05HX01PTUVOVFVNJztcbiAgICBpZiAoaGlzdFN0YXRlID09PSAnUE9TSVRJVkVfQ09OVFJBQ1RJTkcnKSByZXR1cm4gJ0xPTkdfV0VBS0VOSU5HJztcbiAgICByZXR1cm4gJ0xPTkdfSE9MRCc7XG4gIH1cbiAgaWYgKG1hY2RWYWwgPCBzaWduYWxWYWwgJiYgYmVsb3daZXJvKSB7XG4gICAgaWYgKGhpc3RTdGF0ZSA9PT0gJ05FR0FUSVZFX0VYUEFORElORycpIHJldHVybiAnU0hPUlRfTU9NRU5UVU0nO1xuICAgIGlmIChoaXN0U3RhdGUgPT09ICdORUdBVElWRV9DT05UUkFDVElORycpIHJldHVybiAnU0hPUlRfV0VBS0VOSU5HJztcbiAgICByZXR1cm4gJ1NIT1JUX0hPTEQnO1xuICB9XG4gIGlmIChtYWNkVmFsID4gc2lnbmFsVmFsKSByZXR1cm4gJ0JVTExJU0hfVFJBTlNJVElPTic7XG4gIGlmIChtYWNkVmFsIDwgc2lnbmFsVmFsKSByZXR1cm4gJ0JFQVJJU0hfVFJBTlNJVElPTic7XG4gIHJldHVybiAnTkVVVFJBTCc7XG59XG5cbmNvbnN0IExPTkdfU0lHTkFMUzogU2lnbmFsVHlwZVtdID0gW1xuICAnU1RST05HX0xPTkcnLCAnTE9ORycsICdFQVJMWV9MT05HJywgJ0xPTkdfTU9NRU5UVU0nLFxuXTtcbmNvbnN0IFNIT1JUX1NJR05BTFM6IFNpZ25hbFR5cGVbXSA9IFtcbiAgJ1NUUk9OR19TSE9SVCcsICdTSE9SVCcsICdFQVJMWV9TSE9SVCcsICdTSE9SVF9NT01FTlRVTScsXG5dO1xuXG5leHBvcnQgY29uc3QgU0lHTkFMX1BSSU9SSVRZOiBSZWNvcmQ8U2lnbmFsVHlwZSwgbnVtYmVyPiA9IHtcbiAgU1RST05HX0xPTkc6IDEwLCBMT05HOiA5LCBFQVJMWV9MT05HOiA4LCBMT05HX01PTUVOVFVNOiA3LCBMT05HX0hPTEQ6IDYsXG4gIFNUUk9OR19TSE9SVDogMTAsIFNIT1JUOiA5LCBFQVJMWV9TSE9SVDogOCwgU0hPUlRfTU9NRU5UVU06IDcsIFNIT1JUX0hPTEQ6IDYsXG4gIEJVTExJU0hfVFJBTlNJVElPTjogNCwgQkVBUklTSF9UUkFOU0lUSU9OOiA0LFxuICBORVVUUkFMOiAwLCBMT05HX1dFQUtFTklORzogMiwgU0hPUlRfV0VBS0VOSU5HOiAyLFxuICBGSUxURVJFRF9FTUE6IDAsIEZJTFRFUkVEX1JTSTogMCwgRklMVEVSRURfVk9MVU1FOiAwLCBGSUxURVJFRF9ISVNUT0dSQU06IDAsXG59O1xuXG5leHBvcnQgY29uc3QgTUVBTklOR0ZVTF9TSUdOQUxTOiBTaWduYWxUeXBlW10gPSBbXG4gICdTVFJPTkdfTE9ORycsICdMT05HJywgJ0VBUkxZX0xPTkcnLCAnTE9OR19NT01FTlRVTScsXG4gICdTVFJPTkdfU0hPUlQnLCAnU0hPUlQnLCAnRUFSTFlfU0hPUlQnLCAnU0hPUlRfTU9NRU5UVU0nLFxuXTtcblxuZXhwb3J0IGFzeW5jIGZ1bmN0aW9uIGFuYWx5emVTeW1ib2woXG4gIHN5bWJvbDogc3RyaW5nLFxuICBzZXR0aW5nczogU2Nhbm5lclNldHRpbmdzXG4pOiBQcm9taXNlPFNjYW5SZXN1bHQgfCBudWxsPiB7XG4gIHRyeSB7XG4gICAgbGV0IGtsaW5lcyA9IGF3YWl0IGdldEtsaW5lcyhzeW1ib2wsIHNldHRpbmdzKTtcbiAgICBjb25zdCBtaW5DYW5kbGVzID0gTWF0aC5tYXgoXG4gICAgICBzZXR0aW5ncy5tYWNkU2xvdywgc2V0dGluZ3MuZW1hUGVyaW9kLCBzZXR0aW5ncy5yc2lQZXJpb2QsIDUwXG4gICAgKSArIDEwO1xuICAgIGlmIChrbGluZXMubGVuZ3RoIDwgbWluQ2FuZGxlcykgcmV0dXJuIG51bGw7XG5cbiAgICBpZiAoc2V0dGluZ3MuY29uZmlybUNsb3NlZENhbmRsZSkge1xuICAgICAga2xpbmVzID0ga2xpbmVzLnNsaWNlKDAsIC0xKTtcbiAgICB9XG4gICAgaWYgKGtsaW5lcy5sZW5ndGggPCAzKSByZXR1cm4gbnVsbDtcblxuICAgIGNvbnN0IGNsb3NlcyA9IGtsaW5lcy5tYXAoayA9PiBrLmNsb3NlKTtcbiAgICBjb25zdCB2b2x1bWVzID0ga2xpbmVzLm1hcChrID0+IGsudm9sdW1lKTtcblxuICAgIGNvbnN0IHsgbWFjZDogbWFjZExpbmUsIHNpZ25hbDogc2lnbmFsTGluZSwgaGlzdG9ncmFtIH0gPSBtYWNkKFxuICAgICAgY2xvc2VzLCBzZXR0aW5ncy5tYWNkRmFzdCwgc2V0dGluZ3MubWFjZFNsb3csIHNldHRpbmdzLm1hY2RTaWduYWxcbiAgICApO1xuICAgIGNvbnN0IGVtYUFyciA9IGVtYShjbG9zZXMsIHNldHRpbmdzLmVtYVBlcmlvZCk7XG4gICAgY29uc3QgcnNpQXJyID0gcnNpKGNsb3Nlcywgc2V0dGluZ3MucnNpUGVyaW9kKTtcblxuICAgIGNvbnN0IGkgPSBrbGluZXMubGVuZ3RoIC0gMTtcbiAgICBjb25zdCBtYWNkVmFsID0gbWFjZExpbmVbaV07XG4gICAgY29uc3Qgc2lnbmFsVmFsID0gc2lnbmFsTGluZVtpXTtcbiAgICBjb25zdCBwcmV2TWFjZCA9IG1hY2RMaW5lW2kgLSAxXTtcbiAgICBjb25zdCBwcmV2U2lnbmFsID0gc2lnbmFsTGluZVtpIC0gMV07XG4gICAgY29uc3QgaGlzdCA9IGhpc3RvZ3JhbVtpXTtcbiAgICBjb25zdCBoaXN0UHJldiA9IGhpc3RvZ3JhbVtpIC0gMV07XG4gICAgY29uc3QgcHJpY2UgPSBjbG9zZXNbaV07XG4gICAgY29uc3QgcnNpVmFsID0gcnNpQXJyW2ldO1xuICAgIGNvbnN0IGVtYVZhbCA9IGVtYUFycltpXTtcblxuICAgIGlmIChbbWFjZFZhbCwgc2lnbmFsVmFsLCBwcmV2TWFjZCwgcHJldlNpZ25hbCwgaGlzdCwgaGlzdFByZXYsIHJzaVZhbCwgZW1hVmFsXVxuICAgICAgLnNvbWUoaXNOYU4pKSByZXR1cm4gbnVsbDtcblxuICAgIGNvbnN0IGhpc3RTdGF0ZSA9IGhpc3RvZ3JhbVN0YXRlKGhpc3RvZ3JhbS5zbGljZSgtMykpO1xuXG4gICAgbGV0IHNpZ25hbCA9IGNsYXNzaWZ5U2lnbmFsKFxuICAgICAgbWFjZFZhbCwgc2lnbmFsVmFsLCBwcmV2TWFjZCwgcHJldlNpZ25hbCwgaGlzdFN0YXRlXG4gICAgKTtcblxuICAgIC8vIEZpbHRlcnNcbiAgICBpZiAoc2V0dGluZ3MudXNlRW1hRmlsdGVyKSB7XG4gICAgICBpZiAoTE9OR19TSUdOQUxTLmluY2x1ZGVzKHNpZ25hbCkgJiYgIShwcmljZSA+IGVtYVZhbCkpIHtcbiAgICAgICAgc2lnbmFsID0gJ0ZJTFRFUkVEX0VNQSc7XG4gICAgICB9IGVsc2UgaWYgKFNIT1JUX1NJR05BTFMuaW5jbHVkZXMoc2lnbmFsKSAmJiAhKHByaWNlIDwgZW1hVmFsKSkge1xuICAgICAgICBzaWduYWwgPSAnRklMVEVSRURfRU1BJztcbiAgICAgIH1cbiAgICB9XG4gICAgaWYgKHNldHRpbmdzLnVzZVJzaUZpbHRlciAmJiBzaWduYWwgIT09ICdGSUxURVJFRF9FTUEnKSB7XG4gICAgICBpZiAoTE9OR19TSUdOQUxTLmluY2x1ZGVzKHNpZ25hbCkgJiYgcnNpVmFsI
280D4gc2V0dGluZ3MucnNpTG9uZ01heCkge1xuICAgICAgICBzaWduYWwgPSAnRklMVEVSRURfUlNJJztcbiAgICAgIH0gZWxzZSBpZiAoU0hPUlRfU0lHTkFMUy5pbmNsdWRlcyhzaWduYWwpICYmIHJzaVZhbCA8IHNldHRpbmdzLnJzaVNob3J0TWluKSB7XG4gICAgICAgIHNpZ25hbCA9ICdGSUxURVJFRF9SU0knO1xuICAgICAgfVxuICAgIH1cbiAgICBpZiAoc2V0dGluZ3MudXNlVm9sdW1lRmlsdGVyICYmICFzaWduYWwuc3RhcnRzV2l0aCgnRklMVEVSRUQnKSkge1xuICAgICAgY29uc3QgcmVjZW50QXZnID0gdm9sdW1lcy5zbGljZSgtc2V0dGluZ3Mudm9sdW1lUGVyaW9kIC0gMSwgLTEpXG4gICAgICAgIC5yZWR1Y2UoKGEsIGIpID0+IGEgKyBiLCAwKSAvIHNldHRpbmdzLnZvbHVtZVBlcmlvZDtcbiAgICAgIGlmIChyZWNlbnRBdmcgPiAwICYmIHZvbHVtZXNbaV0gLyByZWNlbnRBdmcgPCBzZXR0aW5ncy5taW5Wb2x1bWVSYXRpbykge1xuICAgICAgICBzaWduYWwgPSAnRklMVEVSRURfVk9MVU1FJztcbiAgICAgIH1cbiAgICB9XG4gICAgaWYgKHNldHRpbmdzLm1pbkhpc3RvZ3JhbVBlcmNlbnQgPiAwICYmICFzaWduYWwuc3RhcnRzV2l0aCgnRklMVEVSRUQnKSkge1xuICAgICAgY29uc3QgcGN0ID0gKE1hdGguYWJzKGhpc3QpIC8gcHJpY2UpICogMTAwO1xuICAgICAgaWYgKHBjdCA8IHNldHRpbmdzLm1pbkhpc3RvZ3JhbVBlcmNlbnQpIHNpZ25hbCA9ICdGSUxURVJFRF9ISVNUT0dSQU0nO1xuICAgIH1cblxuICAgIGNvbnN0IG1hY2RTdGF0ZSA9IG1hY2RWYWwgPiBzaWduYWxWYWwgPyAnQlVMTElTSCdcbiAgICAgIDogbWFjZFZhbCA8IHNpZ25hbFZhbCA/ICdCRUFSSVNIJyA6ICdORVVUUkFMJztcbiAgICBjb25zdCB6ZXJvU3RhdGUgPSBtYWNkVmFsID4gMCA/ICdBQk9WRV9aRVJPJ1xuICAgICAgOiBtYWNkVmFsIDwgMCA/ICdCRUxPV19aRVJPJyA6ICdBVF9aRVJPJztcblxuICAgIHJldHVybiB7XG4gICAgICBzeW1ib2wsXG4gICAgICB0aW1lZnJhbWU6IHNldHRpbmdzLnRpbWVmcmFtZSxcbiAgICAgIGNhbmRsZVRpbWU6IGtsaW5lc1tpXS5jbG9zZVRpbWUsXG4gICAgICBwcmljZSxcbiAgICAgIG1hY2Q6IG1hY2RWYWwsXG4gICAgICBzaWduYWw6IHNpZ25hbFZhbCxcbiAgICAgIGhpc3RvZ3JhbTogaGlzdCxcbiAgICAgIGhpc3RvZ3JhbUNoYW5nZTogaGlzdCAtIGhpc3RQcmV2LFxuICAgICAgaGlzdG9ncmFtUGN0OiAoaGlzdCAvIHByaWNlKSAqIDEwMCxcbiAgICAgIG1hY2RTdGF0ZSxcbiAgICAgIHplcm9TdGF0ZSxcbiAgICAgIGhpc3RvZ3JhbVN0YXRlOiBoaXN0U3RhdGUsXG4gICAgICByc2k6IHJzaVZhbCxcbiAgICAgIGVtYTogZW1hVmFsLFxuICAgICAgZW1hVHJlbmQ6IHByaWNlID4gZW1hVmFsID8gJ0FCT1ZFX0VNQScgOiAnQkVMT1dfRU1BJyxcbiAgICAgIHNpZ25hbFR5cGU6IHNpZ25hbCxcbiAgICB9O1xuICB9IGNhdGNoIHtcbiAgICByZXR1cm4gbnVsbDtcbiAgfVxufVxuXG5leHBvcnQgaW50ZXJmYWNlIFNjYW5Qcm9ncmVzcyB7XG4gIGNvbXBsZXRlZDogbnVtYmVyO1xuICB0b3RhbDogbnVtYmVyO1xuICBtZWFuaW5nZnVsOiBTY2FuUmVzdWx0W107XG59XG5cbmV4cG9ydCBhc3luYyBmdW5jdGlvbiBzY2FuQWxsKFxuICBzZXR0aW5nczogU2Nhbm5lclNldHRpbmdzLFxuICBvblByb2dyZXNzOiAocDogU2NhblByb2dyZXNzKSA9PiB2b2lkLFxuICBzaWduYWw6IHsgY2FuY2VsbGVkOiBib29sZWFuIH1cbik6IFByb21pc2U8U2NhblJlc3VsdFtdPiB7XG4gIGxldCBzeW1ib2xzID0gYXdhaXQgZ2V0VXNkdFBlcnBldHVhbFN5bWJvbHMoc2V0dGluZ3MpO1xuXG4gIGlmIChzZXR0aW5ncy5taW4yNGhWb2x1bWVVc2R0ID4gMCkge1xuICAgIGNvbnN0IHZvbHVtZXMgPSBhd2FpdCBnZXQyNGhWb2x1bWUoKTtcbiAgICBzeW1ib2xzID0gc3ltYm9scy5maWx0ZXIocyA9PiAodm9sdW1lc1tzXSA/PyAwKSA+PSBzZXR0aW5ncy5taW4yNGhWb2x1bWVVc2R0KTtcbiAgfVxuXG4gIGNvbnN0IHRvdGFsID0gc3ltYm9scy5sZW5ndGg7XG4gIGxldCBjb21wbGV0ZWQgPSAwO1xuICBjb25zdCBhbGxSZXN1bHRzOiBTY2FuUmVzdWx0W10gPSBbXTtcbiAgY29uc3QgbWVhbmluZ2Z1bDogU2NhblJlc3VsdFtdID0gW107XG5cbiAgLy8gQ29uY3VycmVuY3kgbGltaXRlclxuICBjb25zdCBxdWV1ZSA9IFsuLi5zeW1ib2xzXTtcbiAgY29uc3Qgd29ya2VyczogUHJvbWlzZTx2b2lkPltdID0gW107XG4gIGNvbnN0IGNvbmN1cnJlbmN5ID0gTWF0aC5taW4oc2V0dGluZ3MubWF4V29ya2VycywgMTUpO1xuXG4gIGNvbnN0IHJ1bk5leHQgPSBhc3luYyAoKTogUHJvbWlzZTx2b2lkPiA9PiB7XG4gICAgd2hpbGUgKHF1ZXVlLmxlbmd0aCA+IDAgJiYgIXNpZ25hbC5jYW5jZWxsZWQpIHtcbiAgICAgIGNvbnN0IHN5bSA9IHF1ZXVlLnNoaWZ0KCkhO1xuICAgICAgY29uc3QgcmVzdWx0ID0gYXdhaXQgYW5hbHl6ZVN5bWJvbChzeW0sIHNldHRpbmdzKTtcbiAgICAgIGNvbXBsZXRlZCsrO1xuICAgICAgaWYgKHJlc3VsdCkge1xuICAgICAgICBhbGxSZXN1bHRzLnB1c2gocmVzdWx0KTtcbiAgICAgICAgaWYgKE1FQU5JTkdGVUxfU0lHTkFMUy5pbmNsdWRlcyhyZXN1bHQuc2lnbmFsVHlwZSkpIHtcbiAgICAgICAgICBtZWFuaW5nZnVsLnB1c2gocmVzdWx0KTtcbiAgICAgICAgICBtZWFuaW5nZnVsLnNvcnQoKGEsIGIpID0+XG4gICAgICAgICAgICBTSUdOQUxfUFJJT1JJVFlbYi5zaWduYWxUeXBlXSAtIFNJR05BTF9QUklPUklUWVthLnNpZ25hbFR5cGVdXG4gICAgICAgICAgKTtcbiAgICAgICAgfVxuICAgICAgfVxuICAgICAgb25Qcm9ncmVzcyh7IGNvbXBsZXRlZCwgdG90YWwsIG1lYW5pbmdmdWw6IFsuLi5tZWFuaW5nZnVsXSB9KTtcbiAgICB9XG4gIH07XG5cbiAgZm9yIChsZXQgaSA9IDA7IGkgPCBjb25jdXJyZW5jeTsgaSsrKSB3b3JrZXJzLnB1c2gocnVuTmV4dCgpKTtcbiAgYXdhaXQgUHJvbWlzZS5hbGwod29ya2Vycyk7XG5cbiAgYWxsUmVzdWx0cy5zb3J0KChhLCBiKSA9PlxuICAgIFNJR05BTF9QUklPUklUWVtiLnNpZ25hbFR5cGVdIC0gU0lHTkFMX1BSSU9SSVRZW2Euc2lnbmFsVHlwZV1cbiAgKTtcbiAgcmV0dXJuIGFsbFJlc3VsdHM7XG59XG4iXSwibWFwcGluZ3MiOiJBQUlBLFNBQVMsS0FBSyxLQUFLLFlBQVk7QUEwQnhCLGFBQU0sbUJBQW9DO0FBQUEsRUFDL0MsV0FBVztBQUFBLEVBQ1gsYUFBYTtBQUFBLEVBQ2IsVUFBVTtBQUFBLEVBQ1YsVUFBVTtBQUFBLEVBQ1YsWUFBWTtBQUFBLEVBQ1osY0FBYztBQUFBLEVBQ2QsV0FBVztBQUFBLEVBQ1gsY0FBYztBQUFBLEVBQ2QsV0FBVztBQUFBLEVBQ1gsWUFBWTtBQUFBLEVBQ1osYUFBYTtBQUFBLEVBQ2IsaUJBQWlCO0FBQUEsRUFDakIsY0FBYztBQUFBLEVBQ2QsZ0JBQWdCO0FBQUEsRUFDaEIscUJBQXFCO0FBQUEsRUFDckIscUJBQXFCO0FBQUEsRUFDckIsb0JBQW9CO0FBQUEsRUFDcEIsa0JBQWtCO0FBQUEsRUFDbEIsWUFBWTtBQUFBLEVBQ1osUUFBUTtBQUFBLEVBQ1IsWUFBWTtBQUNkO0FBRUEsTUFBTSxtQkFBbUI7QUE4RHpCLGVBQWUsVUFBVSxLQUEyQjtBQUNsRCxRQUFNLE1BQU0sTUFBTSxNQUFNLEdBQUc7QUFDM0IsTUFBSSxDQUFDLElBQU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
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.