text: /**
   * Licensed to the Apache Software Foundation (ASF) under one
   * or more contributor license agreements.  See the NOTICE file
   * distributed with this work for additional information
   * regarding copyright ownership.  The ASF licenses this file
   * to you under the Apache License, Version 2.0 (the
   * "License"); you may not use this file except in compliance
   * with the License.  You may obtain a copy of the License at
   *
   *     http://www.apache.org/licenses/LICENSE-2.0
   *
   * Unless required by applicable law or agreed to in writing, software
   * distributed under the License is distributed on an "AS IS" BASIS,
   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   * See the License for the specific language governing permissions and
   * limitations under the License.
   */
  
  define(['require', ''], function(require) {
      'use strict';
      var LinegaeUtils = {};
      LinegaeUtils.DragNode = function(options) {
          var that = this,
              g = options.g,
              svg = options.svg,
              guid = options.guid,
              edgePathEl = options.edgeEl;
          return {
              init: function() {
                  var that = this;
                  //give IDs to each of the nodes so that they can be accessed
                  svg.selectAll("g.node rect")
                      .attr("id", function(d) {
                          return "node" + d;
                      });
                  svg.selectAll("g.edgePath path")
                      .attr("id", function(e) {
                          return e.v + "-" + e.w;
                      });
                  svg.selectAll("g.edgeLabel g")
                      .attr("id", function(e) {
                          return 'label_' + e.v + "-" + e.w;
                      });
  
                  g.nodes().forEach(function(v) {
                      var node = g.node(v);
                      node.customId = "node" + v;
                  })
                  g.edges().forEach(function(e) {
                      var edge = g.edge(e.v, e.w);
                      edge.customId = e.v + "-" + e.w
                  });
                  var nodeDrag = d3.behavior.drag()
                      .on("dragstart", this.dragstart)
                      .on("drag", function(d) { that.dragmove(this, d) });
  
                  var edgeDrag = d3.behavior.drag()
                      .on("dragstart", this.dragstart)
                      .on('drag', function(d) {
                          that.translateEdge(g.edge(d.v, d.w), d3.event.dx, d3.event.dy);
                          $('#' + g.edge(d.v, d.w).customId).attr('d', that.calcPoints(d));
                      });
  
                  nodeDrag.call(svg.selectAll("g.node"));
                  edgeDrag.call(svg.selectAll("g.edgePath"));
              },
              dragstart: function(d) {
                  d3.event.sourceEvent.stopPropagation();
              },
              dragmove: function(elem, d) {
                  var that = this,
                      node = d3.select(elem),
                      selectedNode = g.node(d),
                      prevX = selectedNode.x,
                      prevY = selectedNode.y;
  
                  selectedNode.x += d3.event.dx;
                  selectedNode.y += d3.event.dy;
                  node.attr('transform', 'translate(' + selectedNode.x + ',' + selectedNode.y + ')');
  
                  var dx = selectedNode.x - prevX,
                      dy = selectedNode.y - prevY;
  
                  g.edges().forEach(function(e) {
                      if (e.v == d || e.w == d) {
                          var edge = g.edge(e.v, e.w);
                          that.translateEdge(g.edge(e.v, e.w), dx, dy);
                          $('#' + edge.customId).attr('d', that.calcPoints(e));
                          var label = $('#label_' + edge.customId);
                          var xforms = label.attr('transform');
                          if (xforms != "") {
                              var parts = /translate\(\s*([^\s,)]+)[ ,]?([^\s,)]+)?/.exec(xforms),
                                  X = parseInt(parts[1]) + dx,
                                  Y = parseInt(parts[2]) + dy;
                              if (isNaN(Y)) {
                                  Y = dy;
                              }
                              label.attr('transform', 'translate(' + X + ',' + Y + ')');
                          }
                      }
                  });
                  LinegaeUtils.refreshGraphForIE({ "edgeEl": edgePathEl })
              },
              translateEdge: function(e, dx, dy) {
                  e.points.forEach(function(p) {
                      p.x = p.x + dx;
                      p.y = p.y + dy;
                  });
              },
              calcPoints: function(e) {
                  var edge = g.edge(e.v, e.w),
                      tail = g.node(e.v),
                      head = g.node(e.w),
                      points = edge.points.slice(1, edge.points.length - 1),
                      afterslice = edge.points.slice(1, edge.points.length - 1);
                  points.unshift(this.intersectRect(tail, points[0]));
                  points.push(this.intersectRect(head, points[points.length - 1]));
                  return d3.svg.line()
                      .x(function(d) {
                          return d.x;
                      })
                      .y(function(d) {
                          return d.y;
                      })
                      .interpolate("basis")
                      (points);
              },
              intersectRect: function(node, point) {
                  var that = this,
                      x = node.x,
                      y = node.y,
                      dx = point.x - x,
                      dy = point.y - y,
                      w = node.id == guid ? 24 : 21,
                      h = node.id == guid ? 24 : 21,
                      sx = 0,
                      sy = 0;
  
                  if (Math.abs(dy) * w > Math.abs(dx) * h) {
                      // Intersection is top or bottom of rect.
                      if (dy < 0) {
                          h = -h;
                      }
                      sx = dy === 0 ? 0 : h * dx / dy;
                      sy = h;
                  } else {
                      // Intersection is left or right of rect.
                      if (dx < 0) {
                          w = -w;
                      }
                      sx = w;
                      sy = dx === 0 ? 0 : w * dy / dx;
                  }
                  return {
                      x: x + sx,
                      y: y + sy
                  };
              },
          }
      }
      LinegaeUtils.refreshGraphForSafari = function(options) {
          var edgePathEl = options.edgeEl,
              IEGraphRenderDone = 0;
          edgePathEl.each(function(argument) {
              var eleRef = this,
                  childNode = $(this).find('pattern');
              setTimeout(function(argument) {
                  $(eleRef).find('defs').append(childNode);
              }, 500);
          });
      }
      LinegaeUtils.refreshGraphForIE = function(options) {
          var edgePathEl = options.edgeEl,
              IEGraphRenderDone = 0;
          edgePathEl.each(function(argument) {
              var childNode = $(this).find('marker');
              $(this).find('marker').remove();
              var eleRef = this;
              ++IEGraphRenderDone;
              setTimeout(function(argument) {
                  $(eleRef).find('defs').append(childNode);
                  --IEGraphRenderDone;
                  if (IEGraphRenderDone === 0) {
                      this.$('.fontLoader').hide();
                      this.$('svg').fadeTo(1000, 1)
                  }
              }, 1000);
          });
      }
      LinegaeUtils.centerNode = function(options) {
          var nodeID = options.guid,
              svg = options.svg,
              g = options.g,
              afterCenterZoomed = options.afterCenterZoomed,
              zoom = d3.behavior.zoom(),
              svgGroup = svg.find("g"),
              edgePathEl = options.edgeEl,
              zoomBind = function() {
                  svgGroup.attr("transform", "translate(" + d3.event.translate + ")scale(" + d3.event.scale + ")");
              },
              selectedNode = $(svg).find("g.nodes").find('>g#' + nodeID);
          return {
              init: function() {
                  if (selectedNode.length > 0) {
                      selectedNode = selectedNode;
                      var matrix = selectedNode.attr('transform').replace(/[^0-9\-.,]/g, '').split(',');
                      if (platform.name === "IE" || platform.name === "Microsoft Edge") {
                          var matrix = selectedNode.attr('transform').replace(/[a-z\()]/g, '').split(' ');
                      }
                      var x = matrix[0],
                          y = matrix[1];
                  } else {
                      selectedNode = $(svg).find("g.nodes").find('g').eq(1);
                      var x = g.graph().width / 2,
                          y = g.graph().height / 2;
  
                  }
                  var viewerWidth = $(svg).width(),
                      viewerHeight = $(svg).height(),
                      gBBox = d3.select('g').node().getBBox(),
                      zoomListener = zoom.scaleExtent([0.01, 50]).on("zoom", zoomBind),
                      scale = 1.2,
                      xa = -((x * scale) - (viewerWidth / 2)),
                      ya = -((y * scale) - (viewerHeight / 2));
  
                  zoom.translate([xa, ya]);
                  d3.select('g').transition()
                      .duration(350)
                      .attr("transform", "translate(" + xa + "," + ya + ")scale(" + scale + ")");
                  zoomListener.scale(scale);
                  zoomListener.translate([xa, ya]);
                  zoom.scale(scale);
                  afterCenterZoomed({ newScale: scale, newTranslate: [xa, ya] });
                  LinegaeUtils.refreshGraphForIE({ "edgeEl": edgePathEl })
              }
          }
      }
      LinegaeUtils.onHoverFade = function(options) {
          var opacity = options.opacity,
              d = options.selectedNode,
              nodesToHighlight = options.highlight,
              svg = options.svg,
              isConnected = function(a, b, o) {
                  if (a === o || (b && b.length && b.indexOf(o) != -1)) {
                      return true;
                  }
              },
              node = svg.selectAll('.node'),
              path = svg.selectAll('.edgePath');
          return {
              init: function() {
                  node.classed("hover-active", function(selectedNode, i, nodes) {
                      if (isConnected(d, nodesToHighlight, selectedNode)) {
                          return true;
                      } else {
                          return false;
                      }
                  });
                  path.classed('hover-active-node', function(c) {
                      var _thisOpacity = c.v === d || c.w === d ? 1 : 0;
                      if (_thisOpacity) {
                          return true;
                      } else {
                          return false;
                      }
                  });
  
              }
          }
  
      }
      LinegaeUtils.base64Encode = function(options) {
          var str = options.data,
              CHARS = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/",
              out = "",
              i = 0,
              len = str.length,
              c1, c2, c3;
          while (i < len) {
              c1 = str.charCodeAt(i++) & 0xff;
              if (i == len) {
                  out += CHARS.charAt(c1 >> 2);
                  out += CHARS.charAt((c1 & 0x3) << 4);
                  out += "==";
                  break;
              }
              c2 = str.charCodeAt(i++);
              if (i == len) {
                  out += CHARS.charAt(c1 >> 2);
                  out += CHARS.charAt(((c1 & 0x3) << 4) | ((c2 & 0xF0) >> 4));
                  out += CHARS.charAt((c2 & 0xF) << 2);
                  out += "=";
                  break;
              }
              c3 = str.charCodeAt(i++);
              out += CHARS.charAt(c1 >> 2);
              out += CHARS.charAt(((c1 & 0x3) << 4) | ((c2 & 0xF0) >> 4));
              out += CHARS.charAt(((c2 & 0xF) << 2) | ((c3 & 0xC0) >> 6));
              out += CHARS.charAt(c3 & 0x3F);
          }
          return out;
      }
      return LinegaeUtils;
  });