<commit_before>/* global d3 console */

d3.entityflow = function() {
  var entityflow = {}
    , size = [1, 1]
    , sessionWidth = 140
    , sessionPadding = 80
    , sessionMap = function(s) { return s }
    , entityPadding = 10
    , entityFilter = null
    , valueScale = null
    , entities = []
    , sessions = []
    , yscale

  entityflow.size = function(_) {
    if (! arguments.length) return size
    size = _
    return entityflow
  }

  entityflow.sessionWidth = function(_) {
    if (! arguments.length) return sessionWidth
    sessionWidth = +_
    return entityflow
  }

  entityflow.sessionPadding = function(_) {
    if (! arguments.length) return sessionPadding
    sessionPadding = +_
    return entityflow
  }

  entityflow.sessionMap = function(_) {
    if (! arguments.length) return sessionMap
    sessionMap = _
    return entityflow
  }

  entityflow.entityPadding = function(_) {
    if (! arguments.length) return entityPadding
    entityPadding = +_
    return entityflow
  }

  entityflow.entityFilter = function(_) {
    if (! arguments.length) return entityFilter
    entityFilter = _
    return entityflow
  }

  entityflow.valueScale = function(_) {
    if (! arguments.length) return valueScale
    valueScale = _
    return entityflow
  }

  entityflow.entities = function(_) {
    if (! arguments.length) return entities
    entities = _
    return entityflow
  }

  entityflow.sessions = function(_, id, label) {
    if (! arguments.length) return sessions
    sessions = sessions.concat(_.map(sessionMap).map(function(s) {
      s.source = {id:id, label:label}
      return s
    }))
    return entityflow
  }

  entityflow.layout = function(iterations) {
    computeSessionGraph()
    computeSessionBreadths()
    computeSessionDepths(iterations)
    for (; iterations > 0; --iterations) {
      minimizeEntityCrossing()
      minimizeEntityWiggle()
    }
    computeEntityDetours()
    entities.sort(function(a, b) {
      return medianNodeDepth(a) - medianNodeDepth(b)
    })
    return entityflow
  }

  entityflow.entityhead = function() {
    function head(d) {
      return [ { x: d.nodes[0].session.x
               , y: d.nodes[0].y
               , dx: d.nodes[0].session.dx
               , dy: d.nodes[0].dy
               , entity: d }
             ]
    }
    return head
  }

  entityflow.entitynodes = function() {
    function nodes(d) {
      return d.nodes
              .filter(function(node) {
               return (! node.detour)
             })
              .map(function(node) {
                var o = Object.assign({}, node,
                  { x: node.session.x
                  , dx: node.session.dx
                  , entity: d
                  })
                delete o.index
                delete o.session
                return o
             })
    }
    return nodes
  }

  entityflow.entitypath = function() {
    function path(d) {
      d.nodes.sort(ascendingSessionBreadth)

      return ( "M" + [d.nodes[0].session.x, d.nodes[0].y]
             + joinTops(d.nodes)
             + "v" + d.nodes[d.nodes.length - 1].dy
             + joinBottoms(d.nodes.slice().reverse())
             + "Z" )
    }

    function ascendingSessionBreadth(a, b) {
      return a.session.x - b.session.x
    }

    function joinTops(nodes) {
      return nodes.map(
        function(node, i) {
          var path = "", dx, dy, ctrlx
          if (i > 0) {
            dx = node.session.x - (nodes[i - 1].session.x + sessionWidth)
            dy = node.y - nodes[i - 1].y
            if (dy > 0) {
              ctrlx = [ dx*0.6, dx*0.5 ]
            } else {
              ctrlx = [ dx*0.5, dx*0.4 ]
            }
            path = "c" + [ ctrlx[0], 0, ctrlx[1], dy, dx, dy ]
          }
          return path + "h" + sessionWidth
        }).join("")
    }

    function joinBottoms(nodes) {
      return nodes.map(
        function(node, i) {
          var path = "", dx, dy, ctrlx
          if (i > 0) {
            dx = (node.session.x + sessionWidth) - nodes[i - 1].session.x
            dy = (node.y + node.dy) - (nodes[i - 1].y + nodes[i - 1].dy)
            if (dy > 0) {
              ctrlx = [ dx*0.5, dx*0.4 ]
            } else {
              ctrlx = [ dx*0.6, dx*0.5 ]
            }
            path = "c" + [ ctrlx[0], 0, ctrlx[1], dy, dx, dy ]
          }
          return path + "h" + (-sessionWidth)
        }).join("")
    }

    return path
  }

  // Each node in the graph belongs to one entity and one session.
  // Links join sessions participated in by the same entity.
  function computeSessionGraph() {
    sessions.forEach(function(session) {
      session.nodes = []
      session.value = 0
      session.sourceLinks = []
      session.targetLinks = []
      session.entities.forEach(function(e) {
        var entity = entities[e.index]
          , node = { entity: entity
                   , session: session
                   , value: ("value" in e) ? e.value : 1
                   , scaledValue: e.value }
          , link
        for (var prop in e) {
          if (e === 'index' || e === 'value') continue
          node[prop] = e[prop]
        }
        e.name = entity.name
        delete e.index
        if (! ("nodes" in entity)) { entity.nodes = [] }
        if (entity.nodes.length > 0) {
          link = { source: entity.nodes[entity.nodes.length - 1].session
                 , target: session }
          link.source.sourceLinks.push(link)
          link.target.targetLinks.push(link)
        }
        entity.nodes.push(node)
        session.nodes.push(node)
        session.value += node.scaledValue
      })
    })

    if (entityFilter) filterEntities()

    if (valueScale) scaleValues()

    function filterEntities() {
      entities = entities.filter(
        function(entity) {
          if (! ('nodes' in entity)) return false
          var keep = entityFilter(entity)
          if (! keep) {
            entity.nodes.forEach(function(node) {
              node.session.nodes.splice(node.session.nodes.indexOf(node), 1)
              node.session.value -= node.scaledValue
            })
          }
          return keep
        })
    }<commit_msg>Saner entityFilter default.<commit_after>/* global d3 console */

d3.entityflow = function() {
  var entityflow = {}
    , size = [1, 1]
    , sessionWidth = 140
    , sessionPadding = 80
    , sessionMap = function(s) { return s }
    , entityPadding = 10
    , entityFilter = function(e) { return true }
    , valueScale = null
    , entities = []
    , sessions = []
    , yscale

  entityflow.size = function(_) {
    if (! arguments.length) return size
    size = _
    return entityflow
  }

  entityflow.sessionWidth = function(_) {
    if (! arguments.length) return sessionWidth
    sessionWidth = +_
    return entityflow
  }

  entityflow.sessionPadding = function(_) {
    if (! arguments.length) return sessionPadding
    sessionPadding = +_
    return entityflow
  }

  entityflow.sessionMap = function(_) {
    if (! arguments.length) return sessionMap
    sessionMap = _
    return entityflow
  }

  entityflow.entityPadding = function(_) {
    if (! arguments.length) return entityPadding
    entityPadding = +_
    return entityflow
  }

  entityflow.entityFilter = function(_) {
    if (! arguments.length) return entityFilter
    entityFilter = _
    return entityflow
  }

  entityflow.valueScale = function(_) {
    if (! arguments.length) return valueScale
    valueScale = _
    return entityflow
  }

  entityflow.entities = function(_) {
    if (! arguments.length) return entities
    entities = _
    return entityflow
  }

  entityflow.sessions = function(_, id, label) {
    if (! arguments.length) return sessions
    sessions = sessions.concat(_.map(sessionMap).map(function(s) {
      s.source = {id:id, label:label}
      return s
    }))
    return entityflow
  }

  entityflow.layout = function(iterations) {
    computeSessionGraph()
    computeSessionBreadths()
    computeSessionDepths(iterations)
    for (; iterations > 0; --iterations) {
      minimizeEntityCrossing()
      minimizeEntityWiggle()
    }
    computeEntityDetours()
    entities.sort(function(a, b) {
      return medianNodeDepth(a) - medianNodeDepth(b)
    })
    return entityflow
  }

  entityflow.entityhead = function() {
    function head(d) {
      return [ { x: d.nodes[0].session.x
               , y: d.nodes[0].y
               , dx: d.nodes[0].session.dx
               , dy: d.nodes[0].dy
               , entity: d }
             ]
    }
    return head
  }

  entityflow.entitynodes = function() {
    function nodes(d) {
      return d.nodes
              .filter(function(node) {
               return (! node.detour)
             })
              .map(function(node) {
                var o = Object.assign({}, node,
                  { x: node.session.x
                  , dx: node.session.dx
                  , entity: d
                  })
                delete o.index
                delete o.session
                return o
             })
    }
    return nodes
  }

  entityflow.entitypath = function() {
    function path(d) {
      d.nodes.sort(ascendingSessionBreadth)

      return ( "M" + [d.nodes[0].session.x, d.nodes[0].y]
             + joinTops(d.nodes)
             + "v" + d.nodes[d.nodes.length - 1].dy
             + joinBottoms(d.nodes.slice().reverse())
             + "Z" )
    }

    function ascendingSessionBreadth(a, b) {
      return a.session.x - b.session.x
    }

    function joinTops(nodes) {
      return nodes.map(
        function(node, i) {
          var path = "", dx, dy, ctrlx
          if (i > 0) {
            dx = node.session.x - (nodes[i - 1].session.x + sessionWidth)
            dy = node.y - nodes[i - 1].y
            if (dy > 0) {
              ctrlx = [ dx*0.6, dx*0.5 ]
            } else {
              ctrlx = [ dx*0.5, dx*0.4 ]
            }
            path = "c" + [ ctrlx[0], 0, ctrlx[1], dy, dx, dy ]
          }
          return path + "h" + sessionWidth
        }).join("")
    }

    function joinBottoms(nodes) {
      return nodes.map(
        function(node, i) {
          var path = "", dx, dy, ctrlx
          if (i > 0) {
            dx = (node.session.x + sessionWidth) - nodes[i - 1].session.x
            dy = (node.y + node.dy) - (nodes[i - 1].y + nodes[i - 1].dy)
            if (dy > 0) {
              ctrlx = [ dx*0.5, dx*0.4 ]
            } else {
              ctrlx = [ dx*0.6, dx*0.5 ]
            }
            path = "c" + [ ctrlx[0], 0, ctrlx[1], dy, dx, dy ]
          }
          return path + "h" + (-sessionWidth)
        }).join("")
    }

    return path
  }

  // Each node in the graph belongs to one entity and one session.
  // Links join sessions participated in by the same entity.
  function computeSessionGraph() {
    sessions.forEach(function(session) {
      session.nodes = []
      session.value = 0
      session.sourceLinks = []
      session.targetLinks = []
      session.entities.forEach(function(e) {
        var entity = entities[e.index]
          , node = { entity: entity
                   , session: session
                   , value: ("value" in e) ? e.value : 1
                   , scaledValue: e.value }
          , link
        for (var prop in e) {
          if (e === 'index' || e === 'value') continue
          node[prop] = e[prop]
        }
        e.name = entity.name
        delete e.index
        if (! ("nodes" in entity)) { entity.nodes = [] }
        if (entity.nodes.length > 0) {
          link = { source: entity.nodes[entity.nodes.length - 1].session
                 , target: session }
          link.source.sourceLinks.push(link)
          link.target.targetLinks.push(link)
        }
        entity.nodes.push(node)
        session.nodes.push(node)
        session.value += node.scaledValue
      })
    })

    filterEntities()

    if (valueScale) scaleValues()

    function filterEntities() {
      entities = entities.filter(
        function(entity) {
          if (! ('nodes' in entity)) return false
          var keep = entityFilter(entity)
          if (! keep) {
            entity.nodes.forEach(function(node) {
              node.session.nodes.splice(node.session.nodes.indexOf(node), 1)
              node.session.value -= node.scaledValue
            })
          }
          return keep
        })
    }
{'fraction_non_alphanumeric': 0.12381722604124545, 'fraction_numerical': 0.008896077638495753, 'mean_word_length': 1.6847590099869736, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 15, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '1720520', 'n_tokens_mistral': 3791, 'n_tokens_neox': 3683, 'n_words': 826}