<commit_before>//^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
// Draws "square" and "circle" shapes using svg:rect
//------------------------------------------------------------------------------
d3plus.shape.edges = function(vars) {

  var edges = vars.returned.edges,
      scale = vars.zoom_behavior.scaleExtent()[0]

  if (!edges) var edges = []

  //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  // Initialization of Lines
  //----------------------------------------------------------------------------
  function init(l) {

    var opacity = vars.style.edges.opacity == 1 ? vars.style.edges.opacity : 0

    l
      .attr("opacity",opacity)
      .style("stroke-width",0)
      .style("stroke",vars.style.background)
      .style("fill","none")
  }

  //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  // Styling of Lines
  //----------------------------------------------------------------------------
  function style(edges) {

    var marker = vars.edges.arrows.value ? "url(#d3plus_edge_marker_default)" : "none"

    edges
      .style("stroke-width",vars.style.edges.width)
      .style("stroke",vars.style.edges.color)
      .attr("opacity",vars.style.edges.opacity)
      .attr("marker-start",function(e){
        var direction = vars.edges.arrows.direction.value
        return direction == "source" ? marker : "none"
      })
      .attr("marker-end",function(e){
        var direction = vars.edges.arrows.direction.value
        return direction == "target" ? marker : "none"
      })
      .attr("vector-effect","non-scaling-stroke")
  }

  //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  // Positioning of Lines
  //----------------------------------------------------------------------------
  function line(l) {
    l
      .attr("x1",function(d){
        return d[vars.edges.source].d3plus.x
      })
      .attr("y1",function(d){
        return d[vars.edges.source].d3plus.y
      })
      .attr("x2",function(d){
        return d[vars.edges.target].d3plus.x
      })
      .attr("y2",function(d){
        return d[vars.edges.target].d3plus.y
      })
  }

  //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  // Positioning of Splines
  //----------------------------------------------------------------------------
  var diagonal = d3.svg.diagonal(),
      radial = d3.svg.diagonal()
        .projection(function(d){
          var r = d.y, a = d.x;
          return [r * Math.cos(a), r * Math.sin(a)];
        })

  function spline(l) {
    l
      .attr("d", function(d) {
        if (d[vars.edges.source].d3plus.r) {
          var x1 = d[vars.edges.source].d3plus.a,
              y1 = d[vars.edges.source].d3plus.r,
              x2 = d[vars.edges.target].d3plus.a,
              y2 = d[vars.edges.target].d3plus.r
          var obj = {}
          obj[vars.edges.source] = {"x":x1,"y":y1}
          obj[vars.edges.target] = {"x":x2,"y":y2}
          return radial(obj);

        }
        else {
          var x1 = d[vars.edges.source].d3plus.x,
              y1 = d[vars.edges.source].d3plus.y,
              x2 = d[vars.edges.target].d3plus.x,
              y2 = d[vars.edges.target].d3plus.y
          var obj = {}
          obj[vars.edges.source] = {"x":x1,"y":y1}
          obj[vars.edges.target] = {"x":x2,"y":y2}
          return diagonal(obj);
        }
      })
      .attr("transform",function(d){
        if (d.d3plus && d.d3plus.translate) {
          var x = d.d3plus.translate.x || 0
          var y = d.d3plus.translate.y || 0
          return "translate("+x+","+y+")"
        }
        else {
          "translate(0,0)"
        }
      })
  }

  //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  // Calculates and Draws Label for edge
  //----------------------------------------------------------------------------
  function label(d) {

    delete d.d3plus_label

    if (vars.g.edges.selectAll("line, path").size() < vars.edges.large && vars.edges.label && d[vars.edges.label]) {

      if ("spline" in d.d3plus) {

        var length = this.getTotalLength(),
            center = this.getPointAtLength(length/2),
            prev = this.getPointAtLength((length/2)-(length*.1)),
            next = this.getPointAtLength((length/2)+(length*.1)),
            radians = Math.atan2(next.y-prev.y,next.x-prev.x),
            angle = radians*(180/Math.PI),
            bounding = this.parentNode.getBBox(),
            width = length*.8,
            x = d.d3plus.translate.x+center.x,
            y = d.d3plus.translate.y+center.y,
            translate = {
              "x": d.d3plus.translate.x+center.x,
              "y": d.d3plus.translate.y+center.y
            }

      }
      else {

        var bounds = this.getBBox()
            start = {"x": d[vars.edges.source].d3plus.x, "y": d[vars.edges.source].d3plus.y},
            end = {"x": d[vars.edges.target].d3plus.x, "y": d[vars.edges.target].d3plus.y},
            xdiff = end.x-start.x,
            ydiff = end.y-start.y,
            center = {"x": end.x-(xdiff)/2, "y": end.y-(ydiff)/2},
            radians = Math.atan2(ydiff,xdiff),
            angle = radians*(180/Math.PI),
            length = Math.sqrt((xdiff*xdiff)+(ydiff*ydiff)),
            width = length,
            x = center.x,
            y = center.y,
            translate = {
              "x": center.x,
              "y": center.y
            }

      }

      if (vars.edges.arrows.value) {
        var m = typeof vars.edges.arrows.value == "number" ? typeof vars.edges.arrows.value == "number" : 8
        m = m/vars.zoom_behavior.scaleExtent()[1]
        width -= m*2
      }

      if (angle < -90 || angle > 90) {
        angle -= 180
      }

      d.d3plus_label = {
        "x": x,
        "y": y,
        "translate": translate,
        "w": width,
        "h": 15,
        "angle": angle,
        "anchor": "middle",
        "valign": "center",
        "color": vars.style.edges.color,
        "resize": false,
        "names": [vars.format(d[vars.edges.label])],
        "background": true
      }

    }

  }

  //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  // Enter/update/exit the Arrow Marker
  //----------------------------------------------------------------------------
  var marker_data = vars.edges.arrows.value ? ["default","highlight","focus"] : []
  var marker = vars.defs.selectAll(".d3plus_edge_marker")
    .data(marker_data)

  var m = vars.style.edges.arrows

  var marker_style = function(path) {
    path
      .attr("d",function(){
        if (vars.edges.arrows.direction.value == "target") {
          return "M -"+m+",-"+m/2+" L 0,0 L -"+m+","+m/2+" L -"+m+",-"+m/2
        }
        else {
          return "M "+m+",-"+m/2+" L 0,0 L "+m+","+m/2+" L "+m+",-"+m/2
        }
      })
      .attr("fill",function(d){
        if (d == "default") {
          return vars.style.edges.color
        }
        else if (d == "focus") {
          return vars.style.highlight.focus
        }
        else {
          return vars.style.highlight.primary
        }
      })
  }

  if (vars.timing) {
    marker.exit().transition().duration(vars.timing)
      .attr("opacity",0)
      .remove()

    marker.select("path").transition().duration(vars.timing)
      .attr("opacity",1)
      .attr("markerWidth",m)
      .attr("markerHeight",m)
      .call(marker_style)
  }
  else {
    marker.exit().remove()

    marker.select("path")
      .attr("opacity",1)
      .attr("markerWidth",m)
      .attr("markerHeight",m)
      .call(marker_style)
  }

  var opacity = vars.timing ? 0 : 1
  var enter = marker.enter().append("marker")
    .attr("id",function(d){
      return "d3plus_edge_marker_"+d
    })
    .attr("class","d3plus_edge_marker")
    .attr("orient","auto")
    .attr("markerUnits","userSpaceOnUse")
    .attr("markerWidth",m)
    .attr("markerHeight",m)
    .style("overflow","visible")
    .append("path")
    .attr("opacity",opacity)
    .attr("vector-effect","non-scaling-stroke")
    .call(marker_style)

  if (vars.timing) {
    enter.transition().duration(vars.timing)
      .attr("opacity",1)
  }

  //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  // Bind "edges" data to lines in the "edges" group
  //----------------------------------------------------------------------------
  var line_data = edges.filter(function(l){
    return !l.d3plus || (l.d3plus && !("spline" in l.d3plus))
  })

  var lines = vars.g.edges.selectAll("g.d3plus_edge_line")
    .data(line_data,function(d){

      if (!d.d3plus) {
        d.d3plus = {}
      }

      d.d3plus.id = d[vars.edges.source][vars.id.key]+"_"+d[vars.edges.target][vars.id.key]

      return d.d3plus.id

    })

  var spline_data = edges.filter(function(l){
    return l.d3plus && l.d3plus.spline
  })

  var splines = vars.g.edges.selectAll("g.d3plus_edge_path")
    .data(spline_data,function(d){

      if (!d.d3plus) {
        d.d3plus = {}
      }

      d.d3plus.id = d[vars.edges.source][vars.id.key]+"_"+d[vars.edges.target][vars.id.key]

      return d.d3plus.id

    })

  if (vars.timing) {

    lines.exit().transition().duration(vars.timing)
      .attr("opacity",0)
      .remove()

    splines.exit().transition().duration(vars.timing)
      .attr("opacity",0)
      .remove()

    lines.selectAll("text.d3plus_label, rect.d3plus_label_bg")
      .transition().duration(vars.timing/2)
      .attr("opacity",0)
      .remove()

    splines.selectAll("text.d3plus_label, rect.d3plus_label_bg")
      .transition().duration(vars.timing/2)
      .attr("opacity",0)
      .remove()

    lines.selectAll("line").transition().duration(vars.timing)
      .call(line)
      .call(style)
      .each("end",label)

    splines.selectAll("path").transition().duration(vars.timing)
      .call(spline)
      .call(style)
      .each("end",label)

    lines.enter().append("g")
      .attr("class","d3plus_edge_line")
      .append("line")
      .call(line)
      .call(init)
      .transition().duration(vars.timing)
        .call(style)
        .each("end",label)

    splines.enter().append("g")
      .attr("class","d3plus_edge_path")
      .append("path")
      .call(spline)
      .call(init)
      .transition().duration(vars.timing)
        .call(style)
        .each("end",label)

  }
  else {

    lines.exit().remove()

    splines.exit().remove()

    lines.selectAll("text.d3plus_label, rect.d3plus_label_bg")
      .remove()

    splines.selectAll("text.d3plus_label, rect.d3plus_label_bg")
      .remove()

    lines.selectAll("line")
      .call(line)
      .call(style)
      .call(label)

    splines.selectAll("path")
      .call(spline)
      .call(style)
      .call(label)

    lines.enter().append("g")
      .attr("class","d3plus_edge_line")
      .append("line")
      .call(line)
      .call(init)
      .call(style)
      .call(label)

    splines.enter().append("g")
      .attr("class","d3plus_edge_path")
      .append("path")
      .call(spline)
      .call(init)
      .call(style)
      .call(label)

  }

  vars.g.edges.selectAll("g")
    .sort(function(a,b){
      var a = vars.connected(a),
          b = vars.connected(b)
      return a - b
    })

}
<commit_msg>removed pointer-events from edges<commit_after>//^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
// Draws "square" and "circle" shapes using svg:rect
//------------------------------------------------------------------------------
d3plus.shape.edges = function(vars) {

  var edges = vars.returned.edges,
      scale = vars.zoom_behavior.scaleExtent()[0]

  if (!edges) var edges = []

  //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  // Initialization of Lines
  //----------------------------------------------------------------------------
  function init(l) {

    var opacity = vars.style.edges.opacity == 1 ? vars.style.edges.opacity : 0

    l
      .attr("opacity",opacity)
      .style("stroke-width",0)
      .style("stroke",vars.style.background)
      .style("fill","none")
  }

  //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  // Styling of Lines
  //----------------------------------------------------------------------------
  function style(edges) {

    var marker = vars.edges.arrows.value ? "url(#d3plus_edge_marker_default)" : "none"

    edges
      .style("stroke-width",vars.style.edges.width)
      .style("stroke",vars.style.edges.color)
      .attr("opacity",vars.style.edges.opacity)
      .attr("marker-start",function(e){
        var direction = vars.edges.arrows.direction.value
        return direction == "source" ? marker : "none"
      })
      .attr("marker-end",function(e){
        var direction = vars.edges.arrows.direction.value
        return direction == "target" ? marker : "none"
      })
      .attr("vector-effect","non-scaling-stroke")
      .attr("pointer-events","none")
  }

  //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  // Positioning of Lines
  //----------------------------------------------------------------------------
  function line(l) {
    l
      .attr("x1",function(d){
        return d[vars.edges.source].d3plus.x
      })
      .attr("y1",function(d){
        return d[vars.edges.source].d3plus.y
      })
      .attr("x2",function(d){
        return d[vars.edges.target].d3plus.x
      })
      .attr("y2",function(d){
        return d[vars.edges.target].d3plus.y
      })
  }

  //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  // Positioning of Splines
  //----------------------------------------------------------------------------
  var diagonal = d3.svg.diagonal(),
      radial = d3.svg.diagonal()
        .projection(function(d){
          var r = d.y, a = d.x;
          return [r * Math.cos(a), r * Math.sin(a)];
        })

  function spline(l) {
    l
      .attr("d", function(d) {
        if (d[vars.edges.source].d3plus.r) {
          var x1 = d[vars.edges.source].d3plus.a,
              y1 = d[vars.edges.source].d3plus.r,
              x2 = d[vars.edges.target].d3plus.a,
              y2 = d[vars.edges.target].d3plus.r
          var obj = {}
          obj[vars.edges.source] = {"x":x1,"y":y1}
          obj[vars.edges.target] = {"x":x2,"y":y2}
          return radial(obj);

        }
        else {
          var x1 = d[vars.edges.source].d3plus.x,
              y1 = d[vars.edges.source].d3plus.y,
              x2 = d[vars.edges.target].d3plus.x,
              y2 = d[vars.edges.target].d3plus.y
          var obj = {}
          obj[vars.edges.source] = {"x":x1,"y":y1}
          obj[vars.edges.target] = {"x":x2,"y":y2}
          return diagonal(obj);
        }
      })
      .attr("transform",function(d){
        if (d.d3plus && d.d3plus.translate) {
          var x = d.d3plus.translate.x || 0
          var y = d.d3plus.translate.y || 0
          return "translate("+x+","+y+")"
        }
        else {
          "translate(0,0)"
        }
      })
  }

  //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  // Calculates and Draws Label for edge
  //----------------------------------------------------------------------------
  function label(d) {

    delete d.d3plus_label

    if (vars.g.edges.selectAll("line, path").size() < vars.edges.large && vars.edges.label && d[vars.edges.label]) {

      if ("spline" in d.d3plus) {

        var length = this.getTotalLength(),
            center = this.getPointAtLength(length/2),
            prev = this.getPointAtLength((length/2)-(length*.1)),
            next = this.getPointAtLength((length/2)+(length*.1)),
            radians = Math.atan2(next.y-prev.y,next.x-prev.x),
            angle = radians*(180/Math.PI),
            bounding = this.parentNode.getBBox(),
            width = length*.8,
            x = d.d3plus.translate.x+center.x,
            y = d.d3plus.translate.y+center.y,
            translate = {
              "x": d.d3plus.translate.x+center.x,
              "y": d.d3plus.translate.y+center.y
            }

      }
      else {

        var bounds = this.getBBox()
            start = {"x": d[vars.edges.source].d3plus.x, "y": d[vars.edges.source].d3plus.y},
            end = {"x": d[vars.edges.target].d3plus.x, "y": d[vars.edges.target].d3plus.y},
            xdiff = end.x-start.x,
            ydiff = end.y-start.y,
            center = {"x": end.x-(xdiff)/2, "y": end.y-(ydiff)/2},
            radians = Math.atan2(ydiff,xdiff),
            angle = radians*(180/Math.PI),
            length = Math.sqrt((xdiff*xdiff)+(ydiff*ydiff)),
            width = length,
            x = center.x,
            y = center.y,
            translate = {
              "x": center.x,
              "y": center.y
            }

      }

      if (vars.edges.arrows.value) {
        var m = typeof vars.edges.arrows.value == "number" ? typeof vars.edges.arrows.value == "number" : 8
        m = m/vars.zoom_behavior.scaleExtent()[1]
        width -= m*2
      }

      if (angle < -90 || angle > 90) {
        angle -= 180
      }

      d.d3plus_label = {
        "x": x,
        "y": y,
        "translate": translate,
        "w": width,
        "h": 15,
        "angle": angle,
        "anchor": "middle",
        "valign": "center",
        "color": vars.style.edges.color,
        "resize": false,
        "names": [vars.format(d[vars.edges.label])],
        "background": true
      }

    }

  }

  //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  // Enter/update/exit the Arrow Marker
  //----------------------------------------------------------------------------
  var marker_data = vars.edges.arrows.value ? ["default","highlight","focus"] : []
  var marker = vars.defs.selectAll(".d3plus_edge_marker")
    .data(marker_data)

  var m = vars.style.edges.arrows

  var marker_style = function(path) {
    path
      .attr("d",function(){
        if (vars.edges.arrows.direction.value == "target") {
          return "M -"+m+",-"+m/2+" L 0,0 L -"+m+","+m/2+" L -"+m+",-"+m/2
        }
        else {
          return "M "+m+",-"+m/2+" L 0,0 L "+m+","+m/2+" L "+m+",-"+m/2
        }
      })
      .attr("fill",function(d){
        if (d == "default") {
          return vars.style.edges.color
        }
        else if (d == "focus") {
          return vars.style.highlight.focus
        }
        else {
          return vars.style.highlight.primary
        }
      })
  }

  if (vars.timing) {
    marker.exit().transition().duration(vars.timing)
      .attr("opacity",0)
      .remove()

    marker.select("path").transition().duration(vars.timing)
      .attr("opacity",1)
      .attr("markerWidth",m)
      .attr("markerHeight",m)
      .call(marker_style)
  }
  else {
    marker.exit().remove()

    marker.select("path")
      .attr("opacity",1)
      .attr("markerWidth",m)
      .attr("markerHeight",m)
      .call(marker_style)
  }

  var opacity = vars.timing ? 0 : 1
  var enter = marker.enter().append("marker")
    .attr("id",function(d){
      return "d3plus_edge_marker_"+d
    })
    .attr("class","d3plus_edge_marker")
    .attr("orient","auto")
    .attr("markerUnits","userSpaceOnUse")
    .attr("markerWidth",m)
    .attr("markerHeight",m)
    .style("overflow","visible")
    .append("path")
    .attr("opacity",opacity)
    .attr("vector-effect","non-scaling-stroke")
    .call(marker_style)

  if (vars.timing) {
    enter.transition().duration(vars.timing)
      .attr("opacity",1)
  }

  //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  // Bind "edges" data to lines in the "edges" group
  //----------------------------------------------------------------------------
  var line_data = edges.filter(function(l){
    return !l.d3plus || (l.d3plus && !("spline" in l.d3plus))
  })

  var lines = vars.g.edges.selectAll("g.d3plus_edge_line")
    .data(line_data,function(d){

      if (!d.d3plus) {
        d.d3plus = {}
      }

      d.d3plus.id = d[vars.edges.source][vars.id.key]+"_"+d[vars.edges.target][vars.id.key]

      return d.d3plus.id

    })

  var spline_data = edges.filter(function(l){
    return l.d3plus && l.d3plus.spline
  })

  var splines = vars.g.edges.selectAll("g.d3plus_edge_path")
    .data(spline_data,function(d){

      if (!d.d3plus) {
        d.d3plus = {}
      }

      d.d3plus.id = d[vars.edges.source][vars.id.key]+"_"+d[vars.edges.target][vars.id.key]

      return d.d3plus.id

    })

  if (vars.timing) {

    lines.exit().transition().duration(vars.timing)
      .attr("opacity",0)
      .remove()

    splines.exit().transition().duration(vars.timing)
      .attr("opacity",0)
      .remove()

    lines.selectAll("text.d3plus_label, rect.d3plus_label_bg")
      .transition().duration(vars.timing/2)
      .attr("opacity",0)
      .remove()

    splines.selectAll("text.d3plus_label, rect.d3plus_label_bg")
      .transition().duration(vars.timing/2)
      .attr("opacity",0)
      .remove()

    lines.selectAll("line").transition().duration(vars.timing)
      .call(line)
      .call(style)
      .each("end",label)

    splines.selectAll("path").transition().duration(vars.timing)
      .call(spline)
      .call(style)
      .each("end",label)

    lines.enter().append("g")
      .attr("class","d3plus_edge_line")
      .append("line")
      .call(line)
      .call(init)
      .transition().duration(vars.timing)
        .call(style)
        .each("end",label)

    splines.enter().append("g")
      .attr("class","d3plus_edge_path")
      .append("path")
      .call(spline)
      .call(init)
      .transition().duration(vars.timing)
        .call(style)
        .each("end",label)

  }
  else {

    lines.exit().remove()

    splines.exit().remove()

    lines.selectAll("text.d3plus_label, rect.d3plus_label_bg")
      .remove()

    splines.selectAll("text.d3plus_label, rect.d3plus_label_bg")
      .remove()

    lines.selectAll("line")
      .call(line)
      .call(style)
      .call(label)

    splines.selectAll("path")
      .call(spline)
      .call(style)
      .call(label)

    lines.enter().append("g")
      .attr("class","d3plus_edge_line")
      .append("line")
      .call(line)
      .call(init)
      .call(style)
      .call(label)

    splines.enter().append("g")
      .attr("class","d3plus_edge_path")
      .append("path")
      .call(spline)
      .call(init)
      .call(style)
      .call(label)

  }

  vars.g.edges.selectAll("g")
    .sort(function(a,b){
      var a = vars.connected(a),
          b = vars.connected(b)
      return a - b
    })

}
<|endoftext|>


