PageSourceSearch

https://kreepton.com/src/lib/macdScanner.ts

js kreepton.com collected 2026-10-02 01:36:24 UTC 32,862 bytes, 280 lines download raw bytes

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.