<commit_before>L.AwesomeMarkers.Icon.prototype.options.prefix = 'ion'

document.addEventListener('DOMContentLoaded', main)

function get(url) {
  return new Promise(function(resolve, reject) {
    var req = new XMLHttpRequest();
    req.open('GET', url);

    req.onload = function() {
      if (req.status == 200) {
        resolve(req.response);
      }
      else {
        reject(Error(req.statusText));
      }
    };

    req.onerror = function() {
      reject(Error("Network Error"));
    };

    req.send();
  });
}

function getJSON(url) {
  return get(url).then(JSON.parse)
}

function main() {
  getJSON("config.json").then( function (config) {
    moment.locale("de")

    var options = { worldCopyJump: true,
                    zoomControl: false
                  }

    var map = L.map(document.getElementById("map"), options)

    var sh = document.getElementById("sidebarhandle")
    sh.onclick = function () {
      var sb = document.getElementById("sidebar")

      if (sb.classList.contains("hidden"))
        sb.classList.remove("hidden")
      else
        sb.classList.add("hidden")
    }

    var urls = [ config.dataPath + 'nodes.json',
                 config.dataPath + 'graph.json'
               ]

    var p = Promise.all(urls.map(getJSON))
    p.then(handle_data(config, map))
  })
}

function sort(key, d) {
  return d.slice().sort( function (a, b) {
    return a[key] - b[key]
  }).reverse()
}

function limit(key, m, d) {
  return d.filter( function (d) {
    return d[key].isAfter(m)
  })
}

function offline(d) {
  return !d.flags.online
}

function online(d) {
  return d.flags.online
}

function has_location(d) {
  return "location" in d.nodeinfo
}

function subtract(a, b) {
  var ids = {}

  b.forEach( function (d) {
    ids[d.nodeinfo.node_id] = true
  })

  return a.filter( function (d) {
    return !(d.nodeinfo.node_id in ids)
  })
}

function handle_data(config, map) {
  return function (data) {
    var nodedict = data[0]
    var nodes = Object.keys(nodedict.nodes).map(function (key) { return nodedict.nodes[key] })

    nodes = nodes.filter( function (d) {
      return "firstseen" in d && "lastseen" in d
    })

    nodes.forEach( function(node) {
      node.firstseen = moment.utc(node.firstseen)
      node.lastseen = moment.utc(node.lastseen)
    })

    var age = moment().subtract(14, 'days')

    var newnodes = limit("firstseen", age, sort("firstseen", nodes).filter(online))
    var lostnodes = limit("lastseen", age, sort("lastseen", nodes).filter(offline))

    var onlinenodes = subtract(nodes.filter(online).filter(has_location), newnodes)

    var graph = data[1].batadv
    var graphnodes = data[0].nodes

    graph.nodes.forEach( function (d) {
      if (d.node_id in graphnodes && "location" in graphnodes[d.node_id].nodeinfo)
        d.node = graphnodes[d.node_id]
    })

    graph.links.forEach( function (d) {
      if (graph.nodes[d.source].node)
        d.source = graph.nodes[d.source]
      else
        d.source = undefined

      if (graph.nodes[d.target].node)
        d.target = graph.nodes[d.target]
      else
        d.target = undefined
    })

    graph = graph.links.filter( function (d) {
      var ok = d.source !== undefined && d.target !== undefined
      return ok
    })

    graph.forEach( function (d) {
      d.latlngs = []
      d.latlngs.push(L.latLng(d.source.node.nodeinfo.location.latitude, d.source.node.nodeinfo.location.longitude))
      d.latlngs.push(L.latLng(d.target.node.nodeinfo.location.latitude, d.target.node.nodeinfo.location.longitude))

      d.distance = d.latlngs[0].distanceTo(d.latlngs[1])
    })

    longlinks = graph.slice().sort( function (a, b) {
      return a.distance - b.distance
    }).reverse().slice(0, Math.ceil(config.longLinkPercentile * graph.length))


    var gotoAnything = gotoBuilder(config, showNodeinfo, showLinkinfo)

    var markers = mkmap(map, newnodes, lostnodes, onlinenodes, graph, gotoAnything)

    gotoAnything.addMarkers(markers)

    addToList(document.getElementById("newnodes"), config.showContact, "firstseen", gotoAnything.node, newnodes)
    addToList(document.getElementById("lostnodes"), config.showContact, "lastseen", gotoAnything.node, lostnodes)
    addToLongLinksList(document.getElementById("longlinks"), gotoAnything.link, longlinks)

    showMeshstats(document.getElementById("meshstats"), nodes)

    var historyDict = { nodes: {}, links: {} }

    nodes.forEach( function (d) {
      historyDict.nodes[d.nodeinfo.node_id] = d
    })

    graph.forEach( function (d) {
      historyDict.links[linkId(d)] = d
    })

    gotoHistory(gotoAnything, historyDict, window.location.hash)

    window.onpopstate = function (d) {
      gotoHistory(gotoAnything, historyDict, d.state)
    }
  }
}