<commit_before>
function computeLayout(node) {

  function fillNodes(node) {
    node.layout = {
      width: undefined,
      height: undefined,
      top: 0,
      left: 0
    };
    (node.children || []).forEach(fillNodes);
  }

  function extractNodes(node) {
    var layout = node.layout;
    delete node.layout;
    if (node.children) {
      layout.children = node.children.map(extractNodes);
    }
    return layout;
  }

  function capitalizeFirst(str) {
    return str.charAt(0).toUpperCase() + str.slice(1);
  }

  function getMargin(location, node) {
    var key = 'margin' + capitalizeFirst(location);
    if (key in node.style) {
      return node.style[key];
    }

    key = 'margin' + capitalizeFirst(axis[location]);
    if (key in node.style) {
      return node.style[key];
    }

    if ('margin' in node.style) {
      return node.style.margin;
    }

    return 0;
  }

  function getJustifyContent(node) {
    if ('justifyContent' in node.style) {
      return node.style.justifyContent;
    }
    return 'flex-start';
  }

  function getAlignItem(node, child) {
    if ('alignSelf' in child.style) {
      return child.style.alignSelf;
    }
    if ('alignItems' in node.style) {
      return node.style.alignItems;
    }
    return 'flex-start';
  }

  function getFlexDirection(node) {
    if ('flexDirection' in node.style) {
      return node.style.flexDirection;
    }
    return 'column';
  }

  var axis = {
    left: 'horizontal',
    right: 'horizontal',
    top: 'vertical',
    bottom: 'vertical'
  };
  var leading = {
    row: 'left',
    column: 'top'
  };
  var trailing = {
    row: 'right',
    column: 'bottom'
  };
  var pos = {
    row: 'left',
    column: 'top'
  };
  var dim = {
    row: 'width',
    column: 'height'
  };

  var emptyArray = [];

  function layoutNode(node) {
    var mainAxis = getFlexDirection(node);
    var crossAxis = mainAxis === 'row' ? 'column' : 'row';
    var children = node.children || emptyArray;

    var mainDimInStyle = dim[mainAxis] in node.style;
    if (node.layout[dim[mainAxis]] === undefined && mainDimInStyle) {
      node.layout[dim[mainAxis]] = node.style[dim[mainAxis]];
    }

    var crossDimInStyle = dim[crossAxis] in node.style;
    if (node.layout[dim[crossAxis]] === undefined && crossDimInStyle) {
      node.layout[dim[crossAxis]] = node.style[dim[crossAxis]];
    }

    var mainContentDim = 0;
    var flexibleChildrenCount = 0;
    children.forEach(function(child) {
      if (!child.style.flex) {
        layoutNode(child);
        mainContentDim += child.layout[dim[mainAxis]];
      } else {
        flexibleChildrenCount++;
      }
    });

    var remainingMainDim = node.layout[dim[mainAxis]] - mainContentDim;
    var leadingMainDim = 0;
    var betweenMainDim = 0;
    if (flexibleChildrenCount) {
      var flexibleMainDim = remainingMainDim / flexibleChildrenCount;
      children.forEach(function(child) {
        if (child.style.flex) {
          child.layout[dim[mainAxis]] = flexibleMainDim;
          layoutNode(child);
        }
      });
    } else {
      var justifyContent = getJustifyContent(node);
      if (justifyContent == 'flex-start') {
        // Do nothing
      } else if (justifyContent === 'flex-end') {
        leadingMainDim = remainingMainDim;
      } else if (justifyContent === 'center') {
        leadingMainDim = remainingMainDim / 2;
      } else if (justifyContent === 'space-between') {
        betweenMainDim = remainingMainDim / (children.length - 1);
      } else if (justifyContent === 'space-around') {
        betweenMainDim = remainingMainDim / children.length;
        leadingMainDim = betweenMainDim / 2;
      }
    }

    var crossDim = 0;
    var mainPos = leadingMainDim;
    children.forEach(function(child) {
      child.layout[pos[mainAxis]] += mainPos;
      mainPos += child.layout[dim[mainAxis]] +
        getMargin(leading[mainAxis], child) +
        getMargin(trailing[mainAxis], child) +
        betweenMainDim;

      if (child.layout[dim[crossAxis]] !== undefined) {
        var childCrossDim = child.layout[dim[crossAxis]] +
          getMargin(leading[crossAxis], child) +
          getMargin(trailing[crossAxis], child);

        if (childCrossDim > crossDim) {
          crossDim = childCrossDim;
        }
      }
    });

    if (node.layout[dim[mainAxis]] === undefined && !mainDimInStyle) {
      node.layout[dim[mainAxis]] = mainPos;
    }
    if (node.layout[dim[crossAxis]] === undefined) {
      node.layout[dim[crossAxis]] = crossDim;
    }

    children.forEach(function(child) {
      var alignItem = getAlignItem(node, child);
      var remainingCrossDim = node.layout[dim[crossAxis]] - child.layout[dim[crossAxis]];
      var leadingCrossDim = 0;
      if (alignItem === 'flex-start') {
        // Do nothing
      } else if (alignItem === 'center') {
        leadingCrossDim = remainingCrossDim / 2;
      } else if (alignItem === 'flex-end') {
        leadingCrossDim = remainingCrossDim;
      } else if (alignItem === 'stretch') {
        child.layout[dim[crossAxis]] = node.layout[dim[crossAxis]] -
          getMargin(leading[crossAxis], child) -
          getMargin(trailing[crossAxis], child);
      }
      child.layout[pos[crossAxis]] += leadingCrossDim;
    });

    node.layout[leading[mainAxis]] += getMargin(leading[mainAxis], node);
    node.layout[leading[crossAxis]] += getMargin(leading[crossAxis], node);
  }

  fillNodes(node);
  node.layout.top = 0;
  node.layout.left = 0;

  layoutNode(node);
  return extractNodes(node);
}

