[{"data":1,"prerenderedAt":4106},["ShallowReactive",2],{"post:\u002F2026\u002F03\u002F11\u002Fnode-js-discovery-diffing-two-network-scans-to-flag-new-hosts\u002F":3},{"post":4,"newer":4056,"older":4067,"related":4076,"series":4104},{"id":5,"title":6,"body":7,"canonical":4036,"categories":4037,"date":4040,"description":4041,"extension":4042,"featured":4043,"hero":4044,"image":4044,"meta":4045,"navigation":494,"path":4046,"readingTime":144,"seo":4047,"series":4044,"seriesOrder":4044,"sites":4048,"source":4044,"stem":4049,"tags":4050,"updated":4044,"url":4054,"__hash__":4055},"blog\u002Fblog\u002F2026\u002F03\u002F11\u002Fnode-js-discovery-diffing-two-network-scans-to-flag-new-hosts.md","Node.js: Discovery – Diffing Two Network Scans to Flag New Hosts",{"type":8,"value":9,"toc":4029},"minimark",[10,19,28,33,69,73,88,166,169,187,195,198,222,225,408,412,3836,3840,3941,3945,4025],[11,12,13,14,18],"p",{},"A single network scan tells you what's out there today. It's the second scan, compared against the first, that tells you something changed: a rogue device showed up on a subnet it shouldn't be on, a host that was supposed to be decommissioned is still answering, or a service quietly opened a new port. I run a scheduled ",[15,16,17],"code",{},"nmap"," sweep against the office and datacenter subnets and keep the XML output from each run; this script diffs any two of those XML files and reports new hosts, hosts that dropped off, hosts that moved to a different IP, and hosts whose open-port set changed, without pulling in an XML parsing dependency.",[11,20,21,22,27],{},"It's the \"keep it current\" half of the ",[23,24,26],"a",{"href":25},"\u002F2026\u002F07\u002F15\u002Finfrastructure-a-discovery-first-approach-to-documenting-an-undocumented-network\u002F","discovery-first approach to documenting an undocumented network",": the first scan feeds the inventory, and every scan after that feeds a change report.",[29,30,32],"h2",{"id":31},"requirements","Requirements",[34,35,36,52,59,66],"ul",{},[37,38,39,40,43,44,47,48,51],"li",{},"A supported Node.js LTS release (22 or later). No ",[15,41,42],{},"npm install","; only the core ",[15,45,46],{},"fs"," and ",[15,49,50],{},"path"," modules.",[37,53,54,55,58],{},"nmap on the scanning host, run as root or Administrator if you want SYN scans (",[15,56,57],{},"-sS","), OS detection, and MAC addresses. Unprivileged nmap falls back to connect scans, and MAC addresses only appear in the XML for targets on the local Ethernet segment.",[37,60,61,62,65],{},"Two scans taken with the same profile and port range, so the diff is meaningful. Comparing a top-1000-ports scan against a full ",[15,63,64],{},"-p-"," scan reports a lot of \"new ports\" that are only new to the scan.",[37,67,68],{},"Written authorization for every range in the schedule.",[29,70,72],{"id":71},"usage","Usage",[11,74,75,76,79,80,83,84,87],{},"Take a baseline and a follow-up scan with an identical command. ",[15,77,78],{},"-oX"," writes XML; ",[15,81,82],{},"--top-ports 1000"," keeps a daily \u002F24 run short; ",[15,85,86],{},"--reason"," records why each port got its state, which helps when a diff looks wrong:",[89,90,95],"pre",{"className":91,"code":92,"language":93,"meta":94,"style":94},"language-bash shiki shiki-themes github-dark","sudo nmap -sS --top-ports 1000 -T4 --reason -oX baseline.xml 10.0.20.0\u002F24\n# ...next day...\nsudo nmap -sS --top-ports 1000 -T4 --reason -oX current.xml 10.0.20.0\u002F24\n","bash","",[15,96,97,135,142],{"__ignoreMap":94},[98,99,102,106,110,114,117,120,123,126,129,132],"span",{"class":100,"line":101},"line",1,[98,103,105],{"class":104},"svObZ","sudo",[98,107,109],{"class":108},"sU2Wk"," nmap",[98,111,113],{"class":112},"sDLfK"," -sS",[98,115,116],{"class":112}," --top-ports",[98,118,119],{"class":112}," 1000",[98,121,122],{"class":112}," -T4",[98,124,125],{"class":112}," --reason",[98,127,128],{"class":112}," -oX",[98,130,131],{"class":108}," baseline.xml",[98,133,134],{"class":108}," 10.0.20.0\u002F24\n",[98,136,138],{"class":100,"line":137},2,[98,139,141],{"class":140},"sAwPA","# ...next day...\n",[98,143,145,147,149,151,153,155,157,159,161,164],{"class":100,"line":144},3,[98,146,105],{"class":104},[98,148,109],{"class":108},[98,150,113],{"class":112},[98,152,116],{"class":112},[98,154,119],{"class":112},[98,156,122],{"class":112},[98,158,125],{"class":112},[98,160,128],{"class":112},[98,162,163],{"class":108}," current.xml",[98,165,134],{"class":108},[11,167,168],{},"Diff them and print a summary plus the JSON report:",[89,170,172],{"className":91,"code":171,"language":93,"meta":94,"style":94},"node diff-scans.js baseline.xml current.xml\n",[15,173,174],{"__ignoreMap":94},[98,175,176,179,182,184],{"class":100,"line":101},[98,177,178],{"class":104},"node",[98,180,181],{"class":108}," diff-scans.js",[98,183,131],{"class":108},[98,185,186],{"class":108}," current.xml\n",[89,188,193],{"className":189,"code":191,"language":192,"meta":94},[190],"language-text","Baseline: baseline.xml (Tue Mar 10 02:00:01 2026)  Current: current.xml (Wed Mar 11 02:00:01 2026)\nNew hosts: 1, removed: 1, moved: 1, port changes: 2\n\n  NEW      10.0.20.87   (unknown)            mac 3c:22:fb:4e:91:07  ports: tcp\u002F22, tcp\u002F5900\n  REMOVED  10.0.20.31   print-2f.corp.example.internal\n  MOVED    b8:ca:3a:6d:12:a5  10.0.20.44 -> 10.0.20.46\n  PORTS    10.0.20.10   +tcp\u002F8080 (http-proxy)\n  PORTS    10.0.20.12   -tcp\u002F3389 (ms-wbt-server)\n","text",[15,194,191],{"__ignoreMap":94},[11,196,197],{},"Write the report to a file for a scheduled job, and fail the job when anything new shows up:",[89,199,201],{"className":91,"code":200,"language":93,"meta":94,"style":94},"node diff-scans.js baseline.xml current.xml --output diff-report.json --fail-on-new\n",[15,202,203],{"__ignoreMap":94},[98,204,205,207,209,211,213,216,219],{"class":100,"line":101},[98,206,178],{"class":104},[98,208,181],{"class":108},[98,210,131],{"class":108},[98,212,163],{"class":108},[98,214,215],{"class":112}," --output",[98,217,218],{"class":108}," diff-report.json",[98,220,221],{"class":112}," --fail-on-new\n",[11,223,224],{},"A nightly wrapper that rotates the files (cron runs it as root):",[89,226,228],{"className":91,"code":227,"language":93,"meta":94,"style":94},"#!\u002Fusr\u002Fbin\u002Fenv bash\n# nightly-scan.sh: scan, diff against yesterday, keep a dated copy.\nset -euo pipefail\ncd \u002Fvar\u002Flib\u002Fnetscan\nTARGETS=\"10.0.20.0\u002F24 10.0.30.0\u002F24\"\nnmap -sS --top-ports 1000 -T4 --reason -oX current.xml $TARGETS\ncp current.xml \"archive\u002Fscan-$(date +%F).xml\"\nif [ -f baseline.xml ]; then\n    node \u002Fopt\u002Fnetscan\u002Fdiff-scans.js baseline.xml current.xml --output \"archive\u002Fdiff-$(date +%F).json\" --fail-on-new \\\n        || echo \"New hosts detected: see archive\u002Fdiff-$(date +%F).json\" | mail -s \"Network scan: new hosts\" netops@example.com\nfi\nmv current.xml baseline.xml\n",[15,229,230,235,240,251,260,274,296,313,331,360,391,397],{"__ignoreMap":94},[98,231,232],{"class":100,"line":101},[98,233,234],{"class":140},"#!\u002Fusr\u002Fbin\u002Fenv bash\n",[98,236,237],{"class":100,"line":137},[98,238,239],{"class":140},"# nightly-scan.sh: scan, diff against yesterday, keep a dated copy.\n",[98,241,242,245,248],{"class":100,"line":144},[98,243,244],{"class":112},"set",[98,246,247],{"class":112}," -euo",[98,249,250],{"class":108}," pipefail\n",[98,252,254,257],{"class":100,"line":253},4,[98,255,256],{"class":112},"cd",[98,258,259],{"class":108}," \u002Fvar\u002Flib\u002Fnetscan\n",[98,261,263,267,271],{"class":100,"line":262},5,[98,264,266],{"class":265},"s95oV","TARGETS",[98,268,270],{"class":269},"snl16","=",[98,272,273],{"class":108},"\"10.0.20.0\u002F24 10.0.30.0\u002F24\"\n",[98,275,277,279,281,283,285,287,289,291,293],{"class":100,"line":276},6,[98,278,17],{"class":104},[98,280,113],{"class":112},[98,282,116],{"class":112},[98,284,119],{"class":112},[98,286,122],{"class":112},[98,288,125],{"class":112},[98,290,128],{"class":112},[98,292,163],{"class":108},[98,294,295],{"class":265}," $TARGETS\n",[98,297,299,302,304,307,310],{"class":100,"line":298},7,[98,300,301],{"class":104},"cp",[98,303,163],{"class":108},[98,305,306],{"class":108}," \"archive\u002Fscan-$(",[98,308,309],{"class":104},"date",[98,311,312],{"class":108}," +%F).xml\"\n",[98,314,316,319,322,325,328],{"class":100,"line":315},8,[98,317,318],{"class":269},"if",[98,320,321],{"class":265}," [ ",[98,323,324],{"class":269},"-f",[98,326,327],{"class":265}," baseline.xml ]; ",[98,329,330],{"class":269},"then\n",[98,332,334,337,340,342,344,346,349,351,354,357],{"class":100,"line":333},9,[98,335,336],{"class":104},"    node",[98,338,339],{"class":108}," \u002Fopt\u002Fnetscan\u002Fdiff-scans.js",[98,341,131],{"class":108},[98,343,163],{"class":108},[98,345,215],{"class":112},[98,347,348],{"class":108}," \"archive\u002Fdiff-$(",[98,350,309],{"class":104},[98,352,353],{"class":108}," +%F).json\"",[98,355,356],{"class":112}," --fail-on-new",[98,358,359],{"class":112}," \\\n",[98,361,363,366,369,372,374,376,379,382,385,388],{"class":100,"line":362},10,[98,364,365],{"class":269},"        ||",[98,367,368],{"class":112}," echo",[98,370,371],{"class":108}," \"New hosts detected: see archive\u002Fdiff-$(",[98,373,309],{"class":104},[98,375,353],{"class":108},[98,377,378],{"class":269}," |",[98,380,381],{"class":104}," mail",[98,383,384],{"class":112}," -s",[98,386,387],{"class":108}," \"Network scan: new hosts\"",[98,389,390],{"class":108}," netops@example.com\n",[98,392,394],{"class":100,"line":393},11,[98,395,396],{"class":269},"fi\n",[98,398,400,403,405],{"class":100,"line":399},12,[98,401,402],{"class":104},"mv",[98,404,163],{"class":108},[98,406,407],{"class":108}," baseline.xml\n",[29,409,411],{"id":410},"script","Script",[89,413,417],{"className":414,"code":415,"language":416,"meta":94,"style":94},"language-javascript shiki shiki-themes github-dark","#!\u002Fusr\u002Fbin\u002Fenv node\n\u002F**\n * diff-scans.js\n *\n * Diff two nmap XML scans (nmap -oX output) and report hosts that appeared,\n * disappeared, moved to a new IP (same MAC), or changed their open ports.\n *\n * Reads: two nmap XML files given as CLI arguments.\n * Writes: a JSON report to stdout, or to --output if given.\n * Exit code: 2 when --fail-on-new is set and new hosts were found.\n *\n * Dependency-free: it parses the regular subset of nmap's XML it needs with\n * regular expressions. Point it at your own scan output, not untrusted XML.\n *\u002F\n\n'use strict';\n\nconst fs = require('fs');\nconst path = require('path');\n\nfunction parseArgs(argv) {\n  const args = { output: null, failOnNew: false, files: [] };\n  for (let i = 0; i \u003C argv.length; i += 1) {\n    const arg = argv[i];\n    if (arg === '--output') {\n      args.output = argv[i + 1];\n      i += 1;\n    } else if (arg === '--fail-on-new') {\n      args.failOnNew = true;\n    } else {\n      args.files.push(arg);\n    }\n  }\n  if (args.files.length !== 2) {\n    throw new Error('Usage: diff-scans.js \u003Cbaseline.xml> \u003Ccurrent.xml> [--output report.json] [--fail-on-new]');\n  }\n  return args;\n}\n\nfunction decode(value) {\n  return value\n    .replace(\u002F&lt;\u002Fg, '\u003C').replace(\u002F&gt;\u002Fg, '>')\n    .replace(\u002F&quot;\u002Fg, '\"').replace(\u002F&apos;\u002Fg, \"'\").replace(\u002F&amp;\u002Fg, '&');\n}\n\nfunction attr(tag, name) {\n  const match = tag.match(new RegExp(`\\\\s${name}=\"([^\"]*)\"`));\n  return match ? decode(match[1]) : null;\n}\n\nfunction parseScan(xml) {\n  const runTag = (xml.match(\u002F\u003Cnmaprun\\s[^>]*>\u002F) || [''])[0];\n  const hosts = new Map();\n\n  \u002F\u002F \"\u003Chost \" or \"\u003Chost>\" only: nmap's DTD also allows \u003Chosthint> elements, which a\n  \u002F\u002F looser \u002F\u003Chost[\\s\\S]*?\u003C\\\u002Fhost>\u002F pattern would swallow along with the next host.\n  const hostBlocks = xml.match(\u002F\u003Chost[\\s>][\\s\\S]*?\u003C\\\u002Fhost>\u002Fg) || [];\n\n  for (const block of hostBlocks) {\n    const statusTag = (block.match(\u002F\u003Cstatus\\s[^>]*>\u002F) || [''])[0];\n    if (attr(statusTag, 'state') !== 'up') {\n      continue;\n    }\n\n    let ip = null;\n    let mac = null;\n    let vendor = null;\n    for (const addressTag of block.match(\u002F\u003Caddress\\s[^>]*>\u002Fg) || []) {\n      const type = attr(addressTag, 'addrtype');\n      if (type === 'mac') {\n        mac = attr(addressTag, 'addr').toLowerCase();\n        vendor = attr(addressTag, 'vendor');\n      } else if (!ip) {\n        ip = attr(addressTag, 'addr');\n      }\n    }\n    if (!ip) {\n      continue;\n    }\n\n    const hostnameTag = (block.match(\u002F\u003Chostname\\s[^>]*>\u002F) || [''])[0];\n    const openPorts = {};\n    for (const portBlock of block.match(\u002F\u003Cport\\s[^>]*>[\\s\\S]*?\u003C\\\u002Fport>\u002Fg) || []) {\n      const portTag = portBlock.match(\u002F\u003Cport\\s[^>]*>\u002F)[0];\n      const stateTag = (portBlock.match(\u002F\u003Cstate\\s[^>]*>\u002F) || [''])[0];\n      const serviceTag = (portBlock.match(\u002F\u003Cservice\\s[^>]*>\u002F) || [''])[0];\n      if (attr(stateTag, 'state') === 'open') {\n        openPorts[`${attr(portTag, 'protocol')}\u002F${attr(portTag, 'portid')}`] = attr(serviceTag, 'name') || '';\n      }\n    }\n\n    hosts.set(ip, { ip, hostname: attr(hostnameTag, 'name'), mac, vendor, openPorts });\n  }\n\n  return { started: attr(runTag, 'startstr'), hosts };\n}\n\nfunction diffScans(baseline, current) {\n  const newHosts = [];\n  const removedHosts = [];\n  const movedHosts = [];\n  const changedPorts = [];\n\n  const baselineByMac = new Map([...baseline.values()].filter((h) => h.mac).map((h) => [h.mac, h]));\n  const currentByMac = new Map([...current.values()].filter((h) => h.mac).map((h) => [h.mac, h]));\n  \u002F\u002F Current IP -> baseline host for moved hosts, so their ports get compared too.\n  const movedFrom = new Map();\n\n  for (const [ip, host] of current) {\n    if (baseline.has(ip)) {\n      continue;\n    }\n    const previous = host.mac ? baselineByMac.get(host.mac) : null;\n    if (previous && !current.has(previous.ip)) {\n      movedHosts.push({ mac: host.mac, from: previous.ip, to: ip, hostname: host.hostname });\n      movedFrom.set(ip, previous);\n    } else {\n      newHosts.push(host);\n    }\n  }\n\n  for (const [ip, host] of baseline) {\n    if (current.has(ip)) {\n      continue;\n    }\n    const moved = host.mac && currentByMac.has(host.mac) && !baseline.has(currentByMac.get(host.mac).ip);\n    if (!moved) {\n      removedHosts.push(host);\n    }\n  }\n\n  for (const [ip, currentHost] of current) {\n    const baselineHost = baseline.get(ip) || movedFrom.get(ip);\n    if (!baselineHost) {\n      continue;\n    }\n    const added = Object.keys(currentHost.openPorts).filter((p) => !(p in baselineHost.openPorts));\n    const dropped = Object.keys(baselineHost.openPorts).filter((p) => !(p in currentHost.openPorts));\n    if (added.length || dropped.length) {\n      changedPorts.push({\n        ip,\n        hostname: currentHost.hostname,\n        addedPorts: added.map((p) => ({ port: p, service: currentHost.openPorts[p] })),\n        droppedPorts: dropped.map((p) => ({ port: p, service: baselineHost.openPorts[p] })),\n      });\n    }\n  }\n\n  return { newHosts, removedHosts, movedHosts, changedPorts };\n}\n\nfunction printSummary(report) {\n  const { newHosts, removedHosts, movedHosts, changedPorts } = report;\n  console.error(`Baseline: ${report.baseline} (${report.baselineStarted})  Current: ${report.current} (${report.currentStarted})`);\n  console.error(`New hosts: ${newHosts.length}, removed: ${removedHosts.length}, moved: ${movedHosts.length}, port changes: ${changedPorts.length}\\n`);\n  for (const h of newHosts) {\n    const mac = h.mac ? `mac ${h.mac}` : '';\n    console.error(`  NEW      ${h.ip.padEnd(12)} ${(h.hostname || '(unknown)').padEnd(20)} ${mac}  ports: ${Object.keys(h.openPorts).join(', ') || 'none open'}`);\n  }\n  for (const h of removedHosts) {\n    console.error(`  REMOVED  ${h.ip.padEnd(12)} ${h.hostname || ''}`);\n  }\n  for (const m of movedHosts) {\n    console.error(`  MOVED    ${m.mac}  ${m.from} -> ${m.to}`);\n  }\n  for (const c of changedPorts) {\n    const parts = [\n      ...c.addedPorts.map((p) => `+${p.port} (${p.service})`),\n      ...c.droppedPorts.map((p) => `-${p.port} (${p.service})`),\n    ];\n    console.error(`  PORTS    ${c.ip.padEnd(12)} ${parts.join(' ')}`);\n  }\n}\n\nfunction main() {\n  const args = parseArgs(process.argv.slice(2));\n  const [baselinePath, currentPath] = args.files;\n\n  const baseline = parseScan(fs.readFileSync(path.resolve(baselinePath), 'utf8'));\n  const current = parseScan(fs.readFileSync(path.resolve(currentPath), 'utf8'));\n  const diff = diffScans(baseline.hosts, current.hosts);\n\n  const report = {\n    baseline: baselinePath,\n    baselineStarted: baseline.started,\n    current: currentPath,\n    currentStarted: current.started,\n    summary: {\n      newHosts: diff.newHosts.length,\n      removedHosts: diff.removedHosts.length,\n      movedHosts: diff.movedHosts.length,\n      hostsWithPortChanges: diff.changedPorts.length,\n    },\n    ...diff,\n  };\n\n  printSummary(report);\n  const output = JSON.stringify(report, null, 2);\n  if (args.output) {\n    fs.writeFileSync(args.output, output, 'utf8');\n    console.error(`\\nReport written to ${args.output}`);\n  } else {\n    console.log(output);\n  }\n\n  if (args.failOnNew && diff.newHosts.length > 0) {\n    process.exitCode = 2;\n  }\n}\n\nmain();\n","javascript",[15,418,419,424,429,434,439,444,449,453,458,463,468,472,477,483,489,496,505,510,534,553,558,576,602,644,658,675,694,706,727,740,750,762,768,774,793,812,817,826,832,837,852,860,913,978,983,988,1008,1051,1081,1086,1091,1106,1165,1183,1188,1194,1200,1248,1253,1271,1319,1345,1353,1358,1363,1378,1392,1406,1454,1475,1491,1513,1530,1548,1564,1570,1575,1586,1593,1598,1603,1650,1663,1720,1760,1808,1855,1878,1943,1948,1953,1958,1979,1984,1989,2008,2013,2018,2038,2050,2062,2074,2086,2091,2151,2200,2206,2222,2227,2254,2268,2275,2280,2310,2331,2342,2353,2362,2373,2378,2383,2388,2412,2424,2431,2436,2473,2485,2495,2500,2505,2510,2534,2562,2574,2581,2586,2626,2662,2682,2693,2699,2705,2724,2743,2749,2754,2759,2764,2772,2777,2782,2797,2831,2885,2940,2957,2991,3092,3097,3113,3156,3161,3178,3221,3226,3243,3256,3299,3338,3344,3393,3398,3403,3408,3419,3443,3465,3470,3502,3529,3544,3549,3561,3567,3573,3579,3585,3591,3602,3612,3622,3632,3638,3647,3653,3658,3667,3696,3704,3720,3748,3758,3769,3774,3779,3801,3813,3818,3823,3828],{"__ignoreMap":94},[98,420,421],{"class":100,"line":101},[98,422,423],{"class":140},"#!\u002Fusr\u002Fbin\u002Fenv node\n",[98,425,426],{"class":100,"line":137},[98,427,428],{"class":140},"\u002F**\n",[98,430,431],{"class":100,"line":144},[98,432,433],{"class":140}," * diff-scans.js\n",[98,435,436],{"class":100,"line":253},[98,437,438],{"class":140}," *\n",[98,440,441],{"class":100,"line":262},[98,442,443],{"class":140}," * Diff two nmap XML scans (nmap -oX output) and report hosts that appeared,\n",[98,445,446],{"class":100,"line":276},[98,447,448],{"class":140}," * disappeared, moved to a new IP (same MAC), or changed their open ports.\n",[98,450,451],{"class":100,"line":298},[98,452,438],{"class":140},[98,454,455],{"class":100,"line":315},[98,456,457],{"class":140}," * Reads: two nmap XML files given as CLI arguments.\n",[98,459,460],{"class":100,"line":333},[98,461,462],{"class":140}," * Writes: a JSON report to stdout, or to --output if given.\n",[98,464,465],{"class":100,"line":362},[98,466,467],{"class":140}," * Exit code: 2 when --fail-on-new is set and new hosts were found.\n",[98,469,470],{"class":100,"line":393},[98,471,438],{"class":140},[98,473,474],{"class":100,"line":399},[98,475,476],{"class":140}," * Dependency-free: it parses the regular subset of nmap's XML it needs with\n",[98,478,480],{"class":100,"line":479},13,[98,481,482],{"class":140}," * regular expressions. Point it at your own scan output, not untrusted XML.\n",[98,484,486],{"class":100,"line":485},14,[98,487,488],{"class":140}," *\u002F\n",[98,490,492],{"class":100,"line":491},15,[98,493,495],{"emptyLinePlaceholder":494},true,"\n",[98,497,499,502],{"class":100,"line":498},16,[98,500,501],{"class":108},"'use strict'",[98,503,504],{"class":265},";\n",[98,506,508],{"class":100,"line":507},17,[98,509,495],{"emptyLinePlaceholder":494},[98,511,513,516,519,522,525,528,531],{"class":100,"line":512},18,[98,514,515],{"class":269},"const",[98,517,518],{"class":112}," fs",[98,520,521],{"class":269}," =",[98,523,524],{"class":104}," require",[98,526,527],{"class":265},"(",[98,529,530],{"class":108},"'fs'",[98,532,533],{"class":265},");\n",[98,535,537,539,542,544,546,548,551],{"class":100,"line":536},19,[98,538,515],{"class":269},[98,540,541],{"class":112}," path",[98,543,521],{"class":269},[98,545,524],{"class":104},[98,547,527],{"class":265},[98,549,550],{"class":108},"'path'",[98,552,533],{"class":265},[98,554,556],{"class":100,"line":555},20,[98,557,495],{"emptyLinePlaceholder":494},[98,559,561,564,567,569,573],{"class":100,"line":560},21,[98,562,563],{"class":269},"function",[98,565,566],{"class":104}," parseArgs",[98,568,527],{"class":265},[98,570,572],{"class":571},"s9osk","argv",[98,574,575],{"class":265},") {\n",[98,577,579,582,585,587,590,593,596,599],{"class":100,"line":578},22,[98,580,581],{"class":269},"  const",[98,583,584],{"class":112}," args",[98,586,521],{"class":269},[98,588,589],{"class":265}," { output: ",[98,591,592],{"class":112},"null",[98,594,595],{"class":265},", failOnNew: ",[98,597,598],{"class":112},"false",[98,600,601],{"class":265},", files: [] };\n",[98,603,605,608,611,614,617,619,622,625,628,631,634,636,639,642],{"class":100,"line":604},23,[98,606,607],{"class":269},"  for",[98,609,610],{"class":265}," (",[98,612,613],{"class":269},"let",[98,615,616],{"class":265}," i ",[98,618,270],{"class":269},[98,620,621],{"class":112}," 0",[98,623,624],{"class":265},"; i ",[98,626,627],{"class":269},"\u003C",[98,629,630],{"class":265}," argv.",[98,632,633],{"class":112},"length",[98,635,624],{"class":265},[98,637,638],{"class":269},"+=",[98,640,641],{"class":112}," 1",[98,643,575],{"class":265},[98,645,647,650,653,655],{"class":100,"line":646},24,[98,648,649],{"class":269},"    const",[98,651,652],{"class":112}," arg",[98,654,521],{"class":269},[98,656,657],{"class":265}," argv[i];\n",[98,659,661,664,667,670,673],{"class":100,"line":660},25,[98,662,663],{"class":269},"    if",[98,665,666],{"class":265}," (arg ",[98,668,669],{"class":269},"===",[98,671,672],{"class":108}," '--output'",[98,674,575],{"class":265},[98,676,678,681,683,686,689,691],{"class":100,"line":677},26,[98,679,680],{"class":265},"      args.output ",[98,682,270],{"class":269},[98,684,685],{"class":265}," argv[i ",[98,687,688],{"class":269},"+",[98,690,641],{"class":112},[98,692,693],{"class":265},"];\n",[98,695,697,700,702,704],{"class":100,"line":696},27,[98,698,699],{"class":265},"      i ",[98,701,638],{"class":269},[98,703,641],{"class":112},[98,705,504],{"class":265},[98,707,709,712,715,718,720,722,725],{"class":100,"line":708},28,[98,710,711],{"class":265},"    } ",[98,713,714],{"class":269},"else",[98,716,717],{"class":269}," if",[98,719,666],{"class":265},[98,721,669],{"class":269},[98,723,724],{"class":108}," '--fail-on-new'",[98,726,575],{"class":265},[98,728,730,733,735,738],{"class":100,"line":729},29,[98,731,732],{"class":265},"      args.failOnNew ",[98,734,270],{"class":269},[98,736,737],{"class":112}," true",[98,739,504],{"class":265},[98,741,743,745,747],{"class":100,"line":742},30,[98,744,711],{"class":265},[98,746,714],{"class":269},[98,748,749],{"class":265}," {\n",[98,751,753,756,759],{"class":100,"line":752},31,[98,754,755],{"class":265},"      args.files.",[98,757,758],{"class":104},"push",[98,760,761],{"class":265},"(arg);\n",[98,763,765],{"class":100,"line":764},32,[98,766,767],{"class":265},"    }\n",[98,769,771],{"class":100,"line":770},33,[98,772,773],{"class":265},"  }\n",[98,775,777,780,783,785,788,791],{"class":100,"line":776},34,[98,778,779],{"class":269},"  if",[98,781,782],{"class":265}," (args.files.",[98,784,633],{"class":112},[98,786,787],{"class":269}," !==",[98,789,790],{"class":112}," 2",[98,792,575],{"class":265},[98,794,796,799,802,805,807,810],{"class":100,"line":795},35,[98,797,798],{"class":269},"    throw",[98,800,801],{"class":269}," new",[98,803,804],{"class":104}," Error",[98,806,527],{"class":265},[98,808,809],{"class":108},"'Usage: diff-scans.js \u003Cbaseline.xml> \u003Ccurrent.xml> [--output report.json] [--fail-on-new]'",[98,811,533],{"class":265},[98,813,815],{"class":100,"line":814},36,[98,816,773],{"class":265},[98,818,820,823],{"class":100,"line":819},37,[98,821,822],{"class":269},"  return",[98,824,825],{"class":265}," args;\n",[98,827,829],{"class":100,"line":828},38,[98,830,831],{"class":265},"}\n",[98,833,835],{"class":100,"line":834},39,[98,836,495],{"emptyLinePlaceholder":494},[98,838,840,842,845,847,850],{"class":100,"line":839},40,[98,841,563],{"class":269},[98,843,844],{"class":104}," decode",[98,846,527],{"class":265},[98,848,849],{"class":571},"value",[98,851,575],{"class":265},[98,853,855,857],{"class":100,"line":854},41,[98,856,822],{"class":269},[98,858,859],{"class":265}," value\n",[98,861,863,866,869,871,874,878,880,883,886,889,892,894,896,898,901,903,905,907,910],{"class":100,"line":862},42,[98,864,865],{"class":265},"    .",[98,867,868],{"class":104},"replace",[98,870,527],{"class":265},[98,872,873],{"class":108},"\u002F",[98,875,877],{"class":876},"sns5M","&lt;",[98,879,873],{"class":108},[98,881,882],{"class":269},"g",[98,884,885],{"class":265},", ",[98,887,888],{"class":108},"'\u003C'",[98,890,891],{"class":265},").",[98,893,868],{"class":104},[98,895,527],{"class":265},[98,897,873],{"class":108},[98,899,900],{"class":876},"&gt;",[98,902,873],{"class":108},[98,904,882],{"class":269},[98,906,885],{"class":265},[98,908,909],{"class":108},"'>'",[98,911,912],{"class":265},")\n",[98,914,916,918,920,922,924,927,929,931,933,936,938,940,942,944,947,949,951,953,956,958,960,962,964,967,969,971,973,976],{"class":100,"line":915},43,[98,917,865],{"class":265},[98,919,868],{"class":104},[98,921,527],{"class":265},[98,923,873],{"class":108},[98,925,926],{"class":876},"&quot;",[98,928,873],{"class":108},[98,930,882],{"class":269},[98,932,885],{"class":265},[98,934,935],{"class":108},"'\"'",[98,937,891],{"class":265},[98,939,868],{"class":104},[98,941,527],{"class":265},[98,943,873],{"class":108},[98,945,946],{"class":876},"&apos;",[98,948,873],{"class":108},[98,950,882],{"class":269},[98,952,885],{"class":265},[98,954,955],{"class":108},"\"'\"",[98,957,891],{"class":265},[98,959,868],{"class":104},[98,961,527],{"class":265},[98,963,873],{"class":108},[98,965,966],{"class":876},"&amp;",[98,968,873],{"class":108},[98,970,882],{"class":269},[98,972,885],{"class":265},[98,974,975],{"class":108},"'&'",[98,977,533],{"class":265},[98,979,981],{"class":100,"line":980},44,[98,982,831],{"class":265},[98,984,986],{"class":100,"line":985},45,[98,987,495],{"emptyLinePlaceholder":494},[98,989,991,993,996,998,1001,1003,1006],{"class":100,"line":990},46,[98,992,563],{"class":269},[98,994,995],{"class":104}," attr",[98,997,527],{"class":265},[98,999,1000],{"class":571},"tag",[98,1002,885],{"class":265},[98,1004,1005],{"class":571},"name",[98,1007,575],{"class":265},[98,1009,1011,1013,1016,1018,1021,1024,1026,1029,1032,1034,1037,1040,1043,1045,1048],{"class":100,"line":1010},47,[98,1012,581],{"class":269},[98,1014,1015],{"class":112}," match",[98,1017,521],{"class":269},[98,1019,1020],{"class":265}," tag.",[98,1022,1023],{"class":104},"match",[98,1025,527],{"class":265},[98,1027,1028],{"class":269},"new",[98,1030,1031],{"class":104}," RegExp",[98,1033,527],{"class":265},[98,1035,1036],{"class":108},"`",[98,1038,1039],{"class":112},"\\\\",[98,1041,1042],{"class":108},"s${",[98,1044,1005],{"class":265},[98,1046,1047],{"class":108},"}=\"([^\"]*)\"`",[98,1049,1050],{"class":265},"));\n",[98,1052,1054,1056,1059,1062,1064,1067,1070,1073,1076,1079],{"class":100,"line":1053},48,[98,1055,822],{"class":269},[98,1057,1058],{"class":265}," match ",[98,1060,1061],{"class":269},"?",[98,1063,844],{"class":104},[98,1065,1066],{"class":265},"(match[",[98,1068,1069],{"class":112},"1",[98,1071,1072],{"class":265},"]) ",[98,1074,1075],{"class":269},":",[98,1077,1078],{"class":112}," null",[98,1080,504],{"class":265},[98,1082,1084],{"class":100,"line":1083},49,[98,1085,831],{"class":265},[98,1087,1089],{"class":100,"line":1088},50,[98,1090,495],{"emptyLinePlaceholder":494},[98,1092,1094,1096,1099,1101,1104],{"class":100,"line":1093},51,[98,1095,563],{"class":269},[98,1097,1098],{"class":104}," parseScan",[98,1100,527],{"class":265},[98,1102,1103],{"class":571},"xml",[98,1105,575],{"class":265},[98,1107,1109,1111,1114,1116,1119,1121,1123,1125,1128,1131,1134,1137,1140,1143,1145,1148,1151,1154,1157,1160,1163],{"class":100,"line":1108},52,[98,1110,581],{"class":269},[98,1112,1113],{"class":112}," runTag",[98,1115,521],{"class":269},[98,1117,1118],{"class":265}," (xml.",[98,1120,1023],{"class":104},[98,1122,527],{"class":265},[98,1124,873],{"class":108},[98,1126,1127],{"class":876},"\u003Cnmaprun",[98,1129,1130],{"class":112},"\\s[",[98,1132,1133],{"class":269},"^",[98,1135,1136],{"class":112},">]",[98,1138,1139],{"class":269},"*",[98,1141,1142],{"class":876},">",[98,1144,873],{"class":108},[98,1146,1147],{"class":265},") ",[98,1149,1150],{"class":269},"||",[98,1152,1153],{"class":265}," [",[98,1155,1156],{"class":108},"''",[98,1158,1159],{"class":265},"])[",[98,1161,1162],{"class":112},"0",[98,1164,693],{"class":265},[98,1166,1168,1170,1173,1175,1177,1180],{"class":100,"line":1167},53,[98,1169,581],{"class":269},[98,1171,1172],{"class":112}," hosts",[98,1174,521],{"class":269},[98,1176,801],{"class":269},[98,1178,1179],{"class":104}," Map",[98,1181,1182],{"class":265},"();\n",[98,1184,1186],{"class":100,"line":1185},54,[98,1187,495],{"emptyLinePlaceholder":494},[98,1189,1191],{"class":100,"line":1190},55,[98,1192,1193],{"class":140},"  \u002F\u002F \"\u003Chost \" or \"\u003Chost>\" only: nmap's DTD also allows \u003Chosthint> elements, which a\n",[98,1195,1197],{"class":100,"line":1196},56,[98,1198,1199],{"class":140},"  \u002F\u002F looser \u002F\u003Chost[\\s\\S]*?\u003C\\\u002Fhost>\u002F pattern would swallow along with the next host.\n",[98,1201,1203,1205,1208,1210,1213,1215,1217,1219,1222,1225,1228,1230,1234,1237,1239,1241,1243,1245],{"class":100,"line":1202},57,[98,1204,581],{"class":269},[98,1206,1207],{"class":112}," hostBlocks",[98,1209,521],{"class":269},[98,1211,1212],{"class":265}," xml.",[98,1214,1023],{"class":104},[98,1216,527],{"class":265},[98,1218,873],{"class":108},[98,1220,1221],{"class":876},"\u003Chost",[98,1223,1224],{"class":112},"[\\s>][\\s\\S]",[98,1226,1227],{"class":269},"*?",[98,1229,627],{"class":876},[98,1231,1233],{"class":1232},"sRjNt","\\\u002F",[98,1235,1236],{"class":876},"host>",[98,1238,873],{"class":108},[98,1240,882],{"class":269},[98,1242,1147],{"class":265},[98,1244,1150],{"class":269},[98,1246,1247],{"class":265}," [];\n",[98,1249,1251],{"class":100,"line":1250},58,[98,1252,495],{"emptyLinePlaceholder":494},[98,1254,1256,1258,1260,1262,1265,1268],{"class":100,"line":1255},59,[98,1257,607],{"class":269},[98,1259,610],{"class":265},[98,1261,515],{"class":269},[98,1263,1264],{"class":112}," block",[98,1266,1267],{"class":269}," of",[98,1269,1270],{"class":265}," hostBlocks) {\n",[98,1272,1274,1276,1279,1281,1284,1286,1288,1290,1293,1295,1297,1299,1301,1303,1305,1307,1309,1311,1313,1315,1317],{"class":100,"line":1273},60,[98,1275,649],{"class":269},[98,1277,1278],{"class":112}," statusTag",[98,1280,521],{"class":269},[98,1282,1283],{"class":265}," (block.",[98,1285,1023],{"class":104},[98,1287,527],{"class":265},[98,1289,873],{"class":108},[98,1291,1292],{"class":876},"\u003Cstatus",[98,1294,1130],{"class":112},[98,1296,1133],{"class":269},[98,1298,1136],{"class":112},[98,1300,1139],{"class":269},[98,1302,1142],{"class":876},[98,1304,873],{"class":108},[98,1306,1147],{"class":265},[98,1308,1150],{"class":269},[98,1310,1153],{"class":265},[98,1312,1156],{"class":108},[98,1314,1159],{"class":265},[98,1316,1162],{"class":112},[98,1318,693],{"class":265},[98,1320,1322,1324,1326,1329,1332,1335,1337,1340,1343],{"class":100,"line":1321},61,[98,1323,663],{"class":269},[98,1325,610],{"class":265},[98,1327,1328],{"class":104},"attr",[98,1330,1331],{"class":265},"(statusTag, ",[98,1333,1334],{"class":108},"'state'",[98,1336,1147],{"class":265},[98,1338,1339],{"class":269},"!==",[98,1341,1342],{"class":108}," 'up'",[98,1344,575],{"class":265},[98,1346,1348,1351],{"class":100,"line":1347},62,[98,1349,1350],{"class":269},"      continue",[98,1352,504],{"class":265},[98,1354,1356],{"class":100,"line":1355},63,[98,1357,767],{"class":265},[98,1359,1361],{"class":100,"line":1360},64,[98,1362,495],{"emptyLinePlaceholder":494},[98,1364,1366,1369,1372,1374,1376],{"class":100,"line":1365},65,[98,1367,1368],{"class":269},"    let",[98,1370,1371],{"class":265}," ip ",[98,1373,270],{"class":269},[98,1375,1078],{"class":112},[98,1377,504],{"class":265},[98,1379,1381,1383,1386,1388,1390],{"class":100,"line":1380},66,[98,1382,1368],{"class":269},[98,1384,1385],{"class":265}," mac ",[98,1387,270],{"class":269},[98,1389,1078],{"class":112},[98,1391,504],{"class":265},[98,1393,1395,1397,1400,1402,1404],{"class":100,"line":1394},67,[98,1396,1368],{"class":269},[98,1398,1399],{"class":265}," vendor ",[98,1401,270],{"class":269},[98,1403,1078],{"class":112},[98,1405,504],{"class":265},[98,1407,1409,1412,1414,1416,1419,1421,1424,1426,1428,1430,1433,1435,1437,1439,1441,1443,1445,1447,1449,1451],{"class":100,"line":1408},68,[98,1410,1411],{"class":269},"    for",[98,1413,610],{"class":265},[98,1415,515],{"class":269},[98,1417,1418],{"class":112}," addressTag",[98,1420,1267],{"class":269},[98,1422,1423],{"class":265}," block.",[98,1425,1023],{"class":104},[98,1427,527],{"class":265},[98,1429,873],{"class":108},[98,1431,1432],{"class":876},"\u003Caddress",[98,1434,1130],{"class":112},[98,1436,1133],{"class":269},[98,1438,1136],{"class":112},[98,1440,1139],{"class":269},[98,1442,1142],{"class":876},[98,1444,873],{"class":108},[98,1446,882],{"class":269},[98,1448,1147],{"class":265},[98,1450,1150],{"class":269},[98,1452,1453],{"class":265}," []) {\n",[98,1455,1457,1460,1463,1465,1467,1470,1473],{"class":100,"line":1456},69,[98,1458,1459],{"class":269},"      const",[98,1461,1462],{"class":112}," type",[98,1464,521],{"class":269},[98,1466,995],{"class":104},[98,1468,1469],{"class":265},"(addressTag, ",[98,1471,1472],{"class":108},"'addrtype'",[98,1474,533],{"class":265},[98,1476,1478,1481,1484,1486,1489],{"class":100,"line":1477},70,[98,1479,1480],{"class":269},"      if",[98,1482,1483],{"class":265}," (type ",[98,1485,669],{"class":269},[98,1487,1488],{"class":108}," 'mac'",[98,1490,575],{"class":265},[98,1492,1494,1497,1499,1501,1503,1506,1508,1511],{"class":100,"line":1493},71,[98,1495,1496],{"class":265},"        mac ",[98,1498,270],{"class":269},[98,1500,995],{"class":104},[98,1502,1469],{"class":265},[98,1504,1505],{"class":108},"'addr'",[98,1507,891],{"class":265},[98,1509,1510],{"class":104},"toLowerCase",[98,1512,1182],{"class":265},[98,1514,1516,1519,1521,1523,1525,1528],{"class":100,"line":1515},72,[98,1517,1518],{"class":265},"        vendor ",[98,1520,270],{"class":269},[98,1522,995],{"class":104},[98,1524,1469],{"class":265},[98,1526,1527],{"class":108},"'vendor'",[98,1529,533],{"class":265},[98,1531,1533,1536,1538,1540,1542,1545],{"class":100,"line":1532},73,[98,1534,1535],{"class":265},"      } ",[98,1537,714],{"class":269},[98,1539,717],{"class":269},[98,1541,610],{"class":265},[98,1543,1544],{"class":269},"!",[98,1546,1547],{"class":265},"ip) {\n",[98,1549,1551,1554,1556,1558,1560,1562],{"class":100,"line":1550},74,[98,1552,1553],{"class":265},"        ip ",[98,1555,270],{"class":269},[98,1557,995],{"class":104},[98,1559,1469],{"class":265},[98,1561,1505],{"class":108},[98,1563,533],{"class":265},[98,1565,1567],{"class":100,"line":1566},75,[98,1568,1569],{"class":265},"      }\n",[98,1571,1573],{"class":100,"line":1572},76,[98,1574,767],{"class":265},[98,1576,1578,1580,1582,1584],{"class":100,"line":1577},77,[98,1579,663],{"class":269},[98,1581,610],{"class":265},[98,1583,1544],{"class":269},[98,1585,1547],{"class":265},[98,1587,1589,1591],{"class":100,"line":1588},78,[98,1590,1350],{"class":269},[98,1592,504],{"class":265},[98,1594,1596],{"class":100,"line":1595},79,[98,1597,767],{"class":265},[98,1599,1601],{"class":100,"line":1600},80,[98,1602,495],{"emptyLinePlaceholder":494},[98,1604,1606,1608,1611,1613,1615,1617,1619,1621,1624,1626,1628,1630,1632,1634,1636,1638,1640,1642,1644,1646,1648],{"class":100,"line":1605},81,[98,1607,649],{"class":269},[98,1609,1610],{"class":112}," hostnameTag",[98,1612,521],{"class":269},[98,1614,1283],{"class":265},[98,1616,1023],{"class":104},[98,1618,527],{"class":265},[98,1620,873],{"class":108},[98,1622,1623],{"class":876},"\u003Chostname",[98,1625,1130],{"class":112},[98,1627,1133],{"class":269},[98,1629,1136],{"class":112},[98,1631,1139],{"class":269},[98,1633,1142],{"class":876},[98,1635,873],{"class":108},[98,1637,1147],{"class":265},[98,1639,1150],{"class":269},[98,1641,1153],{"class":265},[98,1643,1156],{"class":108},[98,1645,1159],{"class":265},[98,1647,1162],{"class":112},[98,1649,693],{"class":265},[98,1651,1653,1655,1658,1660],{"class":100,"line":1652},82,[98,1654,649],{"class":269},[98,1656,1657],{"class":112}," openPorts",[98,1659,521],{"class":269},[98,1661,1662],{"class":265}," {};\n",[98,1664,1666,1668,1670,1672,1675,1677,1679,1681,1683,1685,1688,1690,1692,1694,1696,1698,1701,1703,1705,1707,1710,1712,1714,1716,1718],{"class":100,"line":1665},83,[98,1667,1411],{"class":269},[98,1669,610],{"class":265},[98,1671,515],{"class":269},[98,1673,1674],{"class":112}," portBlock",[98,1676,1267],{"class":269},[98,1678,1423],{"class":265},[98,1680,1023],{"class":104},[98,1682,527],{"class":265},[98,1684,873],{"class":108},[98,1686,1687],{"class":876},"\u003Cport",[98,1689,1130],{"class":112},[98,1691,1133],{"class":269},[98,1693,1136],{"class":112},[98,1695,1139],{"class":269},[98,1697,1142],{"class":876},[98,1699,1700],{"class":112},"[\\s\\S]",[98,1702,1227],{"class":269},[98,1704,627],{"class":876},[98,1706,1233],{"class":1232},[98,1708,1709],{"class":876},"port>",[98,1711,873],{"class":108},[98,1713,882],{"class":269},[98,1715,1147],{"class":265},[98,1717,1150],{"class":269},[98,1719,1453],{"class":265},[98,1721,1723,1725,1728,1730,1733,1735,1737,1739,1741,1743,1745,1747,1749,1751,1753,1756,1758],{"class":100,"line":1722},84,[98,1724,1459],{"class":269},[98,1726,1727],{"class":112}," portTag",[98,1729,521],{"class":269},[98,1731,1732],{"class":265}," portBlock.",[98,1734,1023],{"class":104},[98,1736,527],{"class":265},[98,1738,873],{"class":108},[98,1740,1687],{"class":876},[98,1742,1130],{"class":112},[98,1744,1133],{"class":269},[98,1746,1136],{"class":112},[98,1748,1139],{"class":269},[98,1750,1142],{"class":876},[98,1752,873],{"class":108},[98,1754,1755],{"class":265},")[",[98,1757,1162],{"class":112},[98,1759,693],{"class":265},[98,1761,1763,1765,1768,1770,1773,1775,1777,1779,1782,1784,1786,1788,1790,1792,1794,1796,1798,1800,1802,1804,1806],{"class":100,"line":1762},85,[98,1764,1459],{"class":269},[98,1766,1767],{"class":112}," stateTag",[98,1769,521],{"class":269},[98,1771,1772],{"class":265}," (portBlock.",[98,1774,1023],{"class":104},[98,1776,527],{"class":265},[98,1778,873],{"class":108},[98,1780,1781],{"class":876},"\u003Cstate",[98,1783,1130],{"class":112},[98,1785,1133],{"class":269},[98,1787,1136],{"class":112},[98,1789,1139],{"class":269},[98,1791,1142],{"class":876},[98,1793,873],{"class":108},[98,1795,1147],{"class":265},[98,1797,1150],{"class":269},[98,1799,1153],{"class":265},[98,1801,1156],{"class":108},[98,1803,1159],{"class":265},[98,1805,1162],{"class":112},[98,1807,693],{"class":265},[98,1809,1811,1813,1816,1818,1820,1822,1824,1826,1829,1831,1833,1835,1837,1839,1841,1843,1845,1847,1849,1851,1853],{"class":100,"line":1810},86,[98,1812,1459],{"class":269},[98,1814,1815],{"class":112}," serviceTag",[98,1817,521],{"class":269},[98,1819,1772],{"class":265},[98,1821,1023],{"class":104},[98,1823,527],{"class":265},[98,1825,873],{"class":108},[98,1827,1828],{"class":876},"\u003Cservice",[98,1830,1130],{"class":112},[98,1832,1133],{"class":269},[98,1834,1136],{"class":112},[98,1836,1139],{"class":269},[98,1838,1142],{"class":876},[98,1840,873],{"class":108},[98,1842,1147],{"class":265},[98,1844,1150],{"class":269},[98,1846,1153],{"class":265},[98,1848,1156],{"class":108},[98,1850,1159],{"class":265},[98,1852,1162],{"class":112},[98,1854,693],{"class":265},[98,1856,1858,1860,1862,1864,1867,1869,1871,1873,1876],{"class":100,"line":1857},87,[98,1859,1480],{"class":269},[98,1861,610],{"class":265},[98,1863,1328],{"class":104},[98,1865,1866],{"class":265},"(stateTag, ",[98,1868,1334],{"class":108},[98,1870,1147],{"class":265},[98,1872,669],{"class":269},[98,1874,1875],{"class":108}," 'open'",[98,1877,575],{"class":265},[98,1879,1881,1884,1887,1889,1891,1894,1896,1899,1902,1905,1907,1909,1911,1913,1916,1918,1921,1924,1926,1928,1931,1934,1936,1938,1941],{"class":100,"line":1880},88,[98,1882,1883],{"class":265},"        openPorts[",[98,1885,1886],{"class":108},"`${",[98,1888,1328],{"class":104},[98,1890,527],{"class":108},[98,1892,1893],{"class":265},"portTag",[98,1895,885],{"class":108},[98,1897,1898],{"class":108},"'protocol'",[98,1900,1901],{"class":108},")",[98,1903,1904],{"class":108},"}\u002F${",[98,1906,1328],{"class":104},[98,1908,527],{"class":108},[98,1910,1893],{"class":265},[98,1912,885],{"class":108},[98,1914,1915],{"class":108},"'portid'",[98,1917,1901],{"class":108},[98,1919,1920],{"class":108},"}`",[98,1922,1923],{"class":265},"] ",[98,1925,270],{"class":269},[98,1927,995],{"class":104},[98,1929,1930],{"class":265},"(serviceTag, ",[98,1932,1933],{"class":108},"'name'",[98,1935,1147],{"class":265},[98,1937,1150],{"class":269},[98,1939,1940],{"class":108}," ''",[98,1942,504],{"class":265},[98,1944,1946],{"class":100,"line":1945},89,[98,1947,1569],{"class":265},[98,1949,1951],{"class":100,"line":1950},90,[98,1952,767],{"class":265},[98,1954,1956],{"class":100,"line":1955},91,[98,1957,495],{"emptyLinePlaceholder":494},[98,1959,1961,1964,1966,1969,1971,1974,1976],{"class":100,"line":1960},92,[98,1962,1963],{"class":265},"    hosts.",[98,1965,244],{"class":104},[98,1967,1968],{"class":265},"(ip, { ip, hostname: ",[98,1970,1328],{"class":104},[98,1972,1973],{"class":265},"(hostnameTag, ",[98,1975,1933],{"class":108},[98,1977,1978],{"class":265},"), mac, vendor, openPorts });\n",[98,1980,1982],{"class":100,"line":1981},93,[98,1983,773],{"class":265},[98,1985,1987],{"class":100,"line":1986},94,[98,1988,495],{"emptyLinePlaceholder":494},[98,1990,1992,1994,1997,1999,2002,2005],{"class":100,"line":1991},95,[98,1993,822],{"class":269},[98,1995,1996],{"class":265}," { started: ",[98,1998,1328],{"class":104},[98,2000,2001],{"class":265},"(runTag, ",[98,2003,2004],{"class":108},"'startstr'",[98,2006,2007],{"class":265},"), hosts };\n",[98,2009,2011],{"class":100,"line":2010},96,[98,2012,831],{"class":265},[98,2014,2016],{"class":100,"line":2015},97,[98,2017,495],{"emptyLinePlaceholder":494},[98,2019,2021,2023,2026,2028,2031,2033,2036],{"class":100,"line":2020},98,[98,2022,563],{"class":269},[98,2024,2025],{"class":104}," diffScans",[98,2027,527],{"class":265},[98,2029,2030],{"class":571},"baseline",[98,2032,885],{"class":265},[98,2034,2035],{"class":571},"current",[98,2037,575],{"class":265},[98,2039,2041,2043,2046,2048],{"class":100,"line":2040},99,[98,2042,581],{"class":269},[98,2044,2045],{"class":112}," newHosts",[98,2047,521],{"class":269},[98,2049,1247],{"class":265},[98,2051,2053,2055,2058,2060],{"class":100,"line":2052},100,[98,2054,581],{"class":269},[98,2056,2057],{"class":112}," removedHosts",[98,2059,521],{"class":269},[98,2061,1247],{"class":265},[98,2063,2065,2067,2070,2072],{"class":100,"line":2064},101,[98,2066,581],{"class":269},[98,2068,2069],{"class":112}," movedHosts",[98,2071,521],{"class":269},[98,2073,1247],{"class":265},[98,2075,2077,2079,2082,2084],{"class":100,"line":2076},102,[98,2078,581],{"class":269},[98,2080,2081],{"class":112}," changedPorts",[98,2083,521],{"class":269},[98,2085,1247],{"class":265},[98,2087,2089],{"class":100,"line":2088},103,[98,2090,495],{"emptyLinePlaceholder":494},[98,2092,2094,2096,2099,2101,2103,2105,2108,2111,2114,2117,2120,2123,2126,2129,2131,2134,2137,2140,2142,2144,2146,2148],{"class":100,"line":2093},104,[98,2095,581],{"class":269},[98,2097,2098],{"class":112}," baselineByMac",[98,2100,521],{"class":269},[98,2102,801],{"class":269},[98,2104,1179],{"class":104},[98,2106,2107],{"class":265},"([",[98,2109,2110],{"class":269},"...",[98,2112,2113],{"class":265},"baseline.",[98,2115,2116],{"class":104},"values",[98,2118,2119],{"class":265},"()].",[98,2121,2122],{"class":104},"filter",[98,2124,2125],{"class":265},"((",[98,2127,2128],{"class":571},"h",[98,2130,1147],{"class":265},[98,2132,2133],{"class":269},"=>",[98,2135,2136],{"class":265}," h.mac).",[98,2138,2139],{"class":104},"map",[98,2141,2125],{"class":265},[98,2143,2128],{"class":571},[98,2145,1147],{"class":265},[98,2147,2133],{"class":269},[98,2149,2150],{"class":265}," [h.mac, h]));\n",[98,2152,2154,2156,2159,2161,2163,2165,2167,2169,2172,2174,2176,2178,2180,2182,2184,2186,2188,2190,2192,2194,2196,2198],{"class":100,"line":2153},105,[98,2155,581],{"class":269},[98,2157,2158],{"class":112}," currentByMac",[98,2160,521],{"class":269},[98,2162,801],{"class":269},[98,2164,1179],{"class":104},[98,2166,2107],{"class":265},[98,2168,2110],{"class":269},[98,2170,2171],{"class":265},"current.",[98,2173,2116],{"class":104},[98,2175,2119],{"class":265},[98,2177,2122],{"class":104},[98,2179,2125],{"class":265},[98,2181,2128],{"class":571},[98,2183,1147],{"class":265},[98,2185,2133],{"class":269},[98,2187,2136],{"class":265},[98,2189,2139],{"class":104},[98,2191,2125],{"class":265},[98,2193,2128],{"class":571},[98,2195,1147],{"class":265},[98,2197,2133],{"class":269},[98,2199,2150],{"class":265},[98,2201,2203],{"class":100,"line":2202},106,[98,2204,2205],{"class":140},"  \u002F\u002F Current IP -> baseline host for moved hosts, so their ports get compared too.\n",[98,2207,2209,2211,2214,2216,2218,2220],{"class":100,"line":2208},107,[98,2210,581],{"class":269},[98,2212,2213],{"class":112}," movedFrom",[98,2215,521],{"class":269},[98,2217,801],{"class":269},[98,2219,1179],{"class":104},[98,2221,1182],{"class":265},[98,2223,2225],{"class":100,"line":2224},108,[98,2226,495],{"emptyLinePlaceholder":494},[98,2228,2230,2232,2234,2236,2238,2241,2243,2246,2248,2251],{"class":100,"line":2229},109,[98,2231,607],{"class":269},[98,2233,610],{"class":265},[98,2235,515],{"class":269},[98,2237,1153],{"class":265},[98,2239,2240],{"class":112},"ip",[98,2242,885],{"class":265},[98,2244,2245],{"class":112},"host",[98,2247,1923],{"class":265},[98,2249,2250],{"class":269},"of",[98,2252,2253],{"class":265}," current) {\n",[98,2255,2257,2259,2262,2265],{"class":100,"line":2256},110,[98,2258,663],{"class":269},[98,2260,2261],{"class":265}," (baseline.",[98,2263,2264],{"class":104},"has",[98,2266,2267],{"class":265},"(ip)) {\n",[98,2269,2271,2273],{"class":100,"line":2270},111,[98,2272,1350],{"class":269},[98,2274,504],{"class":265},[98,2276,2278],{"class":100,"line":2277},112,[98,2279,767],{"class":265},[98,2281,2283,2285,2288,2290,2293,2295,2298,2301,2304,2306,2308],{"class":100,"line":2282},113,[98,2284,649],{"class":269},[98,2286,2287],{"class":112}," previous",[98,2289,521],{"class":269},[98,2291,2292],{"class":265}," host.mac ",[98,2294,1061],{"class":269},[98,2296,2297],{"class":265}," baselineByMac.",[98,2299,2300],{"class":104},"get",[98,2302,2303],{"class":265},"(host.mac) ",[98,2305,1075],{"class":269},[98,2307,1078],{"class":112},[98,2309,504],{"class":265},[98,2311,2313,2315,2318,2321,2324,2326,2328],{"class":100,"line":2312},114,[98,2314,663],{"class":269},[98,2316,2317],{"class":265}," (previous ",[98,2319,2320],{"class":269},"&&",[98,2322,2323],{"class":269}," !",[98,2325,2171],{"class":265},[98,2327,2264],{"class":104},[98,2329,2330],{"class":265},"(previous.ip)) {\n",[98,2332,2334,2337,2339],{"class":100,"line":2333},115,[98,2335,2336],{"class":265},"      movedHosts.",[98,2338,758],{"class":104},[98,2340,2341],{"class":265},"({ mac: host.mac, from: previous.ip, to: ip, hostname: host.hostname });\n",[98,2343,2345,2348,2350],{"class":100,"line":2344},116,[98,2346,2347],{"class":265},"      movedFrom.",[98,2349,244],{"class":104},[98,2351,2352],{"class":265},"(ip, previous);\n",[98,2354,2356,2358,2360],{"class":100,"line":2355},117,[98,2357,711],{"class":265},[98,2359,714],{"class":269},[98,2361,749],{"class":265},[98,2363,2365,2368,2370],{"class":100,"line":2364},118,[98,2366,2367],{"class":265},"      newHosts.",[98,2369,758],{"class":104},[98,2371,2372],{"class":265},"(host);\n",[98,2374,2376],{"class":100,"line":2375},119,[98,2377,767],{"class":265},[98,2379,2381],{"class":100,"line":2380},120,[98,2382,773],{"class":265},[98,2384,2386],{"class":100,"line":2385},121,[98,2387,495],{"emptyLinePlaceholder":494},[98,2389,2391,2393,2395,2397,2399,2401,2403,2405,2407,2409],{"class":100,"line":2390},122,[98,2392,607],{"class":269},[98,2394,610],{"class":265},[98,2396,515],{"class":269},[98,2398,1153],{"class":265},[98,2400,2240],{"class":112},[98,2402,885],{"class":265},[98,2404,2245],{"class":112},[98,2406,1923],{"class":265},[98,2408,2250],{"class":269},[98,2410,2411],{"class":265}," baseline) {\n",[98,2413,2415,2417,2420,2422],{"class":100,"line":2414},123,[98,2416,663],{"class":269},[98,2418,2419],{"class":265}," (current.",[98,2421,2264],{"class":104},[98,2423,2267],{"class":265},[98,2425,2427,2429],{"class":100,"line":2426},124,[98,2428,1350],{"class":269},[98,2430,504],{"class":265},[98,2432,2434],{"class":100,"line":2433},125,[98,2435,767],{"class":265},[98,2437,2439,2441,2444,2446,2448,2450,2453,2455,2457,2459,2461,2463,2465,2468,2470],{"class":100,"line":2438},126,[98,2440,649],{"class":269},[98,2442,2443],{"class":112}," moved",[98,2445,521],{"class":269},[98,2447,2292],{"class":265},[98,2449,2320],{"class":269},[98,2451,2452],{"class":265}," currentByMac.",[98,2454,2264],{"class":104},[98,2456,2303],{"class":265},[98,2458,2320],{"class":269},[98,2460,2323],{"class":269},[98,2462,2113],{"class":265},[98,2464,2264],{"class":104},[98,2466,2467],{"class":265},"(currentByMac.",[98,2469,2300],{"class":104},[98,2471,2472],{"class":265},"(host.mac).ip);\n",[98,2474,2476,2478,2480,2482],{"class":100,"line":2475},127,[98,2477,663],{"class":269},[98,2479,610],{"class":265},[98,2481,1544],{"class":269},[98,2483,2484],{"class":265},"moved) {\n",[98,2486,2488,2491,2493],{"class":100,"line":2487},128,[98,2489,2490],{"class":265},"      removedHosts.",[98,2492,758],{"class":104},[98,2494,2372],{"class":265},[98,2496,2498],{"class":100,"line":2497},129,[98,2499,767],{"class":265},[98,2501,2503],{"class":100,"line":2502},130,[98,2504,773],{"class":265},[98,2506,2508],{"class":100,"line":2507},131,[98,2509,495],{"emptyLinePlaceholder":494},[98,2511,2513,2515,2517,2519,2521,2523,2525,2528,2530,2532],{"class":100,"line":2512},132,[98,2514,607],{"class":269},[98,2516,610],{"class":265},[98,2518,515],{"class":269},[98,2520,1153],{"class":265},[98,2522,2240],{"class":112},[98,2524,885],{"class":265},[98,2526,2527],{"class":112},"currentHost",[98,2529,1923],{"class":265},[98,2531,2250],{"class":269},[98,2533,2253],{"class":265},[98,2535,2537,2539,2542,2544,2547,2549,2552,2554,2557,2559],{"class":100,"line":2536},133,[98,2538,649],{"class":269},[98,2540,2541],{"class":112}," baselineHost",[98,2543,521],{"class":269},[98,2545,2546],{"class":265}," baseline.",[98,2548,2300],{"class":104},[98,2550,2551],{"class":265},"(ip) ",[98,2553,1150],{"class":269},[98,2555,2556],{"class":265}," movedFrom.",[98,2558,2300],{"class":104},[98,2560,2561],{"class":265},"(ip);\n",[98,2563,2565,2567,2569,2571],{"class":100,"line":2564},134,[98,2566,663],{"class":269},[98,2568,610],{"class":265},[98,2570,1544],{"class":269},[98,2572,2573],{"class":265},"baselineHost) {\n",[98,2575,2577,2579],{"class":100,"line":2576},135,[98,2578,1350],{"class":269},[98,2580,504],{"class":265},[98,2582,2584],{"class":100,"line":2583},136,[98,2585,767],{"class":265},[98,2587,2589,2591,2594,2596,2599,2602,2605,2607,2609,2611,2613,2615,2617,2620,2623],{"class":100,"line":2588},137,[98,2590,649],{"class":269},[98,2592,2593],{"class":112}," added",[98,2595,521],{"class":269},[98,2597,2598],{"class":265}," Object.",[98,2600,2601],{"class":104},"keys",[98,2603,2604],{"class":265},"(currentHost.openPorts).",[98,2606,2122],{"class":104},[98,2608,2125],{"class":265},[98,2610,11],{"class":571},[98,2612,1147],{"class":265},[98,2614,2133],{"class":269},[98,2616,2323],{"class":269},[98,2618,2619],{"class":265},"(p ",[98,2621,2622],{"class":269},"in",[98,2624,2625],{"class":265}," baselineHost.openPorts));\n",[98,2627,2629,2631,2634,2636,2638,2640,2643,2645,2647,2649,2651,2653,2655,2657,2659],{"class":100,"line":2628},138,[98,2630,649],{"class":269},[98,2632,2633],{"class":112}," dropped",[98,2635,521],{"class":269},[98,2637,2598],{"class":265},[98,2639,2601],{"class":104},[98,2641,2642],{"class":265},"(baselineHost.openPorts).",[98,2644,2122],{"class":104},[98,2646,2125],{"class":265},[98,2648,11],{"class":571},[98,2650,1147],{"class":265},[98,2652,2133],{"class":269},[98,2654,2323],{"class":269},[98,2656,2619],{"class":265},[98,2658,2622],{"class":269},[98,2660,2661],{"class":265}," currentHost.openPorts));\n",[98,2663,2665,2667,2670,2672,2675,2678,2680],{"class":100,"line":2664},139,[98,2666,663],{"class":269},[98,2668,2669],{"class":265}," (added.",[98,2671,633],{"class":112},[98,2673,2674],{"class":269}," ||",[98,2676,2677],{"class":265}," dropped.",[98,2679,633],{"class":112},[98,2681,575],{"class":265},[98,2683,2685,2688,2690],{"class":100,"line":2684},140,[98,2686,2687],{"class":265},"      changedPorts.",[98,2689,758],{"class":104},[98,2691,2692],{"class":265},"({\n",[98,2694,2696],{"class":100,"line":2695},141,[98,2697,2698],{"class":265},"        ip,\n",[98,2700,2702],{"class":100,"line":2701},142,[98,2703,2704],{"class":265},"        hostname: currentHost.hostname,\n",[98,2706,2708,2711,2713,2715,2717,2719,2721],{"class":100,"line":2707},143,[98,2709,2710],{"class":265},"        addedPorts: added.",[98,2712,2139],{"class":104},[98,2714,2125],{"class":265},[98,2716,11],{"class":571},[98,2718,1147],{"class":265},[98,2720,2133],{"class":269},[98,2722,2723],{"class":265}," ({ port: p, service: currentHost.openPorts[p] })),\n",[98,2725,2727,2730,2732,2734,2736,2738,2740],{"class":100,"line":2726},144,[98,2728,2729],{"class":265},"        droppedPorts: dropped.",[98,2731,2139],{"class":104},[98,2733,2125],{"class":265},[98,2735,11],{"class":571},[98,2737,1147],{"class":265},[98,2739,2133],{"class":269},[98,2741,2742],{"class":265}," ({ port: p, service: baselineHost.openPorts[p] })),\n",[98,2744,2746],{"class":100,"line":2745},145,[98,2747,2748],{"class":265},"      });\n",[98,2750,2752],{"class":100,"line":2751},146,[98,2753,767],{"class":265},[98,2755,2757],{"class":100,"line":2756},147,[98,2758,773],{"class":265},[98,2760,2762],{"class":100,"line":2761},148,[98,2763,495],{"emptyLinePlaceholder":494},[98,2765,2767,2769],{"class":100,"line":2766},149,[98,2768,822],{"class":269},[98,2770,2771],{"class":265}," { newHosts, removedHosts, movedHosts, changedPorts };\n",[98,2773,2775],{"class":100,"line":2774},150,[98,2776,831],{"class":265},[98,2778,2780],{"class":100,"line":2779},151,[98,2781,495],{"emptyLinePlaceholder":494},[98,2783,2785,2787,2790,2792,2795],{"class":100,"line":2784},152,[98,2786,563],{"class":269},[98,2788,2789],{"class":104}," printSummary",[98,2791,527],{"class":265},[98,2793,2794],{"class":571},"report",[98,2796,575],{"class":265},[98,2798,2800,2802,2805,2808,2810,2813,2815,2818,2820,2823,2826,2828],{"class":100,"line":2799},153,[98,2801,581],{"class":269},[98,2803,2804],{"class":265}," { ",[98,2806,2807],{"class":112},"newHosts",[98,2809,885],{"class":265},[98,2811,2812],{"class":112},"removedHosts",[98,2814,885],{"class":265},[98,2816,2817],{"class":112},"movedHosts",[98,2819,885],{"class":265},[98,2821,2822],{"class":112},"changedPorts",[98,2824,2825],{"class":265}," } ",[98,2827,270],{"class":269},[98,2829,2830],{"class":265}," report;\n",[98,2832,2834,2837,2840,2842,2845,2847,2850,2852,2855,2857,2859,2862,2865,2867,2869,2871,2873,2875,2877,2880,2883],{"class":100,"line":2833},154,[98,2835,2836],{"class":265},"  console.",[98,2838,2839],{"class":104},"error",[98,2841,527],{"class":265},[98,2843,2844],{"class":108},"`Baseline: ${",[98,2846,2794],{"class":265},[98,2848,2849],{"class":108},".",[98,2851,2030],{"class":265},[98,2853,2854],{"class":108},"} (${",[98,2856,2794],{"class":265},[98,2858,2849],{"class":108},[98,2860,2861],{"class":265},"baselineStarted",[98,2863,2864],{"class":108},"})  Current: ${",[98,2866,2794],{"class":265},[98,2868,2849],{"class":108},[98,2870,2035],{"class":265},[98,2872,2854],{"class":108},[98,2874,2794],{"class":265},[98,2876,2849],{"class":108},[98,2878,2879],{"class":265},"currentStarted",[98,2881,2882],{"class":108},"})`",[98,2884,533],{"class":265},[98,2886,2888,2890,2892,2894,2897,2899,2901,2903,2906,2908,2910,2912,2915,2917,2919,2921,2924,2926,2928,2930,2933,2936,2938],{"class":100,"line":2887},155,[98,2889,2836],{"class":265},[98,2891,2839],{"class":104},[98,2893,527],{"class":265},[98,2895,2896],{"class":108},"`New hosts: ${",[98,2898,2807],{"class":265},[98,2900,2849],{"class":108},[98,2902,633],{"class":112},[98,2904,2905],{"class":108},"}, removed: ${",[98,2907,2812],{"class":265},[98,2909,2849],{"class":108},[98,2911,633],{"class":112},[98,2913,2914],{"class":108},"}, moved: ${",[98,2916,2817],{"class":265},[98,2918,2849],{"class":108},[98,2920,633],{"class":112},[98,2922,2923],{"class":108},"}, port changes: ${",[98,2925,2822],{"class":265},[98,2927,2849],{"class":108},[98,2929,633],{"class":112},[98,2931,2932],{"class":108},"}",[98,2934,2935],{"class":112},"\\n",[98,2937,1036],{"class":108},[98,2939,533],{"class":265},[98,2941,2943,2945,2947,2949,2952,2954],{"class":100,"line":2942},156,[98,2944,607],{"class":269},[98,2946,610],{"class":265},[98,2948,515],{"class":269},[98,2950,2951],{"class":112}," h",[98,2953,1267],{"class":269},[98,2955,2956],{"class":265}," newHosts) {\n",[98,2958,2960,2962,2965,2967,2970,2972,2975,2977,2979,2982,2984,2987,2989],{"class":100,"line":2959},157,[98,2961,649],{"class":269},[98,2963,2964],{"class":112}," mac",[98,2966,521],{"class":269},[98,2968,2969],{"class":265}," h.mac ",[98,2971,1061],{"class":269},[98,2973,2974],{"class":108}," `mac ${",[98,2976,2128],{"class":265},[98,2978,2849],{"class":108},[98,2980,2981],{"class":265},"mac",[98,2983,1920],{"class":108},[98,2985,2986],{"class":269}," :",[98,2988,1940],{"class":108},[98,2990,504],{"class":265},[98,2992,2994,2997,2999,3001,3004,3006,3008,3010,3012,3015,3017,3020,3022,3025,3027,3029,3031,3034,3036,3039,3041,3043,3045,3048,3050,3052,3054,3057,3060,3062,3064,3066,3068,3070,3073,3075,3078,3080,3083,3085,3087,3090],{"class":100,"line":2993},158,[98,2995,2996],{"class":265},"    console.",[98,2998,2839],{"class":104},[98,3000,527],{"class":265},[98,3002,3003],{"class":108},"`  NEW      ${",[98,3005,2128],{"class":265},[98,3007,2849],{"class":108},[98,3009,2240],{"class":265},[98,3011,2849],{"class":108},[98,3013,3014],{"class":104},"padEnd",[98,3016,527],{"class":108},[98,3018,3019],{"class":112},"12",[98,3021,1901],{"class":108},[98,3023,3024],{"class":108},"} ${",[98,3026,527],{"class":108},[98,3028,2128],{"class":265},[98,3030,2849],{"class":108},[98,3032,3033],{"class":265},"hostname",[98,3035,2674],{"class":269},[98,3037,3038],{"class":108}," '(unknown)'",[98,3040,891],{"class":108},[98,3042,3014],{"class":104},[98,3044,527],{"class":108},[98,3046,3047],{"class":112},"20",[98,3049,1901],{"class":108},[98,3051,3024],{"class":108},[98,3053,2981],{"class":265},[98,3055,3056],{"class":108},"}  ports: ${",[98,3058,3059],{"class":265},"Object",[98,3061,2849],{"class":108},[98,3063,2601],{"class":104},[98,3065,527],{"class":108},[98,3067,2128],{"class":265},[98,3069,2849],{"class":108},[98,3071,3072],{"class":265},"openPorts",[98,3074,891],{"class":108},[98,3076,3077],{"class":104},"join",[98,3079,527],{"class":108},[98,3081,3082],{"class":108},"', '",[98,3084,1147],{"class":108},[98,3086,1150],{"class":269},[98,3088,3089],{"class":108}," 'none open'}`",[98,3091,533],{"class":265},[98,3093,3095],{"class":100,"line":3094},159,[98,3096,773],{"class":265},[98,3098,3100,3102,3104,3106,3108,3110],{"class":100,"line":3099},160,[98,3101,607],{"class":269},[98,3103,610],{"class":265},[98,3105,515],{"class":269},[98,3107,2951],{"class":112},[98,3109,1267],{"class":269},[98,3111,3112],{"class":265}," removedHosts) {\n",[98,3114,3116,3118,3120,3122,3125,3127,3129,3131,3133,3135,3137,3139,3141,3143,3145,3147,3149,3151,3154],{"class":100,"line":3115},161,[98,3117,2996],{"class":265},[98,3119,2839],{"class":104},[98,3121,527],{"class":265},[98,3123,3124],{"class":108},"`  REMOVED  ${",[98,3126,2128],{"class":265},[98,3128,2849],{"class":108},[98,3130,2240],{"class":265},[98,3132,2849],{"class":108},[98,3134,3014],{"class":104},[98,3136,527],{"class":108},[98,3138,3019],{"class":112},[98,3140,1901],{"class":108},[98,3142,3024],{"class":108},[98,3144,2128],{"class":265},[98,3146,2849],{"class":108},[98,3148,3033],{"class":265},[98,3150,2674],{"class":269},[98,3152,3153],{"class":108}," ''}`",[98,3155,533],{"class":265},[98,3157,3159],{"class":100,"line":3158},162,[98,3160,773],{"class":265},[98,3162,3164,3166,3168,3170,3173,3175],{"class":100,"line":3163},163,[98,3165,607],{"class":269},[98,3167,610],{"class":265},[98,3169,515],{"class":269},[98,3171,3172],{"class":112}," m",[98,3174,1267],{"class":269},[98,3176,3177],{"class":265}," movedHosts) {\n",[98,3179,3181,3183,3185,3187,3190,3193,3195,3197,3200,3202,3204,3207,3210,3212,3214,3217,3219],{"class":100,"line":3180},164,[98,3182,2996],{"class":265},[98,3184,2839],{"class":104},[98,3186,527],{"class":265},[98,3188,3189],{"class":108},"`  MOVED    ${",[98,3191,3192],{"class":265},"m",[98,3194,2849],{"class":108},[98,3196,2981],{"class":265},[98,3198,3199],{"class":108},"}  ${",[98,3201,3192],{"class":265},[98,3203,2849],{"class":108},[98,3205,3206],{"class":265},"from",[98,3208,3209],{"class":108},"} -> ${",[98,3211,3192],{"class":265},[98,3213,2849],{"class":108},[98,3215,3216],{"class":265},"to",[98,3218,1920],{"class":108},[98,3220,533],{"class":265},[98,3222,3224],{"class":100,"line":3223},165,[98,3225,773],{"class":265},[98,3227,3229,3231,3233,3235,3238,3240],{"class":100,"line":3228},166,[98,3230,607],{"class":269},[98,3232,610],{"class":265},[98,3234,515],{"class":269},[98,3236,3237],{"class":112}," c",[98,3239,1267],{"class":269},[98,3241,3242],{"class":265}," changedPorts) {\n",[98,3244,3246,3248,3251,3253],{"class":100,"line":3245},167,[98,3247,649],{"class":269},[98,3249,3250],{"class":112}," parts",[98,3252,521],{"class":269},[98,3254,3255],{"class":265}," [\n",[98,3257,3259,3262,3265,3267,3269,3271,3273,3275,3278,3280,3282,3285,3287,3289,3291,3294,3296],{"class":100,"line":3258},168,[98,3260,3261],{"class":269},"      ...",[98,3263,3264],{"class":265},"c.addedPorts.",[98,3266,2139],{"class":104},[98,3268,2125],{"class":265},[98,3270,11],{"class":571},[98,3272,1147],{"class":265},[98,3274,2133],{"class":269},[98,3276,3277],{"class":108}," `+${",[98,3279,11],{"class":265},[98,3281,2849],{"class":108},[98,3283,3284],{"class":265},"port",[98,3286,2854],{"class":108},[98,3288,11],{"class":265},[98,3290,2849],{"class":108},[98,3292,3293],{"class":265},"service",[98,3295,2882],{"class":108},[98,3297,3298],{"class":265},"),\n",[98,3300,3302,3304,3307,3309,3311,3313,3315,3317,3320,3322,3324,3326,3328,3330,3332,3334,3336],{"class":100,"line":3301},169,[98,3303,3261],{"class":269},[98,3305,3306],{"class":265},"c.droppedPorts.",[98,3308,2139],{"class":104},[98,3310,2125],{"class":265},[98,3312,11],{"class":571},[98,3314,1147],{"class":265},[98,3316,2133],{"class":269},[98,3318,3319],{"class":108}," `-${",[98,3321,11],{"class":265},[98,3323,2849],{"class":108},[98,3325,3284],{"class":265},[98,3327,2854],{"class":108},[98,3329,11],{"class":265},[98,3331,2849],{"class":108},[98,3333,3293],{"class":265},[98,3335,2882],{"class":108},[98,3337,3298],{"class":265},[98,3339,3341],{"class":100,"line":3340},170,[98,3342,3343],{"class":265},"    ];\n",[98,3345,3347,3349,3351,3353,3356,3359,3361,3363,3365,3367,3369,3371,3373,3375,3378,3380,3382,3384,3387,3389,3391],{"class":100,"line":3346},171,[98,3348,2996],{"class":265},[98,3350,2839],{"class":104},[98,3352,527],{"class":265},[98,3354,3355],{"class":108},"`  PORTS    ${",[98,3357,3358],{"class":265},"c",[98,3360,2849],{"class":108},[98,3362,2240],{"class":265},[98,3364,2849],{"class":108},[98,3366,3014],{"class":104},[98,3368,527],{"class":108},[98,3370,3019],{"class":112},[98,3372,1901],{"class":108},[98,3374,3024],{"class":108},[98,3376,3377],{"class":265},"parts",[98,3379,2849],{"class":108},[98,3381,3077],{"class":104},[98,3383,527],{"class":108},[98,3385,3386],{"class":108},"' '",[98,3388,1901],{"class":108},[98,3390,1920],{"class":108},[98,3392,533],{"class":265},[98,3394,3396],{"class":100,"line":3395},172,[98,3397,773],{"class":265},[98,3399,3401],{"class":100,"line":3400},173,[98,3402,831],{"class":265},[98,3404,3406],{"class":100,"line":3405},174,[98,3407,495],{"emptyLinePlaceholder":494},[98,3409,3411,3413,3416],{"class":100,"line":3410},175,[98,3412,563],{"class":269},[98,3414,3415],{"class":104}," main",[98,3417,3418],{"class":265},"() {\n",[98,3420,3422,3424,3426,3428,3430,3433,3436,3438,3441],{"class":100,"line":3421},176,[98,3423,581],{"class":269},[98,3425,584],{"class":112},[98,3427,521],{"class":269},[98,3429,566],{"class":104},[98,3431,3432],{"class":265},"(process.argv.",[98,3434,3435],{"class":104},"slice",[98,3437,527],{"class":265},[98,3439,3440],{"class":112},"2",[98,3442,1050],{"class":265},[98,3444,3446,3448,3450,3453,3455,3458,3460,3462],{"class":100,"line":3445},177,[98,3447,581],{"class":269},[98,3449,1153],{"class":265},[98,3451,3452],{"class":112},"baselinePath",[98,3454,885],{"class":265},[98,3456,3457],{"class":112},"currentPath",[98,3459,1923],{"class":265},[98,3461,270],{"class":269},[98,3463,3464],{"class":265}," args.files;\n",[98,3466,3468],{"class":100,"line":3467},178,[98,3469,495],{"emptyLinePlaceholder":494},[98,3471,3473,3475,3478,3480,3482,3485,3488,3491,3494,3497,3500],{"class":100,"line":3472},179,[98,3474,581],{"class":269},[98,3476,3477],{"class":112}," baseline",[98,3479,521],{"class":269},[98,3481,1098],{"class":104},[98,3483,3484],{"class":265},"(fs.",[98,3486,3487],{"class":104},"readFileSync",[98,3489,3490],{"class":265},"(path.",[98,3492,3493],{"class":104},"resolve",[98,3495,3496],{"class":265},"(baselinePath), ",[98,3498,3499],{"class":108},"'utf8'",[98,3501,1050],{"class":265},[98,3503,3505,3507,3510,3512,3514,3516,3518,3520,3522,3525,3527],{"class":100,"line":3504},180,[98,3506,581],{"class":269},[98,3508,3509],{"class":112}," current",[98,3511,521],{"class":269},[98,3513,1098],{"class":104},[98,3515,3484],{"class":265},[98,3517,3487],{"class":104},[98,3519,3490],{"class":265},[98,3521,3493],{"class":104},[98,3523,3524],{"class":265},"(currentPath), ",[98,3526,3499],{"class":108},[98,3528,1050],{"class":265},[98,3530,3532,3534,3537,3539,3541],{"class":100,"line":3531},181,[98,3533,581],{"class":269},[98,3535,3536],{"class":112}," diff",[98,3538,521],{"class":269},[98,3540,2025],{"class":104},[98,3542,3543],{"class":265},"(baseline.hosts, current.hosts);\n",[98,3545,3547],{"class":100,"line":3546},182,[98,3548,495],{"emptyLinePlaceholder":494},[98,3550,3552,3554,3557,3559],{"class":100,"line":3551},183,[98,3553,581],{"class":269},[98,3555,3556],{"class":112}," report",[98,3558,521],{"class":269},[98,3560,749],{"class":265},[98,3562,3564],{"class":100,"line":3563},184,[98,3565,3566],{"class":265},"    baseline: baselinePath,\n",[98,3568,3570],{"class":100,"line":3569},185,[98,3571,3572],{"class":265},"    baselineStarted: baseline.started,\n",[98,3574,3576],{"class":100,"line":3575},186,[98,3577,3578],{"class":265},"    current: currentPath,\n",[98,3580,3582],{"class":100,"line":3581},187,[98,3583,3584],{"class":265},"    currentStarted: current.started,\n",[98,3586,3588],{"class":100,"line":3587},188,[98,3589,3590],{"class":265},"    summary: {\n",[98,3592,3594,3597,3599],{"class":100,"line":3593},189,[98,3595,3596],{"class":265},"      newHosts: diff.newHosts.",[98,3598,633],{"class":112},[98,3600,3601],{"class":265},",\n",[98,3603,3605,3608,3610],{"class":100,"line":3604},190,[98,3606,3607],{"class":265},"      removedHosts: diff.removedHosts.",[98,3609,633],{"class":112},[98,3611,3601],{"class":265},[98,3613,3615,3618,3620],{"class":100,"line":3614},191,[98,3616,3617],{"class":265},"      movedHosts: diff.movedHosts.",[98,3619,633],{"class":112},[98,3621,3601],{"class":265},[98,3623,3625,3628,3630],{"class":100,"line":3624},192,[98,3626,3627],{"class":265},"      hostsWithPortChanges: diff.changedPorts.",[98,3629,633],{"class":112},[98,3631,3601],{"class":265},[98,3633,3635],{"class":100,"line":3634},193,[98,3636,3637],{"class":265},"    },\n",[98,3639,3641,3644],{"class":100,"line":3640},194,[98,3642,3643],{"class":269},"    ...",[98,3645,3646],{"class":265},"diff,\n",[98,3648,3650],{"class":100,"line":3649},195,[98,3651,3652],{"class":265},"  };\n",[98,3654,3656],{"class":100,"line":3655},196,[98,3657,495],{"emptyLinePlaceholder":494},[98,3659,3661,3664],{"class":100,"line":3660},197,[98,3662,3663],{"class":104},"  printSummary",[98,3665,3666],{"class":265},"(report);\n",[98,3668,3670,3672,3675,3677,3680,3682,3685,3688,3690,3692,3694],{"class":100,"line":3669},198,[98,3671,581],{"class":269},[98,3673,3674],{"class":112}," output",[98,3676,521],{"class":269},[98,3678,3679],{"class":112}," JSON",[98,3681,2849],{"class":265},[98,3683,3684],{"class":104},"stringify",[98,3686,3687],{"class":265},"(report, ",[98,3689,592],{"class":112},[98,3691,885],{"class":265},[98,3693,3440],{"class":112},[98,3695,533],{"class":265},[98,3697,3699,3701],{"class":100,"line":3698},199,[98,3700,779],{"class":269},[98,3702,3703],{"class":265}," (args.output) {\n",[98,3705,3707,3710,3713,3716,3718],{"class":100,"line":3706},200,[98,3708,3709],{"class":265},"    fs.",[98,3711,3712],{"class":104},"writeFileSync",[98,3714,3715],{"class":265},"(args.output, output, ",[98,3717,3499],{"class":108},[98,3719,533],{"class":265},[98,3721,3723,3725,3727,3729,3731,3733,3736,3739,3741,3744,3746],{"class":100,"line":3722},201,[98,3724,2996],{"class":265},[98,3726,2839],{"class":104},[98,3728,527],{"class":265},[98,3730,1036],{"class":108},[98,3732,2935],{"class":112},[98,3734,3735],{"class":108},"Report written to ${",[98,3737,3738],{"class":265},"args",[98,3740,2849],{"class":108},[98,3742,3743],{"class":265},"output",[98,3745,1920],{"class":108},[98,3747,533],{"class":265},[98,3749,3751,3754,3756],{"class":100,"line":3750},202,[98,3752,3753],{"class":265},"  } ",[98,3755,714],{"class":269},[98,3757,749],{"class":265},[98,3759,3761,3763,3766],{"class":100,"line":3760},203,[98,3762,2996],{"class":265},[98,3764,3765],{"class":104},"log",[98,3767,3768],{"class":265},"(output);\n",[98,3770,3772],{"class":100,"line":3771},204,[98,3773,773],{"class":265},[98,3775,3777],{"class":100,"line":3776},205,[98,3778,495],{"emptyLinePlaceholder":494},[98,3780,3782,3784,3787,3789,3792,3794,3797,3799],{"class":100,"line":3781},206,[98,3783,779],{"class":269},[98,3785,3786],{"class":265}," (args.failOnNew ",[98,3788,2320],{"class":269},[98,3790,3791],{"class":265}," diff.newHosts.",[98,3793,633],{"class":112},[98,3795,3796],{"class":269}," >",[98,3798,621],{"class":112},[98,3800,575],{"class":265},[98,3802,3804,3807,3809,3811],{"class":100,"line":3803},207,[98,3805,3806],{"class":265},"    process.exitCode ",[98,3808,270],{"class":269},[98,3810,790],{"class":112},[98,3812,504],{"class":265},[98,3814,3816],{"class":100,"line":3815},208,[98,3817,773],{"class":265},[98,3819,3821],{"class":100,"line":3820},209,[98,3822,831],{"class":265},[98,3824,3826],{"class":100,"line":3825},210,[98,3827,495],{"emptyLinePlaceholder":494},[98,3829,3831,3834],{"class":100,"line":3830},211,[98,3832,3833],{"class":104},"main",[98,3835,1182],{"class":265},[29,3837,3839],{"id":3838},"notes","Notes",[34,3841,3842,3871,3897,3903,3917,3931],{},[37,3843,3844,3851,3852,3854,3855,3858,3859,3862,3863,3865,3866,3868,3869,2849],{},[3845,3846,3847,3848,2849],"strong",{},"Bug fixed from the first version: ",[15,3849,3850],{},"\u003Chosthint>"," nmap's DTD allows ",[15,3853,3850],{}," elements (a status, address and hostnames block) as siblings of ",[15,3856,3857],{},"\u003Chost>",". The original ",[15,3860,3861],{},"\u002F\u003Chost[\\s\\S]*?\u003C\\\u002Fhost>\u002F"," pattern matched ",[15,3864,3850],{}," too, so one match could span a hint and the following real host and attribute the wrong ports to an address. The pattern now requires whitespace or ",[15,3867,1142],{}," after ",[15,3870,2245],{},[37,3872,3873,3876,3877,885,3880,885,3883,47,3886,3889,3890,3892,3893,3896],{},[3845,3874,3875],{},"Only up hosts count."," The DTD defines host states ",[15,3878,3879],{},"up",[15,3881,3882],{},"down",[15,3884,3885],{},"unknown",[15,3887,3888],{},"skipped",", and the first version counted any ",[15,3891,3857],{}," element as present. The script now checks ",[15,3894,3895],{},"\u003Cstatus state=\"up\">"," before counting a host.",[37,3898,3899,3902],{},[3845,3900,3901],{},"MAC-based \"moved\"."," On DHCP subnets a device that got a new lease shows up as one \"new\" and one \"removed\" host. When both scans include the MAC (root scan, local segment), the script pairs them, reports a move instead, and compares the moved host's ports against its old address. Across routers there's no MAC in the XML and the pairing doesn't happen.",[37,3904,3905,3908,3909,3912,3913,3916],{},[3845,3906,3907],{},"IPv6 works"," as long as both scans used ",[15,3910,3911],{},"-6"," against the same targets; the first non-MAC ",[15,3914,3915],{},"\u003Caddress>"," is used as the key.",[37,3918,3919,3922,3923,3926,3927,3930],{},[3845,3920,3921],{},"\"Removed\" is not \"gone\"."," A host missing from the current scan may just not have answered discovery probes that night. ",[15,3924,3925],{},"-T4"," already allows up to 6 retransmissions (",[15,3928,3929],{},"--max-retries 6","); if a host flaps every run, check it for power management or a host firewall that drops discovery probes before assuming it was decommissioned.",[37,3932,3933,3936,3937,3940],{},[3845,3934,3935],{},"Parsing trade-off."," Regex parsing keeps this dependency-free and works on nmap's own consistently formatted output. It is not a general XML parser; if you already have a dependency budget, an XML library is the more robust choice. The discovery-first essay uses Python's ",[15,3938,3939],{},"xml.etree.ElementTree"," for the same file.",[29,3942,3944],{"id":3943},"references","References",[34,3946,3947,3960,3982,3994,4008,4015],{},[37,3948,3949],{},[23,3950,3954,3955,885,3957,1901],{"href":3951,"rel":3952},"https:\u002F\u002Fnmap.org\u002Fbook\u002Fman-output.html",[3953],"nofollow","Nmap output options (",[15,3956,78],{},[15,3958,3959],{},"-oA",[37,3961,3962],{},[23,3963,3966,3967,885,3969,885,3972,885,3975,885,3978,885,3980,1901],{"href":3964,"rel":3965},"https:\u002F\u002Fsvn.nmap.org\u002Fnmap\u002Fdocs\u002Fnmap.dtd",[3953],"Nmap XML DTD (",[15,3968,2245],{},[15,3970,3971],{},"hosthint",[15,3973,3974],{},"status",[15,3976,3977],{},"address",[15,3979,3284],{},[15,3981,3293],{},[37,3983,3984],{},[23,3985,3988,3989,885,3991,1901],{"href":3986,"rel":3987},"https:\u002F\u002Fnmap.org\u002Fbook\u002Fman-performance.html",[3953],"Nmap timing and performance (",[15,3990,3925],{},[15,3992,3993],{},"--max-retries",[37,3995,3996],{},[23,3997,4000,4001,4003,4004,4007],{"href":3998,"rel":3999},"https:\u002F\u002Fnmap.org\u002Fbook\u002Fman-port-scanning-techniques.html",[3953],"Nmap port scanning techniques (",[15,4002,57],{}," privileges, ",[15,4005,4006],{},"-sT"," fallback)",[37,4009,4010],{},[23,4011,4014],{"href":4012,"rel":4013},"https:\u002F\u002Fnmap.org\u002Fbook\u002Fman-host-discovery.html",[3953],"Nmap host discovery (ARP on local Ethernet)",[37,4016,4017],{},[23,4018,4021,4022],{"href":4019,"rel":4020},"https:\u002F\u002Fnodejs.org\u002Fapi\u002Ffs.html#fsreadfilesyncpath-options",[3953],"Node.js ",[15,4023,4024],{},"fs.readFileSync",[4026,4027,4028],"style",{},"html pre.shiki code .svObZ, html code.shiki .svObZ{--shiki-default:#B392F0}html pre.shiki code .sU2Wk, html code.shiki .sU2Wk{--shiki-default:#9ECBFF}html pre.shiki code .sDLfK, html code.shiki .sDLfK{--shiki-default:#79B8FF}html pre.shiki code .sAwPA, html code.shiki .sAwPA{--shiki-default:#6A737D}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html pre.shiki code .s95oV, html code.shiki .s95oV{--shiki-default:#E1E4E8}html pre.shiki code .snl16, html code.shiki .snl16{--shiki-default:#F97583}html pre.shiki code .s9osk, html code.shiki .s9osk{--shiki-default:#FFAB70}html pre.shiki code .sns5M, html code.shiki .sns5M{--shiki-default:#DBEDFF}html pre.shiki code .sRjNt, html code.shiki .sRjNt{--shiki-default:#85E89D;--shiki-default-font-weight:bold}",{"title":94,"searchDepth":137,"depth":137,"links":4030},[4031,4032,4033,4034,4035],{"id":31,"depth":137,"text":32},{"id":71,"depth":137,"text":72},{"id":410,"depth":137,"text":411},{"id":3838,"depth":137,"text":3839},{"id":3943,"depth":137,"text":3944},"techcolumnist",[4038,4039],"scripts","engineering","2026-03-11T14:00:00Z","A dependency-free Node.js script that diffs two nmap XML scans and flags new, missing and moved hosts plus port changes, with an exit code for cron or CI.","md",false,null,{},"\u002Fblog\u002F2026\u002F03\u002F11\u002Fnode-js-discovery-diffing-two-network-scans-to-flag-new-hosts",{"title":6,"description":4041},[4036],"blog\u002F2026\u002F03\u002F11\u002Fnode-js-discovery-diffing-two-network-scans-to-flag-new-hosts",[4051,4052,4053],"nodejs","discovery","network","\u002F2026\u002F03\u002F11\u002Fnode-js-discovery-diffing-two-network-scans-to-flag-new-hosts\u002F","RVLGRFwk0YWcrkWaehE3uoWlpZ5Vu8eXKimtmDUvIZc",{"title":4057,"description":4058,"date":4059,"url":4060,"categories":4061,"tags":4062,"image":4044,"readingTime":298,"canonical":4036,"sites":4066,"series":4044,"seriesOrder":4044},"Talos Linux: Bootstrapping a Three-Node Cluster on Bare Metal","Bringing up a three-node Talos Kubernetes cluster on bare metal: secrets, per-node patches, a Layer 2 VIP, apply-config, a single bootstrap, and a full script.","2026-03-18T14:00:00Z","\u002F2026\u002F03\u002F18\u002Ftalos-linux-bootstrapping-a-three-node-kubernetes-cluster-from-bare-metal\u002F",[4039],[4063,4064,4065],"talos","kubernetes","cluster",[4036],{"title":4068,"description":4069,"date":4070,"url":4071,"categories":4072,"tags":4073,"image":4044,"readingTime":253,"canonical":4036,"sites":4075,"series":4044,"seriesOrder":4044},"Node.js: gcloud – Rotating Service Account Keys Before They Expire","A Node.js script that finds aging Google Cloud service account keys, mints one replacement, and disables the old keys once it is deployed.","2026-03-04T14:00:00Z","\u002F2026\u002F03\u002F04\u002Fnode-js-gcloud-rotating-service-account-keys-before-they-expire\u002F",[4038,4039],[4051,4074],"gcloud",[4036],[4077,4086,4096],{"title":4078,"description":4079,"date":4080,"url":4081,"categories":4082,"tags":4083,"image":4044,"readingTime":144,"canonical":4036,"sites":4085,"series":4044,"seriesOrder":4044},"Node.js: Discovery – Scanning a Subnet for Open RDP and SSH","A dependency-free Node.js TCP connect scanner that sweeps a subnet for RDP and SSH, separates closed from filtered ports, grabs SSH banners and writes CSV.","2026-02-11T14:00:00Z","\u002F2026\u002F02\u002F11\u002Fnode-js-discovery-scanning-a-subnet-for-open-rdp-and-ssh\u002F",[4038,4039],[4051,4052,4053,4084],"ssh",[4036],{"title":4087,"description":4088,"date":4089,"url":4090,"categories":4091,"tags":4092,"image":4044,"readingTime":144,"canonical":4036,"sites":4095,"series":4044,"seriesOrder":4044},"Python: Discovery – Crawling DNS Zones for Orphaned Records","A dnspython script that transfers a zone with AXFR, probes every A\u002FAAAA record for signs of life, flags dangling CNAMEs, and reports orphan cleanup candidates.","2026-01-28T14:00:00Z","\u002F2026\u002F01\u002F28\u002Fpython-discovery-crawling-dns-zones-for-orphaned-records\u002F",[4038,4039],[4093,4052,4053,4094],"python","windows",[4036],{"title":4097,"description":4098,"date":4099,"url":4100,"categories":4101,"tags":4102,"image":4044,"readingTime":144,"canonical":4036,"sites":4103,"series":4044,"seriesOrder":4044},"Python: Discovery – Fingerprint Every Device on a Subnet","A Python script that ARP-sweeps a local subnet with Scapy, maps MACs to IEEE vendors, probes common ports for banners, and writes one CSV row per device.","2026-01-07T14:00:00Z","\u002F2026\u002F01\u002F07\u002Fpython-discovery-fingerprint-every-device-on-a-subnet\u002F",[4038,4039],[4093,4052,4053],[4036],{"doc":4044,"posts":4105},[],1790052513749]