function showDistance(d) {
  return (new Intl.NumberFormat("de-DE", {maximumFractionDigits: 0}).format(d.distance)) + " m"
}

function showTq(d) {
  var opts = { maximumFractionDigits: 2,
               minimumFractionDigits: 2
             }

  return (new Intl.NumberFormat("de-DE", opts).format(d.tq)) + " TQ"
}

function linkId(d) {
  return d.source.node.nodeinfo.node_id + "-" + d.target.node.nodeinfo.node_id
}

function mkmap(map, newnodes, lostnodes, onlinenodes, graph, gotoAnything) {
  L.control.zoom({ position: "topright" }).addTo(map)

  L.tileLayer("http://otile{s}.mqcdn.com/tiles/1.0.0/osm/{z}/{x}/{y}.jpg", {
    subdomains: "1234",
    type: "osm",
    attribution: "Map data Tiles &copy; <a href=\"http://www.mapquest.com/\" target=\"_blank\">MapQuest</a> <img src=\"http://developer.mapquest.com/content/osm/mq_logo.png\" />, Map data © OpenStreetMap contributors, CC-BY-SA",
    maxZoom: 18
  }).addTo(map)

  var markersDict = addLinksToMap(map, graph, gotoAnything)

  var nodes = newnodes.concat(lostnodes).filter( function (d) {
    return "location" in d.nodeinfo
  })

  var markers = nodes.map( function (d) {
    var icon = L.AwesomeMarkers.icon({ markerColor: d.flags.online ? "green" : "red",
                                       icon: d.flags.online ? "lightbulb" : "bug" })

    var opt = { icon: icon,
                title: d.nodeinfo.hostname
              }

    var m = L.marker([d.nodeinfo.location.latitude, d.nodeinfo.location.longitude], opt)

    m.on('click', gotoAnything.node(d, false))
    m.bindPopup(d.nodeinfo.hostname)

    markersDict[d.nodeinfo.node_id] = m

    return m
  })

  var onlinemarkers = onlinenodes.map( function (d) {
    var opt = { color: "#76B22D",
                fillColor: "#76B22D",
                radius: 5,
                opacity: 0.7,
                fillOpacity: 0.5
              }
<commit_msg>change nodecolor<commit_after>L.AwesomeMarkers.Icon.prototype.options.prefix = 'ion'

document.addEventListener('DOMContentLoaded', main)

function get(url) {
  return new Promise(function(resolve, reject) {
    var req = new XMLHttpRequest();
    req.open('GET', url);

    req.onload = function() {
      if (req.status == 200) {
        resolve(req.response);
      }
      else {
        reject(Error(req.statusText));
      }
    };

    req.onerror = function() {
      reject(Error("Network Error"));
    };

    req.send();
  });
}

function getJSON(url) {
  return get(url).then(JSON.parse)
}

function main() {
  getJSON("config.json").then( function (config) {
    moment.locale("de")

    var options = { worldCopyJump: true,
                    zoomControl: false
                  }

    var map = L.map(document.getElementById("map"), options)

    var sh = document.getElementById("sidebarhandle")
    sh.onclick = function () {
      var sb = document.getElementById("sidebar")

      if (sb.classList.contains("hidden"))
        sb.classList.remove("hidden")
      else
        sb.classList.add("hidden")
    }

    var urls = [ config.dataPath + 'nodes.json',
                 config.dataPath + 'graph.json'
               ]

    var p = Promise.all(urls.map(getJSON))
    p.then(handle_data(config, map))
  })
}

function sort(key, d) {
  return d.slice().sort( function (a, b) {
    return a[key] - b[key]
  }).reverse()
}

function limit(key, m, d) {
  return d.filter( function (d) {
    return d[key].isAfter(m)
  })
}

function offline(d) {
  return !d.flags.online
}

function online(d) {
  return d.flags.online
}

function has_location(d) {
  return "location" in d.nodeinfo
}

function subtract(a, b) {
  var ids = {}

  b.forEach( function (d) {
    ids[d.nodeinfo.node_id] = true
  })

  return a.filter( function (d) {
    return !(d.nodeinfo.node_id in ids)
  })
}

function handle_data(config, map) {
  return function (data) {
    var nodedict = data[0]
    var nodes = Object.keys(nodedict.nodes).map(function (key) { return nodedict.nodes[key] })

    nodes = nodes.filter( function (d) {
      return "firstseen" in d && "lastseen" in d
    })

    nodes.forEach( function(node) {
      node.firstseen = moment.utc(node.firstseen)
      node.lastseen = moment.utc(node.lastseen)
    })

    var age = moment().subtract(14, 'days')

    var newnodes = limit("firstseen", age, sort("firstseen", nodes).filter(online))
    var lostnodes = limit("lastseen", age, sort("lastseen", nodes).filter(offline))

    var onlinenodes = subtract(nodes.filter(online).filter(has_location), newnodes)

    var graph = data[1].batadv
    var graphnodes = data[0].nodes

    graph.nodes.forEach( function (d) {
      if (d.node_id in graphnodes && "location" in graphnodes[d.node_id].nodeinfo)
        d.node = graphnodes[d.node_id]
    })

    graph.links.forEach( function (d) {
      if (graph.nodes[d.source].node)
        d.source = graph.nodes[d.source]
      else
        d.source = undefined

      if (graph.nodes[d.target].node)
        d.target = graph.nodes[d.target]
      else
        d.target = undefined
    })

    graph = graph.links.filter( function (d) {
      var ok = d.source !== undefined && d.target !== undefined
      return ok
    })

    graph.forEach( function (d) {
      d.latlngs = []
      d.latlngs.push(L.latLng(d.source.node.nodeinfo.location.latitude, d.source.node.nodeinfo.location.longitude))
      d.latlngs.push(L.latLng(d.target.node.nodeinfo.location.latitude, d.target.node.nodeinfo.location.longitude))

      d.distance = d.latlngs[0].distanceTo(d.latlngs[1])
    })

    longlinks = graph.slice().sort( function (a, b) {
      return a.distance - b.distance
    }).reverse().slice(0, Math.ceil(config.longLinkPercentile * graph.length))


    var gotoAnything = gotoBuilder(config, showNodeinfo, showLinkinfo)

    var markers = mkmap(map, newnodes, lostnodes, onlinenodes, graph, gotoAnything)

    gotoAnything.addMarkers(markers)

    addToList(document.getElementById("newnodes"), config.showContact, "firstseen", gotoAnything.node, newnodes)
    addToList(document.getElementById("lostnodes"), config.showContact, "lastseen", gotoAnything.node, lostnodes)
    addToLongLinksList(document.getElementById("longlinks"), gotoAnything.link, longlinks)

    showMeshstats(document.getElementById("meshstats"), nodes)

    var historyDict = { nodes: {}, links: {} }

    nodes.forEach( function (d) {
      historyDict.nodes[d.nodeinfo.node_id] = d
    })

    graph.forEach( function (d) {
      historyDict.links[linkId(d)] = d
    })

    gotoHistory(gotoAnything, historyDict, window.location.hash)

    window.onpopstate = function (d) {
      gotoHistory(gotoAnything, historyDict, d.state)
    }
  }
}

function showDistance(d) {
  return (new Intl.NumberFormat("de-DE", {maximumFractionDigits: 0}).format(d.distance)) + " m"
}

function showTq(d) {
  var opts = { maximumFractionDigits: 2,
               minimumFractionDigits: 2
             }

  return (new Intl.NumberFormat("de-DE", opts).format(d.tq)) + " TQ"
}

function linkId(d) {
  return d.source.node.nodeinfo.node_id + "-" + d.target.node.nodeinfo.node_id
}

function mkmap(map, newnodes, lostnodes, onlinenodes, graph, gotoAnything) {
  L.control.zoom({ position: "topright" }).addTo(map)

  L.tileLayer("http://otile{s}.mqcdn.com/tiles/1.0.0/osm/{z}/{x}/{y}.jpg", {
    subdomains: "1234",
    type: "osm",
    attribution: "Map data Tiles &copy; <a href=\"http://www.mapquest.com/\" target=\"_blank\">MapQuest</a> <img src=\"http://developer.mapquest.com/content/osm/mq_logo.png\" />, Map data © OpenStreetMap contributors, CC-BY-SA",
    maxZoom: 18
  }).addTo(map)

  var markersDict = addLinksToMap(map, graph, gotoAnything)

  var nodes = newnodes.concat(lostnodes).filter( function (d) {
    return "location" in d.nodeinfo
  })

  var markers = nodes.map( function (d) {
    var icon = L.AwesomeMarkers.icon({ markerColor: d.flags.online ? "green" : "red",
                                       icon: d.flags.online ? "lightbulb" : "bug" })

    var opt = { icon: icon,
                title: d.nodeinfo.hostname
              }

    var m = L.marker([d.nodeinfo.location.latitude, d.nodeinfo.location.longitude], opt)

    m.on('click', gotoAnything.node(d, false))
    m.bindPopup(d.nodeinfo.hostname)

    markersDict[d.nodeinfo.node_id] = m

    return m
  })

  var onlinemarkers = onlinenodes.map( function (d) {
    var opt = { color: "#1566A9",
                fillColor: "#1566A9",
                radius: 5,
                opacity: 0.7,
                fillOpacity: 0.5
              }

{'fraction_non_alphanumeric': 0.14904027098231087, 'fraction_numerical': 0.005570191945803537, 'mean_word_length': 2.859965136548518, 'pattern_counts': {'":': 0, '<': 9, '<?xml version=': 0, '>': 9, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 2, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '1290574', 'n_tokens_mistral': 4573, 'n_tokens_neox': 4392, 'n_words': 853}