<commit_msg>Don't go negative in height<commit_after>
function computeLayout(node) {

  function fillNodes(node) {
    node.layout = {
      width: undefined,
      height: undefined,
      top: 0,
      left: 0
    };
    (node.children || []).forEach(fillNodes);
  }

  function extractNodes(node) {
    var layout = node.layout;
    delete node.layout;
    if (node.children) {
      layout.children = node.children.map(extractNodes);
    }
    return layout;
  }

  function capitalizeFirst(str) {
    return str.charAt(0).toUpperCase() + str.slice(1);
  }

  function getMargin(location, node) {
    var key = 'margin' + capitalizeFirst(location);
    if (key in node.style) {
      return node.style[key];
    }

    key = 'margin' + capitalizeFirst(axis[location]);
    if (key in node.style) {
      return node.style[key];
    }

    if ('margin' in node.style) {
      return node.style.margin;
    }

    return 0;
  }

  function getJustifyContent(node) {
    if ('justifyContent' in node.style) {
      return node.style.justifyContent;
    }
    return 'flex-start';
  }

  function getAlignItem(node, child) {
    if ('alignSelf' in child.style) {
      return child.style.alignSelf;
    }
    if ('alignItems' in node.style) {
      return node.style.alignItems;
    }
    return 'flex-start';
  }

  function getFlexDirection(node) {
    if ('flexDirection' in node.style) {
      return node.style.flexDirection;
    }
    return 'column';
  }

  var axis = {
    left: 'horizontal',
    right: 'horizontal',
    top: 'vertical',
    bottom: 'vertical'
  };
  var leading = {
    row: 'left',
    column: 'top'
  };
  var trailing = {
    row: 'right',
    column: 'bottom'
  };
  var pos = {
    row: 'left',
    column: 'top'
  };
  var dim = {
    row: 'width',
    column: 'height'
  };

  var emptyArray = [];

  function layoutNode(node) {
    var mainAxis = getFlexDirection(node);
    var crossAxis = mainAxis === 'row' ? 'column' : 'row';
    var children = node.children || emptyArray;

    var mainDimInStyle = dim[mainAxis] in node.style;
    if (node.layout[dim[mainAxis]] === undefined && mainDimInStyle) {
      node.layout[dim[mainAxis]] = node.style[dim[mainAxis]];
    }

    var crossDimInStyle = dim[crossAxis] in node.style;
    if (node.layout[dim[crossAxis]] === undefined && crossDimInStyle) {
      node.layout[dim[crossAxis]] = node.style[dim[crossAxis]];
    }

    var mainContentDim = 0;
    var flexibleChildrenCount = 0;
    children.forEach(function(child) {
      if (!child.style.flex) {
        layoutNode(child);
        mainContentDim += child.layout[dim[mainAxis]];
      } else {
        flexibleChildrenCount++;
      }
    });

    var remainingMainDim = node.layout[dim[mainAxis]] - mainContentDim;
    var leadingMainDim = 0;
    var betweenMainDim = 0;
    if (flexibleChildrenCount) {
      var flexibleMainDim = remainingMainDim / flexibleChildrenCount;
      children.forEach(function(child) {
        if (child.style.flex) {
          child.layout[dim[mainAxis]] = flexibleMainDim;
          layoutNode(child);
        }
      });
    } else {
      var justifyContent = getJustifyContent(node);
      if (justifyContent == 'flex-start') {
        // Do nothing
      } else if (justifyContent === 'flex-end') {
        leadingMainDim = remainingMainDim;
      } else if (justifyContent === 'center') {
        leadingMainDim = remainingMainDim / 2;
      } else if (justifyContent === 'space-between') {
        betweenMainDim = remainingMainDim / (children.length - 1);
      } else if (justifyContent === 'space-around') {
        betweenMainDim = remainingMainDim / children.length;
        leadingMainDim = betweenMainDim / 2;
      }
    }

    var crossDim = 0;
    var mainPos = leadingMainDim;
    children.forEach(function(child) {
      child.layout[pos[mainAxis]] += mainPos;
      mainPos += child.layout[dim[mainAxis]] +
        getMargin(leading[mainAxis], child) +
        getMargin(trailing[mainAxis], child) +
        betweenMainDim;

      if (child.layout[dim[crossAxis]] !== undefined) {
        var childCrossDim = child.layout[dim[crossAxis]] +
          getMargin(leading[crossAxis], child) +
          getMargin(trailing[crossAxis], child);

        if (childCrossDim > crossDim) {
          crossDim = childCrossDim;
        }
      }
    });

    if (node.layout[dim[mainAxis]] === undefined && !mainDimInStyle) {
      node.layout[dim[mainAxis]] = Math.max(mainPos, 0);
    }
    if (node.layout[dim[crossAxis]] === undefined) {
      node.layout[dim[crossAxis]] = Math.max(crossDim, 0);
    }

    children.forEach(function(child) {
      var alignItem = getAlignItem(node, child);
      var remainingCrossDim = node.layout[dim[crossAxis]] - child.layout[dim[crossAxis]];
      var leadingCrossDim = 0;
      if (alignItem === 'flex-start') {
        // Do nothing
      } else if (alignItem === 'center') {
        leadingCrossDim = remainingCrossDim / 2;
      } else if (alignItem === 'flex-end') {
        leadingCrossDim = remainingCrossDim;
      } else if (alignItem === 'stretch') {
        child.layout[dim[crossAxis]] = node.layout[dim[crossAxis]] -
          getMargin(leading[crossAxis], child) -
          getMargin(trailing[crossAxis], child);
      }
      child.layout[pos[crossAxis]] += leadingCrossDim;
    });

    node.layout[leading[mainAxis]] += getMargin(leading[mainAxis], node);
    node.layout[leading[crossAxis]] += getMargin(leading[crossAxis], node);
  }

  fillNodes(node);
  node.layout.top = 0;
  node.layout.left = 0;

  layoutNode(node);
  return extractNodes(node);
}

<|endoftext|>


<commit_before>/*
 * Copyright 2013 The Toolkitchen Authors. All rights reserved.
 * Use of this source code is governed by a BSD-style
 * license that can be found in the LICENSE file.
 */

(function(scope) {

var thisFile = 'toolkit.js';

// NOTE: use attributes on the script tag for this file as directives
// NOTE: uses 'window' and 'document' globals

// acquire directives and base path from script element

var attributes={}, base = '';

(function() {
  var s$ = document.querySelectorAll('script[src]');
  Array.prototype.forEach.call(s$, function(s) {
    var src = s.getAttribute('src');
    var re = new RegExp(thisFile + '[^\\\\]*');
    var match = src.match(re);
    if (match) {
      attributes = s.attributes;
      base = src.slice(0, -match[0].length);
    }
  });
})();

// flags

var flags = window.flags || {};

// acquire flags from script tag attributes

for (var i=0, a; (a=attributes[i]); i++) {
  flags[a.name] = a.value || true;
}

// acquire flags from url

if (!flags.noOpts) {
  location.search.slice(1).split('&').forEach(function(o) {
    o = o.split('=');
    flags[o[0]] = o[1] || true;
  });
}

// process log flags

var logFlags = window.logFlags || {};
if (flags.log) {
  flags.log.split(',').forEach(function(f) {
    logFlags[f] = true;
  });
}
window.logFlags = logFlags;

// support exportas directive

scope = scope || {};

if (flags.exportas) {
  window[flags.exportas] = scope;
}

// module exports

scope.flags = flags;

// report effective flags

console.log(flags);

// assemble list of dependencies

var modules = [
  'src/lang.js',
  'src/oop.js',
  'src/register.js',
  'src/bindProperties.js',
  'src/bindMDV.js',
  'src/attrs.js',
  'src/marshal.js',
  'src/events.js',
  'src/observeProperties.js',
  'src/styling.js',
  'src/shimStyling.js',
  'src/path.js',
  'src/job.js',
  'src/boot.js'
];

// load platform it it's not already available
if (!window.__platform__) {
    modules.unshift('platform/platform.js');
}

// write script tags for dependencies

modules.forEach(function(inSrc) {
  document.write('<script src="' + base + inSrc + '"></script>');
});

})();
<commit_msg>undo auto platform loading for now, caused problems with builds.<commit_after>/*
 * Copyright 2013 The Toolkitchen Authors. All rights reserved.
 * Use of this source code is governed by a BSD-style
 * license that can be found in the LICENSE file.
 */

