<commit_before><polymer-element name="the-graph-edge" attributes="source target route connection group sourceNode sourcePort targetNode targetPort">

  <style>
    path.edge-touch {
      fill: none;
      stroke: transparent;
      stroke-width: 15px;
      opacity: 0;
      
    }
    .selected path.edge-touch {
      opacity: .1;      
      stroke-dasharray: 10px .5px;
    }
    .selected path.edge {
      opacity:.8;
      
    }
    .edge {
      fill: none;
    }
    

  </style>

  <script>
  (function(){
    "use strict";
    
    // window.requestAnimationFrame = window.requestAnimationFrame || window.mozRequestAnimationFrame ||
    //                               window.webkitRequestAnimationFrame || window.msRequestAnimationFrame;
                                  
    // Thanks bobnice http://stackoverflow.com/a/1583281/592125

    // Circular buffer storage. Externally-apparent 'length' increases indefinitely
    // while any items with indexes below length-n will be forgotten (undefined
    // will be returned if you try to get them, trying to set is an exception).
    // n represents the initial length of the array, not a maximum
    function CircularBuffer(n) {
      this._array= new Array(n);
      this.length= 0;
    }
    CircularBuffer.prototype.toString= function() {
      return '[object CircularBuffer('+this._array.length+') length '+this.length+']';
    };
    CircularBuffer.prototype.get= function(i) {
      if (i<0 || i<this.length-this._array.length)
      return undefined;
      return this._array[i%this._array.length];
    };
    CircularBuffer.prototype.set = function(i, v) {
      if (i<0 || i<this.length-this._array.length)
      throw CircularBuffer.IndexError;
      while (i>this.length) {
        this._array[this.length%this._array.length] = undefined;
        this.length++;
      }
      this._array[i%this._array.length] = v;
      if (i==this.length)
      this.length++;
    };
    CircularBuffer.prototype.push = function(v) {
      this._array[this.length%this._array.length] = v;
      this.length++;
    };
    CircularBuffer.IndexError= {};

    var determinePortSides = function (sourceX, sourceY, targetX, targetY) {
      var edgeType = ['east', 'west', 'R->L'];
      var xDiff = targetX - sourceX;
      var yDiff = targetY - sourceY;

      // TODO: Get from source node's clientHeight?
      var nodeH = theGraph.nodeHeight;
      var nodeW = theGraph.nodeWidth;

      if (Math.abs(xDiff) < Math.abs(yDiff)){
        if (sourceY < targetY) {
          // S: bottom to top
          edgeType = ['south', 'north', 'B->T'];
        } else {
          // N bottom to left
          edgeType = ['south', 'west', 'B->L'];
          if (sourceX+nodeW+10 < targetX) {
            // NE: right to left
            edgeType = ['east', 'west', 'R->L'];
          }
        }
      } else {
        if (sourceX < targetX) {
          // E: right to left
          edgeType = ['east', 'west', 'R->L'];
        } else {
          // W: right to top
          edgeType = ['east', 'north', 'R->T'];
          if (sourceY+nodeH+10 < targetY) {
            // SW: bottom to top
            edgeType = ['south', 'north', 'B->T'];
          }
        }
      }
      return edgeType;
    };

    var makePath = function (sourcePos, targetPos, edgeType, scale){
      var sourceX = sourcePos.left + sourcePos.width / 2;
      var sourceY = sourcePos.top + sourcePos.height / 2;
      var targetX = targetPos.left + targetPos.width / 2;
      var targetY = targetPos.top + targetPos.height / 2;
      var nodeW = theGraph.nodeWidth;
      var nodeW2 = nodeW / 2;
      var nodeH = theGraph.nodeHeight;
      var nodeH2 = nodeH / 2;

      var startX = sourceX;
      var startY = sourceY;
      var endX = targetX;
      var endY = targetY;
      var c1X, c1Y, c2X, c2Y;

      var xDiff = targetX - sourceX;
      var yDiff = targetY - sourceY;

      switch (edgeType) {
        case "B->T":
          // bottom to top
          c1X = startX;
          c1Y = startY + (endY - startY)/2;
          c2X = endX;
          c2Y = c1Y;
          break;
        case "B->L":
          // bottom to left
          c1X = startX + ( startX<endX ? nodeW : 0-nodeW );
          c1Y = startY + nodeH;
          c2X = endX - nodeW;
          c2Y = endY;
          break;
        case "R->T":
          // right to top
          c1X = startX + nodeW;
          c1Y = startY + ( startY<endY ? nodeH : 0-nodeH );
          c2X = endX;
          c2Y = endY - nodeH;
          break;
        case "R->L":
          /* falls through */
        default:
          // right to left
          c1X = startX + (endX - startX)/2;
          c1Y = startY;
          c2X = c1X;
          c2Y = endY;
          break;
        }

      var d = [
        "M", startX, startY, 
        "C", c1X, c1Y,
             c2X, c2Y,
             endX, endY
      ];

      return d.join(" ");
    };
    var edgeCount = 0;
    Polymer('the-graph-edge', {
      source: '',
      target: '',
      route: 0,
      zoom: 1,
      group: null,
      targetNode: null,
      targetPort: null,
      sourceNode: null,
      sourcePort: null,
      ready: function () {
        edgeCount++;
        this.pathId = "edge" + edgeCount;
      },
      log: null,
      enteredView: function () {
        // Find graph in parents, since the-graph-export has an edge child
        var graph = null;
        var parent = this.parentNode;
        while (parent && !graph) {
          if (parent.nodeName === "THE-GRAPH") {
            graph = parent;
          }
          parent = parent.parentNode;
        }
        if (!graph || !graph.$.edges || !graph.$.edges.$.connections) {
          throw new Error('Wire element needs to have a "the-graph" ancestor.');
        }
        this.group = graph.$.edges.$.connections;
        this.log = new CircularBuffer(50);
      },
      leftView: function () {
        if (!this.path) {
          return;
        }
        if (this.group && this.subgroup) {
          this.group.removeChild(this.subgroup);
        }
      },
      getSource: function () {
        var split = this.source.split('.');
        return {
          node: split[0],
          port: split[1]
        };
      },
      getTarget: function () {
        var split = this.target.split('.');
        return {
          node: split[0],
          port: split[1]
        };
      },
      groupChanged: function () {
        if (!this.group) {
          return;
        }
        // Make touchable path
        this.pathTouch = document.createElementNS("http://www.w3.org/2000/svg", "path");
        this.pathTouch.classList.add( "edge-touch" );

        // Make visible path
        this.path = document.createElementNS("http://www.w3.org/2000/svg", "path");
        this.path.setAttributeNS(null, "class", "edge");        
        this.path.setAttribute('id',this.pathId);
        
        
        
        // Add event for touchable path
        this.pathTouch.addEventListener('click', this.onClick.bind(this), false);<commit_msg>Support for unexported subgraph ports<commit_after><polymer-element name="the-graph-edge" attributes="source target route connection group sourceNode sourcePort targetNode targetPort">

  <style>
    path.edge-touch {
      fill: none;
      stroke: transparent;
      stroke-width: 15px;
      opacity: 0;
      
    }
    .selected path.edge-touch {
      opacity: .1;      
      stroke-dasharray: 10px .5px;
    }
    .selected path.edge {
      opacity:.8;
      
    }
    .edge {
      fill: none;
    }
    

  </style>

  <script>
  (function(){
    "use strict";
    
    // window.requestAnimationFrame = window.requestAnimationFrame || window.mozRequestAnimationFrame ||
    //                               window.webkitRequestAnimationFrame || window.msRequestAnimationFrame;
                                  
    // Thanks bobnice http://stackoverflow.com/a/1583281/592125

    // Circular buffer storage. Externally-apparent 'length' increases indefinitely
    // while any items with indexes below length-n will be forgotten (undefined
    // will be returned if you try to get them, trying to set is an exception).
    // n represents the initial length of the array, not a maximum
    function CircularBuffer(n) {
      this._array= new Array(n);
      this.length= 0;
    }
    CircularBuffer.prototype.toString= function() {
      return '[object CircularBuffer('+this._array.length+') length '+this.length+']';
    };
    CircularBuffer.prototype.get= function(i) {
      if (i<0 || i<this.length-this._array.length)
      return undefined;
      return this._array[i%this._array.length];
    };
    CircularBuffer.prototype.set = function(i, v) {
      if (i<0 || i<this.length-this._array.length)
      throw CircularBuffer.IndexError;
      while (i>this.length) {
        this._array[this.length%this._array.length] = undefined;
        this.length++;
      }
      this._array[i%this._array.length] = v;
      if (i==this.length)
      this.length++;
    };
    CircularBuffer.prototype.push = function(v) {
      this._array[this.length%this._array.length] = v;
      this.length++;
    };
    CircularBuffer.IndexError= {};

    var determinePortSides = function (sourceX, sourceY, targetX, targetY) {
      var edgeType = ['east', 'west', 'R->L'];
      var xDiff = targetX - sourceX;
      var yDiff = targetY - sourceY;

      // TODO: Get from source node's clientHeight?
      var nodeH = theGraph.nodeHeight;
      var nodeW = theGraph.nodeWidth;

      if (Math.abs(xDiff) < Math.abs(yDiff)){
        if (sourceY < targetY) {
          // S: bottom to top
          edgeType = ['south', 'north', 'B->T'];
        } else {
          // N bottom to left
          edgeType = ['south', 'west', 'B->L'];
          if (sourceX+nodeW+10 < targetX) {
            // NE: right to left
            edgeType = ['east', 'west', 'R->L'];
          }
        }
      } else {
        if (sourceX < targetX) {
          // E: right to left
          edgeType = ['east', 'west', 'R->L'];
        } else {
          // W: right to top
          edgeType = ['east', 'north', 'R->T'];
          if (sourceY+nodeH+10 < targetY) {
            // SW: bottom to top
            edgeType = ['south', 'north', 'B->T'];
          }
        }
      }
      return edgeType;
    };

    var makePath = function (sourcePos, targetPos, edgeType, scale){
      var sourceX = sourcePos.left + sourcePos.width / 2;
      var sourceY = sourcePos.top + sourcePos.height / 2;
      var targetX = targetPos.left + targetPos.width / 2;
      var targetY = targetPos.top + targetPos.height / 2;
      var nodeW = theGraph.nodeWidth;
      var nodeW2 = nodeW / 2;
      var nodeH = theGraph.nodeHeight;
      var nodeH2 = nodeH / 2;

      var startX = sourceX;
      var startY = sourceY;
      var endX = targetX;
      var endY = targetY;
      var c1X, c1Y, c2X, c2Y;

      var xDiff = targetX - sourceX;
      var yDiff = targetY - sourceY;

      switch (edgeType) {
        case "B->T":
          // bottom to top
          c1X = startX;
          c1Y = startY + (endY - startY)/2;
          c2X = endX;
          c2Y = c1Y;
          break;
        case "B->L":
          // bottom to left
          c1X = startX + ( startX<endX ? nodeW : 0-nodeW );
          c1Y = startY + nodeH;
          c2X = endX - nodeW;
          c2Y = endY;
          break;
        case "R->T":
          // right to top
          c1X = startX + nodeW;
          c1Y = startY + ( startY<endY ? nodeH : 0-nodeH );
          c2X = endX;
          c2Y = endY - nodeH;
          break;
        case "R->L":
          /* falls through */
        default:
          // right to left
          c1X = startX + (endX - startX)/2;
          c1Y = startY;
          c2X = c1X;
          c2Y = endY;
          break;
        }

      var d = [
        "M", startX, startY, 
        "C", c1X, c1Y,
             c2X, c2Y,
             endX, endY
      ];

      return d.join(" ");
    };
    var edgeCount = 0;
    Polymer('the-graph-edge', {
      source: '',
      target: '',
      route: 0,
      zoom: 1,
      group: null,
      targetNode: null,
      targetPort: null,
      sourceNode: null,
      sourcePort: null,
      ready: function () {
        edgeCount++;
        this.pathId = "edge" + edgeCount;
      },
      log: null,
      enteredView: function () {
        // Find graph in parents, since the-graph-export has an edge child
        var graph = null;
        var parent = this.parentNode;
        while (parent && !graph) {
          if (parent.nodeName === "THE-GRAPH") {
            graph = parent;
          }
          parent = parent.parentNode;
        }
        if (!graph || !graph.$.edges || !graph.$.edges.$.connections) {
          throw new Error('Wire element needs to have a "the-graph" ancestor.');
        }
        this.group = graph.$.edges.$.connections;
        this.log = new CircularBuffer(50);
      },
      leftView: function () {
        if (!this.path) {
          return;
        }
        if (this.group && this.subgroup) {
          this.group.removeChild(this.subgroup);
        }
      },
      getSource: function () {
        var split = this.source.split('.');
        return {
          node: split.shift(),
          port: split.join('.')
        };
      },
      getTarget: function () {
        var split = this.target.split('.');
        return {
          node: split.shift(),
          port: split.join('.')
        };
      },
      groupChanged: function () {
        if (!this.group) {
          return;
        }
        // Make touchable path
        this.pathTouch = document.createElementNS("http://www.w3.org/2000/svg", "path");
        this.pathTouch.classList.add( "edge-touch" );

        // Make visible path
        this.path = document.createElementNS("http://www.w3.org/2000/svg", "path");
        this.path.setAttributeNS(null, "class", "edge");        
        this.path.setAttribute('id',this.pathId);
        
        
        
        // Add event for touchable path
        this.pathTouch.addEventListener('click', this.onClick.bind(this), false);
{'fraction_non_alphanumeric': 0.13174244563682574, 'fraction_numerical': 0.011719853148828015, 'mean_word_length': 1.673145876580487, 'pattern_counts': {'":': 8, '<': 33, '<?xml version=': 0, '>': 35, 'https://': 0, 'lorem ipsum': 0, 'www.': 4, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 2, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '4992606', 'n_tokens_mistral': 4449, 'n_tokens_neox': 4327, 'n_words': 1059}