(function(scope) {

var thisFile = 'toolkit.js';

// NOTE: use attributes on the script tag for this file as directives
// NOTE: uses 'window' and 'document' globals

// acquire directives and base path from script element

var attributes={}, base = '';

(function() {
  var s$ = document.querySelectorAll('script[src]');
  Array.prototype.forEach.call(s$, function(s) {
    var src = s.getAttribute('src');
    var re = new RegExp(thisFile + '[^\\\\]*');
    var match = src.match(re);
    if (match) {
      attributes = s.attributes;
      base = src.slice(0, -match[0].length);
    }
  });
})();

// flags

var flags = window.flags || {};

// acquire flags from script tag attributes

for (var i=0, a; (a=attributes[i]); i++) {
  flags[a.name] = a.value || true;
}

// acquire flags from url

if (!flags.noOpts) {
  location.search.slice(1).split('&').forEach(function(o) {
    o = o.split('=');
    flags[o[0]] = o[1] || true;
  });
}

// process log flags

var logFlags = window.logFlags || {};
if (flags.log) {
  flags.log.split(',').forEach(function(f) {
    logFlags[f] = true;
  });
}
window.logFlags = logFlags;

// support exportas directive

scope = scope || {};

if (flags.exportas) {
  window[flags.exportas] = scope;
}

// module exports

scope.flags = flags;

// report effective flags

console.log(flags);

// assemble list of dependencies

var modules = [
  'src/lang.js',
  'src/oop.js',
  'src/register.js',
  'src/bindProperties.js',
  'src/bindMDV.js',
  'src/attrs.js',
  'src/marshal.js',
  'src/events.js',
  'src/observeProperties.js',
  'src/styling.js',
  'src/shimStyling.js',
  'src/path.js',
  'src/job.js',
  'src/boot.js'
];

// write script tags for dependencies

modules.forEach(function(inSrc) {
  document.write('<script src="' + base + inSrc + '"></script>');
});

})();
<|endoftext|>


<commit_before>import React from 'react'
import MapFilter from 'react-mapfilter'
import traverse from 'traverse'
import {ipcRenderer, remote} from 'electron'
import toBuffer from 'blob-to-buffer'
import assign from 'object-assign'
import diff from 'lodash/difference'
import path from 'path'
import {
  FIELD_TYPE_STRING,
  FIELD_TYPE_BOOLEAN,
  FIELD_TYPE_SPACE_DELIMITED
} from 'react-mapfilter/es5/constants'
import xor from 'lodash/xor'
import differenceBy from 'lodash/differenceBy'

import api from '../api'

import Sidebar from './Sidebar'
import MapEditor from './MapEditor'
import ConvertDialog from './ConvertDialog'
import ConvertButton from './ConvertButton'
import XFormUploader from './XFormUploader'
import Title from './Title'

const osmServerHost = 'http://' + remote.getGlobal('osmServerHost')

const mediaBaseUrl = `${osmServerHost}/media/`
const styleUrl = `${osmServerHost}/styles/mapfilter-style/style.json`

class Home extends React.Component {
  constructor (props) {
    super(props)
    var self = this
    self.state = {
      featuresByFormId: {
        'Mapeo Mobile': []
      },
      formId: 'Mapeo Mobile',
      showModal: false,
      mapStyle: styleUrl
    }
    self.getFeatures()
    this.zoomToDataRequest = this.zoomToDataRequest.bind(this)
    this.zoomToDataResponse = this.zoomToDataResponse.bind(this)
    this.zoomToLatLonResponse = this.zoomToLatLonResponse.bind(this)
    ipcRenderer.on('zoom-to-data-request', this.zoomToDataRequest)
    ipcRenderer.on('zoom-to-data-response', self.zoomToDataResponse)
    ipcRenderer.on('zoom-to-latlon-response', self.zoomToLatLonResponse)
  }

  componentWillUnmount () {
    ipcRenderer.removeListener('zoom-to-data-request', this.zoomToDataRequest)
    ipcRenderer.removeListener('zoom-to-data-response', this.zoomToDataResponse)
    ipcRenderer.removeListener('zoom-to-latlon-response', this.zoomToLatLonResponse)
  }

  zoomToLatLonResponse (_, lat, lon) {
    this.setState({
      mapPosition: {center: [lat, lon], zoom: 14}
    })
  }

  zoomToDataResponse (_, loc) {
    this.setState({
      mapPosition: {center: loc, zoom: 14}
    })
  }

  zoomToDataRequest () {
    ipcRenderer.send('zoom-to-data-get-centroid')
  }

  handleDatasetChange = (e) => {
    this.setState({formId: e.target.value})
  }

  handleConvertFeaturesClick = () => {
    this.setState({showModal: 'convert'})
  }

  handleChangeFeatures = (changedFeatures) => {
    const {featuresByFormId, formId} = this.state
    const features = featuresByFormId[formId]
    const xorFeatures = xor(changedFeatures, features)
    const deleted = differenceBy(xorFeatures, changedFeatures, 'id')
    const added = differenceBy(xorFeatures, features, 'id')
    const updated = xorFeatures.filter(f => added.indexOf(f) === -1 && deleted.indexOf(f) === -1)

    var cb = function (err, resp) {
      if (err) return this.handleError(err)
    }

    deleted.forEach(f => api.del(f, cb))
    added.forEach(f => function (f) {
      console.log('added', f)
      api.create(featureToObservation(f), cb)
    })
    updated.forEach(f => function (f) {
      console.log('updated', f)
      api.update(featureToObservation(f), cb)
    })
    const newFeaturesByFormId = assign({}, this.state.featuresByFormId)
    newFeaturesByFormId[this.state.formId] = changedFeatures
    this.setState({featuresByFormId: newFeaturesByFormId})
  }

  closeModal = () => {
    this.setState({showModal: false})
  }

  getFeatures () {
    var self = this
    api.list(function (err, resp) {
      if (err) return this.handleError(err)
      var features = JSON.parse(resp.body)
      self._seen = new Set(features.map(f => f.id))
      features = features.map(observationToFeature)
      self.setState(state => ({
        featuresByFormId: features.reduce(formIdReducer, assign({}, state.featuresByFormId))
      }))
    })
  }

  uploadForm = (formData) => {
    return new Promise((resolve, reject) => {
      api.create(formData, function (err, resp) {
        if (err) return reject(err)
        if (typeof formData.properties.public === 'undefined') {
          formData.properties.public = false
        }
        if (!formData.properties.summary) {
          formData.properties.summary = ''
        }
        resolve(formData)
      })
    })
  }

  onUpload = (err, features) => {
    if (err) return this.handleError(err)
    features.forEach(function (f) {
      f.properties = replaceProtocols(f.properties, mediaBaseUrl)
    })
    this.setState(state => ({
      featuresByFormId: features.reduce(formIdReducer, assign({}, state.featuresByFormId))
    }))
  }

  replicateToServer = (server, done) => {
    var self = this
    ipcRenderer.once('replicate-server-complete', function (event, err) {
      if (err) {
        if (err.code === "ECONNREFUSED")
        self.handleError(new Error('Cant find the server. Is it correct?'))
      }
      return done(err)
    })
    ipcRenderer.send('replicate-server', server)
  }

  uploadFile = (blob, filepath) => {
    return new Promise((resolve, reject) => {
      toBuffer(blob, (err, buf) => {
        if (err) return reject(err)
        api.createMedia(opts, (err, resp) => {
          if (err) return reject(err)
          var json = JSON.parse(resp.body)
          resolve(json.id)
        })
      })
    })
  }

  handleChangeMapPosition (pos) {
    console.log('hi', pos)
  }

  render () {
    const {featuresByFormId, formId, showModal, mapPosition} = this.state
    const {changeView, openModal} = this.props
    const toolbarTitle = <Title
      onConvert={this.handleConvertFeaturesClick}
      datasets={Object.keys(featuresByFormId)}
      activeDataset={formId}
      onChange={this.handleDatasetChange} />

    var features = featuresByFormId[formId] || []

    return (

      <MapFilter
        mapStyle={styleUrl}
        features={features}
        onChangeFeatures={this.handleChangeFeatures}
        fieldTypes={{
          impacts: FIELD_TYPE_SPACE_DELIMITED,
          people: FIELD_TYPE_SPACE_DELIMITED,
          public: FIELD_TYPE_BOOLEAN,
          summary: FIELD_TYPE_STRING,
          'meta.instanceName': FIELD_TYPE_STRING
        }}
        datasetName={formId}
        fieldOrder={{
          location: 0,
          public: 1,
          summary: 2
        }}
        appBarButtons={[<Sidebar
          changeView={changeView}
          openModal={openModal}
          />]}
        appBarTitle={toolbarTitle} />

      <ConvertDialog
        open={showModal === 'convert'}
        onClose={() => { this.setState({showModal: false}) }}
        features={features} />

)
  }
}

function formIdReducer (acc, f) {
  let formId = (f.properties.meta && f.properties.meta.formId) || 'Mapeo Mobile'
  formId = formId.replace(/_v\d+$/, '')
  if (!acc[formId]) {
    acc[formId] = [f]
  } else {
    acc[formId] = acc[formId].concat([f])
  }
  return acc
}

function replaceProtocols (obj, baseUrl) {
  return traverse(obj).map(function (value) {
    if (typeof value !== 'string') return
    var newValue = value.replace(/^mapeo:\/\//, baseUrl)
    if (newValue !== value) {
      this.update(newValue)
    }
  })
}

function observationToFeature (obs, id) {
  var feature = Object.assign(obs, {
    type: 'Feature',
    geometry: null
  })

  feature.properties = obs.tags || {}

  if (obs.lon && obs.lat) {
    feature.geometry = {
      type: 'Point',
      coordinates: [obs.lon, obs.lat]
    }
  }
  feature.properties.media = obs.attachments.map(function (a) {
    // TODO: handle other image types
    return {
      type: 'image',
      value: `${osmServerHost}/media/original/${a.id}`,
      attachment: a
    }
  })

  if (typeof feature.properties.public === 'undefined') {
    feature.properties.public = false
  }
  if (!feature.properties.summary) {
    feature.properties.summary = ' '
  }
  feature.properties = replaceProtocols(feature.properties, mediaBaseUrl)
  return feature
}

function featureToObservation (feature) {
  return {
    lat: feature.lat,
    lon: feature.lon,
    tags: feature.properties,
    version: feature.version,
    attachments: feature.properties.media.map((m) => m.attachment),
  }
}

module.exports = Home

<commit_msg>Revert "don't pass mapPosition in to react-mapfilter"<commit_after>import React from 'react'
import MapFilter from 'react-mapfilter'
import traverse from 'traverse'
import {ipcRenderer, remote} from 'electron'
import toBuffer from 'blob-to-buffer'
import assign from 'object-assign'
import diff from 'lodash/difference'
import path from 'path'
import {
  FIELD_TYPE_STRING,
  FIELD_TYPE_BOOLEAN,
  FIELD_TYPE_SPACE_DELIMITED
} from 'react-mapfilter/es5/constants'
import xor from 'lodash/xor'
import differenceBy from 'lodash/differenceBy'

import api from '../api'

import Sidebar from './Sidebar'
import MapEditor from './MapEditor'
import ConvertDialog from './ConvertDialog'
import ConvertButton from './ConvertButton'
import XFormUploader from './XFormUploader'
import Title from './Title'

const osmServerHost = 'http://' + remote.getGlobal('osmServerHost')

const mediaBaseUrl = `${osmServerHost}/media/`
const styleUrl = `${osmServerHost}/styles/mapfilter-style/style.json`

class Home extends React.Component {
  constructor (props) {
    super(props)
    var self = this
    self.state = {
      featuresByFormId: {
        'Mapeo Mobile': []
      },
      mapPosition: {center: [0,0], zoom: 0},
      formId: 'Mapeo Mobile',
      showModal: false,
      mapStyle: styleUrl
    }
    self.getFeatures()
    this.zoomToDataRequest = this.zoomToDataRequest.bind(this)
    this.zoomToDataResponse = this.zoomToDataResponse.bind(this)
    this.zoomToLatLonResponse = this.zoomToLatLonResponse.bind(this)
    ipcRenderer.on('zoom-to-data-request', this.zoomToDataRequest)
    ipcRenderer.on('zoom-to-data-response', self.zoomToDataResponse)
    ipcRenderer.on('zoom-to-latlon-response', self.zoomToLatLonResponse)
  }

  componentWillUnmount () {
    ipcRenderer.removeListener('zoom-to-data-request', this.zoomToDataRequest)
    ipcRenderer.removeListener('zoom-to-data-response', this.zoomToDataResponse)
    ipcRenderer.removeListener('zoom-to-latlon-response', this.zoomToLatLonResponse)
  }

  zoomToLatLonResponse (_, lat, lon) {
    this.setState({
      mapPosition: {center: [lat, lon], zoom: 14}
    })
  }

  zoomToDataResponse (_, loc) {
    this.setState({
      mapPosition: {center: loc, zoom: 14}
    })
  }

  zoomToDataRequest () {
    ipcRenderer.send('zoom-to-data-get-centroid')
  }

  handleDatasetChange = (e) => {
    this.setState({formId: e.target.value})
  }

  handleConvertFeaturesClick = () => {
    this.setState({showModal: 'convert'})
  }

  handleChangeFeatures = (changedFeatures) => {
    const {featuresByFormId, formId} = this.state
    const features = featuresByFormId[formId]
    const xorFeatures = xor(changedFeatures, features)
    const deleted = differenceBy(xorFeatures, changedFeatures, 'id')
    const added = differenceBy(xorFeatures, features, 'id')
    const updated = xorFeatures.filter(f => added.indexOf(f) === -1 && deleted.indexOf(f) === -1)

    var cb = function (err, resp) {
      if (err) return this.handleError(err)
    }

    deleted.forEach(f => api.del(f, cb))
    added.forEach(f => function (f) {
      console.log('added', f)
      api.create(featureToObservation(f), cb)
    })
    updated.forEach(f => function (f) {
      console.log('updated', f)
      api.update(featureToObservation(f), cb)
    })
    const newFeaturesByFormId = assign({}, this.state.featuresByFormId)
    newFeaturesByFormId[this.state.formId] = changedFeatures
    this.setState({featuresByFormId: newFeaturesByFormId})
  }

  closeModal = () => {
    this.setState({showModal: false})
  }

  getFeatures () {
    var self = this
    api.list(function (err, resp) {
      if (err) return this.handleError(err)
      var features = JSON.parse(resp.body)
      self._seen = new Set(features.map(f => f.id))
      features = features.map(observationToFeature)
      self.setState(state => ({
        featuresByFormId: features.reduce(formIdReducer, assign({}, state.featuresByFormId))
      }))
    })
  }

  uploadForm = (formData) => {
    return new Promise((resolve, reject) => {
      api.create(formData, function (err, resp) {
        if (err) return reject(err)
        if (typeof formData.properties.public === 'undefined') {
          formData.properties.public = false
        }
        if (!formData.properties.summary) {
          formData.properties.summary = ''
        }
        resolve(formData)
      })
    })
  }

  onUpload = (err, features) => {
    if (err) return this.handleError(err)
    features.forEach(function (f) {
      f.properties = replaceProtocols(f.properties, mediaBaseUrl)
    })
    this.setState(state => ({
      featuresByFormId: features.reduce(formIdReducer, assign({}, state.featuresByFormId))
    }))
  }

  replicateToServer = (server, done) => {
    var self = this
    ipcRenderer.once('replicate-server-complete', function (event, err) {
      if (err) {
        if (err.code === "ECONNREFUSED")
        self.handleError(new Error('Cant find the server. Is it correct?'))
      }
      return done(err)
    })
    ipcRenderer.send('replicate-server', server)
  }

  uploadFile = (blob, filepath) => {
    return new Promise((resolve, reject) => {
      toBuffer(blob, (err, buf) => {
        if (err) return reject(err)
        api.createMedia(opts, (err, resp) => {
          if (err) return reject(err)
          var json = JSON.parse(resp.body)
          resolve(json.id)
        })
      })
    })
  }

  handleChangeMapPosition (pos) {
    console.log('hi', pos)
  }

  render () {
    const {featuresByFormId, formId, showModal, mapPosition} = this.state
    const {changeView, openModal} = this.props
    const toolbarTitle = <Title
      onConvert={this.handleConvertFeaturesClick}
      datasets={Object.keys(featuresByFormId)}
      activeDataset={formId}
      onChange={this.handleDatasetChange} />

    var features = featuresByFormId[formId] || []

    return (

      <MapFilter
        mapStyle={styleUrl}
        features={features}
        mapPosition={mapPosition}
        onChangeMapPosition={this.handleChangeMapPosition}
        onChangeFeatures={this.handleChangeFeatures}
        fieldTypes={{
          impacts: FIELD_TYPE_SPACE_DELIMITED,
          people: FIELD_TYPE_SPACE_DELIMITED,
          public: FIELD_TYPE_BOOLEAN,
          summary: FIELD_TYPE_STRING,
          'meta.instanceName': FIELD_TYPE_STRING
        }}
        datasetName={formId}
        fieldOrder={{
          location: 0,
          public: 1,
          summary: 2
        }}
        appBarButtons={[<Sidebar
          changeView={changeView}
          openModal={openModal}
          />]}
        appBarTitle={toolbarTitle} />

      <ConvertDialog
        open={showModal === 'convert'}
        onClose={() => { this.setState({showModal: false}) }}
        features={features} />

)
  }
}

function formIdReducer (acc, f) {
  let formId = (f.properties.meta && f.properties.meta.formId) || 'Mapeo Mobile'
  formId = formId.replace(/_v\d+$/, '')
  if (!acc[formId]) {
    acc[formId] = [f]
  } else {
    acc[formId] = acc[formId].concat([f])
  }
  return acc
}

function replaceProtocols (obj, baseUrl) {
  return traverse(obj).map(function (value) {
    if (typeof value !== 'string') return
    var newValue = value.replace(/^mapeo:\/\//, baseUrl)
    if (newValue !== value) {
      this.update(newValue)
    }
  })
}

function observationToFeature (obs, id) {
  var feature = Object.assign(obs, {
    type: 'Feature',
    geometry: null
  })

  feature.properties = obs.tags || {}

  if (obs.lon && obs.lat) {
    feature.geometry = {
      type: 'Point',
      coordinates: [obs.lon, obs.lat]
    }
  }
  feature.properties.media = obs.attachments.map(function (a) {
    // TODO: handle other image types
    return {
      type: 'image',
      value: `${osmServerHost}/media/original/${a.id}`,
      attachment: a
    }
  })

  if (typeof feature.properties.public === 'undefined') {
    feature.properties.public = false
  }
  if (!feature.properties.summary) {
    feature.properties.summary = ' '
  }
  feature.properties = replaceProtocols(feature.properties, mediaBaseUrl)
  return feature
}

function featureToObservation (feature) {
  return {
    lat: feature.lat,
    lon: feature.lon,
    tags: feature.properties,
    version: feature.version,
    attachments: feature.properties.media.map((m) => m.attachment),
  }
}

module.exports = Home

<|endoftext|>


<commit_before>
openerp.base.formats = function(openerp) {

/**
 * Converts a string to a Date javascript object using OpenERP's
 * datetime string format (exemple: '2011-12-01 15:12:35').
 *
 * The timezone is assumed to be UTC (standard for OpenERP 6.1)
 * and will be converted to the browser's timezone.
 *
 * @param {String} str A string representing a datetime.
 * @returns {Date}
 */
openerp.base.parse_datetime = function(str) {
    if(!str) {
        return str;
    }
    var regex = /\d\d\d\d-\d\d-\d\d \d\d:\d\d:\d\d/;
    var res = regex.exec(str);
    if ( res[0] != str ) {
        throw "'" + str + "' is not a valid datetime";
    }
    var obj = Date.parse(str + " GMT");
    if (! obj) {
        throw "'" + str + "' is not a valid datetime";
    }
    return obj;
};

/**
 * Converts a string to a Date javascript object using OpenERP's
 * date string format (exemple: '2011-12-01').
 *
 * @param {String} str A string representing a date.
 * @returns {Date}
 */
openerp.base.parse_date = function(str) {
    if(!str) {
        return str;
    }
    var regex = /\d\d\d\d-\d\d-\d\d/;
    var res = regex.exec(str);
    if ( res[0] != str ) {
        throw "'" + str + "' is not a valid date";
    }
    var obj = Date.parse(str);
    if (! obj) {
        throw "'" + str + "' is not a valid date";
    }
    return obj;
};

/**
 * Converts a string to a Date javascript object using OpenERP's
 * time string format (exemple: '15:12:35').
 *
 * @param {String} str A string representing a time.
 * @returns {Date}
 */
openerp.base.parse_time = function(str) {
    if(!str) {
        return str;
    }
    var regex = /\d\d:\d\d:\d\d/;
    var res = regex.exec(str);
    if ( res[0] != str ) {
        throw "'" + str + "' is not a valid time";
    }
    var obj = Date.parse(str);
    if (! obj) {
        throw "'" + str + "' is not a valid time";
    }
    return obj;
};

/*
 * Left-pad provided arg 1 with zeroes until reaching size provided by second
 * argument.
 *
 * @param {Number|String} str value to pad
 * @param {Number} size size to reach on the final padded value
 * @returns {String} padded string
 */
var zpad = function(str, size) {
    str = "" + str;
    return new Array(size - str.length).join('0') + str;
};

/**
 * Converts a Date javascript object to a string using OpenERP's
 * datetime string format (exemple: '2011-12-01 15:12:35').
 *
 * The timezone of the Date object is assumed to be the one of the
 * browser and it will be converted to UTC (standard for OpenERP 6.1).
 *
 * @param {Date} obj
 * @returns {String} A string representing a datetime.
 */
openerp.base.format_datetime = function(obj) {
    if (!obj) {
        return false;
    }
    return zpad(obj.getUTCFullYear(),4) + "-" + zpad(obj.getUTCMonth() + 1,2) + "-"
         + zpad(obj.getUTCDate(),2) + " " + zpad(obj.getUTCHours(),2) + ":"
         + zpad(obj.getUTCMinutes(),2) + ":" + zpad(obj.getUTCSeconds(),2);
};

/**
 * Converts a Date javascript object to a string using OpenERP's
 * date string format (exemple: '2011-12-01').
 *
 * @param {Date} obj
 * @returns {String} A string representing a date.
 */
openerp.base.format_date = function(obj) {
    if (!obj) {
        return false;
    }
    return zpad(obj.getFullYear(),4) + "-" + zpad(obj.getMonth() + 1,2) + "-"
         + zpad(obj.getDate(),2);
};

/**
 * Converts a Date javascript object to a string using OpenERP's
 * time string format (exemple: '15:12:35').
 *
 * @param {Date} obj
 * @returns {String} A string representing a time.
 */
openerp.base.format_time = function(obj) {
    if (!obj) {
        return false;
    }
    return zpad(obj.getHours(),2) + ":" + zpad(obj.getMinutes(),2) + ":"
         + zpad(obj.getSeconds(),2);
};

/**
 * Formats a single atomic value based on a field descriptor
 *
 * @param {Object} value read from OpenERP
 * @param {Object} descriptor union of orm field and view field
 * @param {Object} [descriptor.widget] widget to use to display the value
 * @param {Object} descriptor.type fallback if no widget is provided, or if the provided widget is unknown
 * @param {Object} [descriptor.digits] used for the formatting of floats
 * @param {String} [value_if_empty=''] returned if the ``value`` argument is considered empty
 */
openerp.base.format_value = function (value, descriptor, value_if_empty) {
    // If NaN value, display as with a `false` (empty cell)
    if (typeof value === 'number' && isNaN(value)) {
        value = false;
    }
    switch (value) {
        case false:
        case Infinity:
        case -Infinity:
            return value_if_empty === undefined ?  '' : value_if_empty;
    }
    switch (descriptor.widget || descriptor.type) {
        case 'integer':
            return _.sprintf('%d', value);
        case 'float':
            var precision = descriptor.digits ? descriptor.digits[1] : 2;
            return _.sprintf('%.' + precision + 'f', value);
        case 'float_time':
            return _.sprintf("%02d:%02d",
                    Math.floor(value),
                    Math.round((value % 1) * 60));
        case 'progressbar':
            return _.sprintf(
                '<progress value="%.2f" max="100.0">%.2f%%</progress>',
                    value, value);
        case 'many2one':
            // name_get value format
            return value[1];
        default:
            return value;
    }
};

/**
 * Formats a provided cell based on its field type
 *
 * @param {Object} row_data record whose values should be displayed in the cell
 * @param {Object} column column descriptor
 * @param {"button"|"field"} column.tag base control type
 * @param {String} column.type widget type for a field control
 * @param {String} [column.string] button label
 * @param {String} [column.icon] button icon
 * @param {String} [value_if_empty=''] what to display if the field's value is ``false``
 */
openerp.base.format_cell = function (row_data, column, value_if_empty) {
    var attrs = column.modifiers_for(row_data);
    if (attrs.invisible) { return ''; }
    if (column.tag === 'button') {
        return [
            '<button type="button" title="', column.string || '', '">',
                '',
            '</button>'
        ].join('')
    }

    return openerp.base.format_value(
            row_data[column.id].value, column, value_if_empty);
}

};
<commit_msg>[IMP] simplify code of padding function in date formatting.<commit_after>
openerp.base.formats = function(openerp) {

/**
 * Converts a string to a Date javascript object using OpenERP's
 * datetime string format (exemple: '2011-12-01 15:12:35').
 *
 * The timezone is assumed to be UTC (standard for OpenERP 6.1)
 * and will be converted to the browser's timezone.
 *
 * @param {String} str A string representing a datetime.
 * @returns {Date}
 */
openerp.base.parse_datetime = function(str) {
    if(!str) {
        return str;
    }
    var regex = /\d\d\d\d-\d\d-\d\d \d\d:\d\d:\d\d/;
    var res = regex.exec(str);
    if ( res[0] != str ) {
        throw "'" + str + "' is not a valid datetime";
    }
    var obj = Date.parse(str + " GMT");
    if (! obj) {
        throw "'" + str + "' is not a valid datetime";
    }
    return obj;
};

/**
 * Converts a string to a Date javascript object using OpenERP's
 * date string format (exemple: '2011-12-01').
 *
 * @param {String} str A string representing a date.
 * @returns {Date}
 */
openerp.base.parse_date = function(str) {
    if(!str) {
        return str;
    }
    var regex = /\d\d\d\d-\d\d-\d\d/;
    var res = regex.exec(str);
    if ( res[0] != str ) {
        throw "'" + str + "' is not a valid date";
    }
    var obj = Date.parse(str);
    if (! obj) {
        throw "'" + str + "' is not a valid date";
    }
    return obj;
};

/**
 * Converts a string to a Date javascript object using OpenERP's
 * time string format (exemple: '15:12:35').
 *
 * @param {String} str A string representing a time.
 * @returns {Date}
 */
openerp.base.parse_time = function(str) {
    if(!str) {
        return str;
    }
    var regex = /\d\d:\d\d:\d\d/;
    var res = regex.exec(str);
    if ( res[0] != str ) {
        throw "'" + str + "' is not a valid time";
    }
    var obj = Date.parse(str);
    if (! obj) {
        throw "'" + str + "' is not a valid time";
    }
    return obj;
};

/*
 * Left-pad provided arg 1 with zeroes until reaching size provided by second
 * argument.
 *
 * @param {Number|String} str value to pad
 * @param {Number} size size to reach on the final padded value
 * @returns {String} padded string
 */
var zpad = function(str, size) {
    str = "" + str;
    return new Array(_.range(size - str.length)).join('0') + str;
};

/**
 * Converts a Date javascript object to a string using OpenERP's
 * datetime string format (exemple: '2011-12-01 15:12:35').
 *
 * The timezone of the Date object is assumed to be the one of the
 * browser and it will be converted to UTC (standard for OpenERP 6.1).
 *
 * @param {Date} obj
 * @returns {String} A string representing a datetime.
 */
openerp.base.format_datetime = function(obj) {
    if (!obj) {
        return false;
    }
    return zpad(obj.getUTCFullYear(),4) + "-" + zpad(obj.getUTCMonth() + 1,2) + "-"
         + zpad(obj.getUTCDate(),2) + " " + zpad(obj.getUTCHours(),2) + ":"
         + zpad(obj.getUTCMinutes(),2) + ":" + zpad(obj.getUTCSeconds(),2);
};

/**
 * Converts a Date javascript object to a string using OpenERP's
 * date string format (exemple: '2011-12-01').
 *
 * @param {Date} obj
 * @returns {String} A string representing a date.
 */
openerp.base.format_date = function(obj) {
    if (!obj) {
        return false;
    }
    return zpad(obj.getFullYear(),4) + "-" + zpad(obj.getMonth() + 1,2) + "-"
         + zpad(obj.getDate(),2);
};

/**
 * Converts a Date javascript object to a string using OpenERP's
 * time string format (exemple: '15:12:35').
 *
 * @param {Date} obj
 * @returns {String} A string representing a time.
 */
openerp.base.format_time = function(obj) {
    if (!obj) {
        return false;
    }
    return zpad(obj.getHours(),2) + ":" + zpad(obj.getMinutes(),2) + ":"
         + zpad(obj.getSeconds(),2);
};

/**
 * Formats a single atomic value based on a field descriptor
 *
 * @param {Object} value read from OpenERP
 * @param {Object} descriptor union of orm field and view field
 * @param {Object} [descriptor.widget] widget to use to display the value
 * @param {Object} descriptor.type fallback if no widget is provided, or if the provided widget is unknown
 * @param {Object} [descriptor.digits] used for the formatting of floats
 * @param {String} [value_if_empty=''] returned if the ``value`` argument is considered empty
 */
openerp.base.format_value = function (value, descriptor, value_if_empty) {
    // If NaN value, display as with a `false` (empty cell)
    if (typeof value === 'number' && isNaN(value)) {
        value = false;
    }
    switch (value) {
        case false:
        case Infinity:
        case -Infinity:
            return value_if_empty === undefined ?  '' : value_if_empty;
    }
    switch (descriptor.widget || descriptor.type) {
        case 'integer':
            return _.sprintf('%d', value);
        case 'float':
            var precision = descriptor.digits ? descriptor.digits[1] : 2;
            return _.sprintf('%.' + precision + 'f', value);
        case 'float_time':
            return _.sprintf("%02d:%02d",
                    Math.floor(value),
                    Math.round((value % 1) * 60));
        case 'progressbar':
            return _.sprintf(
                '<progress value="%.2f" max="100.0">%.2f%%</progress>',
                    value, value);
        case 'many2one':
            // name_get value format
            return value[1];
        default:
            return value;
    }
};

/**
 * Formats a provided cell based on its field type
 *
 * @param {Object} row_data record whose values should be displayed in the cell
 * @param {Object} column column descriptor
 * @param {"button"|"field"} column.tag base control type
 * @param {String} column.type widget type for a field control
 * @param {String} [column.string] button label
 * @param {String} [column.icon] button icon
 * @param {String} [value_if_empty=''] what to display if the field's value is ``false``
 */
openerp.base.format_cell = function (row_data, column, value_if_empty) {
    var attrs = column.modifiers_for(row_data);
    if (attrs.invisible) { return ''; }
    if (column.tag === 'button') {
        return [
            '<button type="button" title="', column.string || '', '">',
                '',
            '</button>'
        ].join('')
    }

    return openerp.base.format_value(
            row_data[column.id].value, column, value_if_empty);
}

};
<|endoftext|>


<commit_before>var express         = require('express'),
	bodyParser      = require('body-parser');

var sql             = require('mssql'),
	util            = require('../util');

module.exports      = function (configuration) {
    var router      = express.Router(),
    authenticate    = require('azure-mobile-apps/src/express/middleware/authenticate')(configuration),
    authorize       = require('azure-mobile-apps/src/express/middleware/authorize');

	var completeError = function(err, res) {
	    if (err) {
	        console.error(err);
	        if (res) res.sendStatus(500);
	    }
	};

    router.get('/:voucher', authenticate, (req, res, next) => {
		console.log('in GET /private_invitation/:voucher');
		console.log(configuration);
		var voucher = req.params.voucher;
		var userSid = 'req.azureMobile.user.id';
		console.log(voucher);
		console.log(req.azureMobile.user);
		var body = '' +
			'' +
			'
Tertulias
\n' +
			'
Welcome to Tertulias platform site.
' +
			'
You arrived at this page because you followed a link with a private invitation from a friend of yours to join a Tertulia.
' +
			'
Your voucher number is ' + voucher + '.
' +
			'
Your user id is .
' +
			'' +
			'';
		res.send(body);
    	next();
    });
    return router;
};
<commit_msg>wip save<commit_after>var express         = require('express'),
	bodyParser      = require('body-parser');

var sql             = require('mssql'),
	util            = require('../util');

module.exports      = function (configuration) {
    var router      = express.Router(),
    authenticate    = require('azure-mobile-apps/src/express/middleware/authenticate')(configuration),
    authorize       = require('azure-mobile-apps/src/express/middleware/authorize');

	var completeError = function(err, res) {
	    if (err) {
	        console.error(err);
	        if (res) res.sendStatus(500);
	    }
	};

    router.get('/:voucher', authenticate, (req, res, next) => {
		console.log('in GET /private_invitation/:voucher');
		console.log(configuration);
		var voucher = req.params.voucher;
		console.log(voucher);
		var body = '' +
			'' +
			'
Tertulias
\n' +
			'
Welcome to Tertulias platform site.
' +
			'
You arrived at this page because you followed a link with a private invitation from a friend of yours to join a Tertulia.
' +
			'
Your voucher number is ' + voucher + '.
' +
			'
Your user id is ________________________________.
' +
			'' +
			'';
		res.send(body);
    	next();
    });
    return router;
};
<|endoftext|>


<commit_before>import {Keyword, Constants} from './keyword';
import {TokenType} from './token';

export class ParserError extends Error {
    constructor(message, token) {
        super(message);

        this.token = token;
    }
}

export class SigmaNode {
    children = [];

    constructor({name, token}) {
        this.name = name;
        this.token = {...token};
    }

    add(node) {
        this.children.push(node);
    }
}

export class Parser {
    constructor(tokens) {
        this.tokens = tokens;
        this.index = -1;
    }

    getNextToken() {
        const token = this.tokens[++this.index];

        if (!token) {
            throw new ParserError('Unexpected End of program', token);
        }

        return {...token};
    }

    parse() {
        if (!this.tokens.length) {
            throw new ParserError('No Code found');
        }

        const tree = new SigmaNode({
            name: '<signal-program>',
        });

        return this.parseProgram(tree);
    }

    parseProgram(tree) {
        let token = this.getNextToken();

        const node = new SigmaNode({
            name: '<program>'
        });

        if (token.value !== Keyword.PROGRAM) {
            throw new ParserError(`Program should start with ${Keyword.PROGRAM} keyword`);
        }
        node.add(new SigmaNode({token}));

        token = this.getNextToken();
        if (!TokenType.isIdentifier(token.type)) {
            throw new ParserError(`Program should have name`, token);
        }
        const procedure = new SigmaNode({name: '<procedure-identifier>'});
        const identifier = new SigmaNode({name: '<identifier>'});
        identifier.add(new SigmaNode({token}));
        procedure.add(identifier);
        node.add(procedure);

        token = this.getNextToken();
        if (token.value !== ';') {
            throw new ParserError('Wrong punctuation', token);
        }
        node.add(new SigmaNode({token}));

        this.parseBlock(node);

        token = this.getNextToken();
        if (token.value !== '.') {
            throw new ParserError('Program should end with dot', token);
        }
        node.add(new SigmaNode({token}));

        try {
            token = this.getNextToken();
        } catch (err) {
            tree.add(node);
            return tree;
        }

        throw new ParserError('Unexpected input after program end', token);
    }

    parseBlock(tree) {
        const node = new SigmaNode({
            name: '<block>'
        });

        let token = this.getNextToken();
        token = this.parseVariables(token, node);

        if (token.value !== Keyword.BEGIN) {
            throw new ParserError('Block should start with BEGIN keyword', token);
        }
        node.add(new SigmaNode({token}));

        token = this.getNextToken();
        if (token.value !== Keyword.END) {
            throw new ParserError('Block should end with END keyword', token);
        }
        node.add(new SigmaNode({token}));

        tree.add(node);
    }

    parseVariables(token, tree) {
        const node = new SigmaNode({
            name: '<variable-declarations>'
        });
        if (token.value === Keyword.VAR) {
            node.add(new SigmaNode({token}));
            token = this.parseDeclarations(node);
            tree.add(node);
        }

        if (token.value === Keyword.BEGIN) {
            return token;
        }

        throw new ParserError('Unexpected input', token);
    }

    parseDeclarationBlock(token, tree) {
        this.parseDeclaration(token, tree);
        return this.parseDeclarationsList(tree);
    }

    parseDeclarationsList(tree) {
        let token = this.getNextToken();
        if (token.value === ';') {
            return token;
        }

        if (token.value !== ',') {
            return token;
        }
        tree.add(new SigmaNode({token}));

        token = this.getNextToken();
        this.parseDeclaration(token, tree);
        return this.parseDeclarationsList(tree);
    }

    parseDeclaration(token, tree) {
        const node = new SigmaNode({name: '<variable>'});
        tree.add(node);
        if (!TokenType.isIdentifier(token.type)) {
            throw new ParserError('Identifier expected', token);
        }
        const identifier = new SigmaNode({name: '<identifier>'});
        identifier.add(new SigmaNode({token}));
        node.add(identifier);

        return token;
    }

    parseDeclarations(tree) {
        let token = this.getNextToken();
        if (!TokenType.isIdentifier(token.type)) {
            return token;
        }
        const node = new SigmaNode({name: '<declaration>'});
        tree.add(node);

        token = this.parseDeclarationBlock(token, node);

        if (token.value !== ':') {
            throw new ParserError('Variables should have types', token);
        }
        node.add(new SigmaNode({token}));

        token = this.parseAttributeBlock(node);

        if (token.value !== ';') {
            throw new ParserError('Punctuation error, `;` expected', token);
        }
        tree.add(new SigmaNode({token}));

        return this.parseDeclarations(tree);
    }

    parseAttributeBlock(tree) {
        let token = this.getNextToken();
        this.parseAttribute(token, tree);
        return this.parseAttributesList(tree);
    }

    parseAttributesList(tree) {
        let token = this.getNextToken();
        if (token.value === ';') {
            return token;
        }

        this.parseAttribute(token, tree);
        return this.parseAttributesList(tree);
    }

    parseAttribute(token, tree) {
        const node = new SigmaNode({name: '<attribute>'});
        tree.add(node);
        const isConstant = Constants.includes(token.value);

        if (!isConstant) {
            if (token.value === '[') {
                node.add(new SigmaNode({token}));
                return this.parseRangeBlock(node);
            } else {
                throw new ParserError('No Attribute type defined', token);
            }
        }
        node.add(new SigmaNode({token}));

        return token;
    }

    parseRangeBlock(tree) {
        let token = this.getNextToken();
        this.parseRange(token, tree);
        token = this.parseRangeList(tree);

        if (token.value === ']') {
            tree.add(new SigmaNode({token}));
            return token;
        }
    }

    parseRangeList(tree) {
        let token = this.getNextToken();
        if (token.value === ']') {
            return token;
        }

        if (token.value !== ',') {
            throw new ParserError('Comma missing in range list', token);
        }
        tree.add(new SigmaNode({token}));

        token = this.getNextToken();
        this.parseRange(token, tree);
        return this.parseRangeList(tree);
    }

    parseRange(token, tree) {
        const node = new SigmaNode({name: '<range>'});
        if (!TokenType.isNumber(token.type)) {
            throw new ParserError('Range should have numeric as first argument', token);
        }
        node.add(new SigmaNode({token}));

        token = this.getNextToken();
        if (token.value !== '..') {
            throw new ParserError('Range should have `..` between numbers', token);
        }
        node.add(new SigmaNode({token}));

        token = this.getNextToken();
        if (!TokenType.isNumber(token.type)) {
            throw new ParserError('Range should have numeric as second argument', token);
        }
        node.add(new SigmaNode({token}));
        tree.add(node);
    }
}<commit_msg>correctly parse declarations<commit_after>import {Keyword, Constants} from './keyword';
import {TokenType} from './token';

export class ParserError extends Error {
    constructor(message, token) {
        super(message);

        this.token = token;
    }
}

export class SigmaNode {
    children = [];

    constructor({name, token}) {
        this.name = name;
        this.token = {...token};
    }

    add(node) {
        this.children.push(node);
    }
}

export class Parser {
    constructor(tokens) {
        this.tokens = tokens;
        this.index = -1;
    }

    getNextToken() {
        const token = this.tokens[++this.index];

        if (!token) {
            throw new ParserError('Unexpected End of program', token);
        }

        return {...token};
    }

    parse() {
        if (!this.tokens.length) {
            throw new ParserError('No Code found');
        }

        const tree = new SigmaNode({
            name: '<signal-program>',
        });

        return this.parseProgram(tree);
    }

    parseProgram(tree) {
        let token = this.getNextToken();

        const node = new SigmaNode({
            name: '<program>'
        });

        if (token.value !== Keyword.PROGRAM) {
            throw new ParserError(`Program should start with ${Keyword.PROGRAM} keyword`);
        }
        node.add(new SigmaNode({token}));

        token = this.getNextToken();
        if (!TokenType.isIdentifier(token.type)) {
            throw new ParserError(`Program should have name`, token);
        }
        const procedure = new SigmaNode({name: '<procedure-identifier>'});
        const identifier = new SigmaNode({name: '<identifier>'});
        identifier.add(new SigmaNode({token}));
        procedure.add(identifier);
        node.add(procedure);

        token = this.getNextToken();
        if (token.value !== ';') {
            throw new ParserError('Wrong punctuation', token);
        }
        node.add(new SigmaNode({token}));

        this.parseBlock(node);

        token = this.getNextToken();
        if (token.value !== '.') {
            throw new ParserError('Program should end with dot', token);
        }
        node.add(new SigmaNode({token}));

        try {
            token = this.getNextToken();
        } catch (err) {
            tree.add(node);
            return tree;
        }

        throw new ParserError('Unexpected input after program end', token);
    }

    parseBlock(tree) {
        const node = new SigmaNode({
            name: '<block>'
        });

        let token = this.getNextToken();
        token = this.parseVariables(token, node);

        if (token.value !== Keyword.BEGIN) {
            throw new ParserError('Block should start with BEGIN keyword', token);
        }
        node.add(new SigmaNode({token}));

        token = this.getNextToken();
        if (token.value !== Keyword.END) {
            throw new ParserError('Block should end with END keyword', token);
        }
        node.add(new SigmaNode({token}));

        tree.add(node);
    }

    parseVariables(token, tree) {
        const node = new SigmaNode({
            name: '<variable-declarations>'
        });
        if (token.value === Keyword.VAR) {
            node.add(new SigmaNode({token}));
            token = this.parseDeclarations(node);
            tree.add(node);
        }

        if (token.value === Keyword.BEGIN) {
            return token;
        }

        throw new ParserError('Unexpected input', token);
    }

    parseDeclarationBlock(token, tree) {
        this.parseDeclaration(token, tree);
        return this.parseDeclarationsList(tree);
    }

    parseDeclarationsList(tree) {
        let token = this.getNextToken();
        if (token.value === ';') {
            return token;
        }

        if (token.value !== ',') {
            return token;
        }
        tree.add(new SigmaNode({token}));

        token = this.getNextToken();
        this.parseDeclaration(token, tree);
        return this.parseDeclarationsList(tree);
    }

    parseDeclaration(token, tree) {
        const node = new SigmaNode({name: '<variable>'});
        tree.add(node);
        if (!TokenType.isIdentifier(token.type)) {
            throw new ParserError('Identifier expected', token);
        }
        const identifier = new SigmaNode({name: '<identifier>'});
        identifier.add(new SigmaNode({token}));
        node.add(identifier);

        return token;
    }

    parseDeclarations(tree) {
        let token = this.getNextToken();
        if (!TokenType.isIdentifier(token.type)) {
            return token;
        }
        const node = new SigmaNode({name: '<declaration>'});
        tree.add(node);

        token = this.parseDeclarationBlock(token, node);

        if (token.value !== ':') {
            throw new ParserError('Variables should have types', token);
        }
        node.add(new SigmaNode({token}));

        token = this.parseAttributeBlock(node);

        if (token.value !== ';') {
            throw new ParserError('Punctuation error, `;` expected', token);
        }
        tree.add(new SigmaNode({token}));

        return this.parseDeclarations(tree);
    }

    parseAttributeBlock(tree) {
        let token = this.getNextToken();
        this.parseAttribute(token, tree);
        return this.parseAttributesList(tree);
    }

    parseAttributesList(tree) {
        let token = this.getNextToken();
        if (token.value === ';') {
            return token;
        }

        this.parseAttribute(token, tree);
        return this.parseAttributesList(tree);
    }

    parseAttribute(token, tree) {
        const node = new SigmaNode({name: '<attribute>'});
        tree.add(node);
        const isConstant = Constants.includes(token.value);

        if (!isConstant) {
            if (token.value === '[') {
                node.add(new SigmaNode({token}));
                return this.parseRangeBlock(node);
            } else {
                throw new ParserError('No Attribute type defined', token);
            }
        }
        node.add(new SigmaNode({token}));

        return token;
    }

    parseRangeBlock(tree) {
        let token = this.getNextToken();
        this.parseRange(token, tree);
        token = this.parseRangeList(tree);

        if (token.value === ']') {
            tree.add(new SigmaNode({token}));
            return token;
        }
    }

    parseRangeList(tree) {
        let token = this.getNextToken();
        if (token.value === ']') {
            return token;
        }

        if (token.value !== ',') {
            throw new ParserError('Comma missing in range list', token);
        }
        tree.add(new SigmaNode({token}));

        token = this.getNextToken();
        this.parseRange(token, tree);
        return this.parseRangeList(tree);
    }

    parseRange(token, tree) {
        const node = new SigmaNode({name: '<range>'});
        if (!TokenType.isNumber(token.type)) {
            throw new ParserError('Range should have numeric as first argument', token);
        }
        node.add(new SigmaNode({token}));

        token = this.getNextToken();
        if (token.value !== '..') {
            throw new ParserError('Range should have `..` between numbers', token);
        }
        node.add(new SigmaNode({token}));

        token = this.getNextToken();
        if (!TokenType.isNumber(token.type)) {
            throw new ParserError('Range should have numeric as second argument', token);
        }
        node.add(new SigmaNode({token}));
        tree.add(node);
    }
}<|endoftext|>


<commit_before>import React, { Component, Fragment } from 'react';
import PropTypes from 'prop-types';
import { combineReducers } from 'redux';
import { connect } from 'react-redux';
import createBrowserHistory from 'history/createBrowserHistory';
import { IntlProvider } from 'react-intl';
import queryString from 'query-string';
import { ApolloProvider } from 'react-apollo';
import ErrorBoundary from '@folio/stripes-components/lib/ErrorBoundary';
import { metadata } from 'stripes-config';

import { ConnectContext } from '@folio/stripes-connect';
// import { RootContext } from './RootContext';
import initialReducers from '../../initialReducers';
import enhanceReducer from '../../enhanceReducer';
import createApolloClient from '../../createApolloClient';
import { setSinglePlugin, setBindings, setOkapiToken, setTimezone } from '../../okapiActions';
import { loadTranslations, checkOkapiSession } from '../../loginServices';
import { getQueryResourceKey, getCurrentModule } from '../../locationService';
import Stripes from '../../Stripes';
import RootWithIntl from '../../RootWithIntl';
import SystemSkeleton from '../SystemSkeleton';

import './Root.css';

import { withModules } from '../Modules';

if (!metadata) {
  // eslint-disable-next-line no-console
  console.error('No metadata harvested from package files, so you will not get app icons. Probably the stripes-core in your Stripes CLI is too old. Try `yarn global upgrade @folio/stripes-cli`');
}

class Root extends Component {
  constructor(...args) {
    super(...args);
    this.reducers = { ...initialReducers };
    this.epics = {};
    this.withOkapi = this.props.okapi.withoutOkapi !== true;

    const { modules, history } = this.props;
    const appModule = getCurrentModule(modules, history.location);
    this.queryResourceStateKey = (appModule) ? getQueryResourceKey(appModule) : null;
  }

  getChildContext() {
    return { addReducer: this.addReducer, addEpic: this.addEpic };
  }

  componentDidMount() {
    const { okapi, store, locale } = this.props;
    if (this.withOkapi) checkOkapiSession(okapi.url, store, okapi.tenant);
    // TODO: remove this after we load locale and translations at start from a public endpoint
    loadTranslations(store, locale);
  }

  shouldComponentUpdate(nextProps) {
    return !this.withOkapi || nextProps.okapiReady || nextProps.serverDown;
  }

  addReducer = (key, reducer) => {
    if (this.queryResourceStateKey === key) {
      const originalReducer = reducer;
      const initialQueryObject = queryString.parse(window.location.search);
      // eslint-disable-next-line no-param-reassign
      reducer = (state = Object.values(initialQueryObject).length ? initialQueryObject : undefined, action) => originalReducer(state, action);
    }

    if (this.reducers[key] === undefined) {
      this.reducers[key] = reducer;
      this.props.store.replaceReducer(enhanceReducer(combineReducers({ ...this.reducers })));
      return true;
    }
    return false;
  }

  addEpic = (key, epic) => {
    if (this.epics[key] === undefined) {
      this.epics[key] = epic;
      this.props.epics.add(epic);
      return true;
    }
    return false;
  }

  render() {
    const { logger, store, epics, config, okapi, actionNames, token, disableAuth, currentUser, currentPerms, locale, timezone, plugins, bindings, discovery, translations, history, serverDown } = this.props;

    if (serverDown) {
      return
Error: server is down.
;
    }

    if (!translations) {
      // We don't know the locale, so we use English as backup
      return (<SystemSkeleton />);
    }

    const stripes = new Stripes({
      logger,
      store,
      epics,
      config,
      okapi,
      withOkapi: this.withOkapi,
      setToken: (val) => { store.dispatch(setOkapiToken(val)); },
      actionNames,
      locale,
      timezone,
      metadata,
      setLocale: (localeValue) => { loadTranslations(store, localeValue); },
      setTimezone: (timezoneValue) => { store.dispatch(setTimezone(timezoneValue)); },
      plugins: plugins || {},
      setSinglePlugin: (key, value) => { store.dispatch(setSinglePlugin(key, value)); },
      bindings,
      setBindings: (val) => { store.dispatch(setBindings(val)); },
      discovery,
      user: {
        user: currentUser,
        perms: currentPerms,
      },
      connect(X) { return X; },
    });

    return (
      <ErrorBoundary>
        <ConnectContext.Provider value={{ addReducer: this.addReducer, addEpic: this.addEpic, store }}>
          <ApolloProvider client={createApolloClient(okapi)}>
            <IntlProvider
              locale={locale}
              key={locale}
              timeZone={timezone}
              messages={translations}
              textComponent={Fragment}
            >
              <RootWithIntl
                stripes={stripes}
                token={token}
                disableAuth={disableAuth}
                history={history}
              />
            </IntlProvider>
          </ApolloProvider>
        </ConnectContext.Provider>
      </ErrorBoundary>
    );
  }
}

Root.childContextTypes = {
  addReducer: PropTypes.func,
  addEpic: PropTypes.func,
};

Root.propTypes = {
  store: PropTypes.shape({
    subscribe: PropTypes.func.isRequired,
    dispatch: PropTypes.func.isRequired,
    getState: PropTypes.func.isRequired,
    replaceReducer: PropTypes.func.isRequired,
  }),
  token: PropTypes.string,
  disableAuth: PropTypes.bool.isRequired,
  logger: PropTypes.object.isRequired,
  currentPerms: PropTypes.object,
  currentUser: PropTypes.object,
  epics: PropTypes.object,
  locale: PropTypes.string,
  timezone: PropTypes.string,
  translations: PropTypes.object,
  modules: PropTypes.shape({
    app: PropTypes.array,
  }),
  plugins: PropTypes.object,
  bindings: PropTypes.object,
  config: PropTypes.object,
  okapi: PropTypes.shape({
    url: PropTypes.string,
    tenant: PropTypes.string,
    withoutOkapi: PropTypes.bool,
  }),
  actionNames: PropTypes.arrayOf(
    PropTypes.string,
  ).isRequired,
  discovery: PropTypes.shape({
    modules: PropTypes.object,
    interfaces: PropTypes.object,
    isFinished: PropTypes.bool,
  }),
  history: PropTypes.shape({
    length: PropTypes.number.isRequired,
    action: PropTypes.string.isRequired,
    push: PropTypes.func.isRequired,
    replace: PropTypes.func.isRequired,
  }),
  okapiReady: PropTypes.bool,
  serverDown: PropTypes.bool,
};

Root.defaultProps = {
  history: createBrowserHistory(),
  // TODO: remove after locale is accessible from a global config / public url
  locale: 'en-US',
  timezone: 'UTC',
  okapiReady: false,
  serverDown: false,
};

function mapStateToProps(state) {
  return {
    token: state.okapi.token,
    currentUser: state.okapi.currentUser,
    currentPerms: state.okapi.currentPerms,
    locale: state.okapi.locale,
    timezone: state.okapi.timezone,
    translations: state.okapi.translations,
    plugins: state.okapi.plugins,
    bindings: state.okapi.bindings,
    discovery: state.discovery,
    okapiReady: state.okapi.okapiReady,
    serverDown: state.okapi.serverDown,
    okapi: state.okapi,
  };
}

export default connect(mapStateToProps)(withModules(Root));
<commit_msg>comment on switching the source of context in Root.js<commit_after>import React, { Component, Fragment } from 'react';
import PropTypes from 'prop-types';
import { combineReducers } from 'redux';
import { connect } from 'react-redux';
import createBrowserHistory from 'history/createBrowserHistory';
import { IntlProvider } from 'react-intl';
import queryString from 'query-string';
import { ApolloProvider } from 'react-apollo';
import ErrorBoundary from '@folio/stripes-components/lib/ErrorBoundary';
import { metadata } from 'stripes-config';

/* ConnectContext - formerly known as RootContext, now comes from stripes-connect, so stripes-connect
* is providing the infrastructure for store connectivity to the system. This eliminates a circular
* dependency between stripes-connect and stripes-core. STCON-76
*/
import { ConnectContext } from '@folio/stripes-connect';
import initialReducers from '../../initialReducers';
import enhanceReducer from '../../enhanceReducer';
import createApolloClient from '../../createApolloClient';
import { setSinglePlugin, setBindings, setOkapiToken, setTimezone } from '../../okapiActions';
import { loadTranslations, checkOkapiSession } from '../../loginServices';
import { getQueryResourceKey, getCurrentModule } from '../../locationService';
import Stripes from '../../Stripes';
import RootWithIntl from '../../RootWithIntl';
import SystemSkeleton from '../SystemSkeleton';

import './Root.css';

import { withModules } from '../Modules';

if (!metadata) {
  // eslint-disable-next-line no-console
  console.error('No metadata harvested from package files, so you will not get app icons. Probably the stripes-core in your Stripes CLI is too old. Try `yarn global upgrade @folio/stripes-cli`');
}

class Root extends Component {
  constructor(...args) {
    super(...args);
    this.reducers = { ...initialReducers };
    this.epics = {};
    this.withOkapi = this.props.okapi.withoutOkapi !== true;

    const { modules, history } = this.props;
    const appModule = getCurrentModule(modules, history.location);
    this.queryResourceStateKey = (appModule) ? getQueryResourceKey(appModule) : null;
  }

  getChildContext() {
    return { addReducer: this.addReducer, addEpic: this.addEpic };
  }

  componentDidMount() {
    const { okapi, store, locale } = this.props;
    if (this.withOkapi) checkOkapiSession(okapi.url, store, okapi.tenant);
    // TODO: remove this after we load locale and translations at start from a public endpoint
    loadTranslations(store, locale);
  }

  shouldComponentUpdate(nextProps) {
    return !this.withOkapi || nextProps.okapiReady || nextProps.serverDown;
  }

  addReducer = (key, reducer) => {
    if (this.queryResourceStateKey === key) {
      const originalReducer = reducer;
      const initialQueryObject = queryString.parse(window.location.search);
      // eslint-disable-next-line no-param-reassign
      reducer = (state = Object.values(initialQueryObject).length ? initialQueryObject : undefined, action) => originalReducer(state, action);
    }

    if (this.reducers[key] === undefined) {
      this.reducers[key] = reducer;
      this.props.store.replaceReducer(enhanceReducer(combineReducers({ ...this.reducers })));
      return true;
    }
    return false;
  }

  addEpic = (key, epic) => {
    if (this.epics[key] === undefined) {
      this.epics[key] = epic;
      this.props.epics.add(epic);
      return true;
    }
    return false;
  }

  render() {
    const { logger, store, epics, config, okapi, actionNames, token, disableAuth, currentUser, currentPerms, locale, timezone, plugins, bindings, discovery, translations, history, serverDown } = this.props;

    if (serverDown) {
      return
Error: server is down.
;
    }

    if (!translations) {
      // We don't know the locale, so we use English as backup
      return (<SystemSkeleton />);
    }

    const stripes = new Stripes({
      logger,
      store,
      epics,
      config,
      okapi,
      withOkapi: this.withOkapi,
      setToken: (val) => { store.dispatch(setOkapiToken(val)); },
      actionNames,
      locale,
      timezone,
      metadata,
      setLocale: (localeValue) => { loadTranslations(store, localeValue); },
      setTimezone: (timezoneValue) => { store.dispatch(setTimezone(timezoneValue)); },
      plugins: plugins || {},
      setSinglePlugin: (key, value) => { store.dispatch(setSinglePlugin(key, value)); },
      bindings,
      setBindings: (val) => { store.dispatch(setBindings(val)); },
      discovery,
      user: {
        user: currentUser,
        perms: currentPerms,
      },
      connect(X) { return X; },
    });

    return (
      <ErrorBoundary>
        <ConnectContext.Provider value={{ addReducer: this.addReducer, addEpic: this.addEpic, store }}>
          <ApolloProvider client={createApolloClient(okapi)}>
            <IntlProvider
              locale={locale}
              key={locale}
              timeZone={timezone}
              messages={translations}
              textComponent={Fragment}
            >
              <RootWithIntl
                stripes={stripes}
                token={token}
                disableAuth={disableAuth}
                history={history}
              />
            </IntlProvider>
          </ApolloProvider>
        </ConnectContext.Provider>
      </ErrorBoundary>
    );
  }
}

Root.childContextTypes = {
  addReducer: PropTypes.func,
  addEpic: PropTypes.func,
};

Root.propTypes = {
  store: PropTypes.shape({
    subscribe: PropTypes.func.isRequired,
    dispatch: PropTypes.func.isRequired,
    getState: PropTypes.func.isRequired,
    replaceReducer: PropTypes.func.isRequired,
  }),
  token: PropTypes.string,
  disableAuth: PropTypes.bool.isRequired,
  logger: PropTypes.object.isRequired,
  currentPerms: PropTypes.object,
  currentUser: PropTypes.object,
  epics: PropTypes.object,
  locale: PropTypes.string,
  timezone: PropTypes.string,
  translations: PropTypes.object,
  modules: PropTypes.shape({
    app: PropTypes.array,
  }),
  plugins: PropTypes.object,
  bindings: PropTypes.object,
  config: PropTypes.object,
  okapi: PropTypes.shape({
    url: PropTypes.string,
    tenant: PropTypes.string,
    withoutOkapi: PropTypes.bool,
  }),
  actionNames: PropTypes.arrayOf(
    PropTypes.string,
  ).isRequired,
  discovery: PropTypes.shape({
    modules: PropTypes.object,
    interfaces: PropTypes.object,
    isFinished: PropTypes.bool,
  }),
  history: PropTypes.shape({
    length: PropTypes.number.isRequired,
    action: PropTypes.string.isRequired,
    push: PropTypes.func.isRequired,
    replace: PropTypes.func.isRequired,
  }),
  okapiReady: PropTypes.bool,
  serverDown: PropTypes.bool,
};

Root.defaultProps = {
  history: createBrowserHistory(),
  // TODO: remove after locale is accessible from a global config / public url
  locale: 'en-US',
  timezone: 'UTC',
  okapiReady: false,
  serverDown: false,
};

function mapStateToProps(state) {
  return {
    token: state.okapi.token,
    currentUser: state.okapi.currentUser,
    currentPerms: state.okapi.currentPerms,
    locale: state.okapi.locale,
    timezone: state.okapi.timezone,
    translations: state.okapi.translations,
    plugins: state.okapi.plugins,
    bindings: state.okapi.bindings,
    discovery: state.discovery,
    okapiReady: state.okapi.okapiReady,
    serverDown: state.okapi.serverDown,
    okapi: state.okapi,
  };
}

export default connect(mapStateToProps)(withModules(Root));
<|endoftext|>