aboutsummaryrefslogtreecommitdiff
path: root/docs/htmldoc
diff options
context:
space:
mode:
authorEnrico Tassi2018-04-20 10:13:36 +0200
committerEnrico Tassi2018-04-20 10:35:01 +0200
commit24a7fea1648991a77fc4ff86a972b0a3935678c8 (patch)
tree4d6043884fafaf062d33c15a266a7f4c92541f79 /docs/htmldoc
parent9352fc35ebe04b8b4e9002f3cf39ee1acbab8cd2 (diff)
move the webpage from gh-pages branch to docs/
Diffstat (limited to 'docs/htmldoc')
-rw-r--r--docs/htmldoc/Makefile32
-rwxr-xr-xdocs/htmldoc/buildlibgraph162
-rw-r--r--docs/htmldoc/js/cytoscape-dagre.js192
-rw-r--r--docs/htmldoc/js/cytoscape-panzoom.js550
-rw-r--r--docs/htmldoc/js/cytoscape-qtip.js362
-rw-r--r--docs/htmldoc/js/cytoscape.js24515
-rw-r--r--docs/htmldoc/js/cytoscape.js-panzoom.css203
-rw-r--r--docs/htmldoc/js/cytoscape.min.js26
-rw-r--r--docs/htmldoc/js/dagre.js16396
-rw-r--r--docs/htmldoc/js/dagre.min.js6
-rw-r--r--docs/htmldoc/js/jquery-2.0.3.js8829
-rw-r--r--docs/htmldoc/js/jquery-2.0.3.min.js6
-rw-r--r--docs/htmldoc/js/jquery.qtip.css623
-rw-r--r--docs/htmldoc/js/jquery.qtip.js3440
-rw-r--r--docs/htmldoc/js/jquery.qtip.min.css2
-rw-r--r--docs/htmldoc/js/jquery.qtip.min.js4
-rw-r--r--docs/htmldoc/libgraph.html245
17 files changed, 55593 insertions, 0 deletions
diff --git a/docs/htmldoc/Makefile b/docs/htmldoc/Makefile
new file mode 100644
index 0000000..d565125
--- /dev/null
+++ b/docs/htmldoc/Makefile
@@ -0,0 +1,32 @@
+H=@
+
+ifeq "$(COQBIN)" ""
+COQBIN=$(dir $(shell which coqtop))/
+endif
+
+SRC=$(shell cd ../mathcomp; ls */*.v | grep -v attic/)
+HEAD=$(shell git symbolic-ref HEAD)
+ifeq "$(HEAD)" "refs/heads/master"
+LAST=$(shell git tag -l --sort=v:refname "mathcomp-*" | tail -n 1)
+RELEASED=$(shell git show $(LAST):mathcomp/Make | grep 'v *$$' | cut -d / -f 2 | cut -d . -f 1)
+endif
+
+all:
+ $(H) git diff-index --quiet HEAD ||\
+ (echo error: uncommitted files; exit 1)
+ $(H) cd ../mathcomp;\
+ $(COQBIN)/coqdep -R . mathcomp $(SRC) 2>/dev/null |\
+ grep -v vio: > ../htmldoc/depend
+ $(H) cat depend | ./buildlibgraph cytoscape $(RELEASED) > depend.js
+ $(H) . ../etc/utils/builddoc_lib.sh; \
+ cd ../mathcomp; mangle_sources $(SRC)
+ $(H) make -C ../mathcomp clean
+ $(H) make -C ../mathcomp -j2
+ $(H) cd ../mathcomp; $(COQBIN)/coqdoc -t "Mathematical Components"\
+ -g --utf8 -R . mathcomp \
+ --parse-comments \
+ --multi-index $(SRC) -d ../htmldoc/
+ $(H) cp ../etc/artwork/coqdoc.css .
+ $(H) cd ../mathcomp; git checkout $(SRC)
+
+
diff --git a/docs/htmldoc/buildlibgraph b/docs/htmldoc/buildlibgraph
new file mode 100755
index 0000000..b7b91d0
--- /dev/null
+++ b/docs/htmldoc/buildlibgraph
@@ -0,0 +1,162 @@
+#!/usr/bin/lua5.1
+
+nodes = {}
+clusters = {}
+edges = {}
+args = {}
+
+function decompose(n)
+ return n:match("^([^/]+)/([^%.]+)")
+end
+
+for l in io.lines() do
+ local to, froms = l:match("^([^ :]+)[^:]*:(.*)")
+ local cluster, module = decompose(to)
+ clusters[cluster] = clusters[cluster] or {}
+ clusters[cluster][module] = true
+ nodes[module] = true
+ for from in froms:gmatch("[^ ]+") do
+ local cluster, module2 = decompose(from)
+ nodes[module2] = true
+ if module ~= module2 then
+ clusters[cluster] = clusters[cluster] or {}
+ clusters[cluster][module2] = true
+ edges[#edges+1] = { from = module; to = module2 }
+ end
+ end
+end
+
+-- transitive reduction
+--
+-- // reflexive reduction
+-- for (int i = 0; i < N; ++i)
+-- m[i][i] = false;
+--
+-- // transitive reduction
+-- for (int j = 0; j < N; ++j)
+-- for (int i = 0; i < N; ++i)
+-- if (m[i][j])
+-- for (int k = 0; k < N; ++k)
+-- if (m[j][k])
+-- m[i][k] = false;
+--
+function path_matrix(nodes,edges)
+ local m = {}
+ for j,_ in pairs(nodes) do
+ m[j] = {}
+ end
+ for _,e in ipairs(edges) do
+ m[e.from][e.to] = true
+ end
+ -- close
+ for j,_ in pairs(nodes) do
+ for i,_ in pairs(nodes) do
+ for k,_ in pairs(nodes) do
+ if m[i][j] == true and m[j][k] == true then m[i][k] = true end
+ end
+ end
+ end
+ return m
+end
+function tred(nodes,m)
+ -- reduce
+ for j,_ in pairs(nodes) do
+ for i,_ in pairs(nodes) do
+ if m[i][j] == true then
+ for k,_ in pairs(nodes) do
+ if m[j][k] then m[i][k] = false end
+ end
+ end
+ end
+ end
+end
+function matrix_to_list(nodes,m)
+ local edges = {}
+ for j,_ in pairs(nodes) do
+ for i,_ in pairs(nodes) do
+ if m[i][j] == true then
+ edges[#edges+1] = { from = i; to = j }
+ end
+ end
+ end
+ return edges
+end
+
+
+
+m = path_matrix(nodes,edges)
+tred(nodes,m)
+edges = matrix_to_list(nodes,m)
+
+meta_edges = {}
+for c1,nodes1 in pairs(clusters) do
+ for c2,nodes2 in pairs(clusters) do
+ if (c1 ~= c2) then
+ local connected = false
+ for n1,_ in pairs(nodes1) do
+ for n2,_ in pairs(nodes2) do
+ if m[n1][n2] == true then connected = true end
+ end
+ end
+ if connected then meta_edges[#meta_edges+1] = { from = c1; to = c2 } end
+ end
+ end
+end
+
+m = path_matrix(clusters,meta_edges)
+tred(clusters,m)
+meta_edges = matrix_to_list(clusters,m)
+
+function dot()
+ print[[
+ digraph mathcomp {
+ compound = true;
+ ]]
+ for c,nodes in pairs(clusters) do
+ print("subgraph cluster_" .. c .. " {")
+ for node,_ in pairs(nodes) do
+ print('"'..node..'";')
+ end
+ print("}")
+ end
+ for _,edge in ipairs(edges) do
+ print(string.format('"%s" -> "%s";',edge.from,edge.to))
+ end
+ print[[
+ }
+ ]]
+end
+
+function cytoscape()
+ print[[
+ var depends = [
+ ]]
+ for c,nodes in pairs(clusters) do
+ print(string.format('{ data: { id: "cluster_%s", name: "%s" } },', c, c))
+ print(string.format('{ data: { id: "cluster_%s_plus", name: "+", parent: "cluster_%s" } },', c, c))
+ for node,_ in pairs(nodes) do
+ local released = "no"
+ if args[node] then released = "yes" end
+ print(string.format('{ data: { id: "%s", name: "%s", parent: "cluster_%s", released: "%s" } },', node, node, c, released))
+ end
+ end
+ local i = 0
+ for _,edge in ipairs(edges) do
+ print(string.format('{ data: { id: "edge%d", source: "%s", target: "%s" } },', i, edge.from,edge.to))
+ i=i+1
+ end
+ for _,edge in ipairs(meta_edges) do
+ print(string.format('{ data: { id: "edge%d", source: "cluster_%s", target: "cluster_%s" } },', i, edge.from,edge.to))
+ i=i+1
+ end
+ print[[ ]; ]]
+end
+
+for i=2,#arg do
+ args[arg[i]] = true
+end
+_G[arg[1]]()
+
+-- $COQBIN/coqdep -R . mathcomp */*.v | grep -v vio: > depend
+-- cat depend | ./graph.lua dot | tee depend.dot | dot -T png -o depend.png
+-- cat depend | ./graph.lua cytoscape `git show release/1.6:mathcomp/Make | grep 'v *$' | cut -d / -f 2 | cut -d . -f 1` > depend.js
diff --git a/docs/htmldoc/js/cytoscape-dagre.js b/docs/htmldoc/js/cytoscape-dagre.js
new file mode 100644
index 0000000..c93288b
--- /dev/null
+++ b/docs/htmldoc/js/cytoscape-dagre.js
@@ -0,0 +1,192 @@
+;(function(){ 'use strict';
+
+ // registers the extension on a cytoscape lib ref
+ var register = function( cytoscape, dagre ){
+ if( !cytoscape || !dagre ){ return; } // can't register if cytoscape unspecified
+
+ var isFunction = function(o){ return typeof o === 'function'; };
+
+ // default layout options
+ var defaults = {
+ // dagre algo options, uses default value on undefined
+ nodeSep: undefined, // the separation between adjacent nodes in the same rank
+ edgeSep: undefined, // the separation between adjacent edges in the same rank
+ rankSep: undefined, // the separation between adjacent nodes in the same rank
+ rankDir: undefined, // 'TB' for top to bottom flow, 'LR' for left to right
+ minLen: function( edge ){ return 1; }, // number of ranks to keep between the source and target of the edge
+ edgeWeight: function( edge ){ return 1; }, // higher weight edges are generally made shorter and straighter than lower weight edges
+
+ // general layout options
+ fit: true, // whether to fit to viewport
+ padding: 30, // fit padding
+ animate: false, // whether to transition the node positions
+ animationDuration: 500, // duration of animation in ms if enabled
+ animationEasing: undefined, // easing of animation if enabled
+ boundingBox: undefined, // constrain layout bounds; { x1, y1, x2, y2 } or { x1, y1, w, h }
+ ready: function(){}, // on layoutready
+ stop: function(){} // on layoutstop
+ };
+
+ // constructor
+ // options : object containing layout options
+ function DagreLayout( options ){
+ var opts = this.options = {};
+ for( var i in defaults ){ opts[i] = defaults[i]; }
+ for( var i in options ){ opts[i] = options[i]; }
+ }
+
+ // runs the layout
+ DagreLayout.prototype.run = function(){
+ var options = this.options;
+ var layout = this;
+
+ var cy = options.cy; // cy is automatically populated for us in the constructor
+ var eles = options.eles;
+
+ var getVal = function( ele, val ){
+ return isFunction(val) ? val.apply( ele, [ ele ] ) : val;
+ };
+
+ var bb = options.boundingBox || { x1: 0, y1: 0, w: cy.width(), h: cy.height() };
+ if( bb.x2 === undefined ){ bb.x2 = bb.x1 + bb.w; }
+ if( bb.w === undefined ){ bb.w = bb.x2 - bb.x1; }
+ if( bb.y2 === undefined ){ bb.y2 = bb.y1 + bb.h; }
+ if( bb.h === undefined ){ bb.h = bb.y2 - bb.y1; }
+
+ var g = new dagre.graphlib.Graph({
+ multigraph: true,
+ compound: true
+ });
+
+ var gObj = {};
+ var setGObj = function( name, val ){
+ if( val != null ){
+ gObj[ name ] = val;
+ }
+ };
+
+ setGObj( 'nodesep', options.nodeSep );
+ setGObj( 'edgesep', options.edgeSep );
+ setGObj( 'ranksep', options.rankSep );
+ setGObj( 'rankdir', options.rankDir );
+
+ g.setGraph( gObj );
+
+ g.setDefaultEdgeLabel(function() { return {}; });
+ g.setDefaultNodeLabel(function() { return {}; });
+
+ // add nodes to dagre
+ var nodes = eles.nodes();
+ for( var i = 0; i < nodes.length; i++ ){
+ var node = nodes[i];
+ var nbb = node.boundingBox();
+
+ g.setNode( node.id(), {
+ width: nbb.w,
+ height: nbb.h,
+ name: node.id()
+ } );
+
+ // console.log( g.node(node.id()) );
+ }
+
+ // set compound parents
+ for( var i = 0; i < nodes.length; i++ ){
+ var node = nodes[i];
+
+ if( node.isChild() ){
+ g.setParent( node.id(), node.parent().id() );
+ }
+ }
+
+ // add edges to dagre
+ var edges = eles.edges().stdFilter(function( edge ){
+ return !edge.source().isParent() && !edge.target().isParent(); // dagre can't handle edges on compound nodes
+ });
+ for( var i = 0; i < edges.length; i++ ){
+ var edge = edges[i];
+
+ g.setEdge( edge.source().id(), edge.target().id(), {
+ minlen: getVal( edge, options.minLen ),
+ weight: getVal( edge, options.edgeWeight ),
+ name: edge.id()
+ }, edge.id() );
+
+ // console.log( g.edge(edge.source().id(), edge.target().id(), edge.id()) );
+ }
+
+ dagre.layout( g );
+
+ var gNodeIds = g.nodes();
+ for( var i = 0; i < gNodeIds.length; i++ ){
+ var id = gNodeIds[i];
+ var n = g.node( id );
+
+ cy.getElementById(id).scratch().dagre = n;
+ }
+
+ var dagreBB;
+
+ if( options.boundingBox ){
+ dagreBB = { x1: Infinity, x2: -Infinity, y1: Infinity, y2: -Infinity };
+ nodes.forEach(function( node ){
+ var dModel = node.scratch().dagre;
+
+ dagreBB.x1 = Math.min( dagreBB.x1, dModel.x );
+ dagreBB.x2 = Math.max( dagreBB.x2, dModel.x );
+
+ dagreBB.y1 = Math.min( dagreBB.y1, dModel.y );
+ dagreBB.y2 = Math.max( dagreBB.y2, dModel.y );
+ });
+
+ dagreBB.w = dagreBB.x2 - dagreBB.x1;
+ dagreBB.h = dagreBB.y2 - dagreBB.y1;
+ } else {
+ dagreBB = bb;
+ }
+
+ var constrainPos = function( p ){
+ if( options.boundingBox ){
+ var xPct = (p.x - dagreBB.x1) / dagreBB.w;
+ var yPct = (p.y - dagreBB.y1) / dagreBB.h;
+
+ return {
+ x: bb.x1 + xPct * bb.w,
+ y: bb.y1 + yPct * bb.h
+ };
+ } else {
+ return p;
+ }
+ };
+
+ nodes.layoutPositions(layout, options, function(){
+ var dModel = this.scratch().dagre;
+
+ return constrainPos({
+ x: dModel.x,
+ y: dModel.y
+ });
+ });
+
+ return this; // chaining
+ };
+
+ cytoscape('layout', 'dagre', DagreLayout);
+
+ };
+
+ if( typeof module !== 'undefined' && module.exports ){ // expose as a commonjs module
+ module.exports = register;
+ }
+
+ if( typeof define !== 'undefined' && define.amd ){ // expose as an amd/requirejs module
+ define('cytoscape-dagre', function(){
+ return register;
+ });
+ }
+
+ if( typeof cytoscape !== 'undefined' && typeof dagre !== 'undefined' ){ // expose to global cytoscape (i.e. window.cytoscape)
+ register( cytoscape, dagre );
+ }
+
+})();
diff --git a/docs/htmldoc/js/cytoscape-panzoom.js b/docs/htmldoc/js/cytoscape-panzoom.js
new file mode 100644
index 0000000..4680775
--- /dev/null
+++ b/docs/htmldoc/js/cytoscape-panzoom.js
@@ -0,0 +1,550 @@
+;(function(){ 'use strict';
+
+ // registers the extension on a cytoscape lib ref
+ var register = function( cytoscape, $ ){
+ if( !cytoscape ){ return; } // can't register if cytoscape unspecified
+
+ $.fn.cyPanzoom = $.fn.cytoscapePanzoom = function( options ){
+ panzoom.apply( this, [ options ] );
+
+ return this; // chainability
+ };
+
+ // if you want a core extension
+ cytoscape('core', 'panzoom', function( options ){ // could use options object, but args are up to you
+ var cy = this;
+
+ panzoom.apply( cy.container(), [ options ] );
+
+ return this; // chainability
+ });
+
+ };
+
+ var defaults = {
+ zoomFactor: 0.05, // zoom factor per zoom tick
+ zoomDelay: 45, // how many ms between zoom ticks
+ minZoom: 0.1, // min zoom level
+ maxZoom: 10, // max zoom level
+ fitPadding: 50, // padding when fitting
+ panSpeed: 10, // how many ms in between pan ticks
+ panDistance: 10, // max pan distance per tick
+ panDragAreaSize: 75, // the length of the pan drag box in which the vector for panning is calculated (bigger = finer control of pan speed and direction)
+ panMinPercentSpeed: 0.25, // the slowest speed we can pan by (as a percent of panSpeed)
+ panInactiveArea: 8, // radius of inactive area in pan drag box
+ panIndicatorMinOpacity: 0.5, // min opacity of pan indicator (the draggable nib); scales from this to 1.0
+ zoomOnly: false, // a minimal version of the ui only with zooming (useful on systems with bad mousewheel resolution)
+
+ // icon class names
+ sliderHandleIcon: 'fa fa-minus',
+ zoomInIcon: 'fa fa-plus',
+ zoomOutIcon: 'fa fa-minus',
+ resetIcon: 'fa fa-expand'
+ };
+
+ var panzoom = function(params){
+ var options = $.extend(true, {}, defaults, params);
+ var fn = params;
+
+ var functions = {
+ destroy: function(){
+ var $this = $(this);
+ var $pz = $this.find(".cy-panzoom");
+
+ $pz.data('winbdgs').forEach(function( l ){
+ $(window).unbind( l.evt, l.fn );
+ });
+
+ $pz.data('cybdgs').forEach(function( l ){
+ $(this).cytoscape('get').off( l.evt, l.fn );
+ });
+
+ $pz.remove();
+ },
+
+ init: function(){
+ var browserIsMobile = 'ontouchstart' in window;
+
+ return $(this).each(function(){
+ var $container = $(this);
+
+ var winbdgs = [];
+ var $win = $(window);
+
+ var windowBind = function( evt, fn ){
+ winbdgs.push({ evt: evt, fn: fn });
+
+ $win.bind( evt, fn );
+ };
+
+ var windowUnbind = function( evt, fn ){
+ for( var i = 0; i < winbdgs.length; i++ ){
+ var l = winbdgs[i];
+
+ if( l.evt === evt && l.fn === fn ){
+ winbdgs.splice( i, 1 );
+ break;
+ }
+ }
+
+ $win.unbind( evt, fn );
+ };
+
+ var cybdgs = [];
+ var cy = $container.cytoscape('get');
+
+ var cyOn = function( evt, fn ){
+ cybdgs.push({ evt: evt, fn: fn });
+
+ cy.on( evt, fn );
+ };
+
+ var cyOff = function( evt, fn ){
+ for( var i = 0; i < cybdgs.length; i++ ){
+ var l = cybdgs[i];
+
+ if( l.evt === evt && l.fn === fn ){
+ cybdgs.splice( i, 1 );
+ break;
+ }
+ }
+
+ cy.off( evt, fn );
+ };
+
+ var $panzoom = $('<div class="cy-panzoom"></div>');
+ $container.append( $panzoom );
+
+ $panzoom.data('winbdgs', winbdgs);
+ $panzoom.data('cybdgs', cybdgs);
+
+ if( options.zoomOnly ){
+ $panzoom.addClass("cy-panzoom-zoom-only");
+ }
+
+ // add base html elements
+ /////////////////////////
+
+ var $zoomIn = $('<div class="cy-panzoom-zoom-in cy-panzoom-zoom-button"><span class="icon '+ options.zoomInIcon +'"></span></div>');
+ $panzoom.append( $zoomIn );
+
+ var $zoomOut = $('<div class="cy-panzoom-zoom-out cy-panzoom-zoom-button"><span class="icon ' + options.zoomOutIcon + '"></span></div>');
+ $panzoom.append( $zoomOut );
+
+ var $reset = $('<div class="cy-panzoom-reset cy-panzoom-zoom-button"><span class="icon ' + options.resetIcon + '"></span></div>');
+ $panzoom.append( $reset );
+
+ var $slider = $('<div class="cy-panzoom-slider"></div>');
+ $panzoom.append( $slider );
+
+ $slider.append('<div class="cy-panzoom-slider-background"></div>');
+
+ var $sliderHandle = $('<div class="cy-panzoom-slider-handle"><span class="icon ' + options.sliderHandleIcon + '"></span></div>');
+ $slider.append( $sliderHandle );
+
+ var $noZoomTick = $('<div class="cy-panzoom-no-zoom-tick"></div>');
+ $slider.append( $noZoomTick );
+
+ var $panner = $('<div class="cy-panzoom-panner"></div>');
+ $panzoom.append( $panner );
+
+ var $pHandle = $('<div class="cy-panzoom-panner-handle"></div>');
+ $panner.append( $pHandle );
+
+ var $pUp = $('<div class="cy-panzoom-pan-up cy-panzoom-pan-button"></div>');
+ var $pDown = $('<div class="cy-panzoom-pan-down cy-panzoom-pan-button"></div>');
+ var $pLeft = $('<div class="cy-panzoom-pan-left cy-panzoom-pan-button"></div>');
+ var $pRight = $('<div class="cy-panzoom-pan-right cy-panzoom-pan-button"></div>');
+ $panner.append( $pUp ).append( $pDown ).append( $pLeft ).append( $pRight );
+
+ var $pIndicator = $('<div class="cy-panzoom-pan-indicator"></div>');
+ $panner.append( $pIndicator );
+
+ // functions for calculating panning
+ ////////////////////////////////////
+
+ function handle2pan(e){
+ var v = {
+ x: e.originalEvent.pageX - $panner.offset().left - $panner.width()/2,
+ y: e.originalEvent.pageY - $panner.offset().top - $panner.height()/2
+ }
+
+ var r = options.panDragAreaSize;
+ var d = Math.sqrt( v.x*v.x + v.y*v.y );
+ var percent = Math.min( d/r, 1 );
+
+ if( d < options.panInactiveArea ){
+ return {
+ x: NaN,
+ y: NaN
+ };
+ }
+
+ v = {
+ x: v.x/d,
+ y: v.y/d
+ };
+
+ percent = Math.max( options.panMinPercentSpeed, percent );
+
+ var vnorm = {
+ x: -1 * v.x * (percent * options.panDistance),
+ y: -1 * v.y * (percent * options.panDistance)
+ };
+
+ return vnorm;
+ }
+
+ function donePanning(){
+ clearInterval(panInterval);
+ windowUnbind("mousemove", handler);
+
+ $pIndicator.hide();
+ }
+
+ function positionIndicator(pan){
+ var v = pan;
+ var d = Math.sqrt( v.x*v.x + v.y*v.y );
+ var vnorm = {
+ x: -1 * v.x/d,
+ y: -1 * v.y/d
+ };
+
+ var w = $panner.width();
+ var h = $panner.height();
+ var percent = d/options.panDistance;
+ var opacity = Math.max( options.panIndicatorMinOpacity, percent );
+ var color = 255 - Math.round( opacity * 255 );
+
+ $pIndicator.show().css({
+ left: w/2 * vnorm.x + w/2,
+ top: h/2 * vnorm.y + h/2,
+ background: "rgb(" + color + ", " + color + ", " + color + ")"
+ });
+ }
+
+ function calculateZoomCenterPoint(){
+ var cy = $container.cytoscape("get");
+ var pan = cy.pan();
+ var zoom = cy.zoom();
+
+ zx = $container.width()/2;
+ zy = $container.height()/2;
+ }
+
+ var zooming = false;
+ function startZooming(){
+ zooming = true;
+
+ calculateZoomCenterPoint();
+ }
+
+
+ function endZooming(){
+ zooming = false;
+ }
+
+ var zx, zy;
+ function zoomTo(level){
+ var cy = $container.cytoscape("get");
+
+ if( !zooming ){ // for non-continuous zooming (e.g. click slider at pt)
+ calculateZoomCenterPoint();
+ }
+
+ cy.zoom({
+ level: level,
+ renderedPosition: { x: zx, y: zy }
+ });
+ }
+
+ var panInterval;
+
+ var handler = function(e){
+ e.stopPropagation(); // don't trigger dragging of panzoom
+ e.preventDefault(); // don't cause text selection
+ clearInterval(panInterval);
+
+ var pan = handle2pan(e);
+
+ if( isNaN(pan.x) || isNaN(pan.y) ){
+ $pIndicator.hide();
+ return;
+ }
+
+ positionIndicator(pan);
+ panInterval = setInterval(function(){
+ $container.cytoscape("get").panBy(pan);
+ }, options.panSpeed);
+ };
+
+ $pHandle.bind("mousedown", function(e){
+ // handle click of icon
+ handler(e);
+
+ // update on mousemove
+ windowBind("mousemove", handler);
+ });
+
+ $pHandle.bind("mouseup", function(){
+ donePanning();
+ });
+
+ windowBind("mouseup blur", function(){
+ donePanning();
+ });
+
+
+
+ // set up slider behaviour
+ //////////////////////////
+
+ $slider.bind('mousedown', function(){
+ return false; // so we don't pan close to the slider handle
+ });
+
+ var sliderVal;
+ var sliding = false;
+ var sliderPadding = 2;
+
+ function setSliderFromMouse(evt, handleOffset){
+ if( handleOffset === undefined ){
+ handleOffset = 0;
+ }
+
+ var padding = sliderPadding;
+ var min = 0 + padding;
+ var max = $slider.height() - $sliderHandle.height() - 2*padding;
+ var top = evt.pageY - $slider.offset().top - handleOffset;
+
+ // constrain to slider bounds
+ if( top < min ){ top = min }
+ if( top > max ){ top = max }
+
+ var percent = 1 - (top - min) / ( max - min );
+
+ // move the handle
+ $sliderHandle.css('top', top);
+
+ var zmin = options.minZoom;
+ var zmax = options.maxZoom;
+
+ // assume (zoom = zmax ^ p) where p ranges on (x, 1) with x negative
+ var x = Math.log(zmin) / Math.log(zmax);
+ var p = (1 - x)*percent + x;
+
+ // change the zoom level
+ var z = Math.pow( zmax, p );
+
+ // bound the zoom value in case of floating pt rounding error
+ if( z < zmin ){
+ z = zmin;
+ } else if( z > zmax ){
+ z = zmax;
+ }
+
+ zoomTo( z );
+ }
+
+ var sliderMdownHandler, sliderMmoveHandler;
+ $sliderHandle.bind('mousedown', sliderMdownHandler = function( mdEvt ){
+ var handleOffset = mdEvt.target === $sliderHandle[0] ? mdEvt.offsetY : 0;
+ sliding = true;
+
+ startZooming();
+ $sliderHandle.addClass("active");
+
+ var lastMove = 0;
+ windowBind('mousemove', sliderMmoveHandler = function( mmEvt ){
+ var now = +new Date;
+
+ // throttle the zooms every 10 ms so we don't call zoom too often and cause lag
+ if( now > lastMove + 10 ){
+ lastMove = now;
+ } else {
+ return false;
+ }
+
+ setSliderFromMouse(mmEvt, handleOffset);
+
+ return false;
+ });
+
+ // unbind when
+ windowBind('mouseup', function(){
+ windowUnbind('mousemove', sliderMmoveHandler);
+ sliding = false;
+
+ $sliderHandle.removeClass("active");
+ endZooming();
+ });
+
+ return false;
+ });
+
+ $slider.bind('mousedown', function(e){
+ if( e.target !== $sliderHandle[0] ){
+ sliderMdownHandler(e);
+ setSliderFromMouse(e);
+ }
+ });
+
+ function positionSliderFromZoom(){
+ var cy = $container.cytoscape("get");
+ var z = cy.zoom();
+ var zmin = options.minZoom;
+ var zmax = options.maxZoom;
+
+ // assume (zoom = zmax ^ p) where p ranges on (x, 1) with x negative
+ var x = Math.log(zmin) / Math.log(zmax);
+ var p = Math.log(z) / Math.log(zmax);
+ var percent = 1 - (p - x) / (1 - x); // the 1- bit at the front b/c up is in the -ve y direction
+
+ var min = sliderPadding;
+ var max = $slider.height() - $sliderHandle.height() - 2*sliderPadding;
+ var top = percent * ( max - min );
+
+ // constrain to slider bounds
+ if( top < min ){ top = min }
+ if( top > max ){ top = max }
+
+ // move the handle
+ $sliderHandle.css('top', top);
+ }
+
+ positionSliderFromZoom();
+
+ cyOn('zoom', function(){
+ if( !sliding ){
+ positionSliderFromZoom();
+ }
+ });
+
+ // set the position of the zoom=1 tick
+ (function(){
+ var z = 1;
+ var zmin = options.minZoom;
+ var zmax = options.maxZoom;
+
+ // assume (zoom = zmax ^ p) where p ranges on (x, 1) with x negative
+ var x = Math.log(zmin) / Math.log(zmax);
+ var p = Math.log(z) / Math.log(zmax);
+ var percent = 1 - (p - x) / (1 - x); // the 1- bit at the front b/c up is in the -ve y direction
+
+ if( percent > 1 || percent < 0 ){
+ $noZoomTick.hide();
+ return;
+ }
+
+ var min = sliderPadding;
+ var max = $slider.height() - $sliderHandle.height() - 2*sliderPadding;
+ var top = percent * ( max - min );
+
+ // constrain to slider bounds
+ if( top < min ){ top = min }
+ if( top > max ){ top = max }
+
+ $noZoomTick.css('top', top);
+ })();
+
+ // set up zoom in/out buttons
+ /////////////////////////////
+
+ function bindButton($button, factor){
+ var zoomInterval;
+
+ $button.bind("mousedown", function(e){
+ e.preventDefault();
+ e.stopPropagation();
+
+ if( e.button != 0 ){
+ return;
+ }
+
+ var cy = $container.cytoscape("get");
+ var doZoom = function(){
+ var zoom = cy.zoom();
+ var lvl = cy.zoom() * factor;
+
+ if( lvl < options.minZoom ){
+ lvl = options.minZoom;
+ }
+
+ if( lvl > options.maxZoom ){
+ lvl = options.maxZoom;
+ }
+
+ if( (lvl == options.maxZoom && zoom == options.maxZoom) ||
+ (lvl == options.minZoom && zoom == options.minZoom)
+ ){
+ return;
+ }
+
+ zoomTo(lvl);
+ };
+
+ startZooming();
+ doZoom();
+ zoomInterval = setInterval(doZoom, options.zoomDelay);
+
+ return false;
+ });
+
+ windowBind("mouseup blur", function(){
+ clearInterval(zoomInterval);
+ endZooming();
+ });
+ }
+
+ bindButton( $zoomIn, (1 + options.zoomFactor) );
+ bindButton( $zoomOut, (1 - options.zoomFactor) );
+
+ $reset.bind("mousedown", function(e){
+ if( e.button != 0 ){
+ return;
+ }
+
+ var cy = $container.cytoscape("get");
+
+ if( cy.elements().size() === 0 ){
+ cy.reset();
+ } else {
+ cy.fit( options.fitPadding );
+ }
+
+ return false;
+ });
+
+
+
+ });
+ }
+ };
+
+ if( functions[fn] ){
+ return functions[fn].apply(this, Array.prototype.slice.call( arguments, 1 ));
+ } else if( typeof fn == 'object' || !fn ) {
+ return functions.init.apply( this, arguments );
+ } else {
+ $.error("No such function `"+ fn +"` for jquery.cytoscapePanzoom");
+ }
+
+ return $(this);
+ };
+
+
+ if( typeof module !== 'undefined' && module.exports ){ // expose as a commonjs module
+ module.exports = register;
+ }
+
+ if( typeof define !== 'undefined' && define.amd ){ // expose as an amd/requirejs module
+ define('cytoscape-panzoom', function(){
+ return register;
+ });
+ }
+
+ if( typeof cytoscape !== 'undefined' ){ // expose to global cytoscape (i.e. window.cytoscape)
+ register( cytoscape, jQuery || {} );
+ }
+
+})();
diff --git a/docs/htmldoc/js/cytoscape-qtip.js b/docs/htmldoc/js/cytoscape-qtip.js
new file mode 100644
index 0000000..43ad8b9
--- /dev/null
+++ b/docs/htmldoc/js/cytoscape-qtip.js
@@ -0,0 +1,362 @@
+;(function( $, $$ ){ 'use strict';
+
+ var isObject = function(o){
+ return o != null && typeof o === 'object';
+ };
+
+ var isFunction = function(o){
+ return o != null && typeof o === 'function';
+ };
+
+ var isNumber = function(o){
+ return o != null && typeof o === 'number';
+ };
+
+ var throttle = function(func, wait, options) {
+ var leading = true,
+ trailing = true;
+
+ if (options === false) {
+ leading = false;
+ } else if (isObject(options)) {
+ leading = 'leading' in options ? options.leading : leading;
+ trailing = 'trailing' in options ? options.trailing : trailing;
+ }
+ options = options || {};
+ options.leading = leading;
+ options.maxWait = wait;
+ options.trailing = trailing;
+
+ return debounce(func, wait, options);
+ };
+
+ var debounce = function(func, wait, options) { // ported lodash debounce function
+ var args,
+ maxTimeoutId,
+ result,
+ stamp,
+ thisArg,
+ timeoutId,
+ trailingCall,
+ lastCalled = 0,
+ maxWait = false,
+ trailing = true;
+
+ if (!isFunction(func)) {
+ return;
+ }
+ wait = Math.max(0, wait) || 0;
+ if (options === true) {
+ var leading = true;
+ trailing = false;
+ } else if (isObject(options)) {
+ leading = options.leading;
+ maxWait = 'maxWait' in options && (Math.max(wait, options.maxWait) || 0);
+ trailing = 'trailing' in options ? options.trailing : trailing;
+ }
+ var delayed = function() {
+ var remaining = wait - (Date.now() - stamp);
+ if (remaining <= 0) {
+ if (maxTimeoutId) {
+ clearTimeout(maxTimeoutId);
+ }
+ var isCalled = trailingCall;
+ maxTimeoutId = timeoutId = trailingCall = undefined;
+ if (isCalled) {
+ lastCalled = Date.now();
+ result = func.apply(thisArg, args);
+ if (!timeoutId && !maxTimeoutId) {
+ args = thisArg = null;
+ }
+ }
+ } else {
+ timeoutId = setTimeout(delayed, remaining);
+ }
+ };
+
+ var maxDelayed = function() {
+ if (timeoutId) {
+ clearTimeout(timeoutId);
+ }
+ maxTimeoutId = timeoutId = trailingCall = undefined;
+ if (trailing || (maxWait !== wait)) {
+ lastCalled = Date.now();
+ result = func.apply(thisArg, args);
+ if (!timeoutId && !maxTimeoutId) {
+ args = thisArg = null;
+ }
+ }
+ };
+
+ return function() {
+ args = arguments;
+ stamp = Date.now();
+ thisArg = this;
+ trailingCall = trailing && (timeoutId || !leading);
+
+ if (maxWait === false) {
+ var leadingCall = leading && !timeoutId;
+ } else {
+ if (!maxTimeoutId && !leading) {
+ lastCalled = stamp;
+ }
+ var remaining = maxWait - (stamp - lastCalled),
+ isCalled = remaining <= 0;
+
+ if (isCalled) {
+ if (maxTimeoutId) {
+ maxTimeoutId = clearTimeout(maxTimeoutId);
+ }
+ lastCalled = stamp;
+ result = func.apply(thisArg, args);
+ }
+ else if (!maxTimeoutId) {
+ maxTimeoutId = setTimeout(maxDelayed, remaining);
+ }
+ }
+ if (isCalled && timeoutId) {
+ timeoutId = clearTimeout(timeoutId);
+ }
+ else if (!timeoutId && wait !== maxWait) {
+ timeoutId = setTimeout(delayed, wait);
+ }
+ if (leadingCall) {
+ isCalled = true;
+ result = func.apply(thisArg, args);
+ }
+ if (isCalled && !timeoutId && !maxTimeoutId) {
+ args = thisArg = null;
+ }
+ return result;
+ };
+ };
+
+ function register( $$, $ ){
+
+ // use a single dummy dom ele as target for every qtip
+ var $qtipContainer = $('<div></div>');
+ var viewportDebounceRate = 250;
+
+ function generateOpts( target, passedOpts ){
+ var qtip = target.scratch().qtip;
+ var opts = $.extend( {}, passedOpts );
+
+ if( !opts.id ){
+ opts.id = 'cy-qtip-target-' + ( Date.now() + Math.round( Math.random() * 10000) );
+ }
+
+ if( !qtip.$domEle ){
+ qtip.$domEle = $qtipContainer;
+ }
+
+ // qtip should be positioned relative to cy dom container
+ opts.position = opts.position || {};
+ opts.position.container = opts.position.container || $( document.body );
+ opts.position.viewport = opts.position.viewport || $( document.body );
+ opts.position.target = [0, 0];
+ opts.position.my = opts.position.my || 'top center';
+ opts.position.at = opts.position.at || 'bottom center';
+
+ // adjust
+ var adjust = opts.position.adjust = opts.position.adjust || {};
+ adjust.method = adjust.method || 'flip';
+ adjust.mouse = false;
+
+ if( adjust.cyAdjustToEleBB === undefined ){
+ adjust.cyAdjustToEleBB = true;
+ }
+
+ // default show event
+ opts.show = opts.show || {};
+
+ if( !opts.show.event ){
+ opts.show.event = 'tap';
+ }
+
+ // default hide event
+ opts.hide = opts.hide || {};
+ opts.hide.cyViewport = opts.hide.cyViewport === undefined ? true : opts.hide.cyViewport;
+
+ if( !opts.hide.event ){
+ opts.hide.event = 'unfocus';
+ }
+
+ // so multiple qtips can exist at once (only works on recent qtip2 versions)
+ opts.overwrite = false;
+
+ var content;
+ if( opts.content ){
+ if( isFunction(opts.content) ){
+ content = opts.content;
+ } else if( opts.content.text && isFunction(opts.content.text) ){
+ content = opts.content.text;
+ }
+
+ if( content ){
+ opts.content = function(event, api){
+ return content.apply( target, [event, api] );
+ };
+ }
+ }
+
+ return opts;
+ }
+
+ $$('collection', 'qtip', function( passedOpts ){
+ var eles = this;
+ var cy = this.cy();
+ var container = cy.container();
+
+ if( passedOpts === 'api' ){
+ return this.scratch().qtip.api;
+ }
+
+ eles.each(function(i, ele){
+ var scratch = ele.scratch();
+ var qtip = scratch.qtip = scratch.qtip || {};
+ var opts = generateOpts( ele, passedOpts );
+ var adjNums = opts.position.adjust;
+
+
+ qtip.$domEle.qtip( opts );
+ var qtipApi = qtip.api = qtip.$domEle.qtip('api'); // save api ref
+ qtip.$domEle.removeData('qtip'); // remove qtip dom/api ref to be safe
+
+ var updatePosition = function(e){
+ var cOff = container.getBoundingClientRect();
+ var pos = ele.renderedPosition() || ( e ? e.cyRenderedPosition : undefined );
+ if( !pos || pos.x == null || isNaN(pos.x) ){ return; }
+
+ if( opts.position.adjust.cyAdjustToEleBB && ele.isNode() ){
+ var my = opts.position.my.toLowerCase();
+ var at = opts.position.at.toLowerCase();
+ var z = cy.zoom();
+ var w = ele.outerWidth() * z;
+ var h = ele.outerHeight() * z;
+
+ if( at.match('top') ){
+ pos.y -= h/2;
+ } else if( at.match('bottom') ){
+ pos.y += h/2;
+ }
+
+ if( at.match('left') ){
+ pos.x -= w/2;
+ } else if( at.match('right') ){
+ pos.x += w/2;
+ }
+
+ if( isNumber(adjNums.x) ){
+ pos.x += adjNums.x;
+ }
+
+ if( isNumber(adjNums.y) ){
+ pos.y += adjNums.y;
+ }
+ }
+
+ qtipApi.set('position.adjust.x', cOff.left + pos.x + window.pageXOffset);
+ qtipApi.set('position.adjust.y', cOff.top + pos.y + window.pageYOffset);
+ };
+ updatePosition();
+
+ ele.on( opts.show.event, function(e){
+ updatePosition(e);
+
+ qtipApi.show();
+ } );
+
+ ele.on( opts.hide.event, function(e){
+ qtipApi.hide();
+ } );
+
+ if( opts.hide.cyViewport ){
+ cy.on('viewport', debounce(function(){
+ qtipApi.hide();
+ }, viewportDebounceRate, { leading: true }) );
+ }
+
+ if( opts.position.adjust.cyViewport ){
+ cy.on('pan zoom', debounce(function(e){
+ updatePosition(e);
+
+ qtipApi.reposition();
+ }, viewportDebounceRate, { trailing: true }) );
+ }
+
+ });
+
+ return this; // chainability
+
+ });
+
+ $$('core', 'qtip', function( passedOpts ){
+ var cy = this;
+ var container = cy.container();
+
+ if( passedOpts === 'api' ){
+ return this.scratch().qtip.api;
+ }
+
+ var scratch = cy.scratch();
+ var qtip = scratch.qtip = scratch.qtip || {};
+ var opts = generateOpts( cy, passedOpts );
+
+
+ qtip.$domEle.qtip( opts );
+ var qtipApi = qtip.api = qtip.$domEle.qtip('api'); // save api ref
+ qtip.$domEle.removeData('qtip'); // remove qtip dom/api ref to be safe
+
+ var updatePosition = function(e){
+ var cOff = container.getBoundingClientRect();
+ var pos = e.cyRenderedPosition;
+ if( !pos || pos.x == null || isNaN(pos.x) ){ return; }
+
+ qtipApi.set('position.adjust.x', cOff.left + pos.x + window.pageXOffset);
+ qtipApi.set('position.adjust.y', cOff.top + pos.y + window.pageYOffset);
+ };
+
+ cy.on( opts.show.event, function(e){
+ if( !opts.show.cyBgOnly || (opts.show.cyBgOnly && e.cyTarget === cy) ){
+ updatePosition(e);
+
+ qtipApi.show();
+ }
+ } );
+
+ cy.on( opts.hide.event, function(e){
+ if( !opts.hide.cyBgOnly || (opts.hide.cyBgOnly && e.cyTarget === cy) ){
+ qtipApi.hide();
+ }
+ } );
+
+ if( opts.hide.cyViewport ){
+ cy.on('viewport', debounce(function(){
+ qtipApi.hide();
+ }, viewportDebounceRate, { leading: true }) );
+ }
+
+ return this; // chainability
+
+ });
+
+ }
+
+ if( typeof module !== 'undefined' && module.exports ){ // expose as a commonjs module
+ module.exports = register;
+ }
+
+ if( typeof define !== 'undefined' && define.amd ){ // expose as an amd/requirejs module
+ define('cytoscape-qtip', function(){
+ return register;
+ });
+ }
+
+ if( $ && $$ ){
+ register( $$, $ );
+ }
+
+})(
+ typeof jQuery !== 'undefined' ? jQuery : null,
+ typeof cytoscape !== 'undefined' ? cytoscape : null
+);
diff --git a/docs/htmldoc/js/cytoscape.js b/docs/htmldoc/js/cytoscape.js
new file mode 100644
index 0000000..601e6db
--- /dev/null
+++ b/docs/htmldoc/js/cytoscape.js
@@ -0,0 +1,24515 @@
+/*!
+ * This file is part of Cytoscape.js 2.5.1.
+ *
+ * Cytoscape.js is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published by the Free
+ * Software Foundation, either version 3 of the License, or (at your option) any
+ * later version.
+ *
+ * Cytoscape.js is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License along with
+ * Cytoscape.js. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+(function(f){if(typeof exports==="object"&&typeof module!=="undefined"){module.exports=f()}else if(typeof define==="function"&&define.amd){define([],f)}else{var g;if(typeof window!=="undefined"){g=window}else if(typeof global!=="undefined"){g=global}else if(typeof self!=="undefined"){g=self}else{g=this}g.cytoscape = f()}})(function(){var define,module,exports;return (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s})({1:[function(_dereq_,module,exports){
+'use strict';
+
+var util = _dereq_('./util');
+var is = _dereq_('./is');
+var Promise = _dereq_('./promise');
+
+var Animation = function( target, opts, opts2 ){
+ if( !(this instanceof Animation) ){
+ return new Animation( target, opts, opts2 );
+ }
+
+ var _p = this._private = util.extend( {
+ duration: 1000
+ }, opts, opts2 );
+
+ _p.target = target;
+ _p.style = _p.style || _p.css;
+ _p.started = false;
+ _p.playing = false;
+ _p.hooked = false;
+ _p.applying = false;
+ _p.progress = 0;
+ _p.completes = [];
+ _p.frames = [];
+
+ if( _p.complete && is.fn(_p.complete) ){
+ _p.completes.push( _p.complete );
+ }
+
+ // for future timeline/animations impl
+ this.length = 1;
+ this[0] = this;
+};
+
+var anifn = Animation.prototype;
+
+util.extend( anifn, {
+
+ instanceString: function(){ return 'animation'; },
+
+ hook: function(){
+ var _p = this._private;
+
+ if( !_p.hooked ){
+ // add to target's animation queue
+ var q;
+ var tAni = _p.target._private.animation;
+ if( _p.queue ){
+ q = tAni.queue;
+ } else {
+ q = tAni.current;
+ }
+ q.push( this );
+
+ // add to the animation loop pool
+ if( is.elementOrCollection( _p.target ) ){
+ _p.target.cy().addToAnimationPool( _p.target );
+ }
+
+ _p.hooked = true;
+ }
+
+ return this;
+ },
+
+ play: function(){
+ var _p = this._private;
+
+ // autorewind
+ if( _p.progress === 1 ){
+ _p.progress = 0;
+ }
+
+ _p.playing = true;
+ _p.started = false; // needs to be started by animation loop
+ _p.stopped = false;
+
+ this.hook();
+
+ // the animation loop will start the animation...
+
+ return this;
+ },
+
+ playing: function(){
+ return this._private.playing;
+ },
+
+ apply: function(){
+ var _p = this._private;
+
+ _p.applying = true;
+ _p.started = false; // needs to be started by animation loop
+ _p.stopped = false;
+
+ this.hook();
+
+ // the animation loop will apply the animation at this progress
+
+ return this;
+ },
+
+ applying: function(){
+ return this._private.applying;
+ },
+
+ pause: function(){
+ var _p = this._private;
+
+ _p.playing = false;
+ _p.started = false;
+
+ return this;
+ },
+
+ stop: function(){
+ var _p = this._private;
+
+ _p.playing = false;
+ _p.started = false;
+ _p.stopped = true; // to be removed from animation queues
+
+ return this;
+ },
+
+ rewind: function(){
+ return this.progress(0);
+ },
+
+ fastforward: function(){
+ return this.progress(1);
+ },
+
+ time: function( t ){
+ var _p = this._private;
+
+ if( t === undefined ){
+ return _p.progress * _p.duration;
+ } else {
+ return this.progress( t / _p.duration );
+ }
+ },
+
+ progress: function( p ){
+ var _p = this._private;
+ var wasPlaying = _p.playing;
+
+ if( p === undefined ){
+ return _p.progress;
+ } else {
+ if( wasPlaying ){
+ this.pause();
+ }
+
+ _p.progress = p;
+ _p.started = false;
+
+ if( wasPlaying ){
+ this.play();
+ }
+ }
+
+ return this;
+ },
+
+ completed: function(){
+ return this._private.progress === 1;
+ },
+
+ reverse: function(){
+ var _p = this._private;
+ var wasPlaying = _p.playing;
+
+ if( wasPlaying ){
+ this.pause();
+ }
+
+ _p.progress = 1 - _p.progress;
+ _p.started = false;
+
+ var swap = function( a, b ){
+ var _pa = _p[a];
+
+ _p[a] = _p[b];
+ _p[b] = _pa;
+ };
+
+ swap( 'zoom', 'startZoom' );
+ swap( 'pan', 'startPan' );
+ swap( 'position', 'startPosition' );
+
+ // swap styles
+ for( var i = 0; i < _p.style.length; i++ ){
+ var prop = _p.style[i];
+ var name = prop.name;
+ var startStyleProp = _p.startStyle[ name ];
+
+ _p.startStyle[ name ] = _p.startStyle[ util.dash2camel( name ) ] = prop;
+ _p.style[i] = startStyleProp;
+ }
+
+ if( wasPlaying ){
+ this.play();
+ }
+
+ return this;
+ },
+
+ promise: function( type ){
+ var _p = this._private;
+
+ var arr;
+
+ switch( type ){
+ case 'frame':
+ arr = _p.frames;
+ break;
+ default:
+ case 'complete':
+ case 'completed':
+ arr = _p.completes;
+ }
+
+ return new Promise(function( resolve, reject ){
+ arr.push(function(){
+ resolve();
+ });
+ });
+ }
+
+} );
+
+anifn.complete = anifn.completed;
+
+module.exports = Animation;
+
+},{"./is":77,"./promise":80,"./util":94}],2:[function(_dereq_,module,exports){
+'use strict';
+
+var is = _dereq_('../../is');
+
+var elesfn = ({
+
+ // Implemented from pseudocode from wikipedia
+ aStar: function(options) {
+ var eles = this;
+
+ options = options || {};
+
+ // Reconstructs the path from Start to End, acumulating the result in pathAcum
+ var reconstructPath = function(start, end, cameFromMap, pathAcum) {
+ // Base case
+ if (start == end) {
+ pathAcum.push( cy.getElementById(end) );
+ return pathAcum;
+ }
+
+ if (end in cameFromMap) {
+ // We know which node is before the last one
+ var previous = cameFromMap[end];
+ var previousEdge = cameFromEdge[end];
+
+ pathAcum.push( cy.getElementById(end) );
+ pathAcum.push( cy.getElementById(previousEdge) );
+
+
+ return reconstructPath(start,
+ previous,
+ cameFromMap,
+ pathAcum);
+ }
+
+ // We should not reach here!
+ return undefined;
+ };
+
+ // Returns the index of the element in openSet which has minimum fScore
+ var findMin = function(openSet, fScore) {
+ if (openSet.length === 0) {
+ // Should never be the case
+ return undefined;
+ }
+ var minPos = 0;
+ var tempScore = fScore[openSet[0]];
+ for (var i = 1; i < openSet.length; i++) {
+ var s = fScore[openSet[i]];
+ if (s < tempScore) {
+ tempScore = s;
+ minPos = i;
+ }
+ }
+ return minPos;
+ };
+
+ var cy = this._private.cy;
+
+ // root - mandatory!
+ if (options != null && options.root != null) {
+ var source = is.string(options.root) ?
+ // use it as a selector, e.g. "#rootID
+ this.filter(options.root)[0] :
+ options.root[0];
+ } else {
+ return undefined;
+ }
+
+ // goal - mandatory!
+ if (options.goal != null) {
+ var target = is.string(options.goal) ?
+ // use it as a selector, e.g. "#goalID
+ this.filter(options.goal)[0] :
+ options.goal[0];
+ } else {
+ return undefined;
+ }
+
+ // Heuristic function - optional
+ if (options.heuristic != null && is.fn(options.heuristic)) {
+ var heuristic = options.heuristic;
+ } else {
+ var heuristic = function(){ return 0; }; // use constant if unspecified
+ }
+
+ // Weight function - optional
+ if (options.weight != null && is.fn(options.weight)) {
+ var weightFn = options.weight;
+ } else {
+ // If not specified, assume each edge has equal weight (1)
+ var weightFn = function(e) {return 1;};
+ }
+
+ // directed - optional
+ if (options.directed != null) {
+ var directed = options.directed;
+ } else {
+ var directed = false;
+ }
+
+ var closedSet = [];
+ var openSet = [source.id()];
+ var cameFrom = {};
+ var cameFromEdge = {};
+ var gScore = {};
+ var fScore = {};
+
+ gScore[source.id()] = 0;
+ fScore[source.id()] = heuristic(source);
+
+ var edges = this.edges().stdFilter(function(e){ return !e.isLoop(); });
+ var nodes = this.nodes();
+
+ // Counter
+ var steps = 0;
+
+ // Main loop
+ while (openSet.length > 0) {
+ var minPos = findMin(openSet, fScore);
+ var cMin = cy.getElementById( openSet[minPos] );
+ steps++;
+
+ // If we've found our goal, then we are done
+ if (cMin.id() == target.id()) {
+ var rPath = reconstructPath(source.id(), target.id(), cameFrom, []);
+ rPath.reverse();
+ return {
+ found : true,
+ distance : gScore[cMin.id()],
+ path : eles.spawn(rPath),
+ steps : steps
+ };
+ }
+
+ // Add cMin to processed nodes
+ closedSet.push(cMin.id());
+ // Remove cMin from boundary nodes
+ openSet.splice(minPos, 1);
+
+ // Update scores for neighbors of cMin
+ // Take into account if graph is directed or not
+ var vwEdges = cMin.connectedEdges();
+ if( directed ){ vwEdges = vwEdges.stdFilter(function(ele){ return ele.data('source') === cMin.id(); }); }
+ vwEdges = vwEdges.intersect(edges);
+
+ for (var i = 0; i < vwEdges.length; i++) {
+ var e = vwEdges[i];
+ var w = e.connectedNodes().stdFilter(function(n){ return n.id() !== cMin.id(); }).intersect(nodes);
+
+ // if node is in closedSet, ignore it
+ if (closedSet.indexOf(w.id()) != -1) {
+ continue;
+ }
+
+ // New tentative score for node w
+ var tempScore = gScore[cMin.id()] + weightFn.apply(e, [e]);
+
+ // Update gScore for node w if:
+ // w not present in openSet
+ // OR
+ // tentative gScore is less than previous value
+
+ // w not in openSet
+ if (openSet.indexOf(w.id()) == -1) {
+ gScore[w.id()] = tempScore;
+ fScore[w.id()] = tempScore + heuristic(w);
+ openSet.push(w.id()); // Add node to openSet
+ cameFrom[w.id()] = cMin.id();
+ cameFromEdge[w.id()] = e.id();
+ continue;
+ }
+ // w already in openSet, but with greater gScore
+ if (tempScore < gScore[w.id()]) {
+ gScore[w.id()] = tempScore;
+ fScore[w.id()] = tempScore + heuristic(w);
+ cameFrom[w.id()] = cMin.id();
+ }
+
+ } // End of neighbors update
+
+ } // End of main loop
+
+ // If we've reached here, then we've not reached our goal
+ return {
+ found : false,
+ distance : undefined,
+ path : undefined,
+ steps : steps
+ };
+ }
+
+}); // elesfn
+
+
+module.exports = elesfn;
+
+},{"../../is":77}],3:[function(_dereq_,module,exports){
+'use strict';
+
+var is = _dereq_('../../is');
+var util = _dereq_('../../util');
+
+var elesfn = ({
+
+ // Implemented from pseudocode from wikipedia
+ bellmanFord: function(options) {
+ var eles = this;
+
+ options = options || {};
+
+ // Weight function - optional
+ if (options.weight != null && is.fn(options.weight)) {
+ var weightFn = options.weight;
+ } else {
+ // If not specified, assume each edge has equal weight (1)
+ var weightFn = function(e) {return 1;};
+ }
+
+ // directed - optional
+ if (options.directed != null) {
+ var directed = options.directed;
+ } else {
+ var directed = false;
+ }
+
+ // root - mandatory!
+ if (options.root != null) {
+ if (is.string(options.root)) {
+ // use it as a selector, e.g. "#rootID
+ var source = this.filter(options.root)[0];
+ } else {
+ var source = options.root[0];
+ }
+ } else {
+ return undefined;
+ }
+
+ var cy = this._private.cy;
+ var edges = this.edges().stdFilter(function(e){ return !e.isLoop(); });
+ var nodes = this.nodes();
+ var numNodes = nodes.length;
+
+ // mapping: node id -> position in nodes array
+ var id2position = {};
+ for (var i = 0; i < numNodes; i++) {
+ id2position[nodes[i].id()] = i;
+ }
+
+ // Initializations
+ var cost = [];
+ var predecessor = [];
+ var predEdge = [];
+
+ for (var i = 0; i < numNodes; i++) {
+ if (nodes[i].id() === source.id()) {
+ cost[i] = 0;
+ } else {
+ cost[i] = Infinity;
+ }
+ predecessor[i] = undefined;
+ }
+
+ // Edges relaxation
+ var flag = false;
+ for (var i = 1; i < numNodes; i++) {
+ flag = false;
+ for (var e = 0; e < edges.length; e++) {
+ var sourceIndex = id2position[edges[e].source().id()];
+ var targetIndex = id2position[edges[e].target().id()];
+ var weight = weightFn.apply(edges[e], [edges[e]]);
+
+ var temp = cost[sourceIndex] + weight;
+ if (temp < cost[targetIndex]) {
+ cost[targetIndex] = temp;
+ predecessor[targetIndex] = sourceIndex;
+ predEdge[targetIndex] = edges[e];
+ flag = true;
+ }
+
+ // If undirected graph, we need to take into account the 'reverse' edge
+ if (!directed) {
+ var temp = cost[targetIndex] + weight;
+ if (temp < cost[sourceIndex]) {
+ cost[sourceIndex] = temp;
+ predecessor[sourceIndex] = targetIndex;
+ predEdge[sourceIndex] = edges[e];
+ flag = true;
+ }
+ }
+ }
+
+ if (!flag) {
+ break;
+ }
+ }
+
+ if (flag) {
+ // Check for negative weight cycles
+ for (var e = 0; e < edges.length; e++) {
+ var sourceIndex = id2position[edges[e].source().id()];
+ var targetIndex = id2position[edges[e].target().id()];
+ var weight = weightFn.apply(edges[e], [edges[e]]);
+
+ if (cost[sourceIndex] + weight < cost[targetIndex]) {
+ util.error("Graph contains a negative weight cycle for Bellman-Ford");
+ return { pathTo: undefined,
+ distanceTo: undefined,
+ hasNegativeWeightCycle: true};
+ }
+ }
+ }
+
+ // Build result object
+ var position2id = [];
+ for (var i = 0; i < numNodes; i++) {
+ position2id.push(nodes[i].id());
+ }
+
+
+ var res = {
+ distanceTo : function(to) {
+ if (is.string(to)) {
+ // to is a selector string
+ var toId = (cy.filter(to)[0]).id();
+ } else {
+ // to is a node
+ var toId = to.id();
+ }
+
+ return cost[id2position[toId]];
+ },
+
+ pathTo : function(to) {
+
+ var reconstructPathAux = function(predecessor, fromPos, toPos, position2id, acumPath, predEdge) {
+ for(;;){
+ // Add toId to path
+ acumPath.push( cy.getElementById(position2id[toPos]) );
+ acumPath.push( predEdge[toPos] );
+
+ if (fromPos === toPos) {
+ // reached starting node
+ return acumPath;
+ }
+
+ // If no path exists, discart acumulated path and return undefined
+ var predPos = predecessor[toPos];
+ if (typeof predPos === "undefined") {
+ return undefined;
+ }
+
+ toPos = predPos;
+ }
+
+ };
+
+ if (is.string(to)) {
+ // to is a selector string
+ var toId = (cy.filter(to)[0]).id();
+ } else {
+ // to is a node
+ var toId = to.id();
+ }
+ var path = [];
+
+ // This returns a reversed path
+ var res = reconstructPathAux(predecessor,
+ id2position[source.id()],
+ id2position[toId],
+ position2id,
+ path,
+ predEdge);
+
+ // Get it in the correct order and return it
+ if (res != null) {
+ res.reverse();
+ }
+
+ return eles.spawn(res);
+ },
+
+ hasNegativeWeightCycle: false
+ };
+
+ return res;
+
+ } // bellmanFord
+
+}); // elesfn
+
+module.exports = elesfn;
+
+},{"../../is":77,"../../util":94}],4:[function(_dereq_,module,exports){
+'use strict';
+
+var is = _dereq_('../../is');
+
+var elesfn = ({
+
+ // Implemented from the algorithm in the paper "On Variants of Shortest-Path Betweenness Centrality and their Generic Computation" by Ulrik Brandes
+ betweennessCentrality: function (options) {
+ options = options || {};
+
+ // Weight - optional
+ if (options.weight != null && is.fn(options.weight)) {
+ var weightFn = options.weight;
+ var weighted = true;
+ } else {
+ var weighted = false;
+ }
+
+ // Directed - default false
+ if (options.directed != null && is.bool(options.directed)) {
+ var directed = options.directed;
+ } else {
+ var directed = false;
+ }
+
+ var priorityInsert = function (queue, ele) {
+ queue.unshift(ele);
+ for (var i = 0; d[queue[i]] < d[queue[i + 1]] && i < queue.length - 1; i++) {
+ var tmp = queue[i];
+ queue[i] = queue[i + 1];
+ queue[i + 1] = tmp;
+ }
+ };
+
+ var cy = this._private.cy;
+
+ // starting
+ var V = this.nodes();
+ var A = {};
+ var C = {};
+
+ // A contains the neighborhoods of every node
+ for (var i = 0; i < V.length; i++) {
+ if (directed) {
+ A[V[i].id()] = V[i].outgoers("node"); // get outgoers of every node
+ } else {
+ A[V[i].id()] = V[i].openNeighborhood("node"); // get neighbors of every node
+ }
+ }
+
+ // C contains the betweenness values
+ for (var i = 0; i < V.length; i++) {
+ C[V[i].id()] = 0;
+ }
+
+ for (var s = 0; s < V.length; s++) {
+ var S = []; // stack
+ var P = {};
+ var g = {};
+ var d = {};
+ var Q = []; // queue
+
+ // init dictionaries
+ for (var i = 0; i < V.length; i++) {
+ P[V[i].id()] = [];
+ g[V[i].id()] = 0;
+ d[V[i].id()] = Number.POSITIVE_INFINITY;
+ }
+
+ g[V[s].id()] = 1; // sigma
+ d[V[s].id()] = 0; // distance to s
+
+ Q.unshift(V[s].id());
+
+ while (Q.length > 0) {
+ var v = Q.pop();
+ S.push(v);
+ if (weighted) {
+ A[v].forEach(function (w) {
+ if (cy.$('#' + v).edgesTo(w).length > 0) {
+ var edge = cy.$('#' + v).edgesTo(w)[0];
+ } else {
+ var edge = w.edgesTo('#' + v)[0];
+ }
+
+ var edgeWeight = weightFn.apply(edge, [edge]);
+
+ if (d[w.id()] > d[v] + edgeWeight) {
+ d[w.id()] = d[v] + edgeWeight;
+ if (Q.indexOf(w.id()) < 0) { //if w is not in Q
+ priorityInsert(Q, w.id());
+ } else { // update position if w is in Q
+ Q.splice(Q.indexOf(w.id()), 1);
+ priorityInsert(Q, w.id());
+ }
+ g[w.id()] = 0;
+ P[w.id()] = [];
+ }
+ if (d[w.id()] == d[v] + edgeWeight) {
+ g[w.id()] = g[w.id()] + g[v];
+ P[w.id()].push(v);
+ }
+ });
+ } else {
+ A[v].forEach(function (w) {
+ if (d[w.id()] == Number.POSITIVE_INFINITY) {
+ Q.unshift(w.id());
+ d[w.id()] = d[v] + 1;
+ }
+ if (d[w.id()] == d[v] + 1) {
+ g[w.id()] = g[w.id()] + g[v];
+ P[w.id()].push(v);
+ }
+ });
+ }
+ }
+
+ var e = {};
+ for (var i = 0; i < V.length; i++) {
+ e[V[i].id()] = 0;
+ }
+
+ while (S.length > 0) {
+ var w = S.pop();
+ P[w].forEach(function (v) {
+ e[v] = e[v] + (g[v] / g[w]) * (1 + e[w]);
+ if (w != V[s].id())
+ C[w] = C[w] + e[w];
+ });
+ }
+ }
+
+ var max = 0;
+ for (var key in C) {
+ if (max < C[key])
+ max = C[key];
+ }
+
+ var ret = {
+ betweenness: function (node) {
+ if (is.string(node)) {
+ var node = (cy.filter(node)[0]).id();
+ } else {
+ var node = node.id();
+ }
+
+ return C[node];
+ },
+
+ betweennessNormalized: function (node) {
+ if (is.string(node)) {
+ var node = (cy.filter(node)[0]).id();
+ } else {
+ var node = node.id();
+ }
+
+ return C[node] / max;
+ }
+ };
+
+ // alias
+ ret.betweennessNormalised = ret.betweennessNormalized;
+
+ return ret;
+ } // betweennessCentrality
+
+}); // elesfn
+
+// nice, short mathemathical alias
+elesfn.bc = elesfn.betweennessCentrality;
+
+module.exports = elesfn;
+
+},{"../../is":77}],5:[function(_dereq_,module,exports){
+'use strict';
+
+var is = _dereq_('../../is');
+var Heap = _dereq_('../../heap');
+
+var defineSearch = function( params ){
+ params = {
+ bfs: params.bfs || !params.dfs,
+ dfs: params.dfs || !params.bfs
+ };
+
+ // from pseudocode on wikipedia
+ return function searchFn( roots, fn, directed ){
+ var options;
+ var std;
+ var thisArg;
+ if( is.plainObject(roots) && !is.elementOrCollection(roots) ){
+ options = roots;
+ roots = options.roots || options.root;
+ fn = options.visit;
+ directed = options.directed;
+ std = options.std;
+ thisArg = options.thisArg;
+ }
+
+ directed = arguments.length === 2 && !is.fn(fn) ? fn : directed;
+ fn = is.fn(fn) ? fn : function(){};
+
+ var cy = this._private.cy;
+ var v = roots = is.string(roots) ? this.filter(roots) : roots;
+ var Q = [];
+ var connectedNodes = [];
+ var connectedBy = {};
+ var id2depth = {};
+ var V = {};
+ var j = 0;
+ var found;
+ var nodes = this.nodes();
+ var edges = this.edges();
+
+ // enqueue v
+ for( var i = 0; i < v.length; i++ ){
+ if( v[i].isNode() ){
+ Q.unshift( v[i] );
+
+ if( params.bfs ){
+ V[ v[i].id() ] = true;
+
+ connectedNodes.push( v[i] );
+ }
+
+ id2depth[ v[i].id() ] = 0;
+ }
+ }
+
+ while( Q.length !== 0 ){
+ var v = params.bfs ? Q.shift() : Q.pop();
+
+ if( params.dfs ){
+ if( V[ v.id() ] ){ continue; }
+
+ V[ v.id() ] = true;
+
+ connectedNodes.push( v );
+ }
+
+ var depth = id2depth[ v.id() ];
+ var prevEdge = connectedBy[ v.id() ];
+ var prevNode = prevEdge == null ? undefined : prevEdge.connectedNodes().not( v )[0];
+ var ret;
+
+ if( std ){
+ ret = fn.call(thisArg, v, prevEdge, prevNode, j++, depth);
+ } else {
+ ret = fn.call(v, j++, depth, v, prevEdge, prevNode);
+ }
+
+ if( ret === true ){
+ found = v;
+ break;
+ }
+
+ if( ret === false ){
+ break;
+ }
+
+ var vwEdges = v.connectedEdges(directed ? function(){ return this.data('source') === v.id(); } : undefined).intersect( edges );
+ for( var i = 0; i < vwEdges.length; i++ ){
+ var e = vwEdges[i];
+ var w = e.connectedNodes(function(){ return this.id() !== v.id(); }).intersect( nodes );
+
+ if( w.length !== 0 && !V[ w.id() ] ){
+ w = w[0];
+
+ Q.push( w );
+
+ if( params.bfs ){
+ V[ w.id() ] = true;
+
+ connectedNodes.push( w );
+ }
+
+ connectedBy[ w.id() ] = e;
+
+ id2depth[ w.id() ] = id2depth[ v.id() ] + 1;
+ }
+ }
+
+ }
+
+ var connectedEles = [];
+
+ for( var i = 0; i < connectedNodes.length; i++ ){
+ var node = connectedNodes[i];
+ var edge = connectedBy[ node.id() ];
+
+ if( edge ){
+ connectedEles.push( edge );
+ }
+
+ connectedEles.push( node );
+ }
+
+ return {
+ path: cy.collection( connectedEles, { unique: true } ),
+ found: cy.collection( found )
+ };
+ };
+};
+
+// search, spanning trees, etc
+var elesfn = ({
+
+ breadthFirstSearch: defineSearch({ bfs: true }),
+ depthFirstSearch: defineSearch({ dfs: true }),
+
+ // kruskal's algorithm (finds min spanning tree, assuming undirected graph)
+ // implemented from pseudocode from wikipedia
+ kruskal: function( weightFn ){
+ var cy = this.cy();
+
+ weightFn = is.fn(weightFn) ? weightFn : function(){ return 1; }; // if not specified, assume each edge has equal weight (1)
+
+ function findSet(ele){
+ for( var i = 0; i < forest.length; i++ ){
+ var eles = forest[i];
+
+ if( eles.anySame(ele) ){
+ return {
+ eles: eles,
+ index: i
+ };
+ }
+ }
+ }
+
+ var A = cy.collection(cy, []);
+ var forest = [];
+ var nodes = this.nodes();
+
+ for( var i = 0; i < nodes.length; i++ ){
+ forest.push( nodes[i].collection() );
+ }
+
+ var edges = this.edges();
+ var S = edges.toArray().sort(function(a, b){
+ var weightA = weightFn.call(a, a);
+ var weightB = weightFn.call(b, b);
+
+ return weightA - weightB;
+ });
+
+ for(var i = 0; i < S.length; i++){
+ var edge = S[i];
+ var u = edge.source()[0];
+ var v = edge.target()[0];
+ var setU = findSet(u);
+ var setV = findSet(v);
+
+ if( setU.index !== setV.index ){
+ A = A.add( edge );
+
+ // combine forests for u and v
+ forest[ setU.index ] = setU.eles.add( setV.eles );
+ forest.splice( setV.index, 1 );
+ }
+ }
+
+ return nodes.add( A );
+
+ },
+
+ dijkstra: function( root, weightFn, directed ){
+ var options;
+ if( is.plainObject(root) && !is.elementOrCollection(root) ){
+ options = root;
+ root = options.root;
+ weightFn = options.weight;
+ directed = options.directed;
+ }
+
+ var cy = this._private.cy;
+ weightFn = is.fn(weightFn) ? weightFn : function(){ return 1; }; // if not specified, assume each edge has equal weight (1)
+
+ var source = is.string(root) ? this.filter(root)[0] : root[0];
+ var dist = {};
+ var prev = {};
+ var knownDist = {};
+
+ var edges = this.edges().filter(function(){ return !this.isLoop(); });
+ var nodes = this.nodes();
+
+ var getDist = function(node){
+ return dist[ node.id() ];
+ };
+
+ var setDist = function(node, d){
+ dist[ node.id() ] = d;
+
+ Q.updateItem( node );
+ };
+
+ var Q = new Heap(function( a, b ){
+ return getDist(a) - getDist(b);
+ });
+
+ for( var i = 0; i < nodes.length; i++ ){
+ var node = nodes[i];
+
+ dist[ node.id() ] = node.same( source ) ? 0 : Infinity;
+ Q.push( node );
+ }
+
+ var distBetween = function(u, v){
+ var uvs = ( directed ? u.edgesTo(v) : u.edgesWith(v) ).intersect(edges);
+ var smallestDistance = Infinity;
+ var smallestEdge;
+
+ for( var i = 0; i < uvs.length; i++ ){
+ var edge = uvs[i];
+ var weight = weightFn.apply( edge, [edge] );
+
+ if( weight < smallestDistance || !smallestEdge ){
+ smallestDistance = weight;
+ smallestEdge = edge;
+ }
+ }
+
+ return {
+ edge: smallestEdge,
+ dist: smallestDistance
+ };
+ };
+
+ while( Q.size() > 0 ){
+ var u = Q.pop();
+ var smalletsDist = getDist(u);
+ var uid = u.id();
+
+ knownDist[uid] = smalletsDist;
+
+ if( smalletsDist === Math.Infinite ){
+ break;
+ }
+
+ var neighbors = u.neighborhood().intersect(nodes);
+ for( var i = 0; i < neighbors.length; i++ ){
+ var v = neighbors[i];
+ var vid = v.id();
+ var vDist = distBetween(u, v);
+
+ var alt = smalletsDist + vDist.dist;
+
+ if( alt < getDist(v) ){
+ setDist(v, alt);
+
+ prev[ vid ] = {
+ node: u,
+ edge: vDist.edge
+ };
+ }
+ } // for
+ } // while
+
+ return {
+ distanceTo: function(node){
+ var target = is.string(node) ? nodes.filter(node)[0] : node[0];
+
+ return knownDist[ target.id() ];
+ },
+
+ pathTo: function(node){
+ var target = is.string(node) ? nodes.filter(node)[0] : node[0];
+ var S = [];
+ var u = target;
+
+ if( target.length > 0 ){
+ S.unshift( target );
+
+ while( prev[ u.id() ] ){
+ var p = prev[ u.id() ];
+
+ S.unshift( p.edge );
+ S.unshift( p.node );
+
+ u = p.node;
+ }
+ }
+
+ return cy.collection( S );
+ }
+ };
+ }
+});
+
+// nice, short mathemathical alias
+elesfn.bfs = elesfn.breadthFirstSearch;
+elesfn.dfs = elesfn.depthFirstSearch;
+
+module.exports = elesfn;
+
+},{"../../heap":75,"../../is":77}],6:[function(_dereq_,module,exports){
+'use strict';
+
+var is = _dereq_('../../is');
+
+var elesfn = ({
+
+ closenessCentralityNormalized: function (options) {
+ options = options || {};
+
+ var cy = this.cy();
+
+ var harmonic = options.harmonic;
+ if( harmonic === undefined ){
+ harmonic = true;
+ }
+
+ var closenesses = {};
+ var maxCloseness = 0;
+ var nodes = this.nodes();
+ var fw = this.floydWarshall({ weight: options.weight, directed: options.directed });
+
+ // Compute closeness for every node and find the maximum closeness
+ for(var i = 0; i < nodes.length; i++){
+ var currCloseness = 0;
+ for (var j = 0; j < nodes.length; j++) {
+ if (i != j) {
+ var d = fw.distance(nodes[i], nodes[j]);
+
+ if( harmonic ){
+ currCloseness += 1 / d;
+ } else {
+ currCloseness += d;
+ }
+ }
+ }
+
+ if( !harmonic ){
+ currCloseness = 1 / currCloseness;
+ }
+
+ if (maxCloseness < currCloseness){
+ maxCloseness = currCloseness;
+ }
+
+ closenesses[nodes[i].id()] = currCloseness;
+ }
+
+ return {
+ closeness: function (node) {
+ if (is.string(node)) {
+ // from is a selector string
+ var node = (cy.filter(node)[0]).id();
+ } else {
+ // from is a node
+ var node = node.id();
+ }
+
+ return closenesses[node] / maxCloseness;
+ }
+ };
+ },
+
+ // Implemented from pseudocode from wikipedia
+ closenessCentrality: function (options) {
+ options = options || {};
+
+ // root - mandatory!
+ if (options.root != null) {
+ if (is.string(options.root)) {
+ // use it as a selector, e.g. "#rootID
+ var root = this.filter(options.root)[0];
+ } else {
+ var root = options.root[0];
+ }
+ } else {
+ return undefined;
+ }
+
+ // weight - optional
+ if (options.weight != null && is.fn(options.weight)) {
+ var weight = options.weight;
+ } else {
+ var weight = function(){return 1;};
+ }
+
+ // directed - optional
+ if (options.directed != null && is.bool(options.directed)) {
+ var directed = options.directed;
+ } else {
+ var directed = false;
+ }
+
+ var harmonic = options.harmonic;
+ if( harmonic === undefined ){
+ harmonic = true;
+ }
+
+ // we need distance from this node to every other node
+ var dijkstra = this.dijkstra({
+ root: root,
+ weight: weight,
+ directed: directed
+ });
+ var totalDistance = 0;
+
+ var nodes = this.nodes();
+ for (var i = 0; i < nodes.length; i++){
+ if (nodes[i].id() != root.id()){
+ var d = dijkstra.distanceTo(nodes[i]);
+
+ if( harmonic ){
+ totalDistance += 1 / d;
+ } else {
+ totalDistance += d;
+ }
+ }
+ }
+
+ return harmonic ? totalDistance : 1 / totalDistance;
+ } // closenessCentrality
+
+}); // elesfn
+
+// nice, short mathemathical alias
+elesfn.cc = elesfn.closenessCentrality;
+elesfn.ccn = elesfn.closenessCentralityNormalised = elesfn.closenessCentralityNormalized;
+
+module.exports = elesfn;
+
+},{"../../is":77}],7:[function(_dereq_,module,exports){
+'use strict';
+
+var is = _dereq_('../../is');
+var util = _dereq_('../../util');
+
+var elesfn = ({
+
+ degreeCentralityNormalized: function (options) {
+ options = options || {};
+
+ var cy = this.cy();
+
+ // directed - optional
+ if (options.directed != null) {
+ var directed = options.directed;
+ } else {
+ var directed = false;
+ }
+
+ var nodes = this.nodes();
+ var numNodes = nodes.length;
+
+ if (!directed) {
+ var degrees = {};
+ var maxDegree = 0;
+
+ for (var i = 0; i < numNodes; i++) {
+ var node = nodes[i];
+ // add current node to the current options object and call degreeCentrality
+ var currDegree = this.degreeCentrality(util.extend({}, options, {root: node}));
+ if (maxDegree < currDegree.degree)
+ maxDegree = currDegree.degree;
+
+ degrees[node.id()] = currDegree.degree;
+ }
+
+ return {
+ degree: function (node) {
+ if (is.string(node)) {
+ // from is a selector string
+ var node = (cy.filter(node)[0]).id();
+ } else {
+ // from is a node
+ var node = node.id();
+ }
+
+ return degrees[node] / maxDegree;
+ }
+ };
+ } else {
+ var indegrees = {};
+ var outdegrees = {};
+ var maxIndegree = 0;
+ var maxOutdegree = 0;
+
+ for (var i = 0; i < numNodes; i++) {
+ var node = nodes[i];
+ // add current node to the current options object and call degreeCentrality
+ var currDegree = this.degreeCentrality(util.extend({}, options, {root: node}));
+
+ if (maxIndegree < currDegree.indegree)
+ maxIndegree = currDegree.indegree;
+
+ if (maxOutdegree < currDegree.outdegree)
+ maxOutdegree = currDegree.outdegree;
+
+ indegrees[node.id()] = currDegree.indegree;
+ outdegrees[node.id()] = currDegree.outdegree;
+ }
+
+ return {
+ indegree: function (node) {
+ if (is.string(node)) {
+ // from is a selector string
+ var node = (cy.filter(node)[0]).id();
+ } else {
+ // from is a node
+ var node = node.id();
+ }
+
+ return indegrees[node] / maxIndegree;
+ },
+ outdegree: function (node) {
+ if (is.string(node)) {
+ // from is a selector string
+ var node = (cy.filter(node)[0]).id();
+ } else {
+ // from is a node
+ var node = node.id();
+ }
+
+ return outdegrees[node] / maxOutdegree;
+ }
+
+ };
+ }
+
+ }, // degreeCentralityNormalized
+
+ // Implemented from the algorithm in Opsahl's paper
+ // "Node centrality in weighted networks: Generalizing degree and shortest paths"
+ // check the heading 2 "Degree"
+ degreeCentrality: function (options) {
+ options = options || {};
+
+ var callingEles = this;
+
+ // root - mandatory!
+ if (options != null && options.root != null) {
+ var root = is.string(options.root) ? this.filter(options.root)[0] : options.root[0];
+ } else {
+ return undefined;
+ }
+
+ // weight - optional
+ if (options.weight != null && is.fn(options.weight)) {
+ var weightFn = options.weight;
+ } else {
+ // If not specified, assume each edge has equal weight (1)
+ var weightFn = function (e) {
+ return 1;
+ };
+ }
+
+ // directed - optional
+ if (options.directed != null) {
+ var directed = options.directed;
+ } else {
+ var directed = false;
+ }
+
+ // alpha - optional
+ if (options.alpha != null && is.number(options.alpha)) {
+ var alpha = options.alpha;
+ } else {
+ alpha = 0;
+ }
+
+
+ if (!directed) {
+ var connEdges = root.connectedEdges().intersection( callingEles );
+ var k = connEdges.length;
+ var s = 0;
+
+ // Now, sum edge weights
+ for (var i = 0; i < connEdges.length; i++) {
+ var edge = connEdges[i];
+ s += weightFn.apply(edge, [edge]);
+ }
+
+ return {
+ degree: Math.pow(k, 1 - alpha) * Math.pow(s, alpha)
+ };
+ } else {
+ var incoming = root.connectedEdges('edge[target = "' + root.id() + '"]').intersection( callingEles );
+ var outgoing = root.connectedEdges('edge[source = "' + root.id() + '"]').intersection( callingEles );
+ var k_in = incoming.length;
+ var k_out = outgoing.length;
+ var s_in = 0;
+ var s_out = 0;
+
+ // Now, sum incoming edge weights
+ for (var i = 0; i < incoming.length; i++) {
+ var edge = incoming[i];
+ s_in += weightFn.apply(edge, [edge]);
+ }
+
+ // Now, sum outgoing edge weights
+ for (var i = 0; i < outgoing.length; i++) {
+ var edge = outgoing[i];
+ s_out += weightFn.apply(edge, [edge]);
+ }
+
+ return {
+ indegree: Math.pow(k_in, 1 - alpha) * Math.pow(s_in, alpha),
+ outdegree: Math.pow(k_out, 1 - alpha) * Math.pow(s_out, alpha)
+ };
+ }
+ } // degreeCentrality
+
+}); // elesfn
+
+// nice, short mathemathical alias
+elesfn.dc = elesfn.degreeCentrality;
+elesfn.dcn = elesfn.degreeCentralityNormalised = elesfn.degreeCentralityNormalized;
+
+module.exports = elesfn;
+
+},{"../../is":77,"../../util":94}],8:[function(_dereq_,module,exports){
+'use strict';
+
+var is = _dereq_('../../is');
+
+var elesfn = ({
+
+ // Implemented from pseudocode from wikipedia
+ floydWarshall: function(options) {
+ options = options || {};
+
+ var cy = this.cy();
+
+ // Weight function - optional
+ if (options.weight != null && is.fn(options.weight)) {
+ var weightFn = options.weight;
+ } else {
+ // If not specified, assume each edge has equal weight (1)
+ var weightFn = function(e) {return 1;};
+ }
+
+ // directed - optional
+ if (options.directed != null) {
+ var directed = options.directed;
+ } else {
+ var directed = false;
+ }
+
+ var edges = this.edges().stdFilter(function(e){ return !e.isLoop(); });
+ var nodes = this.nodes();
+ var numNodes = nodes.length;
+
+ // mapping: node id -> position in nodes array
+ var id2position = {};
+ for (var i = 0; i < numNodes; i++) {
+ id2position[nodes[i].id()] = i;
+ }
+
+ // Initialize distance matrix
+ var dist = [];
+ for (var i = 0; i < numNodes; i++) {
+ var newRow = new Array(numNodes);
+ for (var j = 0; j < numNodes; j++) {
+ if (i == j) {
+ newRow[j] = 0;
+ } else {
+ newRow[j] = Infinity;
+ }
+ }
+ dist.push(newRow);
+ }
+
+ // Initialize matrix used for path reconstruction
+ // Initialize distance matrix
+ var next = [];
+ var edgeNext = [];
+
+ var initMatrix = function(next){
+ for (var i = 0; i < numNodes; i++) {
+ var newRow = new Array(numNodes);
+ for (var j = 0; j < numNodes; j++) {
+ newRow[j] = undefined;
+ }
+ next.push(newRow);
+ }
+ };
+
+ initMatrix(next);
+ initMatrix(edgeNext);
+
+ // Process edges
+ for (var i = 0; i < edges.length ; i++) {
+ var sourceIndex = id2position[edges[i].source().id()];
+ var targetIndex = id2position[edges[i].target().id()];
+ var weight = weightFn.apply(edges[i], [edges[i]]);
+
+ // Check if already process another edge between same 2 nodes
+ if (dist[sourceIndex][targetIndex] > weight) {
+ dist[sourceIndex][targetIndex] = weight;
+ next[sourceIndex][targetIndex] = targetIndex;
+ edgeNext[sourceIndex][targetIndex] = edges[i];
+ }
+ }
+
+ // If undirected graph, process 'reversed' edges
+ if (!directed) {
+ for (var i = 0; i < edges.length ; i++) {
+ var sourceIndex = id2position[edges[i].target().id()];
+ var targetIndex = id2position[edges[i].source().id()];
+ var weight = weightFn.apply(edges[i], [edges[i]]);
+
+ // Check if already process another edge between same 2 nodes
+ if (dist[sourceIndex][targetIndex] > weight) {
+ dist[sourceIndex][targetIndex] = weight;
+ next[sourceIndex][targetIndex] = targetIndex;
+ edgeNext[sourceIndex][targetIndex] = edges[i];
+ }
+ }
+ }
+
+ // Main loop
+ for (var k = 0; k < numNodes; k++) {
+ for (var i = 0; i < numNodes; i++) {
+ for (var j = 0; j < numNodes; j++) {
+ if (dist[i][k] + dist[k][j] < dist[i][j]) {
+ dist[i][j] = dist[i][k] + dist[k][j];
+ next[i][j] = next[i][k];
+ }
+ }
+ }
+ }
+
+ // Build result object
+ var position2id = [];
+ for (var i = 0; i < numNodes; i++) {
+ position2id.push(nodes[i].id());
+ }
+
+ var res = {
+ distance: function(from, to) {
+ if (is.string(from)) {
+ // from is a selector string
+ var fromId = (cy.filter(from)[0]).id();
+ } else {
+ // from is a node
+ var fromId = from.id();
+ }
+
+ if (is.string(to)) {
+ // to is a selector string
+ var toId = (cy.filter(to)[0]).id();
+ } else {
+ // to is a node
+ var toId = to.id();
+ }
+
+ return dist[id2position[fromId]][id2position[toId]];
+ },
+
+ path: function(from, to) {
+ var reconstructPathAux = function(from, to, next, position2id, edgeNext) {
+ if (from === to) {
+ return cy.getElementById( position2id[from] );
+ }
+ if (next[from][to] === undefined) {
+ return undefined;
+ }
+
+ var path = [ cy.getElementById(position2id[from]) ];
+ var prev = from;
+ while (from !== to) {
+ prev = from;
+ from = next[from][to];
+
+ var edge = edgeNext[prev][from];
+ path.push( edge );
+
+ path.push( cy.getElementById(position2id[from]) );
+ }
+ return path;
+ };
+
+ if (is.string(from)) {
+ // from is a selector string
+ var fromId = (cy.filter(from)[0]).id();
+ } else {
+ // from is a node
+ var fromId = from.id();
+ }
+
+ if (is.string(to)) {
+ // to is a selector string
+ var toId = (cy.filter(to)[0]).id();
+ } else {
+ // to is a node
+ var toId = to.id();
+ }
+
+ var pathArr = reconstructPathAux(id2position[fromId],
+ id2position[toId],
+ next,
+ position2id,
+ edgeNext);
+
+ return cy.collection( pathArr );
+ },
+ };
+
+ return res;
+
+ } // floydWarshall
+
+}); // elesfn
+
+module.exports = elesfn;
+
+},{"../../is":77}],9:[function(_dereq_,module,exports){
+'use strict';
+
+var util = _dereq_('../../util');
+
+var elesfn = {};
+
+[
+ _dereq_('./bfs-dfs'),
+ _dereq_('./a-star'),
+ _dereq_('./floyd-warshall'),
+ _dereq_('./bellman-ford'),
+ _dereq_('./kerger-stein'),
+ _dereq_('./page-rank'),
+ _dereq_('./degree-centrality'),
+ _dereq_('./closeness-centrality'),
+ _dereq_('./betweenness-centrality')
+].forEach(function( props ){
+ util.extend( elesfn, props );
+});
+
+module.exports = elesfn;
+
+},{"../../util":94,"./a-star":2,"./bellman-ford":3,"./betweenness-centrality":4,"./bfs-dfs":5,"./closeness-centrality":6,"./degree-centrality":7,"./floyd-warshall":8,"./kerger-stein":10,"./page-rank":11}],10:[function(_dereq_,module,exports){
+'use strict';
+
+var util = _dereq_('../../util');
+
+var elesfn = ({
+
+ // Computes the minimum cut of an undirected graph
+ // Returns the correct answer with high probability
+ kargerStein: function(options) {
+ var eles = this;
+
+ options = options || {};
+
+ // Function which colapses 2 (meta) nodes into one
+ // Updates the remaining edge lists
+ // Receives as a paramater the edge which causes the collapse
+ var colapse = function(edgeIndex, nodeMap, remainingEdges) {
+ var edgeInfo = remainingEdges[edgeIndex];
+ var sourceIn = edgeInfo[1];
+ var targetIn = edgeInfo[2];
+ var partition1 = nodeMap[sourceIn];
+ var partition2 = nodeMap[targetIn];
+
+ // Delete all edges between partition1 and partition2
+ var newEdges = remainingEdges.filter(function(edge) {
+ if (nodeMap[edge[1]] === partition1 && nodeMap[edge[2]] === partition2) {
+ return false;
+ }
+ if (nodeMap[edge[1]] === partition2 && nodeMap[edge[2]] === partition1) {
+ return false;
+ }
+ return true;
+ });
+
+ // All edges pointing to partition2 should now point to partition1
+ for (var i = 0; i < newEdges.length; i++) {
+ var edge = newEdges[i];
+ if (edge[1] === partition2) { // Check source
+ newEdges[i] = edge.slice(0);
+ newEdges[i][1] = partition1;
+ } else if (edge[2] === partition2) { // Check target
+ newEdges[i] = edge.slice(0);
+ newEdges[i][2] = partition1;
+ }
+ }
+
+ // Move all nodes from partition2 to partition1
+ for (var i = 0; i < nodeMap.length; i++) {
+ if (nodeMap[i] === partition2) {
+ nodeMap[i] = partition1;
+ }
+ }
+
+ return newEdges;
+ };
+
+
+ // Contracts a graph until we reach a certain number of meta nodes
+ var contractUntil = function(metaNodeMap,
+ remainingEdges,
+ size,
+ sizeLimit) {
+ // Stop condition
+ if (size <= sizeLimit) {
+ return remainingEdges;
+ }
+
+ // Choose an edge randomly
+ var edgeIndex = Math.floor((Math.random() * remainingEdges.length));
+
+ // Colapse graph based on edge
+ var newEdges = colapse(edgeIndex, metaNodeMap, remainingEdges);
+
+ return contractUntil(metaNodeMap,
+ newEdges,
+ size - 1,
+ sizeLimit);
+ };
+
+ var cy = this._private.cy;
+ var edges = this.edges().stdFilter(function(e){ return !e.isLoop(); });
+ var nodes = this.nodes();
+ var numNodes = nodes.length;
+ var numEdges = edges.length;
+ var numIter = Math.ceil(Math.pow(Math.log(numNodes) / Math.LN2, 2));
+ var stopSize = Math.floor(numNodes / Math.sqrt(2));
+
+ if (numNodes < 2) {
+ util.error("At least 2 nodes are required for Karger-Stein algorithm");
+ return undefined;
+ }
+
+ // Create numerical identifiers for each node
+ // mapping: node id -> position in nodes array
+ // for reverse mapping, simply use nodes array
+ var id2position = {};
+ for (var i = 0; i < numNodes; i++) {
+ id2position[nodes[i].id()] = i;
+ }
+
+ // Now store edge destination as indexes
+ // Format for each edge (edge index, source node index, target node index)
+ var edgeIndexes = [];
+ for (var i = 0; i < numEdges; i++) {
+ var e = edges[i];
+ edgeIndexes.push([i, id2position[e.source().id()], id2position[e.target().id()]]);
+ }
+
+ // We will store the best cut found here
+ var minCutSize = Infinity;
+ var minCut;
+
+ // Initial meta node partition
+ var originalMetaNode = [];
+ for (var i = 0; i < numNodes; i++) {
+ originalMetaNode.push(i);
+ }
+
+ // Main loop
+ for (var iter = 0; iter <= numIter; iter++) {
+ // Create new meta node partition
+ var metaNodeMap = originalMetaNode.slice(0);
+
+ // Contract until stop point (stopSize nodes)
+ var edgesState = contractUntil(metaNodeMap, edgeIndexes, numNodes, stopSize);
+
+ // Create a copy of the colapsed nodes state
+ var metaNodeMap2 = metaNodeMap.slice(0);
+
+ // Run 2 iterations starting in the stop state
+ var res1 = contractUntil(metaNodeMap, edgesState, stopSize, 2);
+ var res2 = contractUntil(metaNodeMap2, edgesState, stopSize, 2);
+
+ // Is any of the 2 results the best cut so far?
+ if (res1.length <= res2.length && res1.length < minCutSize) {
+ minCutSize = res1.length;
+ minCut = [res1, metaNodeMap];
+ } else if (res2.length <= res1.length && res2.length < minCutSize) {
+ minCutSize = res2.length;
+ minCut = [res2, metaNodeMap2];
+ }
+ } // end of main loop
+
+
+ // Construct result
+ var resEdges = (minCut[0]).map(function(e){ return edges[e[0]]; });
+ var partition1 = [];
+ var partition2 = [];
+
+ // traverse metaNodeMap for best cut
+ var witnessNodePartition = minCut[1][0];
+ for (var i = 0; i < minCut[1].length; i++) {
+ var partitionId = minCut[1][i];
+ if (partitionId === witnessNodePartition) {
+ partition1.push(nodes[i]);
+ } else {
+ partition2.push(nodes[i]);
+ }
+ }
+
+ var ret = {
+ cut: eles.spawn(cy, resEdges),
+ partition1: eles.spawn(partition1),
+ partition2: eles.spawn(partition2)
+ };
+
+ return ret;
+ }
+}); // elesfn
+
+
+module.exports = elesfn;
+
+},{"../../util":94}],11:[function(_dereq_,module,exports){
+'use strict';
+
+var is = _dereq_('../../is');
+
+var elesfn = ({
+
+ pageRank: function(options) {
+ options = options || {};
+
+ var normalizeVector = function(vector) {
+ var length = vector.length;
+
+ // First, get sum of all elements
+ var total = 0;
+ for (var i = 0; i < length; i++) {
+ total += vector[i];
+ }
+
+ // Now, divide each by the sum of all elements
+ for (var i = 0; i < length; i++) {
+ vector[i] = vector[i] / total;
+ }
+ };
+
+ // dampingFactor - optional
+ if (options != null &&
+ options.dampingFactor != null) {
+ var dampingFactor = options.dampingFactor;
+ } else {
+ var dampingFactor = 0.8; // Default damping factor
+ }
+
+ // desired precision - optional
+ if (options != null &&
+ options.precision != null) {
+ var epsilon = options.precision;
+ } else {
+ var epsilon = 0.000001; // Default precision
+ }
+
+ // Max number of iterations - optional
+ if (options != null &&
+ options.iterations != null) {
+ var numIter = options.iterations;
+ } else {
+ var numIter = 200; // Default number of iterations
+ }
+
+ // Weight function - optional
+ if (options != null &&
+ options.weight != null &&
+ is.fn(options.weight)) {
+ var weightFn = options.weight;
+ } else {
+ // If not specified, assume each edge has equal weight (1)
+ var weightFn = function(e) {return 1;};
+ }
+
+ var cy = this._private.cy;
+ var edges = this.edges().stdFilter(function(e){ return !e.isLoop(); });
+ var nodes = this.nodes();
+ var numNodes = nodes.length;
+ var numEdges = edges.length;
+
+ // Create numerical identifiers for each node
+ // mapping: node id -> position in nodes array
+ // for reverse mapping, simply use nodes array
+ var id2position = {};
+ for (var i = 0; i < numNodes; i++) {
+ id2position[nodes[i].id()] = i;
+ }
+
+ // Construct transposed adjacency matrix
+ // First lets have a zeroed matrix of the right size
+ // We'll also keep track of the sum of each column
+ var matrix = [];
+ var columnSum = [];
+ var additionalProb = (1 - dampingFactor) / numNodes;
+
+ // Create null matric
+ for (var i = 0; i < numNodes; i++) {
+ var newRow = [];
+ for (var j = 0; j < numNodes; j++) {
+ newRow.push(0.0);
+ }
+ matrix.push(newRow);
+ columnSum.push(0.0);
+ }
+
+ // Now, process edges
+ for (var i = 0; i < numEdges; i++) {
+ var edge = edges[i];
+ var s = id2position[edge.source().id()];
+ var t = id2position[edge.target().id()];
+ var w = weightFn.apply(edge, [edge]);
+
+ // Update matrix
+ matrix[t][s] += w;
+
+ // Update column sum
+ columnSum[s] += w;
+ }
+
+ // Add additional probability based on damping factor
+ // Also, take into account columns that have sum = 0
+ var p = 1.0 / numNodes + additionalProb; // Shorthand
+ // Traverse matrix, column by column
+ for (var j = 0; j < numNodes; j++) {
+ if (columnSum[j] === 0) {
+ // No 'links' out from node jth, assume equal probability for each possible node
+ for (var i = 0; i < numNodes; i++) {
+ matrix[i][j] = p;
+ }
+ } else {
+ // Node jth has outgoing link, compute normalized probabilities
+ for (var i = 0; i < numNodes; i++) {
+ matrix[i][j] = matrix[i][j] / columnSum[j] + additionalProb;
+ }
+ }
+ }
+
+ // Compute dominant eigenvector using power method
+ var eigenvector = [];
+ var nullVector = [];
+ var previous;
+
+ // Start with a vector of all 1's
+ // Also, initialize a null vector which will be used as shorthand
+ for (var i = 0; i < numNodes; i++) {
+ eigenvector.push(1.0);
+ nullVector.push(0.0);
+ }
+
+ for (var iter = 0; iter < numIter; iter++) {
+ // New array with all 0's
+ var temp = nullVector.slice(0);
+
+ // Multiply matrix with previous result
+ for (var i = 0; i < numNodes; i++) {
+ for (var j = 0; j < numNodes; j++) {
+ temp[i] += matrix[i][j] * eigenvector[j];
+ }
+ }
+
+ normalizeVector(temp);
+ previous = eigenvector;
+ eigenvector = temp;
+
+ var diff = 0;
+ // Compute difference (squared module) of both vectors
+ for (var i = 0; i < numNodes; i++) {
+ diff += Math.pow(previous[i] - eigenvector[i], 2);
+ }
+
+ // If difference is less than the desired threshold, stop iterating
+ if (diff < epsilon) {
+ break;
+ }
+ }
+
+ // Construct result
+ var res = {
+ rank : function(node) {
+ if (is.string(node)) {
+ // is a selector string
+ var nodeId = (cy.filter(node)[0]).id();
+ } else {
+ // is a node object
+ var nodeId = node.id();
+ }
+ return eigenvector[id2position[nodeId]];
+ }
+ };
+
+
+ return res;
+ } // pageRank
+
+}); // elesfn
+
+module.exports = elesfn;
+
+},{"../../is":77}],12:[function(_dereq_,module,exports){
+'use strict';
+
+var define = _dereq_('../define');
+
+var elesfn = ({
+ animate: define.animate(),
+ animation: define.animation(),
+ animated: define.animated(),
+ clearQueue: define.clearQueue(),
+ delay: define.delay(),
+ delayAnimation: define.delayAnimation(),
+ stop: define.stop(),
+});
+
+module.exports = elesfn;
+
+},{"../define":41}],13:[function(_dereq_,module,exports){
+'use strict';
+
+var util = _dereq_('../util');
+
+var elesfn = ({
+ classes: function( classes ){
+ classes = classes.match(/\S+/g) || [];
+ var self = this;
+ var changed = [];
+ var classesMap = {};
+
+ // fill in classes map
+ for( var i = 0; i < classes.length; i++ ){
+ var cls = classes[i];
+
+ classesMap[ cls ] = true;
+ }
+
+ // check and update each ele
+ for( var j = 0; j < self.length; j++ ){
+ var ele = self[j];
+ var _p = ele._private;
+ var eleClasses = _p.classes;
+ var changedEle = false;
+
+ // check if ele has all of the passed classes
+ for( var i = 0; i < classes.length; i++ ){
+ var cls = classes[i];
+ var eleHasClass = eleClasses[ cls ];
+
+ if( !eleHasClass ){
+ changedEle = true;
+ break;
+ }
+ }
+
+ // check if ele has classes outside of those passed
+ if( !changedEle ){ for( var eleCls in eleClasses ){
+ var eleHasClass = eleClasses[ eleCls ];
+ var specdClass = classesMap[ eleCls ]; // i.e. this class is passed to the function
+
+ if( eleHasClass && !specdClass ){
+ changedEle = true;
+ break;
+ }
+ } }
+
+ if( changedEle ){
+ _p.classes = util.copy( classesMap );
+
+ changed.push( ele );
+ }
+ }
+
+ // trigger update style on those eles that had class changes
+ if( changed.length > 0 ){
+ this.spawn(changed)
+ .updateStyle()
+ .trigger('class')
+ ;
+ }
+
+ return self;
+ },
+
+ addClass: function( classes ){
+ return this.toggleClass( classes, true );
+ },
+
+ hasClass: function( className ){
+ var ele = this[0];
+ return ( ele != null && ele._private.classes[className] ) ? true : false;
+ },
+
+ toggleClass: function( classesStr, toggle ){
+ var classes = classesStr.match(/\S+/g) || [];
+ var self = this;
+ var changed = []; // eles who had classes changed
+
+ for( var i = 0, il = self.length; i < il; i++ ){
+ var ele = self[i];
+ var changedEle = false;
+
+ for( var j = 0; j < classes.length; j++ ){
+ var cls = classes[j];
+ var eleClasses = ele._private.classes;
+ var hasClass = eleClasses[cls];
+ var shouldAdd = toggle || (toggle === undefined && !hasClass);
+
+ if( shouldAdd ){
+ eleClasses[cls] = true;
+
+ if( !hasClass && !changedEle ){
+ changed.push(ele);
+ changedEle = true;
+ }
+ } else { // then remove
+ eleClasses[cls] = false;
+
+ if( hasClass && !changedEle ){
+ changed.push(ele);
+ changedEle = true;
+ }
+ }
+
+ } // for j classes
+ } // for i eles
+
+ // trigger update style on those eles that had class changes
+ if( changed.length > 0 ){
+ this.spawn(changed)
+ .updateStyle()
+ .trigger('class')
+ ;
+ }
+
+ return self;
+ },
+
+ removeClass: function( classes ){
+ return this.toggleClass( classes, false );
+ },
+
+ flashClass: function( classes, duration ){
+ var self = this;
+
+ if( duration == null ){
+ duration = 250;
+ } else if( duration === 0 ){
+ return self; // nothing to do really
+ }
+
+ self.addClass( classes );
+ setTimeout(function(){
+ self.removeClass( classes );
+ }, duration);
+
+ return self;
+ }
+});
+
+module.exports = elesfn;
+
+},{"../util":94}],14:[function(_dereq_,module,exports){
+'use strict';
+
+var elesfn = ({
+ allAre: function( selector ){
+ return this.filter(selector).length === this.length;
+ },
+
+ is: function( selector ){
+ return this.filter(selector).length > 0;
+ },
+
+ some: function( fn, thisArg ){
+ for( var i = 0; i < this.length; i++ ){
+ var ret = !thisArg ? fn( this[i], i, this ) : fn.apply( thisArg, [ this[i], i, this ] );
+
+ if( ret ){
+ return true;
+ }
+ }
+
+ return false;
+ },
+
+ every: function( fn, thisArg ){
+ for( var i = 0; i < this.length; i++ ){
+ var ret = !thisArg ? fn( this[i], i, this ) : fn.apply( thisArg, [ this[i], i, this ] );
+
+ if( !ret ){
+ return false;
+ }
+ }
+
+ return true;
+ },
+
+ same: function( collection ){
+ collection = this.cy().collection( collection );
+
+ // cheap extra check
+ if( this.length !== collection.length ){
+ return false;
+ }
+
+ return this.intersect( collection ).length === this.length;
+ },
+
+ anySame: function( collection ){
+ collection = this.cy().collection( collection );
+
+ return this.intersect( collection ).length > 0;
+ },
+
+ allAreNeighbors: function( collection ){
+ collection = this.cy().collection( collection );
+
+ return this.neighborhood().intersect( collection ).length === collection.length;
+ }
+});
+
+elesfn.allAreNeighbours = elesfn.allAreNeighbors;
+
+module.exports = elesfn;
+
+},{}],15:[function(_dereq_,module,exports){
+'use strict';
+
+var elesfn = ({
+ parent: function( selector ){
+ var parents = [];
+ var cy = this._private.cy;
+
+ for( var i = 0; i < this.length; i++ ){
+ var ele = this[i];
+ var parent = cy.getElementById( ele._private.data.parent );
+
+ if( parent.size() > 0 ){
+ parents.push( parent );
+ }
+ }
+
+ return this.spawn( parents, { unique: true } ).filter( selector );
+ },
+
+ parents: function( selector ){
+ var parents = [];
+
+ var eles = this.parent();
+ while( eles.nonempty() ){
+ for( var i = 0; i < eles.length; i++ ){
+ var ele = eles[i];
+ parents.push( ele );
+ }
+
+ eles = eles.parent();
+ }
+
+ return this.spawn( parents, { unique: true } ).filter( selector );
+ },
+
+ commonAncestors: function( selector ){
+ var ancestors;
+
+ for( var i = 0; i < this.length; i++ ){
+ var ele = this[i];
+ var parents = ele.parents();
+
+ ancestors = ancestors || parents;
+
+ ancestors = ancestors.intersect( parents ); // current list must be common with current ele parents set
+ }
+
+ return ancestors.filter( selector );
+ },
+
+ orphans: function( selector ){
+ return this.stdFilter(function( ele ){
+ return ele.isNode() && ele.parent().empty();
+ }).filter( selector );
+ },
+
+ nonorphans: function( selector ){
+ return this.stdFilter(function( ele ){
+ return ele.isNode() && ele.parent().nonempty();
+ }).filter( selector );
+ },
+
+ children: function( selector ){
+ var children = [];
+
+ for( var i = 0; i < this.length; i++ ){
+ var ele = this[i];
+ children = children.concat( ele._private.children );
+ }
+
+ return this.spawn( children, { unique: true } ).filter( selector );
+ },
+
+ siblings: function( selector ){
+ return this.parent().children().not( this ).filter( selector );
+ },
+
+ isParent: function(){
+ var ele = this[0];
+
+ if( ele ){
+ return ele._private.children.length !== 0;
+ }
+ },
+
+ isChild: function(){
+ var ele = this[0];
+
+ if( ele ){
+ return ele._private.data.parent !== undefined && ele.parent().length !== 0;
+ }
+ },
+
+ descendants: function( selector ){
+ var elements = [];
+
+ function add( eles ){
+ for( var i = 0; i < eles.length; i++ ){
+ var ele = eles[i];
+
+ elements.push( ele );
+
+ if( ele.children().nonempty() ){
+ add( ele.children() );
+ }
+ }
+ }
+
+ add( this.children() );
+
+ return this.spawn( elements, { unique: true } ).filter( selector );
+ }
+});
+
+// aliases
+elesfn.ancestors = elesfn.parents;
+
+module.exports = elesfn;
+
+},{}],16:[function(_dereq_,module,exports){
+'use strict';
+
+var define = _dereq_('../define');
+var fn, elesfn;
+
+fn = elesfn = ({
+
+ data: define.data({
+ field: 'data',
+ bindingEvent: 'data',
+ allowBinding: true,
+ allowSetting: true,
+ settingEvent: 'data',
+ settingTriggersEvent: true,
+ triggerFnName: 'trigger',
+ allowGetting: true,
+ immutableKeys: {
+ 'id': true,
+ 'source': true,
+ 'target': true,
+ 'parent': true
+ },
+ updateStyle: true
+ }),
+
+ removeData: define.removeData({
+ field: 'data',
+ event: 'data',
+ triggerFnName: 'trigger',
+ triggerEvent: true,
+ immutableKeys: {
+ 'id': true,
+ 'source': true,
+ 'target': true,
+ 'parent': true
+ },
+ updateStyle: true
+ }),
+
+ scratch: define.data({
+ field: 'scratch',
+ bindingEvent: 'scratch',
+ allowBinding: true,
+ allowSetting: true,
+ settingEvent: 'scratch',
+ settingTriggersEvent: true,
+ triggerFnName: 'trigger',
+ allowGetting: true,
+ updateStyle: true
+ }),
+
+ removeScratch: define.removeData({
+ field: 'scratch',
+ event: 'scratch',
+ triggerFnName: 'trigger',
+ triggerEvent: true,
+ updateStyle: true
+ }),
+
+ rscratch: define.data({
+ field: 'rscratch',
+ allowBinding: false,
+ allowSetting: true,
+ settingTriggersEvent: false,
+ allowGetting: true
+ }),
+
+ removeRscratch: define.removeData({
+ field: 'rscratch',
+ triggerEvent: false
+ }),
+
+ id: function(){
+ var ele = this[0];
+
+ if( ele ){
+ return ele._private.data.id;
+ }
+ }
+
+});
+
+// aliases
+fn.attr = fn.data;
+fn.removeAttr = fn.removeData;
+
+module.exports = elesfn;
+
+},{"../define":41}],17:[function(_dereq_,module,exports){
+'use strict';
+
+var util = _dereq_('../util');
+
+var elesfn = {};
+
+function defineDegreeFunction(callback){
+ return function( includeLoops ){
+ var self = this;
+
+ if( includeLoops === undefined ){
+ includeLoops = true;
+ }
+
+ if( self.length === 0 ){ return; }
+
+ if( self.isNode() && !self.removed() ){
+ var degree = 0;
+ var node = self[0];
+ var connectedEdges = node._private.edges;
+
+ for( var i = 0; i < connectedEdges.length; i++ ){
+ var edge = connectedEdges[i];
+
+ if( !includeLoops && edge.isLoop() ){
+ continue;
+ }
+
+ degree += callback( node, edge );
+ }
+
+ return degree;
+ } else {
+ return;
+ }
+ };
+}
+
+util.extend(elesfn, {
+ degree: defineDegreeFunction(function(node, edge){
+ if( edge.source().same( edge.target() ) ){
+ return 2;
+ } else {
+ return 1;
+ }
+ }),
+
+ indegree: defineDegreeFunction(function(node, edge){
+ if( edge.target().same(node) ){
+ return 1;
+ } else {
+ return 0;
+ }
+ }),
+
+ outdegree: defineDegreeFunction(function(node, edge){
+ if( edge.source().same(node) ){
+ return 1;
+ } else {
+ return 0;
+ }
+ })
+});
+
+function defineDegreeBoundsFunction(degreeFn, callback){
+ return function( includeLoops ){
+ var ret;
+ var nodes = this.nodes();
+
+ for( var i = 0; i < nodes.length; i++ ){
+ var ele = nodes[i];
+ var degree = ele[degreeFn]( includeLoops );
+ if( degree !== undefined && (ret === undefined || callback(degree, ret)) ){
+ ret = degree;
+ }
+ }
+
+ return ret;
+ };
+}
+
+util.extend(elesfn, {
+ minDegree: defineDegreeBoundsFunction('degree', function(degree, min){
+ return degree < min;
+ }),
+
+ maxDegree: defineDegreeBoundsFunction('degree', function(degree, max){
+ return degree > max;
+ }),
+
+ minIndegree: defineDegreeBoundsFunction('indegree', function(degree, min){
+ return degree < min;
+ }),
+
+ maxIndegree: defineDegreeBoundsFunction('indegree', function(degree, max){
+ return degree > max;
+ }),
+
+ minOutdegree: defineDegreeBoundsFunction('outdegree', function(degree, min){
+ return degree < min;
+ }),
+
+ maxOutdegree: defineDegreeBoundsFunction('outdegree', function(degree, max){
+ return degree > max;
+ })
+});
+
+util.extend(elesfn, {
+ totalDegree: function( includeLoops ){
+ var total = 0;
+ var nodes = this.nodes();
+
+ for( var i = 0; i < nodes.length; i++ ){
+ total += nodes[i].degree( includeLoops );
+ }
+
+ return total;
+ }
+});
+
+module.exports = elesfn;
+
+},{"../util":94}],18:[function(_dereq_,module,exports){
+'use strict';
+
+var define = _dereq_('../define');
+var is = _dereq_('../is');
+var util = _dereq_('../util');
+var fn, elesfn;
+
+fn = elesfn = ({
+
+ position: define.data({
+ field: 'position',
+ bindingEvent: 'position',
+ allowBinding: true,
+ allowSetting: true,
+ settingEvent: 'position',
+ settingTriggersEvent: true,
+ triggerFnName: 'rtrigger',
+ allowGetting: true,
+ validKeys: ['x', 'y'],
+ onSet: function( eles ){
+ var updatedEles = eles.updateCompoundBounds();
+ updatedEles.rtrigger('position');
+ },
+ canSet: function( ele ){
+ return !ele.locked() && !ele.isParent();
+ }
+ }),
+
+ // position but no notification to renderer
+ silentPosition: define.data({
+ field: 'position',
+ bindingEvent: 'position',
+ allowBinding: false,
+ allowSetting: true,
+ settingEvent: 'position',
+ settingTriggersEvent: false,
+ triggerFnName: 'trigger',
+ allowGetting: true,
+ validKeys: ['x', 'y'],
+ onSet: function( eles ){
+ eles.updateCompoundBounds();
+ },
+ canSet: function( ele ){
+ return !ele.locked() && !ele.isParent();
+ }
+ }),
+
+ positions: function( pos, silent ){
+ if( is.plainObject(pos) ){
+ this.position(pos);
+
+ } else if( is.fn(pos) ){
+ var fn = pos;
+
+ for( var i = 0; i < this.length; i++ ){
+ var ele = this[i];
+
+ var pos = fn.apply(ele, [i, ele]);
+
+ if( pos && !ele.locked() && !ele.isParent() ){
+ var elePos = ele._private.position;
+ elePos.x = pos.x;
+ elePos.y = pos.y;
+ }
+ }
+
+ var updatedEles = this.updateCompoundBounds();
+ var toTrigger = updatedEles.length > 0 ? this.add( updatedEles ) : this;
+
+ if( silent ){
+ toTrigger.trigger('position');
+ } else {
+ toTrigger.rtrigger('position');
+ }
+ }
+
+ return this; // chaining
+ },
+
+ silentPositions: function( pos ){
+ return this.positions( pos, true );
+ },
+
+ // get/set the rendered (i.e. on screen) positon of the element
+ renderedPosition: function( dim, val ){
+ var ele = this[0];
+ var cy = this.cy();
+ var zoom = cy.zoom();
+ var pan = cy.pan();
+ var rpos = is.plainObject( dim ) ? dim : undefined;
+ var setting = rpos !== undefined || ( val !== undefined && is.string(dim) );
+
+ if( ele && ele.isNode() ){ // must have an element and must be a node to return position
+ if( setting ){
+ for( var i = 0; i < this.length; i++ ){
+ var ele = this[i];
+
+ if( val !== undefined ){ // set one dimension
+ ele._private.position[dim] = ( val - pan[dim] )/zoom;
+ } else if( rpos !== undefined ){ // set whole position
+ ele._private.position = {
+ x: ( rpos.x - pan.x ) /zoom,
+ y: ( rpos.y - pan.y ) /zoom
+ };
+ }
+ }
+
+ this.rtrigger('position');
+ } else { // getting
+ var pos = ele._private.position;
+ rpos = {
+ x: pos.x * zoom + pan.x,
+ y: pos.y * zoom + pan.y
+ };
+
+ if( dim === undefined ){ // then return the whole rendered position
+ return rpos;
+ } else { // then return the specified dimension
+ return rpos[ dim ];
+ }
+ }
+ } else if( !setting ){
+ return undefined; // for empty collection case
+ }
+
+ return this; // chaining
+ },
+
+ // get/set the position relative to the parent
+ relativePosition: function( dim, val ){
+ var ele = this[0];
+ var cy = this.cy();
+ var ppos = is.plainObject( dim ) ? dim : undefined;
+ var setting = ppos !== undefined || ( val !== undefined && is.string(dim) );
+ var hasCompoundNodes = cy.hasCompoundNodes();
+
+ if( ele && ele.isNode() ){ // must have an element and must be a node to return position
+ if( setting ){
+ for( var i = 0; i < this.length; i++ ){
+ var ele = this[i];
+ var parent = hasCompoundNodes ? ele.parent() : null;
+ var hasParent = parent && parent.length > 0;
+ var relativeToParent = hasParent;
+
+ if( hasParent ){
+ parent = parent[0];
+ }
+
+ var origin = relativeToParent ? parent._private.position : { x: 0, y: 0 };
+
+ if( val !== undefined ){ // set one dimension
+ ele._private.position[dim] = val + origin[dim];
+ } else if( ppos !== undefined ){ // set whole position
+ ele._private.position = {
+ x: ppos.x + origin.x,
+ y: ppos.y + origin.y,
+ };
+ }
+ }
+
+ this.rtrigger('position');
+
+ } else { // getting
+ var pos = ele._private.position;
+ var parent = hasCompoundNodes ? ele.parent() : null;
+ var hasParent = parent && parent.length > 0;
+ var relativeToParent = hasParent;
+
+ if( hasParent ){
+ parent = parent[0];
+ }
+
+ var origin = relativeToParent ? parent._private.position : { x: 0, y: 0 };
+
+ ppos = {
+ x: pos.x - origin.x,
+ y: pos.y - origin.y
+ };
+
+ if( dim === undefined ){ // then return the whole rendered position
+ return ppos;
+ } else { // then return the specified dimension
+ return ppos[ dim ];
+ }
+ }
+ } else if( !setting ){
+ return undefined; // for empty collection case
+ }
+
+ return this; // chaining
+ },
+
+ renderedBoundingBox: function( options ){
+ var bb = this.boundingBox( options );
+ var cy = this.cy();
+ var zoom = cy.zoom();
+ var pan = cy.pan();
+
+ var x1 = bb.x1 * zoom + pan.x;
+ var x2 = bb.x2 * zoom + pan.x;
+ var y1 = bb.y1 * zoom + pan.y;
+ var y2 = bb.y2 * zoom + pan.y;
+
+ return {
+ x1: x1,
+ x2: x2,
+ y1: y1,
+ y2: y2,
+ w: x2 - x1,
+ h: y2 - y1
+ };
+ },
+
+ updateCompoundBounds: function(){
+ var cy = this.cy();
+
+ if( !cy.styleEnabled() || !cy.hasCompoundNodes() ){ return cy.collection(); } // save cycles for non compound graphs or when style disabled
+
+ var updated = [];
+
+ function update( parent ){
+ var children = parent.children();
+ var style = parent._private.style;
+ var includeLabels = style['compound-sizing-wrt-labels'].value === 'include';
+ var bb = children.boundingBox({ includeLabels: includeLabels, includeEdges: true });
+ var padding = {
+ top: style['padding-top'].pfValue,
+ bottom: style['padding-bottom'].pfValue,
+ left: style['padding-left'].pfValue,
+ right: style['padding-right'].pfValue
+ };
+ var pos = parent._private.position;
+ var didUpdate = false;
+
+ if( style['width'].value === 'auto' ){
+ parent._private.autoWidth = bb.w;
+ pos.x = (bb.x1 + bb.x2 - padding.left + padding.right)/2;
+ didUpdate = true;
+ }
+
+ if( style['height'].value === 'auto' ){
+ parent._private.autoHeight = bb.h;
+ pos.y = (bb.y1 + bb.y2 - padding.top + padding.bottom)/2;
+ didUpdate = true;
+ }
+
+ if( didUpdate ){
+ updated.push( parent );
+ }
+ }
+
+ // go up, level by level
+ var eles = this.parent();
+ while( eles.nonempty() ){
+
+ // update each parent node in this level
+ for( var i = 0; i < eles.length; i++ ){
+ var ele = eles[i];
+
+ update( ele );
+ }
+
+ // next level
+ eles = eles.parent();
+ }
+
+ // return changed
+ return this.spawn( updated );
+ },
+
+ // get the bounding box of the elements (in raw model position)
+ boundingBox: function( options ){
+ var eles = this;
+ var cy = eles._private.cy;
+ var cy_p = cy._private;
+ var styleEnabled = cy_p.styleEnabled;
+
+ options = options || util.staticEmptyObject();
+
+ var includeNodes = options.includeNodes === undefined ? true : options.includeNodes;
+ var includeEdges = options.includeEdges === undefined ? true : options.includeEdges;
+ var includeLabels = options.includeLabels === undefined ? true : options.includeLabels;
+
+ // recalculate projections etc
+ if( styleEnabled ){
+ cy_p.renderer.recalculateRenderedStyle( this );
+ }
+
+ var x1 = Infinity;
+ var x2 = -Infinity;
+ var y1 = Infinity;
+ var y2 = -Infinity;
+
+ // find bounds of elements
+ for( var i = 0; i < eles.length; i++ ){
+ var ele = eles[i];
+ var _p = ele._private;
+ var style = _p.style;
+ var display = styleEnabled ? _p.style['display'].value : 'element';
+ var isNode = _p.group === 'nodes';
+ var ex1, ex2, ey1, ey2, x, y;
+ var includedEle = false;
+
+ if( display === 'none' ){ continue; } // then ele doesn't take up space
+
+ if( isNode && includeNodes ){
+ includedEle = true;
+
+ var pos = _p.position;
+ x = pos.x;
+ y = pos.y;
+ var w = ele.outerWidth();
+ var halfW = w/2;
+ var h = ele.outerHeight();
+ var halfH = h/2;
+
+ // handle node dimensions
+ /////////////////////////
+
+ ex1 = x - halfW;
+ ex2 = x + halfW;
+ ey1 = y - halfH;
+ ey2 = y + halfH;
+
+ x1 = ex1 < x1 ? ex1 : x1;
+ x2 = ex2 > x2 ? ex2 : x2;
+ y1 = ey1 < y1 ? ey1 : y1;
+ y2 = ey2 > y2 ? ey2 : y2;
+
+ } else if( ele.isEdge() && includeEdges ){
+ includedEle = true;
+
+ var n1 = _p.source;
+ var n1_p = n1._private;
+ var n1pos = n1_p.position;
+
+ var n2 = _p.target;
+ var n2_p = n2._private;
+ var n2pos = n2_p.position;
+
+
+ // handle edge dimensions (rough box estimate)
+ //////////////////////////////////////////////
+
+ var rstyle = _p.rstyle || {};
+ var w = 0;
+ var wHalf = 0;
+
+ if( styleEnabled ){
+ w = style['width'].pfValue;
+ wHalf = w/2;
+ }
+
+ ex1 = n1pos.x;
+ ex2 = n2pos.x;
+ ey1 = n1pos.y;
+ ey2 = n2pos.y;
+
+ if( ex1 > ex2 ){
+ var temp = ex1;
+ ex1 = ex2;
+ ex2 = temp;
+ }
+
+ if( ey1 > ey2 ){
+ var temp = ey1;
+ ey1 = ey2;
+ ey2 = temp;
+ }
+
+ // take into account edge width
+ ex1 -= wHalf;
+ ex2 += wHalf;
+ ey1 -= wHalf;
+ ey2 += wHalf;
+
+ x1 = ex1 < x1 ? ex1 : x1;
+ x2 = ex2 > x2 ? ex2 : x2;
+ y1 = ey1 < y1 ? ey1 : y1;
+ y2 = ey2 > y2 ? ey2 : y2;
+
+ // handle points along edge (sanity check)
+ //////////////////////////////////////////
+
+ if( styleEnabled ){
+ var pts = rstyle.bezierPts || rstyle.linePts || [];
+
+ for( var j = 0; j < pts.length; j++ ){
+ var pt = pts[j];
+
+ ex1 = pt.x - wHalf;
+ ex2 = pt.x + wHalf;
+ ey1 = pt.y - wHalf;
+ ey2 = pt.y + wHalf;
+
+ x1 = ex1 < x1 ? ex1 : x1;
+ x2 = ex2 > x2 ? ex2 : x2;
+ y1 = ey1 < y1 ? ey1 : y1;
+ y2 = ey2 > y2 ? ey2 : y2;
+ }
+ }
+
+ // precise haystacks (sanity check)
+ ///////////////////////////////////
+
+ if( styleEnabled && style['curve-style'].strValue === 'haystack' ){
+ var hpts = rstyle.haystackPts;
+
+ ex1 = hpts[0].x;
+ ey1 = hpts[0].y;
+ ex2 = hpts[1].x;
+ ey2 = hpts[1].y;
+
+ if( ex1 > ex2 ){
+ var temp = ex1;
+ ex1 = ex2;
+ ex2 = temp;
+ }
+
+ if( ey1 > ey2 ){
+ var temp = ey1;
+ ey1 = ey2;
+ ey2 = temp;
+ }
+
+ x1 = ex1 < x1 ? ex1 : x1;
+ x2 = ex2 > x2 ? ex2 : x2;
+ y1 = ey1 < y1 ? ey1 : y1;
+ y2 = ey2 > y2 ? ey2 : y2;
+ }
+
+ } // edges
+
+
+ // handle label dimensions
+ //////////////////////////
+
+ if( styleEnabled ){
+
+ var _p = ele._private;
+ var style = _p.style;
+ var rstyle = _p.rstyle;
+ var label = style['label'].strValue;
+ var fontSize = style['font-size'];
+ var halign = style['text-halign'];
+ var valign = style['text-valign'];
+ var labelWidth = rstyle.labelWidth;
+ var labelHeight = rstyle.labelHeight;
+ var labelX = rstyle.labelX;
+ var labelY = rstyle.labelY;
+ var isEdge = ele.isEdge();
+ var autorotate = style['edge-text-rotation'].strValue === 'autorotate';
+
+ if( includeLabels && label && fontSize && labelHeight != null && labelWidth != null && labelX != null && labelY != null && halign && valign ){
+ var lh = labelHeight;
+ var lw = labelWidth;
+ var lx1, lx2, ly1, ly2;
+
+ if( isEdge ){
+ lx1 = labelX - lw/2;
+ lx2 = labelX + lw/2;
+ ly1 = labelY - lh/2;
+ ly2 = labelY + lh/2;
+
+ if( autorotate ){
+ var theta = _p.rscratch.labelAngle;
+ var cos = Math.cos( theta );
+ var sin = Math.sin( theta );
+
+ var rotate = function( x, y ){
+ x = x - labelX;
+ y = y - labelY;
+
+ return {
+ x: x*cos - y*sin + labelX,
+ y: x*sin + y*cos + labelY
+ };
+ };
+
+ var px1y1 = rotate( lx1, ly1 );
+ var px1y2 = rotate( lx1, ly2 );
+ var px2y1 = rotate( lx2, ly1 );
+ var px2y2 = rotate( lx2, ly2 );
+
+ lx1 = Math.min( px1y1.x, px1y2.x, px2y1.x, px2y2.x );
+ lx2 = Math.max( px1y1.x, px1y2.x, px2y1.x, px2y2.x );
+ ly1 = Math.min( px1y1.y, px1y2.y, px2y1.y, px2y2.y );
+ ly2 = Math.max( px1y1.y, px1y2.y, px2y1.y, px2y2.y );
+ }
+ } else {
+ switch( halign.value ){
+ case 'left':
+ lx1 = labelX - lw;
+ lx2 = labelX;
+ break;
+
+ case 'center':
+ lx1 = labelX - lw/2;
+ lx2 = labelX + lw/2;
+ break;
+
+ case 'right':
+ lx1 = labelX;
+ lx2 = labelX + lw;
+ break;
+ }
+
+ switch( valign.value ){
+ case 'top':
+ ly1 = labelY - lh;
+ ly2 = labelY;
+ break;
+
+ case 'center':
+ ly1 = labelY - lh/2;
+ ly2 = labelY + lh/2;
+ break;
+
+ case 'bottom':
+ ly1 = labelY;
+ ly2 = labelY + lh;
+ break;
+ }
+ }
+
+ x1 = lx1 < x1 ? lx1 : x1;
+ x2 = lx2 > x2 ? lx2 : x2;
+ y1 = ly1 < y1 ? ly1 : y1;
+ y2 = ly2 > y2 ? ly2 : y2;
+ }
+ } // style enabled for labels
+ } // for
+
+ var noninf = function(x){
+ if( x === Infinity || x === -Infinity ){
+ return 0;
+ }
+
+ return x;
+ };
+
+ x1 = noninf(x1);
+ x2 = noninf(x2);
+ y1 = noninf(y1);
+ y2 = noninf(y2);
+
+ return {
+ x1: x1,
+ x2: x2,
+ y1: y1,
+ y2: y2,
+ w: x2 - x1,
+ h: y2 - y1
+ };
+ }
+});
+
+var defineDimFns = function( opts ){
+ opts.uppercaseName = util.capitalize( opts.name );
+ opts.autoName = 'auto' + opts.uppercaseName;
+ opts.labelName = 'label' + opts.uppercaseName;
+ opts.outerName = 'outer' + opts.uppercaseName;
+ opts.uppercaseOuterName = util.capitalize( opts.outerName );
+
+ fn[ opts.name ] = function dimImpl(){
+ var ele = this[0];
+ var _p = ele._private;
+ var cy = _p.cy;
+ var styleEnabled = cy._private.styleEnabled;
+
+ if( ele ){
+ if( styleEnabled ){
+ var d = _p.style[ opts.name ];
+
+ switch( d.strValue ){
+ case 'auto':
+ return _p[ opts.autoName ] || 0;
+ case 'label':
+ return _p.rstyle[ opts.labelName ] || 0;
+ default:
+ return d.pfValue;
+ }
+ } else {
+ return 1;
+ }
+ }
+ };
+
+ fn[ 'outer' + opts.uppercaseName ] = function outerDimImpl(){
+ var ele = this[0];
+ var _p = ele._private;
+ var cy = _p.cy;
+ var styleEnabled = cy._private.styleEnabled;
+
+ if( ele ){
+ if( styleEnabled ){
+ var style = _p.style;
+ var dim = ele[ opts.name ]();
+ var border = style['border-width'].pfValue;
+ var padding = style[ opts.paddings[0] ].pfValue + style[ opts.paddings[1] ].pfValue;
+
+ return dim + border + padding;
+ } else {
+ return 1;
+ }
+ }
+ };
+
+ fn[ 'rendered' + opts.uppercaseName ] = function renderedDimImpl(){
+ var ele = this[0];
+
+ if( ele ){
+ var d = ele[ opts.name ]();
+ return d * this.cy().zoom();
+ }
+ };
+
+ fn[ 'rendered' + opts.uppercaseOuterName ] = function renderedOuterDimImpl(){
+ var ele = this[0];
+
+ if( ele ){
+ var od = ele[ opts.outerName ]();
+ return od * this.cy().zoom();
+ }
+ };
+};
+
+defineDimFns({
+ name: 'width',
+ paddings: ['padding-left', 'padding-right']
+});
+
+defineDimFns({
+ name: 'height',
+ paddings: ['padding-top', 'padding-bottom']
+});
+
+// aliases
+fn.modelPosition = fn.point = fn.position;
+fn.modelPositions = fn.points = fn.positions;
+fn.renderedPoint = fn.renderedPosition;
+fn.relativePoint = fn.relativePosition;
+fn.boundingbox = fn.boundingBox;
+fn.renderedBoundingbox = fn.renderedBoundingBox;
+
+module.exports = elesfn;
+
+},{"../define":41,"../is":77,"../util":94}],19:[function(_dereq_,module,exports){
+'use strict';
+
+var util = _dereq_('../util');
+var is = _dereq_('../is');
+
+// represents a node or an edge
+var Element = function(cy, params, restore){
+ if( !(this instanceof Element) ){
+ return new Element(cy, params, restore);
+ }
+
+ var self = this;
+ restore = (restore === undefined || restore ? true : false);
+
+ if( cy === undefined || params === undefined || !is.core(cy) ){
+ util.error('An element must have a core reference and parameters set');
+ return;
+ }
+
+ var group = params.group;
+
+ // try to automatically infer the group if unspecified
+ if( group == null ){
+ if( params.data.source != null && params.data.target != null ){
+ group = 'edges';
+ } else {
+ group = 'nodes';
+ }
+ }
+
+ // validate group
+ if( group !== 'nodes' && group !== 'edges' ){
+ util.error('An element must be of type `nodes` or `edges`; you specified `' + group + '`');
+ return;
+ }
+
+ // make the element array-like, just like a collection
+ this.length = 1;
+ this[0] = this;
+
+ // NOTE: when something is added here, add also to ele.json()
+ this._private = {
+ cy: cy,
+ single: true, // indicates this is an element
+ data: params.data || {}, // data object
+ position: params.position || {}, // (x, y) position pair
+ autoWidth: undefined, // width and height of nodes calculated by the renderer when set to special 'auto' value
+ autoHeight: undefined,
+ listeners: [], // array of bound listeners
+ group: group, // string; 'nodes' or 'edges'
+ style: {}, // properties as set by the style
+ rstyle: {}, // properties for style sent from the renderer to the core
+ styleCxts: [], // applied style contexts from the styler
+ removed: true, // whether it's inside the vis; true if removed (set true here since we call restore)
+ selected: params.selected ? true : false, // whether it's selected
+ selectable: params.selectable === undefined ? true : ( params.selectable ? true : false ), // whether it's selectable
+ locked: params.locked ? true : false, // whether the element is locked (cannot be moved)
+ grabbed: false, // whether the element is grabbed by the mouse; renderer sets this privately
+ grabbable: params.grabbable === undefined ? true : ( params.grabbable ? true : false ), // whether the element can be grabbed
+ active: false, // whether the element is active from user interaction
+ classes: {}, // map ( className => true )
+ animation: { // object for currently-running animations
+ current: [],
+ queue: []
+ },
+ rscratch: {}, // object in which the renderer can store information
+ scratch: params.scratch || {}, // scratch objects
+ edges: [], // array of connected edges
+ children: [] // array of children
+ };
+
+ // renderedPosition overrides if specified
+ if( params.renderedPosition ){
+ var rpos = params.renderedPosition;
+ var pan = cy.pan();
+ var zoom = cy.zoom();
+
+ this._private.position = {
+ x: (rpos.x - pan.x)/zoom,
+ y: (rpos.y - pan.y)/zoom
+ };
+ }
+
+ if( is.string(params.classes) ){
+ var classes = params.classes.split(/\s+/);
+ for( var i = 0, l = classes.length; i < l; i++ ){
+ var cls = classes[i];
+ if( !cls || cls === '' ){ continue; }
+
+ self._private.classes[cls] = true;
+ }
+ }
+
+ if( params.style || params.css ){
+ cy.style().applyBypass( this, params.style || params.css );
+ }
+
+ if( restore === undefined || restore ){
+ this.restore();
+ }
+
+};
+
+module.exports = Element;
+
+},{"../is":77,"../util":94}],20:[function(_dereq_,module,exports){
+'use strict';
+
+var define = _dereq_('../define');
+
+var elesfn = ({
+ on: define.on(), // .on( events [, selector] [, data], handler)
+ one: define.on({ unbindSelfOnTrigger: true }),
+ once: define.on({ unbindAllBindersOnTrigger: true }),
+ off: define.off(), // .off( events [, selector] [, handler] )
+ trigger: define.trigger(), // .trigger( events [, extraParams] )
+
+ rtrigger: function(event, extraParams){ // for internal use only
+ if( this.length === 0 ){ return; } // empty collections don't need to notify anything
+
+ // notify renderer
+ this.cy().notify({
+ type: event,
+ collection: this
+ });
+
+ this.trigger(event, extraParams);
+ return this;
+ }
+});
+
+// aliases:
+define.eventAliasesOn( elesfn );
+
+module.exports = elesfn;
+
+},{"../define":41}],21:[function(_dereq_,module,exports){
+'use strict';
+
+var is = _dereq_('../is');
+var Selector = _dereq_('../selector');
+
+var elesfn = ({
+ nodes: function( selector ){
+ return this.filter(function(i, element){
+ return element.isNode();
+ }).filter(selector);
+ },
+
+ edges: function( selector ){
+ return this.filter(function(i, element){
+ return element.isEdge();
+ }).filter(selector);
+ },
+
+ filter: function( filter ){
+ if( is.fn(filter) ){
+ var elements = [];
+
+ for( var i = 0; i < this.length; i++ ){
+ var ele = this[i];
+
+ if( filter.apply(ele, [i, ele]) ){
+ elements.push(ele);
+ }
+ }
+
+ return this.spawn(elements);
+
+ } else if( is.string(filter) || is.elementOrCollection(filter) ){
+ return Selector(filter).filter(this);
+
+ } else if( filter === undefined ){
+ return this;
+ }
+
+ return this.spawn(); // if not handled by above, give 'em an empty collection
+ },
+
+ not: function( toRemove ){
+ if( !toRemove ){
+ return this;
+ } else {
+
+ if( is.string( toRemove ) ){
+ toRemove = this.filter( toRemove );
+ }
+
+ var elements = [];
+
+ for( var i = 0; i < this.length; i++ ){
+ var element = this[i];
+
+ var remove = toRemove._private.ids[ element.id() ];
+ if( !remove ){
+ elements.push( element );
+ }
+ }
+
+ return this.spawn( elements );
+ }
+
+ },
+
+ absoluteComplement: function(){
+ var cy = this._private.cy;
+
+ return cy.elements().not( this );
+ },
+
+ intersect: function( other ){
+ // if a selector is specified, then filter by it instead
+ if( is.string(other) ){
+ var selector = other;
+ return this.filter( selector );
+ }
+
+ var elements = [];
+ var col1 = this;
+ var col2 = other;
+ var col1Smaller = this.length < other.length;
+ // var ids1 = col1Smaller ? col1._private.ids : col2._private.ids;
+ var ids2 = col1Smaller ? col2._private.ids : col1._private.ids;
+ var col = col1Smaller ? col1 : col2;
+
+ for( var i = 0; i < col.length; i++ ){
+ var id = col[i]._private.data.id;
+ var ele = ids2[ id ];
+
+ if( ele ){
+ elements.push( ele );
+ }
+ }
+
+ return this.spawn( elements );
+ },
+
+ xor: function( other ){
+ var cy = this._private.cy;
+
+ if( is.string(other) ){
+ other = cy.$( other );
+ }
+
+ var elements = [];
+ var col1 = this;
+ var col2 = other;
+
+ var add = function( col, other ){
+
+ for( var i = 0; i < col.length; i++ ){
+ var ele = col[i];
+ var id = ele._private.data.id;
+ var inOther = other._private.ids[ id ];
+
+ if( !inOther ){
+ elements.push( ele );
+ }
+ }
+
+ };
+
+ add( col1, col2 );
+ add( col2, col1 );
+
+ return this.spawn( elements );
+ },
+
+ diff: function( other ){
+ var cy = this._private.cy;
+
+ if( is.string(other) ){
+ other = cy.$( other );
+ }
+
+ var left = [];
+ var right = [];
+ var both = [];
+ var col1 = this;
+ var col2 = other;
+
+ var add = function( col, other, retEles ){
+
+ for( var i = 0; i < col.length; i++ ){
+ var ele = col[i];
+ var id = ele._private.data.id;
+ var inOther = other._private.ids[ id ];
+
+ if( inOther ){
+ both.push( ele );
+ } else {
+ retEles.push( ele );
+ }
+ }
+
+ };
+
+ add( col1, col2, left );
+ add( col2, col1, right );
+
+ return {
+ left: this.spawn( left, { unique: true } ),
+ right: this.spawn( right, { unique: true } ),
+ both: this.spawn( both, { unique: true } )
+ };
+ },
+
+ add: function( toAdd ){
+ var cy = this._private.cy;
+
+ if( !toAdd ){
+ return this;
+ }
+
+ if( is.string(toAdd) ){
+ var selector = toAdd;
+ toAdd = cy.elements(selector);
+ }
+
+ var elements = [];
+
+ for( var i = 0; i < this.length; i++ ){
+ elements.push( this[i] );
+ }
+
+ for( var i = 0; i < toAdd.length; i++ ){
+
+ var add = !this._private.ids[ toAdd[i].id() ];
+ if( add ){
+ elements.push( toAdd[i] );
+ }
+ }
+
+ return this.spawn(elements);
+ },
+
+ // in place merge on calling collection
+ merge: function( toAdd ){
+ var _p = this._private;
+ var cy = _p.cy;
+
+ if( !toAdd ){
+ return this;
+ }
+
+ if( is.string(toAdd) ){
+ var selector = toAdd;
+ toAdd = cy.elements(selector);
+ }
+
+ for( var i = 0; i < toAdd.length; i++ ){
+ var toAddEle = toAdd[i];
+ var id = toAddEle.id();
+ var add = !_p.ids[ id ];
+
+ if( add ){
+ var index = this.length++;
+
+ this[ index ] = toAddEle;
+ _p.ids[ id ] = toAddEle;
+ _p.indexes[ id ] = index;
+ }
+ }
+
+ return this; // chaining
+ },
+
+ // remove single ele in place in calling collection
+ unmergeOne: function( ele ){
+ ele = ele[0];
+
+ var _p = this._private;
+ var id = ele.id();
+ var i = _p.indexes[ id ];
+
+ if( i == null ){
+ return this; // no need to remove
+ }
+
+ // remove ele
+ this[i] = undefined;
+ _p.ids[ id ] = undefined;
+ _p.indexes[ id ] = undefined;
+
+ var unmergedLastEle = i === this.length - 1;
+
+ // replace empty spot with last ele in collection
+ if( this.length > 1 && !unmergedLastEle ){
+ var lastEleI = this.length - 1;
+ var lastEle = this[ lastEleI ];
+
+ this[ lastEleI ] = undefined;
+ this[i] = lastEle;
+ _p.indexes[ lastEle.id() ] = i;
+ }
+
+ // the collection is now 1 ele smaller
+ this.length--;
+
+ return this;
+ },
+
+ // remove eles in place on calling collection
+ unmerge: function( toRemove ){
+ var cy = this._private.cy;
+
+ if( !toRemove ){
+ return this;
+ }
+
+ if( is.string(toRemove) ){
+ var selector = toRemove;
+ toRemove = cy.elements(selector);
+ }
+
+ for( var i = 0; i < toRemove.length; i++ ){
+ this.unmergeOne( toRemove[i] );
+ }
+
+ return this; // chaining
+ },
+
+ map: function( mapFn, thisArg ){
+ var arr = [];
+ var eles = this;
+
+ for( var i = 0; i < eles.length; i++ ){
+ var ele = eles[i];
+ var ret = thisArg ? mapFn.apply( thisArg, [ele, i, eles] ) : mapFn( ele, i, eles );
+
+ arr.push( ret );
+ }
+
+ return arr;
+ },
+
+ stdFilter: function( fn, thisArg ){
+ var filterEles = [];
+ var eles = this;
+
+ for( var i = 0; i < eles.length; i++ ){
+ var ele = eles[i];
+ var include = thisArg ? fn.apply( thisArg, [ele, i, eles] ) : fn( ele, i, eles );
+
+ if( include ){
+ filterEles.push( ele );
+ }
+ }
+
+ return this.spawn( filterEles );
+ },
+
+ max: function( valFn, thisArg ){
+ var max = -Infinity;
+ var maxEle;
+ var eles = this;
+
+ for( var i = 0; i < eles.length; i++ ){
+ var ele = eles[i];
+ var val = thisArg ? valFn.apply( thisArg, [ ele, i, eles ] ) : valFn( ele, i, eles );
+
+ if( val > max ){
+ max = val;
+ maxEle = ele;
+ }
+ }
+
+ return {
+ value: max,
+ ele: maxEle
+ };
+ },
+
+ min: function( valFn, thisArg ){
+ var min = Infinity;
+ var minEle;
+ var eles = this;
+
+ for( var i = 0; i < eles.length; i++ ){
+ var ele = eles[i];
+ var val = thisArg ? valFn.apply( thisArg, [ ele, i, eles ] ) : valFn( ele, i, eles );
+
+ if( val < min ){
+ min = val;
+ minEle = ele;
+ }
+ }
+
+ return {
+ value: min,
+ ele: minEle
+ };
+ }
+});
+
+// aliases
+var fn = elesfn;
+fn['u'] = fn['|'] = fn['+'] = fn.union = fn.or = fn.add;
+fn['\\'] = fn['!'] = fn['-'] = fn.difference = fn.relativeComplement = fn.subtract = fn.not;
+fn['n'] = fn['&'] = fn['.'] = fn.and = fn.intersection = fn.intersect;
+fn['^'] = fn['(+)'] = fn['(-)'] = fn.symmetricDifference = fn.symdiff = fn.xor;
+fn.fnFilter = fn.filterFn = fn.stdFilter;
+fn.complement = fn.abscomp = fn.absoluteComplement;
+
+module.exports = elesfn;
+
+},{"../is":77,"../selector":81}],22:[function(_dereq_,module,exports){
+'use strict';
+
+var elesfn = ({
+ isNode: function(){
+ return this.group() === 'nodes';
+ },
+
+ isEdge: function(){
+ return this.group() === 'edges';
+ },
+
+ isLoop: function(){
+ return this.isEdge() && this.source().id() === this.target().id();
+ },
+
+ isSimple: function(){
+ return this.isEdge() && this.source().id() !== this.target().id();
+ },
+
+ group: function(){
+ var ele = this[0];
+
+ if( ele ){
+ return ele._private.group;
+ }
+ }
+});
+
+
+module.exports = elesfn;
+
+},{}],23:[function(_dereq_,module,exports){
+'use strict';
+
+var util = _dereq_('../util');
+var is = _dereq_('../is');
+
+var Element = _dereq_('./element');
+
+// factory for generating edge ids when no id is specified for a new element
+var idFactory = {
+ prefix: 'ele',
+ id: 0,
+ generate: function(cy, element, tryThisId){
+ var json = is.element( element ) ? element._private : element;
+ var id = tryThisId != null ? tryThisId : this.prefix + this.id;
+
+ if( cy.getElementById(id).empty() ){
+ this.id++; // we've used the current id, so move it up
+ } else { // otherwise keep trying successive unused ids
+ while( !cy.getElementById(id).empty() ){
+ id = this.prefix + ( ++this.id );
+ }
+ }
+
+ return id;
+ }
+};
+
+// represents a set of nodes, edges, or both together
+var Collection = function(cy, elements, options){
+ if( !(this instanceof Collection) ){
+ return new Collection(cy, elements, options);
+ }
+
+ if( cy === undefined || !is.core(cy) ){
+ util.error('A collection must have a reference to the core');
+ return;
+ }
+
+ var ids = {};
+ var indexes = {};
+ var createdElements = false;
+
+ if( !elements ){
+ elements = [];
+ } else if( elements.length > 0 && is.plainObject( elements[0] ) && !is.element( elements[0] ) ){
+ createdElements = true;
+
+ // make elements from json and restore all at once later
+ var eles = [];
+ var elesIds = {};
+
+ for( var i = 0, l = elements.length; i < l; i++ ){
+ var json = elements[i];
+
+ if( json.data == null ){
+ json.data = {};
+ }
+
+ var data = json.data;
+
+ // make sure newly created elements have valid ids
+ if( data.id == null ){
+ data.id = idFactory.generate( cy, json );
+ } else if( cy.getElementById( data.id ).length !== 0 || elesIds[ data.id ] ){
+ continue; // can't create element if prior id already exists
+ }
+
+ var ele = new Element( cy, json, false );
+ eles.push( ele );
+ elesIds[ data.id ] = true;
+ }
+
+ elements = eles;
+ }
+
+ this.length = 0;
+
+ for( var i = 0, l = elements.length; i < l; i++ ){
+ var element = elements[i];
+ if( !element ){ continue; }
+
+ var id = element._private.data.id;
+
+ if( !options || (options.unique && !ids[ id ] ) ){
+ ids[ id ] = element;
+ indexes[ id ] = this.length;
+
+ this[ this.length ] = element;
+ this.length++;
+ }
+ }
+
+ this._private = {
+ cy: cy,
+ ids: ids,
+ indexes: indexes
+ };
+
+ // restore the elements if we created them from json
+ if( createdElements ){
+ this.restore();
+ }
+};
+
+// Functions
+////////////////////////////////////////////////////////////////////////////////////////////////////
+
+// keep the prototypes in sync (an element has the same functions as a collection)
+// and use elefn and elesfn as shorthands to the prototypes
+var elesfn = Element.prototype = Collection.prototype;
+
+elesfn.instanceString = function(){
+ return 'collection';
+};
+
+elesfn.spawn = function( cy, eles, opts ){
+ if( !is.core(cy) ){ // cy is optional
+ opts = eles;
+ eles = cy;
+ cy = this.cy();
+ }
+
+ return new Collection( cy, eles, opts );
+};
+
+elesfn.cy = function(){
+ return this._private.cy;
+};
+
+elesfn.element = function(){
+ return this[0];
+};
+
+elesfn.collection = function(){
+ if( is.collection(this) ){
+ return this;
+ } else { // an element
+ return new Collection( this._private.cy, [this] );
+ }
+};
+
+elesfn.unique = function(){
+ return new Collection( this._private.cy, this, { unique: true } );
+};
+
+elesfn.getElementById = function( id ){
+ var cy = this._private.cy;
+ var ele = this._private.ids[ id ];
+
+ return ele ? ele : new Collection(cy); // get ele or empty collection
+};
+
+elesfn.json = function( obj ){
+ var ele = this.element();
+ var cy = this.cy();
+
+ if( ele == null && obj ){ return this; } // can't set to no eles
+
+ if( ele == null ){ return undefined; } // can't get from no eles
+
+ var p = ele._private;
+
+ if( is.plainObject(obj) ){ // set
+
+ cy.startBatch();
+
+ if( obj.data ){
+ ele.data( obj.data );
+ }
+
+ if( obj.position ){
+ ele.position( obj.position );
+ }
+
+ // ignore group -- immutable
+
+ var checkSwitch = function( k, trueFnName, falseFnName ){
+ var obj_k = obj[k];
+
+ if( obj_k != null && obj_k !== p[k] ){
+ if( obj_k ){
+ ele[ trueFnName ]();
+ } else {
+ ele[ falseFnName ]();
+ }
+ }
+ };
+
+ checkSwitch( 'removed', 'remove', 'restore' );
+
+ checkSwitch( 'selected', 'select', 'unselect' );
+
+ checkSwitch( 'selectable', 'selectify', 'unselectify' );
+
+ checkSwitch( 'locked', 'lock', 'unlock' );
+
+ checkSwitch( 'grabbable', 'grabify', 'ungrabify' );
+
+ if( obj.classes != null ){
+ ele.classes( obj.classes );
+ }
+
+ cy.endBatch();
+
+ return this;
+
+ } else if( obj === undefined ){ // get
+
+ var json = {
+ data: util.copy( p.data ),
+ position: util.copy( p.position ),
+ group: p.group,
+ removed: p.removed,
+ selected: p.selected,
+ selectable: p.selectable,
+ locked: p.locked,
+ grabbable: p.grabbable,
+ classes: null
+ };
+
+ var classes = [];
+ for( var cls in p.classes ){
+ if( p.classes[cls] ){
+ classes.push(cls);
+ }
+ }
+ json.classes = classes.join(' ');
+
+ return json;
+ }
+};
+
+elesfn.jsons = function(){
+ var jsons = [];
+
+ for( var i = 0; i < this.length; i++ ){
+ var ele = this[i];
+ var json = ele.json();
+
+ jsons.push( json );
+ }
+
+ return jsons;
+};
+
+elesfn.clone = function(){
+ var cy = this.cy();
+ var elesArr = [];
+
+ for( var i = 0; i < this.length; i++ ){
+ var ele = this[i];
+ var json = ele.json();
+ var clone = new Element(cy, json, false); // NB no restore
+
+ elesArr.push( clone );
+ }
+
+ return new Collection( cy, elesArr );
+};
+elesfn.copy = elesfn.clone;
+
+elesfn.restore = function( notifyRenderer ){
+ var self = this;
+ var restored = [];
+ var cy = self.cy();
+
+ if( notifyRenderer === undefined ){
+ notifyRenderer = true;
+ }
+
+ // create arrays of nodes and edges, since we need to
+ // restore the nodes first
+ var elements = [];
+ var nodes = [], edges = [];
+ var numNodes = 0;
+ var numEdges = 0;
+ for( var i = 0, l = self.length; i < l; i++ ){
+ var ele = self[i];
+
+ // keep nodes first in the array and edges after
+ if( ele.isNode() ){ // put to front of array if node
+ nodes.push( ele );
+ numNodes++;
+ } else { // put to end of array if edge
+ edges.push( ele );
+ numEdges++;
+ }
+ }
+
+ elements = nodes.concat( edges );
+
+ // now, restore each element
+ for( var i = 0, l = elements.length; i < l; i++ ){
+ var ele = elements[i];
+
+ if( !ele.removed() ){
+ // don't need to do anything
+ continue;
+ }
+
+ var _private = ele._private;
+ var data = _private.data;
+
+ // set id and validate
+ if( data.id === undefined ){
+ data.id = idFactory.generate( cy, ele );
+
+ } else if( is.number(data.id) ){
+ data.id = '' + data.id; // now it's a string
+
+ } else if( is.emptyString(data.id) || !is.string(data.id) ){
+ util.error('Can not create element with invalid string ID `' + data.id + '`');
+
+ // can't create element if it has empty string as id or non-string id
+ continue;
+ } else if( cy.getElementById( data.id ).length !== 0 ){
+ util.error('Can not create second element with ID `' + data.id + '`');
+
+ // can't create element if one already has that id
+ continue;
+ }
+
+ var id = data.id; // id is finalised, now let's keep a ref
+
+ if( ele.isNode() ){ // extra checks for nodes
+ var node = ele;
+ var pos = _private.position;
+
+ // make sure the nodes have a defined position
+
+ if( pos.x == null ){
+ pos.x = 0;
+ }
+
+ if( pos.y == null ){
+ pos.y = 0;
+ }
+ }
+
+ if( ele.isEdge() ){ // extra checks for edges
+
+ var edge = ele;
+ var fields = ['source', 'target'];
+ var fieldsLength = fields.length;
+ var badSourceOrTarget = false;
+ for(var j = 0; j < fieldsLength; j++){
+
+ var field = fields[j];
+ var val = data[field];
+
+ if( is.number(val) ){
+ val = data[field] = '' + data[field]; // now string
+ }
+
+ if( val == null || val === '' ){
+ // can't create if source or target is not defined properly
+ util.error('Can not create edge `' + id + '` with unspecified ' + field);
+ badSourceOrTarget = true;
+ } else if( cy.getElementById(val).empty() ){
+ // can't create edge if one of its nodes doesn't exist
+ util.error('Can not create edge `' + id + '` with nonexistant ' + field + ' `' + val + '`');
+ badSourceOrTarget = true;
+ }
+ }
+
+ if( badSourceOrTarget ){ continue; } // can't create this
+
+ var src = cy.getElementById( data.source );
+ var tgt = cy.getElementById( data.target );
+
+ src._private.edges.push( edge );
+ tgt._private.edges.push( edge );
+
+ edge._private.source = src;
+ edge._private.target = tgt;
+
+ } // if is edge
+
+ // create mock ids map for element so it can be used like collections
+ _private.ids = {};
+ _private.ids[ id ] = ele;
+
+ _private.removed = false;
+ cy.addToPool( ele );
+
+ restored.push( ele );
+ } // for each element
+
+ // do compound node sanity checks
+ for( var i = 0; i < numNodes; i++ ){ // each node
+ var node = elements[i];
+ var data = node._private.data;
+
+ if( is.number(data.parent) ){ // then automake string
+ data.parent = '' + data.parent;
+ }
+
+ var parentId = data.parent;
+
+ var specifiedParent = parentId != null;
+
+ if( specifiedParent ){
+ var parent = cy.getElementById( parentId );
+
+ if( parent.empty() ){
+ // non-existant parent; just remove it
+ data.parent = undefined;
+ } else {
+ var selfAsParent = false;
+ var ancestor = parent;
+ while( !ancestor.empty() ){
+ if( node.same(ancestor) ){
+ // mark self as parent and remove from data
+ selfAsParent = true;
+ data.parent = undefined; // remove parent reference
+
+ // exit or we loop forever
+ break;
+ }
+
+ ancestor = ancestor.parent();
+ }
+
+ if( !selfAsParent ){
+ // connect with children
+ parent[0]._private.children.push( node );
+ node._private.parent = parent[0];
+
+ // let the core know we have a compound graph
+ cy._private.hasCompoundNodes = true;
+ }
+ } // else
+ } // if specified parent
+ } // for each node
+
+ restored = new Collection( cy, restored );
+ if( restored.length > 0 ){
+
+ var toUpdateStyle = restored.add( restored.connectedNodes() ).add( restored.parent() );
+ toUpdateStyle.updateStyle( notifyRenderer );
+
+ if( notifyRenderer ){
+ restored.rtrigger('add');
+ } else {
+ restored.trigger('add');
+ }
+ }
+
+ return self; // chainability
+};
+
+elesfn.removed = function(){
+ var ele = this[0];
+ return ele && ele._private.removed;
+};
+
+elesfn.inside = function(){
+ var ele = this[0];
+ return ele && !ele._private.removed;
+};
+
+elesfn.remove = function( notifyRenderer ){
+ var self = this;
+ var removed = [];
+ var elesToRemove = [];
+ var elesToRemoveIds = {};
+ var cy = self._private.cy;
+
+ if( notifyRenderer === undefined ){
+ notifyRenderer = true;
+ }
+
+ // add connected edges
+ function addConnectedEdges(node){
+ var edges = node._private.edges;
+ for( var i = 0; i < edges.length; i++ ){
+ add( edges[i] );
+ }
+ }
+
+
+ // add descendant nodes
+ function addChildren(node){
+ var children = node._private.children;
+
+ for( var i = 0; i < children.length; i++ ){
+ add( children[i] );
+ }
+ }
+
+ function add( ele ){
+ var alreadyAdded = elesToRemoveIds[ ele.id() ];
+ if( alreadyAdded ){
+ return;
+ } else {
+ elesToRemoveIds[ ele.id() ] = true;
+ }
+
+ if( ele.isNode() ){
+ elesToRemove.push( ele ); // nodes are removed last
+
+ addConnectedEdges( ele );
+ addChildren( ele );
+ } else {
+ elesToRemove.unshift( ele ); // edges are removed first
+ }
+ }
+
+ // make the list of elements to remove
+ // (may be removing more than specified due to connected edges etc)
+
+ for( var i = 0, l = self.length; i < l; i++ ){
+ var ele = self[i];
+
+ add( ele );
+ }
+
+ function removeEdgeRef(node, edge){
+ var connectedEdges = node._private.edges;
+ for( var j = 0; j < connectedEdges.length; j++ ){
+ var connectedEdge = connectedEdges[j];
+
+ if( edge === connectedEdge ){
+ connectedEdges.splice( j, 1 );
+ break;
+ }
+ }
+ }
+
+ function removeChildRef(parent, ele){
+ ele = ele[0];
+ parent = parent[0];
+ var children = parent._private.children;
+
+ for( var j = 0; j < children.length; j++ ){
+ if( children[j][0] === ele[0] ){
+ children.splice(j, 1);
+ break;
+ }
+ }
+ }
+
+ for( var i = 0; i < elesToRemove.length; i++ ){
+ var ele = elesToRemove[i];
+
+ // mark as removed
+ ele._private.removed = true;
+
+ // remove from core pool
+ cy.removeFromPool( ele );
+
+ // add to list of removed elements
+ removed.push( ele );
+
+ if( ele.isEdge() ){ // remove references to this edge in its connected nodes
+ var src = ele.source()[0];
+ var tgt = ele.target()[0];
+
+ removeEdgeRef( src, ele );
+ removeEdgeRef( tgt, ele );
+
+ } else { // remove reference to parent
+ var parent = ele.parent();
+
+ if( parent.length !== 0 ){
+ removeChildRef(parent, ele);
+ }
+ }
+ }
+
+ // check to see if we have a compound graph or not
+ var elesStillInside = cy._private.elements;
+ cy._private.hasCompoundNodes = false;
+ for( var i = 0; i < elesStillInside.length; i++ ){
+ var ele = elesStillInside[i];
+
+ if( ele.isParent() ){
+ cy._private.hasCompoundNodes = true;
+ break;
+ }
+ }
+
+ var removedElements = new Collection( this.cy(), removed );
+ if( removedElements.size() > 0 ){
+ // must manually notify since trigger won't do this automatically once removed
+
+ if( notifyRenderer ){
+ this.cy().notify({
+ type: 'remove',
+ collection: removedElements
+ });
+ }
+
+ removedElements.trigger('remove');
+ }
+
+ // check for empty remaining parent nodes
+ var checkedParentId = {};
+ for( var i = 0; i < elesToRemove.length; i++ ){
+ var ele = elesToRemove[i];
+ var isNode = ele._private.group === 'nodes';
+ var parentId = ele._private.data.parent;
+
+ if( isNode && parentId !== undefined && !checkedParentId[ parentId ] ){
+ checkedParentId[ parentId ] = true;
+ var parent = cy.getElementById( parentId );
+
+ if( parent && parent.length !== 0 && !parent._private.removed && parent.children().length === 0 ){
+ parent.updateStyle();
+ }
+ }
+ }
+
+ return new Collection( cy, removed );
+};
+
+elesfn.move = function( struct ){
+ var cy = this._private.cy;
+
+ if( struct.source !== undefined || struct.target !== undefined ){
+ var srcId = struct.source;
+ var tgtId = struct.target;
+ var srcExists = cy.getElementById( srcId ).length > 0;
+ var tgtExists = cy.getElementById( tgtId ).length > 0;
+
+ if( srcExists || tgtExists ){
+ var jsons = this.jsons();
+
+ this.remove();
+
+ for( var i = 0; i < jsons.length; i++ ){
+ var json = jsons[i];
+
+ if( json.group === 'edges' ){
+ if( srcExists ){ json.data.source = srcId; }
+ if( tgtExists ){ json.data.target = tgtId; }
+ }
+ }
+
+ return cy.add( jsons );
+ }
+
+ } else if( struct.parent !== undefined ){ // move node to new parent
+ var parentId = struct.parent;
+ var parentExists = parentId === null || cy.getElementById( parentId ).length > 0;
+
+ if( parentExists ){
+ var jsons = this.jsons();
+ var descs = this.descendants();
+ var descsEtc = descs.merge( descs.add(this).connectedEdges() );
+
+ this.remove(); // NB: also removes descendants and their connected edges
+
+ for( var i = 0; i < this.length; i++ ){
+ var json = jsons[i];
+
+ if( json.group === 'nodes' ){
+ json.data.parent = parentId === null ? undefined : parentId;
+ }
+ }
+ }
+
+ return cy.add( jsons ).merge( descsEtc.restore() );
+ }
+
+ return this; // if nothing done
+};
+
+[
+ _dereq_('./algorithms'),
+ _dereq_('./animation'),
+ _dereq_('./class'),
+ _dereq_('./comparators'),
+ _dereq_('./compounds'),
+ _dereq_('./data'),
+ _dereq_('./degree'),
+ _dereq_('./dimensions'),
+ _dereq_('./events'),
+ _dereq_('./filter'),
+ _dereq_('./group'),
+ _dereq_('./index'),
+ _dereq_('./iteration'),
+ _dereq_('./layout'),
+ _dereq_('./style'),
+ _dereq_('./switch-functions'),
+ _dereq_('./traversing')
+].forEach(function( props ){
+ util.extend( elesfn, props );
+});
+
+module.exports = Collection;
+
+},{"../is":77,"../util":94,"./algorithms":9,"./animation":12,"./class":13,"./comparators":14,"./compounds":15,"./data":16,"./degree":17,"./dimensions":18,"./element":19,"./events":20,"./filter":21,"./group":22,"./index":23,"./iteration":24,"./layout":25,"./style":26,"./switch-functions":27,"./traversing":28}],24:[function(_dereq_,module,exports){
+'use strict';
+
+var is = _dereq_('../is');
+var zIndexSort = _dereq_('./zsort');
+
+var elesfn = ({
+ each: function(fn){
+ if( is.fn(fn) ){
+ for(var i = 0; i < this.length; i++){
+ var ele = this[i];
+ var ret = fn.apply( ele, [ i, ele ] );
+
+ if( ret === false ){ break; } // exit each early on return false
+ }
+ }
+ return this;
+ },
+
+ forEach: function(fn, thisArg){
+ if( is.fn(fn) ){
+
+ for(var i = 0; i < this.length; i++){
+ var ele = this[i];
+ var ret = thisArg ? fn.apply( thisArg, [ ele, i, this ] ) : fn( ele, i, this );
+
+ if( ret === false ){ break; } // exit each early on return false
+ }
+ }
+
+ return this;
+ },
+
+ toArray: function(){
+ var array = [];
+
+ for(var i = 0; i < this.length; i++){
+ array.push( this[i] );
+ }
+
+ return array;
+ },
+
+ slice: function(start, end){
+ var array = [];
+ var thisSize = this.length;
+
+ if( end == null ){
+ end = thisSize;
+ }
+
+ if( start == null ){
+ start = 0;
+ }
+
+ if( start < 0 ){
+ start = thisSize + start;
+ }
+
+ if( end < 0 ){
+ end = thisSize + end;
+ }
+
+ for(var i = start; i >= 0 && i < end && i < thisSize; i++){
+ array.push( this[i] );
+ }
+
+ return this.spawn(array);
+ },
+
+ size: function(){
+ return this.length;
+ },
+
+ eq: function(i){
+ return this[i] || this.spawn();
+ },
+
+ first: function(){
+ return this[0] || this.spawn();
+ },
+
+ last: function(){
+ return this[ this.length - 1 ] || this.spawn();
+ },
+
+ empty: function(){
+ return this.length === 0;
+ },
+
+ nonempty: function(){
+ return !this.empty();
+ },
+
+ sort: function( sortFn ){
+ if( !is.fn( sortFn ) ){
+ return this;
+ }
+
+ var sorted = this.toArray().sort( sortFn );
+
+ return this.spawn(sorted);
+ },
+
+ sortByZIndex: function(){
+ return this.sort( zIndexSort );
+ },
+
+ zDepth: function(){
+ var ele = this[0];
+ if( !ele ){ return undefined; }
+
+ // var cy = ele.cy();
+ var _p = ele._private;
+ var group = _p.group;
+
+ if( group === 'nodes' ){
+ var depth = _p.data.parent ? ele.parents().size() : 0;
+
+ if( !ele.isParent() ){
+ return Number.MAX_VALUE; // childless nodes always on top
+ }
+
+ return depth;
+ } else {
+ var src = _p.source;
+ var tgt = _p.target;
+ var srcDepth = src.zDepth();
+ var tgtDepth = tgt.zDepth();
+
+ return Math.max( srcDepth, tgtDepth, 0 ); // depth of deepest parent
+ }
+ }
+});
+
+module.exports = elesfn;
+
+},{"../is":77,"./zsort":29}],25:[function(_dereq_,module,exports){
+'use strict';
+
+var is = _dereq_('../is');
+var util = _dereq_('../util');
+
+var elesfn = ({
+
+ // using standard layout options, apply position function (w/ or w/o animation)
+ layoutPositions: function( layout, options, fn ){
+ var nodes = this.nodes();
+ var cy = this.cy();
+
+ layout.trigger({ type: 'layoutstart', layout: layout });
+
+ layout.animations = [];
+
+ if( options.animate ){
+ for( var i = 0; i < nodes.length; i++ ){
+ var node = nodes[i];
+ var lastNode = i === nodes.length - 1;
+
+ var newPos = fn.call( node, i, node );
+ var pos = node.position();
+
+ if( !is.number(pos.x) || !is.number(pos.y) ){
+ node.silentPosition({ x: 0, y: 0 });
+ }
+
+ var ani = node.animation({
+ position: newPos,
+ duration: options.animationDuration,
+ easing: options.animationEasing,
+ step: !lastNode ? undefined : function(){
+ if( options.fit ){
+ cy.fit( options.eles, options.padding );
+ }
+ },
+ complete: !lastNode ? undefined : function(){
+ if( options.zoom != null ){
+ cy.zoom( options.zoom );
+ }
+
+ if( options.pan ){
+ cy.pan( options.pan );
+ }
+
+ if( options.fit ){
+ cy.fit( options.eles, options.padding );
+ }
+
+ layout.one('layoutstop', options.stop);
+ layout.trigger({ type: 'layoutstop', layout: layout });
+ }
+ });
+
+ layout.animations.push( ani );
+
+ ani.play();
+ }
+
+ layout.one('layoutready', options.ready);
+ layout.trigger({ type: 'layoutready', layout: layout });
+ } else {
+ nodes.positions( fn );
+
+ if( options.fit ){
+ cy.fit( options.eles, options.padding );
+ }
+
+ if( options.zoom != null ){
+ cy.zoom( options.zoom );
+ }
+
+ if( options.pan ){
+ cy.pan( options.pan );
+ }
+
+ layout.one('layoutready', options.ready);
+ layout.trigger({ type: 'layoutready', layout: layout });
+
+ layout.one('layoutstop', options.stop);
+ layout.trigger({ type: 'layoutstop', layout: layout });
+ }
+
+ return this; // chaining
+ },
+
+ layout: function( options ){
+ var cy = this.cy();
+
+ cy.layout( util.extend({}, options, {
+ eles: this
+ }) );
+
+ return this;
+ },
+
+ makeLayout: function( options ){
+ var cy = this.cy();
+
+ return cy.makeLayout( util.extend({}, options, {
+ eles: this
+ }) );
+ }
+
+});
+
+// aliases:
+elesfn.createLayout = elesfn.makeLayout;
+
+module.exports = elesfn;
+
+},{"../is":77,"../util":94}],26:[function(_dereq_,module,exports){
+'use strict';
+
+var is = _dereq_('../is');
+
+var elesfn = ({
+
+ // fully updates (recalculates) the style for the elements
+ updateStyle: function( notifyRenderer ){
+ var cy = this._private.cy;
+
+ if( !cy.styleEnabled() ){ return this; }
+
+ if( cy._private.batchingStyle ){
+ var bEles = cy._private.batchStyleEles;
+
+ bEles.merge( this );
+
+ return this; // chaining and exit early when batching
+ }
+
+ var style = cy.style();
+ notifyRenderer = notifyRenderer || notifyRenderer === undefined ? true : false;
+
+ style.apply( this );
+
+ var updatedCompounds = this.updateCompoundBounds();
+ var toNotify = updatedCompounds.length > 0 ? this.add( updatedCompounds ) : this;
+
+ if( notifyRenderer ){
+ toNotify.rtrigger('style'); // let renderer know we changed style
+ } else {
+ toNotify.trigger('style'); // just fire the event
+ }
+ return this; // chaining
+ },
+
+ // just update the mappers in the elements' styles; cheaper than eles.updateStyle()
+ updateMappers: function( notifyRenderer ){
+ var cy = this._private.cy;
+ var style = cy.style();
+ notifyRenderer = notifyRenderer || notifyRenderer === undefined ? true : false;
+
+ if( !cy.styleEnabled() ){ return this; }
+
+ style.updateMappers( this );
+
+ var updatedCompounds = this.updateCompoundBounds();
+ var toNotify = updatedCompounds.length > 0 ? this.add( updatedCompounds ) : this;
+
+ if( notifyRenderer ){
+ toNotify.rtrigger('style'); // let renderer know we changed style
+ } else {
+ toNotify.trigger('style'); // just fire the event
+ }
+ return this; // chaining
+ },
+
+ // get the specified css property as a rendered value (i.e. on-screen value)
+ // or get the whole rendered style if no property specified (NB doesn't allow setting)
+ renderedCss: function( property ){
+ var cy = this.cy();
+ if( !cy.styleEnabled() ){ return this; }
+
+ var ele = this[0];
+
+ if( ele ){
+ var renstyle = ele.cy().style().getRenderedStyle( ele );
+
+ if( property === undefined ){
+ return renstyle;
+ } else {
+ return renstyle[ property ];
+ }
+ }
+ },
+
+ // read the calculated css style of the element or override the style (via a bypass)
+ css: function( name, value ){
+ var cy = this.cy();
+
+ if( !cy.styleEnabled() ){ return this; }
+
+ var updateTransitions = false;
+ var style = cy.style();
+
+ if( is.plainObject(name) ){ // then extend the bypass
+ var props = name;
+ style.applyBypass( this, props, updateTransitions );
+
+ var updatedCompounds = this.updateCompoundBounds();
+ var toNotify = updatedCompounds.length > 0 ? this.add( updatedCompounds ) : this;
+ toNotify.rtrigger('style'); // let the renderer know we've updated style
+
+ } else if( is.string(name) ){
+
+ if( value === undefined ){ // then get the property from the style
+ var ele = this[0];
+
+ if( ele ){
+ return style.getStylePropertyValue( ele, name );
+ } else { // empty collection => can't get any value
+ return;
+ }
+
+ } else { // then set the bypass with the property value
+ style.applyBypass( this, name, value, updateTransitions );
+
+ var updatedCompounds = this.updateCompoundBounds();
+ var toNotify = updatedCompounds.length > 0 ? this.add( updatedCompounds ) : this;
+ toNotify.rtrigger('style'); // let the renderer know we've updated style
+ }
+
+ } else if( name === undefined ){
+ var ele = this[0];
+
+ if( ele ){
+ return style.getRawStyle( ele );
+ } else { // empty collection => can't get any value
+ return;
+ }
+ }
+
+ return this; // chaining
+ },
+
+ removeCss: function( names ){
+ var cy = this.cy();
+
+ if( !cy.styleEnabled() ){ return this; }
+
+ var updateTransitions = false;
+ var style = cy.style();
+ var eles = this;
+
+ if( names === undefined ){
+ for( var i = 0; i < eles.length; i++ ){
+ var ele = eles[i];
+
+ style.removeAllBypasses( ele, updateTransitions );
+ }
+ } else {
+ names = names.split(/\s+/);
+
+ for( var i = 0; i < eles.length; i++ ){
+ var ele = eles[i];
+
+ style.removeBypasses( ele, names, updateTransitions );
+ }
+ }
+
+ var updatedCompounds = this.updateCompoundBounds();
+ var toNotify = updatedCompounds.length > 0 ? this.add( updatedCompounds ) : this;
+ toNotify.rtrigger('style'); // let the renderer know we've updated style
+
+ return this; // chaining
+ },
+
+ show: function(){
+ this.css('display', 'element');
+ return this; // chaining
+ },
+
+ hide: function(){
+ this.css('display', 'none');
+ return this; // chaining
+ },
+
+ visible: function(){
+ var cy = this.cy();
+ if( !cy.styleEnabled() ){ return true; }
+
+ var ele = this[0];
+ var hasCompoundNodes = cy.hasCompoundNodes();
+
+ if( ele ){
+ var style = ele._private.style;
+
+ if(
+ style['visibility'].value !== 'visible'
+ || style['display'].value !== 'element'
+ ){
+ return false;
+ }
+
+ if( ele._private.group === 'nodes' ){
+ if( !hasCompoundNodes ){ return true; }
+
+ var parents = ele._private.data.parent ? ele.parents() : null;
+
+ if( parents ){
+ for( var i = 0; i < parents.length; i++ ){
+ var parent = parents[i];
+ var pStyle = parent._private.style;
+ var pVis = pStyle['visibility'].value;
+ var pDis = pStyle['display'].value;
+
+ if( pVis !== 'visible' || pDis !== 'element' ){
+ return false;
+ }
+ }
+ }
+
+ return true;
+ } else {
+ var src = ele._private.source;
+ var tgt = ele._private.target;
+
+ return src.visible() && tgt.visible();
+ }
+
+ }
+ },
+
+ hidden: function(){
+ var ele = this[0];
+
+ if( ele ){
+ return !ele.visible();
+ }
+ },
+
+ effectiveOpacity: function(){
+ var cy = this.cy();
+ if( !cy.styleEnabled() ){ return 1; }
+
+ var hasCompoundNodes = cy.hasCompoundNodes();
+ var ele = this[0];
+
+ if( ele ){
+ var _p = ele._private;
+ var parentOpacity = _p.style.opacity.value;
+
+ if( !hasCompoundNodes ){ return parentOpacity; }
+
+ var parents = !_p.data.parent ? null : ele.parents();
+
+ if( parents ){
+ for( var i = 0; i < parents.length; i++ ){
+ var parent = parents[i];
+ var opacity = parent._private.style.opacity.value;
+
+ parentOpacity = opacity * parentOpacity;
+ }
+ }
+
+ return parentOpacity;
+ }
+ },
+
+ transparent: function(){
+ var cy = this.cy();
+ if( !cy.styleEnabled() ){ return false; }
+
+ var ele = this[0];
+ var hasCompoundNodes = ele.cy().hasCompoundNodes();
+
+ if( ele ){
+ if( !hasCompoundNodes ){
+ return ele._private.style.opacity.value === 0;
+ } else {
+ return ele.effectiveOpacity() === 0;
+ }
+ }
+ },
+
+ isFullAutoParent: function(){
+ var cy = this.cy();
+ if( !cy.styleEnabled() ){ return false; }
+
+ var ele = this[0];
+
+ if( ele ){
+ var autoW = ele._private.style['width'].value === 'auto';
+ var autoH = ele._private.style['height'].value === 'auto';
+
+ return ele.isParent() && autoW && autoH;
+ }
+ },
+
+ backgrounding: function(){
+ var cy = this.cy();
+ if( !cy.styleEnabled() ){ return false; }
+
+ var ele = this[0];
+
+ return ele._private.backgrounding ? true : false;
+ }
+
+});
+
+
+elesfn.bypass = elesfn.style = elesfn.css;
+elesfn.renderedStyle = elesfn.renderedCss;
+elesfn.removeBypass = elesfn.removeStyle = elesfn.removeCss;
+
+module.exports = elesfn;
+
+},{"../is":77}],27:[function(_dereq_,module,exports){
+'use strict';
+
+var elesfn = {};
+
+function defineSwitchFunction(params){
+ return function(){
+ var args = arguments;
+ var changedEles = [];
+
+ // e.g. cy.nodes().select( data, handler )
+ if( args.length === 2 ){
+ var data = args[0];
+ var handler = args[1];
+ this.bind( params.event, data, handler );
+ }
+
+ // e.g. cy.nodes().select( handler )
+ else if( args.length === 1 ){
+ var handler = args[0];
+ this.bind( params.event, handler );
+ }
+
+ // e.g. cy.nodes().select()
+ else if( args.length === 0 ){
+ for( var i = 0; i < this.length; i++ ){
+ var ele = this[i];
+ var able = !params.ableField || ele._private[params.ableField];
+ var changed = ele._private[params.field] != params.value;
+
+ if( params.overrideAble ){
+ var overrideAble = params.overrideAble(ele);
+
+ if( overrideAble !== undefined ){
+ able = overrideAble;
+
+ if( !overrideAble ){ return this; } // to save cycles assume not able for all on override
+ }
+ }
+
+ if( able ){
+ ele._private[params.field] = params.value;
+
+ if( changed ){
+ changedEles.push( ele );
+ }
+ }
+ }
+
+ var changedColl = this.spawn( changedEles );
+ changedColl.updateStyle(); // change of state => possible change of style
+ changedColl.trigger( params.event );
+ }
+
+ return this;
+ };
+}
+
+function defineSwitchSet( params ){
+ elesfn[ params.field ] = function(){
+ var ele = this[0];
+
+ if( ele ){
+ if( params.overrideField ){
+ var val = params.overrideField(ele);
+
+ if( val !== undefined ){
+ return val;
+ }
+ }
+
+ return ele._private[ params.field ];
+ }
+ };
+
+ elesfn[ params.on ] = defineSwitchFunction({
+ event: params.on,
+ field: params.field,
+ ableField: params.ableField,
+ overrideAble: params.overrideAble,
+ value: true
+ });
+
+ elesfn[ params.off ] = defineSwitchFunction({
+ event: params.off,
+ field: params.field,
+ ableField: params.ableField,
+ overrideAble: params.overrideAble,
+ value: false
+ });
+}
+
+defineSwitchSet({
+ field: 'locked',
+ overrideField: function(ele){
+ return ele.cy().autolock() ? true : undefined;
+ },
+ on: 'lock',
+ off: 'unlock'
+});
+
+defineSwitchSet({
+ field: 'grabbable',
+ overrideField: function(ele){
+ return ele.cy().autoungrabify() ? false : undefined;
+ },
+ on: 'grabify',
+ off: 'ungrabify'
+});
+
+defineSwitchSet({
+ field: 'selected',
+ ableField: 'selectable',
+ overrideAble: function(ele){
+ return ele.cy().autounselectify() ? false : undefined;
+ },
+ on: 'select',
+ off: 'unselect'
+});
+
+defineSwitchSet({
+ field: 'selectable',
+ overrideField: function(ele){
+ return ele.cy().autounselectify() ? false : undefined;
+ },
+ on: 'selectify',
+ off: 'unselectify'
+});
+
+elesfn.deselect = elesfn.unselect;
+
+elesfn.grabbed = function(){
+ var ele = this[0];
+ if( ele ){
+ return ele._private.grabbed;
+ }
+};
+
+defineSwitchSet({
+ field: 'active',
+ on: 'activate',
+ off: 'unactivate'
+});
+
+elesfn.inactive = function(){
+ var ele = this[0];
+ if( ele ){
+ return !ele._private.active;
+ }
+};
+
+module.exports = elesfn;
+
+},{}],28:[function(_dereq_,module,exports){
+'use strict';
+
+var util = _dereq_('../util');
+var is = _dereq_('../is');
+
+var elesfn = {};
+
+util.extend(elesfn, {
+ // get the root nodes in the DAG
+ roots: function( selector ){
+ var eles = this;
+ var roots = [];
+
+ for( var i = 0; i < eles.length; i++ ){
+ var ele = eles[i];
+ if( !ele.isNode() ){
+ continue;
+ }
+
+ var hasEdgesPointingIn = ele.connectedEdges(function(){
+ return this.data('target') === ele.id() && this.data('source') !== ele.id();
+ }).length > 0;
+
+ if( !hasEdgesPointingIn ){
+ roots.push( ele );
+ }
+ }
+
+ return this.spawn( roots, { unique: true } ).filter( selector );
+ },
+
+ // get the leaf nodes in the DAG
+ leaves: function( selector ){
+ var eles = this;
+ var leaves = [];
+
+ for( var i = 0; i < eles.length; i++ ){
+ var ele = eles[i];
+ if( !ele.isNode() ){
+ continue;
+ }
+
+ var hasEdgesPointingOut = ele.connectedEdges(function(){
+ return this.data('source') === ele.id() && this.data('target') !== ele.id();
+ }).length > 0;
+
+ if( !hasEdgesPointingOut ){
+ leaves.push( ele );
+ }
+ }
+
+ return this.spawn( leaves, { unique: true } ).filter( selector );
+ },
+
+ // normally called children in graph theory
+ // these nodes =edges=> outgoing nodes
+ outgoers: function( selector ){
+ var eles = this;
+ var oEles = [];
+
+ for( var i = 0; i < eles.length; i++ ){
+ var ele = eles[i];
+ var eleId = ele.id();
+
+ if( !ele.isNode() ){ continue; }
+
+ var edges = ele._private.edges;
+ for( var j = 0; j < edges.length; j++ ){
+ var edge = edges[j];
+ var srcId = edge._private.data.source;
+ var tgtId = edge._private.data.target;
+
+ if( srcId === eleId && tgtId !== eleId ){
+ oEles.push( edge );
+ oEles.push( edge.target()[0] );
+ }
+ }
+ }
+
+ return this.spawn( oEles, { unique: true } ).filter( selector );
+ },
+
+ // aka DAG descendants
+ successors: function( selector ){
+ var eles = this;
+ var sEles = [];
+ var sElesIds = {};
+
+ for(;;){
+ var outgoers = eles.outgoers();
+
+ if( outgoers.length === 0 ){ break; } // done if no outgoers left
+
+ var newOutgoers = false;
+ for( var i = 0; i < outgoers.length; i++ ){
+ var outgoer = outgoers[i];
+ var outgoerId = outgoer.id();
+
+ if( !sElesIds[ outgoerId ] ){
+ sElesIds[ outgoerId ] = true;
+ sEles.push( outgoer );
+ newOutgoers = true;
+ }
+ }
+
+ if( !newOutgoers ){ break; } // done if touched all outgoers already
+
+ eles = outgoers;
+ }
+
+ return this.spawn( sEles, { unique: true } ).filter( selector );
+ },
+
+ // normally called parents in graph theory
+ // these nodes <=edges= incoming nodes
+ incomers: function( selector ){
+ var eles = this;
+ var oEles = [];
+
+ for( var i = 0; i < eles.length; i++ ){
+ var ele = eles[i];
+ var eleId = ele.id();
+
+ if( !ele.isNode() ){ continue; }
+
+ var edges = ele._private.edges;
+ for( var j = 0; j < edges.length; j++ ){
+ var edge = edges[j];
+ var srcId = edge._private.data.source;
+ var tgtId = edge._private.data.target;
+
+ if( tgtId === eleId && srcId !== eleId ){
+ oEles.push( edge );
+ oEles.push( edge.source()[0] );
+ }
+ }
+ }
+
+ return this.spawn( oEles, { unique: true } ).filter( selector );
+ },
+
+ // aka DAG ancestors
+ predecessors: function( selector ){
+ var eles = this;
+ var pEles = [];
+ var pElesIds = {};
+
+ for(;;){
+ var incomers = eles.incomers();
+
+ if( incomers.length === 0 ){ break; } // done if no incomers left
+
+ var newIncomers = false;
+ for( var i = 0; i < incomers.length; i++ ){
+ var incomer = incomers[i];
+ var incomerId = incomer.id();
+
+ if( !pElesIds[ incomerId ] ){
+ pElesIds[ incomerId ] = true;
+ pEles.push( incomer );
+ newIncomers = true;
+ }
+ }
+
+ if( !newIncomers ){ break; } // done if touched all incomers already
+
+ eles = incomers;
+ }
+
+ return this.spawn( pEles, { unique: true } ).filter( selector );
+ }
+});
+
+
+// Neighbourhood functions
+//////////////////////////
+
+util.extend(elesfn, {
+ neighborhood: function(selector){
+ var elements = [];
+ var nodes = this.nodes();
+
+ for( var i = 0; i < nodes.length; i++ ){ // for all nodes
+ var node = nodes[i];
+ var connectedEdges = node.connectedEdges();
+
+ // for each connected edge, add the edge and the other node
+ for( var j = 0; j < connectedEdges.length; j++ ){
+ var edge = connectedEdges[j];
+ var src = edge._private.source;
+ var tgt = edge._private.target;
+ var otherNode = node === src ? tgt : src;
+
+ // need check in case of loop
+ if( otherNode.length > 0 ){
+ elements.push( otherNode[0] ); // add node 1 hop away
+ }
+
+ // add connected edge
+ elements.push( edge[0] );
+ }
+
+ }
+
+ return ( this.spawn( elements, { unique: true } ) ).filter( selector );
+ },
+
+ closedNeighborhood: function(selector){
+ return this.neighborhood().add( this ).filter( selector );
+ },
+
+ openNeighborhood: function(selector){
+ return this.neighborhood( selector );
+ }
+});
+
+// aliases
+elesfn.neighbourhood = elesfn.neighborhood;
+elesfn.closedNeighbourhood = elesfn.closedNeighborhood;
+elesfn.openNeighbourhood = elesfn.openNeighborhood;
+
+// Edge functions
+/////////////////
+
+util.extend(elesfn, {
+ source: function( selector ){
+ var ele = this[0];
+ var src;
+
+ if( ele ){
+ src = ele._private.source;
+ }
+
+ return src && selector ? src.filter( selector ) : src;
+ },
+
+ target: function( selector ){
+ var ele = this[0];
+ var tgt;
+
+ if( ele ){
+ tgt = ele._private.target;
+ }
+
+ return tgt && selector ? tgt.filter( selector ) : tgt;
+ },
+
+ sources: defineSourceFunction({
+ attr: 'source'
+ }),
+
+ targets: defineSourceFunction({
+ attr: 'target'
+ })
+});
+
+function defineSourceFunction( params ){
+ return function( selector ){
+ var sources = [];
+
+ for( var i = 0; i < this.length; i++ ){
+ var ele = this[i];
+ var src = ele._private[ params.attr ];
+
+ if( src ){
+ sources.push( src );
+ }
+ }
+
+ return this.spawn( sources, { unique: true } ).filter( selector );
+ };
+}
+
+util.extend(elesfn, {
+ edgesWith: defineEdgesWithFunction(),
+
+ edgesTo: defineEdgesWithFunction({
+ thisIs: 'source'
+ })
+});
+
+function defineEdgesWithFunction( params ){
+
+ return function edgesWithImpl( otherNodes ){
+ var elements = [];
+ var cy = this._private.cy;
+ var p = params || {};
+
+ // get elements if a selector is specified
+ if( is.string(otherNodes) ){
+ otherNodes = cy.$( otherNodes );
+ }
+
+ var thisIds = this._private.ids;
+ var otherIds = otherNodes._private.ids;
+
+ for( var h = 0; h < otherNodes.length; h++ ){
+ var edges = otherNodes[h]._private.edges;
+
+ for( var i = 0; i < edges.length; i++ ){
+ var edge = edges[i];
+ var edgeData = edge._private.data;
+ var thisToOther = thisIds[ edgeData.source ] && otherIds[ edgeData.target ];
+ var otherToThis = otherIds[ edgeData.source ] && thisIds[ edgeData.target ];
+ var edgeConnectsThisAndOther = thisToOther || otherToThis;
+
+ if( !edgeConnectsThisAndOther ){ continue; }
+
+ if( p.thisIs ){
+ if( p.thisIs === 'source' && !thisToOther ){ continue; }
+
+ if( p.thisIs === 'target' && !otherToThis ){ continue; }
+ }
+
+ elements.push( edge );
+ }
+ }
+
+ return this.spawn( elements, { unique: true } );
+ };
+}
+
+util.extend(elesfn, {
+ connectedEdges: function( selector ){
+ var retEles = [];
+
+ var eles = this;
+ for( var i = 0; i < eles.length; i++ ){
+ var node = eles[i];
+ if( !node.isNode() ){ continue; }
+
+ var edges = node._private.edges;
+
+ for( var j = 0; j < edges.length; j++ ){
+ var edge = edges[j];
+ retEles.push( edge );
+ }
+ }
+
+ return this.spawn( retEles, { unique: true } ).filter( selector );
+ },
+
+ connectedNodes: function( selector ){
+ var retEles = [];
+
+ var eles = this;
+ for( var i = 0; i < eles.length; i++ ){
+ var edge = eles[i];
+ if( !edge.isEdge() ){ continue; }
+
+ retEles.push( edge.source()[0] );
+ retEles.push( edge.target()[0] );
+ }
+
+ return this.spawn( retEles, { unique: true } ).filter( selector );
+ },
+
+ parallelEdges: defineParallelEdgesFunction(),
+
+ codirectedEdges: defineParallelEdgesFunction({
+ codirected: true
+ })
+});
+
+function defineParallelEdgesFunction(params){
+ var defaults = {
+ codirected: false
+ };
+ params = util.extend({}, defaults, params);
+
+ return function( selector ){
+ var elements = [];
+ var edges = this.edges();
+ var p = params;
+
+ // look at all the edges in the collection
+ for( var i = 0; i < edges.length; i++ ){
+ var edge1 = edges[i];
+ var src1 = edge1.source()[0];
+ var srcid1 = src1.id();
+ var tgt1 = edge1.target()[0];
+ var tgtid1 = tgt1.id();
+ var srcEdges1 = src1._private.edges;
+
+ // look at edges connected to the src node of this edge
+ for( var j = 0; j < srcEdges1.length; j++ ){
+ var edge2 = srcEdges1[j];
+ var edge2data = edge2._private.data;
+ var tgtid2 = edge2data.target;
+ var srcid2 = edge2data.source;
+
+ var codirected = tgtid2 === tgtid1 && srcid2 === srcid1;
+ var oppdirected = srcid1 === tgtid2 && tgtid1 === srcid2;
+
+ if( (p.codirected && codirected) || (!p.codirected && (codirected || oppdirected)) ){
+ elements.push( edge2 );
+ }
+ }
+ }
+
+ return this.spawn( elements, { unique: true } ).filter( selector );
+ };
+
+}
+
+// Misc functions
+/////////////////
+
+util.extend(elesfn, {
+ components: function(){
+ var cy = this.cy();
+ var visited = cy.collection();
+ var unvisited = this.nodes();
+ var components = [];
+
+ var visitInComponent = function( node, component ){
+ visited.merge( node );
+ unvisited.unmerge( node );
+ component.merge( node );
+ };
+
+ do {
+ var component = cy.collection();
+ components.push( component );
+
+ var root = unvisited[0];
+ visitInComponent( root, component );
+
+ this.bfs({
+ directed: false,
+ roots: root,
+ visit: function( i, depth, v, e, u ){
+ visitInComponent( v, component );
+ }
+ });
+
+ } while( unvisited.length > 0 );
+
+ return components.map(function( component ){
+ return component.closedNeighborhood(); // add the edges
+ });
+ }
+});
+
+module.exports = elesfn;
+
+},{"../is":77,"../util":94}],29:[function(_dereq_,module,exports){
+'use strict';
+
+var zIndexSort = function( a, b ){
+ var cy = a.cy();
+ var a_p = a._private;
+ var b_p = b._private;
+ var zDiff = a_p.style['z-index'].value - b_p.style['z-index'].value;
+ var depthA = 0;
+ var depthB = 0;
+ var hasCompoundNodes = cy.hasCompoundNodes();
+ var aIsNode = a_p.group === 'nodes';
+ var aIsEdge = a_p.group === 'edges';
+ var bIsNode = b_p.group === 'nodes';
+ var bIsEdge = b_p.group === 'edges';
+
+ // no need to calculate element depth if there is no compound node
+ if( hasCompoundNodes ){
+ depthA = a.zDepth();
+ depthB = b.zDepth();
+ }
+
+ var depthDiff = depthA - depthB;
+ var sameDepth = depthDiff === 0;
+
+ if( sameDepth ){
+
+ if( aIsNode && bIsEdge ){
+ return 1; // 'a' is a node, it should be drawn later
+
+ } else if( aIsEdge && bIsNode ){
+ return -1; // 'a' is an edge, it should be drawn first
+
+ } else { // both nodes or both edges
+ if( zDiff === 0 ){ // same z-index => compare indices in the core (order added to graph w/ last on top)
+ return a_p.index - b_p.index;
+ } else {
+ return zDiff;
+ }
+ }
+
+ // elements on different level
+ } else {
+ return depthDiff; // deeper element should be drawn later
+ }
+
+};
+
+module.exports = zIndexSort;
+
+},{}],30:[function(_dereq_,module,exports){
+'use strict';
+
+var is = _dereq_('../is');
+var util = _dereq_('../util');
+var Collection = _dereq_('../collection');
+var Element = _dereq_('../collection/element');
+var window = _dereq_('../window');
+var document = window ? window.document : null;
+var NullRenderer = _dereq_('../extensions/renderer/null');
+
+var corefn = {
+ add: function(opts){
+
+ var elements;
+ var cy = this;
+
+ // add the elements
+ if( is.elementOrCollection(opts) ){
+ var eles = opts;
+
+ if( eles._private.cy === cy ){ // same instance => just restore
+ elements = eles.restore();
+
+ } else { // otherwise, copy from json
+ var jsons = [];
+
+ for( var i = 0; i < eles.length; i++ ){
+ var ele = eles[i];
+ jsons.push( ele.json() );
+ }
+
+ elements = new Collection( cy, jsons );
+ }
+ }
+
+ // specify an array of options
+ else if( is.array(opts) ){
+ var jsons = opts;
+
+ elements = new Collection(cy, jsons);
+ }
+
+ // specify via opts.nodes and opts.edges
+ else if( is.plainObject(opts) && (is.array(opts.nodes) || is.array(opts.edges)) ){
+ var elesByGroup = opts;
+ var jsons = [];
+
+ var grs = ['nodes', 'edges'];
+ for( var i = 0, il = grs.length; i < il; i++ ){
+ var group = grs[i];
+ var elesArray = elesByGroup[group];
+
+ if( is.array(elesArray) ){
+
+ for( var j = 0, jl = elesArray.length; j < jl; j++ ){
+ var json = util.extend( { group: group }, elesArray[j] );
+
+ jsons.push( json );
+ }
+ }
+ }
+
+ elements = new Collection(cy, jsons);
+ }
+
+ // specify options for one element
+ else {
+ var json = opts;
+ elements = (new Element( cy, json )).collection();
+ }
+
+ return elements;
+ },
+
+ remove: function(collection){
+ if( is.elementOrCollection(collection) ){
+ collection = collection;
+ } else if( is.string(collection) ){
+ var selector = collection;
+ collection = this.$( selector );
+ }
+
+ return collection.remove();
+ },
+
+ load: function(elements, onload, ondone){
+ var cy = this;
+
+ cy.notifications(false);
+
+ // remove old elements
+ var oldEles = cy.elements();
+ if( oldEles.length > 0 ){
+ oldEles.remove();
+ }
+
+ if( elements != null ){
+ if( is.plainObject(elements) || is.array(elements) ){
+ cy.add( elements );
+ }
+ }
+
+ cy.one('layoutready', function(e){
+ cy.notifications(true);
+ cy.trigger(e); // we missed this event by turning notifications off, so pass it on
+
+ cy.notify({
+ type: 'load',
+ collection: cy.elements()
+ });
+
+ cy.one('load', onload);
+ cy.trigger('load');
+ }).one('layoutstop', function(){
+ cy.one('done', ondone);
+ cy.trigger('done');
+ });
+
+ var layoutOpts = util.extend({}, cy._private.options.layout);
+ layoutOpts.eles = cy.$();
+
+ cy.layout( layoutOpts );
+
+ return this;
+ }
+};
+
+module.exports = corefn;
+
+},{"../collection":23,"../collection/element":19,"../extensions/renderer/null":73,"../is":77,"../util":94,"../window":100}],31:[function(_dereq_,module,exports){
+'use strict';
+
+var define = _dereq_('../define');
+var util = _dereq_('../util');
+var is = _dereq_('../is');
+
+var corefn = ({
+
+ // pull in animation functions
+ animate: define.animate(),
+ animation: define.animation(),
+ animated: define.animated(),
+ clearQueue: define.clearQueue(),
+ delay: define.delay(),
+ delayAnimation: define.delayAnimation(),
+ stop: define.stop(),
+
+ addToAnimationPool: function( eles ){
+ var cy = this;
+
+ if( !cy.styleEnabled() ){ return; } // save cycles when no style used
+
+ cy._private.aniEles.merge( eles );
+ },
+
+ stopAnimationLoop: function(){
+ this._private.animationsRunning = false;
+ },
+
+ startAnimationLoop: function(){
+ var cy = this;
+
+ cy._private.animationsRunning = true;
+
+ if( !cy.styleEnabled() ){ return; } // save cycles when no style used
+
+ // NB the animation loop will exec in headless environments if style enabled
+ // and explicit cy.destroy() is necessary to stop the loop
+
+ function globalAnimationStep(){
+ if( !cy._private.animationsRunning ){ return; }
+
+ util.requestAnimationFrame(function(now){
+ handleElements(now);
+ globalAnimationStep();
+ });
+ }
+
+ globalAnimationStep(); // first call
+
+ function handleElements( now ){
+ var eles = cy._private.aniEles;
+ var doneEles = [];
+
+ function handleElement( ele, isCore ){
+ var _p = ele._private;
+ var current = _p.animation.current;
+ var queue = _p.animation.queue;
+ var ranAnis = false;
+
+ // if nothing currently animating, get something from the queue
+ if( current.length === 0 ){
+ var next = queue.shift();
+
+ if( next ){
+ current.push( next );
+ }
+ }
+
+ var callbacks = function( callbacks ){
+ for( var j = callbacks.length - 1; j >= 0; j-- ){
+ var cb = callbacks[j];
+
+ cb();
+ }
+
+ callbacks.splice( 0, callbacks.length );
+ };
+
+ // step and remove if done
+ for( var i = current.length - 1; i >= 0; i-- ){
+ var ani = current[i];
+ var ani_p = ani._private;
+
+ if( ani_p.stopped ){
+ current.splice( i, 1 );
+
+ ani_p.hooked = false;
+ ani_p.playing = false;
+ ani_p.started = false;
+
+ callbacks( ani_p.frames );
+
+ continue;
+ }
+
+ if( !ani_p.playing && !ani_p.applying ){ continue; }
+
+ // an apply() while playing shouldn't do anything
+ if( ani_p.playing && ani_p.applying ){
+ ani_p.applying = false;
+ }
+
+ if( !ani_p.started ){
+ startAnimation( ele, ani, now );
+ }
+
+ step( ele, ani, now, isCore );
+
+ if( ani_p.applying ){
+ ani_p.applying = false;
+ }
+
+ callbacks( ani_p.frames );
+
+ if( ani.completed() ){
+ current.splice(i, 1);
+
+ ani_p.hooked = false;
+ ani_p.playing = false;
+ ani_p.started = false;
+
+ callbacks( ani_p.completes );
+ }
+
+ ranAnis = true;
+ }
+
+ if( !isCore && current.length === 0 && queue.length === 0 ){
+ doneEles.push( ele );
+ }
+
+ return ranAnis;
+ } // handleElement
+
+ // handle all eles
+ var ranEleAni = false;
+ for( var e = 0; e < eles.length; e++ ){
+ var ele = eles[e];
+ var handledThisEle = handleElement( ele );
+
+ ranEleAni = ranEleAni || handledThisEle;
+ } // each element
+
+ var ranCoreAni = handleElement( cy, true );
+
+ // notify renderer
+ if( ranEleAni || ranCoreAni ){
+ var toNotify;
+
+ if( eles.length > 0 ){
+ var updatedEles = eles.updateCompoundBounds();
+ toNotify = updatedEles.length > 0 ? eles.add( updatedEles ) : eles;
+ }
+
+ cy.notify({
+ type: 'draw',
+ collection: toNotify
+ });
+ }
+
+ // remove elements from list of currently animating if its queues are empty
+ eles.unmerge( doneEles );
+
+ } // handleElements
+
+ function startAnimation( self, ani, now ){
+ var isCore = is.core( self );
+ var isEles = !isCore;
+ var ele = self;
+ var style = cy._private.style;
+ var ani_p = ani._private;
+
+ if( isEles ){
+ var pos = ele._private.position;
+
+ ani_p.startPosition = ani_p.startPosition || {
+ x: pos.x,
+ y: pos.y
+ };
+
+ ani_p.startStyle = ani_p.startStyle || style.getValueStyle( ele );
+ }
+
+ if( isCore ){
+ var pan = cy._private.pan;
+
+ ani_p.startPan = ani_p.startPan || {
+ x: pan.x,
+ y: pan.y
+ };
+
+ ani_p.startZoom = ani_p.startZoom != null ? ani_p.startZoom : cy._private.zoom;
+ }
+
+ ani_p.started = true;
+ ani_p.startTime = now - ani_p.progress * ani_p.duration;
+ }
+
+ function step( self, ani, now, isCore ){
+ var style = cy._private.style;
+ var isEles = !isCore;
+ var _p = self._private;
+ var ani_p = ani._private;
+ var pEasing = ani_p.easing;
+ var startTime = ani_p.startTime;
+
+ if( !ani_p.easingImpl ){
+
+ if( pEasing == null ){ // use default
+ ani_p.easingImpl = easings['linear'];
+
+ } else { // then define w/ name
+ var easingVals;
+
+ if( is.string( pEasing ) ){
+ var easingProp = style.parse('transition-timing-function', pEasing);
+
+ easingVals = easingProp.value;
+
+ } else { // then assume preparsed array
+ easingVals = pEasing;
+ }
+
+ var name, args;
+
+ if( is.string( easingVals ) ){
+ name = easingVals;
+ args = [];
+ } else {
+ name = easingVals[1];
+ args = easingVals.slice(2).map(function(n){ return +n; });
+ }
+
+ if( args.length > 0 ){ // create with args
+ if( name === 'spring' ){
+ args.push( ani_p.duration ); // need duration to generate spring
+ }
+
+ ani_p.easingImpl = easings[ name ].apply( null, args );
+ } else { // static impl by name
+ ani_p.easingImpl = easings[ name ];
+ }
+ }
+
+ }
+
+ var easing = ani_p.easingImpl;
+ var percent;
+
+ if( ani_p.duration === 0 ){
+ percent = 1;
+ } else {
+ percent = (now - startTime) / ani_p.duration;
+ }
+
+ if( ani_p.applying ){
+ percent = ani_p.progress;
+ }
+
+ if( percent < 0 ){
+ percent = 0;
+ } else if( percent > 1 ){
+ percent = 1;
+ }
+
+ if( ani_p.delay == null ){ // then update
+
+ var startPos = ani_p.startPosition;
+ var endPos = ani_p.position;
+ var pos = _p.position;
+ if( endPos && isEles ){
+ if( valid( startPos.x, endPos.x ) ){
+ pos.x = ease( startPos.x, endPos.x, percent, easing );
+ }
+
+ if( valid( startPos.y, endPos.y ) ){
+ pos.y = ease( startPos.y, endPos.y, percent, easing );
+ }
+ }
+
+ var startPan = ani_p.startPan;
+ var endPan = ani_p.pan;
+ var pan = _p.pan;
+ var animatingPan = endPan != null && isCore;
+ if( animatingPan ){
+ if( valid( startPan.x, endPan.x ) ){
+ pan.x = ease( startPan.x, endPan.x, percent, easing );
+ }
+
+ if( valid( startPan.y, endPan.y ) ){
+ pan.y = ease( startPan.y, endPan.y, percent, easing );
+ }
+
+ self.trigger('pan');
+ }
+
+ var startZoom = ani_p.startZoom;
+ var endZoom = ani_p.zoom;
+ var animatingZoom = endZoom != null && isCore;
+ if( animatingZoom ){
+ if( valid( startZoom, endZoom ) ){
+ _p.zoom = ease( startZoom, endZoom, percent, easing );
+ }
+
+ self.trigger('zoom');
+ }
+
+ if( animatingPan || animatingZoom ){
+ self.trigger('viewport');
+ }
+
+ var props = ani_p.style;
+ if( props && isEles ){
+
+ for( var i = 0; i < props.length; i++ ){
+ var prop = props[i];
+ var name = prop.name;
+ var end = prop;
+
+ var start = ani_p.startStyle[ name ];
+ var easedVal = ease( start, end, percent, easing );
+
+ style.overrideBypass( self, name, easedVal );
+ } // for props
+
+ } // if
+
+ }
+
+ if( is.fn(ani_p.step) ){
+ ani_p.step.apply( self, [ now ] );
+ }
+
+ ani_p.progress = percent;
+
+ return percent;
+ }
+
+ function valid(start, end){
+ if( start == null || end == null ){
+ return false;
+ }
+
+ if( is.number(start) && is.number(end) ){
+ return true;
+ } else if( (start) && (end) ){
+ return true;
+ }
+
+ return false;
+ }
+
+ // assumes p0 = 0, p3 = 1
+ function evalCubicBezier( p1, p2, t ){
+ var one_t = 1 - t;
+ var tsq = t*t;
+
+ return ( 3 * one_t * one_t * t * p1 ) + ( 3 * one_t * tsq * p2 ) + tsq * t;
+ }
+
+ function cubicBezier( p1, p2 ){
+ return function( start, end, percent ){
+ return start + (end - start) * evalCubicBezier( p1, p2, percent );
+ };
+ }
+
+ /* Runge-Kutta spring physics function generator. Adapted from Framer.js, copyright Koen Bok. MIT License: http://en.wikipedia.org/wiki/MIT_License */
+ /* Given a tension, friction, and duration, a simulation at 60FPS will first run without a defined duration in order to calculate the full path. A second pass
+ then adjusts the time delta -- using the relation between actual time and duration -- to calculate the path for the duration-constrained animation. */
+ var generateSpringRK4 = (function () {
+ function springAccelerationForState (state) {
+ return (-state.tension * state.x) - (state.friction * state.v);
+ }
+
+ function springEvaluateStateWithDerivative (initialState, dt, derivative) {
+ var state = {
+ x: initialState.x + derivative.dx * dt,
+ v: initialState.v + derivative.dv * dt,
+ tension: initialState.tension,
+ friction: initialState.friction
+ };
+
+ return { dx: state.v, dv: springAccelerationForState(state) };
+ }
+
+ function springIntegrateState (state, dt) {
+ var a = {
+ dx: state.v,
+ dv: springAccelerationForState(state)
+ },
+ b = springEvaluateStateWithDerivative(state, dt * 0.5, a),
+ c = springEvaluateStateWithDerivative(state, dt * 0.5, b),
+ d = springEvaluateStateWithDerivative(state, dt, c),
+ dxdt = 1.0 / 6.0 * (a.dx + 2.0 * (b.dx + c.dx) + d.dx),
+ dvdt = 1.0 / 6.0 * (a.dv + 2.0 * (b.dv + c.dv) + d.dv);
+
+ state.x = state.x + dxdt * dt;
+ state.v = state.v + dvdt * dt;
+
+ return state;
+ }
+
+ return function springRK4Factory (tension, friction, duration) {
+
+ var initState = {
+ x: -1,
+ v: 0,
+ tension: null,
+ friction: null
+ },
+ path = [0],
+ time_lapsed = 0,
+ tolerance = 1 / 10000,
+ DT = 16 / 1000,
+ have_duration, dt, last_state;
+
+ tension = parseFloat(tension) || 500;
+ friction = parseFloat(friction) || 20;
+ duration = duration || null;
+
+ initState.tension = tension;
+ initState.friction = friction;
+
+ have_duration = duration !== null;
+
+ /* Calculate the actual time it takes for this animation to complete with the provided conditions. */
+ if (have_duration) {
+ /* Run the simulation without a duration. */
+ time_lapsed = springRK4Factory(tension, friction);
+ /* Compute the adjusted time delta. */
+ dt = time_lapsed / duration * DT;
+ } else {
+ dt = DT;
+ }
+
+ while (true) {
+ /* Next/step function .*/
+ last_state = springIntegrateState(last_state || initState, dt);
+ /* Store the position. */
+ path.push(1 + last_state.x);
+ time_lapsed += 16;
+ /* If the change threshold is reached, break. */
+ if (!(Math.abs(last_state.x) > tolerance && Math.abs(last_state.v) > tolerance)) {
+ break;
+ }
+ }
+
+ /* If duration is not defined, return the actual time required for completing this animation. Otherwise, return a closure that holds the
+ computed path and returns a snapshot of the position according to a given percentComplete. */
+ return !have_duration ? time_lapsed : function(percentComplete) { return path[ (percentComplete * (path.length - 1)) | 0 ]; };
+ };
+ }());
+
+ var easings = {
+ 'linear': function( start, end, percent ){
+ return start + (end - start) * percent;
+ },
+
+ // default easings
+ 'ease': cubicBezier( 0.25, 0.1, 0.25, 1 ),
+ 'ease-in': cubicBezier( 0.42, 0, 1, 1 ),
+ 'ease-out': cubicBezier( 0, 0, 0.58, 1 ),
+ 'ease-in-out': cubicBezier( 0.42, 0, 0.58, 1 ),
+
+ // sine
+ 'ease-in-sine': cubicBezier( 0.47, 0, 0.745, 0.715 ),
+ 'ease-out-sine': cubicBezier( 0.39, 0.575, 0.565, 1 ),
+ 'ease-in-out-sine': cubicBezier( 0.445, 0.05, 0.55, 0.95 ),
+
+ // quad
+ 'ease-in-quad': cubicBezier( 0.55, 0.085, 0.68, 0.53 ),
+ 'ease-out-quad': cubicBezier( 0.25, 0.46, 0.45, 0.94 ),
+ 'ease-in-out-quad': cubicBezier( 0.455, 0.03, 0.515, 0.955 ),
+
+ // cubic
+ 'ease-in-cubic': cubicBezier( 0.55, 0.055, 0.675, 0.19 ),
+ 'ease-out-cubic': cubicBezier( 0.215, 0.61, 0.355, 1 ),
+ 'ease-in-out-cubic': cubicBezier( 0.645, 0.045, 0.355, 1 ),
+
+ // quart
+ 'ease-in-quart': cubicBezier( 0.895, 0.03, 0.685, 0.22 ),
+ 'ease-out-quart': cubicBezier( 0.165, 0.84, 0.44, 1 ),
+ 'ease-in-out-quart': cubicBezier( 0.77, 0, 0.175, 1 ),
+
+ // quint
+ 'ease-in-quint': cubicBezier( 0.755, 0.05, 0.855, 0.06 ),
+ 'ease-out-quint': cubicBezier( 0.23, 1, 0.32, 1 ),
+ 'ease-in-out-quint': cubicBezier( 0.86, 0, 0.07, 1 ),
+
+ // expo
+ 'ease-in-expo': cubicBezier( 0.95, 0.05, 0.795, 0.035 ),
+ 'ease-out-expo': cubicBezier( 0.19, 1, 0.22, 1 ),
+ 'ease-in-out-expo': cubicBezier( 1, 0, 0, 1 ),
+
+ // circ
+ 'ease-in-circ': cubicBezier( 0.6, 0.04, 0.98, 0.335 ),
+ 'ease-out-circ': cubicBezier( 0.075, 0.82, 0.165, 1 ),
+ 'ease-in-out-circ': cubicBezier( 0.785, 0.135, 0.15, 0.86 ),
+
+
+ // user param easings...
+
+ 'spring': function( tension, friction, duration ){
+ var spring = generateSpringRK4( tension, friction, duration );
+
+ return function( start, end, percent ){
+ return start + (end - start) * spring( percent );
+ };
+ },
+
+ 'cubic-bezier': function( x1, y1, x2, y2 ){
+ return cubicBezier( x1, y1, x2, y2 );
+ }
+ };
+
+ function ease( startProp, endProp, percent, easingFn ){
+ if( percent < 0 ){
+ percent = 0;
+ } else if( percent > 1 ){
+ percent = 1;
+ }
+
+ var start, end;
+
+ if( startProp.pfValue != null || startProp.value != null ){
+ start = startProp.pfValue != null ? startProp.pfValue : startProp.value;
+ } else {
+ start = startProp;
+ }
+
+ if( endProp.pfValue != null || endProp.value != null ){
+ end = endProp.pfValue != null ? endProp.pfValue : endProp.value;
+ } else {
+ end = endProp;
+ }
+
+ if( is.number(start) && is.number(end) ){
+ return easingFn( start, end, percent );
+
+ } else if( is.array(start) && is.array(end) ){
+ var easedArr = [];
+
+ for( var i = 0; i < end.length; i++ ){
+ var si = start[i];
+ var ei = end[i];
+
+ if( si != null && ei != null ){
+ var val = easingFn(si, ei, percent);
+
+ if( startProp.roundValue ){ val = Math.round( val ); }
+
+ easedArr.push( val );
+ } else {
+ easedArr.push( ei );
+ }
+ }
+
+ return easedArr;
+ }
+
+ return undefined;
+ }
+
+ }
+
+});
+
+module.exports = corefn;
+
+},{"../define":41,"../is":77,"../util":94}],32:[function(_dereq_,module,exports){
+'use strict';
+
+var define = _dereq_('../define');
+
+var corefn = ({
+ on: define.on(), // .on( events [, selector] [, data], handler)
+ one: define.on({ unbindSelfOnTrigger: true }),
+ once: define.on({ unbindAllBindersOnTrigger: true }),
+ off: define.off(), // .off( events [, selector] [, handler] )
+ trigger: define.trigger() // .trigger( events [, extraParams] )
+});
+
+define.eventAliasesOn( corefn );
+
+module.exports = corefn;
+
+},{"../define":41}],33:[function(_dereq_,module,exports){
+'use strict';
+
+var corefn = ({
+
+ png: function( options ){
+ var renderer = this._private.renderer;
+ options = options || {};
+
+ return renderer.png( options );
+ },
+
+ jpg: function( options ){
+ var renderer = this._private.renderer;
+ options = options || {};
+
+ options.bg = options.bg || '#fff';
+
+ return renderer.jpg( options );
+ }
+
+});
+
+corefn.jpeg = corefn.jpg;
+
+module.exports = corefn;
+
+},{}],34:[function(_dereq_,module,exports){
+'use strict';
+
+var window = _dereq_('../window');
+var util = _dereq_('../util');
+var Collection = _dereq_('../collection');
+var is = _dereq_('../is');
+var Promise = _dereq_('../promise');
+var define = _dereq_('../define');
+
+var Core = function( opts ){
+ if( !(this instanceof Core) ){
+ return new Core(opts);
+ }
+ var cy = this;
+
+ opts = util.extend({}, opts);
+
+ var container = opts.container;
+
+ // allow for passing a wrapped jquery object
+ // e.g. cytoscape({ container: $('#cy') })
+ if( container && !is.htmlElement( container ) && is.htmlElement( container[0] ) ){
+ container = container[0];
+ }
+
+ var reg = container ? container._cyreg : null; // e.g. already registered some info (e.g. readies) via jquery
+ reg = reg || {};
+
+ if( reg && reg.cy ){
+ reg.cy.destroy();
+
+ reg = {}; // old instance => replace reg completely
+ }
+
+ var readies = reg.readies = reg.readies || [];
+
+ if( container ){ container._cyreg = reg; } // make sure container assoc'd reg points to this cy
+ reg.cy = cy;
+
+ var head = window !== undefined && container !== undefined && !opts.headless;
+ var options = opts;
+ options.layout = util.extend( { name: head ? 'grid' : 'null' }, options.layout );
+ options.renderer = util.extend( { name: head ? 'canvas' : 'null' }, options.renderer );
+
+ var defVal = function( def, val, altVal ){
+ if( val !== undefined ){
+ return val;
+ } else if( altVal !== undefined ){
+ return altVal;
+ } else {
+ return def;
+ }
+ };
+
+ var _p = this._private = {
+ container: container, // html dom ele container
+ ready: false, // whether ready has been triggered
+ initrender: false, // has initrender has been triggered
+ options: options, // cached options
+ elements: [], // array of elements
+ id2index: {}, // element id => index in elements array
+ listeners: [], // list of listeners
+ onRenders: [], // rendering listeners
+ aniEles: Collection(this), // elements being animated
+ scratch: {}, // scratch object for core
+ layout: null,
+ renderer: null,
+ notificationsEnabled: true, // whether notifications are sent to the renderer
+ minZoom: 1e-50,
+ maxZoom: 1e50,
+ zoomingEnabled: defVal(true, options.zoomingEnabled),
+ userZoomingEnabled: defVal(true, options.userZoomingEnabled),
+ panningEnabled: defVal(true, options.panningEnabled),
+ userPanningEnabled: defVal(true, options.userPanningEnabled),
+ boxSelectionEnabled: defVal(true, options.boxSelectionEnabled),
+ autolock: defVal(false, options.autolock, options.autolockNodes),
+ autoungrabify: defVal(false, options.autoungrabify, options.autoungrabifyNodes),
+ autounselectify: defVal(false, options.autounselectify),
+ styleEnabled: options.styleEnabled === undefined ? head : options.styleEnabled,
+ zoom: is.number(options.zoom) ? options.zoom : 1,
+ pan: {
+ x: is.plainObject(options.pan) && is.number(options.pan.x) ? options.pan.x : 0,
+ y: is.plainObject(options.pan) && is.number(options.pan.y) ? options.pan.y : 0
+ },
+ animation: { // object for currently-running animations
+ current: [],
+ queue: []
+ },
+ hasCompoundNodes: false,
+ deferredExecQueue: []
+ };
+
+ // set selection type
+ var selType = options.selectionType;
+ if( selType === undefined || (selType !== 'additive' && selType !== 'single') ){
+ // then set default
+
+ _p.selectionType = 'single';
+ } else {
+ _p.selectionType = selType;
+ }
+
+ // init zoom bounds
+ if( is.number(options.minZoom) && is.number(options.maxZoom) && options.minZoom < options.maxZoom ){
+ _p.minZoom = options.minZoom;
+ _p.maxZoom = options.maxZoom;
+ } else if( is.number(options.minZoom) && options.maxZoom === undefined ){
+ _p.minZoom = options.minZoom;
+ } else if( is.number(options.maxZoom) && options.minZoom === undefined ){
+ _p.maxZoom = options.maxZoom;
+ }
+
+ var loadExtData = function( next ){
+ var anyIsPromise = false;
+
+ for( var i = 0; i < extData.length; i++ ){
+ var datum = extData[i];
+
+ if( is.promise(datum) ){
+ anyIsPromise = true;
+ break;
+ }
+ }
+
+ if( anyIsPromise ){
+ return Promise.all( extData ).then( next ); // load all data asynchronously, then exec rest of init
+ } else {
+ next( extData ); // exec synchronously for convenience
+ }
+ };
+
+ // create the renderer
+ cy.initRenderer( util.extend({
+ hideEdgesOnViewport: options.hideEdgesOnViewport,
+ hideLabelsOnViewport: options.hideLabelsOnViewport,
+ textureOnViewport: options.textureOnViewport,
+ wheelSensitivity: is.number(options.wheelSensitivity) && options.wheelSensitivity > 0 ? options.wheelSensitivity : 1,
+ motionBlur: options.motionBlur === undefined ? true : options.motionBlur, // on by default
+ motionBlurOpacity: options.motionBlurOpacity === undefined ? 0.05 : options.motionBlurOpacity,
+ pixelRatio: is.number(options.pixelRatio) && options.pixelRatio > 0 ? options.pixelRatio : (options.pixelRatio === 'auto' ? undefined : 1),
+ desktopTapThreshold: options.desktopTapThreshold === undefined ? 4 : options.desktopTapThreshold,
+ touchTapThreshold: options.touchTapThreshold === undefined ? 8 : options.touchTapThreshold
+ }, options.renderer) );
+
+ var extData = [ options.style, options.elements ];
+ loadExtData(function( thens ){
+ var initStyle = thens[0];
+ var initEles = thens[1];
+
+ // init style
+ if( _p.styleEnabled ){
+ cy.setStyle( initStyle );
+ }
+
+ // trigger the passed function for the `initrender` event
+ if( options.initrender ){
+ cy.on('initrender', options.initrender);
+ cy.on('initrender', function(){
+ _p.initrender = true;
+ });
+ }
+
+ // initial load
+ cy.load(initEles, function(){ // onready
+ cy.startAnimationLoop();
+ _p.ready = true;
+
+ // if a ready callback is specified as an option, the bind it
+ if( is.fn( options.ready ) ){
+ cy.on('ready', options.ready);
+ }
+
+ // bind all the ready handlers registered before creating this instance
+ for( var i = 0; i < readies.length; i++ ){
+ var fn = readies[i];
+ cy.on('ready', fn);
+ }
+ if( reg ){ reg.readies = []; } // clear b/c we've bound them all and don't want to keep it around in case a new core uses the same div etc
+
+ cy.trigger('ready');
+ }, options.done);
+
+ });
+};
+
+var corefn = Core.prototype; // short alias
+
+util.extend(corefn, {
+ instanceString: function(){
+ return 'core';
+ },
+
+ isReady: function(){
+ return this._private.ready;
+ },
+
+ ready: function( fn ){
+ if( this.isReady() ){
+ this.trigger('ready', [], fn); // just calls fn as though triggered via ready event
+ } else {
+ this.on('ready', fn);
+ }
+
+ return this;
+ },
+
+ initrender: function(){
+ return this._private.initrender;
+ },
+
+ destroy: function(){
+ var cy = this;
+
+ cy.stopAnimationLoop();
+
+ cy.notify({ type: 'destroy' }); // destroy the renderer
+
+ var domEle = cy.container();
+ if( domEle ){
+ domEle._cyreg = null;
+
+ while( domEle.childNodes.length > 0 ){
+ domEle.removeChild( domEle.childNodes[0] );
+ }
+ }
+
+ return cy;
+ },
+
+ getElementById: function( id ){
+ var index = this._private.id2index[ id ];
+ if( index !== undefined ){
+ return this._private.elements[ index ];
+ }
+
+ // worst case, return an empty collection
+ return Collection( this );
+ },
+
+ selectionType: function(){
+ return this._private.selectionType;
+ },
+
+ hasCompoundNodes: function(){
+ return this._private.hasCompoundNodes;
+ },
+
+ styleEnabled: function(){
+ return this._private.styleEnabled;
+ },
+
+ addToPool: function( eles ){
+ var elements = this._private.elements;
+ var id2index = this._private.id2index;
+
+ for( var i = 0; i < eles.length; i++ ){
+ var ele = eles[i];
+
+ var id = ele._private.data.id;
+ var index = id2index[ id ];
+ var alreadyInPool = index !== undefined;
+
+ if( !alreadyInPool ){
+ index = elements.length;
+ elements.push( ele );
+ id2index[ id ] = index;
+ ele._private.index = index;
+ }
+ }
+
+ return this; // chaining
+ },
+
+ removeFromPool: function( eles ){
+ var elements = this._private.elements;
+ var id2index = this._private.id2index;
+
+ for( var i = 0; i < eles.length; i++ ){
+ var ele = eles[i];
+
+ var id = ele._private.data.id;
+ var index = id2index[ id ];
+ var inPool = index !== undefined;
+
+ if( inPool ){
+ this._private.id2index[ id ] = undefined;
+ elements.splice(index, 1);
+
+ // adjust the index of all elements past this index
+ for( var j = index; j < elements.length; j++ ){
+ var jid = elements[j]._private.data.id;
+ id2index[ jid ]--;
+ elements[j]._private.index--;
+ }
+ }
+ }
+ },
+
+ container: function(){
+ return this._private.container;
+ },
+
+ options: function(){
+ return util.copy( this._private.options );
+ },
+
+ json: function( obj ){
+ var cy = this;
+ var _p = cy._private;
+
+ if( is.plainObject(obj) ){ // set
+
+ cy.startBatch();
+
+ if( obj.elements ){
+ var idInJson = {};
+
+ var updateEles = function( jsons, gr ){
+ for( var i = 0; i < jsons.length; i++ ){
+ var json = jsons[i];
+ var id = json.data.id;
+ var ele = cy.getElementById( id );
+
+ idInJson[ id ] = true;
+
+ if( ele.length !== 0 ){ // existing element should be updated
+ ele.json( json );
+ } else { // otherwise should be added
+ if( gr ){
+ cy.add( util.extend({ group: gr }, json) );
+ } else {
+ cy.add( json );
+ }
+ }
+ }
+ };
+
+ if( is.array(obj.elements) ){ // elements: []
+ updateEles( obj.elements );
+
+ } else { // elements: { nodes: [], edges: [] }
+ var grs = ['nodes', 'edges'];
+ for( var i = 0; i < grs.length; i++ ){
+ var gr = grs[i];
+ var elements = obj.elements[ gr ];
+
+ if( is.array(elements) ){
+ updateEles( elements, gr );
+ }
+ }
+ }
+
+ // elements not specified in json should be removed
+ cy.elements().stdFilter(function( ele ){
+ return !idInJson[ ele.id() ];
+ }).remove();
+ }
+
+ if( obj.style ){
+ cy.style( obj.style );
+ }
+
+ if( obj.zoom != null && obj.zoom !== _p.zoom ){
+ cy.zoom( obj.zoom );
+ }
+
+ if( obj.pan ){
+ if( obj.pan.x !== _p.pan.x || obj.pan.y !== _p.pan.y ){
+ cy.pan( obj.pan );
+ }
+ }
+
+ var fields = [
+ 'minZoom', 'maxZoom', 'zoomingEnabled', 'userZoomingEnabled',
+ 'panningEnabled', 'userPanningEnabled',
+ 'boxSelectionEnabled',
+ 'autolock', 'autoungrabify', 'autounselectify'
+ ];
+
+ for( var i = 0; i < fields.length; i++ ){
+ var f = fields[i];
+
+ if( obj[f] != null ){
+ cy[f]( obj[f] );
+ }
+ }
+
+ cy.endBatch();
+
+ return this; // chaining
+ } else if( obj === undefined ){ // get
+ var json = {};
+
+ json.elements = {};
+ cy.elements().each(function(i, ele){
+ var group = ele.group();
+
+ if( !json.elements[group] ){
+ json.elements[group] = [];
+ }
+
+ json.elements[group].push( ele.json() );
+ });
+
+ if( this._private.styleEnabled ){
+ json.style = cy.style().json();
+ }
+
+ json.zoomingEnabled = cy._private.zoomingEnabled;
+ json.userZoomingEnabled = cy._private.userZoomingEnabled;
+ json.zoom = cy._private.zoom;
+ json.minZoom = cy._private.minZoom;
+ json.maxZoom = cy._private.maxZoom;
+ json.panningEnabled = cy._private.panningEnabled;
+ json.userPanningEnabled = cy._private.userPanningEnabled;
+ json.pan = util.copy( cy._private.pan );
+ json.boxSelectionEnabled = cy._private.boxSelectionEnabled;
+ json.renderer = util.copy( cy._private.options.renderer );
+ json.hideEdgesOnViewport = cy._private.options.hideEdgesOnViewport;
+ json.hideLabelsOnViewport = cy._private.options.hideLabelsOnViewport;
+ json.textureOnViewport = cy._private.options.textureOnViewport;
+ json.wheelSensitivity = cy._private.options.wheelSensitivity;
+ json.motionBlur = cy._private.options.motionBlur;
+
+ return json;
+ }
+ },
+
+ scratch: define.data({
+ field: 'scratch',
+ bindingEvent: 'scratch',
+ allowBinding: true,
+ allowSetting: true,
+ settingEvent: 'scratch',
+ settingTriggersEvent: true,
+ triggerFnName: 'trigger',
+ allowGetting: true
+ }),
+
+ removeScratch: define.removeData({
+ field: 'scratch',
+ event: 'scratch',
+ triggerFnName: 'trigger',
+ triggerEvent: true
+ })
+
+});
+
+[
+ _dereq_('./add-remove'),
+ _dereq_('./animation'),
+ _dereq_('./events'),
+ _dereq_('./export'),
+ _dereq_('./layout'),
+ _dereq_('./notification'),
+ _dereq_('./renderer'),
+ _dereq_('./search'),
+ _dereq_('./style'),
+ _dereq_('./viewport')
+].forEach(function( props ){
+ util.extend( corefn, props );
+});
+
+module.exports = Core;
+
+},{"../collection":23,"../define":41,"../is":77,"../promise":80,"../util":94,"../window":100,"./add-remove":30,"./animation":31,"./events":32,"./export":33,"./layout":35,"./notification":36,"./renderer":37,"./search":38,"./style":39,"./viewport":40}],35:[function(_dereq_,module,exports){
+'use strict';
+
+var util = _dereq_('../util');
+var is = _dereq_('../is');
+
+var corefn = ({
+
+ layout: function( params ){
+ var layout = this._private.prevLayout = ( params == null ? this._private.prevLayout : this.makeLayout( params ) );
+
+ layout.run();
+
+ return this; // chaining
+ },
+
+ makeLayout: function( options ){
+ var cy = this;
+
+ if( options == null ){
+ util.error('Layout options must be specified to make a layout');
+ return;
+ }
+
+ if( options.name == null ){
+ util.error('A `name` must be specified to make a layout');
+ return;
+ }
+
+ var name = options.name;
+ var Layout = cy.extension('layout', name);
+
+ if( Layout == null ){
+ util.error('Can not apply layout: No such layout `' + name + '` found; did you include its JS file?');
+ return;
+ }
+
+ var eles;
+ if( is.string( options.eles ) ){
+ eles = cy.$( options.eles );
+ } else {
+ eles = options.eles != null ? options.eles : cy.$();
+ }
+
+ var layout = new Layout( util.extend({}, options, {
+ cy: cy,
+ eles: eles
+ }) );
+
+ return layout;
+ }
+
+});
+
+corefn.createLayout = corefn.makeLayout;
+
+module.exports = corefn;
+
+},{"../is":77,"../util":94}],36:[function(_dereq_,module,exports){
+'use strict';
+
+var corefn = ({
+ notify: function( params ){
+ var _p = this._private;
+
+ if( _p.batchingNotify ){
+ var bEles = _p.batchNotifyEles;
+ var bTypes = _p.batchNotifyTypes;
+
+ if( params.collection ){
+ bEles.merge( params.collection );
+ }
+
+ if( !bTypes.ids[ params.type ] ){
+ bTypes.push( params.type );
+ }
+
+ return; // notifications are disabled during batching
+ }
+
+ if( !_p.notificationsEnabled ){ return; } // exit on disabled
+
+ var renderer = this.renderer();
+
+ renderer.notify(params);
+ },
+
+ notifications: function( bool ){
+ var p = this._private;
+
+ if( bool === undefined ){
+ return p.notificationsEnabled;
+ } else {
+ p.notificationsEnabled = bool ? true : false;
+ }
+ },
+
+ noNotifications: function( callback ){
+ this.notifications(false);
+ callback();
+ this.notifications(true);
+ },
+
+ startBatch: function(){
+ var _p = this._private;
+
+ if( _p.batchCount == null ){
+ _p.batchCount = 0;
+ }
+
+ if( _p.batchCount === 0 ){
+ _p.batchingStyle = _p.batchingNotify = true;
+ _p.batchStyleEles = this.collection();
+ _p.batchNotifyEles = this.collection();
+ _p.batchNotifyTypes = [];
+
+ _p.batchNotifyTypes.ids = {};
+ }
+
+ _p.batchCount++;
+
+ return this;
+ },
+
+ endBatch: function(){
+ var _p = this._private;
+
+ _p.batchCount--;
+
+ if( _p.batchCount === 0 ){
+ // update style for dirty eles
+ _p.batchingStyle = false;
+ _p.batchStyleEles.updateStyle();
+
+ // notify the renderer of queued eles and event types
+ _p.batchingNotify = false;
+ this.notify({
+ type: _p.batchNotifyTypes,
+ collection: _p.batchNotifyEles
+ });
+ }
+
+ return this;
+ },
+
+ batch: function( callback ){
+ this.startBatch();
+ callback();
+ this.endBatch();
+
+ return this;
+ },
+
+ // for backwards compatibility
+ batchData: function( map ){
+ var cy = this;
+
+ return this.batch(function(){
+ for( var id in map ){
+ var data = map[id];
+ var ele = cy.getElementById( id );
+
+ ele.data( data );
+ }
+ });
+ }
+});
+
+module.exports = corefn;
+
+},{}],37:[function(_dereq_,module,exports){
+'use strict';
+
+var util = _dereq_('../util');
+
+var corefn = ({
+
+ renderTo: function( context, zoom, pan, pxRatio ){
+ var r = this._private.renderer;
+
+ r.renderTo( context, zoom, pan, pxRatio );
+ return this;
+ },
+
+ renderer: function(){
+ return this._private.renderer;
+ },
+
+ forceRender: function(){
+ this.notify({
+ type: 'draw'
+ });
+
+ return this;
+ },
+
+ resize: function(){
+ this.notify({
+ type: 'resize'
+ });
+
+ this.trigger('resize');
+
+ return this;
+ },
+
+ initRenderer: function( options ){
+ var cy = this;
+
+ var RendererProto = cy.extension('renderer', options.name);
+ if( RendererProto == null ){
+ util.error('Can not initialise: No such renderer `%s` found; did you include its JS file?', options.name);
+ return;
+ }
+
+ var rOpts = util.extend({}, options, {
+ cy: cy
+ });
+ var renderer = cy._private.renderer = new RendererProto( rOpts );
+
+ renderer.init( rOpts );
+
+ },
+
+ triggerOnRender: function(){
+ var cbs = this._private.onRenders;
+
+ for( var i = 0; i < cbs.length; i++ ){
+ var cb = cbs[i];
+
+ cb();
+ }
+
+ return this;
+ },
+
+ onRender: function( cb ){
+ this._private.onRenders.push( cb );
+
+ return this;
+ },
+
+ offRender: function( fn ){
+ var cbs = this._private.onRenders;
+
+ if( fn == null ){ // unbind all
+ this._private.onRenders = [];
+ return this;
+ }
+
+ for( var i = 0; i < cbs.length; i++ ){ // unbind specified
+ var cb = cbs[i];
+
+ if( fn === cb ){
+ cbs.splice( i, 1 );
+ break;
+ }
+ }
+
+ return this;
+ }
+
+});
+
+corefn.invalidateDimensions = corefn.resize;
+
+module.exports = corefn;
+
+},{"../util":94}],38:[function(_dereq_,module,exports){
+'use strict';
+
+var is = _dereq_('../is');
+var Collection = _dereq_('../collection');
+
+var corefn = ({
+
+ // get a collection
+ // - empty collection on no args
+ // - collection of elements in the graph on selector arg
+ // - guarantee a returned collection when elements or collection specified
+ collection: function( eles, opts ){
+
+ if( is.string( eles ) ){
+ return this.$( eles );
+
+ } else if( is.elementOrCollection( eles ) ){
+ return eles.collection();
+
+ } else if( is.array( eles ) ){
+ return Collection( this, eles, opts );
+ }
+
+ return Collection( this );
+ },
+
+ nodes: function( selector ){
+ var nodes = this.$(function(){
+ return this.isNode();
+ });
+
+ if( selector ){
+ return nodes.filter( selector );
+ }
+
+ return nodes;
+ },
+
+ edges: function( selector ){
+ var edges = this.$(function(){
+ return this.isEdge();
+ });
+
+ if( selector ){
+ return edges.filter( selector );
+ }
+
+ return edges;
+ },
+
+ // search the graph like jQuery
+ $: function( selector ){
+ var eles = new Collection( this, this._private.elements );
+
+ if( selector ){
+ return eles.filter( selector );
+ }
+
+ return eles;
+ }
+
+});
+
+// aliases
+corefn.elements = corefn.filter = corefn.$;
+
+module.exports = corefn;
+
+},{"../collection":23,"../is":77}],39:[function(_dereq_,module,exports){
+'use strict';
+
+var is = _dereq_('../is');
+var Style = _dereq_('../style');
+
+var corefn = ({
+
+ style: function( newStyle ){
+ if( newStyle ){
+ var s = this.setStyle( newStyle );
+
+ s.update();
+ }
+
+ return this._private.style;
+ },
+
+ setStyle: function( style ){
+ var _p = this._private;
+
+ if( is.stylesheet(style) ){
+ _p.style = style.generateStyle(this);
+
+ } else if( is.array(style) ) {
+ _p.style = Style.fromJson(this, style);
+
+ } else if( is.string(style) ){
+ _p.style = Style.fromString(this, style);
+
+ } else {
+ _p.style = Style( this );
+ }
+
+ return _p.style;
+ }
+});
+
+module.exports = corefn;
+
+},{"../is":77,"../style":86}],40:[function(_dereq_,module,exports){
+'use strict';
+
+var is = _dereq_('../is');
+
+var corefn = ({
+
+ autolock: function(bool){
+ if( bool !== undefined ){
+ this._private.autolock = bool ? true : false;
+ } else {
+ return this._private.autolock;
+ }
+
+ return this; // chaining
+ },
+
+ autoungrabify: function(bool){
+ if( bool !== undefined ){
+ this._private.autoungrabify = bool ? true : false;
+ } else {
+ return this._private.autoungrabify;
+ }
+
+ return this; // chaining
+ },
+
+ autounselectify: function(bool){
+ if( bool !== undefined ){
+ this._private.autounselectify = bool ? true : false;
+ } else {
+ return this._private.autounselectify;
+ }
+
+ return this; // chaining
+ },
+
+ panningEnabled: function( bool ){
+ if( bool !== undefined ){
+ this._private.panningEnabled = bool ? true : false;
+ } else {
+ return this._private.panningEnabled;
+ }
+
+ return this; // chaining
+ },
+
+ userPanningEnabled: function( bool ){
+ if( bool !== undefined ){
+ this._private.userPanningEnabled = bool ? true : false;
+ } else {
+ return this._private.userPanningEnabled;
+ }
+
+ return this; // chaining
+ },
+
+ zoomingEnabled: function( bool ){
+ if( bool !== undefined ){
+ this._private.zoomingEnabled = bool ? true : false;
+ } else {
+ return this._private.zoomingEnabled;
+ }
+
+ return this; // chaining
+ },
+
+ userZoomingEnabled: function( bool ){
+ if( bool !== undefined ){
+ this._private.userZoomingEnabled = bool ? true : false;
+ } else {
+ return this._private.userZoomingEnabled;
+ }
+
+ return this; // chaining
+ },
+
+ boxSelectionEnabled: function( bool ){
+ if( bool !== undefined ){
+ this._private.boxSelectionEnabled = bool ? true : false;
+ } else {
+ return this._private.boxSelectionEnabled;
+ }
+
+ return this; // chaining
+ },
+
+ pan: function(){
+ var args = arguments;
+ var pan = this._private.pan;
+ var dim, val, dims, x, y;
+
+ switch( args.length ){
+ case 0: // .pan()
+ return pan;
+
+ case 1:
+
+ if( is.string( args[0] ) ){ // .pan('x')
+ dim = args[0];
+ return pan[ dim ];
+
+ } else if( is.plainObject( args[0] ) ) { // .pan({ x: 0, y: 100 })
+ if( !this._private.panningEnabled ){
+ return this;
+ }
+
+ dims = args[0];
+ x = dims.x;
+ y = dims.y;
+
+ if( is.number(x) ){
+ pan.x = x;
+ }
+
+ if( is.number(y) ){
+ pan.y = y;
+ }
+
+ this.trigger('pan viewport');
+ }
+ break;
+
+ case 2: // .pan('x', 100)
+ if( !this._private.panningEnabled ){
+ return this;
+ }
+
+ dim = args[0];
+ val = args[1];
+
+ if( (dim === 'x' || dim === 'y') && is.number(val) ){
+ pan[dim] = val;
+ }
+
+ this.trigger('pan viewport');
+ break;
+
+ default:
+ break; // invalid
+ }
+
+ this.notify({ // notify the renderer that the viewport changed
+ type: 'viewport'
+ });
+
+ return this; // chaining
+ },
+
+ panBy: function(params){
+ var args = arguments;
+ var pan = this._private.pan;
+ var dim, val, dims, x, y;
+
+ if( !this._private.panningEnabled ){
+ return this;
+ }
+
+ switch( args.length ){
+ case 1:
+
+ if( is.plainObject( args[0] ) ) { // .panBy({ x: 0, y: 100 })
+ dims = args[0];
+ x = dims.x;
+ y = dims.y;
+
+ if( is.number(x) ){
+ pan.x += x;
+ }
+
+ if( is.number(y) ){
+ pan.y += y;
+ }
+
+ this.trigger('pan viewport');
+ }
+ break;
+
+ case 2: // .panBy('x', 100)
+ dim = args[0];
+ val = args[1];
+
+ if( (dim === 'x' || dim === 'y') && is.number(val) ){
+ pan[dim] += val;
+ }
+
+ this.trigger('pan viewport');
+ break;
+
+ default:
+ break; // invalid
+ }
+
+ this.notify({ // notify the renderer that the viewport changed
+ type: 'viewport'
+ });
+
+ return this; // chaining
+ },
+
+ fit: function( elements, padding ){
+ var viewportState = this.getFitViewport( elements, padding );
+
+ if( viewportState ){
+ var _p = this._private;
+ _p.zoom = viewportState.zoom;
+ _p.pan = viewportState.pan;
+
+ this.trigger('pan zoom viewport');
+
+ this.notify({ // notify the renderer that the viewport changed
+ type: 'viewport'
+ });
+ }
+
+ return this; // chaining
+ },
+
+ getFitViewport: function( elements, padding ){
+ if( is.number(elements) && padding === undefined ){ // elements is optional
+ padding = elements;
+ elements = undefined;
+ }
+
+ if( !this._private.panningEnabled || !this._private.zoomingEnabled ){
+ return;
+ }
+
+ var bb;
+
+ if( is.string(elements) ){
+ var sel = elements;
+ elements = this.$( sel );
+
+ } else if( is.boundingBox(elements) ){ // assume bb
+ var bbe = elements;
+ bb = {
+ x1: bbe.x1,
+ y1: bbe.y1,
+ x2: bbe.x2,
+ y2: bbe.y2
+ };
+
+ bb.w = bb.x2 - bb.x1;
+ bb.h = bb.y2 - bb.y1;
+
+ } else if( !is.elementOrCollection(elements) ){
+ elements = this.elements();
+ }
+
+ bb = bb || elements.boundingBox();
+
+ var w = this.width();
+ var h = this.height();
+ var zoom;
+ padding = is.number(padding) ? padding : 0;
+
+ if( !isNaN(w) && !isNaN(h) && w > 0 && h > 0 && !isNaN(bb.w) && !isNaN(bb.h) && bb.w > 0 && bb.h > 0 ){
+ zoom = Math.min( (w - 2*padding)/bb.w, (h - 2*padding)/bb.h );
+
+ // crop zoom
+ zoom = zoom > this._private.maxZoom ? this._private.maxZoom : zoom;
+ zoom = zoom < this._private.minZoom ? this._private.minZoom : zoom;
+
+ var pan = { // now pan to middle
+ x: (w - zoom*( bb.x1 + bb.x2 ))/2,
+ y: (h - zoom*( bb.y1 + bb.y2 ))/2
+ };
+
+ return {
+ zoom: zoom,
+ pan: pan
+ };
+ }
+
+ return;
+ },
+
+ minZoom: function( zoom ){
+ if( zoom === undefined ){
+ return this._private.minZoom;
+ } else if( is.number(zoom) ){
+ this._private.minZoom = zoom;
+ }
+
+ return this;
+ },
+
+ maxZoom: function( zoom ){
+ if( zoom === undefined ){
+ return this._private.maxZoom;
+ } else if( is.number(zoom) ){
+ this._private.maxZoom = zoom;
+ }
+
+ return this;
+ },
+
+ zoom: function( params ){
+ var pos; // in rendered px
+ var zoom;
+
+ if( params === undefined ){ // then get the zoom
+ return this._private.zoom;
+
+ } else if( is.number(params) ){ // then set the zoom
+ zoom = params;
+
+ } else if( is.plainObject(params) ){ // then zoom about a point
+ zoom = params.level;
+
+ if( params.position ){
+ var p = params.position;
+ var pan = this._private.pan;
+ var z = this._private.zoom;
+
+ pos = { // convert to rendered px
+ x: p.x * z + pan.x,
+ y: p.y * z + pan.y
+ };
+ } else if( params.renderedPosition ){
+ pos = params.renderedPosition;
+ }
+
+ if( pos && !this._private.panningEnabled ){
+ return this; // panning disabled
+ }
+ }
+
+ if( !this._private.zoomingEnabled ){
+ return this; // zooming disabled
+ }
+
+ if( !is.number(zoom) || ( pos && (!is.number(pos.x) || !is.number(pos.y)) ) ){
+ return this; // can't zoom with invalid params
+ }
+
+ // crop zoom
+ zoom = zoom > this._private.maxZoom ? this._private.maxZoom : zoom;
+ zoom = zoom < this._private.minZoom ? this._private.minZoom : zoom;
+
+ if( pos ){ // set zoom about position
+ var pan1 = this._private.pan;
+ var zoom1 = this._private.zoom;
+ var zoom2 = zoom;
+
+ var pan2 = {
+ x: -zoom2/zoom1 * (pos.x - pan1.x) + pos.x,
+ y: -zoom2/zoom1 * (pos.y - pan1.y) + pos.y
+ };
+
+ this._private.zoom = zoom;
+ this._private.pan = pan2;
+
+ var posChanged = pan1.x !== pan2.x || pan1.y !== pan2.y;
+ this.trigger(' zoom ' + (posChanged ? ' pan ' : '') + ' viewport ' );
+
+ } else { // just set the zoom
+ this._private.zoom = zoom;
+ this.trigger('zoom viewport');
+ }
+
+ this.notify({ // notify the renderer that the viewport changed
+ type: 'viewport'
+ });
+
+ return this; // chaining
+ },
+
+ viewport: function( opts ){
+ var _p = this._private;
+ var zoomDefd = true;
+ var panDefd = true;
+ var events = []; // to trigger
+ var zoomFailed = false;
+ var panFailed = false;
+
+ if( !opts ){ return this; }
+ if( !is.number(opts.zoom) ){ zoomDefd = false; }
+ if( !is.plainObject(opts.pan) ){ panDefd = false; }
+ if( !zoomDefd && !panDefd ){ return this; }
+
+ if( zoomDefd ){
+ var z = opts.zoom;
+
+ if( z < _p.minZoom || z > _p.maxZoom || !_p.zoomingEnabled ){
+ zoomFailed = true;
+
+ } else {
+ _p.zoom = z;
+
+ events.push('zoom');
+ }
+ }
+
+ if( panDefd && (!zoomFailed || !opts.cancelOnFailedZoom) && _p.panningEnabled ){
+ var p = opts.pan;
+
+ if( is.number(p.x) ){
+ _p.pan.x = p.x;
+ panFailed = false;
+ }
+
+ if( is.number(p.y) ){
+ _p.pan.y = p.y;
+ panFailed = false;
+ }
+
+ if( !panFailed ){
+ events.push('pan');
+ }
+ }
+
+ if( events.length > 0 ){
+ events.push('viewport');
+ this.trigger( events.join(' ') );
+
+ this.notify({
+ type: 'viewport'
+ });
+ }
+
+ return this; // chaining
+ },
+
+ center: function( elements ){
+ var pan = this.getCenterPan( elements );
+
+ if( pan ){
+ this._private.pan = pan;
+
+ this.trigger('pan viewport');
+
+ this.notify({ // notify the renderer that the viewport changed
+ type: 'viewport'
+ });
+ }
+
+ return this; // chaining
+ },
+
+ getCenterPan: function( elements, zoom ){
+ if( !this._private.panningEnabled ){
+ return;
+ }
+
+ if( is.string(elements) ){
+ var selector = elements;
+ elements = this.elements( selector );
+ } else if( !is.elementOrCollection(elements) ){
+ elements = this.elements();
+ }
+
+ var bb = elements.boundingBox();
+ var w = this.width();
+ var h = this.height();
+ zoom = zoom === undefined ? this._private.zoom : zoom;
+
+ var pan = { // middle
+ x: (w - zoom*( bb.x1 + bb.x2 ))/2,
+ y: (h - zoom*( bb.y1 + bb.y2 ))/2
+ };
+
+ return pan;
+ },
+
+ reset: function(){
+ if( !this._private.panningEnabled || !this._private.zoomingEnabled ){
+ return this;
+ }
+
+ this.viewport({
+ pan: { x: 0, y: 0 },
+ zoom: 1
+ });
+
+ return this; // chaining
+ },
+
+ width: function(){
+ var container = this._private.container;
+
+ if( container ){
+ return container.clientWidth;
+ }
+
+ return 1; // fallback if no container (not 0 b/c can be used for dividing etc)
+ },
+
+ height: function(){
+ var container = this._private.container;
+
+ if( container ){
+ return container.clientHeight;
+ }
+
+ return 1; // fallback if no container (not 0 b/c can be used for dividing etc)
+ },
+
+ extent: function(){
+ var pan = this._private.pan;
+ var zoom = this._private.zoom;
+ var rb = this.renderedExtent();
+
+ var b = {
+ x1: ( rb.x1 - pan.x )/zoom,
+ x2: ( rb.x2 - pan.x )/zoom,
+ y1: ( rb.y1 - pan.y )/zoom,
+ y2: ( rb.y2 - pan.y )/zoom,
+ };
+
+ b.w = b.x2 - b.x1;
+ b.h = b.y2 - b.y1;
+
+ return b;
+ },
+
+ renderedExtent: function(){
+ var width = this.width();
+ var height = this.height();
+
+ return {
+ x1: 0,
+ y1: 0,
+ x2: width,
+ y2: height,
+ w: width,
+ h: height
+ };
+ }
+});
+
+// aliases
+corefn.centre = corefn.center;
+
+// backwards compatibility
+corefn.autolockNodes = corefn.autolock;
+corefn.autoungrabifyNodes = corefn.autoungrabify;
+
+module.exports = corefn;
+
+},{"../is":77}],41:[function(_dereq_,module,exports){
+'use strict';
+
+// use this module to cherry pick functions into your prototype
+// (useful for functions shared between the core and collections, for example)
+
+// e.g.
+// var foo = define.foo({ /* params... */ })
+
+var util = _dereq_('./util');
+var is = _dereq_('./is');
+var Selector = _dereq_('./selector');
+var Promise = _dereq_('./promise');
+var Event = _dereq_('./event');
+var Animation = _dereq_('./animation');
+
+var define = {
+
+ // access data field
+ data: function( params ){
+ var defaults = {
+ field: 'data',
+ bindingEvent: 'data',
+ allowBinding: false,
+ allowSetting: false,
+ allowGetting: false,
+ settingEvent: 'data',
+ settingTriggersEvent: false,
+ triggerFnName: 'trigger',
+ immutableKeys: {}, // key => true if immutable
+ updateStyle: false,
+ onSet: function( self ){},
+ canSet: function( self ){ return true; }
+ };
+ params = util.extend({}, defaults, params);
+
+ return function dataImpl( name, value ){
+ var p = params;
+ var self = this;
+ var selfIsArrayLike = self.length !== undefined;
+ var all = selfIsArrayLike ? self : [self]; // put in array if not array-like
+ var single = selfIsArrayLike ? self[0] : self;
+
+ // .data('foo', ...)
+ if( is.string(name) ){ // set or get property
+
+ // .data('foo')
+ if( p.allowGetting && value === undefined ){ // get
+
+ var ret;
+ if( single ){
+ ret = single._private[ p.field ][ name ];
+ }
+ return ret;
+
+ // .data('foo', 'bar')
+ } else if( p.allowSetting && value !== undefined ) { // set
+ var valid = !p.immutableKeys[name];
+ if( valid ){
+ for( var i = 0, l = all.length; i < l; i++ ){
+ if( p.canSet( all[i] ) ){
+ all[i]._private[ p.field ][ name ] = value;
+ }
+ }
+
+ // update mappers if asked
+ if( p.updateStyle ){ self.updateStyle(); }
+
+ // call onSet callback
+ p.onSet( self );
+
+ if( p.settingTriggersEvent ){
+ self[ p.triggerFnName ]( p.settingEvent );
+ }
+ }
+ }
+
+ // .data({ 'foo': 'bar' })
+ } else if( p.allowSetting && is.plainObject(name) ){ // extend
+ var obj = name;
+ var k, v;
+
+ for( k in obj ){
+ v = obj[ k ];
+
+ var valid = !p.immutableKeys[k];
+ if( valid ){
+ for( var i = 0, l = all.length; i < l; i++ ){
+ if( p.canSet( all[i] ) ){
+ all[i]._private[ p.field ][ k ] = v;
+ }
+ }
+ }
+ }
+
+ // update mappers if asked
+ if( p.updateStyle ){ self.updateStyle(); }
+
+ // call onSet callback
+ p.onSet( self );
+
+ if( p.settingTriggersEvent ){
+ self[ p.triggerFnName ]( p.settingEvent );
+ }
+
+ // .data(function(){ ... })
+ } else if( p.allowBinding && is.fn(name) ){ // bind to event
+ var fn = name;
+ self.bind( p.bindingEvent, fn );
+
+ // .data()
+ } else if( p.allowGetting && name === undefined ){ // get whole object
+ var ret;
+ if( single ){
+ ret = single._private[ p.field ];
+ }
+ return ret;
+ }
+
+ return self; // maintain chainability
+ }; // function
+ }, // data
+
+ // remove data field
+ removeData: function( params ){
+ var defaults = {
+ field: 'data',
+ event: 'data',
+ triggerFnName: 'trigger',
+ triggerEvent: false,
+ immutableKeys: {} // key => true if immutable
+ };
+ params = util.extend({}, defaults, params);
+
+ return function removeDataImpl( names ){
+ var p = params;
+ var self = this;
+ var selfIsArrayLike = self.length !== undefined;
+ var all = selfIsArrayLike ? self : [self]; // put in array if not array-like
+
+ // .removeData('foo bar')
+ if( is.string(names) ){ // then get the list of keys, and delete them
+ var keys = names.split(/\s+/);
+ var l = keys.length;
+
+ for( var i = 0; i < l; i++ ){ // delete each non-empty key
+ var key = keys[i];
+ if( is.emptyString(key) ){ continue; }
+
+ var valid = !p.immutableKeys[ key ]; // not valid if immutable
+ if( valid ){
+ for( var i_a = 0, l_a = all.length; i_a < l_a; i_a++ ){
+ all[ i_a ]._private[ p.field ][ key ] = undefined;
+ }
+ }
+ }
+
+ if( p.triggerEvent ){
+ self[ p.triggerFnName ]( p.event );
+ }
+
+ // .removeData()
+ } else if( names === undefined ){ // then delete all keys
+
+ for( var i_a = 0, l_a = all.length; i_a < l_a; i_a++ ){
+ var _privateFields = all[ i_a ]._private[ p.field ];
+
+ for( var key in _privateFields ){
+ var validKeyToDelete = !p.immutableKeys[ key ];
+
+ if( validKeyToDelete ){
+ _privateFields[ key ] = undefined;
+ }
+ }
+ }
+
+ if( p.triggerEvent ){
+ self[ p.triggerFnName ]( p.event );
+ }
+ }
+
+ return self; // maintain chaining
+ }; // function
+ }, // removeData
+
+ // event function reusable stuff
+ event: {
+ regex: /(\w+)(\.\w+)?/, // regex for matching event strings (e.g. "click.namespace")
+ optionalTypeRegex: /(\w+)?(\.\w+)?/,
+ falseCallback: function(){ return false; }
+ },
+
+ // event binding
+ on: function( params ){
+ var defaults = {
+ unbindSelfOnTrigger: false,
+ unbindAllBindersOnTrigger: false
+ };
+ params = util.extend({}, defaults, params);
+
+ return function onImpl(events, selector, data, callback){
+ var self = this;
+ var selfIsArrayLike = self.length !== undefined;
+ var all = selfIsArrayLike ? self : [self]; // put in array if not array-like
+ var eventsIsString = is.string(events);
+ var p = params;
+
+ if( is.plainObject(selector) ){ // selector is actually data
+ callback = data;
+ data = selector;
+ selector = undefined;
+ } else if( is.fn(selector) || selector === false ){ // selector is actually callback
+ callback = selector;
+ data = undefined;
+ selector = undefined;
+ }
+
+ if( is.fn(data) || data === false ){ // data is actually callback
+ callback = data;
+ data = undefined;
+ }
+
+ // if there isn't a callback, we can't really do anything
+ // (can't speak for mapped events arg version)
+ if( !(is.fn(callback) || callback === false) && eventsIsString ){
+ return self; // maintain chaining
+ }
+
+ if( eventsIsString ){ // then convert to map
+ var map = {};
+ map[ events ] = callback;
+ events = map;
+ }
+
+ for( var evts in events ){
+ callback = events[evts];
+ if( callback === false ){
+ callback = define.event.falseCallback;
+ }
+
+ if( !is.fn(callback) ){ continue; }
+
+ evts = evts.split(/\s+/);
+ for( var i = 0; i < evts.length; i++ ){
+ var evt = evts[i];
+ if( is.emptyString(evt) ){ continue; }
+
+ var match = evt.match( define.event.regex ); // type[.namespace]
+
+ if( match ){
+ var type = match[1];
+ var namespace = match[2] ? match[2] : undefined;
+
+ var listener = {
+ callback: callback, // callback to run
+ data: data, // extra data in eventObj.data
+ delegated: selector ? true : false, // whether the evt is delegated
+ selector: selector, // the selector to match for delegated events
+ selObj: new Selector(selector), // cached selector object to save rebuilding
+ type: type, // the event type (e.g. 'click')
+ namespace: namespace, // the event namespace (e.g. ".foo")
+ unbindSelfOnTrigger: p.unbindSelfOnTrigger,
+ unbindAllBindersOnTrigger: p.unbindAllBindersOnTrigger,
+ binders: all // who bound together
+ };
+
+ for( var j = 0; j < all.length; j++ ){
+ var _p = all[j]._private;
+
+ _p.listeners = _p.listeners || [];
+ _p.listeners.push( listener );
+ }
+ }
+ } // for events array
+ } // for events map
+
+ return self; // maintain chaining
+ }; // function
+ }, // on
+
+ eventAliasesOn: function( proto ){
+ var p = proto;
+
+ p.addListener = p.listen = p.bind = p.on;
+ p.removeListener = p.unlisten = p.unbind = p.off;
+ p.emit = p.trigger;
+
+ // this is just a wrapper alias of .on()
+ p.pon = p.promiseOn = function( events, selector ){
+ var self = this;
+ var args = Array.prototype.slice.call( arguments, 0 );
+
+ return new Promise(function( resolve, reject ){
+ var callback = function( e ){
+ self.off.apply( self, offArgs );
+
+ resolve( e );
+ };
+
+ var onArgs = args.concat([ callback ]);
+ var offArgs = onArgs.concat([]);
+
+ self.on.apply( self, onArgs );
+ });
+ };
+ },
+
+ off: function offImpl( params ){
+ var defaults = {
+ };
+ params = util.extend({}, defaults, params);
+
+ return function(events, selector, callback){
+ var self = this;
+ var selfIsArrayLike = self.length !== undefined;
+ var all = selfIsArrayLike ? self : [self]; // put in array if not array-like
+ var eventsIsString = is.string(events);
+
+ if( arguments.length === 0 ){ // then unbind all
+
+ for( var i = 0; i < all.length; i++ ){
+ all[i]._private.listeners = [];
+ }
+
+ return self; // maintain chaining
+ }
+
+ if( is.fn(selector) || selector === false ){ // selector is actually callback
+ callback = selector;
+ selector = undefined;
+ }
+
+ if( eventsIsString ){ // then convert to map
+ var map = {};
+ map[ events ] = callback;
+ events = map;
+ }
+
+ for( var evts in events ){
+ callback = events[evts];
+
+ if( callback === false ){
+ callback = define.event.falseCallback;
+ }
+
+ evts = evts.split(/\s+/);
+ for( var h = 0; h < evts.length; h++ ){
+ var evt = evts[h];
+ if( is.emptyString(evt) ){ continue; }
+
+ var match = evt.match( define.event.optionalTypeRegex ); // [type][.namespace]
+ if( match ){
+ var type = match[1] ? match[1] : undefined;
+ var namespace = match[2] ? match[2] : undefined;
+
+ for( var i = 0; i < all.length; i++ ){ //
+ var listeners = all[i]._private.listeners = all[i]._private.listeners || [];
+
+ for( var j = 0; j < listeners.length; j++ ){
+ var listener = listeners[j];
+ var nsMatches = !namespace || namespace === listener.namespace;
+ var typeMatches = !type || listener.type === type;
+ var cbMatches = !callback || callback === listener.callback;
+ var listenerMatches = nsMatches && typeMatches && cbMatches;
+
+ // delete listener if it matches
+ if( listenerMatches ){
+ listeners.splice(j, 1);
+ j--;
+ }
+ } // for listeners
+ } // for all
+ } // if match
+ } // for events array
+
+ } // for events map
+
+ return self; // maintain chaining
+ }; // function
+ }, // off
+
+ trigger: function( params ){
+ var defaults = {};
+ params = util.extend({}, defaults, params);
+
+ return function triggerImpl(events, extraParams, fnToTrigger){
+ var self = this;
+ var selfIsArrayLike = self.length !== undefined;
+ var all = selfIsArrayLike ? self : [self]; // put in array if not array-like
+ var eventsIsString = is.string(events);
+ var eventsIsObject = is.plainObject(events);
+ var eventsIsEvent = is.event(events);
+ var cy = this._private.cy || ( is.core(this) ? this : null );
+ var hasCompounds = cy ? cy.hasCompoundNodes() : false;
+
+ if( eventsIsString ){ // then make a plain event object for each event name
+ var evts = events.split(/\s+/);
+ events = [];
+
+ for( var i = 0; i < evts.length; i++ ){
+ var evt = evts[i];
+ if( is.emptyString(evt) ){ continue; }
+
+ var match = evt.match( define.event.regex ); // type[.namespace]
+ var type = match[1];
+ var namespace = match[2] ? match[2] : undefined;
+
+ events.push( {
+ type: type,
+ namespace: namespace
+ } );
+ }
+ } else if( eventsIsObject ){ // put in length 1 array
+ var eventArgObj = events;
+
+ events = [ eventArgObj ];
+ }
+
+ if( extraParams ){
+ if( !is.array(extraParams) ){ // make sure extra params are in an array if specified
+ extraParams = [ extraParams ];
+ }
+ } else { // otherwise, we've got nothing
+ extraParams = [];
+ }
+
+ for( var i = 0; i < events.length; i++ ){ // trigger each event in order
+ var evtObj = events[i];
+
+ for( var j = 0; j < all.length; j++ ){ // for each
+ var triggerer = all[j];
+ var listeners = triggerer._private.listeners = triggerer._private.listeners || [];
+ var triggererIsElement = is.element(triggerer);
+ var bubbleUp = triggererIsElement || params.layout;
+
+ // create the event for this element from the event object
+ var evt;
+
+ if( eventsIsEvent ){ // then just get the object
+ evt = evtObj;
+
+ evt.cyTarget = evt.cyTarget || triggerer;
+ evt.cy = evt.cy || cy;
+
+ } else { // then we have to make one
+ evt = new Event( evtObj, {
+ cyTarget: triggerer,
+ cy: cy,
+ namespace: evtObj.namespace
+ } );
+ }
+
+ // if a layout was specified, then put it in the typed event
+ if( evtObj.layout ){
+ evt.layout = evtObj.layout;
+ }
+
+ // if triggered by layout, put in event
+ if( params.layout ){
+ evt.layout = triggerer;
+ }
+
+ // create a rendered position based on the passed position
+ if( evt.cyPosition ){
+ var pos = evt.cyPosition;
+ var zoom = cy.zoom();
+ var pan = cy.pan();
+
+ evt.cyRenderedPosition = {
+ x: pos.x * zoom + pan.x,
+ y: pos.y * zoom + pan.y
+ };
+ }
+
+ if( fnToTrigger ){ // then override the listeners list with just the one we specified
+ listeners = [{
+ namespace: evt.namespace,
+ type: evt.type,
+ callback: fnToTrigger
+ }];
+ }
+
+ for( var k = 0; k < listeners.length; k++ ){ // check each listener
+ var lis = listeners[k];
+ var nsMatches = !lis.namespace || lis.namespace === evt.namespace;
+ var typeMatches = lis.type === evt.type;
+ var targetMatches = lis.delegated ? ( triggerer !== evt.cyTarget && is.element(evt.cyTarget) && lis.selObj.matches(evt.cyTarget) ) : (true); // we're not going to validate the hierarchy; that's too expensive
+ var listenerMatches = nsMatches && typeMatches && targetMatches;
+
+ if( listenerMatches ){ // then trigger it
+ var args = [ evt ];
+ args = args.concat( extraParams ); // add extra params to args list
+
+ if( lis.data ){ // add on data plugged into binding
+ evt.data = lis.data;
+ } else { // or clear it in case the event obj is reused
+ evt.data = undefined;
+ }
+
+ if( lis.unbindSelfOnTrigger || lis.unbindAllBindersOnTrigger ){ // then remove listener
+ listeners.splice(k, 1);
+ k--;
+ }
+
+ if( lis.unbindAllBindersOnTrigger ){ // then delete the listener for all binders
+ var binders = lis.binders;
+ for( var l = 0; l < binders.length; l++ ){
+ var binder = binders[l];
+ if( !binder || binder === triggerer ){ continue; } // already handled triggerer or we can't handle it
+
+ var binderListeners = binder._private.listeners;
+ for( var m = 0; m < binderListeners.length; m++ ){
+ var binderListener = binderListeners[m];
+
+ if( binderListener === lis ){ // delete listener from list
+ binderListeners.splice(m, 1);
+ m--;
+ }
+ }
+ }
+ }
+
+ // run the callback
+ var context = lis.delegated ? evt.cyTarget : triggerer;
+ var ret = lis.callback.apply( context, args );
+
+ if( ret === false || evt.isPropagationStopped() ){
+ // then don't bubble
+ bubbleUp = false;
+
+ if( ret === false ){
+ // returning false is a shorthand for stopping propagation and preventing the def. action
+ evt.stopPropagation();
+ evt.preventDefault();
+ }
+ }
+ } // if listener matches
+ } // for each listener
+
+ // bubble up event for elements
+ if( bubbleUp ){
+ var parent = hasCompounds ? triggerer._private.parent : null;
+ var hasParent = parent != null && parent.length !== 0;
+
+ if( hasParent ){ // then bubble up to parent
+ parent = parent[0];
+ parent.trigger(evt);
+ } else { // otherwise, bubble up to the core
+ cy.trigger(evt);
+ }
+ }
+
+ } // for each of all
+ } // for each event
+
+ return self; // maintain chaining
+ }; // function
+ }, // trigger
+
+ animated: function( fnParams ){
+ var defaults = {};
+ fnParams = util.extend({}, defaults, fnParams);
+
+ return function animatedImpl(){
+ var self = this;
+ var selfIsArrayLike = self.length !== undefined;
+ var all = selfIsArrayLike ? self : [self]; // put in array if not array-like
+ var cy = this._private.cy || this;
+
+ if( !cy.styleEnabled() ){ return false; }
+
+ var ele = all[0];
+
+ if( ele ){
+ return ele._private.animation.current.length > 0;
+ }
+ };
+ }, // animated
+
+ clearQueue: function( fnParams ){
+ var defaults = {};
+ fnParams = util.extend({}, defaults, fnParams);
+
+ return function clearQueueImpl(){
+ var self = this;
+ var selfIsArrayLike = self.length !== undefined;
+ var all = selfIsArrayLike ? self : [self]; // put in array if not array-like
+ var cy = this._private.cy || this;
+
+ if( !cy.styleEnabled() ){ return this; }
+
+ for( var i = 0; i < all.length; i++ ){
+ var ele = all[i];
+ ele._private.animation.queue = [];
+ }
+
+ return this;
+ };
+ }, // clearQueue
+
+ delay: function( fnParams ){
+ var defaults = {};
+ fnParams = util.extend({}, defaults, fnParams);
+
+ return function delayImpl( time, complete ){
+ var cy = this._private.cy || this;
+
+ if( !cy.styleEnabled() ){ return this; }
+
+ return this.animate({
+ delay: time,
+ duration: time,
+ complete: complete
+ });
+ };
+ }, // delay
+
+ delayAnimation: function( fnParams ){
+ var defaults = {};
+ fnParams = util.extend({}, defaults, fnParams);
+
+ return function delayAnimationImpl( time, complete ){
+ var cy = this._private.cy || this;
+
+ if( !cy.styleEnabled() ){ return this; }
+
+ return this.animation({
+ delay: time,
+ duration: time,
+ complete: complete
+ });
+ };
+ }, // delay
+
+ animation: function( fnParams ){
+ var defaults = {};
+ fnParams = util.extend({}, defaults, fnParams);
+
+ return function animationImpl( properties, params ){
+ var self = this;
+ var selfIsArrayLike = self.length !== undefined;
+ var all = selfIsArrayLike ? self : [self]; // put in array if not array-like
+ var cy = this._private.cy || this;
+ var isCore = !selfIsArrayLike;
+ var isEles = !isCore;
+
+ if( !cy.styleEnabled() ){ return this; }
+
+ var style = cy.style();
+
+ properties = util.extend( {}, properties, params );
+
+ if( properties.duration === undefined ){
+ properties.duration = 400;
+ }
+
+ switch( properties.duration ){
+ case 'slow':
+ properties.duration = 600;
+ break;
+ case 'fast':
+ properties.duration = 200;
+ break;
+ }
+
+ var propertiesEmpty = true;
+ if( properties ){ for( var i in properties ){ // jshint ignore:line
+ propertiesEmpty = false;
+ break;
+ } }
+
+ if( propertiesEmpty ){
+ return new Animation( all[0], properties ); // nothing to animate
+ }
+
+ if( isEles ){
+ properties.style = style.getPropsList( properties.style || properties.css );
+
+ properties.css = undefined;
+ }
+
+ if( properties.renderedPosition && isEles ){
+ var rpos = properties.renderedPosition;
+ var pan = cy.pan();
+ var zoom = cy.zoom();
+
+ properties.position = {
+ x: ( rpos.x - pan.x ) /zoom,
+ y: ( rpos.y - pan.y ) /zoom
+ };
+ }
+
+ // override pan w/ panBy if set
+ if( properties.panBy && isCore ){
+ var panBy = properties.panBy;
+ var cyPan = cy.pan();
+
+ properties.pan = {
+ x: cyPan.x + panBy.x,
+ y: cyPan.y + panBy.y
+ };
+ }
+
+ // override pan w/ center if set
+ var center = properties.center || properties.centre;
+ if( center && isCore ){
+ var centerPan = cy.getCenterPan( center.eles, properties.zoom );
+
+ if( centerPan ){
+ properties.pan = centerPan;
+ }
+ }
+
+ // override pan & zoom w/ fit if set
+ if( properties.fit && isCore ){
+ var fit = properties.fit;
+ var fitVp = cy.getFitViewport( fit.eles || fit.boundingBox, fit.padding );
+
+ if( fitVp ){
+ properties.pan = fitVp.pan;
+ properties.zoom = fitVp.zoom;
+ }
+ }
+
+ return new Animation( all[0], properties );
+ };
+ }, // animate
+
+ animate: function( fnParams ){
+ var defaults = {};
+ fnParams = util.extend({}, defaults, fnParams);
+
+ return function animateImpl( properties, params ){
+ var self = this;
+ var selfIsArrayLike = self.length !== undefined;
+ var all = selfIsArrayLike ? self : [self]; // put in array if not array-like
+ var cy = this._private.cy || this;
+
+ if( !cy.styleEnabled() ){ return this; }
+
+ if( params ){
+ properties = util.extend( {}, properties, params );
+ }
+
+ // manually hook and run the animation
+ for( var i = 0; i < all.length; i++ ){
+ var ele = all[i];
+ var queue = ele.animated() && (properties.queue === undefined || properties.queue);
+
+ var ani = ele.animation( properties, (queue ? { queue: true } : undefined) );
+
+ ani.play();
+ }
+
+ return this; // chaining
+ };
+ }, // animate
+
+ stop: function( fnParams ){
+ var defaults = {};
+ fnParams = util.extend({}, defaults, fnParams);
+
+ return function stopImpl( clearQueue, jumpToEnd ){
+ var self = this;
+ var selfIsArrayLike = self.length !== undefined;
+ var all = selfIsArrayLike ? self : [self]; // put in array if not array-like
+ var cy = this._private.cy || this;
+
+ if( !cy.styleEnabled() ){ return this; }
+
+ for( var i = 0; i < all.length; i++ ){
+ var ele = all[i];
+ var _p = ele._private;
+ var anis = _p.animation.current;
+
+ for( var j = 0; j < anis.length; j++ ){
+ var ani = anis[j];
+ var ani_p = ani._private;
+
+ if( jumpToEnd ){
+ // next iteration of the animation loop, the animation
+ // will go straight to the end and be removed
+ ani_p.duration = 0;
+ }
+ }
+
+ // clear the queue of future animations
+ if( clearQueue ){
+ _p.animation.queue = [];
+ }
+
+ if( !jumpToEnd ){
+ _p.animation.current = [];
+ }
+ }
+
+ // we have to notify (the animation loop doesn't do it for us on `stop`)
+ cy.notify({
+ collection: this,
+ type: 'draw'
+ });
+
+ return this;
+ };
+ } // stop
+
+}; // define
+
+module.exports = define;
+
+},{"./animation":1,"./event":42,"./is":77,"./promise":80,"./selector":81,"./util":94}],42:[function(_dereq_,module,exports){
+'use strict';
+
+// ref
+// https://github.com/jquery/jquery/blob/master/src/event.js
+
+var Event = function( src, props ) {
+ // Allow instantiation without the 'new' keyword
+ if ( !(this instanceof Event) ) {
+ return new Event( src, props );
+ }
+
+ // Event object
+ if ( src && src.type ) {
+ this.originalEvent = src;
+ this.type = src.type;
+
+ // Events bubbling up the document may have been marked as prevented
+ // by a handler lower down the tree; reflect the correct value.
+ this.isDefaultPrevented = ( src.defaultPrevented ) ? returnTrue : returnFalse;
+
+ // Event type
+ } else {
+ this.type = src;
+ }
+
+ // Put explicitly provided properties onto the event object
+ if ( props ) {
+ // util.extend( this, props );
+
+ // more efficient to manually copy fields we use
+ this.type = props.type !== undefined ? props.type : this.type;
+ this.cy = props.cy;
+ this.cyTarget = props.cyTarget;
+ this.cyPosition = props.cyPosition;
+ this.cyRenderedPosition = props.cyRenderedPosition;
+ this.namespace = props.namespace;
+ this.layout = props.layout;
+ this.data = props.data;
+ this.message = props.message;
+ }
+
+ // Create a timestamp if incoming event doesn't have one
+ this.timeStamp = src && src.timeStamp || Date.now();
+};
+
+function returnFalse() {
+ return false;
+}
+
+function returnTrue() {
+ return true;
+}
+
+// http://www.w3.org/TR/2003/WD-DOM-Level-3-Events-20030331/ecma-script-binding.html
+Event.prototype = {
+ instanceString: function(){
+ return 'event';
+ },
+
+ preventDefault: function() {
+ this.isDefaultPrevented = returnTrue;
+
+ var e = this.originalEvent;
+ if ( !e ) {
+ return;
+ }
+
+ // if preventDefault exists run it on the original event
+ if ( e.preventDefault ) {
+ e.preventDefault();
+ }
+ },
+
+ stopPropagation: function() {
+ this.isPropagationStopped = returnTrue;
+
+ var e = this.originalEvent;
+ if ( !e ) {
+ return;
+ }
+
+ // if stopPropagation exists run it on the original event
+ if ( e.stopPropagation ) {
+ e.stopPropagation();
+ }
+ },
+
+ stopImmediatePropagation: function() {
+ this.isImmediatePropagationStopped = returnTrue;
+ this.stopPropagation();
+ },
+
+ isDefaultPrevented: returnFalse,
+ isPropagationStopped: returnFalse,
+ isImmediatePropagationStopped: returnFalse
+};
+
+module.exports = Event;
+
+},{}],43:[function(_dereq_,module,exports){
+'use strict';
+
+var util = _dereq_('./util');
+var define = _dereq_('./define');
+var Collection = _dereq_('./collection');
+var Core = _dereq_('./core');
+var incExts = _dereq_('./extensions');
+var is = _dereq_('./is');
+
+// registered extensions to cytoscape, indexed by name
+var extensions = {};
+
+// registered modules for extensions, indexed by name
+var modules = {};
+
+function setExtension( type, name, registrant ){
+
+ var ext = registrant;
+
+ if( type === 'core' ){
+ Core.prototype[ name ] = registrant;
+
+ } else if( type === 'collection' ){
+ Collection.prototype[ name ] = registrant;
+
+ } else if( type === 'layout' ){
+ // fill in missing layout functions in the prototype
+
+ var Layout = function( options ){
+ this.options = options;
+
+ registrant.call( this, options );
+
+ // make sure layout has _private for use w/ std apis like .on()
+ if( !is.plainObject(this._private) ){
+ this._private = {};
+ }
+
+ this._private.cy = options.cy;
+ this._private.listeners = [];
+ };
+
+ var layoutProto = Layout.prototype = Object.create( registrant.prototype );
+
+ var optLayoutFns = [];
+
+ for( var i = 0; i < optLayoutFns.length; i++ ){
+ var fnName = optLayoutFns[i];
+
+ layoutProto[fnName] = layoutProto[fnName] || function(){ return this; };
+ }
+
+ // either .start() or .run() is defined, so autogen the other
+ if( layoutProto.start && !layoutProto.run ){
+ layoutProto.run = function(){ this.start(); return this; };
+ } else if( !layoutProto.start && layoutProto.run ){
+ layoutProto.start = function(){ this.run(); return this; };
+ }
+
+ if( !layoutProto.stop ){
+ layoutProto.stop = function(){
+ var opts = this.options;
+
+ if( opts && opts.animate ){
+ var anis = this.animations;
+ for( var i = 0; i < anis.length; i++ ){
+ anis[i].stop();
+ }
+ }
+
+ this.trigger('layoutstop');
+
+ return this;
+ };
+ }
+
+ if( !layoutProto.destroy ){
+ layoutProto.destroy = function(){
+ return this;
+ };
+ }
+
+ layoutProto.on = define.on({ layout: true });
+ layoutProto.one = define.on({ layout: true, unbindSelfOnTrigger: true });
+ layoutProto.once = define.on({ layout: true, unbindAllBindersOnTrigger: true });
+ layoutProto.off = define.off({ layout: true });
+ layoutProto.trigger = define.trigger({ layout: true });
+
+ define.eventAliasesOn( layoutProto );
+
+ ext = Layout; // replace with our wrapped layout
+
+ } else if( type === 'renderer' && name !== 'null' && name !== 'base' ){
+ // user registered renderers inherit from base
+
+ var bProto = getExtension( 'renderer', 'base' ).prototype;
+ var rProto = registrant.prototype;
+
+ for( var pName in bProto ){
+ var pVal = bProto[ pName ];
+ var existsInR = rProto[ pName ] != null;
+
+ if( existsInR ){
+ util.error('Can not register renderer `' + name + '` since it overrides `' + pName + '` in its prototype');
+ return;
+ }
+
+ rProto[ pName ] = pVal; // take impl from base
+ }
+
+ bProto.clientFunctions.forEach(function( name ){
+ rProto[ name ] = rProto[ name ] || function(){
+ util.error('Renderer does not implement `renderer.' + name + '()` on its prototype');
+ };
+ });
+
+ }
+
+ return util.setMap({
+ map: extensions,
+ keys: [ type, name ],
+ value: ext
+ });
+}
+
+function getExtension(type, name){
+ return util.getMap({
+ map: extensions,
+ keys: [ type, name ]
+ });
+}
+
+function setModule(type, name, moduleType, moduleName, registrant){
+ return util.setMap({
+ map: modules,
+ keys: [ type, name, moduleType, moduleName ],
+ value: registrant
+ });
+}
+
+function getModule(type, name, moduleType, moduleName){
+ return util.getMap({
+ map: modules,
+ keys: [ type, name, moduleType, moduleName ]
+ });
+}
+
+var extension = function(){
+ // e.g. extension('renderer', 'svg')
+ if( arguments.length === 2 ){
+ return getExtension.apply(null, arguments);
+ }
+
+ // e.g. extension('renderer', 'svg', { ... })
+ else if( arguments.length === 3 ){
+ return setExtension.apply(null, arguments);
+ }
+
+ // e.g. extension('renderer', 'svg', 'nodeShape', 'ellipse')
+ else if( arguments.length === 4 ){
+ return getModule.apply(null, arguments);
+ }
+
+ // e.g. extension('renderer', 'svg', 'nodeShape', 'ellipse', { ... })
+ else if( arguments.length === 5 ){
+ return setModule.apply(null, arguments);
+ }
+
+ else {
+ util.error('Invalid extension access syntax');
+ }
+
+};
+
+// allows a core instance to access extensions internally
+Core.prototype.extension = extension;
+
+// included extensions
+incExts.forEach(function( group ){
+ group.extensions.forEach(function( ext ){
+ setExtension( group.type, ext.name, ext.impl );
+ });
+});
+
+module.exports = extension;
+
+},{"./collection":23,"./core":34,"./define":41,"./extensions":44,"./is":77,"./util":94}],44:[function(_dereq_,module,exports){
+'use strict';
+
+module.exports = [
+ {
+ type: 'layout',
+ extensions: _dereq_('./layout')
+ },
+
+ {
+ type: 'renderer',
+ extensions: _dereq_('./renderer')
+ }
+];
+
+},{"./layout":50,"./renderer":72}],45:[function(_dereq_,module,exports){
+'use strict';
+
+var util = _dereq_('../../util');
+var math = _dereq_('../../math');
+var is = _dereq_('../../is');
+
+var defaults = {
+ fit: true, // whether to fit the viewport to the graph
+ directed: false, // whether the tree is directed downwards (or edges can point in any direction if false)
+ padding: 30, // padding on fit
+ circle: false, // put depths in concentric circles if true, put depths top down if false
+ spacingFactor: 1.75, // positive spacing factor, larger => more space between nodes (N.B. n/a if causes overlap)
+ boundingBox: undefined, // constrain layout bounds; { x1, y1, x2, y2 } or { x1, y1, w, h }
+ avoidOverlap: true, // prevents node overlap, may overflow boundingBox if not enough space
+ roots: undefined, // the roots of the trees
+ maximalAdjustments: 0, // how many times to try to position the nodes in a maximal way (i.e. no backtracking)
+ animate: false, // whether to transition the node positions
+ animationDuration: 500, // duration of animation in ms if enabled
+ animationEasing: undefined, // easing of animation if enabled
+ ready: undefined, // callback on layoutready
+ stop: undefined // callback on layoutstop
+};
+
+function BreadthFirstLayout( options ){
+ this.options = util.extend({}, defaults, options);
+}
+
+BreadthFirstLayout.prototype.run = function(){
+ var params = this.options;
+ var options = params;
+
+ var cy = params.cy;
+ var eles = options.eles;
+ var nodes = eles.nodes().not(':parent');
+ var graph = eles;
+
+ var bb = math.makeBoundingBox( options.boundingBox ? options.boundingBox : {
+ x1: 0, y1: 0, w: cy.width(), h: cy.height()
+ } );
+
+ var roots;
+ if( is.elementOrCollection(options.roots) ){
+ roots = options.roots;
+ } else if( is.array(options.roots) ){
+ var rootsArray = [];
+
+ for( var i = 0; i < options.roots.length; i++ ){
+ var id = options.roots[i];
+ var ele = cy.getElementById( id );
+ rootsArray.push( ele );
+ }
+
+ roots = cy.collection( rootsArray );
+ } else if( is.string(options.roots) ){
+ roots = cy.$( options.roots );
+
+ } else {
+ if( options.directed ){
+ roots = nodes.roots();
+ } else {
+ var components = [];
+ var unhandledNodes = nodes;
+
+ while( unhandledNodes.length > 0 ){
+ var currComp = cy.collection();
+
+ eles.bfs({
+ roots: unhandledNodes[0],
+ visit: function(i, depth, node, edge, pNode){
+ currComp = currComp.add( node );
+ },
+ directed: false
+ });
+
+ unhandledNodes = unhandledNodes.not( currComp );
+ components.push( currComp );
+ }
+
+ roots = cy.collection();
+ for( var i = 0; i < components.length; i++ ){
+ var comp = components[i];
+ var maxDegree = comp.maxDegree( false );
+ var compRoots = comp.filter(function(){
+ return this.degree(false) === maxDegree;
+ });
+
+ roots = roots.add( compRoots );
+ }
+
+ }
+ }
+
+
+ var depths = [];
+ var foundByBfs = {};
+ var id2depth = {};
+ var prevNode = {};
+ var prevEdge = {};
+ var successors = {};
+
+ // find the depths of the nodes
+ graph.bfs({
+ roots: roots,
+ directed: options.directed,
+ visit: function(i, depth, node, edge, pNode){
+ var ele = this[0];
+ var id = ele.id();
+
+ if( !depths[depth] ){
+ depths[depth] = [];
+ }
+
+ depths[depth].push( ele );
+ foundByBfs[ id ] = true;
+ id2depth[ id ] = depth;
+ prevNode[ id ] = pNode;
+ prevEdge[ id ] = edge;
+
+ if( pNode ){
+ var prevId = pNode.id();
+ var succ = successors[ prevId ] = successors[ prevId ] || [];
+
+ succ.push( node );
+ }
+ }
+ });
+
+ // check for nodes not found by bfs
+ var orphanNodes = [];
+ for( var i = 0; i < nodes.length; i++ ){
+ var ele = nodes[i];
+
+ if( foundByBfs[ ele.id() ] ){
+ continue;
+ } else {
+ orphanNodes.push( ele );
+ }
+ }
+
+ // assign orphan nodes a depth from their neighborhood
+ var maxChecks = orphanNodes.length * 3;
+ var checks = 0;
+ while( orphanNodes.length !== 0 && checks < maxChecks ){
+ var node = orphanNodes.shift();
+ var neighbors = node.neighborhood().nodes();
+ var assignedDepth = false;
+
+ for( var i = 0; i < neighbors.length; i++ ){
+ var depth = id2depth[ neighbors[i].id() ];
+
+ if( depth !== undefined ){
+ depths[depth].push( node );
+ assignedDepth = true;
+ break;
+ }
+ }
+
+ if( !assignedDepth ){
+ orphanNodes.push( node );
+ }
+
+ checks++;
+ }
+
+ // assign orphan nodes that are still left to the depth of their subgraph
+ while( orphanNodes.length !== 0 ){
+ var node = orphanNodes.shift();
+ //var subgraph = graph.bfs( node ).path;
+ var assignedDepth = false;
+
+ // for( var i = 0; i < subgraph.length; i++ ){
+ // var depth = id2depth[ subgraph[i].id() ];
+
+ // if( depth !== undefined ){
+ // depths[depth].push( node );
+ // assignedDepth = true;
+ // break;
+ // }
+ // }
+
+ if( !assignedDepth ){ // worst case if the graph really isn't tree friendly, then just dump it in 0
+ if( depths.length === 0 ){
+ depths.push([]);
+ }
+
+ depths[0].push( node );
+ }
+ }
+
+ // assign the nodes a depth and index
+ var assignDepthsToEles = function(){
+ for( var i = 0; i < depths.length; i++ ){
+ var eles = depths[i];
+
+ for( var j = 0; j < eles.length; j++ ){
+ var ele = eles[j];
+
+ ele._private.scratch.breadthfirst = {
+ depth: i,
+ index: j
+ };
+ }
+ }
+ };
+ assignDepthsToEles();
+
+
+ var intersectsDepth = function( node ){ // returns true if has edges pointing in from a higher depth
+ var edges = node.connectedEdges(function(){
+ return this.data('target') === node.id();
+ });
+ var thisInfo = node._private.scratch.breadthfirst;
+ var highestDepthOfOther = 0;
+ var highestOther;
+ for( var i = 0; i < edges.length; i++ ){
+ var edge = edges[i];
+ var otherNode = edge.source()[0];
+ var otherInfo = otherNode._private.scratch.breadthfirst;
+
+ if( thisInfo.depth <= otherInfo.depth && highestDepthOfOther < otherInfo.depth ){
+ highestDepthOfOther = otherInfo.depth;
+ highestOther = otherNode;
+ }
+ }
+
+ return highestOther;
+ };
+
+ // make maximal if so set by adjusting depths
+ for( var adj = 0; adj < options.maximalAdjustments; adj++ ){
+
+ var nDepths = depths.length;
+ var elesToMove = [];
+ for( var i = 0; i < nDepths; i++ ){
+ var depth = depths[i];
+
+ var nDepth = depth.length;
+ for( var j = 0; j < nDepth; j++ ){
+ var ele = depth[j];
+ var info = ele._private.scratch.breadthfirst;
+ var intEle = intersectsDepth(ele);
+
+ if( intEle ){
+ info.intEle = intEle;
+ elesToMove.push( ele );
+ }
+ }
+ }
+
+ for( var i = 0; i < elesToMove.length; i++ ){
+ var ele = elesToMove[i];
+ var info = ele._private.scratch.breadthfirst;
+ var intEle = info.intEle;
+ var intInfo = intEle._private.scratch.breadthfirst;
+
+ depths[ info.depth ].splice( info.index, 1 ); // remove from old depth & index
+
+ // add to end of new depth
+ var newDepth = intInfo.depth + 1;
+ while( newDepth > depths.length - 1 ){
+ depths.push([]);
+ }
+ depths[ newDepth ].push( ele );
+
+ info.depth = newDepth;
+ info.index = depths[newDepth].length - 1;
+ }
+
+ assignDepthsToEles();
+ }
+
+ // find min distance we need to leave between nodes
+ var minDistance = 0;
+ if( options.avoidOverlap ){
+ for( var i = 0; i < nodes.length; i++ ){
+ var n = nodes[i];
+ var nbb = n.boundingBox();
+ var w = nbb.w;
+ var h = nbb.h;
+
+ minDistance = Math.max(minDistance, w, h);
+ }
+ minDistance *= options.spacingFactor; // just to have some nice spacing
+ }
+
+ // get the weighted percent for an element based on its connectivity to other levels
+ var cachedWeightedPercent = {};
+ var getWeightedPercent = function( ele ){
+ if( cachedWeightedPercent[ ele.id() ] ){
+ return cachedWeightedPercent[ ele.id() ];
+ }
+
+ var eleDepth = ele._private.scratch.breadthfirst.depth;
+ var neighbors = ele.neighborhood().nodes().not(':parent');
+ var percent = 0;
+ var samples = 0;
+
+ for( var i = 0; i < neighbors.length; i++ ){
+ var neighbor = neighbors[i];
+ var bf = neighbor._private.scratch.breadthfirst;
+ var index = bf.index;
+ var depth = bf.depth;
+ var nDepth = depths[depth].length;
+
+ if( eleDepth > depth || eleDepth === 0 ){ // only get influenced by elements above
+ percent += index / nDepth;
+ samples++;
+ }
+ }
+
+ samples = Math.max(1, samples);
+ percent = percent / samples;
+
+ if( samples === 0 ){ // so lone nodes have a "don't care" state in sorting
+ percent = undefined;
+ }
+
+ cachedWeightedPercent[ ele.id() ] = percent;
+ return percent;
+ };
+
+
+ // rearrange the indices in each depth level based on connectivity
+
+ var sortFn = function(a, b){
+ var apct = getWeightedPercent( a );
+ var bpct = getWeightedPercent( b );
+
+ return apct - bpct;
+ };
+
+ for( var times = 0; times < 3; times++ ){ // do it a few times b/c the depths are dynamic and we want a more stable result
+
+ for( var i = 0; i < depths.length; i++ ){
+ depths[i] = depths[i].sort( sortFn );
+ }
+ assignDepthsToEles(); // and update
+
+ }
+
+ var biggestDepthSize = 0;
+ for( var i = 0; i < depths.length; i++ ){
+ biggestDepthSize = Math.max( depths[i].length, biggestDepthSize );
+ }
+
+ var center = {
+ x: bb.x1 + bb.w/2,
+ y: bb.x1 + bb.h/2
+ };
+
+ var getPosition = function( ele, isBottomDepth ){
+ var info = ele._private.scratch.breadthfirst;
+ var depth = info.depth;
+ var index = info.index;
+ var depthSize = depths[depth].length;
+
+ var distanceX = Math.max( bb.w / (depthSize + 1), minDistance );
+ var distanceY = Math.max( bb.h / (depths.length + 1), minDistance );
+ var radiusStepSize = Math.min( bb.w / 2 / depths.length, bb.h / 2 / depths.length );
+ radiusStepSize = Math.max( radiusStepSize, minDistance );
+
+ if( !options.circle ){
+
+ var epos = {
+ x: center.x + (index + 1 - (depthSize + 1)/2) * distanceX,
+ y: (depth + 1) * distanceY
+ };
+
+ if( isBottomDepth ){
+ return epos;
+ }
+
+ // var succs = successors[ ele.id() ];
+ // if( succs ){
+ // epos.x = 0;
+ //
+ // for( var i = 0 ; i < succs.length; i++ ){
+ // var spos = pos[ succs[i].id() ];
+ //
+ // epos.x += spos.x;
+ // }
+ //
+ // epos.x /= succs.length;
+ // } else {
+ // //debugger;
+ // }
+
+ return epos;
+
+ } else {
+ if( options.circle ){
+ var radius = radiusStepSize * depth + radiusStepSize - (depths.length > 0 && depths[0].length <= 3 ? radiusStepSize/2 : 0);
+ var theta = 2 * Math.PI / depths[depth].length * index;
+
+ if( depth === 0 && depths[0].length === 1 ){
+ radius = 1;
+ }
+
+ return {
+ x: center.x + radius * Math.cos(theta),
+ y: center.y + radius * Math.sin(theta)
+ };
+
+ } else {
+ return {
+ x: center.x + (index + 1 - (depthSize + 1)/2) * distanceX,
+ y: (depth + 1) * distanceY
+ };
+ }
+ }
+
+ };
+
+ // get positions in reverse depth order
+ var pos = {};
+ for( var i = depths.length - 1; i >=0; i-- ){
+ var depth = depths[i];
+
+ for( var j = 0; j < depth.length; j++ ){
+ var node = depth[j];
+
+ pos[ node.id() ] = getPosition( node, i === depths.length - 1 );
+ }
+ }
+
+ nodes.layoutPositions(this, options, function(){
+ return pos[ this.id() ];
+ });
+
+ return this; // chaining
+};
+
+module.exports = BreadthFirstLayout;
+
+},{"../../is":77,"../../math":79,"../../util":94}],46:[function(_dereq_,module,exports){
+'use strict';
+
+var util = _dereq_('../../util');
+var math = _dereq_('../../math');
+var is = _dereq_('../../is');
+
+var defaults = {
+ fit: true, // whether to fit the viewport to the graph
+ padding: 30, // the padding on fit
+ boundingBox: undefined, // constrain layout bounds; { x1, y1, x2, y2 } or { x1, y1, w, h }
+ avoidOverlap: true, // prevents node overlap, may overflow boundingBox and radius if not enough space
+ radius: undefined, // the radius of the circle
+ startAngle: 3/2 * Math.PI, // where nodes start in radians
+ sweep: undefined, // how many radians should be between the first and last node (defaults to full circle)
+ clockwise: true, // whether the layout should go clockwise (true) or counterclockwise/anticlockwise (false)
+ sort: undefined, // a sorting function to order the nodes; e.g. function(a, b){ return a.data('weight') - b.data('weight') }
+ animate: false, // whether to transition the node positions
+ animationDuration: 500, // duration of animation in ms if enabled
+ animationEasing: undefined, // easing of animation if enabled
+ ready: undefined, // callback on layoutready
+ stop: undefined // callback on layoutstop
+};
+
+function CircleLayout( options ){
+ this.options = util.extend({}, defaults, options);
+}
+
+CircleLayout.prototype.run = function(){
+ var params = this.options;
+ var options = params;
+
+ var cy = params.cy;
+ var eles = options.eles;
+
+ var clockwise = options.counterclockwise !== undefined ? !options.counterclockwise : options.clockwise;
+
+ var nodes = eles.nodes().not(':parent');
+
+ if( options.sort ){
+ nodes = nodes.sort( options.sort );
+ }
+
+ var bb = math.makeBoundingBox( options.boundingBox ? options.boundingBox : {
+ x1: 0, y1: 0, w: cy.width(), h: cy.height()
+ } );
+
+ var center = {
+ x: bb.x1 + bb.w/2,
+ y: bb.y1 + bb.h/2
+ };
+
+ var sweep = options.sweep === undefined ? 2*Math.PI - 2*Math.PI/nodes.length : options.sweep;
+
+ var dTheta = sweep / ( Math.max(1, nodes.length - 1) );
+ var r;
+
+ var minDistance = 0;
+ for( var i = 0; i < nodes.length; i++ ){
+ var n = nodes[i];
+ var nbb = n.boundingBox();
+ var w = nbb.w;
+ var h = nbb.h;
+
+ minDistance = Math.max(minDistance, w, h);
+ }
+
+ if( is.number(options.radius) ){
+ r = options.radius;
+ } else if( nodes.length <= 1 ){
+ r = 0;
+ } else {
+ r = Math.min( bb.h, bb.w )/2 - minDistance;
+ }
+
+ // calculate the radius
+ if( nodes.length > 1 && options.avoidOverlap ){ // but only if more than one node (can't overlap)
+ minDistance *= 1.75; // just to have some nice spacing
+
+ var dcos = Math.cos(dTheta) - Math.cos(0);
+ var dsin = Math.sin(dTheta) - Math.sin(0);
+ var rMin = Math.sqrt( minDistance * minDistance / ( dcos*dcos + dsin*dsin ) ); // s.t. no nodes overlapping
+ r = Math.max( rMin, r );
+ }
+
+ var getPos = function( i, ele ){
+ var theta = options.startAngle + i * dTheta * ( clockwise ? 1 : -1 );
+
+ var rx = r * Math.cos( theta );
+ var ry = r * Math.sin( theta );
+ var pos = {
+ x: center.x + rx,
+ y: center.y + ry
+ };
+
+ return pos;
+ };
+
+ nodes.layoutPositions( this, options, getPos );
+
+ return this; // chaining
+};
+
+module.exports = CircleLayout;
+
+},{"../../is":77,"../../math":79,"../../util":94}],47:[function(_dereq_,module,exports){
+'use strict';
+
+var util = _dereq_('../../util');
+var math = _dereq_('../../math');
+
+var defaults = {
+ fit: true, // whether to fit the viewport to the graph
+ padding: 30, // the padding on fit
+ startAngle: 3/2 * Math.PI, // where nodes start in radians
+ sweep: undefined, // how many radians should be between the first and last node (defaults to full circle)
+ clockwise: true, // whether the layout should go clockwise (true) or counterclockwise/anticlockwise (false)
+ equidistant: false, // whether levels have an equal radial distance betwen them, may cause bounding box overflow
+ minNodeSpacing: 10, // min spacing between outside of nodes (used for radius adjustment)
+ boundingBox: undefined, // constrain layout bounds; { x1, y1, x2, y2 } or { x1, y1, w, h }
+ avoidOverlap: true, // prevents node overlap, may overflow boundingBox if not enough space
+ height: undefined, // height of layout area (overrides container height)
+ width: undefined, // width of layout area (overrides container width)
+ concentric: function(node){ // returns numeric value for each node, placing higher nodes in levels towards the centre
+ return node.degree();
+ },
+ levelWidth: function(nodes){ // the variation of concentric values in each level
+ return nodes.maxDegree() / 4;
+ },
+ animate: false, // whether to transition the node positions
+ animationDuration: 500, // duration of animation in ms if enabled
+ animationEasing: undefined, // easing of animation if enabled
+ ready: undefined, // callback on layoutready
+ stop: undefined // callback on layoutstop
+};
+
+function ConcentricLayout( options ){
+ this.options = util.extend({}, defaults, options);
+}
+
+ConcentricLayout.prototype.run = function(){
+ var params = this.options;
+ var options = params;
+
+ var clockwise = options.counterclockwise !== undefined ? !options.counterclockwise : options.clockwise;
+
+ var cy = params.cy;
+
+ var eles = options.eles;
+ var nodes = eles.nodes().not(':parent');
+
+ var bb = math.makeBoundingBox( options.boundingBox ? options.boundingBox : {
+ x1: 0, y1: 0, w: cy.width(), h: cy.height()
+ } );
+
+ var center = {
+ x: bb.x1 + bb.w/2,
+ y: bb.y1 + bb.h/2
+ };
+
+ var nodeValues = []; // { node, value }
+ var theta = options.startAngle;
+ var maxNodeSize = 0;
+
+ for( var i = 0; i < nodes.length; i++ ){
+ var node = nodes[i];
+ var value;
+
+ // calculate the node value
+ value = options.concentric.apply(node, [ node ]);
+ nodeValues.push({
+ value: value,
+ node: node
+ });
+
+ // for style mapping
+ node._private.scratch.concentric = value;
+ }
+
+ // in case we used the `concentric` in style
+ nodes.updateStyle();
+
+ // calculate max size now based on potentially updated mappers
+ for( var i = 0; i < nodes.length; i++ ){
+ var node = nodes[i];
+ var nbb = node.boundingBox();
+
+ maxNodeSize = Math.max( maxNodeSize, nbb.w, nbb.h );
+ }
+
+ // sort node values in descreasing order
+ nodeValues.sort(function(a, b){
+ return b.value - a.value;
+ });
+
+ var levelWidth = options.levelWidth( nodes );
+
+ // put the values into levels
+ var levels = [ [] ];
+ var currentLevel = levels[0];
+ for( var i = 0; i < nodeValues.length; i++ ){
+ var val = nodeValues[i];
+
+ if( currentLevel.length > 0 ){
+ var diff = Math.abs( currentLevel[0].value - val.value );
+
+ if( diff >= levelWidth ){
+ currentLevel = [];
+ levels.push( currentLevel );
+ }
+ }
+
+ currentLevel.push( val );
+ }
+
+ // create positions from levels
+
+ var minDist = maxNodeSize + options.minNodeSpacing; // min dist between nodes
+
+ if( !options.avoidOverlap ){ // then strictly constrain to bb
+ var firstLvlHasMulti = levels.length > 0 && levels[0].length > 1;
+ var maxR = ( Math.min(bb.w, bb.h) / 2 - minDist );
+ var rStep = maxR / ( levels.length + firstLvlHasMulti ? 1 : 0 );
+
+ minDist = Math.min( minDist, rStep );
+ }
+
+ // find the metrics for each level
+ var r = 0;
+ for( var i = 0; i < levels.length; i++ ){
+ var level = levels[i];
+ var sweep = options.sweep === undefined ? 2*Math.PI - 2*Math.PI/level.length : options.sweep;
+ var dTheta = level.dTheta = sweep / ( Math.max(1, level.length - 1) );
+
+ // calculate the radius
+ if( level.length > 1 && options.avoidOverlap ){ // but only if more than one node (can't overlap)
+ var dcos = Math.cos(dTheta) - Math.cos(0);
+ var dsin = Math.sin(dTheta) - Math.sin(0);
+ var rMin = Math.sqrt( minDist * minDist / ( dcos*dcos + dsin*dsin ) ); // s.t. no nodes overlapping
+
+ r = Math.max( rMin, r );
+ }
+
+ level.r = r;
+
+ r += minDist;
+ }
+
+ if( options.equidistant ){
+ var rDeltaMax = 0;
+ var r = 0;
+
+ for( var i = 0; i < levels.length; i++ ){
+ var level = levels[i];
+ var rDelta = level.r - r;
+
+ rDeltaMax = Math.max( rDeltaMax, rDelta );
+ }
+
+ r = 0;
+ for( var i = 0; i < levels.length; i++ ){
+ var level = levels[i];
+
+ if( i === 0 ){
+ r = level.r;
+ }
+
+ level.r = r;
+
+ r += rDeltaMax;
+ }
+ }
+
+ // calculate the node positions
+ var pos = {}; // id => position
+ for( var i = 0; i < levels.length; i++ ){
+ var level = levels[i];
+ var dTheta = level.dTheta;
+ var r = level.r;
+
+ for( var j = 0; j < level.length; j++ ){
+ var val = level[j];
+ var theta = options.startAngle + (clockwise ? 1 : -1) * dTheta * j;
+
+ var p = {
+ x: center.x + r * Math.cos(theta),
+ y: center.y + r * Math.sin(theta)
+ };
+
+ pos[ val.node.id() ] = p;
+ }
+ }
+
+ // position the nodes
+ nodes.layoutPositions(this, options, function(){
+ var id = this.id();
+
+ return pos[id];
+ });
+
+ return this; // chaining
+};
+
+module.exports = ConcentricLayout;
+
+},{"../../math":79,"../../util":94}],48:[function(_dereq_,module,exports){
+'use strict';
+
+/*
+The CoSE layout was written by Gerardo Huck.
+https://www.linkedin.com/in/gerardohuck/
+
+Based on the following article:
+http://dl.acm.org/citation.cfm?id=1498047
+
+Modifications tracked on Github.
+*/
+
+var util = _dereq_('../../util');
+var math = _dereq_('../../math');
+var Thread = _dereq_('../../thread');
+var is = _dereq_('../../is');
+
+var DEBUG;
+
+/**
+ * @brief : default layout options
+ */
+var defaults = {
+ // Called on `layoutready`
+ ready : function() {},
+
+ // Called on `layoutstop`
+ stop : function() {},
+
+ // Whether to animate while running the layout
+ animate : true,
+
+ // The layout animates only after this many milliseconds
+ // (prevents flashing on fast runs)
+ animationThreshold : 250,
+
+ // Number of iterations between consecutive screen positions update
+ // (0 -> only updated on the end)
+ refresh : 20,
+
+ // Whether to fit the network view after when done
+ fit : true,
+
+ // Padding on fit
+ padding : 30,
+
+ // Constrain layout bounds; { x1, y1, x2, y2 } or { x1, y1, w, h }
+ boundingBox : undefined,
+
+ // Extra spacing between components in non-compound graphs
+ componentSpacing : 100,
+
+ // Node repulsion (non overlapping) multiplier
+ nodeRepulsion : function( node ){ return 400000; },
+
+ // Node repulsion (overlapping) multiplier
+ nodeOverlap : 10,
+
+ // Ideal edge (non nested) length
+ idealEdgeLength : function( edge ){ return 10; },
+
+ // Divisor to compute edge forces
+ edgeElasticity : function( edge ){ return 100; },
+
+ // Nesting factor (multiplier) to compute ideal edge length for nested edges
+ nestingFactor : 5,
+
+ // Gravity force (constant)
+ gravity : 80,
+
+ // Maximum number of iterations to perform
+ numIter : 1000,
+
+ // Initial temperature (maximum node displacement)
+ initialTemp : 200,
+
+ // Cooling factor (how the temperature is reduced between consecutive iterations
+ coolingFactor : 0.95,
+
+ // Lower temperature threshold (below this point the layout will end)
+ minTemp : 1.0,
+
+ // Whether to use threading to speed up the layout
+ useMultitasking : true
+};
+
+
+/**
+ * @brief : constructor
+ * @arg options : object containing layout options
+ */
+function CoseLayout(options) {
+ this.options = util.extend({}, defaults, options);
+
+ this.options.layout = this;
+}
+
+
+/**
+ * @brief : runs the layout
+ */
+CoseLayout.prototype.run = function() {
+ var options = this.options;
+ var cy = options.cy;
+ var layout = this;
+ var thread = this.thread;
+
+ if( !thread || thread.stopped() ){
+ thread = this.thread = Thread({ disabled: !options.useMultitasking });
+ }
+
+ layout.stopped = false;
+
+ layout.trigger({ type: 'layoutstart', layout: layout });
+
+ // Set DEBUG - Global variable
+ if (true === options.debug) {
+ DEBUG = true;
+ } else {
+ DEBUG = false;
+ }
+
+ // Initialize layout info
+ var layoutInfo = createLayoutInfo(cy, layout, options);
+
+ // Show LayoutInfo contents if debugging
+ if (DEBUG) {
+ printLayoutInfo(layoutInfo);
+ }
+
+ // If required, randomize node positions
+ // if (true === options.randomize) {
+ randomizePositions(layoutInfo, cy);
+ // }
+
+ var startTime = Date.now();
+ var refreshRequested = false;
+ var refresh = function( rOpts ){
+ rOpts = rOpts || {};
+
+ if( refreshRequested ){
+ return;
+ }
+
+ if( !rOpts.force && Date.now() - startTime < options.animationThreshold ){
+ return;
+ }
+
+ refreshRequested = true;
+
+ util.requestAnimationFrame(function(){
+ refreshPositions(layoutInfo, cy, options);
+
+ // Fit the graph if necessary
+ if (true === options.fit) {
+ cy.fit( options.padding );
+ }
+
+ refreshRequested = false;
+ });
+ };
+
+ thread.on('message', function( e ){
+ var layoutNodes = e.message;
+
+ layoutInfo.layoutNodes = layoutNodes;
+ refresh();
+ });
+
+ thread.pass({
+ layoutInfo: layoutInfo,
+ options: {
+ animate: options.animate,
+ refresh: options.refresh,
+ componentSpacing: options.componentSpacing,
+ nodeOverlap: options.nodeOverlap,
+ nestingFactor: options.nestingFactor,
+ gravity: options.gravity,
+ numIter: options.numIter,
+ initialTemp: options.initialTemp,
+ coolingFactor: options.coolingFactor,
+ minTemp: options.minTemp
+ }
+ }).run(function( pass ){
+ var layoutInfo = pass.layoutInfo;
+ var options = pass.options;
+ var stopped = false;
+
+ /**
+ * @brief : Performs one iteration of the physical simulation
+ * @arg layoutInfo : LayoutInfo object already initialized
+ * @arg cy : Cytoscape object
+ * @arg options : Layout options
+ */
+ var step = function(layoutInfo, options, step) {
+ // var s = "\n\n###############################";
+ // s += "\nSTEP: " + step;
+ // s += "\n###############################\n";
+ // logDebug(s);
+
+ // Calculate node repulsions
+ calculateNodeForces(layoutInfo, options);
+ // Calculate edge forces
+ calculateEdgeForces(layoutInfo, options);
+ // Calculate gravity forces
+ calculateGravityForces(layoutInfo, options);
+ // Propagate forces from parent to child
+ propagateForces(layoutInfo, options);
+ // Update positions based on calculated forces
+ updatePositions(layoutInfo, options);
+ };
+
+ /**
+ * @brief : Computes the node repulsion forces
+ */
+ var calculateNodeForces = function(layoutInfo, options) {
+ // Go through each of the graphs in graphSet
+ // Nodes only repel each other if they belong to the same graph
+ // var s = 'calculateNodeForces';
+ // logDebug(s);
+ for (var i = 0; i < layoutInfo.graphSet.length; i ++) {
+ var graph = layoutInfo.graphSet[i];
+ var numNodes = graph.length;
+
+ // s = "Set: " + graph.toString();
+ // logDebug(s);
+
+ // Now get all the pairs of nodes
+ // Only get each pair once, (A, B) = (B, A)
+ for (var j = 0; j < numNodes; j++) {
+ var node1 = layoutInfo.layoutNodes[layoutInfo.idToIndex[graph[j]]];
+
+ for (var k = j + 1; k < numNodes; k++) {
+ var node2 = layoutInfo.layoutNodes[layoutInfo.idToIndex[graph[k]]];
+
+ nodeRepulsion(node1, node2, layoutInfo, options);
+ }
+ }
+ }
+ };
+
+ /**
+ * @brief : Compute the node repulsion forces between a pair of nodes
+ */
+ var nodeRepulsion = function(node1, node2, layoutInfo, options) {
+ // var s = "Node repulsion. Node1: " + node1.id + " Node2: " + node2.id;
+
+ var cmptId1 = node1.cmptId;
+ var cmptId2 = node2.cmptId;
+
+ if( cmptId1 !== cmptId2 && !layoutInfo.isCompound ){ return; }
+
+ // Get direction of line connecting both node centers
+ var directionX = node2.positionX - node1.positionX;
+ var directionY = node2.positionY - node1.positionY;
+ // s += "\ndirectionX: " + directionX + ", directionY: " + directionY;
+
+ // If both centers are the same, apply a random force
+ if (0 === directionX && 0 === directionY) {
+ // s += "\nNodes have the same position.";
+ return; // TODO could be improved with random force
+ }
+
+ var overlap = nodesOverlap(node1, node2, directionX, directionY);
+
+ if (overlap > 0) {
+ // s += "\nNodes DO overlap.";
+ // s += "\nOverlap: " + overlap;
+ // If nodes overlap, repulsion force is proportional
+ // to the overlap
+ var force = options.nodeOverlap * overlap;
+
+ // Compute the module and components of the force vector
+ var distance = Math.sqrt(directionX * directionX + directionY * directionY);
+ // s += "\nDistance: " + distance;
+ var forceX = force * directionX / distance;
+ var forceY = force * directionY / distance;
+
+ } else {
+ // s += "\nNodes do NOT overlap.";
+ // If there's no overlap, force is inversely proportional
+ // to squared distance
+
+ // Get clipping points for both nodes
+ var point1 = findClippingPoint(node1, directionX, directionY);
+ var point2 = findClippingPoint(node2, -1 * directionX, -1 * directionY);
+
+ // Use clipping points to compute distance
+ var distanceX = point2.x - point1.x;
+ var distanceY = point2.y - point1.y;
+ var distanceSqr = distanceX * distanceX + distanceY * distanceY;
+ var distance = Math.sqrt(distanceSqr);
+ // s += "\nDistance: " + distance;
+
+ // Compute the module and components of the force vector
+ var force = ( node1.nodeRepulsion + node2.nodeRepulsion ) / distanceSqr;
+ var forceX = force * distanceX / distance;
+ var forceY = force * distanceY / distance;
+ }
+
+ // Apply force
+ if( !node1.isLocked ){
+ node1.offsetX -= forceX;
+ node1.offsetY -= forceY;
+ }
+
+ if( !node2.isLocked ){
+ node2.offsetX += forceX;
+ node2.offsetY += forceY;
+ }
+
+ // s += "\nForceX: " + forceX + " ForceY: " + forceY;
+ // logDebug(s);
+
+ return;
+ };
+
+ /**
+ * @brief : Determines whether two nodes overlap or not
+ * @return : Amount of overlapping (0 => no overlap)
+ */
+ var nodesOverlap = function(node1, node2, dX, dY) {
+
+ if (dX > 0) {
+ var overlapX = node1.maxX - node2.minX;
+ } else {
+ var overlapX = node2.maxX - node1.minX;
+ }
+
+ if (dY > 0) {
+ var overlapY = node1.maxY - node2.minY;
+ } else {
+ var overlapY = node2.maxY - node1.minY;
+ }
+
+ if (overlapX >= 0 && overlapY >= 0) {
+ return Math.sqrt(overlapX * overlapX + overlapY * overlapY);
+ } else {
+ return 0;
+ }
+ };
+
+ /**
+ * @brief : Finds the point in which an edge (direction dX, dY) intersects
+ * the rectangular bounding box of it's source/target node
+ */
+ var findClippingPoint = function(node, dX, dY) {
+
+ // Shorcuts
+ var X = node.positionX;
+ var Y = node.positionY;
+ var H = node.height || 1;
+ var W = node.width || 1;
+ var dirSlope = dY / dX;
+ var nodeSlope = H / W;
+
+ // var s = 'Computing clipping point of node ' + node.id +
+ // " . Height: " + H + ", Width: " + W +
+ // "\nDirection " + dX + ", " + dY;
+ //
+ // Compute intersection
+ var res = {};
+ do {
+ // Case: Vertical direction (up)
+ if (0 === dX && 0 < dY) {
+ res.x = X;
+ // s += "\nUp direction";
+ res.y = Y + H / 2;
+ break;
+ }
+
+ // Case: Vertical direction (down)
+ if (0 === dX && 0 > dY) {
+ res.x = X;
+ res.y = Y + H / 2;
+ // s += "\nDown direction";
+ break;
+ }
+
+ // Case: Intersects the right border
+ if (0 < dX &&
+ -1 * nodeSlope <= dirSlope &&
+ dirSlope <= nodeSlope) {
+ res.x = X + W / 2;
+ res.y = Y + (W * dY / 2 / dX);
+ // s += "\nRightborder";
+ break;
+ }
+
+ // Case: Intersects the left border
+ if (0 > dX &&
+ -1 * nodeSlope <= dirSlope &&
+ dirSlope <= nodeSlope) {
+ res.x = X - W / 2;
+ res.y = Y - (W * dY / 2 / dX);
+ // s += "\nLeftborder";
+ break;
+ }
+
+ // Case: Intersects the top border
+ if (0 < dY &&
+ ( dirSlope <= -1 * nodeSlope ||
+ dirSlope >= nodeSlope )) {
+ res.x = X + (H * dX / 2 / dY);
+ res.y = Y + H / 2;
+ // s += "\nTop border";
+ break;
+ }
+
+ // Case: Intersects the bottom border
+ if (0 > dY &&
+ ( dirSlope <= -1 * nodeSlope ||
+ dirSlope >= nodeSlope )) {
+ res.x = X - (H * dX / 2 / dY);
+ res.y = Y - H / 2;
+ // s += "\nBottom border";
+ break;
+ }
+
+ } while (false);
+
+ // s += "\nClipping point found at " + res.x + ", " + res.y;
+ // logDebug(s);
+ return res;
+ };
+
+ /**
+ * @brief : Calculates all edge forces
+ */
+ var calculateEdgeForces = function(layoutInfo, options) {
+ // Iterate over all edges
+ for (var i = 0; i < layoutInfo.edgeSize; i++) {
+ // Get edge, source & target nodes
+ var edge = layoutInfo.layoutEdges[i];
+ var sourceIx = layoutInfo.idToIndex[edge.sourceId];
+ var source = layoutInfo.layoutNodes[sourceIx];
+ var targetIx = layoutInfo.idToIndex[edge.targetId];
+ var target = layoutInfo.layoutNodes[targetIx];
+
+ // Get direction of line connecting both node centers
+ var directionX = target.positionX - source.positionX;
+ var directionY = target.positionY - source.positionY;
+
+ // If both centers are the same, do nothing.
+ // A random force has already been applied as node repulsion
+ if (0 === directionX && 0 === directionY) {
+ return;
+ }
+
+ // Get clipping points for both nodes
+ var point1 = findClippingPoint(source, directionX, directionY);
+ var point2 = findClippingPoint(target, -1 * directionX, -1 * directionY);
+
+
+ var lx = point2.x - point1.x;
+ var ly = point2.y - point1.y;
+ var l = Math.sqrt(lx * lx + ly * ly);
+
+ var force = Math.pow(edge.idealLength - l, 2) / edge.elasticity;
+
+ if (0 !== l) {
+ var forceX = force * lx / l;
+ var forceY = force * ly / l;
+ } else {
+ var forceX = 0;
+ var forceY = 0;
+ }
+
+ // Add this force to target and source nodes
+ if( !source.isLocked ){
+ source.offsetX += forceX;
+ source.offsetY += forceY;
+ }
+
+ if( !target.isLocked ){
+ target.offsetX -= forceX;
+ target.offsetY -= forceY;
+ }
+
+ // var s = 'Edge force between nodes ' + source.id + ' and ' + target.id;
+ // s += "\nDistance: " + l + " Force: (" + forceX + ", " + forceY + ")";
+ // logDebug(s);
+ }
+ };
+
+ /**
+ * @brief : Computes gravity forces for all nodes
+ */
+ var calculateGravityForces = function(layoutInfo, options) {
+ var distThreshold = 1;
+
+ // var s = 'calculateGravityForces';
+ // logDebug(s);
+ for (var i = 0; i < layoutInfo.graphSet.length; i ++) {
+ var graph = layoutInfo.graphSet[i];
+ var numNodes = graph.length;
+
+ // s = "Set: " + graph.toString();
+ // logDebug(s);
+
+ // Compute graph center
+ if (0 === i) {
+ var centerX = layoutInfo.clientHeight / 2;
+ var centerY = layoutInfo.clientWidth / 2;
+ } else {
+ // Get Parent node for this graph, and use its position as center
+ var temp = layoutInfo.layoutNodes[layoutInfo.idToIndex[graph[0]]];
+ var parent = layoutInfo.layoutNodes[layoutInfo.idToIndex[temp.parentId]];
+ var centerX = parent.positionX;
+ var centerY = parent.positionY;
+ }
+ // s = "Center found at: " + centerX + ", " + centerY;
+ // logDebug(s);
+
+ // Apply force to all nodes in graph
+ for (var j = 0; j < numNodes; j++) {
+ var node = layoutInfo.layoutNodes[layoutInfo.idToIndex[graph[j]]];
+ // s = "Node: " + node.id;
+
+ if( node.isLocked ){ continue; }
+
+ var dx = centerX - node.positionX;
+ var dy = centerY - node.positionY;
+ var d = Math.sqrt(dx * dx + dy * dy);
+ if (d > distThreshold) {
+ var fx = options.gravity * dx / d;
+ var fy = options.gravity * dy / d;
+ node.offsetX += fx;
+ node.offsetY += fy;
+ // s += ": Applied force: " + fx + ", " + fy;
+ } else {
+ // s += ": skypped since it's too close to center";
+ }
+ // logDebug(s);
+ }
+ }
+ };
+
+ /**
+ * @brief : This function propagates the existing offsets from
+ * parent nodes to its descendents.
+ * @arg layoutInfo : layoutInfo Object
+ * @arg cy : cytoscape Object
+ * @arg options : Layout options
+ */
+ var propagateForces = function(layoutInfo, options) {
+ // Inline implementation of a queue, used for traversing the graph in BFS order
+ var queue = [];
+ var start = 0; // Points to the start the queue
+ var end = -1; // Points to the end of the queue
+
+ // logDebug('propagateForces');
+
+ // Start by visiting the nodes in the root graph
+ queue.push.apply(queue, layoutInfo.graphSet[0]);
+ end += layoutInfo.graphSet[0].length;
+
+ // Traverse the graph, level by level,
+ while (start <= end) {
+ // Get the node to visit and remove it from queue
+ var nodeId = queue[start++];
+ var nodeIndex = layoutInfo.idToIndex[nodeId];
+ var node = layoutInfo.layoutNodes[nodeIndex];
+ var children = node.children;
+
+ // We only need to process the node if it's compound
+ if (0 < children.length && !node.isLocked) {
+ var offX = node.offsetX;
+ var offY = node.offsetY;
+
+ // var s = "Propagating offset from parent node : " + node.id +
+ // ". OffsetX: " + offX + ". OffsetY: " + offY;
+ // s += "\n Children: " + children.toString();
+ // logDebug(s);
+
+ for (var i = 0; i < children.length; i++) {
+ var childNode = layoutInfo.layoutNodes[layoutInfo.idToIndex[children[i]]];
+ // Propagate offset
+ childNode.offsetX += offX;
+ childNode.offsetY += offY;
+ // Add children to queue to be visited
+ queue[++end] = children[i];
+ }
+
+ // Reset parent offsets
+ node.offsetX = 0;
+ node.offsetY = 0;
+ }
+
+ }
+ };
+
+ /**
+ * @brief : Updates the layout model positions, based on
+ * the accumulated forces
+ */
+ var updatePositions = function(layoutInfo, options) {
+ // var s = 'Updating positions';
+ // logDebug(s);
+
+ // Reset boundaries for compound nodes
+ for (var i = 0; i < layoutInfo.nodeSize; i++) {
+ var n = layoutInfo.layoutNodes[i];
+ if (0 < n.children.length) {
+ // logDebug("Resetting boundaries of compound node: " + n.id);
+ n.maxX = undefined;
+ n.minX = undefined;
+ n.maxY = undefined;
+ n.minY = undefined;
+ }
+ }
+
+ for (var i = 0; i < layoutInfo.nodeSize; i++) {
+ var n = layoutInfo.layoutNodes[i];
+ if (0 < n.children.length || n.isLocked) {
+ // No need to set compound or locked node position
+ // logDebug("Skipping position update of node: " + n.id);
+ continue;
+ }
+ // s = "Node: " + n.id + " Previous position: (" +
+ // n.positionX + ", " + n.positionY + ").";
+
+ // Limit displacement in order to improve stability
+ var tempForce = limitForce(n.offsetX, n.offsetY, layoutInfo.temperature);
+ n.positionX += tempForce.x;
+ n.positionY += tempForce.y;
+ n.offsetX = 0;
+ n.offsetY = 0;
+ n.minX = n.positionX - n.width;
+ n.maxX = n.positionX + n.width;
+ n.minY = n.positionY - n.height;
+ n.maxY = n.positionY + n.height;
+ // s += " New Position: (" + n.positionX + ", " + n.positionY + ").";
+ // logDebug(s);
+
+ // Update ancestry boudaries
+ updateAncestryBoundaries(n, layoutInfo);
+ }
+
+ // Update size, position of compund nodes
+ for (var i = 0; i < layoutInfo.nodeSize; i++) {
+ var n = layoutInfo.layoutNodes[i];
+ if ( 0 < n.children.length && !n.isLocked ) {
+ n.positionX = (n.maxX + n.minX) / 2;
+ n.positionY = (n.maxY + n.minY) / 2;
+ n.width = n.maxX - n.minX;
+ n.height = n.maxY - n.minY;
+ // s = "Updating position, size of compound node " + n.id;
+ // s += "\nPositionX: " + n.positionX + ", PositionY: " + n.positionY;
+ // s += "\nWidth: " + n.width + ", Height: " + n.height;
+ // logDebug(s);
+ }
+ }
+ };
+
+ /**
+ * @brief : Limits a force (forceX, forceY) to be not
+ * greater (in modulo) than max.
+ 8 Preserves force direction.
+ */
+ var limitForce = function(forceX, forceY, max) {
+ // var s = "Limiting force: (" + forceX + ", " + forceY + "). Max: " + max;
+ var force = Math.sqrt(forceX * forceX + forceY * forceY);
+
+ if (force > max) {
+ var res = {
+ x : max * forceX / force,
+ y : max * forceY / force
+ };
+
+ } else {
+ var res = {
+ x : forceX,
+ y : forceY
+ };
+ }
+
+ // s += ".\nResult: (" + res.x + ", " + res.y + ")";
+ // logDebug(s);
+
+ return res;
+ };
+
+ /**
+ * @brief : Function used for keeping track of compound node
+ * sizes, since they should bound all their subnodes.
+ */
+ var updateAncestryBoundaries = function(node, layoutInfo) {
+ // var s = "Propagating new position/size of node " + node.id;
+ var parentId = node.parentId;
+ if (null == parentId) {
+ // If there's no parent, we are done
+ // s += ". No parent node.";
+ // logDebug(s);
+ return;
+ }
+
+ // Get Parent Node
+ var p = layoutInfo.layoutNodes[layoutInfo.idToIndex[parentId]];
+ var flag = false;
+
+ // MaxX
+ if (null == p.maxX || node.maxX + p.padRight > p.maxX) {
+ p.maxX = node.maxX + p.padRight;
+ flag = true;
+ // s += "\nNew maxX for parent node " + p.id + ": " + p.maxX;
+ }
+
+ // MinX
+ if (null == p.minX || node.minX - p.padLeft < p.minX) {
+ p.minX = node.minX - p.padLeft;
+ flag = true;
+ // s += "\nNew minX for parent node " + p.id + ": " + p.minX;
+ }
+
+ // MaxY
+ if (null == p.maxY || node.maxY + p.padBottom > p.maxY) {
+ p.maxY = node.maxY + p.padBottom;
+ flag = true;
+ // s += "\nNew maxY for parent node " + p.id + ": " + p.maxY;
+ }
+
+ // MinY
+ if (null == p.minY || node.minY - p.padTop < p.minY) {
+ p.minY = node.minY - p.padTop;
+ flag = true;
+ // s += "\nNew minY for parent node " + p.id + ": " + p.minY;
+ }
+
+ // If updated boundaries, propagate changes upward
+ if (flag) {
+ // logDebug(s);
+ return updateAncestryBoundaries(p, layoutInfo);
+ }
+
+ // s += ". No changes in boundaries/position of parent node " + p.id;
+ // logDebug(s);
+ return;
+ };
+
+ var separateComponents = function(layutInfo, options){
+ var nodes = layoutInfo.layoutNodes;
+ var components = [];
+
+ for( var i = 0; i < nodes.length; i++ ){
+ var node = nodes[i];
+ var cid = node.cmptId;
+ var component = components[ cid ] = components[ cid ] || [];
+
+ component.push( node );
+ }
+
+ var totalA = 0;
+
+ for( var i = 0; i < components.length; i++ ){
+ var c = components[i];
+ c.x1 = Infinity;
+ c.x2 = -Infinity;
+ c.y1 = Infinity;
+ c.y2 = -Infinity;
+
+ for( var j = 0; j < c.length; j++ ){
+ var n = c[j];
+
+ c.x1 = Math.min( c.x1, n.positionX - n.width/2 );
+ c.x2 = Math.max( c.x2, n.positionX + n.width/2 );
+ c.y1 = Math.min( c.y1, n.positionY - n.height/2 );
+ c.y2 = Math.max( c.y2, n.positionY + n.height/2 );
+ }
+
+ c.w = c.x2 - c.x1;
+ c.h = c.y2 - c.y1;
+
+ totalA += c.w * c.h;
+ }
+
+ components.sort(function( c1, c2 ){
+ return c2.w*c2.h - c1.w*c1.h;
+ });
+
+ var x = 0;
+ var y = 0;
+ var usedW = 0;
+ var rowH = 0;
+ var maxRowW = Math.sqrt( totalA ) * layoutInfo.clientWidth / layoutInfo.clientHeight;
+
+ for( var i = 0; i < components.length; i++ ){
+ var c = components[i];
+
+ for( var j = 0; j < c.length; j++ ){
+ var n = c[j];
+
+ if( !n.isLocked ){
+ n.positionX += x;
+ n.positionY += y;
+ }
+ }
+
+ x += c.w + options.componentSpacing;
+ usedW += c.w + options.componentSpacing;
+ rowH = Math.max( rowH, c.h );
+
+ if( usedW > maxRowW ){
+ y += rowH + options.componentSpacing;
+ x = 0;
+ usedW = 0;
+ rowH = 0;
+ }
+ }
+ };
+
+ var mainLoop = function(i){
+ if( stopped ){
+ // logDebug("Layout manually stopped. Stopping computation in step " + i);
+ return false;
+ }
+
+ // Do one step in the phisical simulation
+ step(layoutInfo, options, i);
+
+ // Update temperature
+ layoutInfo.temperature = layoutInfo.temperature * options.coolingFactor;
+ // logDebug("New temperature: " + layoutInfo.temperature);
+
+ if (layoutInfo.temperature < options.minTemp) {
+ // logDebug("Temperature drop below minimum threshold. Stopping computation in step " + i);
+ return false;
+ }
+
+ return true;
+ };
+
+ var i = 0;
+ var loopRet;
+
+ do {
+ var f = 0;
+
+ while( f < options.refresh && i < options.numIter ){
+ var loopRet = mainLoop(i);
+ if( !loopRet ){ break; }
+
+ f++;
+ i++;
+ }
+
+ if( options.animate ){
+ broadcast( layoutInfo.layoutNodes ); // jshint ignore:line
+ }
+
+ } while ( loopRet && i + 1 < options.numIter );
+
+ separateComponents( layoutInfo, options );
+
+ return layoutInfo;
+ }).then(function( layoutInfoUpdated ){
+ layoutInfo.layoutNodes = layoutInfoUpdated.layoutNodes; // get the positions
+
+ thread.stop();
+ done();
+ });
+
+ var done = function(){
+ refresh({ force: true });
+
+ // Layout has finished
+ layout.one('layoutstop', options.stop);
+ layout.trigger({ type: 'layoutstop', layout: layout });
+ };
+
+ return this; // chaining
+};
+
+
+/**
+ * @brief : called on continuous layouts to stop them before they finish
+ */
+CoseLayout.prototype.stop = function(){
+ this.stopped = true;
+
+ if( this.thread ){
+ this.thread.stop();
+ }
+
+ this.trigger('layoutstop');
+
+ return this; // chaining
+};
+
+CoseLayout.prototype.destroy = function(){
+ if( this.thread ){
+ this.thread.stop();
+ }
+
+ return this; // chaining
+};
+
+
+/**
+ * @brief : Creates an object which is contains all the data
+ * used in the layout process
+ * @arg cy : cytoscape.js object
+ * @return : layoutInfo object initialized
+ */
+var createLayoutInfo = function(cy, layout, options) {
+ // Shortcut
+ var edges = options.eles.edges();
+ var nodes = options.eles.nodes();
+
+ var layoutInfo = {
+ isCompound : cy.hasCompoundNodes(),
+ layoutNodes : [],
+ idToIndex : {},
+ nodeSize : nodes.size(),
+ graphSet : [],
+ indexToGraph : [],
+ layoutEdges : [],
+ edgeSize : edges.size(),
+ temperature : options.initialTemp,
+ clientWidth : cy.width(),
+ clientHeight : cy.width(),
+ boundingBox : math.makeBoundingBox( options.boundingBox ? options.boundingBox : {
+ x1: 0, y1: 0, w: cy.width(), h: cy.height()
+ } )
+ };
+
+ var components = options.eles.components();
+ var id2cmptId = {};
+
+ for( var i = 0; i < components.length; i++ ){
+ var component = components[i];
+
+ for( var j = 0; j < component.length; j++ ){
+ var node = component[j];
+
+ id2cmptId[ node.id() ] = i;
+ }
+ }
+
+ // Iterate over all nodes, creating layout nodes
+ for (var i = 0; i < layoutInfo.nodeSize; i++) {
+ var n = nodes[i];
+ var nbb = n.boundingBox();
+
+ var tempNode = {};
+ tempNode.isLocked = n.locked();
+ tempNode.id = n.data('id');
+ tempNode.parentId = n.data('parent');
+ tempNode.cmptId = id2cmptId[ n.id() ];
+ tempNode.children = [];
+ tempNode.positionX = n.position('x');
+ tempNode.positionY = n.position('y');
+ tempNode.offsetX = 0;
+ tempNode.offsetY = 0;
+ tempNode.height = nbb.w;
+ tempNode.width = nbb.h;
+ tempNode.maxX = tempNode.positionX + tempNode.width / 2;
+ tempNode.minX = tempNode.positionX - tempNode.width / 2;
+ tempNode.maxY = tempNode.positionY + tempNode.height / 2;
+ tempNode.minY = tempNode.positionY - tempNode.height / 2;
+ tempNode.padLeft = parseFloat( n.style('padding-left') );
+ tempNode.padRight = parseFloat( n.style('padding-right') );
+ tempNode.padTop = parseFloat( n.style('padding-top') );
+ tempNode.padBottom = parseFloat( n.style('padding-bottom') );
+
+ // forces
+ tempNode.nodeRepulsion = is.fn( options.nodeRepulsion ) ? options.nodeRepulsion.call( n, n ) : options.nodeRepulsion;
+
+ // Add new node
+ layoutInfo.layoutNodes.push(tempNode);
+ // Add entry to id-index map
+ layoutInfo.idToIndex[tempNode.id] = i;
+ }
+
+ // Inline implementation of a queue, used for traversing the graph in BFS order
+ var queue = [];
+ var start = 0; // Points to the start the queue
+ var end = -1; // Points to the end of the queue
+
+ var tempGraph = [];
+
+ // Second pass to add child information and
+ // initialize queue for hierarchical traversal
+ for (var i = 0; i < layoutInfo.nodeSize; i++) {
+ var n = layoutInfo.layoutNodes[i];
+ var p_id = n.parentId;
+ // Check if node n has a parent node
+ if (null != p_id) {
+ // Add node Id to parent's list of children
+ layoutInfo.layoutNodes[layoutInfo.idToIndex[p_id]].children.push(n.id);
+ } else {
+ // If a node doesn't have a parent, then it's in the root graph
+ queue[++end] = n.id;
+ tempGraph.push(n.id);
+ }
+ }
+
+ // Add root graph to graphSet
+ layoutInfo.graphSet.push(tempGraph);
+
+ // Traverse the graph, level by level,
+ while (start <= end) {
+ // Get the node to visit and remove it from queue
+ var node_id = queue[start++];
+ var node_ix = layoutInfo.idToIndex[node_id];
+ var node = layoutInfo.layoutNodes[node_ix];
+ var children = node.children;
+ if (children.length > 0) {
+ // Add children nodes as a new graph to graph set
+ layoutInfo.graphSet.push(children);
+ // Add children to que queue to be visited
+ for (var i = 0; i < children.length; i++) {
+ queue[++end] = children[i];
+ }
+ }
+ }
+
+ // Create indexToGraph map
+ for (var i = 0; i < layoutInfo.graphSet.length; i++) {
+ var graph = layoutInfo.graphSet[i];
+ for (var j = 0; j < graph.length; j++) {
+ var index = layoutInfo.idToIndex[graph[j]];
+ layoutInfo.indexToGraph[index] = i;
+ }
+ }
+
+ // Iterate over all edges, creating Layout Edges
+ for (var i = 0; i < layoutInfo.edgeSize; i++) {
+ var e = edges[i];
+ var tempEdge = {};
+ tempEdge.id = e.data('id');
+ tempEdge.sourceId = e.data('source');
+ tempEdge.targetId = e.data('target');
+
+ // Compute ideal length
+ var idealLength = is.fn( options.idealEdgeLength ) ? options.idealEdgeLength.call( e, e ) : options.idealEdgeLength;
+ var elasticity = is.fn( options.edgeElasticity ) ? options.edgeElasticity.call( e, e ) : options.edgeElasticity;
+
+ // Check if it's an inter graph edge
+ var sourceIx = layoutInfo.idToIndex[tempEdge.sourceId];
+ var targetIx = layoutInfo.idToIndex[tempEdge.targetId];
+ var sourceGraph = layoutInfo.indexToGraph[sourceIx];
+ var targetGraph = layoutInfo.indexToGraph[targetIx];
+
+ if (sourceGraph != targetGraph) {
+ // Find lowest common graph ancestor
+ var lca = findLCA(tempEdge.sourceId, tempEdge.targetId, layoutInfo);
+
+ // Compute sum of node depths, relative to lca graph
+ var lcaGraph = layoutInfo.graphSet[lca];
+ var depth = 0;
+
+ // Source depth
+ var tempNode = layoutInfo.layoutNodes[sourceIx];
+ while ( -1 === lcaGraph.indexOf(tempNode.id) ) {
+ tempNode = layoutInfo.layoutNodes[layoutInfo.idToIndex[tempNode.parentId]];
+ depth++;
+ }
+
+ // Target depth
+ tempNode = layoutInfo.layoutNodes[targetIx];
+ while ( -1 === lcaGraph.indexOf(tempNode.id) ) {
+ tempNode = layoutInfo.layoutNodes[layoutInfo.idToIndex[tempNode.parentId]];
+ depth++;
+ }
+
+ // logDebug('LCA of nodes ' + tempEdge.sourceId + ' and ' + tempEdge.targetId +
+ // ". Index: " + lca + " Contents: " + lcaGraph.toString() +
+ // ". Depth: " + depth);
+
+ // Update idealLength
+ idealLength *= depth * options.nestingFactor;
+ }
+
+ tempEdge.idealLength = idealLength;
+ tempEdge.elasticity = elasticity;
+
+ layoutInfo.layoutEdges.push(tempEdge);
+ }
+
+ // Finally, return layoutInfo object
+ return layoutInfo;
+};
+
+
+/**
+ * @brief : This function finds the index of the lowest common
+ * graph ancestor between 2 nodes in the subtree
+ * (from the graph hierarchy induced tree) whose
+ * root is graphIx
+ *
+ * @arg node1: node1's ID
+ * @arg node2: node2's ID
+ * @arg layoutInfo: layoutInfo object
+ *
+ */
+var findLCA = function(node1, node2, layoutInfo) {
+ // Find their common ancester, starting from the root graph
+ var res = findLCA_aux(node1, node2, 0, layoutInfo);
+ if (2 > res.count) {
+ // If aux function couldn't find the common ancester,
+ // then it is the root graph
+ return 0;
+ } else {
+ return res.graph;
+ }
+};
+
+
+/**
+ * @brief : Auxiliary function used for LCA computation
+ *
+ * @arg node1 : node1's ID
+ * @arg node2 : node2's ID
+ * @arg graphIx : subgraph index
+ * @arg layoutInfo : layoutInfo object
+ *
+ * @return : object of the form {count: X, graph: Y}, where:
+ * X is the number of ancesters (max: 2) found in
+ * graphIx (and it's subgraphs),
+ * Y is the graph index of the lowest graph containing
+ * all X nodes
+ */
+var findLCA_aux = function(node1, node2, graphIx, layoutInfo) {
+ var graph = layoutInfo.graphSet[graphIx];
+ // If both nodes belongs to graphIx
+ if (-1 < graph.indexOf(node1) && -1 < graph.indexOf(node2)) {
+ return {count:2, graph:graphIx};
+ }
+
+ // Make recursive calls for all subgraphs
+ var c = 0;
+ for (var i = 0; i < graph.length; i++) {
+ var nodeId = graph[i];
+ var nodeIx = layoutInfo.idToIndex[nodeId];
+ var children = layoutInfo.layoutNodes[nodeIx].children;
+
+ // If the node has no child, skip it
+ if (0 === children.length) {
+ continue;
+ }
+
+ var childGraphIx = layoutInfo.indexToGraph[layoutInfo.idToIndex[children[0]]];
+ var result = findLCA_aux(node1, node2, childGraphIx, layoutInfo);
+ if (0 === result.count) {
+ // Neither node1 nor node2 are present in this subgraph
+ continue;
+ } else if (1 === result.count) {
+ // One of (node1, node2) is present in this subgraph
+ c++;
+ if (2 === c) {
+ // We've already found both nodes, no need to keep searching
+ break;
+ }
+ } else {
+ // Both nodes are present in this subgraph
+ return result;
+ }
+ }
+
+ return {count:c, graph:graphIx};
+};
+
+
+/**
+ * @brief: printsLayoutInfo into js console
+ * Only used for debbuging
+ */
+var printLayoutInfo = function(layoutInfo) {
+ /* jshint ignore:start */
+
+ if (!DEBUG) {
+ return;
+ }
+ console.debug("layoutNodes:");
+ for (var i = 0; i < layoutInfo.nodeSize; i++) {
+ var n = layoutInfo.layoutNodes[i];
+ var s =
+ "\nindex: " + i +
+ "\nId: " + n.id +
+ "\nChildren: " + n.children.toString() +
+ "\nparentId: " + n.parentId +
+ "\npositionX: " + n.positionX +
+ "\npositionY: " + n.positionY +
+ "\nOffsetX: " + n.offsetX +
+ "\nOffsetY: " + n.offsetY +
+ "\npadLeft: " + n.padLeft +
+ "\npadRight: " + n.padRight +
+ "\npadTop: " + n.padTop +
+ "\npadBottom: " + n.padBottom;
+
+ console.debug(s);
+ }
+
+ console.debug('idToIndex');
+ for (var i in layoutInfo.idToIndex) {
+ console.debug("Id: " + i + "\nIndex: " + layoutInfo.idToIndex[i]);
+ }
+
+ console.debug('Graph Set');
+ var set = layoutInfo.graphSet;
+ for (var i = 0; i < set.length; i ++) {
+ console.debug("Set : " + i + ": " + set[i].toString());
+ }
+
+ var s = 'IndexToGraph';
+ for (var i = 0; i < layoutInfo.indexToGraph.length; i ++) {
+ s += "\nIndex : " + i + " Graph: "+ layoutInfo.indexToGraph[i];
+ }
+ console.debug(s);
+
+ s = 'Layout Edges';
+ for (var i = 0; i < layoutInfo.layoutEdges.length; i++) {
+ var e = layoutInfo.layoutEdges[i];
+ s += "\nEdge Index: " + i + " ID: " + e.id +
+ " SouceID: " + e.sourceId + " TargetId: " + e.targetId +
+ " Ideal Length: " + e.idealLength;
+ }
+ console.debug(s);
+
+ s = "nodeSize: " + layoutInfo.nodeSize;
+ s += "\nedgeSize: " + layoutInfo.edgeSize;
+ s += "\ntemperature: " + layoutInfo.temperature;
+ console.debug(s);
+
+ return;
+ /* jshint ignore:end */
+};
+
+
+/**
+ * @brief : Randomizes the position of all nodes
+ */
+var randomizePositions = function(layoutInfo, cy) {
+ var width = layoutInfo.clientWidth;
+ var height = layoutInfo.clientHeight;
+
+ for (var i = 0; i < layoutInfo.nodeSize; i++) {
+ var n = layoutInfo.layoutNodes[i];
+
+ // No need to randomize compound nodes or locked nodes
+ if ( 0 === n.children.length && !n.isLocked ) {
+ n.positionX = Math.random() * width;
+ n.positionY = Math.random() * height;
+ }
+ }
+};
+
+
+/**
+ * @brief : Updates the positions of nodes in the network
+ * @arg layoutInfo : LayoutInfo object
+ * @arg cy : Cytoscape object
+ * @arg options : Layout options
+ */
+var refreshPositions = function(layoutInfo, cy, options) {
+ // var s = 'Refreshing positions';
+ // logDebug(s);
+
+ var layout = options.layout;
+ var nodes = options.eles.nodes();
+ var bb = layoutInfo.boundingBox;
+ var coseBB = { x1: Infinity, x2: -Infinity, y1: Infinity, y2: -Infinity };
+
+ if( options.boundingBox ){
+ nodes.forEach(function( node ){
+ var lnode = layoutInfo.layoutNodes[layoutInfo.idToIndex[node.data('id')]];
+
+ coseBB.x1 = Math.min( coseBB.x1, lnode.positionX );
+ coseBB.x2 = Math.max( coseBB.x2, lnode.positionX );
+
+ coseBB.y1 = Math.min( coseBB.y1, lnode.positionY );
+ coseBB.y2 = Math.max( coseBB.y2, lnode.positionY );
+ });
+
+ coseBB.w = coseBB.x2 - coseBB.x1;
+ coseBB.h = coseBB.y2 - coseBB.y1;
+ }
+
+ nodes.positions(function(i, ele) {
+ var lnode = layoutInfo.layoutNodes[layoutInfo.idToIndex[ele.data('id')]];
+ // s = "Node: " + lnode.id + ". Refreshed position: (" +
+ // lnode.positionX + ", " + lnode.positionY + ").";
+ // logDebug(s);
+
+ if( options.boundingBox ){ // then add extra bounding box constraint
+ var pctX = (lnode.positionX - coseBB.x1) / coseBB.w;
+ var pctY = (lnode.positionY - coseBB.y1) / coseBB.h;
+
+ return {
+ x: bb.x1 + pctX * bb.w,
+ y: bb.y1 + pctY * bb.h
+ };
+ } else {
+ return {
+ x: lnode.positionX,
+ y: lnode.positionY
+ };
+ }
+ });
+
+ // Trigger layoutReady only on first call
+ if (true !== layoutInfo.ready) {
+ // s = 'Triggering layoutready';
+ // logDebug(s);
+ layoutInfo.ready = true;
+ layout.one('layoutready', options.ready);
+ layout.trigger({ type: 'layoutready', layout: this });
+ }
+};
+
+/**
+ * @brief : Logs a debug message in JS console, if DEBUG is ON
+ */
+// var logDebug = function(text) {
+// if (DEBUG) {
+// console.debug(text);
+// }
+// };
+
+module.exports = CoseLayout;
+
+},{"../../is":77,"../../math":79,"../../thread":92,"../../util":94}],49:[function(_dereq_,module,exports){
+'use strict';
+
+var util = _dereq_('../../util');
+var math = _dereq_('../../math');
+
+var defaults = {
+ fit: true, // whether to fit the viewport to the graph
+ padding: 30, // padding used on fit
+ boundingBox: undefined, // constrain layout bounds; { x1, y1, x2, y2 } or { x1, y1, w, h }
+ avoidOverlap: true, // prevents node overlap, may overflow boundingBox if not enough space
+ avoidOverlapPadding: 10, // extra spacing around nodes when avoidOverlap: true
+ condense: false, // uses all available space on false, uses minimal space on true
+ rows: undefined, // force num of rows in the grid
+ cols: undefined, // force num of columns in the grid
+ position: function( node ){}, // returns { row, col } for element
+ sort: undefined, // a sorting function to order the nodes; e.g. function(a, b){ return a.data('weight') - b.data('weight') }
+ animate: false, // whether to transition the node positions
+ animationDuration: 500, // duration of animation in ms if enabled
+ animationEasing: undefined, // easing of animation if enabled
+ ready: undefined, // callback on layoutready
+ stop: undefined // callback on layoutstop
+};
+
+function GridLayout( options ){
+ this.options = util.extend({}, defaults, options);
+}
+
+GridLayout.prototype.run = function(){
+ var params = this.options;
+ var options = params;
+
+ var cy = params.cy;
+ var eles = options.eles;
+ var nodes = eles.nodes().not(':parent');
+
+ if( options.sort ){
+ nodes = nodes.sort( options.sort );
+ }
+
+ var bb = math.makeBoundingBox( options.boundingBox ? options.boundingBox : {
+ x1: 0, y1: 0, w: cy.width(), h: cy.height()
+ } );
+
+ if( bb.h === 0 || bb.w === 0){
+ nodes.layoutPositions(this, options, function(){
+ return { x: bb.x1, y: bb.y1 };
+ });
+
+ } else {
+
+ // width/height * splits^2 = cells where splits is number of times to split width
+ var cells = nodes.size();
+ var splits = Math.sqrt( cells * bb.h/bb.w );
+ var rows = Math.round( splits );
+ var cols = Math.round( bb.w/bb.h * splits );
+
+ var small = function(val){
+ if( val == null ){
+ return Math.min(rows, cols);
+ } else {
+ var min = Math.min(rows, cols);
+ if( min == rows ){
+ rows = val;
+ } else {
+ cols = val;
+ }
+ }
+ };
+
+ var large = function(val){
+ if( val == null ){
+ return Math.max(rows, cols);
+ } else {
+ var max = Math.max(rows, cols);
+ if( max == rows ){
+ rows = val;
+ } else {
+ cols = val;
+ }
+ }
+ };
+
+ var oRows = options.rows;
+ var oCols = options.cols != null ? options.cols : options.columns;
+
+ // if rows or columns were set in options, use those values
+ if( oRows != null && oCols != null ){
+ rows = oRows;
+ cols = oCols;
+ } else if( oRows != null && oCols == null ){
+ rows = oRows;
+ cols = Math.ceil( cells / rows );
+ } else if( oRows == null && oCols != null ){
+ cols = oCols;
+ rows = Math.ceil( cells / cols );
+ }
+
+ // otherwise use the automatic values and adjust accordingly
+
+ // if rounding was up, see if we can reduce rows or columns
+ else if( cols * rows > cells ){
+ var sm = small();
+ var lg = large();
+
+ // reducing the small side takes away the most cells, so try it first
+ if( (sm - 1) * lg >= cells ){
+ small(sm - 1);
+ } else if( (lg - 1) * sm >= cells ){
+ large(lg - 1);
+ }
+ } else {
+
+ // if rounding was too low, add rows or columns
+ while( cols * rows < cells ){
+ var sm = small();
+ var lg = large();
+
+ // try to add to larger side first (adds less in multiplication)
+ if( (lg + 1) * sm >= cells ){
+ large(lg + 1);
+ } else {
+ small(sm + 1);
+ }
+ }
+ }
+
+ var cellWidth = bb.w / cols;
+ var cellHeight = bb.h / rows;
+
+ if( options.condense ){
+ cellWidth = 0;
+ cellHeight = 0;
+ }
+
+ if( options.avoidOverlap ){
+ for( var i = 0; i < nodes.length; i++ ){
+ var node = nodes[i];
+ var pos = node._private.position;
+
+ if( pos.x == null || pos.y == null ){ // for bb
+ pos.x = 0;
+ pos.y = 0;
+ }
+
+ var nbb = node.boundingBox();
+ var p = options.avoidOverlapPadding;
+
+ var w = nbb.w + p;
+ var h = nbb.h + p;
+
+ cellWidth = Math.max( cellWidth, w );
+ cellHeight = Math.max( cellHeight, h );
+ }
+ }
+
+ var cellUsed = {}; // e.g. 'c-0-2' => true
+
+ var used = function(row, col){
+ return cellUsed['c-' + row + '-' + col] ? true : false;
+ };
+
+ var use = function(row, col){
+ cellUsed['c-' + row + '-' + col] = true;
+ };
+
+ // to keep track of current cell position
+ var row = 0;
+ var col = 0;
+ var moveToNextCell = function(){
+ col++;
+ if( col >= cols ){
+ col = 0;
+ row++;
+ }
+ };
+
+ // get a cache of all the manual positions
+ var id2manPos = {};
+ for( var i = 0; i < nodes.length; i++ ){
+ var node = nodes[i];
+ var rcPos = options.position( node );
+
+ if( rcPos && (rcPos.row !== undefined || rcPos.col !== undefined) ){ // must have at least row or col def'd
+ var pos = {
+ row: rcPos.row,
+ col: rcPos.col
+ };
+
+ if( pos.col === undefined ){ // find unused col
+ pos.col = 0;
+
+ while( used(pos.row, pos.col) ){
+ pos.col++;
+ }
+ } else if( pos.row === undefined ){ // find unused row
+ pos.row = 0;
+
+ while( used(pos.row, pos.col) ){
+ pos.row++;
+ }
+ }
+
+ id2manPos[ node.id() ] = pos;
+ use( pos.row, pos.col );
+ }
+ }
+
+ var getPos = function(i, element){
+ var x, y;
+
+ if( element.locked() || element.isFullAutoParent() ){
+ return false;
+ }
+
+ // see if we have a manual position set
+ var rcPos = id2manPos[ element.id() ];
+ if( rcPos ){
+ x = rcPos.col * cellWidth + cellWidth/2 + bb.x1;
+ y = rcPos.row * cellHeight + cellHeight/2 + bb.y1;
+
+ } else { // otherwise set automatically
+
+ while( used(row, col) ){
+ moveToNextCell();
+ }
+
+ x = col * cellWidth + cellWidth/2 + bb.x1;
+ y = row * cellHeight + cellHeight/2 + bb.y1;
+ use( row, col );
+
+ moveToNextCell();
+ }
+
+ return { x: x, y: y };
+
+ };
+
+ nodes.layoutPositions( this, options, getPos );
+ }
+
+ return this; // chaining
+
+};
+
+module.exports = GridLayout;
+
+},{"../../math":79,"../../util":94}],50:[function(_dereq_,module,exports){
+'use strict';
+
+module.exports = [
+ { name: 'breadthfirst', impl: _dereq_('./breadthfirst') },
+ { name: 'circle', impl: _dereq_('./circle') },
+ { name: 'concentric',impl: _dereq_('./concentric') },
+ { name: 'cose', impl: _dereq_('./cose') },
+ { name: 'grid', impl: _dereq_('./grid') },
+ { name: 'null', impl: _dereq_('./null') },
+ { name: 'preset', impl: _dereq_('./preset') },
+ { name: 'random', impl: _dereq_('./random') }
+];
+
+},{"./breadthfirst":45,"./circle":46,"./concentric":47,"./cose":48,"./grid":49,"./null":51,"./preset":52,"./random":53}],51:[function(_dereq_,module,exports){
+'use strict';
+
+var util = _dereq_('../../util');
+
+// default layout options
+var defaults = {
+ ready: function(){}, // on layoutready
+ stop: function(){} // on layoutstop
+};
+
+// constructor
+// options : object containing layout options
+function NullLayout( options ){
+ this.options = util.extend({}, defaults, options);
+}
+
+// runs the layout
+NullLayout.prototype.run = function(){
+ var options = this.options;
+ var eles = options.eles; // elements to consider in the layout
+ var layout = this;
+
+ // cy is automatically populated for us in the constructor
+ var cy = options.cy; // jshint ignore:line
+
+ layout.trigger('layoutstart');
+
+ // puts all nodes at (0, 0)
+ eles.nodes().positions(function(){
+ return {
+ x: 0,
+ y: 0
+ };
+ });
+
+ // trigger layoutready when each node has had its position set at least once
+ layout.one('layoutready', options.ready);
+ layout.trigger('layoutready');
+
+ // trigger layoutstop when the layout stops (e.g. finishes)
+ layout.one('layoutstop', options.stop);
+ layout.trigger('layoutstop');
+
+ return this; // chaining
+};
+
+// called on continuous layouts to stop them before they finish
+NullLayout.prototype.stop = function(){
+ return this; // chaining
+};
+
+module.exports = NullLayout;
+
+},{"../../util":94}],52:[function(_dereq_,module,exports){
+'use strict';
+
+var util = _dereq_('../../util');
+var is = _dereq_('../../is');
+
+var defaults = {
+ positions: undefined, // map of (node id) => (position obj); or function(node){ return somPos; }
+ zoom: undefined, // the zoom level to set (prob want fit = false if set)
+ pan: undefined, // the pan level to set (prob want fit = false if set)
+ fit: true, // whether to fit to viewport
+ padding: 30, // padding on fit
+ animate: false, // whether to transition the node positions
+ animationDuration: 500, // duration of animation in ms if enabled
+ animationEasing: undefined, // easing of animation if enabled
+ ready: undefined, // callback on layoutready
+ stop: undefined // callback on layoutstop
+};
+
+function PresetLayout( options ){
+ this.options = util.extend({}, defaults, options);
+}
+
+PresetLayout.prototype.run = function(){
+ var options = this.options;
+ var eles = options.eles;
+
+ var nodes = eles.nodes();
+ var posIsFn = is.fn( options.positions );
+
+ function getPosition(node){
+ if( options.positions == null ){
+ return null;
+ }
+
+ if( posIsFn ){
+ return options.positions.apply( node, [ node ] );
+ }
+
+ var pos = options.positions[node._private.data.id];
+
+ if( pos == null ){
+ return null;
+ }
+
+ return pos;
+ }
+
+ nodes.layoutPositions(this, options, function(i, node){
+ var position = getPosition(node);
+
+ if( node.locked() || position == null ){
+ return false;
+ }
+
+ return position;
+ });
+
+ return this; // chaining
+};
+
+module.exports = PresetLayout;
+
+},{"../../is":77,"../../util":94}],53:[function(_dereq_,module,exports){
+'use strict';
+
+var util = _dereq_('../../util');
+var math = _dereq_('../../math');
+
+var defaults = {
+ fit: true, // whether to fit to viewport
+ padding: 30, // fit padding
+ boundingBox: undefined, // constrain layout bounds; { x1, y1, x2, y2 } or { x1, y1, w, h }
+ animate: false, // whether to transition the node positions
+ animationDuration: 500, // duration of animation in ms if enabled
+ animationEasing: undefined, // easing of animation if enabled
+ ready: undefined, // callback on layoutready
+ stop: undefined // callback on layoutstop
+};
+
+function RandomLayout( options ){
+ this.options = util.extend({}, defaults, options);
+}
+
+RandomLayout.prototype.run = function(){
+ var options = this.options;
+ var cy = options.cy;
+ var eles = options.eles;
+ var nodes = eles.nodes().not(':parent');
+
+ var bb = math.makeBoundingBox( options.boundingBox ? options.boundingBox : {
+ x1: 0, y1: 0, w: cy.width(), h: cy.height()
+ } );
+
+ var getPos = function( i, node ){
+ return {
+ x: bb.x1 + Math.round( Math.random() * bb.w ),
+ y: bb.y1 + Math.round( Math.random() * bb.h )
+ };
+ };
+
+ nodes.layoutPositions( this, options, getPos );
+
+ return this; // chaining
+};
+
+module.exports = RandomLayout;
+
+},{"../../math":79,"../../util":94}],54:[function(_dereq_,module,exports){
+'use strict';
+
+var math = _dereq_('../../../math');
+var is = _dereq_('../../../is');
+var util = _dereq_('../../../util');
+
+var BRp = {};
+
+BRp.arrowShapeHeight = 0.3;
+
+BRp.registerArrowShapes = function(){
+ var arrowShapes = this.arrowShapes = {};
+ var renderer = this;
+
+ // Contract for arrow shapes:
+ // 0, 0 is arrow tip
+ // (0, 1) is direction towards node
+ // (1, 0) is right
+ //
+ // functional api:
+ // collide: check x, y in shape
+ // roughCollide: called before collide, no false negatives
+ // draw: draw
+ // spacing: dist(arrowTip, nodeBoundary)
+ // gap: dist(edgeTip, nodeBoundary), edgeTip may != arrowTip
+
+ var bbCollide = function( x, y, size, angle, translation, padding ){
+ var x1 = translation.x - size/2 - padding;
+ var x2 = translation.x + size/2 + padding;
+ var y1 = translation.y - size/2 - padding;
+ var y2 = translation.y + size/2 + padding;
+
+ var inside = (x1 <= x && x <= x2) && (y1 <= y && y <= y2);
+
+ return inside;
+ };
+
+ var transform = function( x, y, size, angle, translation ){
+ var xRotated = x * Math.cos(angle) - y * Math.sin(angle);
+ var yRotated = x * Math.sin(angle) + y * Math.cos(angle);
+
+ var xScaled = xRotated * size;
+ var yScaled = yRotated * size;
+
+ var xTranslated = xScaled + translation.x;
+ var yTranslated = yScaled + translation.y;
+
+ return {
+ x: xTranslated,
+ y: yTranslated
+ };
+ };
+
+ var transformPoints = function( pts, size, angle, translation ){
+ var retPts = [];
+
+ for( var i = 0; i < pts.length; i += 2 ){
+ var x = pts[i];
+ var y = pts[i + 1];
+
+ retPts.push( transform(x, y, size, angle, translation) );
+ }
+
+ return retPts;
+ };
+
+ var pointsToArr = function( pts ){
+ var ret = [];
+
+ for( var i = 0; i < pts.length; i++ ){
+ var p = pts[i];
+
+ ret.push( p.x, p.y );
+ }
+
+ return ret;
+ };
+
+ var defineArrowShape = function( name, defn ){
+ if( is.string(defn) ){
+ defn = arrowShapes[ defn ];
+ }
+
+ arrowShapes[ name ] = util.extend( {
+ name: name,
+
+ points: [
+ -0.15, -0.3,
+ 0.15, -0.3,
+ 0.15, 0.3,
+ -0.15, 0.3
+ ],
+
+ collide: function( x, y, size, angle, translation, padding ){
+ var points = pointsToArr( transformPoints( this.points, size + 2*padding, angle, translation ) );
+ var inside = math.pointInsidePolygonPoints( x, y, points );
+
+ return inside;
+ },
+
+ roughCollide: bbCollide,
+
+ draw: function( context, size, angle, translation ){
+ var points = transformPoints( this.points, size, angle, translation );
+
+ renderer.arrowShapeImpl('polygon')( context, points );
+ },
+
+ spacing: function( edge ){
+ return 0;
+ },
+
+ gap: function( edge ){
+ return edge._private.style['width'].pfValue * 2;
+ }
+ }, defn );
+ };
+
+ defineArrowShape( 'none', {
+ collide: util.falsify,
+
+ roughCollide: util.falsify,
+
+ draw: util.noop,
+
+ spacing: util.zeroify,
+
+ gap: util.zeroify
+ } );
+
+ defineArrowShape( 'triangle', {
+ points: [
+ -0.15, -0.3,
+ 0, 0,
+ 0.15, -0.3
+ ]
+ } );
+
+ defineArrowShape( 'arrow', 'triangle' );
+
+ defineArrowShape( 'triangle-backcurve', {
+ points: arrowShapes['triangle'].points,
+
+ controlPoint: [ 0, -0.15 ],
+
+ roughCollide: bbCollide,
+
+ draw: function( context, size, angle, translation ){
+ var ptsTrans = transformPoints( this.points, size, angle, translation );
+ var ctrlPt = this.controlPoint;
+ var ctrlPtTrans = transform( ctrlPt[0], ctrlPt[1], size, angle, translation );
+
+ renderer.arrowShapeImpl( this.name )( context, ptsTrans, ctrlPtTrans );
+ },
+
+ gap: function( edge ){
+ return edge._private.style['width'].pfValue;
+ }
+ } );
+
+
+ defineArrowShape( 'triangle-tee', {
+ points: [
+ -0.15, -0.3,
+ 0, 0,
+ 0.15, -0.3,
+ -0.15, -0.3
+ ],
+
+ pointsTee: [
+ -0.15, -0.4,
+ -0.15, -0.5,
+ 0.15, -0.5,
+ 0.15, -0.4
+ ],
+
+ collide: function( x, y, size, angle, translation, padding ){
+ var triPts = pointsToArr( transformPoints( this.points, size + 2*padding, angle, translation ) );
+ var teePts = pointsToArr( transformPoints( this.pointsTee, size + 2*padding, angle, translation ) );
+
+ var inside = math.pointInsidePolygonPoints( x, y, triPts ) || math.pointInsidePolygonPoints( x, y, teePts );
+
+ return inside;
+ },
+
+ draw: function( context, size, angle, translation ){
+ var triPts = transformPoints( this.points, size, angle, translation );
+ var teePts = transformPoints( this.pointsTee, size, angle, translation );
+
+ renderer.arrowShapeImpl( this.name )( context, triPts, teePts );
+ }
+ } );
+
+ defineArrowShape( 'vee', {
+ points: [
+ -0.15, -0.3,
+ 0, 0,
+ 0.15, -0.3,
+ 0, -0.15,
+ ],
+
+ gap: function( edge ){
+ return edge._private.style['width'].pfValue;
+ }
+ } );
+
+ defineArrowShape( 'half-triangle-overshot', {
+ points: [
+ 0, -0.25,
+ -0.5, -0.25,
+ 0.5, 0.25
+ ],
+
+ leavePathOpen: true,
+
+ matchEdgeWidth: true
+ } );
+
+ defineArrowShape( 'circle', {
+ radius: 0.15,
+
+ collide: function( x, y, size, angle, translation, padding ){
+ var t = translation;
+ var inside = ( Math.pow(t.x - x, 2) + Math.pow(t.y - y, 2) <= Math.pow((size + 2*padding) * this.radius, 2) );
+
+ return inside;
+ },
+
+ draw: function( context, size, angle, translation ){
+ renderer.arrowShapeImpl( this.name )( context, translation.x, translation.y, this.radius * size );
+ },
+
+ spacing: function( edge ){
+ return renderer.getArrowWidth(edge._private.style['width'].pfValue)
+ * this.radius;
+ },
+ } );
+
+ defineArrowShape( 'inhibitor', {
+ points: [
+ -0.25, 0,
+ -0.25, -0.1,
+ 0.25, -0.1,
+ 0.25, 0
+ ],
+
+ spacing: function( edge ){
+ return 1;
+ },
+
+ gap: function( edge ){
+ return 1;
+ }
+ } );
+
+ defineArrowShape( 'tee', 'inhibitor' );
+
+ defineArrowShape( 'square', {
+ points: [
+ -0.15, 0.00,
+ 0.15, 0.00,
+ 0.15, -0.3,
+ -0.15, -0.3
+ ]
+ } );
+
+ defineArrowShape( 'diamond', {
+ points: [
+ -0.15, -0.15,
+ 0, -0.3,
+ 0.15, -0.15,
+ 0, 0
+ ],
+
+ gap: function( edge ){
+ return edge._private.style['width'].pfValue;
+ }
+ } );
+
+};
+
+module.exports = BRp;
+
+},{"../../../is":77,"../../../math":79,"../../../util":94}],55:[function(_dereq_,module,exports){
+'use strict';
+
+var BRp = {};
+
+var delEleCache = function( r ){
+ r.eleEache = null;
+};
+
+var getEleCache = function( r ){
+ if( !r.eleEache ){
+ r.eleEache = {
+ nodes: r.cy.nodes(),
+ edges: r.cy.edges()
+ };
+ }
+
+ return r.eleEache;
+};
+
+BRp.getCachedElements = function(){
+ return getEleCache( this );
+};
+
+BRp.getCachedNodes = function(){
+ return getEleCache( this ).nodes;
+};
+
+BRp.getCachedEdges = function(){
+ return getEleCache( this ).edges;
+};
+
+BRp.updateElementsCache = function(){
+ var r = this;
+
+ delEleCache( r );
+
+ return getEleCache( r );
+};
+
+module.exports = BRp;
+
+},{}],56:[function(_dereq_,module,exports){
+'use strict';
+
+var math = _dereq_('../../../math');
+var is = _dereq_('../../../is');
+var zIndexSort = _dereq_('../../../collection/zsort');
+
+var BRp = {};
+
+// Project mouse
+BRp.projectIntoViewport = function(clientX, clientY) {
+ var offsets = this.findContainerClientCoords();
+ var offsetLeft = offsets[0];
+ var offsetTop = offsets[1];
+
+ var x = clientX - offsetLeft;
+ var y = clientY - offsetTop;
+
+ x -= this.cy.pan().x; y -= this.cy.pan().y; x /= this.cy.zoom(); y /= this.cy.zoom();
+ return [x, y];
+};
+
+BRp.findContainerClientCoords = function() {
+ var container = this.container;
+
+ var bb = this.containerBB = this.containerBB || container.getBoundingClientRect();
+
+ return [bb.left, bb.top, bb.right - bb.left, bb.bottom - bb.top];
+};
+
+BRp.invalidateContainerClientCoordsCache = function(){
+ this.containerBB = null;
+};
+
+// Find nearest element
+BRp.findNearestElement = function(x, y, visibleElementsOnly, isTouch){
+ var self = this;
+ var r = this;
+ var eles = r.getCachedZSortedEles();
+ var near = [];
+ var zoom = r.cy.zoom();
+ var hasCompounds = r.cy.hasCompoundNodes();
+ var edgeThreshold = (isTouch ? 24 : 8) / zoom;
+ var nodeThreshold = (isTouch ? 8 : 2) / zoom;
+ var labelThreshold = (isTouch ? 8 : 2) / zoom;
+
+ function checkNode(node){
+ var _p = node._private;
+
+ if( _p.style['events'].strValue === 'no' ){ return; }
+
+ var width = node.outerWidth() + 2*nodeThreshold;
+ var height = node.outerHeight() + 2*nodeThreshold;
+ var hw = width/2;
+ var hh = height/2;
+ var pos = _p.position;
+
+ if(
+ pos.x - hw <= x && x <= pos.x + hw // bb check x
+ &&
+ pos.y - hh <= y && y <= pos.y + hh // bb check y
+ ){
+ var visible = !visibleElementsOnly || ( node.visible() && !node.transparent() );
+
+ // exit early if invisible edge and must be visible
+ if( visibleElementsOnly && !visible ){
+ return;
+ }
+
+ var shape = r.nodeShapes[ self.getNodeShape(node) ];
+
+ if(
+ shape.checkPoint(x, y, 0, width, height, pos.x, pos.y)
+ ){
+ near.push( node );
+ }
+
+ }
+ }
+
+ function checkEdge(edge){
+ var _p = edge._private;
+
+ if( _p.style['events'].strValue === 'no' ){ return; }
+
+ var rs = _p.rscratch;
+ var style = _p.style;
+ var width = style['width'].pfValue/2 + edgeThreshold; // more like a distance radius from centre
+ var widthSq = width * width;
+ var width2 = width * 2;
+ var src = _p.source;
+ var tgt = _p.target;
+ var inEdgeBB = false;
+ var sqDist;
+
+ // exit early if invisible edge and must be visible
+ var passedVisibilityCheck;
+ var passesVisibilityCheck = function(){
+ if( passedVisibilityCheck !== undefined ){
+ return passedVisibilityCheck;
+ }
+
+ if( !visibleElementsOnly ){
+ passedVisibilityCheck = true;
+ return true;
+ }
+
+ var visible = edge.visible() && !edge.transparent();
+ if( visible ){
+ passedVisibilityCheck = true;
+ return true;
+ }
+
+ passedVisibilityCheck = false;
+ return false;
+ };
+
+ if( rs.edgeType === 'segments' || rs.edgeType === 'straight' || rs.edgeType === 'haystack' ){
+ var pts = rs.allpts;
+
+ for( var i = 0; i + 3 < pts.length; i += 2 ){
+ if(
+ (inEdgeBB = math.inLineVicinity(x, y, pts[i], pts[i+1], pts[i+2], pts[i+3], width2))
+ && passesVisibilityCheck() &&
+ widthSq > ( sqDist = math.sqDistanceToFiniteLine(x, y, pts[i], pts[i+1], pts[i+2], pts[i+3]) )
+ ){
+ near.push( edge );
+ }
+ }
+
+ } else if( rs.edgeType === 'bezier' || rs.edgeType === 'multibezier' || rs.edgeType === 'self' || rs.edgeType === 'compound' ){
+ var pts = rs.allpts;
+ for( var i = 0; i + 5 < rs.allpts.length; i += 4 ){
+ if(
+ (inEdgeBB = math.inBezierVicinity(x, y, pts[i], pts[i+1], pts[i+2], pts[i+3], pts[i+4], pts[i+5], width2))
+ && passesVisibilityCheck() &&
+ (widthSq > (sqDist = math.sqDistanceToQuadraticBezier(x, y, pts[i], pts[i+1], pts[i+2], pts[i+3], pts[i+4], pts[i+5])) )
+ ){
+ near.push( edge );
+ }
+ }
+ }
+
+ // if we're close to the edge but didn't hit it, maybe we hit its arrows
+ if( inEdgeBB && passesVisibilityCheck() && near.length === 0 || near[near.length - 1] !== edge ){
+ var src = src || _p.source;
+ var tgt = tgt || _p.target;
+
+ var eWidth = style['width'].pfValue;
+ var arSize = self.getArrowWidth( eWidth );
+
+ var arrows = [
+ { name: 'source', x: rs.arrowStartX, y: rs.arrowStartY, angle: rs.srcArrowAngle },
+ { name: 'target', x: rs.arrowEndX, y: rs.arrowEndY, angle: rs.tgtArrowAngle },
+ { name: 'mid-source', x: rs.midX, y: rs.midY, angle: rs.midsrcArrowAngle },
+ { name: 'mid-target', x: rs.midX, y: rs.midY, angle: rs.midtgtArrowAngle }
+ ];
+
+ for( var i = 0; i < arrows.length; i++ ){
+ var ar = arrows[i];
+ var shape = r.arrowShapes[ style[ar.name+'-arrow-shape'].value ];
+
+ if(
+ shape.roughCollide(x, y, arSize, ar.angle, { x: ar.x, y: ar.y }, edgeThreshold)
+ &&
+ shape.collide(x, y, arSize, ar.angle, { x: ar.x, y: ar.y }, edgeThreshold)
+ ){
+ near.push( edge );
+ break;
+ }
+ }
+ }
+
+ // for compound graphs, hitting edge may actually want a connected node instead (b/c edge may have greater z-index precedence)
+ if( hasCompounds && near.length > 0 && near[ near.length - 1 ] === edge ){
+ checkNode( src );
+ checkNode( tgt );
+ }
+ }
+
+ function checkLabel(ele){
+ var _p = ele._private;
+ var th = labelThreshold;
+
+ if( _p.style['text-events'].strValue === 'no' ){ return; }
+
+ // adjust bb w/ angle
+ if( _p.group === 'edges' && _p.style['edge-text-rotation'].strValue === 'autorotate' ){
+
+ var rstyle = _p.rstyle;
+ var lw = rstyle.labelWidth + 2*th;
+ var lh = rstyle.labelHeight + 2*th;
+ var lx = rstyle.labelX;
+ var ly = rstyle.labelY;
+
+ var theta = _p.rscratch.labelAngle;
+ var cos = Math.cos( theta );
+ var sin = Math.sin( theta );
+
+ var rotate = function( x, y ){
+ x = x - lx;
+ y = y - ly;
+
+ return {
+ x: x*cos - y*sin + lx,
+ y: x*sin + y*cos + ly
+ };
+ };
+
+ var lx1 = lx - lw/2;
+ var lx2 = lx + lw/2;
+ var ly1 = ly - lh/2;
+ var ly2 = ly + lh/2;
+
+ var px1y1 = rotate( lx1, ly1 );
+ var px1y2 = rotate( lx1, ly2 );
+ var px2y1 = rotate( lx2, ly1 );
+ var px2y2 = rotate( lx2, ly2 );
+
+ var points = [
+ px1y1.x, px1y1.y,
+ px2y1.x, px2y1.y,
+ px2y2.x, px2y2.y,
+ px1y2.x, px1y2.y
+ ];
+
+ if( math.pointInsidePolygonPoints( x, y, points ) ){
+ near.push( ele );
+ }
+
+ } else {
+ var bb = ele.boundingBox({
+ includeLabels: true,
+ includeNodes: false,
+ includeEdges: false
+ });
+
+ // adjust bb w/ threshold
+ bb.x1 -= th;
+ bb.y1 -= th;
+ bb.x2 += th;
+ bb.y2 += th;
+ bb.w = bb.x2 - bb.x1;
+ bb.h = bb.y2 - bb.y1;
+
+ if( math.inBoundingBox( bb, x, y ) ){
+ near.push( ele );
+ }
+ }
+
+ }
+
+ for( var i = eles.length - 1; i >= 0; i-- ){ // reverse order for precedence
+ var ele = eles[i];
+ var _p = ele._private;
+
+ if( near.length > 0 ){ break; } // since we check in z-order, first found is top and best result => exit early
+
+ if( _p.group === 'nodes' ){
+ checkNode( ele );
+
+ } else { // then edge
+ checkEdge( ele );
+ }
+
+ checkLabel( ele );
+
+ }
+
+
+ if( near.length > 0 ){
+ return near[ near.length - 1 ];
+ } else {
+ return null;
+ }
+};
+
+// 'Give me everything from this box'
+BRp.getAllInBox = function(x1, y1, x2, y2) {
+ var nodes = this.getCachedNodes();
+ var edges = this.getCachedEdges();
+ var box = [];
+
+ var x1c = Math.min(x1, x2);
+ var x2c = Math.max(x1, x2);
+ var y1c = Math.min(y1, y2);
+ var y2c = Math.max(y1, y2);
+
+ x1 = x1c;
+ x2 = x2c;
+ y1 = y1c;
+ y2 = y2c;
+
+ var boxBb = math.makeBoundingBox({
+ x1: x1, y1: y1,
+ x2: x2, y2: y2
+ });
+
+ for ( var i = 0; i < nodes.length; i++ ){
+ var node = nodes[i];
+ var nodeBb = node.boundingBox({
+ includeNodes: true,
+ includeEdges: false,
+ includeLabels: false
+ });
+
+ if( math.boundingBoxesIntersect(boxBb, nodeBb) ){
+ box.push(nodes[i]);
+ }
+ }
+
+ for( var e = 0; e < edges.length; e++ ){
+ var edge = edges[e];
+ var _p = edge._private;
+ var rs = _p.rscratch;
+
+ if( rs.startX != null && rs.startY != null && !math.inBoundingBox( boxBb, rs.startX, rs.startY ) ){ continue; }
+ if( rs.endX != null && rs.endY != null && !math.inBoundingBox( boxBb, rs.endX, rs.endY ) ){ continue; }
+
+ if( rs.edgeType === 'bezier' || rs.edgeType === 'multibezier' || rs.edgeType === 'self' || rs.edgeType === 'compound' || rs.edgeType === 'segments' || rs.edgeType === 'haystack' ){
+
+ var pts = _p.rstyle.bezierPts || _p.rstyle.linePts || _p.rstyle.haystackPts;
+ var allInside = true;
+
+ for( var i = 0; i < pts.length; i++ ){
+ if( !math.pointInBoundingBox( boxBb, pts[i] ) ){
+ allInside = false;
+ break;
+ }
+ }
+
+ if( allInside ){
+ box.push( edge );
+ }
+
+ } else if( rs.edgeType === 'haystack' || rs.edgeType === 'straight' ){
+ box.push( edge );
+ }
+
+ }
+
+ return box;
+};
+
+
+/**
+ * Returns the shape of the given node. If the height or width of the given node
+ * is set to auto, the node is considered to be a compound.
+ *
+ * @param node a node
+ * @return {String} shape of the node
+ */
+BRp.getNodeShape = function( node ){
+ var r = this;
+ var style = node._private.style;
+ var shape = style['shape'].value;
+
+ if( node.isParent() ){
+ if( shape === 'rectangle' || shape === 'roundrectangle' ){
+ return shape;
+ } else {
+ return 'rectangle';
+ }
+ }
+
+ if( shape === 'polygon' ){
+ var points = style['shape-polygon-points'].value;
+
+ return r.nodeShapes.makePolygon( points ).name;
+ }
+
+ return shape;
+};
+
+BRp.updateCachedZSortedEles = function(){
+ this.getCachedZSortedEles( true );
+};
+
+BRp.getCachedZSortedEles = function( forceRecalc ){
+ var lastNodes = this.lastZOrderCachedNodes;
+ var lastEdges = this.lastZOrderCachedEdges;
+ var nodes = this.getCachedNodes();
+ var edges = this.getCachedEdges();
+ var eles = [];
+
+ if( forceRecalc || !lastNodes || !lastEdges || lastNodes !== nodes || lastEdges !== edges ){
+ //console.time('cachezorder')
+
+ for( var i = 0; i < nodes.length; i++ ){
+ var n = nodes[i];
+
+ if( n.animated() || (n.visible() && !n.transparent()) ){
+ eles.push( n );
+ }
+ }
+
+ for( var i = 0; i < edges.length; i++ ){
+ var e = edges[i];
+
+ if( e.animated() || (e.visible() && !e.transparent()) ){
+ eles.push( e );
+ }
+ }
+
+ eles.sort( zIndexSort );
+ this.cachedZSortedEles = eles;
+ //console.log('make cache')
+
+ //console.timeEnd('cachezorder')
+ } else {
+ eles = this.cachedZSortedEles;
+ //console.log('read cache')
+ }
+
+ this.lastZOrderCachedNodes = nodes;
+ this.lastZOrderCachedEdges = edges;
+
+ return eles;
+};
+
+function pushBezierPts(edge, pts){
+ var qbezierAt = function( p1, p2, p3, t ){ return math.qbezierAt(p1, p2, p3, t); };
+ var _p = edge._private;
+ var bpts = _p.rstyle.bezierPts;
+
+ bpts.push({
+ x: qbezierAt( pts[0], pts[2], pts[4], 0.05 ),
+ y: qbezierAt( pts[1], pts[3], pts[5], 0.05 )
+ });
+
+ bpts.push({
+ x: qbezierAt( pts[0], pts[2], pts[4], 0.25 ),
+ y: qbezierAt( pts[1], pts[3], pts[5], 0.25 )
+ });
+
+ bpts.push({
+ x: qbezierAt( pts[0], pts[2], pts[4], 0.4 ),
+ y: qbezierAt( pts[1], pts[3], pts[5], 0.4 )
+ });
+
+ bpts.push({
+ x: qbezierAt( pts[0], pts[2], pts[4], 0.5 ),
+ y: qbezierAt( pts[1], pts[3], pts[5], 0.5 )
+ });
+
+ bpts.push({
+ x: qbezierAt( pts[0], pts[2], pts[4], 0.6 ),
+ y: qbezierAt( pts[1], pts[3], pts[5], 0.6 )
+ });
+
+ bpts.push({
+ x: qbezierAt( pts[0], pts[2], pts[4], 0.75 ),
+ y: qbezierAt( pts[1], pts[3], pts[5], 0.75 )
+ });
+
+ bpts.push({
+ x: qbezierAt( pts[0], pts[2], pts[4], 0.95 ),
+ y: qbezierAt( pts[1], pts[3], pts[5], 0.95 )
+ });
+}
+
+BRp.projectLines = function( edge ){
+ var _p = edge._private;
+ var rs = _p.rscratch;
+ var et = rs.edgeType;
+
+ if( et === 'multibezier' || et === 'bezier' || et === 'self' || et === 'compound' ){
+ var bpts = _p.rstyle.bezierPts = []; // jshint ignore:line
+
+ for( var i = 0; i + 5 < rs.allpts.length; i += 4 ){
+ pushBezierPts( edge, rs.allpts.slice(i, i+6) );
+ }
+ } else if( et === 'segments' ){
+ var lpts = _p.rstyle.linePts = [];
+
+ for( var i = 0; i + 1 < rs.allpts.length; i += 2 ){
+ lpts.push({
+ x: rs.allpts[i],
+ y: rs.allpts[i+1]
+ });
+ }
+ } else if( et === 'haystack' ){
+ var hpts = rs.haystackPts;
+
+ _p.rstyle.haystackPts = [
+ { x: hpts[0], y: hpts[1] },
+ { x: hpts[2], y: hpts[3] }
+ ];
+ }
+};
+
+BRp.projectBezier = BRp.projectLines;
+
+BRp.recalculateNodeLabelProjection = function( node ){
+ var content = node._private.style['label'].strValue;
+ if( !content || content.match(/^\s+$/) ){ return; }
+
+ var textX, textY;
+ var nodeWidth = node.outerWidth();
+ var nodeHeight = node.outerHeight();
+ var nodePos = node._private.position;
+ var textHalign = node._private.style['text-halign'].strValue;
+ var textValign = node._private.style['text-valign'].strValue;
+ var rs = node._private.rscratch;
+ var rstyle = node._private.rstyle;
+
+ switch( textHalign ){
+ case 'left':
+ textX = nodePos.x - nodeWidth / 2;
+ break;
+
+ case 'right':
+ textX = nodePos.x + nodeWidth / 2;
+ break;
+
+ default: // e.g. center
+ textX = nodePos.x;
+ }
+
+ switch( textValign ){
+ case 'top':
+ textY = nodePos.y - nodeHeight / 2;
+ break;
+
+ case 'bottom':
+ textY = nodePos.y + nodeHeight / 2;
+ break;
+
+ default: // e.g. middle
+ textY = nodePos.y;
+ }
+
+ rs.labelX = textX;
+ rs.labelY = textY;
+ rstyle.labelX = textX;
+ rstyle.labelY = textY;
+
+ this.applyLabelDimensions( node );
+};
+
+BRp.recalculateEdgeLabelProjection = function( edge ){
+ var content = edge._private.style['label'].strValue;
+ if( !content || content.match(/^\s+$/) ){ return; }
+
+ var textX, textY;
+ var _p = edge._private;
+ var rs = _p.rscratch;
+ //var style = _p.style;
+ var rstyle = _p.rstyle;
+
+ textX = rs.midX;
+ textY = rs.midY;
+
+ // add center point to style so bounding box calculations can use it
+ rs.labelX = textX;
+ rs.labelY = textY;
+ rstyle.labelX = textX;
+ rstyle.labelY = textY;
+
+ this.applyLabelDimensions( edge );
+};
+
+BRp.applyLabelDimensions = function( ele ){
+ var rs = ele._private.rscratch;
+ var rstyle = ele._private.rstyle;
+
+ var text = this.getLabelText( ele );
+ var labelDims = this.calculateLabelDimensions( ele, text );
+
+ rstyle.labelWidth = labelDims.width;
+ rs.labelWidth = labelDims.width;
+
+ rstyle.labelHeight = labelDims.height;
+ rs.labelHeight = labelDims.height;
+};
+
+BRp.getLabelText = function( ele ){
+ var style = ele._private.style;
+ var text = ele._private.style['label'].strValue;
+ var textTransform = style['text-transform'].value;
+ var rscratch = ele._private.rscratch;
+
+ if (textTransform == 'none') {
+ } else if (textTransform == 'uppercase') {
+ text = text.toUpperCase();
+ } else if (textTransform == 'lowercase') {
+ text = text.toLowerCase();
+ }
+
+ if( style['text-wrap'].value === 'wrap' ){
+ //console.log('wrap');
+
+ // save recalc if the label is the same as before
+ if( rscratch.labelWrapKey === rscratch.labelKey ){
+ // console.log('wrap cache hit');
+ return rscratch.labelWrapCachedText;
+ }
+ // console.log('wrap cache miss');
+
+ var lines = text.split('\n');
+ var maxW = style['text-max-width'].pfValue;
+ var wrappedLines = [];
+
+ for( var l = 0; l < lines.length; l++ ){
+ var line = lines[l];
+ var lineDims = this.calculateLabelDimensions( ele, line, 'line=' + line );
+ var lineW = lineDims.width;
+
+ if( lineW > maxW ){ // line is too long
+ var words = line.split(/\s+/); // NB: assume collapsed whitespace into single space
+ var subline = '';
+
+ for( var w = 0; w < words.length; w++ ){
+ var word = words[w];
+ var testLine = subline.length === 0 ? word : subline + ' ' + word;
+ var testDims = this.calculateLabelDimensions( ele, testLine, 'testLine=' + testLine );
+ var testW = testDims.width;
+
+ if( testW <= maxW ){ // word fits on current line
+ subline += word + ' ';
+ } else { // word starts new line
+ wrappedLines.push( subline );
+ subline = word + ' ';
+ }
+ }
+
+ // if there's remaining text, put it in a wrapped line
+ if( !subline.match(/^\s+$/) ){
+ wrappedLines.push( subline );
+ }
+ } else { // line is already short enough
+ wrappedLines.push( line );
+ }
+ } // for
+
+ rscratch.labelWrapCachedLines = wrappedLines;
+ rscratch.labelWrapCachedText = text = wrappedLines.join('\n');
+ rscratch.labelWrapKey = rscratch.labelKey;
+
+ // console.log(text)
+ } // if wrap
+
+ return text;
+};
+
+BRp.calculateLabelDimensions = function( ele, text, extraKey ){
+ var r = this;
+ var style = ele._private.style;
+ var fStyle = style['font-style'].strValue;
+ var size = style['font-size'].pfValue + 'px';
+ var family = style['font-family'].strValue;
+ // var variant = style['font-variant'].strValue;
+ var weight = style['font-weight'].strValue;
+
+ var cacheKey = ele._private.labelKey;
+
+ if( extraKey ){
+ cacheKey += '$@$' + extraKey;
+ }
+
+ var cache = r.labelDimCache || (r.labelDimCache = {});
+
+ if( cache[cacheKey] ){
+ return cache[cacheKey];
+ }
+
+ var div = this.labelCalcDiv;
+
+ if( !div ){
+ div = this.labelCalcDiv = document.createElement('div');
+ document.body.appendChild( div );
+ }
+
+ var ds = div.style;
+
+ // from ele style
+ ds.fontFamily = family;
+ ds.fontStyle = fStyle;
+ ds.fontSize = size;
+ // ds.fontVariant = variant;
+ ds.fontWeight = weight;
+
+ // forced style
+ ds.position = 'absolute';
+ ds.left = '-9999px';
+ ds.top = '-9999px';
+ ds.zIndex = '-1';
+ ds.visibility = 'hidden';
+ ds.pointerEvents = 'none';
+ ds.padding = '0';
+ ds.lineHeight = '1';
+
+ if( style['text-wrap'].value === 'wrap' ){
+ ds.whiteSpace = 'pre'; // so newlines are taken into account
+ } else {
+ ds.whiteSpace = 'normal';
+ }
+
+ // put label content in div
+ div.textContent = text;
+
+ cache[cacheKey] = {
+ width: div.clientWidth,
+ height: div.clientHeight
+ };
+
+ return cache[cacheKey];
+};
+
+BRp.recalculateRenderedStyle = function( eles ){
+ var edges = [];
+ var nodes = [];
+ var handledEdge = {};
+
+ for( var i = 0; i < eles.length; i++ ){
+ var ele = eles[i];
+ var _p = ele._private;
+ var style = _p.style;
+ var rs = _p.rscratch;
+ var rstyle = _p.rstyle;
+ var id = _p.data.id;
+ var bbStyleSame = rs.boundingBoxKey != null && _p.boundingBoxKey === rs.boundingBoxKey;
+ var labelStyleSame = rs.labelKey != null && _p.labelKey === rs.labelKey;
+ var styleSame = bbStyleSame && labelStyleSame;
+
+ if( _p.group === 'nodes' ){
+ var pos = _p.position;
+ var posSame = rstyle.nodeX != null && rstyle.nodeY != null && pos.x === rstyle.nodeX && pos.y === rstyle.nodeY;
+ var wSame = rstyle.nodeW != null && rstyle.nodeW === style['width'].pfValue;
+ var hSame = rstyle.nodeH != null && rstyle.nodeH === style['height'].pfValue;
+
+ if( !posSame || !styleSame || !wSame || !hSame ){
+ nodes.push( ele );
+ }
+
+ rstyle.nodeX = pos.x;
+ rstyle.nodeY = pos.y;
+ rstyle.nodeW = style['width'].pfValue;
+ rstyle.nodeH = style['height'].pfValue;
+ } else { // edges
+
+ var srcPos = _p.source._private.position;
+ var tgtPos = _p.target._private.position;
+ var srcSame = rstyle.srcX != null && rstyle.srcY != null && srcPos.x === rstyle.srcX && srcPos.y === rstyle.srcY;
+ var tgtSame = rstyle.tgtX != null && rstyle.tgtY != null && tgtPos.x === rstyle.tgtX && tgtPos.y === rstyle.tgtY;
+ var positionsSame = srcSame && tgtSame;
+
+ if( !positionsSame || !styleSame ){
+ if( rs.edgeType === 'bezier' || rs.edgeType === 'straight' || rs.edgeType === 'self' || rs.edgeType === 'compound' ){
+ if( !handledEdge[ id ] ){
+ edges.push( ele );
+ handledEdge[ id ] = true;
+
+ var parallelEdges = ele.parallelEdges();
+ for( var i = 0; i < parallelEdges.length; i++ ){
+ var pEdge = parallelEdges[i];
+ var pId = pEdge._private.data.id;
+
+ if( !handledEdge[ pId ] ){
+ edges.push( pEdge );
+ handledEdge[ pId ] = true;
+ }
+
+ }
+ }
+ } else {
+ edges.push( ele );
+ }
+ } // if positions diff
+
+ // update rstyle positions
+ rstyle.srcX = srcPos.x;
+ rstyle.srcY = srcPos.y;
+ rstyle.tgtX = tgtPos.x;
+ rstyle.tgtY = tgtPos.y;
+
+ } // if edges
+
+ rs.boundingBoxKey = _p.boundingBoxKey;
+ rs.labelKey = _p.labelKey;
+ }
+
+ this.recalculateEdgeProjections( edges );
+ this.recalculateLabelProjections( nodes, edges );
+};
+
+BRp.recalculateLabelProjections = function( nodes, edges ){
+ for( var i = 0; i < nodes.length; i++ ){
+ this.recalculateNodeLabelProjection( nodes[i] );
+ }
+
+ for( var i = 0; i < edges.length; i++ ){
+ this.recalculateEdgeLabelProjection( edges[i] );
+ }
+};
+
+BRp.recalculateEdgeProjections = function( edges ){
+ this.findEdgeControlPoints( edges );
+};
+
+
+// Find edge control points
+BRp.findEdgeControlPoints = function(edges) {
+ if( !edges || edges.length === 0 ){ return; }
+
+ var r = this;
+ var cy = r.cy;
+ var hasCompounds = cy.hasCompoundNodes();
+ var hashTable = {};
+ var pairIds = [];
+ var haystackEdges = [];
+ var autorotateEdges = [];
+
+ // create a table of edge (src, tgt) => list of edges between them
+ var pairId;
+ for (var i = 0; i < edges.length; i++){
+ var edge = edges[i];
+ var _p = edge._private;
+ var data = _p.data;
+ var style = _p.style;
+ var curveStyle = style['curve-style'].value;
+ var edgeIsUnbundled = curveStyle === 'unbundled-bezier' || curveStyle === 'segments';
+
+ // ignore edges who are not to be displayed
+ // they shouldn't take up space
+ if( style.display.value === 'none' ){
+ continue;
+ }
+
+ if( style['edge-text-rotation'].strValue === 'autorotate' ){
+ autorotateEdges.push( edge );
+ }
+
+ if( curveStyle === 'haystack' ){
+ haystackEdges.push( edge );
+ continue;
+ }
+
+ var srcId = data.source;
+ var tgtId = data.target;
+
+ pairId = srcId > tgtId ?
+ tgtId + '$-$' + srcId :
+ srcId + '$-$' + tgtId ;
+
+ if( edgeIsUnbundled ){
+ pairId = 'unbundled' + '$-$' + data.id;
+ }
+
+ if( hashTable[pairId] == null ){
+ hashTable[pairId] = [];
+ pairIds.push( pairId );
+ }
+
+ hashTable[pairId].push( edge );
+
+ if( edgeIsUnbundled ){
+ hashTable[pairId].hasUnbundled = true;
+ }
+ }
+
+ var src, tgt, src_p, tgt_p, srcPos, tgtPos, srcW, srcH, tgtW, tgtH, srcShape, tgtShape;
+ var vectorNormInverse;
+ var badBezier;
+
+ // for each pair (src, tgt), create the ctrl pts
+ // Nested for loop is OK; total number of iterations for both loops = edgeCount
+ for (var p = 0; p < pairIds.length; p++) {
+ pairId = pairIds[p];
+ var pairEdges = hashTable[pairId];
+
+ // for each pair id, the edges should be sorted by index
+ pairEdges.sort(function(edge1, edge2){
+ return edge1._private.index - edge2._private.index;
+ });
+
+ src = pairEdges[0]._private.source;
+ tgt = pairEdges[0]._private.target;
+
+ src_p = src._private;
+ tgt_p = tgt._private;
+
+ // make sure src/tgt distinction is consistent
+ // (src/tgt in this case are just for ctrlpts and don't actually have to be true src/tgt)
+ if( src_p.data.id > tgt_p.data.id ){
+ var temp = src;
+ src = tgt;
+ tgt = temp;
+ }
+
+ srcPos = src_p.position;
+ tgtPos = tgt_p.position;
+
+ srcW = src.outerWidth();
+ srcH = src.outerHeight();
+
+ tgtW = tgt.outerWidth();
+ tgtH = tgt.outerHeight();
+
+ srcShape = r.nodeShapes[ this.getNodeShape(src) ];
+ tgtShape = r.nodeShapes[ this.getNodeShape(tgt) ];
+
+ badBezier = false;
+
+
+ if( (pairEdges.length > 1 && src !== tgt) || pairEdges.hasUnbundled ){
+
+ // pt outside src shape to calc distance/displacement from src to tgt
+ var srcOutside = srcShape.intersectLine(
+ srcPos.x,
+ srcPos.y,
+ srcW,
+ srcH,
+ tgtPos.x,
+ tgtPos.y,
+ 0
+ );
+
+ // pt outside tgt shape to calc distance/displacement from src to tgt
+ var tgtOutside = tgtShape.intersectLine(
+ tgtPos.x,
+ tgtPos.y,
+ tgtW,
+ tgtH,
+ srcPos.x,
+ srcPos.y,
+ 0
+ );
+
+ var midptSrcPts = {
+ x1: srcOutside[0],
+ x2: tgtOutside[0],
+ y1: srcOutside[1],
+ y2: tgtOutside[1]
+ };
+
+ var dy = ( tgtOutside[1] - srcOutside[1] );
+ var dx = ( tgtOutside[0] - srcOutside[0] );
+ var l = Math.sqrt( dx*dx + dy*dy );
+
+ var vector = {
+ x: dx,
+ y: dy
+ };
+
+ var vectorNorm = {
+ x: vector.x/l,
+ y: vector.y/l
+ };
+ vectorNormInverse = {
+ x: -vectorNorm.y,
+ y: vectorNorm.x
+ };
+
+
+ // if src intersection is inside tgt or tgt intersection is inside src, then no ctrl pts to draw
+ if(
+ tgtShape.checkPoint( srcOutside[0], srcOutside[1], 0, tgtW, tgtH, tgtPos.x, tgtPos.y ) ||
+ srcShape.checkPoint( tgtOutside[0], tgtOutside[1], 0, srcW, srcH, srcPos.x, srcPos.y )
+ ){
+ vectorNormInverse = {};
+ badBezier = true;
+ }
+
+ }
+
+ var edge;
+ var edge_p;
+ var rs;
+
+ for (var i = 0; i < pairEdges.length; i++) {
+ edge = pairEdges[i];
+ edge_p = edge._private;
+ rs = edge_p.rscratch;
+
+ var edgeIndex1 = rs.lastEdgeIndex;
+ var edgeIndex2 = i;
+
+ var numEdges1 = rs.lastNumEdges;
+ var numEdges2 = pairEdges.length;
+
+ var eStyle = edge_p.style;
+ var style = eStyle;
+ var curveStyle = eStyle['curve-style'].value;
+ var ctrlptDists = eStyle['control-point-distances'];
+ var ctrlptWs = eStyle['control-point-weights'];
+ var bezierN = ctrlptDists && ctrlptWs ? Math.min( ctrlptDists.value.length, ctrlptWs.value.length ) : 1;
+ var stepSize = eStyle['control-point-step-size'].pfValue;
+ var ctrlptDist = ctrlptDists !== undefined ? ctrlptDists.pfValue[0] : undefined;
+ var ctrlptWeight = ctrlptWs.value[0];
+ var edgeIsUnbundled = curveStyle === 'unbundled-bezier' || curveStyle === 'segments';
+
+ var swappedDirection = edge_p.source !== src;
+
+ if( swappedDirection && edgeIsUnbundled ){
+ ctrlptDist *= -1;
+ }
+
+ var srcX1 = rs.lastSrcCtlPtX;
+ var srcX2 = srcPos.x;
+ var srcY1 = rs.lastSrcCtlPtY;
+ var srcY2 = srcPos.y;
+ var srcW1 = rs.lastSrcCtlPtW;
+ var srcW2 = src.outerWidth();
+ var srcH1 = rs.lastSrcCtlPtH;
+ var srcH2 = src.outerHeight();
+
+ var tgtX1 = rs.lastTgtCtlPtX;
+ var tgtX2 = tgtPos.x;
+ var tgtY1 = rs.lastTgtCtlPtY;
+ var tgtY2 = tgtPos.y;
+ var tgtW1 = rs.lastTgtCtlPtW;
+ var tgtW2 = tgt.outerWidth();
+ var tgtH1 = rs.lastTgtCtlPtH;
+ var tgtH2 = tgt.outerHeight();
+
+ var width1 = rs.lastW;
+ var width2 = eStyle['control-point-step-size'].pfValue;
+
+ if( badBezier ){
+ rs.badBezier = true;
+ } else {
+ rs.badBezier = false;
+ }
+
+ if( srcX1 === srcX2 && srcY1 === srcY2 && srcW1 === srcW2 && srcH1 === srcH2
+ && tgtX1 === tgtX2 && tgtY1 === tgtY2 && tgtW1 === tgtW2 && tgtH1 === tgtH2
+ && width1 === width2
+ && ((edgeIndex1 === edgeIndex2 && numEdges1 === numEdges2) || edgeIsUnbundled) ){
+ // console.log('edge ctrl pt cache HIT')
+ continue; // then the control points haven't changed and we can skip calculating them
+ } else {
+ rs.lastSrcCtlPtX = srcX2;
+ rs.lastSrcCtlPtY = srcY2;
+ rs.lastSrcCtlPtW = srcW2;
+ rs.lastSrcCtlPtH = srcH2;
+ rs.lastTgtCtlPtX = tgtX2;
+ rs.lastTgtCtlPtY = tgtY2;
+ rs.lastTgtCtlPtW = tgtW2;
+ rs.lastTgtCtlPtH = tgtH2;
+ rs.lastEdgeIndex = edgeIndex2;
+ rs.lastNumEdges = numEdges2;
+ rs.lastWidth = width2;
+ // console.log('edge ctrl pt cache MISS')
+ }
+
+ if( src === tgt ){
+ // Self-edge
+
+ rs.edgeType = 'self';
+
+ var j = i;
+ var loopDist = stepSize;
+
+ if( edgeIsUnbundled ){
+ j = 0;
+ loopDist = ctrlptDist;
+ }
+
+ rs.ctrlpts = [
+ srcPos.x,
+ srcPos.y - (1 + Math.pow(srcH, 1.12) / 100) * loopDist * (j / 3 + 1),
+
+ srcPos.x - (1 + Math.pow(srcW, 1.12) / 100) * loopDist * (j / 3 + 1),
+ srcPos.y
+ ];
+
+ } else if(
+ hasCompounds &&
+ ( src.isParent() || src.isChild() || tgt.isParent() || tgt.isChild() ) &&
+ ( src.parents().anySame(tgt) || tgt.parents().anySame(src) )
+ ){
+ // Compound edge
+
+ rs.edgeType = 'compound';
+
+ // because the line approximation doesn't apply for compound beziers
+ // (loop/self edges are already elided b/c of cheap src==tgt check)
+ rs.badBezier = false;
+
+ var j = i;
+ var loopDist = stepSize;
+
+ if( edgeIsUnbundled ){
+ j = 0;
+ loopDist = ctrlptDist;
+ }
+
+ var loopW = 50;
+
+ var loopaPos = {
+ x: srcPos.x - srcW/2,
+ y: srcPos.y - srcH/2
+ };
+
+ var loopbPos = {
+ x: tgtPos.x - tgtW/2,
+ y: tgtPos.y - tgtH/2
+ };
+
+ var loopPos = {
+ x: Math.min( loopaPos.x, loopbPos.x ),
+ y: Math.min( loopaPos.y, loopbPos.y )
+ };
+
+ // avoids cases with impossible beziers
+ var minCompoundStretch = 0.5;
+ var compoundStretchA = Math.max( minCompoundStretch, Math.log(srcW * 0.01) );
+ var compoundStretchB = Math.max( minCompoundStretch, Math.log(tgtW * 0.01) );
+
+ rs.ctrlpts = [
+ loopPos.x,
+ loopPos.y - (1 + Math.pow(loopW, 1.12) / 100) * loopDist * (j / 3 + 1) * compoundStretchA,
+
+ loopPos.x - (1 + Math.pow(loopW, 1.12) / 100) * loopDist * (j / 3 + 1) * compoundStretchB,
+ loopPos.y
+ ];
+
+ } else if( curveStyle === 'segments' ){
+ // Segments (multiple straight lines)
+
+ rs.edgeType = 'segments';
+ rs.segpts = [];
+
+ var segmentWs = eStyle['segment-weights'].pfValue;
+ var segmentDs = eStyle['segment-distances'].pfValue;
+ var segmentsN = Math.min( segmentWs.length, segmentDs.length );
+
+ for( var s = 0; s < segmentsN; s++ ){
+ var w = segmentWs[s];
+ var d = segmentDs[s];
+
+ // d = swappedDirection ? -d : d;
+ //
+ // d = Math.abs(d);
+
+ // var w1 = !swappedDirection ? (1 - w) : w;
+ // var w2 = !swappedDirection ? w : (1 - w);
+
+ var w1 = (1 - w);
+ var w2 = w;
+
+ var adjustedMidpt = {
+ x: midptSrcPts.x1 * w1 + midptSrcPts.x2 * w2,
+ y: midptSrcPts.y1 * w1 + midptSrcPts.y2 * w2
+ };
+
+ rs.segpts.push(
+ adjustedMidpt.x + vectorNormInverse.x * d,
+ adjustedMidpt.y + vectorNormInverse.y * d
+ );
+ }
+
+ // Straight edge
+ } else if (
+ pairEdges.length % 2 === 1
+ && i === Math.floor(pairEdges.length / 2)
+ && !edgeIsUnbundled
+ ){
+
+ rs.edgeType = 'straight';
+
+ } else {
+ // (Multi)bezier
+
+ var multi = edgeIsUnbundled;
+
+ rs.edgeType = multi ? 'multibezier' : 'bezier';
+ rs.ctrlpts = [];
+
+ for( var b = 0; b < bezierN; b++ ){
+ var normctrlptDist = (0.5 - pairEdges.length / 2 + i) * stepSize;
+ var manctrlptDist;
+ var sign = math.signum( normctrlptDist );
+
+ if( multi ){
+ ctrlptDist = ctrlptDists ? ctrlptDists.pfValue[b] : stepSize; // fall back on step size
+ ctrlptWeight = ctrlptWs.value[b];
+ }
+
+ if( edgeIsUnbundled ){ // multi or single unbundled
+ manctrlptDist = ctrlptDist;
+ } else {
+ manctrlptDist = ctrlptDist !== undefined ? sign * ctrlptDist : undefined;
+ }
+
+ var distanceFromMidpoint = manctrlptDist !== undefined ? manctrlptDist : normctrlptDist;
+
+ var w1 = !swappedDirection || edgeIsUnbundled ? (1 - ctrlptWeight) : ctrlptWeight;
+ var w2 = !swappedDirection || edgeIsUnbundled ? ctrlptWeight : (1 - ctrlptWeight);
+
+ var adjustedMidpt = {
+ x: midptSrcPts.x1 * w1 + midptSrcPts.x2 * w2,
+ y: midptSrcPts.y1 * w1 + midptSrcPts.y2 * w2
+ };
+
+ rs.ctrlpts.push(
+ adjustedMidpt.x + vectorNormInverse.x * distanceFromMidpoint,
+ adjustedMidpt.y + vectorNormInverse.y * distanceFromMidpoint
+ );
+ }
+
+ }
+
+ // find endpts for edge
+ this.findEndpoints( edge );
+
+ var badStart = !is.number( rs.startX ) || !is.number( rs.startY );
+ var badAStart = !is.number( rs.arrowStartX ) || !is.number( rs.arrowStartY );
+ var badEnd = !is.number( rs.endX ) || !is.number( rs.endY );
+ var badAEnd = !is.number( rs.arrowEndX ) || !is.number( rs.arrowEndY );
+
+ var minCpADistFactor = 3;
+ var arrowW = this.getArrowWidth( eStyle['width'].pfValue ) * this.arrowShapeHeight;
+ var minCpADist = minCpADistFactor * arrowW;
+
+ if( rs.edgeType === 'bezier' ){
+ var startACpDist = math.distance( { x: rs.ctrlpts[0], y: rs.ctrlpts[1] }, { x: rs.startX, y: rs.startY } );
+ var closeStartACp = startACpDist < minCpADist;
+ var endACpDist = math.distance( { x: rs.ctrlpts[0], y: rs.ctrlpts[1] }, { x: rs.endX, y: rs.endY } );
+ var closeEndACp = endACpDist < minCpADist;
+
+ var overlapping = false;
+
+ if( badStart || badAStart || closeStartACp ){
+ overlapping = true;
+
+ // project control point along line from src centre to outside the src shape
+ // (otherwise intersection will yield nothing)
+ var cpD = { // delta
+ x: rs.ctrlpts[0] - srcPos.x,
+ y: rs.ctrlpts[1] - srcPos.y
+ };
+ var cpL = Math.sqrt( cpD.x*cpD.x + cpD.y*cpD.y ); // length of line
+ var cpM = { // normalised delta
+ x: cpD.x / cpL,
+ y: cpD.y / cpL
+ };
+ var radius = Math.max(srcW, srcH);
+ var cpProj = { // *2 radius guarantees outside shape
+ x: rs.ctrlpts[0] + cpM.x * 2 * radius,
+ y: rs.ctrlpts[1] + cpM.y * 2 * radius
+ };
+
+ var srcCtrlPtIntn = srcShape.intersectLine(
+ srcPos.x,
+ srcPos.y,
+ srcW,
+ srcH,
+ cpProj.x,
+ cpProj.y,
+ 0
+ );
+
+ if( closeStartACp ){
+ rs.ctrlpts[0] = rs.ctrlpts[0] + cpM.x * (minCpADist - startACpDist);
+ rs.ctrlpts[1] = rs.ctrlpts[1] + cpM.y * (minCpADist - startACpDist);
+ } else {
+ rs.ctrlpts[0] = srcCtrlPtIntn[0] + cpM.x * minCpADist;
+ rs.ctrlpts[1] = srcCtrlPtIntn[1] + cpM.y * minCpADist;
+ }
+ }
+
+ if( badEnd || badAEnd || closeEndACp ){
+ overlapping = true;
+
+ // project control point along line from tgt centre to outside the tgt shape
+ // (otherwise intersection will yield nothing)
+ var cpD = { // delta
+ x: rs.ctrlpts[0] - tgtPos.x,
+ y: rs.ctrlpts[1] - tgtPos.y
+ };
+ var cpL = Math.sqrt( cpD.x*cpD.x + cpD.y*cpD.y ); // length of line
+ var cpM = { // normalised delta
+ x: cpD.x / cpL,
+ y: cpD.y / cpL
+ };
+ var radius = Math.max(srcW, srcH);
+ var cpProj = { // *2 radius guarantees outside shape
+ x: rs.ctrlpts[0] + cpM.x * 2 * radius,
+ y: rs.ctrlpts[1] + cpM.y * 2 * radius
+ };
+
+ var tgtCtrlPtIntn = tgtShape.intersectLine(
+ tgtPos.x,
+ tgtPos.y,
+ tgtW,
+ tgtH,
+ cpProj.x,
+ cpProj.y,
+ 0
+ );
+
+ if( closeEndACp ){
+ rs.ctrlpts[0] = rs.ctrlpts[0] + cpM.x * (minCpADist - endACpDist);
+ rs.ctrlpts[1] = rs.ctrlpts[1] + cpM.y * (minCpADist - endACpDist);
+ } else {
+ rs.ctrlpts[0] = tgtCtrlPtIntn[0] + cpM.x * minCpADist;
+ rs.ctrlpts[1] = tgtCtrlPtIntn[1] + cpM.y * minCpADist;
+ }
+
+ }
+
+ if( overlapping ){
+ // recalc endpts
+ this.findEndpoints( edge );
+ }
+
+ }
+
+ if( rs.edgeType === 'multibezier' || rs.edgeType === 'bezier' || rs.edgeType === 'self' || rs.edgeType === 'compound' ){
+ rs.allpts = [];
+
+ rs.allpts.push( rs.startX, rs.startY );
+
+ for( var b = 0; b+1 < rs.ctrlpts.length; b += 2 ){
+ // ctrl pt itself
+ rs.allpts.push( rs.ctrlpts[b], rs.ctrlpts[b+1] );
+
+ // the midpt between ctrlpts as intermediate destination pts
+ if( b + 3 < rs.ctrlpts.length ){
+ rs.allpts.push( (rs.ctrlpts[b] + rs.ctrlpts[b+2])/2, (rs.ctrlpts[b+1] + rs.ctrlpts[b+3])/2 );
+ }
+ }
+
+ rs.allpts.push( rs.endX, rs.endY );
+
+ var m, mt;
+ if( rs.edgeType === 'bezier' ){
+ rs.midX = math.qbezierAt( rs.arrowStartX, rs.ctrlpts[0], rs.arrowEndX, 0.5 );
+ rs.midY = math.qbezierAt( rs.arrowStartY, rs.ctrlpts[1], rs.arrowEndY, 0.5 );
+ } else if( rs.ctrlpts.length/2 % 2 === 0 ){
+ m = rs.allpts.length/2 - 1;
+
+ rs.midX = rs.allpts[m];
+ rs.midY = rs.allpts[m+1];
+ } else {
+ m = rs.allpts.length/2 - 3;
+ mt = 0.5;
+
+ rs.midX = math.qbezierAt( rs.allpts[m], rs.allpts[m+2], rs.allpts[m+4], mt );
+ rs.midY = math.qbezierAt( rs.allpts[m+1], rs.allpts[m+3], rs.allpts[m+5], mt );
+ }
+
+ } else if( rs.edgeType === 'straight' ){
+ // need to calc these after endpts
+ rs.allpts = [ rs.startX, rs.startY, rs.endX, rs.endY ];
+
+ // default midpt for labels etc
+ rs.midX = ( rs.arrowStartX + rs.arrowEndX )/2;
+ rs.midY = ( rs.arrowStartY + rs.arrowEndY )/2;
+
+ } else if( rs.edgeType === 'segments' ){
+ rs.allpts = [];
+ rs.allpts.push( rs.startX, rs.startY );
+ rs.allpts.push.apply( rs.allpts, rs.segpts );
+ rs.allpts.push( rs.endX, rs.endY );
+
+ if( rs.segpts.length % 4 === 0 ){
+ var i2 = rs.segpts.length / 2;
+ var i1 = i2 - 2;
+
+ rs.midX = ( rs.segpts[i1] + rs.segpts[i2] ) / 2;
+ rs.midY = ( rs.segpts[i1+1] + rs.segpts[i2+1] ) / 2;
+ } else {
+ var i1 = rs.segpts.length / 2 - 1;
+
+ rs.midX = rs.segpts[i1];
+ rs.midY = rs.segpts[i1+1];
+ }
+
+
+ }
+
+ this.projectLines( edge );
+ this.calculateArrowAngles( edge );
+ this.recalculateEdgeLabelProjection( edge );
+
+ }
+ }
+
+ for( var i = 0; i < haystackEdges.length; i++ ){
+ var edge = haystackEdges[i];
+ var _p = edge._private;
+ var style = _p.style;
+ var rscratch = _p.rscratch;
+ var rs = rscratch;
+
+ if( !rscratch.haystack ){
+ var angle = Math.random() * 2 * Math.PI;
+
+ rscratch.source = {
+ x: Math.cos(angle),
+ y: Math.sin(angle)
+ };
+
+ var angle = Math.random() * 2 * Math.PI;
+
+ rscratch.target = {
+ x: Math.cos(angle),
+ y: Math.sin(angle)
+ };
+
+ }
+
+ var src = _p.source;
+ var tgt = _p.target;
+ var srcPos = src._private.position;
+ var tgtPos = tgt._private.position;
+ var srcW = src.width();
+ var tgtW = tgt.width();
+ var srcH = src.height();
+ var tgtH = tgt.height();
+ var radius = style['haystack-radius'].value;
+ var halfRadius = radius/2; // b/c have to half width/height
+
+ rs.haystackPts = rs.allpts = [
+ rs.source.x * srcW * halfRadius + srcPos.x,
+ rs.source.y * srcH * halfRadius + srcPos.y,
+ rs.target.x * tgtW * halfRadius + tgtPos.x,
+ rs.target.y * tgtH * halfRadius + tgtPos.y
+ ];
+
+ rs.midX = (rs.allpts[0] + rs.allpts[2])/2;
+ rs.midY = (rs.allpts[1] + rs.allpts[3])/2;
+
+ // always override as haystack in case set to different type previously
+ rscratch.edgeType = 'haystack';
+ rscratch.haystack = true;
+
+ this.projectLines( edge );
+ this.calculateArrowAngles( edge );
+ this.recalculateEdgeLabelProjection( edge );
+ }
+
+ for( var i = 0 ; i < autorotateEdges.length; i++ ){
+ var edge = autorotateEdges[i];
+ var rs = edge._private.rscratch;
+
+ rs.labelAngle = Math.atan( rs.midDispY / rs.midDispX );
+ }
+
+ return hashTable;
+};
+
+var getAngleFromDisp = function( dispX, dispY ){
+ return Math.atan2( dispY, dispX ) - Math.PI/2;
+};
+
+BRp.calculateArrowAngles = function( edge ){
+ var rs = edge._private.rscratch;
+ var isHaystack = rs.edgeType === 'haystack';
+ var isMultibezier = rs.edgeType === 'multibezier';
+ var isSegments = rs.edgeType === 'segments';
+ var isCompound = rs.edgeType === 'compound';
+ var isSelf = rs.edgeType === 'self';
+
+ // Displacement gives direction for arrowhead orientation
+ var dispX, dispY;
+ var startX, startY, endX, endY;
+
+ var srcPos = edge.source().position();
+ var tgtPos = edge.target().position();
+
+ if( isHaystack ){
+ startX = rs.haystackPts[0];
+ startY = rs.haystackPts[1];
+ endX = rs.haystackPts[2];
+ endY = rs.haystackPts[3];
+ } else {
+ startX = rs.arrowStartX;
+ startY = rs.arrowStartY;
+ endX = rs.arrowEndX;
+ endY = rs.arrowEndY;
+ }
+
+ // source
+ //
+
+ dispX = srcPos.x - startX;
+ dispY = srcPos.y - startY;
+
+ rs.srcArrowAngle = getAngleFromDisp( dispX, dispY );
+
+ // mid target
+ //
+
+ var midX = rs.midX;
+ var midY = rs.midY;
+
+ if( isHaystack ){
+ midX = ( startX + endX )/2;
+ midY = ( startY + endY )/2;
+ }
+
+ dispX = endX - startX;
+ dispY = endY - startY;
+
+ if( isSelf ){
+ dispX = -1;
+ dispY = 1;
+ } else if( isSegments ){
+ var pts = rs.allpts;
+
+ if( pts.length / 2 % 2 === 0 ){
+ var i2 = pts.length / 2;
+ var i1 = i2 - 2;
+
+ dispX = ( pts[i2] - pts[i1] );
+ dispY = ( pts[i2+1] - pts[i1+1] );
+ } else {
+ var i2 = pts.length / 2 - 1;
+ var i1 = i2 - 2;
+ var i3 = i2 + 2;
+
+ dispX = ( pts[i2] - pts[i1] );
+ dispY = ( pts[i2+1] - pts[i1+1] );
+ }
+ } else if( isMultibezier || isCompound ){
+ var pts = rs.allpts;
+ var cpts = rs.ctrlpts;
+ var bp0x, bp0y;
+ var bp1x, bp1y;
+
+ if( cpts.length / 2 % 2 === 0 ){
+ var p0 = pts.length / 2 - 1; // startpt
+ var ic = p0 + 2;
+ var p1 = ic + 2;
+
+ bp0x = math.qbezierAt( pts[p0], pts[ic], pts[p1], 0.0 );
+ bp0y = math.qbezierAt( pts[p0+1], pts[ic+1], pts[p1+1], 0.0 );
+
+ bp1x = math.qbezierAt( pts[p0], pts[ic], pts[p1], 0.0001 );
+ bp1y = math.qbezierAt( pts[p0+1], pts[ic+1], pts[p1+1], 0.0001 );
+ } else {
+ var ic = pts.length / 2 - 1; // ctrpt
+ var p0 = ic - 2; // startpt
+ var p1 = ic + 2; // endpt
+
+ bp0x = math.qbezierAt( pts[p0], pts[ic], pts[p1], 0.4999 );
+ bp0y = math.qbezierAt( pts[p0+1], pts[ic+1], pts[p1+1], 0.4999 );
+
+ bp1x = math.qbezierAt( pts[p0], pts[ic], pts[p1], 0.5 );
+ bp1y = math.qbezierAt( pts[p0+1], pts[ic+1], pts[p1+1], 0.5 );
+ }
+
+ dispX = ( bp1x - bp0x );
+ dispY = ( bp1y - bp0y );
+ }
+
+ rs.midtgtArrowAngle = getAngleFromDisp( dispX, dispY );
+
+ rs.midDispX = dispX;
+ rs.midDispY = dispY;
+
+ // mid source
+ //
+
+ dispX *= -1;
+ dispY *= -1;
+
+ if( isSegments ){
+ var pts = rs.allpts;
+
+ if( pts.length / 2 % 2 === 0 ){
+ // already ok
+ } else {
+ var i2 = pts.length / 2 - 1;
+ var i3 = i2 + 2;
+
+ dispX = -( pts[i3] - pts[i2] );
+ dispY = -( pts[i3+1] - pts[i2+1] );
+ }
+ }
+
+ rs.midsrcArrowAngle = getAngleFromDisp( dispX, dispY );
+
+ // target
+ //
+
+ dispX = tgtPos.x - endX;
+ dispY = tgtPos.y - endY;
+
+ rs.tgtArrowAngle = getAngleFromDisp( dispX, dispY );
+};
+
+
+BRp.findEndpoints = function( edge ){
+ var r = this;
+ var intersect;
+
+ var source = edge.source()[0];
+ var target = edge.target()[0];
+
+ var src_p = source._private;
+ var tgt_p = target._private;
+
+ var srcPos = src_p.position;
+ var tgtPos = tgt_p.position;
+
+ var tgtArShape = edge._private.style['target-arrow-shape'].value;
+ var srcArShape = edge._private.style['source-arrow-shape'].value;
+
+ var rs = edge._private.rscratch;
+
+ var et = rs.edgeType;
+ var bezier = et === 'bezier' || et === 'multibezier' || et === 'self' || et === 'compound';
+ var multi = et !== 'bezier';
+ var lines = et === 'straight' || et === 'segments';
+ var segments = et === 'segments';
+
+ var p1, p2;
+
+ if( bezier ){
+ var cpStart = [ rs.ctrlpts[0], rs.ctrlpts[1] ];
+ var cpEnd = multi ? [ rs.ctrlpts[rs.ctrlpts.length - 2], rs.ctrlpts[rs.ctrlpts.length - 1] ] : cpStart;
+
+ p1 = cpEnd;
+ p2 = cpStart;
+ } else if( lines ){
+ var srcArrowFromPt = !segments ? [ tgtPos.x, tgtPos.y ] : rs.segpts.slice( 0, 2 );
+ var tgtArrowFromPt = !segments ? [ srcPos.x, srcPos.y ] : rs.segpts.slice( rs.segpts.length - 2 );
+
+ p1 = tgtArrowFromPt;
+ p2 = srcArrowFromPt;
+ }
+
+ intersect = r.nodeShapes[this.getNodeShape(target)].intersectLine(
+ tgtPos.x,
+ tgtPos.y,
+ target.outerWidth(),
+ target.outerHeight(),
+ p1[0],
+ p1[1],
+ 0
+ );
+
+ var arrowEnd = math.shortenIntersection(intersect, p1,
+ r.arrowShapes[tgtArShape].spacing(edge));
+ var edgeEnd = math.shortenIntersection(intersect, p1,
+ r.arrowShapes[tgtArShape].gap(edge));
+
+ rs.endX = edgeEnd[0];
+ rs.endY = edgeEnd[1];
+
+ rs.arrowEndX = arrowEnd[0];
+ rs.arrowEndY = arrowEnd[1];
+
+ intersect = r.nodeShapes[this.getNodeShape(source)].intersectLine(
+ srcPos.x,
+ srcPos.y,
+ source.outerWidth(),
+ source.outerHeight(),
+ p2[0],
+ p2[1],
+ 0
+ );
+
+ var arrowStart = math.shortenIntersection(
+ intersect, p2,
+ r.arrowShapes[srcArShape].spacing(edge)
+ );
+ var edgeStart = math.shortenIntersection(
+ intersect, p2,
+ r.arrowShapes[srcArShape].gap(edge)
+ );
+
+ rs.startX = edgeStart[0];
+ rs.startY = edgeStart[1];
+
+ rs.arrowStartX = arrowStart[0];
+ rs.arrowStartY = arrowStart[1];
+
+ if( lines ){
+ if( !is.number(rs.startX) || !is.number(rs.startY) || !is.number(rs.endX) || !is.number(rs.endY) ){
+ rs.badLine = true;
+ } else {
+ rs.badLine = false;
+ }
+ }
+};
+
+BRp.getArrowWidth = BRp.getArrowHeight = function(edgeWidth) {
+ var cache = this.arrowWidthCache = this.arrowWidthCache || {};
+
+ var cachedVal = cache[edgeWidth];
+ if( cachedVal ){
+ return cachedVal;
+ }
+
+ cachedVal = Math.max(Math.pow(edgeWidth * 13.37, 0.9), 29);
+ cache[edgeWidth] = cachedVal;
+
+ return cachedVal;
+};
+
+module.exports = BRp;
+
+},{"../../../collection/zsort":29,"../../../is":77,"../../../math":79}],57:[function(_dereq_,module,exports){
+'use strict';
+
+var BRp = {};
+
+BRp.getCachedImage = function(url, onLoad) {
+ var r = this;
+ var imageCache = r.imageCache = r.imageCache || {};
+
+ if( imageCache[url] && imageCache[url].image ){
+ return imageCache[url].image;
+ }
+
+ var cache = imageCache[url] = imageCache[url] || {};
+
+ var image = cache.image = new Image();
+ image.addEventListener('load', onLoad);
+ image.src = url;
+
+ return image;
+};
+
+module.exports = BRp;
+
+},{}],58:[function(_dereq_,module,exports){
+'use strict';
+
+var is = _dereq_('../../../is');
+var util = _dereq_('../../../util');
+
+var BaseRenderer = function(){};
+var BR = BaseRenderer;
+var BRp = BR.prototype;
+
+BRp.clientFunctions = [ 'redrawHint', 'render', 'renderTo', 'matchCanvasSize', 'nodeShapeImpl', 'arrowShapeImpl' ];
+
+BRp.init = function( options ){
+ var r = this;
+
+ r.options = options;
+
+ r.cy = options.cy;
+
+ r.container = options.cy.container();
+
+ r.selection = [undefined, undefined, undefined, undefined, 0]; // Coordinates for selection box, plus enabled flag
+
+ //--Pointer-related data
+ r.hoverData = {down: null, last: null,
+ downTime: null, triggerMode: null,
+ dragging: false,
+ initialPan: [null, null], capture: false};
+
+ r.dragData = {possibleDragElements: []};
+
+ r.touchData = {
+ start: null, capture: false,
+
+ // These 3 fields related to tap, taphold events
+ startPosition: [null, null, null, null, null, null],
+ singleTouchStartTime: null,
+ singleTouchMoved: true,
+
+ now: [null, null, null, null, null, null],
+ earlier: [null, null, null, null, null, null]
+ };
+
+ r.redraws = 0;
+ r.showFps = options.showFps;
+
+ r.hideEdgesOnViewport = options.hideEdgesOnViewport;
+ r.hideLabelsOnViewport = options.hideLabelsOnViewport;
+ r.textureOnViewport = options.textureOnViewport;
+ r.wheelSensitivity = options.wheelSensitivity;
+ r.motionBlurEnabled = options.motionBlur; // on by default
+ r.forcedPixelRatio = options.pixelRatio;
+ r.motionBlur = true; // for initial kick off
+ r.motionBlurOpacity = options.motionBlurOpacity;
+ r.motionBlurTransparency = 1 - r.motionBlurOpacity;
+ r.motionBlurPxRatio = 1;
+ r.mbPxRBlurry = 1; //0.8;
+ r.minMbLowQualFrames = 4;
+ r.fullQualityMb = false;
+ r.clearedForMotionBlur = [];
+ r.desktopTapThreshold = options.desktopTapThreshold;
+ r.desktopTapThreshold2 = options.desktopTapThreshold * options.desktopTapThreshold;
+ r.touchTapThreshold = options.touchTapThreshold;
+ r.touchTapThreshold2 = options.touchTapThreshold * options.touchTapThreshold;
+ r.tapholdDuration = 500;
+
+ r.bindings = [];
+
+ r.registerNodeShapes();
+ r.registerArrowShapes();
+ r.load();
+};
+
+BRp.notify = function(params) {
+ var types;
+ var r = this;
+
+ if( is.array( params.type ) ){
+ types = params.type;
+
+ } else {
+ types = [ params.type ];
+ }
+
+ for( var i = 0; i < types.length; i++ ){
+ var type = types[i];
+
+ switch( type ){
+ case 'destroy':
+ r.destroy();
+ return;
+
+ case 'add':
+ case 'remove':
+ case 'load':
+ r.updateElementsCache();
+ break;
+
+ case 'viewport':
+ r.redrawHint('select', true);
+ break;
+
+ case 'style':
+ r.updateCachedZSortedEles();
+ break;
+ }
+
+ if( type === 'load' || type === 'resize' ){
+ r.invalidateContainerClientCoordsCache();
+ r.matchCanvasSize(r.container);
+ }
+ } // for
+
+ r.redrawHint('eles', true);
+ r.redrawHint('drag', true);
+
+ this.startRenderLoop();
+
+ this.redraw();
+};
+
+BRp.destroy = function(){
+ this.destroyed = true;
+
+ this.cy.stopAnimationLoop();
+
+ for( var i = 0; i < this.bindings.length; i++ ){
+ var binding = this.bindings[i];
+ var b = binding;
+
+ b.target.removeEventListener(b.event, b.handler, b.useCapture);
+ }
+
+ if( this.removeObserver ){
+ this.removeObserver.disconnect();
+ }
+
+ if( this.labelCalcDiv ){
+ try{
+ document.body.removeChild(this.labelCalcDiv);
+ } catch(e){
+ // ie10 issue #1014
+ }
+ }
+};
+
+[
+ _dereq_('./arrow-shapes'),
+ _dereq_('./cached-eles'),
+ _dereq_('./coord-ele-math'),
+ _dereq_('./images'),
+ _dereq_('./load-listeners'),
+ _dereq_('./node-shapes'),
+ _dereq_('./redraw')
+].forEach(function( props ){
+ util.extend( BRp, props );
+});
+
+module.exports = BR;
+
+},{"../../../is":77,"../../../util":94,"./arrow-shapes":54,"./cached-eles":55,"./coord-ele-math":56,"./images":57,"./load-listeners":59,"./node-shapes":60,"./redraw":61}],59:[function(_dereq_,module,exports){
+'use strict';
+
+var is = _dereq_('../../../is');
+var util = _dereq_('../../../util');
+var Event = _dereq_('../../../event');
+var Collection = _dereq_('../../../collection');
+
+var BRp = {};
+
+BRp.registerBinding = function(target, event, handler, useCapture){
+ this.bindings.push({
+ target: target,
+ event: event,
+ handler: handler,
+ useCapture: useCapture
+ });
+
+ target.addEventListener(event, handler, useCapture);
+};
+
+BRp.nodeIsDraggable = function(node) {
+ if (node._private.style['opacity'].value !== 0
+ && node._private.style['visibility'].value == 'visible'
+ && node._private.style['display'].value == 'element'
+ && !node.locked()
+ && node.grabbable() ) {
+
+ return true;
+ }
+
+ return false;
+};
+
+BRp.load = function() {
+ var r = this;
+
+ var triggerEvents = function( target, names, e, props ){
+ if( target == null ){
+ target = r.cy;
+ }
+
+ for( var i = 0; i < names.length; i++ ){
+ var name = names[i];
+
+ var event = Event( e, util.extend({ type: name }, props) );
+ target.trigger( event );
+ }
+ };
+
+ var isMultSelKeyDown = function( e ){
+ return e.shiftKey || e.metaKey || e.ctrlKey; // maybe e.altKey
+ };
+
+ var getDragListIds = function(opts){
+ var listHasId;
+
+ if( opts.addToList && r.cy.hasCompoundNodes() ){ // only needed for compound graphs
+ if( !opts.addToList.hasId ){ // build ids lookup if doesn't already exist
+ opts.addToList.hasId = {};
+
+ for( var i = 0; i < opts.addToList.length; i++ ){
+ var ele = opts.addToList[i];
+
+ opts.addToList.hasId[ ele.id() ] = true;
+ }
+ }
+
+ listHasId = opts.addToList.hasId;
+ }
+
+ return listHasId || {};
+ };
+
+ // helper function to determine which child nodes and inner edges
+ // of a compound node to be dragged as well as the grabbed and selected nodes
+ var addDescendantsToDrag = function(node, opts){
+ if( !node._private.cy.hasCompoundNodes() ){
+ return;
+ }
+
+ if( opts.inDragLayer == null && opts.addToList == null ){ return; } // nothing to do
+
+ var listHasId = getDragListIds( opts );
+
+ var innerNodes = node.descendants();
+
+ for( var i = 0; i < innerNodes.size(); i++ ){
+ var iNode = innerNodes[i];
+ var _p = iNode._private;
+
+ if( opts.inDragLayer ){
+ _p.rscratch.inDragLayer = true;
+ }
+
+ if( opts.addToList && !listHasId[ iNode.id() ] ){
+ opts.addToList.push( iNode );
+ listHasId[ iNode.id() ] = true;
+
+ _p.grabbed = true;
+ }
+
+ var edges = _p.edges;
+ for( var j = 0; opts.inDragLayer && j < edges.length; j++ ){
+ edges[j]._private.rscratch.inDragLayer = true;
+ }
+ }
+ };
+
+ // adds the given nodes, and its edges to the drag layer
+ var addNodeToDrag = function(node, opts){
+
+ var _p = node._private;
+ var listHasId = getDragListIds( opts );
+
+ if( opts.inDragLayer ){
+ _p.rscratch.inDragLayer = true;
+ }
+
+ if( opts.addToList && !listHasId[ node.id() ] ){
+ opts.addToList.push( node );
+ listHasId[ node.id() ] = true;
+
+ _p.grabbed = true;
+ }
+
+ var edges = _p.edges;
+ for( var i = 0; opts.inDragLayer && i < edges.length; i++ ){
+ edges[i]._private.rscratch.inDragLayer = true;
+ }
+
+ addDescendantsToDrag( node, opts ); // always add to drag
+
+ // also add nodes and edges related to the topmost ancestor
+ updateAncestorsInDragLayer( node, {
+ inDragLayer: opts.inDragLayer
+ } );
+ };
+
+ var freeDraggedElements = function( draggedElements ){
+ if( !draggedElements ){ return; }
+
+ for (var i=0; i < draggedElements.length; i++) {
+
+ var dEi_p = draggedElements[i]._private;
+
+ if(dEi_p.group === 'nodes') {
+ dEi_p.rscratch.inDragLayer = false;
+ dEi_p.grabbed = false;
+
+ var sEdges = dEi_p.edges;
+ for( var j = 0; j < sEdges.length; j++ ){ sEdges[j]._private.rscratch.inDragLayer = false; }
+
+ // for compound nodes, also remove related nodes and edges from the drag layer
+ updateAncestorsInDragLayer(draggedElements[i], { inDragLayer: false });
+
+ } else if( dEi_p.group === 'edges' ){
+ dEi_p.rscratch.inDragLayer = false;
+ }
+
+ }
+ };
+
+ // helper function to determine which ancestor nodes and edges should go
+ // to the drag layer (or should be removed from drag layer).
+ var updateAncestorsInDragLayer = function(node, opts) {
+
+ if( opts.inDragLayer == null && opts.addToList == null ){ return; } // nothing to do
+
+ // find top-level parent
+ var parent = node;
+
+ if( !node._private.cy.hasCompoundNodes() ){
+ return;
+ }
+
+ while( parent.parent().nonempty() ){
+ parent = parent.parent()[0];
+ }
+
+ // no parent node: no nodes to add to the drag layer
+ if( parent == node ){
+ return;
+ }
+
+ var nodes = parent.descendants()
+ .merge( parent )
+ .unmerge( node )
+ .unmerge( node.descendants() )
+ ;
+
+ var edges = nodes.connectedEdges();
+
+ var listHasId = getDragListIds( opts );
+
+ for( var i = 0; i < nodes.size(); i++ ){
+ if( opts.inDragLayer !== undefined ){
+ nodes[i]._private.rscratch.inDragLayer = opts.inDragLayer;
+ }
+
+ if( opts.addToList && !listHasId[ nodes[i].id() ] ){
+ opts.addToList.push( nodes[i] );
+ listHasId[ nodes[i].id() ] = true;
+
+ nodes[i]._private.grabbed = true;
+ }
+ }
+
+ for( var j = 0; opts.inDragLayer !== undefined && j < edges.length; j++ ) {
+ edges[j]._private.rscratch.inDragLayer = opts.inDragLayer;
+ }
+ };
+
+ if( typeof MutationObserver !== 'undefined' ){
+ r.removeObserver = new MutationObserver(function( mutns ){
+ for( var i = 0; i < mutns.length; i++ ){
+ var mutn = mutns[i];
+ var rNodes = mutn.removedNodes;
+
+ if( rNodes ){ for( var j = 0; j < rNodes.length; j++ ){
+ var rNode = rNodes[j];
+
+ if( rNode === r.container ){
+ r.destroy();
+ break;
+ }
+ } }
+ }
+ });
+
+ if( r.container.parentNode ){
+ r.removeObserver.observe( r.container.parentNode, { childList: true } );
+ }
+ } else {
+ r.registerBinding(r.container, 'DOMNodeRemoved', function(e){
+ r.destroy();
+ });
+ }
+
+
+
+ // auto resize
+ r.registerBinding(window, 'resize', util.debounce( function(e) {
+ r.invalidateContainerClientCoordsCache();
+
+ r.matchCanvasSize(r.container);
+ r.redrawHint('eles', true);
+ r.redraw();
+ }, 100 ) );
+
+ var invalCtnrBBOnScroll = function(domEle){
+ r.registerBinding(domEle, 'scroll', function(e){
+ r.invalidateContainerClientCoordsCache();
+ } );
+ };
+
+ var bbCtnr = r.cy.container();
+
+ for( ;; ){
+
+ invalCtnrBBOnScroll( bbCtnr );
+
+ if( bbCtnr.parentNode ){
+ bbCtnr = bbCtnr.parentNode;
+ } else {
+ break;
+ }
+
+ }
+
+ // stop right click menu from appearing on cy
+ r.registerBinding(r.container, 'contextmenu', function(e){
+ e.preventDefault();
+ });
+
+ var inBoxSelection = function(){
+ return r.selection[4] !== 0;
+ };
+
+ // Primary key
+ r.registerBinding(r.container, 'mousedown', function(e) {
+ e.preventDefault();
+ r.hoverData.capture = true;
+ r.hoverData.which = e.which;
+
+ var cy = r.cy;
+ var pos = r.projectIntoViewport(e.clientX, e.clientY);
+ var select = r.selection;
+ var near = r.findNearestElement(pos[0], pos[1], true, false);
+ var draggedElements = r.dragData.possibleDragElements;
+
+ r.hoverData.mdownPos = pos;
+
+ var checkForTaphold = function(){
+ r.hoverData.tapholdCancelled = false;
+
+ clearTimeout( r.hoverData.tapholdTimeout );
+
+ r.hoverData.tapholdTimeout = setTimeout(function(){
+
+ if( r.hoverData.tapholdCancelled ){
+ return;
+ } else {
+ var ele = r.hoverData.down;
+
+ if( ele ){
+ ele.trigger( Event(e, {
+ type: 'taphold',
+ cyPosition: { x: pos[0], y: pos[1] }
+ }) );
+ } else {
+ cy.trigger( Event(e, {
+ type: 'taphold',
+ cyPosition: { x: pos[0], y: pos[1] }
+ }) );
+ }
+ }
+
+ }, r.tapholdDuration);
+ };
+
+ // Right click button
+ if( e.which == 3 ){
+
+ r.hoverData.cxtStarted = true;
+
+ var cxtEvt = Event(e, {
+ type: 'cxttapstart',
+ cyPosition: { x: pos[0], y: pos[1] }
+ });
+
+ if( near ){
+ near.activate();
+ near.trigger( cxtEvt );
+
+ r.hoverData.down = near;
+ } else {
+ cy.trigger( cxtEvt );
+ }
+
+ r.hoverData.downTime = (new Date()).getTime();
+ r.hoverData.cxtDragged = false;
+
+ // Primary button
+ } else if (e.which == 1) {
+
+ if( near ){
+ near.activate();
+ }
+
+ // Element dragging
+ {
+ // If something is under the cursor and it is draggable, prepare to grab it
+ if (near != null) {
+
+ if( r.nodeIsDraggable(near) ){
+
+ var grabEvent = Event(e, {
+ type: 'grab',
+ cyPosition: { x: pos[0], y: pos[1] }
+ });
+
+ if ( near.isNode() && !near.selected() ){
+
+ draggedElements = r.dragData.possibleDragElements = [];
+ addNodeToDrag( near, { addToList: draggedElements } );
+
+ near.trigger(grabEvent);
+
+ } else if ( near.isNode() && near.selected() ){
+ draggedElements = r.dragData.possibleDragElements = [ ];
+
+ var selectedNodes = cy.$(function(){ return this.isNode() && this.selected(); });
+
+ for( var i = 0; i < selectedNodes.length; i++ ){
+
+ // Only add this selected node to drag if it is draggable, eg. has nonzero opacity
+ if( r.nodeIsDraggable( selectedNodes[i] ) ){
+ addNodeToDrag( selectedNodes[i], { addToList: draggedElements } );
+ }
+ }
+
+ near.trigger( grabEvent );
+ }
+
+ r.redrawHint('eles', true);
+ r.redrawHint('drag', true);
+
+ }
+
+ }
+
+ r.hoverData.down = near;
+ r.hoverData.downTime = (new Date()).getTime();
+ }
+
+ triggerEvents( near, ['mousedown', 'tapstart', 'vmousedown'], e, {
+ cyPosition: { x: pos[0], y: pos[1] }
+ } );
+
+ if ( near == null ) {
+ select[4] = 1;
+
+ r.data.bgActivePosistion = {
+ x: pos[0],
+ y: pos[1]
+ };
+
+ r.redrawHint('select', true);
+
+ r.redraw();
+ } else if( near.isEdge() ){
+ select[4] = 1; // for future pan
+ }
+
+ checkForTaphold();
+
+ }
+
+ // Initialize selection box coordinates
+ select[0] = select[2] = pos[0];
+ select[1] = select[3] = pos[1];
+
+ }, false);
+
+ r.registerBinding(window, 'mousemove', function(e) {
+ var preventDefault = false;
+ var capture = r.hoverData.capture;
+
+ // save cycles if mouse events aren't to be captured
+ if ( !capture ){
+ var containerPageCoords = r.findContainerClientCoords();
+
+ if (e.clientX > containerPageCoords[0] && e.clientX < containerPageCoords[0] + r.canvasWidth
+ && e.clientY > containerPageCoords[1] && e.clientY < containerPageCoords[1] + r.canvasHeight
+ ) {
+ // inside container bounds so OK
+ } else {
+ return;
+ }
+
+ var cyContainer = r.container;
+ var target = e.target;
+ var tParent = target.parentNode;
+ var containerIsTarget = false;
+
+ while( tParent ){
+ if( tParent === cyContainer ){
+ containerIsTarget = true;
+ break;
+ }
+
+ tParent = tParent.parentNode;
+ }
+
+ if( !containerIsTarget ){ return; } // if target is outisde cy container, then this event is not for us
+ }
+
+ var cy = r.cy;
+ var zoom = cy.zoom();
+ var pos = r.projectIntoViewport(e.clientX, e.clientY);
+ var select = r.selection;
+
+ var near = null;
+ if( !r.hoverData.draggingEles ){
+ near = r.findNearestElement(pos[0], pos[1], true, false);
+ }
+ var last = r.hoverData.last;
+ var down = r.hoverData.down;
+
+ var disp = [pos[0] - select[2], pos[1] - select[3]];
+
+ var draggedElements = r.dragData.possibleDragElements;
+
+ var dx = select[2] - select[0];
+ var dx2 = dx * dx;
+ var dy = select[3] - select[1];
+ var dy2 = dy * dy;
+ var dist2 = dx2 + dy2;
+ var rdist2 = dist2 * zoom * zoom;
+
+ var multSelKeyDown = isMultSelKeyDown( e );
+
+ r.hoverData.tapholdCancelled = true;
+
+ var updateDragDelta = function(){
+ var dragDelta = r.hoverData.dragDelta = r.hoverData.dragDelta || [];
+
+ if( dragDelta.length === 0 ){
+ dragDelta.push( disp[0] );
+ dragDelta.push( disp[1] );
+ } else {
+ dragDelta[0] += disp[0];
+ dragDelta[1] += disp[1];
+ }
+ };
+
+
+ preventDefault = true;
+
+ triggerEvents( near, ['mousemove', 'vmousemove', 'tapdrag'], e, {
+ cyPosition: { x: pos[0], y: pos[1] }
+ } );
+
+ // trigger context drag if rmouse down
+ if( r.hoverData.which === 3 ){
+ var cxtEvt = Event(e, {
+ type: 'cxtdrag',
+ cyPosition: { x: pos[0], y: pos[1] }
+ });
+
+ if( down ){
+ down.trigger( cxtEvt );
+ } else {
+ cy.trigger( cxtEvt );
+ }
+
+ r.hoverData.cxtDragged = true;
+
+ if( !r.hoverData.cxtOver || near !== r.hoverData.cxtOver ){
+
+ if( r.hoverData.cxtOver ){
+ r.hoverData.cxtOver.trigger( Event(e, {
+ type: 'cxtdragout',
+ cyPosition: { x: pos[0], y: pos[1] }
+ }) );
+ }
+
+ r.hoverData.cxtOver = near;
+
+ if( near ){
+ near.trigger( Event(e, {
+ type: 'cxtdragover',
+ cyPosition: { x: pos[0], y: pos[1] }
+ }) );
+ }
+
+ }
+
+ // Check if we are drag panning the entire graph
+ } else if (r.hoverData.dragging) {
+ preventDefault = true;
+
+ if( cy.panningEnabled() && cy.userPanningEnabled() ){
+ var deltaP;
+
+ if( r.hoverData.justStartedPan ){
+ var mdPos = r.hoverData.mdownPos;
+
+ deltaP = {
+ x: ( pos[0] - mdPos[0] ) * zoom,
+ y: ( pos[1] - mdPos[1] ) * zoom
+ };
+
+ r.hoverData.justStartedPan = false;
+
+ } else {
+ deltaP = {
+ x: disp[0] * zoom,
+ y: disp[1] * zoom
+ };
+
+ }
+
+ cy.panBy( deltaP );
+
+ r.hoverData.dragged = true;
+ }
+
+ // Needs reproject due to pan changing viewport
+ pos = r.projectIntoViewport(e.clientX, e.clientY);
+
+ // Checks primary button down & out of time & mouse not moved much
+ } else if(
+ select[4] == 1 && (down == null || down.isEdge())
+ ){
+
+ if( !r.hoverData.dragging && cy.boxSelectionEnabled() && ( multSelKeyDown || !cy.panningEnabled() || !cy.userPanningEnabled() ) ){
+ r.data.bgActivePosistion = undefined;
+ r.hoverData.selecting = true;
+
+ r.redrawHint('select', true);
+ r.redraw();
+
+ } else if( !r.hoverData.selecting && cy.panningEnabled() && cy.userPanningEnabled() ){
+ r.hoverData.dragging = true;
+ r.hoverData.justStartedPan = true;
+ select[4] = 0;
+
+ r.data.bgActivePosistion = {
+ x: pos[0],
+ y: pos[1]
+ };
+
+ r.redrawHint('select', true);
+ r.redraw();
+ }
+
+ if( down && down.isEdge() && down.active() ){ down.unactivate(); }
+
+ } else {
+ if( down && down.isEdge() && down.active() ){ down.unactivate(); }
+
+ if (near != last) {
+
+ if (last) {
+ triggerEvents( last, ['mouseout', 'tapdragout'], e, {
+ cyPosition: { x: pos[0], y: pos[1] }
+ } );
+ }
+
+ if (near) {
+ triggerEvents( near, ['mouseover', 'tapdragover'], e, {
+ cyPosition: { x: pos[0], y: pos[1] }
+ } );
+ }
+
+ r.hoverData.last = near;
+ }
+
+ if( down && down.isNode() && r.nodeIsDraggable(down) ){
+
+ if( rdist2 >= r.desktopTapThreshold2 ){ // then drag
+
+ var justStartedDrag = !r.dragData.didDrag;
+
+ if( justStartedDrag ) {
+ r.redrawHint('eles', true);
+ }
+
+ r.dragData.didDrag = true; // indicate that we actually did drag the node
+
+ var toTrigger = [];
+
+ for( var i = 0; i < draggedElements.length; i++ ){
+ var dEle = draggedElements[i];
+
+ // now, add the elements to the drag layer if not done already
+ if( !r.hoverData.draggingEles ){
+ addNodeToDrag( dEle, { inDragLayer: true } );
+ }
+
+ // Locked nodes not draggable, as well as non-visible nodes
+ if( dEle.isNode() && r.nodeIsDraggable(dEle) && dEle.grabbed() ){
+ var dPos = dEle._private.position;
+
+ toTrigger.push( dEle );
+
+ if( is.number(disp[0]) && is.number(disp[1]) ){
+ var updatePos = !dEle.isParent();
+
+ if( updatePos ){
+ dPos.x += disp[0];
+ dPos.y += disp[1];
+ }
+
+ if( justStartedDrag ){
+ var dragDelta = r.hoverData.dragDelta;
+
+ if( updatePos && is.number(dragDelta[0]) && is.number(dragDelta[1]) ){
+ dPos.x += dragDelta[0];
+ dPos.y += dragDelta[1];
+ }
+ }
+ }
+
+ }
+ }
+
+ r.hoverData.draggingEles = true;
+
+ var tcol = (Collection(cy, toTrigger));
+
+ tcol.updateCompoundBounds();
+ tcol.trigger('position drag');
+
+ r.redrawHint('drag', true);
+ r.redraw();
+
+ } else { // otherwise save drag delta for when we actually start dragging so the relative grab pos is constant
+ updateDragDelta();
+ }
+ }
+
+ // prevent the dragging from triggering text selection on the page
+ preventDefault = true;
+ }
+
+ select[2] = pos[0]; select[3] = pos[1];
+
+ if( preventDefault ){
+ if(e.stopPropagation) e.stopPropagation();
+ if(e.preventDefault) e.preventDefault();
+ return false;
+ }
+ }, false);
+
+ r.registerBinding(window, 'mouseup', function(e) {
+ var capture = r.hoverData.capture;
+ if (!capture) { return; }
+ r.hoverData.capture = false;
+
+ var cy = r.cy; var pos = r.projectIntoViewport(e.clientX, e.clientY); var select = r.selection;
+ var near = r.findNearestElement(pos[0], pos[1], true, false);
+ var draggedElements = r.dragData.possibleDragElements; var down = r.hoverData.down;
+ var multSelKeyDown = isMultSelKeyDown( e );
+
+ if( r.data.bgActivePosistion ){
+ r.redrawHint('select', true);
+ r.redraw();
+ }
+
+ r.hoverData.tapholdCancelled = true;
+
+ r.data.bgActivePosistion = undefined; // not active bg now
+
+ if( down ){
+ down.unactivate();
+ }
+
+ if( r.hoverData.which === 3 ){
+ var cxtEvt = Event(e, {
+ type: 'cxttapend',
+ cyPosition: { x: pos[0], y: pos[1] }
+ });
+
+ if( down ){
+ down.trigger( cxtEvt );
+ } else {
+ cy.trigger( cxtEvt );
+ }
+
+ if( !r.hoverData.cxtDragged ){
+ var cxtTap = Event(e, {
+ type: 'cxttap',
+ cyPosition: { x: pos[0], y: pos[1] }
+ });
+
+ if( down ){
+ down.trigger( cxtTap );
+ } else {
+ cy.trigger( cxtTap );
+ }
+ }
+
+ r.hoverData.cxtDragged = false;
+ r.hoverData.which = null;
+
+ } else if( r.hoverData.which === 1 ) {
+
+ // Deselect all elements if nothing is currently under the mouse cursor and we aren't dragging something
+ if ( (down == null) // not mousedown on node
+ && !r.dragData.didDrag // didn't move the node around
+ && !r.hoverData.selecting // not box selection
+ && !r.hoverData.dragged // didn't pan
+ && !isMultSelKeyDown( e )
+ ) {
+
+ cy.$(function(){
+ return this.selected();
+ }).unselect();
+
+ if (draggedElements.length > 0) {
+ r.redrawHint('eles', true);
+ }
+
+ r.dragData.possibleDragElements = draggedElements = [];
+ }
+
+ triggerEvents( near, ['mouseup', 'tapend', 'vmouseup'], e, {
+ cyPosition: { x: pos[0], y: pos[1] }
+ } );
+
+ if(
+ !r.dragData.didDrag // didn't move a node around
+ && !r.hoverData.dragged // didn't pan
+ ){
+ triggerEvents( near, ['click', 'tap', 'vclick'], e, {
+ cyPosition: { x: pos[0], y: pos[1] }
+ } );
+ }
+
+ // Single selection
+ if( near == down && !r.dragData.didDrag && !r.hoverData.selecting ){
+ if( near != null && near._private.selectable ){
+
+ if( r.hoverData.dragging ){
+ // if panning, don't change selection state
+ } else if( cy.selectionType() === 'additive' || multSelKeyDown ){
+ if( near.selected() ){
+ near.unselect();
+ } else {
+ near.select();
+ }
+ } else {
+ if( !multSelKeyDown ){
+ cy.$(':selected').unmerge( near ).unselect();
+ near.select();
+ }
+ }
+
+ r.redrawHint('eles', true);
+ }
+ }
+
+ if ( r.hoverData.selecting ) {
+ var newlySelected = [];
+ var box = r.getAllInBox( select[0], select[1], select[2], select[3] );
+
+ r.redrawHint('select', true);
+
+ if( box.length > 0 ) {
+ r.redrawHint('eles', true);
+ }
+
+ for( var i = 0; i < box.length; i++ ){
+ if( box[i]._private.selectable ){
+ newlySelected.push( box[i] );
+ }
+ }
+
+ var newlySelCol = Collection( cy, newlySelected );
+
+ if( cy.selectionType() === 'additive' ){
+ newlySelCol.select();
+ } else {
+ if( !multSelKeyDown ){
+ cy.$(':selected').unmerge( newlySelCol ).unselect();
+ }
+
+ newlySelCol.select();
+ }
+
+ // always need redraw in case eles unselectable
+ r.redraw();
+
+ }
+
+ // Cancel drag pan
+ if( r.hoverData.dragging ){
+ r.hoverData.dragging = false;
+
+ r.redrawHint('select', true);
+ r.redrawHint('eles', true);
+
+ r.redraw();
+ }
+
+ if (!select[4]) {
+
+
+ r.redrawHint('drag', true);
+ r.redrawHint('eles', true);
+
+ freeDraggedElements( draggedElements );
+
+ if( down ){ down.trigger('free'); }
+ }
+
+ } // else not right mouse
+
+ select[4] = 0; r.hoverData.down = null;
+
+ r.hoverData.cxtStarted = false;
+ r.hoverData.draggingEles = false;
+ r.hoverData.selecting = false;
+ r.dragData.didDrag = false;
+ r.hoverData.dragged = false;
+ r.hoverData.dragDelta = [];
+
+ }, false);
+
+ var wheelHandler = function(e) {
+
+
+ if( r.scrollingPage ){ return; } // while scrolling, ignore wheel-to-zoom
+
+ var cy = r.cy;
+ var pos = r.projectIntoViewport(e.clientX, e.clientY);
+ var rpos = [pos[0] * cy.zoom() + cy.pan().x,
+ pos[1] * cy.zoom() + cy.pan().y];
+
+ if( r.hoverData.draggingEles || r.hoverData.dragging || r.hoverData.cxtStarted || inBoxSelection() ){ // if pan dragging or cxt dragging, wheel movements make no zoom
+ e.preventDefault();
+ return;
+ }
+
+ if( cy.panningEnabled() && cy.userPanningEnabled() && cy.zoomingEnabled() && cy.userZoomingEnabled() ){
+ e.preventDefault();
+
+ r.data.wheelZooming = true;
+ clearTimeout( r.data.wheelTimeout );
+ r.data.wheelTimeout = setTimeout(function(){
+ r.data.wheelZooming = false;
+
+ r.redrawHint('eles', true);
+ r.redraw();
+ }, 150);
+
+ var diff = e.deltaY / -250 || e.wheelDeltaY / 1000 || e.wheelDelta / 1000;
+ diff = diff * r.wheelSensitivity;
+
+ var needsWheelFix = e.deltaMode === 1;
+ if( needsWheelFix ){ // fixes slow wheel events on ff/linux and ff/windows
+ diff *= 33;
+ }
+
+ cy.zoom({
+ level: cy.zoom() * Math.pow(10, diff),
+ renderedPosition: { x: rpos[0], y: rpos[1] }
+ });
+ }
+
+ };
+
+ // Functions to help with whether mouse wheel should trigger zooming
+ // --
+ r.registerBinding(r.container, 'wheel', wheelHandler, true);
+
+ // disable nonstandard wheel events
+ // r.registerBinding(r.container, 'mousewheel', wheelHandler, true);
+ // r.registerBinding(r.container, 'DOMMouseScroll', wheelHandler, true);
+ // r.registerBinding(r.container, 'MozMousePixelScroll', wheelHandler, true); // older firefox
+
+ r.registerBinding(window, 'scroll', function(e){
+ r.scrollingPage = true;
+
+ clearTimeout( r.scrollingPageTimeout );
+ r.scrollingPageTimeout = setTimeout(function(){
+ r.scrollingPage = false;
+ }, 250);
+ }, true);
+
+ // Functions to help with handling mouseout/mouseover on the Cytoscape container
+ // Handle mouseout on Cytoscape container
+ r.registerBinding(r.container, 'mouseout', function(e) {
+ var pos = r.projectIntoViewport(e.clientX, e.clientY);
+
+ r.cy.trigger(Event(e, {
+ type: 'mouseout',
+ cyPosition: { x: pos[0], y: pos[1] }
+ }));
+ }, false);
+
+ r.registerBinding(r.container, 'mouseover', function(e) {
+ var pos = r.projectIntoViewport(e.clientX, e.clientY);
+
+ r.cy.trigger(Event(e, {
+ type: 'mouseover',
+ cyPosition: { x: pos[0], y: pos[1] }
+ }));
+ }, false);
+
+ var f1x1, f1y1, f2x1, f2y1; // starting points for pinch-to-zoom
+ var distance1, distance1Sq; // initial distance between finger 1 and finger 2 for pinch-to-zoom
+ var center1, modelCenter1; // center point on start pinch to zoom
+ var offsetLeft, offsetTop;
+ var containerWidth, containerHeight;
+ var twoFingersStartInside;
+
+ var distance = function(x1, y1, x2, y2){
+ return Math.sqrt( (x2-x1)*(x2-x1) + (y2-y1)*(y2-y1) );
+ };
+
+ var distanceSq = function(x1, y1, x2, y2){
+ return (x2-x1)*(x2-x1) + (y2-y1)*(y2-y1);
+ };
+
+ var touchstartHandler;
+ r.registerBinding(r.container, 'touchstart', touchstartHandler = function(e) {
+ r.touchData.capture = true;
+ r.data.bgActivePosistion = undefined;
+
+ var cy = r.cy;
+ var nodes = r.getCachedNodes();
+ var edges = r.getCachedEdges();
+ var now = r.touchData.now;
+ var earlier = r.touchData.earlier;
+
+ if (e.touches[0]) { var pos = r.projectIntoViewport(e.touches[0].clientX, e.touches[0].clientY); now[0] = pos[0]; now[1] = pos[1]; }
+ if (e.touches[1]) { var pos = r.projectIntoViewport(e.touches[1].clientX, e.touches[1].clientY); now[2] = pos[0]; now[3] = pos[1]; }
+ if (e.touches[2]) { var pos = r.projectIntoViewport(e.touches[2].clientX, e.touches[2].clientY); now[4] = pos[0]; now[5] = pos[1]; }
+
+
+ // record starting points for pinch-to-zoom
+ if( e.touches[1] ){
+
+ // anything in the set of dragged eles should be released
+ var release = function( eles ){
+ for( var i = 0; i < eles.length; i++ ){
+ eles[i]._private.grabbed = false;
+ eles[i]._private.rscratch.inDragLayer = false;
+ if( eles[i].active() ){ eles[i].unactivate(); }
+ }
+ };
+ release(nodes);
+ release(edges);
+
+ var offsets = r.findContainerClientCoords();
+ offsetLeft = offsets[0];
+ offsetTop = offsets[1];
+ containerWidth = offsets[2];
+ containerHeight = offsets[3];
+
+ f1x1 = e.touches[0].clientX - offsetLeft;
+ f1y1 = e.touches[0].clientY - offsetTop;
+
+ f2x1 = e.touches[1].clientX - offsetLeft;
+ f2y1 = e.touches[1].clientY - offsetTop;
+
+ twoFingersStartInside =
+ 0 <= f1x1 && f1x1 <= containerWidth
+ && 0 <= f2x1 && f2x1 <= containerWidth
+ && 0 <= f1y1 && f1y1 <= containerHeight
+ && 0 <= f2y1 && f2y1 <= containerHeight
+ ;
+
+ var pan = cy.pan();
+ var zoom = cy.zoom();
+
+ distance1 = distance( f1x1, f1y1, f2x1, f2y1 );
+ distance1Sq = distanceSq( f1x1, f1y1, f2x1, f2y1 );
+ center1 = [ (f1x1 + f2x1)/2, (f1y1 + f2y1)/2 ];
+ modelCenter1 = [
+ (center1[0] - pan.x) / zoom,
+ (center1[1] - pan.y) / zoom
+ ];
+
+ // consider context tap
+ var cxtDistThreshold = 200;
+ var cxtDistThresholdSq = cxtDistThreshold * cxtDistThreshold;
+ if( distance1Sq < cxtDistThresholdSq && !e.touches[2] ){
+
+ var near1 = r.findNearestElement(now[0], now[1], true, true);
+ var near2 = r.findNearestElement(now[2], now[3], true, true);
+
+ if( near1 && near1.isNode() ){
+ near1.activate().trigger( Event(e, {
+ type: 'cxttapstart',
+ cyPosition: { x: now[0], y: now[1] }
+ }) );
+ r.touchData.start = near1;
+
+ } else if( near2 && near2.isNode() ){
+ near2.activate().trigger( Event(e, {
+ type: 'cxttapstart',
+ cyPosition: { x: now[0], y: now[1] }
+ }) );
+ r.touchData.start = near2;
+
+ } else {
+ cy.trigger( Event(e, {
+ type: 'cxttapstart',
+ cyPosition: { x: now[0], y: now[1] }
+ }) );
+ r.touchData.start = null;
+ }
+
+ if( r.touchData.start ){ r.touchData.start._private.grabbed = false; }
+ r.touchData.cxt = true;
+ r.touchData.cxtDragged = false;
+ r.data.bgActivePosistion = undefined;
+
+ r.redraw();
+ return;
+
+ }
+
+ }
+
+ if (e.touches[2]) {
+
+ } else if (e.touches[1]) {
+
+ } else if (e.touches[0]) {
+ var near = r.findNearestElement(now[0], now[1], true, true);
+
+ if (near != null) {
+ near.activate();
+
+ r.touchData.start = near;
+
+ if( near.isNode() && r.nodeIsDraggable(near) ){
+
+ var draggedEles = r.dragData.touchDragEles = [];
+
+ r.redrawHint('eles', true);
+ r.redrawHint('drag', true);
+
+ if( near.selected() ){
+ // reset drag elements, since near will be added again
+
+ var selectedNodes = cy.$(function(){
+ return this.isNode() && this.selected();
+ });
+
+ for( var k = 0; k < selectedNodes.length; k++ ){
+ var selectedNode = selectedNodes[k];
+
+ if( r.nodeIsDraggable(selectedNode) ){
+ addNodeToDrag( selectedNode, { addToList: draggedEles } );
+ }
+ }
+ } else {
+ addNodeToDrag( near, { addToList: draggedEles } );
+ }
+
+ near.trigger( Event(e, {
+ type: 'grab',
+ cyPosition: { x: now[0], y: now[1] }
+ }) );
+ }
+ }
+
+ triggerEvents( near, ['touchstart', 'tapstart', 'vmousedown'], e, {
+ cyPosition: { x: now[0], y: now[1] }
+ } );
+
+ if (near == null) {
+ r.data.bgActivePosistion = {
+ x: pos[0],
+ y: pos[1]
+ };
+
+ r.redrawHint('select', true);
+ r.redraw();
+ }
+
+
+ // Tap, taphold
+ // -----
+
+ for (var i=0; i<now.length; i++) {
+ earlier[i] = now[i];
+ r.touchData.startPosition[i] = now[i];
+ }
+
+ r.touchData.singleTouchMoved = false;
+ r.touchData.singleTouchStartTime = +new Date();
+
+ clearTimeout( r.touchData.tapholdTimeout );
+ r.touchData.tapholdTimeout = setTimeout(function() {
+ if(
+ r.touchData.singleTouchMoved === false
+ && !r.pinching // if pinching, then taphold unselect shouldn't take effect
+ ){
+ triggerEvents( r.touchData.start, ['taphold'], e, {
+ cyPosition: { x: now[0], y: now[1] }
+ } );
+
+ if (!r.touchData.start) {
+ cy.$(':selected').unselect();
+ }
+
+ }
+ }, r.tapholdDuration);
+ }
+
+ }, false);
+
+ var touchmoveHandler;
+ r.registerBinding(window, 'touchmove', touchmoveHandler = function(e) {
+
+ var select = r.selection;
+ var capture = r.touchData.capture;
+ var cy = r.cy;
+ var now = r.touchData.now; var earlier = r.touchData.earlier;
+ var zoom = cy.zoom();
+
+ if (e.touches[0]) { var pos = r.projectIntoViewport(e.touches[0].clientX, e.touches[0].clientY); now[0] = pos[0]; now[1] = pos[1]; }
+ if (e.touches[1]) { var pos = r.projectIntoViewport(e.touches[1].clientX, e.touches[1].clientY); now[2] = pos[0]; now[3] = pos[1]; }
+ if (e.touches[2]) { var pos = r.projectIntoViewport(e.touches[2].clientX, e.touches[2].clientY); now[4] = pos[0]; now[5] = pos[1]; }
+
+ var disp = []; for (var j=0;j<now.length;j++) { disp[j] = now[j] - earlier[j]; }
+ var startPos = r.touchData.startPosition;
+ var dx = now[0] - startPos[0];
+ var dx2 = dx * dx;
+ var dy = now[1] - startPos[1];
+ var dy2 = dy * dy;
+ var dist2 = dx2 + dy2;
+ var rdist2 = dist2 * zoom * zoom;
+
+ // context swipe cancelling
+ if( capture && r.touchData.cxt ){
+ e.preventDefault();
+
+ var f1x2 = e.touches[0].clientX - offsetLeft, f1y2 = e.touches[0].clientY - offsetTop;
+ var f2x2 = e.touches[1].clientX - offsetLeft, f2y2 = e.touches[1].clientY - offsetTop;
+ // var distance2 = distance( f1x2, f1y2, f2x2, f2y2 );
+ var distance2Sq = distanceSq( f1x2, f1y2, f2x2, f2y2 );
+ var factorSq = distance2Sq / distance1Sq;
+
+ var distThreshold = 150;
+ var distThresholdSq = distThreshold * distThreshold;
+ var factorThreshold = 1.5;
+ var factorThresholdSq = factorThreshold * factorThreshold;
+
+ // cancel ctx gestures if the distance b/t the fingers increases
+ if( factorSq >= factorThresholdSq || distance2Sq >= distThresholdSq ){
+ r.touchData.cxt = false;
+ if( r.touchData.start ){ r.touchData.start.unactivate(); r.touchData.start = null; }
+ r.data.bgActivePosistion = undefined;
+ r.redrawHint('select', true);
+
+ var cxtEvt = Event(e, {
+ type: 'cxttapend',
+ cyPosition: { x: now[0], y: now[1] }
+ });
+ if( r.touchData.start ){
+ r.touchData.start.trigger( cxtEvt );
+ } else {
+ cy.trigger( cxtEvt );
+ }
+ }
+
+ }
+
+ // context swipe
+ if( capture && r.touchData.cxt ){
+ var cxtEvt = Event(e, {
+ type: 'cxtdrag',
+ cyPosition: { x: now[0], y: now[1] }
+ });
+ r.data.bgActivePosistion = undefined;
+ r.redrawHint('select', true);
+
+ if( r.touchData.start ){
+ r.touchData.start.trigger( cxtEvt );
+ } else {
+ cy.trigger( cxtEvt );
+ }
+
+ if( r.touchData.start ){ r.touchData.start._private.grabbed = false; }
+ r.touchData.cxtDragged = true;
+
+ var near = r.findNearestElement(now[0], now[1], true, true);
+
+ if( !r.touchData.cxtOver || near !== r.touchData.cxtOver ){
+
+ if( r.touchData.cxtOver ){
+ r.touchData.cxtOver.trigger( Event(e, {
+ type: 'cxtdragout',
+ cyPosition: { x: now[0], y: now[1] }
+ }) );
+ }
+
+ r.touchData.cxtOver = near;
+
+ if( near ){
+ near.trigger( Event(e, {
+ type: 'cxtdragover',
+ cyPosition: { x: now[0], y: now[1] }
+ }) );
+
+ }
+
+ }
+
+ // box selection
+ } else if( capture && e.touches[2] && cy.boxSelectionEnabled() ){
+ e.preventDefault();
+
+ r.data.bgActivePosistion = undefined;
+
+ this.lastThreeTouch = +new Date();
+ r.touchData.selecting = true;
+
+ r.redrawHint('select', true);
+
+ if( !select || select.length === 0 || select[0] === undefined ){
+ select[0] = (now[0] + now[2] + now[4])/3;
+ select[1] = (now[1] + now[3] + now[5])/3;
+ select[2] = (now[0] + now[2] + now[4])/3 + 1;
+ select[3] = (now[1] + now[3] + now[5])/3 + 1;
+ } else {
+ select[2] = (now[0] + now[2] + now[4])/3;
+ select[3] = (now[1] + now[3] + now[5])/3;
+ }
+
+ select[4] = 1;
+ r.touchData.selecting = true;
+
+ r.redraw();
+
+ // pinch to zoom
+ } else if ( capture && e.touches[1] && cy.zoomingEnabled() && cy.panningEnabled() && cy.userZoomingEnabled() && cy.userPanningEnabled() ) { // two fingers => pinch to zoom
+ e.preventDefault();
+
+ r.data.bgActivePosistion = undefined;
+ r.redrawHint('select', true);
+
+ var draggedEles = r.dragData.touchDragEles;
+ if( draggedEles ){
+ r.redrawHint('drag', true);
+
+ for( var i = 0; i < draggedEles.length; i++ ){
+ draggedEles[i]._private.grabbed = false;
+ draggedEles[i]._private.rscratch.inDragLayer = false;
+ }
+ }
+
+ // (x2, y2) for fingers 1 and 2
+ var f1x2 = e.touches[0].clientX - offsetLeft, f1y2 = e.touches[0].clientY - offsetTop;
+ var f2x2 = e.touches[1].clientX - offsetLeft, f2y2 = e.touches[1].clientY - offsetTop;
+
+
+ var distance2 = distance( f1x2, f1y2, f2x2, f2y2 );
+ // var distance2Sq = distanceSq( f1x2, f1y2, f2x2, f2y2 );
+ // var factor = Math.sqrt( distance2Sq ) / Math.sqrt( distance1Sq );
+ var factor = distance2 / distance1;
+
+ if( factor != 1 && twoFingersStartInside){
+ // delta finger1
+ var df1x = f1x2 - f1x1;
+ var df1y = f1y2 - f1y1;
+
+ // delta finger 2
+ var df2x = f2x2 - f2x1;
+ var df2y = f2y2 - f2y1;
+
+ // translation is the normalised vector of the two fingers movement
+ // i.e. so pinching cancels out and moving together pans
+ var tx = (df1x + df2x)/2;
+ var ty = (df1y + df2y)/2;
+
+ // adjust factor by the speed multiplier
+ // var speed = 1.5;
+ // if( factor > 1 ){
+ // factor = (factor - 1) * speed + 1;
+ // } else {
+ // factor = 1 - (1 - factor) * speed;
+ // }
+
+ // now calculate the zoom
+ var zoom1 = cy.zoom();
+ var zoom2 = zoom1 * factor;
+ var pan1 = cy.pan();
+
+ // the model center point converted to the current rendered pos
+ var ctrx = modelCenter1[0] * zoom1 + pan1.x;
+ var ctry = modelCenter1[1] * zoom1 + pan1.y;
+
+ var pan2 = {
+ x: -zoom2/zoom1 * (ctrx - pan1.x - tx) + ctrx,
+ y: -zoom2/zoom1 * (ctry - pan1.y - ty) + ctry
+ };
+
+ // remove dragged eles
+ if( r.touchData.start ){
+ var draggedEles = r.dragData.touchDragEles;
+
+ if( draggedEles ){ for( var i = 0; i < draggedEles.length; i++ ){
+ var dEi_p = draggedEles[i]._private;
+
+ dEi_p.grabbed = false;
+ dEi_p.rscratch.inDragLayer = false;
+ } }
+
+ var start_p = r.touchData.start._private;
+ start_p.active = false;
+ start_p.grabbed = false;
+ start_p.rscratch.inDragLayer = false;
+
+ r.redrawHint('drag', true);
+
+ r.touchData.start
+ .trigger('free')
+ .trigger('unactivate')
+ ;
+ }
+
+ cy.viewport({
+ zoom: zoom2,
+ pan: pan2,
+ cancelOnFailedZoom: true
+ });
+
+ distance1 = distance2;
+ f1x1 = f1x2;
+ f1y1 = f1y2;
+ f2x1 = f2x2;
+ f2y1 = f2y2;
+
+ r.pinching = true;
+ }
+
+ // Re-project
+ if (e.touches[0]) { var pos = r.projectIntoViewport(e.touches[0].clientX, e.touches[0].clientY); now[0] = pos[0]; now[1] = pos[1]; }
+ if (e.touches[1]) { var pos = r.projectIntoViewport(e.touches[1].clientX, e.touches[1].clientY); now[2] = pos[0]; now[3] = pos[1]; }
+ if (e.touches[2]) { var pos = r.projectIntoViewport(e.touches[2].clientX, e.touches[2].clientY); now[4] = pos[0]; now[5] = pos[1]; }
+
+ } else if (e.touches[0]) {
+ var start = r.touchData.start;
+ var last = r.touchData.last;
+ var near = near || r.findNearestElement(now[0], now[1], true, true);
+
+ if( start != null ){
+ e.preventDefault();
+ }
+
+ // dragging nodes
+ if( start != null && start._private.group == 'nodes' && r.nodeIsDraggable(start) ){
+
+ if( rdist2 >= r.touchTapThreshold2 ){ // then dragging can happen
+ var draggedEles = r.dragData.touchDragEles;
+ var justStartedDrag = !r.dragData.didDrag;
+
+ for( var k = 0; k < draggedEles.length; k++ ){
+ var draggedEle = draggedEles[k];
+
+ if( justStartedDrag ){
+ addNodeToDrag( draggedEle, { inDragLayer: true } );
+ }
+
+ if( r.nodeIsDraggable(draggedEle) && draggedEle.isNode() && draggedEle.grabbed() ){
+ r.dragData.didDrag = true;
+ var dPos = draggedEle._private.position;
+ var updatePos = !draggedEle.isParent();
+
+ if( updatePos && is.number(disp[0]) && is.number(disp[1]) ){
+ dPos.x += disp[0];
+ dPos.y += disp[1];
+ }
+
+ if( justStartedDrag ){
+ r.redrawHint('eles', true);
+
+ var dragDelta = r.touchData.dragDelta;
+
+ if( updatePos && is.number(dragDelta[0]) && is.number(dragDelta[1]) ){
+ dPos.x += dragDelta[0];
+ dPos.y += dragDelta[1];
+ }
+
+ }
+ }
+ }
+
+ var tcol = Collection(cy, draggedEles);
+
+ tcol.updateCompoundBounds();
+ tcol.trigger('position drag');
+
+ r.hoverData.draggingEles = true;
+
+ r.redrawHint('drag', true);
+
+ if(
+ r.touchData.startPosition[0] == earlier[0]
+ && r.touchData.startPosition[1] == earlier[1]
+ ){
+
+ r.redrawHint('eles', true);
+ }
+
+ r.redraw();
+ } else { // otherise keep track of drag delta for later
+ var dragDelta = r.touchData.dragDelta = r.touchData.dragDelta || [];
+
+ if( dragDelta.length === 0 ){
+ dragDelta.push( disp[0] );
+ dragDelta.push( disp[1] );
+ } else {
+ dragDelta[0] += disp[0];
+ dragDelta[1] += disp[1];
+ }
+ }
+ }
+
+ // touchmove
+ {
+ triggerEvents( (start || near), ['touchmove', 'tapdrag', 'vmousemove'], e, {
+ cyPosition: { x: now[0], y: now[1] }
+ } );
+
+ if (near != last) {
+ if (last) { last.trigger(Event(e, { type: 'tapdragout', cyPosition: { x: now[0], y: now[1] } })); }
+ if (near) { near.trigger(Event(e, { type: 'tapdragover', cyPosition: { x: now[0], y: now[1] } })); }
+ }
+
+ r.touchData.last = near;
+ }
+
+ // check to cancel taphold
+ for (var i=0;i<now.length;i++) {
+ if( now[i]
+ && r.touchData.startPosition[i]
+ && rdist2 > r.touchTapThreshold2 ){
+
+ r.touchData.singleTouchMoved = true;
+ }
+ }
+
+ // panning
+ if(
+ capture
+ && ( start == null || start.isEdge() )
+ && cy.panningEnabled() && cy.userPanningEnabled()
+ ){
+
+ e.preventDefault();
+
+ if( r.swipePanning ){
+ cy.panBy({
+ x: disp[0] * zoom,
+ y: disp[1] * zoom
+ });
+
+ } else if( rdist2 >= r.touchTapThreshold2 ){
+ r.swipePanning = true;
+
+ cy.panBy({
+ x: dx * zoom,
+ y: dy * zoom
+ });
+
+ if( start ){
+ start.unactivate();
+
+ if( !r.data.bgActivePosistion ){
+ r.data.bgActivePosistion = {
+ x: now[0],
+ y: now[1]
+ };
+ }
+
+ r.redrawHint('select', true);
+
+ r.touchData.start = null;
+ }
+ }
+
+ // Re-project
+ var pos = r.projectIntoViewport(e.touches[0].clientX, e.touches[0].clientY);
+ now[0] = pos[0]; now[1] = pos[1];
+ }
+ }
+
+ for (var j=0; j<now.length; j++) { earlier[j] = now[j]; }
+ //r.redraw();
+
+ }, false);
+
+ var touchcancelHandler;
+ r.registerBinding(window, 'touchcancel', touchcancelHandler = function(e) {
+ var start = r.touchData.start;
+
+ r.touchData.capture = false;
+
+ if( start ){
+ start.unactivate();
+ }
+ });
+
+ var touchendHandler;
+ r.registerBinding(window, 'touchend', touchendHandler = function(e) {
+ var start = r.touchData.start;
+
+ var capture = r.touchData.capture;
+
+ if( capture ){
+ r.touchData.capture = false;
+
+ e.preventDefault();
+ } else {
+ return;
+ }
+
+ var select = r.selection;
+
+ r.swipePanning = false;
+ r.hoverData.draggingEles = false;
+
+ var cy = r.cy;
+ var zoom = cy.zoom();
+ var now = r.touchData.now;
+ var earlier = r.touchData.earlier;
+
+ if (e.touches[0]) { var pos = r.projectIntoViewport(e.touches[0].clientX, e.touches[0].clientY); now[0] = pos[0]; now[1] = pos[1]; }
+ if (e.touches[1]) { var pos = r.projectIntoViewport(e.touches[1].clientX, e.touches[1].clientY); now[2] = pos[0]; now[3] = pos[1]; }
+ if (e.touches[2]) { var pos = r.projectIntoViewport(e.touches[2].clientX, e.touches[2].clientY); now[4] = pos[0]; now[5] = pos[1]; }
+
+ if( start ){
+ start.unactivate();
+ }
+
+ var ctxTapend;
+ if( r.touchData.cxt ){
+ ctxTapend = Event(e, {
+ type: 'cxttapend',
+ cyPosition: { x: now[0], y: now[1] }
+ });
+
+ if( start ){
+ start.trigger( ctxTapend );
+ } else {
+ cy.trigger( ctxTapend );
+ }
+
+ if( !r.touchData.cxtDragged ){
+ var ctxTap = Event(e, {
+ type: 'cxttap',
+ cyPosition: { x: now[0], y: now[1] }
+ });
+
+ if( start ){
+ start.trigger( ctxTap );
+ } else {
+ cy.trigger( ctxTap );
+ }
+
+ }
+
+ if( r.touchData.start ){ r.touchData.start._private.grabbed = false; }
+ r.touchData.cxt = false;
+ r.touchData.start = null;
+
+ r.redraw();
+ return;
+ }
+
+ // no more box selection if we don't have three fingers
+ if( !e.touches[2] && cy.boxSelectionEnabled() && r.touchData.selecting ){
+ r.touchData.selecting = false;
+
+ var newlySelected = [];
+ var box = r.getAllInBox( select[0], select[1], select[2], select[3] );
+
+ select[0] = undefined;
+ select[1] = undefined;
+ select[2] = undefined;
+ select[3] = undefined;
+ select[4] = 0;
+
+ r.redrawHint('select', true);
+
+ for( var i = 0; i< box.length; i++ ) {
+ if( box[i]._private.selectable ){
+ newlySelected.push( box[i] );
+ }
+ }
+
+ var newlySelCol = Collection( cy, newlySelected );
+
+ newlySelCol.select();
+
+ if( newlySelCol.length > 0 ) {
+ r.redrawHint('eles', true);
+ } else {
+ r.redraw();
+ }
+ }
+
+ var updateStartStyle = false;
+
+ if( start != null ){
+ start._private.active = false;
+ updateStartStyle = true;
+ start.unactivate();
+ }
+
+ if (e.touches[2]) {
+ r.data.bgActivePosistion = undefined;
+ r.redrawHint('select', true);
+ } else if (e.touches[1]) {
+
+ } else if (e.touches[0]) {
+
+ // Last touch released
+ } else if (!e.touches[0]) {
+
+ r.data.bgActivePosistion = undefined;
+ r.redrawHint('select', true);
+
+ var draggedEles = r.dragData.touchDragEles;
+
+ if (start != null ) {
+
+ var startWasGrabbed = start._private.grabbed;
+
+ freeDraggedElements( draggedEles );
+
+ r.redrawHint('drag', true);
+ r.redrawHint('eles', true);
+
+ if( startWasGrabbed ){
+ start.trigger('free');
+ }
+
+ triggerEvents( start, ['touchend', 'tapend', 'vmouseup'], e, {
+ cyPosition: { x: now[0], y: now[1] }
+ } );
+
+ start.unactivate();
+
+ r.touchData.start = null;
+
+ } else {
+ var near = r.findNearestElement(now[0], now[1], true, true);
+
+ triggerEvents( near, ['touchend', 'tapend', 'vmouseup'], e, {
+ cyPosition: { x: now[0], y: now[1] }
+ } );
+
+ }
+
+ var dx = r.touchData.startPosition[0] - now[0];
+ var dx2 = dx * dx;
+ var dy = r.touchData.startPosition[1] - now[1];
+ var dy2 = dy * dy;
+ var dist2 = dx2 + dy2;
+ var rdist2 = dist2 * zoom * zoom;
+
+ // Prepare to select the currently touched node, only if it hasn't been dragged past a certain distance
+ if (start != null
+ && !r.dragData.didDrag // didn't drag nodes around
+ && start._private.selectable
+ && rdist2 < r.touchTapThreshold2
+ && !r.pinching // pinch to zoom should not affect selection
+ ) {
+
+ if( cy.selectionType() === 'single' ){
+ cy.$(':selected').unmerge( start ).unselect();
+ start.select();
+ } else {
+ if( start.selected() ){
+ start.unselect();
+ } else {
+ start.select();
+ }
+ }
+
+ updateStartStyle = true;
+
+
+ r.redrawHint('eles', true);
+ }
+
+ // Tap event, roughly same as mouse click event for touch
+ if( !r.touchData.singleTouchMoved ){
+ triggerEvents( start, ['tap', 'vclick'], e, {
+ cyPosition: { x: now[0], y: now[1] }
+ } );
+ }
+
+ r.touchData.singleTouchMoved = true;
+ }
+
+ for( var j = 0; j < now.length; j++ ){ earlier[j] = now[j]; }
+
+ r.dragData.didDrag = false; // reset for next mousedown
+
+ if( e.touches.length === 0 ){
+ r.touchData.dragDelta = [];
+ }
+
+ if( updateStartStyle && start ){
+ start.updateStyle(false);
+ }
+
+ if( e.touches.length < 2 ){
+ r.pinching = false;
+ r.redrawHint('eles', true);
+ r.redraw();
+ }
+
+ //r.redraw();
+
+ }, false);
+
+ // fallback compatibility layer for ms pointer events
+ if( typeof TouchEvent === 'undefined' ){
+
+ var pointers = [];
+
+ var makeTouch = function( e ){
+ return {
+ clientX: e.clientX,
+ clientY: e.clientY,
+ force: 1,
+ identifier: e.pointerId,
+ pageX: e.pageX,
+ pageY: e.pageY,
+ radiusX: e.width/2,
+ radiusY: e.height/2,
+ screenX: e.screenX,
+ screenY: e.screenY,
+ target: e.target
+ };
+ };
+
+ var makePointer = function( e ){
+ return {
+ event: e,
+ touch: makeTouch(e)
+ };
+ };
+
+ var addPointer = function( e ){
+ pointers.push( makePointer(e) );
+ };
+
+ var removePointer = function( e ){
+ for( var i = 0; i < pointers.length; i++ ){
+ var p = pointers[i];
+
+ if( p.event.pointerId === e.pointerId ){
+ pointers.splice( i, 1 );
+ return;
+ }
+ }
+ };
+
+ var updatePointer = function( e ){
+ var p = pointers.filter(function( p ){
+ return p.event.pointerId === e.pointerId;
+ })[0];
+
+ p.event = e;
+ p.touch = makeTouch(e);
+ };
+
+ var addTouchesToEvent = function( e ){
+ e.touches = pointers.map(function( p ){
+ return p.touch;
+ });
+ };
+
+ r.registerBinding(r.container, 'pointerdown', function(e){
+ if( e.pointerType === 'mouse' ){ return; } // mouse already handled
+
+ e.preventDefault();
+
+ addPointer( e );
+
+ addTouchesToEvent( e );
+ touchstartHandler( e );
+ });
+
+ r.registerBinding(r.container, 'pointerup', function(e){
+ if( e.pointerType === 'mouse' ){ return; } // mouse already handled
+
+ removePointer( e );
+
+ addTouchesToEvent( e );
+ touchendHandler( e );
+ });
+
+ r.registerBinding(r.container, 'pointercancel', function(e){
+ if( e.pointerType === 'mouse' ){ return; } // mouse already handled
+
+ removePointer( e );
+
+ addTouchesToEvent( e );
+ touchcancelHandler( e );
+ });
+
+ r.registerBinding(r.container, 'pointermove', function(e){
+ if( e.pointerType === 'mouse' ){ return; } // mouse already handled
+
+ e.preventDefault();
+
+ updatePointer( e );
+
+ addTouchesToEvent( e );
+ touchmoveHandler( e );
+ });
+
+ }
+};
+
+module.exports = BRp;
+
+},{"../../../collection":23,"../../../event":42,"../../../is":77,"../../../util":94}],60:[function(_dereq_,module,exports){
+'use strict';
+
+var math = _dereq_('../../../math');
+
+var BRp = {};
+
+BRp.registerNodeShapes = function(){
+ var nodeShapes = this.nodeShapes = {};
+ var renderer = this;
+
+ nodeShapes['ellipse'] = {
+ name: 'ellipse',
+
+ draw: function( context, centerX, centerY, width, height ){
+ renderer.nodeShapeImpl( this.name )( context, centerX, centerY, width, height );
+ },
+
+ intersectLine: function( nodeX, nodeY, width, height, x, y, padding ){
+ return math.intersectLineEllipse(
+ x, y,
+ nodeX,
+ nodeY,
+ width / 2 + padding,
+ height / 2 + padding)
+ ;
+ },
+
+ checkPoint: function( x, y, padding, width, height, centerX, centerY ){
+ x -= centerX;
+ y -= centerY;
+
+ x /= (width / 2 + padding);
+ y /= (height / 2 + padding);
+
+ return x*x + y*y <= 1;
+ }
+ };
+
+ function generatePolygon( name, points ){
+ return ( nodeShapes[name] = {
+ name: name,
+
+ points: points,
+
+ draw: function( context, centerX, centerY, width, height ){
+ renderer.nodeShapeImpl('polygon')( context, centerX, centerY, width, height, this.points );
+ },
+
+ intersectLine: function( nodeX, nodeY, width, height, x, y, padding ){
+ return math.polygonIntersectLine(
+ x, y,
+ this.points,
+ nodeX,
+ nodeY,
+ width / 2, height / 2,
+ padding)
+ ;
+ },
+
+ checkPoint: function( x, y, padding, width, height, centerX, centerY ){
+ return math.pointInsidePolygon(x, y, nodeShapes[name].points,
+ centerX, centerY, width, height, [0, -1], padding)
+ ;
+ }
+ } );
+ }
+
+ generatePolygon( 'triangle', math.generateUnitNgonPointsFitToSquare(3, 0) );
+
+ generatePolygon( 'square', math.generateUnitNgonPointsFitToSquare(4, 0) );
+ nodeShapes['rectangle'] = nodeShapes['square'];
+
+ nodeShapes['roundrectangle'] = {
+ name: 'roundrectangle',
+
+ points: math.generateUnitNgonPointsFitToSquare(4, 0),
+
+ draw: function( context, centerX, centerY, width, height ){
+ renderer.nodeShapeImpl( this.name )( context, centerX, centerY, width, height );
+ },
+
+ intersectLine: function( nodeX, nodeY, width, height, x, y, padding ){
+ return math.roundRectangleIntersectLine(
+ x, y,
+ nodeX,
+ nodeY,
+ width, height,
+ padding)
+ ;
+ },
+
+ // Looks like the width passed into this function is actually the total width / 2
+ checkPoint: function(
+ x, y, padding, width, height, centerX, centerY ){
+
+ var cornerRadius = math.getRoundRectangleRadius(width, height);
+
+ // Check hBox
+ if (math.pointInsidePolygon(x, y, this.points,
+ centerX, centerY, width, height - 2 * cornerRadius, [0, -1], padding) ){
+ return true;
+ }
+
+ // Check vBox
+ if (math.pointInsidePolygon(x, y, this.points,
+ centerX, centerY, width - 2 * cornerRadius, height, [0, -1], padding) ){
+ return true;
+ }
+
+ var checkInEllipse = function( x, y, centerX, centerY, width, height, padding ){
+ x -= centerX;
+ y -= centerY;
+
+ x /= (width / 2 + padding);
+ y /= (height / 2 + padding);
+
+ return (x*x + y*y <= 1);
+ };
+
+
+ // Check top left quarter circle
+ if (checkInEllipse(x, y,
+ centerX - width / 2 + cornerRadius,
+ centerY - height / 2 + cornerRadius,
+ cornerRadius * 2, cornerRadius * 2, padding) ){
+
+ return true;
+ }
+
+ // Check top right quarter circle
+ if (checkInEllipse(x, y,
+ centerX + width / 2 - cornerRadius,
+ centerY - height / 2 + cornerRadius,
+ cornerRadius * 2, cornerRadius * 2, padding) ){
+
+ return true;
+ }
+
+ // Check bottom right quarter circle
+ if (checkInEllipse(x, y,
+ centerX + width / 2 - cornerRadius,
+ centerY + height / 2 - cornerRadius,
+ cornerRadius * 2, cornerRadius * 2, padding) ){
+
+ return true;
+ }
+
+ // Check bottom left quarter circle
+ if (checkInEllipse(x, y,
+ centerX - width / 2 + cornerRadius,
+ centerY + height / 2 - cornerRadius,
+ cornerRadius * 2, cornerRadius * 2, padding) ){
+
+ return true;
+ }
+
+ return false;
+ }
+ };
+
+ generatePolygon( 'diamond', [
+ 0, 1,
+ 1, 0,
+ 0, -1,
+ -1, 0
+ ] );
+
+ generatePolygon( 'pentagon', math.generateUnitNgonPointsFitToSquare(5, 0) );
+
+ generatePolygon( 'hexagon', math.generateUnitNgonPointsFitToSquare(6, 0) );
+
+ generatePolygon( 'heptagon', math.generateUnitNgonPointsFitToSquare(7, 0) );
+
+ generatePolygon( 'octagon', math.generateUnitNgonPointsFitToSquare(8, 0) );
+
+ var star5Points = new Array(20);
+ {
+ var outerPoints = math.generateUnitNgonPoints(5, 0);
+ var innerPoints = math.generateUnitNgonPoints(5, Math.PI / 5);
+
+ // Outer radius is 1; inner radius of star is smaller
+ var innerRadius = 0.5 * (3 - Math.sqrt(5));
+ innerRadius *= 1.57;
+
+ for (var i=0;i<innerPoints.length/2;i++ ){
+ innerPoints[i*2] *= innerRadius;
+ innerPoints[i*2+1] *= innerRadius;
+ }
+
+ for (var i=0;i<20/4;i++ ){
+ star5Points[i*4] = outerPoints[i*2];
+ star5Points[i*4+1] = outerPoints[i*2+1];
+
+ star5Points[i*4+2] = innerPoints[i*2];
+ star5Points[i*4+3] = innerPoints[i*2+1];
+ }
+ }
+
+ star5Points = math.fitPolygonToSquare( star5Points );
+
+ generatePolygon( 'star', star5Points );
+
+ generatePolygon( 'vee', [
+ -1, -1,
+ 0, -0.333,
+ 1, -1,
+ 0, 1
+ ] );
+
+ generatePolygon( 'rhomboid', [
+ -1, -1,
+ 0.333, -1,
+ 1, 1,
+ -0.333, 1
+ ] );
+
+ nodeShapes.makePolygon = function( points ){
+
+ // use caching on user-specified polygons so they are as fast as native shapes
+
+ var key = points.join('$');
+ var name = 'polygon-' + key;
+ var shape;
+
+ if( (shape = nodeShapes[name]) ){ // got cached shape
+ return shape;
+ }
+
+ // create and cache new shape
+ return generatePolygon( name, points );
+ };
+
+};
+
+module.exports = BRp;
+
+},{"../../../math":79}],61:[function(_dereq_,module,exports){
+'use strict';
+
+var util = _dereq_('../../../util');
+
+var BRp = {};
+
+BRp.timeToRender = function(){
+ return this.redrawTotalTime / this.redrawCount;
+};
+
+var minRedrawLimit = 1000/60; // people can't see much better than 60fps
+var maxRedrawLimit = 1000; // don't cap max b/c it's more important to be responsive than smooth
+
+BRp.redraw = function( options ){
+ options = options || util.staticEmptyObject();
+
+ var r = this;
+ var forcedContext = options.forcedContext;
+
+ if( r.averageRedrawTime === undefined ){ r.averageRedrawTime = 0; }
+ if( r.lastRedrawTime === undefined ){ r.lastRedrawTime = 0; }
+
+ var redrawLimit = r.lastRedrawTime; // estimate the ideal redraw limit based on how fast we can draw
+ redrawLimit = minRedrawLimit > redrawLimit ? minRedrawLimit : redrawLimit;
+ redrawLimit = redrawLimit < maxRedrawLimit ? redrawLimit : maxRedrawLimit;
+
+ if( r.lastDrawTime === undefined ){ r.lastDrawTime = 0; }
+
+ var nowTime = Date.now();
+ var timeElapsed = nowTime - r.lastDrawTime;
+ var callAfterLimit = timeElapsed >= redrawLimit;
+
+ if( !forcedContext ){
+ if( !callAfterLimit || r.currentlyDrawing ){
+ r.skipFrame = true;
+ return;
+ }
+ }
+
+ r.requestedFrame = true;
+ r.currentlyDrawing = true;
+ r.renderOptions = options;
+};
+
+BRp.startRenderLoop = function(){
+ var r = this;
+
+ var renderFn = function(){
+ if( r.destroyed ){ return; }
+
+ if( r.requestedFrame && !r.skipFrame ){
+ var startTime = util.performanceNow();
+
+ r.render( r.renderOptions );
+
+ var endTime = r.lastRedrawTime = util.performanceNow();
+
+ if( r.averageRedrawTime === undefined ){
+ r.averageRedrawTime = endTime - startTime;
+ }
+
+ if( r.redrawCount === undefined ){
+ r.redrawCount = 0;
+ }
+
+ r.redrawCount++;
+
+ if( r.redrawTotalTime === undefined ){
+ r.redrawTotalTime = 0;
+ }
+
+ var duration = endTime - startTime;
+
+ r.redrawTotalTime += duration;
+ r.lastRedrawTime = duration;
+
+ // use a weighted average with a bias from the previous average so we don't spike so easily
+ r.averageRedrawTime = r.averageRedrawTime/2 + duration/2;
+
+ r.requestedFrame = false;
+ }
+
+ r.skipFrame = false;
+
+ util.requestAnimationFrame( renderFn );
+ };
+
+ util.requestAnimationFrame( renderFn );
+
+};
+
+module.exports = BRp;
+
+},{"../../../util":94}],62:[function(_dereq_,module,exports){
+'use strict';
+
+var CRp = {};
+
+var impl;
+
+CRp.arrowShapeImpl = function( name ){
+ return ( impl || (impl = {
+ 'polygon': function( context, points ){
+ for( var i = 0; i < points.length; i++ ){
+ var pt = points[i];
+
+ context.lineTo( pt.x, pt.y );
+ }
+ },
+
+ 'triangle-backcurve': function( context, points, controlPoint ){
+ var firstPt;
+
+ for( var i = 0; i < points.length; i++ ){
+ var pt = points[i];
+
+ if( i === 0 ){
+ firstPt = pt;
+ }
+
+ context.lineTo( pt.x, pt.y );
+ }
+
+ context.quadraticCurveTo( controlPoint.x, controlPoint.y, firstPt.x, firstPt.y );
+ },
+
+ 'triangle-tee': function( context, trianglePoints, teePoints ){
+ var triPts = trianglePoints;
+ for( var i = 0; i < triPts.length; i++ ){
+ var pt = triPts[i];
+
+ context.lineTo( pt.x, pt.y );
+ }
+
+ var teePts = teePoints;
+ var firstTeePt = teePoints[0];
+ context.moveTo( firstTeePt.x, firstTeePt.y );
+
+ for( var i = 0; i < teePts.length; i++ ){
+ var pt = teePts[i];
+
+ context.lineTo( pt.x, pt.y );
+ }
+ },
+
+ 'circle': function( context, rx, ry, r ){
+ context.arc(rx, ry, r, 0, Math.PI * 2, false);
+ }
+ }) )[ name ];
+};
+
+module.exports = CRp;
+
+},{}],63:[function(_dereq_,module,exports){
+'use strict';
+
+var CRp = {};
+
+CRp.drawEdge = function(context, edge, drawOverlayInstead) {
+ var rs = edge._private.rscratch;
+ var usePaths = this.usePaths();
+
+ // if bezier ctrl pts can not be calculated, then die
+ if( rs.badBezier || rs.badLine || isNaN( rs.allpts[0] ) ){ // iNaN in case edge is impossible and browser bugs (e.g. safari)
+ return;
+ }
+
+ var style = edge._private.style;
+
+ // Edge line width
+ if (style['width'].pfValue <= 0) {
+ return;
+ }
+
+ var overlayPadding = style['overlay-padding'].pfValue;
+ var overlayOpacity = style['overlay-opacity'].value;
+ var overlayColor = style['overlay-color'].value;
+
+ // Edge color & opacity
+ if( drawOverlayInstead ){
+
+ if( overlayOpacity === 0 ){ // exit early if no overlay
+ return;
+ }
+
+ this.strokeStyle(context, overlayColor[0], overlayColor[1], overlayColor[2], overlayOpacity);
+ context.lineCap = 'round';
+
+ if( rs.edgeType == 'self' && !usePaths ){
+ context.lineCap = 'butt';
+ }
+
+ } else {
+ var lineColor = style['line-color'].value;
+
+ this.strokeStyle(context, lineColor[0], lineColor[1], lineColor[2], style.opacity.value);
+
+ context.lineCap = 'butt';
+ }
+
+ var edgeWidth = style['width'].pfValue + (drawOverlayInstead ? 2 * overlayPadding : 0);
+ var lineStyle = drawOverlayInstead ? 'solid' : style['line-style'].value;
+ context.lineWidth = edgeWidth;
+
+ var shadowBlur = style['shadow-blur'].pfValue;
+ var shadowOpacity = style['shadow-opacity'].value;
+ var shadowColor = style['shadow-color'].value;
+ var shadowOffsetX = style['shadow-offset-x'].pfValue;
+ var shadowOffsetY = style['shadow-offset-y'].pfValue;
+
+ this.shadowStyle(context, shadowColor, drawOverlayInstead ? 0 : shadowOpacity, shadowBlur, shadowOffsetX, shadowOffsetY);
+
+ this.drawEdgePath(
+ edge,
+ context,
+ rs.allpts,
+ lineStyle,
+ edgeWidth
+ );
+
+ this.drawArrowheads(context, edge, drawOverlayInstead);
+
+ this.shadowStyle(context, 'transparent', 0); // reset for next guy
+
+};
+
+
+CRp.drawEdgePath = function(edge, context, pts, type, width) {
+ var rs = edge._private.rscratch;
+ var canvasCxt = context;
+ var path;
+ var pathCacheHit = false;
+ var usePaths = this.usePaths();
+
+ if( usePaths ){
+ var pathCacheKey = pts.join('$');
+ var keyMatches = rs.pathCacheKey && rs.pathCacheKey === pathCacheKey;
+
+ if( keyMatches ){
+ path = context = rs.pathCache;
+ pathCacheHit = true;
+ } else {
+ path = context = new Path2D();
+ rs.pathCacheKey = pathCacheKey;
+ rs.pathCache = path;
+ }
+ }
+
+ if( canvasCxt.setLineDash ){ // for very outofdate browsers
+ switch( type ){
+ case 'dotted':
+ canvasCxt.setLineDash([ 1, 1 ]);
+ break;
+
+ case 'dashed':
+ canvasCxt.setLineDash([ 6, 3 ]);
+ break;
+
+ case 'solid':
+ canvasCxt.setLineDash([ ]);
+ break;
+ }
+ }
+
+ if( !pathCacheHit ){
+ if( context.beginPath ){ context.beginPath(); }
+ context.moveTo( pts[0], pts[1] );
+
+ switch( rs.edgeType ){
+ case 'bezier':
+ case 'self':
+ case 'compound':
+ case 'multibezier':
+ if( !rs.badBezier ){
+ for( var i = 2; i + 3 < pts.length; i += 4 ){
+ context.quadraticCurveTo( pts[i], pts[i+1], pts[i+2], pts[i+3] );
+ }
+ }
+ break;
+
+ case 'straight':
+ case 'segments':
+ case 'haystack':
+ if( !rs.badLine ){
+ for( var i = 2; i + 1 < pts.length; i += 2 ){
+ context.lineTo( pts[i], pts[i+1] );
+ }
+ }
+ break;
+ }
+ }
+
+ context = canvasCxt;
+ if( usePaths ){
+ context.stroke( path );
+ } else {
+ context.stroke();
+ }
+
+ // reset any line dashes
+ if( context.setLineDash ){ // for very outofdate browsers
+ context.setLineDash([ ]);
+ }
+
+};
+
+CRp.drawArrowheads = function(context, edge, drawOverlayInstead) {
+ if( drawOverlayInstead ){ return; } // don't do anything for overlays
+
+ var rs = edge._private.rscratch;
+ var isHaystack = rs.edgeType === 'haystack';
+
+ if( !isHaystack ){
+ this.drawArrowhead( context, edge, 'source', rs.arrowStartX, rs.arrowStartY, rs.srcArrowAngle );
+ }
+
+ this.drawArrowhead( context, edge, 'mid-target', rs.midX, rs.midY, rs.midtgtArrowAngle );
+
+ this.drawArrowhead( context, edge, 'mid-source', rs.midX, rs.midY, rs.midsrcArrowAngle );
+
+ if( !isHaystack ){
+ this.drawArrowhead( context, edge, 'target', rs.arrowEndX, rs.arrowEndY, rs.tgtArrowAngle );
+ }
+};
+
+CRp.drawArrowhead = function( context, edge, prefix, x, y, angle ){
+ if( isNaN(x) || x == null || isNaN(y) || y == null || isNaN(angle) || angle == null ){ return; }
+
+ var self = this;
+ var style = edge._private.style;
+ var arrowShape = style[prefix + '-arrow-shape'].value;
+
+ if( arrowShape === 'none' ){
+ return;
+ }
+
+ var gco = context.globalCompositeOperation;
+
+ var arrowClearFill = style[prefix + '-arrow-fill'].value === 'hollow' ? 'both' : 'filled';
+ var arrowFill = style[prefix + '-arrow-fill'].value;
+
+ if( arrowShape === 'half-triangle-overshot' ){
+ arrowFill = 'hollow';
+ arrowClearFill = 'hollow';
+ }
+
+ if( style.opacity.value !== 1 || arrowFill === 'hollow' ){ // then extra clear is needed
+ context.globalCompositeOperation = 'destination-out';
+
+ self.fillStyle(context, 255, 255, 255, 1);
+ self.strokeStyle(context, 255, 255, 255, 1);
+
+ self.drawArrowShape( edge, prefix, context,
+ arrowClearFill, style['width'].pfValue, style[prefix + '-arrow-shape'].value,
+ x, y, angle
+ );
+
+ context.globalCompositeOperation = gco;
+ } // otherwise, the opaque arrow clears it for free :)
+
+ var color = style[prefix + '-arrow-color'].value;
+ self.fillStyle(context, color[0], color[1], color[2], style.opacity.value);
+ self.strokeStyle(context, color[0], color[1], color[2], style.opacity.value);
+
+ self.drawArrowShape( edge, prefix, context,
+ arrowFill, style['width'].pfValue, style[prefix + '-arrow-shape'].value,
+ x, y, angle
+ );
+};
+
+CRp.drawArrowShape = function(edge, arrowType, context, fill, edgeWidth, shape, x, y, angle) {
+ var r = this;
+ var usePaths = this.usePaths();
+ var rs = edge._private.rscratch;
+ var pathCacheHit = false;
+ var path;
+ var canvasContext = context;
+ var translation = { x: x, y: y };
+ var size = this.getArrowWidth( edgeWidth );
+ var shapeImpl = r.arrowShapes[shape];
+
+ if( usePaths ){
+ var pathCacheKey = size + '$' + shape + '$' + angle + '$' + x + '$' + y;
+ rs.arrowPathCacheKey = rs.arrowPathCacheKey || {};
+ rs.arrowPathCache = rs.arrowPathCache || {};
+
+ var alreadyCached = rs.arrowPathCacheKey[arrowType] === pathCacheKey;
+ if( alreadyCached ){
+ path = context = rs.arrowPathCache[arrowType];
+ pathCacheHit = true;
+ } else {
+ path = context = new Path2D();
+ rs.arrowPathCacheKey[arrowType] = pathCacheKey;
+ rs.arrowPathCache[arrowType] = path;
+ }
+ }
+
+ if( context.beginPath ){ context.beginPath(); }
+
+ if( !pathCacheHit ){
+ shapeImpl.draw(context, size, angle, translation);
+ }
+
+ if( !shapeImpl.leavePathOpen && context.closePath ){
+ context.closePath();
+ }
+
+ context = canvasContext;
+
+ if( fill === 'filled' || fill === 'both' ){
+ if( usePaths ){
+ context.fill( path );
+ } else {
+ context.fill();
+ }
+ }
+
+ if( fill === 'hollow' || fill === 'both' ){
+ context.lineWidth = ( shapeImpl.matchEdgeWidth ? edgeWidth : 1 );
+ context.lineJoin = 'miter';
+
+ if( usePaths ){
+ context.stroke( path );
+ } else {
+ context.stroke();
+ }
+
+ }
+};
+
+module.exports = CRp;
+
+},{}],64:[function(_dereq_,module,exports){
+'use strict';
+
+var CRp = {};
+
+CRp.safeDrawImage = function( context, img, ix, iy, iw, ih, x, y, w, h ){
+ var r = this;
+
+ try {
+ context.drawImage( img, ix, iy, iw, ih, x, y, w, h );
+ } catch(e){
+ r.data.canvasNeedsRedraw[r.NODE] = true;
+ r.data.canvasNeedsRedraw[r.DRAG] = true;
+
+ r.drawingImage = true;
+
+ r.redraw();
+ }
+};
+
+CRp.drawInscribedImage = function(context, img, node) {
+ var r = this;
+ var nodeX = node._private.position.x;
+ var nodeY = node._private.position.y;
+ var style = node._private.style;
+ var fit = style['background-fit'].value;
+ var xPos = style['background-position-x'];
+ var yPos = style['background-position-y'];
+ var repeat = style['background-repeat'].value;
+ var nodeW = node.width();
+ var nodeH = node.height();
+ var rs = node._private.rscratch;
+ var clip = style['background-clip'].value;
+ var shouldClip = clip === 'node';
+ var imgOpacity = style['background-image-opacity'].value;
+
+ var imgW = img.width || img.cachedW;
+ var imgH = img.height || img.cachedH;
+
+ // workaround for broken browsers like ie
+ if( null == imgW || null == imgH ){
+ document.body.appendChild( img );
+
+ imgW = img.cachedW = img.width || img.offsetWidth;
+ imgH = img.cachedH = img.height || img.offsetHeight;
+
+ document.body.removeChild( img );
+ }
+
+ var w = imgW;
+ var h = imgH;
+
+ var bgW = style['background-width'];
+ if( bgW.value !== 'auto' ){
+ if( bgW.units === '%' ){
+ w = bgW.value/100 * nodeW;
+ } else {
+ w = bgW.pfValue;
+ }
+ }
+
+ var bgH = style['background-height'];
+ if( bgH.value !== 'auto' ){
+ if( bgH.units === '%' ){
+ h = bgH.value/100 * nodeH;
+ } else {
+ h = bgH.pfValue;
+ }
+ }
+
+ if( w === 0 || h === 0 ){
+ return; // no point in drawing empty image (and chrome is broken in this case)
+ }
+
+ if( fit === 'contain' ){
+ var scale = Math.min( nodeW/w, nodeH/h );
+
+ w *= scale;
+ h *= scale;
+
+ } else if( fit === 'cover' ){
+ var scale = Math.max( nodeW/w, nodeH/h );
+
+ w *= scale;
+ h *= scale;
+ }
+
+ var x = (nodeX - nodeW/2); // left
+ if( xPos.units === '%' ){
+ x += (nodeW - w) * xPos.value/100;
+ } else {
+ x += xPos.pfValue;
+ }
+
+ var y = (nodeY - nodeH/2); // top
+ if( yPos.units === '%' ){
+ y += (nodeH - h) * yPos.value/100;
+ } else {
+ y += yPos.pfValue;
+ }
+
+ if( rs.pathCache ){
+ x -= nodeX;
+ y -= nodeY;
+
+ nodeX = 0;
+ nodeY = 0;
+ }
+
+ var gAlpha = context.globalAlpha;
+
+ context.globalAlpha = imgOpacity;
+
+ if( repeat === 'no-repeat' ){
+
+ if( shouldClip ){
+ context.save();
+
+ if( rs.pathCache ){
+ context.clip( rs.pathCache );
+ } else {
+ r.nodeShapes[r.getNodeShape(node)].draw(
+ context,
+ nodeX, nodeY,
+ nodeW, nodeH);
+
+ context.clip();
+ }
+ }
+
+ r.safeDrawImage( context, img, 0, 0, imgW, imgH, x, y, w, h );
+
+ if( shouldClip ){
+ context.restore();
+ }
+ } else {
+ var pattern = context.createPattern( img, repeat );
+ context.fillStyle = pattern;
+
+ r.nodeShapes[r.getNodeShape(node)].draw(
+ context,
+ nodeX, nodeY,
+ nodeW, nodeH);
+
+ context.translate(x, y);
+ context.fill();
+ context.translate(-x, -y);
+ }
+
+ context.globalAlpha = gAlpha;
+
+};
+
+module.exports = CRp;
+
+},{}],65:[function(_dereq_,module,exports){
+'use strict';
+
+var is = _dereq_('../../../is');
+
+var CRp = {};
+
+// Draw edge text
+CRp.drawEdgeText = function(context, edge) {
+ var text = edge._private.style['label'].strValue;
+
+ if( !text || text.match(/^\s+$/) ){
+ return;
+ }
+
+ if( this.hideEdgesOnViewport && (this.dragData.didDrag || this.pinching || this.hoverData.dragging || this.data.wheel || this.swipePanning) ){ return; } // save cycles on pinching
+
+ var computedSize = edge._private.style['font-size'].pfValue * edge.cy().zoom();
+ var minSize = edge._private.style['min-zoomed-font-size'].pfValue;
+
+ if( computedSize < minSize ){
+ return;
+ }
+
+ // Calculate text draw position
+
+ context.textAlign = 'center';
+ context.textBaseline = 'middle';
+
+ var rs = edge._private.rscratch;
+ if( !is.number( rs.labelX ) || !is.number( rs.labelY ) ){ return; } // no pos => label can't be rendered
+
+ var style = edge._private.style;
+ var autorotate = style['edge-text-rotation'].strValue === 'autorotate';
+ var theta;
+
+ if( autorotate ){
+ theta = rs.labelAngle;
+
+ context.translate(rs.labelX, rs.labelY);
+ context.rotate(theta);
+
+ this.drawText(context, edge, 0, 0);
+
+ context.rotate(-theta);
+ context.translate(-rs.labelX, -rs.labelY);
+ } else {
+ this.drawText(context, edge, rs.labelX, rs.labelY);
+ }
+
+};
+
+// Draw node text
+CRp.drawNodeText = function(context, node) {
+ var text = node._private.style['label'].strValue;
+
+ if ( !text || text.match(/^\s+$/) ) {
+ return;
+ }
+
+ var computedSize = node._private.style['font-size'].pfValue * node.cy().zoom();
+ var minSize = node._private.style['min-zoomed-font-size'].pfValue;
+
+ if( computedSize < minSize ){
+ return;
+ }
+
+ // this.recalculateNodeLabelProjection( node );
+
+ var textHalign = node._private.style['text-halign'].strValue;
+ var textValign = node._private.style['text-valign'].strValue;
+ var rs = node._private.rscratch;
+ if( !is.number( rs.labelX ) || !is.number( rs.labelY ) ){ return; } // no pos => label can't be rendered
+
+ switch( textHalign ){
+ case 'left':
+ context.textAlign = 'right';
+ break;
+
+ case 'right':
+ context.textAlign = 'left';
+ break;
+
+ default: // e.g. center
+ context.textAlign = 'center';
+ }
+
+ switch( textValign ){
+ case 'top':
+ context.textBaseline = 'bottom';
+ break;
+
+ case 'bottom':
+ context.textBaseline = 'top';
+ break;
+
+ default: // e.g. center
+ context.textBaseline = 'middle';
+ }
+
+ this.drawText(context, node, rs.labelX, rs.labelY);
+};
+
+CRp.getFontCache = function(context){
+ var cache;
+
+ this.fontCaches = this.fontCaches || [];
+
+ for( var i = 0; i < this.fontCaches.length; i++ ){
+ cache = this.fontCaches[i];
+
+ if( cache.context === context ){
+ return cache;
+ }
+ }
+
+ cache = {
+ context: context
+ };
+ this.fontCaches.push(cache);
+
+ return cache;
+};
+
+// set up canvas context with font
+// returns transformed text string
+CRp.setupTextStyle = function( context, element ){
+ // Font style
+ var parentOpacity = element.effectiveOpacity();
+ var style = element._private.style;
+ var labelStyle = style['font-style'].strValue;
+ var labelSize = style['font-size'].pfValue + 'px';
+ var labelFamily = style['font-family'].strValue;
+ var labelWeight = style['font-weight'].strValue;
+ var opacity = style['text-opacity'].value * style['opacity'].value * parentOpacity;
+ var outlineOpacity = style['text-outline-opacity'].value * opacity;
+ var color = style['color'].value;
+ var outlineColor = style['text-outline-color'].value;
+ var shadowBlur = style['text-shadow-blur'].pfValue;
+ var shadowOpacity = style['text-shadow-opacity'].value;
+ var shadowColor = style['text-shadow-color'].value;
+ var shadowOffsetX = style['text-shadow-offset-x'].pfValue;
+ var shadowOffsetY = style['text-shadow-offset-y'].pfValue;
+
+ var fontCacheKey = element._private.fontKey;
+ var cache = this.getFontCache(context);
+
+ if( cache.key !== fontCacheKey ){
+ context.font = labelStyle + ' ' + labelWeight + ' ' + labelSize + ' ' + labelFamily;
+
+ cache.key = fontCacheKey;
+ }
+
+ var text = this.getLabelText( element );
+
+ // Calculate text draw position based on text alignment
+
+ // so text outlines aren't jagged
+ context.lineJoin = 'round';
+
+ this.fillStyle(context, color[0], color[1], color[2], opacity);
+
+ this.strokeStyle(context, outlineColor[0], outlineColor[1], outlineColor[2], outlineOpacity);
+
+ this.shadowStyle(context, shadowColor, shadowOpacity, shadowBlur, shadowOffsetX, shadowOffsetY);
+
+ return text;
+};
+
+function roundRect(ctx, x, y, width, height, radius) {
+ var radius = radius || 5;
+ ctx.beginPath();
+ ctx.moveTo(x + radius, y);
+ ctx.lineTo(x + width - radius, y);
+ ctx.quadraticCurveTo(x + width, y, x + width, y + radius);
+ ctx.lineTo(x + width, y + height - radius);
+ ctx.quadraticCurveTo(x + width, y + height, x + width - radius, y + height);
+ ctx.lineTo(x + radius, y + height);
+ ctx.quadraticCurveTo(x, y + height, x, y + height - radius);
+ ctx.lineTo(x, y + radius);
+ ctx.quadraticCurveTo(x, y, x + radius, y);
+ ctx.closePath();
+ ctx.fill();
+}
+
+// Draw text
+CRp.drawText = function(context, element, textX, textY) {
+ var _p = element._private;
+ var style = _p.style;
+ var rstyle = _p.rstyle;
+ var rscratch = _p.rscratch;
+ var parentOpacity = element.effectiveOpacity();
+ if( parentOpacity === 0 || style['text-opacity'].value === 0){ return; }
+
+ var text = this.setupTextStyle( context, element );
+ var halign = style['text-halign'].value;
+ var valign = style['text-valign'].value;
+
+ if( element.isEdge() ){
+ halign = 'center';
+ valign = 'center';
+ }
+
+ if( element.isNode() ){
+ var pLeft = style['padding-left'].pfValue;
+ var pRight = style['padding-right'].pfValue;
+ var pTop = style['padding-top'].pfValue;
+ var pBottom = style['padding-bottom'].pfValue;
+
+ textX += pLeft/2;
+ textX -= pRight/2;
+
+ textY += pTop/2;
+ textY -= pBottom/2;
+ }
+
+ if ( text != null && !isNaN(textX) && !isNaN(textY)) {
+ var backgroundOpacity = style['text-background-opacity'].value;
+ var borderOpacity = style['text-border-opacity'].value;
+ var textBorderWidth = style['text-border-width'].pfValue;
+
+ if( backgroundOpacity > 0 || (textBorderWidth > 0 && borderOpacity > 0) ){
+ var margin = 4 + textBorderWidth/2;
+
+ if (element.isNode()) {
+ //Move textX, textY to include the background margins
+ if (valign === 'top') {
+ textY -= margin;
+ } else if (valign === 'bottom') {
+ textY += margin;
+ }
+ if (halign === 'left') {
+ textX -= margin;
+ } else if (halign === 'right') {
+ textX += margin;
+ }
+ }
+
+ var bgWidth = rstyle.labelWidth;
+ var bgHeight = rstyle.labelHeight;
+ var bgX = textX;
+
+ if (halign) {
+ if (halign == 'center') {
+ bgX = bgX - bgWidth / 2;
+ } else if (halign == 'left') {
+ bgX = bgX- bgWidth;
+ }
+ }
+
+ var bgY = textY;
+
+ if (element.isNode()) {
+ if (valign == 'top') {
+ bgY = bgY - bgHeight;
+ } else if (valign == 'center') {
+ bgY = bgY- bgHeight / 2;
+ }
+ } else {
+ bgY = bgY - bgHeight / 2;
+ }
+
+ if (style['edge-text-rotation'].strValue === 'autorotate') {
+ textY = 0;
+ bgWidth += 4;
+ bgX = textX - bgWidth / 2;
+ bgY = textY - bgHeight / 2;
+ } else {
+ // Adjust with border width & margin
+ bgX -= margin;
+ bgY -= margin;
+ bgHeight += margin*2;
+ bgWidth += margin*2;
+ }
+
+ if( backgroundOpacity > 0 ){
+ var textFill = context.fillStyle;
+ var textBackgroundColor = style['text-background-color'].value;
+
+ context.fillStyle = 'rgba(' + textBackgroundColor[0] + ',' + textBackgroundColor[1] + ',' + textBackgroundColor[2] + ',' + backgroundOpacity * parentOpacity + ')';
+ var styleShape = style['text-background-shape'].strValue;
+ if (styleShape == 'roundrectangle') {
+ roundRect(context, bgX, bgY, bgWidth, bgHeight, 2);
+ } else {
+ context.fillRect(bgX,bgY,bgWidth,bgHeight);
+ }
+ context.fillStyle = textFill;
+ }
+
+ if( textBorderWidth > 0 && borderOpacity > 0 ){
+ var textStroke = context.strokeStyle;
+ var textLineWidth = context.lineWidth;
+ var textBorderColor = style['text-border-color'].value;
+ var textBorderStyle = style['text-border-style'].value;
+
+ context.strokeStyle = 'rgba(' + textBorderColor[0] + ',' + textBorderColor[1] + ',' + textBorderColor[2] + ',' + borderOpacity * parentOpacity + ')';
+ context.lineWidth = textBorderWidth;
+
+ if( context.setLineDash ){ // for very outofdate browsers
+ switch( textBorderStyle ){
+ case 'dotted':
+ context.setLineDash([ 1, 1 ]);
+ break;
+ case 'dashed':
+ context.setLineDash([ 4, 2 ]);
+ break;
+ case 'double':
+ context.lineWidth = textBorderWidth/4; // 50% reserved for white between the two borders
+ context.setLineDash([ ]);
+ break;
+ case 'solid':
+ context.setLineDash([ ]);
+ break;
+ }
+ }
+
+ context.strokeRect(bgX,bgY,bgWidth,bgHeight);
+
+ if( textBorderStyle === 'double' ){
+ var whiteWidth = textBorderWidth/2;
+
+ context.strokeRect(bgX+whiteWidth,bgY+whiteWidth,bgWidth-whiteWidth*2,bgHeight-whiteWidth*2);
+ }
+
+ if( context.setLineDash ){ // for very outofdate browsers
+ context.setLineDash([ ]);
+ }
+ context.lineWidth = textLineWidth;
+ context.strokeStyle = textStroke;
+ }
+
+ }
+
+ var lineWidth = 2 * style['text-outline-width'].pfValue; // *2 b/c the stroke is drawn centred on the middle
+
+ if( lineWidth > 0 ){
+ context.lineWidth = lineWidth;
+ }
+
+ if( style['text-wrap'].value === 'wrap' ){
+ var lines = rscratch.labelWrapCachedLines;
+ var lineHeight = rstyle.labelHeight / lines.length;
+
+ switch( valign ){
+ case 'top':
+ textY -= (lines.length - 1) * lineHeight;
+ break;
+
+ case 'bottom':
+ // nothing required
+ break;
+
+ default:
+ case 'center':
+ textY -= (lines.length - 1) * lineHeight / 2;
+ }
+
+ for( var l = 0; l < lines.length; l++ ){
+ if( lineWidth > 0 ){
+ context.strokeText( lines[l], textX, textY );
+ }
+
+ context.fillText( lines[l], textX, textY );
+
+ textY += lineHeight;
+ }
+
+ } else {
+ if( lineWidth > 0 ){
+ context.strokeText( text, textX, textY );
+ }
+
+ context.fillText( text, textX, textY );
+ }
+
+
+ this.shadowStyle(context, 'transparent', 0); // reset for next guy
+ }
+};
+
+
+module.exports = CRp;
+
+},{"../../../is":77}],66:[function(_dereq_,module,exports){
+'use strict';
+
+var is = _dereq_('../../../is');
+
+var CRp = {};
+
+// Draw node
+CRp.drawNode = function(context, node, drawOverlayInstead) {
+
+ var r = this;
+ var nodeWidth, nodeHeight;
+ var style = node._private.style;
+ var rs = node._private.rscratch;
+ var _p = node._private;
+ var pos = _p.position;
+
+ if( !is.number(pos.x) || !is.number(pos.y) ){
+ return; // can't draw node with undefined position
+ }
+
+ var usePaths = this.usePaths();
+ var canvasContext = context;
+ var path;
+ var pathCacheHit = false;
+
+ var overlayPadding = style['overlay-padding'].pfValue;
+ var overlayOpacity = style['overlay-opacity'].value;
+ var overlayColor = style['overlay-color'].value;
+
+ if( drawOverlayInstead && overlayOpacity === 0 ){ // exit early if drawing overlay but none to draw
+ return;
+ }
+
+ var parentOpacity = node.effectiveOpacity();
+ if( parentOpacity === 0 ){ return; }
+
+ nodeWidth = node.width() + style['padding-left'].pfValue + style['padding-right'].pfValue;
+ nodeHeight = node.height() + style['padding-top'].pfValue + style['padding-bottom'].pfValue;
+
+ context.lineWidth = style['border-width'].pfValue;
+
+ if( drawOverlayInstead === undefined || !drawOverlayInstead ){
+
+ var url = style['background-image'].value[2] ||
+ style['background-image'].value[1];
+ var image;
+
+ if (url !== undefined) {
+
+ // get image, and if not loaded then ask to redraw when later loaded
+ image = this.getCachedImage(url, function(){
+ r.data.canvasNeedsRedraw[r.NODE] = true;
+ r.data.canvasNeedsRedraw[r.DRAG] = true;
+
+ r.drawingImage = true;
+
+ r.redraw();
+ });
+
+ var prevBging = _p.backgrounding;
+ _p.backgrounding = !image.complete;
+
+ if( prevBging !== _p.backgrounding ){ // update style b/c :backgrounding state changed
+ node.updateStyle( false );
+ }
+ }
+
+ // Node color & opacity
+
+ var bgColor = style['background-color'].value;
+ var borderColor = style['border-color'].value;
+ var borderStyle = style['border-style'].value;
+
+ this.fillStyle(context, bgColor[0], bgColor[1], bgColor[2], style['background-opacity'].value * parentOpacity);
+
+ this.strokeStyle(context, borderColor[0], borderColor[1], borderColor[2], style['border-opacity'].value * parentOpacity);
+
+ var shadowBlur = style['shadow-blur'].pfValue;
+ var shadowOpacity = style['shadow-opacity'].value;
+ var shadowColor = style['shadow-color'].value;
+ var shadowOffsetX = style['shadow-offset-x'].pfValue;
+ var shadowOffsetY = style['shadow-offset-y'].pfValue;
+
+ this.shadowStyle(context, shadowColor, shadowOpacity, shadowBlur, shadowOffsetX, shadowOffsetY);
+
+ context.lineJoin = 'miter'; // so borders are square with the node shape
+
+ if( context.setLineDash ){ // for very outofdate browsers
+ switch( borderStyle ){
+ case 'dotted':
+ context.setLineDash([ 1, 1 ]);
+ break;
+
+ case 'dashed':
+ context.setLineDash([ 4, 2 ]);
+ break;
+
+ case 'solid':
+ case 'double':
+ context.setLineDash([ ]);
+ break;
+ }
+ }
+
+
+ var styleShape = style['shape'].strValue;
+
+ if( usePaths ){
+ var pathCacheKey = styleShape + '$' + nodeWidth +'$' + nodeHeight;
+
+ context.translate( pos.x, pos.y );
+
+ if( rs.pathCacheKey === pathCacheKey ){
+ path = context = rs.pathCache;
+ pathCacheHit = true;
+ } else {
+ path = context = new Path2D();
+ rs.pathCacheKey = pathCacheKey;
+ rs.pathCache = path;
+ }
+ }
+
+ if( !pathCacheHit ){
+
+ var npos = pos;
+
+ if( usePaths ){
+ npos = {
+ x: 0,
+ y: 0
+ };
+ }
+
+ r.nodeShapes[this.getNodeShape(node)].draw(
+ context,
+ npos.x,
+ npos.y,
+ nodeWidth,
+ nodeHeight);
+ }
+
+ context = canvasContext;
+
+ if( usePaths ){
+ context.fill( path );
+ } else {
+ context.fill();
+ }
+
+ this.shadowStyle(context, 'transparent', 0); // reset for next guy
+
+ if (url !== undefined) {
+ if( image.complete ){
+ this.drawInscribedImage(context, image, node);
+ }
+ }
+
+ var darkness = style['background-blacken'].value;
+ var borderWidth = style['border-width'].pfValue;
+
+ if( this.hasPie(node) ){
+ this.drawPie( context, node, parentOpacity );
+
+ // redraw path for blacken and border
+ if( darkness !== 0 || borderWidth !== 0 ){
+
+ if( !usePaths ){
+ r.nodeShapes[this.getNodeShape(node)].draw(
+ context,
+ pos.x,
+ pos.y,
+ nodeWidth,
+ nodeHeight);
+ }
+ }
+ }
+
+ if( darkness > 0 ){
+ this.fillStyle(context, 0, 0, 0, darkness);
+
+ if( usePaths ){
+ context.fill( path );
+ } else {
+ context.fill();
+ }
+
+ } else if( darkness < 0 ){
+ this.fillStyle(context, 255, 255, 255, -darkness);
+
+ if( usePaths ){
+ context.fill( path );
+ } else {
+ context.fill();
+ }
+ }
+
+ // Border width, draw border
+ if (borderWidth > 0) {
+
+ if( usePaths ){
+ context.stroke( path );
+ } else {
+ context.stroke();
+ }
+
+ if( borderStyle === 'double' ){
+ context.lineWidth = style['border-width'].pfValue/3;
+
+ var gco = context.globalCompositeOperation;
+ context.globalCompositeOperation = 'destination-out';
+
+ if( usePaths ){
+ context.stroke( path );
+ } else {
+ context.stroke();
+ }
+
+ context.globalCompositeOperation = gco;
+ }
+
+ }
+
+ if( usePaths ){
+ context.translate( -pos.x, -pos.y );
+ }
+
+ // reset in case we changed the border style
+ if( context.setLineDash ){ // for very outofdate browsers
+ context.setLineDash([ ]);
+ }
+
+ // draw the overlay
+ } else {
+
+ if( overlayOpacity > 0 ){
+ this.fillStyle(context, overlayColor[0], overlayColor[1], overlayColor[2], overlayOpacity);
+
+ r.nodeShapes['roundrectangle'].draw(
+ context,
+ node._private.position.x,
+ node._private.position.y,
+ nodeWidth + overlayPadding * 2,
+ nodeHeight + overlayPadding * 2
+ );
+
+ context.fill();
+ }
+ }
+
+};
+
+// does the node have at least one pie piece?
+CRp.hasPie = function(node){
+ node = node[0]; // ensure ele ref
+
+ return node._private.hasPie;
+};
+
+CRp.drawPie = function( context, node, nodeOpacity ){
+ node = node[0]; // ensure ele ref
+
+ var _p = node._private;
+ var cyStyle = node.cy().style();
+ var style = _p.style;
+ var pieSize = style['pie-size'];
+ var nodeW = node.width();
+ var nodeH = node.height();
+ var x = _p.position.x;
+ var y = _p.position.y;
+ var radius = Math.min( nodeW, nodeH ) / 2; // must fit in node
+ var lastPercent = 0; // what % to continue drawing pie slices from on [0, 1]
+ var usePaths = this.usePaths();
+
+ if( usePaths ){
+ x = 0;
+ y = 0;
+ }
+
+ if( pieSize.units === '%' ){
+ radius = radius * pieSize.value / 100;
+ } else if( pieSize.pfValue !== undefined ){
+ radius = pieSize.pfValue / 2;
+ }
+
+ for( var i = 1; i <= cyStyle.pieBackgroundN; i++ ){ // 1..N
+ var size = style['pie-' + i + '-background-size'].value;
+ var color = style['pie-' + i + '-background-color'].value;
+ var opacity = style['pie-' + i + '-background-opacity'].value * nodeOpacity;
+ var percent = size / 100; // map integer range [0, 100] to [0, 1]
+
+ // percent can't push beyond 1
+ if( percent + lastPercent > 1 ){
+ percent = 1 - lastPercent;
+ }
+
+ var angleStart = 1.5 * Math.PI + 2 * Math.PI * lastPercent; // start at 12 o'clock and go clockwise
+ var angleDelta = 2 * Math.PI * percent;
+ var angleEnd = angleStart + angleDelta;
+
+ // ignore if
+ // - zero size
+ // - we're already beyond the full circle
+ // - adding the current slice would go beyond the full circle
+ if( size === 0 || lastPercent >= 1 || lastPercent + percent > 1 ){
+ continue;
+ }
+
+ context.beginPath();
+ context.moveTo(x, y);
+ context.arc( x, y, radius, angleStart, angleEnd );
+ context.closePath();
+
+ this.fillStyle(context, color[0], color[1], color[2], opacity);
+
+ context.fill();
+
+ lastPercent += percent;
+ }
+
+};
+
+
+module.exports = CRp;
+
+},{"../../../is":77}],67:[function(_dereq_,module,exports){
+'use strict';
+
+var CRp = {};
+
+var util = _dereq_('../../../util');
+var math = _dereq_('../../../math');
+
+var motionBlurDelay = 100;
+
+// var isFirefox = typeof InstallTrigger !== 'undefined';
+
+CRp.getPixelRatio = function(){
+ var context = this.data.contexts[0];
+
+ if( this.forcedPixelRatio != null ){
+ return this.forcedPixelRatio;
+ }
+
+ var backingStore = context.backingStorePixelRatio ||
+ context.webkitBackingStorePixelRatio ||
+ context.mozBackingStorePixelRatio ||
+ context.msBackingStorePixelRatio ||
+ context.oBackingStorePixelRatio ||
+ context.backingStorePixelRatio || 1;
+
+ return (window.devicePixelRatio || 1) / backingStore;
+};
+
+CRp.paintCache = function(context){
+ var caches = this.paintCaches = this.paintCaches || [];
+ var needToCreateCache = true;
+ var cache;
+
+ for(var i = 0; i < caches.length; i++ ){
+ cache = caches[i];
+
+ if( cache.context === context ){
+ needToCreateCache = false;
+ break;
+ }
+ }
+
+ if( needToCreateCache ){
+ cache = {
+ context: context
+ };
+ caches.push( cache );
+ }
+
+ return cache;
+};
+
+CRp.fillStyle = function(context, r, g, b, a){
+ context.fillStyle = 'rgba(' + r + ',' + g + ',' + b + ',' + a + ')';
+
+ // turn off for now, seems context does its own caching
+
+ // var cache = this.paintCache(context);
+
+ // var fillStyle = 'rgba(' + r + ',' + g + ',' + b + ',' + a + ')';
+
+ // if( cache.fillStyle !== fillStyle ){
+ // context.fillStyle = cache.fillStyle = fillStyle;
+ // }
+};
+
+CRp.strokeStyle = function(context, r, g, b, a){
+ context.strokeStyle = 'rgba(' + r + ',' + g + ',' + b + ',' + a + ')';
+
+ // turn off for now, seems context does its own caching
+
+ // var cache = this.paintCache(context);
+
+ // var strokeStyle = 'rgba(' + r + ',' + g + ',' + b + ',' + a + ')';
+
+ // if( cache.strokeStyle !== strokeStyle ){
+ // context.strokeStyle = cache.strokeStyle = strokeStyle;
+ // }
+};
+
+CRp.shadowStyle = function(context, color, opacity, blur, offsetX, offsetY){
+ var zoom = this.cy.zoom();
+
+ var cache = this.paintCache(context);
+
+ // don't make expensive changes to the shadow style if it's not used
+ if( cache.shadowOpacity === 0 && opacity === 0 ){
+ return;
+ }
+
+ cache.shadowOpacity = opacity;
+
+ if (opacity > 0) {
+ context.shadowBlur = blur * zoom;
+ context.shadowColor = "rgba(" + color[0] + "," + color[1] + "," + color[2] + "," + opacity + ")";
+ context.shadowOffsetX = offsetX * zoom;
+ context.shadowOffsetY = offsetY * zoom;
+ } else {
+ context.shadowBlur = 0;
+ context.shadowColor = "transparent";
+ }
+};
+
+// Resize canvas
+CRp.matchCanvasSize = function(container) {
+ var r = this;
+ var data = r.data;
+ var width = container.clientWidth;
+ var height = container.clientHeight;
+ var pixelRatio = r.getPixelRatio();
+ var mbPxRatio = r.motionBlurPxRatio;
+
+ if(
+ container === r.data.bufferCanvases[r.MOTIONBLUR_BUFFER_NODE] ||
+ container === r.data.bufferCanvases[r.MOTIONBLUR_BUFFER_DRAG]
+ ){
+ pixelRatio = mbPxRatio;
+ }
+
+ var canvasWidth = width * pixelRatio;
+ var canvasHeight = height * pixelRatio;
+ var canvas;
+
+ if( canvasWidth === r.canvasWidth && canvasHeight === r.canvasHeight ){
+ return; // save cycles if same
+ }
+
+ r.fontCaches = null; // resizing resets the style
+
+ var canvasContainer = data.canvasContainer;
+ canvasContainer.style.width = width + 'px';
+ canvasContainer.style.height = height + 'px';
+
+ for (var i = 0; i < r.CANVAS_LAYERS; i++) {
+
+ canvas = data.canvases[i];
+
+ if (canvas.width !== canvasWidth || canvas.height !== canvasHeight) {
+
+ canvas.width = canvasWidth;
+ canvas.height = canvasHeight;
+
+ canvas.style.width = width + 'px';
+ canvas.style.height = height + 'px';
+ }
+ }
+
+ for (var i = 0; i < r.BUFFER_COUNT; i++) {
+
+ canvas = data.bufferCanvases[i];
+
+ if (canvas.width !== canvasWidth || canvas.height !== canvasHeight) {
+
+ canvas.width = canvasWidth;
+ canvas.height = canvasHeight;
+
+ canvas.style.width = width + 'px';
+ canvas.style.height = height + 'px';
+ }
+ }
+
+ r.textureMult = 1;
+ if( pixelRatio <= 1 ){
+ canvas = data.bufferCanvases[ r.TEXTURE_BUFFER ];
+
+ r.textureMult = 2;
+ canvas.width = canvasWidth * r.textureMult;
+ canvas.height = canvasHeight * r.textureMult;
+ }
+
+ r.canvasWidth = canvasWidth;
+ r.canvasHeight = canvasHeight;
+
+};
+
+CRp.renderTo = function( cxt, zoom, pan, pxRatio ){
+ this.render({
+ forcedContext: cxt,
+ forcedZoom: zoom,
+ forcedPan: pan,
+ drawAllLayers: true,
+ forcedPxRatio: pxRatio
+ });
+};
+
+CRp.render = function( options ) {
+ options = options || util.staticEmptyObject();
+
+ var forcedContext = options.forcedContext;
+ var drawAllLayers = options.drawAllLayers;
+ var drawOnlyNodeLayer = options.drawOnlyNodeLayer;
+ var forcedZoom = options.forcedZoom;
+ var forcedPan = options.forcedPan;
+ var r = this;
+ var pixelRatio = options.forcedPxRatio === undefined ? this.getPixelRatio() : options.forcedPxRatio;
+ var cy = r.cy; var data = r.data;
+ var needDraw = data.canvasNeedsRedraw;
+ var textureDraw = r.textureOnViewport && !forcedContext && (r.pinching || r.hoverData.dragging || r.swipePanning || r.data.wheelZooming);
+ var motionBlur = options.motionBlur !== undefined ? options.motionBlur : r.motionBlur;
+ var mbPxRatio = r.motionBlurPxRatio;
+ var hasCompoundNodes = cy.hasCompoundNodes();
+ var inNodeDragGesture = r.hoverData.draggingEles;
+ var inBoxSelection = r.hoverData.selecting || r.touchData.selecting ? true : false;
+ motionBlur = motionBlur && !forcedContext && r.motionBlurEnabled && !inBoxSelection;
+ var motionBlurFadeEffect = motionBlur;
+
+ if( !forcedContext && r.motionBlurTimeout ){
+ clearTimeout( r.motionBlurTimeout );
+ }
+
+ if( motionBlur ){
+ if( r.mbFrames == null ){
+ r.mbFrames = 0;
+ }
+
+ if( !r.drawingImage ){ // image loading frames don't count towards motion blur blurry frames
+ r.mbFrames++;
+ }
+
+ if( r.mbFrames < 3 ){ // need several frames before even high quality motionblur
+ motionBlurFadeEffect = false;
+ }
+
+ // go to lower quality blurry frames when several m/b frames have been rendered (avoids flashing)
+ if( r.mbFrames > r.minMbLowQualFrames ){
+ //r.fullQualityMb = false;
+ r.motionBlurPxRatio = r.mbPxRBlurry;
+ }
+ }
+
+ if( r.clearingMotionBlur ){
+ r.motionBlurPxRatio = 1;
+ }
+
+ // b/c drawToContext() may be async w.r.t. redraw(), keep track of last texture frame
+ // because a rogue async texture frame would clear needDraw
+ if( r.textureDrawLastFrame && !textureDraw ){
+ needDraw[r.NODE] = true;
+ needDraw[r.SELECT_BOX] = true;
+ }
+
+ var edges = r.getCachedEdges();
+ var coreStyle = cy.style()._private.coreStyle;
+
+ var zoom = cy.zoom();
+ var effectiveZoom = forcedZoom !== undefined ? forcedZoom : zoom;
+ var pan = cy.pan();
+ var effectivePan = {
+ x: pan.x,
+ y: pan.y
+ };
+
+ var vp = {
+ zoom: zoom,
+ pan: {
+ x: pan.x,
+ y: pan.y
+ }
+ };
+ var prevVp = r.prevViewport;
+ var viewportIsDiff = prevVp === undefined || vp.zoom !== prevVp.zoom || vp.pan.x !== prevVp.pan.x || vp.pan.y !== prevVp.pan.y;
+
+ // we want the low quality motionblur only when the viewport is being manipulated etc (where it's not noticed)
+ if( !viewportIsDiff && !(inNodeDragGesture && !hasCompoundNodes) ){
+ r.motionBlurPxRatio = 1;
+ }
+
+ if( forcedPan ){
+ effectivePan = forcedPan;
+ }
+
+ // apply pixel ratio
+
+ effectiveZoom *= pixelRatio;
+ effectivePan.x *= pixelRatio;
+ effectivePan.y *= pixelRatio;
+
+ var eles = {
+ drag: {
+ nodes: [],
+ edges: [],
+ eles: []
+ },
+ nondrag: {
+ nodes: [],
+ edges: [],
+ eles: []
+ }
+ };
+
+ function mbclear( context, x, y, w, h ){
+ var gco = context.globalCompositeOperation;
+
+ context.globalCompositeOperation = 'destination-out';
+ r.fillStyle( context, 255, 255, 255, r.motionBlurTransparency );
+ context.fillRect(x, y, w, h);
+
+ context.globalCompositeOperation = gco;
+ }
+
+ function setContextTransform(context, clear){
+ var ePan, eZoom, w, h;
+
+ if( !r.clearingMotionBlur && (context === data.bufferContexts[r.MOTIONBLUR_BUFFER_NODE] || context === data.bufferContexts[r.MOTIONBLUR_BUFFER_DRAG]) ){
+ ePan = {
+ x: pan.x * mbPxRatio,
+ y: pan.y * mbPxRatio
+ };
+
+ eZoom = zoom * mbPxRatio;
+
+ w = r.canvasWidth * mbPxRatio;
+ h = r.canvasHeight * mbPxRatio;
+ } else {
+ ePan = effectivePan;
+ eZoom = effectiveZoom;
+
+ w = r.canvasWidth;
+ h = r.canvasHeight;
+ }
+
+ context.setTransform(1, 0, 0, 1, 0, 0);
+
+ if( clear === 'motionBlur' ){
+ mbclear(context, 0, 0, w, h);
+ } else if( !forcedContext && (clear === undefined || clear) ){
+ context.clearRect(0, 0, w, h);
+ }
+
+ if( !drawAllLayers ){
+ context.translate( ePan.x, ePan.y );
+ context.scale( eZoom, eZoom );
+ }
+ if( forcedPan ){
+ context.translate( forcedPan.x, forcedPan.y );
+ }
+ if( forcedZoom ){
+ context.scale( forcedZoom, forcedZoom );
+ }
+ }
+
+ if( !textureDraw ){
+ r.textureDrawLastFrame = false;
+ }
+
+ if( textureDraw ){
+ r.textureDrawLastFrame = true;
+
+ var bb;
+
+ if( !r.textureCache ){
+ r.textureCache = {};
+
+ bb = r.textureCache.bb = cy.elements().boundingBox();
+
+ r.textureCache.texture = r.data.bufferCanvases[ r.TEXTURE_BUFFER ];
+
+ var cxt = r.data.bufferContexts[ r.TEXTURE_BUFFER ];
+
+ cxt.setTransform(1, 0, 0, 1, 0, 0);
+ cxt.clearRect(0, 0, r.canvasWidth * r.textureMult, r.canvasHeight * r.textureMult);
+
+ r.render({
+ forcedContext: cxt,
+ drawOnlyNodeLayer: true,
+ forcedPxRatio: pixelRatio * r.textureMult
+ });
+
+ var vp = r.textureCache.viewport = {
+ zoom: cy.zoom(),
+ pan: cy.pan(),
+ width: r.canvasWidth,
+ height: r.canvasHeight
+ };
+
+ vp.mpan = {
+ x: (0 - vp.pan.x)/vp.zoom,
+ y: (0 - vp.pan.y)/vp.zoom
+ };
+ }
+
+ needDraw[r.DRAG] = false;
+ needDraw[r.NODE] = false;
+
+ var context = data.contexts[r.NODE];
+
+ var texture = r.textureCache.texture;
+ var vp = r.textureCache.viewport;
+ bb = r.textureCache.bb;
+
+ context.setTransform(1, 0, 0, 1, 0, 0);
+
+ if( motionBlur ){
+ mbclear(context, 0, 0, vp.width, vp.height);
+ } else {
+ context.clearRect(0, 0, vp.width, vp.height);
+ }
+
+ var outsideBgColor = coreStyle['outside-texture-bg-color'].value;
+ var outsideBgOpacity = coreStyle['outside-texture-bg-opacity'].value;
+ r.fillStyle( context, outsideBgColor[0], outsideBgColor[1], outsideBgColor[2], outsideBgOpacity );
+ context.fillRect( 0, 0, vp.width, vp.height );
+
+ var zoom = cy.zoom();
+
+ setContextTransform( context, false );
+
+ context.clearRect( vp.mpan.x, vp.mpan.y, vp.width/vp.zoom/pixelRatio, vp.height/vp.zoom/pixelRatio );
+ context.drawImage( texture, vp.mpan.x, vp.mpan.y, vp.width/vp.zoom/pixelRatio, vp.height/vp.zoom/pixelRatio );
+
+ } else if( r.textureOnViewport && !forcedContext ){ // clear the cache since we don't need it
+ r.textureCache = null;
+ }
+
+ var vpManip = (r.pinching || r.hoverData.dragging || r.swipePanning || r.data.wheelZooming || r.hoverData.draggingEles);
+ var hideEdges = r.hideEdgesOnViewport && vpManip;
+ var hideLabels = r.hideLabelsOnViewport && vpManip;
+
+ if (needDraw[r.DRAG] || needDraw[r.NODE] || drawAllLayers || drawOnlyNodeLayer) {
+ if( hideEdges ){
+ } else {
+ r.findEdgeControlPoints(edges);
+ }
+
+ var zEles = r.getCachedZSortedEles();
+ var extent = cy.extent();
+
+ for (var i = 0; i < zEles.length; i++) {
+ var ele = zEles[i];
+ var list;
+ var bb = forcedContext ? null : ele.boundingBox();
+ var insideExtent = forcedContext ? true : math.boundingBoxesIntersect( extent, bb );
+
+ if( !insideExtent ){ continue; } // no need to render
+
+ if ( ele._private.rscratch.inDragLayer ) {
+ list = eles.drag;
+ } else {
+ list = eles.nondrag;
+ }
+
+ list.eles.push( ele );
+ }
+
+ }
+
+
+ function drawElements( list, context ){
+ var eles = list.eles;
+
+ for( var i = 0; i < eles.length; i++ ){
+ var ele = eles[i];
+
+ if( ele.isNode() ){
+ r.drawNode(context, ele);
+
+ if( !hideLabels ){
+ r.drawNodeText(context, ele);
+ }
+
+ r.drawNode(context, ele, true);
+ } else if( !hideEdges ) {
+ r.drawEdge(context, ele);
+
+ if( !hideLabels ){
+ r.drawEdgeText(context, ele);
+ }
+
+ r.drawEdge(context, ele, true);
+ }
+
+
+ }
+
+ }
+
+ var needMbClear = [];
+
+ needMbClear[r.NODE] = !needDraw[r.NODE] && motionBlur && !r.clearedForMotionBlur[r.NODE] || r.clearingMotionBlur;
+ if( needMbClear[r.NODE] ){ r.clearedForMotionBlur[r.NODE] = true; }
+
+ needMbClear[r.DRAG] = !needDraw[r.DRAG] && motionBlur && !r.clearedForMotionBlur[r.DRAG] || r.clearingMotionBlur;
+ if( needMbClear[r.DRAG] ){ r.clearedForMotionBlur[r.DRAG] = true; }
+
+ if( needDraw[r.NODE] || drawAllLayers || drawOnlyNodeLayer || needMbClear[r.NODE] ){
+ var useBuffer = motionBlur && !needMbClear[r.NODE] && mbPxRatio !== 1;
+ var context = forcedContext || ( useBuffer ? r.data.bufferContexts[ r.MOTIONBLUR_BUFFER_NODE ] : data.contexts[r.NODE] );
+ var clear = motionBlur && !useBuffer ? 'motionBlur' : undefined;
+
+ setContextTransform( context, clear );
+ drawElements(eles.nondrag, context);
+
+ if( !drawAllLayers && !motionBlur ){
+ needDraw[r.NODE] = false;
+ }
+ }
+
+ if ( !drawOnlyNodeLayer && (needDraw[r.DRAG] || drawAllLayers || needMbClear[r.DRAG]) ) {
+ var useBuffer = motionBlur && !needMbClear[r.DRAG] && mbPxRatio !== 1;
+ var context = forcedContext || ( useBuffer ? r.data.bufferContexts[ r.MOTIONBLUR_BUFFER_DRAG ] : data.contexts[r.DRAG] );
+
+ setContextTransform( context, motionBlur && !useBuffer ? 'motionBlur' : undefined );
+ drawElements(eles.drag, context);
+
+ if( !drawAllLayers && !motionBlur ){
+ needDraw[r.DRAG] = false;
+ }
+ }
+
+ if( r.showFps || (!drawOnlyNodeLayer && (needDraw[r.SELECT_BOX] && !drawAllLayers)) ) {
+ var context = forcedContext || data.contexts[r.SELECT_BOX];
+
+ setContextTransform( context );
+
+ if( r.selection[4] == 1 && ( r.hoverData.selecting || r.touchData.selecting ) ){
+ var zoom = r.cy.zoom();
+ var borderWidth = coreStyle['selection-box-border-width'].value / zoom;
+
+ context.lineWidth = borderWidth;
+ context.fillStyle = "rgba("
+ + coreStyle['selection-box-color'].value[0] + ","
+ + coreStyle['selection-box-color'].value[1] + ","
+ + coreStyle['selection-box-color'].value[2] + ","
+ + coreStyle['selection-box-opacity'].value + ")";
+
+ context.fillRect(
+ r.selection[0],
+ r.selection[1],
+ r.selection[2] - r.selection[0],
+ r.selection[3] - r.selection[1]);
+
+ if (borderWidth > 0) {
+ context.strokeStyle = "rgba("
+ + coreStyle['selection-box-border-color'].value[0] + ","
+ + coreStyle['selection-box-border-color'].value[1] + ","
+ + coreStyle['selection-box-border-color'].value[2] + ","
+ + coreStyle['selection-box-opacity'].value + ")";
+
+ context.strokeRect(
+ r.selection[0],
+ r.selection[1],
+ r.selection[2] - r.selection[0],
+ r.selection[3] - r.selection[1]);
+ }
+ }
+
+ if( data.bgActivePosistion && !r.hoverData.selecting ){
+ var zoom = r.cy.zoom();
+ var pos = data.bgActivePosistion;
+
+ context.fillStyle = "rgba("
+ + coreStyle['active-bg-color'].value[0] + ","
+ + coreStyle['active-bg-color'].value[1] + ","
+ + coreStyle['active-bg-color'].value[2] + ","
+ + coreStyle['active-bg-opacity'].value + ")";
+
+ context.beginPath();
+ context.arc(pos.x, pos.y, coreStyle['active-bg-size'].pfValue / zoom, 0, 2 * Math.PI);
+ context.fill();
+ }
+
+ var timeToRender = r.lastRedrawTime;
+ if( r.showFps && timeToRender ){
+ timeToRender = Math.round( timeToRender );
+ var fps = Math.round(1000/timeToRender);
+
+ context.setTransform(1, 0, 0, 1, 0, 0);
+
+ context.fillStyle = 'rgba(255, 0, 0, 0.75)';
+ context.strokeStyle = 'rgba(255, 0, 0, 0.75)';
+ context.lineWidth = 1;
+ context.fillText( '1 frame = ' + timeToRender + ' ms = ' + fps + ' fps', 0, 20);
+
+ var maxFps = 60;
+ context.strokeRect(0, 30, 250, 20);
+ context.fillRect(0, 30, 250 * Math.min(fps/maxFps, 1), 20);
+ }
+
+ if( !drawAllLayers ){
+ needDraw[r.SELECT_BOX] = false;
+ }
+ }
+
+ // motionblur: blit rendered blurry frames
+ if( motionBlur && mbPxRatio !== 1 ){
+ var cxtNode = data.contexts[r.NODE];
+ var txtNode = r.data.bufferCanvases[ r.MOTIONBLUR_BUFFER_NODE ];
+
+ var cxtDrag = data.contexts[r.DRAG];
+ var txtDrag = r.data.bufferCanvases[ r.MOTIONBLUR_BUFFER_DRAG ];
+
+ var drawMotionBlur = function( cxt, txt, needClear ){
+ cxt.setTransform(1, 0, 0, 1, 0, 0);
+
+ if( needClear || !motionBlurFadeEffect ){
+ cxt.clearRect( 0, 0, r.canvasWidth, r.canvasHeight );
+ } else {
+ mbclear( cxt, 0, 0, r.canvasWidth, r.canvasHeight );
+ }
+
+ var pxr = mbPxRatio;
+
+ cxt.drawImage(
+ txt, // img
+ 0, 0, // sx, sy
+ r.canvasWidth * pxr, r.canvasHeight * pxr, // sw, sh
+ 0, 0, // x, y
+ r.canvasWidth, r.canvasHeight // w, h
+ );
+ };
+
+ if( needDraw[r.NODE] || needMbClear[r.NODE] ){
+ drawMotionBlur( cxtNode, txtNode, needMbClear[r.NODE] );
+ needDraw[r.NODE] = false;
+ }
+
+ if( needDraw[r.DRAG] || needMbClear[r.DRAG] ){
+ drawMotionBlur( cxtDrag, txtDrag, needMbClear[r.DRAG] );
+ needDraw[r.DRAG] = false;
+ }
+ }
+
+ r.currentlyDrawing = false;
+
+ r.prevViewport = vp;
+
+ if( r.clearingMotionBlur ){
+ r.clearingMotionBlur = false;
+ r.motionBlurCleared = true;
+ r.motionBlur = true;
+ }
+
+ if( motionBlur ){
+ r.motionBlurTimeout = setTimeout(function(){
+ r.motionBlurTimeout = null;
+
+ r.clearedForMotionBlur[r.NODE] = false;
+ r.clearedForMotionBlur[r.DRAG] = false;
+ r.motionBlur = false;
+ r.clearingMotionBlur = !textureDraw;
+ r.mbFrames = 0;
+
+ needDraw[r.NODE] = true;
+ needDraw[r.DRAG] = true;
+
+ r.redraw();
+ }, motionBlurDelay);
+ }
+
+ r.drawingImage = false;
+
+
+ if( !forcedContext && !r.initrender ){
+ r.initrender = true;
+ cy.trigger('initrender');
+ }
+
+ if( !forcedContext ){
+ cy.triggerOnRender();
+ }
+
+};
+
+module.exports = CRp;
+
+},{"../../../math":79,"../../../util":94}],68:[function(_dereq_,module,exports){
+'use strict';
+
+ var math = _dereq_('../../../math');
+
+ var CRp = {};
+
+ // @O Polygon drawing
+ CRp.drawPolygonPath = function(
+ context, x, y, width, height, points) {
+
+ var halfW = width / 2;
+ var halfH = height / 2;
+
+ if( context.beginPath ){ context.beginPath(); }
+
+ context.moveTo( x + halfW * points[0], y + halfH * points[1] );
+
+ for (var i = 1; i < points.length / 2; i++) {
+ context.lineTo( x + halfW * points[i * 2], y + halfH * points[i * 2 + 1] );
+ }
+
+ context.closePath();
+ };
+
+ // Round rectangle drawing
+ CRp.drawRoundRectanglePath = function(
+ context, x, y, width, height, radius) {
+
+ var halfWidth = width / 2;
+ var halfHeight = height / 2;
+ var cornerRadius = math.getRoundRectangleRadius(width, height);
+
+ if( context.beginPath ){ context.beginPath(); }
+
+ // Start at top middle
+ context.moveTo(x, y - halfHeight);
+ // Arc from middle top to right side
+ context.arcTo(x + halfWidth, y - halfHeight, x + halfWidth, y, cornerRadius);
+ // Arc from right side to bottom
+ context.arcTo(x + halfWidth, y + halfHeight, x, y + halfHeight, cornerRadius);
+ // Arc from bottom to left side
+ context.arcTo(x - halfWidth, y + halfHeight, x - halfWidth, y, cornerRadius);
+ // Arc from left side to topBorder
+ context.arcTo(x - halfWidth, y - halfHeight, x, y - halfHeight, cornerRadius);
+ // Join line
+ context.lineTo(x, y - halfHeight);
+
+
+ context.closePath();
+ };
+
+ var sin0 = Math.sin(0);
+ var cos0 = Math.cos(0);
+
+ var sin = {};
+ var cos = {};
+
+ var ellipseStepSize = Math.PI / 40;
+
+ for (var i = 0 * Math.PI; i < 2 * Math.PI; i += ellipseStepSize ) {
+ sin[i] = Math.sin(i);
+ cos[i] = Math.cos(i);
+ }
+
+ CRp.drawEllipsePath = function(context, centerX, centerY, width, height){
+ if( context.beginPath ){ context.beginPath(); }
+
+ if( context.ellipse ){
+ context.ellipse( centerX, centerY, width/2, height/2, 0, 0, 2*Math.PI );
+ } else {
+ var xPos, yPos;
+ var rw = width/2;
+ var rh = height/2;
+ for (var i = 0 * Math.PI; i < 2 * Math.PI; i += ellipseStepSize ) {
+ xPos = centerX - (rw * sin[i]) * sin0 + (rw * cos[i]) * cos0;
+ yPos = centerY + (rh * cos[i]) * sin0 + (rh * sin[i]) * cos0;
+
+ if (i === 0) {
+ context.moveTo(xPos, yPos);
+ } else {
+ context.lineTo(xPos, yPos);
+ }
+ }
+ }
+
+ context.closePath();
+ };
+
+module.exports = CRp;
+
+},{"../../../math":79}],69:[function(_dereq_,module,exports){
+'use strict';
+
+var is = _dereq_('../../../is');
+
+var CRp = {};
+
+CRp.createBuffer = function(w, h) {
+ var buffer = document.createElement('canvas');
+ buffer.width = w;
+ buffer.height = h;
+
+ return [buffer, buffer.getContext('2d')];
+};
+
+CRp.bufferCanvasImage = function( options ){
+ var cy = this.cy;
+ var bb = cy.elements().boundingBox();
+ var width = options.full ? Math.ceil(bb.w) : this.container.clientWidth;
+ var height = options.full ? Math.ceil(bb.h) : this.container.clientHeight;
+ var scale = 1;
+
+ if( options.scale !== undefined ){
+ width *= options.scale;
+ height *= options.scale;
+
+ scale = options.scale;
+ } else if( is.number(options.maxWidth) || is.number(options.maxHeight) ){
+ var maxScaleW = Infinity;
+ var maxScaleH = Infinity;
+
+ if( is.number(options.maxWidth) ){
+ maxScaleW = scale * options.maxWidth / width;
+ }
+
+ if( is.number(options.maxHeight) ){
+ maxScaleH = scale * options.maxHeight / height;
+ }
+
+ scale = Math.min( maxScaleW, maxScaleH );
+
+ width *= scale;
+ height *= scale;
+ }
+
+ var buffCanvas = document.createElement('canvas');
+
+ buffCanvas.width = width;
+ buffCanvas.height = height;
+
+ buffCanvas.style.width = width + 'px';
+ buffCanvas.style.height = height + 'px';
+
+ var buffCxt = buffCanvas.getContext('2d');
+
+ // Rasterize the layers, but only if container has nonzero size
+ if (width > 0 && height > 0) {
+
+ buffCxt.clearRect( 0, 0, width, height );
+
+ if( options.bg ){
+ buffCxt.fillStyle = options.bg;
+ buffCxt.rect( 0, 0, width, height );
+ buffCxt.fill();
+ }
+
+ buffCxt.globalCompositeOperation = 'source-over';
+
+ if( options.full ){ // draw the full bounds of the graph
+ this.render({
+ forcedContext: buffCxt,
+ drawAllLayers: true,
+ forcedZoom: scale,
+ forcedPan: { x: -bb.x1*scale, y: -bb.y1*scale },
+ forcedPxRatio: 1
+ });
+ } else { // draw the current view
+ var cyPan = cy.pan();
+ var pan = {
+ x: cyPan.x * scale,
+ y: cyPan.y * scale
+ };
+ var zoom = cy.zoom() * scale;
+
+ this.render({
+ forcedContext: buffCxt,
+ drawAllLayers: true,
+ forcedZoom: zoom,
+ forcedPan: pan,
+ forcedPxRatio: 1
+ });
+ }
+ }
+
+ return buffCanvas;
+};
+
+CRp.png = function( options ){
+ return this.bufferCanvasImage( options ).toDataURL('image/png');
+};
+
+CRp.jpg = function( options ){
+ return this.bufferCanvasImage( options ).toDataURL('image/jpeg');
+};
+
+module.exports = CRp;
+
+},{"../../../is":77}],70:[function(_dereq_,module,exports){
+/*
+The canvas renderer was written by Yue Dong.
+
+Modifications tracked on Github.
+*/
+
+'use strict';
+
+var util = _dereq_('../../../util');
+var is = _dereq_('../../../is');
+
+var CR = CanvasRenderer;
+var CRp = CanvasRenderer.prototype;
+
+CRp.CANVAS_LAYERS = 3;
+//
+CRp.SELECT_BOX = 0;
+CRp.DRAG = 1;
+CRp.NODE = 2;
+
+CRp.BUFFER_COUNT = 3;
+//
+CRp.TEXTURE_BUFFER = 0;
+CRp.MOTIONBLUR_BUFFER_NODE = 1;
+CRp.MOTIONBLUR_BUFFER_DRAG = 2;
+
+function CanvasRenderer(options) {
+ var r = this;
+
+ r.data = {
+ canvases: new Array(CRp.CANVAS_LAYERS),
+ contexts: new Array(CRp.CANVAS_LAYERS),
+ canvasNeedsRedraw: new Array(CRp.CANVAS_LAYERS),
+
+ bufferCanvases: new Array(CRp.BUFFER_COUNT),
+ bufferContexts: new Array(CRp.CANVAS_LAYERS)
+ };
+
+ r.data.canvasContainer = document.createElement('div');
+ var containerStyle = r.data.canvasContainer.style;
+ r.data.canvasContainer.setAttribute('style', '-webkit-tap-highlight-color: rgba(0,0,0,0);');
+ containerStyle.position = 'relative';
+ containerStyle.zIndex = '0';
+ containerStyle.overflow = 'hidden';
+
+ var container = options.cy.container();
+ container.appendChild( r.data.canvasContainer );
+ container.setAttribute('style', ( container.getAttribute('style') || '' ) + '-webkit-tap-highlight-color: rgba(0,0,0,0);');
+
+ for (var i = 0; i < CRp.CANVAS_LAYERS; i++) {
+ var canvas = r.data.canvases[i] = document.createElement('canvas');
+ r.data.contexts[i] = canvas.getContext('2d');
+ canvas.setAttribute( 'style', '-webkit-user-select: none; -moz-user-select: -moz-none; user-select: none; -webkit-tap-highlight-color: rgba(0,0,0,0); outline-style: none;' + ( is.ms() ? ' -ms-touch-action: none; touch-action: none; ' : '' ) );
+ canvas.style.position = 'absolute';
+ canvas.setAttribute('data-id', 'layer' + i);
+ canvas.style.zIndex = String(CRp.CANVAS_LAYERS - i);
+ r.data.canvasContainer.appendChild(canvas);
+
+ r.data.canvasNeedsRedraw[i] = false;
+ }
+ r.data.topCanvas = r.data.canvases[0];
+
+ r.data.canvases[CRp.NODE].setAttribute('data-id', 'layer' + CRp.NODE + '-node');
+ r.data.canvases[CRp.SELECT_BOX].setAttribute('data-id', 'layer' + CRp.SELECT_BOX + '-selectbox');
+ r.data.canvases[CRp.DRAG].setAttribute('data-id', 'layer' + CRp.DRAG + '-drag');
+
+ for (var i = 0; i < CRp.BUFFER_COUNT; i++) {
+ r.data.bufferCanvases[i] = document.createElement('canvas');
+ r.data.bufferContexts[i] = r.data.bufferCanvases[i].getContext('2d');
+ r.data.bufferCanvases[i].style.position = 'absolute';
+ r.data.bufferCanvases[i].setAttribute('data-id', 'buffer' + i);
+ r.data.bufferCanvases[i].style.zIndex = String(-i - 1);
+ r.data.bufferCanvases[i].style.visibility = 'hidden';
+ //r.data.canvasContainer.appendChild(r.data.bufferCanvases[i]);
+ }
+
+ r.pathsEnabled = true;
+}
+
+CRp.redrawHint = function( group, bool ){
+ var r = this;
+
+ switch( group ){
+ case 'eles':
+ r.data.canvasNeedsRedraw[ CRp.NODE ] = bool;
+ break;
+ case 'drag':
+ r.data.canvasNeedsRedraw[ CRp.DRAG ] = bool;
+ break;
+ case 'select':
+ r.data.canvasNeedsRedraw[ CRp.SELECT_BOX ] = bool;
+ break;
+ }
+};
+
+// whether to use Path2D caching for drawing
+var pathsImpld = typeof Path2D !== 'undefined';
+
+CRp.path2dEnabled = function( on ){
+ if( on === undefined ){
+ return this.pathsEnabled;
+ }
+
+ this.pathsEnabled = on ? true : false;
+};
+
+CRp.usePaths = function(){
+ return pathsImpld && this.pathsEnabled;
+};
+
+[
+ _dereq_('./arrow-shapes'),
+ _dereq_('./drawing-edges'),
+ _dereq_('./drawing-images'),
+ _dereq_('./drawing-label-text'),
+ _dereq_('./drawing-nodes'),
+ _dereq_('./drawing-redraw'),
+ _dereq_('./drawing-shapes'),
+ _dereq_('./export-image'),
+ _dereq_('./node-shapes')
+].forEach(function( props ){
+ util.extend( CRp, props );
+});
+
+module.exports = CR;
+
+},{"../../../is":77,"../../../util":94,"./arrow-shapes":62,"./drawing-edges":63,"./drawing-images":64,"./drawing-label-text":65,"./drawing-nodes":66,"./drawing-redraw":67,"./drawing-shapes":68,"./export-image":69,"./node-shapes":71}],71:[function(_dereq_,module,exports){
+'use strict';
+
+var CRp = {};
+
+var impl;
+
+CRp.nodeShapeImpl = function( name ){
+ var self = this;
+
+ return ( impl || (impl = {
+ 'ellipse': function( context, centerX, centerY, width, height ){
+ self.drawEllipsePath( context, centerX, centerY, width, height );
+ },
+
+ 'polygon': function( context, centerX, centerY, width, height, points ){
+ self.drawPolygonPath( context, centerX, centerY, width, height, points );
+ },
+
+ 'roundrectangle': function( context, centerX, centerY, width, height ){
+ self.drawRoundRectanglePath( context, centerX, centerY, width, height, 10 );
+ }
+ }) )[ name ];
+};
+
+module.exports = CRp;
+
+},{}],72:[function(_dereq_,module,exports){
+'use strict';
+
+module.exports = [
+ { name: 'null', impl: _dereq_('./null') },
+ { name: 'base', impl: _dereq_('./base') },
+ { name: 'canvas', impl: _dereq_('./canvas') }
+];
+
+},{"./base":58,"./canvas":70,"./null":73}],73:[function(_dereq_,module,exports){
+'use strict';
+
+function NullRenderer(options){
+ this.options = options;
+ this.notifications = 0; // for testing
+}
+
+var noop = function(){};
+
+NullRenderer.prototype = {
+ recalculateRenderedStyle: noop,
+ notify: function(){ this.notifications++; },
+ init: noop
+};
+
+module.exports = NullRenderer;
+
+},{}],74:[function(_dereq_,module,exports){
+'use strict';
+
+var is = _dereq_('./is');
+var util = _dereq_('./util');
+var Thread = _dereq_('./thread');
+var Promise = _dereq_('./promise');
+var define = _dereq_('./define');
+
+var Fabric = function( N ){
+ if( !(this instanceof Fabric) ){
+ return new Fabric( N );
+ }
+
+ this._private = {
+ pass: []
+ };
+
+ var defN = 4;
+
+ if( is.number(N) ){
+ // then use the specified number of threads
+ } if( typeof navigator !== 'undefined' && navigator.hardwareConcurrency != null ){
+ N = navigator.hardwareConcurrency;
+ } else {
+ try{
+ N = _dereq_('os').cpus().length;
+ } catch( err ){
+ N = defN;
+ }
+ } // TODO could use an estimation here but would the additional expense be worth it?
+
+ for( var i = 0; i < N; i++ ){
+ this[i] = new Thread();
+ }
+
+ this.length = N;
+};
+
+var fabfn = Fabric.prototype; // short alias
+
+util.extend(fabfn, {
+
+ instanceString: function(){ return 'fabric'; },
+
+ // require fn in all threads
+ require: function( fn, as ){
+ for( var i = 0; i < this.length; i++ ){
+ var thread = this[i];
+
+ thread.require( fn, as );
+ }
+
+ return this;
+ },
+
+ // get a random thread
+ random: function(){
+ var i = Math.round( (this.length - 1) * Math.random() );
+ var thread = this[i];
+
+ return thread;
+ },
+
+ // run on random thread
+ run: function( fn ){
+ var pass = this._private.pass.shift();
+
+ return this.random().pass( pass ).run( fn );
+ },
+
+ // sends a random thread a message
+ message: function( m ){
+ return this.random().message( m );
+ },
+
+ // send all threads a message
+ broadcast: function( m ){
+ for( var i = 0; i < this.length; i++ ){
+ var thread = this[i];
+
+ thread.message( m );
+ }
+
+ return this; // chaining
+ },
+
+ // stop all threads
+ stop: function(){
+ for( var i = 0; i < this.length; i++ ){
+ var thread = this[i];
+
+ thread.stop();
+ }
+
+ return this; // chaining
+ },
+
+ // pass data to be used with .spread() etc.
+ pass: function( data ){
+ var pass = this._private.pass;
+
+ if( is.array(data) ){
+ pass.push( data );
+ } else {
+ throw 'Only arrays may be used with fabric.pass()';
+ }
+
+ return this; // chaining
+ },
+
+ spreadSize: function(){
+ var subsize = Math.ceil( this._private.pass[0].length / this.length );
+
+ subsize = Math.max( 1, subsize ); // don't pass less than one ele to each thread
+
+ return subsize;
+ },
+
+ // split the data into slices to spread the data equally among threads
+ spread: function( fn ){
+ var self = this;
+ var _p = self._private;
+ var subsize = self.spreadSize(); // number of pass eles to handle in each thread
+ var pass = _p.pass.shift().concat([]); // keep a copy
+ var runPs = [];
+
+ for( var i = 0; i < this.length; i++ ){
+ var thread = this[i];
+ var slice = pass.splice( 0, subsize );
+
+ var runP = thread.pass( slice ).run( fn );
+
+ runPs.push( runP );
+
+ var doneEarly = pass.length === 0;
+ if( doneEarly ){ break; }
+ }
+
+ return Promise.all( runPs ).then(function( thens ){
+ var postpass = [];
+ var p = 0;
+
+ // fill postpass with the total result joined from all threads
+ for( var i = 0; i < thens.length; i++ ){
+ var then = thens[i]; // array result from thread i
+
+ for( var j = 0; j < then.length; j++ ){
+ var t = then[j]; // array element
+
+ postpass[ p++ ] = t;
+ }
+ }
+
+ return postpass;
+ });
+ },
+
+ // parallel version of array.map()
+ map: function( fn ){
+ var self = this;
+
+ self.require( fn, '_$_$_fabmap' );
+
+ return self.spread(function( split ){
+ var mapped = [];
+ var origResolve = resolve; // jshint ignore:line
+
+ resolve = function( val ){ // jshint ignore:line
+ mapped.push( val );
+ };
+
+ for( var i = 0; i < split.length; i++ ){
+ var oldLen = mapped.length;
+ var ret = _$_$_fabmap( split[i] ); // jshint ignore:line
+ var nothingInsdByResolve = oldLen === mapped.length;
+
+ if( nothingInsdByResolve ){
+ mapped.push( ret );
+ }
+ }
+
+ resolve = origResolve; // jshint ignore:line
+
+ return mapped;
+ });
+
+ },
+
+ // parallel version of array.filter()
+ filter: function( fn ){
+ var _p = this._private;
+ var pass = _p.pass[0];
+
+ return this.map( fn ).then(function( include ){
+ var ret = [];
+
+ for( var i = 0; i < pass.length; i++ ){
+ var datum = pass[i];
+ var incDatum = include[i];
+
+ if( incDatum ){
+ ret.push( datum );
+ }
+ }
+
+ return ret;
+ });
+ },
+
+ // sorts the passed array using a divide and conquer strategy
+ sort: function( cmp ){
+ var self = this;
+ var P = this._private.pass[0].length;
+ var subsize = this.spreadSize();
+
+ cmp = cmp || function( a, b ){ // default comparison function
+ if( a < b ){
+ return -1;
+ } else if( a > b ){
+ return 1;
+ }
+
+ return 0;
+ };
+
+ self.require( cmp, '_$_$_cmp' );
+
+ return self.spread(function( split ){ // sort each split normally
+ var sortedSplit = split.sort( _$_$_cmp ); // jshint ignore:line
+ resolve( sortedSplit ); // jshint ignore:line
+
+ }).then(function( joined ){
+ // do all the merging in the main thread to minimise data transfer
+
+ // TODO could do merging in separate threads but would incur add'l cost of data transfer
+ // for each level of the merge
+
+ var merge = function( i, j, max ){
+ // don't overflow array
+ j = Math.min( j, P );
+ max = Math.min( max, P );
+
+ // left and right sides of merge
+ var l = i;
+ var r = j;
+
+ var sorted = [];
+
+ for( var k = l; k < max; k++ ){
+
+ var eleI = joined[i];
+ var eleJ = joined[j];
+
+ if( i < r && ( j >= max || cmp(eleI, eleJ) <= 0 ) ){
+ sorted.push( eleI );
+ i++;
+ } else {
+ sorted.push( eleJ );
+ j++;
+ }
+
+ }
+
+ // in the array proper, put the sorted values
+ for( var k = 0; k < sorted.length; k++ ){ // kth sorted item
+ var index = l + k;
+
+ joined[ index ] = sorted[k];
+ }
+ };
+
+ for( var splitL = subsize; splitL < P; splitL *= 2 ){ // merge until array is "split" as 1
+
+ for( var i = 0; i < P; i += 2*splitL ){
+ merge( i, i + splitL, i + 2*splitL );
+ }
+
+ }
+
+ return joined;
+ });
+ }
+
+
+});
+
+var defineRandomPasser = function( opts ){
+ opts = opts || {};
+
+ return function( fn, arg1 ){
+ var pass = this._private.pass.shift();
+
+ return this.random().pass( pass )[ opts.threadFn ]( fn, arg1 );
+ };
+};
+
+util.extend(fabfn, {
+ randomMap: defineRandomPasser({ threadFn: 'map' }),
+
+ reduce: defineRandomPasser({ threadFn: 'reduce' }),
+
+ reduceRight: defineRandomPasser({ threadFn: 'reduceRight' })
+});
+
+// aliases
+var fn = fabfn;
+fn.promise = fn.run;
+fn.terminate = fn.halt = fn.stop;
+fn.include = fn.require;
+
+// pull in event apis
+util.extend(fabfn, {
+ on: define.on(),
+ one: define.on({ unbindSelfOnTrigger: true }),
+ off: define.off(),
+ trigger: define.trigger()
+});
+
+define.eventAliasesOn( fabfn );
+
+module.exports = Fabric;
+
+},{"./define":41,"./is":77,"./promise":80,"./thread":92,"./util":94,"os":undefined}],75:[function(_dereq_,module,exports){
+'use strict';
+/* jshint ignore:start */
+
+// Generated by CoffeeScript 1.8.0
+(function() {
+ var Heap, defaultCmp, floor, heapify, heappop, heappush, heappushpop, heapreplace, insort, min, nlargest, nsmallest, updateItem, _siftdown, _siftup;
+
+ floor = Math.floor, min = Math.min;
+
+
+ /*
+ Default comparison function to be used
+ */
+
+ defaultCmp = function(x, y) {
+ if (x < y) {
+ return -1;
+ }
+ if (x > y) {
+ return 1;
+ }
+ return 0;
+ };
+
+
+ /*
+ Insert item x in list a, and keep it sorted assuming a is sorted.
+
+ If x is already in a, insert it to the right of the rightmost x.
+
+ Optional args lo (default 0) and hi (default a.length) bound the slice
+ of a to be searched.
+ */
+
+ insort = function(a, x, lo, hi, cmp) {
+ var mid;
+ if (lo == null) {
+ lo = 0;
+ }
+ if (cmp == null) {
+ cmp = defaultCmp;
+ }
+ if (lo < 0) {
+ throw new Error('lo must be non-negative');
+ }
+ if (hi == null) {
+ hi = a.length;
+ }
+ while (lo < hi) {
+ mid = floor((lo + hi) / 2);
+ if (cmp(x, a[mid]) < 0) {
+ hi = mid;
+ } else {
+ lo = mid + 1;
+ }
+ }
+ return ([].splice.apply(a, [lo, lo - lo].concat(x)), x);
+ };
+
+
+ /*
+ Push item onto heap, maintaining the heap invariant.
+ */
+
+ heappush = function(array, item, cmp) {
+ if (cmp == null) {
+ cmp = defaultCmp;
+ }
+ array.push(item);
+ return _siftdown(array, 0, array.length - 1, cmp);
+ };
+
+
+ /*
+ Pop the smallest item off the heap, maintaining the heap invariant.
+ */
+
+ heappop = function(array, cmp) {
+ var lastelt, returnitem;
+ if (cmp == null) {
+ cmp = defaultCmp;
+ }
+ lastelt = array.pop();
+ if (array.length) {
+ returnitem = array[0];
+ array[0] = lastelt;
+ _siftup(array, 0, cmp);
+ } else {
+ returnitem = lastelt;
+ }
+ return returnitem;
+ };
+
+
+ /*
+ Pop and return the current smallest value, and add the new item.
+
+ This is more efficient than heappop() followed by heappush(), and can be
+ more appropriate when using a fixed size heap. Note that the value
+ returned may be larger than item! That constrains reasonable use of
+ this routine unless written as part of a conditional replacement:
+ if item > array[0]
+ item = heapreplace(array, item)
+ */
+
+ heapreplace = function(array, item, cmp) {
+ var returnitem;
+ if (cmp == null) {
+ cmp = defaultCmp;
+ }
+ returnitem = array[0];
+ array[0] = item;
+ _siftup(array, 0, cmp);
+ return returnitem;
+ };
+
+
+ /*
+ Fast version of a heappush followed by a heappop.
+ */
+
+ heappushpop = function(array, item, cmp) {
+ var _ref;
+ if (cmp == null) {
+ cmp = defaultCmp;
+ }
+ if (array.length && cmp(array[0], item) < 0) {
+ _ref = [array[0], item], item = _ref[0], array[0] = _ref[1];
+ _siftup(array, 0, cmp);
+ }
+ return item;
+ };
+
+
+ /*
+ Transform list into a heap, in-place, in O(array.length) time.
+ */
+
+ heapify = function(array, cmp) {
+ var i, _i, _j, _len, _ref, _ref1, _results, _results1;
+ if (cmp == null) {
+ cmp = defaultCmp;
+ }
+ _ref1 = (function() {
+ _results1 = [];
+ for (var _j = 0, _ref = floor(array.length / 2); 0 <= _ref ? _j < _ref : _j > _ref; 0 <= _ref ? _j++ : _j--){ _results1.push(_j); }
+ return _results1;
+ }).apply(this).reverse();
+ _results = [];
+ for (_i = 0, _len = _ref1.length; _i < _len; _i++) {
+ i = _ref1[_i];
+ _results.push(_siftup(array, i, cmp));
+ }
+ return _results;
+ };
+
+
+ /*
+ Update the position of the given item in the heap.
+ This function should be called every time the item is being modified.
+ */
+
+ updateItem = function(array, item, cmp) {
+ var pos;
+ if (cmp == null) {
+ cmp = defaultCmp;
+ }
+ pos = array.indexOf(item);
+ if (pos === -1) {
+ return;
+ }
+ _siftdown(array, 0, pos, cmp);
+ return _siftup(array, pos, cmp);
+ };
+
+
+ /*
+ Find the n largest elements in a dataset.
+ */
+
+ nlargest = function(array, n, cmp) {
+ var elem, result, _i, _len, _ref;
+ if (cmp == null) {
+ cmp = defaultCmp;
+ }
+ result = array.slice(0, n);
+ if (!result.length) {
+ return result;
+ }
+ heapify(result, cmp);
+ _ref = array.slice(n);
+ for (_i = 0, _len = _ref.length; _i < _len; _i++) {
+ elem = _ref[_i];
+ heappushpop(result, elem, cmp);
+ }
+ return result.sort(cmp).reverse();
+ };
+
+
+ /*
+ Find the n smallest elements in a dataset.
+ */
+
+ nsmallest = function(array, n, cmp) {
+ var elem, i, los, result, _i, _j, _len, _ref, _ref1, _results;
+ if (cmp == null) {
+ cmp = defaultCmp;
+ }
+ if (n * 10 <= array.length) {
+ result = array.slice(0, n).sort(cmp);
+ if (!result.length) {
+ return result;
+ }
+ los = result[result.length - 1];
+ _ref = array.slice(n);
+ for (_i = 0, _len = _ref.length; _i < _len; _i++) {
+ elem = _ref[_i];
+ if (cmp(elem, los) < 0) {
+ insort(result, elem, 0, null, cmp);
+ result.pop();
+ los = result[result.length - 1];
+ }
+ }
+ return result;
+ }
+ heapify(array, cmp);
+ _results = [];
+ for (i = _j = 0, _ref1 = min(n, array.length); 0 <= _ref1 ? _j < _ref1 : _j > _ref1; i = 0 <= _ref1 ? ++_j : --_j) {
+ _results.push(heappop(array, cmp));
+ }
+ return _results;
+ };
+
+ _siftdown = function(array, startpos, pos, cmp) {
+ var newitem, parent, parentpos;
+ if (cmp == null) {
+ cmp = defaultCmp;
+ }
+ newitem = array[pos];
+ while (pos > startpos) {
+ parentpos = (pos - 1) >> 1;
+ parent = array[parentpos];
+ if (cmp(newitem, parent) < 0) {
+ array[pos] = parent;
+ pos = parentpos;
+ continue;
+ }
+ break;
+ }
+ return array[pos] = newitem;
+ };
+
+ _siftup = function(array, pos, cmp) {
+ var childpos, endpos, newitem, rightpos, startpos;
+ if (cmp == null) {
+ cmp = defaultCmp;
+ }
+ endpos = array.length;
+ startpos = pos;
+ newitem = array[pos];
+ childpos = 2 * pos + 1;
+ while (childpos < endpos) {
+ rightpos = childpos + 1;
+ if (rightpos < endpos && !(cmp(array[childpos], array[rightpos]) < 0)) {
+ childpos = rightpos;
+ }
+ array[pos] = array[childpos];
+ pos = childpos;
+ childpos = 2 * pos + 1;
+ }
+ array[pos] = newitem;
+ return _siftdown(array, startpos, pos, cmp);
+ };
+
+ Heap = (function() {
+ Heap.push = heappush;
+
+ Heap.pop = heappop;
+
+ Heap.replace = heapreplace;
+
+ Heap.pushpop = heappushpop;
+
+ Heap.heapify = heapify;
+
+ Heap.updateItem = updateItem;
+
+ Heap.nlargest = nlargest;
+
+ Heap.nsmallest = nsmallest;
+
+ function Heap(cmp) {
+ this.cmp = cmp != null ? cmp : defaultCmp;
+ this.nodes = [];
+ }
+
+ Heap.prototype.push = function(x) {
+ return heappush(this.nodes, x, this.cmp);
+ };
+
+ Heap.prototype.pop = function() {
+ return heappop(this.nodes, this.cmp);
+ };
+
+ Heap.prototype.peek = function() {
+ return this.nodes[0];
+ };
+
+ Heap.prototype.contains = function(x) {
+ return this.nodes.indexOf(x) !== -1;
+ };
+
+ Heap.prototype.replace = function(x) {
+ return heapreplace(this.nodes, x, this.cmp);
+ };
+
+ Heap.prototype.pushpop = function(x) {
+ return heappushpop(this.nodes, x, this.cmp);
+ };
+
+ Heap.prototype.heapify = function() {
+ return heapify(this.nodes, this.cmp);
+ };
+
+ Heap.prototype.updateItem = function(x) {
+ return updateItem(this.nodes, x, this.cmp);
+ };
+
+ Heap.prototype.clear = function() {
+ return this.nodes = [];
+ };
+
+ Heap.prototype.empty = function() {
+ return this.nodes.length === 0;
+ };
+
+ Heap.prototype.size = function() {
+ return this.nodes.length;
+ };
+
+ Heap.prototype.clone = function() {
+ var heap;
+ heap = new Heap();
+ heap.nodes = this.nodes.slice(0);
+ return heap;
+ };
+
+ Heap.prototype.toArray = function() {
+ return this.nodes.slice(0);
+ };
+
+ Heap.prototype.insert = Heap.prototype.push;
+
+ Heap.prototype.top = Heap.prototype.peek;
+
+ Heap.prototype.front = Heap.prototype.peek;
+
+ Heap.prototype.has = Heap.prototype.contains;
+
+ Heap.prototype.copy = Heap.prototype.clone;
+
+ return Heap;
+
+ })();
+
+ (function(root, factory) {
+ if (typeof define === 'function' && define.amd) {
+ return define([], factory);
+ } else if (typeof exports === 'object') {
+ return module.exports = factory();
+ } else {
+ return root.Heap = factory();
+ }
+ })(this, function() {
+ return Heap;
+ });
+
+}).call(this);
+
+/* jshint ignore:end */
+
+},{}],76:[function(_dereq_,module,exports){
+'use strict';
+
+var window = _dereq_('./window');
+var is = _dereq_('./is');
+var Core = _dereq_('./core');
+var extension = _dereq_('./extension');
+var registerJquery = _dereq_('./jquery-plugin');
+var Stylesheet = _dereq_('./stylesheet');
+var Thread = _dereq_('./thread');
+var Fabric = _dereq_('./fabric');
+
+var cytoscape = function( options ){ // jshint ignore:line
+ // if no options specified, use default
+ if( options === undefined ){
+ options = {};
+ }
+
+ // create instance
+ if( is.plainObject( options ) ){
+ return new Core( options );
+ }
+
+ // allow for registration of extensions
+ else if( is.string( options ) ) {
+ return extension.apply(extension, arguments);
+ }
+};
+
+// replaced by build system
+cytoscape.version = '2.5.1';
+
+// try to register w/ jquery
+if( window && window.jQuery ){
+ registerJquery( window.jQuery, cytoscape );
+}
+
+// expose register api
+cytoscape.registerJquery = function( jQuery ){
+ registerJquery( jQuery, cytoscape );
+};
+
+// expose public apis (mostly for extensions)
+cytoscape.stylesheet = cytoscape.Stylesheet = Stylesheet;
+cytoscape.thread = cytoscape.Thread = Thread;
+cytoscape.fabric = cytoscape.Fabric = Fabric;
+
+module.exports = cytoscape;
+
+},{"./core":34,"./extension":43,"./fabric":74,"./is":77,"./jquery-plugin":78,"./stylesheet":91,"./thread":92,"./window":100}],77:[function(_dereq_,module,exports){
+'use strict';
+
+var window = _dereq_('./window');
+var navigator = window ? window.navigator : null;
+
+var typeofstr = typeof '';
+var typeofobj = typeof {};
+var typeoffn = typeof function(){};
+var typeofhtmlele = typeof HTMLElement;
+
+var instanceStr = function( obj ){
+ return obj && obj.instanceString && is.fn( obj.instanceString ) ? obj.instanceString() : null;
+};
+
+var is = {
+ defined: function(obj){
+ return obj != null; // not undefined or null
+ },
+
+ string: function(obj){
+ return obj != null && typeof obj == typeofstr;
+ },
+
+ fn: function(obj){
+ return obj != null && typeof obj === typeoffn;
+ },
+
+ array: function(obj){
+ return Array.isArray ? Array.isArray(obj) : obj != null && obj instanceof Array;
+ },
+
+ plainObject: function(obj){
+ return obj != null && typeof obj === typeofobj && !is.array(obj) && obj.constructor === Object;
+ },
+
+ object: function(obj){
+ return obj != null && typeof obj === typeofobj;
+ },
+
+ number: function(obj){
+ return obj != null && typeof obj === typeof 1 && !isNaN(obj);
+ },
+
+ integer: function( obj ){
+ return is.number(obj) && Math.floor(obj) === obj;
+ },
+
+ bool: function(obj){
+ return obj != null && typeof obj === typeof true;
+ },
+
+ htmlElement: function(obj){
+ if( 'undefined' === typeofhtmlele ){
+ return undefined;
+ } else {
+ return null != obj && obj instanceof HTMLElement;
+ }
+ },
+
+ elementOrCollection: function(obj){
+ return is.element(obj) || is.collection(obj);
+ },
+
+ element: function(obj){
+ return instanceStr(obj) === 'collection' && obj._private.single;
+ },
+
+ collection: function(obj){
+ return instanceStr(obj) === 'collection' && !obj._private.single;
+ },
+
+ core: function(obj){
+ return instanceStr(obj) === 'core';
+ },
+
+ style: function(obj){
+ return instanceStr(obj) === 'style';
+ },
+
+ stylesheet: function(obj){
+ return instanceStr(obj) === 'stylesheet';
+ },
+
+ event: function(obj){
+ return instanceStr(obj) === 'event';
+ },
+
+ thread: function(obj){
+ return instanceStr(obj) === 'thread';
+ },
+
+ fabric: function(obj){
+ return instanceStr(obj) === 'fabric';
+ },
+
+ emptyString: function(obj){
+ if( !obj ){ // null is empty
+ return true;
+ } else if( is.string(obj) ){
+ if( obj === '' || obj.match(/^\s+$/) ){
+ return true; // empty string is empty
+ }
+ }
+
+ return false; // otherwise, we don't know what we've got
+ },
+
+ nonemptyString: function(obj){
+ if( obj && is.string(obj) && obj !== '' && !obj.match(/^\s+$/) ){
+ return true;
+ }
+
+ return false;
+ },
+
+ domElement: function(obj){
+ if( typeof HTMLElement === 'undefined' ){
+ return false; // we're not in a browser so it doesn't matter
+ } else {
+ return obj instanceof HTMLElement;
+ }
+ },
+
+ boundingBox: function(obj){
+ return is.plainObject(obj) &&
+ is.number(obj.x1) && is.number(obj.x2) &&
+ is.number(obj.y1) && is.number(obj.y2)
+ ;
+ },
+
+ promise: function(obj){
+ return is.object(obj) && is.fn(obj.then);
+ },
+
+ touch: function(){
+ return window && ( ('ontouchstart' in window) || window.DocumentTouch && document instanceof DocumentTouch );
+ },
+
+ gecko: function(){
+ return typeof InstallTrigger !== 'undefined' || ('MozAppearance' in document.documentElement.style);
+ },
+
+ webkit: function(){
+ return typeof webkitURL !== 'undefined' || ('WebkitAppearance' in document.documentElement.style);
+ },
+
+ chromium: function(){
+ return typeof chrome !== 'undefined';
+ },
+
+ khtml: function(){
+ return navigator && navigator.vendor.match(/kde/i); // probably a better way to detect this...
+ },
+
+ khtmlEtc: function(){
+ return is.khtml() || is.webkit() || is.chromium();
+ },
+
+ ms: function(){
+ return navigator && navigator.userAgent.match(/msie|trident|edge/i); // probably a better way to detect this...
+ },
+
+ windows: function(){
+ return navigator && navigator.appVersion.match(/Win/i);
+ },
+
+ mac: function(){
+ return navigator && navigator.appVersion.match(/Mac/i);
+ },
+
+ linux: function(){
+ return navigator && navigator.appVersion.match(/Linux/i);
+ },
+
+ unix: function(){
+ return navigator && navigator.appVersion.match(/X11/i);
+ }
+};
+
+module.exports = is;
+
+},{"./window":100}],78:[function(_dereq_,module,exports){
+'use strict';
+
+var is = _dereq_('./is');
+
+var cyReg = function( $ele ){
+ var d = $ele[0]._cyreg = $ele[0]._cyreg || {};
+
+ return d;
+};
+
+var registerJquery = function( $, cytoscape ){
+ if( !$ ){ return; } // no jquery => don't need this
+
+ if( $.fn.cytoscape ){ return; } // already registered
+
+ // allow calls on a jQuery selector by proxying calls to $.cytoscape
+ // e.g. $("#foo").cytoscape(options) => $.cytoscape(options) on #foo
+ $.fn.cytoscape = function(opts){
+ var $this = $(this);
+
+ // get object
+ if( opts === 'get' ){
+ return cyReg( $this ).cy;
+ }
+
+ // bind to ready
+ else if( is.fn(opts) ){
+
+ var ready = opts;
+ var cy = cyReg( $this ).cy;
+
+ if( cy && cy.isReady() ){ // already ready so just trigger now
+ cy.trigger('ready', [], ready);
+
+ } else { // not yet ready, so add to readies list
+ var data = cyReg( $this );
+ var readies = data.readies = data.readies || [];
+
+ readies.push( ready );
+ }
+
+ }
+
+ // proxy to create instance
+ else if( is.plainObject(opts) ){
+ return $this.each(function(){
+ var options = $.extend({}, opts, {
+ container: $(this)[0]
+ });
+
+ cytoscape(options);
+ });
+ }
+ };
+
+ // allow access to the global cytoscape object under jquery for legacy reasons
+ $.cytoscape = cytoscape;
+
+ // use short alias (cy) if not already defined
+ if( $.fn.cy == null && $.cy == null ){
+ $.fn.cy = $.fn.cytoscape;
+ $.cy = $.cytoscape;
+ }
+};
+
+module.exports = registerJquery;
+
+},{"./is":77}],79:[function(_dereq_,module,exports){
+'use strict';
+
+var math = {};
+
+math.signum = function(x){
+ if( x > 0 ){
+ return 1;
+ } else if( x < 0 ){
+ return -1;
+ } else {
+ return 0;
+ }
+};
+
+math.distance = function( p1, p2 ){
+ return Math.sqrt( math.sqDistance(p1, p2) );
+};
+
+math.sqDistance = function( p1, p2 ){
+ var dx = p2.x - p1.x;
+ var dy = p2.y - p1.y;
+
+ return dx*dx + dy*dy;
+};
+
+// from http://en.wikipedia.org/wiki/Bézier_curve#Quadratic_curves
+math.qbezierAt = function(p0, p1, p2, t){
+ return (1 - t)*(1 - t)*p0 + 2*(1 - t)*t*p1 + t*t*p2;
+};
+
+math.qbezierPtAt = function(p0, p1, p2, t){
+ return {
+ x: math.qbezierAt( p0.x, p1.x, p2.x, t ),
+ y: math.qbezierAt( p0.y, p1.y, p2.y, t )
+ };
+};
+
+// makes a full bb (x1, y1, x2, y2, w, h) from implicit params
+math.makeBoundingBox = function( bb ){
+ if( bb.x1 != null && bb.y1 != null ){
+ if( bb.x2 != null && bb.y2 != null && bb.x2 >= bb.x1 && bb.y2 >= bb.y1 ){
+ return {
+ x1: bb.x1,
+ y1: bb.y1,
+ x2: bb.x2,
+ y2: bb.y2,
+ w: bb.x2 - bb.x1,
+ h: bb.y2 - bb.y1
+ };
+ } else if( bb.w != null && bb.h != null && bb.w >= 0 && bb.h >= 0 ){
+ return {
+ x1: bb.x1,
+ y1: bb.y1,
+ x2: bb.x1 + bb.w,
+ y2: bb.y1 + bb.h,
+ w: bb.w,
+ h: bb.h
+ };
+ }
+ }
+};
+
+math.boundingBoxesIntersect = function( bb1, bb2 ){
+ // case: one bb to right of other
+ if( bb1.x1 > bb2.x2 ){ return false; }
+ if( bb2.x1 > bb1.x2 ){ return false; }
+
+ // case: one bb to left of other
+ if( bb1.x2 < bb2.x1 ){ return false; }
+ if( bb2.x2 < bb1.x1 ){ return false; }
+
+ // case: one bb above other
+ if( bb1.y2 < bb2.y1 ){ return false; }
+ if( bb2.y2 < bb1.y1 ){ return false; }
+
+ // case: one bb below other
+ if( bb1.y1 > bb2.y2 ){ return false; }
+ if( bb2.y1 > bb1.y2 ){ return false; }
+
+ // otherwise, must have some overlap
+ return true;
+};
+
+math.inBoundingBox = function( bb, x, y ){
+ return bb.x1 <= x && x <= bb.x2 && bb.y1 <= y && y <= bb.y2;
+};
+
+math.pointInBoundingBox = function( bb, pt ){
+ return this.inBoundingBox( bb, pt.x, pt.y );
+};
+
+math.roundRectangleIntersectLine = function(
+ x, y, nodeX, nodeY, width, height, padding) {
+
+ var cornerRadius = this.getRoundRectangleRadius(width, height);
+
+ var halfWidth = width / 2;
+ var halfHeight = height / 2;
+
+ // Check intersections with straight line segments
+ var straightLineIntersections;
+
+ // Top segment, left to right
+ {
+ var topStartX = nodeX - halfWidth + cornerRadius - padding;
+ var topStartY = nodeY - halfHeight - padding;
+ var topEndX = nodeX + halfWidth - cornerRadius + padding;
+ var topEndY = topStartY;
+
+ straightLineIntersections = this.finiteLinesIntersect(
+ x, y, nodeX, nodeY, topStartX, topStartY, topEndX, topEndY, false);
+
+ if (straightLineIntersections.length > 0) {
+ return straightLineIntersections;
+ }
+ }
+
+ // Right segment, top to bottom
+ {
+ var rightStartX = nodeX + halfWidth + padding;
+ var rightStartY = nodeY - halfHeight + cornerRadius - padding;
+ var rightEndX = rightStartX;
+ var rightEndY = nodeY + halfHeight - cornerRadius + padding;
+
+ straightLineIntersections = this.finiteLinesIntersect(
+ x, y, nodeX, nodeY, rightStartX, rightStartY, rightEndX, rightEndY, false);
+
+ if (straightLineIntersections.length > 0) {
+ return straightLineIntersections;
+ }
+ }
+
+ // Bottom segment, left to right
+ {
+ var bottomStartX = nodeX - halfWidth + cornerRadius - padding;
+ var bottomStartY = nodeY + halfHeight + padding;
+ var bottomEndX = nodeX + halfWidth - cornerRadius + padding;
+ var bottomEndY = bottomStartY;
+
+ straightLineIntersections = this.finiteLinesIntersect(
+ x, y, nodeX, nodeY, bottomStartX, bottomStartY, bottomEndX, bottomEndY, false);
+
+ if (straightLineIntersections.length > 0) {
+ return straightLineIntersections;
+ }
+ }
+
+ // Left segment, top to bottom
+ {
+ var leftStartX = nodeX - halfWidth - padding;
+ var leftStartY = nodeY - halfHeight + cornerRadius - padding;
+ var leftEndX = leftStartX;
+ var leftEndY = nodeY + halfHeight - cornerRadius + padding;
+
+ straightLineIntersections = this.finiteLinesIntersect(
+ x, y, nodeX, nodeY, leftStartX, leftStartY, leftEndX, leftEndY, false);
+
+ if (straightLineIntersections.length > 0) {
+ return straightLineIntersections;
+ }
+ }
+
+ // Check intersections with arc segments
+ var arcIntersections;
+
+ // Top Left
+ {
+ var topLeftCenterX = nodeX - halfWidth + cornerRadius;
+ var topLeftCenterY = nodeY - halfHeight + cornerRadius;
+ arcIntersections = this.intersectLineCircle(
+ x, y, nodeX, nodeY,
+ topLeftCenterX, topLeftCenterY, cornerRadius + padding);
+
+ // Ensure the intersection is on the desired quarter of the circle
+ if (arcIntersections.length > 0
+ && arcIntersections[0] <= topLeftCenterX
+ && arcIntersections[1] <= topLeftCenterY) {
+ return [arcIntersections[0], arcIntersections[1]];
+ }
+ }
+
+ // Top Right
+ {
+ var topRightCenterX = nodeX + halfWidth - cornerRadius;
+ var topRightCenterY = nodeY - halfHeight + cornerRadius;
+ arcIntersections = this.intersectLineCircle(
+ x, y, nodeX, nodeY,
+ topRightCenterX, topRightCenterY, cornerRadius + padding);
+
+ // Ensure the intersection is on the desired quarter of the circle
+ if (arcIntersections.length > 0
+ && arcIntersections[0] >= topRightCenterX
+ && arcIntersections[1] <= topRightCenterY) {
+ return [arcIntersections[0], arcIntersections[1]];
+ }
+ }
+
+ // Bottom Right
+ {
+ var bottomRightCenterX = nodeX + halfWidth - cornerRadius;
+ var bottomRightCenterY = nodeY + halfHeight - cornerRadius;
+ arcIntersections = this.intersectLineCircle(
+ x, y, nodeX, nodeY,
+ bottomRightCenterX, bottomRightCenterY, cornerRadius + padding);
+
+ // Ensure the intersection is on the desired quarter of the circle
+ if (arcIntersections.length > 0
+ && arcIntersections[0] >= bottomRightCenterX
+ && arcIntersections[1] >= bottomRightCenterY) {
+ return [arcIntersections[0], arcIntersections[1]];
+ }
+ }
+
+ // Bottom Left
+ {
+ var bottomLeftCenterX = nodeX - halfWidth + cornerRadius;
+ var bottomLeftCenterY = nodeY + halfHeight - cornerRadius;
+ arcIntersections = this.intersectLineCircle(
+ x, y, nodeX, nodeY,
+ bottomLeftCenterX, bottomLeftCenterY, cornerRadius + padding);
+
+ // Ensure the intersection is on the desired quarter of the circle
+ if (arcIntersections.length > 0
+ && arcIntersections[0] <= bottomLeftCenterX
+ && arcIntersections[1] >= bottomLeftCenterY) {
+ return [arcIntersections[0], arcIntersections[1]];
+ }
+ }
+
+ return []; // if nothing
+};
+
+math.inLineVicinity = function(x, y, lx1, ly1, lx2, ly2, tolerance){
+ var t = tolerance;
+
+ var x1 = Math.min(lx1, lx2);
+ var x2 = Math.max(lx1, lx2);
+ var y1 = Math.min(ly1, ly2);
+ var y2 = Math.max(ly1, ly2);
+
+ return x1 - t <= x && x <= x2 + t
+ && y1 - t <= y && y <= y2 + t;
+};
+
+math.inBezierVicinity = function(
+ x, y, x1, y1, x2, y2, x3, y3, tolerance) {
+
+ var bb = {
+ x1: Math.min( x1, x3, x2 ) - tolerance,
+ x2: Math.max( x1, x3, x2 ) + tolerance,
+ y1: Math.min( y1, y3, y2 ) - tolerance,
+ y2: Math.max( y1, y3, y2 ) + tolerance
+ };
+
+ // if outside the rough bounding box for the bezier, then it can't be a hit
+ if( x < bb.x1 || x > bb.x2 || y < bb.y1 || y > bb.y2 ){
+ // console.log('bezier out of rough bb')
+ return false;
+ } else {
+ // console.log('do more expensive check');
+ return true;
+ }
+
+};
+
+math.solveCubic = function(a, b, c, d, result) {
+
+ // Solves a cubic function, returns root in form [r1, i1, r2, i2, r3, i3], where
+ // r is the real component, i is the imaginary component
+
+ // An implementation of the Cardano method from the year 1545
+ // http://en.wikipedia.org/wiki/Cubic_function#The_nature_of_the_roots
+
+ b /= a;
+ c /= a;
+ d /= a;
+
+ var discriminant, q, r, dum1, s, t, term1, r13;
+
+ q = (3.0 * c - (b * b)) / 9.0;
+ r = -(27.0 * d) + b * (9.0 * c - 2.0 * (b * b));
+ r /= 54.0;
+
+ discriminant = q * q * q + r * r;
+ result[1] = 0;
+ term1 = (b / 3.0);
+
+ if (discriminant > 0) {
+ s = r + Math.sqrt(discriminant);
+ s = ((s < 0) ? -Math.pow(-s, (1.0 / 3.0)) : Math.pow(s, (1.0 / 3.0)));
+ t = r - Math.sqrt(discriminant);
+ t = ((t < 0) ? -Math.pow(-t, (1.0 / 3.0)) : Math.pow(t, (1.0 / 3.0)));
+ result[0] = -term1 + s + t;
+ term1 += (s + t) / 2.0;
+ result[4] = result[2] = -term1;
+ term1 = Math.sqrt(3.0) * (-t + s) / 2;
+ result[3] = term1;
+ result[5] = -term1;
+ return;
+ }
+
+ result[5] = result[3] = 0;
+
+ if (discriminant === 0) {
+ r13 = ((r < 0) ? -Math.pow(-r, (1.0 / 3.0)) : Math.pow(r, (1.0 / 3.0)));
+ result[0] = -term1 + 2.0 * r13;
+ result[4] = result[2] = -(r13 + term1);
+ return;
+ }
+
+ q = -q;
+ dum1 = q * q * q;
+ dum1 = Math.acos(r / Math.sqrt(dum1));
+ r13 = 2.0 * Math.sqrt(q);
+ result[0] = -term1 + r13 * Math.cos(dum1 / 3.0);
+ result[2] = -term1 + r13 * Math.cos((dum1 + 2.0 * Math.PI) / 3.0);
+ result[4] = -term1 + r13 * Math.cos((dum1 + 4.0 * Math.PI) / 3.0);
+
+ return;
+};
+
+math.sqDistanceToQuadraticBezier = function(
+ x, y, x1, y1, x2, y2, x3, y3) {
+
+ // Find minimum distance by using the minimum of the distance
+ // function between the given point and the curve
+
+ // This gives the coefficients of the resulting cubic equation
+ // whose roots tell us where a possible minimum is
+ // (Coefficients are divided by 4)
+
+ var a = 1.0 * x1*x1 - 4*x1*x2 + 2*x1*x3 + 4*x2*x2 - 4*x2*x3 + x3*x3
+ + y1*y1 - 4*y1*y2 + 2*y1*y3 + 4*y2*y2 - 4*y2*y3 + y3*y3;
+
+ var b = 1.0 * 9*x1*x2 - 3*x1*x1 - 3*x1*x3 - 6*x2*x2 + 3*x2*x3
+ + 9*y1*y2 - 3*y1*y1 - 3*y1*y3 - 6*y2*y2 + 3*y2*y3;
+
+ var c = 1.0 * 3*x1*x1 - 6*x1*x2 + x1*x3 - x1*x + 2*x2*x2 + 2*x2*x - x3*x
+ + 3*y1*y1 - 6*y1*y2 + y1*y3 - y1*y + 2*y2*y2 + 2*y2*y - y3*y;
+
+ var d = 1.0 * x1*x2 - x1*x1 + x1*x - x2*x
+ + y1*y2 - y1*y1 + y1*y - y2*y;
+
+ // debug("coefficients: " + a / a + ", " + b / a + ", " + c / a + ", " + d / a);
+
+ var roots = [];
+
+ // Use the cubic solving algorithm
+ this.solveCubic(a, b, c, d, roots);
+
+ var zeroThreshold = 0.0000001;
+
+ var params = [];
+
+ for (var index = 0; index < 6; index += 2) {
+ if (Math.abs(roots[index + 1]) < zeroThreshold
+ && roots[index] >= 0
+ && roots[index] <= 1.0) {
+ params.push(roots[index]);
+ }
+ }
+
+ params.push(1.0);
+ params.push(0.0);
+
+ var minDistanceSquared = -1;
+ var closestParam;
+
+ var curX, curY, distSquared;
+ for (var i = 0; i < params.length; i++) {
+ curX = Math.pow(1.0 - params[i], 2.0) * x1
+ + 2.0 * (1 - params[i]) * params[i] * x2
+ + params[i] * params[i] * x3;
+
+ curY = Math.pow(1 - params[i], 2.0) * y1
+ + 2 * (1.0 - params[i]) * params[i] * y2
+ + params[i] * params[i] * y3;
+
+ distSquared = Math.pow(curX - x, 2) + Math.pow(curY - y, 2);
+ // debug('distance for param ' + params[i] + ": " + Math.sqrt(distSquared));
+ if (minDistanceSquared >= 0) {
+ if (distSquared < minDistanceSquared) {
+ minDistanceSquared = distSquared;
+ closestParam = params[i];
+ }
+ } else {
+ minDistanceSquared = distSquared;
+ closestParam = params[i];
+ }
+ }
+
+ return minDistanceSquared;
+};
+
+math.sqDistanceToFiniteLine = function(x, y, x1, y1, x2, y2) {
+ var offset = [x - x1, y - y1];
+ var line = [x2 - x1, y2 - y1];
+
+ var lineSq = line[0] * line[0] + line[1] * line[1];
+ var hypSq = offset[0] * offset[0] + offset[1] * offset[1];
+
+ var dotProduct = offset[0] * line[0] + offset[1] * line[1];
+ var adjSq = dotProduct * dotProduct / lineSq;
+
+ if (dotProduct < 0) {
+ return hypSq;
+ }
+
+ if (adjSq > lineSq) {
+ return (x - x2) * (x - x2) + (y - y2) * (y - y2);
+ }
+
+ return hypSq - adjSq;
+};
+
+math.pointInsidePolygonPoints = function(x, y, points){
+ var x1, y1, x2, y2;
+ var y3;
+
+ // Intersect with vertical line through (x, y)
+ var up = 0;
+ var down = 0;
+ for (var i = 0; i < points.length / 2; i++) {
+
+ x1 = points[i * 2];
+ y1 = points[i * 2 + 1];
+
+ if (i + 1 < points.length / 2) {
+ x2 = points[(i + 1) * 2];
+ y2 = points[(i + 1) * 2 + 1];
+ } else {
+ x2 = points[(i + 1 - points.length / 2) * 2];
+ y2 = points[(i + 1 - points.length / 2) * 2 + 1];
+ }
+
+ if (x1 == x && x2 == x) {
+
+ } else if ((x1 >= x && x >= x2)
+ || (x1 <= x && x <= x2)) {
+
+ y3 = (x - x1) / (x2 - x1) * (y2 - y1) + y1;
+
+ if (y3 > y) {
+ up++;
+ }
+
+ if (y3 < y) {
+ down++;
+ }
+
+ } else {
+ continue;
+ }
+
+ }
+
+ if (up % 2 === 0) {
+ return false;
+ } else {
+ return true;
+ }
+};
+
+math.pointInsidePolygon = function(
+ x, y, basePoints, centerX, centerY, width, height, direction, padding) {
+
+ //var direction = arguments[6];
+ var transformedPoints = new Array(basePoints.length);
+
+ // Gives negative angle
+ var angle;
+
+ if( direction[0] != null ){
+ angle = Math.atan(direction[1] / direction[0]);
+
+ if (direction[0] < 0) {
+ angle = angle + Math.PI / 2;
+ } else {
+ angle = -angle - Math.PI / 2;
+ }
+ } else {
+ angle = direction;
+ }
+
+ var cos = Math.cos(-angle);
+ var sin = Math.sin(-angle);
+
+ // console.log("base: " + basePoints);
+ for (var i = 0; i < transformedPoints.length / 2; i++) {
+ transformedPoints[i * 2] =
+ width / 2 * (basePoints[i * 2] * cos
+ - basePoints[i * 2 + 1] * sin);
+
+ transformedPoints[i * 2 + 1] =
+ height / 2 * (basePoints[i * 2 + 1] * cos
+ + basePoints[i * 2] * sin);
+
+ transformedPoints[i * 2] += centerX;
+ transformedPoints[i * 2 + 1] += centerY;
+ }
+
+ var points;
+
+ if (padding > 0) {
+ var expandedLineSet = this.expandPolygon(
+ transformedPoints,
+ -padding);
+
+ points = this.joinLines(expandedLineSet);
+ } else {
+ points = transformedPoints;
+ }
+
+ return math.pointInsidePolygonPoints( x, y, points );
+};
+
+math.joinLines = function(lineSet) {
+
+ var vertices = new Array(lineSet.length / 2);
+
+ var currentLineStartX, currentLineStartY, currentLineEndX, currentLineEndY;
+ var nextLineStartX, nextLineStartY, nextLineEndX, nextLineEndY;
+
+ for (var i = 0; i < lineSet.length / 4; i++) {
+ currentLineStartX = lineSet[i * 4];
+ currentLineStartY = lineSet[i * 4 + 1];
+ currentLineEndX = lineSet[i * 4 + 2];
+ currentLineEndY = lineSet[i * 4 + 3];
+
+ if (i < lineSet.length / 4 - 1) {
+ nextLineStartX = lineSet[(i + 1) * 4];
+ nextLineStartY = lineSet[(i + 1) * 4 + 1];
+ nextLineEndX = lineSet[(i + 1) * 4 + 2];
+ nextLineEndY = lineSet[(i + 1) * 4 + 3];
+ } else {
+ nextLineStartX = lineSet[0];
+ nextLineStartY = lineSet[1];
+ nextLineEndX = lineSet[2];
+ nextLineEndY = lineSet[3];
+ }
+
+ var intersection = this.finiteLinesIntersect(
+ currentLineStartX, currentLineStartY,
+ currentLineEndX, currentLineEndY,
+ nextLineStartX, nextLineStartY,
+ nextLineEndX, nextLineEndY,
+ true);
+
+ vertices[i * 2] = intersection[0];
+ vertices[i * 2 + 1] = intersection[1];
+ }
+
+ return vertices;
+};
+
+math.expandPolygon = function(points, pad) {
+
+ var expandedLineSet = new Array(points.length * 2);
+
+ var currentPointX, currentPointY, nextPointX, nextPointY;
+
+ for (var i = 0; i < points.length / 2; i++) {
+ currentPointX = points[i * 2];
+ currentPointY = points[i * 2 + 1];
+
+ if (i < points.length / 2 - 1) {
+ nextPointX = points[(i + 1) * 2];
+ nextPointY = points[(i + 1) * 2 + 1];
+ } else {
+ nextPointX = points[0];
+ nextPointY = points[1];
+ }
+
+ // Current line: [currentPointX, currentPointY] to [nextPointX, nextPointY]
+
+ // Assume CCW polygon winding
+
+ var offsetX = (nextPointY - currentPointY);
+ var offsetY = -(nextPointX - currentPointX);
+
+ // Normalize
+ var offsetLength = Math.sqrt(offsetX * offsetX + offsetY * offsetY);
+ var normalizedOffsetX = offsetX / offsetLength;
+ var normalizedOffsetY = offsetY / offsetLength;
+
+ expandedLineSet[i * 4] = currentPointX + normalizedOffsetX * pad;
+ expandedLineSet[i * 4 + 1] = currentPointY + normalizedOffsetY * pad;
+ expandedLineSet[i * 4 + 2] = nextPointX + normalizedOffsetX * pad;
+ expandedLineSet[i * 4 + 3] = nextPointY + normalizedOffsetY * pad;
+ }
+
+ return expandedLineSet;
+};
+
+math.intersectLineEllipse = function(
+ x, y, centerX, centerY, ellipseWradius, ellipseHradius) {
+
+ var dispX = centerX - x;
+ var dispY = centerY - y;
+
+ dispX /= ellipseWradius;
+ dispY /= ellipseHradius;
+
+ var len = Math.sqrt(dispX * dispX + dispY * dispY);
+
+ var newLength = len - 1;
+
+ if (newLength < 0) {
+ return [];
+ }
+
+ var lenProportion = newLength / len;
+
+ return [(centerX - x) * lenProportion + x, (centerY - y) * lenProportion + y];
+};
+
+// Returns intersections of increasing distance from line's start point
+math.intersectLineCircle = function(
+ x1, y1, x2, y2, centerX, centerY, radius) {
+
+ // Calculate d, direction vector of line
+ var d = [x2 - x1, y2 - y1]; // Direction vector of line
+ var c = [centerX, centerY]; // Center of circle
+ var f = [x1 - centerX, y1 - centerY];
+
+ var a = d[0] * d[0] + d[1] * d[1];
+ var b = 2 * (f[0] * d[0] + f[1] * d[1]);
+ var c = (f[0] * f[0] + f[1] * f[1]) - radius * radius ;
+
+ var discriminant = b*b-4*a*c;
+
+ if (discriminant < 0) {
+ return [];
+ }
+
+ var t1 = (-b + Math.sqrt(discriminant)) / (2 * a);
+ var t2 = (-b - Math.sqrt(discriminant)) / (2 * a);
+
+ var tMin = Math.min(t1, t2);
+ var tMax = Math.max(t1, t2);
+ var inRangeParams = [];
+
+ if (tMin >= 0 && tMin <= 1) {
+ inRangeParams.push(tMin);
+ }
+
+ if (tMax >= 0 && tMax <= 1) {
+ inRangeParams.push(tMax);
+ }
+
+ if (inRangeParams.length === 0) {
+ return [];
+ }
+
+ var nearIntersectionX = inRangeParams[0] * d[0] + x1;
+ var nearIntersectionY = inRangeParams[0] * d[1] + y1;
+
+ if (inRangeParams.length > 1) {
+
+ if (inRangeParams[0] == inRangeParams[1]) {
+ return [nearIntersectionX, nearIntersectionY];
+ } else {
+
+ var farIntersectionX = inRangeParams[1] * d[0] + x1;
+ var farIntersectionY = inRangeParams[1] * d[1] + y1;
+
+ return [nearIntersectionX, nearIntersectionY, farIntersectionX, farIntersectionY];
+ }
+
+ } else {
+ return [nearIntersectionX, nearIntersectionY];
+ }
+
+};
+
+math.findCircleNearPoint = function(centerX, centerY,
+ radius, farX, farY) {
+
+ var displacementX = farX - centerX;
+ var displacementY = farY - centerY;
+ var distance = Math.sqrt(displacementX * displacementX
+ + displacementY * displacementY);
+
+ var unitDisplacementX = displacementX / distance;
+ var unitDisplacementY = displacementY / distance;
+
+ return [centerX + unitDisplacementX * radius,
+ centerY + unitDisplacementY * radius];
+};
+
+math.findMaxSqDistanceToOrigin = function(points) {
+ var maxSqDistance = 0.000001;
+ var sqDistance;
+
+ for (var i = 0; i < points.length / 2; i++) {
+
+ sqDistance = points[i * 2] * points[i * 2]
+ + points[i * 2 + 1] * points[i * 2 + 1];
+
+ if (sqDistance > maxSqDistance) {
+ maxSqDistance = sqDistance;
+ }
+ }
+
+ return maxSqDistance;
+};
+
+math.finiteLinesIntersect = function(
+ x1, y1, x2, y2, x3, y3, x4, y4, infiniteLines) {
+
+ var ua_t = (x4 - x3) * (y1 - y3) - (y4 - y3) * (x1 - x3);
+ var ub_t = (x2 - x1) * (y1 - y3) - (y2 - y1) * (x1 - x3);
+ var u_b = (y4 - y3) * (x2 - x1) - (x4 - x3) * (y2 - y1);
+
+ if (u_b !== 0) {
+ var ua = ua_t / u_b;
+ var ub = ub_t / u_b;
+
+ if (0 <= ua && ua <= 1 && 0 <= ub && ub <= 1) {
+ return [x1 + ua * (x2 - x1), y1 + ua * (y2 - y1)];
+
+ } else {
+ if (!infiniteLines) {
+ return [];
+ } else {
+ return [x1 + ua * (x2 - x1), y1 + ua * (y2 - y1)];
+ }
+ }
+ } else {
+ if (ua_t === 0 || ub_t === 0) {
+
+ // Parallel, coincident lines. Check if overlap
+
+ // Check endpoint of second line
+ if ([x1, x2, x4].sort()[1] === x4) {
+ return [x4, y4];
+ }
+
+ // Check start point of second line
+ if ([x1, x2, x3].sort()[1] === x3) {
+ return [x3, y3];
+ }
+
+ // Endpoint of first line
+ if ([x3, x4, x2].sort()[1] === x2) {
+ return [x2, y2];
+ }
+
+ return [];
+ } else {
+
+ // Parallel, non-coincident
+ return [];
+ }
+ }
+};
+
+math.polygonIntersectLine = function(
+ x, y, basePoints, centerX, centerY, width, height, padding) {
+
+ var intersections = [];
+ var intersection;
+
+ var transformedPoints = new Array(basePoints.length);
+
+ for (var i = 0; i < transformedPoints.length / 2; i++) {
+ transformedPoints[i * 2] = basePoints[i * 2] * width + centerX;
+ transformedPoints[i * 2 + 1] = basePoints[i * 2 + 1] * height + centerY;
+ }
+
+ var points;
+
+ if (padding > 0) {
+ var expandedLineSet = math.expandPolygon(
+ transformedPoints,
+ -padding);
+
+ points = math.joinLines(expandedLineSet);
+ } else {
+ points = transformedPoints;
+ }
+ // var points = transformedPoints;
+
+ var currentX, currentY, nextX, nextY;
+
+ for (var i = 0; i < points.length / 2; i++) {
+
+ currentX = points[i * 2];
+ currentY = points[i * 2 + 1];
+
+ if (i < points.length / 2 - 1) {
+ nextX = points[(i + 1) * 2];
+ nextY = points[(i + 1) * 2 + 1];
+ } else {
+ nextX = points[0];
+ nextY = points[1];
+ }
+
+ intersection = this.finiteLinesIntersect(
+ x, y, centerX, centerY,
+ currentX, currentY,
+ nextX, nextY);
+
+ if (intersection.length !== 0) {
+ intersections.push(intersection[0], intersection[1]);
+ }
+ }
+
+ return intersections;
+};
+
+math.shortenIntersection = function(
+ intersection, offset, amount) {
+
+ var disp = [intersection[0] - offset[0], intersection[1] - offset[1]];
+
+ var length = Math.sqrt(disp[0] * disp[0] + disp[1] * disp[1]);
+
+ var lenRatio = (length - amount) / length;
+
+ if (lenRatio < 0) {
+ lenRatio = 0.00001;
+ }
+
+ return [offset[0] + lenRatio * disp[0], offset[1] + lenRatio * disp[1]];
+};
+
+math.generateUnitNgonPointsFitToSquare = function(sides, rotationRadians) {
+ var points = math.generateUnitNgonPoints(sides, rotationRadians);
+ points = math.fitPolygonToSquare(points);
+
+ return points;
+};
+
+math.fitPolygonToSquare = function(points){
+ var x, y;
+ var sides = points.length/2;
+ var minX = Infinity, minY = Infinity, maxX = -Infinity, maxY = -Infinity;
+
+ for (var i = 0; i < sides; i++) {
+ x = points[2 * i];
+ y = points[2 * i + 1];
+
+ minX = Math.min( minX, x );
+ maxX = Math.max( maxX, x );
+ minY = Math.min( minY, y );
+ maxY = Math.max( maxY, y );
+ }
+
+ // stretch factors
+ var sx = 2 / (maxX - minX);
+ var sy = 2 / (maxY - minY);
+
+ for (var i = 0; i < sides; i++){
+ x = points[2 * i] = points[2 * i] * sx;
+ y = points[2 * i + 1] = points[2 * i + 1] * sy;
+
+ minX = Math.min( minX, x );
+ maxX = Math.max( maxX, x );
+ minY = Math.min( minY, y );
+ maxY = Math.max( maxY, y );
+ }
+
+ if( minY < -1 ){
+ for (var i = 0; i < sides; i++){
+ y = points[2 * i + 1] = points[2 * i + 1] + (-1 -minY);
+ }
+ }
+
+ return points;
+};
+
+math.generateUnitNgonPoints = function(sides, rotationRadians) {
+
+ var increment = 1.0 / sides * 2 * Math.PI;
+ var startAngle = sides % 2 === 0 ?
+ Math.PI / 2.0 + increment / 2.0 : Math.PI / 2.0;
+ // console.log(nodeShapes['square']);
+ startAngle += rotationRadians;
+
+ var points = new Array(sides * 2);
+
+ var currentAngle, x, y;
+ for (var i = 0; i < sides; i++) {
+ currentAngle = i * increment + startAngle;
+
+ x = points[2 * i] = Math.cos(currentAngle);// * (1 + i/2);
+ y = points[2 * i + 1] = Math.sin(-currentAngle);// * (1 + i/2);
+ }
+
+ return points;
+};
+
+math.getRoundRectangleRadius = function(width, height) {
+
+ // Set the default radius, unless half of width or height is smaller than default
+ return Math.min(width / 4, height / 4, 8);
+};
+
+module.exports = math;
+
+},{}],80:[function(_dereq_,module,exports){
+// internal, minimal Promise impl s.t. apis can return promises in old envs
+// based on thenable (http://github.com/rse/thenable)
+
+'use strict';
+
+/* promise states [Promises/A+ 2.1] */
+var STATE_PENDING = 0; /* [Promises/A+ 2.1.1] */
+var STATE_FULFILLED = 1; /* [Promises/A+ 2.1.2] */
+var STATE_REJECTED = 2; /* [Promises/A+ 2.1.3] */
+
+/* promise object constructor */
+var api = function (executor) {
+ /* optionally support non-constructor/plain-function call */
+ if (!(this instanceof api))
+ return new api(executor);
+
+ /* initialize object */
+ this.id = "Thenable/1.0.7";
+ this.state = STATE_PENDING; /* initial state */
+ this.fulfillValue = undefined; /* initial value */ /* [Promises/A+ 1.3, 2.1.2.2] */
+ this.rejectReason = undefined; /* initial reason */ /* [Promises/A+ 1.5, 2.1.3.2] */
+ this.onFulfilled = []; /* initial handlers */
+ this.onRejected = []; /* initial handlers */
+
+ /* provide optional information-hiding proxy */
+ this.proxy = {
+ then: this.then.bind(this)
+ };
+
+ /* support optional executor function */
+ if (typeof executor === "function")
+ executor.call(this, this.fulfill.bind(this), this.reject.bind(this));
+};
+
+/* promise API methods */
+api.prototype = {
+ /* promise resolving methods */
+ fulfill: function (value) { return deliver(this, STATE_FULFILLED, "fulfillValue", value); },
+ reject: function (value) { return deliver(this, STATE_REJECTED, "rejectReason", value); },
+
+ /* "The then Method" [Promises/A+ 1.1, 1.2, 2.2] */
+ then: function (onFulfilled, onRejected) {
+ var curr = this;
+ var next = new api(); /* [Promises/A+ 2.2.7] */
+ curr.onFulfilled.push(
+ resolver(onFulfilled, next, "fulfill")); /* [Promises/A+ 2.2.2/2.2.6] */
+ curr.onRejected.push(
+ resolver(onRejected, next, "reject" )); /* [Promises/A+ 2.2.3/2.2.6] */
+ execute(curr);
+ return next.proxy; /* [Promises/A+ 2.2.7, 3.3] */
+ }
+};
+
+/* deliver an action */
+var deliver = function (curr, state, name, value) {
+ if (curr.state === STATE_PENDING) {
+ curr.state = state; /* [Promises/A+ 2.1.2.1, 2.1.3.1] */
+ curr[name] = value; /* [Promises/A+ 2.1.2.2, 2.1.3.2] */
+ execute(curr);
+ }
+ return curr;
+};
+
+/* execute all handlers */
+var execute = function (curr) {
+ if (curr.state === STATE_FULFILLED)
+ execute_handlers(curr, "onFulfilled", curr.fulfillValue);
+ else if (curr.state === STATE_REJECTED)
+ execute_handlers(curr, "onRejected", curr.rejectReason);
+};
+
+/* execute particular set of handlers */
+var execute_handlers = function (curr, name, value) {
+ /* global setImmediate: true */
+ /* global setTimeout: true */
+
+ /* short-circuit processing */
+ if (curr[name].length === 0)
+ return;
+
+ /* iterate over all handlers, exactly once */
+ var handlers = curr[name];
+ curr[name] = []; /* [Promises/A+ 2.2.2.3, 2.2.3.3] */
+ var func = function () {
+ for (var i = 0; i < handlers.length; i++)
+ handlers[i](value); /* [Promises/A+ 2.2.5] */
+ };
+
+ /* execute procedure asynchronously */ /* [Promises/A+ 2.2.4, 3.1] */
+ if (typeof setImmediate === "function")
+ setImmediate(func);
+ else
+ setTimeout(func, 0);
+};
+
+/* generate a resolver function */
+var resolver = function (cb, next, method) {
+ return function (value) {
+ if (typeof cb !== "function") /* [Promises/A+ 2.2.1, 2.2.7.3, 2.2.7.4] */
+ next[method].call(next, value); /* [Promises/A+ 2.2.7.3, 2.2.7.4] */
+ else {
+ var result;
+ try { result = cb(value); } /* [Promises/A+ 2.2.2.1, 2.2.3.1, 2.2.5, 3.2] */
+ catch (e) {
+ next.reject(e); /* [Promises/A+ 2.2.7.2] */
+ return;
+ }
+ resolve(next, result); /* [Promises/A+ 2.2.7.1] */
+ }
+ };
+};
+
+/* "Promise Resolution Procedure" */ /* [Promises/A+ 2.3] */
+var resolve = function (promise, x) {
+ /* sanity check arguments */ /* [Promises/A+ 2.3.1] */
+ if (promise === x || promise.proxy === x) {
+ promise.reject(new TypeError("cannot resolve promise with itself"));
+ return;
+ }
+
+ /* surgically check for a "then" method
+ (mainly to just call the "getter" of "then" only once) */
+ var then;
+ if ((typeof x === "object" && x !== null) || typeof x === "function") {
+ try { then = x.then; } /* [Promises/A+ 2.3.3.1, 3.5] */
+ catch (e) {
+ promise.reject(e); /* [Promises/A+ 2.3.3.2] */
+ return;
+ }
+ }
+
+ /* handle own Thenables [Promises/A+ 2.3.2]
+ and similar "thenables" [Promises/A+ 2.3.3] */
+ if (typeof then === "function") {
+ var resolved = false;
+ try {
+ /* call retrieved "then" method */ /* [Promises/A+ 2.3.3.3] */
+ then.call(x,
+ /* resolvePromise */ /* [Promises/A+ 2.3.3.3.1] */
+ function (y) {
+ if (resolved) return; resolved = true; /* [Promises/A+ 2.3.3.3.3] */
+ if (y === x) /* [Promises/A+ 3.6] */
+ promise.reject(new TypeError("circular thenable chain"));
+ else
+ resolve(promise, y);
+ },
+
+ /* rejectPromise */ /* [Promises/A+ 2.3.3.3.2] */
+ function (r) {
+ if (resolved) return; resolved = true; /* [Promises/A+ 2.3.3.3.3] */
+ promise.reject(r);
+ }
+ );
+ }
+ catch (e) {
+ if (!resolved) /* [Promises/A+ 2.3.3.3.3] */
+ promise.reject(e); /* [Promises/A+ 2.3.3.3.4] */
+ }
+ return;
+ }
+
+ /* handle other values */
+ promise.fulfill(x); /* [Promises/A+ 2.3.4, 2.3.3.4] */
+};
+
+// use native promises where possible
+var Promise = typeof Promise === 'undefined' ? api : Promise;
+
+// so we always have Promise.all()
+Promise.all = Promise.all || function( ps ){
+ return new Promise(function( resolveAll, rejectAll ){
+ var vals = new Array( ps.length );
+ var doneCount = 0;
+
+ var fulfill = function( i, val ){
+ vals[i] = val;
+ doneCount++;
+
+ if( doneCount === ps.length ){
+ resolveAll( vals );
+ }
+ };
+
+ for( var i = 0; i < ps.length; i++ ){
+ (function( i ){
+ var p = ps[i];
+ var isPromise = p.then != null;
+
+ if( isPromise ){
+ p.then(function( val ){
+ fulfill( i, val );
+ }, function( err ){
+ rejectAll( err );
+ });
+ } else {
+ var val = p;
+ fulfill( i, val );
+ }
+ })( i );
+ }
+
+ });
+};
+
+module.exports = Promise;
+
+},{}],81:[function(_dereq_,module,exports){
+'use strict';
+
+var is = _dereq_('./is');
+var util = _dereq_('./util');
+
+var Selector = function( onlyThisGroup, selector ){
+
+ if( !(this instanceof Selector) ){
+ return new Selector(onlyThisGroup, selector);
+ }
+
+ if( selector === undefined && onlyThisGroup !== undefined ){
+ selector = onlyThisGroup;
+ onlyThisGroup = undefined;
+ }
+
+ var self = this;
+
+ self._private = {
+ selectorText: null,
+ invalid: true
+ };
+
+ if( !selector || ( is.string(selector) && selector.match(/^\s*$/) ) ){
+
+ if( onlyThisGroup == null ){
+ // ignore
+ self.length = 0;
+ } else {
+ self[0] = newQuery();
+ self[0].group = onlyThisGroup;
+ self.length = 1;
+ }
+
+ } else if( is.elementOrCollection( selector ) ){
+ var collection = selector.collection();
+
+ self[0] = newQuery();
+ self[0].collection = collection;
+ self.length = 1;
+
+ } else if( is.fn( selector ) ) {
+ self[0] = newQuery();
+ self[0].filter = selector;
+ self.length = 1;
+
+ } else if( is.string( selector ) ){
+
+ // the current subject in the query
+ var currentSubject = null;
+
+ // storage for parsed queries
+ var newQuery = function(){
+ return {
+ classes: [],
+ colonSelectors: [],
+ data: [],
+ group: null,
+ ids: [],
+ meta: [],
+
+ // fake selectors
+ collection: null, // a collection to match against
+ filter: null, // filter function
+
+ // these are defined in the upward direction rather than down (e.g. child)
+ // because we need to go up in Selector.filter()
+ parent: null, // parent query obj
+ ancestor: null, // ancestor query obj
+ subject: null, // defines subject in compound query (subject query obj; points to self if subject)
+
+ // use these only when subject has been defined
+ child: null,
+ descendant: null
+ };
+ };
+
+ // tokens in the query language
+ var tokens = {
+ metaChar: '[\\!\\"\\#\\$\\%\\&\\\'\\(\\)\\*\\+\\,\\.\\/\\:\\;\\<\\=\\>\\?\\@\\[\\]\\^\\`\\{\\|\\}\\~]', // chars we need to escape in var names, etc
+ comparatorOp: '=|\\!=|>|>=|<|<=|\\$=|\\^=|\\*=', // binary comparison op (used in data selectors)
+ boolOp: '\\?|\\!|\\^', // boolean (unary) operators (used in data selectors)
+ string: '"(?:\\\\"|[^"])+"' + '|' + "'(?:\\\\'|[^'])+'", // string literals (used in data selectors) -- doublequotes | singlequotes
+ number: util.regex.number, // number literal (used in data selectors) --- e.g. 0.1234, 1234, 12e123
+ meta: 'degree|indegree|outdegree', // allowed metadata fields (i.e. allowed functions to use from Collection)
+ separator: '\\s*,\\s*', // queries are separated by commas, e.g. edge[foo = 'bar'], node.someClass
+ descendant: '\\s+',
+ child: '\\s+>\\s+',
+ subject: '\\$'
+ };
+ tokens.variable = '(?:[\\w-]|(?:\\\\'+ tokens.metaChar +'))+'; // a variable name
+ tokens.value = tokens.string + '|' + tokens.number; // a value literal, either a string or number
+ tokens.className = tokens.variable; // a class name (follows variable conventions)
+ tokens.id = tokens.variable; // an element id (follows variable conventions)
+
+ // when a token like a variable has escaped meta characters, we need to clean the backslashes out
+ // so that values get compared properly in Selector.filter()
+ var cleanMetaChars = function(str){
+ return str.replace(new RegExp('\\\\(' + tokens.metaChar + ')', 'g'), function(match, $1, offset, original){
+ return $1;
+ });
+ };
+
+ // add @ variants to comparatorOp
+ var ops = tokens.comparatorOp.split('|');
+ for( var i = 0; i < ops.length; i++ ){
+ var op = ops[i];
+ tokens.comparatorOp += '|@' + op;
+ }
+
+ // add ! variants to comparatorOp
+ var ops = tokens.comparatorOp.split('|');
+ for( var i = 0; i < ops.length; i++ ){
+ var op = ops[i];
+
+ if( op.indexOf('!') >= 0 ){ continue; } // skip ops that explicitly contain !
+ if( op === '=' ){ continue; } // skip = b/c != is explicitly defined
+
+ tokens.comparatorOp += '|\\!' + op;
+ }
+
+ // NOTE: add new expression syntax here to have it recognised by the parser;
+ // - a query contains all adjacent (i.e. no separator in between) expressions;
+ // - the current query is stored in self[i] --- you can use the reference to `this` in the populate function;
+ // - you need to check the query objects in Selector.filter() for it actually filter properly, but that's pretty straight forward
+ // - when you add something here, also add to Selector.toString()
+ var exprs = [
+ {
+ name: 'group',
+ query: true,
+ regex: '(node|edge|\\*)',
+ populate: function( group ){
+ this.group = group == "*" ? group : group + 's';
+ }
+ },
+
+ {
+ name: 'state',
+ query: true,
+ // NB: if one colon selector is a substring of another from its start, place the longer one first
+ // e.g. :foobar|:foo
+ regex: '(:selected|:unselected|:locked|:unlocked|:visible|:hidden|:transparent|:grabbed|:free|:removed|:inside|:grabbable|:ungrabbable|:animated|:unanimated|:selectable|:unselectable|:orphan|:nonorphan|:parent|:child|:loop|:simple|:active|:inactive|:touch|:backgrounding|:nonbackgrounding)',
+ populate: function( state ){
+ this.colonSelectors.push( state );
+ }
+ },
+
+ {
+ name: 'id',
+ query: true,
+ regex: '\\#('+ tokens.id +')',
+ populate: function( id ){
+ this.ids.push( cleanMetaChars(id) );
+ }
+ },
+
+ {
+ name: 'className',
+ query: true,
+ regex: '\\.('+ tokens.className +')',
+ populate: function( className ){
+ this.classes.push( cleanMetaChars(className) );
+ }
+ },
+
+ {
+ name: 'dataExists',
+ query: true,
+ regex: '\\[\\s*('+ tokens.variable +')\\s*\\]',
+ populate: function( variable ){
+ this.data.push({
+ field: cleanMetaChars(variable)
+ });
+ }
+ },
+
+ {
+ name: 'dataCompare',
+ query: true,
+ regex: '\\[\\s*('+ tokens.variable +')\\s*('+ tokens.comparatorOp +')\\s*('+ tokens.value +')\\s*\\]',
+ populate: function( variable, comparatorOp, value ){
+ var valueIsString = new RegExp('^' + tokens.string + '$').exec(value) != null;
+
+ if( valueIsString ){
+ value = value.substring(1, value.length - 1);
+ } else {
+ value = parseFloat(value);
+ }
+
+ this.data.push({
+ field: cleanMetaChars(variable),
+ operator: comparatorOp,
+ value: value
+ });
+ }
+ },
+
+ {
+ name: 'dataBool',
+ query: true,
+ regex: '\\[\\s*('+ tokens.boolOp +')\\s*('+ tokens.variable +')\\s*\\]',
+ populate: function( boolOp, variable ){
+ this.data.push({
+ field: cleanMetaChars(variable),
+ operator: boolOp
+ });
+ }
+ },
+
+ {
+ name: 'metaCompare',
+ query: true,
+ regex: '\\[\\[\\s*('+ tokens.meta +')\\s*('+ tokens.comparatorOp +')\\s*('+ tokens.number +')\\s*\\]\\]',
+ populate: function( meta, comparatorOp, number ){
+ this.meta.push({
+ field: cleanMetaChars(meta),
+ operator: comparatorOp,
+ value: parseFloat(number)
+ });
+ }
+ },
+
+ {
+ name: 'nextQuery',
+ separator: true,
+ regex: tokens.separator,
+ populate: function(){
+ // go on to next query
+ self[++i] = newQuery();
+ currentSubject = null;
+ }
+ },
+
+ {
+ name: 'child',
+ separator: true,
+ regex: tokens.child,
+ populate: function(){
+ // this query is the parent of the following query
+ var childQuery = newQuery();
+ childQuery.parent = this;
+ childQuery.subject = currentSubject;
+
+ // we're now populating the child query with expressions that follow
+ self[i] = childQuery;
+ }
+ },
+
+ {
+ name: 'descendant',
+ separator: true,
+ regex: tokens.descendant,
+ populate: function(){
+ // this query is the ancestor of the following query
+ var descendantQuery = newQuery();
+ descendantQuery.ancestor = this;
+ descendantQuery.subject = currentSubject;
+
+ // we're now populating the descendant query with expressions that follow
+ self[i] = descendantQuery;
+ }
+ },
+
+ {
+ name: 'subject',
+ modifier: true,
+ regex: tokens.subject,
+ populate: function(){
+ if( currentSubject != null && this.subject != this ){
+ util.error('Redefinition of subject in selector `' + selector + '`');
+ return false;
+ }
+
+ currentSubject = this;
+ this.subject = this;
+ }
+
+ }
+ ];
+
+ self._private.selectorText = selector;
+ var remaining = selector;
+ var i = 0;
+
+ // of all the expressions, find the first match in the remaining text
+ var consumeExpr = function( expectation ){
+ var expr;
+ var match;
+ var name;
+
+ for( var j = 0; j < exprs.length; j++ ){
+ var e = exprs[j];
+ var n = e.name;
+
+ // ignore this expression if it doesn't meet the expectation function
+ if( is.fn( expectation ) && !expectation(n, e) ){ continue; }
+
+ var m = remaining.match(new RegExp( '^' + e.regex ));
+
+ if( m != null ){
+ match = m;
+ expr = e;
+ name = n;
+
+ var consumed = m[0];
+ remaining = remaining.substring( consumed.length );
+
+ break; // we've consumed one expr, so we can return now
+ }
+ }
+
+ return {
+ expr: expr,
+ match: match,
+ name: name
+ };
+ };
+
+ // consume all leading whitespace
+ var consumeWhitespace = function(){
+ var match = remaining.match(/^\s+/);
+
+ if( match ){
+ var consumed = match[0];
+ remaining = remaining.substring( consumed.length );
+ }
+ };
+
+ self[0] = newQuery(); // get started
+
+ consumeWhitespace(); // get rid of leading whitespace
+ for(;;){
+ var check = consumeExpr();
+
+ if( check.expr == null ){
+ util.error('The selector `'+ selector +'`is invalid');
+ return;
+ } else {
+ var args = [];
+ for(var j = 1; j < check.match.length; j++){
+ args.push( check.match[j] );
+ }
+
+ // let the token populate the selector object (i.e. in self[i])
+ var ret = check.expr.populate.apply( self[i], args );
+
+ if( ret === false ){ return; } // exit if population failed
+ }
+
+ // we're done when there's nothing left to parse
+ if( remaining.match(/^\s*$/) ){
+ break;
+ }
+ }
+
+ self.length = i + 1;
+
+ // adjust references for subject
+ for(var j = 0; j < self.length; j++){
+ var query = self[j];
+
+ if( query.subject != null ){
+ // go up the tree until we reach the subject
+ for(;;){
+ if( query.subject == query ){ break; } // done if subject is self
+
+ if( query.parent != null ){ // swap parent/child reference
+ var parent = query.parent;
+ var child = query;
+
+ child.parent = null;
+ parent.child = child;
+
+ query = parent; // go up the tree
+ } else if( query.ancestor != null ){ // swap ancestor/descendant
+ var ancestor = query.ancestor;
+ var descendant = query;
+
+ descendant.ancestor = null;
+ ancestor.descendant = descendant;
+
+ query = ancestor; // go up the tree
+ } else {
+ util.error('When adjusting references for the selector `'+ query +'`, neither parent nor ancestor was found');
+ break;
+ }
+ } // for
+
+ self[j] = query.subject; // subject should be the root query
+ } // if
+ } // for
+
+ // make sure for each query that the subject group matches the implicit group if any
+ if( onlyThisGroup != null ){
+ for(var j = 0; j < self.length; j++){
+ if( self[j].group != null && self[j].group != onlyThisGroup ){
+ util.error('Group `'+ self[j].group +'` conflicts with implicit group `'+ onlyThisGroup +'` in selector `'+ selector +'`');
+ return;
+ }
+
+ self[j].group = onlyThisGroup; // set to implicit group
+ }
+ }
+
+ } else {
+ util.error('A selector must be created from a string; found ' + selector);
+ return;
+ }
+
+ self._private.invalid = false;
+
+};
+
+var selfn = Selector.prototype;
+
+selfn.size = function(){
+ return this.length;
+};
+
+selfn.eq = function(i){
+ return this[i];
+};
+
+var queryMatches = function(query, element){
+ // check group
+ if( query.group != null && query.group != '*' && query.group != element._private.group ){
+ return false;
+ }
+
+ var cy = element.cy();
+
+ // check colon selectors
+ var allColonSelectorsMatch = true;
+ for(var k = 0; k < query.colonSelectors.length; k++){
+ var sel = query.colonSelectors[k];
+
+ switch(sel){
+ case ':selected':
+ allColonSelectorsMatch = element.selected();
+ break;
+ case ':unselected':
+ allColonSelectorsMatch = !element.selected();
+ break;
+ case ':selectable':
+ allColonSelectorsMatch = element.selectable();
+ break;
+ case ':unselectable':
+ allColonSelectorsMatch = !element.selectable();
+ break;
+ case ':locked':
+ allColonSelectorsMatch = element.locked();
+ break;
+ case ':unlocked':
+ allColonSelectorsMatch = !element.locked();
+ break;
+ case ':visible':
+ allColonSelectorsMatch = element.visible();
+ break;
+ case ':hidden':
+ allColonSelectorsMatch = !element.visible();
+ break;
+ case ':transparent':
+ allColonSelectorsMatch = element.transparent();
+ break;
+ case ':grabbed':
+ allColonSelectorsMatch = element.grabbed();
+ break;
+ case ':free':
+ allColonSelectorsMatch = !element.grabbed();
+ break;
+ case ':removed':
+ allColonSelectorsMatch = element.removed();
+ break;
+ case ':inside':
+ allColonSelectorsMatch = !element.removed();
+ break;
+ case ':grabbable':
+ allColonSelectorsMatch = element.grabbable();
+ break;
+ case ':ungrabbable':
+ allColonSelectorsMatch = !element.grabbable();
+ break;
+ case ':animated':
+ allColonSelectorsMatch = element.animated();
+ break;
+ case ':unanimated':
+ allColonSelectorsMatch = !element.animated();
+ break;
+ case ':parent':
+ allColonSelectorsMatch = element.isNode() && element.children().nonempty();
+ break;
+ case ':child':
+ case ':nonorphan':
+ allColonSelectorsMatch = element.isNode() && element.parent().nonempty();
+ break;
+ case ':orphan':
+ allColonSelectorsMatch = element.isNode() && element.parent().empty();
+ break;
+ case ':loop':
+ allColonSelectorsMatch = element.isEdge() && element.data('source') === element.data('target');
+ break;
+ case ':simple':
+ allColonSelectorsMatch = element.isEdge() && element.data('source') !== element.data('target');
+ break;
+ case ':active':
+ allColonSelectorsMatch = element.active();
+ break;
+ case ':inactive':
+ allColonSelectorsMatch = !element.active();
+ break;
+ case ':touch':
+ allColonSelectorsMatch = is.touch();
+ break;
+ case ':backgrounding':
+ allColonSelectorsMatch = element.backgrounding();
+ break;
+ case ':nonbackgrounding':
+ allColonSelectorsMatch = !element.backgrounding();
+ break;
+ }
+
+ if( !allColonSelectorsMatch ) break;
+ }
+ if( !allColonSelectorsMatch ) return false;
+
+ // check id
+ var allIdsMatch = true;
+ for(var k = 0; k < query.ids.length; k++){
+ var id = query.ids[k];
+ var actualId = element._private.data.id;
+
+ allIdsMatch = allIdsMatch && (id == actualId);
+
+ if( !allIdsMatch ) break;
+ }
+ if( !allIdsMatch ) return false;
+
+ // check classes
+ var allClassesMatch = true;
+ for(var k = 0; k < query.classes.length; k++){
+ var cls = query.classes[k];
+
+ allClassesMatch = allClassesMatch && element.hasClass(cls);
+
+ if( !allClassesMatch ) break;
+ }
+ if( !allClassesMatch ) return false;
+
+ // generic checking for data/metadata
+ var operandsMatch = function(params){
+ var allDataMatches = true;
+ for(var k = 0; k < query[params.name].length; k++){
+ var data = query[params.name][k];
+ var operator = data.operator;
+ var value = data.value;
+ var field = data.field;
+ var matches;
+
+ if( operator != null && value != null ){
+
+ var fieldVal = params.fieldValue(field);
+ var fieldStr = !is.string(fieldVal) && !is.number(fieldVal) ? '' : '' + fieldVal;
+ var valStr = '' + value;
+
+ var caseInsensitive = false;
+ if( operator.indexOf('@') >= 0 ){
+ fieldStr = fieldStr.toLowerCase();
+ valStr = valStr.toLowerCase();
+
+ operator = operator.replace('@', '');
+ caseInsensitive = true;
+ }
+
+ var notExpr = false;
+ var handledNotExpr = false;
+ if( operator.indexOf('!') >= 0 ){
+ operator = operator.replace('!', '');
+ notExpr = true;
+ }
+
+ // if we're doing a case insensitive comparison, then we're using a STRING comparison
+ // even if we're comparing numbers
+ if( caseInsensitive ){
+ value = valStr.toLowerCase();
+ fieldVal = fieldStr.toLowerCase();
+ }
+
+ switch(operator){
+ case '*=':
+ matches = fieldStr.search(valStr) >= 0;
+ break;
+ case '$=':
+ matches = new RegExp(valStr + '$').exec(fieldStr) != null;
+ break;
+ case '^=':
+ matches = new RegExp('^' + valStr).exec(fieldStr) != null;
+ break;
+ case '=':
+ matches = fieldVal === value;
+ break;
+ case '!=':
+ matches = fieldVal !== value;
+ break;
+ case '>':
+ matches = !notExpr ? fieldVal > value : fieldVal <= value;
+ handledNotExpr = true;
+ break;
+ case '>=':
+ matches = !notExpr ? fieldVal >= value : fieldVal < value;
+ handledNotExpr = true;
+ break;
+ case '<':
+ matches = !notExpr ? fieldVal < value : fieldVal >= value;
+ handledNotExpr = true;
+ break;
+ case '<=':
+ matches = !notExpr ? fieldVal <= value : fieldVal > value;
+ handledNotExpr = true;
+ break;
+ default:
+ matches = false;
+ break;
+
+ }
+ } else if( operator != null ){
+ switch(operator){
+ case '?':
+ matches = params.fieldTruthy(field);
+ break;
+ case '!':
+ matches = !params.fieldTruthy(field);
+ break;
+ case '^':
+ matches = params.fieldUndefined(field);
+ break;
+ }
+ } else {
+ matches = !params.fieldUndefined(field);
+ }
+
+ if( notExpr && !handledNotExpr ){
+ matches = !matches;
+ handledNotExpr = true;
+ }
+
+ if( !matches ){
+ allDataMatches = false;
+ break;
+ }
+ } // for
+
+ return allDataMatches;
+ }; // operandsMatch
+
+ // check data matches
+ var allDataMatches = operandsMatch({
+ name: 'data',
+ fieldValue: function(field){
+ return element._private.data[field];
+ },
+ fieldRef: function(field){
+ return 'element._private.data.' + field;
+ },
+ fieldUndefined: function(field){
+ return element._private.data[field] === undefined;
+ },
+ fieldTruthy: function(field){
+ if( element._private.data[field] ){
+ return true;
+ }
+ return false;
+ }
+ });
+
+ if( !allDataMatches ){
+ return false;
+ }
+
+ // check metadata matches
+ var allMetaMatches = operandsMatch({
+ name: 'meta',
+ fieldValue: function(field){
+ return element[field]();
+ },
+ fieldRef: function(field){
+ return 'element.' + field + '()';
+ },
+ fieldUndefined: function(field){
+ return element[field]() == null;
+ },
+ fieldTruthy: function(field){
+ if( element[field]() ){
+ return true;
+ }
+ return false;
+ }
+ });
+
+ if( !allMetaMatches ){
+ return false;
+ }
+
+ // check collection
+ if( query.collection != null ){
+ var matchesAny = query.collection._private.ids[ element.id() ] != null;
+
+ if( !matchesAny ){
+ return false;
+ }
+ }
+
+ // check filter function
+ if( query.filter != null && element.collection().filter( query.filter ).size() === 0 ){
+ return false;
+ }
+
+
+ // check parent/child relations
+ var confirmRelations = function( query, elements ){
+ if( query != null ){
+ var matches = false;
+
+ if( !cy.hasCompoundNodes() ){
+ return false;
+ }
+
+ elements = elements(); // make elements functional so we save cycles if query == null
+
+ // query must match for at least one element (may be recursive)
+ for(var i = 0; i < elements.length; i++){
+ if( queryMatches( query, elements[i] ) ){
+ matches = true;
+ break;
+ }
+ }
+
+ return matches;
+ } else {
+ return true;
+ }
+ };
+
+ if (! confirmRelations(query.parent, function(){
+ return element.parent();
+ }) ){ return false; }
+
+ if (! confirmRelations(query.ancestor, function(){
+ return element.parents();
+ }) ){ return false; }
+
+ if (! confirmRelations(query.child, function(){
+ return element.children();
+ }) ){ return false; }
+
+ if (! confirmRelations(query.descendant, function(){
+ return element.descendants();
+ }) ){ return false; }
+
+ // we've reached the end, so we've matched everything for this query
+ return true;
+}; // queryMatches
+
+// filter an existing collection
+selfn.filter = function(collection){
+ var self = this;
+ var cy = collection.cy();
+
+ // don't bother trying if it's invalid
+ if( self._private.invalid ){
+ return cy.collection();
+ }
+
+ var selectorFunction = function(i, element){
+ for(var j = 0; j < self.length; j++){
+ var query = self[j];
+
+ if( queryMatches(query, element) ){
+ return true;
+ }
+ }
+
+ return false;
+ };
+
+ if( self._private.selectorText == null ){
+ selectorFunction = function(){ return true; };
+ }
+
+ var filteredCollection = collection.filter( selectorFunction );
+
+ return filteredCollection;
+}; // filter
+
+// does selector match a single element?
+selfn.matches = function(ele){
+ var self = this;
+
+ // don't bother trying if it's invalid
+ if( self._private.invalid ){
+ return false;
+ }
+
+ for(var j = 0; j < self.length; j++){
+ var query = self[j];
+
+ if( queryMatches(query, ele) ){
+ return true;
+ }
+ }
+
+ return false;
+}; // filter
+
+// ith query to string
+selfn.toString = selfn.selector = function(){
+
+ var str = '';
+
+ var clean = function(obj, isValue){
+ if( is.string(obj) ){
+ return isValue ? '"' + obj + '"' : obj;
+ }
+ return '';
+ };
+
+ var queryToString = function(query){
+ var str = '';
+
+ if( query.subject === query ){
+ str += '$';
+ }
+
+ var group = clean(query.group);
+ str += group.substring(0, group.length - 1);
+
+ for(var j = 0; j < query.data.length; j++){
+ var data = query.data[j];
+
+ if( data.value ){
+ str += '[' + data.field + clean(data.operator) + clean(data.value, true) + ']';
+ } else {
+ str += '[' + clean(data.operator) + data.field + ']';
+ }
+ }
+
+ for(var j = 0; j < query.meta.length; j++){
+ var meta = query.meta[j];
+ str += '[[' + meta.field + clean(meta.operator) + clean(meta.value, true) + ']]';
+ }
+
+ for(var j = 0; j < query.colonSelectors.length; j++){
+ var sel = query.colonSelectors[i];
+ str += sel;
+ }
+
+ for(var j = 0; j < query.ids.length; j++){
+ var sel = '#' + query.ids[i];
+ str += sel;
+ }
+
+ for(var j = 0; j < query.classes.length; j++){
+ var sel = '.' + query.classes[j];
+ str += sel;
+ }
+
+ if( query.parent != null ){
+ str = queryToString( query.parent ) + ' > ' + str;
+ }
+
+ if( query.ancestor != null ){
+ str = queryToString( query.ancestor ) + ' ' + str;
+ }
+
+ if( query.child != null ){
+ str += ' > ' + queryToString( query.child );
+ }
+
+ if( query.descendant != null ){
+ str += ' ' + queryToString( query.descendant );
+ }
+
+ return str;
+ };
+
+ for(var i = 0; i < this.length; i++){
+ var query = this[i];
+
+ str += queryToString( query );
+
+ if( this.length > 1 && i < this.length - 1 ){
+ str += ', ';
+ }
+ }
+
+ return str;
+};
+
+module.exports = Selector;
+
+},{"./is":77,"./util":94}],82:[function(_dereq_,module,exports){
+'use strict';
+
+var util = _dereq_('../util');
+var is = _dereq_('../is');
+
+var styfn = {};
+
+// (potentially expensive calculation)
+// apply the style to the element based on
+// - its bypass
+// - what selectors match it
+styfn.apply = function( eles ){
+ var self = this;
+
+ if( self._private.newStyle ){ // clear style caches
+ this._private.contextStyles = {};
+ this._private.propDiffs = {};
+ }
+
+ for( var ie = 0; ie < eles.length; ie++ ){
+ var ele = eles[ie];
+ var cxtMeta = self.getContextMeta( ele );
+ var cxtStyle = self.getContextStyle( cxtMeta );
+ var app = self.applyContextStyle( cxtMeta, cxtStyle, ele );
+
+ self.updateTransitions( ele, app.diffProps );
+ self.updateStyleHints( ele );
+
+ } // for elements
+
+ self._private.newStyle = false;
+};
+
+styfn.getPropertiesDiff = function( oldCxtKey, newCxtKey ){
+ var self = this;
+ var cache = self._private.propDiffs = self._private.propDiffs || {};
+ var dualCxtKey = oldCxtKey + '-' + newCxtKey;
+ var cachedVal = cache[dualCxtKey];
+
+ if( cachedVal ){
+ return cachedVal;
+ }
+
+ var diffProps = [];
+ var addedProp = {};
+
+ for( var i = 0; i < self.length; i++ ){
+ var cxt = self[i];
+ var oldHasCxt = oldCxtKey[i] === 't';
+ var newHasCxt = newCxtKey[i] === 't';
+ var cxtHasDiffed = oldHasCxt !== newHasCxt;
+ var cxtHasMappedProps = cxt.mappedProperties.length > 0;
+
+ if( cxtHasDiffed || cxtHasMappedProps ){
+ var props;
+
+ if( cxtHasDiffed && cxtHasMappedProps ){
+ props = cxt.properties; // suffices b/c mappedProperties is a subset of properties
+ } else if( cxtHasDiffed ){
+ props = cxt.properties; // need to check them all
+ } else if( cxtHasMappedProps ){
+ props = cxt.mappedProperties; // only need to check mapped
+ }
+
+ for( var j = 0; j < props.length; j++ ){
+ var prop = props[j];
+ var name = prop.name;
+
+ // if a later context overrides this property, then the fact that this context has switched/diffed doesn't matter
+ // (semi expensive check since it makes this function O(n^2) on context length, but worth it since overall result
+ // is cached)
+ var laterCxtOverrides = false;
+ for( var k = i + 1; k < self.length; k++ ){
+ var laterCxt = self[k];
+ var hasLaterCxt = newCxtKey[k] === 't';
+
+ if( !hasLaterCxt ){ continue; } // can't override unless the context is active
+
+ laterCxtOverrides = laterCxt.properties[ prop.name ] != null;
+
+ if( laterCxtOverrides ){ break; } // exit early as long as one later context overrides
+ }
+
+ if( !addedProp[name] && !laterCxtOverrides ){
+ addedProp[name] = true;
+ diffProps.push( name );
+ }
+ } // for props
+ } // if
+
+ } // for contexts
+
+ cache[ dualCxtKey ] = diffProps;
+ return diffProps;
+};
+
+styfn.getContextMeta = function( ele ){
+ var self = this;
+ var cxtKey = '';
+ var diffProps;
+ var prevKey = ele._private.styleCxtKey || '';
+
+ if( self._private.newStyle ){
+ prevKey = ''; // since we need to apply all style if a fresh stylesheet
+ }
+
+ // get the cxt key
+ for( var i = 0; i < self.length; i++ ){
+ var context = self[i];
+ var contextSelectorMatches = context.selector && context.selector.matches( ele ); // NB: context.selector may be null for 'core'
+
+ if( contextSelectorMatches ){
+ cxtKey += 't';
+ } else {
+ cxtKey += 'f';
+ }
+ } // for context
+
+ diffProps = self.getPropertiesDiff( prevKey, cxtKey );
+
+ ele._private.styleCxtKey = cxtKey;
+
+ return {
+ key: cxtKey,
+ diffPropNames: diffProps
+ };
+};
+
+// gets a computed ele style object based on matched contexts
+styfn.getContextStyle = function( cxtMeta ){
+ var cxtKey = cxtMeta.key;
+ var self = this;
+ var cxtStyles = this._private.contextStyles = this._private.contextStyles || {};
+
+ // if already computed style, returned cached copy
+ if( cxtStyles[cxtKey] ){ return cxtStyles[cxtKey]; }
+
+ var style = {
+ _private: {
+ key: cxtKey
+ }
+ };
+
+ for( var i = 0; i < self.length; i++ ){
+ var cxt = self[i];
+ var hasCxt = cxtKey[i] === 't';
+
+ if( !hasCxt ){ continue; }
+
+ for( var j = 0; j < cxt.properties.length; j++ ){
+ var prop = cxt.properties[j];
+ var styProp = style[ prop.name ] = prop;
+
+ styProp.context = cxt;
+ }
+ }
+
+ cxtStyles[cxtKey] = style;
+ return style;
+};
+
+styfn.applyContextStyle = function( cxtMeta, cxtStyle, ele ){
+ var self = this;
+ var diffProps = cxtMeta.diffPropNames;
+ var retDiffProps = {};
+
+ for( var i = 0; i < diffProps.length; i++ ){
+ var diffPropName = diffProps[i];
+ var cxtProp = cxtStyle[ diffPropName ];
+ var eleProp = ele._private.style[ diffPropName ];
+
+ // save cycles when the context prop doesn't need to be applied
+ if( !cxtProp || eleProp === cxtProp ){ continue; }
+
+ var retDiffProp = retDiffProps[ diffPropName ] = {
+ prev: eleProp
+ };
+
+ self.applyParsedProperty( ele, cxtProp );
+
+ retDiffProp.next = ele._private.style[ diffPropName ];
+
+ if( retDiffProp.next && retDiffProp.next.bypass ){
+ retDiffProp.next = retDiffProp.next.bypassed;
+ }
+ }
+
+ return {
+ diffProps: retDiffProps
+ };
+};
+
+styfn.updateStyleHints = function(ele){
+ var _p = ele._private;
+ var self = this;
+ var style = _p.style;
+
+ if( ele.removed() ){ return; }
+
+ // set whether has pie or not; for greater efficiency
+ var hasPie = false;
+ if( _p.group === 'nodes' && self._private.hasPie ){
+ for( var i = 1; i <= self.pieBackgroundN; i++ ){ // 1..N
+ var size = _p.style['pie-' + i + '-background-size'].value;
+
+ if( size > 0 ){
+ hasPie = true;
+ break;
+ }
+ }
+ }
+
+ _p.hasPie = hasPie;
+
+ var transform = style['text-transform'].strValue;
+ var content = style['label'].strValue;
+ var fStyle = style['font-style'].strValue;
+ var size = style['font-size'].pfValue + 'px';
+ var family = style['font-family'].strValue;
+ // var variant = style['font-variant'].strValue;
+ var weight = style['font-weight'].strValue;
+ var valign = style['text-valign'].strValue;
+ var halign = style['text-valign'].strValue;
+ var oWidth = style['text-outline-width'].pfValue;
+ var wrap = style['text-wrap'].strValue;
+ var wrapW = style['text-max-width'].pfValue;
+ _p.labelKey = fStyle +'$'+ size +'$'+ family +'$'+ weight +'$'+ content +'$'+ transform +'$'+ valign +'$'+ halign +'$'+ oWidth + '$' + wrap + '$' + wrapW;
+ _p.fontKey = fStyle +'$'+ weight +'$'+ size +'$'+ family;
+
+ var width = style['width'].pfValue;
+ var height = style['height'].pfValue;
+ var borderW = style['border-width'].pfValue;
+ _p.boundingBoxKey = width +'$'+ height +'$'+ borderW;
+
+ if( ele._private.group === 'edges' ){
+ var cpss = style['control-point-step-size'].pfValue;
+ var cpd = style['control-point-distances'] ? style['control-point-distances'].pfValue.join('_') : undefined;
+ var cpw = style['control-point-weights'].value.join('_');
+ var curve = style['curve-style'].strValue;
+
+ _p.boundingBoxKey += '$'+ cpss +'$'+ cpd +'$'+ cpw +'$'+ curve;
+ }
+
+ _p.styleKey = Date.now();
+};
+
+// apply a property to the style (for internal use)
+// returns whether application was successful
+//
+// now, this function flattens the property, and here's how:
+//
+// for parsedProp:{ bypass: true, deleteBypass: true }
+// no property is generated, instead the bypass property in the
+// element's style is replaced by what's pointed to by the `bypassed`
+// field in the bypass property (i.e. restoring the property the
+// bypass was overriding)
+//
+// for parsedProp:{ mapped: truthy }
+// the generated flattenedProp:{ mapping: prop }
+//
+// for parsedProp:{ bypass: true }
+// the generated flattenedProp:{ bypassed: parsedProp }
+styfn.applyParsedProperty = function( ele, parsedProp ){
+ var self = this;
+ var prop = parsedProp;
+ var style = ele._private.style;
+ var fieldVal, flatProp;
+ var types = self.types;
+ var type = self.properties[ prop.name ].type;
+ var propIsBypass = prop.bypass;
+ var origProp = style[ prop.name ];
+ var origPropIsBypass = origProp && origProp.bypass;
+ var _p = ele._private;
+
+ // can't apply auto to width or height unless it's a parent node
+ if( (parsedProp.name === 'height' || parsedProp.name === 'width') && ele.isNode() ){
+ if( parsedProp.value === 'auto' && !ele.isParent() ){
+ return false;
+ } else if( parsedProp.value !== 'auto' && ele.isParent() ){
+ prop = parsedProp = this.parse( parsedProp.name, 'auto', propIsBypass );
+ }
+ }
+
+ // check if we need to delete the current bypass
+ if( propIsBypass && prop.deleteBypass ){ // then this property is just here to indicate we need to delete
+ var currentProp = style[ prop.name ];
+
+ // can only delete if the current prop is a bypass and it points to the property it was overriding
+ if( !currentProp ){
+ return true; // property is already not defined
+ } else if( currentProp.bypass && currentProp.bypassed ){ // then replace the bypass property with the original
+
+ // because the bypassed property was already applied (and therefore parsed), we can just replace it (no reapplying necessary)
+ style[ prop.name ] = currentProp.bypassed;
+ return true;
+
+ } else {
+ return false; // we're unsuccessful deleting the bypass
+ }
+ }
+
+ var printMappingErr = function(){
+ util.error('Do not assign mappings to elements without corresponding data (e.g. ele `'+ ele.id() +'` for property `'+ prop.name +'` with data field `'+ prop.field +'`); try a `['+ prop.field +']` selector to limit scope to elements with `'+ prop.field +'` defined');
+ };
+
+ // put the property in the style objects
+ switch( prop.mapped ){ // flatten the property if mapped
+ case types.mapData:
+ case types.mapLayoutData:
+ case types.mapScratch:
+
+ var isLayout = prop.mapped === types.mapLayoutData;
+ var isScratch = prop.mapped === types.mapScratch;
+
+ // flatten the field (e.g. data.foo.bar)
+ var fields = prop.field.split(".");
+ var fieldVal;
+
+ if( isScratch || isLayout ){
+ fieldVal = _p.scratch;
+ } else {
+ fieldVal = _p.data;
+ }
+
+ for( var i = 0; i < fields.length && fieldVal; i++ ){
+ var field = fields[i];
+ fieldVal = fieldVal[ field ];
+ }
+
+ var percent;
+ if( !is.number(fieldVal) ){ // then keep the mapping but assume 0% for now
+ percent = 0;
+ } else {
+ percent = (fieldVal - prop.fieldMin) / (prop.fieldMax - prop.fieldMin);
+ }
+
+ // make sure to bound percent value
+ if( percent < 0 ){
+ percent = 0;
+ } else if( percent > 1 ){
+ percent = 1;
+ }
+
+ if( type.color ){
+ var r1 = prop.valueMin[0];
+ var r2 = prop.valueMax[0];
+ var g1 = prop.valueMin[1];
+ var g2 = prop.valueMax[1];
+ var b1 = prop.valueMin[2];
+ var b2 = prop.valueMax[2];
+ var a1 = prop.valueMin[3] == null ? 1 : prop.valueMin[3];
+ var a2 = prop.valueMax[3] == null ? 1 : prop.valueMax[3];
+
+ var clr = [
+ Math.round( r1 + (r2 - r1)*percent ),
+ Math.round( g1 + (g2 - g1)*percent ),
+ Math.round( b1 + (b2 - b1)*percent ),
+ Math.round( a1 + (a2 - a1)*percent )
+ ];
+
+ flatProp = { // colours are simple, so just create the flat property instead of expensive string parsing
+ bypass: prop.bypass, // we're a bypass if the mapping property is a bypass
+ name: prop.name,
+ value: clr,
+ strValue: 'rgb(' + clr[0] + ', ' + clr[1] + ', ' + clr[2] + ')'
+ };
+
+ } else if( type.number ){
+ var calcValue = prop.valueMin + (prop.valueMax - prop.valueMin) * percent;
+ flatProp = this.parse( prop.name, calcValue, prop.bypass, true );
+
+ } else {
+ return false; // can only map to colours and numbers
+ }
+
+ if( !flatProp ){ // if we can't flatten the property, then use the origProp so we still keep the mapping itself
+ flatProp = this.parse( prop.name, origProp.strValue, prop.bypass, true );
+ }
+
+ if( !flatProp ){ printMappingErr(); }
+ flatProp.mapping = prop; // keep a reference to the mapping
+ prop = flatProp; // the flattened (mapped) property is the one we want
+
+ break;
+
+ // direct mapping
+ case types.data:
+ case types.layoutData:
+ case types.scratch:
+ var isLayout = prop.mapped === types.layoutData;
+ var isScratch = prop.mapped === types.scratch;
+
+ // flatten the field (e.g. data.foo.bar)
+ var fields = prop.field.split(".");
+ var fieldVal;
+
+ if( isScratch || isLayout ){
+ fieldVal = _p.scratch;
+ } else {
+ fieldVal = _p.data;
+ }
+
+ if( fieldVal ){ for( var i = 0; i < fields.length; i++ ){
+ var field = fields[i];
+ fieldVal = fieldVal[ field ];
+ } }
+
+ flatProp = this.parse( prop.name, fieldVal, prop.bypass, true );
+
+ if( !flatProp ){ // if we can't flatten the property, then use the origProp so we still keep the mapping itself
+ var flatPropVal = origProp ? origProp.strValue : '';
+
+ flatProp = this.parse( prop.name, flatPropVal, prop.bypass, true );
+ }
+
+ if( !flatProp ){ printMappingErr(); }
+ flatProp.mapping = prop; // keep a reference to the mapping
+ prop = flatProp; // the flattened (mapped) property is the one we want
+
+ break;
+
+ case types.fn:
+ var fn = prop.value;
+ var fnRetVal = fn( ele );
+
+ flatProp = this.parse( prop.name, fnRetVal, prop.bypass, true );
+ flatProp.mapping = prop; // keep a reference to the mapping
+ prop = flatProp; // the flattened (mapped) property is the one we want
+
+ break;
+
+ case undefined:
+ break; // just set the property
+
+ default:
+ return false; // not a valid mapping
+ }
+
+ // if the property is a bypass property, then link the resultant property to the original one
+ if( propIsBypass ){
+ if( origPropIsBypass ){ // then this bypass overrides the existing one
+ prop.bypassed = origProp.bypassed; // steal bypassed prop from old bypass
+ } else { // then link the orig prop to the new bypass
+ prop.bypassed = origProp;
+ }
+
+ style[ prop.name ] = prop; // and set
+
+ } else { // prop is not bypass
+ if( origPropIsBypass ){ // then keep the orig prop (since it's a bypass) and link to the new prop
+ origProp.bypassed = prop;
+ } else { // then just replace the old prop with the new one
+ style[ prop.name ] = prop;
+ }
+ }
+
+ return true;
+};
+
+// updates the visual style for all elements (useful for manual style modification after init)
+styfn.update = function(){
+ var cy = this._private.cy;
+ var eles = cy.elements();
+
+ eles.updateStyle();
+};
+
+// just update the functional properties (i.e. mappings) in the elements'
+// styles (less expensive than recalculation)
+styfn.updateMappers = function( eles ){
+ var self = this;
+
+ for( var i = 0; i < eles.length; i++ ){ // for each ele
+ var ele = eles[i];
+ var style = ele._private.style;
+
+ for( var j = 0; j < self.properties.length; j++ ){ // for each prop
+ var prop = self.properties[j];
+ var propInStyle = style[ prop.name ];
+
+ if( propInStyle && propInStyle.mapping ){
+ var mapping = propInStyle.mapping;
+ this.applyParsedProperty( ele, mapping ); // reapply the mapping property
+ }
+ }
+
+ this.updateStyleHints( ele );
+ }
+};
+
+// diffProps : { name => { prev, next } }
+styfn.updateTransitions = function( ele, diffProps, isBypass ){
+ var self = this;
+ var _p = ele._private;
+ var style = _p.style;
+ var props = style['transition-property'].value;
+ var duration = style['transition-duration'].pfValue;
+ var delay = style['transition-delay'].pfValue;
+ var css = {};
+
+ if( props.length > 0 && duration > 0 ){
+
+ // build up the style to animate towards
+ var anyPrev = false;
+ for( var i = 0; i < props.length; i++ ){
+ var prop = props[i];
+ var styProp = style[ prop ];
+ var diffProp = diffProps[ prop ];
+
+ if( !diffProp ){ continue; }
+
+ var prevProp = diffProp.prev;
+ var fromProp = prevProp;
+ var toProp = diffProp.next != null ? diffProp.next : styProp;
+ var diff = false;
+ var initVal;
+ var initDt = 0.000001; // delta time % value for initVal (allows animating out of init zero opacity)
+
+ if( !fromProp ){ continue; }
+
+ // consider px values
+ if( is.number( fromProp.pfValue ) && is.number( toProp.pfValue ) ){
+ diff = toProp.pfValue - fromProp.pfValue; // nonzero is truthy
+ initVal = fromProp.pfValue + initDt * diff;
+
+ // consider numerical values
+ } else if( is.number( fromProp.value ) && is.number( toProp.value ) ){
+ diff = toProp.value - fromProp.value; // nonzero is truthy
+ initVal = fromProp.value + initDt * diff;
+
+ // consider colour values
+ } else if( is.array( fromProp.value ) && is.array( toProp.value ) ){
+ diff = fromProp.value[0] !== toProp.value[0]
+ || fromProp.value[1] !== toProp.value[1]
+ || fromProp.value[2] !== toProp.value[2]
+ ;
+
+ initVal = fromProp.strValue;
+ }
+
+ // the previous value is good for an animation only if it's different
+ if( diff ){
+ css[ prop ] = toProp.strValue; // to val
+ this.applyBypass( ele, prop, initVal ); // from val
+ anyPrev = true;
+ }
+
+ } // end if props allow ani
+
+ // can't transition if there's nothing previous to transition from
+ if( !anyPrev ){ return; }
+
+ _p.transitioning = true;
+
+ ele.stop();
+
+ if( delay > 0 ){
+ ele.delay( delay );
+ }
+
+ ele.animate({
+ css: css
+ }, {
+ duration: duration,
+ easing: style['transition-timing-function'].value,
+ queue: false,
+ complete: function(){
+ if( !isBypass ){
+ self.removeBypasses( ele, props );
+ }
+
+ _p.transitioning = false;
+ }
+ });
+
+ } else if( _p.transitioning ){
+ ele.stop();
+
+ this.removeBypasses( ele, props );
+
+ _p.transitioning = false;
+ }
+};
+
+module.exports = styfn;
+
+},{"../is":77,"../util":94}],83:[function(_dereq_,module,exports){
+'use strict';
+
+var is = _dereq_('../is');
+var util = _dereq_('../util');
+
+var styfn = {};
+
+// bypasses are applied to an existing style on an element, and just tacked on temporarily
+// returns true iff application was successful for at least 1 specified property
+styfn.applyBypass = function( eles, name, value, updateTransitions ){
+ var self = this;
+ var props = [];
+ var isBypass = true;
+
+ // put all the properties (can specify one or many) in an array after parsing them
+ if( name === "*" || name === "**" ){ // apply to all property names
+
+ if( value !== undefined ){
+ for( var i = 0; i < self.properties.length; i++ ){
+ var prop = self.properties[i];
+ var name = prop.name;
+
+ var parsedProp = this.parse(name, value, true);
+
+ if( parsedProp ){
+ props.push( parsedProp );
+ }
+ }
+ }
+
+ } else if( is.string(name) ){ // then parse the single property
+ var parsedProp = this.parse(name, value, true);
+
+ if( parsedProp ){
+ props.push( parsedProp );
+ }
+ } else if( is.plainObject(name) ){ // then parse each property
+ var specifiedProps = name;
+ updateTransitions = value;
+
+ for( var i = 0; i < self.properties.length; i++ ){
+ var prop = self.properties[i];
+ var name = prop.name;
+ var value = specifiedProps[ name ];
+
+ if( value === undefined ){ // try camel case name too
+ value = specifiedProps[ util.dash2camel(name) ];
+ }
+
+ if( value !== undefined ){
+ var parsedProp = this.parse(name, value, true);
+
+ if( parsedProp ){
+ props.push( parsedProp );
+ }
+ }
+ }
+ } else { // can't do anything without well defined properties
+ return false;
+ }
+
+ // we've failed if there are no valid properties
+ if( props.length === 0 ){ return false; }
+
+ // now, apply the bypass properties on the elements
+ var ret = false; // return true if at least one succesful bypass applied
+ for( var i = 0; i < eles.length; i++ ){ // for each ele
+ var ele = eles[i];
+ var style = ele._private.style;
+ var diffProps = {};
+ var diffProp;
+
+ for( var j = 0; j < props.length; j++ ){ // for each prop
+ var prop = props[j];
+
+ if( updateTransitions ){
+ var prevProp = style[ prop.name ];
+ diffProp = diffProps[ prop.name ] = { prev: prevProp };
+ }
+
+ ret = this.applyParsedProperty( ele, prop ) || ret;
+
+ if( updateTransitions ){
+ diffProp.next = style[ prop.name ];
+ }
+
+ } // for props
+
+ if( ret ){
+ this.updateStyleHints( ele );
+ }
+
+ if( updateTransitions ){
+ this.updateTransitions( ele, diffProps, isBypass );
+ }
+ } // for eles
+
+ return ret;
+};
+
+// only useful in specific cases like animation
+styfn.overrideBypass = function( eles, name, value ){
+ name = util.camel2dash(name);
+
+ for( var i = 0; i < eles.length; i++ ){
+ var ele = eles[i];
+ var prop = ele._private.style[ name ];
+ var type = this.properties[ name ].type;
+ var isColor = type.color;
+ var isMulti = type.mutiple;
+
+ if( !prop.bypass ){ // need a bypass if one doesn't exist
+ this.applyBypass( ele, name, value );
+ continue;
+ }
+
+ prop.value = value;
+
+ if( prop.pfValue != null ){
+ prop.pfValue = value;
+ }
+
+ if( isColor ){
+ prop.strValue = 'rgb(' + value.join(',') + ')';
+ } else if( isMulti ){
+ prop.strValue = value.join(' ');
+ } else {
+ prop.strValue = '' + value;
+ }
+ }
+};
+
+styfn.removeAllBypasses = function( eles, updateTransitions ){
+ return this.removeBypasses( eles, this.propertyNames, updateTransitions );
+};
+
+styfn.removeBypasses = function( eles, props, updateTransitions ){
+ var isBypass = true;
+
+ for( var j = 0; j < eles.length; j++ ){
+ var ele = eles[j];
+ var diffProps = {};
+ var style = ele._private.style;
+
+ for( var i = 0; i < props.length; i++ ){
+ var name = props[i];
+ var prop = this.properties[ name ];
+ var value = ''; // empty => remove bypass
+ var parsedProp = this.parse(name, value, true);
+ var prevProp = style[ prop.name ];
+ var diffProp = diffProps[ prop.name ] = { prev: prevProp };
+
+ this.applyParsedProperty(ele, parsedProp);
+
+ diffProp.next = style[ prop.name ];
+ } // for props
+
+ this.updateStyleHints( ele );
+
+ if( updateTransitions ){
+ this.updateTransitions( ele, diffProps, isBypass );
+ }
+ } // for eles
+};
+
+module.exports = styfn;
+
+},{"../is":77,"../util":94}],84:[function(_dereq_,module,exports){
+'use strict';
+
+var window = _dereq_('../window');
+
+var styfn = {};
+
+// gets what an em size corresponds to in pixels relative to a dom element
+styfn.getEmSizeInPixels = function(){
+ var px = this.containerCss('font-size');
+
+ if( px != null ){
+ return parseFloat( px );
+ } else {
+ return 1; // for headless
+ }
+};
+
+// gets css property from the core container
+styfn.containerCss = function( propName ){
+ var cy = this._private.cy;
+ var domElement = cy.container();
+
+ if( window && domElement && window.getComputedStyle ){
+ return window.getComputedStyle(domElement).getPropertyValue( propName );
+ }
+};
+
+module.exports = styfn;
+
+},{"../window":100}],85:[function(_dereq_,module,exports){
+'use strict';
+
+var util = _dereq_('../util');
+var is = _dereq_('../is');
+
+var styfn = {};
+
+// gets the rendered style for an element
+styfn.getRenderedStyle = function( ele ){
+ return this.getRawStyle( ele, true );
+};
+
+// gets the raw style for an element
+styfn.getRawStyle = function( ele, isRenderedVal ){
+ var self = this;
+ var ele = ele[0]; // insure it's an element
+
+ if( ele ){
+ var rstyle = {};
+
+ for( var i = 0; i < self.properties.length; i++ ){
+ var prop = self.properties[i];
+ var val = self.getStylePropertyValue( ele, prop.name, isRenderedVal );
+
+ if( val ){
+ rstyle[ prop.name ] = val;
+ rstyle[ util.dash2camel(prop.name) ] = val;
+ }
+ }
+
+ return rstyle;
+ }
+};
+
+styfn.getStylePropertyValue = function( ele, propName, isRenderedVal ){
+ var self = this;
+ var ele = ele[0]; // insure it's an element
+
+ if( ele ){
+ var style = ele._private.style;
+ var prop = self.properties[ propName ];
+ var type = prop.type;
+ var styleProp = style[ prop.name ];
+ var zoom = ele.cy().zoom();
+
+ if( styleProp ){
+ var units = styleProp.units ? type.implicitUnits || 'px' : null;
+ var val = units ? [].concat( styleProp.pfValue ).map(function( pfValue ){
+ return ( pfValue * (isRenderedVal ? zoom : 1) ) + units;
+ }).join(' ') : styleProp.strValue;
+
+ return val;
+ }
+ }
+};
+
+// gets the value style for an element (useful for things like animations)
+styfn.getValueStyle = function( ele ){
+ var self = this;
+ var rstyle = {};
+ var style;
+ var isEle = is.element(ele);
+
+ if( isEle ){
+ style = ele._private.style;
+ } else {
+ style = ele; // just passed the style itself
+ }
+
+ if( style ){
+ for( var i = 0; i < self.properties.length; i++ ){
+ var prop = self.properties[i];
+ var styleProp = style[ prop.name ] || style[ util.dash2camel(prop.name) ];
+
+ if( styleProp !== undefined ){ // then make a prop of it
+ if( is.plainObject( styleProp ) ){
+ styleProp = this.parse( prop.name, styleProp.strValue );
+ } else {
+ styleProp = this.parse( prop.name, styleProp );
+ }
+ }
+
+ if( styleProp ){
+ rstyle[ prop.name ] = styleProp;
+ rstyle[ util.dash2camel(prop.name) ] = styleProp;
+ }
+ }
+ }
+
+ return rstyle;
+};
+
+styfn.getPropsList = function( propsObj ){
+ var self = this;
+ var rstyle = [];
+ var style = propsObj;
+ var props = self.properties;
+
+ if( style ){
+ for( var name in style ){
+ var val = style[name];
+ var prop = props[name] || props[ util.camel2dash(name) ];
+ var styleProp = this.parse( prop.name, val );
+
+ rstyle.push( styleProp );
+ }
+ }
+
+ return rstyle;
+};
+
+module.exports = styfn;
+
+},{"../is":77,"../util":94}],86:[function(_dereq_,module,exports){
+'use strict';
+
+var is = _dereq_('../is');
+var util = _dereq_('../util');
+var Selector = _dereq_('../selector');
+
+var Style = function( cy ){
+
+ if( !(this instanceof Style) ){
+ return new Style(cy);
+ }
+
+ if( !is.core(cy) ){
+ util.error('A style must have a core reference');
+ return;
+ }
+
+ this._private = {
+ cy: cy,
+ coreStyle: {},
+ newStyle: true
+ };
+
+ this.length = 0;
+
+ this.addDefaultStylesheet();
+};
+
+var styfn = Style.prototype;
+
+styfn.instanceString = function(){
+ return 'style';
+};
+
+// remove all contexts
+styfn.clear = function(){
+ for( var i = 0; i < this.length; i++ ){
+ this[i] = undefined;
+ }
+ this.length = 0;
+ this._private.newStyle = true;
+
+ return this; // chaining
+};
+
+styfn.resetToDefault = function(){
+ this.clear();
+ this.addDefaultStylesheet();
+
+ return this;
+};
+
+// builds a style object for the 'core' selector
+styfn.core = function(){
+ return this._private.coreStyle;
+};
+
+// create a new context from the specified selector string and switch to that context
+styfn.selector = function( selectorStr ){
+ // 'core' is a special case and does not need a selector
+ var selector = selectorStr === 'core' ? null : new Selector( selectorStr );
+
+ var i = this.length++; // new context means new index
+ this[i] = {
+ selector: selector,
+ properties: [],
+ mappedProperties: [],
+ index: i
+ };
+
+ return this; // chaining
+};
+
+// add one or many css rules to the current context
+styfn.css = function(){
+ var self = this;
+ var args = arguments;
+
+ switch( args.length ){
+ case 1:
+ var map = args[0];
+
+ for( var i = 0; i < self.properties.length; i++ ){
+ var prop = self.properties[i];
+ var mapVal = map[ prop.name ];
+
+ if( mapVal === undefined ){
+ mapVal = map[ util.dash2camel(prop.name) ];
+ }
+
+ if( mapVal !== undefined ){
+ this.cssRule( prop.name, mapVal );
+ }
+ }
+
+ break;
+
+ case 2:
+ this.cssRule( args[0], args[1] );
+ break;
+
+ default:
+ break; // do nothing if args are invalid
+ }
+
+ return this; // chaining
+};
+styfn.style = styfn.css;
+
+// add a single css rule to the current context
+styfn.cssRule = function( name, value ){
+ // name-value pair
+ var property = this.parse( name, value );
+
+ // add property to current context if valid
+ if( property ){
+ var i = this.length - 1;
+ this[i].properties.push( property );
+ this[i].properties[ property.name ] = property; // allow access by name as well
+
+ if( property.name.match(/pie-(\d+)-background-size/) && property.value ){
+ this._private.hasPie = true;
+ }
+
+ if( property.mapped ){
+ this[i].mappedProperties.push( property );
+ }
+
+ // add to core style if necessary
+ var currentSelectorIsCore = !this[i].selector;
+ if( currentSelectorIsCore ){
+ this._private.coreStyle[ property.name ] = property;
+ }
+ }
+
+ return this; // chaining
+};
+
+// static function
+Style.fromJson = function( cy, json ){
+ var style = new Style( cy );
+
+ style.fromJson( json );
+
+ return style;
+};
+
+Style.fromString = function( cy, string ){
+ return new Style( cy ).fromString( string );
+};
+
+[
+ _dereq_('./apply'),
+ _dereq_('./bypass'),
+ _dereq_('./container'),
+ _dereq_('./get-for-ele'),
+ _dereq_('./json'),
+ _dereq_('./string-sheet'),
+ _dereq_('./properties'),
+ _dereq_('./parse')
+].forEach(function( props ){
+ util.extend( styfn, props );
+});
+
+
+Style.types = styfn.types;
+Style.properties = styfn.properties;
+
+module.exports = Style;
+
+},{"../is":77,"../selector":81,"../util":94,"./apply":82,"./bypass":83,"./container":84,"./get-for-ele":85,"./json":87,"./parse":88,"./properties":89,"./string-sheet":90}],87:[function(_dereq_,module,exports){
+'use strict';
+
+var styfn = {};
+
+styfn.applyFromJson = function( json ){
+ var style = this;
+
+ for( var i = 0; i < json.length; i++ ){
+ var context = json[i];
+ var selector = context.selector;
+ var props = context.style || context.css;
+
+ style.selector( selector ); // apply selector
+
+ for( var name in props ){
+ var value = props[name];
+
+ style.css( name, value ); // apply property
+ }
+ }
+
+ return style;
+};
+
+// accessible cy.style() function
+styfn.fromJson = function( json ){
+ var style = this;
+
+ style.resetToDefault();
+ style.applyFromJson( json );
+
+ return style;
+};
+
+// get json from cy.style() api
+styfn.json = function(){
+ var json = [];
+
+ for( var i = this.defaultLength; i < this.length; i++ ){
+ var cxt = this[i];
+ var selector = cxt.selector;
+ var props = cxt.properties;
+ var css = {};
+
+ for( var j = 0; j < props.length; j++ ){
+ var prop = props[j];
+ css[ prop.name ] = prop.strValue;
+ }
+
+ json.push({
+ selector: !selector ? 'core' : selector.toString(),
+ style: css
+ });
+ }
+
+ return json;
+};
+
+module.exports = styfn;
+
+},{}],88:[function(_dereq_,module,exports){
+'use strict';
+
+var util = _dereq_('../util');
+var is = _dereq_('../is');
+
+var styfn = {};
+
+// a caching layer for property parsing
+styfn.parse = function( name, value, propIsBypass, propIsFlat ){
+ var argHash = [ name, value, propIsBypass, propIsFlat ].join('$');
+ var propCache = this.propCache = this.propCache || {};
+ var ret;
+ var impl = parseImpl.bind( this );
+
+ if( !(ret = propCache[argHash]) ){
+ ret = propCache[argHash] = impl( name, value, propIsBypass, propIsFlat );
+ }
+
+ // always need a copy since props are mutated later in their lifecycles
+ ret = util.copy( ret );
+
+ if( ret ){
+ ret.value = util.copy( ret.value ); // because it could be an array, e.g. colour
+ }
+
+ return ret;
+};
+
+// parse a property; return null on invalid; return parsed property otherwise
+// fields :
+// - name : the name of the property
+// - value : the parsed, native-typed value of the property
+// - strValue : a string value that represents the property value in valid css
+// - bypass : true iff the property is a bypass property
+var parseImpl = function( name, value, propIsBypass, propIsFlat ){
+ var self = this;
+
+ name = util.camel2dash( name ); // make sure the property name is in dash form (e.g. 'property-name' not 'propertyName')
+
+ var property = self.properties[ name ];
+ var passedValue = value;
+ var types = self.types;
+
+ if( !property ){ return null; } // return null on property of unknown name
+ if( value === undefined || value === null ){ return null; } // can't assign null
+
+ // the property may be an alias
+ if( property.alias ){
+ property = property.pointsTo;
+ name = property.name;
+ }
+
+ var valueIsString = is.string(value);
+ if( valueIsString ){ // trim the value to make parsing easier
+ value = value.trim();
+ }
+
+ var type = property.type;
+ if( !type ){ return null; } // no type, no luck
+
+ // check if bypass is null or empty string (i.e. indication to delete bypass property)
+ if( propIsBypass && (value === '' || value === null) ){
+ return {
+ name: name,
+ value: value,
+ bypass: true,
+ deleteBypass: true
+ };
+ }
+
+ // check if value is a function used as a mapper
+ if( is.fn(value) ){
+ return {
+ name: name,
+ value: value,
+ strValue: 'fn',
+ mapped: types.fn,
+ bypass: propIsBypass
+ };
+ }
+
+ // check if value is mapped
+ var data, mapData, layoutData, mapLayoutData, scratch, mapScratch;
+ if( !valueIsString || propIsFlat ){
+ // then don't bother to do the expensive regex checks
+
+ } else if(
+ ( data = new RegExp( types.data.regex ).exec( value ) ) ||
+ ( layoutData = new RegExp( types.layoutData.regex ).exec( value ) ) ||
+ ( scratch = new RegExp( types.scratch.regex ).exec( value ) )
+ ){
+ if( propIsBypass ){ return false; } // mappers not allowed in bypass
+
+ var mapped;
+ if( data ){
+ mapped = types.data;
+ } else if( layoutData ){
+ mapped = types.layoutData;
+ } else {
+ mapped = types.scratch;
+ }
+
+ data = data || layoutData || scratch;
+
+ return {
+ name: name,
+ value: data,
+ strValue: '' + value,
+ mapped: mapped,
+ field: data[1],
+ bypass: propIsBypass
+ };
+
+ } else if(
+ ( mapData = new RegExp( types.mapData.regex ).exec( value ) ) ||
+ ( mapLayoutData = new RegExp( types.mapLayoutData.regex ).exec( value ) ) ||
+ ( mapScratch = new RegExp( types.mapScratch.regex ).exec( value ) )
+ ){
+ if( propIsBypass ){ return false; } // mappers not allowed in bypass
+ if( type.multiple ){ return false; } // impossible to map to num
+
+ var mapped;
+ if( mapData ){
+ mapped = types.mapData;
+ } else if( mapLayoutData ){
+ mapped = types.mapLayoutData;
+ } else {
+ mapped = types.mapScratch;
+ }
+
+ mapData = mapData || mapLayoutData || mapScratch;
+
+ // we can map only if the type is a colour or a number
+ if( !(type.color || type.number) ){ return false; }
+
+ var valueMin = this.parse( name, mapData[4] ); // parse to validate
+ if( !valueMin || valueMin.mapped ){ return false; } // can't be invalid or mapped
+
+ var valueMax = this.parse( name, mapData[5] ); // parse to validate
+ if( !valueMax || valueMax.mapped ){ return false; } // can't be invalid or mapped
+
+ // check if valueMin and valueMax are the same
+ if( valueMin.value === valueMax.value ){
+ return false; // can't make much of a mapper without a range
+
+ } else if( type.color ){
+ var c1 = valueMin.value;
+ var c2 = valueMax.value;
+
+ var same = c1[0] === c2[0] // red
+ && c1[1] === c2[1] // green
+ && c1[2] === c2[2] // blue
+ && ( // optional alpha
+ c1[3] === c2[3] // same alpha outright
+ || (
+ (c1[3] == null || c1[3] === 1) // full opacity for colour 1?
+ &&
+ (c2[3] == null || c2[3] === 1) // full opacity for colour 2?
+ )
+ )
+ ;
+
+ if( same ){ return false; } // can't make a mapper without a range
+ }
+
+ return {
+ name: name,
+ value: mapData,
+ strValue: '' + value,
+ mapped: mapped,
+ field: mapData[1],
+ fieldMin: parseFloat( mapData[2] ), // min & max are numeric
+ fieldMax: parseFloat( mapData[3] ),
+ valueMin: valueMin.value,
+ valueMax: valueMax.value,
+ bypass: propIsBypass
+ };
+ }
+
+ if( type.multiple && !propIsFlat ){
+ var vals;
+
+ if( valueIsString ){
+ vals = value.split(/\s+/);
+ } else if( is.array(value) ){
+ vals = value;
+ } else {
+ vals = [ value ];
+ }
+
+ if( type.evenMultiple && vals.length % 2 !== 0 ){ return null; }
+
+ var valArr = vals.map(function( v ){
+ var p = self.parse( name, v, propIsBypass, true );
+
+ if( p.pfValue != null ){
+ return p.pfValue;
+ } else {
+ return p.value;
+ }
+ });
+
+ return {
+ name: name,
+ value: valArr,
+ pfValue: valArr,
+ strValue: valArr.join(' '),
+ bypass: propIsBypass,
+ units: type.number && !type.unitless ? type.implicitUnits || 'px' : undefined
+ };
+ }
+
+ // several types also allow enums
+ var checkEnums = function(){
+ for( var i = 0; i < type.enums.length; i++ ){
+ var en = type.enums[i];
+
+ if( en === value ){
+ return {
+ name: name,
+ value: value,
+ strValue: '' + value,
+ bypass: propIsBypass
+ };
+ }
+ }
+
+ return null;
+ };
+
+ // check the type and return the appropriate object
+ if( type.number ){
+ var units;
+ var implicitUnits = 'px'; // not set => px
+
+ if( type.units ){ // use specified units if set
+ units = type.units;
+ }
+
+ if( type.implicitUnits ){
+ implicitUnits = type.implicitUnits;
+ }
+
+ if( !type.unitless ){
+ if( valueIsString ){
+ var unitsRegex = 'px|em' + (type.allowPercent ? '|\\%' : '');
+ if( units ){ unitsRegex = units; } // only allow explicit units if so set
+ var match = value.match( '^(' + util.regex.number + ')(' + unitsRegex + ')?' + '$' );
+
+ if( match ){
+ value = match[1];
+ units = match[2] || implicitUnits;
+ }
+
+ } else if( !units || type.implicitUnits ) {
+ units = implicitUnits; // implicitly px if unspecified
+ }
+ }
+
+ value = parseFloat( value );
+
+ // if not a number and enums not allowed, then the value is invalid
+ if( isNaN(value) && type.enums === undefined ){
+ return null;
+ }
+
+ // check if this number type also accepts special keywords in place of numbers
+ // (i.e. `left`, `auto`, etc)
+ if( isNaN(value) && type.enums !== undefined ){
+ value = passedValue;
+
+ return checkEnums();
+ }
+
+ // check if value must be an integer
+ if( type.integer && !is.integer(value) ){
+ return null;
+ }
+
+ // check value is within range
+ if( (type.min !== undefined && value < type.min)
+ || (type.max !== undefined && value > type.max)
+ ){
+ return null;
+ }
+
+ var ret = {
+ name: name,
+ value: value,
+ strValue: '' + value + (units ? units : ''),
+ units: units,
+ bypass: propIsBypass
+ };
+
+ // normalise value in pixels
+ if( type.unitless || (units !== 'px' && units !== 'em') ){
+ ret.pfValue = value;
+ } else {
+ ret.pfValue = ( units === 'px' || !units ? (value) : (this.getEmSizeInPixels() * value) );
+ }
+
+ // normalise value in ms
+ if( units === 'ms' || units === 's' ){
+ ret.pfValue = units === 'ms' ? value : 1000 * value;
+ }
+
+ // normalise value in rad
+ if( units === 'deg' || units === 'rad' ){
+ ret.pfValue = units === 'rad' ? value : value * Math.PI/180;
+ }
+
+ return ret;
+
+ } else if( type.propList ) {
+
+ var props = [];
+ var propsStr = '' + value;
+
+ if( propsStr === 'none' ){
+ // leave empty
+
+ } else { // go over each prop
+
+ var propsSplit = propsStr.split(',');
+ for( var i = 0; i < propsSplit.length; i++ ){
+ var propName = propsSplit[i].trim();
+
+ if( self.properties[propName] ){
+ props.push( propName );
+ }
+ }
+
+ if( props.length === 0 ){ return null; }
+ }
+
+ return {
+ name: name,
+ value: props,
+ strValue: props.length === 0 ? 'none' : props.join(', '),
+ bypass: propIsBypass
+ };
+
+ } else if( type.color ){
+ var tuple = util.color2tuple( value );
+
+ if( !tuple ){ return null; }
+
+ return {
+ name: name,
+ value: tuple,
+ strValue: '' + value,
+ bypass: propIsBypass,
+ roundValue: true
+ };
+
+ } else if( type.regex || type.regexes ){
+
+ // first check enums
+ if( type.enums ){
+ var enumProp = checkEnums();
+
+ if( enumProp ){ return enumProp; }
+ }
+
+ var regexes = type.regexes ? type.regexes : [ type.regex ];
+
+ for( var i = 0; i < regexes.length; i++ ){
+ var regex = new RegExp( regexes[i] ); // make a regex from the type string
+ var m = regex.exec( value );
+
+ if( m ){ // regex matches
+ return {
+ name: name,
+ value: m,
+ strValue: '' + value,
+ bypass: propIsBypass
+ };
+
+ }
+ }
+
+ return null; // didn't match any
+
+ } else if( type.string ){
+ // just return
+ return {
+ name: name,
+ value: value,
+ strValue: '' + value,
+ bypass: propIsBypass
+ };
+
+ } else if( type.enums ){ // check enums last because it's a combo type in others
+ return checkEnums();
+
+ } else {
+ return null; // not a type we can handle
+ }
+
+};
+
+module.exports = styfn;
+
+},{"../is":77,"../util":94}],89:[function(_dereq_,module,exports){
+'use strict';
+
+var util = _dereq_('../util');
+
+var styfn = {};
+
+(function(){
+ var number = util.regex.number;
+ var rgba = util.regex.rgbaNoBackRefs;
+ var hsla = util.regex.hslaNoBackRefs;
+ var hex3 = util.regex.hex3;
+ var hex6 = util.regex.hex6;
+ var data = function( prefix ){ return '^' + prefix + '\\s*\\(\\s*([\\w\\.]+)\\s*\\)$'; };
+ var mapData = function( prefix ){
+ var mapArg = number + '|\\w+|' + rgba + '|' + hsla + '|' + hex3 + '|' + hex6;
+ return '^' + prefix + '\\s*\\(([\\w\\.]+)\\s*\\,\\s*(' + number + ')\\s*\\,\\s*(' + number + ')\\s*,\\s*(' + mapArg + ')\\s*\\,\\s*(' + mapArg + ')\\)$';
+ };
+
+ // each visual style property has a type and needs to be validated according to it
+ styfn.types = {
+ time: { number: true, min: 0, units: 's|ms', implicitUnits: 'ms' },
+ percent: { number: true, min: 0, max: 100, units: '%', implicitUnits: '%' },
+ zeroOneNumber: { number: true, min: 0, max: 1, unitless: true },
+ nOneOneNumber: { number: true, min: -1, max: 1, unitless: true },
+ nonNegativeInt: { number: true, min: 0, integer: true, unitless: true },
+ position: { enums: ['parent', 'origin'] },
+ nodeSize: { number: true, min: 0, enums: ['auto', 'label'] },
+ number: { number: true, unitless: true },
+ numbers: { number: true, unitless: true, multiple: true },
+ size: { number: true, min: 0 },
+ bidirectionalSize: { number: true }, // allows negative
+ bidirectionalSizes: { number: true, multiple: true }, // allows negative
+ bgSize: { number: true, min: 0, allowPercent: true },
+ bgWH: { number: true, min: 0, allowPercent: true, enums: ['auto'] },
+ bgPos: { number: true, allowPercent: true },
+ bgRepeat: { enums: ['repeat', 'repeat-x', 'repeat-y', 'no-repeat'] },
+ bgFit: { enums: ['none', 'contain', 'cover'] },
+ bgClip: { enums: ['none', 'node'] },
+ color: { color: true },
+ bool: { enums: ['yes', 'no'] },
+ lineStyle: { enums: ['solid', 'dotted', 'dashed'] },
+ borderStyle: { enums: ['solid', 'dotted', 'dashed', 'double'] },
+ curveStyle: { enums: ['bezier', 'unbundled-bezier', 'haystack', 'segments'] },
+ fontFamily: { regex: '^([\\w- \\"]+(?:\\s*,\\s*[\\w- \\"]+)*)$' },
+ fontVariant: { enums: ['small-caps', 'normal'] },
+ fontStyle: { enums: ['italic', 'normal', 'oblique'] },
+ fontWeight: { enums: ['normal', 'bold', 'bolder', 'lighter', '100', '200', '300', '400', '500', '600', '800', '900', 100, 200, 300, 400, 500, 600, 700, 800, 900] },
+ textDecoration: { enums: ['none', 'underline', 'overline', 'line-through'] },
+ textTransform: { enums: ['none', 'uppercase', 'lowercase'] },
+ textWrap: { enums: ['none', 'wrap'] },
+ textBackgroundShape: { enums: ['rectangle', 'roundrectangle']},
+ nodeShape: { enums: ['rectangle', 'roundrectangle', 'ellipse', 'triangle', 'square', 'pentagon', 'hexagon', 'heptagon', 'octagon', 'star', 'diamond', 'vee', 'rhomboid', 'polygon'] },
+ compoundIncludeLabels: { enums: ['include', 'exclude'] },
+ arrowShape: { enums: ['tee', 'triangle', 'triangle-tee', 'triangle-backcurve', 'half-triangle-overshot', 'vee', 'square', 'circle', 'diamond', 'none'] },
+ arrowFill: { enums: ['filled', 'hollow'] },
+ display: { enums: ['element', 'none'] },
+ visibility: { enums: ['hidden', 'visible'] },
+ valign: { enums: ['top', 'center', 'bottom'] },
+ halign: { enums: ['left', 'center', 'right'] },
+ text: { string: true },
+ data: { mapping: true, regex: data('data') },
+ layoutData: { mapping: true, regex: data('layoutData') },
+ scratch: { mapping: true, regex: data('scratch') },
+ mapData: { mapping: true, regex: mapData('mapData') },
+ mapLayoutData: { mapping: true, regex: mapData('mapLayoutData') },
+ mapScratch: { mapping: true, regex: mapData('mapScratch') },
+ fn: { mapping: true, fn: true },
+ url: { regex: '^url\\s*\\(\\s*([^\\s]+)\\s*\\s*\\)|none|(.+)$' },
+ propList: { propList: true },
+ angle: { number: true, units: 'deg|rad', implicitUnits: 'rad' },
+ textRotation: { enums: ['none', 'autorotate'] },
+ polygonPointList: { number: true, multiple: true, evenMultiple: true, min: -1, max: 1, unitless: true },
+ easing: {
+ regexes: [
+ '^(spring)\\s*\\(\\s*(' + number + ')\\s*,\\s*(' + number + ')\\s*\\)$',
+ '^(cubic-bezier)\\s*\\(\\s*(' + number + ')\\s*,\\s*(' + number + ')\\s*,\\s*(' + number + ')\\s*,\\s*(' + number + ')\\s*\\)$'
+ ],
+ enums: [
+ 'linear',
+ 'ease', 'ease-in', 'ease-out', 'ease-in-out',
+ 'ease-in-sine', 'ease-out-sine', 'ease-in-out-sine',
+ 'ease-in-quad', 'ease-out-quad', 'ease-in-out-quad',
+ 'ease-in-cubic', 'ease-out-cubic', 'ease-in-out-cubic',
+ 'ease-in-quart', 'ease-out-quart', 'ease-in-out-quart',
+ 'ease-in-quint', 'ease-out-quint', 'ease-in-out-quint',
+ 'ease-in-expo', 'ease-out-expo', 'ease-in-out-expo',
+ 'ease-in-circ', 'ease-out-circ', 'ease-in-out-circ'
+ ]
+ }
+ };
+
+ // define visual style properties
+ var t = styfn.types;
+ var props = styfn.properties = [
+ // labels
+ { name: 'text-valign', type: t.valign },
+ { name: 'text-halign', type: t.halign },
+ { name: 'color', type: t.color },
+ { name: 'label', type: t.text },
+ { name: 'text-outline-color', type: t.color },
+ { name: 'text-outline-width', type: t.size },
+ { name: 'text-outline-opacity', type: t.zeroOneNumber },
+ { name: 'text-opacity', type: t.zeroOneNumber },
+ { name: 'text-background-color', type: t.color },
+ { name: 'text-background-opacity', type: t.zeroOneNumber },
+ { name: 'text-border-opacity', type: t.zeroOneNumber },
+ { name: 'text-border-color', type: t.color },
+ { name: 'text-border-width', type: t.size },
+ { name: 'text-border-style', type: t.borderStyle },
+ { name: 'text-background-shape', type: t.textBackgroundShape},
+ // { name: 'text-decoration', type: t.textDecoration }, // not supported in canvas
+ { name: 'text-transform', type: t.textTransform },
+ { name: 'text-wrap', type: t.textWrap },
+ { name: 'text-max-width', type: t.size },
+ { name: 'text-events', type: t.bool },
+
+ // { name: 'text-rotation', type: t.angle }, // TODO disabled b/c rotation breaks bounding boxes
+ { name: 'font-family', type: t.fontFamily },
+ { name: 'font-style', type: t.fontStyle },
+ // { name: 'font-variant', type: t.fontVariant }, // not useful
+ { name: 'font-weight', type: t.fontWeight },
+ { name: 'font-size', type: t.size },
+ { name: 'min-zoomed-font-size', type: t.size },
+ { name: 'edge-text-rotation', type: t.textRotation },
+
+ // behaviour
+ { name: 'events', type: t.bool },
+
+ // visibility
+ { name: 'display', type: t.display },
+ { name: 'visibility', type: t.visibility },
+ { name: 'opacity', type: t.zeroOneNumber },
+ { name: 'z-index', type: t.nonNegativeInt },
+
+ // overlays
+ { name: 'overlay-padding', type: t.size },
+ { name: 'overlay-color', type: t.color },
+ { name: 'overlay-opacity', type: t.zeroOneNumber },
+
+ // shadows
+ { name: 'shadow-blur', type: t.size },
+ { name: 'shadow-color', type: t.color },
+ { name: 'shadow-opacity', type: t.zeroOneNumber },
+ { name: 'shadow-offset-x', type: t.bidirectionalSize },
+ { name: 'shadow-offset-y', type: t.bidirectionalSize },
+
+ // label shadows
+ { name: 'text-shadow-blur', type: t.size },
+ { name: 'text-shadow-color', type: t.color },
+ { name: 'text-shadow-opacity', type: t.zeroOneNumber },
+ { name: 'text-shadow-offset-x', type: t.bidirectionalSize },
+ { name: 'text-shadow-offset-y', type: t.bidirectionalSize },
+
+ // transition anis
+ { name: 'transition-property', type: t.propList },
+ { name: 'transition-duration', type: t.time },
+ { name: 'transition-delay', type: t.time },
+ { name: 'transition-timing-function', type: t.easing },
+
+ // node body
+ { name: 'height', type: t.nodeSize },
+ { name: 'width', type: t.nodeSize },
+ { name: 'shape', type: t.nodeShape },
+ { name: 'shape-polygon-points', type: t.polygonPointList },
+ { name: 'background-color', type: t.color },
+ { name: 'background-opacity', type: t.zeroOneNumber },
+ { name: 'background-blacken', type: t.nOneOneNumber },
+ { name: 'padding-left', type: t.size },
+ { name: 'padding-right', type: t.size },
+ { name: 'padding-top', type: t.size },
+ { name: 'padding-bottom', type: t.size },
+
+ // node border
+ { name: 'border-color', type: t.color },
+ { name: 'border-opacity', type: t.zeroOneNumber },
+ { name: 'border-width', type: t.size },
+ { name: 'border-style', type: t.borderStyle },
+
+ // node background images
+ { name: 'background-image', type: t.url },
+ { name: 'background-image-opacity', type: t.zeroOneNumber },
+ { name: 'background-position-x', type: t.bgPos },
+ { name: 'background-position-y', type: t.bgPos },
+ { name: 'background-repeat', type: t.bgRepeat },
+ { name: 'background-fit', type: t.bgFit },
+ { name: 'background-clip', type: t.bgClip },
+ { name: 'background-width', type: t.bgWH },
+ { name: 'background-height', type: t.bgWH },
+
+ // compound props
+ { name: 'position', type: t.position },
+ { name: 'compound-sizing-wrt-labels', type: t.compoundIncludeLabels },
+
+ // edge line
+ { name: 'line-style', type: t.lineStyle },
+ { name: 'line-color', type: t.color },
+ { name: 'curve-style', type: t.curveStyle },
+ { name: 'haystack-radius', type: t.zeroOneNumber },
+ { name: 'control-point-step-size', type: t.size },
+ { name: 'control-point-distances', type: t.bidirectionalSizes },
+ { name: 'control-point-weights', type: t.numbers },
+ { name: 'segment-distances', type: t.bidirectionalSizes },
+ { name: 'segment-weights', type: t.numbers },
+
+ // these are just for the core
+ { name: 'selection-box-color', type: t.color },
+ { name: 'selection-box-opacity', type: t.zeroOneNumber },
+ { name: 'selection-box-border-color', type: t.color },
+ { name: 'selection-box-border-width', type: t.size },
+ { name: 'active-bg-color', type: t.color },
+ { name: 'active-bg-opacity', type: t.zeroOneNumber },
+ { name: 'active-bg-size', type: t.size },
+ { name: 'outside-texture-bg-color', type: t.color },
+ { name: 'outside-texture-bg-opacity', type: t.zeroOneNumber }
+ ];
+
+ // define aliases
+ var aliases = styfn.aliases = [
+ { name: 'content', pointsTo: 'label' },
+ { name: 'control-point-distance', pointsTo: 'control-point-distances' },
+ { name: 'control-point-weight', pointsTo: 'control-point-weights' }
+ ];
+
+ // pie backgrounds for nodes
+ styfn.pieBackgroundN = 16; // because the pie properties are numbered, give access to a constant N (for renderer use)
+ props.push({ name: 'pie-size', type: t.bgSize });
+ for( var i = 1; i <= styfn.pieBackgroundN; i++ ){
+ props.push({ name: 'pie-'+i+'-background-color', type: t.color });
+ props.push({ name: 'pie-'+i+'-background-size', type: t.percent });
+ props.push({ name: 'pie-'+i+'-background-opacity', type: t.zeroOneNumber });
+ }
+
+ // edge arrows
+ var arrowPrefixes = styfn.arrowPrefixes = ['source', 'mid-source', 'target', 'mid-target'];
+ [
+ { name: 'arrow-shape', type: t.arrowShape },
+ { name: 'arrow-color', type: t.color },
+ { name: 'arrow-fill', type: t.arrowFill }
+ ].forEach(function( prop ){
+ arrowPrefixes.forEach(function( prefix ){
+ var name = prefix + '-' + prop.name;
+ var type = prop.type;
+
+ props.push({ name: name, type: type });
+ });
+ }, {});
+
+ // list of property names
+ styfn.propertyNames = props.map(function(p){ return p.name; });
+
+ // allow access of properties by name ( e.g. style.properties.height )
+ for( var i = 0; i < props.length; i++ ){
+ var prop = props[i];
+
+ props[ prop.name ] = prop; // allow lookup by name
+ }
+
+ // map aliases
+ for( var i = 0; i < aliases.length; i++ ){
+ var alias = aliases[i];
+ var pointsToProp = props[ alias.pointsTo ];
+ var aliasProp = {
+ name: alias.name,
+ alias: true,
+ pointsTo: pointsToProp
+ };
+
+ // add alias prop for parsing
+ props.push( aliasProp );
+
+ props[ alias.name ] = aliasProp; // allow lookup by name
+ }
+})();
+
+// adds the default stylesheet to the current style
+styfn.addDefaultStylesheet = function(){
+ // fill the style with the default stylesheet
+ this
+ .selector('node, edge') // common properties
+ .css( util.extend( {
+ 'events': 'yes',
+ 'text-events': 'no',
+ 'text-valign': 'top',
+ 'text-halign': 'center',
+ 'color': '#000',
+ 'text-outline-color': '#000',
+ 'text-outline-width': 0,
+ 'text-outline-opacity': 1,
+ 'text-opacity': 1,
+ 'text-decoration': 'none',
+ 'text-transform': 'none',
+ 'text-wrap': 'none',
+ 'text-max-width': 9999,
+ 'text-background-color': '#000',
+ 'text-background-opacity': 0,
+ 'text-border-opacity': 0,
+ 'text-border-width': 0,
+ 'text-border-style': 'solid',
+ 'text-border-color':'#000',
+ 'text-background-shape':'rectangle',
+ 'font-family': 'Helvetica Neue, Helvetica, sans-serif',
+ 'font-style': 'normal',
+ // 'font-variant': fontVariant,
+ 'font-weight': 'normal',
+ 'font-size': 16,
+ 'min-zoomed-font-size': 0,
+ 'edge-text-rotation': 'none',
+ 'visibility': 'visible',
+ 'display': 'element',
+ 'opacity': 1,
+ 'z-index': 0,
+ 'label': '',
+ 'overlay-opacity': 0,
+ 'overlay-color': '#000',
+ 'overlay-padding': 10,
+ 'shadow-opacity': 0,
+ 'shadow-color': '#000',
+ 'shadow-blur': 10,
+ 'shadow-offset-x': 0,
+ 'shadow-offset-y': 0,
+ 'text-shadow-opacity': 0,
+ 'text-shadow-color': '#000',
+ 'text-shadow-blur': 5,
+ 'text-shadow-offset-x': 0,
+ 'text-shadow-offset-y': 0,
+ 'transition-property': 'none',
+ 'transition-duration': 0,
+ 'transition-delay': 0,
+ 'transition-timing-function': 'linear',
+
+ // node props
+ 'background-blacken': 0,
+ 'background-color': '#888',
+ 'background-opacity': 1,
+ 'background-image': 'none',
+ 'background-image-opacity': 1,
+ 'background-position-x': '50%',
+ 'background-position-y': '50%',
+ 'background-repeat': 'no-repeat',
+ 'background-fit': 'none',
+ 'background-clip': 'node',
+ 'background-width': 'auto',
+ 'background-height': 'auto',
+ 'border-color': '#000',
+ 'border-opacity': 1,
+ 'border-width': 0,
+ 'border-style': 'solid',
+ 'height': 30,
+ 'width': 30,
+ 'shape': 'ellipse',
+ 'shape-polygon-points': '-1, -1, 1, -1, 1, 1, -1, 1',
+
+ // compound props
+ 'padding-top': 0,
+ 'padding-bottom': 0,
+ 'padding-left': 0,
+ 'padding-right': 0,
+ 'position': 'origin',
+ 'compound-sizing-wrt-labels': 'include',
+ }, {
+ // node pie bg
+ 'pie-size': '100%'
+ }, [
+ { name: 'pie-{{i}}-background-color', value: 'black' },
+ { name: 'pie-{{i}}-background-size', value: '0%' },
+ { name: 'pie-{{i}}-background-opacity', value: 1 }
+ ].reduce(function( css, prop ){
+ for( var i = 1; i <= styfn.pieBackgroundN; i++ ){
+ var name = prop.name.replace('{{i}}', i);
+ var val = prop.value;
+
+ css[ name ] = val;
+ }
+
+ return css;
+ }, {}), {
+ // edge props
+ 'line-style': 'solid',
+ 'line-color': '#ddd',
+ 'control-point-step-size': 40,
+ 'control-point-weights': 0.5,
+ 'segment-weights': 0.25,
+ 'segment-distances': 20,
+ 'curve-style': 'bezier',
+ 'haystack-radius': 0.8
+ }, [
+ { name: 'arrow-shape', value: 'none' },
+ { name: 'arrow-color', value: '#ddd' },
+ { name: 'arrow-fill', value: 'filled' }
+ ].reduce(function( css, prop ){
+ styfn.arrowPrefixes.forEach(function( prefix ){
+ var name = prefix + '-' + prop.name;
+ var val = prop.value;
+
+ css[ name ] = val;
+ });
+
+ return css;
+ }, {}) ) )
+ .selector('$node > node') // compound (parent) node properties
+ .css({
+ 'width': 'auto',
+ 'height': 'auto',
+ 'shape': 'rectangle',
+ 'padding-top': 10,
+ 'padding-right': 10,
+ 'padding-left': 10,
+ 'padding-bottom': 10
+ })
+ .selector('edge') // just edge properties
+ .css({
+ 'width': 1
+ })
+ .selector(':active')
+ .css({
+ 'overlay-color': 'black',
+ 'overlay-padding': 10,
+ 'overlay-opacity': 0.25
+ })
+ .selector('core') // just core properties
+ .css({
+ 'selection-box-color': '#ddd',
+ 'selection-box-opacity': 0.65,
+ 'selection-box-border-color': '#aaa',
+ 'selection-box-border-width': 1,
+ 'active-bg-color': 'black',
+ 'active-bg-opacity': 0.15,
+ 'active-bg-size': 30,
+ 'outside-texture-bg-color': '#000',
+ 'outside-texture-bg-opacity': 0.125
+ })
+ ;
+
+ this.defaultLength = this.length;
+};
+
+module.exports = styfn;
+
+},{"../util":94}],90:[function(_dereq_,module,exports){
+'use strict';
+
+var util = _dereq_('../util');
+var Selector = _dereq_('../selector');
+
+var styfn = {};
+
+styfn.applyFromString = function( string ){
+ var self = this;
+ var style = this;
+ var remaining = '' + string;
+ var selAndBlockStr;
+ var blockRem;
+ var propAndValStr;
+
+ // remove comments from the style string
+ remaining = remaining.replace(/[/][*](\s|.)+?[*][/]/g, '');
+
+ function removeSelAndBlockFromRemaining(){
+ // remove the parsed selector and block from the remaining text to parse
+ if( remaining.length > selAndBlockStr.length ){
+ remaining = remaining.substr( selAndBlockStr.length );
+ } else {
+ remaining = '';
+ }
+ }
+
+ function removePropAndValFromRem(){
+ // remove the parsed property and value from the remaining block text to parse
+ if( blockRem.length > propAndValStr.length ){
+ blockRem = blockRem.substr( propAndValStr.length );
+ } else {
+ blockRem = '';
+ }
+ }
+
+ while(true){
+ var nothingLeftToParse = remaining.match(/^\s*$/);
+ if( nothingLeftToParse ){ break; }
+
+ var selAndBlock = remaining.match(/^\s*((?:.|\s)+?)\s*\{((?:.|\s)+?)\}/);
+
+ if( !selAndBlock ){
+ util.error('Halting stylesheet parsing: String stylesheet contains more to parse but no selector and block found in: ' + remaining);
+ break;
+ }
+
+ selAndBlockStr = selAndBlock[0];
+
+ // parse the selector
+ var selectorStr = selAndBlock[1];
+ if( selectorStr !== 'core' ){
+ var selector = new Selector( selectorStr );
+ if( selector._private.invalid ){
+ util.error('Skipping parsing of block: Invalid selector found in string stylesheet: ' + selectorStr);
+
+ // skip this selector and block
+ removeSelAndBlockFromRemaining();
+ continue;
+ }
+ }
+
+ // parse the block of properties and values
+ var blockStr = selAndBlock[2];
+ var invalidBlock = false;
+ blockRem = blockStr;
+ var props = [];
+
+ while(true){
+ var nothingLeftToParse = blockRem.match(/^\s*$/);
+ if( nothingLeftToParse ){ break; }
+
+ var propAndVal = blockRem.match(/^\s*(.+?)\s*:\s*(.+?)\s*;/);
+
+ if( !propAndVal ){
+ util.error('Skipping parsing of block: Invalid formatting of style property and value definitions found in:' + blockStr);
+ invalidBlock = true;
+ break;
+ }
+
+ propAndValStr = propAndVal[0];
+ var propStr = propAndVal[1];
+ var valStr = propAndVal[2];
+
+ var prop = self.properties[ propStr ];
+ if( !prop ){
+ util.error('Skipping property: Invalid property name in: ' + propAndValStr);
+
+ // skip this property in the block
+ removePropAndValFromRem();
+ continue;
+ }
+
+ var parsedProp = style.parse( propStr, valStr );
+
+ if( !parsedProp ){
+ util.error('Skipping property: Invalid property definition in: ' + propAndValStr);
+
+ // skip this property in the block
+ removePropAndValFromRem();
+ continue;
+ }
+
+ props.push({
+ name: propStr,
+ val: valStr
+ });
+ removePropAndValFromRem();
+ }
+
+ if( invalidBlock ){
+ removeSelAndBlockFromRemaining();
+ break;
+ }
+
+ // put the parsed block in the style
+ style.selector( selectorStr );
+ for( var i = 0; i < props.length; i++ ){
+ var prop = props[i];
+ style.css( prop.name, prop.val );
+ }
+
+ removeSelAndBlockFromRemaining();
+ }
+
+ return style;
+};
+
+styfn.fromString = function( string ){
+ var style = this;
+
+ style.resetToDefault();
+ style.applyFromString( string );
+
+ return style;
+};
+
+module.exports = styfn;
+
+},{"../selector":81,"../util":94}],91:[function(_dereq_,module,exports){
+'use strict';
+
+var is = _dereq_('./is');
+var util = _dereq_('./util');
+var Style = _dereq_('./style');
+
+// a dummy stylesheet object that doesn't need a reference to the core
+// (useful for init)
+var Stylesheet = function(){
+ if( !(this instanceof Stylesheet) ){
+ return new Stylesheet();
+ }
+
+ this.length = 0;
+};
+
+var sheetfn = Stylesheet.prototype;
+
+sheetfn.instanceString = function(){
+ return 'stylesheet';
+};
+
+// just store the selector to be parsed later
+sheetfn.selector = function( selector ){
+ var i = this.length++;
+
+ this[i] = {
+ selector: selector,
+ properties: []
+ };
+
+ return this; // chaining
+};
+
+// just store the property to be parsed later
+sheetfn.css = function( name, value ){
+ var i = this.length - 1;
+
+ if( is.string(name) ){
+ this[i].properties.push({
+ name: name,
+ value: value
+ });
+ } else if( is.plainObject(name) ){
+ var map = name;
+
+ for( var j = 0; j < Style.properties.length; j++ ){
+ var prop = Style.properties[j];
+ var mapVal = map[ prop.name ];
+
+ if( mapVal === undefined ){ // also try camel case name
+ mapVal = map[ util.dash2camel(prop.name) ];
+ }
+
+ if( mapVal !== undefined ){
+ var name = prop.name;
+ var value = mapVal;
+
+ this[i].properties.push({
+ name: name,
+ value: value
+ });
+ }
+ }
+ }
+
+ return this; // chaining
+};
+
+sheetfn.style = sheetfn.css;
+
+// generate a real style object from the dummy stylesheet
+sheetfn.generateStyle = function( cy ){
+ var style = new Style(cy);
+
+ for( var i = 0; i < this.length; i++ ){
+ var context = this[i];
+ var selector = context.selector;
+ var props = context.properties;
+
+ style.selector(selector); // apply selector
+
+ for( var j = 0; j < props.length; j++ ){
+ var prop = props[j];
+
+ style.css( prop.name, prop.value ); // apply property
+ }
+ }
+
+ return style;
+};
+
+module.exports = Stylesheet;
+
+},{"./is":77,"./style":86,"./util":94}],92:[function(_dereq_,module,exports){
+// cross-env thread/worker
+// NB : uses (heavyweight) processes on nodejs so best not to create too many threads
+
+'use strict';
+
+var window = _dereq_('./window');
+var util = _dereq_('./util');
+var Promise = _dereq_('./promise');
+var Event = _dereq_('./event');
+var define = _dereq_('./define');
+var is = _dereq_('./is');
+
+var Thread = function( opts ){
+ if( !(this instanceof Thread) ){
+ return new Thread( opts );
+ }
+
+ var _p = this._private = {
+ requires: [],
+ files: [],
+ queue: null,
+ pass: [],
+ disabled: false
+ };
+
+ if( is.plainObject(opts) ){
+ if( opts.disabled != null ){
+ _p.disabled = !!opts.disabled;
+ }
+ }
+
+};
+
+var thdfn = Thread.prototype; // short alias
+
+var stringifyFieldVal = function( val ){
+ var valStr = is.fn( val ) ? val.toString() : 'JSON.parse("' + JSON.stringify(val) + '")';
+
+ return valStr;
+};
+
+// allows for requires with prototypes and subobjs etc
+var fnAsRequire = function( fn ){
+ var req;
+ var fnName;
+
+ if( is.object(fn) && fn.fn ){ // manual fn
+ req = fnAs( fn.fn, fn.name );
+ fnName = fn.name;
+ fn = fn.fn;
+ } else if( is.fn(fn) ){ // auto fn
+ req = fn.toString();
+ fnName = fn.name;
+ } else if( is.string(fn) ){ // stringified fn
+ req = fn;
+ } else if( is.object(fn) ){ // plain object
+ if( fn.proto ){
+ req = '';
+ } else {
+ req = fn.name + ' = {};';
+ }
+
+ fnName = fn.name;
+ fn = fn.obj;
+ }
+
+ req += '\n';
+
+ var protoreq = function( val, subname ){
+ if( val.prototype ){
+ var protoNonempty = false;
+ for( var prop in val.prototype ){ protoNonempty = true; break; } // jshint ignore:line
+
+ if( protoNonempty ){
+ req += fnAsRequire( {
+ name: subname,
+ obj: val,
+ proto: true
+ }, val );
+ }
+ }
+ };
+
+ // pull in prototype
+ if( fn.prototype && fnName != null ){
+
+ for( var name in fn.prototype ){
+ var protoStr = '';
+
+ var val = fn.prototype[ name ];
+ var valStr = stringifyFieldVal( val );
+ var subname = fnName + '.prototype.' + name;
+
+ protoStr += subname + ' = ' + valStr + ';\n';
+
+ if( protoStr ){
+ req += protoStr;
+ }
+
+ protoreq( val, subname ); // subobject with prototype
+ }
+
+ }
+
+ // pull in properties for obj/fns
+ if( !is.string(fn) ){ for( var name in fn ){
+ var propsStr = '';
+
+ if( fn.hasOwnProperty(name) ){
+ var val = fn[ name ];
+ var valStr = stringifyFieldVal( val );
+ var subname = fnName + '["' + name + '"]';
+
+ propsStr += subname + ' = ' + valStr + ';\n';
+ }
+
+ if( propsStr ){
+ req += propsStr;
+ }
+
+ protoreq( val, subname ); // subobject with prototype
+ } }
+
+ return req;
+};
+
+var isPathStr = function( str ){
+ return is.string(str) && str.match(/\.js$/);
+};
+
+util.extend(thdfn, {
+
+ instanceString: function(){ return 'thread'; },
+
+ require: function( fn, as ){
+ var requires = this._private.requires;
+
+ if( isPathStr(fn) ){
+ this._private.files.push( fn );
+
+ return this;
+ }
+
+ if( as ){
+ if( is.fn(fn) ){
+ fn = { name: as, fn: fn };
+ } else {
+ fn = { name: as, obj: fn };
+ }
+ } else {
+ if( is.fn(fn) ){
+ if( !fn.name ){
+ throw 'The function name could not be automatically determined. Use thread.require( someFunction, "someFunction" )';
+ }
+
+ fn = { name: fn.name, fn: fn };
+ }
+ }
+
+ requires.push( fn );
+
+ return this; // chaining
+ },
+
+ pass: function( data ){
+ this._private.pass.push( data );
+
+ return this; // chaining
+ },
+
+ run: function( fn, pass ){ // fn used like main()
+ var self = this;
+ var _p = this._private;
+ pass = pass || _p.pass.shift();
+
+ if( _p.stopped ){
+ throw 'Attempted to run a stopped thread! Start a new thread or do not stop the existing thread and reuse it.';
+ }
+
+ if( _p.running ){
+ return ( _p.queue = _p.queue.then(function(){ // inductive step
+ return self.run( fn, pass );
+ }) );
+ }
+
+ var useWW = window != null && !_p.disabled;
+ var useNode = !window && typeof module !== 'undefined' && !_p.disabled;
+
+ self.trigger('run');
+
+ var runP = new Promise(function( resolve, reject ){
+
+ _p.running = true;
+
+ var threadTechAlreadyExists = _p.ran;
+
+ var fnImplStr = is.string( fn ) ? fn : fn.toString();
+
+ // worker code to exec
+ var fnStr = '\n' + ( _p.requires.map(function( r ){
+ return fnAsRequire( r );
+ }) ).concat( _p.files.map(function( f ){
+ if( useWW ){
+ var wwifyFile = function( file ){
+ if( file.match(/^\.\//) || file.match(/^\.\./) ){
+ return window.location.origin + window.location.pathname + file;
+ } else if( file.match(/^\//) ){
+ return window.location.origin + '/' + file;
+ }
+ return file;
+ };
+
+ return 'importScripts("' + wwifyFile(f) + '");';
+ } else if( useNode ) {
+ return 'eval( require("fs").readFileSync("' + f + '", { encoding: "utf8" }) );';
+ } else {
+ throw 'External file `' + f + '` can not be required without any threading technology.';
+ }
+ }) ).concat([
+ '( function(){',
+ 'var ret = (' + fnImplStr + ')(' + JSON.stringify(pass) + ');',
+ 'if( ret !== undefined ){ resolve(ret); }', // assume if ran fn returns defined value (incl. null), that we want to resolve to it
+ '} )()\n'
+ ]).join('\n');
+
+ // because we've now consumed the requires, empty the list so we don't dupe on next run()
+ _p.requires = [];
+ _p.files = [];
+
+ if( useWW ){
+ var fnBlob, fnUrl;
+
+ // add normalised thread api functions
+ if( !threadTechAlreadyExists ){
+ var fnPre = fnStr + '';
+
+ fnStr = [
+ 'function _ref_(o){ return eval(o); };',
+ 'function broadcast(m){ return message(m); };', // alias
+ 'function message(m){ postMessage(m); };',
+ 'function listen(fn){',
+ ' self.addEventListener("message", function(m){ ',
+ ' if( typeof m === "object" && (m.data.$$eval || m.data === "$$start") ){',
+ ' } else { ',
+ ' fn( m.data );',
+ ' }',
+ ' });',
+ '};',
+ 'self.addEventListener("message", function(m){ if( m.data.$$eval ){ eval( m.data.$$eval ); } });',
+ 'function resolve(v){ postMessage({ $$resolve: v }); };',
+ 'function reject(v){ postMessage({ $$reject: v }); };'
+ ].join('\n');
+
+ fnStr += fnPre;
+
+ fnBlob = new Blob([ fnStr ], {
+ type: 'application/javascript'
+ });
+ fnUrl = window.URL.createObjectURL( fnBlob );
+ }
+ // create webworker and let it exec the serialised code
+ var ww = _p.webworker = _p.webworker || new Worker( fnUrl );
+
+ if( threadTechAlreadyExists ){ // then just exec new run() code
+ ww.postMessage({
+ $$eval: fnStr
+ });
+ }
+
+ // worker messages => events
+ var cb;
+ ww.addEventListener('message', cb = function( m ){
+ var isObject = is.object(m) && is.object( m.data );
+
+ if( isObject && ('$$resolve' in m.data) ){
+ ww.removeEventListener('message', cb); // done listening b/c resolve()
+
+ resolve( m.data.$$resolve );
+ } else if( isObject && ('$$reject' in m.data) ){
+ ww.removeEventListener('message', cb); // done listening b/c reject()
+
+ reject( m.data.$$reject );
+ } else {
+ self.trigger( new Event(m, { type: 'message', message: m.data }) );
+ }
+ }, false);
+
+ if( !threadTechAlreadyExists ){
+ ww.postMessage('$$start'); // start up the worker
+ }
+
+ } else if( useNode ){
+ // create a new process
+
+ if( !_p.child ){
+ _p.child = ( _dereq_('child_process').fork( _dereq_('path').join(__dirname, 'thread-node-fork') ) );
+ }
+
+ var child = _p.child;
+
+ // child process messages => events
+ var cb;
+ child.on('message', cb = function( m ){
+ if( is.object(m) && ('$$resolve' in m) ){
+ child.removeListener('message', cb); // done listening b/c resolve()
+
+ resolve( m.$$resolve );
+ } else if( is.object(m) && ('$$reject' in m) ){
+ child.removeListener('message', cb); // done listening b/c reject()
+
+ reject( m.$$reject );
+ } else {
+ self.trigger( new Event({}, { type: 'message', message: m }) );
+ }
+ });
+
+ // ask the child process to eval the worker code
+ child.send({
+ $$eval: fnStr
+ });
+
+ } else { // use a fallback mechanism using a timeout
+
+ var promiseResolve = resolve;
+ var promiseReject = reject;
+
+ var timer = _p.timer = _p.timer || {
+
+ listeners: [],
+
+ exec: function(){
+ // as a string so it can't be mangled by minifiers and processors
+ fnStr = [
+ 'function _ref_(o){ return eval(o); };',
+ 'function broadcast(m){ return message(m); };',
+ 'function message(m){ self.trigger( new Event({}, { type: "message", message: m }) ); };',
+ 'function listen(fn){ timer.listeners.push( fn ); };',
+ 'function resolve(v){ promiseResolve(v); };',
+ 'function reject(v){ promiseReject(v); };'
+ ].join('\n') + fnStr;
+
+ // the .run() code
+ eval( fnStr ); // jshint ignore:line
+ },
+
+ message: function( m ){
+ var ls = timer.listeners;
+
+ for( var i = 0; i < ls.length; i++ ){
+ var fn = ls[i];
+
+ fn( m );
+ }
+ }
+
+ };
+
+ timer.exec();
+ }
+
+ }).then(function( v ){
+ _p.running = false;
+ _p.ran = true;
+
+ self.trigger('ran');
+
+ return v;
+ });
+
+ if( _p.queue == null ){
+ _p.queue = runP; // i.e. first step of inductive promise chain (for queue)
+ }
+
+ return runP;
+ },
+
+ // send the thread a message
+ message: function( m ){
+ var _p = this._private;
+
+ if( _p.webworker ){
+ _p.webworker.postMessage( m );
+ }
+
+ if( _p.child ){
+ _p.child.send( m );
+ }
+
+ if( _p.timer ){
+ _p.timer.message( m );
+ }
+
+ return this; // chaining
+ },
+
+ stop: function(){
+ var _p = this._private;
+
+ if( _p.webworker ){
+ _p.webworker.terminate();
+ }
+
+ if( _p.child ){
+ _p.child.kill();
+ }
+
+ if( _p.timer ){
+ // nothing we can do if we've run a timeout
+ }
+
+ _p.stopped = true;
+
+ return this.trigger('stop'); // chaining
+ },
+
+ stopped: function(){
+ return this._private.stopped;
+ }
+
+});
+
+// turns a stringified function into a (re)named function
+var fnAs = function( fn, name ){
+ var fnStr = fn.toString();
+ fnStr = fnStr.replace(/function\s*?\S*?\s*?\(/, 'function ' + name + '(');
+
+ return fnStr;
+};
+
+var defineFnal = function( opts ){
+ opts = opts || {};
+
+ return function fnalImpl( fn, arg1 ){
+ var fnStr = fnAs( fn, '_$_$_' + opts.name );
+
+ this.require( fnStr );
+
+ return this.run( [
+ 'function( data ){',
+ ' var origResolve = resolve;',
+ ' var res = [];',
+ ' ',
+ ' resolve = function( val ){',
+ ' res.push( val );',
+ ' };',
+ ' ',
+ ' var ret = data.' + opts.name + '( _$_$_' + opts.name + ( arguments.length > 1 ? ', ' + JSON.stringify(arg1) : '' ) + ' );',
+ ' ',
+ ' resolve = origResolve;',
+ ' resolve( res.length > 0 ? res : ret );',
+ '}'
+ ].join('\n') );
+ };
+};
+
+util.extend(thdfn, {
+ reduce: defineFnal({ name: 'reduce' }),
+
+ reduceRight: defineFnal({ name: 'reduceRight' }),
+
+ map: defineFnal({ name: 'map' })
+});
+
+// aliases
+var fn = thdfn;
+fn.promise = fn.run;
+fn.terminate = fn.halt = fn.stop;
+fn.include = fn.require;
+
+// pull in event apis
+util.extend(thdfn, {
+ on: define.on(),
+ one: define.on({ unbindSelfOnTrigger: true }),
+ off: define.off(),
+ trigger: define.trigger()
+});
+
+define.eventAliasesOn( thdfn );
+
+module.exports = Thread;
+
+},{"./define":41,"./event":42,"./is":77,"./promise":80,"./util":94,"./window":100,"child_process":undefined,"path":undefined}],93:[function(_dereq_,module,exports){
+'use strict';
+
+var is = _dereq_('../is');
+
+module.exports = {
+ // get [r, g, b] from #abc or #aabbcc
+ hex2tuple: function( hex ){
+ if( !(hex.length === 4 || hex.length === 7) || hex[0] !== "#" ){ return; }
+
+ var shortHex = hex.length === 4;
+ var r, g, b;
+ var base = 16;
+
+ if( shortHex ){
+ r = parseInt( hex[1] + hex[1], base );
+ g = parseInt( hex[2] + hex[2], base );
+ b = parseInt( hex[3] + hex[3], base );
+ } else {
+ r = parseInt( hex[1] + hex[2], base );
+ g = parseInt( hex[3] + hex[4], base );
+ b = parseInt( hex[5] + hex[6], base );
+ }
+
+ return [r, g, b];
+ },
+
+ // get [r, g, b, a] from hsl(0, 0, 0) or hsla(0, 0, 0, 0)
+ hsl2tuple: function( hsl ){
+ var ret;
+ var h, s, l, a, r, g, b;
+ function hue2rgb(p, q, t){
+ if(t < 0) t += 1;
+ if(t > 1) t -= 1;
+ if(t < 1/6) return p + (q - p) * 6 * t;
+ if(t < 1/2) return q;
+ if(t < 2/3) return p + (q - p) * (2/3 - t) * 6;
+ return p;
+ }
+
+ var m = new RegExp("^" + this.regex.hsla + "$").exec(hsl);
+ if( m ){
+
+ // get hue
+ h = parseInt( m[1] );
+ if( h < 0 ){
+ h = ( 360 - (-1*h % 360) ) % 360;
+ } else if( h > 360 ){
+ h = h % 360;
+ }
+ h /= 360; // normalise on [0, 1]
+
+ s = parseFloat( m[2] );
+ if( s < 0 || s > 100 ){ return; } // saturation is [0, 100]
+ s = s/100; // normalise on [0, 1]
+
+ l = parseFloat( m[3] );
+ if( l < 0 || l > 100 ){ return; } // lightness is [0, 100]
+ l = l/100; // normalise on [0, 1]
+
+ a = m[4];
+ if( a !== undefined ){
+ a = parseFloat( a );
+
+ if( a < 0 || a > 1 ){ return; } // alpha is [0, 1]
+ }
+
+ // now, convert to rgb
+ // code from http://mjijackson.com/2008/02/rgb-to-hsl-and-rgb-to-hsv-color-model-conversion-algorithms-in-javascript
+ if( s === 0 ){
+ r = g = b = Math.round(l * 255); // achromatic
+ } else {
+ var q = l < 0.5 ? l * (1 + s) : l + s - l * s;
+ var p = 2 * l - q;
+ r = Math.round( 255 * hue2rgb(p, q, h + 1/3) );
+ g = Math.round( 255 * hue2rgb(p, q, h) );
+ b = Math.round( 255 * hue2rgb(p, q, h - 1/3) );
+ }
+
+ ret = [r, g, b, a];
+ }
+
+ return ret;
+ },
+
+ // get [r, g, b, a] from rgb(0, 0, 0) or rgba(0, 0, 0, 0)
+ rgb2tuple: function( rgb ){
+ var ret;
+
+ var m = new RegExp("^" + this.regex.rgba + "$").exec(rgb);
+ if( m ){
+ ret = [];
+
+ var isPct = [];
+ for( var i = 1; i <= 3; i++ ){
+ var channel = m[i];
+
+ if( channel[ channel.length - 1 ] === "%" ){
+ isPct[i] = true;
+ }
+ channel = parseFloat( channel );
+
+ if( isPct[i] ){
+ channel = channel/100 * 255; // normalise to [0, 255]
+ }
+
+ if( channel < 0 || channel > 255 ){ return; } // invalid channel value
+
+ ret.push( Math.floor(channel) );
+ }
+
+ var atLeastOneIsPct = isPct[1] || isPct[2] || isPct[3];
+ var allArePct = isPct[1] && isPct[2] && isPct[3];
+ if( atLeastOneIsPct && !allArePct ){ return; } // must all be percent values if one is
+
+ var alpha = m[4];
+ if( alpha !== undefined ){
+ alpha = parseFloat( alpha );
+
+ if( alpha < 0 || alpha > 1 ){ return; } // invalid alpha value
+
+ ret.push( alpha );
+ }
+ }
+
+ return ret;
+ },
+
+ colorname2tuple: function( color ){
+ return this.colors[ color.toLowerCase() ];
+ },
+
+ color2tuple: function( color ){
+ return ( is.array(color) ? color : null )
+ || this.colorname2tuple(color)
+ || this.hex2tuple(color)
+ || this.rgb2tuple(color)
+ || this.hsl2tuple(color);
+ },
+
+ colors: {
+ // special colour names
+ transparent: [0, 0, 0, 0], // NB alpha === 0
+
+ // regular colours
+ aliceblue: [240, 248, 255],
+ antiquewhite: [250, 235, 215],
+ aqua: [0, 255, 255],
+ aquamarine: [127, 255, 212],
+ azure: [240, 255, 255],
+ beige: [245, 245, 220],
+ bisque: [255, 228, 196],
+ black: [0, 0, 0],
+ blanchedalmond: [255, 235, 205],
+ blue: [0, 0, 255],
+ blueviolet: [138, 43, 226],
+ brown: [165, 42, 42],
+ burlywood: [222, 184, 135],
+ cadetblue: [95, 158, 160],
+ chartreuse: [127, 255, 0],
+ chocolate: [210, 105, 30],
+ coral: [255, 127, 80],
+ cornflowerblue: [100, 149, 237],
+ cornsilk: [255, 248, 220],
+ crimson: [220, 20, 60],
+ cyan: [0, 255, 255],
+ darkblue: [0, 0, 139],
+ darkcyan: [0, 139, 139],
+ darkgoldenrod: [184, 134, 11],
+ darkgray: [169, 169, 169],
+ darkgreen: [0, 100, 0],
+ darkgrey: [169, 169, 169],
+ darkkhaki: [189, 183, 107],
+ darkmagenta: [139, 0, 139],
+ darkolivegreen: [85, 107, 47],
+ darkorange: [255, 140, 0],
+ darkorchid: [153, 50, 204],
+ darkred: [139, 0, 0],
+ darksalmon: [233, 150, 122],
+ darkseagreen: [143, 188, 143],
+ darkslateblue: [72, 61, 139],
+ darkslategray: [47, 79, 79],
+ darkslategrey: [47, 79, 79],
+ darkturquoise: [0, 206, 209],
+ darkviolet: [148, 0, 211],
+ deeppink: [255, 20, 147],
+ deepskyblue: [0, 191, 255],
+ dimgray: [105, 105, 105],
+ dimgrey: [105, 105, 105],
+ dodgerblue: [30, 144, 255],
+ firebrick: [178, 34, 34],
+ floralwhite: [255, 250, 240],
+ forestgreen: [34, 139, 34],
+ fuchsia: [255, 0, 255],
+ gainsboro: [220, 220, 220],
+ ghostwhite: [248, 248, 255],
+ gold: [255, 215, 0],
+ goldenrod: [218, 165, 32],
+ gray: [128, 128, 128],
+ grey: [128, 128, 128],
+ green: [0, 128, 0],
+ greenyellow: [173, 255, 47],
+ honeydew: [240, 255, 240],
+ hotpink: [255, 105, 180],
+ indianred: [205, 92, 92],
+ indigo: [75, 0, 130],
+ ivory: [255, 255, 240],
+ khaki: [240, 230, 140],
+ lavender: [230, 230, 250],
+ lavenderblush: [255, 240, 245],
+ lawngreen: [124, 252, 0],
+ lemonchiffon: [255, 250, 205],
+ lightblue: [173, 216, 230],
+ lightcoral: [240, 128, 128],
+ lightcyan: [224, 255, 255],
+ lightgoldenrodyellow: [250, 250, 210],
+ lightgray: [211, 211, 211],
+ lightgreen: [144, 238, 144],
+ lightgrey: [211, 211, 211],
+ lightpink: [255, 182, 193],
+ lightsalmon: [255, 160, 122],
+ lightseagreen: [32, 178, 170],
+ lightskyblue: [135, 206, 250],
+ lightslategray: [119, 136, 153],
+ lightslategrey: [119, 136, 153],
+ lightsteelblue: [176, 196, 222],
+ lightyellow: [255, 255, 224],
+ lime: [0, 255, 0],
+ limegreen: [50, 205, 50],
+ linen: [250, 240, 230],
+ magenta: [255, 0, 255],
+ maroon: [128, 0, 0],
+ mediumaquamarine: [102, 205, 170],
+ mediumblue: [0, 0, 205],
+ mediumorchid: [186, 85, 211],
+ mediumpurple: [147, 112, 219],
+ mediumseagreen: [60, 179, 113],
+ mediumslateblue: [123, 104, 238],
+ mediumspringgreen: [0, 250, 154],
+ mediumturquoise: [72, 209, 204],
+ mediumvioletred: [199, 21, 133],
+ midnightblue: [25, 25, 112],
+ mintcream: [245, 255, 250],
+ mistyrose: [255, 228, 225],
+ moccasin: [255, 228, 181],
+ navajowhite: [255, 222, 173],
+ navy: [0, 0, 128],
+ oldlace: [253, 245, 230],
+ olive: [128, 128, 0],
+ olivedrab: [107, 142, 35],
+ orange: [255, 165, 0],
+ orangered: [255, 69, 0],
+ orchid: [218, 112, 214],
+ palegoldenrod: [238, 232, 170],
+ palegreen: [152, 251, 152],
+ paleturquoise: [175, 238, 238],
+ palevioletred: [219, 112, 147],
+ papayawhip: [255, 239, 213],
+ peachpuff: [255, 218, 185],
+ peru: [205, 133, 63],
+ pink: [255, 192, 203],
+ plum: [221, 160, 221],
+ powderblue: [176, 224, 230],
+ purple: [128, 0, 128],
+ red: [255, 0, 0],
+ rosybrown: [188, 143, 143],
+ royalblue: [65, 105, 225],
+ saddlebrown: [139, 69, 19],
+ salmon: [250, 128, 114],
+ sandybrown: [244, 164, 96],
+ seagreen: [46, 139, 87],
+ seashell: [255, 245, 238],
+ sienna: [160, 82, 45],
+ silver: [192, 192, 192],
+ skyblue: [135, 206, 235],
+ slateblue: [106, 90, 205],
+ slategray: [112, 128, 144],
+ slategrey: [112, 128, 144],
+ snow: [255, 250, 250],
+ springgreen: [0, 255, 127],
+ steelblue: [70, 130, 180],
+ tan: [210, 180, 140],
+ teal: [0, 128, 128],
+ thistle: [216, 191, 216],
+ tomato: [255, 99, 71],
+ turquoise: [64, 224, 208],
+ violet: [238, 130, 238],
+ wheat: [245, 222, 179],
+ white: [255, 255, 255],
+ whitesmoke: [245, 245, 245],
+ yellow: [255, 255, 0],
+ yellowgreen: [154, 205, 50]
+ }
+};
+
+},{"../is":77}],94:[function(_dereq_,module,exports){
+'use strict';
+
+var is = _dereq_('../is');
+var math = _dereq_('../math');
+
+var util = {
+
+ falsify: function(){ return false; },
+
+ zeroify: function(){ return 0; },
+
+ noop: function(){},
+
+ /* jshint ignore:start */
+ error: function( msg ){
+ if( console.error ){
+ console.error.apply( console, arguments );
+
+ if( console.trace ){ console.trace(); }
+ } else {
+ console.log.apply( console, arguments );
+
+ if( console.trace ){ console.trace(); }
+ }
+ },
+ /* jshint ignore:end */
+
+ clone: function( obj ){
+ return this.extend( {}, obj );
+ },
+
+ // gets a shallow copy of the argument
+ copy: function( obj ){
+ if( obj == null ){
+ return obj;
+ } if( is.array(obj) ){
+ return obj.slice();
+ } else if( is.plainObject(obj) ){
+ return this.clone( obj );
+ } else {
+ return obj;
+ }
+ }
+
+};
+
+util.makeBoundingBox = math.makeBoundingBox.bind( math );
+
+util._staticEmptyObject = {};
+
+util.staticEmptyObject = function(){
+ return util._staticEmptyObject;
+};
+
+util.extend = Object.assign != null ? Object.assign : function( tgt ){
+ var args = arguments;
+
+ for( var i = 1; i < args.length; i++ ){
+ var obj = args[i];
+
+ for( var k in obj ){
+ tgt[k] = obj[k];
+ }
+ }
+
+ return tgt;
+};
+
+[
+ _dereq_('./colors'),
+ _dereq_('./maps'),
+ { memoize: _dereq_('./memoize') },
+ _dereq_('./regex'),
+ _dereq_('./strings'),
+ _dereq_('./timing')
+].forEach(function( req ){
+ util.extend( util, req );
+});
+
+module.exports = util;
+
+},{"../is":77,"../math":79,"./colors":93,"./maps":95,"./memoize":96,"./regex":97,"./strings":98,"./timing":99}],95:[function(_dereq_,module,exports){
+'use strict';
+
+var is = _dereq_('../is');
+
+module.exports = {
+ // has anything been set in the map
+ mapEmpty: function( map ){
+ var empty = true;
+
+ if( map != null ){
+ for(var i in map){ // jshint ignore:line
+ empty = false;
+ break;
+ }
+ }
+
+ return empty;
+ },
+
+ // pushes to the array at the end of a map (map may not be built)
+ pushMap: function( options ){
+ var array = this.getMap(options);
+
+ if( array == null ){ // if empty, put initial array
+ this.setMap( this.extend({}, options, {
+ value: [ options.value ]
+ }) );
+ } else {
+ array.push( options.value );
+ }
+ },
+
+ // sets the value in a map (map may not be built)
+ setMap: function( options ){
+ var obj = options.map;
+ var key;
+ var keys = options.keys;
+ var l = keys.length;
+
+ for(var i = 0; i < l; i++){
+ var key = keys[i];
+
+ if( is.plainObject( key ) ){
+ this.error('Tried to set map with object key');
+ }
+
+ if( i < keys.length - 1 ){
+
+ // extend the map if necessary
+ if( obj[key] == null ){
+ obj[key] = {};
+ }
+
+ obj = obj[key];
+ } else {
+ // set the value
+ obj[key] = options.value;
+ }
+ }
+ },
+
+ // gets the value in a map even if it's not built in places
+ getMap: function( options ){
+ var obj = options.map;
+ var keys = options.keys;
+ var l = keys.length;
+
+ for(var i = 0; i < l; i++){
+ var key = keys[i];
+
+ if( is.plainObject( key ) ){
+ this.error('Tried to get map with object key');
+ }
+
+ obj = obj[key];
+
+ if( obj == null ){
+ return obj;
+ }
+ }
+
+ return obj;
+ },
+
+ // deletes the entry in the map
+ deleteMap: function( options ){
+ var obj = options.map;
+ var keys = options.keys;
+ var l = keys.length;
+ var keepChildren = options.keepChildren;
+
+ for(var i = 0; i < l; i++){
+ var key = keys[i];
+
+ if( is.plainObject( key ) ){
+ this.error('Tried to delete map with object key');
+ }
+
+ var lastKey = i === options.keys.length - 1;
+ if( lastKey ){
+
+ if( keepChildren ){ // then only delete child fields not in keepChildren
+ for( var child in obj ){
+ if( !keepChildren[child] ){
+ obj[child] = undefined;
+ }
+ }
+ } else {
+ obj[key] = undefined;
+ }
+
+ } else {
+ obj = obj[key];
+ }
+ }
+ }
+};
+
+},{"../is":77}],96:[function(_dereq_,module,exports){
+'use strict';
+
+module.exports = function memoize( fn, keyFn ){
+ var self = this;
+ var cache = {};
+
+ if( !keyFn ){
+ keyFn = function(){
+ if( arguments.length === 1 ){
+ return arguments[0];
+ }
+
+ var args = [];
+
+ for( var i = 0; i < arguments.length; i++ ){
+ args.push( arguments[i] );
+ }
+
+ return args.join('$');
+ };
+ }
+
+ return function memoizedFn(){
+ var args = arguments;
+ var ret;
+ var k = keyFn.apply( self, args );
+
+ if( !(ret = cache[k]) ){
+ ret = cache[k] = fn.apply( self, args );
+ }
+
+ return ret;
+ };
+};
+
+},{}],97:[function(_dereq_,module,exports){
+'use strict';
+
+var number = "(?:[-+]?(?:(?:\\d+|\\d*\\.\\d+)(?:[Ee][+-]?\\d+)?))";
+
+var rgba = "rgb[a]?\\(("+ number +"[%]?)\\s*,\\s*("+ number +"[%]?)\\s*,\\s*("+ number +"[%]?)(?:\\s*,\\s*("+ number +"))?\\)";
+var rgbaNoBackRefs = "rgb[a]?\\((?:"+ number +"[%]?)\\s*,\\s*(?:"+ number +"[%]?)\\s*,\\s*(?:"+ number +"[%]?)(?:\\s*,\\s*(?:"+ number +"))?\\)";
+
+var hsla = "hsl[a]?\\(("+ number +")\\s*,\\s*("+ number +"[%])\\s*,\\s*("+ number +"[%])(?:\\s*,\\s*("+ number +"))?\\)";
+var hslaNoBackRefs = "hsl[a]?\\((?:"+ number +")\\s*,\\s*(?:"+ number +"[%])\\s*,\\s*(?:"+ number +"[%])(?:\\s*,\\s*(?:"+ number +"))?\\)";
+
+var hex3 = "\\#[0-9a-fA-F]{3}";
+var hex6 = "\\#[0-9a-fA-F]{6}";
+
+module.exports = {
+ regex: {
+ number: number,
+ rgba: rgba,
+ rgbaNoBackRefs: rgbaNoBackRefs,
+ hsla: hsla,
+ hslaNoBackRefs: hslaNoBackRefs,
+ hex3: hex3,
+ hex6: hex6
+ }
+};
+
+},{}],98:[function(_dereq_,module,exports){
+'use strict';
+
+var memoize = _dereq_('./memoize');
+var is = _dereq_('../is');
+
+module.exports = {
+
+ camel2dash: memoize( function( str ){
+ return str.replace(/([A-Z])/g, function( v ){
+ return '-' + v.toLowerCase();
+ });
+ } ),
+
+ dash2camel: memoize( function( str ){
+ return str.replace(/(-\w)/g, function( v ){
+ return v[1].toUpperCase();
+ });
+ } ),
+
+ capitalize: function(str){
+ if( is.emptyString(str) ){
+ return str;
+ }
+
+ return str.charAt(0).toUpperCase() + str.substring(1);
+ }
+
+};
+
+},{"../is":77,"./memoize":96}],99:[function(_dereq_,module,exports){
+'use strict';
+
+var window = _dereq_('../window');
+var is = _dereq_('../is');
+var performance = window ? window.performance : null;
+
+var util = {};
+
+var raf = !window ? null : ( window.requestAnimationFrame || window.mozRequestAnimationFrame ||
+ window.webkitRequestAnimationFrame || window.msRequestAnimationFrame );
+
+raf = raf || function( fn ){
+ if( fn ){
+ setTimeout(function(){
+ fn( pnow() );
+ }, 1000/60);
+ }
+};
+
+util.requestAnimationFrame = function(fn){
+ raf( fn );
+};
+
+var pnow = performance && performance.now ? function(){ return performance.now(); } : function(){ return Date.now(); };
+
+util.performanceNow = pnow;
+
+// ported lodash throttle function
+util.throttle = function(func, wait, options) {
+ var leading = true,
+ trailing = true;
+
+ if (options === false) {
+ leading = false;
+ } else if (is.plainObject(options)) {
+ leading = 'leading' in options ? options.leading : leading;
+ trailing = 'trailing' in options ? options.trailing : trailing;
+ }
+ options = options || {};
+ options.leading = leading;
+ options.maxWait = wait;
+ options.trailing = trailing;
+
+ return util.debounce(func, wait, options);
+};
+
+util.now = function(){
+ return Date.now();
+};
+
+util.debounce = function(func, wait, options) { // ported lodash debounce function
+ var util = this;
+ var args,
+ maxTimeoutId,
+ result,
+ stamp,
+ thisArg,
+ timeoutId,
+ trailingCall,
+ lastCalled = 0,
+ maxWait = false,
+ trailing = true;
+
+ if (!is.fn(func)) {
+ return;
+ }
+ wait = Math.max(0, wait) || 0;
+ if (options === true) {
+ var leading = true;
+ trailing = false;
+ } else if (is.plainObject(options)) {
+ leading = options.leading;
+ maxWait = 'maxWait' in options && (Math.max(wait, options.maxWait) || 0);
+ trailing = 'trailing' in options ? options.trailing : trailing;
+ }
+ var delayed = function() {
+ var remaining = wait - (util.now() - stamp);
+ if (remaining <= 0) {
+ if (maxTimeoutId) {
+ clearTimeout(maxTimeoutId);
+ }
+ var isCalled = trailingCall;
+ maxTimeoutId = timeoutId = trailingCall = undefined;
+ if (isCalled) {
+ lastCalled = util.now();
+ result = func.apply(thisArg, args);
+ if (!timeoutId && !maxTimeoutId) {
+ args = thisArg = null;
+ }
+ }
+ } else {
+ timeoutId = setTimeout(delayed, remaining);
+ }
+ };
+
+ var maxDelayed = function() {
+ if (timeoutId) {
+ clearTimeout(timeoutId);
+ }
+ maxTimeoutId = timeoutId = trailingCall = undefined;
+ if (trailing || (maxWait !== wait)) {
+ lastCalled = util.now();
+ result = func.apply(thisArg, args);
+ if (!timeoutId && !maxTimeoutId) {
+ args = thisArg = null;
+ }
+ }
+ };
+
+ return function() {
+ args = arguments;
+ stamp = util.now();
+ thisArg = this;
+ trailingCall = trailing && (timeoutId || !leading);
+
+ if (maxWait === false) {
+ var leadingCall = leading && !timeoutId;
+ } else {
+ if (!maxTimeoutId && !leading) {
+ lastCalled = stamp;
+ }
+ var remaining = maxWait - (stamp - lastCalled),
+ isCalled = remaining <= 0;
+
+ if (isCalled) {
+ if (maxTimeoutId) {
+ maxTimeoutId = clearTimeout(maxTimeoutId);
+ }
+ lastCalled = stamp;
+ result = func.apply(thisArg, args);
+ }
+ else if (!maxTimeoutId) {
+ maxTimeoutId = setTimeout(maxDelayed, remaining);
+ }
+ }
+ if (isCalled && timeoutId) {
+ timeoutId = clearTimeout(timeoutId);
+ }
+ else if (!timeoutId && wait !== maxWait) {
+ timeoutId = setTimeout(delayed, wait);
+ }
+ if (leadingCall) {
+ isCalled = true;
+ result = func.apply(thisArg, args);
+ }
+ if (isCalled && !timeoutId && !maxTimeoutId) {
+ args = thisArg = null;
+ }
+ return result;
+ };
+};
+
+module.exports = util;
+
+},{"../is":77,"../window":100}],100:[function(_dereq_,module,exports){
+module.exports = ( typeof window === 'undefined' ? null : window );
+
+},{}]},{},[76])(76)
+});
+
+
+//# sourceMappingURL=cytoscape.js.map
diff --git a/docs/htmldoc/js/cytoscape.js-panzoom.css b/docs/htmldoc/js/cytoscape.js-panzoom.css
new file mode 100644
index 0000000..46d9a36
--- /dev/null
+++ b/docs/htmldoc/js/cytoscape.js-panzoom.css
@@ -0,0 +1,203 @@
+.cy-panzoom {
+ position: fixed;
+ right: 70px;
+ top: 10px;
+ font-size: 13px;
+ color: #fff;
+ font-family: arial, helvetica, sans-serif;
+ line-height: 1;
+ color: #666;
+ font-size: 11px;
+ z-index: 99999;
+}
+
+.cy-panzoom-zoom-button {
+ cursor: pointer;
+ padding: 3px;
+ text-align: center;
+ position: absolute;
+ border-radius: 3px;
+ width: 10px;
+ height: 10px;
+ left: 16px;
+ background: #fff;
+ border: 1px solid #999;
+ margin-left: -1px;
+ margin-top: -1px;
+ z-index: 1;
+}
+
+.cy-panzoom-zoom-button:active,
+.cy-panzoom-slider-handle:active,
+.cy-panzoom-slider-handle.active {
+ background: #ddd;
+}
+
+.cy-panzoom-pan-button {
+ position: absolute;
+ z-index: 1;
+ height: 16px;
+ width: 16px;
+}
+
+.cy-panzoom-reset {
+ top: 55px;
+}
+
+.cy-panzoom-zoom-in {
+ top: 80px;
+}
+
+.cy-panzoom-zoom-out {
+ top: 197px;
+}
+
+.cy-panzoom-pan-up {
+ top: 0;
+ left: 50%;
+ margin-left: -5px;
+ width: 0;
+ height: 0;
+ border-left: 5px solid transparent;
+ border-right: 5px solid transparent;
+ border-bottom: 5px solid #666;
+}
+
+.cy-panzoom-pan-down {
+ bottom: 0;
+ left: 50%;
+ margin-left: -5px;
+ width: 0;
+ height: 0;
+ border-left: 5px solid transparent;
+ border-right: 5px solid transparent;
+ border-top: 5px solid #666;
+}
+
+.cy-panzoom-pan-left {
+ top: 50%;
+ left: 0;
+ margin-top: -5px;
+ width: 0;
+ height: 0;
+ border-top: 5px solid transparent;
+ border-bottom: 5px solid transparent;
+ border-right: 5px solid #666;
+}
+
+.cy-panzoom-pan-right {
+ top: 50%;
+ right: 0;
+ margin-top: -5px;
+ width: 0;
+ height: 0;
+ border-top: 5px solid transparent;
+ border-bottom: 5px solid transparent;
+ border-left: 5px solid #666;
+}
+
+.cy-panzoom-pan-indicator {
+ position: absolute;
+ left: 0;
+ top: 0;
+ width: 8px;
+ height: 8px;
+ border-radius: 8px;
+ background: #000;
+ border-radius: 8px;
+ margin-left: -5px;
+ margin-top: -5px;
+ display: none;
+ z-index: 999;
+ opacity: 0.6;
+}
+
+.cy-panzoom-slider {
+ position: absolute;
+ top: 97px;
+ left: 17px;
+ height: 100px;
+ width: 15px;
+}
+
+.cy-panzoom-slider-background {
+ position: absolute;
+ top: 0;
+ width: 2px;
+ height: 100px;
+ left: 5px;
+ background: #fff;
+ border-left: 1px solid #999;
+ border-right: 1px solid #999;
+}
+
+.cy-panzoom-slider-handle {
+ position: absolute;
+ width: 16px;
+ height: 8px;
+ background: #fff;
+ border: 1px solid #999;
+ border-radius: 2px;
+ margin-left: -2px;
+ z-index: 999;
+ line-height: 8px;
+ cursor: default;
+}
+
+.cy-panzoom-slider-handle .icon {
+ margin: 0 4px;
+ line-height: 10px;
+}
+
+.cy-panzoom-no-zoom-tick {
+ position: absolute;
+ background: #666;
+ border: 1px solid #fff;
+ border-radius: 2px;
+ margin-left: -1px;
+ width: 8px;
+ height: 2px;
+ left: 3px;
+ z-index: 1;
+ margin-top: 3px;
+}
+
+.cy-panzoom-panner {
+ position: absolute;
+ left: 5px;
+ top: 5px;
+ height: 40px;
+ width: 40px;
+ background: #fff;
+ border: 1px solid #999;
+ border-radius: 40px;
+ margin-left: -1px;
+}
+
+.cy-panzoom-panner-handle {
+ position: absolute;
+ left: 0;
+ top: 0;
+ outline: none;
+ height: 40px;
+ width: 40px;
+ position: absolute;
+ z-index: 999;
+}
+
+.cy-panzoom-zoom-only .cy-panzoom-slider,
+.cy-panzoom-zoom-only .cy-panzoom-panner {
+ display: none;
+}
+
+.cy-panzoom-zoom-only .cy-panzoom-reset {
+ top: 20px;
+}
+
+.cy-panzoom-zoom-only .cy-panzoom-zoom-in {
+ top: 45px;
+}
+
+.cy-panzoom-zoom-only .cy-panzoom-zoom-out {
+ top: 70px;
+}
diff --git a/docs/htmldoc/js/cytoscape.min.js b/docs/htmldoc/js/cytoscape.min.js
new file mode 100644
index 0000000..a498936
--- /dev/null
+++ b/docs/htmldoc/js/cytoscape.min.js
@@ -0,0 +1,26 @@
+/*!
+ * This file is part of Cytoscape.js 2.5.1.
+ *
+ * Cytoscape.js is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published by the Free
+ * Software Foundation, either version 3 of the License, or (at your option) any
+ * later version.
+ *
+ * Cytoscape.js is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License along with
+ * Cytoscape.js. If not, see <http://www.gnu.org/licenses/>.
+ */
+!function(e){if("object"==typeof exports&&"undefined"!=typeof module)module.exports=e();else if("function"==typeof define&&define.amd)define([],e);else{var t;t="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof self?self:this,t.cytoscape=e()}}(function(){var define,module,exports;return function e(t,r,n){function i(o,s){if(!r[o]){if(!t[o]){var l="function"==typeof require&&require;if(!s&&l)return l(o,!0);if(a)return a(o,!0);var u=new Error("Cannot find module '"+o+"'");throw u.code="MODULE_NOT_FOUND",u}var c=r[o]={exports:{}};t[o][0].call(c.exports,function(e){var r=t[o][1][e];return i(r?r:e)},c,c.exports,e,t,r,n)}return r[o].exports}for(var a="function"==typeof require&&require,o=0;o<n.length;o++)i(n[o]);return i}({1:[function(e,t,r){"use strict";var n=e("./util"),i=e("./is"),a=e("./promise"),o=function(e,t,r){if(!(this instanceof o))return new o(e,t,r);var a=this._private=n.extend({duration:1e3},t,r);a.target=e,a.style=a.style||a.css,a.started=!1,a.playing=!1,a.hooked=!1,a.applying=!1,a.progress=0,a.completes=[],a.frames=[],a.complete&&i.fn(a.complete)&&a.completes.push(a.complete),this.length=1,this[0]=this},s=o.prototype;n.extend(s,{instanceString:function(){return"animation"},hook:function(){var e=this._private;if(!e.hooked){var t,r=e.target._private.animation;t=e.queue?r.queue:r.current,t.push(this),i.elementOrCollection(e.target)&&e.target.cy().addToAnimationPool(e.target),e.hooked=!0}return this},play:function(){var e=this._private;return 1===e.progress&&(e.progress=0),e.playing=!0,e.started=!1,e.stopped=!1,this.hook(),this},playing:function(){return this._private.playing},apply:function(){var e=this._private;return e.applying=!0,e.started=!1,e.stopped=!1,this.hook(),this},applying:function(){return this._private.applying},pause:function(){var e=this._private;return e.playing=!1,e.started=!1,this},stop:function(){var e=this._private;return e.playing=!1,e.started=!1,e.stopped=!0,this},rewind:function(){return this.progress(0)},fastforward:function(){return this.progress(1)},time:function(e){var t=this._private;return void 0===e?t.progress*t.duration:this.progress(e/t.duration)},progress:function(e){var t=this._private,r=t.playing;return void 0===e?t.progress:(r&&this.pause(),t.progress=e,t.started=!1,r&&this.play(),this)},completed:function(){return 1===this._private.progress},reverse:function(){var e=this._private,t=e.playing;t&&this.pause(),e.progress=1-e.progress,e.started=!1;var r=function(t,r){var n=e[t];e[t]=e[r],e[r]=n};r("zoom","startZoom"),r("pan","startPan"),r("position","startPosition");for(var i=0;i<e.style.length;i++){var a=e.style[i],o=a.name,s=e.startStyle[o];e.startStyle[o]=e.startStyle[n.dash2camel(o)]=a,e.style[i]=s}return t&&this.play(),this},promise:function(e){var t,r=this._private;switch(e){case"frame":t=r.frames;break;default:case"complete":case"completed":t=r.completes}return new a(function(e,r){t.push(function(){e()})})}}),s.complete=s.completed,t.exports=o},{"./is":77,"./promise":80,"./util":94}],2:[function(e,t,r){"use strict";var n=e("../../is"),i={aStar:function(e){var t=this;e=e||{};var r=function(e,t,n,i){if(e==t)return i.push(a.getElementById(t)),i;if(t in n){var o=n[t],s=v[t];return i.push(a.getElementById(t)),i.push(a.getElementById(s)),r(e,o,n,i)}return void 0},i=function(e,t){if(0===e.length)return void 0;for(var r=0,n=t[e[0]],i=1;i<e.length;i++){var a=t[e[i]];n>a&&(n=a,r=i)}return r},a=this._private.cy;if(null==e||null==e.root)return void 0;var o=n.string(e.root)?this.filter(e.root)[0]:e.root[0];if(null==e.goal)return void 0;var s=n.string(e.goal)?this.filter(e.goal)[0]:e.goal[0];if(null!=e.heuristic&&n.fn(e.heuristic))var l=e.heuristic;else var l=function(){return 0};if(null!=e.weight&&n.fn(e.weight))var u=e.weight;else var u=function(e){return 1};if(null!=e.directed)var c=e.directed;else var c=!1;var d=[],h=[o.id()],p={},v={},f={},g={};f[o.id()]=0,g[o.id()]=l(o);for(var y=this.edges().stdFilter(function(e){return!e.isLoop()}),m=this.nodes(),b=0;h.length>0;){var x=i(h,g),w=a.getElementById(h[x]);if(b++,w.id()==s.id()){var _=r(o.id(),s.id(),p,[]);return _.reverse(),{found:!0,distance:f[w.id()],path:t.spawn(_),steps:b}}d.push(w.id()),h.splice(x,1);var E=w.connectedEdges();c&&(E=E.stdFilter(function(e){return e.data("source")===w.id()})),E=E.intersect(y);for(var D=0;D<E.length;D++){var S=E[D],k=S.connectedNodes().stdFilter(function(e){return e.id()!==w.id()}).intersect(m);if(-1==d.indexOf(k.id())){var T=f[w.id()]+u.apply(S,[S]);-1!=h.indexOf(k.id())?T<f[k.id()]&&(f[k.id()]=T,g[k.id()]=T+l(k),p[k.id()]=w.id()):(f[k.id()]=T,g[k.id()]=T+l(k),h.push(k.id()),p[k.id()]=w.id(),v[k.id()]=S.id())}}}return{found:!1,distance:void 0,path:void 0,steps:b}}};t.exports=i},{"../../is":77}],3:[function(e,t,r){"use strict";var n=e("../../is"),i=e("../../util"),a={bellmanFord:function(e){var t=this;if(e=e||{},null!=e.weight&&n.fn(e.weight))var r=e.weight;else var r=function(e){return 1};if(null!=e.directed)var a=e.directed;else var a=!1;if(null==e.root)return void 0;if(n.string(e.root))var o=this.filter(e.root)[0];else var o=e.root[0];for(var s=this._private.cy,l=this.edges().stdFilter(function(e){return!e.isLoop()}),u=this.nodes(),c=u.length,d={},h=0;c>h;h++)d[u[h].id()]=h;for(var p=[],v=[],f=[],h=0;c>h;h++)u[h].id()===o.id()?p[h]=0:p[h]=1/0,v[h]=void 0;for(var g=!1,h=1;c>h;h++){g=!1;for(var y=0;y<l.length;y++){var m=d[l[y].source().id()],b=d[l[y].target().id()],x=r.apply(l[y],[l[y]]),w=p[m]+x;if(w<p[b]&&(p[b]=w,v[b]=m,f[b]=l[y],g=!0),!a){var w=p[b]+x;w<p[m]&&(p[m]=w,v[m]=b,f[m]=l[y],g=!0)}}if(!g)break}if(g)for(var y=0;y<l.length;y++){var m=d[l[y].source().id()],b=d[l[y].target().id()],x=r.apply(l[y],[l[y]]);if(p[m]+x<p[b])return i.error("Graph contains a negative weight cycle for Bellman-Ford"),{pathTo:void 0,distanceTo:void 0,hasNegativeWeightCycle:!0}}for(var _=[],h=0;c>h;h++)_.push(u[h].id());var E={distanceTo:function(e){if(n.string(e))var t=s.filter(e)[0].id();else var t=e.id();return p[d[t]]},pathTo:function(e){var r=function(e,t,r,n,i,a){for(;;){if(i.push(s.getElementById(n[r])),i.push(a[r]),t===r)return i;var o=e[r];if("undefined"==typeof o)return void 0;r=o}};if(n.string(e))var i=s.filter(e)[0].id();else var i=e.id();var a=[],l=r(v,d[o.id()],d[i],_,a,f);return null!=l&&l.reverse(),t.spawn(l)},hasNegativeWeightCycle:!1};return E}};t.exports=a},{"../../is":77,"../../util":94}],4:[function(e,t,r){"use strict";var n=e("../../is"),i={betweennessCentrality:function(e){if(e=e||{},null!=e.weight&&n.fn(e.weight))var t=e.weight,r=!0;else var r=!1;if(null!=e.directed&&n.bool(e.directed))var i=e.directed;else var i=!1;for(var a=function(e,t){e.unshift(t);for(var r=0;f[e[r]]<f[e[r+1]]&&r<e.length-1;r++){var n=e[r];e[r]=e[r+1],e[r+1]=n}},o=this._private.cy,s=this.nodes(),l={},u={},c=0;c<s.length;c++)i?l[s[c].id()]=s[c].outgoers("node"):l[s[c].id()]=s[c].openNeighborhood("node");for(var c=0;c<s.length;c++)u[s[c].id()]=0;for(var d=0;d<s.length;d++){for(var h=[],p={},v={},f={},g=[],c=0;c<s.length;c++)p[s[c].id()]=[],v[s[c].id()]=0,f[s[c].id()]=Number.POSITIVE_INFINITY;for(v[s[d].id()]=1,f[s[d].id()]=0,g.unshift(s[d].id());g.length>0;){var y=g.pop();h.push(y),r?l[y].forEach(function(e){if(o.$("#"+y).edgesTo(e).length>0)var r=o.$("#"+y).edgesTo(e)[0];else var r=e.edgesTo("#"+y)[0];var n=t.apply(r,[r]);f[e.id()]>f[y]+n&&(f[e.id()]=f[y]+n,g.indexOf(e.id())<0?a(g,e.id()):(g.splice(g.indexOf(e.id()),1),a(g,e.id())),v[e.id()]=0,p[e.id()]=[]),f[e.id()]==f[y]+n&&(v[e.id()]=v[e.id()]+v[y],p[e.id()].push(y))}):l[y].forEach(function(e){f[e.id()]==Number.POSITIVE_INFINITY&&(g.unshift(e.id()),f[e.id()]=f[y]+1),f[e.id()]==f[y]+1&&(v[e.id()]=v[e.id()]+v[y],p[e.id()].push(y))})}for(var m={},c=0;c<s.length;c++)m[s[c].id()]=0;for(;h.length>0;){var b=h.pop();p[b].forEach(function(e){m[e]=m[e]+v[e]/v[b]*(1+m[b]),b!=s[d].id()&&(u[b]=u[b]+m[b])})}}var x=0;for(var w in u)x<u[w]&&(x=u[w]);var _={betweenness:function(e){if(n.string(e))var e=o.filter(e)[0].id();else var e=e.id();return u[e]},betweennessNormalized:function(e){if(n.string(e))var e=o.filter(e)[0].id();else var e=e.id();return u[e]/x}};return _.betweennessNormalised=_.betweennessNormalized,_}};i.bc=i.betweennessCentrality,t.exports=i},{"../../is":77}],5:[function(e,t,r){"use strict";var n=e("../../is"),i=e("../../heap"),a=function(e){return e={bfs:e.bfs||!e.dfs,dfs:e.dfs||!e.bfs},function(t,r,i){var a,o,s;n.plainObject(t)&&!n.elementOrCollection(t)&&(a=t,t=a.roots||a.root,r=a.visit,i=a.directed,o=a.std,s=a.thisArg),i=2!==arguments.length||n.fn(r)?i:r,r=n.fn(r)?r:function(){};for(var l,u=this._private.cy,c=t=n.string(t)?this.filter(t):t,d=[],h=[],p={},v={},f={},g=0,y=this.nodes(),m=this.edges(),b=0;b<c.length;b++)c[b].isNode()&&(d.unshift(c[b]),e.bfs&&(f[c[b].id()]=!0,h.push(c[b])),v[c[b].id()]=0);for(;0!==d.length;){var c=e.bfs?d.shift():d.pop();if(e.dfs){if(f[c.id()])continue;f[c.id()]=!0,h.push(c)}var x,w=v[c.id()],_=p[c.id()],E=null==_?void 0:_.connectedNodes().not(c)[0];if(x=o?r.call(s,c,_,E,g++,w):r.call(c,g++,w,c,_,E),x===!0){l=c;break}if(x===!1)break;for(var D=c.connectedEdges(i?function(){return this.data("source")===c.id()}:void 0).intersect(m),b=0;b<D.length;b++){var S=D[b],k=S.connectedNodes(function(){return this.id()!==c.id()}).intersect(y);0===k.length||f[k.id()]||(k=k[0],d.push(k),e.bfs&&(f[k.id()]=!0,h.push(k)),p[k.id()]=S,v[k.id()]=v[c.id()]+1)}}for(var T=[],b=0;b<h.length;b++){var P=h[b],C=p[P.id()];C&&T.push(C),T.push(P)}return{path:u.collection(T,{unique:!0}),found:u.collection(l)}}},o={breadthFirstSearch:a({bfs:!0}),depthFirstSearch:a({dfs:!0}),kruskal:function(e){function t(e){for(var t=0;t<a.length;t++){var r=a[t];if(r.anySame(e))return{eles:r,index:t}}}var r=this.cy();e=n.fn(e)?e:function(){return 1};for(var i=r.collection(r,[]),a=[],o=this.nodes(),s=0;s<o.length;s++)a.push(o[s].collection());for(var l=this.edges(),u=l.toArray().sort(function(t,r){var n=e.call(t,t),i=e.call(r,r);return n-i}),s=0;s<u.length;s++){var c=u[s],d=c.source()[0],h=c.target()[0],p=t(d),v=t(h);p.index!==v.index&&(i=i.add(c),a[p.index]=p.eles.add(v.eles),a.splice(v.index,1))}return o.add(i)},dijkstra:function(e,t,r){var a;n.plainObject(e)&&!n.elementOrCollection(e)&&(a=e,e=a.root,t=a.weight,r=a.directed);var o=this._private.cy;t=n.fn(t)?t:function(){return 1};for(var s=n.string(e)?this.filter(e)[0]:e[0],l={},u={},c={},d=this.edges().filter(function(){return!this.isLoop()}),h=this.nodes(),p=function(e){return l[e.id()]},v=function(e,t){l[e.id()]=t,f.updateItem(e)},f=new i(function(e,t){return p(e)-p(t)}),g=0;g<h.length;g++){var y=h[g];l[y.id()]=y.same(s)?0:1/0,f.push(y)}for(var m=function(e,n){for(var i,a=(r?e.edgesTo(n):e.edgesWith(n)).intersect(d),o=1/0,s=0;s<a.length;s++){var l=a[s],u=t.apply(l,[l]);(o>u||!i)&&(o=u,i=l)}return{edge:i,dist:o}};f.size()>0;){var b=f.pop(),x=p(b),w=b.id();if(c[w]=x,x===Math.Infinite)break;for(var _=b.neighborhood().intersect(h),g=0;g<_.length;g++){var E=_[g],D=E.id(),S=m(b,E),k=x+S.dist;k<p(E)&&(v(E,k),u[D]={node:b,edge:S.edge})}}return{distanceTo:function(e){var t=n.string(e)?h.filter(e)[0]:e[0];return c[t.id()]},pathTo:function(e){var t=n.string(e)?h.filter(e)[0]:e[0],r=[],i=t;if(t.length>0)for(r.unshift(t);u[i.id()];){var a=u[i.id()];r.unshift(a.edge),r.unshift(a.node),i=a.node}return o.collection(r)}}}};o.bfs=o.breadthFirstSearch,o.dfs=o.depthFirstSearch,t.exports=o},{"../../heap":75,"../../is":77}],6:[function(e,t,r){"use strict";var n=e("../../is"),i={closenessCentralityNormalized:function(e){e=e||{};var t=this.cy(),r=e.harmonic;void 0===r&&(r=!0);for(var i={},a=0,o=this.nodes(),s=this.floydWarshall({weight:e.weight,directed:e.directed}),l=0;l<o.length;l++){for(var u=0,c=0;c<o.length;c++)if(l!=c){var d=s.distance(o[l],o[c]);u+=r?1/d:d}r||(u=1/u),u>a&&(a=u),i[o[l].id()]=u}return{closeness:function(e){if(n.string(e))var e=t.filter(e)[0].id();else var e=e.id();return i[e]/a}}},closenessCentrality:function(e){if(e=e||{},null==e.root)return void 0;if(n.string(e.root))var t=this.filter(e.root)[0];else var t=e.root[0];if(null!=e.weight&&n.fn(e.weight))var r=e.weight;else var r=function(){return 1};if(null!=e.directed&&n.bool(e.directed))var i=e.directed;else var i=!1;var a=e.harmonic;void 0===a&&(a=!0);for(var o=this.dijkstra({root:t,weight:r,directed:i}),s=0,l=this.nodes(),u=0;u<l.length;u++)if(l[u].id()!=t.id()){var c=o.distanceTo(l[u]);s+=a?1/c:c}return a?s:1/s}};i.cc=i.closenessCentrality,i.ccn=i.closenessCentralityNormalised=i.closenessCentralityNormalized,t.exports=i},{"../../is":77}],7:[function(e,t,r){"use strict";var n=e("../../is"),i=e("../../util"),a={degreeCentralityNormalized:function(e){e=e||{};var t=this.cy();if(null!=e.directed)var r=e.directed;else var r=!1;var a=this.nodes(),o=a.length;if(r){for(var s={},l={},u=0,c=0,d=0;o>d;d++){var h=a[d],p=this.degreeCentrality(i.extend({},e,{root:h}));u<p.indegree&&(u=p.indegree),c<p.outdegree&&(c=p.outdegree),s[h.id()]=p.indegree,l[h.id()]=p.outdegree}return{indegree:function(e){if(n.string(e))var e=t.filter(e)[0].id();else var e=e.id();return s[e]/u},outdegree:function(e){if(n.string(e))var e=t.filter(e)[0].id();else var e=e.id();return l[e]/c}}}for(var v={},f=0,d=0;o>d;d++){var h=a[d],p=this.degreeCentrality(i.extend({},e,{root:h}));f<p.degree&&(f=p.degree),v[h.id()]=p.degree}return{degree:function(e){if(n.string(e))var e=t.filter(e)[0].id();else var e=e.id();return v[e]/f}}},degreeCentrality:function(e){e=e||{};var t=this;if(null==e||null==e.root)return void 0;var r=n.string(e.root)?this.filter(e.root)[0]:e.root[0];if(null!=e.weight&&n.fn(e.weight))var i=e.weight;else var i=function(e){return 1};if(null!=e.directed)var a=e.directed;else var a=!1;if(null!=e.alpha&&n.number(e.alpha))var o=e.alpha;else o=0;if(a){for(var s=r.connectedEdges('edge[target = "'+r.id()+'"]').intersection(t),l=r.connectedEdges('edge[source = "'+r.id()+'"]').intersection(t),u=s.length,c=l.length,d=0,h=0,p=0;p<s.length;p++){var v=s[p];d+=i.apply(v,[v])}for(var p=0;p<l.length;p++){var v=l[p];h+=i.apply(v,[v])}return{indegree:Math.pow(u,1-o)*Math.pow(d,o),outdegree:Math.pow(c,1-o)*Math.pow(h,o)}}for(var f=r.connectedEdges().intersection(t),g=f.length,y=0,p=0;p<f.length;p++){var v=f[p];y+=i.apply(v,[v])}return{degree:Math.pow(g,1-o)*Math.pow(y,o)}}};a.dc=a.degreeCentrality,a.dcn=a.degreeCentralityNormalised=a.degreeCentralityNormalized,t.exports=a},{"../../is":77,"../../util":94}],8:[function(e,t,r){"use strict";var n=e("../../is"),i={floydWarshall:function(e){e=e||{};var t=this.cy();if(null!=e.weight&&n.fn(e.weight))var r=e.weight;else var r=function(e){return 1};if(null!=e.directed)var i=e.directed;else var i=!1;for(var a=this.edges().stdFilter(function(e){return!e.isLoop()}),o=this.nodes(),s=o.length,l={},u=0;s>u;u++)l[o[u].id()]=u;for(var c=[],u=0;s>u;u++){for(var d=new Array(s),h=0;s>h;h++)u==h?d[h]=0:d[h]=1/0;c.push(d)}var p=[],v=[],f=function(e){for(var t=0;s>t;t++){for(var r=new Array(s),n=0;s>n;n++)r[n]=void 0;e.push(r)}};f(p),f(v);for(var u=0;u<a.length;u++){var g=l[a[u].source().id()],y=l[a[u].target().id()],m=r.apply(a[u],[a[u]]);c[g][y]>m&&(c[g][y]=m,p[g][y]=y,v[g][y]=a[u])}if(!i)for(var u=0;u<a.length;u++){var g=l[a[u].target().id()],y=l[a[u].source().id()],m=r.apply(a[u],[a[u]]);c[g][y]>m&&(c[g][y]=m,p[g][y]=y,v[g][y]=a[u])}for(var b=0;s>b;b++)for(var u=0;s>u;u++)for(var h=0;s>h;h++)c[u][b]+c[b][h]<c[u][h]&&(c[u][h]=c[u][b]+c[b][h],p[u][h]=p[u][b]);for(var x=[],u=0;s>u;u++)x.push(o[u].id());var w={distance:function(e,r){if(n.string(e))var i=t.filter(e)[0].id();else var i=e.id();if(n.string(r))var a=t.filter(r)[0].id();else var a=r.id();return c[l[i]][l[a]]},path:function(e,r){var i=function(e,r,n,i,a){if(e===r)return t.getElementById(i[e]);if(void 0===n[e][r])return void 0;for(var o=[t.getElementById(i[e])],s=e;e!==r;){s=e,e=n[e][r];var l=a[s][e];o.push(l),o.push(t.getElementById(i[e]))}return o};if(n.string(e))var a=t.filter(e)[0].id();else var a=e.id();if(n.string(r))var o=t.filter(r)[0].id();else var o=r.id();var s=i(l[a],l[o],p,x,v);return t.collection(s)}};return w}};t.exports=i},{"../../is":77}],9:[function(e,t,r){"use strict";var n=e("../../util"),i={};[e("./bfs-dfs"),e("./a-star"),e("./floyd-warshall"),e("./bellman-ford"),e("./kerger-stein"),e("./page-rank"),e("./degree-centrality"),e("./closeness-centrality"),e("./betweenness-centrality")].forEach(function(e){n.extend(i,e)}),t.exports=i},{"../../util":94,"./a-star":2,"./bellman-ford":3,"./betweenness-centrality":4,"./bfs-dfs":5,"./closeness-centrality":6,"./degree-centrality":7,"./floyd-warshall":8,"./kerger-stein":10,"./page-rank":11}],10:[function(e,t,r){"use strict";var n=e("../../util"),i={kargerStein:function(e){var t=this;e=e||{};var r=function(e,t,r){for(var n=r[e],i=n[1],a=n[2],o=t[i],s=t[a],l=r.filter(function(e){return t[e[1]]===o&&t[e[2]]===s?!1:t[e[1]]===s&&t[e[2]]===o?!1:!0}),u=0;u<l.length;u++){var c=l[u];c[1]===s?(l[u]=c.slice(0),l[u][1]=o):c[2]===s&&(l[u]=c.slice(0),l[u][2]=o)}for(var u=0;u<t.length;u++)t[u]===s&&(t[u]=o);return l},i=function(e,t,n,a){if(a>=n)return t;var o=Math.floor(Math.random()*t.length),s=r(o,e,t);return i(e,s,n-1,a)},a=this._private.cy,o=this.edges().stdFilter(function(e){return!e.isLoop()}),s=this.nodes(),l=s.length,u=o.length,c=Math.ceil(Math.pow(Math.log(l)/Math.LN2,2)),d=Math.floor(l/Math.sqrt(2));if(2>l)return void n.error("At least 2 nodes are required for Karger-Stein algorithm");for(var h={},p=0;l>p;p++)h[s[p].id()]=p;for(var v=[],p=0;u>p;p++){var f=o[p];v.push([p,h[f.source().id()],h[f.target().id()]])}for(var g,y=1/0,m=[],p=0;l>p;p++)m.push(p);for(var b=0;c>=b;b++){var x=m.slice(0),w=i(x,v,l,d),_=x.slice(0),E=i(x,w,d,2),D=i(_,w,d,2);E.length<=D.length&&E.length<y?(y=E.length,g=[E,x]):D.length<=E.length&&D.length<y&&(y=D.length,g=[D,_])}for(var S=g[0].map(function(e){return o[e[0]]}),k=[],T=[],P=g[1][0],p=0;p<g[1].length;p++){var C=g[1][p];C===P?k.push(s[p]):T.push(s[p])}var N={cut:t.spawn(a,S),partition1:t.spawn(k),partition2:t.spawn(T)};return N}};t.exports=i},{"../../util":94}],11:[function(e,t,r){"use strict";var n=e("../../is"),i={pageRank:function(e){e=e||{};var t=function(e){for(var t=e.length,r=0,n=0;t>n;n++)r+=e[n];for(var n=0;t>n;n++)e[n]=e[n]/r};if(null!=e&&null!=e.dampingFactor)var r=e.dampingFactor;else var r=.8;if(null!=e&&null!=e.precision)var i=e.precision;else var i=1e-6;if(null!=e&&null!=e.iterations)var a=e.iterations;else var a=200;if(null!=e&&null!=e.weight&&n.fn(e.weight))var o=e.weight;else var o=function(e){return 1};for(var s=this._private.cy,l=this.edges().stdFilter(function(e){return!e.isLoop()}),u=this.nodes(),c=u.length,d=l.length,h={},p=0;c>p;p++)h[u[p].id()]=p;for(var v=[],f=[],g=(1-r)/c,p=0;c>p;p++){for(var y=[],m=0;c>m;m++)y.push(0);v.push(y),f.push(0)}for(var p=0;d>p;p++){var b=l[p],x=h[b.source().id()],w=h[b.target().id()],_=o.apply(b,[b]);v[w][x]+=_,f[x]+=_}for(var E=1/c+g,m=0;c>m;m++)if(0===f[m])for(var p=0;c>p;p++)v[p][m]=E;else for(var p=0;c>p;p++)v[p][m]=v[p][m]/f[m]+g;for(var D,S=[],k=[],p=0;c>p;p++)S.push(1),k.push(0);for(var T=0;a>T;T++){for(var P=k.slice(0),p=0;c>p;p++)for(var m=0;c>m;m++)P[p]+=v[p][m]*S[m];t(P),D=S,S=P;for(var C=0,p=0;c>p;p++)C+=Math.pow(D[p]-S[p],2);if(i>C)break}var N={rank:function(e){if(n.string(e))var t=s.filter(e)[0].id();else var t=e.id();return S[h[t]]}};return N}};t.exports=i},{"../../is":77}],12:[function(e,t,r){"use strict";var n=e("../define"),i={animate:n.animate(),animation:n.animation(),animated:n.animated(),clearQueue:n.clearQueue(),delay:n.delay(),delayAnimation:n.delayAnimation(),stop:n.stop()};t.exports=i},{"../define":41}],13:[function(e,t,r){"use strict";var n=e("../util"),i={classes:function(e){e=e.match(/\S+/g)||[];for(var t=this,r=[],i={},a=0;a<e.length;a++){var o=e[a];i[o]=!0}for(var s=0;s<t.length;s++){for(var l=t[s],u=l._private,c=u.classes,d=!1,a=0;a<e.length;a++){var o=e[a],h=c[o];if(!h){d=!0;break}}if(!d)for(var p in c){var h=c[p],v=i[p];if(h&&!v){d=!0;break}}d&&(u.classes=n.copy(i),r.push(l))}return r.length>0&&this.spawn(r).updateStyle().trigger("class"),t},addClass:function(e){return this.toggleClass(e,!0)},hasClass:function(e){var t=this[0];return null!=t&&t._private.classes[e]?!0:!1},toggleClass:function(e,t){for(var r=e.match(/\S+/g)||[],n=this,i=[],a=0,o=n.length;o>a;a++)for(var s=n[a],l=!1,u=0;u<r.length;u++){var c=r[u],d=s._private.classes,h=d[c],p=t||void 0===t&&!h;p?(d[c]=!0,h||l||(i.push(s),l=!0)):(d[c]=!1,h&&!l&&(i.push(s),l=!0))}return i.length>0&&this.spawn(i).updateStyle().trigger("class"),n},removeClass:function(e){return this.toggleClass(e,!1)},flashClass:function(e,t){var r=this;if(null==t)t=250;else if(0===t)return r;return r.addClass(e),setTimeout(function(){r.removeClass(e)},t),r}};t.exports=i},{"../util":94}],14:[function(e,t,r){"use strict";var n={allAre:function(e){return this.filter(e).length===this.length},is:function(e){return this.filter(e).length>0},some:function(e,t){for(var r=0;r<this.length;r++){var n=t?e.apply(t,[this[r],r,this]):e(this[r],r,this);if(n)return!0}return!1},every:function(e,t){for(var r=0;r<this.length;r++){var n=t?e.apply(t,[this[r],r,this]):e(this[r],r,this);if(!n)return!1}return!0},same:function(e){return e=this.cy().collection(e),this.length!==e.length?!1:this.intersect(e).length===this.length},anySame:function(e){return e=this.cy().collection(e),this.intersect(e).length>0},allAreNeighbors:function(e){return e=this.cy().collection(e),this.neighborhood().intersect(e).length===e.length}};n.allAreNeighbours=n.allAreNeighbors,t.exports=n},{}],15:[function(e,t,r){"use strict";var n={parent:function(e){for(var t=[],r=this._private.cy,n=0;n<this.length;n++){var i=this[n],a=r.getElementById(i._private.data.parent);a.size()>0&&t.push(a)}return this.spawn(t,{unique:!0}).filter(e)},parents:function(e){for(var t=[],r=this.parent();r.nonempty();){for(var n=0;n<r.length;n++){var i=r[n];t.push(i)}r=r.parent()}return this.spawn(t,{unique:!0}).filter(e)},commonAncestors:function(e){for(var t,r=0;r<this.length;r++){var n=this[r],i=n.parents();t=t||i,t=t.intersect(i)}return t.filter(e)},orphans:function(e){return this.stdFilter(function(e){return e.isNode()&&e.parent().empty()}).filter(e)},nonorphans:function(e){return this.stdFilter(function(e){return e.isNode()&&e.parent().nonempty()}).filter(e)},children:function(e){for(var t=[],r=0;r<this.length;r++){var n=this[r];t=t.concat(n._private.children)}return this.spawn(t,{unique:!0}).filter(e)},siblings:function(e){return this.parent().children().not(this).filter(e)},isParent:function(){var e=this[0];return e?0!==e._private.children.length:void 0},isChild:function(){var e=this[0];return e?void 0!==e._private.data.parent&&0!==e.parent().length:void 0},descendants:function(e){function t(e){for(var n=0;n<e.length;n++){var i=e[n];r.push(i),i.children().nonempty()&&t(i.children())}}var r=[];return t(this.children()),this.spawn(r,{unique:!0}).filter(e)}};n.ancestors=n.parents,t.exports=n},{}],16:[function(e,t,r){"use strict";var n,i,a=e("../define");n=i={data:a.data({field:"data",bindingEvent:"data",allowBinding:!0,allowSetting:!0,settingEvent:"data",settingTriggersEvent:!0,triggerFnName:"trigger",allowGetting:!0,immutableKeys:{id:!0,source:!0,target:!0,parent:!0},updateStyle:!0}),removeData:a.removeData({field:"data",event:"data",triggerFnName:"trigger",triggerEvent:!0,immutableKeys:{id:!0,source:!0,target:!0,parent:!0},updateStyle:!0}),scratch:a.data({field:"scratch",bindingEvent:"scratch",allowBinding:!0,allowSetting:!0,settingEvent:"scratch",settingTriggersEvent:!0,triggerFnName:"trigger",allowGetting:!0,updateStyle:!0}),removeScratch:a.removeData({field:"scratch",event:"scratch",triggerFnName:"trigger",triggerEvent:!0,updateStyle:!0}),rscratch:a.data({field:"rscratch",allowBinding:!1,allowSetting:!0,settingTriggersEvent:!1,allowGetting:!0}),removeRscratch:a.removeData({field:"rscratch",triggerEvent:!1}),id:function(){var e=this[0];return e?e._private.data.id:void 0}},n.attr=n.data,n.removeAttr=n.removeData,t.exports=i},{"../define":41}],17:[function(e,t,r){"use strict";function n(e){return function(t){var r=this;if(void 0===t&&(t=!0),0!==r.length&&r.isNode()&&!r.removed()){for(var n=0,i=r[0],a=i._private.edges,o=0;o<a.length;o++){var s=a[o];(t||!s.isLoop())&&(n+=e(i,s))}return n}}}function i(e,t){return function(r){for(var n,i=this.nodes(),a=0;a<i.length;a++){var o=i[a],s=o[e](r);void 0===s||void 0!==n&&!t(s,n)||(n=s)}return n}}var a=e("../util"),o={};a.extend(o,{degree:n(function(e,t){return t.source().same(t.target())?2:1}),indegree:n(function(e,t){return t.target().same(e)?1:0}),outdegree:n(function(e,t){return t.source().same(e)?1:0})}),a.extend(o,{minDegree:i("degree",function(e,t){return t>e}),maxDegree:i("degree",function(e,t){return e>t}),minIndegree:i("indegree",function(e,t){return t>e}),maxIndegree:i("indegree",function(e,t){return e>t}),minOutdegree:i("outdegree",function(e,t){return t>e}),maxOutdegree:i("outdegree",function(e,t){return e>t})}),a.extend(o,{totalDegree:function(e){for(var t=0,r=this.nodes(),n=0;n<r.length;n++)t+=r[n].degree(e);return t}}),t.exports=o},{"../util":94}],18:[function(e,t,r){"use strict";var n,i,a=e("../define"),o=e("../is"),s=e("../util");n=i={position:a.data({field:"position",bindingEvent:"position",allowBinding:!0,allowSetting:!0,settingEvent:"position",settingTriggersEvent:!0,triggerFnName:"rtrigger",allowGetting:!0,validKeys:["x","y"],onSet:function(e){var t=e.updateCompoundBounds();t.rtrigger("position")},canSet:function(e){return!e.locked()&&!e.isParent()}}),silentPosition:a.data({field:"position",bindingEvent:"position",allowBinding:!1,allowSetting:!0,settingEvent:"position",settingTriggersEvent:!1,triggerFnName:"trigger",allowGetting:!0,validKeys:["x","y"],onSet:function(e){e.updateCompoundBounds()},canSet:function(e){return!e.locked()&&!e.isParent()}}),positions:function(e,t){if(o.plainObject(e))this.position(e);else if(o.fn(e)){for(var r=e,n=0;n<this.length;n++){var i=this[n],e=r.apply(i,[n,i]);if(e&&!i.locked()&&!i.isParent()){var a=i._private.position;a.x=e.x,a.y=e.y}}var s=this.updateCompoundBounds(),l=s.length>0?this.add(s):this;t?l.trigger("position"):l.rtrigger("position")}return this},silentPositions:function(e){return this.positions(e,!0)},renderedPosition:function(e,t){var r=this[0],n=this.cy(),i=n.zoom(),a=n.pan(),s=o.plainObject(e)?e:void 0,l=void 0!==s||void 0!==t&&o.string(e);if(r&&r.isNode()){if(!l){var u=r._private.position;return s={x:u.x*i+a.x,y:u.y*i+a.y},void 0===e?s:s[e]}for(var c=0;c<this.length;c++){var r=this[c];void 0!==t?r._private.position[e]=(t-a[e])/i:void 0!==s&&(r._private.position={x:(s.x-a.x)/i,y:(s.y-a.y)/i})}this.rtrigger("position")}else if(!l)return void 0;return this},relativePosition:function(e,t){var r=this[0],n=this.cy(),i=o.plainObject(e)?e:void 0,a=void 0!==i||void 0!==t&&o.string(e),s=n.hasCompoundNodes();if(r&&r.isNode()){if(!a){var l=r._private.position,u=s?r.parent():null,c=u&&u.length>0,d=c;c&&(u=u[0]);var h=d?u._private.position:{x:0,y:0};return i={x:l.x-h.x,y:l.y-h.y},void 0===e?i:i[e]}for(var p=0;p<this.length;p++){var r=this[p],u=s?r.parent():null,c=u&&u.length>0,d=c;c&&(u=u[0]);var h=d?u._private.position:{x:0,y:0};void 0!==t?r._private.position[e]=t+h[e]:void 0!==i&&(r._private.position={x:i.x+h.x,y:i.y+h.y})}this.rtrigger("position")}else if(!a)return void 0;return this},renderedBoundingBox:function(e){var t=this.boundingBox(e),r=this.cy(),n=r.zoom(),i=r.pan(),a=t.x1*n+i.x,o=t.x2*n+i.x,s=t.y1*n+i.y,l=t.y2*n+i.y;return{x1:a,x2:o,y1:s,y2:l,w:o-a,h:l-s}},updateCompoundBounds:function(){function e(e){var t=e.children(),n=e._private.style,i="include"===n["compound-sizing-wrt-labels"].value,a=t.boundingBox({includeLabels:i,includeEdges:!0}),o={top:n["padding-top"].pfValue,bottom:n["padding-bottom"].pfValue,left:n["padding-left"].pfValue,right:n["padding-right"].pfValue},s=e._private.position,l=!1;"auto"===n.width.value&&(e._private.autoWidth=a.w,s.x=(a.x1+a.x2-o.left+o.right)/2,l=!0),"auto"===n.height.value&&(e._private.autoHeight=a.h,s.y=(a.y1+a.y2-o.top+o.bottom)/2,l=!0),l&&r.push(e)}var t=this.cy();if(!t.styleEnabled()||!t.hasCompoundNodes())return t.collection();for(var r=[],n=this.parent();n.nonempty();){for(var i=0;i<n.length;i++){var a=n[i];e(a)}n=n.parent()}return this.spawn(r)},boundingBox:function(e){var t=this,r=t._private.cy,n=r._private,i=n.styleEnabled;e=e||s.staticEmptyObject();var a=void 0===e.includeNodes?!0:e.includeNodes,o=void 0===e.includeEdges?!0:e.includeEdges,l=void 0===e.includeLabels?!0:e.includeLabels;i&&n.renderer.recalculateRenderedStyle(this);for(var u=1/0,c=-(1/0),d=1/0,h=-(1/0),p=0;p<t.length;p++){var v,f,g,y,m,b,x=t[p],w=x._private,_=w.style,E=i?w.style.display.value:"element",D="nodes"===w.group,S=!1;if("none"!==E){if(D&&a){S=!0;var k=w.position;m=k.x,b=k.y;var T=x.outerWidth(),P=T/2,C=x.outerHeight(),N=C/2;v=m-P,f=m+P,g=b-N,y=b+N,u=u>v?v:u,c=f>c?f:c,d=d>g?g:d,h=y>h?y:h}else if(x.isEdge()&&o){S=!0;var M=w.source,B=M._private,z=B.position,O=w.target,I=O._private,L=I.position,A=w.rstyle||{},T=0,R=0;if(i&&(T=_.width.pfValue,R=T/2),v=z.x,f=L.x,g=z.y,y=L.y,v>f){var V=v;v=f,f=V}if(g>y){var V=g;g=y,y=V}if(v-=R,f+=R,g-=R,y+=R,u=u>v?v:u,c=f>c?f:c,d=d>g?g:d,h=y>h?y:h,i)for(var F=A.bezierPts||A.linePts||[],j=0;j<F.length;j++){var q=F[j];v=q.x-R,f=q.x+R,g=q.y-R,y=q.y+R,u=u>v?v:u,c=f>c?f:c,d=d>g?g:d,h=y>h?y:h}if(i&&"haystack"===_["curve-style"].strValue){var X=A.haystackPts;if(v=X[0].x,g=X[0].y,f=X[1].x,y=X[1].y,v>f){var V=v;v=f,f=V}if(g>y){var V=g;g=y,y=V}u=u>v?v:u,c=f>c?f:c,d=d>g?g:d,h=y>h?y:h}}if(i){var w=x._private,_=w.style,A=w.rstyle,Y=_.label.strValue,$=_["font-size"],H=_["text-halign"],W=_["text-valign"],Z=A.labelWidth,U=A.labelHeight,G=A.labelX,K=A.labelY,J=x.isEdge(),Q="autorotate"===_["edge-text-rotation"].strValue;if(l&&Y&&$&&null!=U&&null!=Z&&null!=G&&null!=K&&H&&W){var ee,te,re,ne,ie=U,ae=Z;if(J){if(ee=G-ae/2,te=G+ae/2,re=K-ie/2,ne=K+ie/2,Q){var oe=w.rscratch.labelAngle,se=Math.cos(oe),le=Math.sin(oe),ue=function(e,t){return e-=G,t-=K,{x:e*se-t*le+G,y:e*le+t*se+K}},ce=ue(ee,re),de=ue(ee,ne),he=ue(te,re),pe=ue(te,ne);ee=Math.min(ce.x,de.x,he.x,pe.x),te=Math.max(ce.x,de.x,he.x,pe.x),re=Math.min(ce.y,de.y,he.y,pe.y),ne=Math.max(ce.y,de.y,he.y,pe.y)}}else{switch(H.value){case"left":ee=G-ae,te=G;break;case"center":ee=G-ae/2,te=G+ae/2;break;case"right":ee=G,te=G+ae}switch(W.value){case"top":re=K-ie,ne=K;break;case"center":re=K-ie/2,ne=K+ie/2;break;case"bottom":re=K,ne=K+ie}}u=u>ee?ee:u,c=te>c?te:c,d=d>re?re:d,h=ne>h?ne:h}}}}var ve=function(e){return e===1/0||e===-(1/0)?0:e};return u=ve(u),c=ve(c),d=ve(d),h=ve(h),{x1:u,x2:c,y1:d,y2:h,w:c-u,h:h-d}}};var l=function(e){e.uppercaseName=s.capitalize(e.name),e.autoName="auto"+e.uppercaseName,e.labelName="label"+e.uppercaseName,e.outerName="outer"+e.uppercaseName,e.uppercaseOuterName=s.capitalize(e.outerName),n[e.name]=function(){var t=this[0],r=t._private,n=r.cy,i=n._private.styleEnabled;if(t){if(!i)return 1;var a=r.style[e.name];switch(a.strValue){case"auto":return r[e.autoName]||0;case"label":return r.rstyle[e.labelName]||0;default:return a.pfValue}}},n["outer"+e.uppercaseName]=function(){var t=this[0],r=t._private,n=r.cy,i=n._private.styleEnabled;if(t){if(i){var a=r.style,o=t[e.name](),s=a["border-width"].pfValue,l=a[e.paddings[0]].pfValue+a[e.paddings[1]].pfValue;return o+s+l}return 1}},n["rendered"+e.uppercaseName]=function(){var t=this[0];if(t){var r=t[e.name]();return r*this.cy().zoom()}},n["rendered"+e.uppercaseOuterName]=function(){var t=this[0];if(t){var r=t[e.outerName]();return r*this.cy().zoom()}}};l({name:"width",paddings:["padding-left","padding-right"]}),l({name:"height",paddings:["padding-top","padding-bottom"]}),n.modelPosition=n.point=n.position,n.modelPositions=n.points=n.positions,n.renderedPoint=n.renderedPosition,n.relativePoint=n.relativePosition,n.boundingbox=n.boundingBox,n.renderedBoundingbox=n.renderedBoundingBox,t.exports=i},{"../define":41,"../is":77,"../util":94}],19:[function(e,t,r){"use strict";var n=e("../util"),i=e("../is"),a=function(e,t,r){if(!(this instanceof a))return new a(e,t,r);var o=this;if(r=void 0===r||r?!0:!1,void 0===e||void 0===t||!i.core(e))return void n.error("An element must have a core reference and parameters set");var s=t.group;
+if(null==s&&(s=null!=t.data.source&&null!=t.data.target?"edges":"nodes"),"nodes"!==s&&"edges"!==s)return void n.error("An element must be of type `nodes` or `edges`; you specified `"+s+"`");if(this.length=1,this[0]=this,this._private={cy:e,single:!0,data:t.data||{},position:t.position||{},autoWidth:void 0,autoHeight:void 0,listeners:[],group:s,style:{},rstyle:{},styleCxts:[],removed:!0,selected:t.selected?!0:!1,selectable:void 0===t.selectable?!0:t.selectable?!0:!1,locked:t.locked?!0:!1,grabbed:!1,grabbable:void 0===t.grabbable?!0:t.grabbable?!0:!1,active:!1,classes:{},animation:{current:[],queue:[]},rscratch:{},scratch:t.scratch||{},edges:[],children:[]},t.renderedPosition){var l=t.renderedPosition,u=e.pan(),c=e.zoom();this._private.position={x:(l.x-u.x)/c,y:(l.y-u.y)/c}}if(i.string(t.classes))for(var d=t.classes.split(/\s+/),h=0,p=d.length;p>h;h++){var v=d[h];v&&""!==v&&(o._private.classes[v]=!0)}(t.style||t.css)&&e.style().applyBypass(this,t.style||t.css),(void 0===r||r)&&this.restore()};t.exports=a},{"../is":77,"../util":94}],20:[function(e,t,r){"use strict";var n=e("../define"),i={on:n.on(),one:n.on({unbindSelfOnTrigger:!0}),once:n.on({unbindAllBindersOnTrigger:!0}),off:n.off(),trigger:n.trigger(),rtrigger:function(e,t){return 0!==this.length?(this.cy().notify({type:e,collection:this}),this.trigger(e,t),this):void 0}};n.eventAliasesOn(i),t.exports=i},{"../define":41}],21:[function(e,t,r){"use strict";var n=e("../is"),i=e("../selector"),a={nodes:function(e){return this.filter(function(e,t){return t.isNode()}).filter(e)},edges:function(e){return this.filter(function(e,t){return t.isEdge()}).filter(e)},filter:function(e){if(n.fn(e)){for(var t=[],r=0;r<this.length;r++){var a=this[r];e.apply(a,[r,a])&&t.push(a)}return this.spawn(t)}return n.string(e)||n.elementOrCollection(e)?i(e).filter(this):void 0===e?this:this.spawn()},not:function(e){if(e){n.string(e)&&(e=this.filter(e));for(var t=[],r=0;r<this.length;r++){var i=this[r],a=e._private.ids[i.id()];a||t.push(i)}return this.spawn(t)}return this},absoluteComplement:function(){var e=this._private.cy;return e.elements().not(this)},intersect:function(e){if(n.string(e)){var t=e;return this.filter(t)}for(var r=[],i=this,a=e,o=this.length<e.length,s=o?a._private.ids:i._private.ids,l=o?i:a,u=0;u<l.length;u++){var c=l[u]._private.data.id,d=s[c];d&&r.push(d)}return this.spawn(r)},xor:function(e){var t=this._private.cy;n.string(e)&&(e=t.$(e));var r=[],i=this,a=e,o=function(e,t){for(var n=0;n<e.length;n++){var i=e[n],a=i._private.data.id,o=t._private.ids[a];o||r.push(i)}};return o(i,a),o(a,i),this.spawn(r)},diff:function(e){var t=this._private.cy;n.string(e)&&(e=t.$(e));var r=[],i=[],a=[],o=this,s=e,l=function(e,t,r){for(var n=0;n<e.length;n++){var i=e[n],o=i._private.data.id,s=t._private.ids[o];s?a.push(i):r.push(i)}};return l(o,s,r),l(s,o,i),{left:this.spawn(r,{unique:!0}),right:this.spawn(i,{unique:!0}),both:this.spawn(a,{unique:!0})}},add:function(e){var t=this._private.cy;if(!e)return this;if(n.string(e)){var r=e;e=t.elements(r)}for(var i=[],a=0;a<this.length;a++)i.push(this[a]);for(var a=0;a<e.length;a++){var o=!this._private.ids[e[a].id()];o&&i.push(e[a])}return this.spawn(i)},merge:function(e){var t=this._private,r=t.cy;if(!e)return this;if(n.string(e)){var i=e;e=r.elements(i)}for(var a=0;a<e.length;a++){var o=e[a],s=o.id(),l=!t.ids[s];if(l){var u=this.length++;this[u]=o,t.ids[s]=o,t.indexes[s]=u}}return this},unmergeOne:function(e){e=e[0];var t=this._private,r=e.id(),n=t.indexes[r];if(null==n)return this;this[n]=void 0,t.ids[r]=void 0,t.indexes[r]=void 0;var i=n===this.length-1;if(this.length>1&&!i){var a=this.length-1,o=this[a];this[a]=void 0,this[n]=o,t.indexes[o.id()]=n}return this.length--,this},unmerge:function(e){var t=this._private.cy;if(!e)return this;if(n.string(e)){var r=e;e=t.elements(r)}for(var i=0;i<e.length;i++)this.unmergeOne(e[i]);return this},map:function(e,t){for(var r=[],n=this,i=0;i<n.length;i++){var a=n[i],o=t?e.apply(t,[a,i,n]):e(a,i,n);r.push(o)}return r},stdFilter:function(e,t){for(var r=[],n=this,i=0;i<n.length;i++){var a=n[i],o=t?e.apply(t,[a,i,n]):e(a,i,n);o&&r.push(a)}return this.spawn(r)},max:function(e,t){for(var r,n=-(1/0),i=this,a=0;a<i.length;a++){var o=i[a],s=t?e.apply(t,[o,a,i]):e(o,a,i);s>n&&(n=s,r=o)}return{value:n,ele:r}},min:function(e,t){for(var r,n=1/0,i=this,a=0;a<i.length;a++){var o=i[a],s=t?e.apply(t,[o,a,i]):e(o,a,i);n>s&&(n=s,r=o)}return{value:n,ele:r}}},o=a;o.u=o["|"]=o["+"]=o.union=o.or=o.add,o["\\"]=o["!"]=o["-"]=o.difference=o.relativeComplement=o.subtract=o.not,o.n=o["&"]=o["."]=o.and=o.intersection=o.intersect,o["^"]=o["(+)"]=o["(-)"]=o.symmetricDifference=o.symdiff=o.xor,o.fnFilter=o.filterFn=o.stdFilter,o.complement=o.abscomp=o.absoluteComplement,t.exports=a},{"../is":77,"../selector":81}],22:[function(e,t,r){"use strict";var n={isNode:function(){return"nodes"===this.group()},isEdge:function(){return"edges"===this.group()},isLoop:function(){return this.isEdge()&&this.source().id()===this.target().id()},isSimple:function(){return this.isEdge()&&this.source().id()!==this.target().id()},group:function(){var e=this[0];return e?e._private.group:void 0}};t.exports=n},{}],23:[function(e,t,r){"use strict";var n=e("../util"),i=e("../is"),a=e("./element"),o={prefix:"ele",id:0,generate:function(e,t,r){var n=(i.element(t)?t._private:t,null!=r?r:this.prefix+this.id);if(e.getElementById(n).empty())this.id++;else for(;!e.getElementById(n).empty();)n=this.prefix+ ++this.id;return n}},s=function(e,t,r){if(!(this instanceof s))return new s(e,t,r);if(void 0===e||!i.core(e))return void n.error("A collection must have a reference to the core");var l={},u={},c=!1;if(t){if(t.length>0&&i.plainObject(t[0])&&!i.element(t[0])){c=!0;for(var d=[],h={},p=0,v=t.length;v>p;p++){var f=t[p];null==f.data&&(f.data={});var g=f.data;if(null==g.id)g.id=o.generate(e,f);else if(0!==e.getElementById(g.id).length||h[g.id])continue;var y=new a(e,f,!1);d.push(y),h[g.id]=!0}t=d}}else t=[];this.length=0;for(var p=0,v=t.length;v>p;p++){var m=t[p];if(m){var b=m._private.data.id;(!r||r.unique&&!l[b])&&(l[b]=m,u[b]=this.length,this[this.length]=m,this.length++)}}this._private={cy:e,ids:l,indexes:u},c&&this.restore()},l=a.prototype=s.prototype;l.instanceString=function(){return"collection"},l.spawn=function(e,t,r){return i.core(e)||(r=t,t=e,e=this.cy()),new s(e,t,r)},l.cy=function(){return this._private.cy},l.element=function(){return this[0]},l.collection=function(){return i.collection(this)?this:new s(this._private.cy,[this])},l.unique=function(){return new s(this._private.cy,this,{unique:!0})},l.getElementById=function(e){var t=this._private.cy,r=this._private.ids[e];return r?r:new s(t)},l.json=function(e){var t=this.element(),r=this.cy();if(null==t&&e)return this;if(null==t)return void 0;var a=t._private;if(i.plainObject(e)){r.startBatch(),e.data&&t.data(e.data),e.position&&t.position(e.position);var o=function(r,n,i){var o=e[r];null!=o&&o!==a[r]&&(o?t[n]():t[i]())};return o("removed","remove","restore"),o("selected","select","unselect"),o("selectable","selectify","unselectify"),o("locked","lock","unlock"),o("grabbable","grabify","ungrabify"),null!=e.classes&&t.classes(e.classes),r.endBatch(),this}if(void 0===e){var s={data:n.copy(a.data),position:n.copy(a.position),group:a.group,removed:a.removed,selected:a.selected,selectable:a.selectable,locked:a.locked,grabbable:a.grabbable,classes:null},l=[];for(var u in a.classes)a.classes[u]&&l.push(u);return s.classes=l.join(" "),s}},l.jsons=function(){for(var e=[],t=0;t<this.length;t++){var r=this[t],n=r.json();e.push(n)}return e},l.clone=function(){for(var e=this.cy(),t=[],r=0;r<this.length;r++){var n=this[r],i=n.json(),o=new a(e,i,!1);t.push(o)}return new s(e,t)},l.copy=l.clone,l.restore=function(e){var t=this,r=[],a=t.cy();void 0===e&&(e=!0);for(var l=[],u=[],c=[],d=0,h=0,p=0,v=t.length;v>p;p++){var f=t[p];f.isNode()?(u.push(f),d++):(c.push(f),h++)}l=u.concat(c);for(var p=0,v=l.length;v>p;p++){var f=l[p];if(f.removed()){var g=f._private,y=g.data;if(void 0===y.id)y.id=o.generate(a,f);else if(i.number(y.id))y.id=""+y.id;else{if(i.emptyString(y.id)||!i.string(y.id)){n.error("Can not create element with invalid string ID `"+y.id+"`");continue}if(0!==a.getElementById(y.id).length){n.error("Can not create second element with ID `"+y.id+"`");continue}}var m=y.id;if(f.isNode()){var b=f,x=g.position;null==x.x&&(x.x=0),null==x.y&&(x.y=0)}if(f.isEdge()){for(var w=f,_=["source","target"],E=_.length,D=!1,S=0;E>S;S++){var k=_[S],T=y[k];i.number(T)&&(T=y[k]=""+y[k]),null==T||""===T?(n.error("Can not create edge `"+m+"` with unspecified "+k),D=!0):a.getElementById(T).empty()&&(n.error("Can not create edge `"+m+"` with nonexistant "+k+" `"+T+"`"),D=!0)}if(D)continue;var P=a.getElementById(y.source),C=a.getElementById(y.target);P._private.edges.push(w),C._private.edges.push(w),w._private.source=P,w._private.target=C}g.ids={},g.ids[m]=f,g.removed=!1,a.addToPool(f),r.push(f)}}for(var p=0;d>p;p++){var b=l[p],y=b._private.data;i.number(y.parent)&&(y.parent=""+y.parent);var N=y.parent,M=null!=N;if(M){var B=a.getElementById(N);if(B.empty())y.parent=void 0;else{for(var z=!1,O=B;!O.empty();){if(b.same(O)){z=!0,y.parent=void 0;break}O=O.parent()}z||(B[0]._private.children.push(b),b._private.parent=B[0],a._private.hasCompoundNodes=!0)}}}if(r=new s(a,r),r.length>0){var I=r.add(r.connectedNodes()).add(r.parent());I.updateStyle(e),e?r.rtrigger("add"):r.trigger("add")}return t},l.removed=function(){var e=this[0];return e&&e._private.removed},l.inside=function(){var e=this[0];return e&&!e._private.removed},l.remove=function(e){function t(e){for(var t=e._private.edges,r=0;r<t.length;r++)n(t[r])}function r(e){for(var t=e._private.children,r=0;r<t.length;r++)n(t[r])}function n(e){var n=c[e.id()];n||(c[e.id()]=!0,e.isNode()?(u.push(e),t(e),r(e)):u.unshift(e))}function i(e,t){for(var r=e._private.edges,n=0;n<r.length;n++){var i=r[n];if(t===i){r.splice(n,1);break}}}function a(e,t){t=t[0],e=e[0];for(var r=e._private.children,n=0;n<r.length;n++)if(r[n][0]===t[0]){r.splice(n,1);break}}var o=this,l=[],u=[],c={},d=o._private.cy;void 0===e&&(e=!0);for(var h=0,p=o.length;p>h;h++){var v=o[h];n(v)}for(var h=0;h<u.length;h++){var v=u[h];if(v._private.removed=!0,d.removeFromPool(v),l.push(v),v.isEdge()){var f=v.source()[0],g=v.target()[0];i(f,v),i(g,v)}else{var y=v.parent();0!==y.length&&a(y,v)}}var m=d._private.elements;d._private.hasCompoundNodes=!1;for(var h=0;h<m.length;h++){var v=m[h];if(v.isParent()){d._private.hasCompoundNodes=!0;break}}var b=new s(this.cy(),l);b.size()>0&&(e&&this.cy().notify({type:"remove",collection:b}),b.trigger("remove"));for(var x={},h=0;h<u.length;h++){var v=u[h],w="nodes"===v._private.group,_=v._private.data.parent;if(w&&void 0!==_&&!x[_]){x[_]=!0;var y=d.getElementById(_);y&&0!==y.length&&!y._private.removed&&0===y.children().length&&y.updateStyle()}}return new s(d,l)},l.move=function(e){var t=this._private.cy;if(void 0!==e.source||void 0!==e.target){var r=e.source,n=e.target,i=t.getElementById(r).length>0,a=t.getElementById(n).length>0;if(i||a){var o=this.jsons();this.remove();for(var s=0;s<o.length;s++){var l=o[s];"edges"===l.group&&(i&&(l.data.source=r),a&&(l.data.target=n))}return t.add(o)}}else if(void 0!==e.parent){var u=e.parent,c=null===u||t.getElementById(u).length>0;if(c){var o=this.jsons(),d=this.descendants(),h=d.merge(d.add(this).connectedEdges());this.remove();for(var s=0;s<this.length;s++){var l=o[s];"nodes"===l.group&&(l.data.parent=null===u?void 0:u)}}return t.add(o).merge(h.restore())}return this},[e("./algorithms"),e("./animation"),e("./class"),e("./comparators"),e("./compounds"),e("./data"),e("./degree"),e("./dimensions"),e("./events"),e("./filter"),e("./group"),e("./index"),e("./iteration"),e("./layout"),e("./style"),e("./switch-functions"),e("./traversing")].forEach(function(e){n.extend(l,e)}),t.exports=s},{"../is":77,"../util":94,"./algorithms":9,"./animation":12,"./class":13,"./comparators":14,"./compounds":15,"./data":16,"./degree":17,"./dimensions":18,"./element":19,"./events":20,"./filter":21,"./group":22,"./index":23,"./iteration":24,"./layout":25,"./style":26,"./switch-functions":27,"./traversing":28}],24:[function(e,t,r){"use strict";var n=e("../is"),i=e("./zsort"),a={each:function(e){if(n.fn(e))for(var t=0;t<this.length;t++){var r=this[t],i=e.apply(r,[t,r]);if(i===!1)break}return this},forEach:function(e,t){if(n.fn(e))for(var r=0;r<this.length;r++){var i=this[r],a=t?e.apply(t,[i,r,this]):e(i,r,this);if(a===!1)break}return this},toArray:function(){for(var e=[],t=0;t<this.length;t++)e.push(this[t]);return e},slice:function(e,t){var r=[],n=this.length;null==t&&(t=n),null==e&&(e=0),0>e&&(e=n+e),0>t&&(t=n+t);for(var i=e;i>=0&&t>i&&n>i;i++)r.push(this[i]);return this.spawn(r)},size:function(){return this.length},eq:function(e){return this[e]||this.spawn()},first:function(){return this[0]||this.spawn()},last:function(){return this[this.length-1]||this.spawn()},empty:function(){return 0===this.length},nonempty:function(){return!this.empty()},sort:function(e){if(!n.fn(e))return this;var t=this.toArray().sort(e);return this.spawn(t)},sortByZIndex:function(){return this.sort(i)},zDepth:function(){var e=this[0];if(!e)return void 0;var t=e._private,r=t.group;if("nodes"===r){var n=t.data.parent?e.parents().size():0;return e.isParent()?n:Number.MAX_VALUE}var i=t.source,a=t.target,o=i.zDepth(),s=a.zDepth();return Math.max(o,s,0)}};t.exports=a},{"../is":77,"./zsort":29}],25:[function(e,t,r){"use strict";var n=e("../is"),i=e("../util"),a={layoutPositions:function(e,t,r){var i=this.nodes(),a=this.cy();if(e.trigger({type:"layoutstart",layout:e}),e.animations=[],t.animate){for(var o=0;o<i.length;o++){var s=i[o],l=o===i.length-1,u=r.call(s,o,s),c=s.position();n.number(c.x)&&n.number(c.y)||s.silentPosition({x:0,y:0});var d=s.animation({position:u,duration:t.animationDuration,easing:t.animationEasing,step:l?function(){t.fit&&a.fit(t.eles,t.padding)}:void 0,complete:l?function(){null!=t.zoom&&a.zoom(t.zoom),t.pan&&a.pan(t.pan),t.fit&&a.fit(t.eles,t.padding),e.one("layoutstop",t.stop),e.trigger({type:"layoutstop",layout:e})}:void 0});e.animations.push(d),d.play()}e.one("layoutready",t.ready),e.trigger({type:"layoutready",layout:e})}else i.positions(r),t.fit&&a.fit(t.eles,t.padding),null!=t.zoom&&a.zoom(t.zoom),t.pan&&a.pan(t.pan),e.one("layoutready",t.ready),e.trigger({type:"layoutready",layout:e}),e.one("layoutstop",t.stop),e.trigger({type:"layoutstop",layout:e});return this},layout:function(e){var t=this.cy();return t.layout(i.extend({},e,{eles:this})),this},makeLayout:function(e){var t=this.cy();return t.makeLayout(i.extend({},e,{eles:this}))}};a.createLayout=a.makeLayout,t.exports=a},{"../is":77,"../util":94}],26:[function(e,t,r){"use strict";var n=e("../is"),i={updateStyle:function(e){var t=this._private.cy;if(!t.styleEnabled())return this;if(t._private.batchingStyle){var r=t._private.batchStyleEles;return r.merge(this),this}var n=t.style();e=e||void 0===e?!0:!1,n.apply(this);var i=this.updateCompoundBounds(),a=i.length>0?this.add(i):this;return e?a.rtrigger("style"):a.trigger("style"),this},updateMappers:function(e){var t=this._private.cy,r=t.style();if(e=e||void 0===e?!0:!1,!t.styleEnabled())return this;r.updateMappers(this);var n=this.updateCompoundBounds(),i=n.length>0?this.add(n):this;return e?i.rtrigger("style"):i.trigger("style"),this},renderedCss:function(e){var t=this.cy();if(!t.styleEnabled())return this;var r=this[0];if(r){var n=r.cy().style().getRenderedStyle(r);return void 0===e?n:n[e]}},css:function(e,t){var r=this.cy();if(!r.styleEnabled())return this;var i=!1,a=r.style();if(n.plainObject(e)){var o=e;a.applyBypass(this,o,i);var s=this.updateCompoundBounds(),l=s.length>0?this.add(s):this;l.rtrigger("style")}else if(n.string(e)){if(void 0===t){var u=this[0];return u?a.getStylePropertyValue(u,e):void 0}a.applyBypass(this,e,t,i);var s=this.updateCompoundBounds(),l=s.length>0?this.add(s):this;l.rtrigger("style")}else if(void 0===e){var u=this[0];return u?a.getRawStyle(u):void 0}return this},removeCss:function(e){var t=this.cy();if(!t.styleEnabled())return this;var r=!1,n=t.style(),i=this;if(void 0===e)for(var a=0;a<i.length;a++){var o=i[a];n.removeAllBypasses(o,r)}else{e=e.split(/\s+/);for(var a=0;a<i.length;a++){var o=i[a];n.removeBypasses(o,e,r)}}var s=this.updateCompoundBounds(),l=s.length>0?this.add(s):this;return l.rtrigger("style"),this},show:function(){return this.css("display","element"),this},hide:function(){return this.css("display","none"),this},visible:function(){var e=this.cy();if(!e.styleEnabled())return!0;var t=this[0],r=e.hasCompoundNodes();if(t){var n=t._private.style;if("visible"!==n.visibility.value||"element"!==n.display.value)return!1;if("nodes"===t._private.group){if(!r)return!0;var i=t._private.data.parent?t.parents():null;if(i)for(var a=0;a<i.length;a++){var o=i[a],s=o._private.style,l=s.visibility.value,u=s.display.value;if("visible"!==l||"element"!==u)return!1}return!0}var c=t._private.source,d=t._private.target;return c.visible()&&d.visible()}},hidden:function(){var e=this[0];return e?!e.visible():void 0},effectiveOpacity:function(){var e=this.cy();if(!e.styleEnabled())return 1;var t=e.hasCompoundNodes(),r=this[0];if(r){var n=r._private,i=n.style.opacity.value;if(!t)return i;var a=n.data.parent?r.parents():null;if(a)for(var o=0;o<a.length;o++){var s=a[o],l=s._private.style.opacity.value;i=l*i}return i}},transparent:function(){var e=this.cy();if(!e.styleEnabled())return!1;var t=this[0],r=t.cy().hasCompoundNodes();return t?r?0===t.effectiveOpacity():0===t._private.style.opacity.value:void 0},isFullAutoParent:function(){var e=this.cy();if(!e.styleEnabled())return!1;var t=this[0];if(t){var r="auto"===t._private.style.width.value,n="auto"===t._private.style.height.value;return t.isParent()&&r&&n}},backgrounding:function(){var e=this.cy();if(!e.styleEnabled())return!1;var t=this[0];return t._private.backgrounding?!0:!1}};i.bypass=i.style=i.css,i.renderedStyle=i.renderedCss,i.removeBypass=i.removeStyle=i.removeCss,t.exports=i},{"../is":77}],27:[function(e,t,r){"use strict";function n(e){return function(){var t=arguments,r=[];if(2===t.length){var n=t[0],i=t[1];this.bind(e.event,n,i)}else if(1===t.length){var i=t[0];this.bind(e.event,i)}else if(0===t.length){for(var a=0;a<this.length;a++){var o=this[a],s=!e.ableField||o._private[e.ableField],l=o._private[e.field]!=e.value;if(e.overrideAble){var u=e.overrideAble(o);if(void 0!==u&&(s=u,!u))return this}s&&(o._private[e.field]=e.value,l&&r.push(o))}var c=this.spawn(r);c.updateStyle(),c.trigger(e.event)}return this}}function i(e){a[e.field]=function(){var t=this[0];if(t){if(e.overrideField){var r=e.overrideField(t);if(void 0!==r)return r}return t._private[e.field]}},a[e.on]=n({event:e.on,field:e.field,ableField:e.ableField,overrideAble:e.overrideAble,value:!0}),a[e.off]=n({event:e.off,field:e.field,ableField:e.ableField,overrideAble:e.overrideAble,value:!1})}var a={};i({field:"locked",overrideField:function(e){return e.cy().autolock()?!0:void 0},on:"lock",off:"unlock"}),i({field:"grabbable",overrideField:function(e){return e.cy().autoungrabify()?!1:void 0},on:"grabify",off:"ungrabify"}),i({field:"selected",ableField:"selectable",overrideAble:function(e){return e.cy().autounselectify()?!1:void 0},on:"select",off:"unselect"}),i({field:"selectable",overrideField:function(e){return e.cy().autounselectify()?!1:void 0},on:"selectify",off:"unselectify"}),a.deselect=a.unselect,a.grabbed=function(){var e=this[0];return e?e._private.grabbed:void 0},i({field:"active",on:"activate",off:"unactivate"}),a.inactive=function(){var e=this[0];return e?!e._private.active:void 0},t.exports=a},{}],28:[function(e,t,r){"use strict";function n(e){return function(t){for(var r=[],n=0;n<this.length;n++){var i=this[n],a=i._private[e.attr];a&&r.push(a)}return this.spawn(r,{unique:!0}).filter(t)}}function i(e){return function(t){var r=[],n=this._private.cy,i=e||{};s.string(t)&&(t=n.$(t));for(var a=this._private.ids,o=t._private.ids,l=0;l<t.length;l++)for(var u=t[l]._private.edges,c=0;c<u.length;c++){var d=u[c],h=d._private.data,p=a[h.source]&&o[h.target],v=o[h.source]&&a[h.target],f=p||v;if(f){if(i.thisIs){if("source"===i.thisIs&&!p)continue;if("target"===i.thisIs&&!v)continue}r.push(d)}}return this.spawn(r,{unique:!0})}}function a(e){var t={codirected:!1};return e=o.extend({},t,e),function(t){for(var r=[],n=this.edges(),i=e,a=0;a<n.length;a++)for(var o=n[a],s=o.source()[0],l=s.id(),u=o.target()[0],c=u.id(),d=s._private.edges,h=0;h<d.length;h++){var p=d[h],v=p._private.data,f=v.target,g=v.source,y=f===c&&g===l,m=l===f&&c===g;(i.codirected&&y||!i.codirected&&(y||m))&&r.push(p)}return this.spawn(r,{unique:!0}).filter(t)}}var o=e("../util"),s=e("../is"),l={};o.extend(l,{roots:function(e){for(var t=this,r=[],n=0;n<t.length;n++){var i=t[n];if(i.isNode()){var a=i.connectedEdges(function(){return this.data("target")===i.id()&&this.data("source")!==i.id()}).length>0;a||r.push(i)}}return this.spawn(r,{unique:!0}).filter(e)},leaves:function(e){for(var t=this,r=[],n=0;n<t.length;n++){var i=t[n];if(i.isNode()){var a=i.connectedEdges(function(){return this.data("source")===i.id()&&this.data("target")!==i.id()}).length>0;a||r.push(i)}}return this.spawn(r,{unique:!0}).filter(e)},outgoers:function(e){for(var t=this,r=[],n=0;n<t.length;n++){var i=t[n],a=i.id();if(i.isNode())for(var o=i._private.edges,s=0;s<o.length;s++){var l=o[s],u=l._private.data.source,c=l._private.data.target;u===a&&c!==a&&(r.push(l),r.push(l.target()[0]))}}return this.spawn(r,{unique:!0}).filter(e)},successors:function(e){for(var t=this,r=[],n={};;){var i=t.outgoers();if(0===i.length)break;for(var a=!1,o=0;o<i.length;o++){var s=i[o],l=s.id();n[l]||(n[l]=!0,r.push(s),a=!0)}if(!a)break;t=i}return this.spawn(r,{unique:!0}).filter(e)},incomers:function(e){for(var t=this,r=[],n=0;n<t.length;n++){var i=t[n],a=i.id();if(i.isNode())for(var o=i._private.edges,s=0;s<o.length;s++){var l=o[s],u=l._private.data.source,c=l._private.data.target;c===a&&u!==a&&(r.push(l),r.push(l.source()[0]))}}return this.spawn(r,{unique:!0}).filter(e)},predecessors:function(e){for(var t=this,r=[],n={};;){var i=t.incomers();if(0===i.length)break;for(var a=!1,o=0;o<i.length;o++){var s=i[o],l=s.id();n[l]||(n[l]=!0,r.push(s),a=!0)}if(!a)break;t=i}return this.spawn(r,{unique:!0}).filter(e)}}),o.extend(l,{neighborhood:function(e){for(var t=[],r=this.nodes(),n=0;n<r.length;n++)for(var i=r[n],a=i.connectedEdges(),o=0;o<a.length;o++){var s=a[o],l=s._private.source,u=s._private.target,c=i===l?u:l;c.length>0&&t.push(c[0]),t.push(s[0])}return this.spawn(t,{unique:!0}).filter(e)},closedNeighborhood:function(e){return this.neighborhood().add(this).filter(e)},openNeighborhood:function(e){return this.neighborhood(e)}}),l.neighbourhood=l.neighborhood,l.closedNeighbourhood=l.closedNeighborhood,l.openNeighbourhood=l.openNeighborhood,o.extend(l,{source:function(e){var t,r=this[0];return r&&(t=r._private.source),t&&e?t.filter(e):t},target:function(e){var t,r=this[0];return r&&(t=r._private.target),t&&e?t.filter(e):t},sources:n({attr:"source"}),targets:n({attr:"target"})}),o.extend(l,{edgesWith:i(),edgesTo:i({thisIs:"source"})}),o.extend(l,{connectedEdges:function(e){for(var t=[],r=this,n=0;n<r.length;n++){var i=r[n];if(i.isNode())for(var a=i._private.edges,o=0;o<a.length;o++){var s=a[o];t.push(s)}}return this.spawn(t,{unique:!0}).filter(e)},connectedNodes:function(e){for(var t=[],r=this,n=0;n<r.length;n++){var i=r[n];i.isEdge()&&(t.push(i.source()[0]),t.push(i.target()[0]))}return this.spawn(t,{unique:!0}).filter(e)},parallelEdges:a(),codirectedEdges:a({codirected:!0})}),o.extend(l,{components:function(){var e=this.cy(),t=e.collection(),r=this.nodes(),n=[],i=function(e,n){t.merge(e),r.unmerge(e),n.merge(e)};do{var a=e.collection();n.push(a);var o=r[0];i(o,a),this.bfs({directed:!1,roots:o,visit:function(e,t,r,n,o){i(r,a)}})}while(r.length>0);return n.map(function(e){return e.closedNeighborhood()})}}),t.exports=l},{"../is":77,"../util":94}],29:[function(e,t,r){"use strict";var n=function(e,t){var r=e.cy(),n=e._private,i=t._private,a=n.style["z-index"].value-i.style["z-index"].value,o=0,s=0,l=r.hasCompoundNodes(),u="nodes"===n.group,c="edges"===n.group,d="nodes"===i.group,h="edges"===i.group;l&&(o=e.zDepth(),s=t.zDepth());var p=o-s,v=0===p;return v?u&&h?1:c&&d?-1:0===a?n.index-i.index:a:p};t.exports=n},{}],30:[function(e,t,r){"use strict";var n=e("../is"),i=e("../util"),a=e("../collection"),o=e("../collection/element"),s=e("../window"),l=(s?s.document:null,e("../extensions/renderer/null"),{add:function(e){var t,r=this;if(n.elementOrCollection(e)){var s=e;if(s._private.cy===r)t=s.restore();else{for(var l=[],u=0;u<s.length;u++){var c=s[u];l.push(c.json())}t=new a(r,l)}}else if(n.array(e)){var l=e;t=new a(r,l)}else if(n.plainObject(e)&&(n.array(e.nodes)||n.array(e.edges))){for(var d=e,l=[],h=["nodes","edges"],u=0,p=h.length;p>u;u++){var v=h[u],f=d[v];if(n.array(f))for(var g=0,y=f.length;y>g;g++){var m=i.extend({group:v},f[g]);l.push(m)}}t=new a(r,l)}else{var m=e;t=new o(r,m).collection()}return t},remove:function(e){if(n.elementOrCollection(e))e=e;else if(n.string(e)){var t=e;e=this.$(t)}return e.remove()},load:function(e,t,r){var a=this;a.notifications(!1);var o=a.elements();o.length>0&&o.remove(),null!=e&&(n.plainObject(e)||n.array(e))&&a.add(e),a.one("layoutready",function(e){a.notifications(!0),a.trigger(e),a.notify({type:"load",collection:a.elements()}),a.one("load",t),a.trigger("load")}).one("layoutstop",function(){a.one("done",r),a.trigger("done")});var s=i.extend({},a._private.options.layout);return s.eles=a.$(),a.layout(s),this}});t.exports=l},{"../collection":23,"../collection/element":19,"../extensions/renderer/null":73,"../is":77,"../util":94,"../window":100}],31:[function(e,t,r){"use strict";var n=e("../define"),i=e("../util"),a=e("../is"),o={animate:n.animate(),animation:n.animation(),animated:n.animated(),clearQueue:n.clearQueue(),delay:n.delay(),delayAnimation:n.delayAnimation(),stop:n.stop(),addToAnimationPool:function(e){var t=this;t.styleEnabled()&&t._private.aniEles.merge(e)},stopAnimationLoop:function(){this._private.animationsRunning=!1},startAnimationLoop:function(){function e(){c._private.animationsRunning&&i.requestAnimationFrame(function(r){t(r),e()})}function t(e){function t(t,i){var o=t._private,s=o.animation.current,l=o.animation.queue,u=!1;if(0===s.length){var c=l.shift();c&&s.push(c)}for(var d=function(e){for(var t=e.length-1;t>=0;t--){var r=e[t];r()}e.splice(0,e.length)},h=s.length-1;h>=0;h--){var p=s[h],v=p._private;v.stopped?(s.splice(h,1),v.hooked=!1,v.playing=!1,v.started=!1,d(v.frames)):(v.playing||v.applying)&&(v.playing&&v.applying&&(v.applying=!1),v.started||r(t,p,e),n(t,p,e,i),v.applying&&(v.applying=!1),d(v.frames),p.completed()&&(s.splice(h,1),v.hooked=!1,v.playing=!1,v.started=!1,d(v.completes)),u=!0)}return i||0!==s.length||0!==l.length||a.push(t),u}for(var i=c._private.aniEles,a=[],o=!1,s=0;s<i.length;s++){var l=i[s],u=t(l);o=o||u}var d=t(c,!0);if(o||d){var h;if(i.length>0){var p=i.updateCompoundBounds();h=p.length>0?i.add(p):i}c.notify({type:"draw",collection:h})}i.unmerge(a)}function r(e,t,r){var n=a.core(e),i=!n,o=e,s=c._private.style,l=t._private;if(i){var u=o._private.position;l.startPosition=l.startPosition||{x:u.x,y:u.y},l.startStyle=l.startStyle||s.getValueStyle(o)}if(n){var d=c._private.pan;l.startPan=l.startPan||{x:d.x,y:d.y},l.startZoom=null!=l.startZoom?l.startZoom:c._private.zoom}l.started=!0,l.startTime=r-l.progress*l.duration}function n(e,t,r,n){var i=c._private.style,s=!n,l=e._private,d=t._private,p=d.easing,v=d.startTime;if(!d.easingImpl)if(null==p)d.easingImpl=h.linear;else{var f;if(a.string(p)){var g=i.parse("transition-timing-function",p);f=g.value}else f=p;var y,m;a.string(f)?(y=f,m=[]):(y=f[1],m=f.slice(2).map(function(e){return+e})),m.length>0?("spring"===y&&m.push(d.duration),d.easingImpl=h[y].apply(null,m)):d.easingImpl=h[y]}var b,x=d.easingImpl;if(b=0===d.duration?1:(r-v)/d.duration,d.applying&&(b=d.progress),0>b?b=0:b>1&&(b=1),null==d.delay){var w=d.startPosition,_=d.position,E=l.position;_&&s&&(o(w.x,_.x)&&(E.x=u(w.x,_.x,b,x)),o(w.y,_.y)&&(E.y=u(w.y,_.y,b,x)));var D=d.startPan,S=d.pan,k=l.pan,T=null!=S&&n;T&&(o(D.x,S.x)&&(k.x=u(D.x,S.x,b,x)),o(D.y,S.y)&&(k.y=u(D.y,S.y,b,x)),e.trigger("pan"));var P=d.startZoom,C=d.zoom,N=null!=C&&n;N&&(o(P,C)&&(l.zoom=u(P,C,b,x)),e.trigger("zoom")),(T||N)&&e.trigger("viewport");var M=d.style;if(M&&s)for(var B=0;B<M.length;B++){var z=M[B],y=z.name,O=z,I=d.startStyle[y],L=u(I,O,b,x);i.overrideBypass(e,y,L)}}return a.fn(d.step)&&d.step.apply(e,[r]),d.progress=b,b}function o(e,t){return null==e||null==t?!1:a.number(e)&&a.number(t)?!0:e&&t?!0:!1}function s(e,t,r){var n=1-r,i=r*r;return 3*n*n*r*e+3*n*i*t+i*r}function l(e,t){return function(r,n,i){return r+(n-r)*s(e,t,i)}}function u(e,t,r,n){0>r?r=0:r>1&&(r=1);var i,o;if(i=null!=e.pfValue||null!=e.value?null!=e.pfValue?e.pfValue:e.value:e,o=null!=t.pfValue||null!=t.value?null!=t.pfValue?t.pfValue:t.value:t,a.number(i)&&a.number(o))return n(i,o,r);if(a.array(i)&&a.array(o)){for(var s=[],l=0;l<o.length;l++){var u=i[l],c=o[l];if(null!=u&&null!=c){var d=n(u,c,r);e.roundValue&&(d=Math.round(d)),s.push(d)}else s.push(c)}return s}return void 0}var c=this;if(c._private.animationsRunning=!0,c.styleEnabled()){e();var d=function(){function e(e){return-e.tension*e.x-e.friction*e.v}function t(t,r,n){var i={x:t.x+n.dx*r,v:t.v+n.dv*r,tension:t.tension,friction:t.friction};return{dx:i.v,dv:e(i)}}function r(r,n){var i={dx:r.v,dv:e(r)},a=t(r,.5*n,i),o=t(r,.5*n,a),s=t(r,n,o),l=1/6*(i.dx+2*(a.dx+o.dx)+s.dx),u=1/6*(i.dv+2*(a.dv+o.dv)+s.dv);return r.x=r.x+l*n,r.v=r.v+u*n,r}return function n(e,t,i){var a,o,s,l={x:-1,v:0,tension:null,friction:null},u=[0],c=0,d=1e-4,h=.016;for(e=parseFloat(e)||500,t=parseFloat(t)||20,i=i||null,l.tension=e,l.friction=t,a=null!==i,a?(c=n(e,t),o=c/i*h):o=h;;)if(s=r(s||l,o),u.push(1+s.x),c+=16,!(Math.abs(s.x)>d&&Math.abs(s.v)>d))break;return a?function(e){return u[e*(u.length-1)|0]}:c}}(),h={linear:function(e,t,r){return e+(t-e)*r},ease:l(.25,.1,.25,1),"ease-in":l(.42,0,1,1),"ease-out":l(0,0,.58,1),"ease-in-out":l(.42,0,.58,1),"ease-in-sine":l(.47,0,.745,.715),"ease-out-sine":l(.39,.575,.565,1),"ease-in-out-sine":l(.445,.05,.55,.95),"ease-in-quad":l(.55,.085,.68,.53),"ease-out-quad":l(.25,.46,.45,.94),"ease-in-out-quad":l(.455,.03,.515,.955),"ease-in-cubic":l(.55,.055,.675,.19),"ease-out-cubic":l(.215,.61,.355,1),"ease-in-out-cubic":l(.645,.045,.355,1),"ease-in-quart":l(.895,.03,.685,.22),"ease-out-quart":l(.165,.84,.44,1),"ease-in-out-quart":l(.77,0,.175,1),"ease-in-quint":l(.755,.05,.855,.06),"ease-out-quint":l(.23,1,.32,1),"ease-in-out-quint":l(.86,0,.07,1),"ease-in-expo":l(.95,.05,.795,.035),"ease-out-expo":l(.19,1,.22,1),"ease-in-out-expo":l(1,0,0,1),"ease-in-circ":l(.6,.04,.98,.335),"ease-out-circ":l(.075,.82,.165,1),"ease-in-out-circ":l(.785,.135,.15,.86),spring:function(e,t,r){var n=d(e,t,r);return function(e,t,r){return e+(t-e)*n(r)}},"cubic-bezier":function(e,t,r,n){return l(e,t,r,n)}}}}};t.exports=o},{"../define":41,"../is":77,"../util":94}],32:[function(e,t,r){"use strict";var n=e("../define"),i={on:n.on(),one:n.on({unbindSelfOnTrigger:!0}),once:n.on({unbindAllBindersOnTrigger:!0}),off:n.off(),trigger:n.trigger()};n.eventAliasesOn(i),t.exports=i},{"../define":41}],33:[function(e,t,r){"use strict";var n={png:function(e){var t=this._private.renderer;return e=e||{},t.png(e)},jpg:function(e){var t=this._private.renderer;return e=e||{},e.bg=e.bg||"#fff",t.jpg(e)}};n.jpeg=n.jpg,t.exports=n},{}],34:[function(e,t,r){"use strict";var n=e("../window"),i=e("../util"),a=e("../collection"),o=e("../is"),s=e("../promise"),l=e("../define"),u=function(e){if(!(this instanceof u))return new u(e);var t=this;e=i.extend({},e);var r=e.container;r&&!o.htmlElement(r)&&o.htmlElement(r[0])&&(r=r[0]);var l=r?r._cyreg:null;l=l||{},l&&l.cy&&(l.cy.destroy(),l={});var c=l.readies=l.readies||[];r&&(r._cyreg=l),l.cy=t;var d=void 0!==n&&void 0!==r&&!e.headless,h=e;h.layout=i.extend({name:d?"grid":"null"},h.layout),h.renderer=i.extend({
+name:d?"canvas":"null"},h.renderer);var p=function(e,t,r){return void 0!==t?t:void 0!==r?r:e},v=this._private={container:r,ready:!1,initrender:!1,options:h,elements:[],id2index:{},listeners:[],onRenders:[],aniEles:a(this),scratch:{},layout:null,renderer:null,notificationsEnabled:!0,minZoom:1e-50,maxZoom:1e50,zoomingEnabled:p(!0,h.zoomingEnabled),userZoomingEnabled:p(!0,h.userZoomingEnabled),panningEnabled:p(!0,h.panningEnabled),userPanningEnabled:p(!0,h.userPanningEnabled),boxSelectionEnabled:p(!0,h.boxSelectionEnabled),autolock:p(!1,h.autolock,h.autolockNodes),autoungrabify:p(!1,h.autoungrabify,h.autoungrabifyNodes),autounselectify:p(!1,h.autounselectify),styleEnabled:void 0===h.styleEnabled?d:h.styleEnabled,zoom:o.number(h.zoom)?h.zoom:1,pan:{x:o.plainObject(h.pan)&&o.number(h.pan.x)?h.pan.x:0,y:o.plainObject(h.pan)&&o.number(h.pan.y)?h.pan.y:0},animation:{current:[],queue:[]},hasCompoundNodes:!1,deferredExecQueue:[]},f=h.selectionType;void 0===f||"additive"!==f&&"single"!==f?v.selectionType="single":v.selectionType=f,o.number(h.minZoom)&&o.number(h.maxZoom)&&h.minZoom<h.maxZoom?(v.minZoom=h.minZoom,v.maxZoom=h.maxZoom):o.number(h.minZoom)&&void 0===h.maxZoom?v.minZoom=h.minZoom:o.number(h.maxZoom)&&void 0===h.minZoom&&(v.maxZoom=h.maxZoom);var g=function(e){for(var t=!1,r=0;r<y.length;r++){var n=y[r];if(o.promise(n)){t=!0;break}}return t?s.all(y).then(e):void e(y)};t.initRenderer(i.extend({hideEdgesOnViewport:h.hideEdgesOnViewport,hideLabelsOnViewport:h.hideLabelsOnViewport,textureOnViewport:h.textureOnViewport,wheelSensitivity:o.number(h.wheelSensitivity)&&h.wheelSensitivity>0?h.wheelSensitivity:1,motionBlur:void 0===h.motionBlur?!0:h.motionBlur,motionBlurOpacity:void 0===h.motionBlurOpacity?.05:h.motionBlurOpacity,pixelRatio:o.number(h.pixelRatio)&&h.pixelRatio>0?h.pixelRatio:"auto"===h.pixelRatio?void 0:1,desktopTapThreshold:void 0===h.desktopTapThreshold?4:h.desktopTapThreshold,touchTapThreshold:void 0===h.touchTapThreshold?8:h.touchTapThreshold},h.renderer));var y=[h.style,h.elements];g(function(e){var r=e[0],n=e[1];v.styleEnabled&&t.setStyle(r),h.initrender&&(t.on("initrender",h.initrender),t.on("initrender",function(){v.initrender=!0})),t.load(n,function(){t.startAnimationLoop(),v.ready=!0,o.fn(h.ready)&&t.on("ready",h.ready);for(var e=0;e<c.length;e++){var r=c[e];t.on("ready",r)}l&&(l.readies=[]),t.trigger("ready")},h.done)})},c=u.prototype;i.extend(c,{instanceString:function(){return"core"},isReady:function(){return this._private.ready},ready:function(e){return this.isReady()?this.trigger("ready",[],e):this.on("ready",e),this},initrender:function(){return this._private.initrender},destroy:function(){var e=this;e.stopAnimationLoop(),e.notify({type:"destroy"});var t=e.container();if(t)for(t._cyreg=null;t.childNodes.length>0;)t.removeChild(t.childNodes[0]);return e},getElementById:function(e){var t=this._private.id2index[e];return void 0!==t?this._private.elements[t]:a(this)},selectionType:function(){return this._private.selectionType},hasCompoundNodes:function(){return this._private.hasCompoundNodes},styleEnabled:function(){return this._private.styleEnabled},addToPool:function(e){for(var t=this._private.elements,r=this._private.id2index,n=0;n<e.length;n++){var i=e[n],a=i._private.data.id,o=r[a],s=void 0!==o;s||(o=t.length,t.push(i),r[a]=o,i._private.index=o)}return this},removeFromPool:function(e){for(var t=this._private.elements,r=this._private.id2index,n=0;n<e.length;n++){var i=e[n],a=i._private.data.id,o=r[a],s=void 0!==o;if(s){this._private.id2index[a]=void 0,t.splice(o,1);for(var l=o;l<t.length;l++){var u=t[l]._private.data.id;r[u]--,t[l]._private.index--}}}},container:function(){return this._private.container},options:function(){return i.copy(this._private.options)},json:function(e){var t=this,r=t._private;if(o.plainObject(e)){if(t.startBatch(),e.elements){var n={},a=function(e,r){for(var a=0;a<e.length;a++){var o=e[a],s=o.data.id,l=t.getElementById(s);n[s]=!0,0!==l.length?l.json(o):r?t.add(i.extend({group:r},o)):t.add(o)}};if(o.array(e.elements))a(e.elements);else for(var s=["nodes","edges"],l=0;l<s.length;l++){var u=s[l],c=e.elements[u];o.array(c)&&a(c,u)}t.elements().stdFilter(function(e){return!n[e.id()]}).remove()}e.style&&t.style(e.style),null!=e.zoom&&e.zoom!==r.zoom&&t.zoom(e.zoom),e.pan&&(e.pan.x!==r.pan.x||e.pan.y!==r.pan.y)&&t.pan(e.pan);for(var d=["minZoom","maxZoom","zoomingEnabled","userZoomingEnabled","panningEnabled","userPanningEnabled","boxSelectionEnabled","autolock","autoungrabify","autounselectify"],l=0;l<d.length;l++){var h=d[l];null!=e[h]&&t[h](e[h])}return t.endBatch(),this}if(void 0===e){var p={};return p.elements={},t.elements().each(function(e,t){var r=t.group();p.elements[r]||(p.elements[r]=[]),p.elements[r].push(t.json())}),this._private.styleEnabled&&(p.style=t.style().json()),p.zoomingEnabled=t._private.zoomingEnabled,p.userZoomingEnabled=t._private.userZoomingEnabled,p.zoom=t._private.zoom,p.minZoom=t._private.minZoom,p.maxZoom=t._private.maxZoom,p.panningEnabled=t._private.panningEnabled,p.userPanningEnabled=t._private.userPanningEnabled,p.pan=i.copy(t._private.pan),p.boxSelectionEnabled=t._private.boxSelectionEnabled,p.renderer=i.copy(t._private.options.renderer),p.hideEdgesOnViewport=t._private.options.hideEdgesOnViewport,p.hideLabelsOnViewport=t._private.options.hideLabelsOnViewport,p.textureOnViewport=t._private.options.textureOnViewport,p.wheelSensitivity=t._private.options.wheelSensitivity,p.motionBlur=t._private.options.motionBlur,p}},scratch:l.data({field:"scratch",bindingEvent:"scratch",allowBinding:!0,allowSetting:!0,settingEvent:"scratch",settingTriggersEvent:!0,triggerFnName:"trigger",allowGetting:!0}),removeScratch:l.removeData({field:"scratch",event:"scratch",triggerFnName:"trigger",triggerEvent:!0})}),[e("./add-remove"),e("./animation"),e("./events"),e("./export"),e("./layout"),e("./notification"),e("./renderer"),e("./search"),e("./style"),e("./viewport")].forEach(function(e){i.extend(c,e)}),t.exports=u},{"../collection":23,"../define":41,"../is":77,"../promise":80,"../util":94,"../window":100,"./add-remove":30,"./animation":31,"./events":32,"./export":33,"./layout":35,"./notification":36,"./renderer":37,"./search":38,"./style":39,"./viewport":40}],35:[function(e,t,r){"use strict";var n=e("../util"),i=e("../is"),a={layout:function(e){var t=this._private.prevLayout=null==e?this._private.prevLayout:this.makeLayout(e);return t.run(),this},makeLayout:function(e){var t=this;if(null==e)return void n.error("Layout options must be specified to make a layout");if(null==e.name)return void n.error("A `name` must be specified to make a layout");var r=e.name,a=t.extension("layout",r);if(null==a)return void n.error("Can not apply layout: No such layout `"+r+"` found; did you include its JS file?");var o;o=i.string(e.eles)?t.$(e.eles):null!=e.eles?e.eles:t.$();var s=new a(n.extend({},e,{cy:t,eles:o}));return s}};a.createLayout=a.makeLayout,t.exports=a},{"../is":77,"../util":94}],36:[function(e,t,r){"use strict";var n={notify:function(e){var t=this._private;if(t.batchingNotify){var r=t.batchNotifyEles,n=t.batchNotifyTypes;return e.collection&&r.merge(e.collection),void(n.ids[e.type]||n.push(e.type))}if(t.notificationsEnabled){var i=this.renderer();i.notify(e)}},notifications:function(e){var t=this._private;return void 0===e?t.notificationsEnabled:void(t.notificationsEnabled=e?!0:!1)},noNotifications:function(e){this.notifications(!1),e(),this.notifications(!0)},startBatch:function(){var e=this._private;return null==e.batchCount&&(e.batchCount=0),0===e.batchCount&&(e.batchingStyle=e.batchingNotify=!0,e.batchStyleEles=this.collection(),e.batchNotifyEles=this.collection(),e.batchNotifyTypes=[],e.batchNotifyTypes.ids={}),e.batchCount++,this},endBatch:function(){var e=this._private;return e.batchCount--,0===e.batchCount&&(e.batchingStyle=!1,e.batchStyleEles.updateStyle(),e.batchingNotify=!1,this.notify({type:e.batchNotifyTypes,collection:e.batchNotifyEles})),this},batch:function(e){return this.startBatch(),e(),this.endBatch(),this},batchData:function(e){var t=this;return this.batch(function(){for(var r in e){var n=e[r],i=t.getElementById(r);i.data(n)}})}};t.exports=n},{}],37:[function(e,t,r){"use strict";var n=e("../util"),i={renderTo:function(e,t,r,n){var i=this._private.renderer;return i.renderTo(e,t,r,n),this},renderer:function(){return this._private.renderer},forceRender:function(){return this.notify({type:"draw"}),this},resize:function(){return this.notify({type:"resize"}),this.trigger("resize"),this},initRenderer:function(e){var t=this,r=t.extension("renderer",e.name);if(null==r)return void n.error("Can not initialise: No such renderer `%s` found; did you include its JS file?",e.name);var i=n.extend({},e,{cy:t}),a=t._private.renderer=new r(i);a.init(i)},triggerOnRender:function(){for(var e=this._private.onRenders,t=0;t<e.length;t++){var r=e[t];r()}return this},onRender:function(e){return this._private.onRenders.push(e),this},offRender:function(e){var t=this._private.onRenders;if(null==e)return this._private.onRenders=[],this;for(var r=0;r<t.length;r++){var n=t[r];if(e===n){t.splice(r,1);break}}return this}};i.invalidateDimensions=i.resize,t.exports=i},{"../util":94}],38:[function(e,t,r){"use strict";var n=e("../is"),i=e("../collection"),a={collection:function(e,t){return n.string(e)?this.$(e):n.elementOrCollection(e)?e.collection():n.array(e)?i(this,e,t):i(this)},nodes:function(e){var t=this.$(function(){return this.isNode()});return e?t.filter(e):t},edges:function(e){var t=this.$(function(){return this.isEdge()});return e?t.filter(e):t},$:function(e){var t=new i(this,this._private.elements);return e?t.filter(e):t}};a.elements=a.filter=a.$,t.exports=a},{"../collection":23,"../is":77}],39:[function(e,t,r){"use strict";var n=e("../is"),i=e("../style"),a={style:function(e){if(e){var t=this.setStyle(e);t.update()}return this._private.style},setStyle:function(e){var t=this._private;return n.stylesheet(e)?t.style=e.generateStyle(this):n.array(e)?t.style=i.fromJson(this,e):n.string(e)?t.style=i.fromString(this,e):t.style=i(this),t.style}};t.exports=a},{"../is":77,"../style":86}],40:[function(e,t,r){"use strict";var n=e("../is"),i={autolock:function(e){return void 0===e?this._private.autolock:(this._private.autolock=e?!0:!1,this)},autoungrabify:function(e){return void 0===e?this._private.autoungrabify:(this._private.autoungrabify=e?!0:!1,this)},autounselectify:function(e){return void 0===e?this._private.autounselectify:(this._private.autounselectify=e?!0:!1,this)},panningEnabled:function(e){return void 0===e?this._private.panningEnabled:(this._private.panningEnabled=e?!0:!1,this)},userPanningEnabled:function(e){return void 0===e?this._private.userPanningEnabled:(this._private.userPanningEnabled=e?!0:!1,this)},zoomingEnabled:function(e){return void 0===e?this._private.zoomingEnabled:(this._private.zoomingEnabled=e?!0:!1,this)},userZoomingEnabled:function(e){return void 0===e?this._private.userZoomingEnabled:(this._private.userZoomingEnabled=e?!0:!1,this)},boxSelectionEnabled:function(e){return void 0===e?this._private.boxSelectionEnabled:(this._private.boxSelectionEnabled=e?!0:!1,this)},pan:function(){var e,t,r,i,a,o=arguments,s=this._private.pan;switch(o.length){case 0:return s;case 1:if(n.string(o[0]))return e=o[0],s[e];if(n.plainObject(o[0])){if(!this._private.panningEnabled)return this;r=o[0],i=r.x,a=r.y,n.number(i)&&(s.x=i),n.number(a)&&(s.y=a),this.trigger("pan viewport")}break;case 2:if(!this._private.panningEnabled)return this;e=o[0],t=o[1],"x"!==e&&"y"!==e||!n.number(t)||(s[e]=t),this.trigger("pan viewport")}return this.notify({type:"viewport"}),this},panBy:function(e){var t,r,i,a,o,s=arguments,l=this._private.pan;if(!this._private.panningEnabled)return this;switch(s.length){case 1:n.plainObject(s[0])&&(i=s[0],a=i.x,o=i.y,n.number(a)&&(l.x+=a),n.number(o)&&(l.y+=o),this.trigger("pan viewport"));break;case 2:t=s[0],r=s[1],"x"!==t&&"y"!==t||!n.number(r)||(l[t]+=r),this.trigger("pan viewport")}return this.notify({type:"viewport"}),this},fit:function(e,t){var r=this.getFitViewport(e,t);if(r){var n=this._private;n.zoom=r.zoom,n.pan=r.pan,this.trigger("pan zoom viewport"),this.notify({type:"viewport"})}return this},getFitViewport:function(e,t){if(n.number(e)&&void 0===t&&(t=e,e=void 0),this._private.panningEnabled&&this._private.zoomingEnabled){var r;if(n.string(e)){var i=e;e=this.$(i)}else if(n.boundingBox(e)){var a=e;r={x1:a.x1,y1:a.y1,x2:a.x2,y2:a.y2},r.w=r.x2-r.x1,r.h=r.y2-r.y1}else n.elementOrCollection(e)||(e=this.elements());r=r||e.boundingBox();var o,s=this.width(),l=this.height();if(t=n.number(t)?t:0,!isNaN(s)&&!isNaN(l)&&s>0&&l>0&&!isNaN(r.w)&&!isNaN(r.h)&&r.w>0&&r.h>0){o=Math.min((s-2*t)/r.w,(l-2*t)/r.h),o=o>this._private.maxZoom?this._private.maxZoom:o,o=o<this._private.minZoom?this._private.minZoom:o;var u={x:(s-o*(r.x1+r.x2))/2,y:(l-o*(r.y1+r.y2))/2};return{zoom:o,pan:u}}}},minZoom:function(e){return void 0===e?this._private.minZoom:(n.number(e)&&(this._private.minZoom=e),this)},maxZoom:function(e){return void 0===e?this._private.maxZoom:(n.number(e)&&(this._private.maxZoom=e),this)},zoom:function(e){var t,r;if(void 0===e)return this._private.zoom;if(n.number(e))r=e;else if(n.plainObject(e)){if(r=e.level,e.position){var i=e.position,a=this._private.pan,o=this._private.zoom;t={x:i.x*o+a.x,y:i.y*o+a.y}}else e.renderedPosition&&(t=e.renderedPosition);if(t&&!this._private.panningEnabled)return this}if(!this._private.zoomingEnabled)return this;if(!n.number(r)||t&&(!n.number(t.x)||!n.number(t.y)))return this;if(r=r>this._private.maxZoom?this._private.maxZoom:r,r=r<this._private.minZoom?this._private.minZoom:r,t){var s=this._private.pan,l=this._private.zoom,u=r,c={x:-u/l*(t.x-s.x)+t.x,y:-u/l*(t.y-s.y)+t.y};this._private.zoom=r,this._private.pan=c;var d=s.x!==c.x||s.y!==c.y;this.trigger(" zoom "+(d?" pan ":"")+" viewport ")}else this._private.zoom=r,this.trigger("zoom viewport");return this.notify({type:"viewport"}),this},viewport:function(e){var t=this._private,r=!0,i=!0,a=[],o=!1,s=!1;if(!e)return this;if(n.number(e.zoom)||(r=!1),n.plainObject(e.pan)||(i=!1),!r&&!i)return this;if(r){var l=e.zoom;l<t.minZoom||l>t.maxZoom||!t.zoomingEnabled?o=!0:(t.zoom=l,a.push("zoom"))}if(i&&(!o||!e.cancelOnFailedZoom)&&t.panningEnabled){var u=e.pan;n.number(u.x)&&(t.pan.x=u.x,s=!1),n.number(u.y)&&(t.pan.y=u.y,s=!1),s||a.push("pan")}return a.length>0&&(a.push("viewport"),this.trigger(a.join(" ")),this.notify({type:"viewport"})),this},center:function(e){var t=this.getCenterPan(e);return t&&(this._private.pan=t,this.trigger("pan viewport"),this.notify({type:"viewport"})),this},getCenterPan:function(e,t){if(this._private.panningEnabled){if(n.string(e)){var r=e;e=this.elements(r)}else n.elementOrCollection(e)||(e=this.elements());var i=e.boundingBox(),a=this.width(),o=this.height();t=void 0===t?this._private.zoom:t;var s={x:(a-t*(i.x1+i.x2))/2,y:(o-t*(i.y1+i.y2))/2};return s}},reset:function(){return this._private.panningEnabled&&this._private.zoomingEnabled?(this.viewport({pan:{x:0,y:0},zoom:1}),this):this},width:function(){var e=this._private.container;return e?e.clientWidth:1},height:function(){var e=this._private.container;return e?e.clientHeight:1},extent:function(){var e=this._private.pan,t=this._private.zoom,r=this.renderedExtent(),n={x1:(r.x1-e.x)/t,x2:(r.x2-e.x)/t,y1:(r.y1-e.y)/t,y2:(r.y2-e.y)/t};return n.w=n.x2-n.x1,n.h=n.y2-n.y1,n},renderedExtent:function(){var e=this.width(),t=this.height();return{x1:0,y1:0,x2:e,y2:t,w:e,h:t}}};i.centre=i.center,i.autolockNodes=i.autolock,i.autoungrabifyNodes=i.autoungrabify,t.exports=i},{"../is":77}],41:[function(e,t,r){"use strict";var n=e("./util"),i=e("./is"),a=e("./selector"),o=e("./promise"),s=e("./event"),l=e("./animation"),u={data:function(e){var t={field:"data",bindingEvent:"data",allowBinding:!1,allowSetting:!1,allowGetting:!1,settingEvent:"data",settingTriggersEvent:!1,triggerFnName:"trigger",immutableKeys:{},updateStyle:!1,onSet:function(e){},canSet:function(e){return!0}};return e=n.extend({},t,e),function(t,r){var n=e,a=this,o=void 0!==a.length,s=o?a:[a],l=o?a[0]:a;if(i.string(t)){if(n.allowGetting&&void 0===r){var u;return l&&(u=l._private[n.field][t]),u}if(n.allowSetting&&void 0!==r){var c=!n.immutableKeys[t];if(c){for(var d=0,h=s.length;h>d;d++)n.canSet(s[d])&&(s[d]._private[n.field][t]=r);n.updateStyle&&a.updateStyle(),n.onSet(a),n.settingTriggersEvent&&a[n.triggerFnName](n.settingEvent)}}}else if(n.allowSetting&&i.plainObject(t)){var p,v,f=t;for(p in f){v=f[p];var c=!n.immutableKeys[p];if(c)for(var d=0,h=s.length;h>d;d++)n.canSet(s[d])&&(s[d]._private[n.field][p]=v)}n.updateStyle&&a.updateStyle(),n.onSet(a),n.settingTriggersEvent&&a[n.triggerFnName](n.settingEvent)}else if(n.allowBinding&&i.fn(t)){var g=t;a.bind(n.bindingEvent,g)}else if(n.allowGetting&&void 0===t){var u;return l&&(u=l._private[n.field]),u}return a}},removeData:function(e){var t={field:"data",event:"data",triggerFnName:"trigger",triggerEvent:!1,immutableKeys:{}};return e=n.extend({},t,e),function(t){var r=e,n=this,a=void 0!==n.length,o=a?n:[n];if(i.string(t)){for(var s=t.split(/\s+/),l=s.length,u=0;l>u;u++){var c=s[u];if(!i.emptyString(c)){var d=!r.immutableKeys[c];if(d)for(var h=0,p=o.length;p>h;h++)o[h]._private[r.field][c]=void 0}}r.triggerEvent&&n[r.triggerFnName](r.event)}else if(void 0===t){for(var h=0,p=o.length;p>h;h++){var v=o[h]._private[r.field];for(var c in v){var f=!r.immutableKeys[c];f&&(v[c]=void 0)}}r.triggerEvent&&n[r.triggerFnName](r.event)}return n}},event:{regex:/(\w+)(\.\w+)?/,optionalTypeRegex:/(\w+)?(\.\w+)?/,falseCallback:function(){return!1}},on:function(e){var t={unbindSelfOnTrigger:!1,unbindAllBindersOnTrigger:!1};return e=n.extend({},t,e),function(t,r,n,o){var s=this,l=void 0!==s.length,c=l?s:[s],d=i.string(t),h=e;if(i.plainObject(r)?(o=n,n=r,r=void 0):(i.fn(r)||r===!1)&&(o=r,n=void 0,r=void 0),(i.fn(n)||n===!1)&&(o=n,n=void 0),!i.fn(o)&&o!==!1&&d)return s;if(d){var p={};p[t]=o,t=p}for(var v in t)if(o=t[v],o===!1&&(o=u.event.falseCallback),i.fn(o)){v=v.split(/\s+/);for(var f=0;f<v.length;f++){var g=v[f];if(!i.emptyString(g)){var y=g.match(u.event.regex);if(y)for(var m=y[1],b=y[2]?y[2]:void 0,x={callback:o,data:n,delegated:r?!0:!1,selector:r,selObj:new a(r),type:m,namespace:b,unbindSelfOnTrigger:h.unbindSelfOnTrigger,unbindAllBindersOnTrigger:h.unbindAllBindersOnTrigger,binders:c},w=0;w<c.length;w++){var _=c[w]._private;_.listeners=_.listeners||[],_.listeners.push(x)}}}}return s}},eventAliasesOn:function(e){var t=e;t.addListener=t.listen=t.bind=t.on,t.removeListener=t.unlisten=t.unbind=t.off,t.emit=t.trigger,t.pon=t.promiseOn=function(e,t){var r=this,n=Array.prototype.slice.call(arguments,0);return new o(function(e,t){var i=function(t){r.off.apply(r,o),e(t)},a=n.concat([i]),o=a.concat([]);r.on.apply(r,a)})}},off:function(e){var t={};return e=n.extend({},t,e),function(e,t,r){var n=this,a=void 0!==n.length,o=a?n:[n],s=i.string(e);if(0===arguments.length){for(var l=0;l<o.length;l++)o[l]._private.listeners=[];return n}if((i.fn(t)||t===!1)&&(r=t,t=void 0),s){var c={};c[e]=r,e=c}for(var d in e){r=e[d],r===!1&&(r=u.event.falseCallback),d=d.split(/\s+/);for(var h=0;h<d.length;h++){var p=d[h];if(!i.emptyString(p)){var v=p.match(u.event.optionalTypeRegex);if(v)for(var f=v[1]?v[1]:void 0,g=v[2]?v[2]:void 0,l=0;l<o.length;l++)for(var y=o[l]._private.listeners=o[l]._private.listeners||[],m=0;m<y.length;m++){var b=y[m],x=!g||g===b.namespace,w=!f||b.type===f,_=!r||r===b.callback,E=x&&w&&_;E&&(y.splice(m,1),m--)}}}}return n}},trigger:function(e){var t={};return e=n.extend({},t,e),function(t,r,n){var a=this,o=void 0!==a.length,l=o?a:[a],c=i.string(t),d=i.plainObject(t),h=i.event(t),p=this._private.cy||(i.core(this)?this:null),v=p?p.hasCompoundNodes():!1;if(c){var f=t.split(/\s+/);t=[];for(var g=0;g<f.length;g++){var y=f[g];if(!i.emptyString(y)){var m=y.match(u.event.regex),b=m[1],x=m[2]?m[2]:void 0;t.push({type:b,namespace:x})}}}else if(d){var w=t;t=[w]}r?i.array(r)||(r=[r]):r=[];for(var g=0;g<t.length;g++)for(var _=t[g],E=0;E<l.length;E++){var y,D=l[E],S=D._private.listeners=D._private.listeners||[],k=i.element(D),T=k||e.layout;if(h?(y=_,y.cyTarget=y.cyTarget||D,y.cy=y.cy||p):y=new s(_,{cyTarget:D,cy:p,namespace:_.namespace}),_.layout&&(y.layout=_.layout),e.layout&&(y.layout=D),y.cyPosition){var P=y.cyPosition,C=p.zoom(),N=p.pan();y.cyRenderedPosition={x:P.x*C+N.x,y:P.y*C+N.y}}n&&(S=[{namespace:y.namespace,type:y.type,callback:n}]);for(var M=0;M<S.length;M++){var B=S[M],z=!B.namespace||B.namespace===y.namespace,O=B.type===y.type,I=B.delegated?D!==y.cyTarget&&i.element(y.cyTarget)&&B.selObj.matches(y.cyTarget):!0,L=z&&O&&I;if(L){var A=[y];if(A=A.concat(r),B.data?y.data=B.data:y.data=void 0,(B.unbindSelfOnTrigger||B.unbindAllBindersOnTrigger)&&(S.splice(M,1),M--),B.unbindAllBindersOnTrigger)for(var R=B.binders,V=0;V<R.length;V++){var F=R[V];if(F&&F!==D)for(var j=F._private.listeners,q=0;q<j.length;q++){var X=j[q];X===B&&(j.splice(q,1),q--)}}var Y=B.delegated?y.cyTarget:D,$=B.callback.apply(Y,A);($===!1||y.isPropagationStopped())&&(T=!1,$===!1&&(y.stopPropagation(),y.preventDefault()))}}if(T){var H=v?D._private.parent:null,W=null!=H&&0!==H.length;W?(H=H[0],H.trigger(y)):p.trigger(y)}}return a}},animated:function(e){var t={};return e=n.extend({},t,e),function(){var e=this,t=void 0!==e.length,r=t?e:[e],n=this._private.cy||this;if(!n.styleEnabled())return!1;var i=r[0];return i?i._private.animation.current.length>0:void 0}},clearQueue:function(e){var t={};return e=n.extend({},t,e),function(){var e=this,t=void 0!==e.length,r=t?e:[e],n=this._private.cy||this;if(!n.styleEnabled())return this;for(var i=0;i<r.length;i++){var a=r[i];a._private.animation.queue=[]}return this}},delay:function(e){var t={};return e=n.extend({},t,e),function(e,t){var r=this._private.cy||this;return r.styleEnabled()?this.animate({delay:e,duration:e,complete:t}):this}},delayAnimation:function(e){var t={};return e=n.extend({},t,e),function(e,t){var r=this._private.cy||this;return r.styleEnabled()?this.animation({delay:e,duration:e,complete:t}):this}},animation:function(e){var t={};return e=n.extend({},t,e),function(e,t){var r=this,i=void 0!==r.length,a=i?r:[r],o=this._private.cy||this,s=!i,u=!s;if(!o.styleEnabled())return this;var c=o.style();switch(e=n.extend({},e,t),void 0===e.duration&&(e.duration=400),e.duration){case"slow":e.duration=600;break;case"fast":e.duration=200}var d=!0;if(e)for(var h in e){d=!1;break}if(d)return new l(a[0],e);if(u&&(e.style=c.getPropsList(e.style||e.css),e.css=void 0),e.renderedPosition&&u){var p=e.renderedPosition,v=o.pan(),f=o.zoom();e.position={x:(p.x-v.x)/f,y:(p.y-v.y)/f}}if(e.panBy&&s){var g=e.panBy,y=o.pan();e.pan={x:y.x+g.x,y:y.y+g.y}}var m=e.center||e.centre;if(m&&s){var b=o.getCenterPan(m.eles,e.zoom);b&&(e.pan=b)}if(e.fit&&s){var x=e.fit,w=o.getFitViewport(x.eles||x.boundingBox,x.padding);w&&(e.pan=w.pan,e.zoom=w.zoom)}return new l(a[0],e)}},animate:function(e){var t={};return e=n.extend({},t,e),function(e,t){var r=this,i=void 0!==r.length,a=i?r:[r],o=this._private.cy||this;if(!o.styleEnabled())return this;t&&(e=n.extend({},e,t));for(var s=0;s<a.length;s++){var l=a[s],u=l.animated()&&(void 0===e.queue||e.queue),c=l.animation(e,u?{queue:!0}:void 0);c.play()}return this}},stop:function(e){var t={};return e=n.extend({},t,e),function(e,t){var r=this,n=void 0!==r.length,i=n?r:[r],a=this._private.cy||this;if(!a.styleEnabled())return this;for(var o=0;o<i.length;o++){for(var s=i[o],l=s._private,u=l.animation.current,c=0;c<u.length;c++){var d=u[c],h=d._private;t&&(h.duration=0)}e&&(l.animation.queue=[]),t||(l.animation.current=[])}return a.notify({collection:this,type:"draw"}),this}}};t.exports=u},{"./animation":1,"./event":42,"./is":77,"./promise":80,"./selector":81,"./util":94}],42:[function(e,t,r){"use strict";function n(){return!1}function i(){return!0}var a=function(e,t){return this instanceof a?(e&&e.type?(this.originalEvent=e,this.type=e.type,this.isDefaultPrevented=e.defaultPrevented?i:n):this.type=e,t&&(this.type=void 0!==t.type?t.type:this.type,this.cy=t.cy,this.cyTarget=t.cyTarget,this.cyPosition=t.cyPosition,this.cyRenderedPosition=t.cyRenderedPosition,this.namespace=t.namespace,this.layout=t.layout,this.data=t.data,this.message=t.message),void(this.timeStamp=e&&e.timeStamp||Date.now())):new a(e,t)};a.prototype={instanceString:function(){return"event"},preventDefault:function(){this.isDefaultPrevented=i;var e=this.originalEvent;e&&e.preventDefault&&e.preventDefault()},stopPropagation:function(){this.isPropagationStopped=i;var e=this.originalEvent;e&&e.stopPropagation&&e.stopPropagation()},stopImmediatePropagation:function(){this.isImmediatePropagationStopped=i,this.stopPropagation()},isDefaultPrevented:n,isPropagationStopped:n,isImmediatePropagationStopped:n},t.exports=a},{}],43:[function(e,t,r){"use strict";function n(e,t,r){var n=r;if("core"===e)c.prototype[t]=r;else if("collection"===e)u.prototype[t]=r;else if("layout"===e){for(var a=function(e){this.options=e,r.call(this,e),h.plainObject(this._private)||(this._private={}),this._private.cy=e.cy,this._private.listeners=[]},o=a.prototype=Object.create(r.prototype),d=[],v=0;v<d.length;v++){var f=d[v];o[f]=o[f]||function(){return this}}o.start&&!o.run?o.run=function(){return this.start(),this}:!o.start&&o.run&&(o.start=function(){return this.run(),this}),o.stop||(o.stop=function(){var e=this.options;if(e&&e.animate)for(var t=this.animations,r=0;r<t.length;r++)t[r].stop();return this.trigger("layoutstop"),this}),o.destroy||(o.destroy=function(){return this}),o.on=l.on({layout:!0}),o.one=l.on({layout:!0,unbindSelfOnTrigger:!0}),o.once=l.on({layout:!0,unbindAllBindersOnTrigger:!0}),o.off=l.off({layout:!0}),o.trigger=l.trigger({layout:!0}),l.eventAliasesOn(o),n=a}else if("renderer"===e&&"null"!==t&&"base"!==t){var g=i("renderer","base").prototype,y=r.prototype;for(var m in g){var b=g[m],x=null!=y[m];if(x)return void s.error("Can not register renderer `"+t+"` since it overrides `"+m+"` in its prototype");y[m]=b}g.clientFunctions.forEach(function(e){y[e]=y[e]||function(){s.error("Renderer does not implement `renderer."+e+"()` on its prototype")}})}return s.setMap({map:p,keys:[e,t],value:n})}function i(e,t){return s.getMap({map:p,keys:[e,t]})}function a(e,t,r,n,i){return s.setMap({map:v,keys:[e,t,r,n],value:i})}function o(e,t,r,n){return s.getMap({map:v,keys:[e,t,r,n]})}var s=e("./util"),l=e("./define"),u=e("./collection"),c=e("./core"),d=e("./extensions"),h=e("./is"),p={},v={},f=function(){return 2===arguments.length?i.apply(null,arguments):3===arguments.length?n.apply(null,arguments):4===arguments.length?o.apply(null,arguments):5===arguments.length?a.apply(null,arguments):void s.error("Invalid extension access syntax")};c.prototype.extension=f,d.forEach(function(e){e.extensions.forEach(function(t){n(e.type,t.name,t.impl)})}),t.exports=f},{"./collection":23,"./core":34,"./define":41,"./extensions":44,"./is":77,"./util":94}],44:[function(e,t,r){"use strict";t.exports=[{type:"layout",extensions:e("./layout")},{type:"renderer",extensions:e("./renderer")}]},{"./layout":50,"./renderer":72}],45:[function(e,t,r){"use strict";function n(e){this.options=i.extend({},s,e)}var i=e("../../util"),a=e("../../math"),o=e("../../is"),s={fit:!0,directed:!1,padding:30,circle:!1,spacingFactor:1.75,boundingBox:void 0,avoidOverlap:!0,roots:void 0,maximalAdjustments:0,animate:!1,animationDuration:500,animationEasing:void 0,ready:void 0,stop:void 0};n.prototype.run=function(){var e,t=this.options,r=t,n=t.cy,i=r.eles,s=i.nodes().not(":parent"),l=i,u=a.makeBoundingBox(r.boundingBox?r.boundingBox:{x1:0,y1:0,w:n.width(),h:n.height()});if(o.elementOrCollection(r.roots))e=r.roots;else if(o.array(r.roots)){for(var c=[],d=0;d<r.roots.length;d++){var h=r.roots[d],p=n.getElementById(h);c.push(p)}e=n.collection(c)}else if(o.string(r.roots))e=n.$(r.roots);else if(r.directed)e=s.roots();else{for(var v=[],f=s;f.length>0;){var g=n.collection();i.bfs({roots:f[0],visit:function(e,t,r,n,i){g=g.add(r)},directed:!1}),f=f.not(g),v.push(g)}e=n.collection();for(var d=0;d<v.length;d++){var y=v[d],m=y.maxDegree(!1),b=y.filter(function(){return this.degree(!1)===m});e=e.add(b)}}var x=[],w={},_={},E={},D={},S={};l.bfs({roots:e,directed:r.directed,visit:function(e,t,r,n,i){var a=this[0],o=a.id();if(x[t]||(x[t]=[]),x[t].push(a),w[o]=!0,_[o]=t,E[o]=i,D[o]=n,i){var s=i.id(),l=S[s]=S[s]||[];l.push(r)}}});for(var k=[],d=0;d<s.length;d++){var p=s[d];w[p.id()]||k.push(p)}for(var T=3*k.length,P=0;0!==k.length&&T>P;){for(var C=k.shift(),N=C.neighborhood().nodes(),M=!1,d=0;d<N.length;d++){var B=_[N[d].id()];if(void 0!==B){x[B].push(C),M=!0;break}}M||k.push(C),P++}for(;0!==k.length;){var C=k.shift(),M=!1;M||(0===x.length&&x.push([]),x[0].push(C))}var z=function(){for(var e=0;e<x.length;e++)for(var t=x[e],r=0;r<t.length;r++){var n=t[r];n._private.scratch.breadthfirst={depth:e,index:r}}};z();for(var O=function(e){for(var t,r=e.connectedEdges(function(){return this.data("target")===e.id()}),n=e._private.scratch.breadthfirst,i=0,a=0;a<r.length;a++){var o=r[a],s=o.source()[0],l=s._private.scratch.breadthfirst;n.depth<=l.depth&&i<l.depth&&(i=l.depth,t=s)}return t},I=0;I<r.maximalAdjustments;I++){for(var L=x.length,A=[],d=0;L>d;d++)for(var B=x[d],R=B.length,V=0;R>V;V++){var p=B[V],F=p._private.scratch.breadthfirst,j=O(p);j&&(F.intEle=j,A.push(p))}for(var d=0;d<A.length;d++){var p=A[d],F=p._private.scratch.breadthfirst,j=F.intEle,q=j._private.scratch.breadthfirst;x[F.depth].splice(F.index,1);for(var X=q.depth+1;X>x.length-1;)x.push([]);x[X].push(p),F.depth=X,F.index=x[X].length-1}z()}var Y=0;if(r.avoidOverlap){for(var d=0;d<s.length;d++){var $=s[d],H=$.boundingBox(),W=H.w,Z=H.h;Y=Math.max(Y,W,Z)}Y*=r.spacingFactor}for(var U={},G=function(e){if(U[e.id()])return U[e.id()];for(var t=e._private.scratch.breadthfirst.depth,r=e.neighborhood().nodes().not(":parent"),n=0,i=0,a=0;a<r.length;a++){var o=r[a],s=o._private.scratch.breadthfirst,l=s.index,u=s.depth,c=x[u].length;(t>u||0===t)&&(n+=l/c,i++)}return i=Math.max(1,i),n/=i,0===i&&(n=void 0),U[e.id()]=n,n},K=function(e,t){var r=G(e),n=G(t);return r-n},J=0;3>J;J++){for(var d=0;d<x.length;d++)x[d]=x[d].sort(K);z()}for(var Q=0,d=0;d<x.length;d++)Q=Math.max(x[d].length,Q);for(var ee={x:u.x1+u.w/2,y:u.x1+u.h/2},te=function(e,t){var n=e._private.scratch.breadthfirst,i=n.depth,a=n.index,o=x[i].length,s=Math.max(u.w/(o+1),Y),l=Math.max(u.h/(x.length+1),Y),c=Math.min(u.w/2/x.length,u.h/2/x.length);if(c=Math.max(c,Y),r.circle){if(r.circle){var d=c*i+c-(x.length>0&&x[0].length<=3?c/2:0),h=2*Math.PI/x[i].length*a;return 0===i&&1===x[0].length&&(d=1),{x:ee.x+d*Math.cos(h),y:ee.y+d*Math.sin(h)}}return{x:ee.x+(a+1-(o+1)/2)*s,y:(i+1)*l}}var p={x:ee.x+(a+1-(o+1)/2)*s,y:(i+1)*l};return t?p:p},re={},d=x.length-1;d>=0;d--)for(var B=x[d],V=0;V<B.length;V++){var C=B[V];re[C.id()]=te(C,d===x.length-1)}return s.layoutPositions(this,r,function(){return re[this.id()]}),this},t.exports=n},{"../../is":77,"../../math":79,"../../util":94}],46:[function(e,t,r){"use strict";function n(e){this.options=i.extend({},s,e)}var i=e("../../util"),a=e("../../math"),o=e("../../is"),s={fit:!0,padding:30,boundingBox:void 0,avoidOverlap:!0,radius:void 0,startAngle:1.5*Math.PI,sweep:void 0,clockwise:!0,sort:void 0,animate:!1,animationDuration:500,animationEasing:void 0,ready:void 0,stop:void 0};n.prototype.run=function(){var e=this.options,t=e,r=e.cy,n=t.eles,i=void 0!==t.counterclockwise?!t.counterclockwise:t.clockwise,s=n.nodes().not(":parent");t.sort&&(s=s.sort(t.sort));for(var l,u=a.makeBoundingBox(t.boundingBox?t.boundingBox:{x1:0,y1:0,w:r.width(),h:r.height()}),c={x:u.x1+u.w/2,y:u.y1+u.h/2},d=void 0===t.sweep?2*Math.PI-2*Math.PI/s.length:t.sweep,h=d/Math.max(1,s.length-1),p=0,v=0;v<s.length;v++){var f=s[v],g=f.boundingBox(),y=g.w,m=g.h;p=Math.max(p,y,m)}if(l=o.number(t.radius)?t.radius:s.length<=1?0:Math.min(u.h,u.w)/2-p,s.length>1&&t.avoidOverlap){p*=1.75;var b=Math.cos(h)-Math.cos(0),x=Math.sin(h)-Math.sin(0),w=Math.sqrt(p*p/(b*b+x*x));l=Math.max(w,l)}var _=function(e,r){var n=t.startAngle+e*h*(i?1:-1),a=l*Math.cos(n),o=l*Math.sin(n),s={
+x:c.x+a,y:c.y+o};return s};return s.layoutPositions(this,t,_),this},t.exports=n},{"../../is":77,"../../math":79,"../../util":94}],47:[function(e,t,r){"use strict";function n(e){this.options=i.extend({},o,e)}var i=e("../../util"),a=e("../../math"),o={fit:!0,padding:30,startAngle:1.5*Math.PI,sweep:void 0,clockwise:!0,equidistant:!1,minNodeSpacing:10,boundingBox:void 0,avoidOverlap:!0,height:void 0,width:void 0,concentric:function(e){return e.degree()},levelWidth:function(e){return e.maxDegree()/4},animate:!1,animationDuration:500,animationEasing:void 0,ready:void 0,stop:void 0};n.prototype.run=function(){for(var e=this.options,t=e,r=void 0!==t.counterclockwise?!t.counterclockwise:t.clockwise,n=e.cy,i=t.eles,o=i.nodes().not(":parent"),s=a.makeBoundingBox(t.boundingBox?t.boundingBox:{x1:0,y1:0,w:n.width(),h:n.height()}),l={x:s.x1+s.w/2,y:s.y1+s.h/2},u=[],c=t.startAngle,d=0,h=0;h<o.length;h++){var p,v=o[h];p=t.concentric.apply(v,[v]),u.push({value:p,node:v}),v._private.scratch.concentric=p}o.updateStyle();for(var h=0;h<o.length;h++){var v=o[h],f=v.boundingBox();d=Math.max(d,f.w,f.h)}u.sort(function(e,t){return t.value-e.value});for(var g=t.levelWidth(o),y=[[]],m=y[0],h=0;h<u.length;h++){var b=u[h];if(m.length>0){var x=Math.abs(m[0].value-b.value);x>=g&&(m=[],y.push(m))}m.push(b)}var w=d+t.minNodeSpacing;if(!t.avoidOverlap){var _=y.length>0&&y[0].length>1,E=Math.min(s.w,s.h)/2-w,D=E/(y.length+_?1:0);w=Math.min(w,D)}for(var S=0,h=0;h<y.length;h++){var k=y[h],T=void 0===t.sweep?2*Math.PI-2*Math.PI/k.length:t.sweep,P=k.dTheta=T/Math.max(1,k.length-1);if(k.length>1&&t.avoidOverlap){var C=Math.cos(P)-Math.cos(0),N=Math.sin(P)-Math.sin(0),M=Math.sqrt(w*w/(C*C+N*N));S=Math.max(M,S)}k.r=S,S+=w}if(t.equidistant){for(var B=0,S=0,h=0;h<y.length;h++){var k=y[h],z=k.r-S;B=Math.max(B,z)}S=0;for(var h=0;h<y.length;h++){var k=y[h];0===h&&(S=k.r),k.r=S,S+=B}}for(var O={},h=0;h<y.length;h++)for(var k=y[h],P=k.dTheta,S=k.r,I=0;I<k.length;I++){var b=k[I],c=t.startAngle+(r?1:-1)*P*I,L={x:l.x+S*Math.cos(c),y:l.y+S*Math.sin(c)};O[b.node.id()]=L}return o.layoutPositions(this,t,function(){var e=this.id();return O[e]}),this},t.exports=n},{"../../math":79,"../../util":94}],48:[function(e,t,r){"use strict";function n(e){this.options=a.extend({},u,e),this.options.layout=this}var i,a=e("../../util"),o=e("../../math"),s=e("../../thread"),l=e("../../is"),u={ready:function(){},stop:function(){},animate:!0,animationThreshold:250,refresh:20,fit:!0,padding:30,boundingBox:void 0,componentSpacing:100,nodeRepulsion:function(e){return 4e5},nodeOverlap:10,idealEdgeLength:function(e){return 10},edgeElasticity:function(e){return 100},nestingFactor:5,gravity:80,numIter:1e3,initialTemp:200,coolingFactor:.95,minTemp:1,useMultitasking:!0};n.prototype.run=function(){var e=this.options,t=e.cy,r=this,n=this.thread;(!n||n.stopped())&&(n=this.thread=s({disabled:!e.useMultitasking})),r.stopped=!1,r.trigger({type:"layoutstart",layout:r}),i=!0===e.debug?!0:!1;var o=c(t,r,e);i&&p(o),v(o,t);var l=Date.now(),u=!1,d=function(r){r=r||{},u||!r.force&&Date.now()-l<e.animationThreshold||(u=!0,a.requestAnimationFrame(function(){f(o,t,e),!0===e.fit&&t.fit(e.padding),u=!1}))};n.on("message",function(e){var t=e.message;o.layoutNodes=t,d()}),n.pass({layoutInfo:o,options:{animate:e.animate,refresh:e.refresh,componentSpacing:e.componentSpacing,nodeOverlap:e.nodeOverlap,nestingFactor:e.nestingFactor,gravity:e.gravity,numIter:e.numIter,initialTemp:e.initialTemp,coolingFactor:e.coolingFactor,minTemp:e.minTemp}}).run(function(e){var t,r=e.layoutInfo,n=e.options,i=!1,a=function(e,t,r){o(e,t),c(e,t),d(e,t),h(e,t),p(e,t)},o=function(e,t){for(var r=0;r<e.graphSet.length;r++)for(var n=e.graphSet[r],i=n.length,a=0;i>a;a++)for(var o=e.layoutNodes[e.idToIndex[n[a]]],l=a+1;i>l;l++){var u=e.layoutNodes[e.idToIndex[n[l]]];s(o,u,e,t)}},s=function(e,t,r,n){var i=e.cmptId,a=t.cmptId;if(i===a||r.isCompound){var o=t.positionX-e.positionX,s=t.positionY-e.positionY;if(0!==o||0!==s){var c=l(e,t,o,s);if(c>0)var d=n.nodeOverlap*c,h=Math.sqrt(o*o+s*s),p=d*o/h,v=d*s/h;else var f=u(e,o,s),g=u(t,-1*o,-1*s),y=g.x-f.x,m=g.y-f.y,b=y*y+m*m,h=Math.sqrt(b),d=(e.nodeRepulsion+t.nodeRepulsion)/b,p=d*y/h,v=d*m/h;e.isLocked||(e.offsetX-=p,e.offsetY-=v),t.isLocked||(t.offsetX+=p,t.offsetY+=v)}}},l=function(e,t,r,n){if(r>0)var i=e.maxX-t.minX;else var i=t.maxX-e.minX;if(n>0)var a=e.maxY-t.minY;else var a=t.maxY-e.minY;return i>=0&&a>=0?Math.sqrt(i*i+a*a):0},u=function(e,t,r){var n=e.positionX,i=e.positionY,a=e.height||1,o=e.width||1,s=r/t,l=a/o,u={};do{if(0===t&&r>0){u.x=n,u.y=i+a/2;break}if(0===t&&0>r){u.x=n,u.y=i+a/2;break}if(t>0&&s>=-1*l&&l>=s){u.x=n+o/2,u.y=i+o*r/2/t;break}if(0>t&&s>=-1*l&&l>=s){u.x=n-o/2,u.y=i-o*r/2/t;break}if(r>0&&(-1*l>=s||s>=l)){u.x=n+a*t/2/r,u.y=i+a/2;break}if(0>r&&(-1*l>=s||s>=l)){u.x=n-a*t/2/r,u.y=i-a/2;break}}while(!1);return u},c=function(e,t){for(var r=0;r<e.edgeSize;r++){var n=e.layoutEdges[r],i=e.idToIndex[n.sourceId],a=e.layoutNodes[i],o=e.idToIndex[n.targetId],s=e.layoutNodes[o],l=s.positionX-a.positionX,c=s.positionY-a.positionY;if(0===l&&0===c)return;var d=u(a,l,c),h=u(s,-1*l,-1*c),p=h.x-d.x,v=h.y-d.y,f=Math.sqrt(p*p+v*v),g=Math.pow(n.idealLength-f,2)/n.elasticity;if(0!==f)var y=g*p/f,m=g*v/f;else var y=0,m=0;a.isLocked||(a.offsetX+=y,a.offsetY+=m),s.isLocked||(s.offsetX-=y,s.offsetY-=m)}},d=function(e,t){for(var r=1,n=0;n<e.graphSet.length;n++){var i=e.graphSet[n],a=i.length;if(0===n)var o=e.clientHeight/2,s=e.clientWidth/2;else var l=e.layoutNodes[e.idToIndex[i[0]]],u=e.layoutNodes[e.idToIndex[l.parentId]],o=u.positionX,s=u.positionY;for(var c=0;a>c;c++){var d=e.layoutNodes[e.idToIndex[i[c]]];if(!d.isLocked){var h=o-d.positionX,p=s-d.positionY,v=Math.sqrt(h*h+p*p);if(v>r){var f=t.gravity*h/v,g=t.gravity*p/v;d.offsetX+=f,d.offsetY+=g}}}}},h=function(e,t){var r=[],n=0,i=-1;for(r.push.apply(r,e.graphSet[0]),i+=e.graphSet[0].length;i>=n;){var a=r[n++],o=e.idToIndex[a],s=e.layoutNodes[o],l=s.children;if(0<l.length&&!s.isLocked){for(var u=s.offsetX,c=s.offsetY,d=0;d<l.length;d++){var h=e.layoutNodes[e.idToIndex[l[d]]];h.offsetX+=u,h.offsetY+=c,r[++i]=l[d]}s.offsetX=0,s.offsetY=0}}},p=function(e,t){for(var r=0;r<e.nodeSize;r++){var n=e.layoutNodes[r];0<n.children.length&&(n.maxX=void 0,n.minX=void 0,n.maxY=void 0,n.minY=void 0)}for(var r=0;r<e.nodeSize;r++){var n=e.layoutNodes[r];if(!(0<n.children.length||n.isLocked)){var i=v(n.offsetX,n.offsetY,e.temperature);n.positionX+=i.x,n.positionY+=i.y,n.offsetX=0,n.offsetY=0,n.minX=n.positionX-n.width,n.maxX=n.positionX+n.width,n.minY=n.positionY-n.height,n.maxY=n.positionY+n.height,f(n,e)}}for(var r=0;r<e.nodeSize;r++){var n=e.layoutNodes[r];0<n.children.length&&!n.isLocked&&(n.positionX=(n.maxX+n.minX)/2,n.positionY=(n.maxY+n.minY)/2,n.width=n.maxX-n.minX,n.height=n.maxY-n.minY)}},v=function(e,t,r){var n=Math.sqrt(e*e+t*t);if(n>r)var i={x:r*e/n,y:r*t/n};else var i={x:e,y:t};return i},f=function(e,t){var r=e.parentId;if(null!=r){var n=t.layoutNodes[t.idToIndex[r]],i=!1;return(null==n.maxX||e.maxX+n.padRight>n.maxX)&&(n.maxX=e.maxX+n.padRight,i=!0),(null==n.minX||e.minX-n.padLeft<n.minX)&&(n.minX=e.minX-n.padLeft,i=!0),(null==n.maxY||e.maxY+n.padBottom>n.maxY)&&(n.maxY=e.maxY+n.padBottom,i=!0),(null==n.minY||e.minY-n.padTop<n.minY)&&(n.minY=e.minY-n.padTop,i=!0),i?f(n,t):void 0}},g=function(e,t){for(var n=r.layoutNodes,i=[],a=0;a<n.length;a++){var o=n[a],s=o.cmptId,l=i[s]=i[s]||[];l.push(o)}for(var u=0,a=0;a<i.length;a++){var c=i[a];c.x1=1/0,c.x2=-(1/0),c.y1=1/0,c.y2=-(1/0);for(var d=0;d<c.length;d++){var h=c[d];c.x1=Math.min(c.x1,h.positionX-h.width/2),c.x2=Math.max(c.x2,h.positionX+h.width/2),c.y1=Math.min(c.y1,h.positionY-h.height/2),c.y2=Math.max(c.y2,h.positionY+h.height/2)}c.w=c.x2-c.x1,c.h=c.y2-c.y1,u+=c.w*c.h}i.sort(function(e,t){return t.w*t.h-e.w*e.h});for(var p=0,v=0,f=0,g=0,y=Math.sqrt(u)*r.clientWidth/r.clientHeight,a=0;a<i.length;a++){for(var c=i[a],d=0;d<c.length;d++){var h=c[d];h.isLocked||(h.positionX+=p,h.positionY+=v)}p+=c.w+t.componentSpacing,f+=c.w+t.componentSpacing,g=Math.max(g,c.h),f>y&&(v+=g+t.componentSpacing,p=0,f=0,g=0)}},y=function(e){return i?!1:(a(r,n,e),r.temperature=r.temperature*n.coolingFactor,r.temperature<n.minTemp?!1:!0)},m=0;do{for(var b=0;b<n.refresh&&m<n.numIter;){var t=y(m);if(!t)break;b++,m++}n.animate&&broadcast(r.layoutNodes)}while(t&&m+1<n.numIter);return g(r,n),r}).then(function(e){o.layoutNodes=e.layoutNodes,n.stop(),h()});var h=function(){d({force:!0}),r.one("layoutstop",e.stop),r.trigger({type:"layoutstop",layout:r})};return this},n.prototype.stop=function(){return this.stopped=!0,this.thread&&this.thread.stop(),this.trigger("layoutstop"),this},n.prototype.destroy=function(){return this.thread&&this.thread.stop(),this};var c=function(e,t,r){for(var n=r.eles.edges(),i=r.eles.nodes(),a={isCompound:e.hasCompoundNodes(),layoutNodes:[],idToIndex:{},nodeSize:i.size(),graphSet:[],indexToGraph:[],layoutEdges:[],edgeSize:n.size(),temperature:r.initialTemp,clientWidth:e.width(),clientHeight:e.width(),boundingBox:o.makeBoundingBox(r.boundingBox?r.boundingBox:{x1:0,y1:0,w:e.width(),h:e.height()})},s=r.eles.components(),u={},c=0;c<s.length;c++)for(var h=s[c],p=0;p<h.length;p++){var v=h[p];u[v.id()]=c}for(var c=0;c<a.nodeSize;c++){var f=i[c],g=f.boundingBox(),y={};y.isLocked=f.locked(),y.id=f.data("id"),y.parentId=f.data("parent"),y.cmptId=u[f.id()],y.children=[],y.positionX=f.position("x"),y.positionY=f.position("y"),y.offsetX=0,y.offsetY=0,y.height=g.w,y.width=g.h,y.maxX=y.positionX+y.width/2,y.minX=y.positionX-y.width/2,y.maxY=y.positionY+y.height/2,y.minY=y.positionY-y.height/2,y.padLeft=parseFloat(f.style("padding-left")),y.padRight=parseFloat(f.style("padding-right")),y.padTop=parseFloat(f.style("padding-top")),y.padBottom=parseFloat(f.style("padding-bottom")),y.nodeRepulsion=l.fn(r.nodeRepulsion)?r.nodeRepulsion.call(f,f):r.nodeRepulsion,a.layoutNodes.push(y),a.idToIndex[y.id]=c}for(var m=[],b=0,x=-1,w=[],c=0;c<a.nodeSize;c++){var f=a.layoutNodes[c],_=f.parentId;null!=_?a.layoutNodes[a.idToIndex[_]].children.push(f.id):(m[++x]=f.id,w.push(f.id))}for(a.graphSet.push(w);x>=b;){var E=m[b++],D=a.idToIndex[E],v=a.layoutNodes[D],S=v.children;if(S.length>0){a.graphSet.push(S);for(var c=0;c<S.length;c++)m[++x]=S[c]}}for(var c=0;c<a.graphSet.length;c++)for(var k=a.graphSet[c],p=0;p<k.length;p++){var T=a.idToIndex[k[p]];a.indexToGraph[T]=c}for(var c=0;c<a.edgeSize;c++){var P=n[c],C={};C.id=P.data("id"),C.sourceId=P.data("source"),C.targetId=P.data("target");var N=l.fn(r.idealEdgeLength)?r.idealEdgeLength.call(P,P):r.idealEdgeLength,M=l.fn(r.edgeElasticity)?r.edgeElasticity.call(P,P):r.edgeElasticity,B=a.idToIndex[C.sourceId],z=a.idToIndex[C.targetId],O=a.indexToGraph[B],I=a.indexToGraph[z];if(O!=I){for(var L=d(C.sourceId,C.targetId,a),A=a.graphSet[L],R=0,y=a.layoutNodes[B];-1===A.indexOf(y.id);)y=a.layoutNodes[a.idToIndex[y.parentId]],R++;for(y=a.layoutNodes[z];-1===A.indexOf(y.id);)y=a.layoutNodes[a.idToIndex[y.parentId]],R++;N*=R*r.nestingFactor}C.idealLength=N,C.elasticity=M,a.layoutEdges.push(C)}return a},d=function(e,t,r){var n=h(e,t,0,r);return 2>n.count?0:n.graph},h=function(e,t,r,n){var i=n.graphSet[r];if(-1<i.indexOf(e)&&-1<i.indexOf(t))return{count:2,graph:r};for(var a=0,o=0;o<i.length;o++){var s=i[o],l=n.idToIndex[s],u=n.layoutNodes[l].children;if(0!==u.length){var c=n.indexToGraph[n.idToIndex[u[0]]],d=h(e,t,c,n);if(0!==d.count){if(1!==d.count)return d;if(a++,2===a)break}}}return{count:a,graph:r}},p=function(e){if(i){console.debug("layoutNodes:");for(var t=0;t<e.nodeSize;t++){var r=e.layoutNodes[t],n="\nindex: "+t+"\nId: "+r.id+"\nChildren: "+r.children.toString()+"\nparentId: "+r.parentId+"\npositionX: "+r.positionX+"\npositionY: "+r.positionY+"\nOffsetX: "+r.offsetX+"\nOffsetY: "+r.offsetY+"\npadLeft: "+r.padLeft+"\npadRight: "+r.padRight+"\npadTop: "+r.padTop+"\npadBottom: "+r.padBottom;console.debug(n)}console.debug("idToIndex");for(var t in e.idToIndex)console.debug("Id: "+t+"\nIndex: "+e.idToIndex[t]);console.debug("Graph Set");for(var a=e.graphSet,t=0;t<a.length;t++)console.debug("Set : "+t+": "+a[t].toString());for(var n="IndexToGraph",t=0;t<e.indexToGraph.length;t++)n+="\nIndex : "+t+" Graph: "+e.indexToGraph[t];console.debug(n),n="Layout Edges";for(var t=0;t<e.layoutEdges.length;t++){var o=e.layoutEdges[t];n+="\nEdge Index: "+t+" ID: "+o.id+" SouceID: "+o.sourceId+" TargetId: "+o.targetId+" Ideal Length: "+o.idealLength}console.debug(n),n="nodeSize: "+e.nodeSize,n+="\nedgeSize: "+e.edgeSize,n+="\ntemperature: "+e.temperature,console.debug(n)}},v=function(e,t){for(var r=e.clientWidth,n=e.clientHeight,i=0;i<e.nodeSize;i++){var a=e.layoutNodes[i];0!==a.children.length||a.isLocked||(a.positionX=Math.random()*r,a.positionY=Math.random()*n)}},f=function(e,t,r){var n=r.layout,i=r.eles.nodes(),a=e.boundingBox,o={x1:1/0,x2:-(1/0),y1:1/0,y2:-(1/0)};r.boundingBox&&(i.forEach(function(t){var r=e.layoutNodes[e.idToIndex[t.data("id")]];o.x1=Math.min(o.x1,r.positionX),o.x2=Math.max(o.x2,r.positionX),o.y1=Math.min(o.y1,r.positionY),o.y2=Math.max(o.y2,r.positionY)}),o.w=o.x2-o.x1,o.h=o.y2-o.y1),i.positions(function(t,n){var i=e.layoutNodes[e.idToIndex[n.data("id")]];if(r.boundingBox){var s=(i.positionX-o.x1)/o.w,l=(i.positionY-o.y1)/o.h;return{x:a.x1+s*a.w,y:a.y1+l*a.h}}return{x:i.positionX,y:i.positionY}}),!0!==e.ready&&(e.ready=!0,n.one("layoutready",r.ready),n.trigger({type:"layoutready",layout:this}))};t.exports=n},{"../../is":77,"../../math":79,"../../thread":92,"../../util":94}],49:[function(e,t,r){"use strict";function n(e){this.options=i.extend({},o,e)}var i=e("../../util"),a=e("../../math"),o={fit:!0,padding:30,boundingBox:void 0,avoidOverlap:!0,avoidOverlapPadding:10,condense:!1,rows:void 0,cols:void 0,position:function(e){},sort:void 0,animate:!1,animationDuration:500,animationEasing:void 0,ready:void 0,stop:void 0};n.prototype.run=function(){var e=this.options,t=e,r=e.cy,n=t.eles,i=n.nodes().not(":parent");t.sort&&(i=i.sort(t.sort));var o=a.makeBoundingBox(t.boundingBox?t.boundingBox:{x1:0,y1:0,w:r.width(),h:r.height()});if(0===o.h||0===o.w)i.layoutPositions(this,t,function(){return{x:o.x1,y:o.y1}});else{var s=i.size(),l=Math.sqrt(s*o.h/o.w),u=Math.round(l),c=Math.round(o.w/o.h*l),d=function(e){if(null==e)return Math.min(u,c);var t=Math.min(u,c);t==u?u=e:c=e},h=function(e){if(null==e)return Math.max(u,c);var t=Math.max(u,c);t==u?u=e:c=e},p=t.rows,v=null!=t.cols?t.cols:t.columns;if(null!=p&&null!=v)u=p,c=v;else if(null!=p&&null==v)u=p,c=Math.ceil(s/u);else if(null==p&&null!=v)c=v,u=Math.ceil(s/c);else if(c*u>s){var f=d(),g=h();(f-1)*g>=s?d(f-1):(g-1)*f>=s&&h(g-1)}else for(;s>c*u;){var f=d(),g=h();(g+1)*f>=s?h(g+1):d(f+1)}var y=o.w/c,m=o.h/u;if(t.condense&&(y=0,m=0),t.avoidOverlap)for(var b=0;b<i.length;b++){var x=i[b],w=x._private.position;(null==w.x||null==w.y)&&(w.x=0,w.y=0);var _=x.boundingBox(),E=t.avoidOverlapPadding,D=_.w+E,S=_.h+E;y=Math.max(y,D),m=Math.max(m,S)}for(var k={},T=function(e,t){return k["c-"+e+"-"+t]?!0:!1},P=function(e,t){k["c-"+e+"-"+t]=!0},C=0,N=0,M=function(){N++,N>=c&&(N=0,C++)},B={},b=0;b<i.length;b++){var x=i[b],z=t.position(x);if(z&&(void 0!==z.row||void 0!==z.col)){var w={row:z.row,col:z.col};if(void 0===w.col)for(w.col=0;T(w.row,w.col);)w.col++;else if(void 0===w.row)for(w.row=0;T(w.row,w.col);)w.row++;B[x.id()]=w,P(w.row,w.col)}}var O=function(e,t){var r,n;if(t.locked()||t.isFullAutoParent())return!1;var i=B[t.id()];if(i)r=i.col*y+y/2+o.x1,n=i.row*m+m/2+o.y1;else{for(;T(C,N);)M();r=N*y+y/2+o.x1,n=C*m+m/2+o.y1,P(C,N),M()}return{x:r,y:n}};i.layoutPositions(this,t,O)}return this},t.exports=n},{"../../math":79,"../../util":94}],50:[function(e,t,r){"use strict";t.exports=[{name:"breadthfirst",impl:e("./breadthfirst")},{name:"circle",impl:e("./circle")},{name:"concentric",impl:e("./concentric")},{name:"cose",impl:e("./cose")},{name:"grid",impl:e("./grid")},{name:"null",impl:e("./null")},{name:"preset",impl:e("./preset")},{name:"random",impl:e("./random")}]},{"./breadthfirst":45,"./circle":46,"./concentric":47,"./cose":48,"./grid":49,"./null":51,"./preset":52,"./random":53}],51:[function(e,t,r){"use strict";function n(e){this.options=i.extend({},a,e)}var i=e("../../util"),a={ready:function(){},stop:function(){}};n.prototype.run=function(){var e=this.options,t=e.eles,r=this;e.cy;return r.trigger("layoutstart"),t.nodes().positions(function(){return{x:0,y:0}}),r.one("layoutready",e.ready),r.trigger("layoutready"),r.one("layoutstop",e.stop),r.trigger("layoutstop"),this},n.prototype.stop=function(){return this},t.exports=n},{"../../util":94}],52:[function(e,t,r){"use strict";function n(e){this.options=i.extend({},o,e)}var i=e("../../util"),a=e("../../is"),o={positions:void 0,zoom:void 0,pan:void 0,fit:!0,padding:30,animate:!1,animationDuration:500,animationEasing:void 0,ready:void 0,stop:void 0};n.prototype.run=function(){function e(e){if(null==t.positions)return null;if(i)return t.positions.apply(e,[e]);var r=t.positions[e._private.data.id];return null==r?null:r}var t=this.options,r=t.eles,n=r.nodes(),i=a.fn(t.positions);return n.layoutPositions(this,t,function(t,r){var n=e(r);return r.locked()||null==n?!1:n}),this},t.exports=n},{"../../is":77,"../../util":94}],53:[function(e,t,r){"use strict";function n(e){this.options=i.extend({},o,e)}var i=e("../../util"),a=e("../../math"),o={fit:!0,padding:30,boundingBox:void 0,animate:!1,animationDuration:500,animationEasing:void 0,ready:void 0,stop:void 0};n.prototype.run=function(){var e=this.options,t=e.cy,r=e.eles,n=r.nodes().not(":parent"),i=a.makeBoundingBox(e.boundingBox?e.boundingBox:{x1:0,y1:0,w:t.width(),h:t.height()}),o=function(e,t){return{x:i.x1+Math.round(Math.random()*i.w),y:i.y1+Math.round(Math.random()*i.h)}};return n.layoutPositions(this,e,o),this},t.exports=n},{"../../math":79,"../../util":94}],54:[function(e,t,r){"use strict";var n=e("../../../math"),i=e("../../../is"),a=e("../../../util"),o={};o.arrowShapeHeight=.3,o.registerArrowShapes=function(){var e=this.arrowShapes={},t=this,r=function(e,t,r,n,i,a){var o=i.x-r/2-a,s=i.x+r/2+a,l=i.y-r/2-a,u=i.y+r/2+a,c=e>=o&&s>=e&&t>=l&&u>=t;return c},o=function(e,t,r,n,i){var a=e*Math.cos(n)-t*Math.sin(n),o=e*Math.sin(n)+t*Math.cos(n),s=a*r,l=o*r,u=s+i.x,c=l+i.y;return{x:u,y:c}},s=function(e,t,r,n){for(var i=[],a=0;a<e.length;a+=2){var s=e[a],l=e[a+1];i.push(o(s,l,t,r,n))}return i},l=function(e){for(var t=[],r=0;r<e.length;r++){var n=e[r];t.push(n.x,n.y)}return t},u=function(o,u){i.string(u)&&(u=e[u]),e[o]=a.extend({name:o,points:[-.15,-.3,.15,-.3,.15,.3,-.15,.3],collide:function(e,t,r,i,a,o){var u=l(s(this.points,r+2*o,i,a)),c=n.pointInsidePolygonPoints(e,t,u);return c},roughCollide:r,draw:function(e,r,n,i){var a=s(this.points,r,n,i);t.arrowShapeImpl("polygon")(e,a)},spacing:function(e){return 0},gap:function(e){return 2*e._private.style.width.pfValue}},u)};u("none",{collide:a.falsify,roughCollide:a.falsify,draw:a.noop,spacing:a.zeroify,gap:a.zeroify}),u("triangle",{points:[-.15,-.3,0,0,.15,-.3]}),u("arrow","triangle"),u("triangle-backcurve",{points:e.triangle.points,controlPoint:[0,-.15],roughCollide:r,draw:function(e,r,n,i){var a=s(this.points,r,n,i),l=this.controlPoint,u=o(l[0],l[1],r,n,i);t.arrowShapeImpl(this.name)(e,a,u)},gap:function(e){return e._private.style.width.pfValue}}),u("triangle-tee",{points:[-.15,-.3,0,0,.15,-.3,-.15,-.3],pointsTee:[-.15,-.4,-.15,-.5,.15,-.5,.15,-.4],collide:function(e,t,r,i,a,o){var u=l(s(this.points,r+2*o,i,a)),c=l(s(this.pointsTee,r+2*o,i,a)),d=n.pointInsidePolygonPoints(e,t,u)||n.pointInsidePolygonPoints(e,t,c);return d},draw:function(e,r,n,i){var a=s(this.points,r,n,i),o=s(this.pointsTee,r,n,i);t.arrowShapeImpl(this.name)(e,a,o)}}),u("vee",{points:[-.15,-.3,0,0,.15,-.3,0,-.15],gap:function(e){return e._private.style.width.pfValue}}),u("half-triangle-overshot",{points:[0,-.25,-.5,-.25,.5,.25],leavePathOpen:!0,matchEdgeWidth:!0}),u("circle",{radius:.15,collide:function(e,t,r,n,i,a){var o=i,s=Math.pow(o.x-e,2)+Math.pow(o.y-t,2)<=Math.pow((r+2*a)*this.radius,2);return s},draw:function(e,r,n,i){t.arrowShapeImpl(this.name)(e,i.x,i.y,this.radius*r)},spacing:function(e){return t.getArrowWidth(e._private.style.width.pfValue)*this.radius}}),u("inhibitor",{points:[-.25,0,-.25,-.1,.25,-.1,.25,0],spacing:function(e){return 1},gap:function(e){return 1}}),u("tee","inhibitor"),u("square",{points:[-.15,0,.15,0,.15,-.3,-.15,-.3]}),u("diamond",{points:[-.15,-.15,0,-.3,.15,-.15,0,0],gap:function(e){return e._private.style.width.pfValue}})},t.exports=o},{"../../../is":77,"../../../math":79,"../../../util":94}],55:[function(e,t,r){"use strict";var n={},i=function(e){e.eleEache=null},a=function(e){return e.eleEache||(e.eleEache={nodes:e.cy.nodes(),edges:e.cy.edges()}),e.eleEache};n.getCachedElements=function(){return a(this)},n.getCachedNodes=function(){return a(this).nodes},n.getCachedEdges=function(){return a(this).edges},n.updateElementsCache=function(){var e=this;return i(e),a(e)},t.exports=n},{}],56:[function(e,t,r){"use strict";function n(e,t){var r=function(e,t,r,n){return i.qbezierAt(e,t,r,n)},n=e._private,a=n.rstyle.bezierPts;a.push({x:r(t[0],t[2],t[4],.05),y:r(t[1],t[3],t[5],.05)}),a.push({x:r(t[0],t[2],t[4],.25),y:r(t[1],t[3],t[5],.25)}),a.push({x:r(t[0],t[2],t[4],.4),y:r(t[1],t[3],t[5],.4)}),a.push({x:r(t[0],t[2],t[4],.5),y:r(t[1],t[3],t[5],.5)}),a.push({x:r(t[0],t[2],t[4],.6),y:r(t[1],t[3],t[5],.6)}),a.push({x:r(t[0],t[2],t[4],.75),y:r(t[1],t[3],t[5],.75)}),a.push({x:r(t[0],t[2],t[4],.95),y:r(t[1],t[3],t[5],.95)})}var i=e("../../../math"),a=e("../../../is"),o=e("../../../collection/zsort"),s={};s.projectIntoViewport=function(e,t){var r=this.findContainerClientCoords(),n=r[0],i=r[1],a=e-n,o=t-i;return a-=this.cy.pan().x,o-=this.cy.pan().y,a/=this.cy.zoom(),o/=this.cy.zoom(),[a,o]},s.findContainerClientCoords=function(){var e=this.container,t=this.containerBB=this.containerBB||e.getBoundingClientRect();return[t.left,t.top,t.right-t.left,t.bottom-t.top]},s.invalidateContainerClientCoordsCache=function(){this.containerBB=null},s.findNearestElement=function(e,t,r,n){function a(n){var i=n._private;if("no"!==i.style.events.strValue){var a=n.outerWidth()+2*f,o=n.outerHeight()+2*f,s=a/2,c=o/2,h=i.position;if(h.x-s<=e&&e<=h.x+s&&h.y-c<=t&&t<=h.y+c){var p=!r||n.visible()&&!n.transparent();if(r&&!p)return;var v=u.nodeShapes[l.getNodeShape(n)];v.checkPoint(e,t,0,a,o,h.x,h.y)&&d.push(n)}}}function o(n){var o=n._private;if("no"!==o.style.events.strValue){var s,c,h=o.rscratch,f=o.style,g=f.width.pfValue/2+v,y=g*g,m=2*g,b=o.source,x=o.target,w=!1,_=function(){if(void 0!==c)return c;if(!r)return c=!0,!0;var e=n.visible()&&!n.transparent();return e?(c=!0,!0):(c=!1,!1)};if("segments"===h.edgeType||"straight"===h.edgeType||"haystack"===h.edgeType)for(var E=h.allpts,D=0;D+3<E.length;D+=2)(w=i.inLineVicinity(e,t,E[D],E[D+1],E[D+2],E[D+3],m))&&_()&&y>(s=i.sqDistanceToFiniteLine(e,t,E[D],E[D+1],E[D+2],E[D+3]))&&d.push(n);else if("bezier"===h.edgeType||"multibezier"===h.edgeType||"self"===h.edgeType||"compound"===h.edgeType)for(var E=h.allpts,D=0;D+5<h.allpts.length;D+=4)(w=i.inBezierVicinity(e,t,E[D],E[D+1],E[D+2],E[D+3],E[D+4],E[D+5],m))&&_()&&y>(s=i.sqDistanceToQuadraticBezier(e,t,E[D],E[D+1],E[D+2],E[D+3],E[D+4],E[D+5]))&&d.push(n);if(w&&_()&&0===d.length||d[d.length-1]!==n)for(var b=b||o.source,x=x||o.target,S=f.width.pfValue,k=l.getArrowWidth(S),T=[{name:"source",x:h.arrowStartX,y:h.arrowStartY,angle:h.srcArrowAngle},{name:"target",x:h.arrowEndX,y:h.arrowEndY,angle:h.tgtArrowAngle},{name:"mid-source",x:h.midX,y:h.midY,angle:h.midsrcArrowAngle},{name:"mid-target",x:h.midX,y:h.midY,angle:h.midtgtArrowAngle}],D=0;D<T.length;D++){var P=T[D],C=u.arrowShapes[f[P.name+"-arrow-shape"].value];if(C.roughCollide(e,t,k,P.angle,{x:P.x,y:P.y},v)&&C.collide(e,t,k,P.angle,{x:P.x,y:P.y},v)){d.push(n);break}}p&&d.length>0&&d[d.length-1]===n&&(a(b),a(x))}}function s(r){var n=r._private,a=g;if("no"!==n.style["text-events"].strValue)if("edges"===n.group&&"autorotate"===n.style["edge-text-rotation"].strValue){var o=n.rstyle,s=o.labelWidth+2*a,l=o.labelHeight+2*a,u=o.labelX,c=o.labelY,h=n.rscratch.labelAngle,p=Math.cos(h),v=Math.sin(h),f=function(e,t){return e-=u,t-=c,{x:e*p-t*v+u,y:e*v+t*p+c}},y=u-s/2,m=u+s/2,b=c-l/2,x=c+l/2,w=f(y,b),_=f(y,x),E=f(m,b),D=f(m,x),S=[w.x,w.y,E.x,E.y,D.x,D.y,_.x,_.y];i.pointInsidePolygonPoints(e,t,S)&&d.push(r)}else{var k=r.boundingBox({includeLabels:!0,includeNodes:!1,includeEdges:!1});k.x1-=a,k.y1-=a,k.x2+=a,k.y2+=a,k.w=k.x2-k.x1,k.h=k.y2-k.y1,i.inBoundingBox(k,e,t)&&d.push(r)}}for(var l=this,u=this,c=u.getCachedZSortedEles(),d=[],h=u.cy.zoom(),p=u.cy.hasCompoundNodes(),v=(n?24:8)/h,f=(n?8:2)/h,g=(n?8:2)/h,y=c.length-1;y>=0;y--){var m=c[y],b=m._private;if(d.length>0)break;"nodes"===b.group?a(m):o(m),s(m)}return d.length>0?d[d.length-1]:null},s.getAllInBox=function(e,t,r,n){var a=this.getCachedNodes(),o=this.getCachedEdges(),s=[],l=Math.min(e,r),u=Math.max(e,r),c=Math.min(t,n),d=Math.max(t,n);e=l,r=u,t=c,n=d;for(var h=i.makeBoundingBox({x1:e,y1:t,x2:r,y2:n}),p=0;p<a.length;p++){var v=a[p],f=v.boundingBox({includeNodes:!0,includeEdges:!1,includeLabels:!1});i.boundingBoxesIntersect(h,f)&&s.push(a[p])}for(var g=0;g<o.length;g++){var y=o[g],m=y._private,b=m.rscratch;if((null==b.startX||null==b.startY||i.inBoundingBox(h,b.startX,b.startY))&&(null==b.endX||null==b.endY||i.inBoundingBox(h,b.endX,b.endY)))if("bezier"===b.edgeType||"multibezier"===b.edgeType||"self"===b.edgeType||"compound"===b.edgeType||"segments"===b.edgeType||"haystack"===b.edgeType){for(var x=m.rstyle.bezierPts||m.rstyle.linePts||m.rstyle.haystackPts,w=!0,p=0;p<x.length;p++)if(!i.pointInBoundingBox(h,x[p])){w=!1;break}w&&s.push(y)}else("haystack"===b.edgeType||"straight"===b.edgeType)&&s.push(y)}return s},s.getNodeShape=function(e){var t=this,r=e._private.style,n=r.shape.value;if(e.isParent())return"rectangle"===n||"roundrectangle"===n?n:"rectangle";if("polygon"===n){var i=r["shape-polygon-points"].value;return t.nodeShapes.makePolygon(i).name}return n},s.updateCachedZSortedEles=function(){this.getCachedZSortedEles(!0)},s.getCachedZSortedEles=function(e){var t=this.lastZOrderCachedNodes,r=this.lastZOrderCachedEdges,n=this.getCachedNodes(),i=this.getCachedEdges(),a=[];if(!e&&t&&r&&t===n&&r===i)a=this.cachedZSortedEles;else{for(var s=0;s<n.length;s++){var l=n[s];(l.animated()||l.visible()&&!l.transparent())&&a.push(l)}for(var s=0;s<i.length;s++){var u=i[s];(u.animated()||u.visible()&&!u.transparent())&&a.push(u)}a.sort(o),this.cachedZSortedEles=a}return this.lastZOrderCachedNodes=n,this.lastZOrderCachedEdges=i,a},s.projectLines=function(e){var t=e._private,r=t.rscratch,i=r.edgeType;if("multibezier"===i||"bezier"===i||"self"===i||"compound"===i)for(var a=(t.rstyle.bezierPts=[],0);a+5<r.allpts.length;a+=4)n(e,r.allpts.slice(a,a+6));else if("segments"===i)for(var o=t.rstyle.linePts=[],a=0;a+1<r.allpts.length;a+=2)o.push({x:r.allpts[a],y:r.allpts[a+1]});else if("haystack"===i){var s=r.haystackPts;t.rstyle.haystackPts=[{x:s[0],y:s[1]},{x:s[2],y:s[3]}]}},s.projectBezier=s.projectLines,s.recalculateNodeLabelProjection=function(e){var t=e._private.style.label.strValue;if(t&&!t.match(/^\s+$/)){var r,n,i=e.outerWidth(),a=e.outerHeight(),o=e._private.position,s=e._private.style["text-halign"].strValue,l=e._private.style["text-valign"].strValue,u=e._private.rscratch,c=e._private.rstyle;switch(s){case"left":r=o.x-i/2;break;case"right":r=o.x+i/2;break;default:r=o.x}switch(l){case"top":n=o.y-a/2;break;case"bottom":n=o.y+a/2;break;default:n=o.y}u.labelX=r,u.labelY=n,c.labelX=r,c.labelY=n,this.applyLabelDimensions(e)}},s.recalculateEdgeLabelProjection=function(e){var t=e._private.style.label.strValue;if(t&&!t.match(/^\s+$/)){var r,n,i=e._private,a=i.rscratch,o=i.rstyle;r=a.midX,n=a.midY,a.labelX=r,a.labelY=n,o.labelX=r,o.labelY=n,this.applyLabelDimensions(e)}},s.applyLabelDimensions=function(e){var t=e._private.rscratch,r=e._private.rstyle,n=this.getLabelText(e),i=this.calculateLabelDimensions(e,n);r.labelWidth=i.width,t.labelWidth=i.width,r.labelHeight=i.height,t.labelHeight=i.height},s.getLabelText=function(e){var t=e._private.style,r=e._private.style.label.strValue,n=t["text-transform"].value,i=e._private.rscratch;if("none"==n||("uppercase"==n?r=r.toUpperCase():"lowercase"==n&&(r=r.toLowerCase())),"wrap"===t["text-wrap"].value){if(i.labelWrapKey===i.labelKey)return i.labelWrapCachedText;for(var a=r.split("\n"),o=t["text-max-width"].pfValue,s=[],l=0;l<a.length;l++){var u=a[l],c=this.calculateLabelDimensions(e,u,"line="+u),d=c.width;if(d>o){for(var h=u.split(/\s+/),p="",v=0;v<h.length;v++){var f=h[v],g=0===p.length?f:p+" "+f,y=this.calculateLabelDimensions(e,g,"testLine="+g),m=y.width;o>=m?p+=f+" ":(s.push(p),p=f+" ")}p.match(/^\s+$/)||s.push(p)}else s.push(u)}i.labelWrapCachedLines=s,i.labelWrapCachedText=r=s.join("\n"),i.labelWrapKey=i.labelKey}return r},s.calculateLabelDimensions=function(e,t,r){var n=this,i=e._private.style,a=i["font-style"].strValue,o=i["font-size"].pfValue+"px",s=i["font-family"].strValue,l=i["font-weight"].strValue,u=e._private.labelKey;r&&(u+="$@$"+r);var c=n.labelDimCache||(n.labelDimCache={});if(c[u])return c[u];var d=this.labelCalcDiv;d||(d=this.labelCalcDiv=document.createElement("div"),document.body.appendChild(d));var h=d.style;return h.fontFamily=s,h.fontStyle=a,h.fontSize=o,h.fontWeight=l,h.position="absolute",h.left="-9999px",h.top="-9999px",h.zIndex="-1",h.visibility="hidden",h.pointerEvents="none",h.padding="0",h.lineHeight="1","wrap"===i["text-wrap"].value?h.whiteSpace="pre":h.whiteSpace="normal",d.textContent=t,c[u]={width:d.clientWidth,height:d.clientHeight},c[u]},s.recalculateRenderedStyle=function(e){for(var t=[],r=[],n={},i=0;i<e.length;i++){var a=e[i],o=a._private,s=o.style,l=o.rscratch,u=o.rstyle,c=o.data.id,d=null!=l.boundingBoxKey&&o.boundingBoxKey===l.boundingBoxKey,h=null!=l.labelKey&&o.labelKey===l.labelKey,p=d&&h;if("nodes"===o.group){var v=o.position,f=null!=u.nodeX&&null!=u.nodeY&&v.x===u.nodeX&&v.y===u.nodeY,g=null!=u.nodeW&&u.nodeW===s.width.pfValue,y=null!=u.nodeH&&u.nodeH===s.height.pfValue;f&&p&&g&&y||r.push(a),u.nodeX=v.x,u.nodeY=v.y,u.nodeW=s.width.pfValue,u.nodeH=s.height.pfValue}else{var m=o.source._private.position,b=o.target._private.position,x=null!=u.srcX&&null!=u.srcY&&m.x===u.srcX&&m.y===u.srcY,w=null!=u.tgtX&&null!=u.tgtY&&b.x===u.tgtX&&b.y===u.tgtY,_=x&&w;if(!_||!p)if("bezier"===l.edgeType||"straight"===l.edgeType||"self"===l.edgeType||"compound"===l.edgeType){if(!n[c]){t.push(a),n[c]=!0;for(var E=a.parallelEdges(),i=0;i<E.length;i++){var D=E[i],S=D._private.data.id;n[S]||(t.push(D),n[S]=!0)}}}else t.push(a);u.srcX=m.x,u.srcY=m.y,u.tgtX=b.x,u.tgtY=b.y}l.boundingBoxKey=o.boundingBoxKey,l.labelKey=o.labelKey}this.recalculateEdgeProjections(t),this.recalculateLabelProjections(r,t)},s.recalculateLabelProjections=function(e,t){for(var r=0;r<e.length;r++)this.recalculateNodeLabelProjection(e[r]);for(var r=0;r<t.length;r++)this.recalculateEdgeLabelProjection(t[r])},s.recalculateEdgeProjections=function(e){this.findEdgeControlPoints(e)},s.findEdgeControlPoints=function(e){if(e&&0!==e.length){for(var t,r=this,n=r.cy,o=n.hasCompoundNodes(),s={},l=[],u=[],c=[],d=0;d<e.length;d++){var h=e[d],p=h._private,v=p.data,f=p.style,g=f["curve-style"].value,y="unbundled-bezier"===g||"segments"===g;if("none"!==f.display.value)if("autorotate"===f["edge-text-rotation"].strValue&&c.push(h),"haystack"!==g){var m=v.source,b=v.target;t=m>b?b+"$-$"+m:m+"$-$"+b,y&&(t="unbundled$-$"+v.id),null==s[t]&&(s[t]=[],l.push(t)),s[t].push(h),y&&(s[t].hasUnbundled=!0)}else u.push(h)}for(var x,w,_,E,D,S,k,T,P,C,N,M,B,z,O=0;O<l.length;O++){t=l[O];var I=s[t];if(I.sort(function(e,t){return e._private.index-t._private.index}),x=I[0]._private.source,w=I[0]._private.target,_=x._private,E=w._private,_.data.id>E.data.id){var L=x;x=w,w=L}if(D=_.position,S=E.position,k=x.outerWidth(),T=x.outerHeight(),P=w.outerWidth(),C=w.outerHeight(),N=r.nodeShapes[this.getNodeShape(x)],M=r.nodeShapes[this.getNodeShape(w)],z=!1,I.length>1&&x!==w||I.hasUnbundled){var A=N.intersectLine(D.x,D.y,k,T,S.x,S.y,0),R=M.intersectLine(S.x,S.y,P,C,D.x,D.y,0),V={x1:A[0],x2:R[0],y1:A[1],y2:R[1]},F=R[1]-A[1],j=R[0]-A[0],q=Math.sqrt(j*j+F*F),X={
+x:j,y:F},Y={x:X.x/q,y:X.y/q};B={x:-Y.y,y:Y.x},(M.checkPoint(A[0],A[1],0,P,C,S.x,S.y)||N.checkPoint(R[0],R[1],0,k,T,D.x,D.y))&&(B={},z=!0)}for(var h,$,H,d=0;d<I.length;d++){h=I[d],$=h._private,H=$.rscratch;var W=H.lastEdgeIndex,Z=d,U=H.lastNumEdges,G=I.length,K=$.style,f=K,g=K["curve-style"].value,J=K["control-point-distances"],Q=K["control-point-weights"],ee=J&&Q?Math.min(J.value.length,Q.value.length):1,te=K["control-point-step-size"].pfValue,re=void 0!==J?J.pfValue[0]:void 0,ne=Q.value[0],y="unbundled-bezier"===g||"segments"===g,ie=$.source!==x;ie&&y&&(re*=-1);var ae=H.lastSrcCtlPtX,oe=D.x,se=H.lastSrcCtlPtY,le=D.y,ue=H.lastSrcCtlPtW,ce=x.outerWidth(),de=H.lastSrcCtlPtH,he=x.outerHeight(),pe=H.lastTgtCtlPtX,ve=S.x,fe=H.lastTgtCtlPtY,ge=S.y,ye=H.lastTgtCtlPtW,me=w.outerWidth(),be=H.lastTgtCtlPtH,xe=w.outerHeight(),we=H.lastW,_e=K["control-point-step-size"].pfValue;if(z?H.badBezier=!0:H.badBezier=!1,ae!==oe||se!==le||ue!==ce||de!==he||pe!==ve||fe!==ge||ye!==me||be!==xe||we!==_e||!(W===Z&&U===G||y)){if(H.lastSrcCtlPtX=oe,H.lastSrcCtlPtY=le,H.lastSrcCtlPtW=ce,H.lastSrcCtlPtH=he,H.lastTgtCtlPtX=ve,H.lastTgtCtlPtY=ge,H.lastTgtCtlPtW=me,H.lastTgtCtlPtH=xe,H.lastEdgeIndex=Z,H.lastNumEdges=G,H.lastWidth=_e,x===w){H.edgeType="self";var Ee=d,De=te;y&&(Ee=0,De=re),H.ctrlpts=[D.x,D.y-(1+Math.pow(T,1.12)/100)*De*(Ee/3+1),D.x-(1+Math.pow(k,1.12)/100)*De*(Ee/3+1),D.y]}else if(o&&(x.isParent()||x.isChild()||w.isParent()||w.isChild())&&(x.parents().anySame(w)||w.parents().anySame(x))){H.edgeType="compound",H.badBezier=!1;var Ee=d,De=te;y&&(Ee=0,De=re);var Se=50,ke={x:D.x-k/2,y:D.y-T/2},Te={x:S.x-P/2,y:S.y-C/2},Pe={x:Math.min(ke.x,Te.x),y:Math.min(ke.y,Te.y)},Ce=.5,Ne=Math.max(Ce,Math.log(.01*k)),Me=Math.max(Ce,Math.log(.01*P));H.ctrlpts=[Pe.x,Pe.y-(1+Math.pow(Se,1.12)/100)*De*(Ee/3+1)*Ne,Pe.x-(1+Math.pow(Se,1.12)/100)*De*(Ee/3+1)*Me,Pe.y]}else if("segments"===g){H.edgeType="segments",H.segpts=[];for(var Be=K["segment-weights"].pfValue,ze=K["segment-distances"].pfValue,Oe=Math.min(Be.length,ze.length),Ie=0;Oe>Ie;Ie++){var Le=Be[Ie],Ae=ze[Ie],Re=1-Le,Ve=Le,Fe={x:V.x1*Re+V.x2*Ve,y:V.y1*Re+V.y2*Ve};H.segpts.push(Fe.x+B.x*Ae,Fe.y+B.y*Ae)}}else if(I.length%2!==1||d!==Math.floor(I.length/2)||y){var je=y;H.edgeType=je?"multibezier":"bezier",H.ctrlpts=[];for(var qe=0;ee>qe;qe++){var Xe,Ye=(.5-I.length/2+d)*te,$e=i.signum(Ye);je&&(re=J?J.pfValue[qe]:te,ne=Q.value[qe]),Xe=y?re:void 0!==re?$e*re:void 0;var He=void 0!==Xe?Xe:Ye,Re=!ie||y?1-ne:ne,Ve=!ie||y?ne:1-ne,Fe={x:V.x1*Re+V.x2*Ve,y:V.y1*Re+V.y2*Ve};H.ctrlpts.push(Fe.x+B.x*He,Fe.y+B.y*He)}}else H.edgeType="straight";this.findEndpoints(h);var We=!a.number(H.startX)||!a.number(H.startY),Ze=!a.number(H.arrowStartX)||!a.number(H.arrowStartY),Ue=!a.number(H.endX)||!a.number(H.endY),Ge=!a.number(H.arrowEndX)||!a.number(H.arrowEndY),Ke=3,Je=this.getArrowWidth(K.width.pfValue)*this.arrowShapeHeight,Qe=Ke*Je;if("bezier"===H.edgeType){var et=i.distance({x:H.ctrlpts[0],y:H.ctrlpts[1]},{x:H.startX,y:H.startY}),tt=Qe>et,rt=i.distance({x:H.ctrlpts[0],y:H.ctrlpts[1]},{x:H.endX,y:H.endY}),nt=Qe>rt,it=!1;if(We||Ze||tt){it=!0;var at={x:H.ctrlpts[0]-D.x,y:H.ctrlpts[1]-D.y},ot=Math.sqrt(at.x*at.x+at.y*at.y),st={x:at.x/ot,y:at.y/ot},lt=Math.max(k,T),ut={x:H.ctrlpts[0]+2*st.x*lt,y:H.ctrlpts[1]+2*st.y*lt},ct=N.intersectLine(D.x,D.y,k,T,ut.x,ut.y,0);tt?(H.ctrlpts[0]=H.ctrlpts[0]+st.x*(Qe-et),H.ctrlpts[1]=H.ctrlpts[1]+st.y*(Qe-et)):(H.ctrlpts[0]=ct[0]+st.x*Qe,H.ctrlpts[1]=ct[1]+st.y*Qe)}if(Ue||Ge||nt){it=!0;var at={x:H.ctrlpts[0]-S.x,y:H.ctrlpts[1]-S.y},ot=Math.sqrt(at.x*at.x+at.y*at.y),st={x:at.x/ot,y:at.y/ot},lt=Math.max(k,T),ut={x:H.ctrlpts[0]+2*st.x*lt,y:H.ctrlpts[1]+2*st.y*lt},dt=M.intersectLine(S.x,S.y,P,C,ut.x,ut.y,0);nt?(H.ctrlpts[0]=H.ctrlpts[0]+st.x*(Qe-rt),H.ctrlpts[1]=H.ctrlpts[1]+st.y*(Qe-rt)):(H.ctrlpts[0]=dt[0]+st.x*Qe,H.ctrlpts[1]=dt[1]+st.y*Qe)}it&&this.findEndpoints(h)}if("multibezier"===H.edgeType||"bezier"===H.edgeType||"self"===H.edgeType||"compound"===H.edgeType){H.allpts=[],H.allpts.push(H.startX,H.startY);for(var qe=0;qe+1<H.ctrlpts.length;qe+=2)H.allpts.push(H.ctrlpts[qe],H.ctrlpts[qe+1]),qe+3<H.ctrlpts.length&&H.allpts.push((H.ctrlpts[qe]+H.ctrlpts[qe+2])/2,(H.ctrlpts[qe+1]+H.ctrlpts[qe+3])/2);H.allpts.push(H.endX,H.endY);var ht,pt;"bezier"===H.edgeType?(H.midX=i.qbezierAt(H.arrowStartX,H.ctrlpts[0],H.arrowEndX,.5),H.midY=i.qbezierAt(H.arrowStartY,H.ctrlpts[1],H.arrowEndY,.5)):H.ctrlpts.length/2%2===0?(ht=H.allpts.length/2-1,H.midX=H.allpts[ht],H.midY=H.allpts[ht+1]):(ht=H.allpts.length/2-3,pt=.5,H.midX=i.qbezierAt(H.allpts[ht],H.allpts[ht+2],H.allpts[ht+4],pt),H.midY=i.qbezierAt(H.allpts[ht+1],H.allpts[ht+3],H.allpts[ht+5],pt))}else if("straight"===H.edgeType)H.allpts=[H.startX,H.startY,H.endX,H.endY],H.midX=(H.arrowStartX+H.arrowEndX)/2,H.midY=(H.arrowStartY+H.arrowEndY)/2;else if("segments"===H.edgeType)if(H.allpts=[],H.allpts.push(H.startX,H.startY),H.allpts.push.apply(H.allpts,H.segpts),H.allpts.push(H.endX,H.endY),H.segpts.length%4===0){var vt=H.segpts.length/2,ft=vt-2;H.midX=(H.segpts[ft]+H.segpts[vt])/2,H.midY=(H.segpts[ft+1]+H.segpts[vt+1])/2}else{var ft=H.segpts.length/2-1;H.midX=H.segpts[ft],H.midY=H.segpts[ft+1]}this.projectLines(h),this.calculateArrowAngles(h),this.recalculateEdgeLabelProjection(h)}}}for(var d=0;d<u.length;d++){var h=u[d],p=h._private,f=p.style,gt=p.rscratch,H=gt;if(!gt.haystack){var yt=2*Math.random()*Math.PI;gt.source={x:Math.cos(yt),y:Math.sin(yt)};var yt=2*Math.random()*Math.PI;gt.target={x:Math.cos(yt),y:Math.sin(yt)}}var x=p.source,w=p.target,D=x._private.position,S=w._private.position,k=x.width(),P=w.width(),T=x.height(),C=w.height(),lt=f["haystack-radius"].value,mt=lt/2;H.haystackPts=H.allpts=[H.source.x*k*mt+D.x,H.source.y*T*mt+D.y,H.target.x*P*mt+S.x,H.target.y*C*mt+S.y],H.midX=(H.allpts[0]+H.allpts[2])/2,H.midY=(H.allpts[1]+H.allpts[3])/2,gt.edgeType="haystack",gt.haystack=!0,this.projectLines(h),this.calculateArrowAngles(h),this.recalculateEdgeLabelProjection(h)}for(var d=0;d<c.length;d++){var h=c[d],H=h._private.rscratch;H.labelAngle=Math.atan(H.midDispY/H.midDispX)}return s}};var l=function(e,t){return Math.atan2(t,e)-Math.PI/2};s.calculateArrowAngles=function(e){var t,r,n,a,o,s,u=e._private.rscratch,c="haystack"===u.edgeType,d="multibezier"===u.edgeType,h="segments"===u.edgeType,p="compound"===u.edgeType,v="self"===u.edgeType,f=e.source().position(),g=e.target().position();c?(n=u.haystackPts[0],a=u.haystackPts[1],o=u.haystackPts[2],s=u.haystackPts[3]):(n=u.arrowStartX,a=u.arrowStartY,o=u.arrowEndX,s=u.arrowEndY),t=f.x-n,r=f.y-a,u.srcArrowAngle=l(t,r);var y=u.midX,m=u.midY;if(c&&(y=(n+o)/2,m=(a+s)/2),t=o-n,r=s-a,v)t=-1,r=1;else if(h){var b=u.allpts;if(b.length/2%2===0){var x=b.length/2,w=x-2;t=b[x]-b[w],r=b[x+1]-b[w+1]}else{var x=b.length/2-1,w=x-2,_=x+2;t=b[x]-b[w],r=b[x+1]-b[w+1]}}else if(d||p){var E,D,S,k,b=u.allpts,T=u.ctrlpts;if(T.length/2%2===0){var P=b.length/2-1,C=P+2,N=C+2;E=i.qbezierAt(b[P],b[C],b[N],0),D=i.qbezierAt(b[P+1],b[C+1],b[N+1],0),S=i.qbezierAt(b[P],b[C],b[N],1e-4),k=i.qbezierAt(b[P+1],b[C+1],b[N+1],1e-4)}else{var C=b.length/2-1,P=C-2,N=C+2;E=i.qbezierAt(b[P],b[C],b[N],.4999),D=i.qbezierAt(b[P+1],b[C+1],b[N+1],.4999),S=i.qbezierAt(b[P],b[C],b[N],.5),k=i.qbezierAt(b[P+1],b[C+1],b[N+1],.5)}t=S-E,r=k-D}if(u.midtgtArrowAngle=l(t,r),u.midDispX=t,u.midDispY=r,t*=-1,r*=-1,h){var b=u.allpts;if(b.length/2%2===0);else{var x=b.length/2-1,_=x+2;t=-(b[_]-b[x]),r=-(b[_+1]-b[x+1])}}u.midsrcArrowAngle=l(t,r),t=g.x-o,r=g.y-s,u.tgtArrowAngle=l(t,r)},s.findEndpoints=function(e){var t,r,n,o=this,s=e.source()[0],l=e.target()[0],u=s._private,c=l._private,d=u.position,h=c.position,p=e._private.style["target-arrow-shape"].value,v=e._private.style["source-arrow-shape"].value,f=e._private.rscratch,g=f.edgeType,y="bezier"===g||"multibezier"===g||"self"===g||"compound"===g,m="bezier"!==g,b="straight"===g||"segments"===g,x="segments"===g;if(y){var w=[f.ctrlpts[0],f.ctrlpts[1]],_=m?[f.ctrlpts[f.ctrlpts.length-2],f.ctrlpts[f.ctrlpts.length-1]]:w;r=_,n=w}else if(b){var E=x?f.segpts.slice(0,2):[h.x,h.y],D=x?f.segpts.slice(f.segpts.length-2):[d.x,d.y];r=D,n=E}t=o.nodeShapes[this.getNodeShape(l)].intersectLine(h.x,h.y,l.outerWidth(),l.outerHeight(),r[0],r[1],0);var S=i.shortenIntersection(t,r,o.arrowShapes[p].spacing(e)),k=i.shortenIntersection(t,r,o.arrowShapes[p].gap(e));f.endX=k[0],f.endY=k[1],f.arrowEndX=S[0],f.arrowEndY=S[1],t=o.nodeShapes[this.getNodeShape(s)].intersectLine(d.x,d.y,s.outerWidth(),s.outerHeight(),n[0],n[1],0);var T=i.shortenIntersection(t,n,o.arrowShapes[v].spacing(e)),P=i.shortenIntersection(t,n,o.arrowShapes[v].gap(e));f.startX=P[0],f.startY=P[1],f.arrowStartX=T[0],f.arrowStartY=T[1],b&&(a.number(f.startX)&&a.number(f.startY)&&a.number(f.endX)&&a.number(f.endY)?f.badLine=!1:f.badLine=!0)},s.getArrowWidth=s.getArrowHeight=function(e){var t=this.arrowWidthCache=this.arrowWidthCache||{},r=t[e];return r?r:(r=Math.max(Math.pow(13.37*e,.9),29),t[e]=r,r)},t.exports=s},{"../../../collection/zsort":29,"../../../is":77,"../../../math":79}],57:[function(e,t,r){"use strict";var n={};n.getCachedImage=function(e,t){var r=this,n=r.imageCache=r.imageCache||{};if(n[e]&&n[e].image)return n[e].image;var i=n[e]=n[e]||{},a=i.image=new Image;return a.addEventListener("load",t),a.src=e,a},t.exports=n},{}],58:[function(e,t,r){"use strict";var n=e("../../../is"),i=e("../../../util"),a=function(){},o=a,s=o.prototype;s.clientFunctions=["redrawHint","render","renderTo","matchCanvasSize","nodeShapeImpl","arrowShapeImpl"],s.init=function(e){var t=this;t.options=e,t.cy=e.cy,t.container=e.cy.container(),t.selection=[void 0,void 0,void 0,void 0,0],t.hoverData={down:null,last:null,downTime:null,triggerMode:null,dragging:!1,initialPan:[null,null],capture:!1},t.dragData={possibleDragElements:[]},t.touchData={start:null,capture:!1,startPosition:[null,null,null,null,null,null],singleTouchStartTime:null,singleTouchMoved:!0,now:[null,null,null,null,null,null],earlier:[null,null,null,null,null,null]},t.redraws=0,t.showFps=e.showFps,t.hideEdgesOnViewport=e.hideEdgesOnViewport,t.hideLabelsOnViewport=e.hideLabelsOnViewport,t.textureOnViewport=e.textureOnViewport,t.wheelSensitivity=e.wheelSensitivity,t.motionBlurEnabled=e.motionBlur,t.forcedPixelRatio=e.pixelRatio,t.motionBlur=!0,t.motionBlurOpacity=e.motionBlurOpacity,t.motionBlurTransparency=1-t.motionBlurOpacity,t.motionBlurPxRatio=1,t.mbPxRBlurry=1,t.minMbLowQualFrames=4,t.fullQualityMb=!1,t.clearedForMotionBlur=[],t.desktopTapThreshold=e.desktopTapThreshold,t.desktopTapThreshold2=e.desktopTapThreshold*e.desktopTapThreshold,t.touchTapThreshold=e.touchTapThreshold,t.touchTapThreshold2=e.touchTapThreshold*e.touchTapThreshold,t.tapholdDuration=500,t.bindings=[],t.registerNodeShapes(),t.registerArrowShapes(),t.load()},s.notify=function(e){var t,r=this;t=n.array(e.type)?e.type:[e.type];for(var i=0;i<t.length;i++){var a=t[i];switch(a){case"destroy":return void r.destroy();case"add":case"remove":case"load":r.updateElementsCache();break;case"viewport":r.redrawHint("select",!0);break;case"style":r.updateCachedZSortedEles()}("load"===a||"resize"===a)&&(r.invalidateContainerClientCoordsCache(),r.matchCanvasSize(r.container))}r.redrawHint("eles",!0),r.redrawHint("drag",!0),this.startRenderLoop(),this.redraw()},s.destroy=function(){this.destroyed=!0,this.cy.stopAnimationLoop();for(var e=0;e<this.bindings.length;e++){var t=this.bindings[e],r=t;r.target.removeEventListener(r.event,r.handler,r.useCapture)}if(this.removeObserver&&this.removeObserver.disconnect(),this.labelCalcDiv)try{document.body.removeChild(this.labelCalcDiv)}catch(n){}},[e("./arrow-shapes"),e("./cached-eles"),e("./coord-ele-math"),e("./images"),e("./load-listeners"),e("./node-shapes"),e("./redraw")].forEach(function(e){i.extend(s,e)}),t.exports=o},{"../../../is":77,"../../../util":94,"./arrow-shapes":54,"./cached-eles":55,"./coord-ele-math":56,"./images":57,"./load-listeners":59,"./node-shapes":60,"./redraw":61}],59:[function(e,t,r){"use strict";var n=e("../../../is"),i=e("../../../util"),a=e("../../../event"),o=e("../../../collection"),s={};s.registerBinding=function(e,t,r,n){this.bindings.push({target:e,event:t,handler:r,useCapture:n}),e.addEventListener(t,r,n)},s.nodeIsDraggable=function(e){return 0!==e._private.style.opacity.value&&"visible"==e._private.style.visibility.value&&"element"==e._private.style.display.value&&!e.locked()&&e.grabbable()?!0:!1},s.load=function(){var e=this,t=function(t,r,n,o){null==t&&(t=e.cy);for(var s=0;s<r.length;s++){var l=r[s],u=a(n,i.extend({type:l},o));t.trigger(u)}},r=function(e){return e.shiftKey||e.metaKey||e.ctrlKey},s=function(t){var r;if(t.addToList&&e.cy.hasCompoundNodes()){if(!t.addToList.hasId){t.addToList.hasId={};for(var n=0;n<t.addToList.length;n++){var i=t.addToList[n];t.addToList.hasId[i.id()]=!0}}r=t.addToList.hasId}return r||{}},l=function(e,t){if(e._private.cy.hasCompoundNodes()&&(null!=t.inDragLayer||null!=t.addToList))for(var r=s(t),n=e.descendants(),i=0;i<n.size();i++){var a=n[i],o=a._private;t.inDragLayer&&(o.rscratch.inDragLayer=!0),t.addToList&&!r[a.id()]&&(t.addToList.push(a),r[a.id()]=!0,o.grabbed=!0);for(var l=o.edges,u=0;t.inDragLayer&&u<l.length;u++)l[u]._private.rscratch.inDragLayer=!0}},u=function(e,t){var r=e._private,n=s(t);t.inDragLayer&&(r.rscratch.inDragLayer=!0),t.addToList&&!n[e.id()]&&(t.addToList.push(e),n[e.id()]=!0,r.grabbed=!0);for(var i=r.edges,a=0;t.inDragLayer&&a<i.length;a++)i[a]._private.rscratch.inDragLayer=!0;l(e,t),d(e,{inDragLayer:t.inDragLayer})},c=function(e){if(e)for(var t=0;t<e.length;t++){var r=e[t]._private;if("nodes"===r.group){r.rscratch.inDragLayer=!1,r.grabbed=!1;for(var n=r.edges,i=0;i<n.length;i++)n[i]._private.rscratch.inDragLayer=!1;d(e[t],{inDragLayer:!1})}else"edges"===r.group&&(r.rscratch.inDragLayer=!1)}},d=function(e,t){if(null!=t.inDragLayer||null!=t.addToList){var r=e;if(e._private.cy.hasCompoundNodes()){for(;r.parent().nonempty();)r=r.parent()[0];if(r!=e){for(var n=r.descendants().merge(r).unmerge(e).unmerge(e.descendants()),i=n.connectedEdges(),a=s(t),o=0;o<n.size();o++)void 0!==t.inDragLayer&&(n[o]._private.rscratch.inDragLayer=t.inDragLayer),t.addToList&&!a[n[o].id()]&&(t.addToList.push(n[o]),a[n[o].id()]=!0,n[o]._private.grabbed=!0);for(var l=0;void 0!==t.inDragLayer&&l<i.length;l++)i[l]._private.rscratch.inDragLayer=t.inDragLayer}}}};"undefined"!=typeof MutationObserver?(e.removeObserver=new MutationObserver(function(t){for(var r=0;r<t.length;r++){var n=t[r],i=n.removedNodes;if(i)for(var a=0;a<i.length;a++){var o=i[a];if(o===e.container){e.destroy();break}}}}),e.container.parentNode&&e.removeObserver.observe(e.container.parentNode,{childList:!0})):e.registerBinding(e.container,"DOMNodeRemoved",function(t){e.destroy()}),e.registerBinding(window,"resize",i.debounce(function(t){e.invalidateContainerClientCoordsCache(),e.matchCanvasSize(e.container),e.redrawHint("eles",!0),e.redraw()},100));for(var h=function(t){e.registerBinding(t,"scroll",function(t){e.invalidateContainerClientCoordsCache()})},p=e.cy.container();h(p),p.parentNode;)p=p.parentNode;e.registerBinding(e.container,"contextmenu",function(e){e.preventDefault()});var v=function(){return 0!==e.selection[4]};e.registerBinding(e.container,"mousedown",function(r){r.preventDefault(),e.hoverData.capture=!0,e.hoverData.which=r.which;var n=e.cy,i=e.projectIntoViewport(r.clientX,r.clientY),o=e.selection,s=e.findNearestElement(i[0],i[1],!0,!1),l=e.dragData.possibleDragElements;e.hoverData.mdownPos=i;var c=function(){e.hoverData.tapholdCancelled=!1,clearTimeout(e.hoverData.tapholdTimeout),e.hoverData.tapholdTimeout=setTimeout(function(){if(!e.hoverData.tapholdCancelled){var t=e.hoverData.down;t?t.trigger(a(r,{type:"taphold",cyPosition:{x:i[0],y:i[1]}})):n.trigger(a(r,{type:"taphold",cyPosition:{x:i[0],y:i[1]}}))}},e.tapholdDuration)};if(3==r.which){e.hoverData.cxtStarted=!0;var d=a(r,{type:"cxttapstart",cyPosition:{x:i[0],y:i[1]}});s?(s.activate(),s.trigger(d),e.hoverData.down=s):n.trigger(d),e.hoverData.downTime=(new Date).getTime(),e.hoverData.cxtDragged=!1}else if(1==r.which){if(s&&s.activate(),null!=s&&e.nodeIsDraggable(s)){var h=a(r,{type:"grab",cyPosition:{x:i[0],y:i[1]}});if(s.isNode()&&!s.selected())l=e.dragData.possibleDragElements=[],u(s,{addToList:l}),s.trigger(h);else if(s.isNode()&&s.selected()){l=e.dragData.possibleDragElements=[];for(var p=n.$(function(){return this.isNode()&&this.selected()}),v=0;v<p.length;v++)e.nodeIsDraggable(p[v])&&u(p[v],{addToList:l});s.trigger(h)}e.redrawHint("eles",!0),e.redrawHint("drag",!0)}e.hoverData.down=s,e.hoverData.downTime=(new Date).getTime(),t(s,["mousedown","tapstart","vmousedown"],r,{cyPosition:{x:i[0],y:i[1]}}),null==s?(o[4]=1,e.data.bgActivePosistion={x:i[0],y:i[1]},e.redrawHint("select",!0),e.redraw()):s.isEdge()&&(o[4]=1),c()}o[0]=o[2]=i[0],o[1]=o[3]=i[1]},!1),e.registerBinding(window,"mousemove",function(i){var s=!1,l=e.hoverData.capture;if(!l){var c=e.findContainerClientCoords();if(!(i.clientX>c[0]&&i.clientX<c[0]+e.canvasWidth&&i.clientY>c[1]&&i.clientY<c[1]+e.canvasHeight))return;for(var d=e.container,h=i.target,p=h.parentNode,v=!1;p;){if(p===d){v=!0;break}p=p.parentNode}if(!v)return}var f=e.cy,g=f.zoom(),y=e.projectIntoViewport(i.clientX,i.clientY),m=e.selection,b=null;e.hoverData.draggingEles||(b=e.findNearestElement(y[0],y[1],!0,!1));var x=e.hoverData.last,w=e.hoverData.down,_=[y[0]-m[2],y[1]-m[3]],E=e.dragData.possibleDragElements,D=m[2]-m[0],S=D*D,k=m[3]-m[1],T=k*k,P=S+T,C=P*g*g,N=r(i);e.hoverData.tapholdCancelled=!0;var M=function(){var t=e.hoverData.dragDelta=e.hoverData.dragDelta||[];0===t.length?(t.push(_[0]),t.push(_[1])):(t[0]+=_[0],t[1]+=_[1])};if(s=!0,t(b,["mousemove","vmousemove","tapdrag"],i,{cyPosition:{x:y[0],y:y[1]}}),3===e.hoverData.which){var B=a(i,{type:"cxtdrag",cyPosition:{x:y[0],y:y[1]}});w?w.trigger(B):f.trigger(B),e.hoverData.cxtDragged=!0,e.hoverData.cxtOver&&b===e.hoverData.cxtOver||(e.hoverData.cxtOver&&e.hoverData.cxtOver.trigger(a(i,{type:"cxtdragout",cyPosition:{x:y[0],y:y[1]}})),e.hoverData.cxtOver=b,b&&b.trigger(a(i,{type:"cxtdragover",cyPosition:{x:y[0],y:y[1]}})))}else if(e.hoverData.dragging){if(s=!0,f.panningEnabled()&&f.userPanningEnabled()){var z;if(e.hoverData.justStartedPan){var O=e.hoverData.mdownPos;z={x:(y[0]-O[0])*g,y:(y[1]-O[1])*g},e.hoverData.justStartedPan=!1}else z={x:_[0]*g,y:_[1]*g};f.panBy(z),e.hoverData.dragged=!0}y=e.projectIntoViewport(i.clientX,i.clientY)}else if(1!=m[4]||null!=w&&!w.isEdge()){if(w&&w.isEdge()&&w.active()&&w.unactivate(),b!=x&&(x&&t(x,["mouseout","tapdragout"],i,{cyPosition:{x:y[0],y:y[1]}}),b&&t(b,["mouseover","tapdragover"],i,{cyPosition:{x:y[0],y:y[1]}}),e.hoverData.last=b),w&&w.isNode()&&e.nodeIsDraggable(w))if(C>=e.desktopTapThreshold2){var I=!e.dragData.didDrag;I&&e.redrawHint("eles",!0),e.dragData.didDrag=!0;for(var L=[],A=0;A<E.length;A++){var R=E[A];if(e.hoverData.draggingEles||u(R,{inDragLayer:!0}),R.isNode()&&e.nodeIsDraggable(R)&&R.grabbed()){var V=R._private.position;if(L.push(R),n.number(_[0])&&n.number(_[1])){var F=!R.isParent();if(F&&(V.x+=_[0],V.y+=_[1]),I){var j=e.hoverData.dragDelta;F&&n.number(j[0])&&n.number(j[1])&&(V.x+=j[0],V.y+=j[1])}}}}e.hoverData.draggingEles=!0;var q=o(f,L);q.updateCompoundBounds(),q.trigger("position drag"),e.redrawHint("drag",!0),e.redraw()}else M();s=!0}else e.hoverData.dragging||!f.boxSelectionEnabled()||!N&&f.panningEnabled()&&f.userPanningEnabled()?!e.hoverData.selecting&&f.panningEnabled()&&f.userPanningEnabled()&&(e.hoverData.dragging=!0,e.hoverData.justStartedPan=!0,m[4]=0,e.data.bgActivePosistion={x:y[0],y:y[1]},e.redrawHint("select",!0),e.redraw()):(e.data.bgActivePosistion=void 0,e.hoverData.selecting=!0,e.redrawHint("select",!0),e.redraw()),w&&w.isEdge()&&w.active()&&w.unactivate();return m[2]=y[0],m[3]=y[1],s?(i.stopPropagation&&i.stopPropagation(),i.preventDefault&&i.preventDefault(),!1):void 0},!1),e.registerBinding(window,"mouseup",function(n){var i=e.hoverData.capture;if(i){e.hoverData.capture=!1;var s=e.cy,l=e.projectIntoViewport(n.clientX,n.clientY),u=e.selection,d=e.findNearestElement(l[0],l[1],!0,!1),h=e.dragData.possibleDragElements,p=e.hoverData.down,v=r(n);if(e.data.bgActivePosistion&&(e.redrawHint("select",!0),e.redraw()),e.hoverData.tapholdCancelled=!0,e.data.bgActivePosistion=void 0,p&&p.unactivate(),3===e.hoverData.which){var f=a(n,{type:"cxttapend",cyPosition:{x:l[0],y:l[1]}});if(p?p.trigger(f):s.trigger(f),!e.hoverData.cxtDragged){var g=a(n,{type:"cxttap",cyPosition:{x:l[0],y:l[1]}});p?p.trigger(g):s.trigger(g)}e.hoverData.cxtDragged=!1,e.hoverData.which=null}else if(1===e.hoverData.which){if(null!=p||e.dragData.didDrag||e.hoverData.selecting||e.hoverData.dragged||r(n)||(s.$(function(){return this.selected()}).unselect(),h.length>0&&e.redrawHint("eles",!0),e.dragData.possibleDragElements=h=[]),t(d,["mouseup","tapend","vmouseup"],n,{cyPosition:{x:l[0],y:l[1]}}),e.dragData.didDrag||e.hoverData.dragged||t(d,["click","tap","vclick"],n,{cyPosition:{x:l[0],y:l[1]}}),d!=p||e.dragData.didDrag||e.hoverData.selecting||null!=d&&d._private.selectable&&(e.hoverData.dragging||("additive"===s.selectionType()||v?d.selected()?d.unselect():d.select():v||(s.$(":selected").unmerge(d).unselect(),d.select())),e.redrawHint("eles",!0)),e.hoverData.selecting){var y=[],m=e.getAllInBox(u[0],u[1],u[2],u[3]);e.redrawHint("select",!0),m.length>0&&e.redrawHint("eles",!0);for(var b=0;b<m.length;b++)m[b]._private.selectable&&y.push(m[b]);var x=o(s,y);"additive"===s.selectionType()?x.select():(v||s.$(":selected").unmerge(x).unselect(),x.select()),e.redraw()}e.hoverData.dragging&&(e.hoverData.dragging=!1,e.redrawHint("select",!0),e.redrawHint("eles",!0),e.redraw()),u[4]||(e.redrawHint("drag",!0),e.redrawHint("eles",!0),c(h),p&&p.trigger("free"))}u[4]=0,e.hoverData.down=null,e.hoverData.cxtStarted=!1,e.hoverData.draggingEles=!1,e.hoverData.selecting=!1,e.dragData.didDrag=!1,e.hoverData.dragged=!1,e.hoverData.dragDelta=[]}},!1);var f=function(t){if(!e.scrollingPage){var r=e.cy,n=e.projectIntoViewport(t.clientX,t.clientY),i=[n[0]*r.zoom()+r.pan().x,n[1]*r.zoom()+r.pan().y];if(e.hoverData.draggingEles||e.hoverData.dragging||e.hoverData.cxtStarted||v())return void t.preventDefault();if(r.panningEnabled()&&r.userPanningEnabled()&&r.zoomingEnabled()&&r.userZoomingEnabled()){t.preventDefault(),e.data.wheelZooming=!0,clearTimeout(e.data.wheelTimeout),e.data.wheelTimeout=setTimeout(function(){e.data.wheelZooming=!1,e.redrawHint("eles",!0),e.redraw()},150);var a=t.deltaY/-250||t.wheelDeltaY/1e3||t.wheelDelta/1e3;a*=e.wheelSensitivity;var o=1===t.deltaMode;o&&(a*=33),r.zoom({level:r.zoom()*Math.pow(10,a),renderedPosition:{x:i[0],y:i[1]}})}}};e.registerBinding(e.container,"wheel",f,!0),e.registerBinding(window,"scroll",function(t){e.scrollingPage=!0,clearTimeout(e.scrollingPageTimeout),e.scrollingPageTimeout=setTimeout(function(){e.scrollingPage=!1},250)},!0),e.registerBinding(e.container,"mouseout",function(t){var r=e.projectIntoViewport(t.clientX,t.clientY);e.cy.trigger(a(t,{type:"mouseout",cyPosition:{x:r[0],y:r[1]}}))},!1),e.registerBinding(e.container,"mouseover",function(t){var r=e.projectIntoViewport(t.clientX,t.clientY);e.cy.trigger(a(t,{type:"mouseover",cyPosition:{x:r[0],y:r[1]}}))},!1);var g,y,m,b,x,w,_,E,D,S,k,T,P,C,N=function(e,t,r,n){return Math.sqrt((r-e)*(r-e)+(n-t)*(n-t))},M=function(e,t,r,n){return(r-e)*(r-e)+(n-t)*(n-t)};e.registerBinding(e.container,"touchstart",C=function(r){e.touchData.capture=!0,e.data.bgActivePosistion=void 0;var n=e.cy,i=e.getCachedNodes(),o=e.getCachedEdges(),s=e.touchData.now,l=e.touchData.earlier;if(r.touches[0]){var c=e.projectIntoViewport(r.touches[0].clientX,r.touches[0].clientY);s[0]=c[0],s[1]=c[1]}if(r.touches[1]){var c=e.projectIntoViewport(r.touches[1].clientX,r.touches[1].clientY);s[2]=c[0],s[3]=c[1]}if(r.touches[2]){var c=e.projectIntoViewport(r.touches[2].clientX,r.touches[2].clientY);s[4]=c[0],s[5]=c[1]}if(r.touches[1]){var d=function(e){for(var t=0;t<e.length;t++)e[t]._private.grabbed=!1,e[t]._private.rscratch.inDragLayer=!1,e[t].active()&&e[t].unactivate()};d(i),d(o);var h=e.findContainerClientCoords();D=h[0],S=h[1],k=h[2],T=h[3],g=r.touches[0].clientX-D,y=r.touches[0].clientY-S,m=r.touches[1].clientX-D,b=r.touches[1].clientY-S,P=g>=0&&k>=g&&m>=0&&k>=m&&y>=0&&T>=y&&b>=0&&T>=b;var p=n.pan(),v=n.zoom();x=N(g,y,m,b),w=M(g,y,m,b),_=[(g+m)/2,(y+b)/2],E=[(_[0]-p.x)/v,(_[1]-p.y)/v];var f=200,C=f*f;if(C>w&&!r.touches[2]){var B=e.findNearestElement(s[0],s[1],!0,!0),z=e.findNearestElement(s[2],s[3],!0,!0);return B&&B.isNode()?(B.activate().trigger(a(r,{type:"cxttapstart",cyPosition:{x:s[0],y:s[1]}})),e.touchData.start=B):z&&z.isNode()?(z.activate().trigger(a(r,{type:"cxttapstart",cyPosition:{x:s[0],y:s[1]}})),e.touchData.start=z):(n.trigger(a(r,{type:"cxttapstart",cyPosition:{x:s[0],y:s[1]}})),e.touchData.start=null),e.touchData.start&&(e.touchData.start._private.grabbed=!1),e.touchData.cxt=!0,e.touchData.cxtDragged=!1,e.data.bgActivePosistion=void 0,void e.redraw()}}if(r.touches[2]);else if(r.touches[1]);else if(r.touches[0]){var O=e.findNearestElement(s[0],s[1],!0,!0);if(null!=O&&(O.activate(),e.touchData.start=O,O.isNode()&&e.nodeIsDraggable(O))){var I=e.dragData.touchDragEles=[];if(e.redrawHint("eles",!0),e.redrawHint("drag",!0),O.selected())for(var L=n.$(function(){return this.isNode()&&this.selected()}),A=0;A<L.length;A++){var R=L[A];e.nodeIsDraggable(R)&&u(R,{addToList:I})}else u(O,{addToList:I});O.trigger(a(r,{type:"grab",cyPosition:{x:s[0],y:s[1]}}))}t(O,["touchstart","tapstart","vmousedown"],r,{cyPosition:{x:s[0],y:s[1]}}),null==O&&(e.data.bgActivePosistion={x:c[0],y:c[1]},e.redrawHint("select",!0),e.redraw());for(var V=0;V<s.length;V++)l[V]=s[V],e.touchData.startPosition[V]=s[V];e.touchData.singleTouchMoved=!1,e.touchData.singleTouchStartTime=+new Date,clearTimeout(e.touchData.tapholdTimeout),e.touchData.tapholdTimeout=setTimeout(function(){e.touchData.singleTouchMoved!==!1||e.pinching||(t(e.touchData.start,["taphold"],r,{cyPosition:{x:s[0],y:s[1]}}),e.touchData.start||n.$(":selected").unselect())},e.tapholdDuration)}},!1);var B;e.registerBinding(window,"touchmove",B=function(r){var i=e.selection,s=e.touchData.capture,l=e.cy,c=e.touchData.now,d=e.touchData.earlier,h=l.zoom();if(r.touches[0]){var p=e.projectIntoViewport(r.touches[0].clientX,r.touches[0].clientY);c[0]=p[0],c[1]=p[1]}if(r.touches[1]){var p=e.projectIntoViewport(r.touches[1].clientX,r.touches[1].clientY);c[2]=p[0],c[3]=p[1]}if(r.touches[2]){var p=e.projectIntoViewport(r.touches[2].clientX,r.touches[2].clientY);c[4]=p[0],c[5]=p[1]}for(var v=[],f=0;f<c.length;f++)v[f]=c[f]-d[f];var _=e.touchData.startPosition,k=c[0]-_[0],T=k*k,C=c[1]-_[1],B=C*C,z=T+B,O=z*h*h;if(s&&e.touchData.cxt){r.preventDefault();var I=r.touches[0].clientX-D,L=r.touches[0].clientY-S,A=r.touches[1].clientX-D,R=r.touches[1].clientY-S,V=M(I,L,A,R),F=V/w,j=150,q=j*j,X=1.5,Y=X*X;if(F>=Y||V>=q){e.touchData.cxt=!1,e.touchData.start&&(e.touchData.start.unactivate(),e.touchData.start=null),e.data.bgActivePosistion=void 0,e.redrawHint("select",!0);var $=a(r,{type:"cxttapend",cyPosition:{x:c[0],y:c[1]}});e.touchData.start?e.touchData.start.trigger($):l.trigger($)}}if(s&&e.touchData.cxt){var $=a(r,{type:"cxtdrag",cyPosition:{x:c[0],y:c[1]}});e.data.bgActivePosistion=void 0,e.redrawHint("select",!0),e.touchData.start?e.touchData.start.trigger($):l.trigger($),e.touchData.start&&(e.touchData.start._private.grabbed=!1),e.touchData.cxtDragged=!0;var H=e.findNearestElement(c[0],c[1],!0,!0);e.touchData.cxtOver&&H===e.touchData.cxtOver||(e.touchData.cxtOver&&e.touchData.cxtOver.trigger(a(r,{type:"cxtdragout",cyPosition:{x:c[0],y:c[1]}})),e.touchData.cxtOver=H,H&&H.trigger(a(r,{type:"cxtdragover",cyPosition:{x:c[0],y:c[1]}})))}else if(s&&r.touches[2]&&l.boxSelectionEnabled())r.preventDefault(),e.data.bgActivePosistion=void 0,this.lastThreeTouch=+new Date,e.touchData.selecting=!0,e.redrawHint("select",!0),i&&0!==i.length&&void 0!==i[0]?(i[2]=(c[0]+c[2]+c[4])/3,i[3]=(c[1]+c[3]+c[5])/3):(i[0]=(c[0]+c[2]+c[4])/3,i[1]=(c[1]+c[3]+c[5])/3,i[2]=(c[0]+c[2]+c[4])/3+1,i[3]=(c[1]+c[3]+c[5])/3+1),i[4]=1,e.touchData.selecting=!0,e.redraw();else if(s&&r.touches[1]&&l.zoomingEnabled()&&l.panningEnabled()&&l.userZoomingEnabled()&&l.userPanningEnabled()){r.preventDefault(),e.data.bgActivePosistion=void 0,e.redrawHint("select",!0);var W=e.dragData.touchDragEles;if(W){e.redrawHint("drag",!0);for(var Z=0;Z<W.length;Z++)W[Z]._private.grabbed=!1,W[Z]._private.rscratch.inDragLayer=!1}var I=r.touches[0].clientX-D,L=r.touches[0].clientY-S,A=r.touches[1].clientX-D,R=r.touches[1].clientY-S,U=N(I,L,A,R),G=U/x;if(1!=G&&P){var K=I-g,J=L-y,Q=A-m,ee=R-b,te=(K+Q)/2,re=(J+ee)/2,ne=l.zoom(),ie=ne*G,ae=l.pan(),oe=E[0]*ne+ae.x,se=E[1]*ne+ae.y,le={x:-ie/ne*(oe-ae.x-te)+oe,y:-ie/ne*(se-ae.y-re)+se};if(e.touchData.start){var W=e.dragData.touchDragEles;if(W)for(var Z=0;Z<W.length;Z++){var ue=W[Z]._private;ue.grabbed=!1,ue.rscratch.inDragLayer=!1}var ce=e.touchData.start._private;ce.active=!1,ce.grabbed=!1,ce.rscratch.inDragLayer=!1,e.redrawHint("drag",!0),e.touchData.start.trigger("free").trigger("unactivate")}l.viewport({zoom:ie,pan:le,cancelOnFailedZoom:!0}),x=U,g=I,y=L,m=A,b=R,e.pinching=!0}if(r.touches[0]){var p=e.projectIntoViewport(r.touches[0].clientX,r.touches[0].clientY);c[0]=p[0],c[1]=p[1]}if(r.touches[1]){var p=e.projectIntoViewport(r.touches[1].clientX,r.touches[1].clientY);c[2]=p[0],c[3]=p[1]}if(r.touches[2]){var p=e.projectIntoViewport(r.touches[2].clientX,r.touches[2].clientY);c[4]=p[0],c[5]=p[1]}}else if(r.touches[0]){var de=e.touchData.start,he=e.touchData.last,H=H||e.findNearestElement(c[0],c[1],!0,!0);if(null!=de&&r.preventDefault(),null!=de&&"nodes"==de._private.group&&e.nodeIsDraggable(de))if(O>=e.touchTapThreshold2){for(var W=e.dragData.touchDragEles,pe=!e.dragData.didDrag,ve=0;ve<W.length;ve++){var fe=W[ve];if(pe&&u(fe,{inDragLayer:!0}),e.nodeIsDraggable(fe)&&fe.isNode()&&fe.grabbed()){e.dragData.didDrag=!0;var ge=fe._private.position,ye=!fe.isParent();if(ye&&n.number(v[0])&&n.number(v[1])&&(ge.x+=v[0],ge.y+=v[1]),pe){e.redrawHint("eles",!0);var me=e.touchData.dragDelta;ye&&n.number(me[0])&&n.number(me[1])&&(ge.x+=me[0],ge.y+=me[1])}}}var be=o(l,W);be.updateCompoundBounds(),be.trigger("position drag"),e.hoverData.draggingEles=!0,e.redrawHint("drag",!0),e.touchData.startPosition[0]==d[0]&&e.touchData.startPosition[1]==d[1]&&e.redrawHint("eles",!0),e.redraw()}else{var me=e.touchData.dragDelta=e.touchData.dragDelta||[];0===me.length?(me.push(v[0]),me.push(v[1])):(me[0]+=v[0],me[1]+=v[1])}t(de||H,["touchmove","tapdrag","vmousemove"],r,{cyPosition:{x:c[0],y:c[1]}}),H!=he&&(he&&he.trigger(a(r,{type:"tapdragout",cyPosition:{x:c[0],y:c[1]}})),H&&H.trigger(a(r,{type:"tapdragover",cyPosition:{x:c[0],y:c[1]}}))),e.touchData.last=H;for(var Z=0;Z<c.length;Z++)c[Z]&&e.touchData.startPosition[Z]&&O>e.touchTapThreshold2&&(e.touchData.singleTouchMoved=!0);if(s&&(null==de||de.isEdge())&&l.panningEnabled()&&l.userPanningEnabled()){r.preventDefault(),e.swipePanning?l.panBy({x:v[0]*h,y:v[1]*h}):O>=e.touchTapThreshold2&&(e.swipePanning=!0,l.panBy({x:k*h,y:C*h}),de&&(de.unactivate(),e.data.bgActivePosistion||(e.data.bgActivePosistion={x:c[0],y:c[1]}),e.redrawHint("select",!0),e.touchData.start=null));var p=e.projectIntoViewport(r.touches[0].clientX,r.touches[0].clientY);c[0]=p[0],c[1]=p[1]}}for(var f=0;f<c.length;f++)d[f]=c[f]},!1);var z;e.registerBinding(window,"touchcancel",z=function(t){var r=e.touchData.start;e.touchData.capture=!1,r&&r.unactivate()});var O;if(e.registerBinding(window,"touchend",O=function(r){var n=e.touchData.start,i=e.touchData.capture;if(i){e.touchData.capture=!1,r.preventDefault();var s=e.selection;e.swipePanning=!1,e.hoverData.draggingEles=!1;var l=e.cy,u=l.zoom(),d=e.touchData.now,h=e.touchData.earlier;if(r.touches[0]){var p=e.projectIntoViewport(r.touches[0].clientX,r.touches[0].clientY);d[0]=p[0],d[1]=p[1]}if(r.touches[1]){var p=e.projectIntoViewport(r.touches[1].clientX,r.touches[1].clientY);d[2]=p[0],d[3]=p[1]}if(r.touches[2]){var p=e.projectIntoViewport(r.touches[2].clientX,r.touches[2].clientY);d[4]=p[0],d[5]=p[1]}n&&n.unactivate();var v;if(e.touchData.cxt){if(v=a(r,{
+type:"cxttapend",cyPosition:{x:d[0],y:d[1]}}),n?n.trigger(v):l.trigger(v),!e.touchData.cxtDragged){var f=a(r,{type:"cxttap",cyPosition:{x:d[0],y:d[1]}});n?n.trigger(f):l.trigger(f)}return e.touchData.start&&(e.touchData.start._private.grabbed=!1),e.touchData.cxt=!1,e.touchData.start=null,void e.redraw()}if(!r.touches[2]&&l.boxSelectionEnabled()&&e.touchData.selecting){e.touchData.selecting=!1;var g=[],y=e.getAllInBox(s[0],s[1],s[2],s[3]);s[0]=void 0,s[1]=void 0,s[2]=void 0,s[3]=void 0,s[4]=0,e.redrawHint("select",!0);for(var m=0;m<y.length;m++)y[m]._private.selectable&&g.push(y[m]);var b=o(l,g);b.select(),b.length>0?e.redrawHint("eles",!0):e.redraw()}var x=!1;if(null!=n&&(n._private.active=!1,x=!0,n.unactivate()),r.touches[2])e.data.bgActivePosistion=void 0,e.redrawHint("select",!0);else if(r.touches[1]);else if(r.touches[0]);else if(!r.touches[0]){e.data.bgActivePosistion=void 0,e.redrawHint("select",!0);var w=e.dragData.touchDragEles;if(null!=n){var _=n._private.grabbed;c(w),e.redrawHint("drag",!0),e.redrawHint("eles",!0),_&&n.trigger("free"),t(n,["touchend","tapend","vmouseup"],r,{cyPosition:{x:d[0],y:d[1]}}),n.unactivate(),e.touchData.start=null}else{var E=e.findNearestElement(d[0],d[1],!0,!0);t(E,["touchend","tapend","vmouseup"],r,{cyPosition:{x:d[0],y:d[1]}})}var D=e.touchData.startPosition[0]-d[0],S=D*D,k=e.touchData.startPosition[1]-d[1],T=k*k,P=S+T,C=P*u*u;null!=n&&!e.dragData.didDrag&&n._private.selectable&&C<e.touchTapThreshold2&&!e.pinching&&("single"===l.selectionType()?(l.$(":selected").unmerge(n).unselect(),n.select()):n.selected()?n.unselect():n.select(),x=!0,e.redrawHint("eles",!0)),e.touchData.singleTouchMoved||t(n,["tap","vclick"],r,{cyPosition:{x:d[0],y:d[1]}}),e.touchData.singleTouchMoved=!0}for(var N=0;N<d.length;N++)h[N]=d[N];e.dragData.didDrag=!1,0===r.touches.length&&(e.touchData.dragDelta=[]),x&&n&&n.updateStyle(!1),r.touches.length<2&&(e.pinching=!1,e.redrawHint("eles",!0),e.redraw())}},!1),"undefined"==typeof TouchEvent){var I=[],L=function(e){return{clientX:e.clientX,clientY:e.clientY,force:1,identifier:e.pointerId,pageX:e.pageX,pageY:e.pageY,radiusX:e.width/2,radiusY:e.height/2,screenX:e.screenX,screenY:e.screenY,target:e.target}},A=function(e){return{event:e,touch:L(e)}},R=function(e){I.push(A(e))},V=function(e){for(var t=0;t<I.length;t++){var r=I[t];if(r.event.pointerId===e.pointerId)return void I.splice(t,1)}},F=function(e){var t=I.filter(function(t){return t.event.pointerId===e.pointerId})[0];t.event=e,t.touch=L(e)},j=function(e){e.touches=I.map(function(e){return e.touch})};e.registerBinding(e.container,"pointerdown",function(e){"mouse"!==e.pointerType&&(e.preventDefault(),R(e),j(e),C(e))}),e.registerBinding(e.container,"pointerup",function(e){"mouse"!==e.pointerType&&(V(e),j(e),O(e))}),e.registerBinding(e.container,"pointercancel",function(e){"mouse"!==e.pointerType&&(V(e),j(e),z(e))}),e.registerBinding(e.container,"pointermove",function(e){"mouse"!==e.pointerType&&(e.preventDefault(),F(e),j(e),B(e))})}},t.exports=s},{"../../../collection":23,"../../../event":42,"../../../is":77,"../../../util":94}],60:[function(e,t,r){"use strict";var n=e("../../../math"),i={};i.registerNodeShapes=function(){function e(e,i){return t[e]={name:e,points:i,draw:function(e,t,n,i,a){r.nodeShapeImpl("polygon")(e,t,n,i,a,this.points)},intersectLine:function(e,t,r,i,a,o,s){return n.polygonIntersectLine(a,o,this.points,e,t,r/2,i/2,s)},checkPoint:function(r,i,a,o,s,l,u){return n.pointInsidePolygon(r,i,t[e].points,l,u,o,s,[0,-1],a)}}}var t=this.nodeShapes={},r=this;t.ellipse={name:"ellipse",draw:function(e,t,n,i,a){r.nodeShapeImpl(this.name)(e,t,n,i,a)},intersectLine:function(e,t,r,i,a,o,s){return n.intersectLineEllipse(a,o,e,t,r/2+s,i/2+s)},checkPoint:function(e,t,r,n,i,a,o){return e-=a,t-=o,e/=n/2+r,t/=i/2+r,1>=e*e+t*t}},e("triangle",n.generateUnitNgonPointsFitToSquare(3,0)),e("square",n.generateUnitNgonPointsFitToSquare(4,0)),t.rectangle=t.square,t.roundrectangle={name:"roundrectangle",points:n.generateUnitNgonPointsFitToSquare(4,0),draw:function(e,t,n,i,a){r.nodeShapeImpl(this.name)(e,t,n,i,a)},intersectLine:function(e,t,r,i,a,o,s){return n.roundRectangleIntersectLine(a,o,e,t,r,i,s)},checkPoint:function(e,t,r,i,a,o,s){var l=n.getRoundRectangleRadius(i,a);if(n.pointInsidePolygon(e,t,this.points,o,s,i,a-2*l,[0,-1],r))return!0;if(n.pointInsidePolygon(e,t,this.points,o,s,i-2*l,a,[0,-1],r))return!0;var u=function(e,t,r,n,i,a,o){return e-=r,t-=n,e/=i/2+o,t/=a/2+o,1>=e*e+t*t};return u(e,t,o-i/2+l,s-a/2+l,2*l,2*l,r)?!0:u(e,t,o+i/2-l,s-a/2+l,2*l,2*l,r)?!0:u(e,t,o+i/2-l,s+a/2-l,2*l,2*l,r)?!0:u(e,t,o-i/2+l,s+a/2-l,2*l,2*l,r)?!0:!1}},e("diamond",[0,1,1,0,0,-1,-1,0]),e("pentagon",n.generateUnitNgonPointsFitToSquare(5,0)),e("hexagon",n.generateUnitNgonPointsFitToSquare(6,0)),e("heptagon",n.generateUnitNgonPointsFitToSquare(7,0)),e("octagon",n.generateUnitNgonPointsFitToSquare(8,0));var i=new Array(20),a=n.generateUnitNgonPoints(5,0),o=n.generateUnitNgonPoints(5,Math.PI/5),s=.5*(3-Math.sqrt(5));s*=1.57;for(var l=0;l<o.length/2;l++)o[2*l]*=s,o[2*l+1]*=s;for(var l=0;5>l;l++)i[4*l]=a[2*l],i[4*l+1]=a[2*l+1],i[4*l+2]=o[2*l],i[4*l+3]=o[2*l+1];i=n.fitPolygonToSquare(i),e("star",i),e("vee",[-1,-1,0,-.333,1,-1,0,1]),e("rhomboid",[-1,-1,.333,-1,1,1,-.333,1]),t.makePolygon=function(r){var n,i=r.join("$"),a="polygon-"+i;return(n=t[a])?n:e(a,r)}},t.exports=i},{"../../../math":79}],61:[function(e,t,r){"use strict";var n=e("../../../util"),i={};i.timeToRender=function(){return this.redrawTotalTime/this.redrawCount};var a=1e3/60,o=1e3;i.redraw=function(e){e=e||n.staticEmptyObject();var t=this,r=e.forcedContext;void 0===t.averageRedrawTime&&(t.averageRedrawTime=0),void 0===t.lastRedrawTime&&(t.lastRedrawTime=0);var i=t.lastRedrawTime;i=a>i?a:i,i=o>i?i:o,void 0===t.lastDrawTime&&(t.lastDrawTime=0);var s=Date.now(),l=s-t.lastDrawTime,u=l>=i;return r||u&&!t.currentlyDrawing?(t.requestedFrame=!0,t.currentlyDrawing=!0,void(t.renderOptions=e)):void(t.skipFrame=!0)},i.startRenderLoop=function(){var e=this,t=function(){if(!e.destroyed){if(e.requestedFrame&&!e.skipFrame){var r=n.performanceNow();e.render(e.renderOptions);var i=e.lastRedrawTime=n.performanceNow();void 0===e.averageRedrawTime&&(e.averageRedrawTime=i-r),void 0===e.redrawCount&&(e.redrawCount=0),e.redrawCount++,void 0===e.redrawTotalTime&&(e.redrawTotalTime=0);var a=i-r;e.redrawTotalTime+=a,e.lastRedrawTime=a,e.averageRedrawTime=e.averageRedrawTime/2+a/2,e.requestedFrame=!1}e.skipFrame=!1,n.requestAnimationFrame(t)}};n.requestAnimationFrame(t)},t.exports=i},{"../../../util":94}],62:[function(e,t,r){"use strict";var n,i={};i.arrowShapeImpl=function(e){return(n||(n={polygon:function(e,t){for(var r=0;r<t.length;r++){var n=t[r];e.lineTo(n.x,n.y)}},"triangle-backcurve":function(e,t,r){for(var n,i=0;i<t.length;i++){var a=t[i];0===i&&(n=a),e.lineTo(a.x,a.y)}e.quadraticCurveTo(r.x,r.y,n.x,n.y)},"triangle-tee":function(e,t,r){for(var n=t,i=0;i<n.length;i++){var a=n[i];e.lineTo(a.x,a.y)}var o=r,s=r[0];e.moveTo(s.x,s.y);for(var i=0;i<o.length;i++){var a=o[i];e.lineTo(a.x,a.y)}},circle:function(e,t,r,n){e.arc(t,r,n,0,2*Math.PI,!1)}}))[e]},t.exports=i},{}],63:[function(e,t,r){"use strict";var n={};n.drawEdge=function(e,t,r){var n=t._private.rscratch,i=this.usePaths();if(!(n.badBezier||n.badLine||isNaN(n.allpts[0]))){var a=t._private.style;if(!(a.width.pfValue<=0)){var o=a["overlay-padding"].pfValue,s=a["overlay-opacity"].value,l=a["overlay-color"].value;if(r){if(0===s)return;this.strokeStyle(e,l[0],l[1],l[2],s),e.lineCap="round","self"!=n.edgeType||i||(e.lineCap="butt")}else{var u=a["line-color"].value;this.strokeStyle(e,u[0],u[1],u[2],a.opacity.value),e.lineCap="butt"}var c=a.width.pfValue+(r?2*o:0),d=r?"solid":a["line-style"].value;e.lineWidth=c;var h=a["shadow-blur"].pfValue,p=a["shadow-opacity"].value,v=a["shadow-color"].value,f=a["shadow-offset-x"].pfValue,g=a["shadow-offset-y"].pfValue;this.shadowStyle(e,v,r?0:p,h,f,g),this.drawEdgePath(t,e,n.allpts,d,c),this.drawArrowheads(e,t,r),this.shadowStyle(e,"transparent",0)}}},n.drawEdgePath=function(e,t,r,n,i){var a,o=e._private.rscratch,s=t,l=!1,u=this.usePaths();if(u){var c=r.join("$"),d=o.pathCacheKey&&o.pathCacheKey===c;d?(a=t=o.pathCache,l=!0):(a=t=new Path2D,o.pathCacheKey=c,o.pathCache=a)}if(s.setLineDash)switch(n){case"dotted":s.setLineDash([1,1]);break;case"dashed":s.setLineDash([6,3]);break;case"solid":s.setLineDash([])}if(!l)switch(t.beginPath&&t.beginPath(),t.moveTo(r[0],r[1]),o.edgeType){case"bezier":case"self":case"compound":case"multibezier":if(!o.badBezier)for(var h=2;h+3<r.length;h+=4)t.quadraticCurveTo(r[h],r[h+1],r[h+2],r[h+3]);break;case"straight":case"segments":case"haystack":if(!o.badLine)for(var h=2;h+1<r.length;h+=2)t.lineTo(r[h],r[h+1])}t=s,u?t.stroke(a):t.stroke(),t.setLineDash&&t.setLineDash([])},n.drawArrowheads=function(e,t,r){if(!r){var n=t._private.rscratch,i="haystack"===n.edgeType;i||this.drawArrowhead(e,t,"source",n.arrowStartX,n.arrowStartY,n.srcArrowAngle),this.drawArrowhead(e,t,"mid-target",n.midX,n.midY,n.midtgtArrowAngle),this.drawArrowhead(e,t,"mid-source",n.midX,n.midY,n.midsrcArrowAngle),i||this.drawArrowhead(e,t,"target",n.arrowEndX,n.arrowEndY,n.tgtArrowAngle)}},n.drawArrowhead=function(e,t,r,n,i,a){if(!(isNaN(n)||null==n||isNaN(i)||null==i||isNaN(a)||null==a)){var o=this,s=t._private.style,l=s[r+"-arrow-shape"].value;if("none"!==l){var u=e.globalCompositeOperation,c="hollow"===s[r+"-arrow-fill"].value?"both":"filled",d=s[r+"-arrow-fill"].value;"half-triangle-overshot"===l&&(d="hollow",c="hollow"),(1!==s.opacity.value||"hollow"===d)&&(e.globalCompositeOperation="destination-out",o.fillStyle(e,255,255,255,1),o.strokeStyle(e,255,255,255,1),o.drawArrowShape(t,r,e,c,s.width.pfValue,s[r+"-arrow-shape"].value,n,i,a),e.globalCompositeOperation=u);var h=s[r+"-arrow-color"].value;o.fillStyle(e,h[0],h[1],h[2],s.opacity.value),o.strokeStyle(e,h[0],h[1],h[2],s.opacity.value),o.drawArrowShape(t,r,e,d,s.width.pfValue,s[r+"-arrow-shape"].value,n,i,a)}}},n.drawArrowShape=function(e,t,r,n,i,a,o,s,l){var u,c=this,d=this.usePaths(),h=e._private.rscratch,p=!1,v=r,f={x:o,y:s},g=this.getArrowWidth(i),y=c.arrowShapes[a];if(d){var m=g+"$"+a+"$"+l+"$"+o+"$"+s;h.arrowPathCacheKey=h.arrowPathCacheKey||{},h.arrowPathCache=h.arrowPathCache||{};var b=h.arrowPathCacheKey[t]===m;b?(u=r=h.arrowPathCache[t],p=!0):(u=r=new Path2D,h.arrowPathCacheKey[t]=m,h.arrowPathCache[t]=u)}r.beginPath&&r.beginPath(),p||y.draw(r,g,l,f),!y.leavePathOpen&&r.closePath&&r.closePath(),r=v,("filled"===n||"both"===n)&&(d?r.fill(u):r.fill()),("hollow"===n||"both"===n)&&(r.lineWidth=y.matchEdgeWidth?i:1,r.lineJoin="miter",d?r.stroke(u):r.stroke())},t.exports=n},{}],64:[function(e,t,r){"use strict";var n={};n.safeDrawImage=function(e,t,r,n,i,a,o,s,l,u){var c=this;try{e.drawImage(t,r,n,i,a,o,s,l,u)}catch(d){c.data.canvasNeedsRedraw[c.NODE]=!0,c.data.canvasNeedsRedraw[c.DRAG]=!0,c.drawingImage=!0,c.redraw()}},n.drawInscribedImage=function(e,t,r){var n=this,i=r._private.position.x,a=r._private.position.y,o=r._private.style,s=o["background-fit"].value,l=o["background-position-x"],u=o["background-position-y"],c=o["background-repeat"].value,d=r.width(),h=r.height(),p=r._private.rscratch,v=o["background-clip"].value,f="node"===v,g=o["background-image-opacity"].value,y=t.width||t.cachedW,m=t.height||t.cachedH;(null==y||null==m)&&(document.body.appendChild(t),y=t.cachedW=t.width||t.offsetWidth,m=t.cachedH=t.height||t.offsetHeight,document.body.removeChild(t));var b=y,x=m,w=o["background-width"];"auto"!==w.value&&(b="%"===w.units?w.value/100*d:w.pfValue);var _=o["background-height"];if("auto"!==_.value&&(x="%"===_.units?_.value/100*h:_.pfValue),0!==b&&0!==x){if("contain"===s){var E=Math.min(d/b,h/x);b*=E,x*=E}else if("cover"===s){var E=Math.max(d/b,h/x);b*=E,x*=E}var D=i-d/2;D+="%"===l.units?(d-b)*l.value/100:l.pfValue;var S=a-h/2;S+="%"===u.units?(h-x)*u.value/100:u.pfValue,p.pathCache&&(D-=i,S-=a,i=0,a=0);var k=e.globalAlpha;if(e.globalAlpha=g,"no-repeat"===c)f&&(e.save(),p.pathCache?e.clip(p.pathCache):(n.nodeShapes[n.getNodeShape(r)].draw(e,i,a,d,h),e.clip())),n.safeDrawImage(e,t,0,0,y,m,D,S,b,x),f&&e.restore();else{var T=e.createPattern(t,c);e.fillStyle=T,n.nodeShapes[n.getNodeShape(r)].draw(e,i,a,d,h),e.translate(D,S),e.fill(),e.translate(-D,-S)}e.globalAlpha=k}},t.exports=n},{}],65:[function(e,t,r){"use strict";function n(e,t,r,n,i,a){var a=a||5;e.beginPath(),e.moveTo(t+a,r),e.lineTo(t+n-a,r),e.quadraticCurveTo(t+n,r,t+n,r+a),e.lineTo(t+n,r+i-a),e.quadraticCurveTo(t+n,r+i,t+n-a,r+i),e.lineTo(t+a,r+i),e.quadraticCurveTo(t,r+i,t,r+i-a),e.lineTo(t,r+a),e.quadraticCurveTo(t,r,t+a,r),e.closePath(),e.fill()}var i=e("../../../is"),a={};a.drawEdgeText=function(e,t){var r=t._private.style.label.strValue;if(r&&!r.match(/^\s+$/)&&(!this.hideEdgesOnViewport||!(this.dragData.didDrag||this.pinching||this.hoverData.dragging||this.data.wheel||this.swipePanning))){var n=t._private.style["font-size"].pfValue*t.cy().zoom(),a=t._private.style["min-zoomed-font-size"].pfValue;if(!(a>n)){e.textAlign="center",e.textBaseline="middle";var o=t._private.rscratch;if(i.number(o.labelX)&&i.number(o.labelY)){var s,l=t._private.style,u="autorotate"===l["edge-text-rotation"].strValue;u?(s=o.labelAngle,e.translate(o.labelX,o.labelY),e.rotate(s),this.drawText(e,t,0,0),e.rotate(-s),e.translate(-o.labelX,-o.labelY)):this.drawText(e,t,o.labelX,o.labelY)}}}},a.drawNodeText=function(e,t){var r=t._private.style.label.strValue;if(r&&!r.match(/^\s+$/)){var n=t._private.style["font-size"].pfValue*t.cy().zoom(),a=t._private.style["min-zoomed-font-size"].pfValue;if(!(a>n)){var o=t._private.style["text-halign"].strValue,s=t._private.style["text-valign"].strValue,l=t._private.rscratch;if(i.number(l.labelX)&&i.number(l.labelY)){switch(o){case"left":e.textAlign="right";break;case"right":e.textAlign="left";break;default:e.textAlign="center"}switch(s){case"top":e.textBaseline="bottom";break;case"bottom":e.textBaseline="top";break;default:e.textBaseline="middle"}this.drawText(e,t,l.labelX,l.labelY)}}}},a.getFontCache=function(e){var t;this.fontCaches=this.fontCaches||[];for(var r=0;r<this.fontCaches.length;r++)if(t=this.fontCaches[r],t.context===e)return t;return t={context:e},this.fontCaches.push(t),t},a.setupTextStyle=function(e,t){var r=t.effectiveOpacity(),n=t._private.style,i=n["font-style"].strValue,a=n["font-size"].pfValue+"px",o=n["font-family"].strValue,s=n["font-weight"].strValue,l=n["text-opacity"].value*n.opacity.value*r,u=n["text-outline-opacity"].value*l,c=n.color.value,d=n["text-outline-color"].value,h=n["text-shadow-blur"].pfValue,p=n["text-shadow-opacity"].value,v=n["text-shadow-color"].value,f=n["text-shadow-offset-x"].pfValue,g=n["text-shadow-offset-y"].pfValue,y=t._private.fontKey,m=this.getFontCache(e);m.key!==y&&(e.font=i+" "+s+" "+a+" "+o,m.key=y);var b=this.getLabelText(t);return e.lineJoin="round",this.fillStyle(e,c[0],c[1],c[2],l),this.strokeStyle(e,d[0],d[1],d[2],u),this.shadowStyle(e,v,p,h,f,g),b},a.drawText=function(e,t,r,i){var a=t._private,o=a.style,s=a.rstyle,l=a.rscratch,u=t.effectiveOpacity();if(0!==u&&0!==o["text-opacity"].value){var c=this.setupTextStyle(e,t),d=o["text-halign"].value,h=o["text-valign"].value;if(t.isEdge()&&(d="center",h="center"),t.isNode()){var p=o["padding-left"].pfValue,v=o["padding-right"].pfValue,f=o["padding-top"].pfValue,g=o["padding-bottom"].pfValue;r+=p/2,r-=v/2,i+=f/2,i-=g/2}if(null!=c&&!isNaN(r)&&!isNaN(i)){var y=o["text-background-opacity"].value,m=o["text-border-opacity"].value,b=o["text-border-width"].pfValue;if(y>0||b>0&&m>0){var x=4+b/2;t.isNode()&&("top"===h?i-=x:"bottom"===h&&(i+=x),"left"===d?r-=x:"right"===d&&(r+=x));var w=s.labelWidth,_=s.labelHeight,E=r;d&&("center"==d?E-=w/2:"left"==d&&(E-=w));var D=i;if(t.isNode()?"top"==h?D-=_:"center"==h&&(D-=_/2):D-=_/2,"autorotate"===o["edge-text-rotation"].strValue?(i=0,w+=4,E=r-w/2,D=i-_/2):(E-=x,D-=x,_+=2*x,w+=2*x),y>0){var S=e.fillStyle,k=o["text-background-color"].value;e.fillStyle="rgba("+k[0]+","+k[1]+","+k[2]+","+y*u+")";var T=o["text-background-shape"].strValue;"roundrectangle"==T?n(e,E,D,w,_,2):e.fillRect(E,D,w,_),e.fillStyle=S}if(b>0&&m>0){var P=e.strokeStyle,C=e.lineWidth,N=o["text-border-color"].value,M=o["text-border-style"].value;if(e.strokeStyle="rgba("+N[0]+","+N[1]+","+N[2]+","+m*u+")",e.lineWidth=b,e.setLineDash)switch(M){case"dotted":e.setLineDash([1,1]);break;case"dashed":e.setLineDash([4,2]);break;case"double":e.lineWidth=b/4,e.setLineDash([]);break;case"solid":e.setLineDash([])}if(e.strokeRect(E,D,w,_),"double"===M){var B=b/2;e.strokeRect(E+B,D+B,w-2*B,_-2*B)}e.setLineDash&&e.setLineDash([]),e.lineWidth=C,e.strokeStyle=P}}var z=2*o["text-outline-width"].pfValue;if(z>0&&(e.lineWidth=z),"wrap"===o["text-wrap"].value){var O=l.labelWrapCachedLines,I=s.labelHeight/O.length;switch(h){case"top":i-=(O.length-1)*I;break;case"bottom":break;default:case"center":i-=(O.length-1)*I/2}for(var L=0;L<O.length;L++)z>0&&e.strokeText(O[L],r,i),e.fillText(O[L],r,i),i+=I}else z>0&&e.strokeText(c,r,i),e.fillText(c,r,i);this.shadowStyle(e,"transparent",0)}}},t.exports=a},{"../../../is":77}],66:[function(e,t,r){"use strict";var n=e("../../../is"),i={};i.drawNode=function(e,t,r){var i,a,o=this,s=t._private.style,l=t._private.rscratch,u=t._private,c=u.position;if(n.number(c.x)&&n.number(c.y)){var d,h=this.usePaths(),p=e,v=!1,f=s["overlay-padding"].pfValue,g=s["overlay-opacity"].value,y=s["overlay-color"].value;if(!r||0!==g){var m=t.effectiveOpacity();if(0!==m)if(i=t.width()+s["padding-left"].pfValue+s["padding-right"].pfValue,a=t.height()+s["padding-top"].pfValue+s["padding-bottom"].pfValue,e.lineWidth=s["border-width"].pfValue,void 0!==r&&r)g>0&&(this.fillStyle(e,y[0],y[1],y[2],g),o.nodeShapes.roundrectangle.draw(e,t._private.position.x,t._private.position.y,i+2*f,a+2*f),e.fill());else{var b,x=s["background-image"].value[2]||s["background-image"].value[1];if(void 0!==x){b=this.getCachedImage(x,function(){o.data.canvasNeedsRedraw[o.NODE]=!0,o.data.canvasNeedsRedraw[o.DRAG]=!0,o.drawingImage=!0,o.redraw()});var w=u.backgrounding;u.backgrounding=!b.complete,w!==u.backgrounding&&t.updateStyle(!1)}var _=s["background-color"].value,E=s["border-color"].value,D=s["border-style"].value;this.fillStyle(e,_[0],_[1],_[2],s["background-opacity"].value*m),this.strokeStyle(e,E[0],E[1],E[2],s["border-opacity"].value*m);var S=s["shadow-blur"].pfValue,k=s["shadow-opacity"].value,T=s["shadow-color"].value,P=s["shadow-offset-x"].pfValue,C=s["shadow-offset-y"].pfValue;if(this.shadowStyle(e,T,k,S,P,C),e.lineJoin="miter",e.setLineDash)switch(D){case"dotted":e.setLineDash([1,1]);break;case"dashed":e.setLineDash([4,2]);break;case"solid":case"double":e.setLineDash([])}var N=s.shape.strValue;if(h){var M=N+"$"+i+"$"+a;e.translate(c.x,c.y),l.pathCacheKey===M?(d=e=l.pathCache,v=!0):(d=e=new Path2D,l.pathCacheKey=M,l.pathCache=d)}if(!v){var B=c;h&&(B={x:0,y:0}),o.nodeShapes[this.getNodeShape(t)].draw(e,B.x,B.y,i,a)}e=p,h?e.fill(d):e.fill(),this.shadowStyle(e,"transparent",0),void 0!==x&&b.complete&&this.drawInscribedImage(e,b,t);var z=s["background-blacken"].value,O=s["border-width"].pfValue;if(this.hasPie(t)&&(this.drawPie(e,t,m),(0!==z||0!==O)&&(h||o.nodeShapes[this.getNodeShape(t)].draw(e,c.x,c.y,i,a))),z>0?(this.fillStyle(e,0,0,0,z),h?e.fill(d):e.fill()):0>z&&(this.fillStyle(e,255,255,255,-z),h?e.fill(d):e.fill()),O>0&&(h?e.stroke(d):e.stroke(),"double"===D)){e.lineWidth=s["border-width"].pfValue/3;var I=e.globalCompositeOperation;e.globalCompositeOperation="destination-out",h?e.stroke(d):e.stroke(),e.globalCompositeOperation=I}h&&e.translate(-c.x,-c.y),e.setLineDash&&e.setLineDash([])}}}},i.hasPie=function(e){return e=e[0],e._private.hasPie},i.drawPie=function(e,t,r){t=t[0];var n=t._private,i=t.cy().style(),a=n.style,o=a["pie-size"],s=t.width(),l=t.height(),u=n.position.x,c=n.position.y,d=Math.min(s,l)/2,h=0,p=this.usePaths();p&&(u=0,c=0),"%"===o.units?d=d*o.value/100:void 0!==o.pfValue&&(d=o.pfValue/2);for(var v=1;v<=i.pieBackgroundN;v++){var f=a["pie-"+v+"-background-size"].value,g=a["pie-"+v+"-background-color"].value,y=a["pie-"+v+"-background-opacity"].value*r,m=f/100;m+h>1&&(m=1-h);var b=1.5*Math.PI+2*Math.PI*h,x=2*Math.PI*m,w=b+x;0===f||h>=1||h+m>1||(e.beginPath(),e.moveTo(u,c),e.arc(u,c,d,b,w),e.closePath(),this.fillStyle(e,g[0],g[1],g[2],y),e.fill(),h+=m)}},t.exports=i},{"../../../is":77}],67:[function(e,t,r){"use strict";var n={},i=e("../../../util"),a=e("../../../math"),o=100;n.getPixelRatio=function(){var e=this.data.contexts[0];if(null!=this.forcedPixelRatio)return this.forcedPixelRatio;var t=e.backingStorePixelRatio||e.webkitBackingStorePixelRatio||e.mozBackingStorePixelRatio||e.msBackingStorePixelRatio||e.oBackingStorePixelRatio||e.backingStorePixelRatio||1;return(window.devicePixelRatio||1)/t},n.paintCache=function(e){for(var t,r=this.paintCaches=this.paintCaches||[],n=!0,i=0;i<r.length;i++)if(t=r[i],t.context===e){n=!1;break}return n&&(t={context:e},r.push(t)),t},n.fillStyle=function(e,t,r,n,i){e.fillStyle="rgba("+t+","+r+","+n+","+i+")"},n.strokeStyle=function(e,t,r,n,i){e.strokeStyle="rgba("+t+","+r+","+n+","+i+")"},n.shadowStyle=function(e,t,r,n,i,a){var o=this.cy.zoom(),s=this.paintCache(e);(0!==s.shadowOpacity||0!==r)&&(s.shadowOpacity=r,r>0?(e.shadowBlur=n*o,e.shadowColor="rgba("+t[0]+","+t[1]+","+t[2]+","+r+")",e.shadowOffsetX=i*o,e.shadowOffsetY=a*o):(e.shadowBlur=0,e.shadowColor="transparent"))},n.matchCanvasSize=function(e){var t=this,r=t.data,n=e.clientWidth,i=e.clientHeight,a=t.getPixelRatio(),o=t.motionBlurPxRatio;(e===t.data.bufferCanvases[t.MOTIONBLUR_BUFFER_NODE]||e===t.data.bufferCanvases[t.MOTIONBLUR_BUFFER_DRAG])&&(a=o);var s,l=n*a,u=i*a;if(l!==t.canvasWidth||u!==t.canvasHeight){t.fontCaches=null;var c=r.canvasContainer;c.style.width=n+"px",c.style.height=i+"px";for(var d=0;d<t.CANVAS_LAYERS;d++)s=r.canvases[d],(s.width!==l||s.height!==u)&&(s.width=l,s.height=u,s.style.width=n+"px",s.style.height=i+"px");for(var d=0;d<t.BUFFER_COUNT;d++)s=r.bufferCanvases[d],(s.width!==l||s.height!==u)&&(s.width=l,s.height=u,s.style.width=n+"px",s.style.height=i+"px");t.textureMult=1,1>=a&&(s=r.bufferCanvases[t.TEXTURE_BUFFER],t.textureMult=2,s.width=l*t.textureMult,s.height=u*t.textureMult),t.canvasWidth=l,t.canvasHeight=u}},n.renderTo=function(e,t,r,n){this.render({forcedContext:e,forcedZoom:t,forcedPan:r,drawAllLayers:!0,forcedPxRatio:n})},n.render=function(e){function t(e,t,r,n,i){var a=e.globalCompositeOperation;e.globalCompositeOperation="destination-out",h.fillStyle(e,255,255,255,h.motionBlurTransparency),e.fillRect(t,r,n,i),e.globalCompositeOperation=a}function r(e,r){var n,i,a,o;h.clearingMotionBlur||e!==f.bufferContexts[h.MOTIONBLUR_BUFFER_NODE]&&e!==f.bufferContexts[h.MOTIONBLUR_BUFFER_DRAG]?(n=C,i=T,a=h.canvasWidth,o=h.canvasHeight):(n={x:P.x*b,y:P.y*b},i=k*b,a=h.canvasWidth*b,o=h.canvasHeight*b),e.setTransform(1,0,0,1,0,0),"motionBlur"===r?t(e,0,0,a,o):s||void 0!==r&&!r||e.clearRect(0,0,a,o),l||(e.translate(n.x,n.y),e.scale(i,i)),d&&e.translate(d.x,d.y),c&&e.scale(c,c)}function n(e,t){for(var r=e.eles,n=0;n<r.length;n++){var i=r[n];i.isNode()?(h.drawNode(t,i),q||h.drawNodeText(t,i),h.drawNode(t,i,!0)):j||(h.drawEdge(t,i),q||h.drawEdgeText(t,i),h.drawEdge(t,i,!0))}}e=e||i.staticEmptyObject();var s=e.forcedContext,l=e.drawAllLayers,u=e.drawOnlyNodeLayer,c=e.forcedZoom,d=e.forcedPan,h=this,p=void 0===e.forcedPxRatio?this.getPixelRatio():e.forcedPxRatio,v=h.cy,f=h.data,g=f.canvasNeedsRedraw,y=h.textureOnViewport&&!s&&(h.pinching||h.hoverData.dragging||h.swipePanning||h.data.wheelZooming),m=void 0!==e.motionBlur?e.motionBlur:h.motionBlur,b=h.motionBlurPxRatio,x=v.hasCompoundNodes(),w=h.hoverData.draggingEles,_=h.hoverData.selecting||h.touchData.selecting?!0:!1;m=m&&!s&&h.motionBlurEnabled&&!_;var E=m;!s&&h.motionBlurTimeout&&clearTimeout(h.motionBlurTimeout),m&&(null==h.mbFrames&&(h.mbFrames=0),h.drawingImage||h.mbFrames++,h.mbFrames<3&&(E=!1),h.mbFrames>h.minMbLowQualFrames&&(h.motionBlurPxRatio=h.mbPxRBlurry)),h.clearingMotionBlur&&(h.motionBlurPxRatio=1),h.textureDrawLastFrame&&!y&&(g[h.NODE]=!0,g[h.SELECT_BOX]=!0);var D=h.getCachedEdges(),S=v.style()._private.coreStyle,k=v.zoom(),T=void 0!==c?c:k,P=v.pan(),C={x:P.x,y:P.y},N={zoom:k,pan:{x:P.x,y:P.y}},M=h.prevViewport,B=void 0===M||N.zoom!==M.zoom||N.pan.x!==M.pan.x||N.pan.y!==M.pan.y;B||w&&!x||(h.motionBlurPxRatio=1),d&&(C=d),T*=p,C.x*=p,C.y*=p;var z={drag:{nodes:[],edges:[],eles:[]},nondrag:{nodes:[],edges:[],eles:[]}};if(y||(h.textureDrawLastFrame=!1),y){h.textureDrawLastFrame=!0;var O;if(!h.textureCache){h.textureCache={},O=h.textureCache.bb=v.elements().boundingBox(),h.textureCache.texture=h.data.bufferCanvases[h.TEXTURE_BUFFER];var I=h.data.bufferContexts[h.TEXTURE_BUFFER];I.setTransform(1,0,0,1,0,0),I.clearRect(0,0,h.canvasWidth*h.textureMult,h.canvasHeight*h.textureMult),h.render({forcedContext:I,drawOnlyNodeLayer:!0,forcedPxRatio:p*h.textureMult});var N=h.textureCache.viewport={zoom:v.zoom(),pan:v.pan(),width:h.canvasWidth,height:h.canvasHeight};N.mpan={x:(0-N.pan.x)/N.zoom,y:(0-N.pan.y)/N.zoom}}g[h.DRAG]=!1,g[h.NODE]=!1;var L=f.contexts[h.NODE],A=h.textureCache.texture,N=h.textureCache.viewport;O=h.textureCache.bb,L.setTransform(1,0,0,1,0,0),m?t(L,0,0,N.width,N.height):L.clearRect(0,0,N.width,N.height);var R=S["outside-texture-bg-color"].value,V=S["outside-texture-bg-opacity"].value;h.fillStyle(L,R[0],R[1],R[2],V),L.fillRect(0,0,N.width,N.height);var k=v.zoom();r(L,!1),L.clearRect(N.mpan.x,N.mpan.y,N.width/N.zoom/p,N.height/N.zoom/p),L.drawImage(A,N.mpan.x,N.mpan.y,N.width/N.zoom/p,N.height/N.zoom/p)}else h.textureOnViewport&&!s&&(h.textureCache=null);var F=h.pinching||h.hoverData.dragging||h.swipePanning||h.data.wheelZooming||h.hoverData.draggingEles,j=h.hideEdgesOnViewport&&F,q=h.hideLabelsOnViewport&&F;if(g[h.DRAG]||g[h.NODE]||l||u){j||h.findEdgeControlPoints(D);for(var X=h.getCachedZSortedEles(),Y=v.extent(),$=0;$<X.length;$++){var H,W=X[$],O=s?null:W.boundingBox(),Z=s?!0:a.boundingBoxesIntersect(Y,O);Z&&(H=W._private.rscratch.inDragLayer?z.drag:z.nondrag,H.eles.push(W))}}var U=[];if(U[h.NODE]=!g[h.NODE]&&m&&!h.clearedForMotionBlur[h.NODE]||h.clearingMotionBlur,U[h.NODE]&&(h.clearedForMotionBlur[h.NODE]=!0),U[h.DRAG]=!g[h.DRAG]&&m&&!h.clearedForMotionBlur[h.DRAG]||h.clearingMotionBlur,U[h.DRAG]&&(h.clearedForMotionBlur[h.DRAG]=!0),g[h.NODE]||l||u||U[h.NODE]){var G=m&&!U[h.NODE]&&1!==b,L=s||(G?h.data.bufferContexts[h.MOTIONBLUR_BUFFER_NODE]:f.contexts[h.NODE]),K=m&&!G?"motionBlur":void 0;r(L,K),n(z.nondrag,L),l||m||(g[h.NODE]=!1)}if(!u&&(g[h.DRAG]||l||U[h.DRAG])){var G=m&&!U[h.DRAG]&&1!==b,L=s||(G?h.data.bufferContexts[h.MOTIONBLUR_BUFFER_DRAG]:f.contexts[h.DRAG]);r(L,m&&!G?"motionBlur":void 0),n(z.drag,L),l||m||(g[h.DRAG]=!1)}if(h.showFps||!u&&g[h.SELECT_BOX]&&!l){var L=s||f.contexts[h.SELECT_BOX];if(r(L),1==h.selection[4]&&(h.hoverData.selecting||h.touchData.selecting)){var k=h.cy.zoom(),J=S["selection-box-border-width"].value/k;L.lineWidth=J,L.fillStyle="rgba("+S["selection-box-color"].value[0]+","+S["selection-box-color"].value[1]+","+S["selection-box-color"].value[2]+","+S["selection-box-opacity"].value+")",L.fillRect(h.selection[0],h.selection[1],h.selection[2]-h.selection[0],h.selection[3]-h.selection[1]),J>0&&(L.strokeStyle="rgba("+S["selection-box-border-color"].value[0]+","+S["selection-box-border-color"].value[1]+","+S["selection-box-border-color"].value[2]+","+S["selection-box-opacity"].value+")",L.strokeRect(h.selection[0],h.selection[1],h.selection[2]-h.selection[0],h.selection[3]-h.selection[1]))}if(f.bgActivePosistion&&!h.hoverData.selecting){var k=h.cy.zoom(),Q=f.bgActivePosistion;L.fillStyle="rgba("+S["active-bg-color"].value[0]+","+S["active-bg-color"].value[1]+","+S["active-bg-color"].value[2]+","+S["active-bg-opacity"].value+")",L.beginPath(),L.arc(Q.x,Q.y,S["active-bg-size"].pfValue/k,0,2*Math.PI),L.fill()}var ee=h.lastRedrawTime;if(h.showFps&&ee){ee=Math.round(ee);var te=Math.round(1e3/ee);L.setTransform(1,0,0,1,0,0),L.fillStyle="rgba(255, 0, 0, 0.75)",L.strokeStyle="rgba(255, 0, 0, 0.75)",L.lineWidth=1,L.fillText("1 frame = "+ee+" ms = "+te+" fps",0,20);var re=60;L.strokeRect(0,30,250,20),L.fillRect(0,30,250*Math.min(te/re,1),20)}l||(g[h.SELECT_BOX]=!1)}if(m&&1!==b){var ne=f.contexts[h.NODE],ie=h.data.bufferCanvases[h.MOTIONBLUR_BUFFER_NODE],ae=f.contexts[h.DRAG],oe=h.data.bufferCanvases[h.MOTIONBLUR_BUFFER_DRAG],se=function(e,r,n){e.setTransform(1,0,0,1,0,0),n||!E?e.clearRect(0,0,h.canvasWidth,h.canvasHeight):t(e,0,0,h.canvasWidth,h.canvasHeight);var i=b;e.drawImage(r,0,0,h.canvasWidth*i,h.canvasHeight*i,0,0,h.canvasWidth,h.canvasHeight)};(g[h.NODE]||U[h.NODE])&&(se(ne,ie,U[h.NODE]),g[h.NODE]=!1),(g[h.DRAG]||U[h.DRAG])&&(se(ae,oe,U[h.DRAG]),g[h.DRAG]=!1)}h.currentlyDrawing=!1,h.prevViewport=N,h.clearingMotionBlur&&(h.clearingMotionBlur=!1,h.motionBlurCleared=!0,h.motionBlur=!0),m&&(h.motionBlurTimeout=setTimeout(function(){h.motionBlurTimeout=null,h.clearedForMotionBlur[h.NODE]=!1,h.clearedForMotionBlur[h.DRAG]=!1,h.motionBlur=!1,h.clearingMotionBlur=!y,h.mbFrames=0,g[h.NODE]=!0,g[h.DRAG]=!0,h.redraw()},o)),h.drawingImage=!1,s||h.initrender||(h.initrender=!0,v.trigger("initrender")),s||v.triggerOnRender()},t.exports=n},{"../../../math":79,"../../../util":94}],68:[function(e,t,r){"use strict";var n=e("../../../math"),i={};i.drawPolygonPath=function(e,t,r,n,i,a){var o=n/2,s=i/2;e.beginPath&&e.beginPath(),e.moveTo(t+o*a[0],r+s*a[1]);for(var l=1;l<a.length/2;l++)e.lineTo(t+o*a[2*l],r+s*a[2*l+1]);e.closePath()},i.drawRoundRectanglePath=function(e,t,r,i,a,o){var s=i/2,l=a/2,u=n.getRoundRectangleRadius(i,a);e.beginPath&&e.beginPath(),e.moveTo(t,r-l),e.arcTo(t+s,r-l,t+s,r,u),e.arcTo(t+s,r+l,t,r+l,u),e.arcTo(t-s,r+l,t-s,r,u),e.arcTo(t-s,r-l,t,r-l,u),e.lineTo(t,r-l),e.closePath()};for(var a=Math.sin(0),o=Math.cos(0),s={},l={},u=Math.PI/40,c=0*Math.PI;c<2*Math.PI;c+=u)s[c]=Math.sin(c),l[c]=Math.cos(c);i.drawEllipsePath=function(e,t,r,n,i){if(e.beginPath&&e.beginPath(),e.ellipse)e.ellipse(t,r,n/2,i/2,0,0,2*Math.PI);else for(var c,d,h=n/2,p=i/2,v=0*Math.PI;v<2*Math.PI;v+=u)c=t-h*s[v]*a+h*l[v]*o,d=r+p*l[v]*a+p*s[v]*o,0===v?e.moveTo(c,d):e.lineTo(c,d);e.closePath()},t.exports=i},{"../../../math":79}],69:[function(e,t,r){"use strict";var n=e("../../../is"),i={};i.createBuffer=function(e,t){var r=document.createElement("canvas");return r.width=e,r.height=t,[r,r.getContext("2d")]},i.bufferCanvasImage=function(e){var t=this.cy,r=t.elements().boundingBox(),i=e.full?Math.ceil(r.w):this.container.clientWidth,a=e.full?Math.ceil(r.h):this.container.clientHeight,o=1;if(void 0!==e.scale)i*=e.scale,a*=e.scale,o=e.scale;else if(n.number(e.maxWidth)||n.number(e.maxHeight)){var s=1/0,l=1/0;n.number(e.maxWidth)&&(s=o*e.maxWidth/i),n.number(e.maxHeight)&&(l=o*e.maxHeight/a),o=Math.min(s,l),i*=o,a*=o}var u=document.createElement("canvas");u.width=i,u.height=a,u.style.width=i+"px",u.style.height=a+"px";var c=u.getContext("2d");if(i>0&&a>0)if(c.clearRect(0,0,i,a),e.bg&&(c.fillStyle=e.bg,c.rect(0,0,i,a),c.fill()),c.globalCompositeOperation="source-over",e.full)this.render({forcedContext:c,drawAllLayers:!0,forcedZoom:o,forcedPan:{x:-r.x1*o,y:-r.y1*o},forcedPxRatio:1});else{var d=t.pan(),h={x:d.x*o,y:d.y*o},p=t.zoom()*o;this.render({forcedContext:c,drawAllLayers:!0,forcedZoom:p,forcedPan:h,forcedPxRatio:1})}return u},i.png=function(e){return this.bufferCanvasImage(e).toDataURL("image/png")},i.jpg=function(e){return this.bufferCanvasImage(e).toDataURL("image/jpeg")},t.exports=i},{"../../../is":77}],70:[function(e,t,r){"use strict";function n(e){var t=this;t.data={canvases:new Array(s.CANVAS_LAYERS),contexts:new Array(s.CANVAS_LAYERS),canvasNeedsRedraw:new Array(s.CANVAS_LAYERS),bufferCanvases:new Array(s.BUFFER_COUNT),bufferContexts:new Array(s.CANVAS_LAYERS)},t.data.canvasContainer=document.createElement("div");var r=t.data.canvasContainer.style;t.data.canvasContainer.setAttribute("style","-webkit-tap-highlight-color: rgba(0,0,0,0);"),r.position="relative",r.zIndex="0",r.overflow="hidden";var n=e.cy.container();n.appendChild(t.data.canvasContainer),n.setAttribute("style",(n.getAttribute("style")||"")+"-webkit-tap-highlight-color: rgba(0,0,0,0);");
+for(var i=0;i<s.CANVAS_LAYERS;i++){var o=t.data.canvases[i]=document.createElement("canvas");t.data.contexts[i]=o.getContext("2d"),o.setAttribute("style","-webkit-user-select: none; -moz-user-select: -moz-none; user-select: none; -webkit-tap-highlight-color: rgba(0,0,0,0); outline-style: none;"+(a.ms()?" -ms-touch-action: none; touch-action: none; ":"")),o.style.position="absolute",o.setAttribute("data-id","layer"+i),o.style.zIndex=String(s.CANVAS_LAYERS-i),t.data.canvasContainer.appendChild(o),t.data.canvasNeedsRedraw[i]=!1}t.data.topCanvas=t.data.canvases[0],t.data.canvases[s.NODE].setAttribute("data-id","layer"+s.NODE+"-node"),t.data.canvases[s.SELECT_BOX].setAttribute("data-id","layer"+s.SELECT_BOX+"-selectbox"),t.data.canvases[s.DRAG].setAttribute("data-id","layer"+s.DRAG+"-drag");for(var i=0;i<s.BUFFER_COUNT;i++)t.data.bufferCanvases[i]=document.createElement("canvas"),t.data.bufferContexts[i]=t.data.bufferCanvases[i].getContext("2d"),t.data.bufferCanvases[i].style.position="absolute",t.data.bufferCanvases[i].setAttribute("data-id","buffer"+i),t.data.bufferCanvases[i].style.zIndex=String(-i-1),t.data.bufferCanvases[i].style.visibility="hidden";t.pathsEnabled=!0}var i=e("../../../util"),a=e("../../../is"),o=n,s=n.prototype;s.CANVAS_LAYERS=3,s.SELECT_BOX=0,s.DRAG=1,s.NODE=2,s.BUFFER_COUNT=3,s.TEXTURE_BUFFER=0,s.MOTIONBLUR_BUFFER_NODE=1,s.MOTIONBLUR_BUFFER_DRAG=2,s.redrawHint=function(e,t){var r=this;switch(e){case"eles":r.data.canvasNeedsRedraw[s.NODE]=t;break;case"drag":r.data.canvasNeedsRedraw[s.DRAG]=t;break;case"select":r.data.canvasNeedsRedraw[s.SELECT_BOX]=t}};var l="undefined"!=typeof Path2D;s.path2dEnabled=function(e){return void 0===e?this.pathsEnabled:void(this.pathsEnabled=e?!0:!1)},s.usePaths=function(){return l&&this.pathsEnabled},[e("./arrow-shapes"),e("./drawing-edges"),e("./drawing-images"),e("./drawing-label-text"),e("./drawing-nodes"),e("./drawing-redraw"),e("./drawing-shapes"),e("./export-image"),e("./node-shapes")].forEach(function(e){i.extend(s,e)}),t.exports=o},{"../../../is":77,"../../../util":94,"./arrow-shapes":62,"./drawing-edges":63,"./drawing-images":64,"./drawing-label-text":65,"./drawing-nodes":66,"./drawing-redraw":67,"./drawing-shapes":68,"./export-image":69,"./node-shapes":71}],71:[function(e,t,r){"use strict";var n,i={};i.nodeShapeImpl=function(e){var t=this;return(n||(n={ellipse:function(e,r,n,i,a){t.drawEllipsePath(e,r,n,i,a)},polygon:function(e,r,n,i,a,o){t.drawPolygonPath(e,r,n,i,a,o)},roundrectangle:function(e,r,n,i,a){t.drawRoundRectanglePath(e,r,n,i,a,10)}}))[e]},t.exports=i},{}],72:[function(e,t,r){"use strict";t.exports=[{name:"null",impl:e("./null")},{name:"base",impl:e("./base")},{name:"canvas",impl:e("./canvas")}]},{"./base":58,"./canvas":70,"./null":73}],73:[function(e,t,r){"use strict";function n(e){this.options=e,this.notifications=0}var i=function(){};n.prototype={recalculateRenderedStyle:i,notify:function(){this.notifications++},init:i},t.exports=n},{}],74:[function(e,t,r){"use strict";var n=e("./is"),i=e("./util"),a=e("./thread"),o=e("./promise"),s=e("./define"),l=function(t){if(!(this instanceof l))return new l(t);this._private={pass:[]};var r=4;if(n.number(t),"undefined"!=typeof navigator&&null!=navigator.hardwareConcurrency)t=navigator.hardwareConcurrency;else try{t=e("os").cpus().length}catch(i){t=r}for(var o=0;t>o;o++)this[o]=new a;this.length=t},u=l.prototype;i.extend(u,{instanceString:function(){return"fabric"},require:function(e,t){for(var r=0;r<this.length;r++){var n=this[r];n.require(e,t)}return this},random:function(){var e=Math.round((this.length-1)*Math.random()),t=this[e];return t},run:function(e){var t=this._private.pass.shift();return this.random().pass(t).run(e)},message:function(e){return this.random().message(e)},broadcast:function(e){for(var t=0;t<this.length;t++){var r=this[t];r.message(e)}return this},stop:function(){for(var e=0;e<this.length;e++){var t=this[e];t.stop()}return this},pass:function(e){var t=this._private.pass;if(!n.array(e))throw"Only arrays may be used with fabric.pass()";return t.push(e),this},spreadSize:function(){var e=Math.ceil(this._private.pass[0].length/this.length);return e=Math.max(1,e)},spread:function(e){for(var t=this,r=t._private,n=t.spreadSize(),i=r.pass.shift().concat([]),a=[],s=0;s<this.length;s++){var l=this[s],u=i.splice(0,n),c=l.pass(u).run(e);a.push(c);var d=0===i.length;if(d)break}return o.all(a).then(function(e){for(var t=[],r=0,n=0;n<e.length;n++)for(var i=e[n],a=0;a<i.length;a++){var o=i[a];t[r++]=o}return t})},map:function(e){var t=this;return t.require(e,"_$_$_fabmap"),t.spread(function(e){var t=[],r=resolve;resolve=function(e){t.push(e)};for(var n=0;n<e.length;n++){var i=t.length,a=_$_$_fabmap(e[n]),o=i===t.length;o&&t.push(a)}return resolve=r,t})},filter:function(e){var t=this._private,r=t.pass[0];return this.map(e).then(function(e){for(var t=[],n=0;n<r.length;n++){var i=r[n],a=e[n];a&&t.push(i)}return t})},sort:function(e){var t=this,r=this._private.pass[0].length,n=this.spreadSize();return e=e||function(e,t){return t>e?-1:e>t?1:0},t.require(e,"_$_$_cmp"),t.spread(function(e){var t=e.sort(_$_$_cmp);resolve(t)}).then(function(t){for(var i=function(n,i,a){i=Math.min(i,r),a=Math.min(a,r);for(var o=n,s=i,l=[],u=o;a>u;u++){var c=t[n],d=t[i];s>n&&(i>=a||e(c,d)<=0)?(l.push(c),n++):(l.push(d),i++)}for(var u=0;u<l.length;u++){var h=o+u;t[h]=l[u]}},a=n;r>a;a*=2)for(var o=0;r>o;o+=2*a)i(o,o+a,o+2*a);return t})}});var c=function(e){return e=e||{},function(t,r){var n=this._private.pass.shift();return this.random().pass(n)[e.threadFn](t,r)}};i.extend(u,{randomMap:c({threadFn:"map"}),reduce:c({threadFn:"reduce"}),reduceRight:c({threadFn:"reduceRight"})});var d=u;d.promise=d.run,d.terminate=d.halt=d.stop,d.include=d.require,i.extend(u,{on:s.on(),one:s.on({unbindSelfOnTrigger:!0}),off:s.off(),trigger:s.trigger()}),s.eventAliasesOn(u),t.exports=l},{"./define":41,"./is":77,"./promise":80,"./thread":92,"./util":94,os:void 0}],75:[function(e,t,r){"use strict";(function(){var e,n,i,a,o,s,l,u,c,d,h,p,v,f,g;i=Math.floor,d=Math.min,n=function(e,t){return t>e?-1:e>t?1:0},c=function(e,t,r,a,o){var s;if(null==r&&(r=0),null==o&&(o=n),0>r)throw new Error("lo must be non-negative");for(null==a&&(a=e.length);a>r;)s=i((r+a)/2),o(t,e[s])<0?a=s:r=s+1;return[].splice.apply(e,[r,r-r].concat(t)),t},s=function(e,t,r){return null==r&&(r=n),e.push(t),f(e,0,e.length-1,r)},o=function(e,t){var r,i;return null==t&&(t=n),r=e.pop(),e.length?(i=e[0],e[0]=r,g(e,0,t)):i=r,i},u=function(e,t,r){var i;return null==r&&(r=n),i=e[0],e[0]=t,g(e,0,r),i},l=function(e,t,r){var i;return null==r&&(r=n),e.length&&r(e[0],t)<0&&(i=[e[0],t],t=i[0],e[0]=i[1],g(e,0,r)),t},a=function(e,t){var r,a,o,s,l,u;for(null==t&&(t=n),s=function(){u=[];for(var t=0,r=i(e.length/2);r>=0?r>t:t>r;r>=0?t++:t--)u.push(t);return u}.apply(this).reverse(),l=[],a=0,o=s.length;o>a;a++)r=s[a],l.push(g(e,r,t));return l},v=function(e,t,r){var i;return null==r&&(r=n),i=e.indexOf(t),-1!==i?(f(e,0,i,r),g(e,i,r)):void 0},h=function(e,t,r){var i,o,s,u,c;if(null==r&&(r=n),o=e.slice(0,t),!o.length)return o;for(a(o,r),c=e.slice(t),s=0,u=c.length;u>s;s++)i=c[s],l(o,i,r);return o.sort(r).reverse()},p=function(e,t,r){var i,s,l,u,h,p,v,f,g,y;if(null==r&&(r=n),10*t<=e.length){if(u=e.slice(0,t).sort(r),!u.length)return u;for(l=u[u.length-1],f=e.slice(t),h=0,v=f.length;v>h;h++)i=f[h],r(i,l)<0&&(c(u,i,0,null,r),u.pop(),l=u[u.length-1]);return u}for(a(e,r),y=[],s=p=0,g=d(t,e.length);g>=0?g>p:p>g;s=g>=0?++p:--p)y.push(o(e,r));return y},f=function(e,t,r,i){var a,o,s;for(null==i&&(i=n),a=e[r];r>t&&(s=r-1>>1,o=e[s],i(a,o)<0);)e[r]=o,r=s;return e[r]=a},g=function(e,t,r){var i,a,o,s,l;for(null==r&&(r=n),a=e.length,l=t,o=e[t],i=2*t+1;a>i;)s=i+1,a>s&&!(r(e[i],e[s])<0)&&(i=s),e[t]=e[i],t=i,i=2*t+1;return e[t]=o,f(e,l,t,r)},e=function(){function e(e){this.cmp=null!=e?e:n,this.nodes=[]}return e.push=s,e.pop=o,e.replace=u,e.pushpop=l,e.heapify=a,e.updateItem=v,e.nlargest=h,e.nsmallest=p,e.prototype.push=function(e){return s(this.nodes,e,this.cmp)},e.prototype.pop=function(){return o(this.nodes,this.cmp)},e.prototype.peek=function(){return this.nodes[0]},e.prototype.contains=function(e){return-1!==this.nodes.indexOf(e)},e.prototype.replace=function(e){return u(this.nodes,e,this.cmp)},e.prototype.pushpop=function(e){return l(this.nodes,e,this.cmp)},e.prototype.heapify=function(){return a(this.nodes,this.cmp)},e.prototype.updateItem=function(e){return v(this.nodes,e,this.cmp)},e.prototype.clear=function(){return this.nodes=[]},e.prototype.empty=function(){return 0===this.nodes.length},e.prototype.size=function(){return this.nodes.length},e.prototype.clone=function(){var t;return t=new e,t.nodes=this.nodes.slice(0),t},e.prototype.toArray=function(){return this.nodes.slice(0)},e.prototype.insert=e.prototype.push,e.prototype.top=e.prototype.peek,e.prototype.front=e.prototype.peek,e.prototype.has=e.prototype.contains,e.prototype.copy=e.prototype.clone,e}(),function(e,n){return"function"==typeof define&&define.amd?define([],n):"object"==typeof r?t.exports=n():e.Heap=n()}(this,function(){return e})}).call(this)},{}],76:[function(e,t,r){"use strict";var n=e("./window"),i=e("./is"),a=e("./core"),o=e("./extension"),s=e("./jquery-plugin"),l=e("./stylesheet"),u=e("./thread"),c=e("./fabric"),d=function(e){return void 0===e&&(e={}),i.plainObject(e)?new a(e):i.string(e)?o.apply(o,arguments):void 0};d.version="2.5.1",n&&n.jQuery&&s(n.jQuery,d),d.registerJquery=function(e){s(e,d)},d.stylesheet=d.Stylesheet=l,d.thread=d.Thread=u,d.fabric=d.Fabric=c,t.exports=d},{"./core":34,"./extension":43,"./fabric":74,"./is":77,"./jquery-plugin":78,"./stylesheet":91,"./thread":92,"./window":100}],77:[function(e,t,r){"use strict";var n=e("./window"),i=n?n.navigator:null,a="string",o=typeof{},s="function",l=typeof HTMLElement,u=function(e){return e&&e.instanceString&&c.fn(e.instanceString)?e.instanceString():null},c={defined:function(e){return null!=e},string:function(e){return null!=e&&typeof e==a},fn:function(e){return null!=e&&typeof e===s},array:function(e){return Array.isArray?Array.isArray(e):null!=e&&e instanceof Array},plainObject:function(e){return null!=e&&typeof e===o&&!c.array(e)&&e.constructor===Object},object:function(e){return null!=e&&typeof e===o},number:function(e){return null!=e&&"number"==typeof e&&!isNaN(e)},integer:function(e){return c.number(e)&&Math.floor(e)===e},bool:function(e){return null!=e&&typeof e==typeof!0},htmlElement:function(e){return"undefined"===l?void 0:null!=e&&e instanceof HTMLElement},elementOrCollection:function(e){return c.element(e)||c.collection(e)},element:function(e){return"collection"===u(e)&&e._private.single},collection:function(e){return"collection"===u(e)&&!e._private.single},core:function(e){return"core"===u(e)},style:function(e){return"style"===u(e)},stylesheet:function(e){return"stylesheet"===u(e)},event:function(e){return"event"===u(e)},thread:function(e){return"thread"===u(e)},fabric:function(e){return"fabric"===u(e)},emptyString:function(e){return e?c.string(e)&&(""===e||e.match(/^\s+$/))?!0:!1:!0},nonemptyString:function(e){return e&&c.string(e)&&""!==e&&!e.match(/^\s+$/)?!0:!1},domElement:function(e){return"undefined"==typeof HTMLElement?!1:e instanceof HTMLElement},boundingBox:function(e){return c.plainObject(e)&&c.number(e.x1)&&c.number(e.x2)&&c.number(e.y1)&&c.number(e.y2)},promise:function(e){return c.object(e)&&c.fn(e.then)},touch:function(){return n&&("ontouchstart"in n||n.DocumentTouch&&document instanceof DocumentTouch)},gecko:function(){return"undefined"!=typeof InstallTrigger||"MozAppearance"in document.documentElement.style},webkit:function(){return"undefined"!=typeof webkitURL||"WebkitAppearance"in document.documentElement.style},chromium:function(){return"undefined"!=typeof chrome},khtml:function(){return i&&i.vendor.match(/kde/i)},khtmlEtc:function(){return c.khtml()||c.webkit()||c.chromium()},ms:function(){return i&&i.userAgent.match(/msie|trident|edge/i)},windows:function(){return i&&i.appVersion.match(/Win/i)},mac:function(){return i&&i.appVersion.match(/Mac/i)},linux:function(){return i&&i.appVersion.match(/Linux/i)},unix:function(){return i&&i.appVersion.match(/X11/i)}};t.exports=c},{"./window":100}],78:[function(e,t,r){"use strict";var n=e("./is"),i=function(e){var t=e[0]._cyreg=e[0]._cyreg||{};return t},a=function(e,t){e&&(e.fn.cytoscape||(e.fn.cytoscape=function(r){var a=e(this);if("get"===r)return i(a).cy;if(n.fn(r)){var o=r,s=i(a).cy;if(s&&s.isReady())s.trigger("ready",[],o);else{var l=i(a),u=l.readies=l.readies||[];u.push(o)}}else if(n.plainObject(r))return a.each(function(){var n=e.extend({},r,{container:e(this)[0]});t(n)})},e.cytoscape=t,null==e.fn.cy&&null==e.cy&&(e.fn.cy=e.fn.cytoscape,e.cy=e.cytoscape)))};t.exports=a},{"./is":77}],79:[function(e,t,r){"use strict";var n={};n.signum=function(e){return e>0?1:0>e?-1:0},n.distance=function(e,t){return Math.sqrt(n.sqDistance(e,t))},n.sqDistance=function(e,t){var r=t.x-e.x,n=t.y-e.y;return r*r+n*n},n.qbezierAt=function(e,t,r,n){return(1-n)*(1-n)*e+2*(1-n)*n*t+n*n*r},n.qbezierPtAt=function(e,t,r,i){return{x:n.qbezierAt(e.x,t.x,r.x,i),y:n.qbezierAt(e.y,t.y,r.y,i)}},n.makeBoundingBox=function(e){if(null!=e.x1&&null!=e.y1){if(null!=e.x2&&null!=e.y2&&e.x2>=e.x1&&e.y2>=e.y1)return{x1:e.x1,y1:e.y1,x2:e.x2,y2:e.y2,w:e.x2-e.x1,h:e.y2-e.y1};if(null!=e.w&&null!=e.h&&e.w>=0&&e.h>=0)return{x1:e.x1,y1:e.y1,x2:e.x1+e.w,y2:e.y1+e.h,w:e.w,h:e.h}}},n.boundingBoxesIntersect=function(e,t){return e.x1>t.x2?!1:t.x1>e.x2?!1:e.x2<t.x1?!1:t.x2<e.x1?!1:e.y2<t.y1?!1:t.y2<e.y1?!1:e.y1>t.y2?!1:t.y1>e.y2?!1:!0},n.inBoundingBox=function(e,t,r){return e.x1<=t&&t<=e.x2&&e.y1<=r&&r<=e.y2},n.pointInBoundingBox=function(e,t){return this.inBoundingBox(e,t.x,t.y)},n.roundRectangleIntersectLine=function(e,t,r,n,i,a,o){var s,l=this.getRoundRectangleRadius(i,a),u=i/2,c=a/2,d=r-u+l-o,h=n-c-o,p=r+u-l+o,v=h;if(s=this.finiteLinesIntersect(e,t,r,n,d,h,p,v,!1),s.length>0)return s;var f=r+u+o,g=n-c+l-o,y=f,m=n+c-l+o;if(s=this.finiteLinesIntersect(e,t,r,n,f,g,y,m,!1),s.length>0)return s;var b=r-u+l-o,x=n+c+o,w=r+u-l+o,_=x;if(s=this.finiteLinesIntersect(e,t,r,n,b,x,w,_,!1),s.length>0)return s;var E=r-u-o,D=n-c+l-o,S=E,k=n+c-l+o;if(s=this.finiteLinesIntersect(e,t,r,n,E,D,S,k,!1),s.length>0)return s;var T,P=r-u+l,C=n-c+l;if(T=this.intersectLineCircle(e,t,r,n,P,C,l+o),T.length>0&&T[0]<=P&&T[1]<=C)return[T[0],T[1]];var N=r+u-l,M=n-c+l;if(T=this.intersectLineCircle(e,t,r,n,N,M,l+o),T.length>0&&T[0]>=N&&T[1]<=M)return[T[0],T[1]];var B=r+u-l,z=n+c-l;if(T=this.intersectLineCircle(e,t,r,n,B,z,l+o),T.length>0&&T[0]>=B&&T[1]>=z)return[T[0],T[1]];var O=r-u+l,I=n+c-l;return T=this.intersectLineCircle(e,t,r,n,O,I,l+o),T.length>0&&T[0]<=O&&T[1]>=I?[T[0],T[1]]:[]},n.inLineVicinity=function(e,t,r,n,i,a,o){var s=o,l=Math.min(r,i),u=Math.max(r,i),c=Math.min(n,a),d=Math.max(n,a);return e>=l-s&&u+s>=e&&t>=c-s&&d+s>=t},n.inBezierVicinity=function(e,t,r,n,i,a,o,s,l){var u={x1:Math.min(r,o,i)-l,x2:Math.max(r,o,i)+l,y1:Math.min(n,s,a)-l,y2:Math.max(n,s,a)+l};return e<u.x1||e>u.x2||t<u.y1||t>u.y2?!1:!0},n.solveCubic=function(e,t,r,n,i){t/=e,r/=e,n/=e;var a,o,s,l,u,c,d,h;return o=(3*r-t*t)/9,s=-(27*n)+t*(9*r-2*(t*t)),s/=54,a=o*o*o+s*s,i[1]=0,d=t/3,a>0?(u=s+Math.sqrt(a),u=0>u?-Math.pow(-u,1/3):Math.pow(u,1/3),c=s-Math.sqrt(a),c=0>c?-Math.pow(-c,1/3):Math.pow(c,1/3),i[0]=-d+u+c,d+=(u+c)/2,i[4]=i[2]=-d,d=Math.sqrt(3)*(-c+u)/2,i[3]=d,void(i[5]=-d)):(i[5]=i[3]=0,0===a?(h=0>s?-Math.pow(-s,1/3):Math.pow(s,1/3),i[0]=-d+2*h,void(i[4]=i[2]=-(h+d))):(o=-o,l=o*o*o,l=Math.acos(s/Math.sqrt(l)),h=2*Math.sqrt(o),i[0]=-d+h*Math.cos(l/3),i[2]=-d+h*Math.cos((l+2*Math.PI)/3),void(i[4]=-d+h*Math.cos((l+4*Math.PI)/3))))},n.sqDistanceToQuadraticBezier=function(e,t,r,n,i,a,o,s){var l=1*r*r-4*r*i+2*r*o+4*i*i-4*i*o+o*o+n*n-4*n*a+2*n*s+4*a*a-4*a*s+s*s,u=9*r*i-3*r*r-3*r*o-6*i*i+3*i*o+9*n*a-3*n*n-3*n*s-6*a*a+3*a*s,c=3*r*r-6*r*i+r*o-r*e+2*i*i+2*i*e-o*e+3*n*n-6*n*a+n*s-n*t+2*a*a+2*a*t-s*t,d=1*r*i-r*r+r*e-i*e+n*a-n*n+n*t-a*t,h=[];this.solveCubic(l,u,c,d,h);for(var p=1e-7,v=[],f=0;6>f;f+=2)Math.abs(h[f+1])<p&&h[f]>=0&&h[f]<=1&&v.push(h[f]);v.push(1),v.push(0);for(var g,y,m,b,x=-1,w=0;w<v.length;w++)y=Math.pow(1-v[w],2)*r+2*(1-v[w])*v[w]*i+v[w]*v[w]*o,m=Math.pow(1-v[w],2)*n+2*(1-v[w])*v[w]*a+v[w]*v[w]*s,b=Math.pow(y-e,2)+Math.pow(m-t,2),x>=0?x>b&&(x=b,g=v[w]):(x=b,g=v[w]);return x},n.sqDistanceToFiniteLine=function(e,t,r,n,i,a){var o=[e-r,t-n],s=[i-r,a-n],l=s[0]*s[0]+s[1]*s[1],u=o[0]*o[0]+o[1]*o[1],c=o[0]*s[0]+o[1]*s[1],d=c*c/l;return 0>c?u:d>l?(e-i)*(e-i)+(t-a)*(t-a):u-d},n.pointInsidePolygonPoints=function(e,t,r){for(var n,i,a,o,s,l=0,u=0,c=0;c<r.length/2;c++)if(n=r[2*c],i=r[2*c+1],c+1<r.length/2?(a=r[2*(c+1)],o=r[2*(c+1)+1]):(a=r[2*(c+1-r.length/2)],o=r[2*(c+1-r.length/2)+1]),n==e&&a==e);else{if(!(n>=e&&e>=a||e>=n&&a>=e))continue;s=(e-n)/(a-n)*(o-i)+i,s>t&&l++,t>s&&u++}return l%2===0?!1:!0},n.pointInsidePolygon=function(e,t,r,i,a,o,s,l,u){var c,d=new Array(r.length);null!=l[0]?(c=Math.atan(l[1]/l[0]),l[0]<0?c+=Math.PI/2:c=-c-Math.PI/2):c=l;for(var h=Math.cos(-c),p=Math.sin(-c),v=0;v<d.length/2;v++)d[2*v]=o/2*(r[2*v]*h-r[2*v+1]*p),d[2*v+1]=s/2*(r[2*v+1]*h+r[2*v]*p),d[2*v]+=i,d[2*v+1]+=a;var f;if(u>0){var g=this.expandPolygon(d,-u);f=this.joinLines(g)}else f=d;return n.pointInsidePolygonPoints(e,t,f)},n.joinLines=function(e){for(var t,r,n,i,a,o,s,l,u=new Array(e.length/2),c=0;c<e.length/4;c++){t=e[4*c],r=e[4*c+1],n=e[4*c+2],i=e[4*c+3],c<e.length/4-1?(a=e[4*(c+1)],o=e[4*(c+1)+1],s=e[4*(c+1)+2],l=e[4*(c+1)+3]):(a=e[0],o=e[1],s=e[2],l=e[3]);var d=this.finiteLinesIntersect(t,r,n,i,a,o,s,l,!0);u[2*c]=d[0],u[2*c+1]=d[1]}return u},n.expandPolygon=function(e,t){for(var r,n,i,a,o=new Array(2*e.length),s=0;s<e.length/2;s++){r=e[2*s],n=e[2*s+1],s<e.length/2-1?(i=e[2*(s+1)],a=e[2*(s+1)+1]):(i=e[0],a=e[1]);var l=a-n,u=-(i-r),c=Math.sqrt(l*l+u*u),d=l/c,h=u/c;o[4*s]=r+d*t,o[4*s+1]=n+h*t,o[4*s+2]=i+d*t,o[4*s+3]=a+h*t}return o},n.intersectLineEllipse=function(e,t,r,n,i,a){var o=r-e,s=n-t;o/=i,s/=a;var l=Math.sqrt(o*o+s*s),u=l-1;if(0>u)return[];var c=u/l;return[(r-e)*c+e,(n-t)*c+t]},n.intersectLineCircle=function(e,t,r,n,i,a,o){var s=[r-e,n-t],l=[i,a],u=[e-i,t-a],c=s[0]*s[0]+s[1]*s[1],d=2*(u[0]*s[0]+u[1]*s[1]),l=u[0]*u[0]+u[1]*u[1]-o*o,h=d*d-4*c*l;if(0>h)return[];var p=(-d+Math.sqrt(h))/(2*c),v=(-d-Math.sqrt(h))/(2*c),f=Math.min(p,v),g=Math.max(p,v),y=[];if(f>=0&&1>=f&&y.push(f),g>=0&&1>=g&&y.push(g),0===y.length)return[];var m=y[0]*s[0]+e,b=y[0]*s[1]+t;if(y.length>1){if(y[0]==y[1])return[m,b];var x=y[1]*s[0]+e,w=y[1]*s[1]+t;return[m,b,x,w]}return[m,b]},n.findCircleNearPoint=function(e,t,r,n,i){var a=n-e,o=i-t,s=Math.sqrt(a*a+o*o),l=a/s,u=o/s;return[e+l*r,t+u*r]},n.findMaxSqDistanceToOrigin=function(e){for(var t,r=1e-6,n=0;n<e.length/2;n++)t=e[2*n]*e[2*n]+e[2*n+1]*e[2*n+1],t>r&&(r=t);return r},n.finiteLinesIntersect=function(e,t,r,n,i,a,o,s,l){var u=(o-i)*(t-a)-(s-a)*(e-i),c=(r-e)*(t-a)-(n-t)*(e-i),d=(s-a)*(r-e)-(o-i)*(n-t);if(0!==d){var h=u/d,p=c/d;return h>=0&&1>=h&&p>=0&&1>=p?[e+h*(r-e),t+h*(n-t)]:l?[e+h*(r-e),t+h*(n-t)]:[]}return 0===u||0===c?[e,r,o].sort()[1]===o?[o,s]:[e,r,i].sort()[1]===i?[i,a]:[i,o,r].sort()[1]===r?[r,n]:[]:[]},n.polygonIntersectLine=function(e,t,r,i,a,o,s,l){for(var u,c=[],d=new Array(r.length),h=0;h<d.length/2;h++)d[2*h]=r[2*h]*o+i,d[2*h+1]=r[2*h+1]*s+a;var p;if(l>0){var v=n.expandPolygon(d,-l);p=n.joinLines(v)}else p=d;for(var f,g,y,m,h=0;h<p.length/2;h++)f=p[2*h],g=p[2*h+1],h<p.length/2-1?(y=p[2*(h+1)],m=p[2*(h+1)+1]):(y=p[0],m=p[1]),u=this.finiteLinesIntersect(e,t,i,a,f,g,y,m),0!==u.length&&c.push(u[0],u[1]);return c},n.shortenIntersection=function(e,t,r){var n=[e[0]-t[0],e[1]-t[1]],i=Math.sqrt(n[0]*n[0]+n[1]*n[1]),a=(i-r)/i;return 0>a&&(a=1e-5),[t[0]+a*n[0],t[1]+a*n[1]]},n.generateUnitNgonPointsFitToSquare=function(e,t){var r=n.generateUnitNgonPoints(e,t);return r=n.fitPolygonToSquare(r)},n.fitPolygonToSquare=function(e){for(var t,r,n=e.length/2,i=1/0,a=1/0,o=-(1/0),s=-(1/0),l=0;n>l;l++)t=e[2*l],r=e[2*l+1],i=Math.min(i,t),o=Math.max(o,t),a=Math.min(a,r),s=Math.max(s,r);for(var u=2/(o-i),c=2/(s-a),l=0;n>l;l++)t=e[2*l]=e[2*l]*u,r=e[2*l+1]=e[2*l+1]*c,i=Math.min(i,t),o=Math.max(o,t),a=Math.min(a,r),s=Math.max(s,r);if(-1>a)for(var l=0;n>l;l++)r=e[2*l+1]=e[2*l+1]+(-1-a);return e},n.generateUnitNgonPoints=function(e,t){var r=1/e*2*Math.PI,n=e%2===0?Math.PI/2+r/2:Math.PI/2;n+=t;for(var i,a,o,s=new Array(2*e),l=0;e>l;l++)i=l*r+n,a=s[2*l]=Math.cos(i),o=s[2*l+1]=Math.sin(-i);return s},n.getRoundRectangleRadius=function(e,t){return Math.min(e/4,t/4,8)},t.exports=n},{}],80:[function(e,t,r){"use strict";var n=0,i=1,a=2,o=function(e){return this instanceof o?(this.id="Thenable/1.0.7",this.state=n,this.fulfillValue=void 0,this.rejectReason=void 0,this.onFulfilled=[],this.onRejected=[],this.proxy={then:this.then.bind(this)},void("function"==typeof e&&e.call(this,this.fulfill.bind(this),this.reject.bind(this)))):new o(e)};o.prototype={fulfill:function(e){return s(this,i,"fulfillValue",e)},reject:function(e){return s(this,a,"rejectReason",e)},then:function(e,t){var r=this,n=new o;return r.onFulfilled.push(c(e,n,"fulfill")),r.onRejected.push(c(t,n,"reject")),l(r),n.proxy}};var s=function(e,t,r,i){return e.state===n&&(e.state=t,e[r]=i,l(e)),e},l=function(e){e.state===i?u(e,"onFulfilled",e.fulfillValue):e.state===a&&u(e,"onRejected",e.rejectReason)},u=function(e,t,r){if(0!==e[t].length){var n=e[t];e[t]=[];var i=function(){for(var e=0;e<n.length;e++)n[e](r)};"function"==typeof setImmediate?setImmediate(i):setTimeout(i,0)}},c=function(e,t,r){return function(n){if("function"!=typeof e)t[r].call(t,n);else{var i;try{i=e(n)}catch(a){return void t.reject(a)}d(t,i)}}},d=function(e,t){if(e===t||e.proxy===t)return void e.reject(new TypeError("cannot resolve promise with itself"));var r;if("object"==typeof t&&null!==t||"function"==typeof t)try{r=t.then}catch(n){return void e.reject(n)}if("function"!=typeof r)e.fulfill(t);else{var i=!1;try{r.call(t,function(r){i||(i=!0,r===t?e.reject(new TypeError("circular thenable chain")):d(e,r))},function(t){i||(i=!0,e.reject(t))})}catch(n){i||e.reject(n)}}},h="undefined"==typeof h?o:h;h.all=h.all||function(e){return new h(function(t,r){for(var n=new Array(e.length),i=0,a=function(r,a){n[r]=a,i++,i===e.length&&t(n)},o=0;o<e.length;o++)!function(t){var n=e[t],i=null!=n.then;if(i)n.then(function(e){a(t,e)},function(e){r(e)});else{var o=n;a(t,o)}}(o)})},t.exports=h},{}],81:[function(e,t,r){"use strict";var n=e("./is"),i=e("./util"),a=function(e,t){if(!(this instanceof a))return new a(e,t);void 0===t&&void 0!==e&&(t=e,e=void 0);var r=this;if(r._private={selectorText:null,invalid:!0},!t||n.string(t)&&t.match(/^\s*$/))null==e?r.length=0:(r[0]=l(),r[0].group=e,r.length=1);else if(n.elementOrCollection(t)){var o=t.collection();r[0]=l(),r[0].collection=o,r.length=1}else if(n.fn(t))r[0]=l(),r[0].filter=t,r.length=1;else{if(!n.string(t))return void i.error("A selector must be created from a string; found "+t);var s=null,l=function(){return{classes:[],colonSelectors:[],data:[],group:null,ids:[],meta:[],collection:null,filter:null,parent:null,ancestor:null,subject:null,child:null,descendant:null}},u={metaChar:"[\\!\\\"\\#\\$\\%\\&\\'\\(\\)\\*\\+\\,\\.\\/\\:\\;\\<\\=\\>\\?\\@\\[\\]\\^\\`\\{\\|\\}\\~]",comparatorOp:"=|\\!=|>|>=|<|<=|\\$=|\\^=|\\*=",boolOp:"\\?|\\!|\\^",string:'"(?:\\\\"|[^"])+"|'+"'(?:\\\\'|[^'])+'",number:i.regex.number,meta:"degree|indegree|outdegree",separator:"\\s*,\\s*",descendant:"\\s+",child:"\\s+>\\s+",subject:"\\$"};u.variable="(?:[\\w-]|(?:\\\\"+u.metaChar+"))+",u.value=u.string+"|"+u.number,u.className=u.variable,u.id=u.variable;for(var c=function(e){return e.replace(new RegExp("\\\\("+u.metaChar+")","g"),function(e,t,r,n){return t})},d=u.comparatorOp.split("|"),h=0;h<d.length;h++){var p=d[h];u.comparatorOp+="|@"+p}for(var d=u.comparatorOp.split("|"),h=0;h<d.length;h++){var p=d[h];p.indexOf("!")>=0||"="!==p&&(u.comparatorOp+="|\\!"+p)}var v=[{name:"group",query:!0,regex:"(node|edge|\\*)",populate:function(e){this.group="*"==e?e:e+"s"}},{name:"state",query:!0,regex:"(:selected|:unselected|:locked|:unlocked|:visible|:hidden|:transparent|:grabbed|:free|:removed|:inside|:grabbable|:ungrabbable|:animated|:unanimated|:selectable|:unselectable|:orphan|:nonorphan|:parent|:child|:loop|:simple|:active|:inactive|:touch|:backgrounding|:nonbackgrounding)",populate:function(e){this.colonSelectors.push(e)}},{name:"id",query:!0,regex:"\\#("+u.id+")",populate:function(e){this.ids.push(c(e))}},{name:"className",query:!0,regex:"\\.("+u.className+")",populate:function(e){this.classes.push(c(e))}},{name:"dataExists",query:!0,regex:"\\[\\s*("+u.variable+")\\s*\\]",populate:function(e){this.data.push({field:c(e)})}},{name:"dataCompare",query:!0,regex:"\\[\\s*("+u.variable+")\\s*("+u.comparatorOp+")\\s*("+u.value+")\\s*\\]",populate:function(e,t,r){var n=null!=new RegExp("^"+u.string+"$").exec(r);r=n?r.substring(1,r.length-1):parseFloat(r),this.data.push({field:c(e),operator:t,value:r})}},{name:"dataBool",query:!0,regex:"\\[\\s*("+u.boolOp+")\\s*("+u.variable+")\\s*\\]",populate:function(e,t){this.data.push({field:c(t),operator:e})}},{name:"metaCompare",query:!0,regex:"\\[\\[\\s*("+u.meta+")\\s*("+u.comparatorOp+")\\s*("+u.number+")\\s*\\]\\]",populate:function(e,t,r){this.meta.push({field:c(e),operator:t,value:parseFloat(r)})}},{name:"nextQuery",separator:!0,regex:u.separator,populate:function(){r[++h]=l(),s=null}},{name:"child",separator:!0,regex:u.child,populate:function(){var e=l();e.parent=this,e.subject=s,r[h]=e}},{name:"descendant",separator:!0,regex:u.descendant,populate:function(){var e=l();e.ancestor=this,e.subject=s,r[h]=e}},{name:"subject",modifier:!0,regex:u.subject,populate:function(){return null!=s&&this.subject!=this?(i.error("Redefinition of subject in selector `"+t+"`"),!1):(s=this,void(this.subject=this))}}];r._private.selectorText=t;var f=t,h=0,g=function(e){for(var t,r,i,a=0;a<v.length;a++){var o=v[a],s=o.name;if(!n.fn(e)||e(s,o)){var l=f.match(new RegExp("^"+o.regex));if(null!=l){r=l,t=o,i=s;var u=l[0];f=f.substring(u.length);break}}}return{expr:t,match:r,name:i}},y=function(){var e=f.match(/^\s+/);if(e){var t=e[0];f=f.substring(t.length)}};for(r[0]=l(),y();;){var m=g();if(null==m.expr)return void i.error("The selector `"+t+"`is invalid");for(var b=[],x=1;x<m.match.length;x++)b.push(m.match[x]);var w=m.expr.populate.apply(r[h],b);if(w===!1)return;if(f.match(/^\s*$/))break}r.length=h+1;for(var x=0;x<r.length;x++){var _=r[x];if(null!=_.subject){for(;_.subject!=_;)if(null!=_.parent){var E=_.parent,D=_;D.parent=null,E.child=D,_=E}else{if(null==_.ancestor){i.error("When adjusting references for the selector `"+_+"`, neither parent nor ancestor was found");break}var S=_.ancestor,k=_;k.ancestor=null,S.descendant=k,_=S}r[x]=_.subject}}if(null!=e)for(var x=0;x<r.length;x++){if(null!=r[x].group&&r[x].group!=e)return void i.error("Group `"+r[x].group+"` conflicts with implicit group `"+e+"` in selector `"+t+"`");r[x].group=e}}r._private.invalid=!1},o=a.prototype;o.size=function(){return this.length},o.eq=function(e){return this[e]};var s=function(e,t){if(null!=e.group&&"*"!=e.group&&e.group!=t._private.group)return!1;for(var r=t.cy(),i=!0,a=0;a<e.colonSelectors.length;a++){var o=e.colonSelectors[a];switch(o){case":selected":i=t.selected();break;case":unselected":i=!t.selected();break;case":selectable":i=t.selectable();break;case":unselectable":i=!t.selectable();break;case":locked":i=t.locked();break;case":unlocked":i=!t.locked();break;case":visible":i=t.visible();break;case":hidden":i=!t.visible();break;case":transparent":i=t.transparent();break;case":grabbed":i=t.grabbed();break;case":free":i=!t.grabbed();break;case":removed":i=t.removed();break;case":inside":i=!t.removed();break;case":grabbable":i=t.grabbable();break;case":ungrabbable":i=!t.grabbable();break;case":animated":i=t.animated();break;case":unanimated":i=!t.animated();break;case":parent":i=t.isNode()&&t.children().nonempty();break;case":child":case":nonorphan":i=t.isNode()&&t.parent().nonempty();break;case":orphan":i=t.isNode()&&t.parent().empty();break;case":loop":i=t.isEdge()&&t.data("source")===t.data("target");break;case":simple":i=t.isEdge()&&t.data("source")!==t.data("target");break;case":active":i=t.active();break;case":inactive":i=!t.active();break;case":touch":i=n.touch();break;case":backgrounding":i=t.backgrounding();break;case":nonbackgrounding":i=!t.backgrounding()}if(!i)break}if(!i)return!1;for(var l=!0,a=0;a<e.ids.length;a++){var u=e.ids[a],c=t._private.data.id;if(l=l&&u==c,!l)break}if(!l)return!1;for(var d=!0,a=0;a<e.classes.length;a++){var h=e.classes[a];if(d=d&&t.hasClass(h),!d)break}if(!d)return!1;var p=function(t){for(var r=!0,i=0;i<e[t.name].length;i++){var a,o=e[t.name][i],s=o.operator,l=o.value,u=o.field;if(null!=s&&null!=l){var c=t.fieldValue(u),d=n.string(c)||n.number(c)?""+c:"",h=""+l,p=!1;s.indexOf("@")>=0&&(d=d.toLowerCase(),h=h.toLowerCase(),s=s.replace("@",""),p=!0);var v=!1,f=!1;switch(s.indexOf("!")>=0&&(s=s.replace("!",""),v=!0),p&&(l=h.toLowerCase(),c=d.toLowerCase()),s){case"*=":a=d.search(h)>=0;break;case"$=":a=null!=new RegExp(h+"$").exec(d);break;case"^=":a=null!=new RegExp("^"+h).exec(d);break;case"=":a=c===l;break;case"!=":a=c!==l;break;case">":a=v?l>=c:c>l,f=!0;break;case">=":a=v?l>c:c>=l,f=!0;break;case"<":a=v?c>=l:l>c,f=!0;break;case"<=":a=v?c>l:l>=c,f=!0;break;default:a=!1}}else if(null!=s)switch(s){case"?":a=t.fieldTruthy(u);break;case"!":a=!t.fieldTruthy(u);break;case"^":a=t.fieldUndefined(u)}else a=!t.fieldUndefined(u);if(v&&!f&&(a=!a,f=!0),!a){r=!1;break}}return r},v=p({name:"data",fieldValue:function(e){return t._private.data[e]},fieldRef:function(e){return"element._private.data."+e},fieldUndefined:function(e){return void 0===t._private.data[e]},fieldTruthy:function(e){return t._private.data[e]?!0:!1}});if(!v)return!1;var f=p({name:"meta",fieldValue:function(e){return t[e]()},fieldRef:function(e){return"element."+e+"()"},fieldUndefined:function(e){return null==t[e]()},fieldTruthy:function(e){return t[e]()?!0:!1}});if(!f)return!1;if(null!=e.collection){var g=null!=e.collection._private.ids[t.id()];if(!g)return!1}if(null!=e.filter&&0===t.collection().filter(e.filter).size())return!1;var y=function(e,t){if(null!=e){var n=!1;if(!r.hasCompoundNodes())return!1;t=t();for(var i=0;i<t.length;i++)if(s(e,t[i])){n=!0;break}return n}return!0};return y(e.parent,function(){return t.parent()})&&y(e.ancestor,function(){return t.parents()})&&y(e.child,function(){return t.children()})&&y(e.descendant,function(){return t.descendants()})?!0:!1};o.filter=function(e){var t=this,r=e.cy();if(t._private.invalid)return r.collection();var n=function(e,r){for(var n=0;n<t.length;n++){var i=t[n];if(s(i,r))return!0}return!1};null==t._private.selectorText&&(n=function(){return!0});var i=e.filter(n);return i},o.matches=function(e){var t=this;if(t._private.invalid)return!1;for(var r=0;r<t.length;r++){var n=t[r];if(s(n,e))return!0}return!1},o.toString=o.selector=function(){for(var e="",t=function(e,t){return n.string(e)?t?'"'+e+'"':e:""},r=function(e){var n="";e.subject===e&&(n+="$");var a=t(e.group);n+=a.substring(0,a.length-1);for(var o=0;o<e.data.length;o++){var s=e.data[o];n+=s.value?"["+s.field+t(s.operator)+t(s.value,!0)+"]":"["+t(s.operator)+s.field+"]"}for(var o=0;o<e.meta.length;o++){var l=e.meta[o];n+="[["+l.field+t(l.operator)+t(l.value,!0)+"]]"}for(var o=0;o<e.colonSelectors.length;o++){var u=e.colonSelectors[i];n+=u}for(var o=0;o<e.ids.length;o++){var u="#"+e.ids[i];n+=u}for(var o=0;o<e.classes.length;o++){var u="."+e.classes[o];n+=u}return null!=e.parent&&(n=r(e.parent)+" > "+n),null!=e.ancestor&&(n=r(e.ancestor)+" "+n),null!=e.child&&(n+=" > "+r(e.child)),null!=e.descendant&&(n+=" "+r(e.descendant)),n},i=0;i<this.length;i++){var a=this[i];e+=r(a),this.length>1&&i<this.length-1&&(e+=", ")}return e},t.exports=a},{"./is":77,"./util":94}],82:[function(e,t,r){"use strict";var n=e("../util"),i=e("../is"),a={};a.apply=function(e){var t=this;t._private.newStyle&&(this._private.contextStyles={},this._private.propDiffs={});for(var r=0;r<e.length;r++){var n=e[r],i=t.getContextMeta(n),a=t.getContextStyle(i),o=t.applyContextStyle(i,a,n);
+t.updateTransitions(n,o.diffProps),t.updateStyleHints(n)}t._private.newStyle=!1},a.getPropertiesDiff=function(e,t){var r=this,n=r._private.propDiffs=r._private.propDiffs||{},i=e+"-"+t,a=n[i];if(a)return a;for(var o=[],s={},l=0;l<r.length;l++){var u=r[l],c="t"===e[l],d="t"===t[l],h=c!==d,p=u.mappedProperties.length>0;if(h||p){var v;h&&p?v=u.properties:h?v=u.properties:p&&(v=u.mappedProperties);for(var f=0;f<v.length;f++){for(var g=v[f],y=g.name,m=!1,b=l+1;b<r.length;b++){var x=r[b],w="t"===t[b];if(w&&(m=null!=x.properties[g.name]))break}s[y]||m||(s[y]=!0,o.push(y))}}}return n[i]=o,o},a.getContextMeta=function(e){var t,r=this,n="",i=e._private.styleCxtKey||"";r._private.newStyle&&(i="");for(var a=0;a<r.length;a++){var o=r[a],s=o.selector&&o.selector.matches(e);n+=s?"t":"f"}return t=r.getPropertiesDiff(i,n),e._private.styleCxtKey=n,{key:n,diffPropNames:t}},a.getContextStyle=function(e){var t=e.key,r=this,n=this._private.contextStyles=this._private.contextStyles||{};if(n[t])return n[t];for(var i={_private:{key:t}},a=0;a<r.length;a++){var o=r[a],s="t"===t[a];if(s)for(var l=0;l<o.properties.length;l++){var u=o.properties[l],c=i[u.name]=u;c.context=o}}return n[t]=i,i},a.applyContextStyle=function(e,t,r){for(var n=this,i=e.diffPropNames,a={},o=0;o<i.length;o++){var s=i[o],l=t[s],u=r._private.style[s];if(l&&u!==l){var c=a[s]={prev:u};n.applyParsedProperty(r,l),c.next=r._private.style[s],c.next&&c.next.bypass&&(c.next=c.next.bypassed)}}return{diffProps:a}},a.updateStyleHints=function(e){var t=e._private,r=this,n=t.style;if(!e.removed()){var i=!1;if("nodes"===t.group&&r._private.hasPie)for(var a=1;a<=r.pieBackgroundN;a++){var o=t.style["pie-"+a+"-background-size"].value;if(o>0){i=!0;break}}t.hasPie=i;var s=n["text-transform"].strValue,l=n.label.strValue,u=n["font-style"].strValue,o=n["font-size"].pfValue+"px",c=n["font-family"].strValue,d=n["font-weight"].strValue,h=n["text-valign"].strValue,p=n["text-valign"].strValue,v=n["text-outline-width"].pfValue,f=n["text-wrap"].strValue,g=n["text-max-width"].pfValue;t.labelKey=u+"$"+o+"$"+c+"$"+d+"$"+l+"$"+s+"$"+h+"$"+p+"$"+v+"$"+f+"$"+g,t.fontKey=u+"$"+d+"$"+o+"$"+c;var y=n.width.pfValue,m=n.height.pfValue,b=n["border-width"].pfValue;if(t.boundingBoxKey=y+"$"+m+"$"+b,"edges"===e._private.group){var x=n["control-point-step-size"].pfValue,w=n["control-point-distances"]?n["control-point-distances"].pfValue.join("_"):void 0,_=n["control-point-weights"].value.join("_"),E=n["curve-style"].strValue;t.boundingBoxKey+="$"+x+"$"+w+"$"+_+"$"+E}t.styleKey=Date.now()}},a.applyParsedProperty=function(e,t){var r,a,o=this,s=t,l=e._private.style,u=o.types,c=o.properties[s.name].type,d=s.bypass,h=l[s.name],p=h&&h.bypass,v=e._private;if(("height"===t.name||"width"===t.name)&&e.isNode()){if("auto"===t.value&&!e.isParent())return!1;"auto"!==t.value&&e.isParent()&&(s=t=this.parse(t.name,"auto",d))}if(d&&s.deleteBypass){var f=l[s.name];return f?f.bypass&&f.bypassed?(l[s.name]=f.bypassed,!0):!1:!0}var g=function(){n.error("Do not assign mappings to elements without corresponding data (e.g. ele `"+e.id()+"` for property `"+s.name+"` with data field `"+s.field+"`); try a `["+s.field+"]` selector to limit scope to elements with `"+s.field+"` defined")};switch(s.mapped){case u.mapData:case u.mapLayoutData:case u.mapScratch:var r,y=s.mapped===u.mapLayoutData,m=s.mapped===u.mapScratch,b=s.field.split(".");r=m||y?v.scratch:v.data;for(var x=0;x<b.length&&r;x++){var w=b[x];r=r[w]}var _;if(_=i.number(r)?(r-s.fieldMin)/(s.fieldMax-s.fieldMin):0,0>_?_=0:_>1&&(_=1),c.color){var E=s.valueMin[0],D=s.valueMax[0],S=s.valueMin[1],k=s.valueMax[1],T=s.valueMin[2],P=s.valueMax[2],C=null==s.valueMin[3]?1:s.valueMin[3],N=null==s.valueMax[3]?1:s.valueMax[3],M=[Math.round(E+(D-E)*_),Math.round(S+(k-S)*_),Math.round(T+(P-T)*_),Math.round(C+(N-C)*_)];a={bypass:s.bypass,name:s.name,value:M,strValue:"rgb("+M[0]+", "+M[1]+", "+M[2]+")"}}else{if(!c.number)return!1;var B=s.valueMin+(s.valueMax-s.valueMin)*_;a=this.parse(s.name,B,s.bypass,!0)}a||(a=this.parse(s.name,h.strValue,s.bypass,!0)),a||g(),a.mapping=s,s=a;break;case u.data:case u.layoutData:case u.scratch:var r,y=s.mapped===u.layoutData,m=s.mapped===u.scratch,b=s.field.split(".");if(r=m||y?v.scratch:v.data)for(var x=0;x<b.length;x++){var w=b[x];r=r[w]}if(a=this.parse(s.name,r,s.bypass,!0),!a){var z=h?h.strValue:"";a=this.parse(s.name,z,s.bypass,!0)}a||g(),a.mapping=s,s=a;break;case u.fn:var O=s.value,I=O(e);a=this.parse(s.name,I,s.bypass,!0),a.mapping=s,s=a;break;case void 0:break;default:return!1}return d?(p?s.bypassed=h.bypassed:s.bypassed=h,l[s.name]=s):p?h.bypassed=s:l[s.name]=s,!0},a.update=function(){var e=this._private.cy,t=e.elements();t.updateStyle()},a.updateMappers=function(e){for(var t=this,r=0;r<e.length;r++){for(var n=e[r],i=n._private.style,a=0;a<t.properties.length;a++){var o=t.properties[a],s=i[o.name];if(s&&s.mapping){var l=s.mapping;this.applyParsedProperty(n,l)}}this.updateStyleHints(n)}},a.updateTransitions=function(e,t,r){var n=this,a=e._private,o=a.style,s=o["transition-property"].value,l=o["transition-duration"].pfValue,u=o["transition-delay"].pfValue,c={};if(s.length>0&&l>0){for(var d=!1,h=0;h<s.length;h++){var p=s[h],v=o[p],f=t[p];if(f){var g,y=f.prev,m=y,b=null!=f.next?f.next:v,x=!1,w=1e-6;m&&(i.number(m.pfValue)&&i.number(b.pfValue)?(x=b.pfValue-m.pfValue,g=m.pfValue+w*x):i.number(m.value)&&i.number(b.value)?(x=b.value-m.value,g=m.value+w*x):i.array(m.value)&&i.array(b.value)&&(x=m.value[0]!==b.value[0]||m.value[1]!==b.value[1]||m.value[2]!==b.value[2],g=m.strValue),x&&(c[p]=b.strValue,this.applyBypass(e,p,g),d=!0))}}if(!d)return;a.transitioning=!0,e.stop(),u>0&&e.delay(u),e.animate({css:c},{duration:l,easing:o["transition-timing-function"].value,queue:!1,complete:function(){r||n.removeBypasses(e,s),a.transitioning=!1}})}else a.transitioning&&(e.stop(),this.removeBypasses(e,s),a.transitioning=!1)},t.exports=a},{"../is":77,"../util":94}],83:[function(e,t,r){"use strict";var n=e("../is"),i=e("../util"),a={};a.applyBypass=function(e,t,r,a){var o=this,s=[],l=!0;if("*"===t||"**"===t){if(void 0!==r)for(var u=0;u<o.properties.length;u++){var c=o.properties[u],t=c.name,d=this.parse(t,r,!0);d&&s.push(d)}}else if(n.string(t)){var d=this.parse(t,r,!0);d&&s.push(d)}else{if(!n.plainObject(t))return!1;var h=t;a=r;for(var u=0;u<o.properties.length;u++){var c=o.properties[u],t=c.name,r=h[t];if(void 0===r&&(r=h[i.dash2camel(t)]),void 0!==r){var d=this.parse(t,r,!0);d&&s.push(d)}}}if(0===s.length)return!1;for(var p=!1,u=0;u<e.length;u++){for(var v,f=e[u],g=f._private.style,y={},m=0;m<s.length;m++){var c=s[m];if(a){var b=g[c.name];v=y[c.name]={prev:b}}p=this.applyParsedProperty(f,c)||p,a&&(v.next=g[c.name])}p&&this.updateStyleHints(f),a&&this.updateTransitions(f,y,l)}return p},a.overrideBypass=function(e,t,r){t=i.camel2dash(t);for(var n=0;n<e.length;n++){var a=e[n],o=a._private.style[t],s=this.properties[t].type,l=s.color,u=s.mutiple;o.bypass?(o.value=r,null!=o.pfValue&&(o.pfValue=r),l?o.strValue="rgb("+r.join(",")+")":u?o.strValue=r.join(" "):o.strValue=""+r):this.applyBypass(a,t,r)}},a.removeAllBypasses=function(e,t){return this.removeBypasses(e,this.propertyNames,t)},a.removeBypasses=function(e,t,r){for(var n=!0,i=0;i<e.length;i++){for(var a=e[i],o={},s=a._private.style,l=0;l<t.length;l++){var u=t[l],c=this.properties[u],d="",h=this.parse(u,d,!0),p=s[c.name],v=o[c.name]={prev:p};this.applyParsedProperty(a,h),v.next=s[c.name]}this.updateStyleHints(a),r&&this.updateTransitions(a,o,n)}},t.exports=a},{"../is":77,"../util":94}],84:[function(e,t,r){"use strict";var n=e("../window"),i={};i.getEmSizeInPixels=function(){var e=this.containerCss("font-size");return null!=e?parseFloat(e):1},i.containerCss=function(e){var t=this._private.cy,r=t.container();return n&&r&&n.getComputedStyle?n.getComputedStyle(r).getPropertyValue(e):void 0},t.exports=i},{"../window":100}],85:[function(e,t,r){"use strict";var n=e("../util"),i=e("../is"),a={};a.getRenderedStyle=function(e){return this.getRawStyle(e,!0)},a.getRawStyle=function(e,t){var r=this,e=e[0];if(e){for(var i={},a=0;a<r.properties.length;a++){var o=r.properties[a],s=r.getStylePropertyValue(e,o.name,t);s&&(i[o.name]=s,i[n.dash2camel(o.name)]=s)}return i}},a.getStylePropertyValue=function(e,t,r){var n=this,e=e[0];if(e){var i=e._private.style,a=n.properties[t],o=a.type,s=i[a.name],l=e.cy().zoom();if(s){var u=s.units?o.implicitUnits||"px":null,c=u?[].concat(s.pfValue).map(function(e){return e*(r?l:1)+u}).join(" "):s.strValue;return c}}},a.getValueStyle=function(e){var t,r=this,a={},o=i.element(e);if(t=o?e._private.style:e)for(var s=0;s<r.properties.length;s++){var l=r.properties[s],u=t[l.name]||t[n.dash2camel(l.name)];void 0!==u&&(u=i.plainObject(u)?this.parse(l.name,u.strValue):this.parse(l.name,u)),u&&(a[l.name]=u,a[n.dash2camel(l.name)]=u)}return a},a.getPropsList=function(e){var t=this,r=[],i=e,a=t.properties;if(i)for(var o in i){var s=i[o],l=a[o]||a[n.camel2dash(o)],u=this.parse(l.name,s);r.push(u)}return r},t.exports=a},{"../is":77,"../util":94}],86:[function(e,t,r){"use strict";var n=e("../is"),i=e("../util"),a=e("../selector"),o=function(e){return this instanceof o?n.core(e)?(this._private={cy:e,coreStyle:{},newStyle:!0},this.length=0,void this.addDefaultStylesheet()):void i.error("A style must have a core reference"):new o(e)},s=o.prototype;s.instanceString=function(){return"style"},s.clear=function(){for(var e=0;e<this.length;e++)this[e]=void 0;return this.length=0,this._private.newStyle=!0,this},s.resetToDefault=function(){return this.clear(),this.addDefaultStylesheet(),this},s.core=function(){return this._private.coreStyle},s.selector=function(e){var t="core"===e?null:new a(e),r=this.length++;return this[r]={selector:t,properties:[],mappedProperties:[],index:r},this},s.css=function(){var e=this,t=arguments;switch(t.length){case 1:for(var r=t[0],n=0;n<e.properties.length;n++){var a=e.properties[n],o=r[a.name];void 0===o&&(o=r[i.dash2camel(a.name)]),void 0!==o&&this.cssRule(a.name,o)}break;case 2:this.cssRule(t[0],t[1])}return this},s.style=s.css,s.cssRule=function(e,t){var r=this.parse(e,t);if(r){var n=this.length-1;this[n].properties.push(r),this[n].properties[r.name]=r,r.name.match(/pie-(\d+)-background-size/)&&r.value&&(this._private.hasPie=!0),r.mapped&&this[n].mappedProperties.push(r);var i=!this[n].selector;i&&(this._private.coreStyle[r.name]=r)}return this},o.fromJson=function(e,t){var r=new o(e);return r.fromJson(t),r},o.fromString=function(e,t){return new o(e).fromString(t)},[e("./apply"),e("./bypass"),e("./container"),e("./get-for-ele"),e("./json"),e("./string-sheet"),e("./properties"),e("./parse")].forEach(function(e){i.extend(s,e)}),o.types=s.types,o.properties=s.properties,t.exports=o},{"../is":77,"../selector":81,"../util":94,"./apply":82,"./bypass":83,"./container":84,"./get-for-ele":85,"./json":87,"./parse":88,"./properties":89,"./string-sheet":90}],87:[function(e,t,r){"use strict";var n={};n.applyFromJson=function(e){for(var t=this,r=0;r<e.length;r++){var n=e[r],i=n.selector,a=n.style||n.css;t.selector(i);for(var o in a){var s=a[o];t.css(o,s)}}return t},n.fromJson=function(e){var t=this;return t.resetToDefault(),t.applyFromJson(e),t},n.json=function(){for(var e=[],t=this.defaultLength;t<this.length;t++){for(var r=this[t],n=r.selector,i=r.properties,a={},o=0;o<i.length;o++){var s=i[o];a[s.name]=s.strValue}e.push({selector:n?n.toString():"core",style:a})}return e},t.exports=n},{}],88:[function(e,t,r){"use strict";var n=e("../util"),i=e("../is"),a={};a.parse=function(e,t,r,i){var a,s=[e,t,r,i].join("$"),l=this.propCache=this.propCache||{},u=o.bind(this);return(a=l[s])||(a=l[s]=u(e,t,r,i)),a=n.copy(a),a&&(a.value=n.copy(a.value)),a};var o=function(e,t,r,a){var o=this;e=n.camel2dash(e);var s=o.properties[e],l=t,u=o.types;if(!s)return null;if(void 0===t||null===t)return null;s.alias&&(s=s.pointsTo,e=s.name);var c=i.string(t);c&&(t=t.trim());var d=s.type;if(!d)return null;if(r&&(""===t||null===t))return{name:e,value:t,bypass:!0,deleteBypass:!0};if(i.fn(t))return{name:e,value:t,strValue:"fn",mapped:u.fn,bypass:r};var h,p,v,f,g,y;if(!c||a);else{if((h=new RegExp(u.data.regex).exec(t))||(v=new RegExp(u.layoutData.regex).exec(t))||(g=new RegExp(u.scratch.regex).exec(t))){if(r)return!1;var m;return m=h?u.data:v?u.layoutData:u.scratch,h=h||v||g,{name:e,value:h,strValue:""+t,mapped:m,field:h[1],bypass:r}}if((p=new RegExp(u.mapData.regex).exec(t))||(f=new RegExp(u.mapLayoutData.regex).exec(t))||(y=new RegExp(u.mapScratch.regex).exec(t))){if(r)return!1;if(d.multiple)return!1;var m;if(m=p?u.mapData:f?u.mapLayoutData:u.mapScratch,p=p||f||y,!d.color&&!d.number)return!1;var b=this.parse(e,p[4]);if(!b||b.mapped)return!1;var x=this.parse(e,p[5]);if(!x||x.mapped)return!1;if(b.value===x.value)return!1;if(d.color){var w=b.value,_=x.value,E=!(w[0]!==_[0]||w[1]!==_[1]||w[2]!==_[2]||w[3]!==_[3]&&(null!=w[3]&&1!==w[3]||null!=_[3]&&1!==_[3]));if(E)return!1}return{name:e,value:p,strValue:""+t,mapped:m,field:p[1],fieldMin:parseFloat(p[2]),fieldMax:parseFloat(p[3]),valueMin:b.value,valueMax:x.value,bypass:r}}}if(d.multiple&&!a){var D;if(D=c?t.split(/\s+/):i.array(t)?t:[t],d.evenMultiple&&D.length%2!==0)return null;var S=D.map(function(t){var n=o.parse(e,t,r,!0);return null!=n.pfValue?n.pfValue:n.value});return{name:e,value:S,pfValue:S,strValue:S.join(" "),bypass:r,units:d.number&&!d.unitless?d.implicitUnits||"px":void 0}}var k=function(){for(var n=0;n<d.enums.length;n++){var i=d.enums[n];if(i===t)return{name:e,value:t,strValue:""+t,bypass:r}}return null};if(d.number){var T,P="px";if(d.units&&(T=d.units),d.implicitUnits&&(P=d.implicitUnits),!d.unitless)if(c){var C="px|em"+(d.allowPercent?"|\\%":"");T&&(C=T);var N=t.match("^("+n.regex.number+")("+C+")?$");N&&(t=N[1],T=N[2]||P)}else(!T||d.implicitUnits)&&(T=P);if(t=parseFloat(t),isNaN(t)&&void 0===d.enums)return null;if(isNaN(t)&&void 0!==d.enums)return t=l,k();if(d.integer&&!i.integer(t))return null;if(void 0!==d.min&&t<d.min||void 0!==d.max&&t>d.max)return null;var M={name:e,value:t,strValue:""+t+(T?T:""),units:T,bypass:r};return d.unitless||"px"!==T&&"em"!==T?M.pfValue=t:M.pfValue="px"!==T&&T?this.getEmSizeInPixels()*t:t,("ms"===T||"s"===T)&&(M.pfValue="ms"===T?t:1e3*t),("deg"===T||"rad"===T)&&(M.pfValue="rad"===T?t:t*Math.PI/180),M}if(d.propList){var B=[],z=""+t;if("none"===z);else{for(var O=z.split(","),I=0;I<O.length;I++){var L=O[I].trim();o.properties[L]&&B.push(L)}if(0===B.length)return null}return{name:e,value:B,strValue:0===B.length?"none":B.join(", "),bypass:r}}if(d.color){var A=n.color2tuple(t);return A?{name:e,value:A,strValue:""+t,bypass:r,roundValue:!0}:null}if(d.regex||d.regexes){if(d.enums){var R=k();if(R)return R}for(var V=d.regexes?d.regexes:[d.regex],I=0;I<V.length;I++){var F=new RegExp(V[I]),j=F.exec(t);if(j)return{name:e,value:j,strValue:""+t,bypass:r}}return null}return d.string?{name:e,value:t,strValue:""+t,bypass:r}:d.enums?k():null};t.exports=a},{"../is":77,"../util":94}],89:[function(e,t,r){"use strict";var n=e("../util"),i={};!function(){var e=n.regex.number,t=n.regex.rgbaNoBackRefs,r=n.regex.hslaNoBackRefs,a=n.regex.hex3,o=n.regex.hex6,s=function(e){return"^"+e+"\\s*\\(\\s*([\\w\\.]+)\\s*\\)$"},l=function(n){var i=e+"|\\w+|"+t+"|"+r+"|"+a+"|"+o;return"^"+n+"\\s*\\(([\\w\\.]+)\\s*\\,\\s*("+e+")\\s*\\,\\s*("+e+")\\s*,\\s*("+i+")\\s*\\,\\s*("+i+")\\)$"};i.types={time:{number:!0,min:0,units:"s|ms",implicitUnits:"ms"},percent:{number:!0,min:0,max:100,units:"%",implicitUnits:"%"},zeroOneNumber:{number:!0,min:0,max:1,unitless:!0},nOneOneNumber:{number:!0,min:-1,max:1,unitless:!0},nonNegativeInt:{number:!0,min:0,integer:!0,unitless:!0},position:{enums:["parent","origin"]},nodeSize:{number:!0,min:0,enums:["auto","label"]},number:{number:!0,unitless:!0},numbers:{number:!0,unitless:!0,multiple:!0},size:{number:!0,min:0},bidirectionalSize:{number:!0},bidirectionalSizes:{number:!0,multiple:!0},bgSize:{number:!0,min:0,allowPercent:!0},bgWH:{number:!0,min:0,allowPercent:!0,enums:["auto"]},bgPos:{number:!0,allowPercent:!0},bgRepeat:{enums:["repeat","repeat-x","repeat-y","no-repeat"]},bgFit:{enums:["none","contain","cover"]},bgClip:{enums:["none","node"]},color:{color:!0},bool:{enums:["yes","no"]},lineStyle:{enums:["solid","dotted","dashed"]},borderStyle:{enums:["solid","dotted","dashed","double"]},curveStyle:{enums:["bezier","unbundled-bezier","haystack","segments"]},fontFamily:{regex:'^([\\w- \\"]+(?:\\s*,\\s*[\\w- \\"]+)*)$'},fontVariant:{enums:["small-caps","normal"]},fontStyle:{enums:["italic","normal","oblique"]},fontWeight:{enums:["normal","bold","bolder","lighter","100","200","300","400","500","600","800","900",100,200,300,400,500,600,700,800,900]},textDecoration:{enums:["none","underline","overline","line-through"]},textTransform:{enums:["none","uppercase","lowercase"]},textWrap:{enums:["none","wrap"]},textBackgroundShape:{enums:["rectangle","roundrectangle"]},nodeShape:{enums:["rectangle","roundrectangle","ellipse","triangle","square","pentagon","hexagon","heptagon","octagon","star","diamond","vee","rhomboid","polygon"]},compoundIncludeLabels:{enums:["include","exclude"]},arrowShape:{enums:["tee","triangle","triangle-tee","triangle-backcurve","half-triangle-overshot","vee","square","circle","diamond","none"]},arrowFill:{enums:["filled","hollow"]},display:{enums:["element","none"]},visibility:{enums:["hidden","visible"]},valign:{enums:["top","center","bottom"]},halign:{enums:["left","center","right"]},text:{string:!0},data:{mapping:!0,regex:s("data")},layoutData:{mapping:!0,regex:s("layoutData")},scratch:{mapping:!0,regex:s("scratch")},mapData:{mapping:!0,regex:l("mapData")},mapLayoutData:{mapping:!0,regex:l("mapLayoutData")},mapScratch:{mapping:!0,regex:l("mapScratch")},fn:{mapping:!0,fn:!0},url:{regex:"^url\\s*\\(\\s*([^\\s]+)\\s*\\s*\\)|none|(.+)$"},propList:{propList:!0},angle:{number:!0,units:"deg|rad",implicitUnits:"rad"},textRotation:{enums:["none","autorotate"]},polygonPointList:{number:!0,multiple:!0,evenMultiple:!0,min:-1,max:1,unitless:!0},easing:{regexes:["^(spring)\\s*\\(\\s*("+e+")\\s*,\\s*("+e+")\\s*\\)$","^(cubic-bezier)\\s*\\(\\s*("+e+")\\s*,\\s*("+e+")\\s*,\\s*("+e+")\\s*,\\s*("+e+")\\s*\\)$"],enums:["linear","ease","ease-in","ease-out","ease-in-out","ease-in-sine","ease-out-sine","ease-in-out-sine","ease-in-quad","ease-out-quad","ease-in-out-quad","ease-in-cubic","ease-out-cubic","ease-in-out-cubic","ease-in-quart","ease-out-quart","ease-in-out-quart","ease-in-quint","ease-out-quint","ease-in-out-quint","ease-in-expo","ease-out-expo","ease-in-out-expo","ease-in-circ","ease-out-circ","ease-in-out-circ"]}};var u=i.types,c=i.properties=[{name:"text-valign",type:u.valign},{name:"text-halign",type:u.halign},{name:"color",type:u.color},{name:"label",type:u.text},{name:"text-outline-color",type:u.color},{name:"text-outline-width",type:u.size},{name:"text-outline-opacity",type:u.zeroOneNumber},{name:"text-opacity",type:u.zeroOneNumber},{name:"text-background-color",type:u.color},{name:"text-background-opacity",type:u.zeroOneNumber},{name:"text-border-opacity",type:u.zeroOneNumber},{name:"text-border-color",type:u.color},{name:"text-border-width",type:u.size},{name:"text-border-style",type:u.borderStyle},{name:"text-background-shape",type:u.textBackgroundShape},{name:"text-transform",type:u.textTransform},{name:"text-wrap",type:u.textWrap},{name:"text-max-width",type:u.size},{name:"text-events",type:u.bool},{name:"font-family",type:u.fontFamily},{name:"font-style",type:u.fontStyle},{name:"font-weight",type:u.fontWeight},{name:"font-size",type:u.size},{name:"min-zoomed-font-size",type:u.size},{name:"edge-text-rotation",type:u.textRotation},{name:"events",type:u.bool},{name:"display",type:u.display},{name:"visibility",type:u.visibility},{name:"opacity",type:u.zeroOneNumber},{name:"z-index",type:u.nonNegativeInt},{name:"overlay-padding",type:u.size},{name:"overlay-color",type:u.color},{name:"overlay-opacity",type:u.zeroOneNumber},{name:"shadow-blur",type:u.size},{name:"shadow-color",type:u.color},{name:"shadow-opacity",type:u.zeroOneNumber},{name:"shadow-offset-x",type:u.bidirectionalSize},{name:"shadow-offset-y",type:u.bidirectionalSize},{name:"text-shadow-blur",type:u.size},{name:"text-shadow-color",type:u.color},{name:"text-shadow-opacity",type:u.zeroOneNumber},{name:"text-shadow-offset-x",type:u.bidirectionalSize},{name:"text-shadow-offset-y",type:u.bidirectionalSize},{name:"transition-property",type:u.propList},{name:"transition-duration",type:u.time},{name:"transition-delay",type:u.time},{name:"transition-timing-function",type:u.easing},{name:"height",type:u.nodeSize},{name:"width",type:u.nodeSize},{name:"shape",type:u.nodeShape},{name:"shape-polygon-points",type:u.polygonPointList},{name:"background-color",type:u.color},{name:"background-opacity",type:u.zeroOneNumber},{name:"background-blacken",type:u.nOneOneNumber},{name:"padding-left",type:u.size},{name:"padding-right",type:u.size},{name:"padding-top",type:u.size},{name:"padding-bottom",type:u.size},{name:"border-color",type:u.color},{name:"border-opacity",type:u.zeroOneNumber},{name:"border-width",type:u.size},{name:"border-style",type:u.borderStyle},{name:"background-image",type:u.url},{name:"background-image-opacity",type:u.zeroOneNumber},{name:"background-position-x",type:u.bgPos},{name:"background-position-y",type:u.bgPos},{name:"background-repeat",type:u.bgRepeat},{name:"background-fit",type:u.bgFit},{name:"background-clip",type:u.bgClip},{name:"background-width",type:u.bgWH},{name:"background-height",type:u.bgWH},{name:"position",type:u.position},{name:"compound-sizing-wrt-labels",type:u.compoundIncludeLabels},{name:"line-style",type:u.lineStyle},{name:"line-color",type:u.color},{name:"curve-style",type:u.curveStyle},{name:"haystack-radius",type:u.zeroOneNumber},{name:"control-point-step-size",type:u.size},{name:"control-point-distances",type:u.bidirectionalSizes},{name:"control-point-weights",type:u.numbers},{name:"segment-distances",type:u.bidirectionalSizes},{name:"segment-weights",type:u.numbers},{name:"selection-box-color",type:u.color},{name:"selection-box-opacity",type:u.zeroOneNumber},{name:"selection-box-border-color",type:u.color},{name:"selection-box-border-width",type:u.size},{name:"active-bg-color",type:u.color},{name:"active-bg-opacity",type:u.zeroOneNumber},{name:"active-bg-size",type:u.size},{name:"outside-texture-bg-color",type:u.color},{name:"outside-texture-bg-opacity",type:u.zeroOneNumber}],d=i.aliases=[{name:"content",pointsTo:"label"},{name:"control-point-distance",pointsTo:"control-point-distances"},{name:"control-point-weight",pointsTo:"control-point-weights"}];i.pieBackgroundN=16,c.push({name:"pie-size",type:u.bgSize});for(var h=1;h<=i.pieBackgroundN;h++)c.push({name:"pie-"+h+"-background-color",type:u.color}),c.push({name:"pie-"+h+"-background-size",type:u.percent}),c.push({name:"pie-"+h+"-background-opacity",type:u.zeroOneNumber});var p=i.arrowPrefixes=["source","mid-source","target","mid-target"];[{name:"arrow-shape",type:u.arrowShape},{name:"arrow-color",type:u.color},{name:"arrow-fill",type:u.arrowFill}].forEach(function(e){p.forEach(function(t){var r=t+"-"+e.name,n=e.type;c.push({name:r,type:n})})},{}),i.propertyNames=c.map(function(e){return e.name});for(var h=0;h<c.length;h++){var v=c[h];c[v.name]=v}for(var h=0;h<d.length;h++){var f=d[h],g=c[f.pointsTo],y={name:f.name,alias:!0,pointsTo:g};c.push(y),c[f.name]=y}}(),i.addDefaultStylesheet=function(){this.selector("node, edge").css(n.extend({events:"yes","text-events":"no","text-valign":"top","text-halign":"center",color:"#000","text-outline-color":"#000","text-outline-width":0,"text-outline-opacity":1,"text-opacity":1,"text-decoration":"none","text-transform":"none","text-wrap":"none","text-max-width":9999,"text-background-color":"#000","text-background-opacity":0,"text-border-opacity":0,"text-border-width":0,"text-border-style":"solid","text-border-color":"#000","text-background-shape":"rectangle","font-family":"Helvetica Neue, Helvetica, sans-serif","font-style":"normal","font-weight":"normal","font-size":16,"min-zoomed-font-size":0,"edge-text-rotation":"none",visibility:"visible",display:"element",opacity:1,"z-index":0,label:"","overlay-opacity":0,"overlay-color":"#000","overlay-padding":10,"shadow-opacity":0,"shadow-color":"#000","shadow-blur":10,"shadow-offset-x":0,"shadow-offset-y":0,"text-shadow-opacity":0,"text-shadow-color":"#000","text-shadow-blur":5,"text-shadow-offset-x":0,"text-shadow-offset-y":0,"transition-property":"none","transition-duration":0,"transition-delay":0,"transition-timing-function":"linear","background-blacken":0,"background-color":"#888","background-opacity":1,"background-image":"none","background-image-opacity":1,"background-position-x":"50%","background-position-y":"50%","background-repeat":"no-repeat","background-fit":"none","background-clip":"node","background-width":"auto","background-height":"auto","border-color":"#000","border-opacity":1,"border-width":0,"border-style":"solid",height:30,width:30,shape:"ellipse","shape-polygon-points":"-1, -1, 1, -1, 1, 1, -1, 1","padding-top":0,"padding-bottom":0,"padding-left":0,"padding-right":0,position:"origin","compound-sizing-wrt-labels":"include"},{"pie-size":"100%"},[{name:"pie-{{i}}-background-color",value:"black"},{name:"pie-{{i}}-background-size",value:"0%"},{name:"pie-{{i}}-background-opacity",value:1}].reduce(function(e,t){for(var r=1;r<=i.pieBackgroundN;r++){var n=t.name.replace("{{i}}",r),a=t.value;e[n]=a}return e},{}),{"line-style":"solid","line-color":"#ddd","control-point-step-size":40,"control-point-weights":.5,"segment-weights":.25,"segment-distances":20,"curve-style":"bezier","haystack-radius":.8},[{name:"arrow-shape",value:"none"},{name:"arrow-color",value:"#ddd"},{name:"arrow-fill",value:"filled"}].reduce(function(e,t){return i.arrowPrefixes.forEach(function(r){var n=r+"-"+t.name,i=t.value;e[n]=i}),e},{}))).selector("$node > node").css({width:"auto",height:"auto",shape:"rectangle","padding-top":10,"padding-right":10,"padding-left":10,"padding-bottom":10}).selector("edge").css({width:1}).selector(":active").css({"overlay-color":"black","overlay-padding":10,"overlay-opacity":.25}).selector("core").css({"selection-box-color":"#ddd","selection-box-opacity":.65,"selection-box-border-color":"#aaa","selection-box-border-width":1,"active-bg-color":"black","active-bg-opacity":.15,"active-bg-size":30,"outside-texture-bg-color":"#000","outside-texture-bg-opacity":.125}),this.defaultLength=this.length},t.exports=i},{"../util":94}],90:[function(e,t,r){"use strict";var n=e("../util"),i=e("../selector"),a={};a.applyFromString=function(e){function t(){c=c.length>a.length?c.substr(a.length):""}function r(){o=o.length>s.length?o.substr(s.length):""}var a,o,s,l=this,u=this,c=""+e;for(c=c.replace(/[\/][*](\s|.)+?[*][\/]/g,"");;){var d=c.match(/^\s*$/);if(d)break;var h=c.match(/^\s*((?:.|\s)+?)\s*\{((?:.|\s)+?)\}/);if(!h){n.error("Halting stylesheet parsing: String stylesheet contains more to parse but no selector and block found in: "+c);break}a=h[0];var p=h[1];if("core"!==p){var v=new i(p);if(v._private.invalid){n.error("Skipping parsing of block: Invalid selector found in string stylesheet: "+p),t();continue}}var f=h[2],g=!1;o=f;for(var y=[];;){var d=o.match(/^\s*$/);if(d)break;var m=o.match(/^\s*(.+?)\s*:\s*(.+?)\s*;/);if(!m){n.error("Skipping parsing of block: Invalid formatting of style property and value definitions found in:"+f),g=!0;break}s=m[0];var b=m[1],x=m[2],w=l.properties[b];if(w){var _=u.parse(b,x);_?(y.push({name:b,val:x}),r()):(n.error("Skipping property: Invalid property definition in: "+s),r())}else n.error("Skipping property: Invalid property name in: "+s),r()}if(g){t();break}u.selector(p);for(var E=0;E<y.length;E++){var w=y[E];u.css(w.name,w.val)}t()}return u},a.fromString=function(e){var t=this;return t.resetToDefault(),t.applyFromString(e),t},t.exports=a},{"../selector":81,"../util":94}],91:[function(e,t,r){"use strict";var n=e("./is"),i=e("./util"),a=e("./style"),o=function(){return this instanceof o?void(this.length=0):new o},s=o.prototype;s.instanceString=function(){return"stylesheet"},s.selector=function(e){var t=this.length++;return this[t]={selector:e,properties:[]},this},s.css=function(e,t){var r=this.length-1;if(n.string(e))this[r].properties.push({name:e,value:t});else if(n.plainObject(e))for(var o=e,s=0;s<a.properties.length;s++){var l=a.properties[s],u=o[l.name];if(void 0===u&&(u=o[i.dash2camel(l.name)]),void 0!==u){var e=l.name,t=u;this[r].properties.push({name:e,value:t})}}return this},s.style=s.css,s.generateStyle=function(e){for(var t=new a(e),r=0;r<this.length;r++){var n=this[r],i=n.selector,o=n.properties;t.selector(i);for(var s=0;s<o.length;s++){var l=o[s];t.css(l.name,l.value)}}return t},t.exports=o},{"./is":77,"./style":86,"./util":94}],92:[function(_dereq_,module,exports){"use strict";var window=_dereq_("./window"),util=_dereq_("./util"),Promise=_dereq_("./promise"),Event=_dereq_("./event"),define=_dereq_("./define"),is=_dereq_("./is"),Thread=function(e){if(!(this instanceof Thread))return new Thread(e);var t=this._private={requires:[],files:[],queue:null,pass:[],disabled:!1};is.plainObject(e)&&null!=e.disabled&&(t.disabled=!!e.disabled)},thdfn=Thread.prototype,stringifyFieldVal=function(e){var t=is.fn(e)?e.toString():'JSON.parse("'+JSON.stringify(e)+'")';return t},fnAsRequire=function(e){var t,r;is.object(e)&&e.fn?(t=fnAs(e.fn,e.name),r=e.name,e=e.fn):is.fn(e)?(t=e.toString(),r=e.name):is.string(e)?t=e:is.object(e)&&(t=e.proto?"":e.name+" = {};",r=e.name,e=e.obj),t+="\n";var n=function(e,r){if(e.prototype){var n=!1;for(var i in e.prototype){n=!0;break}n&&(t+=fnAsRequire({name:r,obj:e,proto:!0},e))}};if(e.prototype&&null!=r)for(var i in e.prototype){var a="",o=e.prototype[i],s=stringifyFieldVal(o),l=r+".prototype."+i;a+=l+" = "+s+";\n",a&&(t+=a),n(o,l)}if(!is.string(e))for(var i in e){var u="";if(e.hasOwnProperty(i)){var o=e[i],s=stringifyFieldVal(o),l=r+'["'+i+'"]';u+=l+" = "+s+";\n"}u&&(t+=u),n(o,l)}return t},isPathStr=function(e){return is.string(e)&&e.match(/\.js$/)};util.extend(thdfn,{instanceString:function(){return"thread"},require:function(e,t){var r=this._private.requires;if(isPathStr(e))return this._private.files.push(e),this;if(t)e=is.fn(e)?{name:t,fn:e}:{name:t,obj:e};else if(is.fn(e)){if(!e.name)throw'The function name could not be automatically determined. Use thread.require( someFunction, "someFunction" )';e={name:e.name,fn:e}}return r.push(e),this},pass:function(e){return this._private.pass.push(e),this},run:function(fn,pass){var self=this,_p=this._private;if(pass=pass||_p.pass.shift(),_p.stopped)throw"Attempted to run a stopped thread! Start a new thread or do not stop the existing thread and reuse it.";if(_p.running)return _p.queue=_p.queue.then(function(){return self.run(fn,pass)});var useWW=null!=window&&!_p.disabled,useNode=!window&&"undefined"!=typeof module&&!_p.disabled;self.trigger("run");var runP=new Promise(function(resolve,reject){_p.running=!0;var threadTechAlreadyExists=_p.ran,fnImplStr=is.string(fn)?fn:fn.toString(),fnStr="\n"+_p.requires.map(function(e){return fnAsRequire(e)}).concat(_p.files.map(function(e){if(useWW){var t=function(e){return e.match(/^\.\//)||e.match(/^\.\./)?window.location.origin+window.location.pathname+e:e.match(/^\//)?window.location.origin+"/"+e:e};return'importScripts("'+t(e)+'");'}if(useNode)return'eval( require("fs").readFileSync("'+e+'", { encoding: "utf8" }) );';throw"External file `"+e+"` can not be required without any threading technology."})).concat(["( function(){","var ret = ("+fnImplStr+")("+JSON.stringify(pass)+");","if( ret !== undefined ){ resolve(ret); }","} )()\n"]).join("\n");if(_p.requires=[],_p.files=[],useWW){var fnBlob,fnUrl;if(!threadTechAlreadyExists){var fnPre=fnStr+"";fnStr=["function _ref_(o){ return eval(o); };","function broadcast(m){ return message(m); };","function message(m){ postMessage(m); };","function listen(fn){",' self.addEventListener("message", function(m){ ',' if( typeof m === "object" && (m.data.$$eval || m.data === "$$start") ){'," } else { "," fn( m.data );"," }"," });","};",'self.addEventListener("message", function(m){ if( m.data.$$eval ){ eval( m.data.$$eval ); } });',"function resolve(v){ postMessage({ $$resolve: v }); };","function reject(v){ postMessage({ $$reject: v }); };"].join("\n"),
+fnStr+=fnPre,fnBlob=new Blob([fnStr],{type:"application/javascript"}),fnUrl=window.URL.createObjectURL(fnBlob)}var ww=_p.webworker=_p.webworker||new Worker(fnUrl);threadTechAlreadyExists&&ww.postMessage({$$eval:fnStr});var cb;ww.addEventListener("message",cb=function(e){var t=is.object(e)&&is.object(e.data);t&&"$$resolve"in e.data?(ww.removeEventListener("message",cb),resolve(e.data.$$resolve)):t&&"$$reject"in e.data?(ww.removeEventListener("message",cb),reject(e.data.$$reject)):self.trigger(new Event(e,{type:"message",message:e.data}))},!1),threadTechAlreadyExists||ww.postMessage("$$start")}else if(useNode){_p.child||(_p.child=_dereq_("child_process").fork(_dereq_("path").join(__dirname,"thread-node-fork")));var child=_p.child,cb;child.on("message",cb=function(e){is.object(e)&&"$$resolve"in e?(child.removeListener("message",cb),resolve(e.$$resolve)):is.object(e)&&"$$reject"in e?(child.removeListener("message",cb),reject(e.$$reject)):self.trigger(new Event({},{type:"message",message:e}))}),child.send({$$eval:fnStr})}else{var promiseResolve=resolve,promiseReject=reject,timer=_p.timer=_p.timer||{listeners:[],exec:function(){fnStr=["function _ref_(o){ return eval(o); };","function broadcast(m){ return message(m); };",'function message(m){ self.trigger( new Event({}, { type: "message", message: m }) ); };',"function listen(fn){ timer.listeners.push( fn ); };","function resolve(v){ promiseResolve(v); };","function reject(v){ promiseReject(v); };"].join("\n")+fnStr,eval(fnStr)},message:function(e){for(var t=timer.listeners,r=0;r<t.length;r++){var n=t[r];n(e)}}};timer.exec()}}).then(function(e){return _p.running=!1,_p.ran=!0,self.trigger("ran"),e});return null==_p.queue&&(_p.queue=runP),runP},message:function(e){var t=this._private;return t.webworker&&t.webworker.postMessage(e),t.child&&t.child.send(e),t.timer&&t.timer.message(e),this},stop:function(){var e=this._private;return e.webworker&&e.webworker.terminate(),e.child&&e.child.kill(),e.timer,e.stopped=!0,this.trigger("stop")},stopped:function(){return this._private.stopped}});var fnAs=function(e,t){var r=e.toString();return r=r.replace(/function\s*?\S*?\s*?\(/,"function "+t+"(")},defineFnal=function(e){return e=e||{},function(t,r){var n=fnAs(t,"_$_$_"+e.name);return this.require(n),this.run(["function( data ){"," var origResolve = resolve;"," var res = [];"," "," resolve = function( val ){"," res.push( val );"," };"," "," var ret = data."+e.name+"( _$_$_"+e.name+(arguments.length>1?", "+JSON.stringify(r):"")+" );"," "," resolve = origResolve;"," resolve( res.length > 0 ? res : ret );","}"].join("\n"))}};util.extend(thdfn,{reduce:defineFnal({name:"reduce"}),reduceRight:defineFnal({name:"reduceRight"}),map:defineFnal({name:"map"})});var fn=thdfn;fn.promise=fn.run,fn.terminate=fn.halt=fn.stop,fn.include=fn.require,util.extend(thdfn,{on:define.on(),one:define.on({unbindSelfOnTrigger:!0}),off:define.off(),trigger:define.trigger()}),define.eventAliasesOn(thdfn),module.exports=Thread},{"./define":41,"./event":42,"./is":77,"./promise":80,"./util":94,"./window":100,child_process:void 0,path:void 0}],93:[function(e,t,r){"use strict";var n=e("../is");t.exports={hex2tuple:function(e){if((4===e.length||7===e.length)&&"#"===e[0]){var t,r,n,i=4===e.length,a=16;return i?(t=parseInt(e[1]+e[1],a),r=parseInt(e[2]+e[2],a),n=parseInt(e[3]+e[3],a)):(t=parseInt(e[1]+e[2],a),r=parseInt(e[3]+e[4],a),n=parseInt(e[5]+e[6],a)),[t,r,n]}},hsl2tuple:function(e){function t(e,t,r){return 0>r&&(r+=1),r>1&&(r-=1),1/6>r?e+6*(t-e)*r:.5>r?t:2/3>r?e+(t-e)*(2/3-r)*6:e}var r,n,i,a,o,s,l,u,c=new RegExp("^"+this.regex.hsla+"$").exec(e);if(c){if(n=parseInt(c[1]),0>n?n=(360- -1*n%360)%360:n>360&&(n%=360),n/=360,i=parseFloat(c[2]),0>i||i>100)return;if(i/=100,a=parseFloat(c[3]),0>a||a>100)return;if(a/=100,o=c[4],void 0!==o&&(o=parseFloat(o),0>o||o>1))return;if(0===i)s=l=u=Math.round(255*a);else{var d=.5>a?a*(1+i):a+i-a*i,h=2*a-d;s=Math.round(255*t(h,d,n+1/3)),l=Math.round(255*t(h,d,n)),u=Math.round(255*t(h,d,n-1/3))}r=[s,l,u,o]}return r},rgb2tuple:function(e){var t,r=new RegExp("^"+this.regex.rgba+"$").exec(e);if(r){t=[];for(var n=[],i=1;3>=i;i++){var a=r[i];if("%"===a[a.length-1]&&(n[i]=!0),a=parseFloat(a),n[i]&&(a=a/100*255),0>a||a>255)return;t.push(Math.floor(a))}var o=n[1]||n[2]||n[3],s=n[1]&&n[2]&&n[3];if(o&&!s)return;var l=r[4];if(void 0!==l){if(l=parseFloat(l),0>l||l>1)return;t.push(l)}}return t},colorname2tuple:function(e){return this.colors[e.toLowerCase()]},color2tuple:function(e){return(n.array(e)?e:null)||this.colorname2tuple(e)||this.hex2tuple(e)||this.rgb2tuple(e)||this.hsl2tuple(e)},colors:{transparent:[0,0,0,0],aliceblue:[240,248,255],antiquewhite:[250,235,215],aqua:[0,255,255],aquamarine:[127,255,212],azure:[240,255,255],beige:[245,245,220],bisque:[255,228,196],black:[0,0,0],blanchedalmond:[255,235,205],blue:[0,0,255],blueviolet:[138,43,226],brown:[165,42,42],burlywood:[222,184,135],cadetblue:[95,158,160],chartreuse:[127,255,0],chocolate:[210,105,30],coral:[255,127,80],cornflowerblue:[100,149,237],cornsilk:[255,248,220],crimson:[220,20,60],cyan:[0,255,255],darkblue:[0,0,139],darkcyan:[0,139,139],darkgoldenrod:[184,134,11],darkgray:[169,169,169],darkgreen:[0,100,0],darkgrey:[169,169,169],darkkhaki:[189,183,107],darkmagenta:[139,0,139],darkolivegreen:[85,107,47],darkorange:[255,140,0],darkorchid:[153,50,204],darkred:[139,0,0],darksalmon:[233,150,122],darkseagreen:[143,188,143],darkslateblue:[72,61,139],darkslategray:[47,79,79],darkslategrey:[47,79,79],darkturquoise:[0,206,209],darkviolet:[148,0,211],deeppink:[255,20,147],deepskyblue:[0,191,255],dimgray:[105,105,105],dimgrey:[105,105,105],dodgerblue:[30,144,255],firebrick:[178,34,34],floralwhite:[255,250,240],forestgreen:[34,139,34],fuchsia:[255,0,255],gainsboro:[220,220,220],ghostwhite:[248,248,255],gold:[255,215,0],goldenrod:[218,165,32],gray:[128,128,128],grey:[128,128,128],green:[0,128,0],greenyellow:[173,255,47],honeydew:[240,255,240],hotpink:[255,105,180],indianred:[205,92,92],indigo:[75,0,130],ivory:[255,255,240],khaki:[240,230,140],lavender:[230,230,250],lavenderblush:[255,240,245],lawngreen:[124,252,0],lemonchiffon:[255,250,205],lightblue:[173,216,230],lightcoral:[240,128,128],lightcyan:[224,255,255],lightgoldenrodyellow:[250,250,210],lightgray:[211,211,211],lightgreen:[144,238,144],lightgrey:[211,211,211],lightpink:[255,182,193],lightsalmon:[255,160,122],lightseagreen:[32,178,170],lightskyblue:[135,206,250],lightslategray:[119,136,153],lightslategrey:[119,136,153],lightsteelblue:[176,196,222],lightyellow:[255,255,224],lime:[0,255,0],limegreen:[50,205,50],linen:[250,240,230],magenta:[255,0,255],maroon:[128,0,0],mediumaquamarine:[102,205,170],mediumblue:[0,0,205],mediumorchid:[186,85,211],mediumpurple:[147,112,219],mediumseagreen:[60,179,113],mediumslateblue:[123,104,238],mediumspringgreen:[0,250,154],mediumturquoise:[72,209,204],mediumvioletred:[199,21,133],midnightblue:[25,25,112],mintcream:[245,255,250],mistyrose:[255,228,225],moccasin:[255,228,181],navajowhite:[255,222,173],navy:[0,0,128],oldlace:[253,245,230],olive:[128,128,0],olivedrab:[107,142,35],orange:[255,165,0],orangered:[255,69,0],orchid:[218,112,214],palegoldenrod:[238,232,170],palegreen:[152,251,152],paleturquoise:[175,238,238],palevioletred:[219,112,147],papayawhip:[255,239,213],peachpuff:[255,218,185],peru:[205,133,63],pink:[255,192,203],plum:[221,160,221],powderblue:[176,224,230],purple:[128,0,128],red:[255,0,0],rosybrown:[188,143,143],royalblue:[65,105,225],saddlebrown:[139,69,19],salmon:[250,128,114],sandybrown:[244,164,96],seagreen:[46,139,87],seashell:[255,245,238],sienna:[160,82,45],silver:[192,192,192],skyblue:[135,206,235],slateblue:[106,90,205],slategray:[112,128,144],slategrey:[112,128,144],snow:[255,250,250],springgreen:[0,255,127],steelblue:[70,130,180],tan:[210,180,140],teal:[0,128,128],thistle:[216,191,216],tomato:[255,99,71],turquoise:[64,224,208],violet:[238,130,238],wheat:[245,222,179],white:[255,255,255],whitesmoke:[245,245,245],yellow:[255,255,0],yellowgreen:[154,205,50]}}},{"../is":77}],94:[function(e,t,r){"use strict";var n=e("../is"),i=e("../math"),a={falsify:function(){return!1},zeroify:function(){return 0},noop:function(){},error:function(e){console.error?(console.error.apply(console,arguments),console.trace&&console.trace()):(console.log.apply(console,arguments),console.trace&&console.trace())},clone:function(e){return this.extend({},e)},copy:function(e){return null==e?e:n.array(e)?e.slice():n.plainObject(e)?this.clone(e):e}};a.makeBoundingBox=i.makeBoundingBox.bind(i),a._staticEmptyObject={},a.staticEmptyObject=function(){return a._staticEmptyObject},a.extend=null!=Object.assign?Object.assign:function(e){for(var t=arguments,r=1;r<t.length;r++){var n=t[r];for(var i in n)e[i]=n[i]}return e},[e("./colors"),e("./maps"),{memoize:e("./memoize")},e("./regex"),e("./strings"),e("./timing")].forEach(function(e){a.extend(a,e)}),t.exports=a},{"../is":77,"../math":79,"./colors":93,"./maps":95,"./memoize":96,"./regex":97,"./strings":98,"./timing":99}],95:[function(e,t,r){"use strict";var n=e("../is");t.exports={mapEmpty:function(e){var t=!0;if(null!=e)for(var r in e){t=!1;break}return t},pushMap:function(e){var t=this.getMap(e);null==t?this.setMap(this.extend({},e,{value:[e.value]})):t.push(e.value)},setMap:function(e){for(var t,r=e.map,i=e.keys,a=i.length,o=0;a>o;o++){var t=i[o];n.plainObject(t)&&this.error("Tried to set map with object key"),o<i.length-1?(null==r[t]&&(r[t]={}),r=r[t]):r[t]=e.value}},getMap:function(e){for(var t=e.map,r=e.keys,i=r.length,a=0;i>a;a++){var o=r[a];if(n.plainObject(o)&&this.error("Tried to get map with object key"),t=t[o],null==t)return t}return t},deleteMap:function(e){for(var t=e.map,r=e.keys,i=r.length,a=e.keepChildren,o=0;i>o;o++){var s=r[o];n.plainObject(s)&&this.error("Tried to delete map with object key");var l=o===e.keys.length-1;if(l)if(a)for(var u in t)a[u]||(t[u]=void 0);else t[s]=void 0;else t=t[s]}}}},{"../is":77}],96:[function(e,t,r){"use strict";t.exports=function(e,t){var r=this,n={};return t||(t=function(){if(1===arguments.length)return arguments[0];for(var e=[],t=0;t<arguments.length;t++)e.push(arguments[t]);return e.join("$")}),function(){var i,a=arguments,o=t.apply(r,a);return(i=n[o])||(i=n[o]=e.apply(r,a)),i}}},{}],97:[function(e,t,r){"use strict";var n="(?:[-+]?(?:(?:\\d+|\\d*\\.\\d+)(?:[Ee][+-]?\\d+)?))",i="rgb[a]?\\(("+n+"[%]?)\\s*,\\s*("+n+"[%]?)\\s*,\\s*("+n+"[%]?)(?:\\s*,\\s*("+n+"))?\\)",a="rgb[a]?\\((?:"+n+"[%]?)\\s*,\\s*(?:"+n+"[%]?)\\s*,\\s*(?:"+n+"[%]?)(?:\\s*,\\s*(?:"+n+"))?\\)",o="hsl[a]?\\(("+n+")\\s*,\\s*("+n+"[%])\\s*,\\s*("+n+"[%])(?:\\s*,\\s*("+n+"))?\\)",s="hsl[a]?\\((?:"+n+")\\s*,\\s*(?:"+n+"[%])\\s*,\\s*(?:"+n+"[%])(?:\\s*,\\s*(?:"+n+"))?\\)",l="\\#[0-9a-fA-F]{3}",u="\\#[0-9a-fA-F]{6}";t.exports={regex:{number:n,rgba:i,rgbaNoBackRefs:a,hsla:o,hslaNoBackRefs:s,hex3:l,hex6:u}}},{}],98:[function(e,t,r){"use strict";var n=e("./memoize"),i=e("../is");t.exports={camel2dash:n(function(e){return e.replace(/([A-Z])/g,function(e){return"-"+e.toLowerCase()})}),dash2camel:n(function(e){return e.replace(/(-\w)/g,function(e){return e[1].toUpperCase()})}),capitalize:function(e){return i.emptyString(e)?e:e.charAt(0).toUpperCase()+e.substring(1)}}},{"../is":77,"./memoize":96}],99:[function(e,t,r){"use strict";var n=e("../window"),i=e("../is"),a=n?n.performance:null,o={},s=n?n.requestAnimationFrame||n.mozRequestAnimationFrame||n.webkitRequestAnimationFrame||n.msRequestAnimationFrame:null;s=s||function(e){e&&setTimeout(function(){e(l())},1e3/60)},o.requestAnimationFrame=function(e){s(e)};var l=a&&a.now?function(){return a.now()}:function(){return Date.now()};o.performanceNow=l,o.throttle=function(e,t,r){var n=!0,a=!0;return r===!1?n=!1:i.plainObject(r)&&(n="leading"in r?r.leading:n,a="trailing"in r?r.trailing:a),r=r||{},r.leading=n,r.maxWait=t,r.trailing=a,o.debounce(e,t,r)},o.now=function(){return Date.now()},o.debounce=function(e,t,r){var n,a,o,s,l,u,c,d=this,h=0,p=!1,v=!0;if(i.fn(e)){if(t=Math.max(0,t)||0,r===!0){var f=!0;v=!1}else i.plainObject(r)&&(f=r.leading,p="maxWait"in r&&(Math.max(t,r.maxWait)||0),v="trailing"in r?r.trailing:v);var g=function(){var r=t-(d.now()-s);if(0>=r){a&&clearTimeout(a);var i=c;a=u=c=void 0,i&&(h=d.now(),o=e.apply(l,n),u||a||(n=l=null))}else u=setTimeout(g,r)},y=function(){u&&clearTimeout(u),a=u=c=void 0,(v||p!==t)&&(h=d.now(),o=e.apply(l,n),u||a||(n=l=null))};return function(){if(n=arguments,s=d.now(),l=this,c=v&&(u||!f),p===!1)var r=f&&!u;else{a||f||(h=s);var i=p-(s-h),m=0>=i;m?(a&&(a=clearTimeout(a)),h=s,o=e.apply(l,n)):a||(a=setTimeout(y,i))}return m&&u?u=clearTimeout(u):u||t===p||(u=setTimeout(g,t)),r&&(m=!0,o=e.apply(l,n)),!m||u||a||(n=l=null),o}}},t.exports=o},{"../is":77,"../window":100}],100:[function(e,t,r){t.exports="undefined"==typeof window?null:window},{}]},{},[76])(76)});
+//# sourceMappingURL=cytoscape.min.js.map
diff --git a/docs/htmldoc/js/dagre.js b/docs/htmldoc/js/dagre.js
new file mode 100644
index 0000000..830997b
--- /dev/null
+++ b/docs/htmldoc/js/dagre.js
@@ -0,0 +1,16396 @@
+!function(e){if("object"==typeof exports&&"undefined"!=typeof module)module.exports=e();else if("function"==typeof define&&define.amd)define([],e);else{var f;"undefined"!=typeof window?f=window:"undefined"!=typeof global?f=global:"undefined"!=typeof self&&(f=self),f.dagre=e()}}(function(){var define,module,exports;return (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s})({1:[function(require,module,exports){
+/*
+Copyright (c) 2012-2014 Chris Pettitt
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+*/
+
+module.exports = {
+ graphlib: require("./lib/graphlib"),
+
+ layout: require("./lib/layout"),
+ debug: require("./lib/debug"),
+ util: {
+ time: require("./lib/util").time,
+ notime: require("./lib/util").notime
+ },
+ version: require("./lib/version")
+};
+
+},{"./lib/debug":6,"./lib/graphlib":7,"./lib/layout":9,"./lib/util":29,"./lib/version":30}],2:[function(require,module,exports){
+"use strict";
+
+var _ = require("./lodash"),
+ greedyFAS = require("./greedy-fas");
+
+module.exports = {
+ run: run,
+ undo: undo
+};
+
+function run(g) {
+ var fas = (g.graph().acyclicer === "greedy"
+ ? greedyFAS(g, weightFn(g))
+ : dfsFAS(g));
+ _.each(fas, function(e) {
+ var label = g.edge(e);
+ g.removeEdge(e);
+ label.forwardName = e.name;
+ label.reversed = true;
+ g.setEdge(e.w, e.v, label, _.uniqueId("rev"));
+ });
+
+ function weightFn(g) {
+ return function(e) {
+ return g.edge(e).weight;
+ };
+ }
+}
+
+function dfsFAS(g) {
+ var fas = [],
+ stack = {},
+ visited = {};
+
+ function dfs(v) {
+ if (_.has(visited, v)) {
+ return;
+ }
+ visited[v] = true;
+ stack[v] = true;
+ _.each(g.outEdges(v), function(e) {
+ if (_.has(stack, e.w)) {
+ fas.push(e);
+ } else {
+ dfs(e.w);
+ }
+ });
+ delete stack[v];
+ }
+
+ _.each(g.nodes(), dfs);
+ return fas;
+}
+
+function undo(g) {
+ _.each(g.edges(), function(e) {
+ var label = g.edge(e);
+ if (label.reversed) {
+ g.removeEdge(e);
+
+ var forwardName = label.forwardName;
+ delete label.reversed;
+ delete label.forwardName;
+ g.setEdge(e.w, e.v, label, forwardName);
+ }
+ });
+}
+
+},{"./greedy-fas":8,"./lodash":10}],3:[function(require,module,exports){
+var _ = require("./lodash"),
+ util = require("./util");
+
+module.exports = addBorderSegments;
+
+function addBorderSegments(g) {
+ function dfs(v) {
+ var children = g.children(v),
+ node = g.node(v);
+ if (children.length) {
+ _.each(children, dfs);
+ }
+
+ if (_.has(node, "minRank")) {
+ node.borderLeft = [];
+ node.borderRight = [];
+ for (var rank = node.minRank, maxRank = node.maxRank + 1;
+ rank < maxRank;
+ ++rank) {
+ addBorderNode(g, "borderLeft", "_bl", v, node, rank);
+ addBorderNode(g, "borderRight", "_br", v, node, rank);
+ }
+ }
+ }
+
+ _.each(g.children(), dfs);
+}
+
+function addBorderNode(g, prop, prefix, sg, sgNode, rank) {
+ var label = { width: 0, height: 0, rank: rank, borderType: prop },
+ prev = sgNode[prop][rank - 1],
+ curr = util.addDummyNode(g, "border", label, prefix);
+ sgNode[prop][rank] = curr;
+ g.setParent(curr, sg);
+ if (prev) {
+ g.setEdge(prev, curr, { weight: 1 });
+ }
+}
+
+},{"./lodash":10,"./util":29}],4:[function(require,module,exports){
+"use strict";
+
+var _ = require("./lodash");
+
+module.exports = {
+ adjust: adjust,
+ undo: undo
+};
+
+function adjust(g) {
+ var rankDir = g.graph().rankdir.toLowerCase();
+ if (rankDir === "lr" || rankDir === "rl") {
+ swapWidthHeight(g);
+ }
+}
+
+function undo(g) {
+ var rankDir = g.graph().rankdir.toLowerCase();
+ if (rankDir === "bt" || rankDir === "rl") {
+ reverseY(g);
+ }
+
+ if (rankDir === "lr" || rankDir === "rl") {
+ swapXY(g);
+ swapWidthHeight(g);
+ }
+}
+
+function swapWidthHeight(g) {
+ _.each(g.nodes(), function(v) { swapWidthHeightOne(g.node(v)); });
+ _.each(g.edges(), function(e) { swapWidthHeightOne(g.edge(e)); });
+}
+
+function swapWidthHeightOne(attrs) {
+ var w = attrs.width;
+ attrs.width = attrs.height;
+ attrs.height = w;
+}
+
+function reverseY(g) {
+ _.each(g.nodes(), function(v) { reverseYOne(g.node(v)); });
+
+ _.each(g.edges(), function(e) {
+ var edge = g.edge(e);
+ _.each(edge.points, reverseYOne);
+ if (_.has(edge, "y")) {
+ reverseYOne(edge);
+ }
+ });
+}
+
+function reverseYOne(attrs) {
+ attrs.y = -attrs.y;
+}
+
+function swapXY(g) {
+ _.each(g.nodes(), function(v) { swapXYOne(g.node(v)); });
+
+ _.each(g.edges(), function(e) {
+ var edge = g.edge(e);
+ _.each(edge.points, swapXYOne);
+ if (_.has(edge, "x")) {
+ swapXYOne(edge);
+ }
+ });
+}
+
+function swapXYOne(attrs) {
+ var x = attrs.x;
+ attrs.x = attrs.y;
+ attrs.y = x;
+}
+
+},{"./lodash":10}],5:[function(require,module,exports){
+/*
+ * Simple doubly linked list implementation derived from Cormen, et al.,
+ * "Introduction to Algorithms".
+ */
+
+module.exports = List;
+
+function List() {
+ var sentinel = {};
+ sentinel._next = sentinel._prev = sentinel;
+ this._sentinel = sentinel;
+}
+
+List.prototype.dequeue = function() {
+ var sentinel = this._sentinel,
+ entry = sentinel._prev;
+ if (entry !== sentinel) {
+ unlink(entry);
+ return entry;
+ }
+};
+
+List.prototype.enqueue = function(entry) {
+ var sentinel = this._sentinel;
+ if (entry._prev && entry._next) {
+ unlink(entry);
+ }
+ entry._next = sentinel._next;
+ sentinel._next._prev = entry;
+ sentinel._next = entry;
+ entry._prev = sentinel;
+};
+
+List.prototype.toString = function() {
+ var strs = [],
+ sentinel = this._sentinel,
+ curr = sentinel._prev;
+ while (curr !== sentinel) {
+ strs.push(JSON.stringify(curr, filterOutLinks));
+ curr = curr._prev;
+ }
+ return "[" + strs.join(", ") + "]";
+};
+
+function unlink(entry) {
+ entry._prev._next = entry._next;
+ entry._next._prev = entry._prev;
+ delete entry._next;
+ delete entry._prev;
+}
+
+function filterOutLinks(k, v) {
+ if (k !== "_next" && k !== "_prev") {
+ return v;
+ }
+}
+
+},{}],6:[function(require,module,exports){
+var _ = require("./lodash"),
+ util = require("./util"),
+ Graph = require("./graphlib").Graph;
+
+module.exports = {
+ debugOrdering: debugOrdering
+};
+
+/* istanbul ignore next */
+function debugOrdering(g) {
+ var layerMatrix = util.buildLayerMatrix(g);
+
+ var h = new Graph({ compound: true, multigraph: true }).setGraph({});
+
+ _.each(g.nodes(), function(v) {
+ h.setNode(v, { label: v });
+ h.setParent(v, "layer" + g.node(v).rank);
+ });
+
+ _.each(g.edges(), function(e) {
+ h.setEdge(e.v, e.w, {}, e.name);
+ });
+
+ _.each(layerMatrix, function(layer, i) {
+ var layerV = "layer" + i;
+ h.setNode(layerV, { rank: "same" });
+ _.reduce(layer, function(u, v) {
+ h.setEdge(u, v, { style: "invis" });
+ return v;
+ });
+ });
+
+ return h;
+}
+
+},{"./graphlib":7,"./lodash":10,"./util":29}],7:[function(require,module,exports){
+/* global window */
+
+var graphlib;
+
+if (typeof require === "function") {
+ try {
+ graphlib = require("graphlib");
+ } catch (e) {}
+}
+
+if (!graphlib) {
+ graphlib = window.graphlib;
+}
+
+module.exports = graphlib;
+
+},{"graphlib":31}],8:[function(require,module,exports){
+var _ = require("./lodash"),
+ Graph = require("./graphlib").Graph,
+ List = require("./data/list");
+
+/*
+ * A greedy heuristic for finding a feedback arc set for a graph. A feedback
+ * arc set is a set of edges that can be removed to make a graph acyclic.
+ * The algorithm comes from: P. Eades, X. Lin, and W. F. Smyth, "A fast and
+ * effective heuristic for the feedback arc set problem." This implementation
+ * adjusts that from the paper to allow for weighted edges.
+ */
+module.exports = greedyFAS;
+
+var DEFAULT_WEIGHT_FN = _.constant(1);
+
+function greedyFAS(g, weightFn) {
+ if (g.nodeCount() <= 1) {
+ return [];
+ }
+ var state = buildState(g, weightFn || DEFAULT_WEIGHT_FN);
+ var results = doGreedyFAS(state.graph, state.buckets, state.zeroIdx);
+
+ // Expand multi-edges
+ return _.flatten(_.map(results, function(e) {
+ return g.outEdges(e.v, e.w);
+ }), true);
+}
+
+function doGreedyFAS(g, buckets, zeroIdx) {
+ var results = [],
+ sources = buckets[buckets.length - 1],
+ sinks = buckets[0];
+
+ var entry;
+ while (g.nodeCount()) {
+ while ((entry = sinks.dequeue())) { removeNode(g, buckets, zeroIdx, entry); }
+ while ((entry = sources.dequeue())) { removeNode(g, buckets, zeroIdx, entry); }
+ if (g.nodeCount()) {
+ for (var i = buckets.length - 2; i > 0; --i) {
+ entry = buckets[i].dequeue();
+ if (entry) {
+ results = results.concat(removeNode(g, buckets, zeroIdx, entry, true));
+ break;
+ }
+ }
+ }
+ }
+
+ return results;
+}
+
+function removeNode(g, buckets, zeroIdx, entry, collectPredecessors) {
+ var results = collectPredecessors ? [] : undefined;
+
+ _.each(g.inEdges(entry.v), function(edge) {
+ var weight = g.edge(edge),
+ uEntry = g.node(edge.v);
+
+ if (collectPredecessors) {
+ results.push({ v: edge.v, w: edge.w });
+ }
+
+ uEntry.out -= weight;
+ assignBucket(buckets, zeroIdx, uEntry);
+ });
+
+ _.each(g.outEdges(entry.v), function(edge) {
+ var weight = g.edge(edge),
+ w = edge.w,
+ wEntry = g.node(w);
+ wEntry["in"] -= weight;
+ assignBucket(buckets, zeroIdx, wEntry);
+ });
+
+ g.removeNode(entry.v);
+
+ return results;
+}
+
+function buildState(g, weightFn) {
+ var fasGraph = new Graph(),
+ maxIn = 0,
+ maxOut = 0;
+
+ _.each(g.nodes(), function(v) {
+ fasGraph.setNode(v, { v: v, "in": 0, out: 0 });
+ });
+
+ // Aggregate weights on nodes, but also sum the weights across multi-edges
+ // into a single edge for the fasGraph.
+ _.each(g.edges(), function(e) {
+ var prevWeight = fasGraph.edge(e.v, e.w) || 0,
+ weight = weightFn(e),
+ edgeWeight = prevWeight + weight;
+ fasGraph.setEdge(e.v, e.w, edgeWeight);
+ maxOut = Math.max(maxOut, fasGraph.node(e.v).out += weight);
+ maxIn = Math.max(maxIn, fasGraph.node(e.w)["in"] += weight);
+ });
+
+ var buckets = _.range(maxOut + maxIn + 3).map(function() { return new List(); });
+ var zeroIdx = maxIn + 1;
+
+ _.each(fasGraph.nodes(), function(v) {
+ assignBucket(buckets, zeroIdx, fasGraph.node(v));
+ });
+
+ return { graph: fasGraph, buckets: buckets, zeroIdx: zeroIdx };
+}
+
+function assignBucket(buckets, zeroIdx, entry) {
+ if (!entry.out) {
+ buckets[0].enqueue(entry);
+ } else if (!entry["in"]) {
+ buckets[buckets.length - 1].enqueue(entry);
+ } else {
+ buckets[entry.out - entry["in"] + zeroIdx].enqueue(entry);
+ }
+}
+
+},{"./data/list":5,"./graphlib":7,"./lodash":10}],9:[function(require,module,exports){
+"use strict";
+
+var _ = require("./lodash"),
+ acyclic = require("./acyclic"),
+ normalize = require("./normalize"),
+ rank = require("./rank"),
+ normalizeRanks = require("./util").normalizeRanks,
+ parentDummyChains = require("./parent-dummy-chains"),
+ removeEmptyRanks = require("./util").removeEmptyRanks,
+ nestingGraph = require("./nesting-graph"),
+ addBorderSegments = require("./add-border-segments"),
+ coordinateSystem = require("./coordinate-system"),
+ order = require("./order"),
+ position = require("./position"),
+ util = require("./util"),
+ Graph = require("./graphlib").Graph;
+
+module.exports = layout;
+
+function layout(g, opts) {
+ var time = opts && opts.debugTiming ? util.time : util.notime;
+ time("layout", function() {
+ var layoutGraph = time(" buildLayoutGraph",
+ function() { return buildLayoutGraph(g); });
+ time(" runLayout", function() { runLayout(layoutGraph, time); });
+ time(" updateInputGraph", function() { updateInputGraph(g, layoutGraph); });
+ });
+}
+
+function runLayout(g, time) {
+ time(" makeSpaceForEdgeLabels", function() { makeSpaceForEdgeLabels(g); });
+ time(" removeSelfEdges", function() { removeSelfEdges(g); });
+ time(" acyclic", function() { acyclic.run(g); });
+ time(" nestingGraph.run", function() { nestingGraph.run(g); });
+ time(" rank", function() { rank(util.asNonCompoundGraph(g)); });
+ time(" injectEdgeLabelProxies", function() { injectEdgeLabelProxies(g); });
+ time(" removeEmptyRanks", function() { removeEmptyRanks(g); });
+ time(" nestingGraph.cleanup", function() { nestingGraph.cleanup(g); });
+ time(" normalizeRanks", function() { normalizeRanks(g); });
+ time(" assignRankMinMax", function() { assignRankMinMax(g); });
+ time(" removeEdgeLabelProxies", function() { removeEdgeLabelProxies(g); });
+ time(" normalize.run", function() { normalize.run(g); });
+ time(" parentDummyChains", function() { parentDummyChains(g); });
+ time(" addBorderSegments", function() { addBorderSegments(g); });
+ time(" order", function() { order(g); });
+ time(" insertSelfEdges", function() { insertSelfEdges(g); });
+ time(" adjustCoordinateSystem", function() { coordinateSystem.adjust(g); });
+ time(" position", function() { position(g); });
+ time(" positionSelfEdges", function() { positionSelfEdges(g); });
+ time(" removeBorderNodes", function() { removeBorderNodes(g); });
+ time(" normalize.undo", function() { normalize.undo(g); });
+ time(" fixupEdgeLabelCoords", function() { fixupEdgeLabelCoords(g); });
+ time(" undoCoordinateSystem", function() { coordinateSystem.undo(g); });
+ time(" translateGraph", function() { translateGraph(g); });
+ time(" assignNodeIntersects", function() { assignNodeIntersects(g); });
+ time(" reversePoints", function() { reversePointsForReversedEdges(g); });
+ time(" acyclic.undo", function() { acyclic.undo(g); });
+}
+
+/*
+ * Copies final layout information from the layout graph back to the input
+ * graph. This process only copies whitelisted attributes from the layout graph
+ * to the input graph, so it serves as a good place to determine what
+ * attributes can influence layout.
+ */
+function updateInputGraph(inputGraph, layoutGraph) {
+ _.each(inputGraph.nodes(), function(v) {
+ var inputLabel = inputGraph.node(v),
+ layoutLabel = layoutGraph.node(v);
+
+ if (inputLabel) {
+ inputLabel.x = layoutLabel.x;
+ inputLabel.y = layoutLabel.y;
+
+ if (layoutGraph.children(v).length) {
+ inputLabel.width = layoutLabel.width;
+ inputLabel.height = layoutLabel.height;
+ }
+ }
+ });
+
+ _.each(inputGraph.edges(), function(e) {
+ var inputLabel = inputGraph.edge(e),
+ layoutLabel = layoutGraph.edge(e);
+
+ inputLabel.points = layoutLabel.points;
+ if (_.has(layoutLabel, "x")) {
+ inputLabel.x = layoutLabel.x;
+ inputLabel.y = layoutLabel.y;
+ }
+ });
+
+ inputGraph.graph().width = layoutGraph.graph().width;
+ inputGraph.graph().height = layoutGraph.graph().height;
+}
+
+var graphNumAttrs = ["nodesep", "edgesep", "ranksep", "marginx", "marginy"],
+ graphDefaults = { ranksep: 50, edgesep: 20, nodesep: 50, rankdir: "tb" },
+ graphAttrs = ["acyclicer", "ranker", "rankdir", "align"],
+ nodeNumAttrs = ["width", "height"],
+ nodeDefaults = { width: 0, height: 0 },
+ edgeNumAttrs = ["minlen", "weight", "width", "height", "labeloffset"],
+ edgeDefaults = {
+ minlen: 1, weight: 1, width: 0, height: 0,
+ labeloffset: 10, labelpos: "r"
+ },
+ edgeAttrs = ["labelpos"];
+
+/*
+ * Constructs a new graph from the input graph, which can be used for layout.
+ * This process copies only whitelisted attributes from the input graph to the
+ * layout graph. Thus this function serves as a good place to determine what
+ * attributes can influence layout.
+ */
+function buildLayoutGraph(inputGraph) {
+ var g = new Graph({ multigraph: true, compound: true }),
+ graph = canonicalize(inputGraph.graph());
+
+ g.setGraph(_.merge({},
+ graphDefaults,
+ selectNumberAttrs(graph, graphNumAttrs),
+ _.pick(graph, graphAttrs)));
+
+ _.each(inputGraph.nodes(), function(v) {
+ var node = canonicalize(inputGraph.node(v));
+ g.setNode(v, _.defaults(selectNumberAttrs(node, nodeNumAttrs), nodeDefaults));
+ g.setParent(v, inputGraph.parent(v));
+ });
+
+ _.each(inputGraph.edges(), function(e) {
+ var edge = canonicalize(inputGraph.edge(e));
+ g.setEdge(e, _.merge({},
+ edgeDefaults,
+ selectNumberAttrs(edge, edgeNumAttrs),
+ _.pick(edge, edgeAttrs)));
+ });
+
+ return g;
+}
+
+/*
+ * This idea comes from the Gansner paper: to account for edge labels in our
+ * layout we split each rank in half by doubling minlen and halving ranksep.
+ * Then we can place labels at these mid-points between nodes.
+ *
+ * We also add some minimal padding to the width to push the label for the edge
+ * away from the edge itself a bit.
+ */
+function makeSpaceForEdgeLabels(g) {
+ var graph = g.graph();
+ graph.ranksep /= 2;
+ _.each(g.edges(), function(e) {
+ var edge = g.edge(e);
+ edge.minlen *= 2;
+ if (edge.labelpos.toLowerCase() !== "c") {
+ if (graph.rankdir === "TB" || graph.rankdir === "BT") {
+ edge.width += edge.labeloffset;
+ } else {
+ edge.height += edge.labeloffset;
+ }
+ }
+ });
+}
+
+/*
+ * Creates temporary dummy nodes that capture the rank in which each edge's
+ * label is going to, if it has one of non-zero width and height. We do this
+ * so that we can safely remove empty ranks while preserving balance for the
+ * label's position.
+ */
+function injectEdgeLabelProxies(g) {
+ _.each(g.edges(), function(e) {
+ var edge = g.edge(e);
+ if (edge.width && edge.height) {
+ var v = g.node(e.v),
+ w = g.node(e.w),
+ label = { rank: (w.rank - v.rank) / 2 + v.rank, e: e };
+ util.addDummyNode(g, "edge-proxy", label, "_ep");
+ }
+ });
+}
+
+function assignRankMinMax(g) {
+ var maxRank = 0;
+ _.each(g.nodes(), function(v) {
+ var node = g.node(v);
+ if (node.borderTop) {
+ node.minRank = g.node(node.borderTop).rank;
+ node.maxRank = g.node(node.borderBottom).rank;
+ maxRank = _.max(maxRank, node.maxRank);
+ }
+ });
+ g.graph().maxRank = maxRank;
+}
+
+function removeEdgeLabelProxies(g) {
+ _.each(g.nodes(), function(v) {
+ var node = g.node(v);
+ if (node.dummy === "edge-proxy") {
+ g.edge(node.e).labelRank = node.rank;
+ g.removeNode(v);
+ }
+ });
+}
+
+function translateGraph(g) {
+ var minX = Number.POSITIVE_INFINITY,
+ maxX = 0,
+ minY = Number.POSITIVE_INFINITY,
+ maxY = 0,
+ graphLabel = g.graph(),
+ marginX = graphLabel.marginx || 0,
+ marginY = graphLabel.marginy || 0;
+
+ function getExtremes(attrs) {
+ var x = attrs.x,
+ y = attrs.y,
+ w = attrs.width,
+ h = attrs.height;
+ minX = Math.min(minX, x - w / 2);
+ maxX = Math.max(maxX, x + w / 2);
+ minY = Math.min(minY, y - h / 2);
+ maxY = Math.max(maxY, y + h / 2);
+ }
+
+ _.each(g.nodes(), function(v) { getExtremes(g.node(v)); });
+ _.each(g.edges(), function(e) {
+ var edge = g.edge(e);
+ if (_.has(edge, "x")) {
+ getExtremes(edge);
+ }
+ });
+
+ minX -= marginX;
+ minY -= marginY;
+
+ _.each(g.nodes(), function(v) {
+ var node = g.node(v);
+ node.x -= minX;
+ node.y -= minY;
+ });
+
+ _.each(g.edges(), function(e) {
+ var edge = g.edge(e);
+ _.each(edge.points, function(p) {
+ p.x -= minX;
+ p.y -= minY;
+ });
+ if (_.has(edge, "x")) { edge.x -= minX; }
+ if (_.has(edge, "y")) { edge.y -= minY; }
+ });
+
+ graphLabel.width = maxX - minX + marginX;
+ graphLabel.height = maxY - minY + marginY;
+}
+
+function assignNodeIntersects(g) {
+ _.each(g.edges(), function(e) {
+ var edge = g.edge(e),
+ nodeV = g.node(e.v),
+ nodeW = g.node(e.w),
+ p1, p2;
+ if (!edge.points) {
+ edge.points = [];
+ p1 = nodeW;
+ p2 = nodeV;
+ } else {
+ p1 = edge.points[0];
+ p2 = edge.points[edge.points.length - 1];
+ }
+ edge.points.unshift(util.intersectRect(nodeV, p1));
+ edge.points.push(util.intersectRect(nodeW, p2));
+ });
+}
+
+function fixupEdgeLabelCoords(g) {
+ _.each(g.edges(), function(e) {
+ var edge = g.edge(e);
+ if (_.has(edge, "x")) {
+ if (edge.labelpos === "l" || edge.labelpos === "r") {
+ edge.width -= edge.labeloffset;
+ }
+ switch (edge.labelpos) {
+ case "l": edge.x -= edge.width / 2 + edge.labeloffset; break;
+ case "r": edge.x += edge.width / 2 + edge.labeloffset; break;
+ }
+ }
+ });
+}
+
+function reversePointsForReversedEdges(g) {
+ _.each(g.edges(), function(e) {
+ var edge = g.edge(e);
+ if (edge.reversed) {
+ edge.points.reverse();
+ }
+ });
+}
+
+function removeBorderNodes(g) {
+ _.each(g.nodes(), function(v) {
+ if (g.children(v).length) {
+ var node = g.node(v),
+ t = g.node(node.borderTop),
+ b = g.node(node.borderBottom),
+ l = g.node(_.last(node.borderLeft)),
+ r = g.node(_.last(node.borderRight));
+
+ node.width = Math.abs(r.x - l.x);
+ node.height = Math.abs(b.y - t.y);
+ node.x = l.x + node.width / 2;
+ node.y = t.y + node.height / 2;
+ }
+ });
+
+ _.each(g.nodes(), function(v) {
+ if (g.node(v).dummy === "border") {
+ g.removeNode(v);
+ }
+ });
+}
+
+function removeSelfEdges(g) {
+ _.each(g.edges(), function(e) {
+ if (e.v === e.w) {
+ var node = g.node(e.v);
+ if (!node.selfEdges) {
+ node.selfEdges = [];
+ }
+ node.selfEdges.push({ e: e, label: g.edge(e) });
+ g.removeEdge(e);
+ }
+ });
+}
+
+function insertSelfEdges(g) {
+ var layers = util.buildLayerMatrix(g);
+ _.each(layers, function(layer) {
+ var orderShift = 0;
+ _.each(layer, function(v, i) {
+ var node = g.node(v);
+ node.order = i + orderShift;
+ _.each(node.selfEdges, function(selfEdge) {
+ util.addDummyNode(g, "selfedge", {
+ width: selfEdge.label.width,
+ height: selfEdge.label.height,
+ rank: node.rank,
+ order: i + (++orderShift),
+ e: selfEdge.e,
+ label: selfEdge.label
+ }, "_se");
+ });
+ delete node.selfEdges;
+ });
+ });
+}
+
+function positionSelfEdges(g) {
+ _.each(g.nodes(), function(v) {
+ var node = g.node(v);
+ if (node.dummy === "selfedge") {
+ var selfNode = g.node(node.e.v),
+ x = selfNode.x + selfNode.width / 2,
+ y = selfNode.y,
+ dx = node.x - x,
+ dy = selfNode.height / 2;
+ g.setEdge(node.e, node.label);
+ g.removeNode(v);
+ node.label.points = [
+ { x: x + 2 * dx / 3, y: y - dy },
+ { x: x + 5 * dx / 6, y: y - dy },
+ { x: x + dx , y: y },
+ { x: x + 5 * dx / 6, y: y + dy },
+ { x: x + 2 * dx / 3, y: y + dy },
+ ];
+ node.label.x = node.x;
+ node.label.y = node.y;
+ }
+ });
+}
+
+function selectNumberAttrs(obj, attrs) {
+ return _.mapValues(_.pick(obj, attrs), Number);
+}
+
+function canonicalize(attrs) {
+ var newAttrs = {};
+ _.each(attrs, function(v, k) {
+ newAttrs[k.toLowerCase()] = v;
+ });
+ return newAttrs;
+}
+
+},{"./acyclic":2,"./add-border-segments":3,"./coordinate-system":4,"./graphlib":7,"./lodash":10,"./nesting-graph":11,"./normalize":12,"./order":17,"./parent-dummy-chains":22,"./position":24,"./rank":26,"./util":29}],10:[function(require,module,exports){
+/* global window */
+
+var lodash;
+
+if (typeof require === "function") {
+ try {
+ lodash = require("lodash");
+ } catch (e) {}
+}
+
+if (!lodash) {
+ lodash = window._;
+}
+
+module.exports = lodash;
+
+},{"lodash":51}],11:[function(require,module,exports){
+var _ = require("./lodash"),
+ util = require("./util");
+
+module.exports = {
+ run: run,
+ cleanup: cleanup
+};
+
+/*
+ * A nesting graph creates dummy nodes for the tops and bottoms of subgraphs,
+ * adds appropriate edges to ensure that all cluster nodes are placed between
+ * these boundries, and ensures that the graph is connected.
+ *
+ * In addition we ensure, through the use of the minlen property, that nodes
+ * and subgraph border nodes to not end up on the same rank.
+ *
+ * Preconditions:
+ *
+ * 1. Input graph is a DAG
+ * 2. Nodes in the input graph has a minlen attribute
+ *
+ * Postconditions:
+ *
+ * 1. Input graph is connected.
+ * 2. Dummy nodes are added for the tops and bottoms of subgraphs.
+ * 3. The minlen attribute for nodes is adjusted to ensure nodes do not
+ * get placed on the same rank as subgraph border nodes.
+ *
+ * The nesting graph idea comes from Sander, "Layout of Compound Directed
+ * Graphs."
+ */
+function run(g) {
+ var root = util.addDummyNode(g, "root", {}, "_root"),
+ depths = treeDepths(g),
+ height = _.max(depths) - 1,
+ nodeSep = 2 * height + 1;
+
+ g.graph().nestingRoot = root;
+
+ // Multiply minlen by nodeSep to align nodes on non-border ranks.
+ _.each(g.edges(), function(e) { g.edge(e).minlen *= nodeSep; });
+
+ // Calculate a weight that is sufficient to keep subgraphs vertically compact
+ var weight = sumWeights(g) + 1;
+
+ // Create border nodes and link them up
+ _.each(g.children(), function(child) {
+ dfs(g, root, nodeSep, weight, height, depths, child);
+ });
+
+ // Save the multiplier for node layers for later removal of empty border
+ // layers.
+ g.graph().nodeRankFactor = nodeSep;
+}
+
+function dfs(g, root, nodeSep, weight, height, depths, v) {
+ var children = g.children(v);
+ if (!children.length) {
+ if (v !== root) {
+ g.setEdge(root, v, { weight: 0, minlen: nodeSep });
+ }
+ return;
+ }
+
+ var top = util.addBorderNode(g, "_bt"),
+ bottom = util.addBorderNode(g, "_bb"),
+ label = g.node(v);
+
+ g.setParent(top, v);
+ label.borderTop = top;
+ g.setParent(bottom, v);
+ label.borderBottom = bottom;
+
+ _.each(children, function(child) {
+ dfs(g, root, nodeSep, weight, height, depths, child);
+
+ var childNode = g.node(child),
+ childTop = childNode.borderTop ? childNode.borderTop : child,
+ childBottom = childNode.borderBottom ? childNode.borderBottom : child,
+ thisWeight = childNode.borderTop ? weight : 2 * weight,
+ minlen = childTop !== childBottom ? 1 : height - depths[v] + 1;
+
+ g.setEdge(top, childTop, {
+ weight: thisWeight,
+ minlen: minlen,
+ nestingEdge: true
+ });
+
+ g.setEdge(childBottom, bottom, {
+ weight: thisWeight,
+ minlen: minlen,
+ nestingEdge: true
+ });
+ });
+
+ if (!g.parent(v)) {
+ g.setEdge(root, top, { weight: 0, minlen: height + depths[v] });
+ }
+}
+
+function treeDepths(g) {
+ var depths = {};
+ function dfs(v, depth) {
+ var children = g.children(v);
+ if (children && children.length) {
+ _.each(children, function(child) {
+ dfs(child, depth + 1);
+ });
+ }
+ depths[v] = depth;
+ }
+ _.each(g.children(), function(v) { dfs(v, 1); });
+ return depths;
+}
+
+function sumWeights(g) {
+ return _.reduce(g.edges(), function(acc, e) {
+ return acc + g.edge(e).weight;
+ }, 0);
+}
+
+function cleanup(g) {
+ var graphLabel = g.graph();
+ g.removeNode(graphLabel.nestingRoot);
+ delete graphLabel.nestingRoot;
+ _.each(g.edges(), function(e) {
+ var edge = g.edge(e);
+ if (edge.nestingEdge) {
+ g.removeEdge(e);
+ }
+ });
+}
+
+},{"./lodash":10,"./util":29}],12:[function(require,module,exports){
+"use strict";
+
+var _ = require("./lodash"),
+ util = require("./util");
+
+module.exports = {
+ run: run,
+ undo: undo
+};
+
+/*
+ * Breaks any long edges in the graph into short segments that span 1 layer
+ * each. This operation is undoable with the denormalize function.
+ *
+ * Pre-conditions:
+ *
+ * 1. The input graph is a DAG.
+ * 2. Each node in the graph has a "rank" property.
+ *
+ * Post-condition:
+ *
+ * 1. All edges in the graph have a length of 1.
+ * 2. Dummy nodes are added where edges have been split into segments.
+ * 3. The graph is augmented with a "dummyChains" attribute which contains
+ * the first dummy in each chain of dummy nodes produced.
+ */
+function run(g) {
+ g.graph().dummyChains = [];
+ _.each(g.edges(), function(edge) { normalizeEdge(g, edge); });
+}
+
+function normalizeEdge(g, e) {
+ var v = e.v,
+ vRank = g.node(v).rank,
+ w = e.w,
+ wRank = g.node(w).rank,
+ name = e.name,
+ edgeLabel = g.edge(e),
+ labelRank = edgeLabel.labelRank;
+
+ if (wRank === vRank + 1) return;
+
+ g.removeEdge(e);
+
+ var dummy, attrs, i;
+ for (i = 0, ++vRank; vRank < wRank; ++i, ++vRank) {
+ edgeLabel.points = [];
+ attrs = {
+ width: 0, height: 0,
+ edgeLabel: edgeLabel, edgeObj: e,
+ rank: vRank
+ };
+ dummy = util.addDummyNode(g, "edge", attrs, "_d");
+ if (vRank === labelRank) {
+ attrs.width = edgeLabel.width;
+ attrs.height = edgeLabel.height;
+ attrs.dummy = "edge-label";
+ attrs.labelpos = edgeLabel.labelpos;
+ }
+ g.setEdge(v, dummy, { weight: edgeLabel.weight }, name);
+ if (i === 0) {
+ g.graph().dummyChains.push(dummy);
+ }
+ v = dummy;
+ }
+
+ g.setEdge(v, w, { weight: edgeLabel.weight }, name);
+}
+
+function undo(g) {
+ _.each(g.graph().dummyChains, function(v) {
+ var node = g.node(v),
+ origLabel = node.edgeLabel,
+ w;
+ g.setEdge(node.edgeObj, origLabel);
+ while (node.dummy) {
+ w = g.successors(v)[0];
+ g.removeNode(v);
+ origLabel.points.push({ x: node.x, y: node.y });
+ if (node.dummy === "edge-label") {
+ origLabel.x = node.x;
+ origLabel.y = node.y;
+ origLabel.width = node.width;
+ origLabel.height = node.height;
+ }
+ v = w;
+ node = g.node(v);
+ }
+ });
+}
+
+},{"./lodash":10,"./util":29}],13:[function(require,module,exports){
+var _ = require("../lodash");
+
+module.exports = addSubgraphConstraints;
+
+function addSubgraphConstraints(g, cg, vs) {
+ var prev = {},
+ rootPrev;
+
+ _.each(vs, function(v) {
+ var child = g.parent(v),
+ parent,
+ prevChild;
+ while (child) {
+ parent = g.parent(child);
+ if (parent) {
+ prevChild = prev[parent];
+ prev[parent] = child;
+ } else {
+ prevChild = rootPrev;
+ rootPrev = child;
+ }
+ if (prevChild && prevChild !== child) {
+ cg.setEdge(prevChild, child);
+ return;
+ }
+ child = parent;
+ }
+ });
+
+ /*
+ function dfs(v) {
+ var children = v ? g.children(v) : g.children();
+ if (children.length) {
+ var min = Number.POSITIVE_INFINITY,
+ subgraphs = [];
+ _.each(children, function(child) {
+ var childMin = dfs(child);
+ if (g.children(child).length) {
+ subgraphs.push({ v: child, order: childMin });
+ }
+ min = Math.min(min, childMin);
+ });
+ _.reduce(_.sortBy(subgraphs, "order"), function(prev, curr) {
+ cg.setEdge(prev.v, curr.v);
+ return curr;
+ });
+ return min;
+ }
+ return g.node(v).order;
+ }
+ dfs(undefined);
+ */
+}
+
+},{"../lodash":10}],14:[function(require,module,exports){
+var _ = require("../lodash");
+
+module.exports = barycenter;
+
+function barycenter(g, movable) {
+ return _.map(movable, function(v) {
+ var inV = g.inEdges(v);
+ if (!inV.length) {
+ return { v: v };
+ } else {
+ var result = _.reduce(inV, function(acc, e) {
+ var edge = g.edge(e),
+ nodeU = g.node(e.v);
+ return {
+ sum: acc.sum + (edge.weight * nodeU.order),
+ weight: acc.weight + edge.weight
+ };
+ }, { sum: 0, weight: 0 });
+
+ return {
+ v: v,
+ barycenter: result.sum / result.weight,
+ weight: result.weight
+ };
+ }
+ });
+}
+
+
+},{"../lodash":10}],15:[function(require,module,exports){
+var _ = require("../lodash"),
+ Graph = require("../graphlib").Graph;
+
+module.exports = buildLayerGraph;
+
+/*
+ * Constructs a graph that can be used to sort a layer of nodes. The graph will
+ * contain all base and subgraph nodes from the request layer in their original
+ * hierarchy and any edges that are incident on these nodes and are of the type
+ * requested by the "relationship" parameter.
+ *
+ * Nodes from the requested rank that do not have parents are assigned a root
+ * node in the output graph, which is set in the root graph attribute. This
+ * makes it easy to walk the hierarchy of movable nodes during ordering.
+ *
+ * Pre-conditions:
+ *
+ * 1. Input graph is a DAG
+ * 2. Base nodes in the input graph have a rank attribute
+ * 3. Subgraph nodes in the input graph has minRank and maxRank attributes
+ * 4. Edges have an assigned weight
+ *
+ * Post-conditions:
+ *
+ * 1. Output graph has all nodes in the movable rank with preserved
+ * hierarchy.
+ * 2. Root nodes in the movable layer are made children of the node
+ * indicated by the root attribute of the graph.
+ * 3. Non-movable nodes incident on movable nodes, selected by the
+ * relationship parameter, are included in the graph (without hierarchy).
+ * 4. Edges incident on movable nodes, selected by the relationship
+ * parameter, are added to the output graph.
+ * 5. The weights for copied edges are aggregated as need, since the output
+ * graph is not a multi-graph.
+ */
+function buildLayerGraph(g, rank, relationship) {
+ var root = createRootNode(g),
+ result = new Graph({ compound: true }).setGraph({ root: root })
+ .setDefaultNodeLabel(function(v) { return g.node(v); });
+
+ _.each(g.nodes(), function(v) {
+ var node = g.node(v),
+ parent = g.parent(v);
+
+ if (node.rank === rank || node.minRank <= rank && rank <= node.maxRank) {
+ result.setNode(v);
+ result.setParent(v, parent || root);
+
+ // This assumes we have only short edges!
+ _.each(g[relationship](v), function(e) {
+ var u = e.v === v ? e.w : e.v,
+ edge = result.edge(u, v),
+ weight = !_.isUndefined(edge) ? edge.weight : 0;
+ result.setEdge(u, v, { weight: g.edge(e).weight + weight });
+ });
+
+ if (_.has(node, "minRank")) {
+ result.setNode(v, {
+ borderLeft: node.borderLeft[rank],
+ borderRight: node.borderRight[rank]
+ });
+ }
+ }
+ });
+
+ return result;
+}
+
+function createRootNode(g) {
+ var v;
+ while (g.hasNode((v = _.uniqueId("_root"))));
+ return v;
+}
+
+},{"../graphlib":7,"../lodash":10}],16:[function(require,module,exports){
+"use strict";
+
+var _ = require("../lodash");
+
+module.exports = crossCount;
+
+/*
+ * A function that takes a layering (an array of layers, each with an array of
+ * ordererd nodes) and a graph and returns a weighted crossing count.
+ *
+ * Pre-conditions:
+ *
+ * 1. Input graph must be simple (not a multigraph), directed, and include
+ * only simple edges.
+ * 2. Edges in the input graph must have assigned weights.
+ *
+ * Post-conditions:
+ *
+ * 1. The graph and layering matrix are left unchanged.
+ *
+ * This algorithm is derived from Barth, et al., "Bilayer Cross Counting."
+ */
+function crossCount(g, layering) {
+ var cc = 0;
+ for (var i = 1; i < layering.length; ++i) {
+ cc += twoLayerCrossCount(g, layering[i-1], layering[i]);
+ }
+ return cc;
+}
+
+function twoLayerCrossCount(g, northLayer, southLayer) {
+ // Sort all of the edges between the north and south layers by their position
+ // in the north layer and then the south. Map these edges to the position of
+ // their head in the south layer.
+ var southPos = _.zipObject(southLayer,
+ _.map(southLayer, function (v, i) { return i; }));
+ var southEntries = _.flatten(_.map(northLayer, function(v) {
+ return _.chain(g.outEdges(v))
+ .map(function(e) {
+ return { pos: southPos[e.w], weight: g.edge(e).weight };
+ })
+ .sortBy("pos")
+ .value();
+ }), true);
+
+ // Build the accumulator tree
+ var firstIndex = 1;
+ while (firstIndex < southLayer.length) firstIndex <<= 1;
+ var treeSize = 2 * firstIndex - 1;
+ firstIndex -= 1;
+ var tree = _.map(new Array(treeSize), function() { return 0; });
+
+ // Calculate the weighted crossings
+ var cc = 0;
+ _.each(southEntries.forEach(function(entry) {
+ var index = entry.pos + firstIndex;
+ tree[index] += entry.weight;
+ var weightSum = 0;
+ while (index > 0) {
+ if (index % 2) {
+ weightSum += tree[index + 1];
+ }
+ index = (index - 1) >> 1;
+ tree[index] += entry.weight;
+ }
+ cc += entry.weight * weightSum;
+ }));
+
+ return cc;
+}
+
+},{"../lodash":10}],17:[function(require,module,exports){
+"use strict";
+
+var _ = require("../lodash"),
+ initOrder = require("./init-order"),
+ crossCount = require("./cross-count"),
+ sortSubgraph = require("./sort-subgraph"),
+ buildLayerGraph = require("./build-layer-graph"),
+ addSubgraphConstraints = require("./add-subgraph-constraints"),
+ Graph = require("../graphlib").Graph,
+ util = require("../util");
+
+module.exports = order;
+
+/*
+ * Applies heuristics to minimize edge crossings in the graph and sets the best
+ * order solution as an order attribute on each node.
+ *
+ * Pre-conditions:
+ *
+ * 1. Graph must be DAG
+ * 2. Graph nodes must be objects with a "rank" attribute
+ * 3. Graph edges must have the "weight" attribute
+ *
+ * Post-conditions:
+ *
+ * 1. Graph nodes will have an "order" attribute based on the results of the
+ * algorithm.
+ */
+function order(g) {
+ var maxRank = util.maxRank(g),
+ downLayerGraphs = buildLayerGraphs(g, _.range(1, maxRank + 1), "inEdges"),
+ upLayerGraphs = buildLayerGraphs(g, _.range(maxRank - 1, -1, -1), "outEdges");
+
+ var layering = initOrder(g);
+ assignOrder(g, layering);
+
+ var bestCC = Number.POSITIVE_INFINITY,
+ best;
+
+ for (var i = 0, lastBest = 0; lastBest < 4; ++i, ++lastBest) {
+ sweepLayerGraphs(i % 2 ? downLayerGraphs : upLayerGraphs, i % 4 >= 2);
+
+ layering = util.buildLayerMatrix(g);
+ var cc = crossCount(g, layering);
+ if (cc < bestCC) {
+ lastBest = 0;
+ best = _.cloneDeep(layering);
+ bestCC = cc;
+ }
+ }
+
+ assignOrder(g, best);
+}
+
+function buildLayerGraphs(g, ranks, relationship) {
+ return _.map(ranks, function(rank) {
+ return buildLayerGraph(g, rank, relationship);
+ });
+}
+
+function sweepLayerGraphs(layerGraphs, biasRight) {
+ var cg = new Graph();
+ _.each(layerGraphs, function(lg) {
+ var root = lg.graph().root;
+ var sorted = sortSubgraph(lg, root, cg, biasRight);
+ _.each(sorted.vs, function(v, i) {
+ lg.node(v).order = i;
+ });
+ addSubgraphConstraints(lg, cg, sorted.vs);
+ });
+}
+
+function assignOrder(g, layering) {
+ _.each(layering, function(layer) {
+ _.each(layer, function(v, i) {
+ g.node(v).order = i;
+ });
+ });
+}
+
+},{"../graphlib":7,"../lodash":10,"../util":29,"./add-subgraph-constraints":13,"./build-layer-graph":15,"./cross-count":16,"./init-order":18,"./sort-subgraph":20}],18:[function(require,module,exports){
+"use strict";
+
+var _ = require("../lodash");
+
+module.exports = initOrder;
+
+/*
+ * Assigns an initial order value for each node by performing a DFS search
+ * starting from nodes in the first rank. Nodes are assigned an order in their
+ * rank as they are first visited.
+ *
+ * This approach comes from Gansner, et al., "A Technique for Drawing Directed
+ * Graphs."
+ *
+ * Returns a layering matrix with an array per layer and each layer sorted by
+ * the order of its nodes.
+ */
+function initOrder(g) {
+ var visited = {},
+ simpleNodes = _.filter(g.nodes(), function(v) {
+ return !g.children(v).length;
+ }),
+ maxRank = _.max(_.map(simpleNodes, function(v) { return g.node(v).rank; })),
+ layers = _.map(_.range(maxRank + 1), function() { return []; });
+
+ function dfs(v) {
+ if (_.has(visited, v)) return;
+ visited[v] = true;
+ var node = g.node(v);
+ layers[node.rank].push(v);
+ _.each(g.successors(v), dfs);
+ }
+
+ var orderedVs = _.sortBy(simpleNodes, function(v) { return g.node(v).rank; });
+ _.each(orderedVs, dfs);
+
+ return layers;
+}
+
+},{"../lodash":10}],19:[function(require,module,exports){
+"use strict";
+
+var _ = require("../lodash");
+
+module.exports = resolveConflicts;
+
+/*
+ * Given a list of entries of the form {v, barycenter, weight} and a
+ * constraint graph this function will resolve any conflicts between the
+ * constraint graph and the barycenters for the entries. If the barycenters for
+ * an entry would violate a constraint in the constraint graph then we coalesce
+ * the nodes in the conflict into a new node that respects the contraint and
+ * aggregates barycenter and weight information.
+ *
+ * This implementation is based on the description in Forster, "A Fast and
+ * Simple Hueristic for Constrained Two-Level Crossing Reduction," thought it
+ * differs in some specific details.
+ *
+ * Pre-conditions:
+ *
+ * 1. Each entry has the form {v, barycenter, weight}, or if the node has
+ * no barycenter, then {v}.
+ *
+ * Returns:
+ *
+ * A new list of entries of the form {vs, i, barycenter, weight}. The list
+ * `vs` may either be a singleton or it may be an aggregation of nodes
+ * ordered such that they do not violate constraints from the constraint
+ * graph. The property `i` is the lowest original index of any of the
+ * elements in `vs`.
+ */
+function resolveConflicts(entries, cg) {
+ var mappedEntries = {};
+ _.each(entries, function(entry, i) {
+ var tmp = mappedEntries[entry.v] = {
+ indegree: 0,
+ "in": [],
+ out: [],
+ vs: [entry.v],
+ i: i
+ };
+ if (!_.isUndefined(entry.barycenter)) {
+ tmp.barycenter = entry.barycenter;
+ tmp.weight = entry.weight;
+ }
+ });
+
+ _.each(cg.edges(), function(e) {
+ var entryV = mappedEntries[e.v],
+ entryW = mappedEntries[e.w];
+ if (!_.isUndefined(entryV) && !_.isUndefined(entryW)) {
+ entryW.indegree++;
+ entryV.out.push(mappedEntries[e.w]);
+ }
+ });
+
+ var sourceSet = _.filter(mappedEntries, function(entry) {
+ return !entry.indegree;
+ });
+
+ return doResolveConflicts(sourceSet);
+}
+
+function doResolveConflicts(sourceSet) {
+ var entries = [];
+
+ function handleIn(vEntry) {
+ return function(uEntry) {
+ if (uEntry.merged) {
+ return;
+ }
+ if (_.isUndefined(uEntry.barycenter) ||
+ _.isUndefined(vEntry.barycenter) ||
+ uEntry.barycenter >= vEntry.barycenter) {
+ mergeEntries(vEntry, uEntry);
+ }
+ };
+ }
+
+ function handleOut(vEntry) {
+ return function(wEntry) {
+ wEntry["in"].push(vEntry);
+ if (--wEntry.indegree === 0) {
+ sourceSet.push(wEntry);
+ }
+ };
+ }
+
+ while (sourceSet.length) {
+ var entry = sourceSet.pop();
+ entries.push(entry);
+ _.each(entry["in"].reverse(), handleIn(entry));
+ _.each(entry.out, handleOut(entry));
+ }
+
+ return _.chain(entries)
+ .filter(function(entry) { return !entry.merged; })
+ .map(function(entry) {
+ return _.pick(entry, ["vs", "i", "barycenter", "weight"]);
+ })
+ .value();
+}
+
+function mergeEntries(target, source) {
+ var sum = 0,
+ weight = 0;
+
+ if (target.weight) {
+ sum += target.barycenter * target.weight;
+ weight += target.weight;
+ }
+
+ if (source.weight) {
+ sum += source.barycenter * source.weight;
+ weight += source.weight;
+ }
+
+ target.vs = source.vs.concat(target.vs);
+ target.barycenter = sum / weight;
+ target.weight = weight;
+ target.i = Math.min(source.i, target.i);
+ source.merged = true;
+}
+
+},{"../lodash":10}],20:[function(require,module,exports){
+var _ = require("../lodash"),
+ barycenter = require("./barycenter"),
+ resolveConflicts = require("./resolve-conflicts"),
+ sort = require("./sort");
+
+module.exports = sortSubgraph;
+
+function sortSubgraph(g, v, cg, biasRight) {
+ var movable = g.children(v),
+ node = g.node(v),
+ bl = node ? node.borderLeft : undefined,
+ br = node ? node.borderRight: undefined,
+ subgraphs = {};
+
+ if (bl) {
+ movable = _.filter(movable, function(w) {
+ return w !== bl && w !== br;
+ });
+ }
+
+ var barycenters = barycenter(g, movable);
+ _.each(barycenters, function(entry) {
+ if (g.children(entry.v).length) {
+ var subgraphResult = sortSubgraph(g, entry.v, cg, biasRight);
+ subgraphs[entry.v] = subgraphResult;
+ if (_.has(subgraphResult, "barycenter")) {
+ mergeBarycenters(entry, subgraphResult);
+ }
+ }
+ });
+
+ var entries = resolveConflicts(barycenters, cg);
+ expandSubgraphs(entries, subgraphs);
+
+ var result = sort(entries, biasRight);
+
+ if (bl) {
+ result.vs = _.flatten([bl, result.vs, br], true);
+ if (g.predecessors(bl).length) {
+ var blPred = g.node(g.predecessors(bl)[0]),
+ brPred = g.node(g.predecessors(br)[0]);
+ if (!_.has(result, "barycenter")) {
+ result.barycenter = 0;
+ result.weight = 0;
+ }
+ result.barycenter = (result.barycenter * result.weight +
+ blPred.order + brPred.order) / (result.weight + 2);
+ result.weight += 2;
+ }
+ }
+
+ return result;
+}
+
+function expandSubgraphs(entries, subgraphs) {
+ _.each(entries, function(entry) {
+ entry.vs = _.flatten(entry.vs.map(function(v) {
+ if (subgraphs[v]) {
+ return subgraphs[v].vs;
+ }
+ return v;
+ }), true);
+ });
+}
+
+function mergeBarycenters(target, other) {
+ if (!_.isUndefined(target.barycenter)) {
+ target.barycenter = (target.barycenter * target.weight +
+ other.barycenter * other.weight) /
+ (target.weight + other.weight);
+ target.weight += other.weight;
+ } else {
+ target.barycenter = other.barycenter;
+ target.weight = other.weight;
+ }
+}
+
+},{"../lodash":10,"./barycenter":14,"./resolve-conflicts":19,"./sort":21}],21:[function(require,module,exports){
+var _ = require("../lodash"),
+ util = require("../util");
+
+module.exports = sort;
+
+function sort(entries, biasRight) {
+ var parts = util.partition(entries, function(entry) {
+ return _.has(entry, "barycenter");
+ });
+ var sortable = parts.lhs,
+ unsortable = _.sortBy(parts.rhs, function(entry) { return -entry.i; }),
+ vs = [],
+ sum = 0,
+ weight = 0,
+ vsIndex = 0;
+
+ sortable.sort(compareWithBias(!!biasRight));
+
+ vsIndex = consumeUnsortable(vs, unsortable, vsIndex);
+
+ _.each(sortable, function (entry) {
+ vsIndex += entry.vs.length;
+ vs.push(entry.vs);
+ sum += entry.barycenter * entry.weight;
+ weight += entry.weight;
+ vsIndex = consumeUnsortable(vs, unsortable, vsIndex);
+ });
+
+ var result = { vs: _.flatten(vs, true) };
+ if (weight) {
+ result.barycenter = sum / weight;
+ result.weight = weight;
+ }
+ return result;
+}
+
+function consumeUnsortable(vs, unsortable, index) {
+ var last;
+ while (unsortable.length && (last = _.last(unsortable)).i <= index) {
+ unsortable.pop();
+ vs.push(last.vs);
+ index++;
+ }
+ return index;
+}
+
+function compareWithBias(bias) {
+ return function(entryV, entryW) {
+ if (entryV.barycenter < entryW.barycenter) {
+ return -1;
+ } else if (entryV.barycenter > entryW.barycenter) {
+ return 1;
+ }
+
+ return !bias ? entryV.i - entryW.i : entryW.i - entryV.i;
+ };
+}
+
+},{"../lodash":10,"../util":29}],22:[function(require,module,exports){
+var _ = require("./lodash");
+
+module.exports = parentDummyChains;
+
+function parentDummyChains(g) {
+ var postorderNums = postorder(g);
+
+ _.each(g.graph().dummyChains, function(v) {
+ var node = g.node(v),
+ edgeObj = node.edgeObj,
+ pathData = findPath(g, postorderNums, edgeObj.v, edgeObj.w),
+ path = pathData.path,
+ lca = pathData.lca,
+ pathIdx = 0,
+ pathV = path[pathIdx],
+ ascending = true;
+
+ while (v !== edgeObj.w) {
+ node = g.node(v);
+
+ if (ascending) {
+ while ((pathV = path[pathIdx]) !== lca &&
+ g.node(pathV).maxRank < node.rank) {
+ pathIdx++;
+ }
+
+ if (pathV === lca) {
+ ascending = false;
+ }
+ }
+
+ if (!ascending) {
+ while (pathIdx < path.length - 1 &&
+ g.node(pathV = path[pathIdx + 1]).minRank <= node.rank) {
+ pathIdx++;
+ }
+ pathV = path[pathIdx];
+ }
+
+ g.setParent(v, pathV);
+ v = g.successors(v)[0];
+ }
+ });
+}
+
+// Find a path from v to w through the lowest common ancestor (LCA). Return the
+// full path and the LCA.
+function findPath(g, postorderNums, v, w) {
+ var vPath = [],
+ wPath = [],
+ low = Math.min(postorderNums[v].low, postorderNums[w].low),
+ lim = Math.max(postorderNums[v].lim, postorderNums[w].lim),
+ parent,
+ lca;
+
+ // Traverse up from v to find the LCA
+ parent = v;
+ do {
+ parent = g.parent(parent);
+ vPath.push(parent);
+ } while (parent &&
+ (postorderNums[parent].low > low || lim > postorderNums[parent].lim));
+ lca = parent;
+
+ // Traverse from w to LCA
+ parent = w;
+ while ((parent = g.parent(parent)) !== lca) {
+ wPath.push(parent);
+ }
+
+ return { path: vPath.concat(wPath.reverse()), lca: lca };
+}
+
+function postorder(g) {
+ var result = {},
+ lim = 0;
+
+ function dfs(v) {
+ var low = lim;
+ _.each(g.children(v), dfs);
+ result[v] = { low: low, lim: lim++ };
+ }
+ _.each(g.children(), dfs);
+
+ return result;
+}
+
+},{"./lodash":10}],23:[function(require,module,exports){
+"use strict";
+
+var _ = require("../lodash"),
+ Graph = require("../graphlib").Graph,
+ util = require("../util");
+
+/*
+ * This module provides coordinate assignment based on Brandes and Köpf, "Fast
+ * and Simple Horizontal Coordinate Assignment."
+ */
+
+module.exports = {
+ positionX: positionX,
+ findType1Conflicts: findType1Conflicts,
+ findType2Conflicts: findType2Conflicts,
+ addConflict: addConflict,
+ hasConflict: hasConflict,
+ verticalAlignment: verticalAlignment,
+ horizontalCompaction: horizontalCompaction,
+ alignCoordinates: alignCoordinates,
+ findSmallestWidthAlignment: findSmallestWidthAlignment,
+ balance: balance
+};
+
+/*
+ * Marks all edges in the graph with a type-1 conflict with the "type1Conflict"
+ * property. A type-1 conflict is one where a non-inner segment crosses an
+ * inner segment. An inner segment is an edge with both incident nodes marked
+ * with the "dummy" property.
+ *
+ * This algorithm scans layer by layer, starting with the second, for type-1
+ * conflicts between the current layer and the previous layer. For each layer
+ * it scans the nodes from left to right until it reaches one that is incident
+ * on an inner segment. It then scans predecessors to determine if they have
+ * edges that cross that inner segment. At the end a final scan is done for all
+ * nodes on the current rank to see if they cross the last visited inner
+ * segment.
+ *
+ * This algorithm (safely) assumes that a dummy node will only be incident on a
+ * single node in the layers being scanned.
+ */
+function findType1Conflicts(g, layering) {
+ var conflicts = {};
+
+ function visitLayer(prevLayer, layer) {
+ var
+ // last visited node in the previous layer that is incident on an inner
+ // segment.
+ k0 = 0,
+ // Tracks the last node in this layer scanned for crossings with a type-1
+ // segment.
+ scanPos = 0,
+ prevLayerLength = prevLayer.length,
+ lastNode = _.last(layer);
+
+ _.each(layer, function(v, i) {
+ var w = findOtherInnerSegmentNode(g, v),
+ k1 = w ? g.node(w).order : prevLayerLength;
+
+ if (w || v === lastNode) {
+ _.each(layer.slice(scanPos, i +1), function(scanNode) {
+ _.each(g.predecessors(scanNode), function(u) {
+ var uLabel = g.node(u),
+ uPos = uLabel.order;
+ if ((uPos < k0 || k1 < uPos) &&
+ !(uLabel.dummy && g.node(scanNode).dummy)) {
+ addConflict(conflicts, u, scanNode);
+ }
+ });
+ });
+ scanPos = i + 1;
+ k0 = k1;
+ }
+ });
+
+ return layer;
+ }
+
+ _.reduce(layering, visitLayer);
+ return conflicts;
+}
+
+function findType2Conflicts(g, layering) {
+ var conflicts = {};
+
+ function scan(south, southPos, southEnd, prevNorthBorder, nextNorthBorder) {
+ var v;
+ _.each(_.range(southPos, southEnd), function(i) {
+ v = south[i];
+ if (g.node(v).dummy) {
+ _.each(g.predecessors(v), function(u) {
+ var uNode = g.node(u);
+ if (uNode.dummy &&
+ (uNode.order < prevNorthBorder || uNode.order > nextNorthBorder)) {
+ addConflict(conflicts, u, v);
+ }
+ });
+ }
+ });
+ }
+
+
+ function visitLayer(north, south) {
+ var prevNorthPos = -1,
+ nextNorthPos,
+ southPos = 0;
+
+ _.each(south, function(v, southLookahead) {
+ if (g.node(v).dummy === "border") {
+ var predecessors = g.predecessors(v);
+ if (predecessors.length) {
+ nextNorthPos = g.node(predecessors[0]).order;
+ scan(south, southPos, southLookahead, prevNorthPos, nextNorthPos);
+ southPos = southLookahead;
+ prevNorthPos = nextNorthPos;
+ }
+ }
+ scan(south, southPos, south.length, nextNorthPos, north.length);
+ });
+
+ return south;
+ }
+
+ _.reduce(layering, visitLayer);
+ return conflicts;
+}
+
+function findOtherInnerSegmentNode(g, v) {
+ if (g.node(v).dummy) {
+ return _.find(g.predecessors(v), function(u) {
+ return g.node(u).dummy;
+ });
+ }
+}
+
+function addConflict(conflicts, v, w) {
+ if (v > w) {
+ var tmp = v;
+ v = w;
+ w = tmp;
+ }
+
+ var conflictsV = conflicts[v];
+ if (!conflictsV) {
+ conflicts[v] = conflictsV = {};
+ }
+ conflictsV[w] = true;
+}
+
+function hasConflict(conflicts, v, w) {
+ if (v > w) {
+ var tmp = v;
+ v = w;
+ w = tmp;
+ }
+ return _.has(conflicts[v], w);
+}
+
+/*
+ * Try to align nodes into vertical "blocks" where possible. This algorithm
+ * attempts to align a node with one of its median neighbors. If the edge
+ * connecting a neighbor is a type-1 conflict then we ignore that possibility.
+ * If a previous node has already formed a block with a node after the node
+ * we're trying to form a block with, we also ignore that possibility - our
+ * blocks would be split in that scenario.
+ */
+function verticalAlignment(g, layering, conflicts, neighborFn) {
+ var root = {},
+ align = {},
+ pos = {};
+
+ // We cache the position here based on the layering because the graph and
+ // layering may be out of sync. The layering matrix is manipulated to
+ // generate different extreme alignments.
+ _.each(layering, function(layer) {
+ _.each(layer, function(v, order) {
+ root[v] = v;
+ align[v] = v;
+ pos[v] = order;
+ });
+ });
+
+ _.each(layering, function(layer) {
+ var prevIdx = -1;
+ _.each(layer, function(v) {
+ var ws = neighborFn(v);
+ if (ws.length) {
+ ws = _.sortBy(ws, function(w) { return pos[w]; });
+ var mp = (ws.length - 1) / 2;
+ for (var i = Math.floor(mp), il = Math.ceil(mp); i <= il; ++i) {
+ var w = ws[i];
+ if (align[v] === v &&
+ prevIdx < pos[w] &&
+ !hasConflict(conflicts, v, w)) {
+ align[w] = v;
+ align[v] = root[v] = root[w];
+ prevIdx = pos[w];
+ }
+ }
+ }
+ });
+ });
+
+ return { root: root, align: align };
+}
+
+function horizontalCompaction(g, layering, root, align, reverseSep) {
+ // This portion of the algorithm differs from BK due to a number of problems.
+ // Instead of their algorithm we construct a new block graph and do two
+ // sweeps. The first sweep places blocks with the smallest possible
+ // coordinates. The second sweep removes unused space by moving blocks to the
+ // greatest coordinates without violating separation.
+ var xs = {},
+ blockG = buildBlockGraph(g, layering, root, reverseSep);
+
+ // First pass, assign smallest coordinates via DFS
+ var visited = {};
+ function pass1(v) {
+ if (!_.has(visited, v)) {
+ visited[v] = true;
+ xs[v] = _.reduce(blockG.inEdges(v), function(max, e) {
+ pass1(e.v);
+ return Math.max(max, xs[e.v] + blockG.edge(e));
+ }, 0);
+ }
+ }
+ _.each(blockG.nodes(), pass1);
+
+ var borderType = reverseSep ? "borderLeft" : "borderRight";
+ function pass2(v) {
+ if (visited[v] !== 2) {
+ visited[v]++;
+ var node = g.node(v);
+ var min = _.reduce(blockG.outEdges(v), function(min, e) {
+ pass2(e.w);
+ return Math.min(min, xs[e.w] - blockG.edge(e));
+ }, Number.POSITIVE_INFINITY);
+ if (min !== Number.POSITIVE_INFINITY && node.borderType !== borderType) {
+ xs[v] = Math.max(xs[v], min);
+ }
+ }
+ }
+ _.each(blockG.nodes(), pass2);
+
+ // Assign x coordinates to all nodes
+ _.each(align, function(v) {
+ xs[v] = xs[root[v]];
+ });
+
+ return xs;
+}
+
+
+function buildBlockGraph(g, layering, root, reverseSep) {
+ var blockGraph = new Graph(),
+ graphLabel = g.graph(),
+ sepFn = sep(graphLabel.nodesep, graphLabel.edgesep, reverseSep);
+
+ _.each(layering, function(layer) {
+ var u;
+ _.each(layer, function(v) {
+ var vRoot = root[v];
+ blockGraph.setNode(vRoot);
+ if (u) {
+ var uRoot = root[u],
+ prevMax = blockGraph.edge(uRoot, vRoot);
+ blockGraph.setEdge(uRoot, vRoot, Math.max(sepFn(g, v, u), prevMax || 0));
+ }
+ u = v;
+ });
+ });
+
+ return blockGraph;
+}
+
+/*
+ * Returns the alignment that has the smallest width of the given alignments.
+ */
+function findSmallestWidthAlignment(g, xss) {
+ return _.min(xss, function(xs) {
+ var min = _.min(xs, function(x, v) { return x - width(g, v) / 2; }),
+ max = _.max(xs, function(x, v) { return x + width(g, v) / 2; });
+ return max - min;
+ });
+}
+
+/*
+ * Align the coordinates of each of the layout alignments such that
+ * left-biased alignments have their minimum coordinate at the same point as
+ * the minimum coordinate of the smallest width alignment and right-biased
+ * alignments have their maximum coordinate at the same point as the maximum
+ * coordinate of the smallest width alignment.
+ */
+function alignCoordinates(xss, alignTo) {
+ var alignToMin = _.min(alignTo),
+ alignToMax = _.max(alignTo);
+
+ _.each(["u", "d"], function(vert) {
+ _.each(["l", "r"], function(horiz) {
+ var alignment = vert + horiz,
+ xs = xss[alignment],
+ delta;
+ if (xs === alignTo) return;
+
+ delta = horiz === "l" ? alignToMin - _.min(xs) : alignToMax - _.max(xs);
+
+ if (delta) {
+ xss[alignment] = _.mapValues(xs, function(x) { return x + delta; });
+ }
+ });
+ });
+}
+
+function balance(xss, align) {
+ return _.mapValues(xss.ul, function(ignore, v) {
+ if (align) {
+ return xss[align.toLowerCase()][v];
+ } else {
+ var xs = _.sortBy(_.pluck(xss, v));
+ return (xs[1] + xs[2]) / 2;
+ }
+ });
+}
+
+function positionX(g) {
+ var layering = util.buildLayerMatrix(g),
+ conflicts = _.merge(findType1Conflicts(g, layering),
+ findType2Conflicts(g, layering));
+
+ var xss = {},
+ adjustedLayering;
+ _.each(["u", "d"], function(vert) {
+ adjustedLayering = vert === "u" ? layering : _.values(layering).reverse();
+ _.each(["l", "r"], function(horiz) {
+ if (horiz === "r") {
+ adjustedLayering = _.map(adjustedLayering, function(inner) {
+ return _.values(inner).reverse();
+ });
+ }
+
+ var neighborFn = _.bind(vert === "u" ? g.predecessors : g.successors, g);
+ var align = verticalAlignment(g, adjustedLayering, conflicts, neighborFn);
+ var xs = horizontalCompaction(g, adjustedLayering,
+ align.root, align.align,
+ horiz === "r");
+ if (horiz === "r") {
+ xs = _.mapValues(xs, function(x) { return -x; });
+ }
+ xss[vert + horiz] = xs;
+ });
+ });
+
+ var smallestWidth = findSmallestWidthAlignment(g, xss);
+ alignCoordinates(xss, smallestWidth);
+ return balance(xss, g.graph().align);
+}
+
+function sep(nodeSep, edgeSep, reverseSep) {
+ return function(g, v, w) {
+ var vLabel = g.node(v),
+ wLabel = g.node(w),
+ sum = 0,
+ delta;
+
+ sum += vLabel.width / 2;
+ if (_.has(vLabel, "labelpos")) {
+ switch (vLabel.labelpos.toLowerCase()) {
+ case "l": delta = -vLabel.width / 2; break;
+ case "r": delta = vLabel.width / 2; break;
+ }
+ }
+ if (delta) {
+ sum += reverseSep ? delta : -delta;
+ }
+ delta = 0;
+
+ sum += (vLabel.dummy ? edgeSep : nodeSep) / 2;
+ sum += (wLabel.dummy ? edgeSep : nodeSep) / 2;
+
+ sum += wLabel.width / 2;
+ if (_.has(wLabel, "labelpos")) {
+ switch (wLabel.labelpos.toLowerCase()) {
+ case "l": delta = wLabel.width / 2; break;
+ case "r": delta = -wLabel.width / 2; break;
+ }
+ }
+ if (delta) {
+ sum += reverseSep ? delta : -delta;
+ }
+ delta = 0;
+
+ return sum;
+ };
+}
+
+function width(g, v) {
+ return g.node(v).width;
+}
+
+},{"../graphlib":7,"../lodash":10,"../util":29}],24:[function(require,module,exports){
+"use strict";
+
+var _ = require("../lodash"),
+ util = require("../util"),
+ positionX = require("./bk").positionX;
+
+module.exports = position;
+
+function position(g) {
+ g = util.asNonCompoundGraph(g);
+
+ positionY(g);
+ _.each(positionX(g), function(x, v) {
+ g.node(v).x = x;
+ });
+}
+
+function positionY(g) {
+ var layering = util.buildLayerMatrix(g),
+ rankSep = g.graph().ranksep,
+ prevY = 0;
+ _.each(layering, function(layer) {
+ var maxHeight = _.max(_.map(layer, function(v) { return g.node(v).height; }));
+ _.each(layer, function(v) {
+ g.node(v).y = prevY + maxHeight / 2;
+ });
+ prevY += maxHeight + rankSep;
+ });
+}
+
+
+},{"../lodash":10,"../util":29,"./bk":23}],25:[function(require,module,exports){
+"use strict";
+
+var _ = require("../lodash"),
+ Graph = require("../graphlib").Graph,
+ slack = require("./util").slack;
+
+module.exports = feasibleTree;
+
+/*
+ * Constructs a spanning tree with tight edges and adjusted the input node's
+ * ranks to achieve this. A tight edge is one that is has a length that matches
+ * its "minlen" attribute.
+ *
+ * The basic structure for this function is derived from Gansner, et al., "A
+ * Technique for Drawing Directed Graphs."
+ *
+ * Pre-conditions:
+ *
+ * 1. Graph must be a DAG.
+ * 2. Graph must be connected.
+ * 3. Graph must have at least one node.
+ * 5. Graph nodes must have been previously assigned a "rank" property that
+ * respects the "minlen" property of incident edges.
+ * 6. Graph edges must have a "minlen" property.
+ *
+ * Post-conditions:
+ *
+ * - Graph nodes will have their rank adjusted to ensure that all edges are
+ * tight.
+ *
+ * Returns a tree (undirected graph) that is constructed using only "tight"
+ * edges.
+ */
+function feasibleTree(g) {
+ var t = new Graph({ directed: false });
+
+ // Choose arbitrary node from which to start our tree
+ var start = g.nodes()[0],
+ size = g.nodeCount();
+ t.setNode(start, {});
+
+ var edge, delta;
+ while (tightTree(t, g) < size) {
+ edge = findMinSlackEdge(t, g);
+ delta = t.hasNode(edge.v) ? slack(g, edge) : -slack(g, edge);
+ shiftRanks(t, g, delta);
+ }
+
+ return t;
+}
+
+/*
+ * Finds a maximal tree of tight edges and returns the number of nodes in the
+ * tree.
+ */
+function tightTree(t, g) {
+ function dfs(v) {
+ _.each(g.nodeEdges(v), function(e) {
+ var edgeV = e.v,
+ w = (v === edgeV) ? e.w : edgeV;
+ if (!t.hasNode(w) && !slack(g, e)) {
+ t.setNode(w, {});
+ t.setEdge(v, w, {});
+ dfs(w);
+ }
+ });
+ }
+
+ _.each(t.nodes(), dfs);
+ return t.nodeCount();
+}
+
+/*
+ * Finds the edge with the smallest slack that is incident on tree and returns
+ * it.
+ */
+function findMinSlackEdge(t, g) {
+ return _.min(g.edges(), function(e) {
+ if (t.hasNode(e.v) !== t.hasNode(e.w)) {
+ return slack(g, e);
+ }
+ });
+}
+
+function shiftRanks(t, g, delta) {
+ _.each(t.nodes(), function(v) {
+ g.node(v).rank += delta;
+ });
+}
+
+},{"../graphlib":7,"../lodash":10,"./util":28}],26:[function(require,module,exports){
+"use strict";
+
+var rankUtil = require("./util"),
+ longestPath = rankUtil.longestPath,
+ feasibleTree = require("./feasible-tree"),
+ networkSimplex = require("./network-simplex");
+
+module.exports = rank;
+
+/*
+ * Assigns a rank to each node in the input graph that respects the "minlen"
+ * constraint specified on edges between nodes.
+ *
+ * This basic structure is derived from Gansner, et al., "A Technique for
+ * Drawing Directed Graphs."
+ *
+ * Pre-conditions:
+ *
+ * 1. Graph must be a connected DAG
+ * 2. Graph nodes must be objects
+ * 3. Graph edges must have "weight" and "minlen" attributes
+ *
+ * Post-conditions:
+ *
+ * 1. Graph nodes will have a "rank" attribute based on the results of the
+ * algorithm. Ranks can start at any index (including negative), we'll
+ * fix them up later.
+ */
+function rank(g) {
+ switch(g.graph().ranker) {
+ case "network-simplex": networkSimplexRanker(g); break;
+ case "tight-tree": tightTreeRanker(g); break;
+ case "longest-path": longestPathRanker(g); break;
+ default: networkSimplexRanker(g);
+ }
+}
+
+// A fast and simple ranker, but results are far from optimal.
+var longestPathRanker = longestPath;
+
+function tightTreeRanker(g) {
+ longestPath(g);
+ feasibleTree(g);
+}
+
+function networkSimplexRanker(g) {
+ networkSimplex(g);
+}
+
+},{"./feasible-tree":25,"./network-simplex":27,"./util":28}],27:[function(require,module,exports){
+"use strict";
+
+var _ = require("../lodash"),
+ feasibleTree = require("./feasible-tree"),
+ slack = require("./util").slack,
+ initRank = require("./util").longestPath,
+ preorder = require("../graphlib").alg.preorder,
+ postorder = require("../graphlib").alg.postorder,
+ simplify = require("../util").simplify;
+
+module.exports = networkSimplex;
+
+// Expose some internals for testing purposes
+networkSimplex.initLowLimValues = initLowLimValues;
+networkSimplex.initCutValues = initCutValues;
+networkSimplex.calcCutValue = calcCutValue;
+networkSimplex.leaveEdge = leaveEdge;
+networkSimplex.enterEdge = enterEdge;
+networkSimplex.exchangeEdges = exchangeEdges;
+
+/*
+ * The network simplex algorithm assigns ranks to each node in the input graph
+ * and iteratively improves the ranking to reduce the length of edges.
+ *
+ * Preconditions:
+ *
+ * 1. The input graph must be a DAG.
+ * 2. All nodes in the graph must have an object value.
+ * 3. All edges in the graph must have "minlen" and "weight" attributes.
+ *
+ * Postconditions:
+ *
+ * 1. All nodes in the graph will have an assigned "rank" attribute that has
+ * been optimized by the network simplex algorithm. Ranks start at 0.
+ *
+ *
+ * A rough sketch of the algorithm is as follows:
+ *
+ * 1. Assign initial ranks to each node. We use the longest path algorithm,
+ * which assigns ranks to the lowest position possible. In general this
+ * leads to very wide bottom ranks and unnecessarily long edges.
+ * 2. Construct a feasible tight tree. A tight tree is one such that all
+ * edges in the tree have no slack (difference between length of edge
+ * and minlen for the edge). This by itself greatly improves the assigned
+ * rankings by shorting edges.
+ * 3. Iteratively find edges that have negative cut values. Generally a
+ * negative cut value indicates that the edge could be removed and a new
+ * tree edge could be added to produce a more compact graph.
+ *
+ * Much of the algorithms here are derived from Gansner, et al., "A Technique
+ * for Drawing Directed Graphs." The structure of the file roughly follows the
+ * structure of the overall algorithm.
+ */
+function networkSimplex(g) {
+ g = simplify(g);
+ initRank(g);
+ var t = feasibleTree(g);
+ initLowLimValues(t);
+ initCutValues(t, g);
+
+ var e, f;
+ while ((e = leaveEdge(t))) {
+ f = enterEdge(t, g, e);
+ exchangeEdges(t, g, e, f);
+ }
+}
+
+/*
+ * Initializes cut values for all edges in the tree.
+ */
+function initCutValues(t, g) {
+ var vs = postorder(t, t.nodes());
+ vs = vs.slice(0, vs.length - 1);
+ _.each(vs, function(v) {
+ assignCutValue(t, g, v);
+ });
+}
+
+function assignCutValue(t, g, child) {
+ var childLab = t.node(child),
+ parent = childLab.parent;
+ t.edge(child, parent).cutvalue = calcCutValue(t, g, child);
+}
+
+/*
+ * Given the tight tree, its graph, and a child in the graph calculate and
+ * return the cut value for the edge between the child and its parent.
+ */
+function calcCutValue(t, g, child) {
+ var childLab = t.node(child),
+ parent = childLab.parent,
+ // True if the child is on the tail end of the edge in the directed graph
+ childIsTail = true,
+ // The graph's view of the tree edge we're inspecting
+ graphEdge = g.edge(child, parent),
+ // The accumulated cut value for the edge between this node and its parent
+ cutValue = 0;
+
+ if (!graphEdge) {
+ childIsTail = false;
+ graphEdge = g.edge(parent, child);
+ }
+
+ cutValue = graphEdge.weight;
+
+ _.each(g.nodeEdges(child), function(e) {
+ var isOutEdge = e.v === child,
+ other = isOutEdge ? e.w : e.v;
+
+ if (other !== parent) {
+ var pointsToHead = isOutEdge === childIsTail,
+ otherWeight = g.edge(e).weight;
+
+ cutValue += pointsToHead ? otherWeight : -otherWeight;
+ if (isTreeEdge(t, child, other)) {
+ var otherCutValue = t.edge(child, other).cutvalue;
+ cutValue += pointsToHead ? -otherCutValue : otherCutValue;
+ }
+ }
+ });
+
+ return cutValue;
+}
+
+function initLowLimValues(tree, root) {
+ if (arguments.length < 2) {
+ root = tree.nodes()[0];
+ }
+ dfsAssignLowLim(tree, {}, 1, root);
+}
+
+function dfsAssignLowLim(tree, visited, nextLim, v, parent) {
+ var low = nextLim,
+ label = tree.node(v);
+
+ visited[v] = true;
+ _.each(tree.neighbors(v), function(w) {
+ if (!_.has(visited, w)) {
+ nextLim = dfsAssignLowLim(tree, visited, nextLim, w, v);
+ }
+ });
+
+ label.low = low;
+ label.lim = nextLim++;
+ if (parent) {
+ label.parent = parent;
+ } else {
+ // TODO should be able to remove this when we incrementally update low lim
+ delete label.parent;
+ }
+
+ return nextLim;
+}
+
+function leaveEdge(tree) {
+ return _.find(tree.edges(), function(e) {
+ return tree.edge(e).cutvalue < 0;
+ });
+}
+
+function enterEdge(t, g, edge) {
+ var v = edge.v,
+ w = edge.w;
+
+ // For the rest of this function we assume that v is the tail and w is the
+ // head, so if we don't have this edge in the graph we should flip it to
+ // match the correct orientation.
+ if (!g.hasEdge(v, w)) {
+ v = edge.w;
+ w = edge.v;
+ }
+
+ var vLabel = t.node(v),
+ wLabel = t.node(w),
+ tailLabel = vLabel,
+ flip = false;
+
+ // If the root is in the tail of the edge then we need to flip the logic that
+ // checks for the head and tail nodes in the candidates function below.
+ if (vLabel.lim > wLabel.lim) {
+ tailLabel = wLabel;
+ flip = true;
+ }
+
+ var candidates = _.filter(g.edges(), function(edge) {
+ return flip === isDescendant(t, t.node(edge.v), tailLabel) &&
+ flip !== isDescendant(t, t.node(edge.w), tailLabel);
+ });
+
+ return _.min(candidates, function(edge) { return slack(g, edge); });
+}
+
+function exchangeEdges(t, g, e, f) {
+ var v = e.v,
+ w = e.w;
+ t.removeEdge(v, w);
+ t.setEdge(f.v, f.w, {});
+ initLowLimValues(t);
+ initCutValues(t, g);
+ updateRanks(t, g);
+}
+
+function updateRanks(t, g) {
+ var root = _.find(t.nodes(), function(v) { return !g.node(v).parent; }),
+ vs = preorder(t, root);
+ vs = vs.slice(1);
+ _.each(vs, function(v) {
+ var parent = t.node(v).parent,
+ edge = g.edge(v, parent),
+ flipped = false;
+
+ if (!edge) {
+ edge = g.edge(parent, v);
+ flipped = true;
+ }
+
+ g.node(v).rank = g.node(parent).rank + (flipped ? edge.minlen : -edge.minlen);
+ });
+}
+
+/*
+ * Returns true if the edge is in the tree.
+ */
+function isTreeEdge(tree, u, v) {
+ return tree.hasEdge(u, v);
+}
+
+/*
+ * Returns true if the specified node is descendant of the root node per the
+ * assigned low and lim attributes in the tree.
+ */
+function isDescendant(tree, vLabel, rootLabel) {
+ return rootLabel.low <= vLabel.lim && vLabel.lim <= rootLabel.lim;
+}
+
+},{"../graphlib":7,"../lodash":10,"../util":29,"./feasible-tree":25,"./util":28}],28:[function(require,module,exports){
+"use strict";
+
+var _ = require("../lodash");
+
+module.exports = {
+ longestPath: longestPath,
+ slack: slack
+};
+
+/*
+ * Initializes ranks for the input graph using the longest path algorithm. This
+ * algorithm scales well and is fast in practice, it yields rather poor
+ * solutions. Nodes are pushed to the lowest layer possible, leaving the bottom
+ * ranks wide and leaving edges longer than necessary. However, due to its
+ * speed, this algorithm is good for getting an initial ranking that can be fed
+ * into other algorithms.
+ *
+ * This algorithm does not normalize layers because it will be used by other
+ * algorithms in most cases. If using this algorithm directly, be sure to
+ * run normalize at the end.
+ *
+ * Pre-conditions:
+ *
+ * 1. Input graph is a DAG.
+ * 2. Input graph node labels can be assigned properties.
+ *
+ * Post-conditions:
+ *
+ * 1. Each node will be assign an (unnormalized) "rank" property.
+ */
+function longestPath(g) {
+ var visited = {};
+
+ function dfs(v) {
+ var label = g.node(v);
+ if (_.has(visited, v)) {
+ return label.rank;
+ }
+ visited[v] = true;
+
+ var rank = _.min(_.map(g.outEdges(v), function(e) {
+ return dfs(e.w) - g.edge(e).minlen;
+ }));
+
+ if (rank === Number.POSITIVE_INFINITY) {
+ rank = 0;
+ }
+
+ return (label.rank = rank);
+ }
+
+ _.each(g.sources(), dfs);
+}
+
+/*
+ * Returns the amount of slack for the given edge. The slack is defined as the
+ * difference between the length of the edge and its minimum length.
+ */
+function slack(g, e) {
+ return g.node(e.w).rank - g.node(e.v).rank - g.edge(e).minlen;
+}
+
+},{"../lodash":10}],29:[function(require,module,exports){
+"use strict";
+
+var _ = require("./lodash"),
+ Graph = require("./graphlib").Graph;
+
+module.exports = {
+ addDummyNode: addDummyNode,
+ simplify: simplify,
+ asNonCompoundGraph: asNonCompoundGraph,
+ successorWeights: successorWeights,
+ predecessorWeights: predecessorWeights,
+ intersectRect: intersectRect,
+ buildLayerMatrix: buildLayerMatrix,
+ normalizeRanks: normalizeRanks,
+ removeEmptyRanks: removeEmptyRanks,
+ addBorderNode: addBorderNode,
+ maxRank: maxRank,
+ partition: partition,
+ time: time,
+ notime: notime
+};
+
+/*
+ * Adds a dummy node to the graph and return v.
+ */
+function addDummyNode(g, type, attrs, name) {
+ var v;
+ do {
+ v = _.uniqueId(name);
+ } while (g.hasNode(v));
+
+ attrs.dummy = type;
+ g.setNode(v, attrs);
+ return v;
+}
+
+/*
+ * Returns a new graph with only simple edges. Handles aggregation of data
+ * associated with multi-edges.
+ */
+function simplify(g) {
+ var simplified = new Graph().setGraph(g.graph());
+ _.each(g.nodes(), function(v) { simplified.setNode(v, g.node(v)); });
+ _.each(g.edges(), function(e) {
+ var simpleLabel = simplified.edge(e.v, e.w) || { weight: 0, minlen: 1 },
+ label = g.edge(e);
+ simplified.setEdge(e.v, e.w, {
+ weight: simpleLabel.weight + label.weight,
+ minlen: Math.max(simpleLabel.minlen, label.minlen)
+ });
+ });
+ return simplified;
+}
+
+function asNonCompoundGraph(g) {
+ var simplified = new Graph({ multigraph: g.isMultigraph() }).setGraph(g.graph());
+ _.each(g.nodes(), function(v) {
+ if (!g.children(v).length) {
+ simplified.setNode(v, g.node(v));
+ }
+ });
+ _.each(g.edges(), function(e) {
+ simplified.setEdge(e, g.edge(e));
+ });
+ return simplified;
+}
+
+function successorWeights(g) {
+ var weightMap = _.map(g.nodes(), function(v) {
+ var sucs = {};
+ _.each(g.outEdges(v), function(e) {
+ sucs[e.w] = (sucs[e.w] || 0) + g.edge(e).weight;
+ });
+ return sucs;
+ });
+ return _.zipObject(g.nodes(), weightMap);
+}
+
+function predecessorWeights(g) {
+ var weightMap = _.map(g.nodes(), function(v) {
+ var preds = {};
+ _.each(g.inEdges(v), function(e) {
+ preds[e.v] = (preds[e.v] || 0) + g.edge(e).weight;
+ });
+ return preds;
+ });
+ return _.zipObject(g.nodes(), weightMap);
+}
+
+/*
+ * Finds where a line starting at point ({x, y}) would intersect a rectangle
+ * ({x, y, width, height}) if it were pointing at the rectangle's center.
+ */
+function intersectRect(rect, point) {
+ var x = rect.x;
+ var y = rect.y;
+
+ // Rectangle intersection algorithm from:
+ // http://math.stackexchange.com/questions/108113/find-edge-between-two-boxes
+ var dx = point.x - x;
+ var dy = point.y - y;
+ var w = rect.width / 2;
+ var h = rect.height / 2;
+
+ if (!dx && !dy) {
+ throw new Error("Not possible to find intersection inside of the rectangle");
+ }
+
+ var sx, sy;
+ if (Math.abs(dy) * w > Math.abs(dx) * h) {
+ // Intersection is top or bottom of rect.
+ if (dy < 0) {
+ h = -h;
+ }
+ sx = h * dx / dy;
+ sy = h;
+ } else {
+ // Intersection is left or right of rect.
+ if (dx < 0) {
+ w = -w;
+ }
+ sx = w;
+ sy = w * dy / dx;
+ }
+
+ return { x: x + sx, y: y + sy };
+}
+
+/*
+ * Given a DAG with each node assigned "rank" and "order" properties, this
+ * function will produce a matrix with the ids of each node.
+ */
+function buildLayerMatrix(g) {
+ var layering = _.map(_.range(maxRank(g) + 1), function() { return []; });
+ _.each(g.nodes(), function(v) {
+ var node = g.node(v),
+ rank = node.rank;
+ if (!_.isUndefined(rank)) {
+ layering[rank][node.order] = v;
+ }
+ });
+ return layering;
+}
+
+/*
+ * Adjusts the ranks for all nodes in the graph such that all nodes v have
+ * rank(v) >= 0 and at least one node w has rank(w) = 0.
+ */
+function normalizeRanks(g) {
+ var min = _.min(_.map(g.nodes(), function(v) { return g.node(v).rank; }));
+ _.each(g.nodes(), function(v) {
+ var node = g.node(v);
+ if (_.has(node, "rank")) {
+ node.rank -= min;
+ }
+ });
+}
+
+function removeEmptyRanks(g) {
+ // Ranks may not start at 0, so we need to offset them
+ var offset = _.min(_.map(g.nodes(), function(v) { return g.node(v).rank; }));
+
+ var layers = [];
+ _.each(g.nodes(), function(v) {
+ var rank = g.node(v).rank - offset;
+ if (!layers[rank]) {
+ layers[rank] = [];
+ }
+ layers[rank].push(v);
+ });
+
+ var delta = 0,
+ nodeRankFactor = g.graph().nodeRankFactor;
+ _.each(layers, function(vs, i) {
+ if (_.isUndefined(vs) && i % nodeRankFactor !== 0) {
+ --delta;
+ } else if (delta) {
+ _.each(vs, function(v) { g.node(v).rank += delta; });
+ }
+ });
+}
+
+function addBorderNode(g, prefix, rank, order) {
+ var node = {
+ width: 0,
+ height: 0
+ };
+ if (arguments.length >= 4) {
+ node.rank = rank;
+ node.order = order;
+ }
+ return addDummyNode(g, "border", node, prefix);
+}
+
+function maxRank(g) {
+ return _.max(_.map(g.nodes(), function(v) {
+ var rank = g.node(v).rank;
+ if (!_.isUndefined(rank)) {
+ return rank;
+ }
+ }));
+}
+
+/*
+ * Partition a collection into two groups: `lhs` and `rhs`. If the supplied
+ * function returns true for an entry it goes into `lhs`. Otherwise it goes
+ * into `rhs.
+ */
+function partition(collection, fn) {
+ var result = { lhs: [], rhs: [] };
+ _.each(collection, function(value) {
+ if (fn(value)) {
+ result.lhs.push(value);
+ } else {
+ result.rhs.push(value);
+ }
+ });
+ return result;
+}
+
+/*
+ * Returns a new function that wraps `fn` with a timer. The wrapper logs the
+ * time it takes to execute the function.
+ */
+function time(name, fn) {
+ var start = _.now();
+ try {
+ return fn();
+ } finally {
+ console.log(name + " time: " + (_.now() - start) + "ms");
+ }
+}
+
+function notime(name, fn) {
+ return fn();
+}
+
+},{"./graphlib":7,"./lodash":10}],30:[function(require,module,exports){
+module.exports = "0.7.4";
+
+},{}],31:[function(require,module,exports){
+/**
+ * Copyright (c) 2014, Chris Pettitt
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * 3. Neither the name of the copyright holder nor the names of its contributors
+ * may be used to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+var lib = require("./lib");
+
+module.exports = {
+ Graph: lib.Graph,
+ json: require("./lib/json"),
+ alg: require("./lib/alg"),
+ version: lib.version
+};
+
+},{"./lib":47,"./lib/alg":38,"./lib/json":48}],32:[function(require,module,exports){
+var _ = require("../lodash");
+
+module.exports = components;
+
+function components(g) {
+ var visited = {},
+ cmpts = [],
+ cmpt;
+
+ function dfs(v) {
+ if (_.has(visited, v)) return;
+ visited[v] = true;
+ cmpt.push(v);
+ _.each(g.successors(v), dfs);
+ _.each(g.predecessors(v), dfs);
+ }
+
+ _.each(g.nodes(), function(v) {
+ cmpt = [];
+ dfs(v);
+ if (cmpt.length) {
+ cmpts.push(cmpt);
+ }
+ });
+
+ return cmpts;
+}
+
+},{"../lodash":49}],33:[function(require,module,exports){
+var _ = require("../lodash");
+
+module.exports = dfs;
+
+/*
+ * A helper that preforms a pre- or post-order traversal on the input graph
+ * and returns the nodes in the order they were visited. This algorithm treats
+ * the input as undirected.
+ *
+ * Order must be one of "pre" or "post".
+ */
+function dfs(g, vs, order) {
+ if (!_.isArray(vs)) {
+ vs = [vs];
+ }
+
+ var acc = [],
+ visited = {};
+ _.each(vs, function(v) {
+ if (!g.hasNode(v)) {
+ throw new Error("Graph does not have node: " + v);
+ }
+
+ doDfs(g, v, order === "post", visited, acc);
+ });
+ return acc;
+}
+
+function doDfs(g, v, postorder, visited, acc) {
+ if (!_.has(visited, v)) {
+ visited[v] = true;
+
+ if (!postorder) { acc.push(v); }
+ _.each(g.neighbors(v), function(w) {
+ doDfs(g, w, postorder, visited, acc);
+ });
+ if (postorder) { acc.push(v); }
+ }
+}
+
+},{"../lodash":49}],34:[function(require,module,exports){
+var dijkstra = require("./dijkstra"),
+ _ = require("../lodash");
+
+module.exports = dijkstraAll;
+
+function dijkstraAll(g, weightFunc, edgeFunc) {
+ return _.transform(g.nodes(), function(acc, v) {
+ acc[v] = dijkstra(g, v, weightFunc, edgeFunc);
+ }, {});
+}
+
+},{"../lodash":49,"./dijkstra":35}],35:[function(require,module,exports){
+var _ = require("../lodash"),
+ PriorityQueue = require("../data/priority-queue");
+
+module.exports = dijkstra;
+
+var DEFAULT_WEIGHT_FUNC = _.constant(1);
+
+function dijkstra(g, source, weightFn, edgeFn) {
+ return runDijkstra(g, String(source),
+ weightFn || DEFAULT_WEIGHT_FUNC,
+ edgeFn || function(v) { return g.outEdges(v); });
+}
+
+function runDijkstra(g, source, weightFn, edgeFn) {
+ var results = {},
+ pq = new PriorityQueue(),
+ v, vEntry;
+
+ var updateNeighbors = function(edge) {
+ var w = edge.v !== v ? edge.v : edge.w,
+ wEntry = results[w],
+ weight = weightFn(edge),
+ distance = vEntry.distance + weight;
+
+ if (weight < 0) {
+ throw new Error("dijkstra does not allow negative edge weights. " +
+ "Bad edge: " + edge + " Weight: " + weight);
+ }
+
+ if (distance < wEntry.distance) {
+ wEntry.distance = distance;
+ wEntry.predecessor = v;
+ pq.decrease(w, distance);
+ }
+ };
+
+ g.nodes().forEach(function(v) {
+ var distance = v === source ? 0 : Number.POSITIVE_INFINITY;
+ results[v] = { distance: distance };
+ pq.add(v, distance);
+ });
+
+ while (pq.size() > 0) {
+ v = pq.removeMin();
+ vEntry = results[v];
+ if (vEntry.distance === Number.POSITIVE_INFINITY) {
+ break;
+ }
+
+ edgeFn(v).forEach(updateNeighbors);
+ }
+
+ return results;
+}
+
+},{"../data/priority-queue":45,"../lodash":49}],36:[function(require,module,exports){
+var _ = require("../lodash"),
+ tarjan = require("./tarjan");
+
+module.exports = findCycles;
+
+function findCycles(g) {
+ return _.filter(tarjan(g), function(cmpt) {
+ return cmpt.length > 1 || (cmpt.length === 1 && g.hasEdge(cmpt[0], cmpt[0]));
+ });
+}
+
+},{"../lodash":49,"./tarjan":43}],37:[function(require,module,exports){
+var _ = require("../lodash");
+
+module.exports = floydWarshall;
+
+var DEFAULT_WEIGHT_FUNC = _.constant(1);
+
+function floydWarshall(g, weightFn, edgeFn) {
+ return runFloydWarshall(g,
+ weightFn || DEFAULT_WEIGHT_FUNC,
+ edgeFn || function(v) { return g.outEdges(v); });
+}
+
+function runFloydWarshall(g, weightFn, edgeFn) {
+ var results = {},
+ nodes = g.nodes();
+
+ nodes.forEach(function(v) {
+ results[v] = {};
+ results[v][v] = { distance: 0 };
+ nodes.forEach(function(w) {
+ if (v !== w) {
+ results[v][w] = { distance: Number.POSITIVE_INFINITY };
+ }
+ });
+ edgeFn(v).forEach(function(edge) {
+ var w = edge.v === v ? edge.w : edge.v,
+ d = weightFn(edge);
+ results[v][w] = { distance: d, predecessor: v };
+ });
+ });
+
+ nodes.forEach(function(k) {
+ var rowK = results[k];
+ nodes.forEach(function(i) {
+ var rowI = results[i];
+ nodes.forEach(function(j) {
+ var ik = rowI[k];
+ var kj = rowK[j];
+ var ij = rowI[j];
+ var altDistance = ik.distance + kj.distance;
+ if (altDistance < ij.distance) {
+ ij.distance = altDistance;
+ ij.predecessor = kj.predecessor;
+ }
+ });
+ });
+ });
+
+ return results;
+}
+
+},{"../lodash":49}],38:[function(require,module,exports){
+module.exports = {
+ components: require("./components"),
+ dijkstra: require("./dijkstra"),
+ dijkstraAll: require("./dijkstra-all"),
+ findCycles: require("./find-cycles"),
+ floydWarshall: require("./floyd-warshall"),
+ isAcyclic: require("./is-acyclic"),
+ postorder: require("./postorder"),
+ preorder: require("./preorder"),
+ prim: require("./prim"),
+ tarjan: require("./tarjan"),
+ topsort: require("./topsort")
+};
+
+},{"./components":32,"./dijkstra":35,"./dijkstra-all":34,"./find-cycles":36,"./floyd-warshall":37,"./is-acyclic":39,"./postorder":40,"./preorder":41,"./prim":42,"./tarjan":43,"./topsort":44}],39:[function(require,module,exports){
+var topsort = require("./topsort");
+
+module.exports = isAcyclic;
+
+function isAcyclic(g) {
+ try {
+ topsort(g);
+ } catch (e) {
+ if (e instanceof topsort.CycleException) {
+ return false;
+ }
+ throw e;
+ }
+ return true;
+}
+
+},{"./topsort":44}],40:[function(require,module,exports){
+var dfs = require("./dfs");
+
+module.exports = postorder;
+
+function postorder(g, vs) {
+ return dfs(g, vs, "post");
+}
+
+},{"./dfs":33}],41:[function(require,module,exports){
+var dfs = require("./dfs");
+
+module.exports = preorder;
+
+function preorder(g, vs) {
+ return dfs(g, vs, "pre");
+}
+
+},{"./dfs":33}],42:[function(require,module,exports){
+var _ = require("../lodash"),
+ Graph = require("../graph"),
+ PriorityQueue = require("../data/priority-queue");
+
+module.exports = prim;
+
+function prim(g, weightFunc) {
+ var result = new Graph(),
+ parents = {},
+ pq = new PriorityQueue(),
+ v;
+
+ function updateNeighbors(edge) {
+ var w = edge.v === v ? edge.w : edge.v,
+ pri = pq.priority(w);
+ if (pri !== undefined) {
+ var edgeWeight = weightFunc(edge);
+ if (edgeWeight < pri) {
+ parents[w] = v;
+ pq.decrease(w, edgeWeight);
+ }
+ }
+ }
+
+ if (g.nodeCount() === 0) {
+ return result;
+ }
+
+ _.each(g.nodes(), function(v) {
+ pq.add(v, Number.POSITIVE_INFINITY);
+ result.setNode(v);
+ });
+
+ // Start from an arbitrary node
+ pq.decrease(g.nodes()[0], 0);
+
+ var init = false;
+ while (pq.size() > 0) {
+ v = pq.removeMin();
+ if (_.has(parents, v)) {
+ result.setEdge(v, parents[v]);
+ } else if (init) {
+ throw new Error("Input graph is not connected: " + g);
+ } else {
+ init = true;
+ }
+
+ g.nodeEdges(v).forEach(updateNeighbors);
+ }
+
+ return result;
+}
+
+},{"../data/priority-queue":45,"../graph":46,"../lodash":49}],43:[function(require,module,exports){
+var _ = require("../lodash");
+
+module.exports = tarjan;
+
+function tarjan(g) {
+ var index = 0,
+ stack = [],
+ visited = {}, // node id -> { onStack, lowlink, index }
+ results = [];
+
+ function dfs(v) {
+ var entry = visited[v] = {
+ onStack: true,
+ lowlink: index,
+ index: index++
+ };
+ stack.push(v);
+
+ g.successors(v).forEach(function(w) {
+ if (!_.has(visited, w)) {
+ dfs(w);
+ entry.lowlink = Math.min(entry.lowlink, visited[w].lowlink);
+ } else if (visited[w].onStack) {
+ entry.lowlink = Math.min(entry.lowlink, visited[w].index);
+ }
+ });
+
+ if (entry.lowlink === entry.index) {
+ var cmpt = [],
+ w;
+ do {
+ w = stack.pop();
+ visited[w].onStack = false;
+ cmpt.push(w);
+ } while (v !== w);
+ results.push(cmpt);
+ }
+ }
+
+ g.nodes().forEach(function(v) {
+ if (!_.has(visited, v)) {
+ dfs(v);
+ }
+ });
+
+ return results;
+}
+
+},{"../lodash":49}],44:[function(require,module,exports){
+var _ = require("../lodash");
+
+module.exports = topsort;
+topsort.CycleException = CycleException;
+
+function topsort(g) {
+ var visited = {},
+ stack = {},
+ results = [];
+
+ function visit(node) {
+ if (_.has(stack, node)) {
+ throw new CycleException();
+ }
+
+ if (!_.has(visited, node)) {
+ stack[node] = true;
+ visited[node] = true;
+ _.each(g.predecessors(node), visit);
+ delete stack[node];
+ results.push(node);
+ }
+ }
+
+ _.each(g.sinks(), visit);
+
+ if (_.size(visited) !== g.nodeCount()) {
+ throw new CycleException();
+ }
+
+ return results;
+}
+
+function CycleException() {}
+
+},{"../lodash":49}],45:[function(require,module,exports){
+var _ = require("../lodash");
+
+module.exports = PriorityQueue;
+
+/**
+ * A min-priority queue data structure. This algorithm is derived from Cormen,
+ * et al., "Introduction to Algorithms". The basic idea of a min-priority
+ * queue is that you can efficiently (in O(1) time) get the smallest key in
+ * the queue. Adding and removing elements takes O(log n) time. A key can
+ * have its priority decreased in O(log n) time.
+ */
+function PriorityQueue() {
+ this._arr = [];
+ this._keyIndices = {};
+}
+
+/**
+ * Returns the number of elements in the queue. Takes `O(1)` time.
+ */
+PriorityQueue.prototype.size = function() {
+ return this._arr.length;
+};
+
+/**
+ * Returns the keys that are in the queue. Takes `O(n)` time.
+ */
+PriorityQueue.prototype.keys = function() {
+ return this._arr.map(function(x) { return x.key; });
+};
+
+/**
+ * Returns `true` if **key** is in the queue and `false` if not.
+ */
+PriorityQueue.prototype.has = function(key) {
+ return _.has(this._keyIndices, key);
+};
+
+/**
+ * Returns the priority for **key**. If **key** is not present in the queue
+ * then this function returns `undefined`. Takes `O(1)` time.
+ *
+ * @param {Object} key
+ */
+PriorityQueue.prototype.priority = function(key) {
+ var index = this._keyIndices[key];
+ if (index !== undefined) {
+ return this._arr[index].priority;
+ }
+};
+
+/**
+ * Returns the key for the minimum element in this queue. If the queue is
+ * empty this function throws an Error. Takes `O(1)` time.
+ */
+PriorityQueue.prototype.min = function() {
+ if (this.size() === 0) {
+ throw new Error("Queue underflow");
+ }
+ return this._arr[0].key;
+};
+
+/**
+ * Inserts a new key into the priority queue. If the key already exists in
+ * the queue this function returns `false`; otherwise it will return `true`.
+ * Takes `O(n)` time.
+ *
+ * @param {Object} key the key to add
+ * @param {Number} priority the initial priority for the key
+ */
+PriorityQueue.prototype.add = function(key, priority) {
+ var keyIndices = this._keyIndices;
+ key = String(key);
+ if (!_.has(keyIndices, key)) {
+ var arr = this._arr;
+ var index = arr.length;
+ keyIndices[key] = index;
+ arr.push({key: key, priority: priority});
+ this._decrease(index);
+ return true;
+ }
+ return false;
+};
+
+/**
+ * Removes and returns the smallest key in the queue. Takes `O(log n)` time.
+ */
+PriorityQueue.prototype.removeMin = function() {
+ this._swap(0, this._arr.length - 1);
+ var min = this._arr.pop();
+ delete this._keyIndices[min.key];
+ this._heapify(0);
+ return min.key;
+};
+
+/**
+ * Decreases the priority for **key** to **priority**. If the new priority is
+ * greater than the previous priority, this function will throw an Error.
+ *
+ * @param {Object} key the key for which to raise priority
+ * @param {Number} priority the new priority for the key
+ */
+PriorityQueue.prototype.decrease = function(key, priority) {
+ var index = this._keyIndices[key];
+ if (priority > this._arr[index].priority) {
+ throw new Error("New priority is greater than current priority. " +
+ "Key: " + key + " Old: " + this._arr[index].priority + " New: " + priority);
+ }
+ this._arr[index].priority = priority;
+ this._decrease(index);
+};
+
+PriorityQueue.prototype._heapify = function(i) {
+ var arr = this._arr;
+ var l = 2 * i,
+ r = l + 1,
+ largest = i;
+ if (l < arr.length) {
+ largest = arr[l].priority < arr[largest].priority ? l : largest;
+ if (r < arr.length) {
+ largest = arr[r].priority < arr[largest].priority ? r : largest;
+ }
+ if (largest !== i) {
+ this._swap(i, largest);
+ this._heapify(largest);
+ }
+ }
+};
+
+PriorityQueue.prototype._decrease = function(index) {
+ var arr = this._arr;
+ var priority = arr[index].priority;
+ var parent;
+ while (index !== 0) {
+ parent = index >> 1;
+ if (arr[parent].priority < priority) {
+ break;
+ }
+ this._swap(index, parent);
+ index = parent;
+ }
+};
+
+PriorityQueue.prototype._swap = function(i, j) {
+ var arr = this._arr;
+ var keyIndices = this._keyIndices;
+ var origArrI = arr[i];
+ var origArrJ = arr[j];
+ arr[i] = origArrJ;
+ arr[j] = origArrI;
+ keyIndices[origArrJ.key] = i;
+ keyIndices[origArrI.key] = j;
+};
+
+},{"../lodash":49}],46:[function(require,module,exports){
+"use strict";
+
+var _ = require("./lodash");
+
+module.exports = Graph;
+
+var DEFAULT_EDGE_NAME = "\x00",
+ GRAPH_NODE = "\x00",
+ EDGE_KEY_DELIM = "\x01";
+
+// Implementation notes:
+//
+// * Node id query functions should return string ids for the nodes
+// * Edge id query functions should return an "edgeObj", edge object, that is
+// composed of enough information to uniquely identify an edge: {v, w, name}.
+// * Internally we use an "edgeId", a stringified form of the edgeObj, to
+// reference edges. This is because we need a performant way to look these
+// edges up and, object properties, which have string keys, are the closest
+// we're going to get to a performant hashtable in JavaScript.
+
+function Graph(opts) {
+ this._isDirected = _.has(opts, "directed") ? opts.directed : true;
+ this._isMultigraph = _.has(opts, "multigraph") ? opts.multigraph : false;
+ this._isCompound = _.has(opts, "compound") ? opts.compound : false;
+
+ // Label for the graph itself
+ this._label = undefined;
+
+ // Defaults to be set when creating a new node
+ this._defaultNodeLabelFn = _.constant(undefined);
+
+ // Defaults to be set when creating a new edge
+ this._defaultEdgeLabelFn = _.constant(undefined);
+
+ // v -> label
+ this._nodes = {};
+
+ if (this._isCompound) {
+ // v -> parent
+ this._parent = {};
+
+ // v -> children
+ this._children = {};
+ this._children[GRAPH_NODE] = {};
+ }
+
+ // v -> edgeObj
+ this._in = {};
+
+ // u -> v -> Number
+ this._preds = {};
+
+ // v -> edgeObj
+ this._out = {};
+
+ // v -> w -> Number
+ this._sucs = {};
+
+ // e -> edgeObj
+ this._edgeObjs = {};
+
+ // e -> label
+ this._edgeLabels = {};
+}
+
+/* Number of nodes in the graph. Should only be changed by the implementation. */
+Graph.prototype._nodeCount = 0;
+
+/* Number of edges in the graph. Should only be changed by the implementation. */
+Graph.prototype._edgeCount = 0;
+
+
+/* === Graph functions ========= */
+
+Graph.prototype.isDirected = function() {
+ return this._isDirected;
+};
+
+Graph.prototype.isMultigraph = function() {
+ return this._isMultigraph;
+};
+
+Graph.prototype.isCompound = function() {
+ return this._isCompound;
+};
+
+Graph.prototype.setGraph = function(label) {
+ this._label = label;
+ return this;
+};
+
+Graph.prototype.graph = function() {
+ return this._label;
+};
+
+
+/* === Node functions ========== */
+
+Graph.prototype.setDefaultNodeLabel = function(newDefault) {
+ if (!_.isFunction(newDefault)) {
+ newDefault = _.constant(newDefault);
+ }
+ this._defaultNodeLabelFn = newDefault;
+ return this;
+};
+
+Graph.prototype.nodeCount = function() {
+ return this._nodeCount;
+};
+
+Graph.prototype.nodes = function() {
+ return _.keys(this._nodes);
+};
+
+Graph.prototype.sources = function() {
+ return _.filter(this.nodes(), function(v) {
+ return _.isEmpty(this._in[v]);
+ }, this);
+};
+
+Graph.prototype.sinks = function() {
+ return _.filter(this.nodes(), function(v) {
+ return _.isEmpty(this._out[v]);
+ }, this);
+};
+
+Graph.prototype.setNodes = function(vs, value) {
+ var args = arguments;
+ _.each(vs, function(v) {
+ if (args.length > 1) {
+ this.setNode(v, value);
+ } else {
+ this.setNode(v);
+ }
+ }, this);
+ return this;
+};
+
+Graph.prototype.setNode = function(v, value) {
+ if (_.has(this._nodes, v)) {
+ if (arguments.length > 1) {
+ this._nodes[v] = value;
+ }
+ return this;
+ }
+
+ this._nodes[v] = arguments.length > 1 ? value : this._defaultNodeLabelFn(v);
+ if (this._isCompound) {
+ this._parent[v] = GRAPH_NODE;
+ this._children[v] = {};
+ this._children[GRAPH_NODE][v] = true;
+ }
+ this._in[v] = {};
+ this._preds[v] = {};
+ this._out[v] = {};
+ this._sucs[v] = {};
+ ++this._nodeCount;
+ return this;
+};
+
+Graph.prototype.node = function(v) {
+ return this._nodes[v];
+};
+
+Graph.prototype.hasNode = function(v) {
+ return _.has(this._nodes, v);
+};
+
+Graph.prototype.removeNode = function(v) {
+ var self = this;
+ if (_.has(this._nodes, v)) {
+ var removeEdge = function(e) { self.removeEdge(self._edgeObjs[e]); };
+ delete this._nodes[v];
+ if (this._isCompound) {
+ this._removeFromParentsChildList(v);
+ delete this._parent[v];
+ _.each(this.children(v), function(child) {
+ this.setParent(child);
+ }, this);
+ delete this._children[v];
+ }
+ _.each(_.keys(this._in[v]), removeEdge);
+ delete this._in[v];
+ delete this._preds[v];
+ _.each(_.keys(this._out[v]), removeEdge);
+ delete this._out[v];
+ delete this._sucs[v];
+ --this._nodeCount;
+ }
+ return this;
+};
+
+Graph.prototype.setParent = function(v, parent) {
+ if (!this._isCompound) {
+ throw new Error("Cannot set parent in a non-compound graph");
+ }
+
+ if (_.isUndefined(parent)) {
+ parent = GRAPH_NODE;
+ } else {
+ // Coerce parent to string
+ parent += "";
+ for (var ancestor = parent;
+ !_.isUndefined(ancestor);
+ ancestor = this.parent(ancestor)) {
+ if (ancestor === v) {
+ throw new Error("Setting " + parent+ " as parent of " + v +
+ " would create create a cycle");
+ }
+ }
+
+ this.setNode(parent);
+ }
+
+ this.setNode(v);
+ this._removeFromParentsChildList(v);
+ this._parent[v] = parent;
+ this._children[parent][v] = true;
+ return this;
+};
+
+Graph.prototype._removeFromParentsChildList = function(v) {
+ delete this._children[this._parent[v]][v];
+};
+
+Graph.prototype.parent = function(v) {
+ if (this._isCompound) {
+ var parent = this._parent[v];
+ if (parent !== GRAPH_NODE) {
+ return parent;
+ }
+ }
+};
+
+Graph.prototype.children = function(v) {
+ if (_.isUndefined(v)) {
+ v = GRAPH_NODE;
+ }
+
+ if (this._isCompound) {
+ var children = this._children[v];
+ if (children) {
+ return _.keys(children);
+ }
+ } else if (v === GRAPH_NODE) {
+ return this.nodes();
+ } else if (this.hasNode(v)) {
+ return [];
+ }
+};
+
+Graph.prototype.predecessors = function(v) {
+ var predsV = this._preds[v];
+ if (predsV) {
+ return _.keys(predsV);
+ }
+};
+
+Graph.prototype.successors = function(v) {
+ var sucsV = this._sucs[v];
+ if (sucsV) {
+ return _.keys(sucsV);
+ }
+};
+
+Graph.prototype.neighbors = function(v) {
+ var preds = this.predecessors(v);
+ if (preds) {
+ return _.union(preds, this.successors(v));
+ }
+};
+
+/* === Edge functions ========== */
+
+Graph.prototype.setDefaultEdgeLabel = function(newDefault) {
+ if (!_.isFunction(newDefault)) {
+ newDefault = _.constant(newDefault);
+ }
+ this._defaultEdgeLabelFn = newDefault;
+ return this;
+};
+
+Graph.prototype.edgeCount = function() {
+ return this._edgeCount;
+};
+
+Graph.prototype.edges = function() {
+ return _.values(this._edgeObjs);
+};
+
+Graph.prototype.setPath = function(vs, value) {
+ var self = this,
+ args = arguments;
+ _.reduce(vs, function(v, w) {
+ if (args.length > 1) {
+ self.setEdge(v, w, value);
+ } else {
+ self.setEdge(v, w);
+ }
+ return w;
+ });
+ return this;
+};
+
+/*
+ * setEdge(v, w, [value, [name]])
+ * setEdge({ v, w, [name] }, [value])
+ */
+Graph.prototype.setEdge = function() {
+ var v, w, name, value,
+ valueSpecified = false;
+
+ if (_.isPlainObject(arguments[0])) {
+ v = arguments[0].v;
+ w = arguments[0].w;
+ name = arguments[0].name;
+ if (arguments.length === 2) {
+ value = arguments[1];
+ valueSpecified = true;
+ }
+ } else {
+ v = arguments[0];
+ w = arguments[1];
+ name = arguments[3];
+ if (arguments.length > 2) {
+ value = arguments[2];
+ valueSpecified = true;
+ }
+ }
+
+ v = "" + v;
+ w = "" + w;
+ if (!_.isUndefined(name)) {
+ name = "" + name;
+ }
+
+ var e = edgeArgsToId(this._isDirected, v, w, name);
+ if (_.has(this._edgeLabels, e)) {
+ if (valueSpecified) {
+ this._edgeLabels[e] = value;
+ }
+ return this;
+ }
+
+ if (!_.isUndefined(name) && !this._isMultigraph) {
+ throw new Error("Cannot set a named edge when isMultigraph = false");
+ }
+
+ // It didn't exist, so we need to create it.
+ // First ensure the nodes exist.
+ this.setNode(v);
+ this.setNode(w);
+
+ this._edgeLabels[e] = valueSpecified ? value : this._defaultEdgeLabelFn(v, w, name);
+
+ var edgeObj = edgeArgsToObj(this._isDirected, v, w, name);
+ // Ensure we add undirected edges in a consistent way.
+ v = edgeObj.v;
+ w = edgeObj.w;
+
+ Object.freeze(edgeObj);
+ this._edgeObjs[e] = edgeObj;
+ incrementOrInitEntry(this._preds[w], v);
+ incrementOrInitEntry(this._sucs[v], w);
+ this._in[w][e] = edgeObj;
+ this._out[v][e] = edgeObj;
+ this._edgeCount++;
+ return this;
+};
+
+Graph.prototype.edge = function(v, w, name) {
+ var e = (arguments.length === 1
+ ? edgeObjToId(this._isDirected, arguments[0])
+ : edgeArgsToId(this._isDirected, v, w, name));
+ return this._edgeLabels[e];
+};
+
+Graph.prototype.hasEdge = function(v, w, name) {
+ var e = (arguments.length === 1
+ ? edgeObjToId(this._isDirected, arguments[0])
+ : edgeArgsToId(this._isDirected, v, w, name));
+ return _.has(this._edgeLabels, e);
+};
+
+Graph.prototype.removeEdge = function(v, w, name) {
+ var e = (arguments.length === 1
+ ? edgeObjToId(this._isDirected, arguments[0])
+ : edgeArgsToId(this._isDirected, v, w, name)),
+ edge = this._edgeObjs[e];
+ if (edge) {
+ v = edge.v;
+ w = edge.w;
+ delete this._edgeLabels[e];
+ delete this._edgeObjs[e];
+ decrementOrRemoveEntry(this._preds[w], v);
+ decrementOrRemoveEntry(this._sucs[v], w);
+ delete this._in[w][e];
+ delete this._out[v][e];
+ this._edgeCount--;
+ }
+ return this;
+};
+
+Graph.prototype.inEdges = function(v, u) {
+ var inV = this._in[v];
+ if (inV) {
+ var edges = _.values(inV);
+ if (!u) {
+ return edges;
+ }
+ return _.filter(edges, function(edge) { return edge.v === u; });
+ }
+};
+
+Graph.prototype.outEdges = function(v, w) {
+ var outV = this._out[v];
+ if (outV) {
+ var edges = _.values(outV);
+ if (!w) {
+ return edges;
+ }
+ return _.filter(edges, function(edge) { return edge.w === w; });
+ }
+};
+
+Graph.prototype.nodeEdges = function(v, w) {
+ var inEdges = this.inEdges(v, w);
+ if (inEdges) {
+ return inEdges.concat(this.outEdges(v, w));
+ }
+};
+
+function incrementOrInitEntry(map, k) {
+ if (_.has(map, k)) {
+ map[k]++;
+ } else {
+ map[k] = 1;
+ }
+}
+
+function decrementOrRemoveEntry(map, k) {
+ if (!--map[k]) { delete map[k]; }
+}
+
+function edgeArgsToId(isDirected, v, w, name) {
+ if (!isDirected && v > w) {
+ var tmp = v;
+ v = w;
+ w = tmp;
+ }
+ return v + EDGE_KEY_DELIM + w + EDGE_KEY_DELIM +
+ (_.isUndefined(name) ? DEFAULT_EDGE_NAME : name);
+}
+
+function edgeArgsToObj(isDirected, v, w, name) {
+ if (!isDirected && v > w) {
+ var tmp = v;
+ v = w;
+ w = tmp;
+ }
+ var edgeObj = { v: v, w: w };
+ if (name) {
+ edgeObj.name = name;
+ }
+ return edgeObj;
+}
+
+function edgeObjToId(isDirected, edgeObj) {
+ return edgeArgsToId(isDirected, edgeObj.v, edgeObj.w, edgeObj.name);
+}
+
+},{"./lodash":49}],47:[function(require,module,exports){
+// Includes only the "core" of graphlib
+module.exports = {
+ Graph: require("./graph"),
+ version: require("./version")
+};
+
+},{"./graph":46,"./version":50}],48:[function(require,module,exports){
+var _ = require("./lodash"),
+ Graph = require("./graph");
+
+module.exports = {
+ write: write,
+ read: read
+};
+
+function write(g) {
+ var json = {
+ options: {
+ directed: g.isDirected(),
+ multigraph: g.isMultigraph(),
+ compound: g.isCompound()
+ },
+ nodes: writeNodes(g),
+ edges: writeEdges(g)
+ };
+ if (!_.isUndefined(g.graph())) {
+ json.value = _.clone(g.graph());
+ }
+ return json;
+}
+
+function writeNodes(g) {
+ return _.map(g.nodes(), function(v) {
+ var nodeValue = g.node(v),
+ parent = g.parent(v),
+ node = { v: v };
+ if (!_.isUndefined(nodeValue)) {
+ node.value = nodeValue;
+ }
+ if (!_.isUndefined(parent)) {
+ node.parent = parent;
+ }
+ return node;
+ });
+}
+
+function writeEdges(g) {
+ return _.map(g.edges(), function(e) {
+ var edgeValue = g.edge(e),
+ edge = { v: e.v, w: e.w };
+ if (!_.isUndefined(e.name)) {
+ edge.name = e.name;
+ }
+ if (!_.isUndefined(edgeValue)) {
+ edge.value = edgeValue;
+ }
+ return edge;
+ });
+}
+
+function read(json) {
+ var g = new Graph(json.options).setGraph(json.value);
+ _.each(json.nodes, function(entry) {
+ g.setNode(entry.v, entry.value);
+ if (entry.parent) {
+ g.setParent(entry.v, entry.parent);
+ }
+ });
+ _.each(json.edges, function(entry) {
+ g.setEdge({ v: entry.v, w: entry.w, name: entry.name }, entry.value);
+ });
+ return g;
+}
+
+},{"./graph":46,"./lodash":49}],49:[function(require,module,exports){
+module.exports=require(10)
+},{"/Users/cpettitt/projects/dagre/lib/lodash.js":10,"lodash":51}],50:[function(require,module,exports){
+module.exports = '1.0.5';
+
+},{}],51:[function(require,module,exports){
+(function (global){
+/**
+ * @license
+ * lodash 3.10.0 (Custom Build) <https://lodash.com/>
+ * Build: `lodash modern -d -o ./index.js`
+ * Copyright 2012-2015 The Dojo Foundation <http://dojofoundation.org/>
+ * Based on Underscore.js 1.8.3 <http://underscorejs.org/LICENSE>
+ * Copyright 2009-2015 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors
+ * Available under MIT license <https://lodash.com/license>
+ */
+;(function() {
+
+ /** Used as a safe reference for `undefined` in pre-ES5 environments. */
+ var undefined;
+
+ /** Used as the semantic version number. */
+ var VERSION = '3.10.0';
+
+ /** Used to compose bitmasks for wrapper metadata. */
+ var BIND_FLAG = 1,
+ BIND_KEY_FLAG = 2,
+ CURRY_BOUND_FLAG = 4,
+ CURRY_FLAG = 8,
+ CURRY_RIGHT_FLAG = 16,
+ PARTIAL_FLAG = 32,
+ PARTIAL_RIGHT_FLAG = 64,
+ ARY_FLAG = 128,
+ REARG_FLAG = 256;
+
+ /** Used as default options for `_.trunc`. */
+ var DEFAULT_TRUNC_LENGTH = 30,
+ DEFAULT_TRUNC_OMISSION = '...';
+
+ /** Used to detect when a function becomes hot. */
+ var HOT_COUNT = 150,
+ HOT_SPAN = 16;
+
+ /** Used as the size to enable large array optimizations. */
+ var LARGE_ARRAY_SIZE = 200;
+
+ /** Used to indicate the type of lazy iteratees. */
+ var LAZY_FILTER_FLAG = 1,
+ LAZY_MAP_FLAG = 2;
+
+ /** Used as the `TypeError` message for "Functions" methods. */
+ var FUNC_ERROR_TEXT = 'Expected a function';
+
+ /** Used as the internal argument placeholder. */
+ var PLACEHOLDER = '__lodash_placeholder__';
+
+ /** `Object#toString` result references. */
+ var argsTag = '[object Arguments]',
+ arrayTag = '[object Array]',
+ boolTag = '[object Boolean]',
+ dateTag = '[object Date]',
+ errorTag = '[object Error]',
+ funcTag = '[object Function]',
+ mapTag = '[object Map]',
+ numberTag = '[object Number]',
+ objectTag = '[object Object]',
+ regexpTag = '[object RegExp]',
+ setTag = '[object Set]',
+ stringTag = '[object String]',
+ weakMapTag = '[object WeakMap]';
+
+ var arrayBufferTag = '[object ArrayBuffer]',
+ float32Tag = '[object Float32Array]',
+ float64Tag = '[object Float64Array]',
+ int8Tag = '[object Int8Array]',
+ int16Tag = '[object Int16Array]',
+ int32Tag = '[object Int32Array]',
+ uint8Tag = '[object Uint8Array]',
+ uint8ClampedTag = '[object Uint8ClampedArray]',
+ uint16Tag = '[object Uint16Array]',
+ uint32Tag = '[object Uint32Array]';
+
+ /** Used to match empty string literals in compiled template source. */
+ var reEmptyStringLeading = /\b__p \+= '';/g,
+ reEmptyStringMiddle = /\b(__p \+=) '' \+/g,
+ reEmptyStringTrailing = /(__e\(.*?\)|\b__t\)) \+\n'';/g;
+
+ /** Used to match HTML entities and HTML characters. */
+ var reEscapedHtml = /&(?:amp|lt|gt|quot|#39|#96);/g,
+ reUnescapedHtml = /[&<>"'`]/g,
+ reHasEscapedHtml = RegExp(reEscapedHtml.source),
+ reHasUnescapedHtml = RegExp(reUnescapedHtml.source);
+
+ /** Used to match template delimiters. */
+ var reEscape = /<%-([\s\S]+?)%>/g,
+ reEvaluate = /<%([\s\S]+?)%>/g,
+ reInterpolate = /<%=([\s\S]+?)%>/g;
+
+ /** Used to match property names within property paths. */
+ var reIsDeepProp = /\.|\[(?:[^[\]]*|(["'])(?:(?!\1)[^\n\\]|\\.)*?\1)\]/,
+ reIsPlainProp = /^\w*$/,
+ rePropName = /[^.[\]]+|\[(?:(-?\d+(?:\.\d+)?)|(["'])((?:(?!\2)[^\n\\]|\\.)*?)\2)\]/g;
+
+ /**
+ * Used to match `RegExp` [syntax characters](http://ecma-international.org/ecma-262/6.0/#sec-patterns)
+ * and those outlined by [`EscapeRegExpPattern`](http://ecma-international.org/ecma-262/6.0/#sec-escaperegexppattern).
+ */
+ var reRegExpChars = /^[:!,]|[\\^$.*+?()[\]{}|\/]|(^[0-9a-fA-Fnrtuvx])|([\n\r\u2028\u2029])/g,
+ reHasRegExpChars = RegExp(reRegExpChars.source);
+
+ /** Used to match [combining diacritical marks](https://en.wikipedia.org/wiki/Combining_Diacritical_Marks). */
+ var reComboMark = /[\u0300-\u036f\ufe20-\ufe23]/g;
+
+ /** Used to match backslashes in property paths. */
+ var reEscapeChar = /\\(\\)?/g;
+
+ /** Used to match [ES template delimiters](http://ecma-international.org/ecma-262/6.0/#sec-template-literal-lexical-components). */
+ var reEsTemplate = /\$\{([^\\}]*(?:\\.[^\\}]*)*)\}/g;
+
+ /** Used to match `RegExp` flags from their coerced string values. */
+ var reFlags = /\w*$/;
+
+ /** Used to detect hexadecimal string values. */
+ var reHasHexPrefix = /^0[xX]/;
+
+ /** Used to detect host constructors (Safari > 5). */
+ var reIsHostCtor = /^\[object .+?Constructor\]$/;
+
+ /** Used to detect unsigned integer values. */
+ var reIsUint = /^\d+$/;
+
+ /** Used to match latin-1 supplementary letters (excluding mathematical operators). */
+ var reLatin1 = /[\xc0-\xd6\xd8-\xde\xdf-\xf6\xf8-\xff]/g;
+
+ /** Used to ensure capturing order of template delimiters. */
+ var reNoMatch = /($^)/;
+
+ /** Used to match unescaped characters in compiled string literals. */
+ var reUnescapedString = /['\n\r\u2028\u2029\\]/g;
+
+ /** Used to match words to create compound words. */
+ var reWords = (function() {
+ var upper = '[A-Z\\xc0-\\xd6\\xd8-\\xde]',
+ lower = '[a-z\\xdf-\\xf6\\xf8-\\xff]+';
+
+ return RegExp(upper + '+(?=' + upper + lower + ')|' + upper + '?' + lower + '|' + upper + '+|[0-9]+', 'g');
+ }());
+
+ /** Used to assign default `context` object properties. */
+ var contextProps = [
+ 'Array', 'ArrayBuffer', 'Date', 'Error', 'Float32Array', 'Float64Array',
+ 'Function', 'Int8Array', 'Int16Array', 'Int32Array', 'Math', 'Number',
+ 'Object', 'RegExp', 'Set', 'String', '_', 'clearTimeout', 'isFinite',
+ 'parseFloat', 'parseInt', 'setTimeout', 'TypeError', 'Uint8Array',
+ 'Uint8ClampedArray', 'Uint16Array', 'Uint32Array', 'WeakMap'
+ ];
+
+ /** Used to make template sourceURLs easier to identify. */
+ var templateCounter = -1;
+
+ /** Used to identify `toStringTag` values of typed arrays. */
+ var typedArrayTags = {};
+ typedArrayTags[float32Tag] = typedArrayTags[float64Tag] =
+ typedArrayTags[int8Tag] = typedArrayTags[int16Tag] =
+ typedArrayTags[int32Tag] = typedArrayTags[uint8Tag] =
+ typedArrayTags[uint8ClampedTag] = typedArrayTags[uint16Tag] =
+ typedArrayTags[uint32Tag] = true;
+ typedArrayTags[argsTag] = typedArrayTags[arrayTag] =
+ typedArrayTags[arrayBufferTag] = typedArrayTags[boolTag] =
+ typedArrayTags[dateTag] = typedArrayTags[errorTag] =
+ typedArrayTags[funcTag] = typedArrayTags[mapTag] =
+ typedArrayTags[numberTag] = typedArrayTags[objectTag] =
+ typedArrayTags[regexpTag] = typedArrayTags[setTag] =
+ typedArrayTags[stringTag] = typedArrayTags[weakMapTag] = false;
+
+ /** Used to identify `toStringTag` values supported by `_.clone`. */
+ var cloneableTags = {};
+ cloneableTags[argsTag] = cloneableTags[arrayTag] =
+ cloneableTags[arrayBufferTag] = cloneableTags[boolTag] =
+ cloneableTags[dateTag] = cloneableTags[float32Tag] =
+ cloneableTags[float64Tag] = cloneableTags[int8Tag] =
+ cloneableTags[int16Tag] = cloneableTags[int32Tag] =
+ cloneableTags[numberTag] = cloneableTags[objectTag] =
+ cloneableTags[regexpTag] = cloneableTags[stringTag] =
+ cloneableTags[uint8Tag] = cloneableTags[uint8ClampedTag] =
+ cloneableTags[uint16Tag] = cloneableTags[uint32Tag] = true;
+ cloneableTags[errorTag] = cloneableTags[funcTag] =
+ cloneableTags[mapTag] = cloneableTags[setTag] =
+ cloneableTags[weakMapTag] = false;
+
+ /** Used to map latin-1 supplementary letters to basic latin letters. */
+ var deburredLetters = {
+ '\xc0': 'A', '\xc1': 'A', '\xc2': 'A', '\xc3': 'A', '\xc4': 'A', '\xc5': 'A',
+ '\xe0': 'a', '\xe1': 'a', '\xe2': 'a', '\xe3': 'a', '\xe4': 'a', '\xe5': 'a',
+ '\xc7': 'C', '\xe7': 'c',
+ '\xd0': 'D', '\xf0': 'd',
+ '\xc8': 'E', '\xc9': 'E', '\xca': 'E', '\xcb': 'E',
+ '\xe8': 'e', '\xe9': 'e', '\xea': 'e', '\xeb': 'e',
+ '\xcC': 'I', '\xcd': 'I', '\xce': 'I', '\xcf': 'I',
+ '\xeC': 'i', '\xed': 'i', '\xee': 'i', '\xef': 'i',
+ '\xd1': 'N', '\xf1': 'n',
+ '\xd2': 'O', '\xd3': 'O', '\xd4': 'O', '\xd5': 'O', '\xd6': 'O', '\xd8': 'O',
+ '\xf2': 'o', '\xf3': 'o', '\xf4': 'o', '\xf5': 'o', '\xf6': 'o', '\xf8': 'o',
+ '\xd9': 'U', '\xda': 'U', '\xdb': 'U', '\xdc': 'U',
+ '\xf9': 'u', '\xfa': 'u', '\xfb': 'u', '\xfc': 'u',
+ '\xdd': 'Y', '\xfd': 'y', '\xff': 'y',
+ '\xc6': 'Ae', '\xe6': 'ae',
+ '\xde': 'Th', '\xfe': 'th',
+ '\xdf': 'ss'
+ };
+
+ /** Used to map characters to HTML entities. */
+ var htmlEscapes = {
+ '&': '&amp;',
+ '<': '&lt;',
+ '>': '&gt;',
+ '"': '&quot;',
+ "'": '&#39;',
+ '`': '&#96;'
+ };
+
+ /** Used to map HTML entities to characters. */
+ var htmlUnescapes = {
+ '&amp;': '&',
+ '&lt;': '<',
+ '&gt;': '>',
+ '&quot;': '"',
+ '&#39;': "'",
+ '&#96;': '`'
+ };
+
+ /** Used to determine if values are of the language type `Object`. */
+ var objectTypes = {
+ 'function': true,
+ 'object': true
+ };
+
+ /** Used to escape characters for inclusion in compiled regexes. */
+ var regexpEscapes = {
+ '0': 'x30', '1': 'x31', '2': 'x32', '3': 'x33', '4': 'x34',
+ '5': 'x35', '6': 'x36', '7': 'x37', '8': 'x38', '9': 'x39',
+ 'A': 'x41', 'B': 'x42', 'C': 'x43', 'D': 'x44', 'E': 'x45', 'F': 'x46',
+ 'a': 'x61', 'b': 'x62', 'c': 'x63', 'd': 'x64', 'e': 'x65', 'f': 'x66',
+ 'n': 'x6e', 'r': 'x72', 't': 'x74', 'u': 'x75', 'v': 'x76', 'x': 'x78'
+ };
+
+ /** Used to escape characters for inclusion in compiled string literals. */
+ var stringEscapes = {
+ '\\': '\\',
+ "'": "'",
+ '\n': 'n',
+ '\r': 'r',
+ '\u2028': 'u2028',
+ '\u2029': 'u2029'
+ };
+
+ /** Detect free variable `exports`. */
+ var freeExports = objectTypes[typeof exports] && exports && !exports.nodeType && exports;
+
+ /** Detect free variable `module`. */
+ var freeModule = objectTypes[typeof module] && module && !module.nodeType && module;
+
+ /** Detect free variable `global` from Node.js. */
+ var freeGlobal = freeExports && freeModule && typeof global == 'object' && global && global.Object && global;
+
+ /** Detect free variable `self`. */
+ var freeSelf = objectTypes[typeof self] && self && self.Object && self;
+
+ /** Detect free variable `window`. */
+ var freeWindow = objectTypes[typeof window] && window && window.Object && window;
+
+ /** Detect the popular CommonJS extension `module.exports`. */
+ var moduleExports = freeModule && freeModule.exports === freeExports && freeExports;
+
+ /**
+ * Used as a reference to the global object.
+ *
+ * The `this` value is used if it's the global object to avoid Greasemonkey's
+ * restricted `window` object, otherwise the `window` object is used.
+ */
+ var root = freeGlobal || ((freeWindow !== (this && this.window)) && freeWindow) || freeSelf || this;
+
+ /*--------------------------------------------------------------------------*/
+
+ /**
+ * The base implementation of `compareAscending` which compares values and
+ * sorts them in ascending order without guaranteeing a stable sort.
+ *
+ * @private
+ * @param {*} value The value to compare.
+ * @param {*} other The other value to compare.
+ * @returns {number} Returns the sort order indicator for `value`.
+ */
+ function baseCompareAscending(value, other) {
+ if (value !== other) {
+ var valIsNull = value === null,
+ valIsUndef = value === undefined,
+ valIsReflexive = value === value;
+
+ var othIsNull = other === null,
+ othIsUndef = other === undefined,
+ othIsReflexive = other === other;
+
+ if ((value > other && !othIsNull) || !valIsReflexive ||
+ (valIsNull && !othIsUndef && othIsReflexive) ||
+ (valIsUndef && othIsReflexive)) {
+ return 1;
+ }
+ if ((value < other && !valIsNull) || !othIsReflexive ||
+ (othIsNull && !valIsUndef && valIsReflexive) ||
+ (othIsUndef && valIsReflexive)) {
+ return -1;
+ }
+ }
+ return 0;
+ }
+
+ /**
+ * The base implementation of `_.findIndex` and `_.findLastIndex` without
+ * support for callback shorthands and `this` binding.
+ *
+ * @private
+ * @param {Array} array The array to search.
+ * @param {Function} predicate The function invoked per iteration.
+ * @param {boolean} [fromRight] Specify iterating from right to left.
+ * @returns {number} Returns the index of the matched value, else `-1`.
+ */
+ function baseFindIndex(array, predicate, fromRight) {
+ var length = array.length,
+ index = fromRight ? length : -1;
+
+ while ((fromRight ? index-- : ++index < length)) {
+ if (predicate(array[index], index, array)) {
+ return index;
+ }
+ }
+ return -1;
+ }
+
+ /**
+ * The base implementation of `_.indexOf` without support for binary searches.
+ *
+ * @private
+ * @param {Array} array The array to search.
+ * @param {*} value The value to search for.
+ * @param {number} fromIndex The index to search from.
+ * @returns {number} Returns the index of the matched value, else `-1`.
+ */
+ function baseIndexOf(array, value, fromIndex) {
+ if (value !== value) {
+ return indexOfNaN(array, fromIndex);
+ }
+ var index = fromIndex - 1,
+ length = array.length;
+
+ while (++index < length) {
+ if (array[index] === value) {
+ return index;
+ }
+ }
+ return -1;
+ }
+
+ /**
+ * The base implementation of `_.isFunction` without support for environments
+ * with incorrect `typeof` results.
+ *
+ * @private
+ * @param {*} value The value to check.
+ * @returns {boolean} Returns `true` if `value` is correctly classified, else `false`.
+ */
+ function baseIsFunction(value) {
+ // Avoid a Chakra JIT bug in compatibility modes of IE 11.
+ // See https://github.com/jashkenas/underscore/issues/1621 for more details.
+ return typeof value == 'function' || false;
+ }
+
+ /**
+ * Converts `value` to a string if it's not one. An empty string is returned
+ * for `null` or `undefined` values.
+ *
+ * @private
+ * @param {*} value The value to process.
+ * @returns {string} Returns the string.
+ */
+ function baseToString(value) {
+ return value == null ? '' : (value + '');
+ }
+
+ /**
+ * Used by `_.trim` and `_.trimLeft` to get the index of the first character
+ * of `string` that is not found in `chars`.
+ *
+ * @private
+ * @param {string} string The string to inspect.
+ * @param {string} chars The characters to find.
+ * @returns {number} Returns the index of the first character not found in `chars`.
+ */
+ function charsLeftIndex(string, chars) {
+ var index = -1,
+ length = string.length;
+
+ while (++index < length && chars.indexOf(string.charAt(index)) > -1) {}
+ return index;
+ }
+
+ /**
+ * Used by `_.trim` and `_.trimRight` to get the index of the last character
+ * of `string` that is not found in `chars`.
+ *
+ * @private
+ * @param {string} string The string to inspect.
+ * @param {string} chars The characters to find.
+ * @returns {number} Returns the index of the last character not found in `chars`.
+ */
+ function charsRightIndex(string, chars) {
+ var index = string.length;
+
+ while (index-- && chars.indexOf(string.charAt(index)) > -1) {}
+ return index;
+ }
+
+ /**
+ * Used by `_.sortBy` to compare transformed elements of a collection and stable
+ * sort them in ascending order.
+ *
+ * @private
+ * @param {Object} object The object to compare.
+ * @param {Object} other The other object to compare.
+ * @returns {number} Returns the sort order indicator for `object`.
+ */
+ function compareAscending(object, other) {
+ return baseCompareAscending(object.criteria, other.criteria) || (object.index - other.index);
+ }
+
+ /**
+ * Used by `_.sortByOrder` to compare multiple properties of a value to another
+ * and stable sort them.
+ *
+ * If `orders` is unspecified, all valuess are sorted in ascending order. Otherwise,
+ * a value is sorted in ascending order if its corresponding order is "asc", and
+ * descending if "desc".
+ *
+ * @private
+ * @param {Object} object The object to compare.
+ * @param {Object} other The other object to compare.
+ * @param {boolean[]} orders The order to sort by for each property.
+ * @returns {number} Returns the sort order indicator for `object`.
+ */
+ function compareMultiple(object, other, orders) {
+ var index = -1,
+ objCriteria = object.criteria,
+ othCriteria = other.criteria,
+ length = objCriteria.length,
+ ordersLength = orders.length;
+
+ while (++index < length) {
+ var result = baseCompareAscending(objCriteria[index], othCriteria[index]);
+ if (result) {
+ if (index >= ordersLength) {
+ return result;
+ }
+ var order = orders[index];
+ return result * ((order === 'asc' || order === true) ? 1 : -1);
+ }
+ }
+ // Fixes an `Array#sort` bug in the JS engine embedded in Adobe applications
+ // that causes it, under certain circumstances, to provide the same value for
+ // `object` and `other`. See https://github.com/jashkenas/underscore/pull/1247
+ // for more details.
+ //
+ // This also ensures a stable sort in V8 and other engines.
+ // See https://code.google.com/p/v8/issues/detail?id=90 for more details.
+ return object.index - other.index;
+ }
+
+ /**
+ * Used by `_.deburr` to convert latin-1 supplementary letters to basic latin letters.
+ *
+ * @private
+ * @param {string} letter The matched letter to deburr.
+ * @returns {string} Returns the deburred letter.
+ */
+ function deburrLetter(letter) {
+ return deburredLetters[letter];
+ }
+
+ /**
+ * Used by `_.escape` to convert characters to HTML entities.
+ *
+ * @private
+ * @param {string} chr The matched character to escape.
+ * @returns {string} Returns the escaped character.
+ */
+ function escapeHtmlChar(chr) {
+ return htmlEscapes[chr];
+ }
+
+ /**
+ * Used by `_.escapeRegExp` to escape characters for inclusion in compiled regexes.
+ *
+ * @private
+ * @param {string} chr The matched character to escape.
+ * @param {string} leadingChar The capture group for a leading character.
+ * @param {string} whitespaceChar The capture group for a whitespace character.
+ * @returns {string} Returns the escaped character.
+ */
+ function escapeRegExpChar(chr, leadingChar, whitespaceChar) {
+ if (leadingChar) {
+ chr = regexpEscapes[chr];
+ } else if (whitespaceChar) {
+ chr = stringEscapes[chr];
+ }
+ return '\\' + chr;
+ }
+
+ /**
+ * Used by `_.template` to escape characters for inclusion in compiled string literals.
+ *
+ * @private
+ * @param {string} chr The matched character to escape.
+ * @returns {string} Returns the escaped character.
+ */
+ function escapeStringChar(chr) {
+ return '\\' + stringEscapes[chr];
+ }
+
+ /**
+ * Gets the index at which the first occurrence of `NaN` is found in `array`.
+ *
+ * @private
+ * @param {Array} array The array to search.
+ * @param {number} fromIndex The index to search from.
+ * @param {boolean} [fromRight] Specify iterating from right to left.
+ * @returns {number} Returns the index of the matched `NaN`, else `-1`.
+ */
+ function indexOfNaN(array, fromIndex, fromRight) {
+ var length = array.length,
+ index = fromIndex + (fromRight ? 0 : -1);
+
+ while ((fromRight ? index-- : ++index < length)) {
+ var other = array[index];
+ if (other !== other) {
+ return index;
+ }
+ }
+ return -1;
+ }
+
+ /**
+ * Checks if `value` is object-like.
+ *
+ * @private
+ * @param {*} value The value to check.
+ * @returns {boolean} Returns `true` if `value` is object-like, else `false`.
+ */
+ function isObjectLike(value) {
+ return !!value && typeof value == 'object';
+ }
+
+ /**
+ * Used by `trimmedLeftIndex` and `trimmedRightIndex` to determine if a
+ * character code is whitespace.
+ *
+ * @private
+ * @param {number} charCode The character code to inspect.
+ * @returns {boolean} Returns `true` if `charCode` is whitespace, else `false`.
+ */
+ function isSpace(charCode) {
+ return ((charCode <= 160 && (charCode >= 9 && charCode <= 13) || charCode == 32 || charCode == 160) || charCode == 5760 || charCode == 6158 ||
+ (charCode >= 8192 && (charCode <= 8202 || charCode == 8232 || charCode == 8233 || charCode == 8239 || charCode == 8287 || charCode == 12288 || charCode == 65279)));
+ }
+
+ /**
+ * Replaces all `placeholder` elements in `array` with an internal placeholder
+ * and returns an array of their indexes.
+ *
+ * @private
+ * @param {Array} array The array to modify.
+ * @param {*} placeholder The placeholder to replace.
+ * @returns {Array} Returns the new array of placeholder indexes.
+ */
+ function replaceHolders(array, placeholder) {
+ var index = -1,
+ length = array.length,
+ resIndex = -1,
+ result = [];
+
+ while (++index < length) {
+ if (array[index] === placeholder) {
+ array[index] = PLACEHOLDER;
+ result[++resIndex] = index;
+ }
+ }
+ return result;
+ }
+
+ /**
+ * An implementation of `_.uniq` optimized for sorted arrays without support
+ * for callback shorthands and `this` binding.
+ *
+ * @private
+ * @param {Array} array The array to inspect.
+ * @param {Function} [iteratee] The function invoked per iteration.
+ * @returns {Array} Returns the new duplicate-value-free array.
+ */
+ function sortedUniq(array, iteratee) {
+ var seen,
+ index = -1,
+ length = array.length,
+ resIndex = -1,
+ result = [];
+
+ while (++index < length) {
+ var value = array[index],
+ computed = iteratee ? iteratee(value, index, array) : value;
+
+ if (!index || seen !== computed) {
+ seen = computed;
+ result[++resIndex] = value;
+ }
+ }
+ return result;
+ }
+
+ /**
+ * Used by `_.trim` and `_.trimLeft` to get the index of the first non-whitespace
+ * character of `string`.
+ *
+ * @private
+ * @param {string} string The string to inspect.
+ * @returns {number} Returns the index of the first non-whitespace character.
+ */
+ function trimmedLeftIndex(string) {
+ var index = -1,
+ length = string.length;
+
+ while (++index < length && isSpace(string.charCodeAt(index))) {}
+ return index;
+ }
+
+ /**
+ * Used by `_.trim` and `_.trimRight` to get the index of the last non-whitespace
+ * character of `string`.
+ *
+ * @private
+ * @param {string} string The string to inspect.
+ * @returns {number} Returns the index of the last non-whitespace character.
+ */
+ function trimmedRightIndex(string) {
+ var index = string.length;
+
+ while (index-- && isSpace(string.charCodeAt(index))) {}
+ return index;
+ }
+
+ /**
+ * Used by `_.unescape` to convert HTML entities to characters.
+ *
+ * @private
+ * @param {string} chr The matched character to unescape.
+ * @returns {string} Returns the unescaped character.
+ */
+ function unescapeHtmlChar(chr) {
+ return htmlUnescapes[chr];
+ }
+
+ /*--------------------------------------------------------------------------*/
+
+ /**
+ * Create a new pristine `lodash` function using the given `context` object.
+ *
+ * @static
+ * @memberOf _
+ * @category Utility
+ * @param {Object} [context=root] The context object.
+ * @returns {Function} Returns a new `lodash` function.
+ * @example
+ *
+ * _.mixin({ 'foo': _.constant('foo') });
+ *
+ * var lodash = _.runInContext();
+ * lodash.mixin({ 'bar': lodash.constant('bar') });
+ *
+ * _.isFunction(_.foo);
+ * // => true
+ * _.isFunction(_.bar);
+ * // => false
+ *
+ * lodash.isFunction(lodash.foo);
+ * // => false
+ * lodash.isFunction(lodash.bar);
+ * // => true
+ *
+ * // using `context` to mock `Date#getTime` use in `_.now`
+ * var mock = _.runInContext({
+ * 'Date': function() {
+ * return { 'getTime': getTimeMock };
+ * }
+ * });
+ *
+ * // or creating a suped-up `defer` in Node.js
+ * var defer = _.runInContext({ 'setTimeout': setImmediate }).defer;
+ */
+ function runInContext(context) {
+ // Avoid issues with some ES3 environments that attempt to use values, named
+ // after built-in constructors like `Object`, for the creation of literals.
+ // ES5 clears this up by stating that literals must use built-in constructors.
+ // See https://es5.github.io/#x11.1.5 for more details.
+ context = context ? _.defaults(root.Object(), context, _.pick(root, contextProps)) : root;
+
+ /** Native constructor references. */
+ var Array = context.Array,
+ Date = context.Date,
+ Error = context.Error,
+ Function = context.Function,
+ Math = context.Math,
+ Number = context.Number,
+ Object = context.Object,
+ RegExp = context.RegExp,
+ String = context.String,
+ TypeError = context.TypeError;
+
+ /** Used for native method references. */
+ var arrayProto = Array.prototype,
+ objectProto = Object.prototype,
+ stringProto = String.prototype;
+
+ /** Used to resolve the decompiled source of functions. */
+ var fnToString = Function.prototype.toString;
+
+ /** Used to check objects for own properties. */
+ var hasOwnProperty = objectProto.hasOwnProperty;
+
+ /** Used to generate unique IDs. */
+ var idCounter = 0;
+
+ /**
+ * Used to resolve the [`toStringTag`](http://ecma-international.org/ecma-262/6.0/#sec-object.prototype.tostring)
+ * of values.
+ */
+ var objToString = objectProto.toString;
+
+ /** Used to restore the original `_` reference in `_.noConflict`. */
+ var oldDash = root._;
+
+ /** Used to detect if a method is native. */
+ var reIsNative = RegExp('^' +
+ fnToString.call(hasOwnProperty).replace(/[\\^$.*+?()[\]{}|]/g, '\\$&')
+ .replace(/hasOwnProperty|(function).*?(?=\\\()| for .+?(?=\\\])/g, '$1.*?') + '$'
+ );
+
+ /** Native method references. */
+ var ArrayBuffer = context.ArrayBuffer,
+ clearTimeout = context.clearTimeout,
+ parseFloat = context.parseFloat,
+ pow = Math.pow,
+ propertyIsEnumerable = objectProto.propertyIsEnumerable,
+ Set = getNative(context, 'Set'),
+ setTimeout = context.setTimeout,
+ splice = arrayProto.splice,
+ Uint8Array = context.Uint8Array,
+ WeakMap = getNative(context, 'WeakMap');
+
+ /* Native method references for those with the same name as other `lodash` methods. */
+ var nativeCeil = Math.ceil,
+ nativeCreate = getNative(Object, 'create'),
+ nativeFloor = Math.floor,
+ nativeIsArray = getNative(Array, 'isArray'),
+ nativeIsFinite = context.isFinite,
+ nativeKeys = getNative(Object, 'keys'),
+ nativeMax = Math.max,
+ nativeMin = Math.min,
+ nativeNow = getNative(Date, 'now'),
+ nativeParseInt = context.parseInt,
+ nativeRandom = Math.random;
+
+ /** Used as references for `-Infinity` and `Infinity`. */
+ var NEGATIVE_INFINITY = Number.NEGATIVE_INFINITY,
+ POSITIVE_INFINITY = Number.POSITIVE_INFINITY;
+
+ /** Used as references for the maximum length and index of an array. */
+ var MAX_ARRAY_LENGTH = 4294967295,
+ MAX_ARRAY_INDEX = MAX_ARRAY_LENGTH - 1,
+ HALF_MAX_ARRAY_LENGTH = MAX_ARRAY_LENGTH >>> 1;
+
+ /**
+ * Used as the [maximum length](http://ecma-international.org/ecma-262/6.0/#sec-number.max_safe_integer)
+ * of an array-like value.
+ */
+ var MAX_SAFE_INTEGER = 9007199254740991;
+
+ /** Used to store function metadata. */
+ var metaMap = WeakMap && new WeakMap;
+
+ /** Used to lookup unminified function names. */
+ var realNames = {};
+
+ /*------------------------------------------------------------------------*/
+
+ /**
+ * Creates a `lodash` object which wraps `value` to enable implicit chaining.
+ * Methods that operate on and return arrays, collections, and functions can
+ * be chained together. Methods that retrieve a single value or may return a
+ * primitive value will automatically end the chain returning the unwrapped
+ * value. Explicit chaining may be enabled using `_.chain`. The execution of
+ * chained methods is lazy, that is, execution is deferred until `_#value`
+ * is implicitly or explicitly called.
+ *
+ * Lazy evaluation allows several methods to support shortcut fusion. Shortcut
+ * fusion is an optimization strategy which merge iteratee calls; this can help
+ * to avoid the creation of intermediate data structures and greatly reduce the
+ * number of iteratee executions.
+ *
+ * Chaining is supported in custom builds as long as the `_#value` method is
+ * directly or indirectly included in the build.
+ *
+ * In addition to lodash methods, wrappers have `Array` and `String` methods.
+ *
+ * The wrapper `Array` methods are:
+ * `concat`, `join`, `pop`, `push`, `reverse`, `shift`, `slice`, `sort`,
+ * `splice`, and `unshift`
+ *
+ * The wrapper `String` methods are:
+ * `replace` and `split`
+ *
+ * The wrapper methods that support shortcut fusion are:
+ * `compact`, `drop`, `dropRight`, `dropRightWhile`, `dropWhile`, `filter`,
+ * `first`, `initial`, `last`, `map`, `pluck`, `reject`, `rest`, `reverse`,
+ * `slice`, `take`, `takeRight`, `takeRightWhile`, `takeWhile`, `toArray`,
+ * and `where`
+ *
+ * The chainable wrapper methods are:
+ * `after`, `ary`, `assign`, `at`, `before`, `bind`, `bindAll`, `bindKey`,
+ * `callback`, `chain`, `chunk`, `commit`, `compact`, `concat`, `constant`,
+ * `countBy`, `create`, `curry`, `debounce`, `defaults`, `defaultsDeep`,
+ * `defer`, `delay`, `difference`, `drop`, `dropRight`, `dropRightWhile`,
+ * `dropWhile`, `fill`, `filter`, `flatten`, `flattenDeep`, `flow`, `flowRight`,
+ * `forEach`, `forEachRight`, `forIn`, `forInRight`, `forOwn`, `forOwnRight`,
+ * `functions`, `groupBy`, `indexBy`, `initial`, `intersection`, `invert`,
+ * `invoke`, `keys`, `keysIn`, `map`, `mapKeys`, `mapValues`, `matches`,
+ * `matchesProperty`, `memoize`, `merge`, `method`, `methodOf`, `mixin`,
+ * `modArgs`, `negate`, `omit`, `once`, `pairs`, `partial`, `partialRight`,
+ * `partition`, `pick`, `plant`, `pluck`, `property`, `propertyOf`, `pull`,
+ * `pullAt`, `push`, `range`, `rearg`, `reject`, `remove`, `rest`, `restParam`,
+ * `reverse`, `set`, `shuffle`, `slice`, `sort`, `sortBy`, `sortByAll`,
+ * `sortByOrder`, `splice`, `spread`, `take`, `takeRight`, `takeRightWhile`,
+ * `takeWhile`, `tap`, `throttle`, `thru`, `times`, `toArray`, `toPlainObject`,
+ * `transform`, `union`, `uniq`, `unshift`, `unzip`, `unzipWith`, `values`,
+ * `valuesIn`, `where`, `without`, `wrap`, `xor`, `zip`, `zipObject`, `zipWith`
+ *
+ * The wrapper methods that are **not** chainable by default are:
+ * `add`, `attempt`, `camelCase`, `capitalize`, `ceil`, `clone`, `cloneDeep`,
+ * `deburr`, `endsWith`, `escape`, `escapeRegExp`, `every`, `find`, `findIndex`,
+ * `findKey`, `findLast`, `findLastIndex`, `findLastKey`, `findWhere`, `first`,
+ * `floor`, `get`, `gt`, `gte`, `has`, `identity`, `includes`, `indexOf`,
+ * `inRange`, `isArguments`, `isArray`, `isBoolean`, `isDate`, `isElement`,
+ * `isEmpty`, `isEqual`, `isError`, `isFinite` `isFunction`, `isMatch`,
+ * `isNative`, `isNaN`, `isNull`, `isNumber`, `isObject`, `isPlainObject`,
+ * `isRegExp`, `isString`, `isUndefined`, `isTypedArray`, `join`, `kebabCase`,
+ * `last`, `lastIndexOf`, `lt`, `lte`, `max`, `min`, `noConflict`, `noop`,
+ * `now`, `pad`, `padLeft`, `padRight`, `parseInt`, `pop`, `random`, `reduce`,
+ * `reduceRight`, `repeat`, `result`, `round`, `runInContext`, `shift`, `size`,
+ * `snakeCase`, `some`, `sortedIndex`, `sortedLastIndex`, `startCase`,
+ * `startsWith`, `sum`, `template`, `trim`, `trimLeft`, `trimRight`, `trunc`,
+ * `unescape`, `uniqueId`, `value`, and `words`
+ *
+ * The wrapper method `sample` will return a wrapped value when `n` is provided,
+ * otherwise an unwrapped value is returned.
+ *
+ * @name _
+ * @constructor
+ * @category Chain
+ * @param {*} value The value to wrap in a `lodash` instance.
+ * @returns {Object} Returns the new `lodash` wrapper instance.
+ * @example
+ *
+ * var wrapped = _([1, 2, 3]);
+ *
+ * // returns an unwrapped value
+ * wrapped.reduce(function(total, n) {
+ * return total + n;
+ * });
+ * // => 6
+ *
+ * // returns a wrapped value
+ * var squares = wrapped.map(function(n) {
+ * return n * n;
+ * });
+ *
+ * _.isArray(squares);
+ * // => false
+ *
+ * _.isArray(squares.value());
+ * // => true
+ */
+ function lodash(value) {
+ if (isObjectLike(value) && !isArray(value) && !(value instanceof LazyWrapper)) {
+ if (value instanceof LodashWrapper) {
+ return value;
+ }
+ if (hasOwnProperty.call(value, '__chain__') && hasOwnProperty.call(value, '__wrapped__')) {
+ return wrapperClone(value);
+ }
+ }
+ return new LodashWrapper(value);
+ }
+
+ /**
+ * The function whose prototype all chaining wrappers inherit from.
+ *
+ * @private
+ */
+ function baseLodash() {
+ // No operation performed.
+ }
+
+ /**
+ * The base constructor for creating `lodash` wrapper objects.
+ *
+ * @private
+ * @param {*} value The value to wrap.
+ * @param {boolean} [chainAll] Enable chaining for all wrapper methods.
+ * @param {Array} [actions=[]] Actions to peform to resolve the unwrapped value.
+ */
+ function LodashWrapper(value, chainAll, actions) {
+ this.__wrapped__ = value;
+ this.__actions__ = actions || [];
+ this.__chain__ = !!chainAll;
+ }
+
+ /**
+ * An object environment feature flags.
+ *
+ * @static
+ * @memberOf _
+ * @type Object
+ */
+ var support = lodash.support = {};
+
+ /**
+ * By default, the template delimiters used by lodash are like those in
+ * embedded Ruby (ERB). Change the following template settings to use
+ * alternative delimiters.
+ *
+ * @static
+ * @memberOf _
+ * @type Object
+ */
+ lodash.templateSettings = {
+
+ /**
+ * Used to detect `data` property values to be HTML-escaped.
+ *
+ * @memberOf _.templateSettings
+ * @type RegExp
+ */
+ 'escape': reEscape,
+
+ /**
+ * Used to detect code to be evaluated.
+ *
+ * @memberOf _.templateSettings
+ * @type RegExp
+ */
+ 'evaluate': reEvaluate,
+
+ /**
+ * Used to detect `data` property values to inject.
+ *
+ * @memberOf _.templateSettings
+ * @type RegExp
+ */
+ 'interpolate': reInterpolate,
+
+ /**
+ * Used to reference the data object in the template text.
+ *
+ * @memberOf _.templateSettings
+ * @type string
+ */
+ 'variable': '',
+
+ /**
+ * Used to import variables into the compiled template.
+ *
+ * @memberOf _.templateSettings
+ * @type Object
+ */
+ 'imports': {
+
+ /**
+ * A reference to the `lodash` function.
+ *
+ * @memberOf _.templateSettings.imports
+ * @type Function
+ */
+ '_': lodash
+ }
+ };
+
+ /*------------------------------------------------------------------------*/
+
+ /**
+ * Creates a lazy wrapper object which wraps `value` to enable lazy evaluation.
+ *
+ * @private
+ * @param {*} value The value to wrap.
+ */
+ function LazyWrapper(value) {
+ this.__wrapped__ = value;
+ this.__actions__ = [];
+ this.__dir__ = 1;
+ this.__filtered__ = false;
+ this.__iteratees__ = [];
+ this.__takeCount__ = POSITIVE_INFINITY;
+ this.__views__ = [];
+ }
+
+ /**
+ * Creates a clone of the lazy wrapper object.
+ *
+ * @private
+ * @name clone
+ * @memberOf LazyWrapper
+ * @returns {Object} Returns the cloned `LazyWrapper` object.
+ */
+ function lazyClone() {
+ var result = new LazyWrapper(this.__wrapped__);
+ result.__actions__ = arrayCopy(this.__actions__);
+ result.__dir__ = this.__dir__;
+ result.__filtered__ = this.__filtered__;
+ result.__iteratees__ = arrayCopy(this.__iteratees__);
+ result.__takeCount__ = this.__takeCount__;
+ result.__views__ = arrayCopy(this.__views__);
+ return result;
+ }
+
+ /**
+ * Reverses the direction of lazy iteration.
+ *
+ * @private
+ * @name reverse
+ * @memberOf LazyWrapper
+ * @returns {Object} Returns the new reversed `LazyWrapper` object.
+ */
+ function lazyReverse() {
+ if (this.__filtered__) {
+ var result = new LazyWrapper(this);
+ result.__dir__ = -1;
+ result.__filtered__ = true;
+ } else {
+ result = this.clone();
+ result.__dir__ *= -1;
+ }
+ return result;
+ }
+
+ /**
+ * Extracts the unwrapped value from its lazy wrapper.
+ *
+ * @private
+ * @name value
+ * @memberOf LazyWrapper
+ * @returns {*} Returns the unwrapped value.
+ */
+ function lazyValue() {
+ var array = this.__wrapped__.value(),
+ dir = this.__dir__,
+ isArr = isArray(array),
+ isRight = dir < 0,
+ arrLength = isArr ? array.length : 0,
+ view = getView(0, arrLength, this.__views__),
+ start = view.start,
+ end = view.end,
+ length = end - start,
+ index = isRight ? end : (start - 1),
+ iteratees = this.__iteratees__,
+ iterLength = iteratees.length,
+ resIndex = 0,
+ takeCount = nativeMin(length, this.__takeCount__);
+
+ if (!isArr || arrLength < LARGE_ARRAY_SIZE || (arrLength == length && takeCount == length)) {
+ return baseWrapperValue((isRight && isArr) ? array.reverse() : array, this.__actions__);
+ }
+ var result = [];
+
+ outer:
+ while (length-- && resIndex < takeCount) {
+ index += dir;
+
+ var iterIndex = -1,
+ value = array[index];
+
+ while (++iterIndex < iterLength) {
+ var data = iteratees[iterIndex],
+ iteratee = data.iteratee,
+ type = data.type,
+ computed = iteratee(value);
+
+ if (type == LAZY_MAP_FLAG) {
+ value = computed;
+ } else if (!computed) {
+ if (type == LAZY_FILTER_FLAG) {
+ continue outer;
+ } else {
+ break outer;
+ }
+ }
+ }
+ result[resIndex++] = value;
+ }
+ return result;
+ }
+
+ /*------------------------------------------------------------------------*/
+
+ /**
+ * Creates a cache object to store key/value pairs.
+ *
+ * @private
+ * @static
+ * @name Cache
+ * @memberOf _.memoize
+ */
+ function MapCache() {
+ this.__data__ = {};
+ }
+
+ /**
+ * Removes `key` and its value from the cache.
+ *
+ * @private
+ * @name delete
+ * @memberOf _.memoize.Cache
+ * @param {string} key The key of the value to remove.
+ * @returns {boolean} Returns `true` if the entry was removed successfully, else `false`.
+ */
+ function mapDelete(key) {
+ return this.has(key) && delete this.__data__[key];
+ }
+
+ /**
+ * Gets the cached value for `key`.
+ *
+ * @private
+ * @name get
+ * @memberOf _.memoize.Cache
+ * @param {string} key The key of the value to get.
+ * @returns {*} Returns the cached value.
+ */
+ function mapGet(key) {
+ return key == '__proto__' ? undefined : this.__data__[key];
+ }
+
+ /**
+ * Checks if a cached value for `key` exists.
+ *
+ * @private
+ * @name has
+ * @memberOf _.memoize.Cache
+ * @param {string} key The key of the entry to check.
+ * @returns {boolean} Returns `true` if an entry for `key` exists, else `false`.
+ */
+ function mapHas(key) {
+ return key != '__proto__' && hasOwnProperty.call(this.__data__, key);
+ }
+
+ /**
+ * Sets `value` to `key` of the cache.
+ *
+ * @private
+ * @name set
+ * @memberOf _.memoize.Cache
+ * @param {string} key The key of the value to cache.
+ * @param {*} value The value to cache.
+ * @returns {Object} Returns the cache object.
+ */
+ function mapSet(key, value) {
+ if (key != '__proto__') {
+ this.__data__[key] = value;
+ }
+ return this;
+ }
+
+ /*------------------------------------------------------------------------*/
+
+ /**
+ *
+ * Creates a cache object to store unique values.
+ *
+ * @private
+ * @param {Array} [values] The values to cache.
+ */
+ function SetCache(values) {
+ var length = values ? values.length : 0;
+
+ this.data = { 'hash': nativeCreate(null), 'set': new Set };
+ while (length--) {
+ this.push(values[length]);
+ }
+ }
+
+ /**
+ * Checks if `value` is in `cache` mimicking the return signature of
+ * `_.indexOf` by returning `0` if the value is found, else `-1`.
+ *
+ * @private
+ * @param {Object} cache The cache to search.
+ * @param {*} value The value to search for.
+ * @returns {number} Returns `0` if `value` is found, else `-1`.
+ */
+ function cacheIndexOf(cache, value) {
+ var data = cache.data,
+ result = (typeof value == 'string' || isObject(value)) ? data.set.has(value) : data.hash[value];
+
+ return result ? 0 : -1;
+ }
+
+ /**
+ * Adds `value` to the cache.
+ *
+ * @private
+ * @name push
+ * @memberOf SetCache
+ * @param {*} value The value to cache.
+ */
+ function cachePush(value) {
+ var data = this.data;
+ if (typeof value == 'string' || isObject(value)) {
+ data.set.add(value);
+ } else {
+ data.hash[value] = true;
+ }
+ }
+
+ /*------------------------------------------------------------------------*/
+
+ /**
+ * Creates a new array joining `array` with `other`.
+ *
+ * @private
+ * @param {Array} array The array to join.
+ * @param {Array} other The other array to join.
+ * @returns {Array} Returns the new concatenated array.
+ */
+ function arrayConcat(array, other) {
+ var index = -1,
+ length = array.length,
+ othIndex = -1,
+ othLength = other.length,
+ result = Array(length + othLength);
+
+ while (++index < length) {
+ result[index] = array[index];
+ }
+ while (++othIndex < othLength) {
+ result[index++] = other[othIndex];
+ }
+ return result;
+ }
+
+ /**
+ * Copies the values of `source` to `array`.
+ *
+ * @private
+ * @param {Array} source The array to copy values from.
+ * @param {Array} [array=[]] The array to copy values to.
+ * @returns {Array} Returns `array`.
+ */
+ function arrayCopy(source, array) {
+ var index = -1,
+ length = source.length;
+
+ array || (array = Array(length));
+ while (++index < length) {
+ array[index] = source[index];
+ }
+ return array;
+ }
+
+ /**
+ * A specialized version of `_.forEach` for arrays without support for callback
+ * shorthands and `this` binding.
+ *
+ * @private
+ * @param {Array} array The array to iterate over.
+ * @param {Function} iteratee The function invoked per iteration.
+ * @returns {Array} Returns `array`.
+ */
+ function arrayEach(array, iteratee) {
+ var index = -1,
+ length = array.length;
+
+ while (++index < length) {
+ if (iteratee(array[index], index, array) === false) {
+ break;
+ }
+ }
+ return array;
+ }
+
+ /**
+ * A specialized version of `_.forEachRight` for arrays without support for
+ * callback shorthands and `this` binding.
+ *
+ * @private
+ * @param {Array} array The array to iterate over.
+ * @param {Function} iteratee The function invoked per iteration.
+ * @returns {Array} Returns `array`.
+ */
+ function arrayEachRight(array, iteratee) {
+ var length = array.length;
+
+ while (length--) {
+ if (iteratee(array[length], length, array) === false) {
+ break;
+ }
+ }
+ return array;
+ }
+
+ /**
+ * A specialized version of `_.every` for arrays without support for callback
+ * shorthands and `this` binding.
+ *
+ * @private
+ * @param {Array} array The array to iterate over.
+ * @param {Function} predicate The function invoked per iteration.
+ * @returns {boolean} Returns `true` if all elements pass the predicate check,
+ * else `false`.
+ */
+ function arrayEvery(array, predicate) {
+ var index = -1,
+ length = array.length;
+
+ while (++index < length) {
+ if (!predicate(array[index], index, array)) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ /**
+ * A specialized version of `baseExtremum` for arrays which invokes `iteratee`
+ * with one argument: (value).
+ *
+ * @private
+ * @param {Array} array The array to iterate over.
+ * @param {Function} iteratee The function invoked per iteration.
+ * @param {Function} comparator The function used to compare values.
+ * @param {*} exValue The initial extremum value.
+ * @returns {*} Returns the extremum value.
+ */
+ function arrayExtremum(array, iteratee, comparator, exValue) {
+ var index = -1,
+ length = array.length,
+ computed = exValue,
+ result = computed;
+
+ while (++index < length) {
+ var value = array[index],
+ current = +iteratee(value);
+
+ if (comparator(current, computed)) {
+ computed = current;
+ result = value;
+ }
+ }
+ return result;
+ }
+
+ /**
+ * A specialized version of `_.filter` for arrays without support for callback
+ * shorthands and `this` binding.
+ *
+ * @private
+ * @param {Array} array The array to iterate over.
+ * @param {Function} predicate The function invoked per iteration.
+ * @returns {Array} Returns the new filtered array.
+ */
+ function arrayFilter(array, predicate) {
+ var index = -1,
+ length = array.length,
+ resIndex = -1,
+ result = [];
+
+ while (++index < length) {
+ var value = array[index];
+ if (predicate(value, index, array)) {
+ result[++resIndex] = value;
+ }
+ }
+ return result;
+ }
+
+ /**
+ * A specialized version of `_.map` for arrays without support for callback
+ * shorthands and `this` binding.
+ *
+ * @private
+ * @param {Array} array The array to iterate over.
+ * @param {Function} iteratee The function invoked per iteration.
+ * @returns {Array} Returns the new mapped array.
+ */
+ function arrayMap(array, iteratee) {
+ var index = -1,
+ length = array.length,
+ result = Array(length);
+
+ while (++index < length) {
+ result[index] = iteratee(array[index], index, array);
+ }
+ return result;
+ }
+
+ /**
+ * Appends the elements of `values` to `array`.
+ *
+ * @private
+ * @param {Array} array The array to modify.
+ * @param {Array} values The values to append.
+ * @returns {Array} Returns `array`.
+ */
+ function arrayPush(array, values) {
+ var index = -1,
+ length = values.length,
+ offset = array.length;
+
+ while (++index < length) {
+ array[offset + index] = values[index];
+ }
+ return array;
+ }
+
+ /**
+ * A specialized version of `_.reduce` for arrays without support for callback
+ * shorthands and `this` binding.
+ *
+ * @private
+ * @param {Array} array The array to iterate over.
+ * @param {Function} iteratee The function invoked per iteration.
+ * @param {*} [accumulator] The initial value.
+ * @param {boolean} [initFromArray] Specify using the first element of `array`
+ * as the initial value.
+ * @returns {*} Returns the accumulated value.
+ */
+ function arrayReduce(array, iteratee, accumulator, initFromArray) {
+ var index = -1,
+ length = array.length;
+
+ if (initFromArray && length) {
+ accumulator = array[++index];
+ }
+ while (++index < length) {
+ accumulator = iteratee(accumulator, array[index], index, array);
+ }
+ return accumulator;
+ }
+
+ /**
+ * A specialized version of `_.reduceRight` for arrays without support for
+ * callback shorthands and `this` binding.
+ *
+ * @private
+ * @param {Array} array The array to iterate over.
+ * @param {Function} iteratee The function invoked per iteration.
+ * @param {*} [accumulator] The initial value.
+ * @param {boolean} [initFromArray] Specify using the last element of `array`
+ * as the initial value.
+ * @returns {*} Returns the accumulated value.
+ */
+ function arrayReduceRight(array, iteratee, accumulator, initFromArray) {
+ var length = array.length;
+ if (initFromArray && length) {
+ accumulator = array[--length];
+ }
+ while (length--) {
+ accumulator = iteratee(accumulator, array[length], length, array);
+ }
+ return accumulator;
+ }
+
+ /**
+ * A specialized version of `_.some` for arrays without support for callback
+ * shorthands and `this` binding.
+ *
+ * @private
+ * @param {Array} array The array to iterate over.
+ * @param {Function} predicate The function invoked per iteration.
+ * @returns {boolean} Returns `true` if any element passes the predicate check,
+ * else `false`.
+ */
+ function arraySome(array, predicate) {
+ var index = -1,
+ length = array.length;
+
+ while (++index < length) {
+ if (predicate(array[index], index, array)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * A specialized version of `_.sum` for arrays without support for callback
+ * shorthands and `this` binding..
+ *
+ * @private
+ * @param {Array} array The array to iterate over.
+ * @param {Function} iteratee The function invoked per iteration.
+ * @returns {number} Returns the sum.
+ */
+ function arraySum(array, iteratee) {
+ var length = array.length,
+ result = 0;
+
+ while (length--) {
+ result += +iteratee(array[length]) || 0;
+ }
+ return result;
+ }
+
+ /**
+ * Used by `_.defaults` to customize its `_.assign` use.
+ *
+ * @private
+ * @param {*} objectValue The destination object property value.
+ * @param {*} sourceValue The source object property value.
+ * @returns {*} Returns the value to assign to the destination object.
+ */
+ function assignDefaults(objectValue, sourceValue) {
+ return objectValue === undefined ? sourceValue : objectValue;
+ }
+
+ /**
+ * Used by `_.template` to customize its `_.assign` use.
+ *
+ * **Note:** This function is like `assignDefaults` except that it ignores
+ * inherited property values when checking if a property is `undefined`.
+ *
+ * @private
+ * @param {*} objectValue The destination object property value.
+ * @param {*} sourceValue The source object property value.
+ * @param {string} key The key associated with the object and source values.
+ * @param {Object} object The destination object.
+ * @returns {*} Returns the value to assign to the destination object.
+ */
+ function assignOwnDefaults(objectValue, sourceValue, key, object) {
+ return (objectValue === undefined || !hasOwnProperty.call(object, key))
+ ? sourceValue
+ : objectValue;
+ }
+
+ /**
+ * A specialized version of `_.assign` for customizing assigned values without
+ * support for argument juggling, multiple sources, and `this` binding `customizer`
+ * functions.
+ *
+ * @private
+ * @param {Object} object The destination object.
+ * @param {Object} source The source object.
+ * @param {Function} customizer The function to customize assigned values.
+ * @returns {Object} Returns `object`.
+ */
+ function assignWith(object, source, customizer) {
+ var index = -1,
+ props = keys(source),
+ length = props.length;
+
+ while (++index < length) {
+ var key = props[index],
+ value = object[key],
+ result = customizer(value, source[key], key, object, source);
+
+ if ((result === result ? (result !== value) : (value === value)) ||
+ (value === undefined && !(key in object))) {
+ object[key] = result;
+ }
+ }
+ return object;
+ }
+
+ /**
+ * The base implementation of `_.assign` without support for argument juggling,
+ * multiple sources, and `customizer` functions.
+ *
+ * @private
+ * @param {Object} object The destination object.
+ * @param {Object} source The source object.
+ * @returns {Object} Returns `object`.
+ */
+ function baseAssign(object, source) {
+ return source == null
+ ? object
+ : baseCopy(source, keys(source), object);
+ }
+
+ /**
+ * The base implementation of `_.at` without support for string collections
+ * and individual key arguments.
+ *
+ * @private
+ * @param {Array|Object} collection The collection to iterate over.
+ * @param {number[]|string[]} props The property names or indexes of elements to pick.
+ * @returns {Array} Returns the new array of picked elements.
+ */
+ function baseAt(collection, props) {
+ var index = -1,
+ isNil = collection == null,
+ isArr = !isNil && isArrayLike(collection),
+ length = isArr ? collection.length : 0,
+ propsLength = props.length,
+ result = Array(propsLength);
+
+ while(++index < propsLength) {
+ var key = props[index];
+ if (isArr) {
+ result[index] = isIndex(key, length) ? collection[key] : undefined;
+ } else {
+ result[index] = isNil ? undefined : collection[key];
+ }
+ }
+ return result;
+ }
+
+ /**
+ * Copies properties of `source` to `object`.
+ *
+ * @private
+ * @param {Object} source The object to copy properties from.
+ * @param {Array} props The property names to copy.
+ * @param {Object} [object={}] The object to copy properties to.
+ * @returns {Object} Returns `object`.
+ */
+ function baseCopy(source, props, object) {
+ object || (object = {});
+
+ var index = -1,
+ length = props.length;
+
+ while (++index < length) {
+ var key = props[index];
+ object[key] = source[key];
+ }
+ return object;
+ }
+
+ /**
+ * The base implementation of `_.callback` which supports specifying the
+ * number of arguments to provide to `func`.
+ *
+ * @private
+ * @param {*} [func=_.identity] The value to convert to a callback.
+ * @param {*} [thisArg] The `this` binding of `func`.
+ * @param {number} [argCount] The number of arguments to provide to `func`.
+ * @returns {Function} Returns the callback.
+ */
+ function baseCallback(func, thisArg, argCount) {
+ var type = typeof func;
+ if (type == 'function') {
+ return thisArg === undefined
+ ? func
+ : bindCallback(func, thisArg, argCount);
+ }
+ if (func == null) {
+ return identity;
+ }
+ if (type == 'object') {
+ return baseMatches(func);
+ }
+ return thisArg === undefined
+ ? property(func)
+ : baseMatchesProperty(func, thisArg);
+ }
+
+ /**
+ * The base implementation of `_.clone` without support for argument juggling
+ * and `this` binding `customizer` functions.
+ *
+ * @private
+ * @param {*} value The value to clone.
+ * @param {boolean} [isDeep] Specify a deep clone.
+ * @param {Function} [customizer] The function to customize cloning values.
+ * @param {string} [key] The key of `value`.
+ * @param {Object} [object] The object `value` belongs to.
+ * @param {Array} [stackA=[]] Tracks traversed source objects.
+ * @param {Array} [stackB=[]] Associates clones with source counterparts.
+ * @returns {*} Returns the cloned value.
+ */
+ function baseClone(value, isDeep, customizer, key, object, stackA, stackB) {
+ var result;
+ if (customizer) {
+ result = object ? customizer(value, key, object) : customizer(value);
+ }
+ if (result !== undefined) {
+ return result;
+ }
+ if (!isObject(value)) {
+ return value;
+ }
+ var isArr = isArray(value);
+ if (isArr) {
+ result = initCloneArray(value);
+ if (!isDeep) {
+ return arrayCopy(value, result);
+ }
+ } else {
+ var tag = objToString.call(value),
+ isFunc = tag == funcTag;
+
+ if (tag == objectTag || tag == argsTag || (isFunc && !object)) {
+ result = initCloneObject(isFunc ? {} : value);
+ if (!isDeep) {
+ return baseAssign(result, value);
+ }
+ } else {
+ return cloneableTags[tag]
+ ? initCloneByTag(value, tag, isDeep)
+ : (object ? value : {});
+ }
+ }
+ // Check for circular references and return its corresponding clone.
+ stackA || (stackA = []);
+ stackB || (stackB = []);
+
+ var length = stackA.length;
+ while (length--) {
+ if (stackA[length] == value) {
+ return stackB[length];
+ }
+ }
+ // Add the source value to the stack of traversed objects and associate it with its clone.
+ stackA.push(value);
+ stackB.push(result);
+
+ // Recursively populate clone (susceptible to call stack limits).
+ (isArr ? arrayEach : baseForOwn)(value, function(subValue, key) {
+ result[key] = baseClone(subValue, isDeep, customizer, key, value, stackA, stackB);
+ });
+ return result;
+ }
+
+ /**
+ * The base implementation of `_.create` without support for assigning
+ * properties to the created object.
+ *
+ * @private
+ * @param {Object} prototype The object to inherit from.
+ * @returns {Object} Returns the new object.
+ */
+ var baseCreate = (function() {
+ function object() {}
+ return function(prototype) {
+ if (isObject(prototype)) {
+ object.prototype = prototype;
+ var result = new object;
+ object.prototype = undefined;
+ }
+ return result || {};
+ };
+ }());
+
+ /**
+ * The base implementation of `_.delay` and `_.defer` which accepts an index
+ * of where to slice the arguments to provide to `func`.
+ *
+ * @private
+ * @param {Function} func The function to delay.
+ * @param {number} wait The number of milliseconds to delay invocation.
+ * @param {Object} args The arguments provide to `func`.
+ * @returns {number} Returns the timer id.
+ */
+ function baseDelay(func, wait, args) {
+ if (typeof func != 'function') {
+ throw new TypeError(FUNC_ERROR_TEXT);
+ }
+ return setTimeout(function() { func.apply(undefined, args); }, wait);
+ }
+
+ /**
+ * The base implementation of `_.difference` which accepts a single array
+ * of values to exclude.
+ *
+ * @private
+ * @param {Array} array The array to inspect.
+ * @param {Array} values The values to exclude.
+ * @returns {Array} Returns the new array of filtered values.
+ */
+ function baseDifference(array, values) {
+ var length = array ? array.length : 0,
+ result = [];
+
+ if (!length) {
+ return result;
+ }
+ var index = -1,
+ indexOf = getIndexOf(),
+ isCommon = indexOf == baseIndexOf,
+ cache = (isCommon && values.length >= LARGE_ARRAY_SIZE) ? createCache(values) : null,
+ valuesLength = values.length;
+
+ if (cache) {
+ indexOf = cacheIndexOf;
+ isCommon = false;
+ values = cache;
+ }
+ outer:
+ while (++index < length) {
+ var value = array[index];
+
+ if (isCommon && value === value) {
+ var valuesIndex = valuesLength;
+ while (valuesIndex--) {
+ if (values[valuesIndex] === value) {
+ continue outer;
+ }
+ }
+ result.push(value);
+ }
+ else if (indexOf(values, value, 0) < 0) {
+ result.push(value);
+ }
+ }
+ return result;
+ }
+
+ /**
+ * The base implementation of `_.forEach` without support for callback
+ * shorthands and `this` binding.
+ *
+ * @private
+ * @param {Array|Object|string} collection The collection to iterate over.
+ * @param {Function} iteratee The function invoked per iteration.
+ * @returns {Array|Object|string} Returns `collection`.
+ */
+ var baseEach = createBaseEach(baseForOwn);
+
+ /**
+ * The base implementation of `_.forEachRight` without support for callback
+ * shorthands and `this` binding.
+ *
+ * @private
+ * @param {Array|Object|string} collection The collection to iterate over.
+ * @param {Function} iteratee The function invoked per iteration.
+ * @returns {Array|Object|string} Returns `collection`.
+ */
+ var baseEachRight = createBaseEach(baseForOwnRight, true);
+
+ /**
+ * The base implementation of `_.every` without support for callback
+ * shorthands and `this` binding.
+ *
+ * @private
+ * @param {Array|Object|string} collection The collection to iterate over.
+ * @param {Function} predicate The function invoked per iteration.
+ * @returns {boolean} Returns `true` if all elements pass the predicate check,
+ * else `false`
+ */
+ function baseEvery(collection, predicate) {
+ var result = true;
+ baseEach(collection, function(value, index, collection) {
+ result = !!predicate(value, index, collection);
+ return result;
+ });
+ return result;
+ }
+
+ /**
+ * Gets the extremum value of `collection` invoking `iteratee` for each value
+ * in `collection` to generate the criterion by which the value is ranked.
+ * The `iteratee` is invoked with three arguments: (value, index|key, collection).
+ *
+ * @private
+ * @param {Array|Object|string} collection The collection to iterate over.
+ * @param {Function} iteratee The function invoked per iteration.
+ * @param {Function} comparator The function used to compare values.
+ * @param {*} exValue The initial extremum value.
+ * @returns {*} Returns the extremum value.
+ */
+ function baseExtremum(collection, iteratee, comparator, exValue) {
+ var computed = exValue,
+ result = computed;
+
+ baseEach(collection, function(value, index, collection) {
+ var current = +iteratee(value, index, collection);
+ if (comparator(current, computed) || (current === exValue && current === result)) {
+ computed = current;
+ result = value;
+ }
+ });
+ return result;
+ }
+
+ /**
+ * The base implementation of `_.fill` without an iteratee call guard.
+ *
+ * @private
+ * @param {Array} array The array to fill.
+ * @param {*} value The value to fill `array` with.
+ * @param {number} [start=0] The start position.
+ * @param {number} [end=array.length] The end position.
+ * @returns {Array} Returns `array`.
+ */
+ function baseFill(array, value, start, end) {
+ var length = array.length;
+
+ start = start == null ? 0 : (+start || 0);
+ if (start < 0) {
+ start = -start > length ? 0 : (length + start);
+ }
+ end = (end === undefined || end > length) ? length : (+end || 0);
+ if (end < 0) {
+ end += length;
+ }
+ length = start > end ? 0 : (end >>> 0);
+ start >>>= 0;
+
+ while (start < length) {
+ array[start++] = value;
+ }
+ return array;
+ }
+
+ /**
+ * The base implementation of `_.filter` without support for callback
+ * shorthands and `this` binding.
+ *
+ * @private
+ * @param {Array|Object|string} collection The collection to iterate over.
+ * @param {Function} predicate The function invoked per iteration.
+ * @returns {Array} Returns the new filtered array.
+ */
+ function baseFilter(collection, predicate) {
+ var result = [];
+ baseEach(collection, function(value, index, collection) {
+ if (predicate(value, index, collection)) {
+ result.push(value);
+ }
+ });
+ return result;
+ }
+
+ /**
+ * The base implementation of `_.find`, `_.findLast`, `_.findKey`, and `_.findLastKey`,
+ * without support for callback shorthands and `this` binding, which iterates
+ * over `collection` using the provided `eachFunc`.
+ *
+ * @private
+ * @param {Array|Object|string} collection The collection to search.
+ * @param {Function} predicate The function invoked per iteration.
+ * @param {Function} eachFunc The function to iterate over `collection`.
+ * @param {boolean} [retKey] Specify returning the key of the found element
+ * instead of the element itself.
+ * @returns {*} Returns the found element or its key, else `undefined`.
+ */
+ function baseFind(collection, predicate, eachFunc, retKey) {
+ var result;
+ eachFunc(collection, function(value, key, collection) {
+ if (predicate(value, key, collection)) {
+ result = retKey ? key : value;
+ return false;
+ }
+ });
+ return result;
+ }
+
+ /**
+ * The base implementation of `_.flatten` with added support for restricting
+ * flattening and specifying the start index.
+ *
+ * @private
+ * @param {Array} array The array to flatten.
+ * @param {boolean} [isDeep] Specify a deep flatten.
+ * @param {boolean} [isStrict] Restrict flattening to arrays-like objects.
+ * @param {Array} [result=[]] The initial result value.
+ * @returns {Array} Returns the new flattened array.
+ */
+ function baseFlatten(array, isDeep, isStrict, result) {
+ result || (result = []);
+
+ var index = -1,
+ length = array.length;
+
+ while (++index < length) {
+ var value = array[index];
+ if (isObjectLike(value) && isArrayLike(value) &&
+ (isStrict || isArray(value) || isArguments(value))) {
+ if (isDeep) {
+ // Recursively flatten arrays (susceptible to call stack limits).
+ baseFlatten(value, isDeep, isStrict, result);
+ } else {
+ arrayPush(result, value);
+ }
+ } else if (!isStrict) {
+ result[result.length] = value;
+ }
+ }
+ return result;
+ }
+
+ /**
+ * The base implementation of `baseForIn` and `baseForOwn` which iterates
+ * over `object` properties returned by `keysFunc` invoking `iteratee` for
+ * each property. Iteratee functions may exit iteration early by explicitly
+ * returning `false`.
+ *
+ * @private
+ * @param {Object} object The object to iterate over.
+ * @param {Function} iteratee The function invoked per iteration.
+ * @param {Function} keysFunc The function to get the keys of `object`.
+ * @returns {Object} Returns `object`.
+ */
+ var baseFor = createBaseFor();
+
+ /**
+ * This function is like `baseFor` except that it iterates over properties
+ * in the opposite order.
+ *
+ * @private
+ * @param {Object} object The object to iterate over.
+ * @param {Function} iteratee The function invoked per iteration.
+ * @param {Function} keysFunc The function to get the keys of `object`.
+ * @returns {Object} Returns `object`.
+ */
+ var baseForRight = createBaseFor(true);
+
+ /**
+ * The base implementation of `_.forIn` without support for callback
+ * shorthands and `this` binding.
+ *
+ * @private
+ * @param {Object} object The object to iterate over.
+ * @param {Function} iteratee The function invoked per iteration.
+ * @returns {Object} Returns `object`.
+ */
+ function baseForIn(object, iteratee) {
+ return baseFor(object, iteratee, keysIn);
+ }
+
+ /**
+ * The base implementation of `_.forOwn` without support for callback
+ * shorthands and `this` binding.
+ *
+ * @private
+ * @param {Object} object The object to iterate over.
+ * @param {Function} iteratee The function invoked per iteration.
+ * @returns {Object} Returns `object`.
+ */
+ function baseForOwn(object, iteratee) {
+ return baseFor(object, iteratee, keys);
+ }
+
+ /**
+ * The base implementation of `_.forOwnRight` without support for callback
+ * shorthands and `this` binding.
+ *
+ * @private
+ * @param {Object} object The object to iterate over.
+ * @param {Function} iteratee The function invoked per iteration.
+ * @returns {Object} Returns `object`.
+ */
+ function baseForOwnRight(object, iteratee) {
+ return baseForRight(object, iteratee, keys);
+ }
+
+ /**
+ * The base implementation of `_.functions` which creates an array of
+ * `object` function property names filtered from those provided.
+ *
+ * @private
+ * @param {Object} object The object to inspect.
+ * @param {Array} props The property names to filter.
+ * @returns {Array} Returns the new array of filtered property names.
+ */
+ function baseFunctions(object, props) {
+ var index = -1,
+ length = props.length,
+ resIndex = -1,
+ result = [];
+
+ while (++index < length) {
+ var key = props[index];
+ if (isFunction(object[key])) {
+ result[++resIndex] = key;
+ }
+ }
+ return result;
+ }
+
+ /**
+ * The base implementation of `get` without support for string paths
+ * and default values.
+ *
+ * @private
+ * @param {Object} object The object to query.
+ * @param {Array} path The path of the property to get.
+ * @param {string} [pathKey] The key representation of path.
+ * @returns {*} Returns the resolved value.
+ */
+ function baseGet(object, path, pathKey) {
+ if (object == null) {
+ return;
+ }
+ if (pathKey !== undefined && pathKey in toObject(object)) {
+ path = [pathKey];
+ }
+ var index = 0,
+ length = path.length;
+
+ while (object != null && index < length) {
+ object = object[path[index++]];
+ }
+ return (index && index == length) ? object : undefined;
+ }
+
+ /**
+ * The base implementation of `_.isEqual` without support for `this` binding
+ * `customizer` functions.
+ *
+ * @private
+ * @param {*} value The value to compare.
+ * @param {*} other The other value to compare.
+ * @param {Function} [customizer] The function to customize comparing values.
+ * @param {boolean} [isLoose] Specify performing partial comparisons.
+ * @param {Array} [stackA] Tracks traversed `value` objects.
+ * @param {Array} [stackB] Tracks traversed `other` objects.
+ * @returns {boolean} Returns `true` if the values are equivalent, else `false`.
+ */
+ function baseIsEqual(value, other, customizer, isLoose, stackA, stackB) {
+ if (value === other) {
+ return true;
+ }
+ if (value == null || other == null || (!isObject(value) && !isObjectLike(other))) {
+ return value !== value && other !== other;
+ }
+ return baseIsEqualDeep(value, other, baseIsEqual, customizer, isLoose, stackA, stackB);
+ }
+
+ /**
+ * A specialized version of `baseIsEqual` for arrays and objects which performs
+ * deep comparisons and tracks traversed objects enabling objects with circular
+ * references to be compared.
+ *
+ * @private
+ * @param {Object} object The object to compare.
+ * @param {Object} other The other object to compare.
+ * @param {Function} equalFunc The function to determine equivalents of values.
+ * @param {Function} [customizer] The function to customize comparing objects.
+ * @param {boolean} [isLoose] Specify performing partial comparisons.
+ * @param {Array} [stackA=[]] Tracks traversed `value` objects.
+ * @param {Array} [stackB=[]] Tracks traversed `other` objects.
+ * @returns {boolean} Returns `true` if the objects are equivalent, else `false`.
+ */
+ function baseIsEqualDeep(object, other, equalFunc, customizer, isLoose, stackA, stackB) {
+ var objIsArr = isArray(object),
+ othIsArr = isArray(other),
+ objTag = arrayTag,
+ othTag = arrayTag;
+
+ if (!objIsArr) {
+ objTag = objToString.call(object);
+ if (objTag == argsTag) {
+ objTag = objectTag;
+ } else if (objTag != objectTag) {
+ objIsArr = isTypedArray(object);
+ }
+ }
+ if (!othIsArr) {
+ othTag = objToString.call(other);
+ if (othTag == argsTag) {
+ othTag = objectTag;
+ } else if (othTag != objectTag) {
+ othIsArr = isTypedArray(other);
+ }
+ }
+ var objIsObj = objTag == objectTag,
+ othIsObj = othTag == objectTag,
+ isSameTag = objTag == othTag;
+
+ if (isSameTag && !(objIsArr || objIsObj)) {
+ return equalByTag(object, other, objTag);
+ }
+ if (!isLoose) {
+ var objIsWrapped = objIsObj && hasOwnProperty.call(object, '__wrapped__'),
+ othIsWrapped = othIsObj && hasOwnProperty.call(other, '__wrapped__');
+
+ if (objIsWrapped || othIsWrapped) {
+ return equalFunc(objIsWrapped ? object.value() : object, othIsWrapped ? other.value() : other, customizer, isLoose, stackA, stackB);
+ }
+ }
+ if (!isSameTag) {
+ return false;
+ }
+ // Assume cyclic values are equal.
+ // For more information on detecting circular references see https://es5.github.io/#JO.
+ stackA || (stackA = []);
+ stackB || (stackB = []);
+
+ var length = stackA.length;
+ while (length--) {
+ if (stackA[length] == object) {
+ return stackB[length] == other;
+ }
+ }
+ // Add `object` and `other` to the stack of traversed objects.
+ stackA.push(object);
+ stackB.push(other);
+
+ var result = (objIsArr ? equalArrays : equalObjects)(object, other, equalFunc, customizer, isLoose, stackA, stackB);
+
+ stackA.pop();
+ stackB.pop();
+
+ return result;
+ }
+
+ /**
+ * The base implementation of `_.isMatch` without support for callback
+ * shorthands and `this` binding.
+ *
+ * @private
+ * @param {Object} object The object to inspect.
+ * @param {Array} matchData The propery names, values, and compare flags to match.
+ * @param {Function} [customizer] The function to customize comparing objects.
+ * @returns {boolean} Returns `true` if `object` is a match, else `false`.
+ */
+ function baseIsMatch(object, matchData, customizer) {
+ var index = matchData.length,
+ length = index,
+ noCustomizer = !customizer;
+
+ if (object == null) {
+ return !length;
+ }
+ object = toObject(object);
+ while (index--) {
+ var data = matchData[index];
+ if ((noCustomizer && data[2])
+ ? data[1] !== object[data[0]]
+ : !(data[0] in object)
+ ) {
+ return false;
+ }
+ }
+ while (++index < length) {
+ data = matchData[index];
+ var key = data[0],
+ objValue = object[key],
+ srcValue = data[1];
+
+ if (noCustomizer && data[2]) {
+ if (objValue === undefined && !(key in object)) {
+ return false;
+ }
+ } else {
+ var result = customizer ? customizer(objValue, srcValue, key) : undefined;
+ if (!(result === undefined ? baseIsEqual(srcValue, objValue, customizer, true) : result)) {
+ return false;
+ }
+ }
+ }
+ return true;
+ }
+
+ /**
+ * The base implementation of `_.map` without support for callback shorthands
+ * and `this` binding.
+ *
+ * @private
+ * @param {Array|Object|string} collection The collection to iterate over.
+ * @param {Function} iteratee The function invoked per iteration.
+ * @returns {Array} Returns the new mapped array.
+ */
+ function baseMap(collection, iteratee) {
+ var index = -1,
+ result = isArrayLike(collection) ? Array(collection.length) : [];
+
+ baseEach(collection, function(value, key, collection) {
+ result[++index] = iteratee(value, key, collection);
+ });
+ return result;
+ }
+
+ /**
+ * The base implementation of `_.matches` which does not clone `source`.
+ *
+ * @private
+ * @param {Object} source The object of property values to match.
+ * @returns {Function} Returns the new function.
+ */
+ function baseMatches(source) {
+ var matchData = getMatchData(source);
+ if (matchData.length == 1 && matchData[0][2]) {
+ var key = matchData[0][0],
+ value = matchData[0][1];
+
+ return function(object) {
+ if (object == null) {
+ return false;
+ }
+ return object[key] === value && (value !== undefined || (key in toObject(object)));
+ };
+ }
+ return function(object) {
+ return baseIsMatch(object, matchData);
+ };
+ }
+
+ /**
+ * The base implementation of `_.matchesProperty` which does not clone `srcValue`.
+ *
+ * @private
+ * @param {string} path The path of the property to get.
+ * @param {*} srcValue The value to compare.
+ * @returns {Function} Returns the new function.
+ */
+ function baseMatchesProperty(path, srcValue) {
+ var isArr = isArray(path),
+ isCommon = isKey(path) && isStrictComparable(srcValue),
+ pathKey = (path + '');
+
+ path = toPath(path);
+ return function(object) {
+ if (object == null) {
+ return false;
+ }
+ var key = pathKey;
+ object = toObject(object);
+ if ((isArr || !isCommon) && !(key in object)) {
+ object = path.length == 1 ? object : baseGet(object, baseSlice(path, 0, -1));
+ if (object == null) {
+ return false;
+ }
+ key = last(path);
+ object = toObject(object);
+ }
+ return object[key] === srcValue
+ ? (srcValue !== undefined || (key in object))
+ : baseIsEqual(srcValue, object[key], undefined, true);
+ };
+ }
+
+ /**
+ * The base implementation of `_.merge` without support for argument juggling,
+ * multiple sources, and `this` binding `customizer` functions.
+ *
+ * @private
+ * @param {Object} object The destination object.
+ * @param {Object} source The source object.
+ * @param {Function} [customizer] The function to customize merged values.
+ * @param {Array} [stackA=[]] Tracks traversed source objects.
+ * @param {Array} [stackB=[]] Associates values with source counterparts.
+ * @returns {Object} Returns `object`.
+ */
+ function baseMerge(object, source, customizer, stackA, stackB) {
+ if (!isObject(object)) {
+ return object;
+ }
+ var isSrcArr = isArrayLike(source) && (isArray(source) || isTypedArray(source)),
+ props = isSrcArr ? undefined : keys(source);
+
+ arrayEach(props || source, function(srcValue, key) {
+ if (props) {
+ key = srcValue;
+ srcValue = source[key];
+ }
+ if (isObjectLike(srcValue)) {
+ stackA || (stackA = []);
+ stackB || (stackB = []);
+ baseMergeDeep(object, source, key, baseMerge, customizer, stackA, stackB);
+ }
+ else {
+ var value = object[key],
+ result = customizer ? customizer(value, srcValue, key, object, source) : undefined,
+ isCommon = result === undefined;
+
+ if (isCommon) {
+ result = srcValue;
+ }
+ if ((result !== undefined || (isSrcArr && !(key in object))) &&
+ (isCommon || (result === result ? (result !== value) : (value === value)))) {
+ object[key] = result;
+ }
+ }
+ });
+ return object;
+ }
+
+ /**
+ * A specialized version of `baseMerge` for arrays and objects which performs
+ * deep merges and tracks traversed objects enabling objects with circular
+ * references to be merged.
+ *
+ * @private
+ * @param {Object} object The destination object.
+ * @param {Object} source The source object.
+ * @param {string} key The key of the value to merge.
+ * @param {Function} mergeFunc The function to merge values.
+ * @param {Function} [customizer] The function to customize merged values.
+ * @param {Array} [stackA=[]] Tracks traversed source objects.
+ * @param {Array} [stackB=[]] Associates values with source counterparts.
+ * @returns {boolean} Returns `true` if the objects are equivalent, else `false`.
+ */
+ function baseMergeDeep(object, source, key, mergeFunc, customizer, stackA, stackB) {
+ var length = stackA.length,
+ srcValue = source[key];
+
+ while (length--) {
+ if (stackA[length] == srcValue) {
+ object[key] = stackB[length];
+ return;
+ }
+ }
+ var value = object[key],
+ result = customizer ? customizer(value, srcValue, key, object, source) : undefined,
+ isCommon = result === undefined;
+
+ if (isCommon) {
+ result = srcValue;
+ if (isArrayLike(srcValue) && (isArray(srcValue) || isTypedArray(srcValue))) {
+ result = isArray(value)
+ ? value
+ : (isArrayLike(value) ? arrayCopy(value) : []);
+ }
+ else if (isPlainObject(srcValue) || isArguments(srcValue)) {
+ result = isArguments(value)
+ ? toPlainObject(value)
+ : (isPlainObject(value) ? value : {});
+ }
+ else {
+ isCommon = false;
+ }
+ }
+ // Add the source value to the stack of traversed objects and associate
+ // it with its merged value.
+ stackA.push(srcValue);
+ stackB.push(result);
+
+ if (isCommon) {
+ // Recursively merge objects and arrays (susceptible to call stack limits).
+ object[key] = mergeFunc(result, srcValue, customizer, stackA, stackB);
+ } else if (result === result ? (result !== value) : (value === value)) {
+ object[key] = result;
+ }
+ }
+
+ /**
+ * The base implementation of `_.property` without support for deep paths.
+ *
+ * @private
+ * @param {string} key The key of the property to get.
+ * @returns {Function} Returns the new function.
+ */
+ function baseProperty(key) {
+ return function(object) {
+ return object == null ? undefined : object[key];
+ };
+ }
+
+ /**
+ * A specialized version of `baseProperty` which supports deep paths.
+ *
+ * @private
+ * @param {Array|string} path The path of the property to get.
+ * @returns {Function} Returns the new function.
+ */
+ function basePropertyDeep(path) {
+ var pathKey = (path + '');
+ path = toPath(path);
+ return function(object) {
+ return baseGet(object, path, pathKey);
+ };
+ }
+
+ /**
+ * The base implementation of `_.pullAt` without support for individual
+ * index arguments and capturing the removed elements.
+ *
+ * @private
+ * @param {Array} array The array to modify.
+ * @param {number[]} indexes The indexes of elements to remove.
+ * @returns {Array} Returns `array`.
+ */
+ function basePullAt(array, indexes) {
+ var length = array ? indexes.length : 0;
+ while (length--) {
+ var index = indexes[length];
+ if (index != previous && isIndex(index)) {
+ var previous = index;
+ splice.call(array, index, 1);
+ }
+ }
+ return array;
+ }
+
+ /**
+ * The base implementation of `_.random` without support for argument juggling
+ * and returning floating-point numbers.
+ *
+ * @private
+ * @param {number} min The minimum possible value.
+ * @param {number} max The maximum possible value.
+ * @returns {number} Returns the random number.
+ */
+ function baseRandom(min, max) {
+ return min + nativeFloor(nativeRandom() * (max - min + 1));
+ }
+
+ /**
+ * The base implementation of `_.reduce` and `_.reduceRight` without support
+ * for callback shorthands and `this` binding, which iterates over `collection`
+ * using the provided `eachFunc`.
+ *
+ * @private
+ * @param {Array|Object|string} collection The collection to iterate over.
+ * @param {Function} iteratee The function invoked per iteration.
+ * @param {*} accumulator The initial value.
+ * @param {boolean} initFromCollection Specify using the first or last element
+ * of `collection` as the initial value.
+ * @param {Function} eachFunc The function to iterate over `collection`.
+ * @returns {*} Returns the accumulated value.
+ */
+ function baseReduce(collection, iteratee, accumulator, initFromCollection, eachFunc) {
+ eachFunc(collection, function(value, index, collection) {
+ accumulator = initFromCollection
+ ? (initFromCollection = false, value)
+ : iteratee(accumulator, value, index, collection);
+ });
+ return accumulator;
+ }
+
+ /**
+ * The base implementation of `setData` without support for hot loop detection.
+ *
+ * @private
+ * @param {Function} func The function to associate metadata with.
+ * @param {*} data The metadata.
+ * @returns {Function} Returns `func`.
+ */
+ var baseSetData = !metaMap ? identity : function(func, data) {
+ metaMap.set(func, data);
+ return func;
+ };
+
+ /**
+ * The base implementation of `_.slice` without an iteratee call guard.
+ *
+ * @private
+ * @param {Array} array The array to slice.
+ * @param {number} [start=0] The start position.
+ * @param {number} [end=array.length] The end position.
+ * @returns {Array} Returns the slice of `array`.
+ */
+ function baseSlice(array, start, end) {
+ var index = -1,
+ length = array.length;
+
+ start = start == null ? 0 : (+start || 0);
+ if (start < 0) {
+ start = -start > length ? 0 : (length + start);
+ }
+ end = (end === undefined || end > length) ? length : (+end || 0);
+ if (end < 0) {
+ end += length;
+ }
+ length = start > end ? 0 : ((end - start) >>> 0);
+ start >>>= 0;
+
+ var result = Array(length);
+ while (++index < length) {
+ result[index] = array[index + start];
+ }
+ return result;
+ }
+
+ /**
+ * The base implementation of `_.some` without support for callback shorthands
+ * and `this` binding.
+ *
+ * @private
+ * @param {Array|Object|string} collection The collection to iterate over.
+ * @param {Function} predicate The function invoked per iteration.
+ * @returns {boolean} Returns `true` if any element passes the predicate check,
+ * else `false`.
+ */
+ function baseSome(collection, predicate) {
+ var result;
+
+ baseEach(collection, function(value, index, collection) {
+ result = predicate(value, index, collection);
+ return !result;
+ });
+ return !!result;
+ }
+
+ /**
+ * The base implementation of `_.sortBy` which uses `comparer` to define
+ * the sort order of `array` and replaces criteria objects with their
+ * corresponding values.
+ *
+ * @private
+ * @param {Array} array The array to sort.
+ * @param {Function} comparer The function to define sort order.
+ * @returns {Array} Returns `array`.
+ */
+ function baseSortBy(array, comparer) {
+ var length = array.length;
+
+ array.sort(comparer);
+ while (length--) {
+ array[length] = array[length].value;
+ }
+ return array;
+ }
+
+ /**
+ * The base implementation of `_.sortByOrder` without param guards.
+ *
+ * @private
+ * @param {Array|Object|string} collection The collection to iterate over.
+ * @param {Function[]|Object[]|string[]} iteratees The iteratees to sort by.
+ * @param {boolean[]} orders The sort orders of `iteratees`.
+ * @returns {Array} Returns the new sorted array.
+ */
+ function baseSortByOrder(collection, iteratees, orders) {
+ var callback = getCallback(),
+ index = -1;
+
+ iteratees = arrayMap(iteratees, function(iteratee) { return callback(iteratee); });
+
+ var result = baseMap(collection, function(value) {
+ var criteria = arrayMap(iteratees, function(iteratee) { return iteratee(value); });
+ return { 'criteria': criteria, 'index': ++index, 'value': value };
+ });
+
+ return baseSortBy(result, function(object, other) {
+ return compareMultiple(object, other, orders);
+ });
+ }
+
+ /**
+ * The base implementation of `_.sum` without support for callback shorthands
+ * and `this` binding.
+ *
+ * @private
+ * @param {Array|Object|string} collection The collection to iterate over.
+ * @param {Function} iteratee The function invoked per iteration.
+ * @returns {number} Returns the sum.
+ */
+ function baseSum(collection, iteratee) {
+ var result = 0;
+ baseEach(collection, function(value, index, collection) {
+ result += +iteratee(value, index, collection) || 0;
+ });
+ return result;
+ }
+
+ /**
+ * The base implementation of `_.uniq` without support for callback shorthands
+ * and `this` binding.
+ *
+ * @private
+ * @param {Array} array The array to inspect.
+ * @param {Function} [iteratee] The function invoked per iteration.
+ * @returns {Array} Returns the new duplicate-value-free array.
+ */
+ function baseUniq(array, iteratee) {
+ var index = -1,
+ indexOf = getIndexOf(),
+ length = array.length,
+ isCommon = indexOf == baseIndexOf,
+ isLarge = isCommon && length >= LARGE_ARRAY_SIZE,
+ seen = isLarge ? createCache() : null,
+ result = [];
+
+ if (seen) {
+ indexOf = cacheIndexOf;
+ isCommon = false;
+ } else {
+ isLarge = false;
+ seen = iteratee ? [] : result;
+ }
+ outer:
+ while (++index < length) {
+ var value = array[index],
+ computed = iteratee ? iteratee(value, index, array) : value;
+
+ if (isCommon && value === value) {
+ var seenIndex = seen.length;
+ while (seenIndex--) {
+ if (seen[seenIndex] === computed) {
+ continue outer;
+ }
+ }
+ if (iteratee) {
+ seen.push(computed);
+ }
+ result.push(value);
+ }
+ else if (indexOf(seen, computed, 0) < 0) {
+ if (iteratee || isLarge) {
+ seen.push(computed);
+ }
+ result.push(value);
+ }
+ }
+ return result;
+ }
+
+ /**
+ * The base implementation of `_.values` and `_.valuesIn` which creates an
+ * array of `object` property values corresponding to the property names
+ * of `props`.
+ *
+ * @private
+ * @param {Object} object The object to query.
+ * @param {Array} props The property names to get values for.
+ * @returns {Object} Returns the array of property values.
+ */
+ function baseValues(object, props) {
+ var index = -1,
+ length = props.length,
+ result = Array(length);
+
+ while (++index < length) {
+ result[index] = object[props[index]];
+ }
+ return result;
+ }
+
+ /**
+ * The base implementation of `_.dropRightWhile`, `_.dropWhile`, `_.takeRightWhile`,
+ * and `_.takeWhile` without support for callback shorthands and `this` binding.
+ *
+ * @private
+ * @param {Array} array The array to query.
+ * @param {Function} predicate The function invoked per iteration.
+ * @param {boolean} [isDrop] Specify dropping elements instead of taking them.
+ * @param {boolean} [fromRight] Specify iterating from right to left.
+ * @returns {Array} Returns the slice of `array`.
+ */
+ function baseWhile(array, predicate, isDrop, fromRight) {
+ var length = array.length,
+ index = fromRight ? length : -1;
+
+ while ((fromRight ? index-- : ++index < length) && predicate(array[index], index, array)) {}
+ return isDrop
+ ? baseSlice(array, (fromRight ? 0 : index), (fromRight ? index + 1 : length))
+ : baseSlice(array, (fromRight ? index + 1 : 0), (fromRight ? length : index));
+ }
+
+ /**
+ * The base implementation of `wrapperValue` which returns the result of
+ * performing a sequence of actions on the unwrapped `value`, where each
+ * successive action is supplied the return value of the previous.
+ *
+ * @private
+ * @param {*} value The unwrapped value.
+ * @param {Array} actions Actions to peform to resolve the unwrapped value.
+ * @returns {*} Returns the resolved value.
+ */
+ function baseWrapperValue(value, actions) {
+ var result = value;
+ if (result instanceof LazyWrapper) {
+ result = result.value();
+ }
+ var index = -1,
+ length = actions.length;
+
+ while (++index < length) {
+ var action = actions[index];
+ result = action.func.apply(action.thisArg, arrayPush([result], action.args));
+ }
+ return result;
+ }
+
+ /**
+ * Performs a binary search of `array` to determine the index at which `value`
+ * should be inserted into `array` in order to maintain its sort order.
+ *
+ * @private
+ * @param {Array} array The sorted array to inspect.
+ * @param {*} value The value to evaluate.
+ * @param {boolean} [retHighest] Specify returning the highest qualified index.
+ * @returns {number} Returns the index at which `value` should be inserted
+ * into `array`.
+ */
+ function binaryIndex(array, value, retHighest) {
+ var low = 0,
+ high = array ? array.length : low;
+
+ if (typeof value == 'number' && value === value && high <= HALF_MAX_ARRAY_LENGTH) {
+ while (low < high) {
+ var mid = (low + high) >>> 1,
+ computed = array[mid];
+
+ if ((retHighest ? (computed <= value) : (computed < value)) && computed !== null) {
+ low = mid + 1;
+ } else {
+ high = mid;
+ }
+ }
+ return high;
+ }
+ return binaryIndexBy(array, value, identity, retHighest);
+ }
+
+ /**
+ * This function is like `binaryIndex` except that it invokes `iteratee` for
+ * `value` and each element of `array` to compute their sort ranking. The
+ * iteratee is invoked with one argument; (value).
+ *
+ * @private
+ * @param {Array} array The sorted array to inspect.
+ * @param {*} value The value to evaluate.
+ * @param {Function} iteratee The function invoked per iteration.
+ * @param {boolean} [retHighest] Specify returning the highest qualified index.
+ * @returns {number} Returns the index at which `value` should be inserted
+ * into `array`.
+ */
+ function binaryIndexBy(array, value, iteratee, retHighest) {
+ value = iteratee(value);
+
+ var low = 0,
+ high = array ? array.length : 0,
+ valIsNaN = value !== value,
+ valIsNull = value === null,
+ valIsUndef = value === undefined;
+
+ while (low < high) {
+ var mid = nativeFloor((low + high) / 2),
+ computed = iteratee(array[mid]),
+ isDef = computed !== undefined,
+ isReflexive = computed === computed;
+
+ if (valIsNaN) {
+ var setLow = isReflexive || retHighest;
+ } else if (valIsNull) {
+ setLow = isReflexive && isDef && (retHighest || computed != null);
+ } else if (valIsUndef) {
+ setLow = isReflexive && (retHighest || isDef);
+ } else if (computed == null) {
+ setLow = false;
+ } else {
+ setLow = retHighest ? (computed <= value) : (computed < value);
+ }
+ if (setLow) {
+ low = mid + 1;
+ } else {
+ high = mid;
+ }
+ }
+ return nativeMin(high, MAX_ARRAY_INDEX);
+ }
+
+ /**
+ * A specialized version of `baseCallback` which only supports `this` binding
+ * and specifying the number of arguments to provide to `func`.
+ *
+ * @private
+ * @param {Function} func The function to bind.
+ * @param {*} thisArg The `this` binding of `func`.
+ * @param {number} [argCount] The number of arguments to provide to `func`.
+ * @returns {Function} Returns the callback.
+ */
+ function bindCallback(func, thisArg, argCount) {
+ if (typeof func != 'function') {
+ return identity;
+ }
+ if (thisArg === undefined) {
+ return func;
+ }
+ switch (argCount) {
+ case 1: return function(value) {
+ return func.call(thisArg, value);
+ };
+ case 3: return function(value, index, collection) {
+ return func.call(thisArg, value, index, collection);
+ };
+ case 4: return function(accumulator, value, index, collection) {
+ return func.call(thisArg, accumulator, value, index, collection);
+ };
+ case 5: return function(value, other, key, object, source) {
+ return func.call(thisArg, value, other, key, object, source);
+ };
+ }
+ return function() {
+ return func.apply(thisArg, arguments);
+ };
+ }
+
+ /**
+ * Creates a clone of the given array buffer.
+ *
+ * @private
+ * @param {ArrayBuffer} buffer The array buffer to clone.
+ * @returns {ArrayBuffer} Returns the cloned array buffer.
+ */
+ function bufferClone(buffer) {
+ var result = new ArrayBuffer(buffer.byteLength),
+ view = new Uint8Array(result);
+
+ view.set(new Uint8Array(buffer));
+ return result;
+ }
+
+ /**
+ * Creates an array that is the composition of partially applied arguments,
+ * placeholders, and provided arguments into a single array of arguments.
+ *
+ * @private
+ * @param {Array|Object} args The provided arguments.
+ * @param {Array} partials The arguments to prepend to those provided.
+ * @param {Array} holders The `partials` placeholder indexes.
+ * @returns {Array} Returns the new array of composed arguments.
+ */
+ function composeArgs(args, partials, holders) {
+ var holdersLength = holders.length,
+ argsIndex = -1,
+ argsLength = nativeMax(args.length - holdersLength, 0),
+ leftIndex = -1,
+ leftLength = partials.length,
+ result = Array(leftLength + argsLength);
+
+ while (++leftIndex < leftLength) {
+ result[leftIndex] = partials[leftIndex];
+ }
+ while (++argsIndex < holdersLength) {
+ result[holders[argsIndex]] = args[argsIndex];
+ }
+ while (argsLength--) {
+ result[leftIndex++] = args[argsIndex++];
+ }
+ return result;
+ }
+
+ /**
+ * This function is like `composeArgs` except that the arguments composition
+ * is tailored for `_.partialRight`.
+ *
+ * @private
+ * @param {Array|Object} args The provided arguments.
+ * @param {Array} partials The arguments to append to those provided.
+ * @param {Array} holders The `partials` placeholder indexes.
+ * @returns {Array} Returns the new array of composed arguments.
+ */
+ function composeArgsRight(args, partials, holders) {
+ var holdersIndex = -1,
+ holdersLength = holders.length,
+ argsIndex = -1,
+ argsLength = nativeMax(args.length - holdersLength, 0),
+ rightIndex = -1,
+ rightLength = partials.length,
+ result = Array(argsLength + rightLength);
+
+ while (++argsIndex < argsLength) {
+ result[argsIndex] = args[argsIndex];
+ }
+ var offset = argsIndex;
+ while (++rightIndex < rightLength) {
+ result[offset + rightIndex] = partials[rightIndex];
+ }
+ while (++holdersIndex < holdersLength) {
+ result[offset + holders[holdersIndex]] = args[argsIndex++];
+ }
+ return result;
+ }
+
+ /**
+ * Creates a `_.countBy`, `_.groupBy`, `_.indexBy`, or `_.partition` function.
+ *
+ * @private
+ * @param {Function} setter The function to set keys and values of the accumulator object.
+ * @param {Function} [initializer] The function to initialize the accumulator object.
+ * @returns {Function} Returns the new aggregator function.
+ */
+ function createAggregator(setter, initializer) {
+ return function(collection, iteratee, thisArg) {
+ var result = initializer ? initializer() : {};
+ iteratee = getCallback(iteratee, thisArg, 3);
+
+ if (isArray(collection)) {
+ var index = -1,
+ length = collection.length;
+
+ while (++index < length) {
+ var value = collection[index];
+ setter(result, value, iteratee(value, index, collection), collection);
+ }
+ } else {
+ baseEach(collection, function(value, key, collection) {
+ setter(result, value, iteratee(value, key, collection), collection);
+ });
+ }
+ return result;
+ };
+ }
+
+ /**
+ * Creates a `_.assign`, `_.defaults`, or `_.merge` function.
+ *
+ * @private
+ * @param {Function} assigner The function to assign values.
+ * @returns {Function} Returns the new assigner function.
+ */
+ function createAssigner(assigner) {
+ return restParam(function(object, sources) {
+ var index = -1,
+ length = object == null ? 0 : sources.length,
+ customizer = length > 2 ? sources[length - 2] : undefined,
+ guard = length > 2 ? sources[2] : undefined,
+ thisArg = length > 1 ? sources[length - 1] : undefined;
+
+ if (typeof customizer == 'function') {
+ customizer = bindCallback(customizer, thisArg, 5);
+ length -= 2;
+ } else {
+ customizer = typeof thisArg == 'function' ? thisArg : undefined;
+ length -= (customizer ? 1 : 0);
+ }
+ if (guard && isIterateeCall(sources[0], sources[1], guard)) {
+ customizer = length < 3 ? undefined : customizer;
+ length = 1;
+ }
+ while (++index < length) {
+ var source = sources[index];
+ if (source) {
+ assigner(object, source, customizer);
+ }
+ }
+ return object;
+ });
+ }
+
+ /**
+ * Creates a `baseEach` or `baseEachRight` function.
+ *
+ * @private
+ * @param {Function} eachFunc The function to iterate over a collection.
+ * @param {boolean} [fromRight] Specify iterating from right to left.
+ * @returns {Function} Returns the new base function.
+ */
+ function createBaseEach(eachFunc, fromRight) {
+ return function(collection, iteratee) {
+ var length = collection ? getLength(collection) : 0;
+ if (!isLength(length)) {
+ return eachFunc(collection, iteratee);
+ }
+ var index = fromRight ? length : -1,
+ iterable = toObject(collection);
+
+ while ((fromRight ? index-- : ++index < length)) {
+ if (iteratee(iterable[index], index, iterable) === false) {
+ break;
+ }
+ }
+ return collection;
+ };
+ }
+
+ /**
+ * Creates a base function for `_.forIn` or `_.forInRight`.
+ *
+ * @private
+ * @param {boolean} [fromRight] Specify iterating from right to left.
+ * @returns {Function} Returns the new base function.
+ */
+ function createBaseFor(fromRight) {
+ return function(object, iteratee, keysFunc) {
+ var iterable = toObject(object),
+ props = keysFunc(object),
+ length = props.length,
+ index = fromRight ? length : -1;
+
+ while ((fromRight ? index-- : ++index < length)) {
+ var key = props[index];
+ if (iteratee(iterable[key], key, iterable) === false) {
+ break;
+ }
+ }
+ return object;
+ };
+ }
+
+ /**
+ * Creates a function that wraps `func` and invokes it with the `this`
+ * binding of `thisArg`.
+ *
+ * @private
+ * @param {Function} func The function to bind.
+ * @param {*} [thisArg] The `this` binding of `func`.
+ * @returns {Function} Returns the new bound function.
+ */
+ function createBindWrapper(func, thisArg) {
+ var Ctor = createCtorWrapper(func);
+
+ function wrapper() {
+ var fn = (this && this !== root && this instanceof wrapper) ? Ctor : func;
+ return fn.apply(thisArg, arguments);
+ }
+ return wrapper;
+ }
+
+ /**
+ * Creates a `Set` cache object to optimize linear searches of large arrays.
+ *
+ * @private
+ * @param {Array} [values] The values to cache.
+ * @returns {null|Object} Returns the new cache object if `Set` is supported, else `null`.
+ */
+ function createCache(values) {
+ return (nativeCreate && Set) ? new SetCache(values) : null;
+ }
+
+ /**
+ * Creates a function that produces compound words out of the words in a
+ * given string.
+ *
+ * @private
+ * @param {Function} callback The function to combine each word.
+ * @returns {Function} Returns the new compounder function.
+ */
+ function createCompounder(callback) {
+ return function(string) {
+ var index = -1,
+ array = words(deburr(string)),
+ length = array.length,
+ result = '';
+
+ while (++index < length) {
+ result = callback(result, array[index], index);
+ }
+ return result;
+ };
+ }
+
+ /**
+ * Creates a function that produces an instance of `Ctor` regardless of
+ * whether it was invoked as part of a `new` expression or by `call` or `apply`.
+ *
+ * @private
+ * @param {Function} Ctor The constructor to wrap.
+ * @returns {Function} Returns the new wrapped function.
+ */
+ function createCtorWrapper(Ctor) {
+ return function() {
+ // Use a `switch` statement to work with class constructors.
+ // See http://ecma-international.org/ecma-262/6.0/#sec-ecmascript-function-objects-call-thisargument-argumentslist
+ // for more details.
+ var args = arguments;
+ switch (args.length) {
+ case 0: return new Ctor;
+ case 1: return new Ctor(args[0]);
+ case 2: return new Ctor(args[0], args[1]);
+ case 3: return new Ctor(args[0], args[1], args[2]);
+ case 4: return new Ctor(args[0], args[1], args[2], args[3]);
+ case 5: return new Ctor(args[0], args[1], args[2], args[3], args[4]);
+ case 6: return new Ctor(args[0], args[1], args[2], args[3], args[4], args[5]);
+ case 7: return new Ctor(args[0], args[1], args[2], args[3], args[4], args[5], args[6]);
+ }
+ var thisBinding = baseCreate(Ctor.prototype),
+ result = Ctor.apply(thisBinding, args);
+
+ // Mimic the constructor's `return` behavior.
+ // See https://es5.github.io/#x13.2.2 for more details.
+ return isObject(result) ? result : thisBinding;
+ };
+ }
+
+ /**
+ * Creates a `_.curry` or `_.curryRight` function.
+ *
+ * @private
+ * @param {boolean} flag The curry bit flag.
+ * @returns {Function} Returns the new curry function.
+ */
+ function createCurry(flag) {
+ function curryFunc(func, arity, guard) {
+ if (guard && isIterateeCall(func, arity, guard)) {
+ arity = undefined;
+ }
+ var result = createWrapper(func, flag, undefined, undefined, undefined, undefined, undefined, arity);
+ result.placeholder = curryFunc.placeholder;
+ return result;
+ }
+ return curryFunc;
+ }
+
+ /**
+ * Creates a `_.defaults` or `_.defaultsDeep` function.
+ *
+ * @private
+ * @param {Function} assigner The function to assign values.
+ * @param {Function} customizer The function to customize assigned values.
+ * @returns {Function} Returns the new defaults function.
+ */
+ function createDefaults(assigner, customizer) {
+ return restParam(function(args) {
+ var object = args[0];
+ if (object == null) {
+ return object;
+ }
+ args.push(customizer);
+ return assigner.apply(undefined, args);
+ });
+ }
+
+ /**
+ * Creates a `_.max` or `_.min` function.
+ *
+ * @private
+ * @param {Function} comparator The function used to compare values.
+ * @param {*} exValue The initial extremum value.
+ * @returns {Function} Returns the new extremum function.
+ */
+ function createExtremum(comparator, exValue) {
+ return function(collection, iteratee, thisArg) {
+ if (thisArg && isIterateeCall(collection, iteratee, thisArg)) {
+ iteratee = undefined;
+ }
+ iteratee = getCallback(iteratee, thisArg, 3);
+ if (iteratee.length == 1) {
+ collection = isArray(collection) ? collection : toIterable(collection);
+ var result = arrayExtremum(collection, iteratee, comparator, exValue);
+ if (!(collection.length && result === exValue)) {
+ return result;
+ }
+ }
+ return baseExtremum(collection, iteratee, comparator, exValue);
+ };
+ }
+
+ /**
+ * Creates a `_.find` or `_.findLast` function.
+ *
+ * @private
+ * @param {Function} eachFunc The function to iterate over a collection.
+ * @param {boolean} [fromRight] Specify iterating from right to left.
+ * @returns {Function} Returns the new find function.
+ */
+ function createFind(eachFunc, fromRight) {
+ return function(collection, predicate, thisArg) {
+ predicate = getCallback(predicate, thisArg, 3);
+ if (isArray(collection)) {
+ var index = baseFindIndex(collection, predicate, fromRight);
+ return index > -1 ? collection[index] : undefined;
+ }
+ return baseFind(collection, predicate, eachFunc);
+ };
+ }
+
+ /**
+ * Creates a `_.findIndex` or `_.findLastIndex` function.
+ *
+ * @private
+ * @param {boolean} [fromRight] Specify iterating from right to left.
+ * @returns {Function} Returns the new find function.
+ */
+ function createFindIndex(fromRight) {
+ return function(array, predicate, thisArg) {
+ if (!(array && array.length)) {
+ return -1;
+ }
+ predicate = getCallback(predicate, thisArg, 3);
+ return baseFindIndex(array, predicate, fromRight);
+ };
+ }
+
+ /**
+ * Creates a `_.findKey` or `_.findLastKey` function.
+ *
+ * @private
+ * @param {Function} objectFunc The function to iterate over an object.
+ * @returns {Function} Returns the new find function.
+ */
+ function createFindKey(objectFunc) {
+ return function(object, predicate, thisArg) {
+ predicate = getCallback(predicate, thisArg, 3);
+ return baseFind(object, predicate, objectFunc, true);
+ };
+ }
+
+ /**
+ * Creates a `_.flow` or `_.flowRight` function.
+ *
+ * @private
+ * @param {boolean} [fromRight] Specify iterating from right to left.
+ * @returns {Function} Returns the new flow function.
+ */
+ function createFlow(fromRight) {
+ return function() {
+ var wrapper,
+ length = arguments.length,
+ index = fromRight ? length : -1,
+ leftIndex = 0,
+ funcs = Array(length);
+
+ while ((fromRight ? index-- : ++index < length)) {
+ var func = funcs[leftIndex++] = arguments[index];
+ if (typeof func != 'function') {
+ throw new TypeError(FUNC_ERROR_TEXT);
+ }
+ if (!wrapper && LodashWrapper.prototype.thru && getFuncName(func) == 'wrapper') {
+ wrapper = new LodashWrapper([], true);
+ }
+ }
+ index = wrapper ? -1 : length;
+ while (++index < length) {
+ func = funcs[index];
+
+ var funcName = getFuncName(func),
+ data = funcName == 'wrapper' ? getData(func) : undefined;
+
+ if (data && isLaziable(data[0]) && data[1] == (ARY_FLAG | CURRY_FLAG | PARTIAL_FLAG | REARG_FLAG) && !data[4].length && data[9] == 1) {
+ wrapper = wrapper[getFuncName(data[0])].apply(wrapper, data[3]);
+ } else {
+ wrapper = (func.length == 1 && isLaziable(func)) ? wrapper[funcName]() : wrapper.thru(func);
+ }
+ }
+ return function() {
+ var args = arguments,
+ value = args[0];
+
+ if (wrapper && args.length == 1 && isArray(value) && value.length >= LARGE_ARRAY_SIZE) {
+ return wrapper.plant(value).value();
+ }
+ var index = 0,
+ result = length ? funcs[index].apply(this, args) : value;
+
+ while (++index < length) {
+ result = funcs[index].call(this, result);
+ }
+ return result;
+ };
+ };
+ }
+
+ /**
+ * Creates a function for `_.forEach` or `_.forEachRight`.
+ *
+ * @private
+ * @param {Function} arrayFunc The function to iterate over an array.
+ * @param {Function} eachFunc The function to iterate over a collection.
+ * @returns {Function} Returns the new each function.
+ */
+ function createForEach(arrayFunc, eachFunc) {
+ return function(collection, iteratee, thisArg) {
+ return (typeof iteratee == 'function' && thisArg === undefined && isArray(collection))
+ ? arrayFunc(collection, iteratee)
+ : eachFunc(collection, bindCallback(iteratee, thisArg, 3));
+ };
+ }
+
+ /**
+ * Creates a function for `_.forIn` or `_.forInRight`.
+ *
+ * @private
+ * @param {Function} objectFunc The function to iterate over an object.
+ * @returns {Function} Returns the new each function.
+ */
+ function createForIn(objectFunc) {
+ return function(object, iteratee, thisArg) {
+ if (typeof iteratee != 'function' || thisArg !== undefined) {
+ iteratee = bindCallback(iteratee, thisArg, 3);
+ }
+ return objectFunc(object, iteratee, keysIn);
+ };
+ }
+
+ /**
+ * Creates a function for `_.forOwn` or `_.forOwnRight`.
+ *
+ * @private
+ * @param {Function} objectFunc The function to iterate over an object.
+ * @returns {Function} Returns the new each function.
+ */
+ function createForOwn(objectFunc) {
+ return function(object, iteratee, thisArg) {
+ if (typeof iteratee != 'function' || thisArg !== undefined) {
+ iteratee = bindCallback(iteratee, thisArg, 3);
+ }
+ return objectFunc(object, iteratee);
+ };
+ }
+
+ /**
+ * Creates a function for `_.mapKeys` or `_.mapValues`.
+ *
+ * @private
+ * @param {boolean} [isMapKeys] Specify mapping keys instead of values.
+ * @returns {Function} Returns the new map function.
+ */
+ function createObjectMapper(isMapKeys) {
+ return function(object, iteratee, thisArg) {
+ var result = {};
+ iteratee = getCallback(iteratee, thisArg, 3);
+
+ baseForOwn(object, function(value, key, object) {
+ var mapped = iteratee(value, key, object);
+ key = isMapKeys ? mapped : key;
+ value = isMapKeys ? value : mapped;
+ result[key] = value;
+ });
+ return result;
+ };
+ }
+
+ /**
+ * Creates a function for `_.padLeft` or `_.padRight`.
+ *
+ * @private
+ * @param {boolean} [fromRight] Specify padding from the right.
+ * @returns {Function} Returns the new pad function.
+ */
+ function createPadDir(fromRight) {
+ return function(string, length, chars) {
+ string = baseToString(string);
+ return (fromRight ? string : '') + createPadding(string, length, chars) + (fromRight ? '' : string);
+ };
+ }
+
+ /**
+ * Creates a `_.partial` or `_.partialRight` function.
+ *
+ * @private
+ * @param {boolean} flag The partial bit flag.
+ * @returns {Function} Returns the new partial function.
+ */
+ function createPartial(flag) {
+ var partialFunc = restParam(function(func, partials) {
+ var holders = replaceHolders(partials, partialFunc.placeholder);
+ return createWrapper(func, flag, undefined, partials, holders);
+ });
+ return partialFunc;
+ }
+
+ /**
+ * Creates a function for `_.reduce` or `_.reduceRight`.
+ *
+ * @private
+ * @param {Function} arrayFunc The function to iterate over an array.
+ * @param {Function} eachFunc The function to iterate over a collection.
+ * @returns {Function} Returns the new each function.
+ */
+ function createReduce(arrayFunc, eachFunc) {
+ return function(collection, iteratee, accumulator, thisArg) {
+ var initFromArray = arguments.length < 3;
+ return (typeof iteratee == 'function' && thisArg === undefined && isArray(collection))
+ ? arrayFunc(collection, iteratee, accumulator, initFromArray)
+ : baseReduce(collection, getCallback(iteratee, thisArg, 4), accumulator, initFromArray, eachFunc);
+ };
+ }
+
+ /**
+ * Creates a function that wraps `func` and invokes it with optional `this`
+ * binding of, partial application, and currying.
+ *
+ * @private
+ * @param {Function|string} func The function or method name to reference.
+ * @param {number} bitmask The bitmask of flags. See `createWrapper` for more details.
+ * @param {*} [thisArg] The `this` binding of `func`.
+ * @param {Array} [partials] The arguments to prepend to those provided to the new function.
+ * @param {Array} [holders] The `partials` placeholder indexes.
+ * @param {Array} [partialsRight] The arguments to append to those provided to the new function.
+ * @param {Array} [holdersRight] The `partialsRight` placeholder indexes.
+ * @param {Array} [argPos] The argument positions of the new function.
+ * @param {number} [ary] The arity cap of `func`.
+ * @param {number} [arity] The arity of `func`.
+ * @returns {Function} Returns the new wrapped function.
+ */
+ function createHybridWrapper(func, bitmask, thisArg, partials, holders, partialsRight, holdersRight, argPos, ary, arity) {
+ var isAry = bitmask & ARY_FLAG,
+ isBind = bitmask & BIND_FLAG,
+ isBindKey = bitmask & BIND_KEY_FLAG,
+ isCurry = bitmask & CURRY_FLAG,
+ isCurryBound = bitmask & CURRY_BOUND_FLAG,
+ isCurryRight = bitmask & CURRY_RIGHT_FLAG,
+ Ctor = isBindKey ? undefined : createCtorWrapper(func);
+
+ function wrapper() {
+ // Avoid `arguments` object use disqualifying optimizations by
+ // converting it to an array before providing it to other functions.
+ var length = arguments.length,
+ index = length,
+ args = Array(length);
+
+ while (index--) {
+ args[index] = arguments[index];
+ }
+ if (partials) {
+ args = composeArgs(args, partials, holders);
+ }
+ if (partialsRight) {
+ args = composeArgsRight(args, partialsRight, holdersRight);
+ }
+ if (isCurry || isCurryRight) {
+ var placeholder = wrapper.placeholder,
+ argsHolders = replaceHolders(args, placeholder);
+
+ length -= argsHolders.length;
+ if (length < arity) {
+ var newArgPos = argPos ? arrayCopy(argPos) : undefined,
+ newArity = nativeMax(arity - length, 0),
+ newsHolders = isCurry ? argsHolders : undefined,
+ newHoldersRight = isCurry ? undefined : argsHolders,
+ newPartials = isCurry ? args : undefined,
+ newPartialsRight = isCurry ? undefined : args;
+
+ bitmask |= (isCurry ? PARTIAL_FLAG : PARTIAL_RIGHT_FLAG);
+ bitmask &= ~(isCurry ? PARTIAL_RIGHT_FLAG : PARTIAL_FLAG);
+
+ if (!isCurryBound) {
+ bitmask &= ~(BIND_FLAG | BIND_KEY_FLAG);
+ }
+ var newData = [func, bitmask, thisArg, newPartials, newsHolders, newPartialsRight, newHoldersRight, newArgPos, ary, newArity],
+ result = createHybridWrapper.apply(undefined, newData);
+
+ if (isLaziable(func)) {
+ setData(result, newData);
+ }
+ result.placeholder = placeholder;
+ return result;
+ }
+ }
+ var thisBinding = isBind ? thisArg : this,
+ fn = isBindKey ? thisBinding[func] : func;
+
+ if (argPos) {
+ args = reorder(args, argPos);
+ }
+ if (isAry && ary < args.length) {
+ args.length = ary;
+ }
+ if (this && this !== root && this instanceof wrapper) {
+ fn = Ctor || createCtorWrapper(func);
+ }
+ return fn.apply(thisBinding, args);
+ }
+ return wrapper;
+ }
+
+ /**
+ * Creates the padding required for `string` based on the given `length`.
+ * The `chars` string is truncated if the number of characters exceeds `length`.
+ *
+ * @private
+ * @param {string} string The string to create padding for.
+ * @param {number} [length=0] The padding length.
+ * @param {string} [chars=' '] The string used as padding.
+ * @returns {string} Returns the pad for `string`.
+ */
+ function createPadding(string, length, chars) {
+ var strLength = string.length;
+ length = +length;
+
+ if (strLength >= length || !nativeIsFinite(length)) {
+ return '';
+ }
+ var padLength = length - strLength;
+ chars = chars == null ? ' ' : (chars + '');
+ return repeat(chars, nativeCeil(padLength / chars.length)).slice(0, padLength);
+ }
+
+ /**
+ * Creates a function that wraps `func` and invokes it with the optional `this`
+ * binding of `thisArg` and the `partials` prepended to those provided to
+ * the wrapper.
+ *
+ * @private
+ * @param {Function} func The function to partially apply arguments to.
+ * @param {number} bitmask The bitmask of flags. See `createWrapper` for more details.
+ * @param {*} thisArg The `this` binding of `func`.
+ * @param {Array} partials The arguments to prepend to those provided to the new function.
+ * @returns {Function} Returns the new bound function.
+ */
+ function createPartialWrapper(func, bitmask, thisArg, partials) {
+ var isBind = bitmask & BIND_FLAG,
+ Ctor = createCtorWrapper(func);
+
+ function wrapper() {
+ // Avoid `arguments` object use disqualifying optimizations by
+ // converting it to an array before providing it `func`.
+ var argsIndex = -1,
+ argsLength = arguments.length,
+ leftIndex = -1,
+ leftLength = partials.length,
+ args = Array(leftLength + argsLength);
+
+ while (++leftIndex < leftLength) {
+ args[leftIndex] = partials[leftIndex];
+ }
+ while (argsLength--) {
+ args[leftIndex++] = arguments[++argsIndex];
+ }
+ var fn = (this && this !== root && this instanceof wrapper) ? Ctor : func;
+ return fn.apply(isBind ? thisArg : this, args);
+ }
+ return wrapper;
+ }
+
+ /**
+ * Creates a `_.ceil`, `_.floor`, or `_.round` function.
+ *
+ * @private
+ * @param {string} methodName The name of the `Math` method to use when rounding.
+ * @returns {Function} Returns the new round function.
+ */
+ function createRound(methodName) {
+ var func = Math[methodName];
+ return function(number, precision) {
+ precision = precision === undefined ? 0 : (+precision || 0);
+ if (precision) {
+ precision = pow(10, precision);
+ return func(number * precision) / precision;
+ }
+ return func(number);
+ };
+ }
+
+ /**
+ * Creates a `_.sortedIndex` or `_.sortedLastIndex` function.
+ *
+ * @private
+ * @param {boolean} [retHighest] Specify returning the highest qualified index.
+ * @returns {Function} Returns the new index function.
+ */
+ function createSortedIndex(retHighest) {
+ return function(array, value, iteratee, thisArg) {
+ var callback = getCallback(iteratee);
+ return (iteratee == null && callback === baseCallback)
+ ? binaryIndex(array, value, retHighest)
+ : binaryIndexBy(array, value, callback(iteratee, thisArg, 1), retHighest);
+ };
+ }
+
+ /**
+ * Creates a function that either curries or invokes `func` with optional
+ * `this` binding and partially applied arguments.
+ *
+ * @private
+ * @param {Function|string} func The function or method name to reference.
+ * @param {number} bitmask The bitmask of flags.
+ * The bitmask may be composed of the following flags:
+ * 1 - `_.bind`
+ * 2 - `_.bindKey`
+ * 4 - `_.curry` or `_.curryRight` of a bound function
+ * 8 - `_.curry`
+ * 16 - `_.curryRight`
+ * 32 - `_.partial`
+ * 64 - `_.partialRight`
+ * 128 - `_.rearg`
+ * 256 - `_.ary`
+ * @param {*} [thisArg] The `this` binding of `func`.
+ * @param {Array} [partials] The arguments to be partially applied.
+ * @param {Array} [holders] The `partials` placeholder indexes.
+ * @param {Array} [argPos] The argument positions of the new function.
+ * @param {number} [ary] The arity cap of `func`.
+ * @param {number} [arity] The arity of `func`.
+ * @returns {Function} Returns the new wrapped function.
+ */
+ function createWrapper(func, bitmask, thisArg, partials, holders, argPos, ary, arity) {
+ var isBindKey = bitmask & BIND_KEY_FLAG;
+ if (!isBindKey && typeof func != 'function') {
+ throw new TypeError(FUNC_ERROR_TEXT);
+ }
+ var length = partials ? partials.length : 0;
+ if (!length) {
+ bitmask &= ~(PARTIAL_FLAG | PARTIAL_RIGHT_FLAG);
+ partials = holders = undefined;
+ }
+ length -= (holders ? holders.length : 0);
+ if (bitmask & PARTIAL_RIGHT_FLAG) {
+ var partialsRight = partials,
+ holdersRight = holders;
+
+ partials = holders = undefined;
+ }
+ var data = isBindKey ? undefined : getData(func),
+ newData = [func, bitmask, thisArg, partials, holders, partialsRight, holdersRight, argPos, ary, arity];
+
+ if (data) {
+ mergeData(newData, data);
+ bitmask = newData[1];
+ arity = newData[9];
+ }
+ newData[9] = arity == null
+ ? (isBindKey ? 0 : func.length)
+ : (nativeMax(arity - length, 0) || 0);
+
+ if (bitmask == BIND_FLAG) {
+ var result = createBindWrapper(newData[0], newData[2]);
+ } else if ((bitmask == PARTIAL_FLAG || bitmask == (BIND_FLAG | PARTIAL_FLAG)) && !newData[4].length) {
+ result = createPartialWrapper.apply(undefined, newData);
+ } else {
+ result = createHybridWrapper.apply(undefined, newData);
+ }
+ var setter = data ? baseSetData : setData;
+ return setter(result, newData);
+ }
+
+ /**
+ * A specialized version of `baseIsEqualDeep` for arrays with support for
+ * partial deep comparisons.
+ *
+ * @private
+ * @param {Array} array The array to compare.
+ * @param {Array} other The other array to compare.
+ * @param {Function} equalFunc The function to determine equivalents of values.
+ * @param {Function} [customizer] The function to customize comparing arrays.
+ * @param {boolean} [isLoose] Specify performing partial comparisons.
+ * @param {Array} [stackA] Tracks traversed `value` objects.
+ * @param {Array} [stackB] Tracks traversed `other` objects.
+ * @returns {boolean} Returns `true` if the arrays are equivalent, else `false`.
+ */
+ function equalArrays(array, other, equalFunc, customizer, isLoose, stackA, stackB) {
+ var index = -1,
+ arrLength = array.length,
+ othLength = other.length;
+
+ if (arrLength != othLength && !(isLoose && othLength > arrLength)) {
+ return false;
+ }
+ // Ignore non-index properties.
+ while (++index < arrLength) {
+ var arrValue = array[index],
+ othValue = other[index],
+ result = customizer ? customizer(isLoose ? othValue : arrValue, isLoose ? arrValue : othValue, index) : undefined;
+
+ if (result !== undefined) {
+ if (result) {
+ continue;
+ }
+ return false;
+ }
+ // Recursively compare arrays (susceptible to call stack limits).
+ if (isLoose) {
+ if (!arraySome(other, function(othValue) {
+ return arrValue === othValue || equalFunc(arrValue, othValue, customizer, isLoose, stackA, stackB);
+ })) {
+ return false;
+ }
+ } else if (!(arrValue === othValue || equalFunc(arrValue, othValue, customizer, isLoose, stackA, stackB))) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ /**
+ * A specialized version of `baseIsEqualDeep` for comparing objects of
+ * the same `toStringTag`.
+ *
+ * **Note:** This function only supports comparing values with tags of
+ * `Boolean`, `Date`, `Error`, `Number`, `RegExp`, or `String`.
+ *
+ * @private
+ * @param {Object} object The object to compare.
+ * @param {Object} other The other object to compare.
+ * @param {string} tag The `toStringTag` of the objects to compare.
+ * @returns {boolean} Returns `true` if the objects are equivalent, else `false`.
+ */
+ function equalByTag(object, other, tag) {
+ switch (tag) {
+ case boolTag:
+ case dateTag:
+ // Coerce dates and booleans to numbers, dates to milliseconds and booleans
+ // to `1` or `0` treating invalid dates coerced to `NaN` as not equal.
+ return +object == +other;
+
+ case errorTag:
+ return object.name == other.name && object.message == other.message;
+
+ case numberTag:
+ // Treat `NaN` vs. `NaN` as equal.
+ return (object != +object)
+ ? other != +other
+ : object == +other;
+
+ case regexpTag:
+ case stringTag:
+ // Coerce regexes to strings and treat strings primitives and string
+ // objects as equal. See https://es5.github.io/#x15.10.6.4 for more details.
+ return object == (other + '');
+ }
+ return false;
+ }
+
+ /**
+ * A specialized version of `baseIsEqualDeep` for objects with support for
+ * partial deep comparisons.
+ *
+ * @private
+ * @param {Object} object The object to compare.
+ * @param {Object} other The other object to compare.
+ * @param {Function} equalFunc The function to determine equivalents of values.
+ * @param {Function} [customizer] The function to customize comparing values.
+ * @param {boolean} [isLoose] Specify performing partial comparisons.
+ * @param {Array} [stackA] Tracks traversed `value` objects.
+ * @param {Array} [stackB] Tracks traversed `other` objects.
+ * @returns {boolean} Returns `true` if the objects are equivalent, else `false`.
+ */
+ function equalObjects(object, other, equalFunc, customizer, isLoose, stackA, stackB) {
+ var objProps = keys(object),
+ objLength = objProps.length,
+ othProps = keys(other),
+ othLength = othProps.length;
+
+ if (objLength != othLength && !isLoose) {
+ return false;
+ }
+ var index = objLength;
+ while (index--) {
+ var key = objProps[index];
+ if (!(isLoose ? key in other : hasOwnProperty.call(other, key))) {
+ return false;
+ }
+ }
+ var skipCtor = isLoose;
+ while (++index < objLength) {
+ key = objProps[index];
+ var objValue = object[key],
+ othValue = other[key],
+ result = customizer ? customizer(isLoose ? othValue : objValue, isLoose? objValue : othValue, key) : undefined;
+
+ // Recursively compare objects (susceptible to call stack limits).
+ if (!(result === undefined ? equalFunc(objValue, othValue, customizer, isLoose, stackA, stackB) : result)) {
+ return false;
+ }
+ skipCtor || (skipCtor = key == 'constructor');
+ }
+ if (!skipCtor) {
+ var objCtor = object.constructor,
+ othCtor = other.constructor;
+
+ // Non `Object` object instances with different constructors are not equal.
+ if (objCtor != othCtor &&
+ ('constructor' in object && 'constructor' in other) &&
+ !(typeof objCtor == 'function' && objCtor instanceof objCtor &&
+ typeof othCtor == 'function' && othCtor instanceof othCtor)) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ /**
+ * Gets the appropriate "callback" function. If the `_.callback` method is
+ * customized this function returns the custom method, otherwise it returns
+ * the `baseCallback` function. If arguments are provided the chosen function
+ * is invoked with them and its result is returned.
+ *
+ * @private
+ * @returns {Function} Returns the chosen function or its result.
+ */
+ function getCallback(func, thisArg, argCount) {
+ var result = lodash.callback || callback;
+ result = result === callback ? baseCallback : result;
+ return argCount ? result(func, thisArg, argCount) : result;
+ }
+
+ /**
+ * Gets metadata for `func`.
+ *
+ * @private
+ * @param {Function} func The function to query.
+ * @returns {*} Returns the metadata for `func`.
+ */
+ var getData = !metaMap ? noop : function(func) {
+ return metaMap.get(func);
+ };
+
+ /**
+ * Gets the name of `func`.
+ *
+ * @private
+ * @param {Function} func The function to query.
+ * @returns {string} Returns the function name.
+ */
+ function getFuncName(func) {
+ var result = func.name,
+ array = realNames[result],
+ length = array ? array.length : 0;
+
+ while (length--) {
+ var data = array[length],
+ otherFunc = data.func;
+ if (otherFunc == null || otherFunc == func) {
+ return data.name;
+ }
+ }
+ return result;
+ }
+
+ /**
+ * Gets the appropriate "indexOf" function. If the `_.indexOf` method is
+ * customized this function returns the custom method, otherwise it returns
+ * the `baseIndexOf` function. If arguments are provided the chosen function
+ * is invoked with them and its result is returned.
+ *
+ * @private
+ * @returns {Function|number} Returns the chosen function or its result.
+ */
+ function getIndexOf(collection, target, fromIndex) {
+ var result = lodash.indexOf || indexOf;
+ result = result === indexOf ? baseIndexOf : result;
+ return collection ? result(collection, target, fromIndex) : result;
+ }
+
+ /**
+ * Gets the "length" property value of `object`.
+ *
+ * **Note:** This function is used to avoid a [JIT bug](https://bugs.webkit.org/show_bug.cgi?id=142792)
+ * that affects Safari on at least iOS 8.1-8.3 ARM64.
+ *
+ * @private
+ * @param {Object} object The object to query.
+ * @returns {*} Returns the "length" value.
+ */
+ var getLength = baseProperty('length');
+
+ /**
+ * Gets the propery names, values, and compare flags of `object`.
+ *
+ * @private
+ * @param {Object} object The object to query.
+ * @returns {Array} Returns the match data of `object`.
+ */
+ function getMatchData(object) {
+ var result = pairs(object),
+ length = result.length;
+
+ while (length--) {
+ result[length][2] = isStrictComparable(result[length][1]);
+ }
+ return result;
+ }
+
+ /**
+ * Gets the native function at `key` of `object`.
+ *
+ * @private
+ * @param {Object} object The object to query.
+ * @param {string} key The key of the method to get.
+ * @returns {*} Returns the function if it's native, else `undefined`.
+ */
+ function getNative(object, key) {
+ var value = object == null ? undefined : object[key];
+ return isNative(value) ? value : undefined;
+ }
+
+ /**
+ * Gets the view, applying any `transforms` to the `start` and `end` positions.
+ *
+ * @private
+ * @param {number} start The start of the view.
+ * @param {number} end The end of the view.
+ * @param {Array} transforms The transformations to apply to the view.
+ * @returns {Object} Returns an object containing the `start` and `end`
+ * positions of the view.
+ */
+ function getView(start, end, transforms) {
+ var index = -1,
+ length = transforms.length;
+
+ while (++index < length) {
+ var data = transforms[index],
+ size = data.size;
+
+ switch (data.type) {
+ case 'drop': start += size; break;
+ case 'dropRight': end -= size; break;
+ case 'take': end = nativeMin(end, start + size); break;
+ case 'takeRight': start = nativeMax(start, end - size); break;
+ }
+ }
+ return { 'start': start, 'end': end };
+ }
+
+ /**
+ * Initializes an array clone.
+ *
+ * @private
+ * @param {Array} array The array to clone.
+ * @returns {Array} Returns the initialized clone.
+ */
+ function initCloneArray(array) {
+ var length = array.length,
+ result = new array.constructor(length);
+
+ // Add array properties assigned by `RegExp#exec`.
+ if (length && typeof array[0] == 'string' && hasOwnProperty.call(array, 'index')) {
+ result.index = array.index;
+ result.input = array.input;
+ }
+ return result;
+ }
+
+ /**
+ * Initializes an object clone.
+ *
+ * @private
+ * @param {Object} object The object to clone.
+ * @returns {Object} Returns the initialized clone.
+ */
+ function initCloneObject(object) {
+ var Ctor = object.constructor;
+ if (!(typeof Ctor == 'function' && Ctor instanceof Ctor)) {
+ Ctor = Object;
+ }
+ return new Ctor;
+ }
+
+ /**
+ * Initializes an object clone based on its `toStringTag`.
+ *
+ * **Note:** This function only supports cloning values with tags of
+ * `Boolean`, `Date`, `Error`, `Number`, `RegExp`, or `String`.
+ *
+ * @private
+ * @param {Object} object The object to clone.
+ * @param {string} tag The `toStringTag` of the object to clone.
+ * @param {boolean} [isDeep] Specify a deep clone.
+ * @returns {Object} Returns the initialized clone.
+ */
+ function initCloneByTag(object, tag, isDeep) {
+ var Ctor = object.constructor;
+ switch (tag) {
+ case arrayBufferTag:
+ return bufferClone(object);
+
+ case boolTag:
+ case dateTag:
+ return new Ctor(+object);
+
+ case float32Tag: case float64Tag:
+ case int8Tag: case int16Tag: case int32Tag:
+ case uint8Tag: case uint8ClampedTag: case uint16Tag: case uint32Tag:
+ var buffer = object.buffer;
+ return new Ctor(isDeep ? bufferClone(buffer) : buffer, object.byteOffset, object.length);
+
+ case numberTag:
+ case stringTag:
+ return new Ctor(object);
+
+ case regexpTag:
+ var result = new Ctor(object.source, reFlags.exec(object));
+ result.lastIndex = object.lastIndex;
+ }
+ return result;
+ }
+
+ /**
+ * Invokes the method at `path` on `object`.
+ *
+ * @private
+ * @param {Object} object The object to query.
+ * @param {Array|string} path The path of the method to invoke.
+ * @param {Array} args The arguments to invoke the method with.
+ * @returns {*} Returns the result of the invoked method.
+ */
+ function invokePath(object, path, args) {
+ if (object != null && !isKey(path, object)) {
+ path = toPath(path);
+ object = path.length == 1 ? object : baseGet(object, baseSlice(path, 0, -1));
+ path = last(path);
+ }
+ var func = object == null ? object : object[path];
+ return func == null ? undefined : func.apply(object, args);
+ }
+
+ /**
+ * Checks if `value` is array-like.
+ *
+ * @private
+ * @param {*} value The value to check.
+ * @returns {boolean} Returns `true` if `value` is array-like, else `false`.
+ */
+ function isArrayLike(value) {
+ return value != null && isLength(getLength(value));
+ }
+
+ /**
+ * Checks if `value` is a valid array-like index.
+ *
+ * @private
+ * @param {*} value The value to check.
+ * @param {number} [length=MAX_SAFE_INTEGER] The upper bounds of a valid index.
+ * @returns {boolean} Returns `true` if `value` is a valid index, else `false`.
+ */
+ function isIndex(value, length) {
+ value = (typeof value == 'number' || reIsUint.test(value)) ? +value : -1;
+ length = length == null ? MAX_SAFE_INTEGER : length;
+ return value > -1 && value % 1 == 0 && value < length;
+ }
+
+ /**
+ * Checks if the provided arguments are from an iteratee call.
+ *
+ * @private
+ * @param {*} value The potential iteratee value argument.
+ * @param {*} index The potential iteratee index or key argument.
+ * @param {*} object The potential iteratee object argument.
+ * @returns {boolean} Returns `true` if the arguments are from an iteratee call, else `false`.
+ */
+ function isIterateeCall(value, index, object) {
+ if (!isObject(object)) {
+ return false;
+ }
+ var type = typeof index;
+ if (type == 'number'
+ ? (isArrayLike(object) && isIndex(index, object.length))
+ : (type == 'string' && index in object)) {
+ var other = object[index];
+ return value === value ? (value === other) : (other !== other);
+ }
+ return false;
+ }
+
+ /**
+ * Checks if `value` is a property name and not a property path.
+ *
+ * @private
+ * @param {*} value The value to check.
+ * @param {Object} [object] The object to query keys on.
+ * @returns {boolean} Returns `true` if `value` is a property name, else `false`.
+ */
+ function isKey(value, object) {
+ var type = typeof value;
+ if ((type == 'string' && reIsPlainProp.test(value)) || type == 'number') {
+ return true;
+ }
+ if (isArray(value)) {
+ return false;
+ }
+ var result = !reIsDeepProp.test(value);
+ return result || (object != null && value in toObject(object));
+ }
+
+ /**
+ * Checks if `func` has a lazy counterpart.
+ *
+ * @private
+ * @param {Function} func The function to check.
+ * @returns {boolean} Returns `true` if `func` has a lazy counterpart, else `false`.
+ */
+ function isLaziable(func) {
+ var funcName = getFuncName(func);
+ if (!(funcName in LazyWrapper.prototype)) {
+ return false;
+ }
+ var other = lodash[funcName];
+ if (func === other) {
+ return true;
+ }
+ var data = getData(other);
+ return !!data && func === data[0];
+ }
+
+ /**
+ * Checks if `value` is a valid array-like length.
+ *
+ * **Note:** This function is based on [`ToLength`](http://ecma-international.org/ecma-262/6.0/#sec-tolength).
+ *
+ * @private
+ * @param {*} value The value to check.
+ * @returns {boolean} Returns `true` if `value` is a valid length, else `false`.
+ */
+ function isLength(value) {
+ return typeof value == 'number' && value > -1 && value % 1 == 0 && value <= MAX_SAFE_INTEGER;
+ }
+
+ /**
+ * Checks if `value` is suitable for strict equality comparisons, i.e. `===`.
+ *
+ * @private
+ * @param {*} value The value to check.
+ * @returns {boolean} Returns `true` if `value` if suitable for strict
+ * equality comparisons, else `false`.
+ */
+ function isStrictComparable(value) {
+ return value === value && !isObject(value);
+ }
+
+ /**
+ * Merges the function metadata of `source` into `data`.
+ *
+ * Merging metadata reduces the number of wrappers required to invoke a function.
+ * This is possible because methods like `_.bind`, `_.curry`, and `_.partial`
+ * may be applied regardless of execution order. Methods like `_.ary` and `_.rearg`
+ * augment function arguments, making the order in which they are executed important,
+ * preventing the merging of metadata. However, we make an exception for a safe
+ * common case where curried functions have `_.ary` and or `_.rearg` applied.
+ *
+ * @private
+ * @param {Array} data The destination metadata.
+ * @param {Array} source The source metadata.
+ * @returns {Array} Returns `data`.
+ */
+ function mergeData(data, source) {
+ var bitmask = data[1],
+ srcBitmask = source[1],
+ newBitmask = bitmask | srcBitmask,
+ isCommon = newBitmask < ARY_FLAG;
+
+ var isCombo =
+ (srcBitmask == ARY_FLAG && bitmask == CURRY_FLAG) ||
+ (srcBitmask == ARY_FLAG && bitmask == REARG_FLAG && data[7].length <= source[8]) ||
+ (srcBitmask == (ARY_FLAG | REARG_FLAG) && bitmask == CURRY_FLAG);
+
+ // Exit early if metadata can't be merged.
+ if (!(isCommon || isCombo)) {
+ return data;
+ }
+ // Use source `thisArg` if available.
+ if (srcBitmask & BIND_FLAG) {
+ data[2] = source[2];
+ // Set when currying a bound function.
+ newBitmask |= (bitmask & BIND_FLAG) ? 0 : CURRY_BOUND_FLAG;
+ }
+ // Compose partial arguments.
+ var value = source[3];
+ if (value) {
+ var partials = data[3];
+ data[3] = partials ? composeArgs(partials, value, source[4]) : arrayCopy(value);
+ data[4] = partials ? replaceHolders(data[3], PLACEHOLDER) : arrayCopy(source[4]);
+ }
+ // Compose partial right arguments.
+ value = source[5];
+ if (value) {
+ partials = data[5];
+ data[5] = partials ? composeArgsRight(partials, value, source[6]) : arrayCopy(value);
+ data[6] = partials ? replaceHolders(data[5], PLACEHOLDER) : arrayCopy(source[6]);
+ }
+ // Use source `argPos` if available.
+ value = source[7];
+ if (value) {
+ data[7] = arrayCopy(value);
+ }
+ // Use source `ary` if it's smaller.
+ if (srcBitmask & ARY_FLAG) {
+ data[8] = data[8] == null ? source[8] : nativeMin(data[8], source[8]);
+ }
+ // Use source `arity` if one is not provided.
+ if (data[9] == null) {
+ data[9] = source[9];
+ }
+ // Use source `func` and merge bitmasks.
+ data[0] = source[0];
+ data[1] = newBitmask;
+
+ return data;
+ }
+
+ /**
+ * Used by `_.defaultsDeep` to customize its `_.merge` use.
+ *
+ * @private
+ * @param {*} objectValue The destination object property value.
+ * @param {*} sourceValue The source object property value.
+ * @returns {*} Returns the value to assign to the destination object.
+ */
+ function mergeDefaults(objectValue, sourceValue) {
+ return objectValue === undefined ? sourceValue : merge(objectValue, sourceValue, mergeDefaults);
+ }
+
+ /**
+ * A specialized version of `_.pick` which picks `object` properties specified
+ * by `props`.
+ *
+ * @private
+ * @param {Object} object The source object.
+ * @param {string[]} props The property names to pick.
+ * @returns {Object} Returns the new object.
+ */
+ function pickByArray(object, props) {
+ object = toObject(object);
+
+ var index = -1,
+ length = props.length,
+ result = {};
+
+ while (++index < length) {
+ var key = props[index];
+ if (key in object) {
+ result[key] = object[key];
+ }
+ }
+ return result;
+ }
+
+ /**
+ * A specialized version of `_.pick` which picks `object` properties `predicate`
+ * returns truthy for.
+ *
+ * @private
+ * @param {Object} object The source object.
+ * @param {Function} predicate The function invoked per iteration.
+ * @returns {Object} Returns the new object.
+ */
+ function pickByCallback(object, predicate) {
+ var result = {};
+ baseForIn(object, function(value, key, object) {
+ if (predicate(value, key, object)) {
+ result[key] = value;
+ }
+ });
+ return result;
+ }
+
+ /**
+ * Reorder `array` according to the specified indexes where the element at
+ * the first index is assigned as the first element, the element at
+ * the second index is assigned as the second element, and so on.
+ *
+ * @private
+ * @param {Array} array The array to reorder.
+ * @param {Array} indexes The arranged array indexes.
+ * @returns {Array} Returns `array`.
+ */
+ function reorder(array, indexes) {
+ var arrLength = array.length,
+ length = nativeMin(indexes.length, arrLength),
+ oldArray = arrayCopy(array);
+
+ while (length--) {
+ var index = indexes[length];
+ array[length] = isIndex(index, arrLength) ? oldArray[index] : undefined;
+ }
+ return array;
+ }
+
+ /**
+ * Sets metadata for `func`.
+ *
+ * **Note:** If this function becomes hot, i.e. is invoked a lot in a short
+ * period of time, it will trip its breaker and transition to an identity function
+ * to avoid garbage collection pauses in V8. See [V8 issue 2070](https://code.google.com/p/v8/issues/detail?id=2070)
+ * for more details.
+ *
+ * @private
+ * @param {Function} func The function to associate metadata with.
+ * @param {*} data The metadata.
+ * @returns {Function} Returns `func`.
+ */
+ var setData = (function() {
+ var count = 0,
+ lastCalled = 0;
+
+ return function(key, value) {
+ var stamp = now(),
+ remaining = HOT_SPAN - (stamp - lastCalled);
+
+ lastCalled = stamp;
+ if (remaining > 0) {
+ if (++count >= HOT_COUNT) {
+ return key;
+ }
+ } else {
+ count = 0;
+ }
+ return baseSetData(key, value);
+ };
+ }());
+
+ /**
+ * A fallback implementation of `Object.keys` which creates an array of the
+ * own enumerable property names of `object`.
+ *
+ * @private
+ * @param {Object} object The object to query.
+ * @returns {Array} Returns the array of property names.
+ */
+ function shimKeys(object) {
+ var props = keysIn(object),
+ propsLength = props.length,
+ length = propsLength && object.length;
+
+ var allowIndexes = !!length && isLength(length) &&
+ (isArray(object) || isArguments(object));
+
+ var index = -1,
+ result = [];
+
+ while (++index < propsLength) {
+ var key = props[index];
+ if ((allowIndexes && isIndex(key, length)) || hasOwnProperty.call(object, key)) {
+ result.push(key);
+ }
+ }
+ return result;
+ }
+
+ /**
+ * Converts `value` to an array-like object if it's not one.
+ *
+ * @private
+ * @param {*} value The value to process.
+ * @returns {Array|Object} Returns the array-like object.
+ */
+ function toIterable(value) {
+ if (value == null) {
+ return [];
+ }
+ if (!isArrayLike(value)) {
+ return values(value);
+ }
+ return isObject(value) ? value : Object(value);
+ }
+
+ /**
+ * Converts `value` to an object if it's not one.
+ *
+ * @private
+ * @param {*} value The value to process.
+ * @returns {Object} Returns the object.
+ */
+ function toObject(value) {
+ return isObject(value) ? value : Object(value);
+ }
+
+ /**
+ * Converts `value` to property path array if it's not one.
+ *
+ * @private
+ * @param {*} value The value to process.
+ * @returns {Array} Returns the property path array.
+ */
+ function toPath(value) {
+ if (isArray(value)) {
+ return value;
+ }
+ var result = [];
+ baseToString(value).replace(rePropName, function(match, number, quote, string) {
+ result.push(quote ? string.replace(reEscapeChar, '$1') : (number || match));
+ });
+ return result;
+ }
+
+ /**
+ * Creates a clone of `wrapper`.
+ *
+ * @private
+ * @param {Object} wrapper The wrapper to clone.
+ * @returns {Object} Returns the cloned wrapper.
+ */
+ function wrapperClone(wrapper) {
+ return wrapper instanceof LazyWrapper
+ ? wrapper.clone()
+ : new LodashWrapper(wrapper.__wrapped__, wrapper.__chain__, arrayCopy(wrapper.__actions__));
+ }
+
+ /*------------------------------------------------------------------------*/
+
+ /**
+ * Creates an array of elements split into groups the length of `size`.
+ * If `collection` can't be split evenly, the final chunk will be the remaining
+ * elements.
+ *
+ * @static
+ * @memberOf _
+ * @category Array
+ * @param {Array} array The array to process.
+ * @param {number} [size=1] The length of each chunk.
+ * @param- {Object} [guard] Enables use as a callback for functions like `_.map`.
+ * @returns {Array} Returns the new array containing chunks.
+ * @example
+ *
+ * _.chunk(['a', 'b', 'c', 'd'], 2);
+ * // => [['a', 'b'], ['c', 'd']]
+ *
+ * _.chunk(['a', 'b', 'c', 'd'], 3);
+ * // => [['a', 'b', 'c'], ['d']]
+ */
+ function chunk(array, size, guard) {
+ if (guard ? isIterateeCall(array, size, guard) : size == null) {
+ size = 1;
+ } else {
+ size = nativeMax(nativeFloor(size) || 1, 1);
+ }
+ var index = 0,
+ length = array ? array.length : 0,
+ resIndex = -1,
+ result = Array(nativeCeil(length / size));
+
+ while (index < length) {
+ result[++resIndex] = baseSlice(array, index, (index += size));
+ }
+ return result;
+ }
+
+ /**
+ * Creates an array with all falsey values removed. The values `false`, `null`,
+ * `0`, `""`, `undefined`, and `NaN` are falsey.
+ *
+ * @static
+ * @memberOf _
+ * @category Array
+ * @param {Array} array The array to compact.
+ * @returns {Array} Returns the new array of filtered values.
+ * @example
+ *
+ * _.compact([0, 1, false, 2, '', 3]);
+ * // => [1, 2, 3]
+ */
+ function compact(array) {
+ var index = -1,
+ length = array ? array.length : 0,
+ resIndex = -1,
+ result = [];
+
+ while (++index < length) {
+ var value = array[index];
+ if (value) {
+ result[++resIndex] = value;
+ }
+ }
+ return result;
+ }
+
+ /**
+ * Creates an array of unique `array` values not included in the other
+ * provided arrays using [`SameValueZero`](http://ecma-international.org/ecma-262/6.0/#sec-samevaluezero)
+ * for equality comparisons.
+ *
+ * @static
+ * @memberOf _
+ * @category Array
+ * @param {Array} array The array to inspect.
+ * @param {...Array} [values] The arrays of values to exclude.
+ * @returns {Array} Returns the new array of filtered values.
+ * @example
+ *
+ * _.difference([1, 2, 3], [4, 2]);
+ * // => [1, 3]
+ */
+ var difference = restParam(function(array, values) {
+ return (isObjectLike(array) && isArrayLike(array))
+ ? baseDifference(array, baseFlatten(values, false, true))
+ : [];
+ });
+
+ /**
+ * Creates a slice of `array` with `n` elements dropped from the beginning.
+ *
+ * @static
+ * @memberOf _
+ * @category Array
+ * @param {Array} array The array to query.
+ * @param {number} [n=1] The number of elements to drop.
+ * @param- {Object} [guard] Enables use as a callback for functions like `_.map`.
+ * @returns {Array} Returns the slice of `array`.
+ * @example
+ *
+ * _.drop([1, 2, 3]);
+ * // => [2, 3]
+ *
+ * _.drop([1, 2, 3], 2);
+ * // => [3]
+ *
+ * _.drop([1, 2, 3], 5);
+ * // => []
+ *
+ * _.drop([1, 2, 3], 0);
+ * // => [1, 2, 3]
+ */
+ function drop(array, n, guard) {
+ var length = array ? array.length : 0;
+ if (!length) {
+ return [];
+ }
+ if (guard ? isIterateeCall(array, n, guard) : n == null) {
+ n = 1;
+ }
+ return baseSlice(array, n < 0 ? 0 : n);
+ }
+
+ /**
+ * Creates a slice of `array` with `n` elements dropped from the end.
+ *
+ * @static
+ * @memberOf _
+ * @category Array
+ * @param {Array} array The array to query.
+ * @param {number} [n=1] The number of elements to drop.
+ * @param- {Object} [guard] Enables use as a callback for functions like `_.map`.
+ * @returns {Array} Returns the slice of `array`.
+ * @example
+ *
+ * _.dropRight([1, 2, 3]);
+ * // => [1, 2]
+ *
+ * _.dropRight([1, 2, 3], 2);
+ * // => [1]
+ *
+ * _.dropRight([1, 2, 3], 5);
+ * // => []
+ *
+ * _.dropRight([1, 2, 3], 0);
+ * // => [1, 2, 3]
+ */
+ function dropRight(array, n, guard) {
+ var length = array ? array.length : 0;
+ if (!length) {
+ return [];
+ }
+ if (guard ? isIterateeCall(array, n, guard) : n == null) {
+ n = 1;
+ }
+ n = length - (+n || 0);
+ return baseSlice(array, 0, n < 0 ? 0 : n);
+ }
+
+ /**
+ * Creates a slice of `array` excluding elements dropped from the end.
+ * Elements are dropped until `predicate` returns falsey. The predicate is
+ * bound to `thisArg` and invoked with three arguments: (value, index, array).
+ *
+ * If a property name is provided for `predicate` the created `_.property`
+ * style callback returns the property value of the given element.
+ *
+ * If a value is also provided for `thisArg` the created `_.matchesProperty`
+ * style callback returns `true` for elements that have a matching property
+ * value, else `false`.
+ *
+ * If an object is provided for `predicate` the created `_.matches` style
+ * callback returns `true` for elements that match the properties of the given
+ * object, else `false`.
+ *
+ * @static
+ * @memberOf _
+ * @category Array
+ * @param {Array} array The array to query.
+ * @param {Function|Object|string} [predicate=_.identity] The function invoked
+ * per iteration.
+ * @param {*} [thisArg] The `this` binding of `predicate`.
+ * @returns {Array} Returns the slice of `array`.
+ * @example
+ *
+ * _.dropRightWhile([1, 2, 3], function(n) {
+ * return n > 1;
+ * });
+ * // => [1]
+ *
+ * var users = [
+ * { 'user': 'barney', 'active': true },
+ * { 'user': 'fred', 'active': false },
+ * { 'user': 'pebbles', 'active': false }
+ * ];
+ *
+ * // using the `_.matches` callback shorthand
+ * _.pluck(_.dropRightWhile(users, { 'user': 'pebbles', 'active': false }), 'user');
+ * // => ['barney', 'fred']
+ *
+ * // using the `_.matchesProperty` callback shorthand
+ * _.pluck(_.dropRightWhile(users, 'active', false), 'user');
+ * // => ['barney']
+ *
+ * // using the `_.property` callback shorthand
+ * _.pluck(_.dropRightWhile(users, 'active'), 'user');
+ * // => ['barney', 'fred', 'pebbles']
+ */
+ function dropRightWhile(array, predicate, thisArg) {
+ return (array && array.length)
+ ? baseWhile(array, getCallback(predicate, thisArg, 3), true, true)
+ : [];
+ }
+
+ /**
+ * Creates a slice of `array` excluding elements dropped from the beginning.
+ * Elements are dropped until `predicate` returns falsey. The predicate is
+ * bound to `thisArg` and invoked with three arguments: (value, index, array).
+ *
+ * If a property name is provided for `predicate` the created `_.property`
+ * style callback returns the property value of the given element.
+ *
+ * If a value is also provided for `thisArg` the created `_.matchesProperty`
+ * style callback returns `true` for elements that have a matching property
+ * value, else `false`.
+ *
+ * If an object is provided for `predicate` the created `_.matches` style
+ * callback returns `true` for elements that have the properties of the given
+ * object, else `false`.
+ *
+ * @static
+ * @memberOf _
+ * @category Array
+ * @param {Array} array The array to query.
+ * @param {Function|Object|string} [predicate=_.identity] The function invoked
+ * per iteration.
+ * @param {*} [thisArg] The `this` binding of `predicate`.
+ * @returns {Array} Returns the slice of `array`.
+ * @example
+ *
+ * _.dropWhile([1, 2, 3], function(n) {
+ * return n < 3;
+ * });
+ * // => [3]
+ *
+ * var users = [
+ * { 'user': 'barney', 'active': false },
+ * { 'user': 'fred', 'active': false },
+ * { 'user': 'pebbles', 'active': true }
+ * ];
+ *
+ * // using the `_.matches` callback shorthand
+ * _.pluck(_.dropWhile(users, { 'user': 'barney', 'active': false }), 'user');
+ * // => ['fred', 'pebbles']
+ *
+ * // using the `_.matchesProperty` callback shorthand
+ * _.pluck(_.dropWhile(users, 'active', false), 'user');
+ * // => ['pebbles']
+ *
+ * // using the `_.property` callback shorthand
+ * _.pluck(_.dropWhile(users, 'active'), 'user');
+ * // => ['barney', 'fred', 'pebbles']
+ */
+ function dropWhile(array, predicate, thisArg) {
+ return (array && array.length)
+ ? baseWhile(array, getCallback(predicate, thisArg, 3), true)
+ : [];
+ }
+
+ /**
+ * Fills elements of `array` with `value` from `start` up to, but not
+ * including, `end`.
+ *
+ * **Note:** This method mutates `array`.
+ *
+ * @static
+ * @memberOf _
+ * @category Array
+ * @param {Array} array The array to fill.
+ * @param {*} value The value to fill `array` with.
+ * @param {number} [start=0] The start position.
+ * @param {number} [end=array.length] The end position.
+ * @returns {Array} Returns `array`.
+ * @example
+ *
+ * var array = [1, 2, 3];
+ *
+ * _.fill(array, 'a');
+ * console.log(array);
+ * // => ['a', 'a', 'a']
+ *
+ * _.fill(Array(3), 2);
+ * // => [2, 2, 2]
+ *
+ * _.fill([4, 6, 8], '*', 1, 2);
+ * // => [4, '*', 8]
+ */
+ function fill(array, value, start, end) {
+ var length = array ? array.length : 0;
+ if (!length) {
+ return [];
+ }
+ if (start && typeof start != 'number' && isIterateeCall(array, value, start)) {
+ start = 0;
+ end = length;
+ }
+ return baseFill(array, value, start, end);
+ }
+
+ /**
+ * This method is like `_.find` except that it returns the index of the first
+ * element `predicate` returns truthy for instead of the element itself.
+ *
+ * If a property name is provided for `predicate` the created `_.property`
+ * style callback returns the property value of the given element.
+ *
+ * If a value is also provided for `thisArg` the created `_.matchesProperty`
+ * style callback returns `true` for elements that have a matching property
+ * value, else `false`.
+ *
+ * If an object is provided for `predicate` the created `_.matches` style
+ * callback returns `true` for elements that have the properties of the given
+ * object, else `false`.
+ *
+ * @static
+ * @memberOf _
+ * @category Array
+ * @param {Array} array The array to search.
+ * @param {Function|Object|string} [predicate=_.identity] The function invoked
+ * per iteration.
+ * @param {*} [thisArg] The `this` binding of `predicate`.
+ * @returns {number} Returns the index of the found element, else `-1`.
+ * @example
+ *
+ * var users = [
+ * { 'user': 'barney', 'active': false },
+ * { 'user': 'fred', 'active': false },
+ * { 'user': 'pebbles', 'active': true }
+ * ];
+ *
+ * _.findIndex(users, function(chr) {
+ * return chr.user == 'barney';
+ * });
+ * // => 0
+ *
+ * // using the `_.matches` callback shorthand
+ * _.findIndex(users, { 'user': 'fred', 'active': false });
+ * // => 1
+ *
+ * // using the `_.matchesProperty` callback shorthand
+ * _.findIndex(users, 'active', false);
+ * // => 0
+ *
+ * // using the `_.property` callback shorthand
+ * _.findIndex(users, 'active');
+ * // => 2
+ */
+ var findIndex = createFindIndex();
+
+ /**
+ * This method is like `_.findIndex` except that it iterates over elements
+ * of `collection` from right to left.
+ *
+ * If a property name is provided for `predicate` the created `_.property`
+ * style callback returns the property value of the given element.
+ *
+ * If a value is also provided for `thisArg` the created `_.matchesProperty`
+ * style callback returns `true` for elements that have a matching property
+ * value, else `false`.
+ *
+ * If an object is provided for `predicate` the created `_.matches` style
+ * callback returns `true` for elements that have the properties of the given
+ * object, else `false`.
+ *
+ * @static
+ * @memberOf _
+ * @category Array
+ * @param {Array} array The array to search.
+ * @param {Function|Object|string} [predicate=_.identity] The function invoked
+ * per iteration.
+ * @param {*} [thisArg] The `this` binding of `predicate`.
+ * @returns {number} Returns the index of the found element, else `-1`.
+ * @example
+ *
+ * var users = [
+ * { 'user': 'barney', 'active': true },
+ * { 'user': 'fred', 'active': false },
+ * { 'user': 'pebbles', 'active': false }
+ * ];
+ *
+ * _.findLastIndex(users, function(chr) {
+ * return chr.user == 'pebbles';
+ * });
+ * // => 2
+ *
+ * // using the `_.matches` callback shorthand
+ * _.findLastIndex(users, { 'user': 'barney', 'active': true });
+ * // => 0
+ *
+ * // using the `_.matchesProperty` callback shorthand
+ * _.findLastIndex(users, 'active', false);
+ * // => 2
+ *
+ * // using the `_.property` callback shorthand
+ * _.findLastIndex(users, 'active');
+ * // => 0
+ */
+ var findLastIndex = createFindIndex(true);
+
+ /**
+ * Gets the first element of `array`.
+ *
+ * @static
+ * @memberOf _
+ * @alias head
+ * @category Array
+ * @param {Array} array The array to query.
+ * @returns {*} Returns the first element of `array`.
+ * @example
+ *
+ * _.first([1, 2, 3]);
+ * // => 1
+ *
+ * _.first([]);
+ * // => undefined
+ */
+ function first(array) {
+ return array ? array[0] : undefined;
+ }
+
+ /**
+ * Flattens a nested array. If `isDeep` is `true` the array is recursively
+ * flattened, otherwise it is only flattened a single level.
+ *
+ * @static
+ * @memberOf _
+ * @category Array
+ * @param {Array} array The array to flatten.
+ * @param {boolean} [isDeep] Specify a deep flatten.
+ * @param- {Object} [guard] Enables use as a callback for functions like `_.map`.
+ * @returns {Array} Returns the new flattened array.
+ * @example
+ *
+ * _.flatten([1, [2, 3, [4]]]);
+ * // => [1, 2, 3, [4]]
+ *
+ * // using `isDeep`
+ * _.flatten([1, [2, 3, [4]]], true);
+ * // => [1, 2, 3, 4]
+ */
+ function flatten(array, isDeep, guard) {
+ var length = array ? array.length : 0;
+ if (guard && isIterateeCall(array, isDeep, guard)) {
+ isDeep = false;
+ }
+ return length ? baseFlatten(array, isDeep) : [];
+ }
+
+ /**
+ * Recursively flattens a nested array.
+ *
+ * @static
+ * @memberOf _
+ * @category Array
+ * @param {Array} array The array to recursively flatten.
+ * @returns {Array} Returns the new flattened array.
+ * @example
+ *
+ * _.flattenDeep([1, [2, 3, [4]]]);
+ * // => [1, 2, 3, 4]
+ */
+ function flattenDeep(array) {
+ var length = array ? array.length : 0;
+ return length ? baseFlatten(array, true) : [];
+ }
+
+ /**
+ * Gets the index at which the first occurrence of `value` is found in `array`
+ * using [`SameValueZero`](http://ecma-international.org/ecma-262/6.0/#sec-samevaluezero)
+ * for equality comparisons. If `fromIndex` is negative, it is used as the offset
+ * from the end of `array`. If `array` is sorted providing `true` for `fromIndex`
+ * performs a faster binary search.
+ *
+ * @static
+ * @memberOf _
+ * @category Array
+ * @param {Array} array The array to search.
+ * @param {*} value The value to search for.
+ * @param {boolean|number} [fromIndex=0] The index to search from or `true`
+ * to perform a binary search on a sorted array.
+ * @returns {number} Returns the index of the matched value, else `-1`.
+ * @example
+ *
+ * _.indexOf([1, 2, 1, 2], 2);
+ * // => 1
+ *
+ * // using `fromIndex`
+ * _.indexOf([1, 2, 1, 2], 2, 2);
+ * // => 3
+ *
+ * // performing a binary search
+ * _.indexOf([1, 1, 2, 2], 2, true);
+ * // => 2
+ */
+ function indexOf(array, value, fromIndex) {
+ var length = array ? array.length : 0;
+ if (!length) {
+ return -1;
+ }
+ if (typeof fromIndex == 'number') {
+ fromIndex = fromIndex < 0 ? nativeMax(length + fromIndex, 0) : fromIndex;
+ } else if (fromIndex) {
+ var index = binaryIndex(array, value);
+ if (index < length &&
+ (value === value ? (value === array[index]) : (array[index] !== array[index]))) {
+ return index;
+ }
+ return -1;
+ }
+ return baseIndexOf(array, value, fromIndex || 0);
+ }
+
+ /**
+ * Gets all but the last element of `array`.
+ *
+ * @static
+ * @memberOf _
+ * @category Array
+ * @param {Array} array The array to query.
+ * @returns {Array} Returns the slice of `array`.
+ * @example
+ *
+ * _.initial([1, 2, 3]);
+ * // => [1, 2]
+ */
+ function initial(array) {
+ return dropRight(array, 1);
+ }
+
+ /**
+ * Creates an array of unique values that are included in all of the provided
+ * arrays using [`SameValueZero`](http://ecma-international.org/ecma-262/6.0/#sec-samevaluezero)
+ * for equality comparisons.
+ *
+ * @static
+ * @memberOf _
+ * @category Array
+ * @param {...Array} [arrays] The arrays to inspect.
+ * @returns {Array} Returns the new array of shared values.
+ * @example
+ * _.intersection([1, 2], [4, 2], [2, 1]);
+ * // => [2]
+ */
+ var intersection = restParam(function(arrays) {
+ var othLength = arrays.length,
+ othIndex = othLength,
+ caches = Array(length),
+ indexOf = getIndexOf(),
+ isCommon = indexOf == baseIndexOf,
+ result = [];
+
+ while (othIndex--) {
+ var value = arrays[othIndex] = isArrayLike(value = arrays[othIndex]) ? value : [];
+ caches[othIndex] = (isCommon && value.length >= 120) ? createCache(othIndex && value) : null;
+ }
+ var array = arrays[0],
+ index = -1,
+ length = array ? array.length : 0,
+ seen = caches[0];
+
+ outer:
+ while (++index < length) {
+ value = array[index];
+ if ((seen ? cacheIndexOf(seen, value) : indexOf(result, value, 0)) < 0) {
+ var othIndex = othLength;
+ while (--othIndex) {
+ var cache = caches[othIndex];
+ if ((cache ? cacheIndexOf(cache, value) : indexOf(arrays[othIndex], value, 0)) < 0) {
+ continue outer;
+ }
+ }
+ if (seen) {
+ seen.push(value);
+ }
+ result.push(value);
+ }
+ }
+ return result;
+ });
+
+ /**
+ * Gets the last element of `array`.
+ *
+ * @static
+ * @memberOf _
+ * @category Array
+ * @param {Array} array The array to query.
+ * @returns {*} Returns the last element of `array`.
+ * @example
+ *
+ * _.last([1, 2, 3]);
+ * // => 3
+ */
+ function last(array) {
+ var length = array ? array.length : 0;
+ return length ? array[length - 1] : undefined;
+ }
+
+ /**
+ * This method is like `_.indexOf` except that it iterates over elements of
+ * `array` from right to left.
+ *
+ * @static
+ * @memberOf _
+ * @category Array
+ * @param {Array} array The array to search.
+ * @param {*} value The value to search for.
+ * @param {boolean|number} [fromIndex=array.length-1] The index to search from
+ * or `true` to perform a binary search on a sorted array.
+ * @returns {number} Returns the index of the matched value, else `-1`.
+ * @example
+ *
+ * _.lastIndexOf([1, 2, 1, 2], 2);
+ * // => 3
+ *
+ * // using `fromIndex`
+ * _.lastIndexOf([1, 2, 1, 2], 2, 2);
+ * // => 1
+ *
+ * // performing a binary search
+ * _.lastIndexOf([1, 1, 2, 2], 2, true);
+ * // => 3
+ */
+ function lastIndexOf(array, value, fromIndex) {
+ var length = array ? array.length : 0;
+ if (!length) {
+ return -1;
+ }
+ var index = length;
+ if (typeof fromIndex == 'number') {
+ index = (fromIndex < 0 ? nativeMax(length + fromIndex, 0) : nativeMin(fromIndex || 0, length - 1)) + 1;
+ } else if (fromIndex) {
+ index = binaryIndex(array, value, true) - 1;
+ var other = array[index];
+ if (value === value ? (value === other) : (other !== other)) {
+ return index;
+ }
+ return -1;
+ }
+ if (value !== value) {
+ return indexOfNaN(array, index, true);
+ }
+ while (index--) {
+ if (array[index] === value) {
+ return index;
+ }
+ }
+ return -1;
+ }
+
+ /**
+ * Removes all provided values from `array` using
+ * [`SameValueZero`](http://ecma-international.org/ecma-262/6.0/#sec-samevaluezero)
+ * for equality comparisons.
+ *
+ * **Note:** Unlike `_.without`, this method mutates `array`.
+ *
+ * @static
+ * @memberOf _
+ * @category Array
+ * @param {Array} array The array to modify.
+ * @param {...*} [values] The values to remove.
+ * @returns {Array} Returns `array`.
+ * @example
+ *
+ * var array = [1, 2, 3, 1, 2, 3];
+ *
+ * _.pull(array, 2, 3);
+ * console.log(array);
+ * // => [1, 1]
+ */
+ function pull() {
+ var args = arguments,
+ array = args[0];
+
+ if (!(array && array.length)) {
+ return array;
+ }
+ var index = 0,
+ indexOf = getIndexOf(),
+ length = args.length;
+
+ while (++index < length) {
+ var fromIndex = 0,
+ value = args[index];
+
+ while ((fromIndex = indexOf(array, value, fromIndex)) > -1) {
+ splice.call(array, fromIndex, 1);
+ }
+ }
+ return array;
+ }
+
+ /**
+ * Removes elements from `array` corresponding to the given indexes and returns
+ * an array of the removed elements. Indexes may be specified as an array of
+ * indexes or as individual arguments.
+ *
+ * **Note:** Unlike `_.at`, this method mutates `array`.
+ *
+ * @static
+ * @memberOf _
+ * @category Array
+ * @param {Array} array The array to modify.
+ * @param {...(number|number[])} [indexes] The indexes of elements to remove,
+ * specified as individual indexes or arrays of indexes.
+ * @returns {Array} Returns the new array of removed elements.
+ * @example
+ *
+ * var array = [5, 10, 15, 20];
+ * var evens = _.pullAt(array, 1, 3);
+ *
+ * console.log(array);
+ * // => [5, 15]
+ *
+ * console.log(evens);
+ * // => [10, 20]
+ */
+ var pullAt = restParam(function(array, indexes) {
+ indexes = baseFlatten(indexes);
+
+ var result = baseAt(array, indexes);
+ basePullAt(array, indexes.sort(baseCompareAscending));
+ return result;
+ });
+
+ /**
+ * Removes all elements from `array` that `predicate` returns truthy for
+ * and returns an array of the removed elements. The predicate is bound to
+ * `thisArg` and invoked with three arguments: (value, index, array).
+ *
+ * If a property name is provided for `predicate` the created `_.property`
+ * style callback returns the property value of the given element.
+ *
+ * If a value is also provided for `thisArg` the created `_.matchesProperty`
+ * style callback returns `true` for elements that have a matching property
+ * value, else `false`.
+ *
+ * If an object is provided for `predicate` the created `_.matches` style
+ * callback returns `true` for elements that have the properties of the given
+ * object, else `false`.
+ *
+ * **Note:** Unlike `_.filter`, this method mutates `array`.
+ *
+ * @static
+ * @memberOf _
+ * @category Array
+ * @param {Array} array The array to modify.
+ * @param {Function|Object|string} [predicate=_.identity] The function invoked
+ * per iteration.
+ * @param {*} [thisArg] The `this` binding of `predicate`.
+ * @returns {Array} Returns the new array of removed elements.
+ * @example
+ *
+ * var array = [1, 2, 3, 4];
+ * var evens = _.remove(array, function(n) {
+ * return n % 2 == 0;
+ * });
+ *
+ * console.log(array);
+ * // => [1, 3]
+ *
+ * console.log(evens);
+ * // => [2, 4]
+ */
+ function remove(array, predicate, thisArg) {
+ var result = [];
+ if (!(array && array.length)) {
+ return result;
+ }
+ var index = -1,
+ indexes = [],
+ length = array.length;
+
+ predicate = getCallback(predicate, thisArg, 3);
+ while (++index < length) {
+ var value = array[index];
+ if (predicate(value, index, array)) {
+ result.push(value);
+ indexes.push(index);
+ }
+ }
+ basePullAt(array, indexes);
+ return result;
+ }
+
+ /**
+ * Gets all but the first element of `array`.
+ *
+ * @static
+ * @memberOf _
+ * @alias tail
+ * @category Array
+ * @param {Array} array The array to query.
+ * @returns {Array} Returns the slice of `array`.
+ * @example
+ *
+ * _.rest([1, 2, 3]);
+ * // => [2, 3]
+ */
+ function rest(array) {
+ return drop(array, 1);
+ }
+
+ /**
+ * Creates a slice of `array` from `start` up to, but not including, `end`.
+ *
+ * **Note:** This method is used instead of `Array#slice` to support node
+ * lists in IE < 9 and to ensure dense arrays are returned.
+ *
+ * @static
+ * @memberOf _
+ * @category Array
+ * @param {Array} array The array to slice.
+ * @param {number} [start=0] The start position.
+ * @param {number} [end=array.length] The end position.
+ * @returns {Array} Returns the slice of `array`.
+ */
+ function slice(array, start, end) {
+ var length = array ? array.length : 0;
+ if (!length) {
+ return [];
+ }
+ if (end && typeof end != 'number' && isIterateeCall(array, start, end)) {
+ start = 0;
+ end = length;
+ }
+ return baseSlice(array, start, end);
+ }
+
+ /**
+ * Uses a binary search to determine the lowest index at which `value` should
+ * be inserted into `array` in order to maintain its sort order. If an iteratee
+ * function is provided it is invoked for `value` and each element of `array`
+ * to compute their sort ranking. The iteratee is bound to `thisArg` and
+ * invoked with one argument; (value).
+ *
+ * If a property name is provided for `iteratee` the created `_.property`
+ * style callback returns the property value of the given element.
+ *
+ * If a value is also provided for `thisArg` the created `_.matchesProperty`
+ * style callback returns `true` for elements that have a matching property
+ * value, else `false`.
+ *
+ * If an object is provided for `iteratee` the created `_.matches` style
+ * callback returns `true` for elements that have the properties of the given
+ * object, else `false`.
+ *
+ * @static
+ * @memberOf _
+ * @category Array
+ * @param {Array} array The sorted array to inspect.
+ * @param {*} value The value to evaluate.
+ * @param {Function|Object|string} [iteratee=_.identity] The function invoked
+ * per iteration.
+ * @param {*} [thisArg] The `this` binding of `iteratee`.
+ * @returns {number} Returns the index at which `value` should be inserted
+ * into `array`.
+ * @example
+ *
+ * _.sortedIndex([30, 50], 40);
+ * // => 1
+ *
+ * _.sortedIndex([4, 4, 5, 5], 5);
+ * // => 2
+ *
+ * var dict = { 'data': { 'thirty': 30, 'forty': 40, 'fifty': 50 } };
+ *
+ * // using an iteratee function
+ * _.sortedIndex(['thirty', 'fifty'], 'forty', function(word) {
+ * return this.data[word];
+ * }, dict);
+ * // => 1
+ *
+ * // using the `_.property` callback shorthand
+ * _.sortedIndex([{ 'x': 30 }, { 'x': 50 }], { 'x': 40 }, 'x');
+ * // => 1
+ */
+ var sortedIndex = createSortedIndex();
+
+ /**
+ * This method is like `_.sortedIndex` except that it returns the highest
+ * index at which `value` should be inserted into `array` in order to
+ * maintain its sort order.
+ *
+ * @static
+ * @memberOf _
+ * @category Array
+ * @param {Array} array The sorted array to inspect.
+ * @param {*} value The value to evaluate.
+ * @param {Function|Object|string} [iteratee=_.identity] The function invoked
+ * per iteration.
+ * @param {*} [thisArg] The `this` binding of `iteratee`.
+ * @returns {number} Returns the index at which `value` should be inserted
+ * into `array`.
+ * @example
+ *
+ * _.sortedLastIndex([4, 4, 5, 5], 5);
+ * // => 4
+ */
+ var sortedLastIndex = createSortedIndex(true);
+
+ /**
+ * Creates a slice of `array` with `n` elements taken from the beginning.
+ *
+ * @static
+ * @memberOf _
+ * @category Array
+ * @param {Array} array The array to query.
+ * @param {number} [n=1] The number of elements to take.
+ * @param- {Object} [guard] Enables use as a callback for functions like `_.map`.
+ * @returns {Array} Returns the slice of `array`.
+ * @example
+ *
+ * _.take([1, 2, 3]);
+ * // => [1]
+ *
+ * _.take([1, 2, 3], 2);
+ * // => [1, 2]
+ *
+ * _.take([1, 2, 3], 5);
+ * // => [1, 2, 3]
+ *
+ * _.take([1, 2, 3], 0);
+ * // => []
+ */
+ function take(array, n, guard) {
+ var length = array ? array.length : 0;
+ if (!length) {
+ return [];
+ }
+ if (guard ? isIterateeCall(array, n, guard) : n == null) {
+ n = 1;
+ }
+ return baseSlice(array, 0, n < 0 ? 0 : n);
+ }
+
+ /**
+ * Creates a slice of `array` with `n` elements taken from the end.
+ *
+ * @static
+ * @memberOf _
+ * @category Array
+ * @param {Array} array The array to query.
+ * @param {number} [n=1] The number of elements to take.
+ * @param- {Object} [guard] Enables use as a callback for functions like `_.map`.
+ * @returns {Array} Returns the slice of `array`.
+ * @example
+ *
+ * _.takeRight([1, 2, 3]);
+ * // => [3]
+ *
+ * _.takeRight([1, 2, 3], 2);
+ * // => [2, 3]
+ *
+ * _.takeRight([1, 2, 3], 5);
+ * // => [1, 2, 3]
+ *
+ * _.takeRight([1, 2, 3], 0);
+ * // => []
+ */
+ function takeRight(array, n, guard) {
+ var length = array ? array.length : 0;
+ if (!length) {
+ return [];
+ }
+ if (guard ? isIterateeCall(array, n, guard) : n == null) {
+ n = 1;
+ }
+ n = length - (+n || 0);
+ return baseSlice(array, n < 0 ? 0 : n);
+ }
+
+ /**
+ * Creates a slice of `array` with elements taken from the end. Elements are
+ * taken until `predicate` returns falsey. The predicate is bound to `thisArg`
+ * and invoked with three arguments: (value, index, array).
+ *
+ * If a property name is provided for `predicate` the created `_.property`
+ * style callback returns the property value of the given element.
+ *
+ * If a value is also provided for `thisArg` the created `_.matchesProperty`
+ * style callback returns `true` for elements that have a matching property
+ * value, else `false`.
+ *
+ * If an object is provided for `predicate` the created `_.matches` style
+ * callback returns `true` for elements that have the properties of the given
+ * object, else `false`.
+ *
+ * @static
+ * @memberOf _
+ * @category Array
+ * @param {Array} array The array to query.
+ * @param {Function|Object|string} [predicate=_.identity] The function invoked
+ * per iteration.
+ * @param {*} [thisArg] The `this` binding of `predicate`.
+ * @returns {Array} Returns the slice of `array`.
+ * @example
+ *
+ * _.takeRightWhile([1, 2, 3], function(n) {
+ * return n > 1;
+ * });
+ * // => [2, 3]
+ *
+ * var users = [
+ * { 'user': 'barney', 'active': true },
+ * { 'user': 'fred', 'active': false },
+ * { 'user': 'pebbles', 'active': false }
+ * ];
+ *
+ * // using the `_.matches` callback shorthand
+ * _.pluck(_.takeRightWhile(users, { 'user': 'pebbles', 'active': false }), 'user');
+ * // => ['pebbles']
+ *
+ * // using the `_.matchesProperty` callback shorthand
+ * _.pluck(_.takeRightWhile(users, 'active', false), 'user');
+ * // => ['fred', 'pebbles']
+ *
+ * // using the `_.property` callback shorthand
+ * _.pluck(_.takeRightWhile(users, 'active'), 'user');
+ * // => []
+ */
+ function takeRightWhile(array, predicate, thisArg) {
+ return (array && array.length)
+ ? baseWhile(array, getCallback(predicate, thisArg, 3), false, true)
+ : [];
+ }
+
+ /**
+ * Creates a slice of `array` with elements taken from the beginning. Elements
+ * are taken until `predicate` returns falsey. The predicate is bound to
+ * `thisArg` and invoked with three arguments: (value, index, array).
+ *
+ * If a property name is provided for `predicate` the created `_.property`
+ * style callback returns the property value of the given element.
+ *
+ * If a value is also provided for `thisArg` the created `_.matchesProperty`
+ * style callback returns `true` for elements that have a matching property
+ * value, else `false`.
+ *
+ * If an object is provided for `predicate` the created `_.matches` style
+ * callback returns `true` for elements that have the properties of the given
+ * object, else `false`.
+ *
+ * @static
+ * @memberOf _
+ * @category Array
+ * @param {Array} array The array to query.
+ * @param {Function|Object|string} [predicate=_.identity] The function invoked
+ * per iteration.
+ * @param {*} [thisArg] The `this` binding of `predicate`.
+ * @returns {Array} Returns the slice of `array`.
+ * @example
+ *
+ * _.takeWhile([1, 2, 3], function(n) {
+ * return n < 3;
+ * });
+ * // => [1, 2]
+ *
+ * var users = [
+ * { 'user': 'barney', 'active': false },
+ * { 'user': 'fred', 'active': false},
+ * { 'user': 'pebbles', 'active': true }
+ * ];
+ *
+ * // using the `_.matches` callback shorthand
+ * _.pluck(_.takeWhile(users, { 'user': 'barney', 'active': false }), 'user');
+ * // => ['barney']
+ *
+ * // using the `_.matchesProperty` callback shorthand
+ * _.pluck(_.takeWhile(users, 'active', false), 'user');
+ * // => ['barney', 'fred']
+ *
+ * // using the `_.property` callback shorthand
+ * _.pluck(_.takeWhile(users, 'active'), 'user');
+ * // => []
+ */
+ function takeWhile(array, predicate, thisArg) {
+ return (array && array.length)
+ ? baseWhile(array, getCallback(predicate, thisArg, 3))
+ : [];
+ }
+
+ /**
+ * Creates an array of unique values, in order, from all of the provided arrays
+ * using [`SameValueZero`](http://ecma-international.org/ecma-262/6.0/#sec-samevaluezero)
+ * for equality comparisons.
+ *
+ * @static
+ * @memberOf _
+ * @category Array
+ * @param {...Array} [arrays] The arrays to inspect.
+ * @returns {Array} Returns the new array of combined values.
+ * @example
+ *
+ * _.union([1, 2], [4, 2], [2, 1]);
+ * // => [1, 2, 4]
+ */
+ var union = restParam(function(arrays) {
+ return baseUniq(baseFlatten(arrays, false, true));
+ });
+
+ /**
+ * Creates a duplicate-free version of an array, using
+ * [`SameValueZero`](http://ecma-international.org/ecma-262/6.0/#sec-samevaluezero)
+ * for equality comparisons, in which only the first occurence of each element
+ * is kept. Providing `true` for `isSorted` performs a faster search algorithm
+ * for sorted arrays. If an iteratee function is provided it is invoked for
+ * each element in the array to generate the criterion by which uniqueness
+ * is computed. The `iteratee` is bound to `thisArg` and invoked with three
+ * arguments: (value, index, array).
+ *
+ * If a property name is provided for `iteratee` the created `_.property`
+ * style callback returns the property value of the given element.
+ *
+ * If a value is also provided for `thisArg` the created `_.matchesProperty`
+ * style callback returns `true` for elements that have a matching property
+ * value, else `false`.
+ *
+ * If an object is provided for `iteratee` the created `_.matches` style
+ * callback returns `true` for elements that have the properties of the given
+ * object, else `false`.
+ *
+ * @static
+ * @memberOf _
+ * @alias unique
+ * @category Array
+ * @param {Array} array The array to inspect.
+ * @param {boolean} [isSorted] Specify the array is sorted.
+ * @param {Function|Object|string} [iteratee] The function invoked per iteration.
+ * @param {*} [thisArg] The `this` binding of `iteratee`.
+ * @returns {Array} Returns the new duplicate-value-free array.
+ * @example
+ *
+ * _.uniq([2, 1, 2]);
+ * // => [2, 1]
+ *
+ * // using `isSorted`
+ * _.uniq([1, 1, 2], true);
+ * // => [1, 2]
+ *
+ * // using an iteratee function
+ * _.uniq([1, 2.5, 1.5, 2], function(n) {
+ * return this.floor(n);
+ * }, Math);
+ * // => [1, 2.5]
+ *
+ * // using the `_.property` callback shorthand
+ * _.uniq([{ 'x': 1 }, { 'x': 2 }, { 'x': 1 }], 'x');
+ * // => [{ 'x': 1 }, { 'x': 2 }]
+ */
+ function uniq(array, isSorted, iteratee, thisArg) {
+ var length = array ? array.length : 0;
+ if (!length) {
+ return [];
+ }
+ if (isSorted != null && typeof isSorted != 'boolean') {
+ thisArg = iteratee;
+ iteratee = isIterateeCall(array, isSorted, thisArg) ? undefined : isSorted;
+ isSorted = false;
+ }
+ var callback = getCallback();
+ if (!(iteratee == null && callback === baseCallback)) {
+ iteratee = callback(iteratee, thisArg, 3);
+ }
+ return (isSorted && getIndexOf() == baseIndexOf)
+ ? sortedUniq(array, iteratee)
+ : baseUniq(array, iteratee);
+ }
+
+ /**
+ * This method is like `_.zip` except that it accepts an array of grouped
+ * elements and creates an array regrouping the elements to their pre-zip
+ * configuration.
+ *
+ * @static
+ * @memberOf _
+ * @category Array
+ * @param {Array} array The array of grouped elements to process.
+ * @returns {Array} Returns the new array of regrouped elements.
+ * @example
+ *
+ * var zipped = _.zip(['fred', 'barney'], [30, 40], [true, false]);
+ * // => [['fred', 30, true], ['barney', 40, false]]
+ *
+ * _.unzip(zipped);
+ * // => [['fred', 'barney'], [30, 40], [true, false]]
+ */
+ function unzip(array) {
+ if (!(array && array.length)) {
+ return [];
+ }
+ var index = -1,
+ length = 0;
+
+ array = arrayFilter(array, function(group) {
+ if (isArrayLike(group)) {
+ length = nativeMax(group.length, length);
+ return true;
+ }
+ });
+ var result = Array(length);
+ while (++index < length) {
+ result[index] = arrayMap(array, baseProperty(index));
+ }
+ return result;
+ }
+
+ /**
+ * This method is like `_.unzip` except that it accepts an iteratee to specify
+ * how regrouped values should be combined. The `iteratee` is bound to `thisArg`
+ * and invoked with four arguments: (accumulator, value, index, group).
+ *
+ * @static
+ * @memberOf _
+ * @category Array
+ * @param {Array} array The array of grouped elements to process.
+ * @param {Function} [iteratee] The function to combine regrouped values.
+ * @param {*} [thisArg] The `this` binding of `iteratee`.
+ * @returns {Array} Returns the new array of regrouped elements.
+ * @example
+ *
+ * var zipped = _.zip([1, 2], [10, 20], [100, 200]);
+ * // => [[1, 10, 100], [2, 20, 200]]
+ *
+ * _.unzipWith(zipped, _.add);
+ * // => [3, 30, 300]
+ */
+ function unzipWith(array, iteratee, thisArg) {
+ var length = array ? array.length : 0;
+ if (!length) {
+ return [];
+ }
+ var result = unzip(array);
+ if (iteratee == null) {
+ return result;
+ }
+ iteratee = bindCallback(iteratee, thisArg, 4);
+ return arrayMap(result, function(group) {
+ return arrayReduce(group, iteratee, undefined, true);
+ });
+ }
+
+ /**
+ * Creates an array excluding all provided values using
+ * [`SameValueZero`](http://ecma-international.org/ecma-262/6.0/#sec-samevaluezero)
+ * for equality comparisons.
+ *
+ * @static
+ * @memberOf _
+ * @category Array
+ * @param {Array} array The array to filter.
+ * @param {...*} [values] The values to exclude.
+ * @returns {Array} Returns the new array of filtered values.
+ * @example
+ *
+ * _.without([1, 2, 1, 3], 1, 2);
+ * // => [3]
+ */
+ var without = restParam(function(array, values) {
+ return isArrayLike(array)
+ ? baseDifference(array, values)
+ : [];
+ });
+
+ /**
+ * Creates an array of unique values that is the [symmetric difference](https://en.wikipedia.org/wiki/Symmetric_difference)
+ * of the provided arrays.
+ *
+ * @static
+ * @memberOf _
+ * @category Array
+ * @param {...Array} [arrays] The arrays to inspect.
+ * @returns {Array} Returns the new array of values.
+ * @example
+ *
+ * _.xor([1, 2], [4, 2]);
+ * // => [1, 4]
+ */
+ function xor() {
+ var index = -1,
+ length = arguments.length;
+
+ while (++index < length) {
+ var array = arguments[index];
+ if (isArrayLike(array)) {
+ var result = result
+ ? arrayPush(baseDifference(result, array), baseDifference(array, result))
+ : array;
+ }
+ }
+ return result ? baseUniq(result) : [];
+ }
+
+ /**
+ * Creates an array of grouped elements, the first of which contains the first
+ * elements of the given arrays, the second of which contains the second elements
+ * of the given arrays, and so on.
+ *
+ * @static
+ * @memberOf _
+ * @category Array
+ * @param {...Array} [arrays] The arrays to process.
+ * @returns {Array} Returns the new array of grouped elements.
+ * @example
+ *
+ * _.zip(['fred', 'barney'], [30, 40], [true, false]);
+ * // => [['fred', 30, true], ['barney', 40, false]]
+ */
+ var zip = restParam(unzip);
+
+ /**
+ * The inverse of `_.pairs`; this method returns an object composed from arrays
+ * of property names and values. Provide either a single two dimensional array,
+ * e.g. `[[key1, value1], [key2, value2]]` or two arrays, one of property names
+ * and one of corresponding values.
+ *
+ * @static
+ * @memberOf _
+ * @alias object
+ * @category Array
+ * @param {Array} props The property names.
+ * @param {Array} [values=[]] The property values.
+ * @returns {Object} Returns the new object.
+ * @example
+ *
+ * _.zipObject([['fred', 30], ['barney', 40]]);
+ * // => { 'fred': 30, 'barney': 40 }
+ *
+ * _.zipObject(['fred', 'barney'], [30, 40]);
+ * // => { 'fred': 30, 'barney': 40 }
+ */
+ function zipObject(props, values) {
+ var index = -1,
+ length = props ? props.length : 0,
+ result = {};
+
+ if (length && !values && !isArray(props[0])) {
+ values = [];
+ }
+ while (++index < length) {
+ var key = props[index];
+ if (values) {
+ result[key] = values[index];
+ } else if (key) {
+ result[key[0]] = key[1];
+ }
+ }
+ return result;
+ }
+
+ /**
+ * This method is like `_.zip` except that it accepts an iteratee to specify
+ * how grouped values should be combined. The `iteratee` is bound to `thisArg`
+ * and invoked with four arguments: (accumulator, value, index, group).
+ *
+ * @static
+ * @memberOf _
+ * @category Array
+ * @param {...Array} [arrays] The arrays to process.
+ * @param {Function} [iteratee] The function to combine grouped values.
+ * @param {*} [thisArg] The `this` binding of `iteratee`.
+ * @returns {Array} Returns the new array of grouped elements.
+ * @example
+ *
+ * _.zipWith([1, 2], [10, 20], [100, 200], _.add);
+ * // => [111, 222]
+ */
+ var zipWith = restParam(function(arrays) {
+ var length = arrays.length,
+ iteratee = length > 2 ? arrays[length - 2] : undefined,
+ thisArg = length > 1 ? arrays[length - 1] : undefined;
+
+ if (length > 2 && typeof iteratee == 'function') {
+ length -= 2;
+ } else {
+ iteratee = (length > 1 && typeof thisArg == 'function') ? (--length, thisArg) : undefined;
+ thisArg = undefined;
+ }
+ arrays.length = length;
+ return unzipWith(arrays, iteratee, thisArg);
+ });
+
+ /*------------------------------------------------------------------------*/
+
+ /**
+ * Creates a `lodash` object that wraps `value` with explicit method
+ * chaining enabled.
+ *
+ * @static
+ * @memberOf _
+ * @category Chain
+ * @param {*} value The value to wrap.
+ * @returns {Object} Returns the new `lodash` wrapper instance.
+ * @example
+ *
+ * var users = [
+ * { 'user': 'barney', 'age': 36 },
+ * { 'user': 'fred', 'age': 40 },
+ * { 'user': 'pebbles', 'age': 1 }
+ * ];
+ *
+ * var youngest = _.chain(users)
+ * .sortBy('age')
+ * .map(function(chr) {
+ * return chr.user + ' is ' + chr.age;
+ * })
+ * .first()
+ * .value();
+ * // => 'pebbles is 1'
+ */
+ function chain(value) {
+ var result = lodash(value);
+ result.__chain__ = true;
+ return result;
+ }
+
+ /**
+ * This method invokes `interceptor` and returns `value`. The interceptor is
+ * bound to `thisArg` and invoked with one argument; (value). The purpose of
+ * this method is to "tap into" a method chain in order to perform operations
+ * on intermediate results within the chain.
+ *
+ * @static
+ * @memberOf _
+ * @category Chain
+ * @param {*} value The value to provide to `interceptor`.
+ * @param {Function} interceptor The function to invoke.
+ * @param {*} [thisArg] The `this` binding of `interceptor`.
+ * @returns {*} Returns `value`.
+ * @example
+ *
+ * _([1, 2, 3])
+ * .tap(function(array) {
+ * array.pop();
+ * })
+ * .reverse()
+ * .value();
+ * // => [2, 1]
+ */
+ function tap(value, interceptor, thisArg) {
+ interceptor.call(thisArg, value);
+ return value;
+ }
+
+ /**
+ * This method is like `_.tap` except that it returns the result of `interceptor`.
+ *
+ * @static
+ * @memberOf _
+ * @category Chain
+ * @param {*} value The value to provide to `interceptor`.
+ * @param {Function} interceptor The function to invoke.
+ * @param {*} [thisArg] The `this` binding of `interceptor`.
+ * @returns {*} Returns the result of `interceptor`.
+ * @example
+ *
+ * _(' abc ')
+ * .chain()
+ * .trim()
+ * .thru(function(value) {
+ * return [value];
+ * })
+ * .value();
+ * // => ['abc']
+ */
+ function thru(value, interceptor, thisArg) {
+ return interceptor.call(thisArg, value);
+ }
+
+ /**
+ * Enables explicit method chaining on the wrapper object.
+ *
+ * @name chain
+ * @memberOf _
+ * @category Chain
+ * @returns {Object} Returns the new `lodash` wrapper instance.
+ * @example
+ *
+ * var users = [
+ * { 'user': 'barney', 'age': 36 },
+ * { 'user': 'fred', 'age': 40 }
+ * ];
+ *
+ * // without explicit chaining
+ * _(users).first();
+ * // => { 'user': 'barney', 'age': 36 }
+ *
+ * // with explicit chaining
+ * _(users).chain()
+ * .first()
+ * .pick('user')
+ * .value();
+ * // => { 'user': 'barney' }
+ */
+ function wrapperChain() {
+ return chain(this);
+ }
+
+ /**
+ * Executes the chained sequence and returns the wrapped result.
+ *
+ * @name commit
+ * @memberOf _
+ * @category Chain
+ * @returns {Object} Returns the new `lodash` wrapper instance.
+ * @example
+ *
+ * var array = [1, 2];
+ * var wrapped = _(array).push(3);
+ *
+ * console.log(array);
+ * // => [1, 2]
+ *
+ * wrapped = wrapped.commit();
+ * console.log(array);
+ * // => [1, 2, 3]
+ *
+ * wrapped.last();
+ * // => 3
+ *
+ * console.log(array);
+ * // => [1, 2, 3]
+ */
+ function wrapperCommit() {
+ return new LodashWrapper(this.value(), this.__chain__);
+ }
+
+ /**
+ * Creates a new array joining a wrapped array with any additional arrays
+ * and/or values.
+ *
+ * @name concat
+ * @memberOf _
+ * @category Chain
+ * @param {...*} [values] The values to concatenate.
+ * @returns {Array} Returns the new concatenated array.
+ * @example
+ *
+ * var array = [1];
+ * var wrapped = _(array).concat(2, [3], [[4]]);
+ *
+ * console.log(wrapped.value());
+ * // => [1, 2, 3, [4]]
+ *
+ * console.log(array);
+ * // => [1]
+ */
+ var wrapperConcat = restParam(function(values) {
+ values = baseFlatten(values);
+ return this.thru(function(array) {
+ return arrayConcat(isArray(array) ? array : [toObject(array)], values);
+ });
+ });
+
+ /**
+ * Creates a clone of the chained sequence planting `value` as the wrapped value.
+ *
+ * @name plant
+ * @memberOf _
+ * @category Chain
+ * @returns {Object} Returns the new `lodash` wrapper instance.
+ * @example
+ *
+ * var array = [1, 2];
+ * var wrapped = _(array).map(function(value) {
+ * return Math.pow(value, 2);
+ * });
+ *
+ * var other = [3, 4];
+ * var otherWrapped = wrapped.plant(other);
+ *
+ * otherWrapped.value();
+ * // => [9, 16]
+ *
+ * wrapped.value();
+ * // => [1, 4]
+ */
+ function wrapperPlant(value) {
+ var result,
+ parent = this;
+
+ while (parent instanceof baseLodash) {
+ var clone = wrapperClone(parent);
+ if (result) {
+ previous.__wrapped__ = clone;
+ } else {
+ result = clone;
+ }
+ var previous = clone;
+ parent = parent.__wrapped__;
+ }
+ previous.__wrapped__ = value;
+ return result;
+ }
+
+ /**
+ * Reverses the wrapped array so the first element becomes the last, the
+ * second element becomes the second to last, and so on.
+ *
+ * **Note:** This method mutates the wrapped array.
+ *
+ * @name reverse
+ * @memberOf _
+ * @category Chain
+ * @returns {Object} Returns the new reversed `lodash` wrapper instance.
+ * @example
+ *
+ * var array = [1, 2, 3];
+ *
+ * _(array).reverse().value()
+ * // => [3, 2, 1]
+ *
+ * console.log(array);
+ * // => [3, 2, 1]
+ */
+ function wrapperReverse() {
+ var value = this.__wrapped__;
+
+ var interceptor = function(value) {
+ return (wrapped && wrapped.__dir__ < 0) ? value : value.reverse();
+ };
+ if (value instanceof LazyWrapper) {
+ var wrapped = value;
+ if (this.__actions__.length) {
+ wrapped = new LazyWrapper(this);
+ }
+ wrapped = wrapped.reverse();
+ wrapped.__actions__.push({ 'func': thru, 'args': [interceptor], 'thisArg': undefined });
+ return new LodashWrapper(wrapped, this.__chain__);
+ }
+ return this.thru(interceptor);
+ }
+
+ /**
+ * Produces the result of coercing the unwrapped value to a string.
+ *
+ * @name toString
+ * @memberOf _
+ * @category Chain
+ * @returns {string} Returns the coerced string value.
+ * @example
+ *
+ * _([1, 2, 3]).toString();
+ * // => '1,2,3'
+ */
+ function wrapperToString() {
+ return (this.value() + '');
+ }
+
+ /**
+ * Executes the chained sequence to extract the unwrapped value.
+ *
+ * @name value
+ * @memberOf _
+ * @alias run, toJSON, valueOf
+ * @category Chain
+ * @returns {*} Returns the resolved unwrapped value.
+ * @example
+ *
+ * _([1, 2, 3]).value();
+ * // => [1, 2, 3]
+ */
+ function wrapperValue() {
+ return baseWrapperValue(this.__wrapped__, this.__actions__);
+ }
+
+ /*------------------------------------------------------------------------*/
+
+ /**
+ * Creates an array of elements corresponding to the given keys, or indexes,
+ * of `collection`. Keys may be specified as individual arguments or as arrays
+ * of keys.
+ *
+ * @static
+ * @memberOf _
+ * @category Collection
+ * @param {Array|Object|string} collection The collection to iterate over.
+ * @param {...(number|number[]|string|string[])} [props] The property names
+ * or indexes of elements to pick, specified individually or in arrays.
+ * @returns {Array} Returns the new array of picked elements.
+ * @example
+ *
+ * _.at(['a', 'b', 'c'], [0, 2]);
+ * // => ['a', 'c']
+ *
+ * _.at(['barney', 'fred', 'pebbles'], 0, 2);
+ * // => ['barney', 'pebbles']
+ */
+ var at = restParam(function(collection, props) {
+ return baseAt(collection, baseFlatten(props));
+ });
+
+ /**
+ * Creates an object composed of keys generated from the results of running
+ * each element of `collection` through `iteratee`. The corresponding value
+ * of each key is the number of times the key was returned by `iteratee`.
+ * The `iteratee` is bound to `thisArg` and invoked with three arguments:
+ * (value, index|key, collection).
+ *
+ * If a property name is provided for `iteratee` the created `_.property`
+ * style callback returns the property value of the given element.
+ *
+ * If a value is also provided for `thisArg` the created `_.matchesProperty`
+ * style callback returns `true` for elements that have a matching property
+ * value, else `false`.
+ *
+ * If an object is provided for `iteratee` the created `_.matches` style
+ * callback returns `true` for elements that have the properties of the given
+ * object, else `false`.
+ *
+ * @static
+ * @memberOf _
+ * @category Collection
+ * @param {Array|Object|string} collection The collection to iterate over.
+ * @param {Function|Object|string} [iteratee=_.identity] The function invoked
+ * per iteration.
+ * @param {*} [thisArg] The `this` binding of `iteratee`.
+ * @returns {Object} Returns the composed aggregate object.
+ * @example
+ *
+ * _.countBy([4.3, 6.1, 6.4], function(n) {
+ * return Math.floor(n);
+ * });
+ * // => { '4': 1, '6': 2 }
+ *
+ * _.countBy([4.3, 6.1, 6.4], function(n) {
+ * return this.floor(n);
+ * }, Math);
+ * // => { '4': 1, '6': 2 }
+ *
+ * _.countBy(['one', 'two', 'three'], 'length');
+ * // => { '3': 2, '5': 1 }
+ */
+ var countBy = createAggregator(function(result, value, key) {
+ hasOwnProperty.call(result, key) ? ++result[key] : (result[key] = 1);
+ });
+
+ /**
+ * Checks if `predicate` returns truthy for **all** elements of `collection`.
+ * The predicate is bound to `thisArg` and invoked with three arguments:
+ * (value, index|key, collection).
+ *
+ * If a property name is provided for `predicate` the created `_.property`
+ * style callback returns the property value of the given element.
+ *
+ * If a value is also provided for `thisArg` the created `_.matchesProperty`
+ * style callback returns `true` for elements that have a matching property
+ * value, else `false`.
+ *
+ * If an object is provided for `predicate` the created `_.matches` style
+ * callback returns `true` for elements that have the properties of the given
+ * object, else `false`.
+ *
+ * @static
+ * @memberOf _
+ * @alias all
+ * @category Collection
+ * @param {Array|Object|string} collection The collection to iterate over.
+ * @param {Function|Object|string} [predicate=_.identity] The function invoked
+ * per iteration.
+ * @param {*} [thisArg] The `this` binding of `predicate`.
+ * @returns {boolean} Returns `true` if all elements pass the predicate check,
+ * else `false`.
+ * @example
+ *
+ * _.every([true, 1, null, 'yes'], Boolean);
+ * // => false
+ *
+ * var users = [
+ * { 'user': 'barney', 'active': false },
+ * { 'user': 'fred', 'active': false }
+ * ];
+ *
+ * // using the `_.matches` callback shorthand
+ * _.every(users, { 'user': 'barney', 'active': false });
+ * // => false
+ *
+ * // using the `_.matchesProperty` callback shorthand
+ * _.every(users, 'active', false);
+ * // => true
+ *
+ * // using the `_.property` callback shorthand
+ * _.every(users, 'active');
+ * // => false
+ */
+ function every(collection, predicate, thisArg) {
+ var func = isArray(collection) ? arrayEvery : baseEvery;
+ if (thisArg && isIterateeCall(collection, predicate, thisArg)) {
+ predicate = undefined;
+ }
+ if (typeof predicate != 'function' || thisArg !== undefined) {
+ predicate = getCallback(predicate, thisArg, 3);
+ }
+ return func(collection, predicate);
+ }
+
+ /**
+ * Iterates over elements of `collection`, returning an array of all elements
+ * `predicate` returns truthy for. The predicate is bound to `thisArg` and
+ * invoked with three arguments: (value, index|key, collection).
+ *
+ * If a property name is provided for `predicate` the created `_.property`
+ * style callback returns the property value of the given element.
+ *
+ * If a value is also provided for `thisArg` the created `_.matchesProperty`
+ * style callback returns `true` for elements that have a matching property
+ * value, else `false`.
+ *
+ * If an object is provided for `predicate` the created `_.matches` style
+ * callback returns `true` for elements that have the properties of the given
+ * object, else `false`.
+ *
+ * @static
+ * @memberOf _
+ * @alias select
+ * @category Collection
+ * @param {Array|Object|string} collection The collection to iterate over.
+ * @param {Function|Object|string} [predicate=_.identity] The function invoked
+ * per iteration.
+ * @param {*} [thisArg] The `this` binding of `predicate`.
+ * @returns {Array} Returns the new filtered array.
+ * @example
+ *
+ * _.filter([4, 5, 6], function(n) {
+ * return n % 2 == 0;
+ * });
+ * // => [4, 6]
+ *
+ * var users = [
+ * { 'user': 'barney', 'age': 36, 'active': true },
+ * { 'user': 'fred', 'age': 40, 'active': false }
+ * ];
+ *
+ * // using the `_.matches` callback shorthand
+ * _.pluck(_.filter(users, { 'age': 36, 'active': true }), 'user');
+ * // => ['barney']
+ *
+ * // using the `_.matchesProperty` callback shorthand
+ * _.pluck(_.filter(users, 'active', false), 'user');
+ * // => ['fred']
+ *
+ * // using the `_.property` callback shorthand
+ * _.pluck(_.filter(users, 'active'), 'user');
+ * // => ['barney']
+ */
+ function filter(collection, predicate, thisArg) {
+ var func = isArray(collection) ? arrayFilter : baseFilter;
+ predicate = getCallback(predicate, thisArg, 3);
+ return func(collection, predicate);
+ }
+
+ /**
+ * Iterates over elements of `collection`, returning the first element
+ * `predicate` returns truthy for. The predicate is bound to `thisArg` and
+ * invoked with three arguments: (value, index|key, collection).
+ *
+ * If a property name is provided for `predicate` the created `_.property`
+ * style callback returns the property value of the given element.
+ *
+ * If a value is also provided for `thisArg` the created `_.matchesProperty`
+ * style callback returns `true` for elements that have a matching property
+ * value, else `false`.
+ *
+ * If an object is provided for `predicate` the created `_.matches` style
+ * callback returns `true` for elements that have the properties of the given
+ * object, else `false`.
+ *
+ * @static
+ * @memberOf _
+ * @alias detect
+ * @category Collection
+ * @param {Array|Object|string} collection The collection to search.
+ * @param {Function|Object|string} [predicate=_.identity] The function invoked
+ * per iteration.
+ * @param {*} [thisArg] The `this` binding of `predicate`.
+ * @returns {*} Returns the matched element, else `undefined`.
+ * @example
+ *
+ * var users = [
+ * { 'user': 'barney', 'age': 36, 'active': true },
+ * { 'user': 'fred', 'age': 40, 'active': false },
+ * { 'user': 'pebbles', 'age': 1, 'active': true }
+ * ];
+ *
+ * _.result(_.find(users, function(chr) {
+ * return chr.age < 40;
+ * }), 'user');
+ * // => 'barney'
+ *
+ * // using the `_.matches` callback shorthand
+ * _.result(_.find(users, { 'age': 1, 'active': true }), 'user');
+ * // => 'pebbles'
+ *
+ * // using the `_.matchesProperty` callback shorthand
+ * _.result(_.find(users, 'active', false), 'user');
+ * // => 'fred'
+ *
+ * // using the `_.property` callback shorthand
+ * _.result(_.find(users, 'active'), 'user');
+ * // => 'barney'
+ */
+ var find = createFind(baseEach);
+
+ /**
+ * This method is like `_.find` except that it iterates over elements of
+ * `collection` from right to left.
+ *
+ * @static
+ * @memberOf _
+ * @category Collection
+ * @param {Array|Object|string} collection The collection to search.
+ * @param {Function|Object|string} [predicate=_.identity] The function invoked
+ * per iteration.
+ * @param {*} [thisArg] The `this` binding of `predicate`.
+ * @returns {*} Returns the matched element, else `undefined`.
+ * @example
+ *
+ * _.findLast([1, 2, 3, 4], function(n) {
+ * return n % 2 == 1;
+ * });
+ * // => 3
+ */
+ var findLast = createFind(baseEachRight, true);
+
+ /**
+ * Performs a deep comparison between each element in `collection` and the
+ * source object, returning the first element that has equivalent property
+ * values.
+ *
+ * **Note:** This method supports comparing arrays, booleans, `Date` objects,
+ * numbers, `Object` objects, regexes, and strings. Objects are compared by
+ * their own, not inherited, enumerable properties. For comparing a single
+ * own or inherited property value see `_.matchesProperty`.
+ *
+ * @static
+ * @memberOf _
+ * @category Collection
+ * @param {Array|Object|string} collection The collection to search.
+ * @param {Object} source The object of property values to match.
+ * @returns {*} Returns the matched element, else `undefined`.
+ * @example
+ *
+ * var users = [
+ * { 'user': 'barney', 'age': 36, 'active': true },
+ * { 'user': 'fred', 'age': 40, 'active': false }
+ * ];
+ *
+ * _.result(_.findWhere(users, { 'age': 36, 'active': true }), 'user');
+ * // => 'barney'
+ *
+ * _.result(_.findWhere(users, { 'age': 40, 'active': false }), 'user');
+ * // => 'fred'
+ */
+ function findWhere(collection, source) {
+ return find(collection, baseMatches(source));
+ }
+
+ /**
+ * Iterates over elements of `collection` invoking `iteratee` for each element.
+ * The `iteratee` is bound to `thisArg` and invoked with three arguments:
+ * (value, index|key, collection). Iteratee functions may exit iteration early
+ * by explicitly returning `false`.
+ *
+ * **Note:** As with other "Collections" methods, objects with a "length" property
+ * are iterated like arrays. To avoid this behavior `_.forIn` or `_.forOwn`
+ * may be used for object iteration.
+ *
+ * @static
+ * @memberOf _
+ * @alias each
+ * @category Collection
+ * @param {Array|Object|string} collection The collection to iterate over.
+ * @param {Function} [iteratee=_.identity] The function invoked per iteration.
+ * @param {*} [thisArg] The `this` binding of `iteratee`.
+ * @returns {Array|Object|string} Returns `collection`.
+ * @example
+ *
+ * _([1, 2]).forEach(function(n) {
+ * console.log(n);
+ * }).value();
+ * // => logs each value from left to right and returns the array
+ *
+ * _.forEach({ 'a': 1, 'b': 2 }, function(n, key) {
+ * console.log(n, key);
+ * });
+ * // => logs each value-key pair and returns the object (iteration order is not guaranteed)
+ */
+ var forEach = createForEach(arrayEach, baseEach);
+
+ /**
+ * This method is like `_.forEach` except that it iterates over elements of
+ * `collection` from right to left.
+ *
+ * @static
+ * @memberOf _
+ * @alias eachRight
+ * @category Collection
+ * @param {Array|Object|string} collection The collection to iterate over.
+ * @param {Function} [iteratee=_.identity] The function invoked per iteration.
+ * @param {*} [thisArg] The `this` binding of `iteratee`.
+ * @returns {Array|Object|string} Returns `collection`.
+ * @example
+ *
+ * _([1, 2]).forEachRight(function(n) {
+ * console.log(n);
+ * }).value();
+ * // => logs each value from right to left and returns the array
+ */
+ var forEachRight = createForEach(arrayEachRight, baseEachRight);
+
+ /**
+ * Creates an object composed of keys generated from the results of running
+ * each element of `collection` through `iteratee`. The corresponding value
+ * of each key is an array of the elements responsible for generating the key.
+ * The `iteratee` is bound to `thisArg` and invoked with three arguments:
+ * (value, index|key, collection).
+ *
+ * If a property name is provided for `iteratee` the created `_.property`
+ * style callback returns the property value of the given element.
+ *
+ * If a value is also provided for `thisArg` the created `_.matchesProperty`
+ * style callback returns `true` for elements that have a matching property
+ * value, else `false`.
+ *
+ * If an object is provided for `iteratee` the created `_.matches` style
+ * callback returns `true` for elements that have the properties of the given
+ * object, else `false`.
+ *
+ * @static
+ * @memberOf _
+ * @category Collection
+ * @param {Array|Object|string} collection The collection to iterate over.
+ * @param {Function|Object|string} [iteratee=_.identity] The function invoked
+ * per iteration.
+ * @param {*} [thisArg] The `this` binding of `iteratee`.
+ * @returns {Object} Returns the composed aggregate object.
+ * @example
+ *
+ * _.groupBy([4.2, 6.1, 6.4], function(n) {
+ * return Math.floor(n);
+ * });
+ * // => { '4': [4.2], '6': [6.1, 6.4] }
+ *
+ * _.groupBy([4.2, 6.1, 6.4], function(n) {
+ * return this.floor(n);
+ * }, Math);
+ * // => { '4': [4.2], '6': [6.1, 6.4] }
+ *
+ * // using the `_.property` callback shorthand
+ * _.groupBy(['one', 'two', 'three'], 'length');
+ * // => { '3': ['one', 'two'], '5': ['three'] }
+ */
+ var groupBy = createAggregator(function(result, value, key) {
+ if (hasOwnProperty.call(result, key)) {
+ result[key].push(value);
+ } else {
+ result[key] = [value];
+ }
+ });
+
+ /**
+ * Checks if `value` is in `collection` using
+ * [`SameValueZero`](http://ecma-international.org/ecma-262/6.0/#sec-samevaluezero)
+ * for equality comparisons. If `fromIndex` is negative, it is used as the offset
+ * from the end of `collection`.
+ *
+ * @static
+ * @memberOf _
+ * @alias contains, include
+ * @category Collection
+ * @param {Array|Object|string} collection The collection to search.
+ * @param {*} target The value to search for.
+ * @param {number} [fromIndex=0] The index to search from.
+ * @param- {Object} [guard] Enables use as a callback for functions like `_.reduce`.
+ * @returns {boolean} Returns `true` if a matching element is found, else `false`.
+ * @example
+ *
+ * _.includes([1, 2, 3], 1);
+ * // => true
+ *
+ * _.includes([1, 2, 3], 1, 2);
+ * // => false
+ *
+ * _.includes({ 'user': 'fred', 'age': 40 }, 'fred');
+ * // => true
+ *
+ * _.includes('pebbles', 'eb');
+ * // => true
+ */
+ function includes(collection, target, fromIndex, guard) {
+ var length = collection ? getLength(collection) : 0;
+ if (!isLength(length)) {
+ collection = values(collection);
+ length = collection.length;
+ }
+ if (typeof fromIndex != 'number' || (guard && isIterateeCall(target, fromIndex, guard))) {
+ fromIndex = 0;
+ } else {
+ fromIndex = fromIndex < 0 ? nativeMax(length + fromIndex, 0) : (fromIndex || 0);
+ }
+ return (typeof collection == 'string' || !isArray(collection) && isString(collection))
+ ? (fromIndex <= length && collection.indexOf(target, fromIndex) > -1)
+ : (!!length && getIndexOf(collection, target, fromIndex) > -1);
+ }
+
+ /**
+ * Creates an object composed of keys generated from the results of running
+ * each element of `collection` through `iteratee`. The corresponding value
+ * of each key is the last element responsible for generating the key. The
+ * iteratee function is bound to `thisArg` and invoked with three arguments:
+ * (value, index|key, collection).
+ *
+ * If a property name is provided for `iteratee` the created `_.property`
+ * style callback returns the property value of the given element.
+ *
+ * If a value is also provided for `thisArg` the created `_.matchesProperty`
+ * style callback returns `true` for elements that have a matching property
+ * value, else `false`.
+ *
+ * If an object is provided for `iteratee` the created `_.matches` style
+ * callback returns `true` for elements that have the properties of the given
+ * object, else `false`.
+ *
+ * @static
+ * @memberOf _
+ * @category Collection
+ * @param {Array|Object|string} collection The collection to iterate over.
+ * @param {Function|Object|string} [iteratee=_.identity] The function invoked
+ * per iteration.
+ * @param {*} [thisArg] The `this` binding of `iteratee`.
+ * @returns {Object} Returns the composed aggregate object.
+ * @example
+ *
+ * var keyData = [
+ * { 'dir': 'left', 'code': 97 },
+ * { 'dir': 'right', 'code': 100 }
+ * ];
+ *
+ * _.indexBy(keyData, 'dir');
+ * // => { 'left': { 'dir': 'left', 'code': 97 }, 'right': { 'dir': 'right', 'code': 100 } }
+ *
+ * _.indexBy(keyData, function(object) {
+ * return String.fromCharCode(object.code);
+ * });
+ * // => { 'a': { 'dir': 'left', 'code': 97 }, 'd': { 'dir': 'right', 'code': 100 } }
+ *
+ * _.indexBy(keyData, function(object) {
+ * return this.fromCharCode(object.code);
+ * }, String);
+ * // => { 'a': { 'dir': 'left', 'code': 97 }, 'd': { 'dir': 'right', 'code': 100 } }
+ */
+ var indexBy = createAggregator(function(result, value, key) {
+ result[key] = value;
+ });
+
+ /**
+ * Invokes the method at `path` of each element in `collection`, returning
+ * an array of the results of each invoked method. Any additional arguments
+ * are provided to each invoked method. If `methodName` is a function it is
+ * invoked for, and `this` bound to, each element in `collection`.
+ *
+ * @static
+ * @memberOf _
+ * @category Collection
+ * @param {Array|Object|string} collection The collection to iterate over.
+ * @param {Array|Function|string} path The path of the method to invoke or
+ * the function invoked per iteration.
+ * @param {...*} [args] The arguments to invoke the method with.
+ * @returns {Array} Returns the array of results.
+ * @example
+ *
+ * _.invoke([[5, 1, 7], [3, 2, 1]], 'sort');
+ * // => [[1, 5, 7], [1, 2, 3]]
+ *
+ * _.invoke([123, 456], String.prototype.split, '');
+ * // => [['1', '2', '3'], ['4', '5', '6']]
+ */
+ var invoke = restParam(function(collection, path, args) {
+ var index = -1,
+ isFunc = typeof path == 'function',
+ isProp = isKey(path),
+ result = isArrayLike(collection) ? Array(collection.length) : [];
+
+ baseEach(collection, function(value) {
+ var func = isFunc ? path : ((isProp && value != null) ? value[path] : undefined);
+ result[++index] = func ? func.apply(value, args) : invokePath(value, path, args);
+ });
+ return result;
+ });
+
+ /**
+ * Creates an array of values by running each element in `collection` through
+ * `iteratee`. The `iteratee` is bound to `thisArg` and invoked with three
+ * arguments: (value, index|key, collection).
+ *
+ * If a property name is provided for `iteratee` the created `_.property`
+ * style callback returns the property value of the given element.
+ *
+ * If a value is also provided for `thisArg` the created `_.matchesProperty`
+ * style callback returns `true` for elements that have a matching property
+ * value, else `false`.
+ *
+ * If an object is provided for `iteratee` the created `_.matches` style
+ * callback returns `true` for elements that have the properties of the given
+ * object, else `false`.
+ *
+ * Many lodash methods are guarded to work as iteratees for methods like
+ * `_.every`, `_.filter`, `_.map`, `_.mapValues`, `_.reject`, and `_.some`.
+ *
+ * The guarded methods are:
+ * `ary`, `callback`, `chunk`, `clone`, `create`, `curry`, `curryRight`,
+ * `drop`, `dropRight`, `every`, `fill`, `flatten`, `invert`, `max`, `min`,
+ * `parseInt`, `slice`, `sortBy`, `take`, `takeRight`, `template`, `trim`,
+ * `trimLeft`, `trimRight`, `trunc`, `random`, `range`, `sample`, `some`,
+ * `sum`, `uniq`, and `words`
+ *
+ * @static
+ * @memberOf _
+ * @alias collect
+ * @category Collection
+ * @param {Array|Object|string} collection The collection to iterate over.
+ * @param {Function|Object|string} [iteratee=_.identity] The function invoked
+ * per iteration.
+ * @param {*} [thisArg] The `this` binding of `iteratee`.
+ * @returns {Array} Returns the new mapped array.
+ * @example
+ *
+ * function timesThree(n) {
+ * return n * 3;
+ * }
+ *
+ * _.map([1, 2], timesThree);
+ * // => [3, 6]
+ *
+ * _.map({ 'a': 1, 'b': 2 }, timesThree);
+ * // => [3, 6] (iteration order is not guaranteed)
+ *
+ * var users = [
+ * { 'user': 'barney' },
+ * { 'user': 'fred' }
+ * ];
+ *
+ * // using the `_.property` callback shorthand
+ * _.map(users, 'user');
+ * // => ['barney', 'fred']
+ */
+ function map(collection, iteratee, thisArg) {
+ var func = isArray(collection) ? arrayMap : baseMap;
+ iteratee = getCallback(iteratee, thisArg, 3);
+ return func(collection, iteratee);
+ }
+
+ /**
+ * Creates an array of elements split into two groups, the first of which
+ * contains elements `predicate` returns truthy for, while the second of which
+ * contains elements `predicate` returns falsey for. The predicate is bound
+ * to `thisArg` and invoked with three arguments: (value, index|key, collection).
+ *
+ * If a property name is provided for `predicate` the created `_.property`
+ * style callback returns the property value of the given element.
+ *
+ * If a value is also provided for `thisArg` the created `_.matchesProperty`
+ * style callback returns `true` for elements that have a matching property
+ * value, else `false`.
+ *
+ * If an object is provided for `predicate` the created `_.matches` style
+ * callback returns `true` for elements that have the properties of the given
+ * object, else `false`.
+ *
+ * @static
+ * @memberOf _
+ * @category Collection
+ * @param {Array|Object|string} collection The collection to iterate over.
+ * @param {Function|Object|string} [predicate=_.identity] The function invoked
+ * per iteration.
+ * @param {*} [thisArg] The `this` binding of `predicate`.
+ * @returns {Array} Returns the array of grouped elements.
+ * @example
+ *
+ * _.partition([1, 2, 3], function(n) {
+ * return n % 2;
+ * });
+ * // => [[1, 3], [2]]
+ *
+ * _.partition([1.2, 2.3, 3.4], function(n) {
+ * return this.floor(n) % 2;
+ * }, Math);
+ * // => [[1.2, 3.4], [2.3]]
+ *
+ * var users = [
+ * { 'user': 'barney', 'age': 36, 'active': false },
+ * { 'user': 'fred', 'age': 40, 'active': true },
+ * { 'user': 'pebbles', 'age': 1, 'active': false }
+ * ];
+ *
+ * var mapper = function(array) {
+ * return _.pluck(array, 'user');
+ * };
+ *
+ * // using the `_.matches` callback shorthand
+ * _.map(_.partition(users, { 'age': 1, 'active': false }), mapper);
+ * // => [['pebbles'], ['barney', 'fred']]
+ *
+ * // using the `_.matchesProperty` callback shorthand
+ * _.map(_.partition(users, 'active', false), mapper);
+ * // => [['barney', 'pebbles'], ['fred']]
+ *
+ * // using the `_.property` callback shorthand
+ * _.map(_.partition(users, 'active'), mapper);
+ * // => [['fred'], ['barney', 'pebbles']]
+ */
+ var partition = createAggregator(function(result, value, key) {
+ result[key ? 0 : 1].push(value);
+ }, function() { return [[], []]; });
+
+ /**
+ * Gets the property value of `path` from all elements in `collection`.
+ *
+ * @static
+ * @memberOf _
+ * @category Collection
+ * @param {Array|Object|string} collection The collection to iterate over.
+ * @param {Array|string} path The path of the property to pluck.
+ * @returns {Array} Returns the property values.
+ * @example
+ *
+ * var users = [
+ * { 'user': 'barney', 'age': 36 },
+ * { 'user': 'fred', 'age': 40 }
+ * ];
+ *
+ * _.pluck(users, 'user');
+ * // => ['barney', 'fred']
+ *
+ * var userIndex = _.indexBy(users, 'user');
+ * _.pluck(userIndex, 'age');
+ * // => [36, 40] (iteration order is not guaranteed)
+ */
+ function pluck(collection, path) {
+ return map(collection, property(path));
+ }
+
+ /**
+ * Reduces `collection` to a value which is the accumulated result of running
+ * each element in `collection` through `iteratee`, where each successive
+ * invocation is supplied the return value of the previous. If `accumulator`
+ * is not provided the first element of `collection` is used as the initial
+ * value. The `iteratee` is bound to `thisArg` and invoked with four arguments:
+ * (accumulator, value, index|key, collection).
+ *
+ * Many lodash methods are guarded to work as iteratees for methods like
+ * `_.reduce`, `_.reduceRight`, and `_.transform`.
+ *
+ * The guarded methods are:
+ * `assign`, `defaults`, `defaultsDeep`, `includes`, `merge`, `sortByAll`,
+ * and `sortByOrder`
+ *
+ * @static
+ * @memberOf _
+ * @alias foldl, inject
+ * @category Collection
+ * @param {Array|Object|string} collection The collection to iterate over.
+ * @param {Function} [iteratee=_.identity] The function invoked per iteration.
+ * @param {*} [accumulator] The initial value.
+ * @param {*} [thisArg] The `this` binding of `iteratee`.
+ * @returns {*} Returns the accumulated value.
+ * @example
+ *
+ * _.reduce([1, 2], function(total, n) {
+ * return total + n;
+ * });
+ * // => 3
+ *
+ * _.reduce({ 'a': 1, 'b': 2 }, function(result, n, key) {
+ * result[key] = n * 3;
+ * return result;
+ * }, {});
+ * // => { 'a': 3, 'b': 6 } (iteration order is not guaranteed)
+ */
+ var reduce = createReduce(arrayReduce, baseEach);
+
+ /**
+ * This method is like `_.reduce` except that it iterates over elements of
+ * `collection` from right to left.
+ *
+ * @static
+ * @memberOf _
+ * @alias foldr
+ * @category Collection
+ * @param {Array|Object|string} collection The collection to iterate over.
+ * @param {Function} [iteratee=_.identity] The function invoked per iteration.
+ * @param {*} [accumulator] The initial value.
+ * @param {*} [thisArg] The `this` binding of `iteratee`.
+ * @returns {*} Returns the accumulated value.
+ * @example
+ *
+ * var array = [[0, 1], [2, 3], [4, 5]];
+ *
+ * _.reduceRight(array, function(flattened, other) {
+ * return flattened.concat(other);
+ * }, []);
+ * // => [4, 5, 2, 3, 0, 1]
+ */
+ var reduceRight = createReduce(arrayReduceRight, baseEachRight);
+
+ /**
+ * The opposite of `_.filter`; this method returns the elements of `collection`
+ * that `predicate` does **not** return truthy for.
+ *
+ * @static
+ * @memberOf _
+ * @category Collection
+ * @param {Array|Object|string} collection The collection to iterate over.
+ * @param {Function|Object|string} [predicate=_.identity] The function invoked
+ * per iteration.
+ * @param {*} [thisArg] The `this` binding of `predicate`.
+ * @returns {Array} Returns the new filtered array.
+ * @example
+ *
+ * _.reject([1, 2, 3, 4], function(n) {
+ * return n % 2 == 0;
+ * });
+ * // => [1, 3]
+ *
+ * var users = [
+ * { 'user': 'barney', 'age': 36, 'active': false },
+ * { 'user': 'fred', 'age': 40, 'active': true }
+ * ];
+ *
+ * // using the `_.matches` callback shorthand
+ * _.pluck(_.reject(users, { 'age': 40, 'active': true }), 'user');
+ * // => ['barney']
+ *
+ * // using the `_.matchesProperty` callback shorthand
+ * _.pluck(_.reject(users, 'active', false), 'user');
+ * // => ['fred']
+ *
+ * // using the `_.property` callback shorthand
+ * _.pluck(_.reject(users, 'active'), 'user');
+ * // => ['barney']
+ */
+ function reject(collection, predicate, thisArg) {
+ var func = isArray(collection) ? arrayFilter : baseFilter;
+ predicate = getCallback(predicate, thisArg, 3);
+ return func(collection, function(value, index, collection) {
+ return !predicate(value, index, collection);
+ });
+ }
+
+ /**
+ * Gets a random element or `n` random elements from a collection.
+ *
+ * @static
+ * @memberOf _
+ * @category Collection
+ * @param {Array|Object|string} collection The collection to sample.
+ * @param {number} [n] The number of elements to sample.
+ * @param- {Object} [guard] Enables use as a callback for functions like `_.map`.
+ * @returns {*} Returns the random sample(s).
+ * @example
+ *
+ * _.sample([1, 2, 3, 4]);
+ * // => 2
+ *
+ * _.sample([1, 2, 3, 4], 2);
+ * // => [3, 1]
+ */
+ function sample(collection, n, guard) {
+ if (guard ? isIterateeCall(collection, n, guard) : n == null) {
+ collection = toIterable(collection);
+ var length = collection.length;
+ return length > 0 ? collection[baseRandom(0, length - 1)] : undefined;
+ }
+ var index = -1,
+ result = toArray(collection),
+ length = result.length,
+ lastIndex = length - 1;
+
+ n = nativeMin(n < 0 ? 0 : (+n || 0), length);
+ while (++index < n) {
+ var rand = baseRandom(index, lastIndex),
+ value = result[rand];
+
+ result[rand] = result[index];
+ result[index] = value;
+ }
+ result.length = n;
+ return result;
+ }
+
+ /**
+ * Creates an array of shuffled values, using a version of the
+ * [Fisher-Yates shuffle](https://en.wikipedia.org/wiki/Fisher-Yates_shuffle).
+ *
+ * @static
+ * @memberOf _
+ * @category Collection
+ * @param {Array|Object|string} collection The collection to shuffle.
+ * @returns {Array} Returns the new shuffled array.
+ * @example
+ *
+ * _.shuffle([1, 2, 3, 4]);
+ * // => [4, 1, 3, 2]
+ */
+ function shuffle(collection) {
+ return sample(collection, POSITIVE_INFINITY);
+ }
+
+ /**
+ * Gets the size of `collection` by returning its length for array-like
+ * values or the number of own enumerable properties for objects.
+ *
+ * @static
+ * @memberOf _
+ * @category Collection
+ * @param {Array|Object|string} collection The collection to inspect.
+ * @returns {number} Returns the size of `collection`.
+ * @example
+ *
+ * _.size([1, 2, 3]);
+ * // => 3
+ *
+ * _.size({ 'a': 1, 'b': 2 });
+ * // => 2
+ *
+ * _.size('pebbles');
+ * // => 7
+ */
+ function size(collection) {
+ var length = collection ? getLength(collection) : 0;
+ return isLength(length) ? length : keys(collection).length;
+ }
+
+ /**
+ * Checks if `predicate` returns truthy for **any** element of `collection`.
+ * The function returns as soon as it finds a passing value and does not iterate
+ * over the entire collection. The predicate is bound to `thisArg` and invoked
+ * with three arguments: (value, index|key, collection).
+ *
+ * If a property name is provided for `predicate` the created `_.property`
+ * style callback returns the property value of the given element.
+ *
+ * If a value is also provided for `thisArg` the created `_.matchesProperty`
+ * style callback returns `true` for elements that have a matching property
+ * value, else `false`.
+ *
+ * If an object is provided for `predicate` the created `_.matches` style
+ * callback returns `true` for elements that have the properties of the given
+ * object, else `false`.
+ *
+ * @static
+ * @memberOf _
+ * @alias any
+ * @category Collection
+ * @param {Array|Object|string} collection The collection to iterate over.
+ * @param {Function|Object|string} [predicate=_.identity] The function invoked
+ * per iteration.
+ * @param {*} [thisArg] The `this` binding of `predicate`.
+ * @returns {boolean} Returns `true` if any element passes the predicate check,
+ * else `false`.
+ * @example
+ *
+ * _.some([null, 0, 'yes', false], Boolean);
+ * // => true
+ *
+ * var users = [
+ * { 'user': 'barney', 'active': true },
+ * { 'user': 'fred', 'active': false }
+ * ];
+ *
+ * // using the `_.matches` callback shorthand
+ * _.some(users, { 'user': 'barney', 'active': false });
+ * // => false
+ *
+ * // using the `_.matchesProperty` callback shorthand
+ * _.some(users, 'active', false);
+ * // => true
+ *
+ * // using the `_.property` callback shorthand
+ * _.some(users, 'active');
+ * // => true
+ */
+ function some(collection, predicate, thisArg) {
+ var func = isArray(collection) ? arraySome : baseSome;
+ if (thisArg && isIterateeCall(collection, predicate, thisArg)) {
+ predicate = undefined;
+ }
+ if (typeof predicate != 'function' || thisArg !== undefined) {
+ predicate = getCallback(predicate, thisArg, 3);
+ }
+ return func(collection, predicate);
+ }
+
+ /**
+ * Creates an array of elements, sorted in ascending order by the results of
+ * running each element in a collection through `iteratee`. This method performs
+ * a stable sort, that is, it preserves the original sort order of equal elements.
+ * The `iteratee` is bound to `thisArg` and invoked with three arguments:
+ * (value, index|key, collection).
+ *
+ * If a property name is provided for `iteratee` the created `_.property`
+ * style callback returns the property value of the given element.
+ *
+ * If a value is also provided for `thisArg` the created `_.matchesProperty`
+ * style callback returns `true` for elements that have a matching property
+ * value, else `false`.
+ *
+ * If an object is provided for `iteratee` the created `_.matches` style
+ * callback returns `true` for elements that have the properties of the given
+ * object, else `false`.
+ *
+ * @static
+ * @memberOf _
+ * @category Collection
+ * @param {Array|Object|string} collection The collection to iterate over.
+ * @param {Function|Object|string} [iteratee=_.identity] The function invoked
+ * per iteration.
+ * @param {*} [thisArg] The `this` binding of `iteratee`.
+ * @returns {Array} Returns the new sorted array.
+ * @example
+ *
+ * _.sortBy([1, 2, 3], function(n) {
+ * return Math.sin(n);
+ * });
+ * // => [3, 1, 2]
+ *
+ * _.sortBy([1, 2, 3], function(n) {
+ * return this.sin(n);
+ * }, Math);
+ * // => [3, 1, 2]
+ *
+ * var users = [
+ * { 'user': 'fred' },
+ * { 'user': 'pebbles' },
+ * { 'user': 'barney' }
+ * ];
+ *
+ * // using the `_.property` callback shorthand
+ * _.pluck(_.sortBy(users, 'user'), 'user');
+ * // => ['barney', 'fred', 'pebbles']
+ */
+ function sortBy(collection, iteratee, thisArg) {
+ if (collection == null) {
+ return [];
+ }
+ if (thisArg && isIterateeCall(collection, iteratee, thisArg)) {
+ iteratee = undefined;
+ }
+ var index = -1;
+ iteratee = getCallback(iteratee, thisArg, 3);
+
+ var result = baseMap(collection, function(value, key, collection) {
+ return { 'criteria': iteratee(value, key, collection), 'index': ++index, 'value': value };
+ });
+ return baseSortBy(result, compareAscending);
+ }
+
+ /**
+ * This method is like `_.sortBy` except that it can sort by multiple iteratees
+ * or property names.
+ *
+ * If a property name is provided for an iteratee the created `_.property`
+ * style callback returns the property value of the given element.
+ *
+ * If an object is provided for an iteratee the created `_.matches` style
+ * callback returns `true` for elements that have the properties of the given
+ * object, else `false`.
+ *
+ * @static
+ * @memberOf _
+ * @category Collection
+ * @param {Array|Object|string} collection The collection to iterate over.
+ * @param {...(Function|Function[]|Object|Object[]|string|string[])} iteratees
+ * The iteratees to sort by, specified as individual values or arrays of values.
+ * @returns {Array} Returns the new sorted array.
+ * @example
+ *
+ * var users = [
+ * { 'user': 'fred', 'age': 48 },
+ * { 'user': 'barney', 'age': 36 },
+ * { 'user': 'fred', 'age': 42 },
+ * { 'user': 'barney', 'age': 34 }
+ * ];
+ *
+ * _.map(_.sortByAll(users, ['user', 'age']), _.values);
+ * // => [['barney', 34], ['barney', 36], ['fred', 42], ['fred', 48]]
+ *
+ * _.map(_.sortByAll(users, 'user', function(chr) {
+ * return Math.floor(chr.age / 10);
+ * }), _.values);
+ * // => [['barney', 36], ['barney', 34], ['fred', 48], ['fred', 42]]
+ */
+ var sortByAll = restParam(function(collection, iteratees) {
+ if (collection == null) {
+ return [];
+ }
+ var guard = iteratees[2];
+ if (guard && isIterateeCall(iteratees[0], iteratees[1], guard)) {
+ iteratees.length = 1;
+ }
+ return baseSortByOrder(collection, baseFlatten(iteratees), []);
+ });
+
+ /**
+ * This method is like `_.sortByAll` except that it allows specifying the
+ * sort orders of the iteratees to sort by. If `orders` is unspecified, all
+ * values are sorted in ascending order. Otherwise, a value is sorted in
+ * ascending order if its corresponding order is "asc", and descending if "desc".
+ *
+ * If a property name is provided for an iteratee the created `_.property`
+ * style callback returns the property value of the given element.
+ *
+ * If an object is provided for an iteratee the created `_.matches` style
+ * callback returns `true` for elements that have the properties of the given
+ * object, else `false`.
+ *
+ * @static
+ * @memberOf _
+ * @category Collection
+ * @param {Array|Object|string} collection The collection to iterate over.
+ * @param {Function[]|Object[]|string[]} iteratees The iteratees to sort by.
+ * @param {boolean[]} [orders] The sort orders of `iteratees`.
+ * @param- {Object} [guard] Enables use as a callback for functions like `_.reduce`.
+ * @returns {Array} Returns the new sorted array.
+ * @example
+ *
+ * var users = [
+ * { 'user': 'fred', 'age': 48 },
+ * { 'user': 'barney', 'age': 34 },
+ * { 'user': 'fred', 'age': 42 },
+ * { 'user': 'barney', 'age': 36 }
+ * ];
+ *
+ * // sort by `user` in ascending order and by `age` in descending order
+ * _.map(_.sortByOrder(users, ['user', 'age'], ['asc', 'desc']), _.values);
+ * // => [['barney', 36], ['barney', 34], ['fred', 48], ['fred', 42]]
+ */
+ function sortByOrder(collection, iteratees, orders, guard) {
+ if (collection == null) {
+ return [];
+ }
+ if (guard && isIterateeCall(iteratees, orders, guard)) {
+ orders = undefined;
+ }
+ if (!isArray(iteratees)) {
+ iteratees = iteratees == null ? [] : [iteratees];
+ }
+ if (!isArray(orders)) {
+ orders = orders == null ? [] : [orders];
+ }
+ return baseSortByOrder(collection, iteratees, orders);
+ }
+
+ /**
+ * Performs a deep comparison between each element in `collection` and the
+ * source object, returning an array of all elements that have equivalent
+ * property values.
+ *
+ * **Note:** This method supports comparing arrays, booleans, `Date` objects,
+ * numbers, `Object` objects, regexes, and strings. Objects are compared by
+ * their own, not inherited, enumerable properties. For comparing a single
+ * own or inherited property value see `_.matchesProperty`.
+ *
+ * @static
+ * @memberOf _
+ * @category Collection
+ * @param {Array|Object|string} collection The collection to search.
+ * @param {Object} source The object of property values to match.
+ * @returns {Array} Returns the new filtered array.
+ * @example
+ *
+ * var users = [
+ * { 'user': 'barney', 'age': 36, 'active': false, 'pets': ['hoppy'] },
+ * { 'user': 'fred', 'age': 40, 'active': true, 'pets': ['baby puss', 'dino'] }
+ * ];
+ *
+ * _.pluck(_.where(users, { 'age': 36, 'active': false }), 'user');
+ * // => ['barney']
+ *
+ * _.pluck(_.where(users, { 'pets': ['dino'] }), 'user');
+ * // => ['fred']
+ */
+ function where(collection, source) {
+ return filter(collection, baseMatches(source));
+ }
+
+ /*------------------------------------------------------------------------*/
+
+ /**
+ * Gets the number of milliseconds that have elapsed since the Unix epoch
+ * (1 January 1970 00:00:00 UTC).
+ *
+ * @static
+ * @memberOf _
+ * @category Date
+ * @example
+ *
+ * _.defer(function(stamp) {
+ * console.log(_.now() - stamp);
+ * }, _.now());
+ * // => logs the number of milliseconds it took for the deferred function to be invoked
+ */
+ var now = nativeNow || function() {
+ return new Date().getTime();
+ };
+
+ /*------------------------------------------------------------------------*/
+
+ /**
+ * The opposite of `_.before`; this method creates a function that invokes
+ * `func` once it is called `n` or more times.
+ *
+ * @static
+ * @memberOf _
+ * @category Function
+ * @param {number} n The number of calls before `func` is invoked.
+ * @param {Function} func The function to restrict.
+ * @returns {Function} Returns the new restricted function.
+ * @example
+ *
+ * var saves = ['profile', 'settings'];
+ *
+ * var done = _.after(saves.length, function() {
+ * console.log('done saving!');
+ * });
+ *
+ * _.forEach(saves, function(type) {
+ * asyncSave({ 'type': type, 'complete': done });
+ * });
+ * // => logs 'done saving!' after the two async saves have completed
+ */
+ function after(n, func) {
+ if (typeof func != 'function') {
+ if (typeof n == 'function') {
+ var temp = n;
+ n = func;
+ func = temp;
+ } else {
+ throw new TypeError(FUNC_ERROR_TEXT);
+ }
+ }
+ n = nativeIsFinite(n = +n) ? n : 0;
+ return function() {
+ if (--n < 1) {
+ return func.apply(this, arguments);
+ }
+ };
+ }
+
+ /**
+ * Creates a function that accepts up to `n` arguments ignoring any
+ * additional arguments.
+ *
+ * @static
+ * @memberOf _
+ * @category Function
+ * @param {Function} func The function to cap arguments for.
+ * @param {number} [n=func.length] The arity cap.
+ * @param- {Object} [guard] Enables use as a callback for functions like `_.map`.
+ * @returns {Function} Returns the new function.
+ * @example
+ *
+ * _.map(['6', '8', '10'], _.ary(parseInt, 1));
+ * // => [6, 8, 10]
+ */
+ function ary(func, n, guard) {
+ if (guard && isIterateeCall(func, n, guard)) {
+ n = undefined;
+ }
+ n = (func && n == null) ? func.length : nativeMax(+n || 0, 0);
+ return createWrapper(func, ARY_FLAG, undefined, undefined, undefined, undefined, n);
+ }
+
+ /**
+ * Creates a function that invokes `func`, with the `this` binding and arguments
+ * of the created function, while it is called less than `n` times. Subsequent
+ * calls to the created function return the result of the last `func` invocation.
+ *
+ * @static
+ * @memberOf _
+ * @category Function
+ * @param {number} n The number of calls at which `func` is no longer invoked.
+ * @param {Function} func The function to restrict.
+ * @returns {Function} Returns the new restricted function.
+ * @example
+ *
+ * jQuery('#add').on('click', _.before(5, addContactToList));
+ * // => allows adding up to 4 contacts to the list
+ */
+ function before(n, func) {
+ var result;
+ if (typeof func != 'function') {
+ if (typeof n == 'function') {
+ var temp = n;
+ n = func;
+ func = temp;
+ } else {
+ throw new TypeError(FUNC_ERROR_TEXT);
+ }
+ }
+ return function() {
+ if (--n > 0) {
+ result = func.apply(this, arguments);
+ }
+ if (n <= 1) {
+ func = undefined;
+ }
+ return result;
+ };
+ }
+
+ /**
+ * Creates a function that invokes `func` with the `this` binding of `thisArg`
+ * and prepends any additional `_.bind` arguments to those provided to the
+ * bound function.
+ *
+ * The `_.bind.placeholder` value, which defaults to `_` in monolithic builds,
+ * may be used as a placeholder for partially applied arguments.
+ *
+ * **Note:** Unlike native `Function#bind` this method does not set the "length"
+ * property of bound functions.
+ *
+ * @static
+ * @memberOf _
+ * @category Function
+ * @param {Function} func The function to bind.
+ * @param {*} thisArg The `this` binding of `func`.
+ * @param {...*} [partials] The arguments to be partially applied.
+ * @returns {Function} Returns the new bound function.
+ * @example
+ *
+ * var greet = function(greeting, punctuation) {
+ * return greeting + ' ' + this.user + punctuation;
+ * };
+ *
+ * var object = { 'user': 'fred' };
+ *
+ * var bound = _.bind(greet, object, 'hi');
+ * bound('!');
+ * // => 'hi fred!'
+ *
+ * // using placeholders
+ * var bound = _.bind(greet, object, _, '!');
+ * bound('hi');
+ * // => 'hi fred!'
+ */
+ var bind = restParam(function(func, thisArg, partials) {
+ var bitmask = BIND_FLAG;
+ if (partials.length) {
+ var holders = replaceHolders(partials, bind.placeholder);
+ bitmask |= PARTIAL_FLAG;
+ }
+ return createWrapper(func, bitmask, thisArg, partials, holders);
+ });
+
+ /**
+ * Binds methods of an object to the object itself, overwriting the existing
+ * method. Method names may be specified as individual arguments or as arrays
+ * of method names. If no method names are provided all enumerable function
+ * properties, own and inherited, of `object` are bound.
+ *
+ * **Note:** This method does not set the "length" property of bound functions.
+ *
+ * @static
+ * @memberOf _
+ * @category Function
+ * @param {Object} object The object to bind and assign the bound methods to.
+ * @param {...(string|string[])} [methodNames] The object method names to bind,
+ * specified as individual method names or arrays of method names.
+ * @returns {Object} Returns `object`.
+ * @example
+ *
+ * var view = {
+ * 'label': 'docs',
+ * 'onClick': function() {
+ * console.log('clicked ' + this.label);
+ * }
+ * };
+ *
+ * _.bindAll(view);
+ * jQuery('#docs').on('click', view.onClick);
+ * // => logs 'clicked docs' when the element is clicked
+ */
+ var bindAll = restParam(function(object, methodNames) {
+ methodNames = methodNames.length ? baseFlatten(methodNames) : functions(object);
+
+ var index = -1,
+ length = methodNames.length;
+
+ while (++index < length) {
+ var key = methodNames[index];
+ object[key] = createWrapper(object[key], BIND_FLAG, object);
+ }
+ return object;
+ });
+
+ /**
+ * Creates a function that invokes the method at `object[key]` and prepends
+ * any additional `_.bindKey` arguments to those provided to the bound function.
+ *
+ * This method differs from `_.bind` by allowing bound functions to reference
+ * methods that may be redefined or don't yet exist.
+ * See [Peter Michaux's article](http://peter.michaux.ca/articles/lazy-function-definition-pattern)
+ * for more details.
+ *
+ * The `_.bindKey.placeholder` value, which defaults to `_` in monolithic
+ * builds, may be used as a placeholder for partially applied arguments.
+ *
+ * @static
+ * @memberOf _
+ * @category Function
+ * @param {Object} object The object the method belongs to.
+ * @param {string} key The key of the method.
+ * @param {...*} [partials] The arguments to be partially applied.
+ * @returns {Function} Returns the new bound function.
+ * @example
+ *
+ * var object = {
+ * 'user': 'fred',
+ * 'greet': function(greeting, punctuation) {
+ * return greeting + ' ' + this.user + punctuation;
+ * }
+ * };
+ *
+ * var bound = _.bindKey(object, 'greet', 'hi');
+ * bound('!');
+ * // => 'hi fred!'
+ *
+ * object.greet = function(greeting, punctuation) {
+ * return greeting + 'ya ' + this.user + punctuation;
+ * };
+ *
+ * bound('!');
+ * // => 'hiya fred!'
+ *
+ * // using placeholders
+ * var bound = _.bindKey(object, 'greet', _, '!');
+ * bound('hi');
+ * // => 'hiya fred!'
+ */
+ var bindKey = restParam(function(object, key, partials) {
+ var bitmask = BIND_FLAG | BIND_KEY_FLAG;
+ if (partials.length) {
+ var holders = replaceHolders(partials, bindKey.placeholder);
+ bitmask |= PARTIAL_FLAG;
+ }
+ return createWrapper(key, bitmask, object, partials, holders);
+ });
+
+ /**
+ * Creates a function that accepts one or more arguments of `func` that when
+ * called either invokes `func` returning its result, if all `func` arguments
+ * have been provided, or returns a function that accepts one or more of the
+ * remaining `func` arguments, and so on. The arity of `func` may be specified
+ * if `func.length` is not sufficient.
+ *
+ * The `_.curry.placeholder` value, which defaults to `_` in monolithic builds,
+ * may be used as a placeholder for provided arguments.
+ *
+ * **Note:** This method does not set the "length" property of curried functions.
+ *
+ * @static
+ * @memberOf _
+ * @category Function
+ * @param {Function} func The function to curry.
+ * @param {number} [arity=func.length] The arity of `func`.
+ * @param- {Object} [guard] Enables use as a callback for functions like `_.map`.
+ * @returns {Function} Returns the new curried function.
+ * @example
+ *
+ * var abc = function(a, b, c) {
+ * return [a, b, c];
+ * };
+ *
+ * var curried = _.curry(abc);
+ *
+ * curried(1)(2)(3);
+ * // => [1, 2, 3]
+ *
+ * curried(1, 2)(3);
+ * // => [1, 2, 3]
+ *
+ * curried(1, 2, 3);
+ * // => [1, 2, 3]
+ *
+ * // using placeholders
+ * curried(1)(_, 3)(2);
+ * // => [1, 2, 3]
+ */
+ var curry = createCurry(CURRY_FLAG);
+
+ /**
+ * This method is like `_.curry` except that arguments are applied to `func`
+ * in the manner of `_.partialRight` instead of `_.partial`.
+ *
+ * The `_.curryRight.placeholder` value, which defaults to `_` in monolithic
+ * builds, may be used as a placeholder for provided arguments.
+ *
+ * **Note:** This method does not set the "length" property of curried functions.
+ *
+ * @static
+ * @memberOf _
+ * @category Function
+ * @param {Function} func The function to curry.
+ * @param {number} [arity=func.length] The arity of `func`.
+ * @param- {Object} [guard] Enables use as a callback for functions like `_.map`.
+ * @returns {Function} Returns the new curried function.
+ * @example
+ *
+ * var abc = function(a, b, c) {
+ * return [a, b, c];
+ * };
+ *
+ * var curried = _.curryRight(abc);
+ *
+ * curried(3)(2)(1);
+ * // => [1, 2, 3]
+ *
+ * curried(2, 3)(1);
+ * // => [1, 2, 3]
+ *
+ * curried(1, 2, 3);
+ * // => [1, 2, 3]
+ *
+ * // using placeholders
+ * curried(3)(1, _)(2);
+ * // => [1, 2, 3]
+ */
+ var curryRight = createCurry(CURRY_RIGHT_FLAG);
+
+ /**
+ * Creates a debounced function that delays invoking `func` until after `wait`
+ * milliseconds have elapsed since the last time the debounced function was
+ * invoked. The debounced function comes with a `cancel` method to cancel
+ * delayed invocations. Provide an options object to indicate that `func`
+ * should be invoked on the leading and/or trailing edge of the `wait` timeout.
+ * Subsequent calls to the debounced function return the result of the last
+ * `func` invocation.
+ *
+ * **Note:** If `leading` and `trailing` options are `true`, `func` is invoked
+ * on the trailing edge of the timeout only if the the debounced function is
+ * invoked more than once during the `wait` timeout.
+ *
+ * See [David Corbacho's article](http://drupalmotion.com/article/debounce-and-throttle-visual-explanation)
+ * for details over the differences between `_.debounce` and `_.throttle`.
+ *
+ * @static
+ * @memberOf _
+ * @category Function
+ * @param {Function} func The function to debounce.
+ * @param {number} [wait=0] The number of milliseconds to delay.
+ * @param {Object} [options] The options object.
+ * @param {boolean} [options.leading=false] Specify invoking on the leading
+ * edge of the timeout.
+ * @param {number} [options.maxWait] The maximum time `func` is allowed to be
+ * delayed before it is invoked.
+ * @param {boolean} [options.trailing=true] Specify invoking on the trailing
+ * edge of the timeout.
+ * @returns {Function} Returns the new debounced function.
+ * @example
+ *
+ * // avoid costly calculations while the window size is in flux
+ * jQuery(window).on('resize', _.debounce(calculateLayout, 150));
+ *
+ * // invoke `sendMail` when the click event is fired, debouncing subsequent calls
+ * jQuery('#postbox').on('click', _.debounce(sendMail, 300, {
+ * 'leading': true,
+ * 'trailing': false
+ * }));
+ *
+ * // ensure `batchLog` is invoked once after 1 second of debounced calls
+ * var source = new EventSource('/stream');
+ * jQuery(source).on('message', _.debounce(batchLog, 250, {
+ * 'maxWait': 1000
+ * }));
+ *
+ * // cancel a debounced call
+ * var todoChanges = _.debounce(batchLog, 1000);
+ * Object.observe(models.todo, todoChanges);
+ *
+ * Object.observe(models, function(changes) {
+ * if (_.find(changes, { 'user': 'todo', 'type': 'delete'})) {
+ * todoChanges.cancel();
+ * }
+ * }, ['delete']);
+ *
+ * // ...at some point `models.todo` is changed
+ * models.todo.completed = true;
+ *
+ * // ...before 1 second has passed `models.todo` is deleted
+ * // which cancels the debounced `todoChanges` call
+ * delete models.todo;
+ */
+ function debounce(func, wait, options) {
+ var args,
+ maxTimeoutId,
+ result,
+ stamp,
+ thisArg,
+ timeoutId,
+ trailingCall,
+ lastCalled = 0,
+ maxWait = false,
+ trailing = true;
+
+ if (typeof func != 'function') {
+ throw new TypeError(FUNC_ERROR_TEXT);
+ }
+ wait = wait < 0 ? 0 : (+wait || 0);
+ if (options === true) {
+ var leading = true;
+ trailing = false;
+ } else if (isObject(options)) {
+ leading = !!options.leading;
+ maxWait = 'maxWait' in options && nativeMax(+options.maxWait || 0, wait);
+ trailing = 'trailing' in options ? !!options.trailing : trailing;
+ }
+
+ function cancel() {
+ if (timeoutId) {
+ clearTimeout(timeoutId);
+ }
+ if (maxTimeoutId) {
+ clearTimeout(maxTimeoutId);
+ }
+ lastCalled = 0;
+ maxTimeoutId = timeoutId = trailingCall = undefined;
+ }
+
+ function complete(isCalled, id) {
+ if (id) {
+ clearTimeout(id);
+ }
+ maxTimeoutId = timeoutId = trailingCall = undefined;
+ if (isCalled) {
+ lastCalled = now();
+ result = func.apply(thisArg, args);
+ if (!timeoutId && !maxTimeoutId) {
+ args = thisArg = undefined;
+ }
+ }
+ }
+
+ function delayed() {
+ var remaining = wait - (now() - stamp);
+ if (remaining <= 0 || remaining > wait) {
+ complete(trailingCall, maxTimeoutId);
+ } else {
+ timeoutId = setTimeout(delayed, remaining);
+ }
+ }
+
+ function maxDelayed() {
+ complete(trailing, timeoutId);
+ }
+
+ function debounced() {
+ args = arguments;
+ stamp = now();
+ thisArg = this;
+ trailingCall = trailing && (timeoutId || !leading);
+
+ if (maxWait === false) {
+ var leadingCall = leading && !timeoutId;
+ } else {
+ if (!maxTimeoutId && !leading) {
+ lastCalled = stamp;
+ }
+ var remaining = maxWait - (stamp - lastCalled),
+ isCalled = remaining <= 0 || remaining > maxWait;
+
+ if (isCalled) {
+ if (maxTimeoutId) {
+ maxTimeoutId = clearTimeout(maxTimeoutId);
+ }
+ lastCalled = stamp;
+ result = func.apply(thisArg, args);
+ }
+ else if (!maxTimeoutId) {
+ maxTimeoutId = setTimeout(maxDelayed, remaining);
+ }
+ }
+ if (isCalled && timeoutId) {
+ timeoutId = clearTimeout(timeoutId);
+ }
+ else if (!timeoutId && wait !== maxWait) {
+ timeoutId = setTimeout(delayed, wait);
+ }
+ if (leadingCall) {
+ isCalled = true;
+ result = func.apply(thisArg, args);
+ }
+ if (isCalled && !timeoutId && !maxTimeoutId) {
+ args = thisArg = undefined;
+ }
+ return result;
+ }
+ debounced.cancel = cancel;
+ return debounced;
+ }
+
+ /**
+ * Defers invoking the `func` until the current call stack has cleared. Any
+ * additional arguments are provided to `func` when it is invoked.
+ *
+ * @static
+ * @memberOf _
+ * @category Function
+ * @param {Function} func The function to defer.
+ * @param {...*} [args] The arguments to invoke the function with.
+ * @returns {number} Returns the timer id.
+ * @example
+ *
+ * _.defer(function(text) {
+ * console.log(text);
+ * }, 'deferred');
+ * // logs 'deferred' after one or more milliseconds
+ */
+ var defer = restParam(function(func, args) {
+ return baseDelay(func, 1, args);
+ });
+
+ /**
+ * Invokes `func` after `wait` milliseconds. Any additional arguments are
+ * provided to `func` when it is invoked.
+ *
+ * @static
+ * @memberOf _
+ * @category Function
+ * @param {Function} func The function to delay.
+ * @param {number} wait The number of milliseconds to delay invocation.
+ * @param {...*} [args] The arguments to invoke the function with.
+ * @returns {number} Returns the timer id.
+ * @example
+ *
+ * _.delay(function(text) {
+ * console.log(text);
+ * }, 1000, 'later');
+ * // => logs 'later' after one second
+ */
+ var delay = restParam(function(func, wait, args) {
+ return baseDelay(func, wait, args);
+ });
+
+ /**
+ * Creates a function that returns the result of invoking the provided
+ * functions with the `this` binding of the created function, where each
+ * successive invocation is supplied the return value of the previous.
+ *
+ * @static
+ * @memberOf _
+ * @category Function
+ * @param {...Function} [funcs] Functions to invoke.
+ * @returns {Function} Returns the new function.
+ * @example
+ *
+ * function square(n) {
+ * return n * n;
+ * }
+ *
+ * var addSquare = _.flow(_.add, square);
+ * addSquare(1, 2);
+ * // => 9
+ */
+ var flow = createFlow();
+
+ /**
+ * This method is like `_.flow` except that it creates a function that
+ * invokes the provided functions from right to left.
+ *
+ * @static
+ * @memberOf _
+ * @alias backflow, compose
+ * @category Function
+ * @param {...Function} [funcs] Functions to invoke.
+ * @returns {Function} Returns the new function.
+ * @example
+ *
+ * function square(n) {
+ * return n * n;
+ * }
+ *
+ * var addSquare = _.flowRight(square, _.add);
+ * addSquare(1, 2);
+ * // => 9
+ */
+ var flowRight = createFlow(true);
+
+ /**
+ * Creates a function that memoizes the result of `func`. If `resolver` is
+ * provided it determines the cache key for storing the result based on the
+ * arguments provided to the memoized function. By default, the first argument
+ * provided to the memoized function is coerced to a string and used as the
+ * cache key. The `func` is invoked with the `this` binding of the memoized
+ * function.
+ *
+ * **Note:** The cache is exposed as the `cache` property on the memoized
+ * function. Its creation may be customized by replacing the `_.memoize.Cache`
+ * constructor with one whose instances implement the [`Map`](http://ecma-international.org/ecma-262/6.0/#sec-properties-of-the-map-prototype-object)
+ * method interface of `get`, `has`, and `set`.
+ *
+ * @static
+ * @memberOf _
+ * @category Function
+ * @param {Function} func The function to have its output memoized.
+ * @param {Function} [resolver] The function to resolve the cache key.
+ * @returns {Function} Returns the new memoizing function.
+ * @example
+ *
+ * var upperCase = _.memoize(function(string) {
+ * return string.toUpperCase();
+ * });
+ *
+ * upperCase('fred');
+ * // => 'FRED'
+ *
+ * // modifying the result cache
+ * upperCase.cache.set('fred', 'BARNEY');
+ * upperCase('fred');
+ * // => 'BARNEY'
+ *
+ * // replacing `_.memoize.Cache`
+ * var object = { 'user': 'fred' };
+ * var other = { 'user': 'barney' };
+ * var identity = _.memoize(_.identity);
+ *
+ * identity(object);
+ * // => { 'user': 'fred' }
+ * identity(other);
+ * // => { 'user': 'fred' }
+ *
+ * _.memoize.Cache = WeakMap;
+ * var identity = _.memoize(_.identity);
+ *
+ * identity(object);
+ * // => { 'user': 'fred' }
+ * identity(other);
+ * // => { 'user': 'barney' }
+ */
+ function memoize(func, resolver) {
+ if (typeof func != 'function' || (resolver && typeof resolver != 'function')) {
+ throw new TypeError(FUNC_ERROR_TEXT);
+ }
+ var memoized = function() {
+ var args = arguments,
+ key = resolver ? resolver.apply(this, args) : args[0],
+ cache = memoized.cache;
+
+ if (cache.has(key)) {
+ return cache.get(key);
+ }
+ var result = func.apply(this, args);
+ memoized.cache = cache.set(key, result);
+ return result;
+ };
+ memoized.cache = new memoize.Cache;
+ return memoized;
+ }
+
+ /**
+ * Creates a function that runs each argument through a corresponding
+ * transform function.
+ *
+ * @static
+ * @memberOf _
+ * @category Function
+ * @param {Function} func The function to wrap.
+ * @param {...(Function|Function[])} [transforms] The functions to transform
+ * arguments, specified as individual functions or arrays of functions.
+ * @returns {Function} Returns the new function.
+ * @example
+ *
+ * function doubled(n) {
+ * return n * 2;
+ * }
+ *
+ * function square(n) {
+ * return n * n;
+ * }
+ *
+ * var modded = _.modArgs(function(x, y) {
+ * return [x, y];
+ * }, square, doubled);
+ *
+ * modded(1, 2);
+ * // => [1, 4]
+ *
+ * modded(5, 10);
+ * // => [25, 20]
+ */
+ var modArgs = restParam(function(func, transforms) {
+ transforms = baseFlatten(transforms);
+ if (typeof func != 'function' || !arrayEvery(transforms, baseIsFunction)) {
+ throw new TypeError(FUNC_ERROR_TEXT);
+ }
+ var length = transforms.length;
+ return restParam(function(args) {
+ var index = nativeMin(args.length, length);
+ while (index--) {
+ args[index] = transforms[index](args[index]);
+ }
+ return func.apply(this, args);
+ });
+ });
+
+ /**
+ * Creates a function that negates the result of the predicate `func`. The
+ * `func` predicate is invoked with the `this` binding and arguments of the
+ * created function.
+ *
+ * @static
+ * @memberOf _
+ * @category Function
+ * @param {Function} predicate The predicate to negate.
+ * @returns {Function} Returns the new function.
+ * @example
+ *
+ * function isEven(n) {
+ * return n % 2 == 0;
+ * }
+ *
+ * _.filter([1, 2, 3, 4, 5, 6], _.negate(isEven));
+ * // => [1, 3, 5]
+ */
+ function negate(predicate) {
+ if (typeof predicate != 'function') {
+ throw new TypeError(FUNC_ERROR_TEXT);
+ }
+ return function() {
+ return !predicate.apply(this, arguments);
+ };
+ }
+
+ /**
+ * Creates a function that is restricted to invoking `func` once. Repeat calls
+ * to the function return the value of the first call. The `func` is invoked
+ * with the `this` binding and arguments of the created function.
+ *
+ * @static
+ * @memberOf _
+ * @category Function
+ * @param {Function} func The function to restrict.
+ * @returns {Function} Returns the new restricted function.
+ * @example
+ *
+ * var initialize = _.once(createApplication);
+ * initialize();
+ * initialize();
+ * // `initialize` invokes `createApplication` once
+ */
+ function once(func) {
+ return before(2, func);
+ }
+
+ /**
+ * Creates a function that invokes `func` with `partial` arguments prepended
+ * to those provided to the new function. This method is like `_.bind` except
+ * it does **not** alter the `this` binding.
+ *
+ * The `_.partial.placeholder` value, which defaults to `_` in monolithic
+ * builds, may be used as a placeholder for partially applied arguments.
+ *
+ * **Note:** This method does not set the "length" property of partially
+ * applied functions.
+ *
+ * @static
+ * @memberOf _
+ * @category Function
+ * @param {Function} func The function to partially apply arguments to.
+ * @param {...*} [partials] The arguments to be partially applied.
+ * @returns {Function} Returns the new partially applied function.
+ * @example
+ *
+ * var greet = function(greeting, name) {
+ * return greeting + ' ' + name;
+ * };
+ *
+ * var sayHelloTo = _.partial(greet, 'hello');
+ * sayHelloTo('fred');
+ * // => 'hello fred'
+ *
+ * // using placeholders
+ * var greetFred = _.partial(greet, _, 'fred');
+ * greetFred('hi');
+ * // => 'hi fred'
+ */
+ var partial = createPartial(PARTIAL_FLAG);
+
+ /**
+ * This method is like `_.partial` except that partially applied arguments
+ * are appended to those provided to the new function.
+ *
+ * The `_.partialRight.placeholder` value, which defaults to `_` in monolithic
+ * builds, may be used as a placeholder for partially applied arguments.
+ *
+ * **Note:** This method does not set the "length" property of partially
+ * applied functions.
+ *
+ * @static
+ * @memberOf _
+ * @category Function
+ * @param {Function} func The function to partially apply arguments to.
+ * @param {...*} [partials] The arguments to be partially applied.
+ * @returns {Function} Returns the new partially applied function.
+ * @example
+ *
+ * var greet = function(greeting, name) {
+ * return greeting + ' ' + name;
+ * };
+ *
+ * var greetFred = _.partialRight(greet, 'fred');
+ * greetFred('hi');
+ * // => 'hi fred'
+ *
+ * // using placeholders
+ * var sayHelloTo = _.partialRight(greet, 'hello', _);
+ * sayHelloTo('fred');
+ * // => 'hello fred'
+ */
+ var partialRight = createPartial(PARTIAL_RIGHT_FLAG);
+
+ /**
+ * Creates a function that invokes `func` with arguments arranged according
+ * to the specified indexes where the argument value at the first index is
+ * provided as the first argument, the argument value at the second index is
+ * provided as the second argument, and so on.
+ *
+ * @static
+ * @memberOf _
+ * @category Function
+ * @param {Function} func The function to rearrange arguments for.
+ * @param {...(number|number[])} indexes The arranged argument indexes,
+ * specified as individual indexes or arrays of indexes.
+ * @returns {Function} Returns the new function.
+ * @example
+ *
+ * var rearged = _.rearg(function(a, b, c) {
+ * return [a, b, c];
+ * }, 2, 0, 1);
+ *
+ * rearged('b', 'c', 'a')
+ * // => ['a', 'b', 'c']
+ *
+ * var map = _.rearg(_.map, [1, 0]);
+ * map(function(n) {
+ * return n * 3;
+ * }, [1, 2, 3]);
+ * // => [3, 6, 9]
+ */
+ var rearg = restParam(function(func, indexes) {
+ return createWrapper(func, REARG_FLAG, undefined, undefined, undefined, baseFlatten(indexes));
+ });
+
+ /**
+ * Creates a function that invokes `func` with the `this` binding of the
+ * created function and arguments from `start` and beyond provided as an array.
+ *
+ * **Note:** This method is based on the [rest parameter](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/rest_parameters).
+ *
+ * @static
+ * @memberOf _
+ * @category Function
+ * @param {Function} func The function to apply a rest parameter to.
+ * @param {number} [start=func.length-1] The start position of the rest parameter.
+ * @returns {Function} Returns the new function.
+ * @example
+ *
+ * var say = _.restParam(function(what, names) {
+ * return what + ' ' + _.initial(names).join(', ') +
+ * (_.size(names) > 1 ? ', & ' : '') + _.last(names);
+ * });
+ *
+ * say('hello', 'fred', 'barney', 'pebbles');
+ * // => 'hello fred, barney, & pebbles'
+ */
+ function restParam(func, start) {
+ if (typeof func != 'function') {
+ throw new TypeError(FUNC_ERROR_TEXT);
+ }
+ start = nativeMax(start === undefined ? (func.length - 1) : (+start || 0), 0);
+ return function() {
+ var args = arguments,
+ index = -1,
+ length = nativeMax(args.length - start, 0),
+ rest = Array(length);
+
+ while (++index < length) {
+ rest[index] = args[start + index];
+ }
+ switch (start) {
+ case 0: return func.call(this, rest);
+ case 1: return func.call(this, args[0], rest);
+ case 2: return func.call(this, args[0], args[1], rest);
+ }
+ var otherArgs = Array(start + 1);
+ index = -1;
+ while (++index < start) {
+ otherArgs[index] = args[index];
+ }
+ otherArgs[start] = rest;
+ return func.apply(this, otherArgs);
+ };
+ }
+
+ /**
+ * Creates a function that invokes `func` with the `this` binding of the created
+ * function and an array of arguments much like [`Function#apply`](https://es5.github.io/#x15.3.4.3).
+ *
+ * **Note:** This method is based on the [spread operator](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Spread_operator).
+ *
+ * @static
+ * @memberOf _
+ * @category Function
+ * @param {Function} func The function to spread arguments over.
+ * @returns {Function} Returns the new function.
+ * @example
+ *
+ * var say = _.spread(function(who, what) {
+ * return who + ' says ' + what;
+ * });
+ *
+ * say(['fred', 'hello']);
+ * // => 'fred says hello'
+ *
+ * // with a Promise
+ * var numbers = Promise.all([
+ * Promise.resolve(40),
+ * Promise.resolve(36)
+ * ]);
+ *
+ * numbers.then(_.spread(function(x, y) {
+ * return x + y;
+ * }));
+ * // => a Promise of 76
+ */
+ function spread(func) {
+ if (typeof func != 'function') {
+ throw new TypeError(FUNC_ERROR_TEXT);
+ }
+ return function(array) {
+ return func.apply(this, array);
+ };
+ }
+
+ /**
+ * Creates a throttled function that only invokes `func` at most once per
+ * every `wait` milliseconds. The throttled function comes with a `cancel`
+ * method to cancel delayed invocations. Provide an options object to indicate
+ * that `func` should be invoked on the leading and/or trailing edge of the
+ * `wait` timeout. Subsequent calls to the throttled function return the
+ * result of the last `func` call.
+ *
+ * **Note:** If `leading` and `trailing` options are `true`, `func` is invoked
+ * on the trailing edge of the timeout only if the the throttled function is
+ * invoked more than once during the `wait` timeout.
+ *
+ * See [David Corbacho's article](http://drupalmotion.com/article/debounce-and-throttle-visual-explanation)
+ * for details over the differences between `_.throttle` and `_.debounce`.
+ *
+ * @static
+ * @memberOf _
+ * @category Function
+ * @param {Function} func The function to throttle.
+ * @param {number} [wait=0] The number of milliseconds to throttle invocations to.
+ * @param {Object} [options] The options object.
+ * @param {boolean} [options.leading=true] Specify invoking on the leading
+ * edge of the timeout.
+ * @param {boolean} [options.trailing=true] Specify invoking on the trailing
+ * edge of the timeout.
+ * @returns {Function} Returns the new throttled function.
+ * @example
+ *
+ * // avoid excessively updating the position while scrolling
+ * jQuery(window).on('scroll', _.throttle(updatePosition, 100));
+ *
+ * // invoke `renewToken` when the click event is fired, but not more than once every 5 minutes
+ * jQuery('.interactive').on('click', _.throttle(renewToken, 300000, {
+ * 'trailing': false
+ * }));
+ *
+ * // cancel a trailing throttled call
+ * jQuery(window).on('popstate', throttled.cancel);
+ */
+ function throttle(func, wait, options) {
+ var leading = true,
+ trailing = true;
+
+ if (typeof func != 'function') {
+ throw new TypeError(FUNC_ERROR_TEXT);
+ }
+ if (options === false) {
+ leading = false;
+ } else if (isObject(options)) {
+ leading = 'leading' in options ? !!options.leading : leading;
+ trailing = 'trailing' in options ? !!options.trailing : trailing;
+ }
+ return debounce(func, wait, { 'leading': leading, 'maxWait': +wait, 'trailing': trailing });
+ }
+
+ /**
+ * Creates a function that provides `value` to the wrapper function as its
+ * first argument. Any additional arguments provided to the function are
+ * appended to those provided to the wrapper function. The wrapper is invoked
+ * with the `this` binding of the created function.
+ *
+ * @static
+ * @memberOf _
+ * @category Function
+ * @param {*} value The value to wrap.
+ * @param {Function} wrapper The wrapper function.
+ * @returns {Function} Returns the new function.
+ * @example
+ *
+ * var p = _.wrap(_.escape, function(func, text) {
+ * return '<p>' + func(text) + '</p>';
+ * });
+ *
+ * p('fred, barney, & pebbles');
+ * // => '<p>fred, barney, &amp; pebbles</p>'
+ */
+ function wrap(value, wrapper) {
+ wrapper = wrapper == null ? identity : wrapper;
+ return createWrapper(wrapper, PARTIAL_FLAG, undefined, [value], []);
+ }
+
+ /*------------------------------------------------------------------------*/
+
+ /**
+ * Creates a clone of `value`. If `isDeep` is `true` nested objects are cloned,
+ * otherwise they are assigned by reference. If `customizer` is provided it is
+ * invoked to produce the cloned values. If `customizer` returns `undefined`
+ * cloning is handled by the method instead. The `customizer` is bound to
+ * `thisArg` and invoked with two argument; (value [, index|key, object]).
+ *
+ * **Note:** This method is loosely based on the
+ * [structured clone algorithm](http://www.w3.org/TR/html5/infrastructure.html#internal-structured-cloning-algorithm).
+ * The enumerable properties of `arguments` objects and objects created by
+ * constructors other than `Object` are cloned to plain `Object` objects. An
+ * empty object is returned for uncloneable values such as functions, DOM nodes,
+ * Maps, Sets, and WeakMaps.
+ *
+ * @static
+ * @memberOf _
+ * @category Lang
+ * @param {*} value The value to clone.
+ * @param {boolean} [isDeep] Specify a deep clone.
+ * @param {Function} [customizer] The function to customize cloning values.
+ * @param {*} [thisArg] The `this` binding of `customizer`.
+ * @returns {*} Returns the cloned value.
+ * @example
+ *
+ * var users = [
+ * { 'user': 'barney' },
+ * { 'user': 'fred' }
+ * ];
+ *
+ * var shallow = _.clone(users);
+ * shallow[0] === users[0];
+ * // => true
+ *
+ * var deep = _.clone(users, true);
+ * deep[0] === users[0];
+ * // => false
+ *
+ * // using a customizer callback
+ * var el = _.clone(document.body, function(value) {
+ * if (_.isElement(value)) {
+ * return value.cloneNode(false);
+ * }
+ * });
+ *
+ * el === document.body
+ * // => false
+ * el.nodeName
+ * // => BODY
+ * el.childNodes.length;
+ * // => 0
+ */
+ function clone(value, isDeep, customizer, thisArg) {
+ if (isDeep && typeof isDeep != 'boolean' && isIterateeCall(value, isDeep, customizer)) {
+ isDeep = false;
+ }
+ else if (typeof isDeep == 'function') {
+ thisArg = customizer;
+ customizer = isDeep;
+ isDeep = false;
+ }
+ return typeof customizer == 'function'
+ ? baseClone(value, isDeep, bindCallback(customizer, thisArg, 1))
+ : baseClone(value, isDeep);
+ }
+
+ /**
+ * Creates a deep clone of `value`. If `customizer` is provided it is invoked
+ * to produce the cloned values. If `customizer` returns `undefined` cloning
+ * is handled by the method instead. The `customizer` is bound to `thisArg`
+ * and invoked with two argument; (value [, index|key, object]).
+ *
+ * **Note:** This method is loosely based on the
+ * [structured clone algorithm](http://www.w3.org/TR/html5/infrastructure.html#internal-structured-cloning-algorithm).
+ * The enumerable properties of `arguments` objects and objects created by
+ * constructors other than `Object` are cloned to plain `Object` objects. An
+ * empty object is returned for uncloneable values such as functions, DOM nodes,
+ * Maps, Sets, and WeakMaps.
+ *
+ * @static
+ * @memberOf _
+ * @category Lang
+ * @param {*} value The value to deep clone.
+ * @param {Function} [customizer] The function to customize cloning values.
+ * @param {*} [thisArg] The `this` binding of `customizer`.
+ * @returns {*} Returns the deep cloned value.
+ * @example
+ *
+ * var users = [
+ * { 'user': 'barney' },
+ * { 'user': 'fred' }
+ * ];
+ *
+ * var deep = _.cloneDeep(users);
+ * deep[0] === users[0];
+ * // => false
+ *
+ * // using a customizer callback
+ * var el = _.cloneDeep(document.body, function(value) {
+ * if (_.isElement(value)) {
+ * return value.cloneNode(true);
+ * }
+ * });
+ *
+ * el === document.body
+ * // => false
+ * el.nodeName
+ * // => BODY
+ * el.childNodes.length;
+ * // => 20
+ */
+ function cloneDeep(value, customizer, thisArg) {
+ return typeof customizer == 'function'
+ ? baseClone(value, true, bindCallback(customizer, thisArg, 1))
+ : baseClone(value, true);
+ }
+
+ /**
+ * Checks if `value` is greater than `other`.
+ *
+ * @static
+ * @memberOf _
+ * @category Lang
+ * @param {*} value The value to compare.
+ * @param {*} other The other value to compare.
+ * @returns {boolean} Returns `true` if `value` is greater than `other`, else `false`.
+ * @example
+ *
+ * _.gt(3, 1);
+ * // => true
+ *
+ * _.gt(3, 3);
+ * // => false
+ *
+ * _.gt(1, 3);
+ * // => false
+ */
+ function gt(value, other) {
+ return value > other;
+ }
+
+ /**
+ * Checks if `value` is greater than or equal to `other`.
+ *
+ * @static
+ * @memberOf _
+ * @category Lang
+ * @param {*} value The value to compare.
+ * @param {*} other The other value to compare.
+ * @returns {boolean} Returns `true` if `value` is greater than or equal to `other`, else `false`.
+ * @example
+ *
+ * _.gte(3, 1);
+ * // => true
+ *
+ * _.gte(3, 3);
+ * // => true
+ *
+ * _.gte(1, 3);
+ * // => false
+ */
+ function gte(value, other) {
+ return value >= other;
+ }
+
+ /**
+ * Checks if `value` is classified as an `arguments` object.
+ *
+ * @static
+ * @memberOf _
+ * @category Lang
+ * @param {*} value The value to check.
+ * @returns {boolean} Returns `true` if `value` is correctly classified, else `false`.
+ * @example
+ *
+ * _.isArguments(function() { return arguments; }());
+ * // => true
+ *
+ * _.isArguments([1, 2, 3]);
+ * // => false
+ */
+ function isArguments(value) {
+ return isObjectLike(value) && isArrayLike(value) &&
+ hasOwnProperty.call(value, 'callee') && !propertyIsEnumerable.call(value, 'callee');
+ }
+
+ /**
+ * Checks if `value` is classified as an `Array` object.
+ *
+ * @static
+ * @memberOf _
+ * @category Lang
+ * @param {*} value The value to check.
+ * @returns {boolean} Returns `true` if `value` is correctly classified, else `false`.
+ * @example
+ *
+ * _.isArray([1, 2, 3]);
+ * // => true
+ *
+ * _.isArray(function() { return arguments; }());
+ * // => false
+ */
+ var isArray = nativeIsArray || function(value) {
+ return isObjectLike(value) && isLength(value.length) && objToString.call(value) == arrayTag;
+ };
+
+ /**
+ * Checks if `value` is classified as a boolean primitive or object.
+ *
+ * @static
+ * @memberOf _
+ * @category Lang
+ * @param {*} value The value to check.
+ * @returns {boolean} Returns `true` if `value` is correctly classified, else `false`.
+ * @example
+ *
+ * _.isBoolean(false);
+ * // => true
+ *
+ * _.isBoolean(null);
+ * // => false
+ */
+ function isBoolean(value) {
+ return value === true || value === false || (isObjectLike(value) && objToString.call(value) == boolTag);
+ }
+
+ /**
+ * Checks if `value` is classified as a `Date` object.
+ *
+ * @static
+ * @memberOf _
+ * @category Lang
+ * @param {*} value The value to check.
+ * @returns {boolean} Returns `true` if `value` is correctly classified, else `false`.
+ * @example
+ *
+ * _.isDate(new Date);
+ * // => true
+ *
+ * _.isDate('Mon April 23 2012');
+ * // => false
+ */
+ function isDate(value) {
+ return isObjectLike(value) && objToString.call(value) == dateTag;
+ }
+
+ /**
+ * Checks if `value` is a DOM element.
+ *
+ * @static
+ * @memberOf _
+ * @category Lang
+ * @param {*} value The value to check.
+ * @returns {boolean} Returns `true` if `value` is a DOM element, else `false`.
+ * @example
+ *
+ * _.isElement(document.body);
+ * // => true
+ *
+ * _.isElement('<body>');
+ * // => false
+ */
+ function isElement(value) {
+ return !!value && value.nodeType === 1 && isObjectLike(value) && !isPlainObject(value);
+ }
+
+ /**
+ * Checks if `value` is empty. A value is considered empty unless it is an
+ * `arguments` object, array, string, or jQuery-like collection with a length
+ * greater than `0` or an object with own enumerable properties.
+ *
+ * @static
+ * @memberOf _
+ * @category Lang
+ * @param {Array|Object|string} value The value to inspect.
+ * @returns {boolean} Returns `true` if `value` is empty, else `false`.
+ * @example
+ *
+ * _.isEmpty(null);
+ * // => true
+ *
+ * _.isEmpty(true);
+ * // => true
+ *
+ * _.isEmpty(1);
+ * // => true
+ *
+ * _.isEmpty([1, 2, 3]);
+ * // => false
+ *
+ * _.isEmpty({ 'a': 1 });
+ * // => false
+ */
+ function isEmpty(value) {
+ if (value == null) {
+ return true;
+ }
+ if (isArrayLike(value) && (isArray(value) || isString(value) || isArguments(value) ||
+ (isObjectLike(value) && isFunction(value.splice)))) {
+ return !value.length;
+ }
+ return !keys(value).length;
+ }
+
+ /**
+ * Performs a deep comparison between two values to determine if they are
+ * equivalent. If `customizer` is provided it is invoked to compare values.
+ * If `customizer` returns `undefined` comparisons are handled by the method
+ * instead. The `customizer` is bound to `thisArg` and invoked with three
+ * arguments: (value, other [, index|key]).
+ *
+ * **Note:** This method supports comparing arrays, booleans, `Date` objects,
+ * numbers, `Object` objects, regexes, and strings. Objects are compared by
+ * their own, not inherited, enumerable properties. Functions and DOM nodes
+ * are **not** supported. Provide a customizer function to extend support
+ * for comparing other values.
+ *
+ * @static
+ * @memberOf _
+ * @alias eq
+ * @category Lang
+ * @param {*} value The value to compare.
+ * @param {*} other The other value to compare.
+ * @param {Function} [customizer] The function to customize value comparisons.
+ * @param {*} [thisArg] The `this` binding of `customizer`.
+ * @returns {boolean} Returns `true` if the values are equivalent, else `false`.
+ * @example
+ *
+ * var object = { 'user': 'fred' };
+ * var other = { 'user': 'fred' };
+ *
+ * object == other;
+ * // => false
+ *
+ * _.isEqual(object, other);
+ * // => true
+ *
+ * // using a customizer callback
+ * var array = ['hello', 'goodbye'];
+ * var other = ['hi', 'goodbye'];
+ *
+ * _.isEqual(array, other, function(value, other) {
+ * if (_.every([value, other], RegExp.prototype.test, /^h(?:i|ello)$/)) {
+ * return true;
+ * }
+ * });
+ * // => true
+ */
+ function isEqual(value, other, customizer, thisArg) {
+ customizer = typeof customizer == 'function' ? bindCallback(customizer, thisArg, 3) : undefined;
+ var result = customizer ? customizer(value, other) : undefined;
+ return result === undefined ? baseIsEqual(value, other, customizer) : !!result;
+ }
+
+ /**
+ * Checks if `value` is an `Error`, `EvalError`, `RangeError`, `ReferenceError`,
+ * `SyntaxError`, `TypeError`, or `URIError` object.
+ *
+ * @static
+ * @memberOf _
+ * @category Lang
+ * @param {*} value The value to check.
+ * @returns {boolean} Returns `true` if `value` is an error object, else `false`.
+ * @example
+ *
+ * _.isError(new Error);
+ * // => true
+ *
+ * _.isError(Error);
+ * // => false
+ */
+ function isError(value) {
+ return isObjectLike(value) && typeof value.message == 'string' && objToString.call(value) == errorTag;
+ }
+
+ /**
+ * Checks if `value` is a finite primitive number.
+ *
+ * **Note:** This method is based on [`Number.isFinite`](http://ecma-international.org/ecma-262/6.0/#sec-number.isfinite).
+ *
+ * @static
+ * @memberOf _
+ * @category Lang
+ * @param {*} value The value to check.
+ * @returns {boolean} Returns `true` if `value` is a finite number, else `false`.
+ * @example
+ *
+ * _.isFinite(10);
+ * // => true
+ *
+ * _.isFinite('10');
+ * // => false
+ *
+ * _.isFinite(true);
+ * // => false
+ *
+ * _.isFinite(Object(10));
+ * // => false
+ *
+ * _.isFinite(Infinity);
+ * // => false
+ */
+ function isFinite(value) {
+ return typeof value == 'number' && nativeIsFinite(value);
+ }
+
+ /**
+ * Checks if `value` is classified as a `Function` object.
+ *
+ * @static
+ * @memberOf _
+ * @category Lang
+ * @param {*} value The value to check.
+ * @returns {boolean} Returns `true` if `value` is correctly classified, else `false`.
+ * @example
+ *
+ * _.isFunction(_);
+ * // => true
+ *
+ * _.isFunction(/abc/);
+ * // => false
+ */
+ function isFunction(value) {
+ // The use of `Object#toString` avoids issues with the `typeof` operator
+ // in older versions of Chrome and Safari which return 'function' for regexes
+ // and Safari 8 equivalents which return 'object' for typed array constructors.
+ return isObject(value) && objToString.call(value) == funcTag;
+ }
+
+ /**
+ * Checks if `value` is the [language type](https://es5.github.io/#x8) of `Object`.
+ * (e.g. arrays, functions, objects, regexes, `new Number(0)`, and `new String('')`)
+ *
+ * @static
+ * @memberOf _
+ * @category Lang
+ * @param {*} value The value to check.
+ * @returns {boolean} Returns `true` if `value` is an object, else `false`.
+ * @example
+ *
+ * _.isObject({});
+ * // => true
+ *
+ * _.isObject([1, 2, 3]);
+ * // => true
+ *
+ * _.isObject(1);
+ * // => false
+ */
+ function isObject(value) {
+ // Avoid a V8 JIT bug in Chrome 19-20.
+ // See https://code.google.com/p/v8/issues/detail?id=2291 for more details.
+ var type = typeof value;
+ return !!value && (type == 'object' || type == 'function');
+ }
+
+ /**
+ * Performs a deep comparison between `object` and `source` to determine if
+ * `object` contains equivalent property values. If `customizer` is provided
+ * it is invoked to compare values. If `customizer` returns `undefined`
+ * comparisons are handled by the method instead. The `customizer` is bound
+ * to `thisArg` and invoked with three arguments: (value, other, index|key).
+ *
+ * **Note:** This method supports comparing properties of arrays, booleans,
+ * `Date` objects, numbers, `Object` objects, regexes, and strings. Functions
+ * and DOM nodes are **not** supported. Provide a customizer function to extend
+ * support for comparing other values.
+ *
+ * @static
+ * @memberOf _
+ * @category Lang
+ * @param {Object} object The object to inspect.
+ * @param {Object} source The object of property values to match.
+ * @param {Function} [customizer] The function to customize value comparisons.
+ * @param {*} [thisArg] The `this` binding of `customizer`.
+ * @returns {boolean} Returns `true` if `object` is a match, else `false`.
+ * @example
+ *
+ * var object = { 'user': 'fred', 'age': 40 };
+ *
+ * _.isMatch(object, { 'age': 40 });
+ * // => true
+ *
+ * _.isMatch(object, { 'age': 36 });
+ * // => false
+ *
+ * // using a customizer callback
+ * var object = { 'greeting': 'hello' };
+ * var source = { 'greeting': 'hi' };
+ *
+ * _.isMatch(object, source, function(value, other) {
+ * return _.every([value, other], RegExp.prototype.test, /^h(?:i|ello)$/) || undefined;
+ * });
+ * // => true
+ */
+ function isMatch(object, source, customizer, thisArg) {
+ customizer = typeof customizer == 'function' ? bindCallback(customizer, thisArg, 3) : undefined;
+ return baseIsMatch(object, getMatchData(source), customizer);
+ }
+
+ /**
+ * Checks if `value` is `NaN`.
+ *
+ * **Note:** This method is not the same as [`isNaN`](https://es5.github.io/#x15.1.2.4)
+ * which returns `true` for `undefined` and other non-numeric values.
+ *
+ * @static
+ * @memberOf _
+ * @category Lang
+ * @param {*} value The value to check.
+ * @returns {boolean} Returns `true` if `value` is `NaN`, else `false`.
+ * @example
+ *
+ * _.isNaN(NaN);
+ * // => true
+ *
+ * _.isNaN(new Number(NaN));
+ * // => true
+ *
+ * isNaN(undefined);
+ * // => true
+ *
+ * _.isNaN(undefined);
+ * // => false
+ */
+ function isNaN(value) {
+ // An `NaN` primitive is the only value that is not equal to itself.
+ // Perform the `toStringTag` check first to avoid errors with some host objects in IE.
+ return isNumber(value) && value != +value;
+ }
+
+ /**
+ * Checks if `value` is a native function.
+ *
+ * @static
+ * @memberOf _
+ * @category Lang
+ * @param {*} value The value to check.
+ * @returns {boolean} Returns `true` if `value` is a native function, else `false`.
+ * @example
+ *
+ * _.isNative(Array.prototype.push);
+ * // => true
+ *
+ * _.isNative(_);
+ * // => false
+ */
+ function isNative(value) {
+ if (value == null) {
+ return false;
+ }
+ if (isFunction(value)) {
+ return reIsNative.test(fnToString.call(value));
+ }
+ return isObjectLike(value) && reIsHostCtor.test(value);
+ }
+
+ /**
+ * Checks if `value` is `null`.
+ *
+ * @static
+ * @memberOf _
+ * @category Lang
+ * @param {*} value The value to check.
+ * @returns {boolean} Returns `true` if `value` is `null`, else `false`.
+ * @example
+ *
+ * _.isNull(null);
+ * // => true
+ *
+ * _.isNull(void 0);
+ * // => false
+ */
+ function isNull(value) {
+ return value === null;
+ }
+
+ /**
+ * Checks if `value` is classified as a `Number` primitive or object.
+ *
+ * **Note:** To exclude `Infinity`, `-Infinity`, and `NaN`, which are classified
+ * as numbers, use the `_.isFinite` method.
+ *
+ * @static
+ * @memberOf _
+ * @category Lang
+ * @param {*} value The value to check.
+ * @returns {boolean} Returns `true` if `value` is correctly classified, else `false`.
+ * @example
+ *
+ * _.isNumber(8.4);
+ * // => true
+ *
+ * _.isNumber(NaN);
+ * // => true
+ *
+ * _.isNumber('8.4');
+ * // => false
+ */
+ function isNumber(value) {
+ return typeof value == 'number' || (isObjectLike(value) && objToString.call(value) == numberTag);
+ }
+
+ /**
+ * Checks if `value` is a plain object, that is, an object created by the
+ * `Object` constructor or one with a `[[Prototype]]` of `null`.
+ *
+ * **Note:** This method assumes objects created by the `Object` constructor
+ * have no inherited enumerable properties.
+ *
+ * @static
+ * @memberOf _
+ * @category Lang
+ * @param {*} value The value to check.
+ * @returns {boolean} Returns `true` if `value` is a plain object, else `false`.
+ * @example
+ *
+ * function Foo() {
+ * this.a = 1;
+ * }
+ *
+ * _.isPlainObject(new Foo);
+ * // => false
+ *
+ * _.isPlainObject([1, 2, 3]);
+ * // => false
+ *
+ * _.isPlainObject({ 'x': 0, 'y': 0 });
+ * // => true
+ *
+ * _.isPlainObject(Object.create(null));
+ * // => true
+ */
+ function isPlainObject(value) {
+ var Ctor;
+
+ // Exit early for non `Object` objects.
+ if (!(isObjectLike(value) && objToString.call(value) == objectTag && !isArguments(value)) ||
+ (!hasOwnProperty.call(value, 'constructor') && (Ctor = value.constructor, typeof Ctor == 'function' && !(Ctor instanceof Ctor)))) {
+ return false;
+ }
+ // IE < 9 iterates inherited properties before own properties. If the first
+ // iterated property is an object's own property then there are no inherited
+ // enumerable properties.
+ var result;
+ // In most environments an object's own properties are iterated before
+ // its inherited properties. If the last iterated property is an object's
+ // own property then there are no inherited enumerable properties.
+ baseForIn(value, function(subValue, key) {
+ result = key;
+ });
+ return result === undefined || hasOwnProperty.call(value, result);
+ }
+
+ /**
+ * Checks if `value` is classified as a `RegExp` object.
+ *
+ * @static
+ * @memberOf _
+ * @category Lang
+ * @param {*} value The value to check.
+ * @returns {boolean} Returns `true` if `value` is correctly classified, else `false`.
+ * @example
+ *
+ * _.isRegExp(/abc/);
+ * // => true
+ *
+ * _.isRegExp('/abc/');
+ * // => false
+ */
+ function isRegExp(value) {
+ return isObject(value) && objToString.call(value) == regexpTag;
+ }
+
+ /**
+ * Checks if `value` is classified as a `String` primitive or object.
+ *
+ * @static
+ * @memberOf _
+ * @category Lang
+ * @param {*} value The value to check.
+ * @returns {boolean} Returns `true` if `value` is correctly classified, else `false`.
+ * @example
+ *
+ * _.isString('abc');
+ * // => true
+ *
+ * _.isString(1);
+ * // => false
+ */
+ function isString(value) {
+ return typeof value == 'string' || (isObjectLike(value) && objToString.call(value) == stringTag);
+ }
+
+ /**
+ * Checks if `value` is classified as a typed array.
+ *
+ * @static
+ * @memberOf _
+ * @category Lang
+ * @param {*} value The value to check.
+ * @returns {boolean} Returns `true` if `value` is correctly classified, else `false`.
+ * @example
+ *
+ * _.isTypedArray(new Uint8Array);
+ * // => true
+ *
+ * _.isTypedArray([]);
+ * // => false
+ */
+ function isTypedArray(value) {
+ return isObjectLike(value) && isLength(value.length) && !!typedArrayTags[objToString.call(value)];
+ }
+
+ /**
+ * Checks if `value` is `undefined`.
+ *
+ * @static
+ * @memberOf _
+ * @category Lang
+ * @param {*} value The value to check.
+ * @returns {boolean} Returns `true` if `value` is `undefined`, else `false`.
+ * @example
+ *
+ * _.isUndefined(void 0);
+ * // => true
+ *
+ * _.isUndefined(null);
+ * // => false
+ */
+ function isUndefined(value) {
+ return value === undefined;
+ }
+
+ /**
+ * Checks if `value` is less than `other`.
+ *
+ * @static
+ * @memberOf _
+ * @category Lang
+ * @param {*} value The value to compare.
+ * @param {*} other The other value to compare.
+ * @returns {boolean} Returns `true` if `value` is less than `other`, else `false`.
+ * @example
+ *
+ * _.lt(1, 3);
+ * // => true
+ *
+ * _.lt(3, 3);
+ * // => false
+ *
+ * _.lt(3, 1);
+ * // => false
+ */
+ function lt(value, other) {
+ return value < other;
+ }
+
+ /**
+ * Checks if `value` is less than or equal to `other`.
+ *
+ * @static
+ * @memberOf _
+ * @category Lang
+ * @param {*} value The value to compare.
+ * @param {*} other The other value to compare.
+ * @returns {boolean} Returns `true` if `value` is less than or equal to `other`, else `false`.
+ * @example
+ *
+ * _.lte(1, 3);
+ * // => true
+ *
+ * _.lte(3, 3);
+ * // => true
+ *
+ * _.lte(3, 1);
+ * // => false
+ */
+ function lte(value, other) {
+ return value <= other;
+ }
+
+ /**
+ * Converts `value` to an array.
+ *
+ * @static
+ * @memberOf _
+ * @category Lang
+ * @param {*} value The value to convert.
+ * @returns {Array} Returns the converted array.
+ * @example
+ *
+ * (function() {
+ * return _.toArray(arguments).slice(1);
+ * }(1, 2, 3));
+ * // => [2, 3]
+ */
+ function toArray(value) {
+ var length = value ? getLength(value) : 0;
+ if (!isLength(length)) {
+ return values(value);
+ }
+ if (!length) {
+ return [];
+ }
+ return arrayCopy(value);
+ }
+
+ /**
+ * Converts `value` to a plain object flattening inherited enumerable
+ * properties of `value` to own properties of the plain object.
+ *
+ * @static
+ * @memberOf _
+ * @category Lang
+ * @param {*} value The value to convert.
+ * @returns {Object} Returns the converted plain object.
+ * @example
+ *
+ * function Foo() {
+ * this.b = 2;
+ * }
+ *
+ * Foo.prototype.c = 3;
+ *
+ * _.assign({ 'a': 1 }, new Foo);
+ * // => { 'a': 1, 'b': 2 }
+ *
+ * _.assign({ 'a': 1 }, _.toPlainObject(new Foo));
+ * // => { 'a': 1, 'b': 2, 'c': 3 }
+ */
+ function toPlainObject(value) {
+ return baseCopy(value, keysIn(value));
+ }
+
+ /*------------------------------------------------------------------------*/
+
+ /**
+ * Recursively merges own enumerable properties of the source object(s), that
+ * don't resolve to `undefined` into the destination object. Subsequent sources
+ * overwrite property assignments of previous sources. If `customizer` is
+ * provided it is invoked to produce the merged values of the destination and
+ * source properties. If `customizer` returns `undefined` merging is handled
+ * by the method instead. The `customizer` is bound to `thisArg` and invoked
+ * with five arguments: (objectValue, sourceValue, key, object, source).
+ *
+ * @static
+ * @memberOf _
+ * @category Object
+ * @param {Object} object The destination object.
+ * @param {...Object} [sources] The source objects.
+ * @param {Function} [customizer] The function to customize assigned values.
+ * @param {*} [thisArg] The `this` binding of `customizer`.
+ * @returns {Object} Returns `object`.
+ * @example
+ *
+ * var users = {
+ * 'data': [{ 'user': 'barney' }, { 'user': 'fred' }]
+ * };
+ *
+ * var ages = {
+ * 'data': [{ 'age': 36 }, { 'age': 40 }]
+ * };
+ *
+ * _.merge(users, ages);
+ * // => { 'data': [{ 'user': 'barney', 'age': 36 }, { 'user': 'fred', 'age': 40 }] }
+ *
+ * // using a customizer callback
+ * var object = {
+ * 'fruits': ['apple'],
+ * 'vegetables': ['beet']
+ * };
+ *
+ * var other = {
+ * 'fruits': ['banana'],
+ * 'vegetables': ['carrot']
+ * };
+ *
+ * _.merge(object, other, function(a, b) {
+ * if (_.isArray(a)) {
+ * return a.concat(b);
+ * }
+ * });
+ * // => { 'fruits': ['apple', 'banana'], 'vegetables': ['beet', 'carrot'] }
+ */
+ var merge = createAssigner(baseMerge);
+
+ /**
+ * Assigns own enumerable properties of source object(s) to the destination
+ * object. Subsequent sources overwrite property assignments of previous sources.
+ * If `customizer` is provided it is invoked to produce the assigned values.
+ * The `customizer` is bound to `thisArg` and invoked with five arguments:
+ * (objectValue, sourceValue, key, object, source).
+ *
+ * **Note:** This method mutates `object` and is based on
+ * [`Object.assign`](http://ecma-international.org/ecma-262/6.0/#sec-object.assign).
+ *
+ * @static
+ * @memberOf _
+ * @alias extend
+ * @category Object
+ * @param {Object} object The destination object.
+ * @param {...Object} [sources] The source objects.
+ * @param {Function} [customizer] The function to customize assigned values.
+ * @param {*} [thisArg] The `this` binding of `customizer`.
+ * @returns {Object} Returns `object`.
+ * @example
+ *
+ * _.assign({ 'user': 'barney' }, { 'age': 40 }, { 'user': 'fred' });
+ * // => { 'user': 'fred', 'age': 40 }
+ *
+ * // using a customizer callback
+ * var defaults = _.partialRight(_.assign, function(value, other) {
+ * return _.isUndefined(value) ? other : value;
+ * });
+ *
+ * defaults({ 'user': 'barney' }, { 'age': 36 }, { 'user': 'fred' });
+ * // => { 'user': 'barney', 'age': 36 }
+ */
+ var assign = createAssigner(function(object, source, customizer) {
+ return customizer
+ ? assignWith(object, source, customizer)
+ : baseAssign(object, source);
+ });
+
+ /**
+ * Creates an object that inherits from the given `prototype` object. If a
+ * `properties` object is provided its own enumerable properties are assigned
+ * to the created object.
+ *
+ * @static
+ * @memberOf _
+ * @category Object
+ * @param {Object} prototype The object to inherit from.
+ * @param {Object} [properties] The properties to assign to the object.
+ * @param- {Object} [guard] Enables use as a callback for functions like `_.map`.
+ * @returns {Object} Returns the new object.
+ * @example
+ *
+ * function Shape() {
+ * this.x = 0;
+ * this.y = 0;
+ * }
+ *
+ * function Circle() {
+ * Shape.call(this);
+ * }
+ *
+ * Circle.prototype = _.create(Shape.prototype, {
+ * 'constructor': Circle
+ * });
+ *
+ * var circle = new Circle;
+ * circle instanceof Circle;
+ * // => true
+ *
+ * circle instanceof Shape;
+ * // => true
+ */
+ function create(prototype, properties, guard) {
+ var result = baseCreate(prototype);
+ if (guard && isIterateeCall(prototype, properties, guard)) {
+ properties = undefined;
+ }
+ return properties ? baseAssign(result, properties) : result;
+ }
+
+ /**
+ * Assigns own enumerable properties of source object(s) to the destination
+ * object for all destination properties that resolve to `undefined`. Once a
+ * property is set, additional values of the same property are ignored.
+ *
+ * **Note:** This method mutates `object`.
+ *
+ * @static
+ * @memberOf _
+ * @category Object
+ * @param {Object} object The destination object.
+ * @param {...Object} [sources] The source objects.
+ * @returns {Object} Returns `object`.
+ * @example
+ *
+ * _.defaults({ 'user': 'barney' }, { 'age': 36 }, { 'user': 'fred' });
+ * // => { 'user': 'barney', 'age': 36 }
+ */
+ var defaults = createDefaults(assign, assignDefaults);
+
+ /**
+ * This method is like `_.defaults` except that it recursively assigns
+ * default properties.
+ *
+ * **Note:** This method mutates `object`.
+ *
+ * @static
+ * @memberOf _
+ * @category Object
+ * @param {Object} object The destination object.
+ * @param {...Object} [sources] The source objects.
+ * @returns {Object} Returns `object`.
+ * @example
+ *
+ * _.defaultsDeep({ 'user': { 'name': 'barney' } }, { 'user': { 'name': 'fred', 'age': 36 } });
+ * // => { 'user': { 'name': 'barney', 'age': 36 } }
+ *
+ */
+ var defaultsDeep = createDefaults(merge, mergeDefaults);
+
+ /**
+ * This method is like `_.find` except that it returns the key of the first
+ * element `predicate` returns truthy for instead of the element itself.
+ *
+ * If a property name is provided for `predicate` the created `_.property`
+ * style callback returns the property value of the given element.
+ *
+ * If a value is also provided for `thisArg` the created `_.matchesProperty`
+ * style callback returns `true` for elements that have a matching property
+ * value, else `false`.
+ *
+ * If an object is provided for `predicate` the created `_.matches` style
+ * callback returns `true` for elements that have the properties of the given
+ * object, else `false`.
+ *
+ * @static
+ * @memberOf _
+ * @category Object
+ * @param {Object} object The object to search.
+ * @param {Function|Object|string} [predicate=_.identity] The function invoked
+ * per iteration.
+ * @param {*} [thisArg] The `this` binding of `predicate`.
+ * @returns {string|undefined} Returns the key of the matched element, else `undefined`.
+ * @example
+ *
+ * var users = {
+ * 'barney': { 'age': 36, 'active': true },
+ * 'fred': { 'age': 40, 'active': false },
+ * 'pebbles': { 'age': 1, 'active': true }
+ * };
+ *
+ * _.findKey(users, function(chr) {
+ * return chr.age < 40;
+ * });
+ * // => 'barney' (iteration order is not guaranteed)
+ *
+ * // using the `_.matches` callback shorthand
+ * _.findKey(users, { 'age': 1, 'active': true });
+ * // => 'pebbles'
+ *
+ * // using the `_.matchesProperty` callback shorthand
+ * _.findKey(users, 'active', false);
+ * // => 'fred'
+ *
+ * // using the `_.property` callback shorthand
+ * _.findKey(users, 'active');
+ * // => 'barney'
+ */
+ var findKey = createFindKey(baseForOwn);
+
+ /**
+ * This method is like `_.findKey` except that it iterates over elements of
+ * a collection in the opposite order.
+ *
+ * If a property name is provided for `predicate` the created `_.property`
+ * style callback returns the property value of the given element.
+ *
+ * If a value is also provided for `thisArg` the created `_.matchesProperty`
+ * style callback returns `true` for elements that have a matching property
+ * value, else `false`.
+ *
+ * If an object is provided for `predicate` the created `_.matches` style
+ * callback returns `true` for elements that have the properties of the given
+ * object, else `false`.
+ *
+ * @static
+ * @memberOf _
+ * @category Object
+ * @param {Object} object The object to search.
+ * @param {Function|Object|string} [predicate=_.identity] The function invoked
+ * per iteration.
+ * @param {*} [thisArg] The `this` binding of `predicate`.
+ * @returns {string|undefined} Returns the key of the matched element, else `undefined`.
+ * @example
+ *
+ * var users = {
+ * 'barney': { 'age': 36, 'active': true },
+ * 'fred': { 'age': 40, 'active': false },
+ * 'pebbles': { 'age': 1, 'active': true }
+ * };
+ *
+ * _.findLastKey(users, function(chr) {
+ * return chr.age < 40;
+ * });
+ * // => returns `pebbles` assuming `_.findKey` returns `barney`
+ *
+ * // using the `_.matches` callback shorthand
+ * _.findLastKey(users, { 'age': 36, 'active': true });
+ * // => 'barney'
+ *
+ * // using the `_.matchesProperty` callback shorthand
+ * _.findLastKey(users, 'active', false);
+ * // => 'fred'
+ *
+ * // using the `_.property` callback shorthand
+ * _.findLastKey(users, 'active');
+ * // => 'pebbles'
+ */
+ var findLastKey = createFindKey(baseForOwnRight);
+
+ /**
+ * Iterates over own and inherited enumerable properties of an object invoking
+ * `iteratee` for each property. The `iteratee` is bound to `thisArg` and invoked
+ * with three arguments: (value, key, object). Iteratee functions may exit
+ * iteration early by explicitly returning `false`.
+ *
+ * @static
+ * @memberOf _
+ * @category Object
+ * @param {Object} object The object to iterate over.
+ * @param {Function} [iteratee=_.identity] The function invoked per iteration.
+ * @param {*} [thisArg] The `this` binding of `iteratee`.
+ * @returns {Object} Returns `object`.
+ * @example
+ *
+ * function Foo() {
+ * this.a = 1;
+ * this.b = 2;
+ * }
+ *
+ * Foo.prototype.c = 3;
+ *
+ * _.forIn(new Foo, function(value, key) {
+ * console.log(key);
+ * });
+ * // => logs 'a', 'b', and 'c' (iteration order is not guaranteed)
+ */
+ var forIn = createForIn(baseFor);
+
+ /**
+ * This method is like `_.forIn` except that it iterates over properties of
+ * `object` in the opposite order.
+ *
+ * @static
+ * @memberOf _
+ * @category Object
+ * @param {Object} object The object to iterate over.
+ * @param {Function} [iteratee=_.identity] The function invoked per iteration.
+ * @param {*} [thisArg] The `this` binding of `iteratee`.
+ * @returns {Object} Returns `object`.
+ * @example
+ *
+ * function Foo() {
+ * this.a = 1;
+ * this.b = 2;
+ * }
+ *
+ * Foo.prototype.c = 3;
+ *
+ * _.forInRight(new Foo, function(value, key) {
+ * console.log(key);
+ * });
+ * // => logs 'c', 'b', and 'a' assuming `_.forIn ` logs 'a', 'b', and 'c'
+ */
+ var forInRight = createForIn(baseForRight);
+
+ /**
+ * Iterates over own enumerable properties of an object invoking `iteratee`
+ * for each property. The `iteratee` is bound to `thisArg` and invoked with
+ * three arguments: (value, key, object). Iteratee functions may exit iteration
+ * early by explicitly returning `false`.
+ *
+ * @static
+ * @memberOf _
+ * @category Object
+ * @param {Object} object The object to iterate over.
+ * @param {Function} [iteratee=_.identity] The function invoked per iteration.
+ * @param {*} [thisArg] The `this` binding of `iteratee`.
+ * @returns {Object} Returns `object`.
+ * @example
+ *
+ * function Foo() {
+ * this.a = 1;
+ * this.b = 2;
+ * }
+ *
+ * Foo.prototype.c = 3;
+ *
+ * _.forOwn(new Foo, function(value, key) {
+ * console.log(key);
+ * });
+ * // => logs 'a' and 'b' (iteration order is not guaranteed)
+ */
+ var forOwn = createForOwn(baseForOwn);
+
+ /**
+ * This method is like `_.forOwn` except that it iterates over properties of
+ * `object` in the opposite order.
+ *
+ * @static
+ * @memberOf _
+ * @category Object
+ * @param {Object} object The object to iterate over.
+ * @param {Function} [iteratee=_.identity] The function invoked per iteration.
+ * @param {*} [thisArg] The `this` binding of `iteratee`.
+ * @returns {Object} Returns `object`.
+ * @example
+ *
+ * function Foo() {
+ * this.a = 1;
+ * this.b = 2;
+ * }
+ *
+ * Foo.prototype.c = 3;
+ *
+ * _.forOwnRight(new Foo, function(value, key) {
+ * console.log(key);
+ * });
+ * // => logs 'b' and 'a' assuming `_.forOwn` logs 'a' and 'b'
+ */
+ var forOwnRight = createForOwn(baseForOwnRight);
+
+ /**
+ * Creates an array of function property names from all enumerable properties,
+ * own and inherited, of `object`.
+ *
+ * @static
+ * @memberOf _
+ * @alias methods
+ * @category Object
+ * @param {Object} object The object to inspect.
+ * @returns {Array} Returns the new array of property names.
+ * @example
+ *
+ * _.functions(_);
+ * // => ['after', 'ary', 'assign', ...]
+ */
+ function functions(object) {
+ return baseFunctions(object, keysIn(object));
+ }
+
+ /**
+ * Gets the property value at `path` of `object`. If the resolved value is
+ * `undefined` the `defaultValue` is used in its place.
+ *
+ * @static
+ * @memberOf _
+ * @category Object
+ * @param {Object} object The object to query.
+ * @param {Array|string} path The path of the property to get.
+ * @param {*} [defaultValue] The value returned if the resolved value is `undefined`.
+ * @returns {*} Returns the resolved value.
+ * @example
+ *
+ * var object = { 'a': [{ 'b': { 'c': 3 } }] };
+ *
+ * _.get(object, 'a[0].b.c');
+ * // => 3
+ *
+ * _.get(object, ['a', '0', 'b', 'c']);
+ * // => 3
+ *
+ * _.get(object, 'a.b.c', 'default');
+ * // => 'default'
+ */
+ function get(object, path, defaultValue) {
+ var result = object == null ? undefined : baseGet(object, toPath(path), path + '');
+ return result === undefined ? defaultValue : result;
+ }
+
+ /**
+ * Checks if `path` is a direct property.
+ *
+ * @static
+ * @memberOf _
+ * @category Object
+ * @param {Object} object The object to query.
+ * @param {Array|string} path The path to check.
+ * @returns {boolean} Returns `true` if `path` is a direct property, else `false`.
+ * @example
+ *
+ * var object = { 'a': { 'b': { 'c': 3 } } };
+ *
+ * _.has(object, 'a');
+ * // => true
+ *
+ * _.has(object, 'a.b.c');
+ * // => true
+ *
+ * _.has(object, ['a', 'b', 'c']);
+ * // => true
+ */
+ function has(object, path) {
+ if (object == null) {
+ return false;
+ }
+ var result = hasOwnProperty.call(object, path);
+ if (!result && !isKey(path)) {
+ path = toPath(path);
+ object = path.length == 1 ? object : baseGet(object, baseSlice(path, 0, -1));
+ if (object == null) {
+ return false;
+ }
+ path = last(path);
+ result = hasOwnProperty.call(object, path);
+ }
+ return result || (isLength(object.length) && isIndex(path, object.length) &&
+ (isArray(object) || isArguments(object)));
+ }
+
+ /**
+ * Creates an object composed of the inverted keys and values of `object`.
+ * If `object` contains duplicate values, subsequent values overwrite property
+ * assignments of previous values unless `multiValue` is `true`.
+ *
+ * @static
+ * @memberOf _
+ * @category Object
+ * @param {Object} object The object to invert.
+ * @param {boolean} [multiValue] Allow multiple values per key.
+ * @param- {Object} [guard] Enables use as a callback for functions like `_.map`.
+ * @returns {Object} Returns the new inverted object.
+ * @example
+ *
+ * var object = { 'a': 1, 'b': 2, 'c': 1 };
+ *
+ * _.invert(object);
+ * // => { '1': 'c', '2': 'b' }
+ *
+ * // with `multiValue`
+ * _.invert(object, true);
+ * // => { '1': ['a', 'c'], '2': ['b'] }
+ */
+ function invert(object, multiValue, guard) {
+ if (guard && isIterateeCall(object, multiValue, guard)) {
+ multiValue = undefined;
+ }
+ var index = -1,
+ props = keys(object),
+ length = props.length,
+ result = {};
+
+ while (++index < length) {
+ var key = props[index],
+ value = object[key];
+
+ if (multiValue) {
+ if (hasOwnProperty.call(result, value)) {
+ result[value].push(key);
+ } else {
+ result[value] = [key];
+ }
+ }
+ else {
+ result[value] = key;
+ }
+ }
+ return result;
+ }
+
+ /**
+ * Creates an array of the own enumerable property names of `object`.
+ *
+ * **Note:** Non-object values are coerced to objects. See the
+ * [ES spec](http://ecma-international.org/ecma-262/6.0/#sec-object.keys)
+ * for more details.
+ *
+ * @static
+ * @memberOf _
+ * @category Object
+ * @param {Object} object The object to query.
+ * @returns {Array} Returns the array of property names.
+ * @example
+ *
+ * function Foo() {
+ * this.a = 1;
+ * this.b = 2;
+ * }
+ *
+ * Foo.prototype.c = 3;
+ *
+ * _.keys(new Foo);
+ * // => ['a', 'b'] (iteration order is not guaranteed)
+ *
+ * _.keys('hi');
+ * // => ['0', '1']
+ */
+ var keys = !nativeKeys ? shimKeys : function(object) {
+ var Ctor = object == null ? undefined : object.constructor;
+ if ((typeof Ctor == 'function' && Ctor.prototype === object) ||
+ (typeof object != 'function' && isArrayLike(object))) {
+ return shimKeys(object);
+ }
+ return isObject(object) ? nativeKeys(object) : [];
+ };
+
+ /**
+ * Creates an array of the own and inherited enumerable property names of `object`.
+ *
+ * **Note:** Non-object values are coerced to objects.
+ *
+ * @static
+ * @memberOf _
+ * @category Object
+ * @param {Object} object The object to query.
+ * @returns {Array} Returns the array of property names.
+ * @example
+ *
+ * function Foo() {
+ * this.a = 1;
+ * this.b = 2;
+ * }
+ *
+ * Foo.prototype.c = 3;
+ *
+ * _.keysIn(new Foo);
+ * // => ['a', 'b', 'c'] (iteration order is not guaranteed)
+ */
+ function keysIn(object) {
+ if (object == null) {
+ return [];
+ }
+ if (!isObject(object)) {
+ object = Object(object);
+ }
+ var length = object.length;
+ length = (length && isLength(length) &&
+ (isArray(object) || isArguments(object)) && length) || 0;
+
+ var Ctor = object.constructor,
+ index = -1,
+ isProto = typeof Ctor == 'function' && Ctor.prototype === object,
+ result = Array(length),
+ skipIndexes = length > 0;
+
+ while (++index < length) {
+ result[index] = (index + '');
+ }
+ for (var key in object) {
+ if (!(skipIndexes && isIndex(key, length)) &&
+ !(key == 'constructor' && (isProto || !hasOwnProperty.call(object, key)))) {
+ result.push(key);
+ }
+ }
+ return result;
+ }
+
+ /**
+ * The opposite of `_.mapValues`; this method creates an object with the
+ * same values as `object` and keys generated by running each own enumerable
+ * property of `object` through `iteratee`.
+ *
+ * @static
+ * @memberOf _
+ * @category Object
+ * @param {Object} object The object to iterate over.
+ * @param {Function|Object|string} [iteratee=_.identity] The function invoked
+ * per iteration.
+ * @param {*} [thisArg] The `this` binding of `iteratee`.
+ * @returns {Object} Returns the new mapped object.
+ * @example
+ *
+ * _.mapKeys({ 'a': 1, 'b': 2 }, function(value, key) {
+ * return key + value;
+ * });
+ * // => { 'a1': 1, 'b2': 2 }
+ */
+ var mapKeys = createObjectMapper(true);
+
+ /**
+ * Creates an object with the same keys as `object` and values generated by
+ * running each own enumerable property of `object` through `iteratee`. The
+ * iteratee function is bound to `thisArg` and invoked with three arguments:
+ * (value, key, object).
+ *
+ * If a property name is provided for `iteratee` the created `_.property`
+ * style callback returns the property value of the given element.
+ *
+ * If a value is also provided for `thisArg` the created `_.matchesProperty`
+ * style callback returns `true` for elements that have a matching property
+ * value, else `false`.
+ *
+ * If an object is provided for `iteratee` the created `_.matches` style
+ * callback returns `true` for elements that have the properties of the given
+ * object, else `false`.
+ *
+ * @static
+ * @memberOf _
+ * @category Object
+ * @param {Object} object The object to iterate over.
+ * @param {Function|Object|string} [iteratee=_.identity] The function invoked
+ * per iteration.
+ * @param {*} [thisArg] The `this` binding of `iteratee`.
+ * @returns {Object} Returns the new mapped object.
+ * @example
+ *
+ * _.mapValues({ 'a': 1, 'b': 2 }, function(n) {
+ * return n * 3;
+ * });
+ * // => { 'a': 3, 'b': 6 }
+ *
+ * var users = {
+ * 'fred': { 'user': 'fred', 'age': 40 },
+ * 'pebbles': { 'user': 'pebbles', 'age': 1 }
+ * };
+ *
+ * // using the `_.property` callback shorthand
+ * _.mapValues(users, 'age');
+ * // => { 'fred': 40, 'pebbles': 1 } (iteration order is not guaranteed)
+ */
+ var mapValues = createObjectMapper();
+
+ /**
+ * The opposite of `_.pick`; this method creates an object composed of the
+ * own and inherited enumerable properties of `object` that are not omitted.
+ *
+ * @static
+ * @memberOf _
+ * @category Object
+ * @param {Object} object The source object.
+ * @param {Function|...(string|string[])} [predicate] The function invoked per
+ * iteration or property names to omit, specified as individual property
+ * names or arrays of property names.
+ * @param {*} [thisArg] The `this` binding of `predicate`.
+ * @returns {Object} Returns the new object.
+ * @example
+ *
+ * var object = { 'user': 'fred', 'age': 40 };
+ *
+ * _.omit(object, 'age');
+ * // => { 'user': 'fred' }
+ *
+ * _.omit(object, _.isNumber);
+ * // => { 'user': 'fred' }
+ */
+ var omit = restParam(function(object, props) {
+ if (object == null) {
+ return {};
+ }
+ if (typeof props[0] != 'function') {
+ var props = arrayMap(baseFlatten(props), String);
+ return pickByArray(object, baseDifference(keysIn(object), props));
+ }
+ var predicate = bindCallback(props[0], props[1], 3);
+ return pickByCallback(object, function(value, key, object) {
+ return !predicate(value, key, object);
+ });
+ });
+
+ /**
+ * Creates a two dimensional array of the key-value pairs for `object`,
+ * e.g. `[[key1, value1], [key2, value2]]`.
+ *
+ * @static
+ * @memberOf _
+ * @category Object
+ * @param {Object} object The object to query.
+ * @returns {Array} Returns the new array of key-value pairs.
+ * @example
+ *
+ * _.pairs({ 'barney': 36, 'fred': 40 });
+ * // => [['barney', 36], ['fred', 40]] (iteration order is not guaranteed)
+ */
+ function pairs(object) {
+ object = toObject(object);
+
+ var index = -1,
+ props = keys(object),
+ length = props.length,
+ result = Array(length);
+
+ while (++index < length) {
+ var key = props[index];
+ result[index] = [key, object[key]];
+ }
+ return result;
+ }
+
+ /**
+ * Creates an object composed of the picked `object` properties. Property
+ * names may be specified as individual arguments or as arrays of property
+ * names. If `predicate` is provided it is invoked for each property of `object`
+ * picking the properties `predicate` returns truthy for. The predicate is
+ * bound to `thisArg` and invoked with three arguments: (value, key, object).
+ *
+ * @static
+ * @memberOf _
+ * @category Object
+ * @param {Object} object The source object.
+ * @param {Function|...(string|string[])} [predicate] The function invoked per
+ * iteration or property names to pick, specified as individual property
+ * names or arrays of property names.
+ * @param {*} [thisArg] The `this` binding of `predicate`.
+ * @returns {Object} Returns the new object.
+ * @example
+ *
+ * var object = { 'user': 'fred', 'age': 40 };
+ *
+ * _.pick(object, 'user');
+ * // => { 'user': 'fred' }
+ *
+ * _.pick(object, _.isString);
+ * // => { 'user': 'fred' }
+ */
+ var pick = restParam(function(object, props) {
+ if (object == null) {
+ return {};
+ }
+ return typeof props[0] == 'function'
+ ? pickByCallback(object, bindCallback(props[0], props[1], 3))
+ : pickByArray(object, baseFlatten(props));
+ });
+
+ /**
+ * This method is like `_.get` except that if the resolved value is a function
+ * it is invoked with the `this` binding of its parent object and its result
+ * is returned.
+ *
+ * @static
+ * @memberOf _
+ * @category Object
+ * @param {Object} object The object to query.
+ * @param {Array|string} path The path of the property to resolve.
+ * @param {*} [defaultValue] The value returned if the resolved value is `undefined`.
+ * @returns {*} Returns the resolved value.
+ * @example
+ *
+ * var object = { 'a': [{ 'b': { 'c1': 3, 'c2': _.constant(4) } }] };
+ *
+ * _.result(object, 'a[0].b.c1');
+ * // => 3
+ *
+ * _.result(object, 'a[0].b.c2');
+ * // => 4
+ *
+ * _.result(object, 'a.b.c', 'default');
+ * // => 'default'
+ *
+ * _.result(object, 'a.b.c', _.constant('default'));
+ * // => 'default'
+ */
+ function result(object, path, defaultValue) {
+ var result = object == null ? undefined : object[path];
+ if (result === undefined) {
+ if (object != null && !isKey(path, object)) {
+ path = toPath(path);
+ object = path.length == 1 ? object : baseGet(object, baseSlice(path, 0, -1));
+ result = object == null ? undefined : object[last(path)];
+ }
+ result = result === undefined ? defaultValue : result;
+ }
+ return isFunction(result) ? result.call(object) : result;
+ }
+
+ /**
+ * Sets the property value of `path` on `object`. If a portion of `path`
+ * does not exist it is created.
+ *
+ * @static
+ * @memberOf _
+ * @category Object
+ * @param {Object} object The object to augment.
+ * @param {Array|string} path The path of the property to set.
+ * @param {*} value The value to set.
+ * @returns {Object} Returns `object`.
+ * @example
+ *
+ * var object = { 'a': [{ 'b': { 'c': 3 } }] };
+ *
+ * _.set(object, 'a[0].b.c', 4);
+ * console.log(object.a[0].b.c);
+ * // => 4
+ *
+ * _.set(object, 'x[0].y.z', 5);
+ * console.log(object.x[0].y.z);
+ * // => 5
+ */
+ function set(object, path, value) {
+ if (object == null) {
+ return object;
+ }
+ var pathKey = (path + '');
+ path = (object[pathKey] != null || isKey(path, object)) ? [pathKey] : toPath(path);
+
+ var index = -1,
+ length = path.length,
+ lastIndex = length - 1,
+ nested = object;
+
+ while (nested != null && ++index < length) {
+ var key = path[index];
+ if (isObject(nested)) {
+ if (index == lastIndex) {
+ nested[key] = value;
+ } else if (nested[key] == null) {
+ nested[key] = isIndex(path[index + 1]) ? [] : {};
+ }
+ }
+ nested = nested[key];
+ }
+ return object;
+ }
+
+ /**
+ * An alternative to `_.reduce`; this method transforms `object` to a new
+ * `accumulator` object which is the result of running each of its own enumerable
+ * properties through `iteratee`, with each invocation potentially mutating
+ * the `accumulator` object. The `iteratee` is bound to `thisArg` and invoked
+ * with four arguments: (accumulator, value, key, object). Iteratee functions
+ * may exit iteration early by explicitly returning `false`.
+ *
+ * @static
+ * @memberOf _
+ * @category Object
+ * @param {Array|Object} object The object to iterate over.
+ * @param {Function} [iteratee=_.identity] The function invoked per iteration.
+ * @param {*} [accumulator] The custom accumulator value.
+ * @param {*} [thisArg] The `this` binding of `iteratee`.
+ * @returns {*} Returns the accumulated value.
+ * @example
+ *
+ * _.transform([2, 3, 4], function(result, n) {
+ * result.push(n *= n);
+ * return n % 2 == 0;
+ * });
+ * // => [4, 9]
+ *
+ * _.transform({ 'a': 1, 'b': 2 }, function(result, n, key) {
+ * result[key] = n * 3;
+ * });
+ * // => { 'a': 3, 'b': 6 }
+ */
+ function transform(object, iteratee, accumulator, thisArg) {
+ var isArr = isArray(object) || isTypedArray(object);
+ iteratee = getCallback(iteratee, thisArg, 4);
+
+ if (accumulator == null) {
+ if (isArr || isObject(object)) {
+ var Ctor = object.constructor;
+ if (isArr) {
+ accumulator = isArray(object) ? new Ctor : [];
+ } else {
+ accumulator = baseCreate(isFunction(Ctor) ? Ctor.prototype : undefined);
+ }
+ } else {
+ accumulator = {};
+ }
+ }
+ (isArr ? arrayEach : baseForOwn)(object, function(value, index, object) {
+ return iteratee(accumulator, value, index, object);
+ });
+ return accumulator;
+ }
+
+ /**
+ * Creates an array of the own enumerable property values of `object`.
+ *
+ * **Note:** Non-object values are coerced to objects.
+ *
+ * @static
+ * @memberOf _
+ * @category Object
+ * @param {Object} object The object to query.
+ * @returns {Array} Returns the array of property values.
+ * @example
+ *
+ * function Foo() {
+ * this.a = 1;
+ * this.b = 2;
+ * }
+ *
+ * Foo.prototype.c = 3;
+ *
+ * _.values(new Foo);
+ * // => [1, 2] (iteration order is not guaranteed)
+ *
+ * _.values('hi');
+ * // => ['h', 'i']
+ */
+ function values(object) {
+ return baseValues(object, keys(object));
+ }
+
+ /**
+ * Creates an array of the own and inherited enumerable property values
+ * of `object`.
+ *
+ * **Note:** Non-object values are coerced to objects.
+ *
+ * @static
+ * @memberOf _
+ * @category Object
+ * @param {Object} object The object to query.
+ * @returns {Array} Returns the array of property values.
+ * @example
+ *
+ * function Foo() {
+ * this.a = 1;
+ * this.b = 2;
+ * }
+ *
+ * Foo.prototype.c = 3;
+ *
+ * _.valuesIn(new Foo);
+ * // => [1, 2, 3] (iteration order is not guaranteed)
+ */
+ function valuesIn(object) {
+ return baseValues(object, keysIn(object));
+ }
+
+ /*------------------------------------------------------------------------*/
+
+ /**
+ * Checks if `n` is between `start` and up to but not including, `end`. If
+ * `end` is not specified it is set to `start` with `start` then set to `0`.
+ *
+ * @static
+ * @memberOf _
+ * @category Number
+ * @param {number} n The number to check.
+ * @param {number} [start=0] The start of the range.
+ * @param {number} end The end of the range.
+ * @returns {boolean} Returns `true` if `n` is in the range, else `false`.
+ * @example
+ *
+ * _.inRange(3, 2, 4);
+ * // => true
+ *
+ * _.inRange(4, 8);
+ * // => true
+ *
+ * _.inRange(4, 2);
+ * // => false
+ *
+ * _.inRange(2, 2);
+ * // => false
+ *
+ * _.inRange(1.2, 2);
+ * // => true
+ *
+ * _.inRange(5.2, 4);
+ * // => false
+ */
+ function inRange(value, start, end) {
+ start = +start || 0;
+ if (end === undefined) {
+ end = start;
+ start = 0;
+ } else {
+ end = +end || 0;
+ }
+ return value >= nativeMin(start, end) && value < nativeMax(start, end);
+ }
+
+ /**
+ * Produces a random number between `min` and `max` (inclusive). If only one
+ * argument is provided a number between `0` and the given number is returned.
+ * If `floating` is `true`, or either `min` or `max` are floats, a floating-point
+ * number is returned instead of an integer.
+ *
+ * @static
+ * @memberOf _
+ * @category Number
+ * @param {number} [min=0] The minimum possible value.
+ * @param {number} [max=1] The maximum possible value.
+ * @param {boolean} [floating] Specify returning a floating-point number.
+ * @returns {number} Returns the random number.
+ * @example
+ *
+ * _.random(0, 5);
+ * // => an integer between 0 and 5
+ *
+ * _.random(5);
+ * // => also an integer between 0 and 5
+ *
+ * _.random(5, true);
+ * // => a floating-point number between 0 and 5
+ *
+ * _.random(1.2, 5.2);
+ * // => a floating-point number between 1.2 and 5.2
+ */
+ function random(min, max, floating) {
+ if (floating && isIterateeCall(min, max, floating)) {
+ max = floating = undefined;
+ }
+ var noMin = min == null,
+ noMax = max == null;
+
+ if (floating == null) {
+ if (noMax && typeof min == 'boolean') {
+ floating = min;
+ min = 1;
+ }
+ else if (typeof max == 'boolean') {
+ floating = max;
+ noMax = true;
+ }
+ }
+ if (noMin && noMax) {
+ max = 1;
+ noMax = false;
+ }
+ min = +min || 0;
+ if (noMax) {
+ max = min;
+ min = 0;
+ } else {
+ max = +max || 0;
+ }
+ if (floating || min % 1 || max % 1) {
+ var rand = nativeRandom();
+ return nativeMin(min + (rand * (max - min + parseFloat('1e-' + ((rand + '').length - 1)))), max);
+ }
+ return baseRandom(min, max);
+ }
+
+ /*------------------------------------------------------------------------*/
+
+ /**
+ * Converts `string` to [camel case](https://en.wikipedia.org/wiki/CamelCase).
+ *
+ * @static
+ * @memberOf _
+ * @category String
+ * @param {string} [string=''] The string to convert.
+ * @returns {string} Returns the camel cased string.
+ * @example
+ *
+ * _.camelCase('Foo Bar');
+ * // => 'fooBar'
+ *
+ * _.camelCase('--foo-bar');
+ * // => 'fooBar'
+ *
+ * _.camelCase('__foo_bar__');
+ * // => 'fooBar'
+ */
+ var camelCase = createCompounder(function(result, word, index) {
+ word = word.toLowerCase();
+ return result + (index ? (word.charAt(0).toUpperCase() + word.slice(1)) : word);
+ });
+
+ /**
+ * Capitalizes the first character of `string`.
+ *
+ * @static
+ * @memberOf _
+ * @category String
+ * @param {string} [string=''] The string to capitalize.
+ * @returns {string} Returns the capitalized string.
+ * @example
+ *
+ * _.capitalize('fred');
+ * // => 'Fred'
+ */
+ function capitalize(string) {
+ string = baseToString(string);
+ return string && (string.charAt(0).toUpperCase() + string.slice(1));
+ }
+
+ /**
+ * Deburrs `string` by converting [latin-1 supplementary letters](https://en.wikipedia.org/wiki/Latin-1_Supplement_(Unicode_block)#Character_table)
+ * to basic latin letters and removing [combining diacritical marks](https://en.wikipedia.org/wiki/Combining_Diacritical_Marks).
+ *
+ * @static
+ * @memberOf _
+ * @category String
+ * @param {string} [string=''] The string to deburr.
+ * @returns {string} Returns the deburred string.
+ * @example
+ *
+ * _.deburr('déjà vu');
+ * // => 'deja vu'
+ */
+ function deburr(string) {
+ string = baseToString(string);
+ return string && string.replace(reLatin1, deburrLetter).replace(reComboMark, '');
+ }
+
+ /**
+ * Checks if `string` ends with the given target string.
+ *
+ * @static
+ * @memberOf _
+ * @category String
+ * @param {string} [string=''] The string to search.
+ * @param {string} [target] The string to search for.
+ * @param {number} [position=string.length] The position to search from.
+ * @returns {boolean} Returns `true` if `string` ends with `target`, else `false`.
+ * @example
+ *
+ * _.endsWith('abc', 'c');
+ * // => true
+ *
+ * _.endsWith('abc', 'b');
+ * // => false
+ *
+ * _.endsWith('abc', 'b', 2);
+ * // => true
+ */
+ function endsWith(string, target, position) {
+ string = baseToString(string);
+ target = (target + '');
+
+ var length = string.length;
+ position = position === undefined
+ ? length
+ : nativeMin(position < 0 ? 0 : (+position || 0), length);
+
+ position -= target.length;
+ return position >= 0 && string.indexOf(target, position) == position;
+ }
+
+ /**
+ * Converts the characters "&", "<", ">", '"', "'", and "\`", in `string` to
+ * their corresponding HTML entities.
+ *
+ * **Note:** No other characters are escaped. To escape additional characters
+ * use a third-party library like [_he_](https://mths.be/he).
+ *
+ * Though the ">" character is escaped for symmetry, characters like
+ * ">" and "/" don't need escaping in HTML and have no special meaning
+ * unless they're part of a tag or unquoted attribute value.
+ * See [Mathias Bynens's article](https://mathiasbynens.be/notes/ambiguous-ampersands)
+ * (under "semi-related fun fact") for more details.
+ *
+ * Backticks are escaped because in Internet Explorer < 9, they can break out
+ * of attribute values or HTML comments. See [#59](https://html5sec.org/#59),
+ * [#102](https://html5sec.org/#102), [#108](https://html5sec.org/#108), and
+ * [#133](https://html5sec.org/#133) of the [HTML5 Security Cheatsheet](https://html5sec.org/)
+ * for more details.
+ *
+ * When working with HTML you should always [quote attribute values](http://wonko.com/post/html-escaping)
+ * to reduce XSS vectors.
+ *
+ * @static
+ * @memberOf _
+ * @category String
+ * @param {string} [string=''] The string to escape.
+ * @returns {string} Returns the escaped string.
+ * @example
+ *
+ * _.escape('fred, barney, & pebbles');
+ * // => 'fred, barney, &amp; pebbles'
+ */
+ function escape(string) {
+ // Reset `lastIndex` because in IE < 9 `String#replace` does not.
+ string = baseToString(string);
+ return (string && reHasUnescapedHtml.test(string))
+ ? string.replace(reUnescapedHtml, escapeHtmlChar)
+ : string;
+ }
+
+ /**
+ * Escapes the `RegExp` special characters "\", "/", "^", "$", ".", "|", "?",
+ * "*", "+", "(", ")", "[", "]", "{" and "}" in `string`.
+ *
+ * @static
+ * @memberOf _
+ * @category String
+ * @param {string} [string=''] The string to escape.
+ * @returns {string} Returns the escaped string.
+ * @example
+ *
+ * _.escapeRegExp('[lodash](https://lodash.com/)');
+ * // => '\[lodash\]\(https:\/\/lodash\.com\/\)'
+ */
+ function escapeRegExp(string) {
+ string = baseToString(string);
+ return (string && reHasRegExpChars.test(string))
+ ? string.replace(reRegExpChars, escapeRegExpChar)
+ : (string || '(?:)');
+ }
+
+ /**
+ * Converts `string` to [kebab case](https://en.wikipedia.org/wiki/Letter_case#Special_case_styles).
+ *
+ * @static
+ * @memberOf _
+ * @category String
+ * @param {string} [string=''] The string to convert.
+ * @returns {string} Returns the kebab cased string.
+ * @example
+ *
+ * _.kebabCase('Foo Bar');
+ * // => 'foo-bar'
+ *
+ * _.kebabCase('fooBar');
+ * // => 'foo-bar'
+ *
+ * _.kebabCase('__foo_bar__');
+ * // => 'foo-bar'
+ */
+ var kebabCase = createCompounder(function(result, word, index) {
+ return result + (index ? '-' : '') + word.toLowerCase();
+ });
+
+ /**
+ * Pads `string` on the left and right sides if it's shorter than `length`.
+ * Padding characters are truncated if they can't be evenly divided by `length`.
+ *
+ * @static
+ * @memberOf _
+ * @category String
+ * @param {string} [string=''] The string to pad.
+ * @param {number} [length=0] The padding length.
+ * @param {string} [chars=' '] The string used as padding.
+ * @returns {string} Returns the padded string.
+ * @example
+ *
+ * _.pad('abc', 8);
+ * // => ' abc '
+ *
+ * _.pad('abc', 8, '_-');
+ * // => '_-abc_-_'
+ *
+ * _.pad('abc', 3);
+ * // => 'abc'
+ */
+ function pad(string, length, chars) {
+ string = baseToString(string);
+ length = +length;
+
+ var strLength = string.length;
+ if (strLength >= length || !nativeIsFinite(length)) {
+ return string;
+ }
+ var mid = (length - strLength) / 2,
+ leftLength = nativeFloor(mid),
+ rightLength = nativeCeil(mid);
+
+ chars = createPadding('', rightLength, chars);
+ return chars.slice(0, leftLength) + string + chars;
+ }
+
+ /**
+ * Pads `string` on the left side if it's shorter than `length`. Padding
+ * characters are truncated if they exceed `length`.
+ *
+ * @static
+ * @memberOf _
+ * @category String
+ * @param {string} [string=''] The string to pad.
+ * @param {number} [length=0] The padding length.
+ * @param {string} [chars=' '] The string used as padding.
+ * @returns {string} Returns the padded string.
+ * @example
+ *
+ * _.padLeft('abc', 6);
+ * // => ' abc'
+ *
+ * _.padLeft('abc', 6, '_-');
+ * // => '_-_abc'
+ *
+ * _.padLeft('abc', 3);
+ * // => 'abc'
+ */
+ var padLeft = createPadDir();
+
+ /**
+ * Pads `string` on the right side if it's shorter than `length`. Padding
+ * characters are truncated if they exceed `length`.
+ *
+ * @static
+ * @memberOf _
+ * @category String
+ * @param {string} [string=''] The string to pad.
+ * @param {number} [length=0] The padding length.
+ * @param {string} [chars=' '] The string used as padding.
+ * @returns {string} Returns the padded string.
+ * @example
+ *
+ * _.padRight('abc', 6);
+ * // => 'abc '
+ *
+ * _.padRight('abc', 6, '_-');
+ * // => 'abc_-_'
+ *
+ * _.padRight('abc', 3);
+ * // => 'abc'
+ */
+ var padRight = createPadDir(true);
+
+ /**
+ * Converts `string` to an integer of the specified radix. If `radix` is
+ * `undefined` or `0`, a `radix` of `10` is used unless `value` is a hexadecimal,
+ * in which case a `radix` of `16` is used.
+ *
+ * **Note:** This method aligns with the [ES5 implementation](https://es5.github.io/#E)
+ * of `parseInt`.
+ *
+ * @static
+ * @memberOf _
+ * @category String
+ * @param {string} string The string to convert.
+ * @param {number} [radix] The radix to interpret `value` by.
+ * @param- {Object} [guard] Enables use as a callback for functions like `_.map`.
+ * @returns {number} Returns the converted integer.
+ * @example
+ *
+ * _.parseInt('08');
+ * // => 8
+ *
+ * _.map(['6', '08', '10'], _.parseInt);
+ * // => [6, 8, 10]
+ */
+ function parseInt(string, radix, guard) {
+ // Firefox < 21 and Opera < 15 follow ES3 for `parseInt`.
+ // Chrome fails to trim leading <BOM> whitespace characters.
+ // See https://code.google.com/p/v8/issues/detail?id=3109 for more details.
+ if (guard ? isIterateeCall(string, radix, guard) : radix == null) {
+ radix = 0;
+ } else if (radix) {
+ radix = +radix;
+ }
+ string = trim(string);
+ return nativeParseInt(string, radix || (reHasHexPrefix.test(string) ? 16 : 10));
+ }
+
+ /**
+ * Repeats the given string `n` times.
+ *
+ * @static
+ * @memberOf _
+ * @category String
+ * @param {string} [string=''] The string to repeat.
+ * @param {number} [n=0] The number of times to repeat the string.
+ * @returns {string} Returns the repeated string.
+ * @example
+ *
+ * _.repeat('*', 3);
+ * // => '***'
+ *
+ * _.repeat('abc', 2);
+ * // => 'abcabc'
+ *
+ * _.repeat('abc', 0);
+ * // => ''
+ */
+ function repeat(string, n) {
+ var result = '';
+ string = baseToString(string);
+ n = +n;
+ if (n < 1 || !string || !nativeIsFinite(n)) {
+ return result;
+ }
+ // Leverage the exponentiation by squaring algorithm for a faster repeat.
+ // See https://en.wikipedia.org/wiki/Exponentiation_by_squaring for more details.
+ do {
+ if (n % 2) {
+ result += string;
+ }
+ n = nativeFloor(n / 2);
+ string += string;
+ } while (n);
+
+ return result;
+ }
+
+ /**
+ * Converts `string` to [snake case](https://en.wikipedia.org/wiki/Snake_case).
+ *
+ * @static
+ * @memberOf _
+ * @category String
+ * @param {string} [string=''] The string to convert.
+ * @returns {string} Returns the snake cased string.
+ * @example
+ *
+ * _.snakeCase('Foo Bar');
+ * // => 'foo_bar'
+ *
+ * _.snakeCase('fooBar');
+ * // => 'foo_bar'
+ *
+ * _.snakeCase('--foo-bar');
+ * // => 'foo_bar'
+ */
+ var snakeCase = createCompounder(function(result, word, index) {
+ return result + (index ? '_' : '') + word.toLowerCase();
+ });
+
+ /**
+ * Converts `string` to [start case](https://en.wikipedia.org/wiki/Letter_case#Stylistic_or_specialised_usage).
+ *
+ * @static
+ * @memberOf _
+ * @category String
+ * @param {string} [string=''] The string to convert.
+ * @returns {string} Returns the start cased string.
+ * @example
+ *
+ * _.startCase('--foo-bar');
+ * // => 'Foo Bar'
+ *
+ * _.startCase('fooBar');
+ * // => 'Foo Bar'
+ *
+ * _.startCase('__foo_bar__');
+ * // => 'Foo Bar'
+ */
+ var startCase = createCompounder(function(result, word, index) {
+ return result + (index ? ' ' : '') + (word.charAt(0).toUpperCase() + word.slice(1));
+ });
+
+ /**
+ * Checks if `string` starts with the given target string.
+ *
+ * @static
+ * @memberOf _
+ * @category String
+ * @param {string} [string=''] The string to search.
+ * @param {string} [target] The string to search for.
+ * @param {number} [position=0] The position to search from.
+ * @returns {boolean} Returns `true` if `string` starts with `target`, else `false`.
+ * @example
+ *
+ * _.startsWith('abc', 'a');
+ * // => true
+ *
+ * _.startsWith('abc', 'b');
+ * // => false
+ *
+ * _.startsWith('abc', 'b', 1);
+ * // => true
+ */
+ function startsWith(string, target, position) {
+ string = baseToString(string);
+ position = position == null
+ ? 0
+ : nativeMin(position < 0 ? 0 : (+position || 0), string.length);
+
+ return string.lastIndexOf(target, position) == position;
+ }
+
+ /**
+ * Creates a compiled template function that can interpolate data properties
+ * in "interpolate" delimiters, HTML-escape interpolated data properties in
+ * "escape" delimiters, and execute JavaScript in "evaluate" delimiters. Data
+ * properties may be accessed as free variables in the template. If a setting
+ * object is provided it takes precedence over `_.templateSettings` values.
+ *
+ * **Note:** In the development build `_.template` utilizes
+ * [sourceURLs](http://www.html5rocks.com/en/tutorials/developertools/sourcemaps/#toc-sourceurl)
+ * for easier debugging.
+ *
+ * For more information on precompiling templates see
+ * [lodash's custom builds documentation](https://lodash.com/custom-builds).
+ *
+ * For more information on Chrome extension sandboxes see
+ * [Chrome's extensions documentation](https://developer.chrome.com/extensions/sandboxingEval).
+ *
+ * @static
+ * @memberOf _
+ * @category String
+ * @param {string} [string=''] The template string.
+ * @param {Object} [options] The options object.
+ * @param {RegExp} [options.escape] The HTML "escape" delimiter.
+ * @param {RegExp} [options.evaluate] The "evaluate" delimiter.
+ * @param {Object} [options.imports] An object to import into the template as free variables.
+ * @param {RegExp} [options.interpolate] The "interpolate" delimiter.
+ * @param {string} [options.sourceURL] The sourceURL of the template's compiled source.
+ * @param {string} [options.variable] The data object variable name.
+ * @param- {Object} [otherOptions] Enables the legacy `options` param signature.
+ * @returns {Function} Returns the compiled template function.
+ * @example
+ *
+ * // using the "interpolate" delimiter to create a compiled template
+ * var compiled = _.template('hello <%= user %>!');
+ * compiled({ 'user': 'fred' });
+ * // => 'hello fred!'
+ *
+ * // using the HTML "escape" delimiter to escape data property values
+ * var compiled = _.template('<b><%- value %></b>');
+ * compiled({ 'value': '<script>' });
+ * // => '<b>&lt;script&gt;</b>'
+ *
+ * // using the "evaluate" delimiter to execute JavaScript and generate HTML
+ * var compiled = _.template('<% _.forEach(users, function(user) { %><li><%- user %></li><% }); %>');
+ * compiled({ 'users': ['fred', 'barney'] });
+ * // => '<li>fred</li><li>barney</li>'
+ *
+ * // using the internal `print` function in "evaluate" delimiters
+ * var compiled = _.template('<% print("hello " + user); %>!');
+ * compiled({ 'user': 'barney' });
+ * // => 'hello barney!'
+ *
+ * // using the ES delimiter as an alternative to the default "interpolate" delimiter
+ * var compiled = _.template('hello ${ user }!');
+ * compiled({ 'user': 'pebbles' });
+ * // => 'hello pebbles!'
+ *
+ * // using custom template delimiters
+ * _.templateSettings.interpolate = /{{([\s\S]+?)}}/g;
+ * var compiled = _.template('hello {{ user }}!');
+ * compiled({ 'user': 'mustache' });
+ * // => 'hello mustache!'
+ *
+ * // using backslashes to treat delimiters as plain text
+ * var compiled = _.template('<%= "\\<%- value %\\>" %>');
+ * compiled({ 'value': 'ignored' });
+ * // => '<%- value %>'
+ *
+ * // using the `imports` option to import `jQuery` as `jq`
+ * var text = '<% jq.each(users, function(user) { %><li><%- user %></li><% }); %>';
+ * var compiled = _.template(text, { 'imports': { 'jq': jQuery } });
+ * compiled({ 'users': ['fred', 'barney'] });
+ * // => '<li>fred</li><li>barney</li>'
+ *
+ * // using the `sourceURL` option to specify a custom sourceURL for the template
+ * var compiled = _.template('hello <%= user %>!', { 'sourceURL': '/basic/greeting.jst' });
+ * compiled(data);
+ * // => find the source of "greeting.jst" under the Sources tab or Resources panel of the web inspector
+ *
+ * // using the `variable` option to ensure a with-statement isn't used in the compiled template
+ * var compiled = _.template('hi <%= data.user %>!', { 'variable': 'data' });
+ * compiled.source;
+ * // => function(data) {
+ * // var __t, __p = '';
+ * // __p += 'hi ' + ((__t = ( data.user )) == null ? '' : __t) + '!';
+ * // return __p;
+ * // }
+ *
+ * // using the `source` property to inline compiled templates for meaningful
+ * // line numbers in error messages and a stack trace
+ * fs.writeFileSync(path.join(cwd, 'jst.js'), '\
+ * var JST = {\
+ * "main": ' + _.template(mainText).source + '\
+ * };\
+ * ');
+ */
+ function template(string, options, otherOptions) {
+ // Based on John Resig's `tmpl` implementation (http://ejohn.org/blog/javascript-micro-templating/)
+ // and Laura Doktorova's doT.js (https://github.com/olado/doT).
+ var settings = lodash.templateSettings;
+
+ if (otherOptions && isIterateeCall(string, options, otherOptions)) {
+ options = otherOptions = undefined;
+ }
+ string = baseToString(string);
+ options = assignWith(baseAssign({}, otherOptions || options), settings, assignOwnDefaults);
+
+ var imports = assignWith(baseAssign({}, options.imports), settings.imports, assignOwnDefaults),
+ importsKeys = keys(imports),
+ importsValues = baseValues(imports, importsKeys);
+
+ var isEscaping,
+ isEvaluating,
+ index = 0,
+ interpolate = options.interpolate || reNoMatch,
+ source = "__p += '";
+
+ // Compile the regexp to match each delimiter.
+ var reDelimiters = RegExp(
+ (options.escape || reNoMatch).source + '|' +
+ interpolate.source + '|' +
+ (interpolate === reInterpolate ? reEsTemplate : reNoMatch).source + '|' +
+ (options.evaluate || reNoMatch).source + '|$'
+ , 'g');
+
+ // Use a sourceURL for easier debugging.
+ var sourceURL = '//# sourceURL=' +
+ ('sourceURL' in options
+ ? options.sourceURL
+ : ('lodash.templateSources[' + (++templateCounter) + ']')
+ ) + '\n';
+
+ string.replace(reDelimiters, function(match, escapeValue, interpolateValue, esTemplateValue, evaluateValue, offset) {
+ interpolateValue || (interpolateValue = esTemplateValue);
+
+ // Escape characters that can't be included in string literals.
+ source += string.slice(index, offset).replace(reUnescapedString, escapeStringChar);
+
+ // Replace delimiters with snippets.
+ if (escapeValue) {
+ isEscaping = true;
+ source += "' +\n__e(" + escapeValue + ") +\n'";
+ }
+ if (evaluateValue) {
+ isEvaluating = true;
+ source += "';\n" + evaluateValue + ";\n__p += '";
+ }
+ if (interpolateValue) {
+ source += "' +\n((__t = (" + interpolateValue + ")) == null ? '' : __t) +\n'";
+ }
+ index = offset + match.length;
+
+ // The JS engine embedded in Adobe products requires returning the `match`
+ // string in order to produce the correct `offset` value.
+ return match;
+ });
+
+ source += "';\n";
+
+ // If `variable` is not specified wrap a with-statement around the generated
+ // code to add the data object to the top of the scope chain.
+ var variable = options.variable;
+ if (!variable) {
+ source = 'with (obj) {\n' + source + '\n}\n';
+ }
+ // Cleanup code by stripping empty strings.
+ source = (isEvaluating ? source.replace(reEmptyStringLeading, '') : source)
+ .replace(reEmptyStringMiddle, '$1')
+ .replace(reEmptyStringTrailing, '$1;');
+
+ // Frame code as the function body.
+ source = 'function(' + (variable || 'obj') + ') {\n' +
+ (variable
+ ? ''
+ : 'obj || (obj = {});\n'
+ ) +
+ "var __t, __p = ''" +
+ (isEscaping
+ ? ', __e = _.escape'
+ : ''
+ ) +
+ (isEvaluating
+ ? ', __j = Array.prototype.join;\n' +
+ "function print() { __p += __j.call(arguments, '') }\n"
+ : ';\n'
+ ) +
+ source +
+ 'return __p\n}';
+
+ var result = attempt(function() {
+ return Function(importsKeys, sourceURL + 'return ' + source).apply(undefined, importsValues);
+ });
+
+ // Provide the compiled function's source by its `toString` method or
+ // the `source` property as a convenience for inlining compiled templates.
+ result.source = source;
+ if (isError(result)) {
+ throw result;
+ }
+ return result;
+ }
+
+ /**
+ * Removes leading and trailing whitespace or specified characters from `string`.
+ *
+ * @static
+ * @memberOf _
+ * @category String
+ * @param {string} [string=''] The string to trim.
+ * @param {string} [chars=whitespace] The characters to trim.
+ * @param- {Object} [guard] Enables use as a callback for functions like `_.map`.
+ * @returns {string} Returns the trimmed string.
+ * @example
+ *
+ * _.trim(' abc ');
+ * // => 'abc'
+ *
+ * _.trim('-_-abc-_-', '_-');
+ * // => 'abc'
+ *
+ * _.map([' foo ', ' bar '], _.trim);
+ * // => ['foo', 'bar']
+ */
+ function trim(string, chars, guard) {
+ var value = string;
+ string = baseToString(string);
+ if (!string) {
+ return string;
+ }
+ if (guard ? isIterateeCall(value, chars, guard) : chars == null) {
+ return string.slice(trimmedLeftIndex(string), trimmedRightIndex(string) + 1);
+ }
+ chars = (chars + '');
+ return string.slice(charsLeftIndex(string, chars), charsRightIndex(string, chars) + 1);
+ }
+
+ /**
+ * Removes leading whitespace or specified characters from `string`.
+ *
+ * @static
+ * @memberOf _
+ * @category String
+ * @param {string} [string=''] The string to trim.
+ * @param {string} [chars=whitespace] The characters to trim.
+ * @param- {Object} [guard] Enables use as a callback for functions like `_.map`.
+ * @returns {string} Returns the trimmed string.
+ * @example
+ *
+ * _.trimLeft(' abc ');
+ * // => 'abc '
+ *
+ * _.trimLeft('-_-abc-_-', '_-');
+ * // => 'abc-_-'
+ */
+ function trimLeft(string, chars, guard) {
+ var value = string;
+ string = baseToString(string);
+ if (!string) {
+ return string;
+ }
+ if (guard ? isIterateeCall(value, chars, guard) : chars == null) {
+ return string.slice(trimmedLeftIndex(string));
+ }
+ return string.slice(charsLeftIndex(string, (chars + '')));
+ }
+
+ /**
+ * Removes trailing whitespace or specified characters from `string`.
+ *
+ * @static
+ * @memberOf _
+ * @category String
+ * @param {string} [string=''] The string to trim.
+ * @param {string} [chars=whitespace] The characters to trim.
+ * @param- {Object} [guard] Enables use as a callback for functions like `_.map`.
+ * @returns {string} Returns the trimmed string.
+ * @example
+ *
+ * _.trimRight(' abc ');
+ * // => ' abc'
+ *
+ * _.trimRight('-_-abc-_-', '_-');
+ * // => '-_-abc'
+ */
+ function trimRight(string, chars, guard) {
+ var value = string;
+ string = baseToString(string);
+ if (!string) {
+ return string;
+ }
+ if (guard ? isIterateeCall(value, chars, guard) : chars == null) {
+ return string.slice(0, trimmedRightIndex(string) + 1);
+ }
+ return string.slice(0, charsRightIndex(string, (chars + '')) + 1);
+ }
+
+ /**
+ * Truncates `string` if it's longer than the given maximum string length.
+ * The last characters of the truncated string are replaced with the omission
+ * string which defaults to "...".
+ *
+ * @static
+ * @memberOf _
+ * @category String
+ * @param {string} [string=''] The string to truncate.
+ * @param {Object|number} [options] The options object or maximum string length.
+ * @param {number} [options.length=30] The maximum string length.
+ * @param {string} [options.omission='...'] The string to indicate text is omitted.
+ * @param {RegExp|string} [options.separator] The separator pattern to truncate to.
+ * @param- {Object} [guard] Enables use as a callback for functions like `_.map`.
+ * @returns {string} Returns the truncated string.
+ * @example
+ *
+ * _.trunc('hi-diddly-ho there, neighborino');
+ * // => 'hi-diddly-ho there, neighbo...'
+ *
+ * _.trunc('hi-diddly-ho there, neighborino', 24);
+ * // => 'hi-diddly-ho there, n...'
+ *
+ * _.trunc('hi-diddly-ho there, neighborino', {
+ * 'length': 24,
+ * 'separator': ' '
+ * });
+ * // => 'hi-diddly-ho there,...'
+ *
+ * _.trunc('hi-diddly-ho there, neighborino', {
+ * 'length': 24,
+ * 'separator': /,? +/
+ * });
+ * // => 'hi-diddly-ho there...'
+ *
+ * _.trunc('hi-diddly-ho there, neighborino', {
+ * 'omission': ' [...]'
+ * });
+ * // => 'hi-diddly-ho there, neig [...]'
+ */
+ function trunc(string, options, guard) {
+ if (guard && isIterateeCall(string, options, guard)) {
+ options = undefined;
+ }
+ var length = DEFAULT_TRUNC_LENGTH,
+ omission = DEFAULT_TRUNC_OMISSION;
+
+ if (options != null) {
+ if (isObject(options)) {
+ var separator = 'separator' in options ? options.separator : separator;
+ length = 'length' in options ? (+options.length || 0) : length;
+ omission = 'omission' in options ? baseToString(options.omission) : omission;
+ } else {
+ length = +options || 0;
+ }
+ }
+ string = baseToString(string);
+ if (length >= string.length) {
+ return string;
+ }
+ var end = length - omission.length;
+ if (end < 1) {
+ return omission;
+ }
+ var result = string.slice(0, end);
+ if (separator == null) {
+ return result + omission;
+ }
+ if (isRegExp(separator)) {
+ if (string.slice(end).search(separator)) {
+ var match,
+ newEnd,
+ substring = string.slice(0, end);
+
+ if (!separator.global) {
+ separator = RegExp(separator.source, (reFlags.exec(separator) || '') + 'g');
+ }
+ separator.lastIndex = 0;
+ while ((match = separator.exec(substring))) {
+ newEnd = match.index;
+ }
+ result = result.slice(0, newEnd == null ? end : newEnd);
+ }
+ } else if (string.indexOf(separator, end) != end) {
+ var index = result.lastIndexOf(separator);
+ if (index > -1) {
+ result = result.slice(0, index);
+ }
+ }
+ return result + omission;
+ }
+
+ /**
+ * The inverse of `_.escape`; this method converts the HTML entities
+ * `&amp;`, `&lt;`, `&gt;`, `&quot;`, `&#39;`, and `&#96;` in `string` to their
+ * corresponding characters.
+ *
+ * **Note:** No other HTML entities are unescaped. To unescape additional HTML
+ * entities use a third-party library like [_he_](https://mths.be/he).
+ *
+ * @static
+ * @memberOf _
+ * @category String
+ * @param {string} [string=''] The string to unescape.
+ * @returns {string} Returns the unescaped string.
+ * @example
+ *
+ * _.unescape('fred, barney, &amp; pebbles');
+ * // => 'fred, barney, & pebbles'
+ */
+ function unescape(string) {
+ string = baseToString(string);
+ return (string && reHasEscapedHtml.test(string))
+ ? string.replace(reEscapedHtml, unescapeHtmlChar)
+ : string;
+ }
+
+ /**
+ * Splits `string` into an array of its words.
+ *
+ * @static
+ * @memberOf _
+ * @category String
+ * @param {string} [string=''] The string to inspect.
+ * @param {RegExp|string} [pattern] The pattern to match words.
+ * @param- {Object} [guard] Enables use as a callback for functions like `_.map`.
+ * @returns {Array} Returns the words of `string`.
+ * @example
+ *
+ * _.words('fred, barney, & pebbles');
+ * // => ['fred', 'barney', 'pebbles']
+ *
+ * _.words('fred, barney, & pebbles', /[^, ]+/g);
+ * // => ['fred', 'barney', '&', 'pebbles']
+ */
+ function words(string, pattern, guard) {
+ if (guard && isIterateeCall(string, pattern, guard)) {
+ pattern = undefined;
+ }
+ string = baseToString(string);
+ return string.match(pattern || reWords) || [];
+ }
+
+ /*------------------------------------------------------------------------*/
+
+ /**
+ * Attempts to invoke `func`, returning either the result or the caught error
+ * object. Any additional arguments are provided to `func` when it is invoked.
+ *
+ * @static
+ * @memberOf _
+ * @category Utility
+ * @param {Function} func The function to attempt.
+ * @returns {*} Returns the `func` result or error object.
+ * @example
+ *
+ * // avoid throwing errors for invalid selectors
+ * var elements = _.attempt(function(selector) {
+ * return document.querySelectorAll(selector);
+ * }, '>_>');
+ *
+ * if (_.isError(elements)) {
+ * elements = [];
+ * }
+ */
+ var attempt = restParam(function(func, args) {
+ try {
+ return func.apply(undefined, args);
+ } catch(e) {
+ return isError(e) ? e : new Error(e);
+ }
+ });
+
+ /**
+ * Creates a function that invokes `func` with the `this` binding of `thisArg`
+ * and arguments of the created function. If `func` is a property name the
+ * created callback returns the property value for a given element. If `func`
+ * is an object the created callback returns `true` for elements that contain
+ * the equivalent object properties, otherwise it returns `false`.
+ *
+ * @static
+ * @memberOf _
+ * @alias iteratee
+ * @category Utility
+ * @param {*} [func=_.identity] The value to convert to a callback.
+ * @param {*} [thisArg] The `this` binding of `func`.
+ * @param- {Object} [guard] Enables use as a callback for functions like `_.map`.
+ * @returns {Function} Returns the callback.
+ * @example
+ *
+ * var users = [
+ * { 'user': 'barney', 'age': 36 },
+ * { 'user': 'fred', 'age': 40 }
+ * ];
+ *
+ * // wrap to create custom callback shorthands
+ * _.callback = _.wrap(_.callback, function(callback, func, thisArg) {
+ * var match = /^(.+?)__([gl]t)(.+)$/.exec(func);
+ * if (!match) {
+ * return callback(func, thisArg);
+ * }
+ * return function(object) {
+ * return match[2] == 'gt'
+ * ? object[match[1]] > match[3]
+ * : object[match[1]] < match[3];
+ * };
+ * });
+ *
+ * _.filter(users, 'age__gt36');
+ * // => [{ 'user': 'fred', 'age': 40 }]
+ */
+ function callback(func, thisArg, guard) {
+ if (guard && isIterateeCall(func, thisArg, guard)) {
+ thisArg = undefined;
+ }
+ return isObjectLike(func)
+ ? matches(func)
+ : baseCallback(func, thisArg);
+ }
+
+ /**
+ * Creates a function that returns `value`.
+ *
+ * @static
+ * @memberOf _
+ * @category Utility
+ * @param {*} value The value to return from the new function.
+ * @returns {Function} Returns the new function.
+ * @example
+ *
+ * var object = { 'user': 'fred' };
+ * var getter = _.constant(object);
+ *
+ * getter() === object;
+ * // => true
+ */
+ function constant(value) {
+ return function() {
+ return value;
+ };
+ }
+
+ /**
+ * This method returns the first argument provided to it.
+ *
+ * @static
+ * @memberOf _
+ * @category Utility
+ * @param {*} value Any value.
+ * @returns {*} Returns `value`.
+ * @example
+ *
+ * var object = { 'user': 'fred' };
+ *
+ * _.identity(object) === object;
+ * // => true
+ */
+ function identity(value) {
+ return value;
+ }
+
+ /**
+ * Creates a function that performs a deep comparison between a given object
+ * and `source`, returning `true` if the given object has equivalent property
+ * values, else `false`.
+ *
+ * **Note:** This method supports comparing arrays, booleans, `Date` objects,
+ * numbers, `Object` objects, regexes, and strings. Objects are compared by
+ * their own, not inherited, enumerable properties. For comparing a single
+ * own or inherited property value see `_.matchesProperty`.
+ *
+ * @static
+ * @memberOf _
+ * @category Utility
+ * @param {Object} source The object of property values to match.
+ * @returns {Function} Returns the new function.
+ * @example
+ *
+ * var users = [
+ * { 'user': 'barney', 'age': 36, 'active': true },
+ * { 'user': 'fred', 'age': 40, 'active': false }
+ * ];
+ *
+ * _.filter(users, _.matches({ 'age': 40, 'active': false }));
+ * // => [{ 'user': 'fred', 'age': 40, 'active': false }]
+ */
+ function matches(source) {
+ return baseMatches(baseClone(source, true));
+ }
+
+ /**
+ * Creates a function that compares the property value of `path` on a given
+ * object to `value`.
+ *
+ * **Note:** This method supports comparing arrays, booleans, `Date` objects,
+ * numbers, `Object` objects, regexes, and strings. Objects are compared by
+ * their own, not inherited, enumerable properties.
+ *
+ * @static
+ * @memberOf _
+ * @category Utility
+ * @param {Array|string} path The path of the property to get.
+ * @param {*} srcValue The value to match.
+ * @returns {Function} Returns the new function.
+ * @example
+ *
+ * var users = [
+ * { 'user': 'barney' },
+ * { 'user': 'fred' }
+ * ];
+ *
+ * _.find(users, _.matchesProperty('user', 'fred'));
+ * // => { 'user': 'fred' }
+ */
+ function matchesProperty(path, srcValue) {
+ return baseMatchesProperty(path, baseClone(srcValue, true));
+ }
+
+ /**
+ * Creates a function that invokes the method at `path` on a given object.
+ * Any additional arguments are provided to the invoked method.
+ *
+ * @static
+ * @memberOf _
+ * @category Utility
+ * @param {Array|string} path The path of the method to invoke.
+ * @param {...*} [args] The arguments to invoke the method with.
+ * @returns {Function} Returns the new function.
+ * @example
+ *
+ * var objects = [
+ * { 'a': { 'b': { 'c': _.constant(2) } } },
+ * { 'a': { 'b': { 'c': _.constant(1) } } }
+ * ];
+ *
+ * _.map(objects, _.method('a.b.c'));
+ * // => [2, 1]
+ *
+ * _.invoke(_.sortBy(objects, _.method(['a', 'b', 'c'])), 'a.b.c');
+ * // => [1, 2]
+ */
+ var method = restParam(function(path, args) {
+ return function(object) {
+ return invokePath(object, path, args);
+ };
+ });
+
+ /**
+ * The opposite of `_.method`; this method creates a function that invokes
+ * the method at a given path on `object`. Any additional arguments are
+ * provided to the invoked method.
+ *
+ * @static
+ * @memberOf _
+ * @category Utility
+ * @param {Object} object The object to query.
+ * @param {...*} [args] The arguments to invoke the method with.
+ * @returns {Function} Returns the new function.
+ * @example
+ *
+ * var array = _.times(3, _.constant),
+ * object = { 'a': array, 'b': array, 'c': array };
+ *
+ * _.map(['a[2]', 'c[0]'], _.methodOf(object));
+ * // => [2, 0]
+ *
+ * _.map([['a', '2'], ['c', '0']], _.methodOf(object));
+ * // => [2, 0]
+ */
+ var methodOf = restParam(function(object, args) {
+ return function(path) {
+ return invokePath(object, path, args);
+ };
+ });
+
+ /**
+ * Adds all own enumerable function properties of a source object to the
+ * destination object. If `object` is a function then methods are added to
+ * its prototype as well.
+ *
+ * **Note:** Use `_.runInContext` to create a pristine `lodash` function to
+ * avoid conflicts caused by modifying the original.
+ *
+ * @static
+ * @memberOf _
+ * @category Utility
+ * @param {Function|Object} [object=lodash] The destination object.
+ * @param {Object} source The object of functions to add.
+ * @param {Object} [options] The options object.
+ * @param {boolean} [options.chain=true] Specify whether the functions added
+ * are chainable.
+ * @returns {Function|Object} Returns `object`.
+ * @example
+ *
+ * function vowels(string) {
+ * return _.filter(string, function(v) {
+ * return /[aeiou]/i.test(v);
+ * });
+ * }
+ *
+ * _.mixin({ 'vowels': vowels });
+ * _.vowels('fred');
+ * // => ['e']
+ *
+ * _('fred').vowels().value();
+ * // => ['e']
+ *
+ * _.mixin({ 'vowels': vowels }, { 'chain': false });
+ * _('fred').vowels();
+ * // => ['e']
+ */
+ function mixin(object, source, options) {
+ if (options == null) {
+ var isObj = isObject(source),
+ props = isObj ? keys(source) : undefined,
+ methodNames = (props && props.length) ? baseFunctions(source, props) : undefined;
+
+ if (!(methodNames ? methodNames.length : isObj)) {
+ methodNames = false;
+ options = source;
+ source = object;
+ object = this;
+ }
+ }
+ if (!methodNames) {
+ methodNames = baseFunctions(source, keys(source));
+ }
+ var chain = true,
+ index = -1,
+ isFunc = isFunction(object),
+ length = methodNames.length;
+
+ if (options === false) {
+ chain = false;
+ } else if (isObject(options) && 'chain' in options) {
+ chain = options.chain;
+ }
+ while (++index < length) {
+ var methodName = methodNames[index],
+ func = source[methodName];
+
+ object[methodName] = func;
+ if (isFunc) {
+ object.prototype[methodName] = (function(func) {
+ return function() {
+ var chainAll = this.__chain__;
+ if (chain || chainAll) {
+ var result = object(this.__wrapped__),
+ actions = result.__actions__ = arrayCopy(this.__actions__);
+
+ actions.push({ 'func': func, 'args': arguments, 'thisArg': object });
+ result.__chain__ = chainAll;
+ return result;
+ }
+ return func.apply(object, arrayPush([this.value()], arguments));
+ };
+ }(func));
+ }
+ }
+ return object;
+ }
+
+ /**
+ * Reverts the `_` variable to its previous value and returns a reference to
+ * the `lodash` function.
+ *
+ * @static
+ * @memberOf _
+ * @category Utility
+ * @returns {Function} Returns the `lodash` function.
+ * @example
+ *
+ * var lodash = _.noConflict();
+ */
+ function noConflict() {
+ root._ = oldDash;
+ return this;
+ }
+
+ /**
+ * A no-operation function that returns `undefined` regardless of the
+ * arguments it receives.
+ *
+ * @static
+ * @memberOf _
+ * @category Utility
+ * @example
+ *
+ * var object = { 'user': 'fred' };
+ *
+ * _.noop(object) === undefined;
+ * // => true
+ */
+ function noop() {
+ // No operation performed.
+ }
+
+ /**
+ * Creates a function that returns the property value at `path` on a
+ * given object.
+ *
+ * @static
+ * @memberOf _
+ * @category Utility
+ * @param {Array|string} path The path of the property to get.
+ * @returns {Function} Returns the new function.
+ * @example
+ *
+ * var objects = [
+ * { 'a': { 'b': { 'c': 2 } } },
+ * { 'a': { 'b': { 'c': 1 } } }
+ * ];
+ *
+ * _.map(objects, _.property('a.b.c'));
+ * // => [2, 1]
+ *
+ * _.pluck(_.sortBy(objects, _.property(['a', 'b', 'c'])), 'a.b.c');
+ * // => [1, 2]
+ */
+ function property(path) {
+ return isKey(path) ? baseProperty(path) : basePropertyDeep(path);
+ }
+
+ /**
+ * The opposite of `_.property`; this method creates a function that returns
+ * the property value at a given path on `object`.
+ *
+ * @static
+ * @memberOf _
+ * @category Utility
+ * @param {Object} object The object to query.
+ * @returns {Function} Returns the new function.
+ * @example
+ *
+ * var array = [0, 1, 2],
+ * object = { 'a': array, 'b': array, 'c': array };
+ *
+ * _.map(['a[2]', 'c[0]'], _.propertyOf(object));
+ * // => [2, 0]
+ *
+ * _.map([['a', '2'], ['c', '0']], _.propertyOf(object));
+ * // => [2, 0]
+ */
+ function propertyOf(object) {
+ return function(path) {
+ return baseGet(object, toPath(path), path + '');
+ };
+ }
+
+ /**
+ * Creates an array of numbers (positive and/or negative) progressing from
+ * `start` up to, but not including, `end`. If `end` is not specified it is
+ * set to `start` with `start` then set to `0`. If `end` is less than `start`
+ * a zero-length range is created unless a negative `step` is specified.
+ *
+ * @static
+ * @memberOf _
+ * @category Utility
+ * @param {number} [start=0] The start of the range.
+ * @param {number} end The end of the range.
+ * @param {number} [step=1] The value to increment or decrement by.
+ * @returns {Array} Returns the new array of numbers.
+ * @example
+ *
+ * _.range(4);
+ * // => [0, 1, 2, 3]
+ *
+ * _.range(1, 5);
+ * // => [1, 2, 3, 4]
+ *
+ * _.range(0, 20, 5);
+ * // => [0, 5, 10, 15]
+ *
+ * _.range(0, -4, -1);
+ * // => [0, -1, -2, -3]
+ *
+ * _.range(1, 4, 0);
+ * // => [1, 1, 1]
+ *
+ * _.range(0);
+ * // => []
+ */
+ function range(start, end, step) {
+ if (step && isIterateeCall(start, end, step)) {
+ end = step = undefined;
+ }
+ start = +start || 0;
+ step = step == null ? 1 : (+step || 0);
+
+ if (end == null) {
+ end = start;
+ start = 0;
+ } else {
+ end = +end || 0;
+ }
+ // Use `Array(length)` so engines like Chakra and V8 avoid slower modes.
+ // See https://youtu.be/XAqIpGU8ZZk#t=17m25s for more details.
+ var index = -1,
+ length = nativeMax(nativeCeil((end - start) / (step || 1)), 0),
+ result = Array(length);
+
+ while (++index < length) {
+ result[index] = start;
+ start += step;
+ }
+ return result;
+ }
+
+ /**
+ * Invokes the iteratee function `n` times, returning an array of the results
+ * of each invocation. The `iteratee` is bound to `thisArg` and invoked with
+ * one argument; (index).
+ *
+ * @static
+ * @memberOf _
+ * @category Utility
+ * @param {number} n The number of times to invoke `iteratee`.
+ * @param {Function} [iteratee=_.identity] The function invoked per iteration.
+ * @param {*} [thisArg] The `this` binding of `iteratee`.
+ * @returns {Array} Returns the array of results.
+ * @example
+ *
+ * var diceRolls = _.times(3, _.partial(_.random, 1, 6, false));
+ * // => [3, 6, 4]
+ *
+ * _.times(3, function(n) {
+ * mage.castSpell(n);
+ * });
+ * // => invokes `mage.castSpell(n)` three times with `n` of `0`, `1`, and `2`
+ *
+ * _.times(3, function(n) {
+ * this.cast(n);
+ * }, mage);
+ * // => also invokes `mage.castSpell(n)` three times
+ */
+ function times(n, iteratee, thisArg) {
+ n = nativeFloor(n);
+
+ // Exit early to avoid a JSC JIT bug in Safari 8
+ // where `Array(0)` is treated as `Array(1)`.
+ if (n < 1 || !nativeIsFinite(n)) {
+ return [];
+ }
+ var index = -1,
+ result = Array(nativeMin(n, MAX_ARRAY_LENGTH));
+
+ iteratee = bindCallback(iteratee, thisArg, 1);
+ while (++index < n) {
+ if (index < MAX_ARRAY_LENGTH) {
+ result[index] = iteratee(index);
+ } else {
+ iteratee(index);
+ }
+ }
+ return result;
+ }
+
+ /**
+ * Generates a unique ID. If `prefix` is provided the ID is appended to it.
+ *
+ * @static
+ * @memberOf _
+ * @category Utility
+ * @param {string} [prefix] The value to prefix the ID with.
+ * @returns {string} Returns the unique ID.
+ * @example
+ *
+ * _.uniqueId('contact_');
+ * // => 'contact_104'
+ *
+ * _.uniqueId();
+ * // => '105'
+ */
+ function uniqueId(prefix) {
+ var id = ++idCounter;
+ return baseToString(prefix) + id;
+ }
+
+ /*------------------------------------------------------------------------*/
+
+ /**
+ * Adds two numbers.
+ *
+ * @static
+ * @memberOf _
+ * @category Math
+ * @param {number} augend The first number to add.
+ * @param {number} addend The second number to add.
+ * @returns {number} Returns the sum.
+ * @example
+ *
+ * _.add(6, 4);
+ * // => 10
+ */
+ function add(augend, addend) {
+ return (+augend || 0) + (+addend || 0);
+ }
+
+ /**
+ * Calculates `n` rounded up to `precision`.
+ *
+ * @static
+ * @memberOf _
+ * @category Math
+ * @param {number} n The number to round up.
+ * @param {number} [precision=0] The precision to round up to.
+ * @returns {number} Returns the rounded up number.
+ * @example
+ *
+ * _.ceil(4.006);
+ * // => 5
+ *
+ * _.ceil(6.004, 2);
+ * // => 6.01
+ *
+ * _.ceil(6040, -2);
+ * // => 6100
+ */
+ var ceil = createRound('ceil');
+
+ /**
+ * Calculates `n` rounded down to `precision`.
+ *
+ * @static
+ * @memberOf _
+ * @category Math
+ * @param {number} n The number to round down.
+ * @param {number} [precision=0] The precision to round down to.
+ * @returns {number} Returns the rounded down number.
+ * @example
+ *
+ * _.floor(4.006);
+ * // => 4
+ *
+ * _.floor(0.046, 2);
+ * // => 0.04
+ *
+ * _.floor(4060, -2);
+ * // => 4000
+ */
+ var floor = createRound('floor');
+
+ /**
+ * Gets the maximum value of `collection`. If `collection` is empty or falsey
+ * `-Infinity` is returned. If an iteratee function is provided it is invoked
+ * for each value in `collection` to generate the criterion by which the value
+ * is ranked. The `iteratee` is bound to `thisArg` and invoked with three
+ * arguments: (value, index, collection).
+ *
+ * If a property name is provided for `iteratee` the created `_.property`
+ * style callback returns the property value of the given element.
+ *
+ * If a value is also provided for `thisArg` the created `_.matchesProperty`
+ * style callback returns `true` for elements that have a matching property
+ * value, else `false`.
+ *
+ * If an object is provided for `iteratee` the created `_.matches` style
+ * callback returns `true` for elements that have the properties of the given
+ * object, else `false`.
+ *
+ * @static
+ * @memberOf _
+ * @category Math
+ * @param {Array|Object|string} collection The collection to iterate over.
+ * @param {Function|Object|string} [iteratee] The function invoked per iteration.
+ * @param {*} [thisArg] The `this` binding of `iteratee`.
+ * @returns {*} Returns the maximum value.
+ * @example
+ *
+ * _.max([4, 2, 8, 6]);
+ * // => 8
+ *
+ * _.max([]);
+ * // => -Infinity
+ *
+ * var users = [
+ * { 'user': 'barney', 'age': 36 },
+ * { 'user': 'fred', 'age': 40 }
+ * ];
+ *
+ * _.max(users, function(chr) {
+ * return chr.age;
+ * });
+ * // => { 'user': 'fred', 'age': 40 }
+ *
+ * // using the `_.property` callback shorthand
+ * _.max(users, 'age');
+ * // => { 'user': 'fred', 'age': 40 }
+ */
+ var max = createExtremum(gt, NEGATIVE_INFINITY);
+
+ /**
+ * Gets the minimum value of `collection`. If `collection` is empty or falsey
+ * `Infinity` is returned. If an iteratee function is provided it is invoked
+ * for each value in `collection` to generate the criterion by which the value
+ * is ranked. The `iteratee` is bound to `thisArg` and invoked with three
+ * arguments: (value, index, collection).
+ *
+ * If a property name is provided for `iteratee` the created `_.property`
+ * style callback returns the property value of the given element.
+ *
+ * If a value is also provided for `thisArg` the created `_.matchesProperty`
+ * style callback returns `true` for elements that have a matching property
+ * value, else `false`.
+ *
+ * If an object is provided for `iteratee` the created `_.matches` style
+ * callback returns `true` for elements that have the properties of the given
+ * object, else `false`.
+ *
+ * @static
+ * @memberOf _
+ * @category Math
+ * @param {Array|Object|string} collection The collection to iterate over.
+ * @param {Function|Object|string} [iteratee] The function invoked per iteration.
+ * @param {*} [thisArg] The `this` binding of `iteratee`.
+ * @returns {*} Returns the minimum value.
+ * @example
+ *
+ * _.min([4, 2, 8, 6]);
+ * // => 2
+ *
+ * _.min([]);
+ * // => Infinity
+ *
+ * var users = [
+ * { 'user': 'barney', 'age': 36 },
+ * { 'user': 'fred', 'age': 40 }
+ * ];
+ *
+ * _.min(users, function(chr) {
+ * return chr.age;
+ * });
+ * // => { 'user': 'barney', 'age': 36 }
+ *
+ * // using the `_.property` callback shorthand
+ * _.min(users, 'age');
+ * // => { 'user': 'barney', 'age': 36 }
+ */
+ var min = createExtremum(lt, POSITIVE_INFINITY);
+
+ /**
+ * Calculates `n` rounded to `precision`.
+ *
+ * @static
+ * @memberOf _
+ * @category Math
+ * @param {number} n The number to round.
+ * @param {number} [precision=0] The precision to round to.
+ * @returns {number} Returns the rounded number.
+ * @example
+ *
+ * _.round(4.006);
+ * // => 4
+ *
+ * _.round(4.006, 2);
+ * // => 4.01
+ *
+ * _.round(4060, -2);
+ * // => 4100
+ */
+ var round = createRound('round');
+
+ /**
+ * Gets the sum of the values in `collection`.
+ *
+ * @static
+ * @memberOf _
+ * @category Math
+ * @param {Array|Object|string} collection The collection to iterate over.
+ * @param {Function|Object|string} [iteratee] The function invoked per iteration.
+ * @param {*} [thisArg] The `this` binding of `iteratee`.
+ * @returns {number} Returns the sum.
+ * @example
+ *
+ * _.sum([4, 6]);
+ * // => 10
+ *
+ * _.sum({ 'a': 4, 'b': 6 });
+ * // => 10
+ *
+ * var objects = [
+ * { 'n': 4 },
+ * { 'n': 6 }
+ * ];
+ *
+ * _.sum(objects, function(object) {
+ * return object.n;
+ * });
+ * // => 10
+ *
+ * // using the `_.property` callback shorthand
+ * _.sum(objects, 'n');
+ * // => 10
+ */
+ function sum(collection, iteratee, thisArg) {
+ if (thisArg && isIterateeCall(collection, iteratee, thisArg)) {
+ iteratee = undefined;
+ }
+ iteratee = getCallback(iteratee, thisArg, 3);
+ return iteratee.length == 1
+ ? arraySum(isArray(collection) ? collection : toIterable(collection), iteratee)
+ : baseSum(collection, iteratee);
+ }
+
+ /*------------------------------------------------------------------------*/
+
+ // Ensure wrappers are instances of `baseLodash`.
+ lodash.prototype = baseLodash.prototype;
+
+ LodashWrapper.prototype = baseCreate(baseLodash.prototype);
+ LodashWrapper.prototype.constructor = LodashWrapper;
+
+ LazyWrapper.prototype = baseCreate(baseLodash.prototype);
+ LazyWrapper.prototype.constructor = LazyWrapper;
+
+ // Add functions to the `Map` cache.
+ MapCache.prototype['delete'] = mapDelete;
+ MapCache.prototype.get = mapGet;
+ MapCache.prototype.has = mapHas;
+ MapCache.prototype.set = mapSet;
+
+ // Add functions to the `Set` cache.
+ SetCache.prototype.push = cachePush;
+
+ // Assign cache to `_.memoize`.
+ memoize.Cache = MapCache;
+
+ // Add functions that return wrapped values when chaining.
+ lodash.after = after;
+ lodash.ary = ary;
+ lodash.assign = assign;
+ lodash.at = at;
+ lodash.before = before;
+ lodash.bind = bind;
+ lodash.bindAll = bindAll;
+ lodash.bindKey = bindKey;
+ lodash.callback = callback;
+ lodash.chain = chain;
+ lodash.chunk = chunk;
+ lodash.compact = compact;
+ lodash.constant = constant;
+ lodash.countBy = countBy;
+ lodash.create = create;
+ lodash.curry = curry;
+ lodash.curryRight = curryRight;
+ lodash.debounce = debounce;
+ lodash.defaults = defaults;
+ lodash.defaultsDeep = defaultsDeep;
+ lodash.defer = defer;
+ lodash.delay = delay;
+ lodash.difference = difference;
+ lodash.drop = drop;
+ lodash.dropRight = dropRight;
+ lodash.dropRightWhile = dropRightWhile;
+ lodash.dropWhile = dropWhile;
+ lodash.fill = fill;
+ lodash.filter = filter;
+ lodash.flatten = flatten;
+ lodash.flattenDeep = flattenDeep;
+ lodash.flow = flow;
+ lodash.flowRight = flowRight;
+ lodash.forEach = forEach;
+ lodash.forEachRight = forEachRight;
+ lodash.forIn = forIn;
+ lodash.forInRight = forInRight;
+ lodash.forOwn = forOwn;
+ lodash.forOwnRight = forOwnRight;
+ lodash.functions = functions;
+ lodash.groupBy = groupBy;
+ lodash.indexBy = indexBy;
+ lodash.initial = initial;
+ lodash.intersection = intersection;
+ lodash.invert = invert;
+ lodash.invoke = invoke;
+ lodash.keys = keys;
+ lodash.keysIn = keysIn;
+ lodash.map = map;
+ lodash.mapKeys = mapKeys;
+ lodash.mapValues = mapValues;
+ lodash.matches = matches;
+ lodash.matchesProperty = matchesProperty;
+ lodash.memoize = memoize;
+ lodash.merge = merge;
+ lodash.method = method;
+ lodash.methodOf = methodOf;
+ lodash.mixin = mixin;
+ lodash.modArgs = modArgs;
+ lodash.negate = negate;
+ lodash.omit = omit;
+ lodash.once = once;
+ lodash.pairs = pairs;
+ lodash.partial = partial;
+ lodash.partialRight = partialRight;
+ lodash.partition = partition;
+ lodash.pick = pick;
+ lodash.pluck = pluck;
+ lodash.property = property;
+ lodash.propertyOf = propertyOf;
+ lodash.pull = pull;
+ lodash.pullAt = pullAt;
+ lodash.range = range;
+ lodash.rearg = rearg;
+ lodash.reject = reject;
+ lodash.remove = remove;
+ lodash.rest = rest;
+ lodash.restParam = restParam;
+ lodash.set = set;
+ lodash.shuffle = shuffle;
+ lodash.slice = slice;
+ lodash.sortBy = sortBy;
+ lodash.sortByAll = sortByAll;
+ lodash.sortByOrder = sortByOrder;
+ lodash.spread = spread;
+ lodash.take = take;
+ lodash.takeRight = takeRight;
+ lodash.takeRightWhile = takeRightWhile;
+ lodash.takeWhile = takeWhile;
+ lodash.tap = tap;
+ lodash.throttle = throttle;
+ lodash.thru = thru;
+ lodash.times = times;
+ lodash.toArray = toArray;
+ lodash.toPlainObject = toPlainObject;
+ lodash.transform = transform;
+ lodash.union = union;
+ lodash.uniq = uniq;
+ lodash.unzip = unzip;
+ lodash.unzipWith = unzipWith;
+ lodash.values = values;
+ lodash.valuesIn = valuesIn;
+ lodash.where = where;
+ lodash.without = without;
+ lodash.wrap = wrap;
+ lodash.xor = xor;
+ lodash.zip = zip;
+ lodash.zipObject = zipObject;
+ lodash.zipWith = zipWith;
+
+ // Add aliases.
+ lodash.backflow = flowRight;
+ lodash.collect = map;
+ lodash.compose = flowRight;
+ lodash.each = forEach;
+ lodash.eachRight = forEachRight;
+ lodash.extend = assign;
+ lodash.iteratee = callback;
+ lodash.methods = functions;
+ lodash.object = zipObject;
+ lodash.select = filter;
+ lodash.tail = rest;
+ lodash.unique = uniq;
+
+ // Add functions to `lodash.prototype`.
+ mixin(lodash, lodash);
+
+ /*------------------------------------------------------------------------*/
+
+ // Add functions that return unwrapped values when chaining.
+ lodash.add = add;
+ lodash.attempt = attempt;
+ lodash.camelCase = camelCase;
+ lodash.capitalize = capitalize;
+ lodash.ceil = ceil;
+ lodash.clone = clone;
+ lodash.cloneDeep = cloneDeep;
+ lodash.deburr = deburr;
+ lodash.endsWith = endsWith;
+ lodash.escape = escape;
+ lodash.escapeRegExp = escapeRegExp;
+ lodash.every = every;
+ lodash.find = find;
+ lodash.findIndex = findIndex;
+ lodash.findKey = findKey;
+ lodash.findLast = findLast;
+ lodash.findLastIndex = findLastIndex;
+ lodash.findLastKey = findLastKey;
+ lodash.findWhere = findWhere;
+ lodash.first = first;
+ lodash.floor = floor;
+ lodash.get = get;
+ lodash.gt = gt;
+ lodash.gte = gte;
+ lodash.has = has;
+ lodash.identity = identity;
+ lodash.includes = includes;
+ lodash.indexOf = indexOf;
+ lodash.inRange = inRange;
+ lodash.isArguments = isArguments;
+ lodash.isArray = isArray;
+ lodash.isBoolean = isBoolean;
+ lodash.isDate = isDate;
+ lodash.isElement = isElement;
+ lodash.isEmpty = isEmpty;
+ lodash.isEqual = isEqual;
+ lodash.isError = isError;
+ lodash.isFinite = isFinite;
+ lodash.isFunction = isFunction;
+ lodash.isMatch = isMatch;
+ lodash.isNaN = isNaN;
+ lodash.isNative = isNative;
+ lodash.isNull = isNull;
+ lodash.isNumber = isNumber;
+ lodash.isObject = isObject;
+ lodash.isPlainObject = isPlainObject;
+ lodash.isRegExp = isRegExp;
+ lodash.isString = isString;
+ lodash.isTypedArray = isTypedArray;
+ lodash.isUndefined = isUndefined;
+ lodash.kebabCase = kebabCase;
+ lodash.last = last;
+ lodash.lastIndexOf = lastIndexOf;
+ lodash.lt = lt;
+ lodash.lte = lte;
+ lodash.max = max;
+ lodash.min = min;
+ lodash.noConflict = noConflict;
+ lodash.noop = noop;
+ lodash.now = now;
+ lodash.pad = pad;
+ lodash.padLeft = padLeft;
+ lodash.padRight = padRight;
+ lodash.parseInt = parseInt;
+ lodash.random = random;
+ lodash.reduce = reduce;
+ lodash.reduceRight = reduceRight;
+ lodash.repeat = repeat;
+ lodash.result = result;
+ lodash.round = round;
+ lodash.runInContext = runInContext;
+ lodash.size = size;
+ lodash.snakeCase = snakeCase;
+ lodash.some = some;
+ lodash.sortedIndex = sortedIndex;
+ lodash.sortedLastIndex = sortedLastIndex;
+ lodash.startCase = startCase;
+ lodash.startsWith = startsWith;
+ lodash.sum = sum;
+ lodash.template = template;
+ lodash.trim = trim;
+ lodash.trimLeft = trimLeft;
+ lodash.trimRight = trimRight;
+ lodash.trunc = trunc;
+ lodash.unescape = unescape;
+ lodash.uniqueId = uniqueId;
+ lodash.words = words;
+
+ // Add aliases.
+ lodash.all = every;
+ lodash.any = some;
+ lodash.contains = includes;
+ lodash.eq = isEqual;
+ lodash.detect = find;
+ lodash.foldl = reduce;
+ lodash.foldr = reduceRight;
+ lodash.head = first;
+ lodash.include = includes;
+ lodash.inject = reduce;
+
+ mixin(lodash, (function() {
+ var source = {};
+ baseForOwn(lodash, function(func, methodName) {
+ if (!lodash.prototype[methodName]) {
+ source[methodName] = func;
+ }
+ });
+ return source;
+ }()), false);
+
+ /*------------------------------------------------------------------------*/
+
+ // Add functions capable of returning wrapped and unwrapped values when chaining.
+ lodash.sample = sample;
+
+ lodash.prototype.sample = function(n) {
+ if (!this.__chain__ && n == null) {
+ return sample(this.value());
+ }
+ return this.thru(function(value) {
+ return sample(value, n);
+ });
+ };
+
+ /*------------------------------------------------------------------------*/
+
+ /**
+ * The semantic version number.
+ *
+ * @static
+ * @memberOf _
+ * @type string
+ */
+ lodash.VERSION = VERSION;
+
+ // Assign default placeholders.
+ arrayEach(['bind', 'bindKey', 'curry', 'curryRight', 'partial', 'partialRight'], function(methodName) {
+ lodash[methodName].placeholder = lodash;
+ });
+
+ // Add `LazyWrapper` methods for `_.drop` and `_.take` variants.
+ arrayEach(['drop', 'take'], function(methodName, index) {
+ LazyWrapper.prototype[methodName] = function(n) {
+ var filtered = this.__filtered__;
+ if (filtered && !index) {
+ return new LazyWrapper(this);
+ }
+ n = n == null ? 1 : nativeMax(nativeFloor(n) || 0, 0);
+
+ var result = this.clone();
+ if (filtered) {
+ result.__takeCount__ = nativeMin(result.__takeCount__, n);
+ } else {
+ result.__views__.push({ 'size': n, 'type': methodName + (result.__dir__ < 0 ? 'Right' : '') });
+ }
+ return result;
+ };
+
+ LazyWrapper.prototype[methodName + 'Right'] = function(n) {
+ return this.reverse()[methodName](n).reverse();
+ };
+ });
+
+ // Add `LazyWrapper` methods that accept an `iteratee` value.
+ arrayEach(['filter', 'map', 'takeWhile'], function(methodName, index) {
+ var type = index + 1,
+ isFilter = type != LAZY_MAP_FLAG;
+
+ LazyWrapper.prototype[methodName] = function(iteratee, thisArg) {
+ var result = this.clone();
+ result.__iteratees__.push({ 'iteratee': getCallback(iteratee, thisArg, 1), 'type': type });
+ result.__filtered__ = result.__filtered__ || isFilter;
+ return result;
+ };
+ });
+
+ // Add `LazyWrapper` methods for `_.first` and `_.last`.
+ arrayEach(['first', 'last'], function(methodName, index) {
+ var takeName = 'take' + (index ? 'Right' : '');
+
+ LazyWrapper.prototype[methodName] = function() {
+ return this[takeName](1).value()[0];
+ };
+ });
+
+ // Add `LazyWrapper` methods for `_.initial` and `_.rest`.
+ arrayEach(['initial', 'rest'], function(methodName, index) {
+ var dropName = 'drop' + (index ? '' : 'Right');
+
+ LazyWrapper.prototype[methodName] = function() {
+ return this.__filtered__ ? new LazyWrapper(this) : this[dropName](1);
+ };
+ });
+
+ // Add `LazyWrapper` methods for `_.pluck` and `_.where`.
+ arrayEach(['pluck', 'where'], function(methodName, index) {
+ var operationName = index ? 'filter' : 'map',
+ createCallback = index ? baseMatches : property;
+
+ LazyWrapper.prototype[methodName] = function(value) {
+ return this[operationName](createCallback(value));
+ };
+ });
+
+ LazyWrapper.prototype.compact = function() {
+ return this.filter(identity);
+ };
+
+ LazyWrapper.prototype.reject = function(predicate, thisArg) {
+ predicate = getCallback(predicate, thisArg, 1);
+ return this.filter(function(value) {
+ return !predicate(value);
+ });
+ };
+
+ LazyWrapper.prototype.slice = function(start, end) {
+ start = start == null ? 0 : (+start || 0);
+
+ var result = this;
+ if (result.__filtered__ && (start > 0 || end < 0)) {
+ return new LazyWrapper(result);
+ }
+ if (start < 0) {
+ result = result.takeRight(-start);
+ } else if (start) {
+ result = result.drop(start);
+ }
+ if (end !== undefined) {
+ end = (+end || 0);
+ result = end < 0 ? result.dropRight(-end) : result.take(end - start);
+ }
+ return result;
+ };
+
+ LazyWrapper.prototype.takeRightWhile = function(predicate, thisArg) {
+ return this.reverse().takeWhile(predicate, thisArg).reverse();
+ };
+
+ LazyWrapper.prototype.toArray = function() {
+ return this.take(POSITIVE_INFINITY);
+ };
+
+ // Add `LazyWrapper` methods to `lodash.prototype`.
+ baseForOwn(LazyWrapper.prototype, function(func, methodName) {
+ var checkIteratee = /^(?:filter|map|reject)|While$/.test(methodName),
+ retUnwrapped = /^(?:first|last)$/.test(methodName),
+ lodashFunc = lodash[retUnwrapped ? ('take' + (methodName == 'last' ? 'Right' : '')) : methodName];
+
+ if (!lodashFunc) {
+ return;
+ }
+ lodash.prototype[methodName] = function() {
+ var args = retUnwrapped ? [1] : arguments,
+ chainAll = this.__chain__,
+ value = this.__wrapped__,
+ isHybrid = !!this.__actions__.length,
+ isLazy = value instanceof LazyWrapper,
+ iteratee = args[0],
+ useLazy = isLazy || isArray(value);
+
+ if (useLazy && checkIteratee && typeof iteratee == 'function' && iteratee.length != 1) {
+ // Avoid lazy use if the iteratee has a "length" value other than `1`.
+ isLazy = useLazy = false;
+ }
+ var interceptor = function(value) {
+ return (retUnwrapped && chainAll)
+ ? lodashFunc(value, 1)[0]
+ : lodashFunc.apply(undefined, arrayPush([value], args));
+ };
+
+ var action = { 'func': thru, 'args': [interceptor], 'thisArg': undefined },
+ onlyLazy = isLazy && !isHybrid;
+
+ if (retUnwrapped && !chainAll) {
+ if (onlyLazy) {
+ value = value.clone();
+ value.__actions__.push(action);
+ return func.call(value);
+ }
+ return lodashFunc.call(undefined, this.value())[0];
+ }
+ if (!retUnwrapped && useLazy) {
+ value = onlyLazy ? value : new LazyWrapper(this);
+ var result = func.apply(value, args);
+ result.__actions__.push(action);
+ return new LodashWrapper(result, chainAll);
+ }
+ return this.thru(interceptor);
+ };
+ });
+
+ // Add `Array` and `String` methods to `lodash.prototype`.
+ arrayEach(['join', 'pop', 'push', 'replace', 'shift', 'sort', 'splice', 'split', 'unshift'], function(methodName) {
+ var func = (/^(?:replace|split)$/.test(methodName) ? stringProto : arrayProto)[methodName],
+ chainName = /^(?:push|sort|unshift)$/.test(methodName) ? 'tap' : 'thru',
+ retUnwrapped = /^(?:join|pop|replace|shift)$/.test(methodName);
+
+ lodash.prototype[methodName] = function() {
+ var args = arguments;
+ if (retUnwrapped && !this.__chain__) {
+ return func.apply(this.value(), args);
+ }
+ return this[chainName](function(value) {
+ return func.apply(value, args);
+ });
+ };
+ });
+
+ // Map minified function names to their real names.
+ baseForOwn(LazyWrapper.prototype, function(func, methodName) {
+ var lodashFunc = lodash[methodName];
+ if (lodashFunc) {
+ var key = lodashFunc.name,
+ names = realNames[key] || (realNames[key] = []);
+
+ names.push({ 'name': methodName, 'func': lodashFunc });
+ }
+ });
+
+ realNames[createHybridWrapper(undefined, BIND_KEY_FLAG).name] = [{ 'name': 'wrapper', 'func': undefined }];
+
+ // Add functions to the lazy wrapper.
+ LazyWrapper.prototype.clone = lazyClone;
+ LazyWrapper.prototype.reverse = lazyReverse;
+ LazyWrapper.prototype.value = lazyValue;
+
+ // Add chaining functions to the `lodash` wrapper.
+ lodash.prototype.chain = wrapperChain;
+ lodash.prototype.commit = wrapperCommit;
+ lodash.prototype.concat = wrapperConcat;
+ lodash.prototype.plant = wrapperPlant;
+ lodash.prototype.reverse = wrapperReverse;
+ lodash.prototype.toString = wrapperToString;
+ lodash.prototype.run = lodash.prototype.toJSON = lodash.prototype.valueOf = lodash.prototype.value = wrapperValue;
+
+ // Add function aliases to the `lodash` wrapper.
+ lodash.prototype.collect = lodash.prototype.map;
+ lodash.prototype.head = lodash.prototype.first;
+ lodash.prototype.select = lodash.prototype.filter;
+ lodash.prototype.tail = lodash.prototype.rest;
+
+ return lodash;
+ }
+
+ /*--------------------------------------------------------------------------*/
+
+ // Export lodash.
+ var _ = runInContext();
+
+ // Some AMD build optimizers like r.js check for condition patterns like the following:
+ if (typeof define == 'function' && typeof define.amd == 'object' && define.amd) {
+ // Expose lodash to the global object when an AMD loader is present to avoid
+ // errors in cases where lodash is loaded by a script tag and not intended
+ // as an AMD module. See http://requirejs.org/docs/errors.html#mismatch for
+ // more details.
+ root._ = _;
+
+ // Define as an anonymous module so, through path mapping, it can be
+ // referenced as the "underscore" module.
+ define(function() {
+ return _;
+ });
+ }
+ // Check for `exports` after `define` in case a build optimizer adds an `exports` object.
+ else if (freeExports && freeModule) {
+ // Export for Node.js or RingoJS.
+ if (moduleExports) {
+ (freeModule.exports = _)._ = _;
+ }
+ // Export for Rhino with CommonJS support.
+ else {
+ freeExports._ = _;
+ }
+ }
+ else {
+ // Export for a browser or Rhino.
+ root._ = _;
+ }
+}.call(this));
+
+}).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {})
+},{}]},{},[1])(1)
+}); \ No newline at end of file
diff --git a/docs/htmldoc/js/dagre.min.js b/docs/htmldoc/js/dagre.min.js
new file mode 100644
index 0000000..b7a9bbc
--- /dev/null
+++ b/docs/htmldoc/js/dagre.min.js
@@ -0,0 +1,6 @@
+!function(e){if("object"==typeof exports&&"undefined"!=typeof module)module.exports=e();else if("function"==typeof define&&define.amd)define([],e);else{var f;"undefined"!=typeof window?f=window:"undefined"!=typeof global?f=global:"undefined"!=typeof self&&(f=self),f.dagre=e()}}(function(){var define,module,exports;return function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s}({1:[function(require,module,exports){module.exports={graphlib:require("./lib/graphlib"),layout:require("./lib/layout"),debug:require("./lib/debug"),util:{time:require("./lib/util").time,notime:require("./lib/util").notime},version:require("./lib/version")}},{"./lib/debug":6,"./lib/graphlib":7,"./lib/layout":9,"./lib/util":29,"./lib/version":30}],2:[function(require,module,exports){"use strict";var _=require("./lodash"),greedyFAS=require("./greedy-fas");module.exports={run:run,undo:undo};function run(g){var fas=g.graph().acyclicer==="greedy"?greedyFAS(g,weightFn(g)):dfsFAS(g);_.each(fas,function(e){var label=g.edge(e);g.removeEdge(e);label.forwardName=e.name;label.reversed=true;g.setEdge(e.w,e.v,label,_.uniqueId("rev"))});function weightFn(g){return function(e){return g.edge(e).weight}}}function dfsFAS(g){var fas=[],stack={},visited={};function dfs(v){if(_.has(visited,v)){return}visited[v]=true;stack[v]=true;_.each(g.outEdges(v),function(e){if(_.has(stack,e.w)){fas.push(e)}else{dfs(e.w)}});delete stack[v]}_.each(g.nodes(),dfs);return fas}function undo(g){_.each(g.edges(),function(e){var label=g.edge(e);if(label.reversed){g.removeEdge(e);var forwardName=label.forwardName;delete label.reversed;delete label.forwardName;g.setEdge(e.w,e.v,label,forwardName)}})}},{"./greedy-fas":8,"./lodash":10}],3:[function(require,module,exports){var _=require("./lodash"),util=require("./util");module.exports=addBorderSegments;function addBorderSegments(g){function dfs(v){var children=g.children(v),node=g.node(v);if(children.length){_.each(children,dfs)}if(_.has(node,"minRank")){node.borderLeft=[];node.borderRight=[];for(var rank=node.minRank,maxRank=node.maxRank+1;rank<maxRank;++rank){addBorderNode(g,"borderLeft","_bl",v,node,rank);addBorderNode(g,"borderRight","_br",v,node,rank)}}}_.each(g.children(),dfs)}function addBorderNode(g,prop,prefix,sg,sgNode,rank){var label={width:0,height:0,rank:rank,borderType:prop},prev=sgNode[prop][rank-1],curr=util.addDummyNode(g,"border",label,prefix);sgNode[prop][rank]=curr;g.setParent(curr,sg);if(prev){g.setEdge(prev,curr,{weight:1})}}},{"./lodash":10,"./util":29}],4:[function(require,module,exports){"use strict";var _=require("./lodash");module.exports={adjust:adjust,undo:undo};function adjust(g){var rankDir=g.graph().rankdir.toLowerCase();if(rankDir==="lr"||rankDir==="rl"){swapWidthHeight(g)}}function undo(g){var rankDir=g.graph().rankdir.toLowerCase();if(rankDir==="bt"||rankDir==="rl"){reverseY(g)}if(rankDir==="lr"||rankDir==="rl"){swapXY(g);swapWidthHeight(g)}}function swapWidthHeight(g){_.each(g.nodes(),function(v){swapWidthHeightOne(g.node(v))});_.each(g.edges(),function(e){swapWidthHeightOne(g.edge(e))})}function swapWidthHeightOne(attrs){var w=attrs.width;attrs.width=attrs.height;attrs.height=w}function reverseY(g){_.each(g.nodes(),function(v){reverseYOne(g.node(v))});_.each(g.edges(),function(e){var edge=g.edge(e);_.each(edge.points,reverseYOne);if(_.has(edge,"y")){reverseYOne(edge)}})}function reverseYOne(attrs){attrs.y=-attrs.y}function swapXY(g){_.each(g.nodes(),function(v){swapXYOne(g.node(v))});_.each(g.edges(),function(e){var edge=g.edge(e);_.each(edge.points,swapXYOne);if(_.has(edge,"x")){swapXYOne(edge)}})}function swapXYOne(attrs){var x=attrs.x;attrs.x=attrs.y;attrs.y=x}},{"./lodash":10}],5:[function(require,module,exports){module.exports=List;function List(){var sentinel={};sentinel._next=sentinel._prev=sentinel;this._sentinel=sentinel}List.prototype.dequeue=function(){var sentinel=this._sentinel,entry=sentinel._prev;if(entry!==sentinel){unlink(entry);return entry}};List.prototype.enqueue=function(entry){var sentinel=this._sentinel;if(entry._prev&&entry._next){unlink(entry)}entry._next=sentinel._next;sentinel._next._prev=entry;sentinel._next=entry;entry._prev=sentinel};List.prototype.toString=function(){var strs=[],sentinel=this._sentinel,curr=sentinel._prev;while(curr!==sentinel){strs.push(JSON.stringify(curr,filterOutLinks));curr=curr._prev}return"["+strs.join(", ")+"]"};function unlink(entry){entry._prev._next=entry._next;entry._next._prev=entry._prev;delete entry._next;delete entry._prev}function filterOutLinks(k,v){if(k!=="_next"&&k!=="_prev"){return v}}},{}],6:[function(require,module,exports){var _=require("./lodash"),util=require("./util"),Graph=require("./graphlib").Graph;module.exports={debugOrdering:debugOrdering};function debugOrdering(g){var layerMatrix=util.buildLayerMatrix(g);var h=new Graph({compound:true,multigraph:true}).setGraph({});_.each(g.nodes(),function(v){h.setNode(v,{label:v});h.setParent(v,"layer"+g.node(v).rank)});_.each(g.edges(),function(e){h.setEdge(e.v,e.w,{},e.name)});_.each(layerMatrix,function(layer,i){var layerV="layer"+i;h.setNode(layerV,{rank:"same"});_.reduce(layer,function(u,v){h.setEdge(u,v,{style:"invis"});return v})});return h}},{"./graphlib":7,"./lodash":10,"./util":29}],7:[function(require,module,exports){var graphlib;if(typeof require==="function"){try{graphlib=require("graphlib")}catch(e){}}if(!graphlib){graphlib=window.graphlib}module.exports=graphlib},{graphlib:31}],8:[function(require,module,exports){var _=require("./lodash"),Graph=require("./graphlib").Graph,List=require("./data/list");module.exports=greedyFAS;var DEFAULT_WEIGHT_FN=_.constant(1);function greedyFAS(g,weightFn){if(g.nodeCount()<=1){return[]}var state=buildState(g,weightFn||DEFAULT_WEIGHT_FN);var results=doGreedyFAS(state.graph,state.buckets,state.zeroIdx);return _.flatten(_.map(results,function(e){return g.outEdges(e.v,e.w)}),true)}function doGreedyFAS(g,buckets,zeroIdx){var results=[],sources=buckets[buckets.length-1],sinks=buckets[0];var entry;while(g.nodeCount()){while(entry=sinks.dequeue()){removeNode(g,buckets,zeroIdx,entry)}while(entry=sources.dequeue()){removeNode(g,buckets,zeroIdx,entry)}if(g.nodeCount()){for(var i=buckets.length-2;i>0;--i){entry=buckets[i].dequeue();if(entry){results=results.concat(removeNode(g,buckets,zeroIdx,entry,true));break}}}}return results}function removeNode(g,buckets,zeroIdx,entry,collectPredecessors){var results=collectPredecessors?[]:undefined;_.each(g.inEdges(entry.v),function(edge){var weight=g.edge(edge),uEntry=g.node(edge.v);if(collectPredecessors){results.push({v:edge.v,w:edge.w})}uEntry.out-=weight;assignBucket(buckets,zeroIdx,uEntry)});_.each(g.outEdges(entry.v),function(edge){var weight=g.edge(edge),w=edge.w,wEntry=g.node(w);wEntry["in"]-=weight;assignBucket(buckets,zeroIdx,wEntry)});g.removeNode(entry.v);return results}function buildState(g,weightFn){var fasGraph=new Graph,maxIn=0,maxOut=0;_.each(g.nodes(),function(v){fasGraph.setNode(v,{v:v,"in":0,out:0})});_.each(g.edges(),function(e){var prevWeight=fasGraph.edge(e.v,e.w)||0,weight=weightFn(e),edgeWeight=prevWeight+weight;fasGraph.setEdge(e.v,e.w,edgeWeight);maxOut=Math.max(maxOut,fasGraph.node(e.v).out+=weight);maxIn=Math.max(maxIn,fasGraph.node(e.w)["in"]+=weight)});var buckets=_.range(maxOut+maxIn+3).map(function(){return new List});var zeroIdx=maxIn+1;_.each(fasGraph.nodes(),function(v){assignBucket(buckets,zeroIdx,fasGraph.node(v))});return{graph:fasGraph,buckets:buckets,zeroIdx:zeroIdx}}function assignBucket(buckets,zeroIdx,entry){if(!entry.out){buckets[0].enqueue(entry)}else if(!entry["in"]){buckets[buckets.length-1].enqueue(entry)}else{buckets[entry.out-entry["in"]+zeroIdx].enqueue(entry)}}},{"./data/list":5,"./graphlib":7,"./lodash":10}],9:[function(require,module,exports){"use strict";var _=require("./lodash"),acyclic=require("./acyclic"),normalize=require("./normalize"),rank=require("./rank"),normalizeRanks=require("./util").normalizeRanks,parentDummyChains=require("./parent-dummy-chains"),removeEmptyRanks=require("./util").removeEmptyRanks,nestingGraph=require("./nesting-graph"),addBorderSegments=require("./add-border-segments"),coordinateSystem=require("./coordinate-system"),order=require("./order"),position=require("./position"),util=require("./util"),Graph=require("./graphlib").Graph;module.exports=layout;function layout(g,opts){var time=opts&&opts.debugTiming?util.time:util.notime;time("layout",function(){var layoutGraph=time(" buildLayoutGraph",function(){return buildLayoutGraph(g)});time(" runLayout",function(){runLayout(layoutGraph,time)});time(" updateInputGraph",function(){updateInputGraph(g,layoutGraph)})})}function runLayout(g,time){time(" makeSpaceForEdgeLabels",function(){makeSpaceForEdgeLabels(g)});time(" removeSelfEdges",function(){removeSelfEdges(g)});time(" acyclic",function(){acyclic.run(g)});time(" nestingGraph.run",function(){nestingGraph.run(g)});time(" rank",function(){rank(util.asNonCompoundGraph(g))});time(" injectEdgeLabelProxies",function(){injectEdgeLabelProxies(g)});time(" removeEmptyRanks",function(){removeEmptyRanks(g)});time(" nestingGraph.cleanup",function(){nestingGraph.cleanup(g)});time(" normalizeRanks",function(){normalizeRanks(g)});time(" assignRankMinMax",function(){assignRankMinMax(g)});time(" removeEdgeLabelProxies",function(){removeEdgeLabelProxies(g)});time(" normalize.run",function(){normalize.run(g)});time(" parentDummyChains",function(){parentDummyChains(g)});time(" addBorderSegments",function(){addBorderSegments(g)});time(" order",function(){order(g)});time(" insertSelfEdges",function(){insertSelfEdges(g)});time(" adjustCoordinateSystem",function(){coordinateSystem.adjust(g)});time(" position",function(){position(g)});time(" positionSelfEdges",function(){positionSelfEdges(g)});time(" removeBorderNodes",function(){removeBorderNodes(g)});time(" normalize.undo",function(){normalize.undo(g)});time(" fixupEdgeLabelCoords",function(){fixupEdgeLabelCoords(g)});time(" undoCoordinateSystem",function(){coordinateSystem.undo(g)});time(" translateGraph",function(){translateGraph(g)});time(" assignNodeIntersects",function(){assignNodeIntersects(g)});time(" reversePoints",function(){reversePointsForReversedEdges(g)});time(" acyclic.undo",function(){acyclic.undo(g)})}function updateInputGraph(inputGraph,layoutGraph){_.each(inputGraph.nodes(),function(v){var inputLabel=inputGraph.node(v),layoutLabel=layoutGraph.node(v);if(inputLabel){inputLabel.x=layoutLabel.x;inputLabel.y=layoutLabel.y;if(layoutGraph.children(v).length){inputLabel.width=layoutLabel.width;inputLabel.height=layoutLabel.height}}});_.each(inputGraph.edges(),function(e){var inputLabel=inputGraph.edge(e),layoutLabel=layoutGraph.edge(e);inputLabel.points=layoutLabel.points;if(_.has(layoutLabel,"x")){inputLabel.x=layoutLabel.x;inputLabel.y=layoutLabel.y}});inputGraph.graph().width=layoutGraph.graph().width;inputGraph.graph().height=layoutGraph.graph().height}var graphNumAttrs=["nodesep","edgesep","ranksep","marginx","marginy"],graphDefaults={ranksep:50,edgesep:20,nodesep:50,rankdir:"tb"},graphAttrs=["acyclicer","ranker","rankdir","align"],nodeNumAttrs=["width","height"],nodeDefaults={width:0,height:0},edgeNumAttrs=["minlen","weight","width","height","labeloffset"],edgeDefaults={minlen:1,weight:1,width:0,height:0,labeloffset:10,labelpos:"r"},edgeAttrs=["labelpos"];function buildLayoutGraph(inputGraph){var g=new Graph({multigraph:true,compound:true}),graph=canonicalize(inputGraph.graph());g.setGraph(_.merge({},graphDefaults,selectNumberAttrs(graph,graphNumAttrs),_.pick(graph,graphAttrs)));_.each(inputGraph.nodes(),function(v){var node=canonicalize(inputGraph.node(v));g.setNode(v,_.defaults(selectNumberAttrs(node,nodeNumAttrs),nodeDefaults));g.setParent(v,inputGraph.parent(v))});_.each(inputGraph.edges(),function(e){var edge=canonicalize(inputGraph.edge(e));g.setEdge(e,_.merge({},edgeDefaults,selectNumberAttrs(edge,edgeNumAttrs),_.pick(edge,edgeAttrs)))});return g}function makeSpaceForEdgeLabels(g){var graph=g.graph();graph.ranksep/=2;_.each(g.edges(),function(e){var edge=g.edge(e);edge.minlen*=2;if(edge.labelpos.toLowerCase()!=="c"){if(graph.rankdir==="TB"||graph.rankdir==="BT"){edge.width+=edge.labeloffset}else{edge.height+=edge.labeloffset}}})}function injectEdgeLabelProxies(g){_.each(g.edges(),function(e){var edge=g.edge(e);if(edge.width&&edge.height){var v=g.node(e.v),w=g.node(e.w),label={rank:(w.rank-v.rank)/2+v.rank,e:e};util.addDummyNode(g,"edge-proxy",label,"_ep")}})}function assignRankMinMax(g){var maxRank=0;_.each(g.nodes(),function(v){var node=g.node(v);if(node.borderTop){node.minRank=g.node(node.borderTop).rank;node.maxRank=g.node(node.borderBottom).rank;maxRank=_.max(maxRank,node.maxRank)}});g.graph().maxRank=maxRank}function removeEdgeLabelProxies(g){_.each(g.nodes(),function(v){var node=g.node(v);if(node.dummy==="edge-proxy"){g.edge(node.e).labelRank=node.rank;g.removeNode(v)}})}function translateGraph(g){var minX=Number.POSITIVE_INFINITY,maxX=0,minY=Number.POSITIVE_INFINITY,maxY=0,graphLabel=g.graph(),marginX=graphLabel.marginx||0,marginY=graphLabel.marginy||0;function getExtremes(attrs){var x=attrs.x,y=attrs.y,w=attrs.width,h=attrs.height;minX=Math.min(minX,x-w/2);maxX=Math.max(maxX,x+w/2);minY=Math.min(minY,y-h/2);maxY=Math.max(maxY,y+h/2)}_.each(g.nodes(),function(v){getExtremes(g.node(v))});_.each(g.edges(),function(e){var edge=g.edge(e);if(_.has(edge,"x")){getExtremes(edge)}});minX-=marginX;minY-=marginY;_.each(g.nodes(),function(v){var node=g.node(v);node.x-=minX;node.y-=minY});_.each(g.edges(),function(e){var edge=g.edge(e);_.each(edge.points,function(p){p.x-=minX;p.y-=minY});if(_.has(edge,"x")){edge.x-=minX}if(_.has(edge,"y")){edge.y-=minY}});graphLabel.width=maxX-minX+marginX;graphLabel.height=maxY-minY+marginY}function assignNodeIntersects(g){_.each(g.edges(),function(e){var edge=g.edge(e),nodeV=g.node(e.v),nodeW=g.node(e.w),p1,p2;if(!edge.points){edge.points=[];p1=nodeW;p2=nodeV}else{p1=edge.points[0];p2=edge.points[edge.points.length-1]}edge.points.unshift(util.intersectRect(nodeV,p1));edge.points.push(util.intersectRect(nodeW,p2))})}function fixupEdgeLabelCoords(g){_.each(g.edges(),function(e){var edge=g.edge(e);if(_.has(edge,"x")){if(edge.labelpos==="l"||edge.labelpos==="r"){edge.width-=edge.labeloffset}switch(edge.labelpos){case"l":edge.x-=edge.width/2+edge.labeloffset;break;case"r":edge.x+=edge.width/2+edge.labeloffset;break}}})}function reversePointsForReversedEdges(g){_.each(g.edges(),function(e){var edge=g.edge(e);if(edge.reversed){edge.points.reverse()}})}function removeBorderNodes(g){_.each(g.nodes(),function(v){if(g.children(v).length){var node=g.node(v),t=g.node(node.borderTop),b=g.node(node.borderBottom),l=g.node(_.last(node.borderLeft)),r=g.node(_.last(node.borderRight));node.width=Math.abs(r.x-l.x);node.height=Math.abs(b.y-t.y);node.x=l.x+node.width/2;node.y=t.y+node.height/2}});_.each(g.nodes(),function(v){if(g.node(v).dummy==="border"){g.removeNode(v)}})}function removeSelfEdges(g){_.each(g.edges(),function(e){if(e.v===e.w){var node=g.node(e.v);if(!node.selfEdges){node.selfEdges=[]}node.selfEdges.push({e:e,label:g.edge(e)});g.removeEdge(e)}})}function insertSelfEdges(g){var layers=util.buildLayerMatrix(g);_.each(layers,function(layer){var orderShift=0;_.each(layer,function(v,i){var node=g.node(v);node.order=i+orderShift;_.each(node.selfEdges,function(selfEdge){util.addDummyNode(g,"selfedge",{width:selfEdge.label.width,height:selfEdge.label.height,rank:node.rank,order:i+ ++orderShift,e:selfEdge.e,label:selfEdge.label},"_se")});delete node.selfEdges})})}function positionSelfEdges(g){_.each(g.nodes(),function(v){var node=g.node(v);if(node.dummy==="selfedge"){var selfNode=g.node(node.e.v),x=selfNode.x+selfNode.width/2,y=selfNode.y,dx=node.x-x,dy=selfNode.height/2;g.setEdge(node.e,node.label);g.removeNode(v);node.label.points=[{x:x+2*dx/3,y:y-dy},{x:x+5*dx/6,y:y-dy},{x:x+dx,y:y},{x:x+5*dx/6,y:y+dy},{x:x+2*dx/3,y:y+dy}];node.label.x=node.x;node.label.y=node.y}})}function selectNumberAttrs(obj,attrs){return _.mapValues(_.pick(obj,attrs),Number)}function canonicalize(attrs){var newAttrs={};_.each(attrs,function(v,k){newAttrs[k.toLowerCase()]=v});return newAttrs}},{"./acyclic":2,"./add-border-segments":3,"./coordinate-system":4,"./graphlib":7,"./lodash":10,"./nesting-graph":11,"./normalize":12,"./order":17,"./parent-dummy-chains":22,"./position":24,"./rank":26,"./util":29}],10:[function(require,module,exports){var lodash;if(typeof require==="function"){try{lodash=require("lodash")}catch(e){}}if(!lodash){lodash=window._}module.exports=lodash},{lodash:51}],11:[function(require,module,exports){var _=require("./lodash"),util=require("./util");module.exports={run:run,cleanup:cleanup};function run(g){var root=util.addDummyNode(g,"root",{},"_root"),depths=treeDepths(g),height=_.max(depths)-1,nodeSep=2*height+1;g.graph().nestingRoot=root;_.each(g.edges(),function(e){g.edge(e).minlen*=nodeSep});var weight=sumWeights(g)+1;_.each(g.children(),function(child){dfs(g,root,nodeSep,weight,height,depths,child)});g.graph().nodeRankFactor=nodeSep}function dfs(g,root,nodeSep,weight,height,depths,v){var children=g.children(v);if(!children.length){if(v!==root){g.setEdge(root,v,{weight:0,minlen:nodeSep})}return}var top=util.addBorderNode(g,"_bt"),bottom=util.addBorderNode(g,"_bb"),label=g.node(v);g.setParent(top,v);label.borderTop=top;g.setParent(bottom,v);label.borderBottom=bottom;_.each(children,function(child){dfs(g,root,nodeSep,weight,height,depths,child);var childNode=g.node(child),childTop=childNode.borderTop?childNode.borderTop:child,childBottom=childNode.borderBottom?childNode.borderBottom:child,thisWeight=childNode.borderTop?weight:2*weight,minlen=childTop!==childBottom?1:height-depths[v]+1;g.setEdge(top,childTop,{weight:thisWeight,minlen:minlen,nestingEdge:true});g.setEdge(childBottom,bottom,{weight:thisWeight,minlen:minlen,nestingEdge:true})});if(!g.parent(v)){g.setEdge(root,top,{weight:0,minlen:height+depths[v]})}}function treeDepths(g){var depths={};function dfs(v,depth){var children=g.children(v);if(children&&children.length){_.each(children,function(child){dfs(child,depth+1)})}depths[v]=depth}_.each(g.children(),function(v){dfs(v,1)});return depths}function sumWeights(g){return _.reduce(g.edges(),function(acc,e){return acc+g.edge(e).weight},0)}function cleanup(g){var graphLabel=g.graph();g.removeNode(graphLabel.nestingRoot);delete graphLabel.nestingRoot;_.each(g.edges(),function(e){var edge=g.edge(e);if(edge.nestingEdge){g.removeEdge(e)}})}},{"./lodash":10,"./util":29}],12:[function(require,module,exports){"use strict";var _=require("./lodash"),util=require("./util");module.exports={run:run,undo:undo};function run(g){g.graph().dummyChains=[];_.each(g.edges(),function(edge){normalizeEdge(g,edge)})}function normalizeEdge(g,e){var v=e.v,vRank=g.node(v).rank,w=e.w,wRank=g.node(w).rank,name=e.name,edgeLabel=g.edge(e),labelRank=edgeLabel.labelRank;if(wRank===vRank+1)return;g.removeEdge(e);var dummy,attrs,i;for(i=0,++vRank;vRank<wRank;++i,++vRank){edgeLabel.points=[];attrs={width:0,height:0,edgeLabel:edgeLabel,edgeObj:e,rank:vRank};dummy=util.addDummyNode(g,"edge",attrs,"_d");if(vRank===labelRank){attrs.width=edgeLabel.width;attrs.height=edgeLabel.height;attrs.dummy="edge-label";attrs.labelpos=edgeLabel.labelpos}g.setEdge(v,dummy,{weight:edgeLabel.weight},name);if(i===0){g.graph().dummyChains.push(dummy)}v=dummy}g.setEdge(v,w,{weight:edgeLabel.weight},name)}function undo(g){_.each(g.graph().dummyChains,function(v){var node=g.node(v),origLabel=node.edgeLabel,w;g.setEdge(node.edgeObj,origLabel);while(node.dummy){w=g.successors(v)[0];g.removeNode(v);origLabel.points.push({x:node.x,y:node.y});if(node.dummy==="edge-label"){origLabel.x=node.x;origLabel.y=node.y;origLabel.width=node.width;origLabel.height=node.height}v=w;node=g.node(v)}})}},{"./lodash":10,"./util":29}],13:[function(require,module,exports){var _=require("../lodash");module.exports=addSubgraphConstraints;function addSubgraphConstraints(g,cg,vs){var prev={},rootPrev;_.each(vs,function(v){var child=g.parent(v),parent,prevChild;while(child){parent=g.parent(child);if(parent){prevChild=prev[parent];prev[parent]=child}else{prevChild=rootPrev;rootPrev=child}if(prevChild&&prevChild!==child){cg.setEdge(prevChild,child);return}child=parent}})}},{"../lodash":10}],14:[function(require,module,exports){var _=require("../lodash");module.exports=barycenter;function barycenter(g,movable){return _.map(movable,function(v){var inV=g.inEdges(v);if(!inV.length){return{v:v}}else{var result=_.reduce(inV,function(acc,e){var edge=g.edge(e),nodeU=g.node(e.v);return{sum:acc.sum+edge.weight*nodeU.order,weight:acc.weight+edge.weight}},{sum:0,weight:0});return{v:v,barycenter:result.sum/result.weight,weight:result.weight}}})}},{"../lodash":10}],15:[function(require,module,exports){var _=require("../lodash"),Graph=require("../graphlib").Graph;module.exports=buildLayerGraph;function buildLayerGraph(g,rank,relationship){var root=createRootNode(g),result=new Graph({compound:true}).setGraph({root:root}).setDefaultNodeLabel(function(v){return g.node(v)});_.each(g.nodes(),function(v){var node=g.node(v),parent=g.parent(v);if(node.rank===rank||node.minRank<=rank&&rank<=node.maxRank){result.setNode(v);result.setParent(v,parent||root);_.each(g[relationship](v),function(e){var u=e.v===v?e.w:e.v,edge=result.edge(u,v),weight=!_.isUndefined(edge)?edge.weight:0;result.setEdge(u,v,{weight:g.edge(e).weight+weight})});if(_.has(node,"minRank")){result.setNode(v,{borderLeft:node.borderLeft[rank],borderRight:node.borderRight[rank]})}}});return result}function createRootNode(g){var v;while(g.hasNode(v=_.uniqueId("_root")));return v}},{"../graphlib":7,"../lodash":10}],16:[function(require,module,exports){"use strict";var _=require("../lodash");module.exports=crossCount;function crossCount(g,layering){var cc=0;for(var i=1;i<layering.length;++i){cc+=twoLayerCrossCount(g,layering[i-1],layering[i])}return cc}function twoLayerCrossCount(g,northLayer,southLayer){var southPos=_.zipObject(southLayer,_.map(southLayer,function(v,i){return i}));var southEntries=_.flatten(_.map(northLayer,function(v){return _.chain(g.outEdges(v)).map(function(e){return{pos:southPos[e.w],weight:g.edge(e).weight}}).sortBy("pos").value()}),true);var firstIndex=1;while(firstIndex<southLayer.length)firstIndex<<=1;var treeSize=2*firstIndex-1;firstIndex-=1;var tree=_.map(new Array(treeSize),function(){return 0});var cc=0;_.each(southEntries.forEach(function(entry){var index=entry.pos+firstIndex;tree[index]+=entry.weight;var weightSum=0;while(index>0){if(index%2){weightSum+=tree[index+1]}index=index-1>>1;tree[index]+=entry.weight}cc+=entry.weight*weightSum}));return cc}},{"../lodash":10}],17:[function(require,module,exports){"use strict";var _=require("../lodash"),initOrder=require("./init-order"),crossCount=require("./cross-count"),sortSubgraph=require("./sort-subgraph"),buildLayerGraph=require("./build-layer-graph"),addSubgraphConstraints=require("./add-subgraph-constraints"),Graph=require("../graphlib").Graph,util=require("../util");module.exports=order;function order(g){var maxRank=util.maxRank(g),downLayerGraphs=buildLayerGraphs(g,_.range(1,maxRank+1),"inEdges"),upLayerGraphs=buildLayerGraphs(g,_.range(maxRank-1,-1,-1),"outEdges");var layering=initOrder(g);assignOrder(g,layering);var bestCC=Number.POSITIVE_INFINITY,best;for(var i=0,lastBest=0;lastBest<4;++i,++lastBest){sweepLayerGraphs(i%2?downLayerGraphs:upLayerGraphs,i%4>=2);layering=util.buildLayerMatrix(g);var cc=crossCount(g,layering);if(cc<bestCC){lastBest=0;best=_.cloneDeep(layering);bestCC=cc}}assignOrder(g,best)}function buildLayerGraphs(g,ranks,relationship){return _.map(ranks,function(rank){return buildLayerGraph(g,rank,relationship)})}function sweepLayerGraphs(layerGraphs,biasRight){var cg=new Graph;_.each(layerGraphs,function(lg){var root=lg.graph().root;var sorted=sortSubgraph(lg,root,cg,biasRight);_.each(sorted.vs,function(v,i){lg.node(v).order=i});addSubgraphConstraints(lg,cg,sorted.vs)})}function assignOrder(g,layering){_.each(layering,function(layer){_.each(layer,function(v,i){g.node(v).order=i})})}},{"../graphlib":7,"../lodash":10,"../util":29,"./add-subgraph-constraints":13,"./build-layer-graph":15,"./cross-count":16,"./init-order":18,"./sort-subgraph":20}],18:[function(require,module,exports){"use strict";var _=require("../lodash");module.exports=initOrder;function initOrder(g){var visited={},simpleNodes=_.filter(g.nodes(),function(v){return!g.children(v).length}),maxRank=_.max(_.map(simpleNodes,function(v){return g.node(v).rank})),layers=_.map(_.range(maxRank+1),function(){return[]});function dfs(v){if(_.has(visited,v))return;visited[v]=true;var node=g.node(v);layers[node.rank].push(v);_.each(g.successors(v),dfs)}var orderedVs=_.sortBy(simpleNodes,function(v){return g.node(v).rank});_.each(orderedVs,dfs);return layers}},{"../lodash":10}],19:[function(require,module,exports){"use strict";var _=require("../lodash");module.exports=resolveConflicts;function resolveConflicts(entries,cg){var mappedEntries={};_.each(entries,function(entry,i){var tmp=mappedEntries[entry.v]={indegree:0,"in":[],out:[],vs:[entry.v],i:i};if(!_.isUndefined(entry.barycenter)){tmp.barycenter=entry.barycenter;tmp.weight=entry.weight}});_.each(cg.edges(),function(e){var entryV=mappedEntries[e.v],entryW=mappedEntries[e.w];if(!_.isUndefined(entryV)&&!_.isUndefined(entryW)){entryW.indegree++;entryV.out.push(mappedEntries[e.w])}});var sourceSet=_.filter(mappedEntries,function(entry){return!entry.indegree});return doResolveConflicts(sourceSet)}function doResolveConflicts(sourceSet){var entries=[];function handleIn(vEntry){return function(uEntry){if(uEntry.merged){return}if(_.isUndefined(uEntry.barycenter)||_.isUndefined(vEntry.barycenter)||uEntry.barycenter>=vEntry.barycenter){mergeEntries(vEntry,uEntry)}}}function handleOut(vEntry){return function(wEntry){wEntry["in"].push(vEntry);if(--wEntry.indegree===0){sourceSet.push(wEntry)}}}while(sourceSet.length){var entry=sourceSet.pop();entries.push(entry);_.each(entry["in"].reverse(),handleIn(entry));_.each(entry.out,handleOut(entry))}return _.chain(entries).filter(function(entry){return!entry.merged}).map(function(entry){return _.pick(entry,["vs","i","barycenter","weight"])}).value()}function mergeEntries(target,source){var sum=0,weight=0;if(target.weight){sum+=target.barycenter*target.weight;weight+=target.weight}if(source.weight){sum+=source.barycenter*source.weight;weight+=source.weight}target.vs=source.vs.concat(target.vs);target.barycenter=sum/weight;target.weight=weight;target.i=Math.min(source.i,target.i);source.merged=true}},{"../lodash":10}],20:[function(require,module,exports){var _=require("../lodash"),barycenter=require("./barycenter"),resolveConflicts=require("./resolve-conflicts"),sort=require("./sort");module.exports=sortSubgraph;function sortSubgraph(g,v,cg,biasRight){var movable=g.children(v),node=g.node(v),bl=node?node.borderLeft:undefined,br=node?node.borderRight:undefined,subgraphs={};if(bl){movable=_.filter(movable,function(w){return w!==bl&&w!==br})}var barycenters=barycenter(g,movable);_.each(barycenters,function(entry){if(g.children(entry.v).length){var subgraphResult=sortSubgraph(g,entry.v,cg,biasRight);subgraphs[entry.v]=subgraphResult;if(_.has(subgraphResult,"barycenter")){mergeBarycenters(entry,subgraphResult)}}});var entries=resolveConflicts(barycenters,cg);expandSubgraphs(entries,subgraphs);var result=sort(entries,biasRight);if(bl){result.vs=_.flatten([bl,result.vs,br],true);if(g.predecessors(bl).length){var blPred=g.node(g.predecessors(bl)[0]),brPred=g.node(g.predecessors(br)[0]);if(!_.has(result,"barycenter")){result.barycenter=0;result.weight=0}result.barycenter=(result.barycenter*result.weight+blPred.order+brPred.order)/(result.weight+2);result.weight+=2}}return result}function expandSubgraphs(entries,subgraphs){_.each(entries,function(entry){entry.vs=_.flatten(entry.vs.map(function(v){if(subgraphs[v]){return subgraphs[v].vs}return v}),true)})}function mergeBarycenters(target,other){if(!_.isUndefined(target.barycenter)){target.barycenter=(target.barycenter*target.weight+other.barycenter*other.weight)/(target.weight+other.weight);target.weight+=other.weight}else{target.barycenter=other.barycenter;target.weight=other.weight}}},{"../lodash":10,"./barycenter":14,"./resolve-conflicts":19,"./sort":21}],21:[function(require,module,exports){var _=require("../lodash"),util=require("../util");module.exports=sort;function sort(entries,biasRight){var parts=util.partition(entries,function(entry){return _.has(entry,"barycenter")});var sortable=parts.lhs,unsortable=_.sortBy(parts.rhs,function(entry){return-entry.i}),vs=[],sum=0,weight=0,vsIndex=0;sortable.sort(compareWithBias(!!biasRight));vsIndex=consumeUnsortable(vs,unsortable,vsIndex);_.each(sortable,function(entry){vsIndex+=entry.vs.length;vs.push(entry.vs);sum+=entry.barycenter*entry.weight;weight+=entry.weight;vsIndex=consumeUnsortable(vs,unsortable,vsIndex)});var result={vs:_.flatten(vs,true)};if(weight){result.barycenter=sum/weight;result.weight=weight}return result}function consumeUnsortable(vs,unsortable,index){var last;while(unsortable.length&&(last=_.last(unsortable)).i<=index){unsortable.pop();vs.push(last.vs);index++}return index}function compareWithBias(bias){return function(entryV,entryW){if(entryV.barycenter<entryW.barycenter){return-1}else if(entryV.barycenter>entryW.barycenter){return 1}return!bias?entryV.i-entryW.i:entryW.i-entryV.i}}},{"../lodash":10,"../util":29}],22:[function(require,module,exports){var _=require("./lodash");module.exports=parentDummyChains;function parentDummyChains(g){var postorderNums=postorder(g);_.each(g.graph().dummyChains,function(v){var node=g.node(v),edgeObj=node.edgeObj,pathData=findPath(g,postorderNums,edgeObj.v,edgeObj.w),path=pathData.path,lca=pathData.lca,pathIdx=0,pathV=path[pathIdx],ascending=true;while(v!==edgeObj.w){node=g.node(v);if(ascending){while((pathV=path[pathIdx])!==lca&&g.node(pathV).maxRank<node.rank){pathIdx++}if(pathV===lca){ascending=false}}if(!ascending){while(pathIdx<path.length-1&&g.node(pathV=path[pathIdx+1]).minRank<=node.rank){pathIdx++}pathV=path[pathIdx]}g.setParent(v,pathV);v=g.successors(v)[0]}})}function findPath(g,postorderNums,v,w){var vPath=[],wPath=[],low=Math.min(postorderNums[v].low,postorderNums[w].low),lim=Math.max(postorderNums[v].lim,postorderNums[w].lim),parent,lca;parent=v;do{parent=g.parent(parent);vPath.push(parent)}while(parent&&(postorderNums[parent].low>low||lim>postorderNums[parent].lim));lca=parent;parent=w;while((parent=g.parent(parent))!==lca){wPath.push(parent)}return{path:vPath.concat(wPath.reverse()),lca:lca}}function postorder(g){var result={},lim=0;function dfs(v){var low=lim;_.each(g.children(v),dfs);result[v]={low:low,lim:lim++}}_.each(g.children(),dfs);return result}},{"./lodash":10}],23:[function(require,module,exports){"use strict";var _=require("../lodash"),Graph=require("../graphlib").Graph,util=require("../util");module.exports={positionX:positionX,findType1Conflicts:findType1Conflicts,findType2Conflicts:findType2Conflicts,addConflict:addConflict,hasConflict:hasConflict,verticalAlignment:verticalAlignment,horizontalCompaction:horizontalCompaction,alignCoordinates:alignCoordinates,findSmallestWidthAlignment:findSmallestWidthAlignment,balance:balance};function findType1Conflicts(g,layering){var conflicts={};function visitLayer(prevLayer,layer){var k0=0,scanPos=0,prevLayerLength=prevLayer.length,lastNode=_.last(layer);_.each(layer,function(v,i){var w=findOtherInnerSegmentNode(g,v),k1=w?g.node(w).order:prevLayerLength;if(w||v===lastNode){_.each(layer.slice(scanPos,i+1),function(scanNode){_.each(g.predecessors(scanNode),function(u){var uLabel=g.node(u),uPos=uLabel.order;
+if((uPos<k0||k1<uPos)&&!(uLabel.dummy&&g.node(scanNode).dummy)){addConflict(conflicts,u,scanNode)}})});scanPos=i+1;k0=k1}});return layer}_.reduce(layering,visitLayer);return conflicts}function findType2Conflicts(g,layering){var conflicts={};function scan(south,southPos,southEnd,prevNorthBorder,nextNorthBorder){var v;_.each(_.range(southPos,southEnd),function(i){v=south[i];if(g.node(v).dummy){_.each(g.predecessors(v),function(u){var uNode=g.node(u);if(uNode.dummy&&(uNode.order<prevNorthBorder||uNode.order>nextNorthBorder)){addConflict(conflicts,u,v)}})}})}function visitLayer(north,south){var prevNorthPos=-1,nextNorthPos,southPos=0;_.each(south,function(v,southLookahead){if(g.node(v).dummy==="border"){var predecessors=g.predecessors(v);if(predecessors.length){nextNorthPos=g.node(predecessors[0]).order;scan(south,southPos,southLookahead,prevNorthPos,nextNorthPos);southPos=southLookahead;prevNorthPos=nextNorthPos}}scan(south,southPos,south.length,nextNorthPos,north.length)});return south}_.reduce(layering,visitLayer);return conflicts}function findOtherInnerSegmentNode(g,v){if(g.node(v).dummy){return _.find(g.predecessors(v),function(u){return g.node(u).dummy})}}function addConflict(conflicts,v,w){if(v>w){var tmp=v;v=w;w=tmp}var conflictsV=conflicts[v];if(!conflictsV){conflicts[v]=conflictsV={}}conflictsV[w]=true}function hasConflict(conflicts,v,w){if(v>w){var tmp=v;v=w;w=tmp}return _.has(conflicts[v],w)}function verticalAlignment(g,layering,conflicts,neighborFn){var root={},align={},pos={};_.each(layering,function(layer){_.each(layer,function(v,order){root[v]=v;align[v]=v;pos[v]=order})});_.each(layering,function(layer){var prevIdx=-1;_.each(layer,function(v){var ws=neighborFn(v);if(ws.length){ws=_.sortBy(ws,function(w){return pos[w]});var mp=(ws.length-1)/2;for(var i=Math.floor(mp),il=Math.ceil(mp);i<=il;++i){var w=ws[i];if(align[v]===v&&prevIdx<pos[w]&&!hasConflict(conflicts,v,w)){align[w]=v;align[v]=root[v]=root[w];prevIdx=pos[w]}}}})});return{root:root,align:align}}function horizontalCompaction(g,layering,root,align,reverseSep){var xs={},blockG=buildBlockGraph(g,layering,root,reverseSep);var visited={};function pass1(v){if(!_.has(visited,v)){visited[v]=true;xs[v]=_.reduce(blockG.inEdges(v),function(max,e){pass1(e.v);return Math.max(max,xs[e.v]+blockG.edge(e))},0)}}_.each(blockG.nodes(),pass1);var borderType=reverseSep?"borderLeft":"borderRight";function pass2(v){if(visited[v]!==2){visited[v]++;var node=g.node(v);var min=_.reduce(blockG.outEdges(v),function(min,e){pass2(e.w);return Math.min(min,xs[e.w]-blockG.edge(e))},Number.POSITIVE_INFINITY);if(min!==Number.POSITIVE_INFINITY&&node.borderType!==borderType){xs[v]=Math.max(xs[v],min)}}}_.each(blockG.nodes(),pass2);_.each(align,function(v){xs[v]=xs[root[v]]});return xs}function buildBlockGraph(g,layering,root,reverseSep){var blockGraph=new Graph,graphLabel=g.graph(),sepFn=sep(graphLabel.nodesep,graphLabel.edgesep,reverseSep);_.each(layering,function(layer){var u;_.each(layer,function(v){var vRoot=root[v];blockGraph.setNode(vRoot);if(u){var uRoot=root[u],prevMax=blockGraph.edge(uRoot,vRoot);blockGraph.setEdge(uRoot,vRoot,Math.max(sepFn(g,v,u),prevMax||0))}u=v})});return blockGraph}function findSmallestWidthAlignment(g,xss){return _.min(xss,function(xs){var min=_.min(xs,function(x,v){return x-width(g,v)/2}),max=_.max(xs,function(x,v){return x+width(g,v)/2});return max-min})}function alignCoordinates(xss,alignTo){var alignToMin=_.min(alignTo),alignToMax=_.max(alignTo);_.each(["u","d"],function(vert){_.each(["l","r"],function(horiz){var alignment=vert+horiz,xs=xss[alignment],delta;if(xs===alignTo)return;delta=horiz==="l"?alignToMin-_.min(xs):alignToMax-_.max(xs);if(delta){xss[alignment]=_.mapValues(xs,function(x){return x+delta})}})})}function balance(xss,align){return _.mapValues(xss.ul,function(ignore,v){if(align){return xss[align.toLowerCase()][v]}else{var xs=_.sortBy(_.pluck(xss,v));return(xs[1]+xs[2])/2}})}function positionX(g){var layering=util.buildLayerMatrix(g),conflicts=_.merge(findType1Conflicts(g,layering),findType2Conflicts(g,layering));var xss={},adjustedLayering;_.each(["u","d"],function(vert){adjustedLayering=vert==="u"?layering:_.values(layering).reverse();_.each(["l","r"],function(horiz){if(horiz==="r"){adjustedLayering=_.map(adjustedLayering,function(inner){return _.values(inner).reverse()})}var neighborFn=_.bind(vert==="u"?g.predecessors:g.successors,g);var align=verticalAlignment(g,adjustedLayering,conflicts,neighborFn);var xs=horizontalCompaction(g,adjustedLayering,align.root,align.align,horiz==="r");if(horiz==="r"){xs=_.mapValues(xs,function(x){return-x})}xss[vert+horiz]=xs})});var smallestWidth=findSmallestWidthAlignment(g,xss);alignCoordinates(xss,smallestWidth);return balance(xss,g.graph().align)}function sep(nodeSep,edgeSep,reverseSep){return function(g,v,w){var vLabel=g.node(v),wLabel=g.node(w),sum=0,delta;sum+=vLabel.width/2;if(_.has(vLabel,"labelpos")){switch(vLabel.labelpos.toLowerCase()){case"l":delta=-vLabel.width/2;break;case"r":delta=vLabel.width/2;break}}if(delta){sum+=reverseSep?delta:-delta}delta=0;sum+=(vLabel.dummy?edgeSep:nodeSep)/2;sum+=(wLabel.dummy?edgeSep:nodeSep)/2;sum+=wLabel.width/2;if(_.has(wLabel,"labelpos")){switch(wLabel.labelpos.toLowerCase()){case"l":delta=wLabel.width/2;break;case"r":delta=-wLabel.width/2;break}}if(delta){sum+=reverseSep?delta:-delta}delta=0;return sum}}function width(g,v){return g.node(v).width}},{"../graphlib":7,"../lodash":10,"../util":29}],24:[function(require,module,exports){"use strict";var _=require("../lodash"),util=require("../util"),positionX=require("./bk").positionX;module.exports=position;function position(g){g=util.asNonCompoundGraph(g);positionY(g);_.each(positionX(g),function(x,v){g.node(v).x=x})}function positionY(g){var layering=util.buildLayerMatrix(g),rankSep=g.graph().ranksep,prevY=0;_.each(layering,function(layer){var maxHeight=_.max(_.map(layer,function(v){return g.node(v).height}));_.each(layer,function(v){g.node(v).y=prevY+maxHeight/2});prevY+=maxHeight+rankSep})}},{"../lodash":10,"../util":29,"./bk":23}],25:[function(require,module,exports){"use strict";var _=require("../lodash"),Graph=require("../graphlib").Graph,slack=require("./util").slack;module.exports=feasibleTree;function feasibleTree(g){var t=new Graph({directed:false});var start=g.nodes()[0],size=g.nodeCount();t.setNode(start,{});var edge,delta;while(tightTree(t,g)<size){edge=findMinSlackEdge(t,g);delta=t.hasNode(edge.v)?slack(g,edge):-slack(g,edge);shiftRanks(t,g,delta)}return t}function tightTree(t,g){function dfs(v){_.each(g.nodeEdges(v),function(e){var edgeV=e.v,w=v===edgeV?e.w:edgeV;if(!t.hasNode(w)&&!slack(g,e)){t.setNode(w,{});t.setEdge(v,w,{});dfs(w)}})}_.each(t.nodes(),dfs);return t.nodeCount()}function findMinSlackEdge(t,g){return _.min(g.edges(),function(e){if(t.hasNode(e.v)!==t.hasNode(e.w)){return slack(g,e)}})}function shiftRanks(t,g,delta){_.each(t.nodes(),function(v){g.node(v).rank+=delta})}},{"../graphlib":7,"../lodash":10,"./util":28}],26:[function(require,module,exports){"use strict";var rankUtil=require("./util"),longestPath=rankUtil.longestPath,feasibleTree=require("./feasible-tree"),networkSimplex=require("./network-simplex");module.exports=rank;function rank(g){switch(g.graph().ranker){case"network-simplex":networkSimplexRanker(g);break;case"tight-tree":tightTreeRanker(g);break;case"longest-path":longestPathRanker(g);break;default:networkSimplexRanker(g)}}var longestPathRanker=longestPath;function tightTreeRanker(g){longestPath(g);feasibleTree(g)}function networkSimplexRanker(g){networkSimplex(g)}},{"./feasible-tree":25,"./network-simplex":27,"./util":28}],27:[function(require,module,exports){"use strict";var _=require("../lodash"),feasibleTree=require("./feasible-tree"),slack=require("./util").slack,initRank=require("./util").longestPath,preorder=require("../graphlib").alg.preorder,postorder=require("../graphlib").alg.postorder,simplify=require("../util").simplify;module.exports=networkSimplex;networkSimplex.initLowLimValues=initLowLimValues;networkSimplex.initCutValues=initCutValues;networkSimplex.calcCutValue=calcCutValue;networkSimplex.leaveEdge=leaveEdge;networkSimplex.enterEdge=enterEdge;networkSimplex.exchangeEdges=exchangeEdges;function networkSimplex(g){g=simplify(g);initRank(g);var t=feasibleTree(g);initLowLimValues(t);initCutValues(t,g);var e,f;while(e=leaveEdge(t)){f=enterEdge(t,g,e);exchangeEdges(t,g,e,f)}}function initCutValues(t,g){var vs=postorder(t,t.nodes());vs=vs.slice(0,vs.length-1);_.each(vs,function(v){assignCutValue(t,g,v)})}function assignCutValue(t,g,child){var childLab=t.node(child),parent=childLab.parent;t.edge(child,parent).cutvalue=calcCutValue(t,g,child)}function calcCutValue(t,g,child){var childLab=t.node(child),parent=childLab.parent,childIsTail=true,graphEdge=g.edge(child,parent),cutValue=0;if(!graphEdge){childIsTail=false;graphEdge=g.edge(parent,child)}cutValue=graphEdge.weight;_.each(g.nodeEdges(child),function(e){var isOutEdge=e.v===child,other=isOutEdge?e.w:e.v;if(other!==parent){var pointsToHead=isOutEdge===childIsTail,otherWeight=g.edge(e).weight;cutValue+=pointsToHead?otherWeight:-otherWeight;if(isTreeEdge(t,child,other)){var otherCutValue=t.edge(child,other).cutvalue;cutValue+=pointsToHead?-otherCutValue:otherCutValue}}});return cutValue}function initLowLimValues(tree,root){if(arguments.length<2){root=tree.nodes()[0]}dfsAssignLowLim(tree,{},1,root)}function dfsAssignLowLim(tree,visited,nextLim,v,parent){var low=nextLim,label=tree.node(v);visited[v]=true;_.each(tree.neighbors(v),function(w){if(!_.has(visited,w)){nextLim=dfsAssignLowLim(tree,visited,nextLim,w,v)}});label.low=low;label.lim=nextLim++;if(parent){label.parent=parent}else{delete label.parent}return nextLim}function leaveEdge(tree){return _.find(tree.edges(),function(e){return tree.edge(e).cutvalue<0})}function enterEdge(t,g,edge){var v=edge.v,w=edge.w;if(!g.hasEdge(v,w)){v=edge.w;w=edge.v}var vLabel=t.node(v),wLabel=t.node(w),tailLabel=vLabel,flip=false;if(vLabel.lim>wLabel.lim){tailLabel=wLabel;flip=true}var candidates=_.filter(g.edges(),function(edge){return flip===isDescendant(t,t.node(edge.v),tailLabel)&&flip!==isDescendant(t,t.node(edge.w),tailLabel)});return _.min(candidates,function(edge){return slack(g,edge)})}function exchangeEdges(t,g,e,f){var v=e.v,w=e.w;t.removeEdge(v,w);t.setEdge(f.v,f.w,{});initLowLimValues(t);initCutValues(t,g);updateRanks(t,g)}function updateRanks(t,g){var root=_.find(t.nodes(),function(v){return!g.node(v).parent}),vs=preorder(t,root);vs=vs.slice(1);_.each(vs,function(v){var parent=t.node(v).parent,edge=g.edge(v,parent),flipped=false;if(!edge){edge=g.edge(parent,v);flipped=true}g.node(v).rank=g.node(parent).rank+(flipped?edge.minlen:-edge.minlen)})}function isTreeEdge(tree,u,v){return tree.hasEdge(u,v)}function isDescendant(tree,vLabel,rootLabel){return rootLabel.low<=vLabel.lim&&vLabel.lim<=rootLabel.lim}},{"../graphlib":7,"../lodash":10,"../util":29,"./feasible-tree":25,"./util":28}],28:[function(require,module,exports){"use strict";var _=require("../lodash");module.exports={longestPath:longestPath,slack:slack};function longestPath(g){var visited={};function dfs(v){var label=g.node(v);if(_.has(visited,v)){return label.rank}visited[v]=true;var rank=_.min(_.map(g.outEdges(v),function(e){return dfs(e.w)-g.edge(e).minlen}));if(rank===Number.POSITIVE_INFINITY){rank=0}return label.rank=rank}_.each(g.sources(),dfs)}function slack(g,e){return g.node(e.w).rank-g.node(e.v).rank-g.edge(e).minlen}},{"../lodash":10}],29:[function(require,module,exports){"use strict";var _=require("./lodash"),Graph=require("./graphlib").Graph;module.exports={addDummyNode:addDummyNode,simplify:simplify,asNonCompoundGraph:asNonCompoundGraph,successorWeights:successorWeights,predecessorWeights:predecessorWeights,intersectRect:intersectRect,buildLayerMatrix:buildLayerMatrix,normalizeRanks:normalizeRanks,removeEmptyRanks:removeEmptyRanks,addBorderNode:addBorderNode,maxRank:maxRank,partition:partition,time:time,notime:notime};function addDummyNode(g,type,attrs,name){var v;do{v=_.uniqueId(name)}while(g.hasNode(v));attrs.dummy=type;g.setNode(v,attrs);return v}function simplify(g){var simplified=(new Graph).setGraph(g.graph());_.each(g.nodes(),function(v){simplified.setNode(v,g.node(v))});_.each(g.edges(),function(e){var simpleLabel=simplified.edge(e.v,e.w)||{weight:0,minlen:1},label=g.edge(e);simplified.setEdge(e.v,e.w,{weight:simpleLabel.weight+label.weight,minlen:Math.max(simpleLabel.minlen,label.minlen)})});return simplified}function asNonCompoundGraph(g){var simplified=new Graph({multigraph:g.isMultigraph()}).setGraph(g.graph());_.each(g.nodes(),function(v){if(!g.children(v).length){simplified.setNode(v,g.node(v))}});_.each(g.edges(),function(e){simplified.setEdge(e,g.edge(e))});return simplified}function successorWeights(g){var weightMap=_.map(g.nodes(),function(v){var sucs={};_.each(g.outEdges(v),function(e){sucs[e.w]=(sucs[e.w]||0)+g.edge(e).weight});return sucs});return _.zipObject(g.nodes(),weightMap)}function predecessorWeights(g){var weightMap=_.map(g.nodes(),function(v){var preds={};_.each(g.inEdges(v),function(e){preds[e.v]=(preds[e.v]||0)+g.edge(e).weight});return preds});return _.zipObject(g.nodes(),weightMap)}function intersectRect(rect,point){var x=rect.x;var y=rect.y;var dx=point.x-x;var dy=point.y-y;var w=rect.width/2;var h=rect.height/2;if(!dx&&!dy){throw new Error("Not possible to find intersection inside of the rectangle")}var sx,sy;if(Math.abs(dy)*w>Math.abs(dx)*h){if(dy<0){h=-h}sx=h*dx/dy;sy=h}else{if(dx<0){w=-w}sx=w;sy=w*dy/dx}return{x:x+sx,y:y+sy}}function buildLayerMatrix(g){var layering=_.map(_.range(maxRank(g)+1),function(){return[]});_.each(g.nodes(),function(v){var node=g.node(v),rank=node.rank;if(!_.isUndefined(rank)){layering[rank][node.order]=v}});return layering}function normalizeRanks(g){var min=_.min(_.map(g.nodes(),function(v){return g.node(v).rank}));_.each(g.nodes(),function(v){var node=g.node(v);if(_.has(node,"rank")){node.rank-=min}})}function removeEmptyRanks(g){var offset=_.min(_.map(g.nodes(),function(v){return g.node(v).rank}));var layers=[];_.each(g.nodes(),function(v){var rank=g.node(v).rank-offset;if(!layers[rank]){layers[rank]=[]}layers[rank].push(v)});var delta=0,nodeRankFactor=g.graph().nodeRankFactor;_.each(layers,function(vs,i){if(_.isUndefined(vs)&&i%nodeRankFactor!==0){--delta}else if(delta){_.each(vs,function(v){g.node(v).rank+=delta})}})}function addBorderNode(g,prefix,rank,order){var node={width:0,height:0};if(arguments.length>=4){node.rank=rank;node.order=order}return addDummyNode(g,"border",node,prefix)}function maxRank(g){return _.max(_.map(g.nodes(),function(v){var rank=g.node(v).rank;if(!_.isUndefined(rank)){return rank}}))}function partition(collection,fn){var result={lhs:[],rhs:[]};_.each(collection,function(value){if(fn(value)){result.lhs.push(value)}else{result.rhs.push(value)}});return result}function time(name,fn){var start=_.now();try{return fn()}finally{console.log(name+" time: "+(_.now()-start)+"ms")}}function notime(name,fn){return fn()}},{"./graphlib":7,"./lodash":10}],30:[function(require,module,exports){module.exports="0.7.4"},{}],31:[function(require,module,exports){var lib=require("./lib");module.exports={Graph:lib.Graph,json:require("./lib/json"),alg:require("./lib/alg"),version:lib.version}},{"./lib":47,"./lib/alg":38,"./lib/json":48}],32:[function(require,module,exports){var _=require("../lodash");module.exports=components;function components(g){var visited={},cmpts=[],cmpt;function dfs(v){if(_.has(visited,v))return;visited[v]=true;cmpt.push(v);_.each(g.successors(v),dfs);_.each(g.predecessors(v),dfs)}_.each(g.nodes(),function(v){cmpt=[];dfs(v);if(cmpt.length){cmpts.push(cmpt)}});return cmpts}},{"../lodash":49}],33:[function(require,module,exports){var _=require("../lodash");module.exports=dfs;function dfs(g,vs,order){if(!_.isArray(vs)){vs=[vs]}var acc=[],visited={};_.each(vs,function(v){if(!g.hasNode(v)){throw new Error("Graph does not have node: "+v)}doDfs(g,v,order==="post",visited,acc)});return acc}function doDfs(g,v,postorder,visited,acc){if(!_.has(visited,v)){visited[v]=true;if(!postorder){acc.push(v)}_.each(g.neighbors(v),function(w){doDfs(g,w,postorder,visited,acc)});if(postorder){acc.push(v)}}}},{"../lodash":49}],34:[function(require,module,exports){var dijkstra=require("./dijkstra"),_=require("../lodash");module.exports=dijkstraAll;function dijkstraAll(g,weightFunc,edgeFunc){return _.transform(g.nodes(),function(acc,v){acc[v]=dijkstra(g,v,weightFunc,edgeFunc)},{})}},{"../lodash":49,"./dijkstra":35}],35:[function(require,module,exports){var _=require("../lodash"),PriorityQueue=require("../data/priority-queue");module.exports=dijkstra;var DEFAULT_WEIGHT_FUNC=_.constant(1);function dijkstra(g,source,weightFn,edgeFn){return runDijkstra(g,String(source),weightFn||DEFAULT_WEIGHT_FUNC,edgeFn||function(v){return g.outEdges(v)})}function runDijkstra(g,source,weightFn,edgeFn){var results={},pq=new PriorityQueue,v,vEntry;var updateNeighbors=function(edge){var w=edge.v!==v?edge.v:edge.w,wEntry=results[w],weight=weightFn(edge),distance=vEntry.distance+weight;if(weight<0){throw new Error("dijkstra does not allow negative edge weights. "+"Bad edge: "+edge+" Weight: "+weight)}if(distance<wEntry.distance){wEntry.distance=distance;wEntry.predecessor=v;pq.decrease(w,distance)}};g.nodes().forEach(function(v){var distance=v===source?0:Number.POSITIVE_INFINITY;results[v]={distance:distance};pq.add(v,distance)});while(pq.size()>0){v=pq.removeMin();vEntry=results[v];if(vEntry.distance===Number.POSITIVE_INFINITY){break}edgeFn(v).forEach(updateNeighbors)}return results}},{"../data/priority-queue":45,"../lodash":49}],36:[function(require,module,exports){var _=require("../lodash"),tarjan=require("./tarjan");module.exports=findCycles;function findCycles(g){return _.filter(tarjan(g),function(cmpt){return cmpt.length>1||cmpt.length===1&&g.hasEdge(cmpt[0],cmpt[0])})}},{"../lodash":49,"./tarjan":43}],37:[function(require,module,exports){var _=require("../lodash");module.exports=floydWarshall;var DEFAULT_WEIGHT_FUNC=_.constant(1);function floydWarshall(g,weightFn,edgeFn){return runFloydWarshall(g,weightFn||DEFAULT_WEIGHT_FUNC,edgeFn||function(v){return g.outEdges(v)})}function runFloydWarshall(g,weightFn,edgeFn){var results={},nodes=g.nodes();nodes.forEach(function(v){results[v]={};results[v][v]={distance:0};nodes.forEach(function(w){if(v!==w){results[v][w]={distance:Number.POSITIVE_INFINITY}}});edgeFn(v).forEach(function(edge){var w=edge.v===v?edge.w:edge.v,d=weightFn(edge);results[v][w]={distance:d,predecessor:v}})});nodes.forEach(function(k){var rowK=results[k];nodes.forEach(function(i){var rowI=results[i];nodes.forEach(function(j){var ik=rowI[k];var kj=rowK[j];var ij=rowI[j];var altDistance=ik.distance+kj.distance;if(altDistance<ij.distance){ij.distance=altDistance;ij.predecessor=kj.predecessor}})})});return results}},{"../lodash":49}],38:[function(require,module,exports){module.exports={components:require("./components"),dijkstra:require("./dijkstra"),dijkstraAll:require("./dijkstra-all"),findCycles:require("./find-cycles"),floydWarshall:require("./floyd-warshall"),isAcyclic:require("./is-acyclic"),postorder:require("./postorder"),preorder:require("./preorder"),prim:require("./prim"),tarjan:require("./tarjan"),topsort:require("./topsort")}},{"./components":32,"./dijkstra":35,"./dijkstra-all":34,"./find-cycles":36,"./floyd-warshall":37,"./is-acyclic":39,"./postorder":40,"./preorder":41,"./prim":42,"./tarjan":43,"./topsort":44}],39:[function(require,module,exports){var topsort=require("./topsort");module.exports=isAcyclic;function isAcyclic(g){try{topsort(g)}catch(e){if(e instanceof topsort.CycleException){return false}throw e}return true}},{"./topsort":44}],40:[function(require,module,exports){var dfs=require("./dfs");module.exports=postorder;function postorder(g,vs){return dfs(g,vs,"post")}},{"./dfs":33}],41:[function(require,module,exports){var dfs=require("./dfs");module.exports=preorder;function preorder(g,vs){return dfs(g,vs,"pre")}},{"./dfs":33}],42:[function(require,module,exports){var _=require("../lodash"),Graph=require("../graph"),PriorityQueue=require("../data/priority-queue");module.exports=prim;function prim(g,weightFunc){var result=new Graph,parents={},pq=new PriorityQueue,v;function updateNeighbors(edge){var w=edge.v===v?edge.w:edge.v,pri=pq.priority(w);if(pri!==undefined){var edgeWeight=weightFunc(edge);if(edgeWeight<pri){parents[w]=v;pq.decrease(w,edgeWeight)}}}if(g.nodeCount()===0){return result}_.each(g.nodes(),function(v){pq.add(v,Number.POSITIVE_INFINITY);result.setNode(v)});pq.decrease(g.nodes()[0],0);var init=false;while(pq.size()>0){v=pq.removeMin();if(_.has(parents,v)){result.setEdge(v,parents[v])}else if(init){throw new Error("Input graph is not connected: "+g)}else{init=true}g.nodeEdges(v).forEach(updateNeighbors)}return result}},{"../data/priority-queue":45,"../graph":46,"../lodash":49}],43:[function(require,module,exports){var _=require("../lodash");module.exports=tarjan;function tarjan(g){var index=0,stack=[],visited={},results=[];function dfs(v){var entry=visited[v]={onStack:true,lowlink:index,index:index++};stack.push(v);g.successors(v).forEach(function(w){if(!_.has(visited,w)){dfs(w);entry.lowlink=Math.min(entry.lowlink,visited[w].lowlink)}else if(visited[w].onStack){entry.lowlink=Math.min(entry.lowlink,visited[w].index)}});if(entry.lowlink===entry.index){var cmpt=[],w;do{w=stack.pop();visited[w].onStack=false;cmpt.push(w)}while(v!==w);results.push(cmpt)}}g.nodes().forEach(function(v){if(!_.has(visited,v)){dfs(v)}});return results}},{"../lodash":49}],44:[function(require,module,exports){var _=require("../lodash");module.exports=topsort;topsort.CycleException=CycleException;function topsort(g){var visited={},stack={},results=[];function visit(node){if(_.has(stack,node)){throw new CycleException}if(!_.has(visited,node)){stack[node]=true;visited[node]=true;_.each(g.predecessors(node),visit);delete stack[node];results.push(node)}}_.each(g.sinks(),visit);if(_.size(visited)!==g.nodeCount()){throw new CycleException}return results}function CycleException(){}},{"../lodash":49}],45:[function(require,module,exports){var _=require("../lodash");module.exports=PriorityQueue;function PriorityQueue(){this._arr=[];this._keyIndices={}}PriorityQueue.prototype.size=function(){return this._arr.length};PriorityQueue.prototype.keys=function(){return this._arr.map(function(x){return x.key})};PriorityQueue.prototype.has=function(key){return _.has(this._keyIndices,key)};PriorityQueue.prototype.priority=function(key){var index=this._keyIndices[key];if(index!==undefined){return this._arr[index].priority}};PriorityQueue.prototype.min=function(){if(this.size()===0){throw new Error("Queue underflow")}return this._arr[0].key};PriorityQueue.prototype.add=function(key,priority){var keyIndices=this._keyIndices;key=String(key);if(!_.has(keyIndices,key)){var arr=this._arr;var index=arr.length;keyIndices[key]=index;arr.push({key:key,priority:priority});this._decrease(index);return true}return false};PriorityQueue.prototype.removeMin=function(){this._swap(0,this._arr.length-1);var min=this._arr.pop();delete this._keyIndices[min.key];this._heapify(0);return min.key};PriorityQueue.prototype.decrease=function(key,priority){var index=this._keyIndices[key];if(priority>this._arr[index].priority){throw new Error("New priority is greater than current priority. "+"Key: "+key+" Old: "+this._arr[index].priority+" New: "+priority)}this._arr[index].priority=priority;this._decrease(index)};PriorityQueue.prototype._heapify=function(i){var arr=this._arr;var l=2*i,r=l+1,largest=i;if(l<arr.length){largest=arr[l].priority<arr[largest].priority?l:largest;if(r<arr.length){largest=arr[r].priority<arr[largest].priority?r:largest}if(largest!==i){this._swap(i,largest);this._heapify(largest)}}};PriorityQueue.prototype._decrease=function(index){var arr=this._arr;var priority=arr[index].priority;var parent;while(index!==0){parent=index>>1;if(arr[parent].priority<priority){break}this._swap(index,parent);index=parent}};PriorityQueue.prototype._swap=function(i,j){var arr=this._arr;var keyIndices=this._keyIndices;var origArrI=arr[i];var origArrJ=arr[j];arr[i]=origArrJ;arr[j]=origArrI;keyIndices[origArrJ.key]=i;keyIndices[origArrI.key]=j}},{"../lodash":49}],46:[function(require,module,exports){"use strict";var _=require("./lodash");module.exports=Graph;var DEFAULT_EDGE_NAME="\x00",GRAPH_NODE="\x00",EDGE_KEY_DELIM="";function Graph(opts){this._isDirected=_.has(opts,"directed")?opts.directed:true;this._isMultigraph=_.has(opts,"multigraph")?opts.multigraph:false;this._isCompound=_.has(opts,"compound")?opts.compound:false;this._label=undefined;this._defaultNodeLabelFn=_.constant(undefined);this._defaultEdgeLabelFn=_.constant(undefined);this._nodes={};if(this._isCompound){this._parent={};this._children={};this._children[GRAPH_NODE]={}}this._in={};this._preds={};this._out={};this._sucs={};this._edgeObjs={};this._edgeLabels={}}Graph.prototype._nodeCount=0;Graph.prototype._edgeCount=0;Graph.prototype.isDirected=function(){return this._isDirected};Graph.prototype.isMultigraph=function(){return this._isMultigraph};Graph.prototype.isCompound=function(){return this._isCompound};Graph.prototype.setGraph=function(label){this._label=label;return this};Graph.prototype.graph=function(){return this._label};Graph.prototype.setDefaultNodeLabel=function(newDefault){if(!_.isFunction(newDefault)){newDefault=_.constant(newDefault)}this._defaultNodeLabelFn=newDefault;return this};Graph.prototype.nodeCount=function(){return this._nodeCount};Graph.prototype.nodes=function(){return _.keys(this._nodes)};Graph.prototype.sources=function(){return _.filter(this.nodes(),function(v){return _.isEmpty(this._in[v])},this)};Graph.prototype.sinks=function(){return _.filter(this.nodes(),function(v){return _.isEmpty(this._out[v])},this)};Graph.prototype.setNodes=function(vs,value){var args=arguments;_.each(vs,function(v){if(args.length>1){this.setNode(v,value)}else{this.setNode(v)}},this);return this};Graph.prototype.setNode=function(v,value){if(_.has(this._nodes,v)){if(arguments.length>1){this._nodes[v]=value}return this}this._nodes[v]=arguments.length>1?value:this._defaultNodeLabelFn(v);if(this._isCompound){this._parent[v]=GRAPH_NODE;this._children[v]={};this._children[GRAPH_NODE][v]=true}this._in[v]={};this._preds[v]={};this._out[v]={};this._sucs[v]={};++this._nodeCount;return this};Graph.prototype.node=function(v){return this._nodes[v]};Graph.prototype.hasNode=function(v){return _.has(this._nodes,v)};Graph.prototype.removeNode=function(v){var self=this;if(_.has(this._nodes,v)){var removeEdge=function(e){self.removeEdge(self._edgeObjs[e])};delete this._nodes[v];if(this._isCompound){this._removeFromParentsChildList(v);delete this._parent[v];_.each(this.children(v),function(child){this.setParent(child)},this);delete this._children[v]}_.each(_.keys(this._in[v]),removeEdge);delete this._in[v];delete this._preds[v];_.each(_.keys(this._out[v]),removeEdge);delete this._out[v];delete this._sucs[v];--this._nodeCount}return this};Graph.prototype.setParent=function(v,parent){if(!this._isCompound){throw new Error("Cannot set parent in a non-compound graph")}if(_.isUndefined(parent)){parent=GRAPH_NODE}else{parent+="";for(var ancestor=parent;!_.isUndefined(ancestor);ancestor=this.parent(ancestor)){if(ancestor===v){throw new Error("Setting "+parent+" as parent of "+v+" would create create a cycle")}}this.setNode(parent)}this.setNode(v);this._removeFromParentsChildList(v);this._parent[v]=parent;this._children[parent][v]=true;return this};Graph.prototype._removeFromParentsChildList=function(v){delete this._children[this._parent[v]][v]};Graph.prototype.parent=function(v){if(this._isCompound){var parent=this._parent[v];if(parent!==GRAPH_NODE){return parent}}};Graph.prototype.children=function(v){if(_.isUndefined(v)){v=GRAPH_NODE}if(this._isCompound){var children=this._children[v];if(children){return _.keys(children)}}else if(v===GRAPH_NODE){return this.nodes()}else if(this.hasNode(v)){return[]}};Graph.prototype.predecessors=function(v){var predsV=this._preds[v];if(predsV){return _.keys(predsV)}};Graph.prototype.successors=function(v){var sucsV=this._sucs[v];if(sucsV){return _.keys(sucsV)}};Graph.prototype.neighbors=function(v){var preds=this.predecessors(v);if(preds){return _.union(preds,this.successors(v))}};Graph.prototype.setDefaultEdgeLabel=function(newDefault){if(!_.isFunction(newDefault)){newDefault=_.constant(newDefault)}this._defaultEdgeLabelFn=newDefault;return this};Graph.prototype.edgeCount=function(){return this._edgeCount};Graph.prototype.edges=function(){return _.values(this._edgeObjs)};Graph.prototype.setPath=function(vs,value){var self=this,args=arguments;_.reduce(vs,function(v,w){if(args.length>1){self.setEdge(v,w,value)}else{self.setEdge(v,w)}return w});return this};Graph.prototype.setEdge=function(){var v,w,name,value,valueSpecified=false;if(_.isPlainObject(arguments[0])){v=arguments[0].v;w=arguments[0].w;name=arguments[0].name;if(arguments.length===2){value=arguments[1];valueSpecified=true}}else{v=arguments[0];w=arguments[1];name=arguments[3];if(arguments.length>2){value=arguments[2];valueSpecified=true}}v=""+v;w=""+w;if(!_.isUndefined(name)){name=""+name}var e=edgeArgsToId(this._isDirected,v,w,name);if(_.has(this._edgeLabels,e)){if(valueSpecified){this._edgeLabels[e]=value}return this}if(!_.isUndefined(name)&&!this._isMultigraph){throw new Error("Cannot set a named edge when isMultigraph = false")}this.setNode(v);this.setNode(w);this._edgeLabels[e]=valueSpecified?value:this._defaultEdgeLabelFn(v,w,name);var edgeObj=edgeArgsToObj(this._isDirected,v,w,name);v=edgeObj.v;w=edgeObj.w;Object.freeze(edgeObj);this._edgeObjs[e]=edgeObj;incrementOrInitEntry(this._preds[w],v);incrementOrInitEntry(this._sucs[v],w);this._in[w][e]=edgeObj;this._out[v][e]=edgeObj;this._edgeCount++;return this};Graph.prototype.edge=function(v,w,name){var e=arguments.length===1?edgeObjToId(this._isDirected,arguments[0]):edgeArgsToId(this._isDirected,v,w,name);return this._edgeLabels[e]};Graph.prototype.hasEdge=function(v,w,name){var e=arguments.length===1?edgeObjToId(this._isDirected,arguments[0]):edgeArgsToId(this._isDirected,v,w,name);return _.has(this._edgeLabels,e)};Graph.prototype.removeEdge=function(v,w,name){var e=arguments.length===1?edgeObjToId(this._isDirected,arguments[0]):edgeArgsToId(this._isDirected,v,w,name),edge=this._edgeObjs[e];if(edge){v=edge.v;w=edge.w;delete this._edgeLabels[e];delete this._edgeObjs[e];decrementOrRemoveEntry(this._preds[w],v);decrementOrRemoveEntry(this._sucs[v],w);delete this._in[w][e];delete this._out[v][e];this._edgeCount--}return this};Graph.prototype.inEdges=function(v,u){var inV=this._in[v];if(inV){var edges=_.values(inV);if(!u){return edges}return _.filter(edges,function(edge){return edge.v===u})}};Graph.prototype.outEdges=function(v,w){var outV=this._out[v];if(outV){var edges=_.values(outV);if(!w){return edges}return _.filter(edges,function(edge){return edge.w===w})}};Graph.prototype.nodeEdges=function(v,w){var inEdges=this.inEdges(v,w);if(inEdges){return inEdges.concat(this.outEdges(v,w))}};function incrementOrInitEntry(map,k){if(_.has(map,k)){map[k]++}else{map[k]=1}}function decrementOrRemoveEntry(map,k){if(!--map[k]){delete map[k]}}function edgeArgsToId(isDirected,v,w,name){if(!isDirected&&v>w){var tmp=v;v=w;w=tmp}return v+EDGE_KEY_DELIM+w+EDGE_KEY_DELIM+(_.isUndefined(name)?DEFAULT_EDGE_NAME:name)}function edgeArgsToObj(isDirected,v,w,name){if(!isDirected&&v>w){var tmp=v;v=w;w=tmp}var edgeObj={v:v,w:w};if(name){edgeObj.name=name}return edgeObj}function edgeObjToId(isDirected,edgeObj){return edgeArgsToId(isDirected,edgeObj.v,edgeObj.w,edgeObj.name)}},{"./lodash":49}],47:[function(require,module,exports){module.exports={Graph:require("./graph"),version:require("./version")}},{"./graph":46,"./version":50}],48:[function(require,module,exports){var _=require("./lodash"),Graph=require("./graph");module.exports={write:write,read:read};function write(g){var json={options:{directed:g.isDirected(),multigraph:g.isMultigraph(),compound:g.isCompound()},nodes:writeNodes(g),edges:writeEdges(g)};
+if(!_.isUndefined(g.graph())){json.value=_.clone(g.graph())}return json}function writeNodes(g){return _.map(g.nodes(),function(v){var nodeValue=g.node(v),parent=g.parent(v),node={v:v};if(!_.isUndefined(nodeValue)){node.value=nodeValue}if(!_.isUndefined(parent)){node.parent=parent}return node})}function writeEdges(g){return _.map(g.edges(),function(e){var edgeValue=g.edge(e),edge={v:e.v,w:e.w};if(!_.isUndefined(e.name)){edge.name=e.name}if(!_.isUndefined(edgeValue)){edge.value=edgeValue}return edge})}function read(json){var g=new Graph(json.options).setGraph(json.value);_.each(json.nodes,function(entry){g.setNode(entry.v,entry.value);if(entry.parent){g.setParent(entry.v,entry.parent)}});_.each(json.edges,function(entry){g.setEdge({v:entry.v,w:entry.w,name:entry.name},entry.value)});return g}},{"./graph":46,"./lodash":49}],49:[function(require,module,exports){module.exports=require(10)},{"/Users/cpettitt/projects/dagre/lib/lodash.js":10,lodash:51}],50:[function(require,module,exports){module.exports="1.0.5"},{}],51:[function(require,module,exports){(function(global){(function(){var undefined;var VERSION="3.10.0";var BIND_FLAG=1,BIND_KEY_FLAG=2,CURRY_BOUND_FLAG=4,CURRY_FLAG=8,CURRY_RIGHT_FLAG=16,PARTIAL_FLAG=32,PARTIAL_RIGHT_FLAG=64,ARY_FLAG=128,REARG_FLAG=256;var DEFAULT_TRUNC_LENGTH=30,DEFAULT_TRUNC_OMISSION="...";var HOT_COUNT=150,HOT_SPAN=16;var LARGE_ARRAY_SIZE=200;var LAZY_FILTER_FLAG=1,LAZY_MAP_FLAG=2;var FUNC_ERROR_TEXT="Expected a function";var PLACEHOLDER="__lodash_placeholder__";var argsTag="[object Arguments]",arrayTag="[object Array]",boolTag="[object Boolean]",dateTag="[object Date]",errorTag="[object Error]",funcTag="[object Function]",mapTag="[object Map]",numberTag="[object Number]",objectTag="[object Object]",regexpTag="[object RegExp]",setTag="[object Set]",stringTag="[object String]",weakMapTag="[object WeakMap]";var arrayBufferTag="[object ArrayBuffer]",float32Tag="[object Float32Array]",float64Tag="[object Float64Array]",int8Tag="[object Int8Array]",int16Tag="[object Int16Array]",int32Tag="[object Int32Array]",uint8Tag="[object Uint8Array]",uint8ClampedTag="[object Uint8ClampedArray]",uint16Tag="[object Uint16Array]",uint32Tag="[object Uint32Array]";var reEmptyStringLeading=/\b__p \+= '';/g,reEmptyStringMiddle=/\b(__p \+=) '' \+/g,reEmptyStringTrailing=/(__e\(.*?\)|\b__t\)) \+\n'';/g;var reEscapedHtml=/&(?:amp|lt|gt|quot|#39|#96);/g,reUnescapedHtml=/[&<>"'`]/g,reHasEscapedHtml=RegExp(reEscapedHtml.source),reHasUnescapedHtml=RegExp(reUnescapedHtml.source);var reEscape=/<%-([\s\S]+?)%>/g,reEvaluate=/<%([\s\S]+?)%>/g,reInterpolate=/<%=([\s\S]+?)%>/g;var reIsDeepProp=/\.|\[(?:[^[\]]*|(["'])(?:(?!\1)[^\n\\]|\\.)*?\1)\]/,reIsPlainProp=/^\w*$/,rePropName=/[^.[\]]+|\[(?:(-?\d+(?:\.\d+)?)|(["'])((?:(?!\2)[^\n\\]|\\.)*?)\2)\]/g;var reRegExpChars=/^[:!,]|[\\^$.*+?()[\]{}|\/]|(^[0-9a-fA-Fnrtuvx])|([\n\r\u2028\u2029])/g,reHasRegExpChars=RegExp(reRegExpChars.source);var reComboMark=/[\u0300-\u036f\ufe20-\ufe23]/g;var reEscapeChar=/\\(\\)?/g;var reEsTemplate=/\$\{([^\\}]*(?:\\.[^\\}]*)*)\}/g;var reFlags=/\w*$/;var reHasHexPrefix=/^0[xX]/;var reIsHostCtor=/^\[object .+?Constructor\]$/;var reIsUint=/^\d+$/;var reLatin1=/[\xc0-\xd6\xd8-\xde\xdf-\xf6\xf8-\xff]/g;var reNoMatch=/($^)/;var reUnescapedString=/['\n\r\u2028\u2029\\]/g;var reWords=function(){var upper="[A-Z\\xc0-\\xd6\\xd8-\\xde]",lower="[a-z\\xdf-\\xf6\\xf8-\\xff]+";return RegExp(upper+"+(?="+upper+lower+")|"+upper+"?"+lower+"|"+upper+"+|[0-9]+","g")}();var contextProps=["Array","ArrayBuffer","Date","Error","Float32Array","Float64Array","Function","Int8Array","Int16Array","Int32Array","Math","Number","Object","RegExp","Set","String","_","clearTimeout","isFinite","parseFloat","parseInt","setTimeout","TypeError","Uint8Array","Uint8ClampedArray","Uint16Array","Uint32Array","WeakMap"];var templateCounter=-1;var typedArrayTags={};typedArrayTags[float32Tag]=typedArrayTags[float64Tag]=typedArrayTags[int8Tag]=typedArrayTags[int16Tag]=typedArrayTags[int32Tag]=typedArrayTags[uint8Tag]=typedArrayTags[uint8ClampedTag]=typedArrayTags[uint16Tag]=typedArrayTags[uint32Tag]=true;typedArrayTags[argsTag]=typedArrayTags[arrayTag]=typedArrayTags[arrayBufferTag]=typedArrayTags[boolTag]=typedArrayTags[dateTag]=typedArrayTags[errorTag]=typedArrayTags[funcTag]=typedArrayTags[mapTag]=typedArrayTags[numberTag]=typedArrayTags[objectTag]=typedArrayTags[regexpTag]=typedArrayTags[setTag]=typedArrayTags[stringTag]=typedArrayTags[weakMapTag]=false;var cloneableTags={};cloneableTags[argsTag]=cloneableTags[arrayTag]=cloneableTags[arrayBufferTag]=cloneableTags[boolTag]=cloneableTags[dateTag]=cloneableTags[float32Tag]=cloneableTags[float64Tag]=cloneableTags[int8Tag]=cloneableTags[int16Tag]=cloneableTags[int32Tag]=cloneableTags[numberTag]=cloneableTags[objectTag]=cloneableTags[regexpTag]=cloneableTags[stringTag]=cloneableTags[uint8Tag]=cloneableTags[uint8ClampedTag]=cloneableTags[uint16Tag]=cloneableTags[uint32Tag]=true;cloneableTags[errorTag]=cloneableTags[funcTag]=cloneableTags[mapTag]=cloneableTags[setTag]=cloneableTags[weakMapTag]=false;var deburredLetters={"À":"A","Á":"A","Â":"A","Ã":"A","Ä":"A","Å":"A","à":"a","á":"a","â":"a","ã":"a","ä":"a","å":"a","Ç":"C","ç":"c","Ð":"D","ð":"d","È":"E","É":"E","Ê":"E","Ë":"E","è":"e","é":"e","ê":"e","ë":"e","Ì":"I","Í":"I","Î":"I","Ï":"I","ì":"i","í":"i","î":"i","ï":"i","Ñ":"N","ñ":"n","Ò":"O","Ó":"O","Ô":"O","Õ":"O","Ö":"O","Ø":"O","ò":"o","ó":"o","ô":"o","õ":"o","ö":"o","ø":"o","Ù":"U","Ú":"U","Û":"U","Ü":"U","ù":"u","ú":"u","û":"u","ü":"u","Ý":"Y","ý":"y","ÿ":"y","Æ":"Ae","æ":"ae","Þ":"Th","þ":"th","ß":"ss"};var htmlEscapes={"&":"&amp;","<":"&lt;",">":"&gt;",'"':"&quot;","'":"&#39;","`":"&#96;"};var htmlUnescapes={"&amp;":"&","&lt;":"<","&gt;":">","&quot;":'"',"&#39;":"'","&#96;":"`"};var objectTypes={"function":true,object:true};var regexpEscapes={0:"x30",1:"x31",2:"x32",3:"x33",4:"x34",5:"x35",6:"x36",7:"x37",8:"x38",9:"x39",A:"x41",B:"x42",C:"x43",D:"x44",E:"x45",F:"x46",a:"x61",b:"x62",c:"x63",d:"x64",e:"x65",f:"x66",n:"x6e",r:"x72",t:"x74",u:"x75",v:"x76",x:"x78"};var stringEscapes={"\\":"\\","'":"'","\n":"n","\r":"r","\u2028":"u2028","\u2029":"u2029"};var freeExports=objectTypes[typeof exports]&&exports&&!exports.nodeType&&exports;var freeModule=objectTypes[typeof module]&&module&&!module.nodeType&&module;var freeGlobal=freeExports&&freeModule&&typeof global=="object"&&global&&global.Object&&global;var freeSelf=objectTypes[typeof self]&&self&&self.Object&&self;var freeWindow=objectTypes[typeof window]&&window&&window.Object&&window;var moduleExports=freeModule&&freeModule.exports===freeExports&&freeExports;var root=freeGlobal||freeWindow!==(this&&this.window)&&freeWindow||freeSelf||this;function baseCompareAscending(value,other){if(value!==other){var valIsNull=value===null,valIsUndef=value===undefined,valIsReflexive=value===value;var othIsNull=other===null,othIsUndef=other===undefined,othIsReflexive=other===other;if(value>other&&!othIsNull||!valIsReflexive||valIsNull&&!othIsUndef&&othIsReflexive||valIsUndef&&othIsReflexive){return 1}if(value<other&&!valIsNull||!othIsReflexive||othIsNull&&!valIsUndef&&valIsReflexive||othIsUndef&&valIsReflexive){return-1}}return 0}function baseFindIndex(array,predicate,fromRight){var length=array.length,index=fromRight?length:-1;while(fromRight?index--:++index<length){if(predicate(array[index],index,array)){return index}}return-1}function baseIndexOf(array,value,fromIndex){if(value!==value){return indexOfNaN(array,fromIndex)}var index=fromIndex-1,length=array.length;while(++index<length){if(array[index]===value){return index}}return-1}function baseIsFunction(value){return typeof value=="function"||false}function baseToString(value){return value==null?"":value+""}function charsLeftIndex(string,chars){var index=-1,length=string.length;while(++index<length&&chars.indexOf(string.charAt(index))>-1){}return index}function charsRightIndex(string,chars){var index=string.length;while(index--&&chars.indexOf(string.charAt(index))>-1){}return index}function compareAscending(object,other){return baseCompareAscending(object.criteria,other.criteria)||object.index-other.index}function compareMultiple(object,other,orders){var index=-1,objCriteria=object.criteria,othCriteria=other.criteria,length=objCriteria.length,ordersLength=orders.length;while(++index<length){var result=baseCompareAscending(objCriteria[index],othCriteria[index]);if(result){if(index>=ordersLength){return result}var order=orders[index];return result*(order==="asc"||order===true?1:-1)}}return object.index-other.index}function deburrLetter(letter){return deburredLetters[letter]}function escapeHtmlChar(chr){return htmlEscapes[chr]}function escapeRegExpChar(chr,leadingChar,whitespaceChar){if(leadingChar){chr=regexpEscapes[chr]}else if(whitespaceChar){chr=stringEscapes[chr]}return"\\"+chr}function escapeStringChar(chr){return"\\"+stringEscapes[chr]}function indexOfNaN(array,fromIndex,fromRight){var length=array.length,index=fromIndex+(fromRight?0:-1);while(fromRight?index--:++index<length){var other=array[index];if(other!==other){return index}}return-1}function isObjectLike(value){return!!value&&typeof value=="object"}function isSpace(charCode){return charCode<=160&&(charCode>=9&&charCode<=13)||charCode==32||charCode==160||charCode==5760||charCode==6158||charCode>=8192&&(charCode<=8202||charCode==8232||charCode==8233||charCode==8239||charCode==8287||charCode==12288||charCode==65279)}function replaceHolders(array,placeholder){var index=-1,length=array.length,resIndex=-1,result=[];while(++index<length){if(array[index]===placeholder){array[index]=PLACEHOLDER;result[++resIndex]=index}}return result}function sortedUniq(array,iteratee){var seen,index=-1,length=array.length,resIndex=-1,result=[];while(++index<length){var value=array[index],computed=iteratee?iteratee(value,index,array):value;if(!index||seen!==computed){seen=computed;result[++resIndex]=value}}return result}function trimmedLeftIndex(string){var index=-1,length=string.length;while(++index<length&&isSpace(string.charCodeAt(index))){}return index}function trimmedRightIndex(string){var index=string.length;while(index--&&isSpace(string.charCodeAt(index))){}return index}function unescapeHtmlChar(chr){return htmlUnescapes[chr]}function runInContext(context){context=context?_.defaults(root.Object(),context,_.pick(root,contextProps)):root;var Array=context.Array,Date=context.Date,Error=context.Error,Function=context.Function,Math=context.Math,Number=context.Number,Object=context.Object,RegExp=context.RegExp,String=context.String,TypeError=context.TypeError;var arrayProto=Array.prototype,objectProto=Object.prototype,stringProto=String.prototype;var fnToString=Function.prototype.toString;var hasOwnProperty=objectProto.hasOwnProperty;var idCounter=0;var objToString=objectProto.toString;var oldDash=root._;var reIsNative=RegExp("^"+fnToString.call(hasOwnProperty).replace(/[\\^$.*+?()[\]{}|]/g,"\\$&").replace(/hasOwnProperty|(function).*?(?=\\\()| for .+?(?=\\\])/g,"$1.*?")+"$");var ArrayBuffer=context.ArrayBuffer,clearTimeout=context.clearTimeout,parseFloat=context.parseFloat,pow=Math.pow,propertyIsEnumerable=objectProto.propertyIsEnumerable,Set=getNative(context,"Set"),setTimeout=context.setTimeout,splice=arrayProto.splice,Uint8Array=context.Uint8Array,WeakMap=getNative(context,"WeakMap");var nativeCeil=Math.ceil,nativeCreate=getNative(Object,"create"),nativeFloor=Math.floor,nativeIsArray=getNative(Array,"isArray"),nativeIsFinite=context.isFinite,nativeKeys=getNative(Object,"keys"),nativeMax=Math.max,nativeMin=Math.min,nativeNow=getNative(Date,"now"),nativeParseInt=context.parseInt,nativeRandom=Math.random;var NEGATIVE_INFINITY=Number.NEGATIVE_INFINITY,POSITIVE_INFINITY=Number.POSITIVE_INFINITY;var MAX_ARRAY_LENGTH=4294967295,MAX_ARRAY_INDEX=MAX_ARRAY_LENGTH-1,HALF_MAX_ARRAY_LENGTH=MAX_ARRAY_LENGTH>>>1;var MAX_SAFE_INTEGER=9007199254740991;var metaMap=WeakMap&&new WeakMap;var realNames={};function lodash(value){if(isObjectLike(value)&&!isArray(value)&&!(value instanceof LazyWrapper)){if(value instanceof LodashWrapper){return value}if(hasOwnProperty.call(value,"__chain__")&&hasOwnProperty.call(value,"__wrapped__")){return wrapperClone(value)}}return new LodashWrapper(value)}function baseLodash(){}function LodashWrapper(value,chainAll,actions){this.__wrapped__=value;this.__actions__=actions||[];this.__chain__=!!chainAll}var support=lodash.support={};lodash.templateSettings={escape:reEscape,evaluate:reEvaluate,interpolate:reInterpolate,variable:"",imports:{_:lodash}};function LazyWrapper(value){this.__wrapped__=value;this.__actions__=[];this.__dir__=1;this.__filtered__=false;this.__iteratees__=[];this.__takeCount__=POSITIVE_INFINITY;this.__views__=[]}function lazyClone(){var result=new LazyWrapper(this.__wrapped__);result.__actions__=arrayCopy(this.__actions__);result.__dir__=this.__dir__;result.__filtered__=this.__filtered__;result.__iteratees__=arrayCopy(this.__iteratees__);result.__takeCount__=this.__takeCount__;result.__views__=arrayCopy(this.__views__);return result}function lazyReverse(){if(this.__filtered__){var result=new LazyWrapper(this);result.__dir__=-1;result.__filtered__=true}else{result=this.clone();result.__dir__*=-1}return result}function lazyValue(){var array=this.__wrapped__.value(),dir=this.__dir__,isArr=isArray(array),isRight=dir<0,arrLength=isArr?array.length:0,view=getView(0,arrLength,this.__views__),start=view.start,end=view.end,length=end-start,index=isRight?end:start-1,iteratees=this.__iteratees__,iterLength=iteratees.length,resIndex=0,takeCount=nativeMin(length,this.__takeCount__);if(!isArr||arrLength<LARGE_ARRAY_SIZE||arrLength==length&&takeCount==length){return baseWrapperValue(isRight&&isArr?array.reverse():array,this.__actions__)}var result=[];outer:while(length--&&resIndex<takeCount){index+=dir;var iterIndex=-1,value=array[index];while(++iterIndex<iterLength){var data=iteratees[iterIndex],iteratee=data.iteratee,type=data.type,computed=iteratee(value);if(type==LAZY_MAP_FLAG){value=computed}else if(!computed){if(type==LAZY_FILTER_FLAG){continue outer}else{break outer}}}result[resIndex++]=value}return result}function MapCache(){this.__data__={}}function mapDelete(key){return this.has(key)&&delete this.__data__[key]}function mapGet(key){return key=="__proto__"?undefined:this.__data__[key]}function mapHas(key){return key!="__proto__"&&hasOwnProperty.call(this.__data__,key)}function mapSet(key,value){if(key!="__proto__"){this.__data__[key]=value}return this}function SetCache(values){var length=values?values.length:0;this.data={hash:nativeCreate(null),set:new Set};while(length--){this.push(values[length])}}function cacheIndexOf(cache,value){var data=cache.data,result=typeof value=="string"||isObject(value)?data.set.has(value):data.hash[value];return result?0:-1}function cachePush(value){var data=this.data;if(typeof value=="string"||isObject(value)){data.set.add(value)}else{data.hash[value]=true}}function arrayConcat(array,other){var index=-1,length=array.length,othIndex=-1,othLength=other.length,result=Array(length+othLength);while(++index<length){result[index]=array[index]}while(++othIndex<othLength){result[index++]=other[othIndex]}return result}function arrayCopy(source,array){var index=-1,length=source.length;array||(array=Array(length));while(++index<length){array[index]=source[index]}return array}function arrayEach(array,iteratee){var index=-1,length=array.length;while(++index<length){if(iteratee(array[index],index,array)===false){break}}return array}function arrayEachRight(array,iteratee){var length=array.length;while(length--){if(iteratee(array[length],length,array)===false){break}}return array}function arrayEvery(array,predicate){var index=-1,length=array.length;while(++index<length){if(!predicate(array[index],index,array)){return false}}return true}function arrayExtremum(array,iteratee,comparator,exValue){var index=-1,length=array.length,computed=exValue,result=computed;while(++index<length){var value=array[index],current=+iteratee(value);if(comparator(current,computed)){computed=current;result=value}}return result}function arrayFilter(array,predicate){var index=-1,length=array.length,resIndex=-1,result=[];while(++index<length){var value=array[index];if(predicate(value,index,array)){result[++resIndex]=value}}return result}function arrayMap(array,iteratee){var index=-1,length=array.length,result=Array(length);while(++index<length){result[index]=iteratee(array[index],index,array)}return result}function arrayPush(array,values){var index=-1,length=values.length,offset=array.length;while(++index<length){array[offset+index]=values[index]}return array}function arrayReduce(array,iteratee,accumulator,initFromArray){var index=-1,length=array.length;if(initFromArray&&length){accumulator=array[++index]}while(++index<length){accumulator=iteratee(accumulator,array[index],index,array)}return accumulator}function arrayReduceRight(array,iteratee,accumulator,initFromArray){var length=array.length;if(initFromArray&&length){accumulator=array[--length]}while(length--){accumulator=iteratee(accumulator,array[length],length,array)}return accumulator}function arraySome(array,predicate){var index=-1,length=array.length;while(++index<length){if(predicate(array[index],index,array)){return true}}return false}function arraySum(array,iteratee){var length=array.length,result=0;while(length--){result+=+iteratee(array[length])||0}return result}function assignDefaults(objectValue,sourceValue){return objectValue===undefined?sourceValue:objectValue}function assignOwnDefaults(objectValue,sourceValue,key,object){return objectValue===undefined||!hasOwnProperty.call(object,key)?sourceValue:objectValue}function assignWith(object,source,customizer){var index=-1,props=keys(source),length=props.length;while(++index<length){var key=props[index],value=object[key],result=customizer(value,source[key],key,object,source);if((result===result?result!==value:value===value)||value===undefined&&!(key in object)){object[key]=result}}return object}function baseAssign(object,source){return source==null?object:baseCopy(source,keys(source),object)}function baseAt(collection,props){var index=-1,isNil=collection==null,isArr=!isNil&&isArrayLike(collection),length=isArr?collection.length:0,propsLength=props.length,result=Array(propsLength);while(++index<propsLength){var key=props[index];if(isArr){result[index]=isIndex(key,length)?collection[key]:undefined}else{result[index]=isNil?undefined:collection[key]}}return result}function baseCopy(source,props,object){object||(object={});var index=-1,length=props.length;while(++index<length){var key=props[index];object[key]=source[key]}return object}function baseCallback(func,thisArg,argCount){var type=typeof func;if(type=="function"){return thisArg===undefined?func:bindCallback(func,thisArg,argCount)}if(func==null){return identity}if(type=="object"){return baseMatches(func)}return thisArg===undefined?property(func):baseMatchesProperty(func,thisArg)}function baseClone(value,isDeep,customizer,key,object,stackA,stackB){var result;if(customizer){result=object?customizer(value,key,object):customizer(value)}if(result!==undefined){return result}if(!isObject(value)){return value}var isArr=isArray(value);if(isArr){result=initCloneArray(value);if(!isDeep){return arrayCopy(value,result)}}else{var tag=objToString.call(value),isFunc=tag==funcTag;if(tag==objectTag||tag==argsTag||isFunc&&!object){result=initCloneObject(isFunc?{}:value);if(!isDeep){return baseAssign(result,value)}}else{return cloneableTags[tag]?initCloneByTag(value,tag,isDeep):object?value:{}}}stackA||(stackA=[]);stackB||(stackB=[]);var length=stackA.length;while(length--){if(stackA[length]==value){return stackB[length]}}stackA.push(value);stackB.push(result);(isArr?arrayEach:baseForOwn)(value,function(subValue,key){result[key]=baseClone(subValue,isDeep,customizer,key,value,stackA,stackB)});return result}var baseCreate=function(){function object(){}return function(prototype){if(isObject(prototype)){object.prototype=prototype;var result=new object;object.prototype=undefined}return result||{}}}();function baseDelay(func,wait,args){if(typeof func!="function"){throw new TypeError(FUNC_ERROR_TEXT)}return setTimeout(function(){func.apply(undefined,args)},wait)}function baseDifference(array,values){var length=array?array.length:0,result=[];if(!length){return result}var index=-1,indexOf=getIndexOf(),isCommon=indexOf==baseIndexOf,cache=isCommon&&values.length>=LARGE_ARRAY_SIZE?createCache(values):null,valuesLength=values.length;if(cache){indexOf=cacheIndexOf;isCommon=false;values=cache}outer:while(++index<length){var value=array[index];if(isCommon&&value===value){var valuesIndex=valuesLength;while(valuesIndex--){if(values[valuesIndex]===value){continue outer}}result.push(value)}else if(indexOf(values,value,0)<0){result.push(value)}}return result}var baseEach=createBaseEach(baseForOwn);var baseEachRight=createBaseEach(baseForOwnRight,true);function baseEvery(collection,predicate){var result=true;baseEach(collection,function(value,index,collection){result=!!predicate(value,index,collection);return result});return result}function baseExtremum(collection,iteratee,comparator,exValue){var computed=exValue,result=computed;baseEach(collection,function(value,index,collection){var current=+iteratee(value,index,collection);if(comparator(current,computed)||current===exValue&&current===result){computed=current;result=value}});return result}function baseFill(array,value,start,end){var length=array.length;start=start==null?0:+start||0;if(start<0){start=-start>length?0:length+start}end=end===undefined||end>length?length:+end||0;if(end<0){end+=length}length=start>end?0:end>>>0;start>>>=0;while(start<length){array[start++]=value}return array}function baseFilter(collection,predicate){var result=[];baseEach(collection,function(value,index,collection){if(predicate(value,index,collection)){result.push(value)}});return result}function baseFind(collection,predicate,eachFunc,retKey){var result;eachFunc(collection,function(value,key,collection){if(predicate(value,key,collection)){result=retKey?key:value;return false}});return result}function baseFlatten(array,isDeep,isStrict,result){result||(result=[]);var index=-1,length=array.length;while(++index<length){var value=array[index];if(isObjectLike(value)&&isArrayLike(value)&&(isStrict||isArray(value)||isArguments(value))){if(isDeep){baseFlatten(value,isDeep,isStrict,result)}else{arrayPush(result,value)}}else if(!isStrict){result[result.length]=value}}return result}var baseFor=createBaseFor();var baseForRight=createBaseFor(true);function baseForIn(object,iteratee){return baseFor(object,iteratee,keysIn)}function baseForOwn(object,iteratee){return baseFor(object,iteratee,keys)}function baseForOwnRight(object,iteratee){return baseForRight(object,iteratee,keys)}function baseFunctions(object,props){var index=-1,length=props.length,resIndex=-1,result=[];while(++index<length){var key=props[index];if(isFunction(object[key])){result[++resIndex]=key}}return result}function baseGet(object,path,pathKey){if(object==null){return}if(pathKey!==undefined&&pathKey in toObject(object)){path=[pathKey]}var index=0,length=path.length;while(object!=null&&index<length){object=object[path[index++]]}return index&&index==length?object:undefined}function baseIsEqual(value,other,customizer,isLoose,stackA,stackB){if(value===other){return true}if(value==null||other==null||!isObject(value)&&!isObjectLike(other)){return value!==value&&other!==other}return baseIsEqualDeep(value,other,baseIsEqual,customizer,isLoose,stackA,stackB)}function baseIsEqualDeep(object,other,equalFunc,customizer,isLoose,stackA,stackB){var objIsArr=isArray(object),othIsArr=isArray(other),objTag=arrayTag,othTag=arrayTag;if(!objIsArr){objTag=objToString.call(object);if(objTag==argsTag){objTag=objectTag}else if(objTag!=objectTag){objIsArr=isTypedArray(object)}}if(!othIsArr){othTag=objToString.call(other);if(othTag==argsTag){othTag=objectTag}else if(othTag!=objectTag){othIsArr=isTypedArray(other)}}var objIsObj=objTag==objectTag,othIsObj=othTag==objectTag,isSameTag=objTag==othTag;if(isSameTag&&!(objIsArr||objIsObj)){return equalByTag(object,other,objTag)}if(!isLoose){var objIsWrapped=objIsObj&&hasOwnProperty.call(object,"__wrapped__"),othIsWrapped=othIsObj&&hasOwnProperty.call(other,"__wrapped__");if(objIsWrapped||othIsWrapped){return equalFunc(objIsWrapped?object.value():object,othIsWrapped?other.value():other,customizer,isLoose,stackA,stackB)}}if(!isSameTag){return false}stackA||(stackA=[]);stackB||(stackB=[]);var length=stackA.length;while(length--){if(stackA[length]==object){return stackB[length]==other}}stackA.push(object);stackB.push(other);var result=(objIsArr?equalArrays:equalObjects)(object,other,equalFunc,customizer,isLoose,stackA,stackB);stackA.pop();stackB.pop();return result}function baseIsMatch(object,matchData,customizer){var index=matchData.length,length=index,noCustomizer=!customizer;if(object==null){return!length}object=toObject(object);while(index--){var data=matchData[index];if(noCustomizer&&data[2]?data[1]!==object[data[0]]:!(data[0]in object)){return false}}while(++index<length){data=matchData[index];var key=data[0],objValue=object[key],srcValue=data[1];if(noCustomizer&&data[2]){if(objValue===undefined&&!(key in object)){return false}}else{var result=customizer?customizer(objValue,srcValue,key):undefined;if(!(result===undefined?baseIsEqual(srcValue,objValue,customizer,true):result)){return false}}}return true}function baseMap(collection,iteratee){var index=-1,result=isArrayLike(collection)?Array(collection.length):[];baseEach(collection,function(value,key,collection){result[++index]=iteratee(value,key,collection)});return result}function baseMatches(source){var matchData=getMatchData(source);if(matchData.length==1&&matchData[0][2]){var key=matchData[0][0],value=matchData[0][1];return function(object){if(object==null){return false}return object[key]===value&&(value!==undefined||key in toObject(object))}}return function(object){return baseIsMatch(object,matchData)}}function baseMatchesProperty(path,srcValue){var isArr=isArray(path),isCommon=isKey(path)&&isStrictComparable(srcValue),pathKey=path+"";path=toPath(path);return function(object){if(object==null){return false}var key=pathKey;object=toObject(object);if((isArr||!isCommon)&&!(key in object)){object=path.length==1?object:baseGet(object,baseSlice(path,0,-1));if(object==null){return false}key=last(path);object=toObject(object)}return object[key]===srcValue?srcValue!==undefined||key in object:baseIsEqual(srcValue,object[key],undefined,true)}}function baseMerge(object,source,customizer,stackA,stackB){if(!isObject(object)){return object}var isSrcArr=isArrayLike(source)&&(isArray(source)||isTypedArray(source)),props=isSrcArr?undefined:keys(source);arrayEach(props||source,function(srcValue,key){if(props){key=srcValue;srcValue=source[key]}if(isObjectLike(srcValue)){stackA||(stackA=[]);stackB||(stackB=[]);baseMergeDeep(object,source,key,baseMerge,customizer,stackA,stackB)}else{var value=object[key],result=customizer?customizer(value,srcValue,key,object,source):undefined,isCommon=result===undefined;if(isCommon){result=srcValue}if((result!==undefined||isSrcArr&&!(key in object))&&(isCommon||(result===result?result!==value:value===value))){object[key]=result}}});return object}function baseMergeDeep(object,source,key,mergeFunc,customizer,stackA,stackB){var length=stackA.length,srcValue=source[key];while(length--){if(stackA[length]==srcValue){object[key]=stackB[length];return}}var value=object[key],result=customizer?customizer(value,srcValue,key,object,source):undefined,isCommon=result===undefined;if(isCommon){result=srcValue;if(isArrayLike(srcValue)&&(isArray(srcValue)||isTypedArray(srcValue))){result=isArray(value)?value:isArrayLike(value)?arrayCopy(value):[]}else if(isPlainObject(srcValue)||isArguments(srcValue)){result=isArguments(value)?toPlainObject(value):isPlainObject(value)?value:{}}else{isCommon=false}}stackA.push(srcValue);stackB.push(result);if(isCommon){object[key]=mergeFunc(result,srcValue,customizer,stackA,stackB)}else if(result===result?result!==value:value===value){object[key]=result}}function baseProperty(key){return function(object){return object==null?undefined:object[key]}}function basePropertyDeep(path){var pathKey=path+"";path=toPath(path);return function(object){return baseGet(object,path,pathKey)}}function basePullAt(array,indexes){var length=array?indexes.length:0;while(length--){var index=indexes[length];if(index!=previous&&isIndex(index)){var previous=index;splice.call(array,index,1)}}return array}function baseRandom(min,max){return min+nativeFloor(nativeRandom()*(max-min+1))}function baseReduce(collection,iteratee,accumulator,initFromCollection,eachFunc){eachFunc(collection,function(value,index,collection){accumulator=initFromCollection?(initFromCollection=false,value):iteratee(accumulator,value,index,collection)});return accumulator}var baseSetData=!metaMap?identity:function(func,data){metaMap.set(func,data);return func};function baseSlice(array,start,end){var index=-1,length=array.length;start=start==null?0:+start||0;if(start<0){start=-start>length?0:length+start}end=end===undefined||end>length?length:+end||0;if(end<0){end+=length}length=start>end?0:end-start>>>0;start>>>=0;var result=Array(length);while(++index<length){result[index]=array[index+start]}return result}function baseSome(collection,predicate){var result;baseEach(collection,function(value,index,collection){result=predicate(value,index,collection);return!result});return!!result}function baseSortBy(array,comparer){var length=array.length;array.sort(comparer);while(length--){array[length]=array[length].value}return array}function baseSortByOrder(collection,iteratees,orders){var callback=getCallback(),index=-1;iteratees=arrayMap(iteratees,function(iteratee){return callback(iteratee)});var result=baseMap(collection,function(value){var criteria=arrayMap(iteratees,function(iteratee){return iteratee(value)});return{criteria:criteria,index:++index,value:value}});return baseSortBy(result,function(object,other){return compareMultiple(object,other,orders)})}function baseSum(collection,iteratee){var result=0;baseEach(collection,function(value,index,collection){result+=+iteratee(value,index,collection)||0});return result}function baseUniq(array,iteratee){var index=-1,indexOf=getIndexOf(),length=array.length,isCommon=indexOf==baseIndexOf,isLarge=isCommon&&length>=LARGE_ARRAY_SIZE,seen=isLarge?createCache():null,result=[];if(seen){indexOf=cacheIndexOf;isCommon=false}else{isLarge=false;seen=iteratee?[]:result}outer:while(++index<length){var value=array[index],computed=iteratee?iteratee(value,index,array):value;if(isCommon&&value===value){var seenIndex=seen.length;while(seenIndex--){if(seen[seenIndex]===computed){continue outer}}if(iteratee){seen.push(computed)}result.push(value)}else if(indexOf(seen,computed,0)<0){if(iteratee||isLarge){seen.push(computed)}result.push(value)}}return result}function baseValues(object,props){var index=-1,length=props.length,result=Array(length);while(++index<length){result[index]=object[props[index]]}return result}function baseWhile(array,predicate,isDrop,fromRight){var length=array.length,index=fromRight?length:-1;while((fromRight?index--:++index<length)&&predicate(array[index],index,array)){}return isDrop?baseSlice(array,fromRight?0:index,fromRight?index+1:length):baseSlice(array,fromRight?index+1:0,fromRight?length:index)}function baseWrapperValue(value,actions){var result=value;if(result instanceof LazyWrapper){result=result.value()}var index=-1,length=actions.length;while(++index<length){var action=actions[index];result=action.func.apply(action.thisArg,arrayPush([result],action.args))}return result}function binaryIndex(array,value,retHighest){var low=0,high=array?array.length:low;if(typeof value=="number"&&value===value&&high<=HALF_MAX_ARRAY_LENGTH){while(low<high){var mid=low+high>>>1,computed=array[mid];if((retHighest?computed<=value:computed<value)&&computed!==null){low=mid+1}else{high=mid}}return high
+}return binaryIndexBy(array,value,identity,retHighest)}function binaryIndexBy(array,value,iteratee,retHighest){value=iteratee(value);var low=0,high=array?array.length:0,valIsNaN=value!==value,valIsNull=value===null,valIsUndef=value===undefined;while(low<high){var mid=nativeFloor((low+high)/2),computed=iteratee(array[mid]),isDef=computed!==undefined,isReflexive=computed===computed;if(valIsNaN){var setLow=isReflexive||retHighest}else if(valIsNull){setLow=isReflexive&&isDef&&(retHighest||computed!=null)}else if(valIsUndef){setLow=isReflexive&&(retHighest||isDef)}else if(computed==null){setLow=false}else{setLow=retHighest?computed<=value:computed<value}if(setLow){low=mid+1}else{high=mid}}return nativeMin(high,MAX_ARRAY_INDEX)}function bindCallback(func,thisArg,argCount){if(typeof func!="function"){return identity}if(thisArg===undefined){return func}switch(argCount){case 1:return function(value){return func.call(thisArg,value)};case 3:return function(value,index,collection){return func.call(thisArg,value,index,collection)};case 4:return function(accumulator,value,index,collection){return func.call(thisArg,accumulator,value,index,collection)};case 5:return function(value,other,key,object,source){return func.call(thisArg,value,other,key,object,source)}}return function(){return func.apply(thisArg,arguments)}}function bufferClone(buffer){var result=new ArrayBuffer(buffer.byteLength),view=new Uint8Array(result);view.set(new Uint8Array(buffer));return result}function composeArgs(args,partials,holders){var holdersLength=holders.length,argsIndex=-1,argsLength=nativeMax(args.length-holdersLength,0),leftIndex=-1,leftLength=partials.length,result=Array(leftLength+argsLength);while(++leftIndex<leftLength){result[leftIndex]=partials[leftIndex]}while(++argsIndex<holdersLength){result[holders[argsIndex]]=args[argsIndex]}while(argsLength--){result[leftIndex++]=args[argsIndex++]}return result}function composeArgsRight(args,partials,holders){var holdersIndex=-1,holdersLength=holders.length,argsIndex=-1,argsLength=nativeMax(args.length-holdersLength,0),rightIndex=-1,rightLength=partials.length,result=Array(argsLength+rightLength);while(++argsIndex<argsLength){result[argsIndex]=args[argsIndex]}var offset=argsIndex;while(++rightIndex<rightLength){result[offset+rightIndex]=partials[rightIndex]}while(++holdersIndex<holdersLength){result[offset+holders[holdersIndex]]=args[argsIndex++]}return result}function createAggregator(setter,initializer){return function(collection,iteratee,thisArg){var result=initializer?initializer():{};iteratee=getCallback(iteratee,thisArg,3);if(isArray(collection)){var index=-1,length=collection.length;while(++index<length){var value=collection[index];setter(result,value,iteratee(value,index,collection),collection)}}else{baseEach(collection,function(value,key,collection){setter(result,value,iteratee(value,key,collection),collection)})}return result}}function createAssigner(assigner){return restParam(function(object,sources){var index=-1,length=object==null?0:sources.length,customizer=length>2?sources[length-2]:undefined,guard=length>2?sources[2]:undefined,thisArg=length>1?sources[length-1]:undefined;if(typeof customizer=="function"){customizer=bindCallback(customizer,thisArg,5);length-=2}else{customizer=typeof thisArg=="function"?thisArg:undefined;length-=customizer?1:0}if(guard&&isIterateeCall(sources[0],sources[1],guard)){customizer=length<3?undefined:customizer;length=1}while(++index<length){var source=sources[index];if(source){assigner(object,source,customizer)}}return object})}function createBaseEach(eachFunc,fromRight){return function(collection,iteratee){var length=collection?getLength(collection):0;if(!isLength(length)){return eachFunc(collection,iteratee)}var index=fromRight?length:-1,iterable=toObject(collection);while(fromRight?index--:++index<length){if(iteratee(iterable[index],index,iterable)===false){break}}return collection}}function createBaseFor(fromRight){return function(object,iteratee,keysFunc){var iterable=toObject(object),props=keysFunc(object),length=props.length,index=fromRight?length:-1;while(fromRight?index--:++index<length){var key=props[index];if(iteratee(iterable[key],key,iterable)===false){break}}return object}}function createBindWrapper(func,thisArg){var Ctor=createCtorWrapper(func);function wrapper(){var fn=this&&this!==root&&this instanceof wrapper?Ctor:func;return fn.apply(thisArg,arguments)}return wrapper}function createCache(values){return nativeCreate&&Set?new SetCache(values):null}function createCompounder(callback){return function(string){var index=-1,array=words(deburr(string)),length=array.length,result="";while(++index<length){result=callback(result,array[index],index)}return result}}function createCtorWrapper(Ctor){return function(){var args=arguments;switch(args.length){case 0:return new Ctor;case 1:return new Ctor(args[0]);case 2:return new Ctor(args[0],args[1]);case 3:return new Ctor(args[0],args[1],args[2]);case 4:return new Ctor(args[0],args[1],args[2],args[3]);case 5:return new Ctor(args[0],args[1],args[2],args[3],args[4]);case 6:return new Ctor(args[0],args[1],args[2],args[3],args[4],args[5]);case 7:return new Ctor(args[0],args[1],args[2],args[3],args[4],args[5],args[6])}var thisBinding=baseCreate(Ctor.prototype),result=Ctor.apply(thisBinding,args);return isObject(result)?result:thisBinding}}function createCurry(flag){function curryFunc(func,arity,guard){if(guard&&isIterateeCall(func,arity,guard)){arity=undefined}var result=createWrapper(func,flag,undefined,undefined,undefined,undefined,undefined,arity);result.placeholder=curryFunc.placeholder;return result}return curryFunc}function createDefaults(assigner,customizer){return restParam(function(args){var object=args[0];if(object==null){return object}args.push(customizer);return assigner.apply(undefined,args)})}function createExtremum(comparator,exValue){return function(collection,iteratee,thisArg){if(thisArg&&isIterateeCall(collection,iteratee,thisArg)){iteratee=undefined}iteratee=getCallback(iteratee,thisArg,3);if(iteratee.length==1){collection=isArray(collection)?collection:toIterable(collection);var result=arrayExtremum(collection,iteratee,comparator,exValue);if(!(collection.length&&result===exValue)){return result}}return baseExtremum(collection,iteratee,comparator,exValue)}}function createFind(eachFunc,fromRight){return function(collection,predicate,thisArg){predicate=getCallback(predicate,thisArg,3);if(isArray(collection)){var index=baseFindIndex(collection,predicate,fromRight);return index>-1?collection[index]:undefined}return baseFind(collection,predicate,eachFunc)}}function createFindIndex(fromRight){return function(array,predicate,thisArg){if(!(array&&array.length)){return-1}predicate=getCallback(predicate,thisArg,3);return baseFindIndex(array,predicate,fromRight)}}function createFindKey(objectFunc){return function(object,predicate,thisArg){predicate=getCallback(predicate,thisArg,3);return baseFind(object,predicate,objectFunc,true)}}function createFlow(fromRight){return function(){var wrapper,length=arguments.length,index=fromRight?length:-1,leftIndex=0,funcs=Array(length);while(fromRight?index--:++index<length){var func=funcs[leftIndex++]=arguments[index];if(typeof func!="function"){throw new TypeError(FUNC_ERROR_TEXT)}if(!wrapper&&LodashWrapper.prototype.thru&&getFuncName(func)=="wrapper"){wrapper=new LodashWrapper([],true)}}index=wrapper?-1:length;while(++index<length){func=funcs[index];var funcName=getFuncName(func),data=funcName=="wrapper"?getData(func):undefined;if(data&&isLaziable(data[0])&&data[1]==(ARY_FLAG|CURRY_FLAG|PARTIAL_FLAG|REARG_FLAG)&&!data[4].length&&data[9]==1){wrapper=wrapper[getFuncName(data[0])].apply(wrapper,data[3])}else{wrapper=func.length==1&&isLaziable(func)?wrapper[funcName]():wrapper.thru(func)}}return function(){var args=arguments,value=args[0];if(wrapper&&args.length==1&&isArray(value)&&value.length>=LARGE_ARRAY_SIZE){return wrapper.plant(value).value()}var index=0,result=length?funcs[index].apply(this,args):value;while(++index<length){result=funcs[index].call(this,result)}return result}}}function createForEach(arrayFunc,eachFunc){return function(collection,iteratee,thisArg){return typeof iteratee=="function"&&thisArg===undefined&&isArray(collection)?arrayFunc(collection,iteratee):eachFunc(collection,bindCallback(iteratee,thisArg,3))}}function createForIn(objectFunc){return function(object,iteratee,thisArg){if(typeof iteratee!="function"||thisArg!==undefined){iteratee=bindCallback(iteratee,thisArg,3)}return objectFunc(object,iteratee,keysIn)}}function createForOwn(objectFunc){return function(object,iteratee,thisArg){if(typeof iteratee!="function"||thisArg!==undefined){iteratee=bindCallback(iteratee,thisArg,3)}return objectFunc(object,iteratee)}}function createObjectMapper(isMapKeys){return function(object,iteratee,thisArg){var result={};iteratee=getCallback(iteratee,thisArg,3);baseForOwn(object,function(value,key,object){var mapped=iteratee(value,key,object);key=isMapKeys?mapped:key;value=isMapKeys?value:mapped;result[key]=value});return result}}function createPadDir(fromRight){return function(string,length,chars){string=baseToString(string);return(fromRight?string:"")+createPadding(string,length,chars)+(fromRight?"":string)}}function createPartial(flag){var partialFunc=restParam(function(func,partials){var holders=replaceHolders(partials,partialFunc.placeholder);return createWrapper(func,flag,undefined,partials,holders)});return partialFunc}function createReduce(arrayFunc,eachFunc){return function(collection,iteratee,accumulator,thisArg){var initFromArray=arguments.length<3;return typeof iteratee=="function"&&thisArg===undefined&&isArray(collection)?arrayFunc(collection,iteratee,accumulator,initFromArray):baseReduce(collection,getCallback(iteratee,thisArg,4),accumulator,initFromArray,eachFunc)}}function createHybridWrapper(func,bitmask,thisArg,partials,holders,partialsRight,holdersRight,argPos,ary,arity){var isAry=bitmask&ARY_FLAG,isBind=bitmask&BIND_FLAG,isBindKey=bitmask&BIND_KEY_FLAG,isCurry=bitmask&CURRY_FLAG,isCurryBound=bitmask&CURRY_BOUND_FLAG,isCurryRight=bitmask&CURRY_RIGHT_FLAG,Ctor=isBindKey?undefined:createCtorWrapper(func);function wrapper(){var length=arguments.length,index=length,args=Array(length);while(index--){args[index]=arguments[index]}if(partials){args=composeArgs(args,partials,holders)}if(partialsRight){args=composeArgsRight(args,partialsRight,holdersRight)}if(isCurry||isCurryRight){var placeholder=wrapper.placeholder,argsHolders=replaceHolders(args,placeholder);length-=argsHolders.length;if(length<arity){var newArgPos=argPos?arrayCopy(argPos):undefined,newArity=nativeMax(arity-length,0),newsHolders=isCurry?argsHolders:undefined,newHoldersRight=isCurry?undefined:argsHolders,newPartials=isCurry?args:undefined,newPartialsRight=isCurry?undefined:args;bitmask|=isCurry?PARTIAL_FLAG:PARTIAL_RIGHT_FLAG;bitmask&=~(isCurry?PARTIAL_RIGHT_FLAG:PARTIAL_FLAG);if(!isCurryBound){bitmask&=~(BIND_FLAG|BIND_KEY_FLAG)}var newData=[func,bitmask,thisArg,newPartials,newsHolders,newPartialsRight,newHoldersRight,newArgPos,ary,newArity],result=createHybridWrapper.apply(undefined,newData);if(isLaziable(func)){setData(result,newData)}result.placeholder=placeholder;return result}}var thisBinding=isBind?thisArg:this,fn=isBindKey?thisBinding[func]:func;if(argPos){args=reorder(args,argPos)}if(isAry&&ary<args.length){args.length=ary}if(this&&this!==root&&this instanceof wrapper){fn=Ctor||createCtorWrapper(func)}return fn.apply(thisBinding,args)}return wrapper}function createPadding(string,length,chars){var strLength=string.length;length=+length;if(strLength>=length||!nativeIsFinite(length)){return""}var padLength=length-strLength;chars=chars==null?" ":chars+"";return repeat(chars,nativeCeil(padLength/chars.length)).slice(0,padLength)}function createPartialWrapper(func,bitmask,thisArg,partials){var isBind=bitmask&BIND_FLAG,Ctor=createCtorWrapper(func);function wrapper(){var argsIndex=-1,argsLength=arguments.length,leftIndex=-1,leftLength=partials.length,args=Array(leftLength+argsLength);while(++leftIndex<leftLength){args[leftIndex]=partials[leftIndex]}while(argsLength--){args[leftIndex++]=arguments[++argsIndex]}var fn=this&&this!==root&&this instanceof wrapper?Ctor:func;return fn.apply(isBind?thisArg:this,args)}return wrapper}function createRound(methodName){var func=Math[methodName];return function(number,precision){precision=precision===undefined?0:+precision||0;if(precision){precision=pow(10,precision);return func(number*precision)/precision}return func(number)}}function createSortedIndex(retHighest){return function(array,value,iteratee,thisArg){var callback=getCallback(iteratee);return iteratee==null&&callback===baseCallback?binaryIndex(array,value,retHighest):binaryIndexBy(array,value,callback(iteratee,thisArg,1),retHighest)}}function createWrapper(func,bitmask,thisArg,partials,holders,argPos,ary,arity){var isBindKey=bitmask&BIND_KEY_FLAG;if(!isBindKey&&typeof func!="function"){throw new TypeError(FUNC_ERROR_TEXT)}var length=partials?partials.length:0;if(!length){bitmask&=~(PARTIAL_FLAG|PARTIAL_RIGHT_FLAG);partials=holders=undefined}length-=holders?holders.length:0;if(bitmask&PARTIAL_RIGHT_FLAG){var partialsRight=partials,holdersRight=holders;partials=holders=undefined}var data=isBindKey?undefined:getData(func),newData=[func,bitmask,thisArg,partials,holders,partialsRight,holdersRight,argPos,ary,arity];if(data){mergeData(newData,data);bitmask=newData[1];arity=newData[9]}newData[9]=arity==null?isBindKey?0:func.length:nativeMax(arity-length,0)||0;if(bitmask==BIND_FLAG){var result=createBindWrapper(newData[0],newData[2])}else if((bitmask==PARTIAL_FLAG||bitmask==(BIND_FLAG|PARTIAL_FLAG))&&!newData[4].length){result=createPartialWrapper.apply(undefined,newData)}else{result=createHybridWrapper.apply(undefined,newData)}var setter=data?baseSetData:setData;return setter(result,newData)}function equalArrays(array,other,equalFunc,customizer,isLoose,stackA,stackB){var index=-1,arrLength=array.length,othLength=other.length;if(arrLength!=othLength&&!(isLoose&&othLength>arrLength)){return false}while(++index<arrLength){var arrValue=array[index],othValue=other[index],result=customizer?customizer(isLoose?othValue:arrValue,isLoose?arrValue:othValue,index):undefined;if(result!==undefined){if(result){continue}return false}if(isLoose){if(!arraySome(other,function(othValue){return arrValue===othValue||equalFunc(arrValue,othValue,customizer,isLoose,stackA,stackB)})){return false}}else if(!(arrValue===othValue||equalFunc(arrValue,othValue,customizer,isLoose,stackA,stackB))){return false}}return true}function equalByTag(object,other,tag){switch(tag){case boolTag:case dateTag:return+object==+other;case errorTag:return object.name==other.name&&object.message==other.message;case numberTag:return object!=+object?other!=+other:object==+other;case regexpTag:case stringTag:return object==other+""}return false}function equalObjects(object,other,equalFunc,customizer,isLoose,stackA,stackB){var objProps=keys(object),objLength=objProps.length,othProps=keys(other),othLength=othProps.length;if(objLength!=othLength&&!isLoose){return false}var index=objLength;while(index--){var key=objProps[index];if(!(isLoose?key in other:hasOwnProperty.call(other,key))){return false}}var skipCtor=isLoose;while(++index<objLength){key=objProps[index];var objValue=object[key],othValue=other[key],result=customizer?customizer(isLoose?othValue:objValue,isLoose?objValue:othValue,key):undefined;if(!(result===undefined?equalFunc(objValue,othValue,customizer,isLoose,stackA,stackB):result)){return false}skipCtor||(skipCtor=key=="constructor")}if(!skipCtor){var objCtor=object.constructor,othCtor=other.constructor;if(objCtor!=othCtor&&("constructor"in object&&"constructor"in other)&&!(typeof objCtor=="function"&&objCtor instanceof objCtor&&typeof othCtor=="function"&&othCtor instanceof othCtor)){return false}}return true}function getCallback(func,thisArg,argCount){var result=lodash.callback||callback;result=result===callback?baseCallback:result;return argCount?result(func,thisArg,argCount):result}var getData=!metaMap?noop:function(func){return metaMap.get(func)};function getFuncName(func){var result=func.name,array=realNames[result],length=array?array.length:0;while(length--){var data=array[length],otherFunc=data.func;if(otherFunc==null||otherFunc==func){return data.name}}return result}function getIndexOf(collection,target,fromIndex){var result=lodash.indexOf||indexOf;result=result===indexOf?baseIndexOf:result;return collection?result(collection,target,fromIndex):result}var getLength=baseProperty("length");function getMatchData(object){var result=pairs(object),length=result.length;while(length--){result[length][2]=isStrictComparable(result[length][1])}return result}function getNative(object,key){var value=object==null?undefined:object[key];return isNative(value)?value:undefined}function getView(start,end,transforms){var index=-1,length=transforms.length;while(++index<length){var data=transforms[index],size=data.size;switch(data.type){case"drop":start+=size;break;case"dropRight":end-=size;break;case"take":end=nativeMin(end,start+size);break;case"takeRight":start=nativeMax(start,end-size);break}}return{start:start,end:end}}function initCloneArray(array){var length=array.length,result=new array.constructor(length);if(length&&typeof array[0]=="string"&&hasOwnProperty.call(array,"index")){result.index=array.index;result.input=array.input}return result}function initCloneObject(object){var Ctor=object.constructor;if(!(typeof Ctor=="function"&&Ctor instanceof Ctor)){Ctor=Object}return new Ctor}function initCloneByTag(object,tag,isDeep){var Ctor=object.constructor;switch(tag){case arrayBufferTag:return bufferClone(object);case boolTag:case dateTag:return new Ctor(+object);case float32Tag:case float64Tag:case int8Tag:case int16Tag:case int32Tag:case uint8Tag:case uint8ClampedTag:case uint16Tag:case uint32Tag:var buffer=object.buffer;return new Ctor(isDeep?bufferClone(buffer):buffer,object.byteOffset,object.length);case numberTag:case stringTag:return new Ctor(object);case regexpTag:var result=new Ctor(object.source,reFlags.exec(object));result.lastIndex=object.lastIndex}return result}function invokePath(object,path,args){if(object!=null&&!isKey(path,object)){path=toPath(path);object=path.length==1?object:baseGet(object,baseSlice(path,0,-1));path=last(path)}var func=object==null?object:object[path];return func==null?undefined:func.apply(object,args)}function isArrayLike(value){return value!=null&&isLength(getLength(value))}function isIndex(value,length){value=typeof value=="number"||reIsUint.test(value)?+value:-1;length=length==null?MAX_SAFE_INTEGER:length;return value>-1&&value%1==0&&value<length}function isIterateeCall(value,index,object){if(!isObject(object)){return false}var type=typeof index;if(type=="number"?isArrayLike(object)&&isIndex(index,object.length):type=="string"&&index in object){var other=object[index];return value===value?value===other:other!==other}return false}function isKey(value,object){var type=typeof value;if(type=="string"&&reIsPlainProp.test(value)||type=="number"){return true}if(isArray(value)){return false}var result=!reIsDeepProp.test(value);return result||object!=null&&value in toObject(object)}function isLaziable(func){var funcName=getFuncName(func);if(!(funcName in LazyWrapper.prototype)){return false}var other=lodash[funcName];if(func===other){return true}var data=getData(other);return!!data&&func===data[0]}function isLength(value){return typeof value=="number"&&value>-1&&value%1==0&&value<=MAX_SAFE_INTEGER}function isStrictComparable(value){return value===value&&!isObject(value)}function mergeData(data,source){var bitmask=data[1],srcBitmask=source[1],newBitmask=bitmask|srcBitmask,isCommon=newBitmask<ARY_FLAG;var isCombo=srcBitmask==ARY_FLAG&&bitmask==CURRY_FLAG||srcBitmask==ARY_FLAG&&bitmask==REARG_FLAG&&data[7].length<=source[8]||srcBitmask==(ARY_FLAG|REARG_FLAG)&&bitmask==CURRY_FLAG;if(!(isCommon||isCombo)){return data}if(srcBitmask&BIND_FLAG){data[2]=source[2];newBitmask|=bitmask&BIND_FLAG?0:CURRY_BOUND_FLAG}var value=source[3];if(value){var partials=data[3];data[3]=partials?composeArgs(partials,value,source[4]):arrayCopy(value);data[4]=partials?replaceHolders(data[3],PLACEHOLDER):arrayCopy(source[4])}value=source[5];if(value){partials=data[5];data[5]=partials?composeArgsRight(partials,value,source[6]):arrayCopy(value);data[6]=partials?replaceHolders(data[5],PLACEHOLDER):arrayCopy(source[6])}value=source[7];if(value){data[7]=arrayCopy(value)}if(srcBitmask&ARY_FLAG){data[8]=data[8]==null?source[8]:nativeMin(data[8],source[8])}if(data[9]==null){data[9]=source[9]}data[0]=source[0];data[1]=newBitmask;return data}function mergeDefaults(objectValue,sourceValue){return objectValue===undefined?sourceValue:merge(objectValue,sourceValue,mergeDefaults)}function pickByArray(object,props){object=toObject(object);var index=-1,length=props.length,result={};while(++index<length){var key=props[index];if(key in object){result[key]=object[key]}}return result}function pickByCallback(object,predicate){var result={};baseForIn(object,function(value,key,object){if(predicate(value,key,object)){result[key]=value}});return result}function reorder(array,indexes){var arrLength=array.length,length=nativeMin(indexes.length,arrLength),oldArray=arrayCopy(array);while(length--){var index=indexes[length];array[length]=isIndex(index,arrLength)?oldArray[index]:undefined}return array}var setData=function(){var count=0,lastCalled=0;return function(key,value){var stamp=now(),remaining=HOT_SPAN-(stamp-lastCalled);lastCalled=stamp;if(remaining>0){if(++count>=HOT_COUNT){return key}}else{count=0}return baseSetData(key,value)}}();function shimKeys(object){var props=keysIn(object),propsLength=props.length,length=propsLength&&object.length;var allowIndexes=!!length&&isLength(length)&&(isArray(object)||isArguments(object));var index=-1,result=[];while(++index<propsLength){var key=props[index];if(allowIndexes&&isIndex(key,length)||hasOwnProperty.call(object,key)){result.push(key)}}return result}function toIterable(value){if(value==null){return[]}if(!isArrayLike(value)){return values(value)}return isObject(value)?value:Object(value)}function toObject(value){return isObject(value)?value:Object(value)}function toPath(value){if(isArray(value)){return value}var result=[];baseToString(value).replace(rePropName,function(match,number,quote,string){result.push(quote?string.replace(reEscapeChar,"$1"):number||match)});return result}function wrapperClone(wrapper){return wrapper instanceof LazyWrapper?wrapper.clone():new LodashWrapper(wrapper.__wrapped__,wrapper.__chain__,arrayCopy(wrapper.__actions__))}function chunk(array,size,guard){if(guard?isIterateeCall(array,size,guard):size==null){size=1}else{size=nativeMax(nativeFloor(size)||1,1)}var index=0,length=array?array.length:0,resIndex=-1,result=Array(nativeCeil(length/size));while(index<length){result[++resIndex]=baseSlice(array,index,index+=size)}return result}function compact(array){var index=-1,length=array?array.length:0,resIndex=-1,result=[];while(++index<length){var value=array[index];if(value){result[++resIndex]=value}}return result}var difference=restParam(function(array,values){return isObjectLike(array)&&isArrayLike(array)?baseDifference(array,baseFlatten(values,false,true)):[]});function drop(array,n,guard){var length=array?array.length:0;if(!length){return[]}if(guard?isIterateeCall(array,n,guard):n==null){n=1}return baseSlice(array,n<0?0:n)}function dropRight(array,n,guard){var length=array?array.length:0;if(!length){return[]}if(guard?isIterateeCall(array,n,guard):n==null){n=1}n=length-(+n||0);return baseSlice(array,0,n<0?0:n)}function dropRightWhile(array,predicate,thisArg){return array&&array.length?baseWhile(array,getCallback(predicate,thisArg,3),true,true):[]}function dropWhile(array,predicate,thisArg){return array&&array.length?baseWhile(array,getCallback(predicate,thisArg,3),true):[]}function fill(array,value,start,end){var length=array?array.length:0;if(!length){return[]}if(start&&typeof start!="number"&&isIterateeCall(array,value,start)){start=0;end=length}return baseFill(array,value,start,end)}var findIndex=createFindIndex();var findLastIndex=createFindIndex(true);function first(array){return array?array[0]:undefined}function flatten(array,isDeep,guard){var length=array?array.length:0;if(guard&&isIterateeCall(array,isDeep,guard)){isDeep=false}return length?baseFlatten(array,isDeep):[]}function flattenDeep(array){var length=array?array.length:0;return length?baseFlatten(array,true):[]}function indexOf(array,value,fromIndex){var length=array?array.length:0;if(!length){return-1}if(typeof fromIndex=="number"){fromIndex=fromIndex<0?nativeMax(length+fromIndex,0):fromIndex}else if(fromIndex){var index=binaryIndex(array,value);if(index<length&&(value===value?value===array[index]:array[index]!==array[index])){return index}return-1}return baseIndexOf(array,value,fromIndex||0)}function initial(array){return dropRight(array,1)}var intersection=restParam(function(arrays){var othLength=arrays.length,othIndex=othLength,caches=Array(length),indexOf=getIndexOf(),isCommon=indexOf==baseIndexOf,result=[];while(othIndex--){var value=arrays[othIndex]=isArrayLike(value=arrays[othIndex])?value:[];caches[othIndex]=isCommon&&value.length>=120?createCache(othIndex&&value):null}var array=arrays[0],index=-1,length=array?array.length:0,seen=caches[0];outer:while(++index<length){value=array[index];if((seen?cacheIndexOf(seen,value):indexOf(result,value,0))<0){var othIndex=othLength;while(--othIndex){var cache=caches[othIndex];if((cache?cacheIndexOf(cache,value):indexOf(arrays[othIndex],value,0))<0){continue outer}}if(seen){seen.push(value)}result.push(value)}}return result});function last(array){var length=array?array.length:0;return length?array[length-1]:undefined}function lastIndexOf(array,value,fromIndex){var length=array?array.length:0;if(!length){return-1}var index=length;if(typeof fromIndex=="number"){index=(fromIndex<0?nativeMax(length+fromIndex,0):nativeMin(fromIndex||0,length-1))+1}else if(fromIndex){index=binaryIndex(array,value,true)-1;var other=array[index];if(value===value?value===other:other!==other){return index}return-1}if(value!==value){return indexOfNaN(array,index,true)}while(index--){if(array[index]===value){return index}}return-1}function pull(){var args=arguments,array=args[0];if(!(array&&array.length)){return array}var index=0,indexOf=getIndexOf(),length=args.length;while(++index<length){var fromIndex=0,value=args[index];while((fromIndex=indexOf(array,value,fromIndex))>-1){splice.call(array,fromIndex,1)}}return array}var pullAt=restParam(function(array,indexes){indexes=baseFlatten(indexes);var result=baseAt(array,indexes);basePullAt(array,indexes.sort(baseCompareAscending));return result});function remove(array,predicate,thisArg){var result=[];if(!(array&&array.length)){return result}var index=-1,indexes=[],length=array.length;predicate=getCallback(predicate,thisArg,3);while(++index<length){var value=array[index];if(predicate(value,index,array)){result.push(value);indexes.push(index)}}basePullAt(array,indexes);return result}function rest(array){return drop(array,1)}function slice(array,start,end){var length=array?array.length:0;if(!length){return[]}if(end&&typeof end!="number"&&isIterateeCall(array,start,end)){start=0;end=length}return baseSlice(array,start,end)}var sortedIndex=createSortedIndex();var sortedLastIndex=createSortedIndex(true);function take(array,n,guard){var length=array?array.length:0;if(!length){return[]}if(guard?isIterateeCall(array,n,guard):n==null){n=1}return baseSlice(array,0,n<0?0:n)}function takeRight(array,n,guard){var length=array?array.length:0;if(!length){return[]}if(guard?isIterateeCall(array,n,guard):n==null){n=1}n=length-(+n||0);return baseSlice(array,n<0?0:n)}function takeRightWhile(array,predicate,thisArg){return array&&array.length?baseWhile(array,getCallback(predicate,thisArg,3),false,true):[]}function takeWhile(array,predicate,thisArg){return array&&array.length?baseWhile(array,getCallback(predicate,thisArg,3)):[]}var union=restParam(function(arrays){return baseUniq(baseFlatten(arrays,false,true))});function uniq(array,isSorted,iteratee,thisArg){var length=array?array.length:0;if(!length){return[]}if(isSorted!=null&&typeof isSorted!="boolean"){thisArg=iteratee;iteratee=isIterateeCall(array,isSorted,thisArg)?undefined:isSorted;isSorted=false}var callback=getCallback();if(!(iteratee==null&&callback===baseCallback)){iteratee=callback(iteratee,thisArg,3)}return isSorted&&getIndexOf()==baseIndexOf?sortedUniq(array,iteratee):baseUniq(array,iteratee)}function unzip(array){if(!(array&&array.length)){return[]}var index=-1,length=0;array=arrayFilter(array,function(group){if(isArrayLike(group)){length=nativeMax(group.length,length);return true}});var result=Array(length);while(++index<length){result[index]=arrayMap(array,baseProperty(index))}return result}function unzipWith(array,iteratee,thisArg){var length=array?array.length:0;if(!length){return[]}var result=unzip(array);if(iteratee==null){return result}iteratee=bindCallback(iteratee,thisArg,4);return arrayMap(result,function(group){return arrayReduce(group,iteratee,undefined,true)})}var without=restParam(function(array,values){return isArrayLike(array)?baseDifference(array,values):[]});function xor(){var index=-1,length=arguments.length;while(++index<length){var array=arguments[index];if(isArrayLike(array)){var result=result?arrayPush(baseDifference(result,array),baseDifference(array,result)):array}}return result?baseUniq(result):[]}var zip=restParam(unzip);function zipObject(props,values){var index=-1,length=props?props.length:0,result={};if(length&&!values&&!isArray(props[0])){values=[]}while(++index<length){var key=props[index];if(values){result[key]=values[index]}else if(key){result[key[0]]=key[1]}}return result}var zipWith=restParam(function(arrays){var length=arrays.length,iteratee=length>2?arrays[length-2]:undefined,thisArg=length>1?arrays[length-1]:undefined;if(length>2&&typeof iteratee=="function"){length-=2}else{iteratee=length>1&&typeof thisArg=="function"?(--length,thisArg):undefined;thisArg=undefined}arrays.length=length;return unzipWith(arrays,iteratee,thisArg)});function chain(value){var result=lodash(value);result.__chain__=true;return result}function tap(value,interceptor,thisArg){interceptor.call(thisArg,value);return value}function thru(value,interceptor,thisArg){return interceptor.call(thisArg,value)}function wrapperChain(){return chain(this)}function wrapperCommit(){return new LodashWrapper(this.value(),this.__chain__)}var wrapperConcat=restParam(function(values){values=baseFlatten(values);return this.thru(function(array){return arrayConcat(isArray(array)?array:[toObject(array)],values)})});function wrapperPlant(value){var result,parent=this;while(parent instanceof baseLodash){var clone=wrapperClone(parent);if(result){previous.__wrapped__=clone}else{result=clone}var previous=clone;parent=parent.__wrapped__}previous.__wrapped__=value;return result}function wrapperReverse(){var value=this.__wrapped__;var interceptor=function(value){return wrapped&&wrapped.__dir__<0?value:value.reverse()};if(value instanceof LazyWrapper){var wrapped=value;if(this.__actions__.length){wrapped=new LazyWrapper(this)}wrapped=wrapped.reverse();wrapped.__actions__.push({func:thru,args:[interceptor],thisArg:undefined});return new LodashWrapper(wrapped,this.__chain__)}return this.thru(interceptor)}function wrapperToString(){return this.value()+""}function wrapperValue(){return baseWrapperValue(this.__wrapped__,this.__actions__)}var at=restParam(function(collection,props){return baseAt(collection,baseFlatten(props))});var countBy=createAggregator(function(result,value,key){hasOwnProperty.call(result,key)?++result[key]:result[key]=1});function every(collection,predicate,thisArg){var func=isArray(collection)?arrayEvery:baseEvery;if(thisArg&&isIterateeCall(collection,predicate,thisArg)){predicate=undefined}if(typeof predicate!="function"||thisArg!==undefined){predicate=getCallback(predicate,thisArg,3)
+}return func(collection,predicate)}function filter(collection,predicate,thisArg){var func=isArray(collection)?arrayFilter:baseFilter;predicate=getCallback(predicate,thisArg,3);return func(collection,predicate)}var find=createFind(baseEach);var findLast=createFind(baseEachRight,true);function findWhere(collection,source){return find(collection,baseMatches(source))}var forEach=createForEach(arrayEach,baseEach);var forEachRight=createForEach(arrayEachRight,baseEachRight);var groupBy=createAggregator(function(result,value,key){if(hasOwnProperty.call(result,key)){result[key].push(value)}else{result[key]=[value]}});function includes(collection,target,fromIndex,guard){var length=collection?getLength(collection):0;if(!isLength(length)){collection=values(collection);length=collection.length}if(typeof fromIndex!="number"||guard&&isIterateeCall(target,fromIndex,guard)){fromIndex=0}else{fromIndex=fromIndex<0?nativeMax(length+fromIndex,0):fromIndex||0}return typeof collection=="string"||!isArray(collection)&&isString(collection)?fromIndex<=length&&collection.indexOf(target,fromIndex)>-1:!!length&&getIndexOf(collection,target,fromIndex)>-1}var indexBy=createAggregator(function(result,value,key){result[key]=value});var invoke=restParam(function(collection,path,args){var index=-1,isFunc=typeof path=="function",isProp=isKey(path),result=isArrayLike(collection)?Array(collection.length):[];baseEach(collection,function(value){var func=isFunc?path:isProp&&value!=null?value[path]:undefined;result[++index]=func?func.apply(value,args):invokePath(value,path,args)});return result});function map(collection,iteratee,thisArg){var func=isArray(collection)?arrayMap:baseMap;iteratee=getCallback(iteratee,thisArg,3);return func(collection,iteratee)}var partition=createAggregator(function(result,value,key){result[key?0:1].push(value)},function(){return[[],[]]});function pluck(collection,path){return map(collection,property(path))}var reduce=createReduce(arrayReduce,baseEach);var reduceRight=createReduce(arrayReduceRight,baseEachRight);function reject(collection,predicate,thisArg){var func=isArray(collection)?arrayFilter:baseFilter;predicate=getCallback(predicate,thisArg,3);return func(collection,function(value,index,collection){return!predicate(value,index,collection)})}function sample(collection,n,guard){if(guard?isIterateeCall(collection,n,guard):n==null){collection=toIterable(collection);var length=collection.length;return length>0?collection[baseRandom(0,length-1)]:undefined}var index=-1,result=toArray(collection),length=result.length,lastIndex=length-1;n=nativeMin(n<0?0:+n||0,length);while(++index<n){var rand=baseRandom(index,lastIndex),value=result[rand];result[rand]=result[index];result[index]=value}result.length=n;return result}function shuffle(collection){return sample(collection,POSITIVE_INFINITY)}function size(collection){var length=collection?getLength(collection):0;return isLength(length)?length:keys(collection).length}function some(collection,predicate,thisArg){var func=isArray(collection)?arraySome:baseSome;if(thisArg&&isIterateeCall(collection,predicate,thisArg)){predicate=undefined}if(typeof predicate!="function"||thisArg!==undefined){predicate=getCallback(predicate,thisArg,3)}return func(collection,predicate)}function sortBy(collection,iteratee,thisArg){if(collection==null){return[]}if(thisArg&&isIterateeCall(collection,iteratee,thisArg)){iteratee=undefined}var index=-1;iteratee=getCallback(iteratee,thisArg,3);var result=baseMap(collection,function(value,key,collection){return{criteria:iteratee(value,key,collection),index:++index,value:value}});return baseSortBy(result,compareAscending)}var sortByAll=restParam(function(collection,iteratees){if(collection==null){return[]}var guard=iteratees[2];if(guard&&isIterateeCall(iteratees[0],iteratees[1],guard)){iteratees.length=1}return baseSortByOrder(collection,baseFlatten(iteratees),[])});function sortByOrder(collection,iteratees,orders,guard){if(collection==null){return[]}if(guard&&isIterateeCall(iteratees,orders,guard)){orders=undefined}if(!isArray(iteratees)){iteratees=iteratees==null?[]:[iteratees]}if(!isArray(orders)){orders=orders==null?[]:[orders]}return baseSortByOrder(collection,iteratees,orders)}function where(collection,source){return filter(collection,baseMatches(source))}var now=nativeNow||function(){return(new Date).getTime()};function after(n,func){if(typeof func!="function"){if(typeof n=="function"){var temp=n;n=func;func=temp}else{throw new TypeError(FUNC_ERROR_TEXT)}}n=nativeIsFinite(n=+n)?n:0;return function(){if(--n<1){return func.apply(this,arguments)}}}function ary(func,n,guard){if(guard&&isIterateeCall(func,n,guard)){n=undefined}n=func&&n==null?func.length:nativeMax(+n||0,0);return createWrapper(func,ARY_FLAG,undefined,undefined,undefined,undefined,n)}function before(n,func){var result;if(typeof func!="function"){if(typeof n=="function"){var temp=n;n=func;func=temp}else{throw new TypeError(FUNC_ERROR_TEXT)}}return function(){if(--n>0){result=func.apply(this,arguments)}if(n<=1){func=undefined}return result}}var bind=restParam(function(func,thisArg,partials){var bitmask=BIND_FLAG;if(partials.length){var holders=replaceHolders(partials,bind.placeholder);bitmask|=PARTIAL_FLAG}return createWrapper(func,bitmask,thisArg,partials,holders)});var bindAll=restParam(function(object,methodNames){methodNames=methodNames.length?baseFlatten(methodNames):functions(object);var index=-1,length=methodNames.length;while(++index<length){var key=methodNames[index];object[key]=createWrapper(object[key],BIND_FLAG,object)}return object});var bindKey=restParam(function(object,key,partials){var bitmask=BIND_FLAG|BIND_KEY_FLAG;if(partials.length){var holders=replaceHolders(partials,bindKey.placeholder);bitmask|=PARTIAL_FLAG}return createWrapper(key,bitmask,object,partials,holders)});var curry=createCurry(CURRY_FLAG);var curryRight=createCurry(CURRY_RIGHT_FLAG);function debounce(func,wait,options){var args,maxTimeoutId,result,stamp,thisArg,timeoutId,trailingCall,lastCalled=0,maxWait=false,trailing=true;if(typeof func!="function"){throw new TypeError(FUNC_ERROR_TEXT)}wait=wait<0?0:+wait||0;if(options===true){var leading=true;trailing=false}else if(isObject(options)){leading=!!options.leading;maxWait="maxWait"in options&&nativeMax(+options.maxWait||0,wait);trailing="trailing"in options?!!options.trailing:trailing}function cancel(){if(timeoutId){clearTimeout(timeoutId)}if(maxTimeoutId){clearTimeout(maxTimeoutId)}lastCalled=0;maxTimeoutId=timeoutId=trailingCall=undefined}function complete(isCalled,id){if(id){clearTimeout(id)}maxTimeoutId=timeoutId=trailingCall=undefined;if(isCalled){lastCalled=now();result=func.apply(thisArg,args);if(!timeoutId&&!maxTimeoutId){args=thisArg=undefined}}}function delayed(){var remaining=wait-(now()-stamp);if(remaining<=0||remaining>wait){complete(trailingCall,maxTimeoutId)}else{timeoutId=setTimeout(delayed,remaining)}}function maxDelayed(){complete(trailing,timeoutId)}function debounced(){args=arguments;stamp=now();thisArg=this;trailingCall=trailing&&(timeoutId||!leading);if(maxWait===false){var leadingCall=leading&&!timeoutId}else{if(!maxTimeoutId&&!leading){lastCalled=stamp}var remaining=maxWait-(stamp-lastCalled),isCalled=remaining<=0||remaining>maxWait;if(isCalled){if(maxTimeoutId){maxTimeoutId=clearTimeout(maxTimeoutId)}lastCalled=stamp;result=func.apply(thisArg,args)}else if(!maxTimeoutId){maxTimeoutId=setTimeout(maxDelayed,remaining)}}if(isCalled&&timeoutId){timeoutId=clearTimeout(timeoutId)}else if(!timeoutId&&wait!==maxWait){timeoutId=setTimeout(delayed,wait)}if(leadingCall){isCalled=true;result=func.apply(thisArg,args)}if(isCalled&&!timeoutId&&!maxTimeoutId){args=thisArg=undefined}return result}debounced.cancel=cancel;return debounced}var defer=restParam(function(func,args){return baseDelay(func,1,args)});var delay=restParam(function(func,wait,args){return baseDelay(func,wait,args)});var flow=createFlow();var flowRight=createFlow(true);function memoize(func,resolver){if(typeof func!="function"||resolver&&typeof resolver!="function"){throw new TypeError(FUNC_ERROR_TEXT)}var memoized=function(){var args=arguments,key=resolver?resolver.apply(this,args):args[0],cache=memoized.cache;if(cache.has(key)){return cache.get(key)}var result=func.apply(this,args);memoized.cache=cache.set(key,result);return result};memoized.cache=new memoize.Cache;return memoized}var modArgs=restParam(function(func,transforms){transforms=baseFlatten(transforms);if(typeof func!="function"||!arrayEvery(transforms,baseIsFunction)){throw new TypeError(FUNC_ERROR_TEXT)}var length=transforms.length;return restParam(function(args){var index=nativeMin(args.length,length);while(index--){args[index]=transforms[index](args[index])}return func.apply(this,args)})});function negate(predicate){if(typeof predicate!="function"){throw new TypeError(FUNC_ERROR_TEXT)}return function(){return!predicate.apply(this,arguments)}}function once(func){return before(2,func)}var partial=createPartial(PARTIAL_FLAG);var partialRight=createPartial(PARTIAL_RIGHT_FLAG);var rearg=restParam(function(func,indexes){return createWrapper(func,REARG_FLAG,undefined,undefined,undefined,baseFlatten(indexes))});function restParam(func,start){if(typeof func!="function"){throw new TypeError(FUNC_ERROR_TEXT)}start=nativeMax(start===undefined?func.length-1:+start||0,0);return function(){var args=arguments,index=-1,length=nativeMax(args.length-start,0),rest=Array(length);while(++index<length){rest[index]=args[start+index]}switch(start){case 0:return func.call(this,rest);case 1:return func.call(this,args[0],rest);case 2:return func.call(this,args[0],args[1],rest)}var otherArgs=Array(start+1);index=-1;while(++index<start){otherArgs[index]=args[index]}otherArgs[start]=rest;return func.apply(this,otherArgs)}}function spread(func){if(typeof func!="function"){throw new TypeError(FUNC_ERROR_TEXT)}return function(array){return func.apply(this,array)}}function throttle(func,wait,options){var leading=true,trailing=true;if(typeof func!="function"){throw new TypeError(FUNC_ERROR_TEXT)}if(options===false){leading=false}else if(isObject(options)){leading="leading"in options?!!options.leading:leading;trailing="trailing"in options?!!options.trailing:trailing}return debounce(func,wait,{leading:leading,maxWait:+wait,trailing:trailing})}function wrap(value,wrapper){wrapper=wrapper==null?identity:wrapper;return createWrapper(wrapper,PARTIAL_FLAG,undefined,[value],[])}function clone(value,isDeep,customizer,thisArg){if(isDeep&&typeof isDeep!="boolean"&&isIterateeCall(value,isDeep,customizer)){isDeep=false}else if(typeof isDeep=="function"){thisArg=customizer;customizer=isDeep;isDeep=false}return typeof customizer=="function"?baseClone(value,isDeep,bindCallback(customizer,thisArg,1)):baseClone(value,isDeep)}function cloneDeep(value,customizer,thisArg){return typeof customizer=="function"?baseClone(value,true,bindCallback(customizer,thisArg,1)):baseClone(value,true)}function gt(value,other){return value>other}function gte(value,other){return value>=other}function isArguments(value){return isObjectLike(value)&&isArrayLike(value)&&hasOwnProperty.call(value,"callee")&&!propertyIsEnumerable.call(value,"callee")}var isArray=nativeIsArray||function(value){return isObjectLike(value)&&isLength(value.length)&&objToString.call(value)==arrayTag};function isBoolean(value){return value===true||value===false||isObjectLike(value)&&objToString.call(value)==boolTag}function isDate(value){return isObjectLike(value)&&objToString.call(value)==dateTag}function isElement(value){return!!value&&value.nodeType===1&&isObjectLike(value)&&!isPlainObject(value)}function isEmpty(value){if(value==null){return true}if(isArrayLike(value)&&(isArray(value)||isString(value)||isArguments(value)||isObjectLike(value)&&isFunction(value.splice))){return!value.length}return!keys(value).length}function isEqual(value,other,customizer,thisArg){customizer=typeof customizer=="function"?bindCallback(customizer,thisArg,3):undefined;var result=customizer?customizer(value,other):undefined;return result===undefined?baseIsEqual(value,other,customizer):!!result}function isError(value){return isObjectLike(value)&&typeof value.message=="string"&&objToString.call(value)==errorTag}function isFinite(value){return typeof value=="number"&&nativeIsFinite(value)}function isFunction(value){return isObject(value)&&objToString.call(value)==funcTag}function isObject(value){var type=typeof value;return!!value&&(type=="object"||type=="function")}function isMatch(object,source,customizer,thisArg){customizer=typeof customizer=="function"?bindCallback(customizer,thisArg,3):undefined;return baseIsMatch(object,getMatchData(source),customizer)}function isNaN(value){return isNumber(value)&&value!=+value}function isNative(value){if(value==null){return false}if(isFunction(value)){return reIsNative.test(fnToString.call(value))}return isObjectLike(value)&&reIsHostCtor.test(value)}function isNull(value){return value===null}function isNumber(value){return typeof value=="number"||isObjectLike(value)&&objToString.call(value)==numberTag}function isPlainObject(value){var Ctor;if(!(isObjectLike(value)&&objToString.call(value)==objectTag&&!isArguments(value))||!hasOwnProperty.call(value,"constructor")&&(Ctor=value.constructor,typeof Ctor=="function"&&!(Ctor instanceof Ctor))){return false}var result;baseForIn(value,function(subValue,key){result=key});return result===undefined||hasOwnProperty.call(value,result)}function isRegExp(value){return isObject(value)&&objToString.call(value)==regexpTag}function isString(value){return typeof value=="string"||isObjectLike(value)&&objToString.call(value)==stringTag}function isTypedArray(value){return isObjectLike(value)&&isLength(value.length)&&!!typedArrayTags[objToString.call(value)]}function isUndefined(value){return value===undefined}function lt(value,other){return value<other}function lte(value,other){return value<=other}function toArray(value){var length=value?getLength(value):0;if(!isLength(length)){return values(value)}if(!length){return[]}return arrayCopy(value)}function toPlainObject(value){return baseCopy(value,keysIn(value))}var merge=createAssigner(baseMerge);var assign=createAssigner(function(object,source,customizer){return customizer?assignWith(object,source,customizer):baseAssign(object,source)});function create(prototype,properties,guard){var result=baseCreate(prototype);if(guard&&isIterateeCall(prototype,properties,guard)){properties=undefined}return properties?baseAssign(result,properties):result}var defaults=createDefaults(assign,assignDefaults);var defaultsDeep=createDefaults(merge,mergeDefaults);var findKey=createFindKey(baseForOwn);var findLastKey=createFindKey(baseForOwnRight);var forIn=createForIn(baseFor);var forInRight=createForIn(baseForRight);var forOwn=createForOwn(baseForOwn);var forOwnRight=createForOwn(baseForOwnRight);function functions(object){return baseFunctions(object,keysIn(object))}function get(object,path,defaultValue){var result=object==null?undefined:baseGet(object,toPath(path),path+"");return result===undefined?defaultValue:result}function has(object,path){if(object==null){return false}var result=hasOwnProperty.call(object,path);if(!result&&!isKey(path)){path=toPath(path);object=path.length==1?object:baseGet(object,baseSlice(path,0,-1));if(object==null){return false}path=last(path);result=hasOwnProperty.call(object,path)}return result||isLength(object.length)&&isIndex(path,object.length)&&(isArray(object)||isArguments(object))}function invert(object,multiValue,guard){if(guard&&isIterateeCall(object,multiValue,guard)){multiValue=undefined}var index=-1,props=keys(object),length=props.length,result={};while(++index<length){var key=props[index],value=object[key];if(multiValue){if(hasOwnProperty.call(result,value)){result[value].push(key)}else{result[value]=[key]}}else{result[value]=key}}return result}var keys=!nativeKeys?shimKeys:function(object){var Ctor=object==null?undefined:object.constructor;if(typeof Ctor=="function"&&Ctor.prototype===object||typeof object!="function"&&isArrayLike(object)){return shimKeys(object)}return isObject(object)?nativeKeys(object):[]};function keysIn(object){if(object==null){return[]}if(!isObject(object)){object=Object(object)}var length=object.length;length=length&&isLength(length)&&(isArray(object)||isArguments(object))&&length||0;var Ctor=object.constructor,index=-1,isProto=typeof Ctor=="function"&&Ctor.prototype===object,result=Array(length),skipIndexes=length>0;while(++index<length){result[index]=index+""}for(var key in object){if(!(skipIndexes&&isIndex(key,length))&&!(key=="constructor"&&(isProto||!hasOwnProperty.call(object,key)))){result.push(key)}}return result}var mapKeys=createObjectMapper(true);var mapValues=createObjectMapper();var omit=restParam(function(object,props){if(object==null){return{}}if(typeof props[0]!="function"){var props=arrayMap(baseFlatten(props),String);return pickByArray(object,baseDifference(keysIn(object),props))}var predicate=bindCallback(props[0],props[1],3);return pickByCallback(object,function(value,key,object){return!predicate(value,key,object)})});function pairs(object){object=toObject(object);var index=-1,props=keys(object),length=props.length,result=Array(length);while(++index<length){var key=props[index];result[index]=[key,object[key]]}return result}var pick=restParam(function(object,props){if(object==null){return{}}return typeof props[0]=="function"?pickByCallback(object,bindCallback(props[0],props[1],3)):pickByArray(object,baseFlatten(props))});function result(object,path,defaultValue){var result=object==null?undefined:object[path];if(result===undefined){if(object!=null&&!isKey(path,object)){path=toPath(path);object=path.length==1?object:baseGet(object,baseSlice(path,0,-1));result=object==null?undefined:object[last(path)]}result=result===undefined?defaultValue:result}return isFunction(result)?result.call(object):result}function set(object,path,value){if(object==null){return object}var pathKey=path+"";path=object[pathKey]!=null||isKey(path,object)?[pathKey]:toPath(path);var index=-1,length=path.length,lastIndex=length-1,nested=object;while(nested!=null&&++index<length){var key=path[index];if(isObject(nested)){if(index==lastIndex){nested[key]=value}else if(nested[key]==null){nested[key]=isIndex(path[index+1])?[]:{}}}nested=nested[key]}return object}function transform(object,iteratee,accumulator,thisArg){var isArr=isArray(object)||isTypedArray(object);iteratee=getCallback(iteratee,thisArg,4);if(accumulator==null){if(isArr||isObject(object)){var Ctor=object.constructor;if(isArr){accumulator=isArray(object)?new Ctor:[]}else{accumulator=baseCreate(isFunction(Ctor)?Ctor.prototype:undefined)}}else{accumulator={}}}(isArr?arrayEach:baseForOwn)(object,function(value,index,object){return iteratee(accumulator,value,index,object)});return accumulator}function values(object){return baseValues(object,keys(object))}function valuesIn(object){return baseValues(object,keysIn(object))}function inRange(value,start,end){start=+start||0;if(end===undefined){end=start;start=0}else{end=+end||0}return value>=nativeMin(start,end)&&value<nativeMax(start,end)}function random(min,max,floating){if(floating&&isIterateeCall(min,max,floating)){max=floating=undefined}var noMin=min==null,noMax=max==null;if(floating==null){if(noMax&&typeof min=="boolean"){floating=min;min=1}else if(typeof max=="boolean"){floating=max;noMax=true}}if(noMin&&noMax){max=1;noMax=false}min=+min||0;if(noMax){max=min;min=0}else{max=+max||0}if(floating||min%1||max%1){var rand=nativeRandom();return nativeMin(min+rand*(max-min+parseFloat("1e-"+((rand+"").length-1))),max)}return baseRandom(min,max)}var camelCase=createCompounder(function(result,word,index){word=word.toLowerCase();return result+(index?word.charAt(0).toUpperCase()+word.slice(1):word)});function capitalize(string){string=baseToString(string);return string&&string.charAt(0).toUpperCase()+string.slice(1)}function deburr(string){string=baseToString(string);return string&&string.replace(reLatin1,deburrLetter).replace(reComboMark,"")}function endsWith(string,target,position){string=baseToString(string);target=target+"";var length=string.length;position=position===undefined?length:nativeMin(position<0?0:+position||0,length);position-=target.length;return position>=0&&string.indexOf(target,position)==position}function escape(string){string=baseToString(string);return string&&reHasUnescapedHtml.test(string)?string.replace(reUnescapedHtml,escapeHtmlChar):string}function escapeRegExp(string){string=baseToString(string);return string&&reHasRegExpChars.test(string)?string.replace(reRegExpChars,escapeRegExpChar):string||"(?:)"}var kebabCase=createCompounder(function(result,word,index){return result+(index?"-":"")+word.toLowerCase()});function pad(string,length,chars){string=baseToString(string);length=+length;var strLength=string.length;if(strLength>=length||!nativeIsFinite(length)){return string}var mid=(length-strLength)/2,leftLength=nativeFloor(mid),rightLength=nativeCeil(mid);chars=createPadding("",rightLength,chars);return chars.slice(0,leftLength)+string+chars}var padLeft=createPadDir();var padRight=createPadDir(true);function parseInt(string,radix,guard){if(guard?isIterateeCall(string,radix,guard):radix==null){radix=0}else if(radix){radix=+radix}string=trim(string);return nativeParseInt(string,radix||(reHasHexPrefix.test(string)?16:10))}function repeat(string,n){var result="";string=baseToString(string);n=+n;if(n<1||!string||!nativeIsFinite(n)){return result}do{if(n%2){result+=string}n=nativeFloor(n/2);string+=string}while(n);return result}var snakeCase=createCompounder(function(result,word,index){return result+(index?"_":"")+word.toLowerCase()});var startCase=createCompounder(function(result,word,index){return result+(index?" ":"")+(word.charAt(0).toUpperCase()+word.slice(1))});function startsWith(string,target,position){string=baseToString(string);position=position==null?0:nativeMin(position<0?0:+position||0,string.length);return string.lastIndexOf(target,position)==position}function template(string,options,otherOptions){var settings=lodash.templateSettings;if(otherOptions&&isIterateeCall(string,options,otherOptions)){options=otherOptions=undefined}string=baseToString(string);options=assignWith(baseAssign({},otherOptions||options),settings,assignOwnDefaults);var imports=assignWith(baseAssign({},options.imports),settings.imports,assignOwnDefaults),importsKeys=keys(imports),importsValues=baseValues(imports,importsKeys);var isEscaping,isEvaluating,index=0,interpolate=options.interpolate||reNoMatch,source="__p += '";var reDelimiters=RegExp((options.escape||reNoMatch).source+"|"+interpolate.source+"|"+(interpolate===reInterpolate?reEsTemplate:reNoMatch).source+"|"+(options.evaluate||reNoMatch).source+"|$","g");var sourceURL="//# sourceURL="+("sourceURL"in options?options.sourceURL:"lodash.templateSources["+ ++templateCounter+"]")+"\n";string.replace(reDelimiters,function(match,escapeValue,interpolateValue,esTemplateValue,evaluateValue,offset){interpolateValue||(interpolateValue=esTemplateValue);source+=string.slice(index,offset).replace(reUnescapedString,escapeStringChar);if(escapeValue){isEscaping=true;source+="' +\n__e("+escapeValue+") +\n'"}if(evaluateValue){isEvaluating=true;source+="';\n"+evaluateValue+";\n__p += '"}if(interpolateValue){source+="' +\n((__t = ("+interpolateValue+")) == null ? '' : __t) +\n'"}index=offset+match.length;return match});source+="';\n";var variable=options.variable;if(!variable){source="with (obj) {\n"+source+"\n}\n"}source=(isEvaluating?source.replace(reEmptyStringLeading,""):source).replace(reEmptyStringMiddle,"$1").replace(reEmptyStringTrailing,"$1;");source="function("+(variable||"obj")+") {\n"+(variable?"":"obj || (obj = {});\n")+"var __t, __p = ''"+(isEscaping?", __e = _.escape":"")+(isEvaluating?", __j = Array.prototype.join;\n"+"function print() { __p += __j.call(arguments, '') }\n":";\n")+source+"return __p\n}";var result=attempt(function(){return Function(importsKeys,sourceURL+"return "+source).apply(undefined,importsValues)});result.source=source;if(isError(result)){throw result}return result}function trim(string,chars,guard){var value=string;string=baseToString(string);if(!string){return string}if(guard?isIterateeCall(value,chars,guard):chars==null){return string.slice(trimmedLeftIndex(string),trimmedRightIndex(string)+1)}chars=chars+"";return string.slice(charsLeftIndex(string,chars),charsRightIndex(string,chars)+1)}function trimLeft(string,chars,guard){var value=string;string=baseToString(string);if(!string){return string}if(guard?isIterateeCall(value,chars,guard):chars==null){return string.slice(trimmedLeftIndex(string))}return string.slice(charsLeftIndex(string,chars+""))}function trimRight(string,chars,guard){var value=string;string=baseToString(string);if(!string){return string}if(guard?isIterateeCall(value,chars,guard):chars==null){return string.slice(0,trimmedRightIndex(string)+1)}return string.slice(0,charsRightIndex(string,chars+"")+1)}function trunc(string,options,guard){if(guard&&isIterateeCall(string,options,guard)){options=undefined}var length=DEFAULT_TRUNC_LENGTH,omission=DEFAULT_TRUNC_OMISSION;if(options!=null){if(isObject(options)){var separator="separator"in options?options.separator:separator;length="length"in options?+options.length||0:length;omission="omission"in options?baseToString(options.omission):omission}else{length=+options||0}}string=baseToString(string);if(length>=string.length){return string}var end=length-omission.length;if(end<1){return omission}var result=string.slice(0,end);if(separator==null){return result+omission}if(isRegExp(separator)){if(string.slice(end).search(separator)){var match,newEnd,substring=string.slice(0,end);if(!separator.global){separator=RegExp(separator.source,(reFlags.exec(separator)||"")+"g")}separator.lastIndex=0;while(match=separator.exec(substring)){newEnd=match.index}result=result.slice(0,newEnd==null?end:newEnd)}}else if(string.indexOf(separator,end)!=end){var index=result.lastIndexOf(separator);if(index>-1){result=result.slice(0,index)}}return result+omission}function unescape(string){string=baseToString(string);return string&&reHasEscapedHtml.test(string)?string.replace(reEscapedHtml,unescapeHtmlChar):string}function words(string,pattern,guard){if(guard&&isIterateeCall(string,pattern,guard)){pattern=undefined}string=baseToString(string);return string.match(pattern||reWords)||[]}var attempt=restParam(function(func,args){try{return func.apply(undefined,args)}catch(e){return isError(e)?e:new Error(e)}});function callback(func,thisArg,guard){if(guard&&isIterateeCall(func,thisArg,guard)){thisArg=undefined}return isObjectLike(func)?matches(func):baseCallback(func,thisArg)}function constant(value){return function(){return value}}function identity(value){return value}function matches(source){return baseMatches(baseClone(source,true))}function matchesProperty(path,srcValue){return baseMatchesProperty(path,baseClone(srcValue,true))}var method=restParam(function(path,args){return function(object){return invokePath(object,path,args)}});var methodOf=restParam(function(object,args){return function(path){return invokePath(object,path,args)}});function mixin(object,source,options){if(options==null){var isObj=isObject(source),props=isObj?keys(source):undefined,methodNames=props&&props.length?baseFunctions(source,props):undefined;if(!(methodNames?methodNames.length:isObj)){methodNames=false;options=source;source=object;object=this}}if(!methodNames){methodNames=baseFunctions(source,keys(source))}var chain=true,index=-1,isFunc=isFunction(object),length=methodNames.length;if(options===false){chain=false}else if(isObject(options)&&"chain"in options){chain=options.chain}while(++index<length){var methodName=methodNames[index],func=source[methodName];object[methodName]=func;if(isFunc){object.prototype[methodName]=function(func){return function(){var chainAll=this.__chain__;if(chain||chainAll){var result=object(this.__wrapped__),actions=result.__actions__=arrayCopy(this.__actions__);actions.push({func:func,args:arguments,thisArg:object});result.__chain__=chainAll;return result}return func.apply(object,arrayPush([this.value()],arguments))}}(func)}}return object}function noConflict(){root._=oldDash;return this}function noop(){}function property(path){return isKey(path)?baseProperty(path):basePropertyDeep(path)}function propertyOf(object){return function(path){return baseGet(object,toPath(path),path+"")}}function range(start,end,step){if(step&&isIterateeCall(start,end,step)){end=step=undefined}start=+start||0;step=step==null?1:+step||0;if(end==null){end=start;start=0}else{end=+end||0}var index=-1,length=nativeMax(nativeCeil((end-start)/(step||1)),0),result=Array(length);while(++index<length){result[index]=start;start+=step}return result}function times(n,iteratee,thisArg){n=nativeFloor(n);if(n<1||!nativeIsFinite(n)){return[]}var index=-1,result=Array(nativeMin(n,MAX_ARRAY_LENGTH));iteratee=bindCallback(iteratee,thisArg,1);while(++index<n){if(index<MAX_ARRAY_LENGTH){result[index]=iteratee(index)}else{iteratee(index)}}return result}function uniqueId(prefix){var id=++idCounter;return baseToString(prefix)+id}function add(augend,addend){return(+augend||0)+(+addend||0)}var ceil=createRound("ceil");var floor=createRound("floor");var max=createExtremum(gt,NEGATIVE_INFINITY);var min=createExtremum(lt,POSITIVE_INFINITY);var round=createRound("round");function sum(collection,iteratee,thisArg){if(thisArg&&isIterateeCall(collection,iteratee,thisArg)){iteratee=undefined}iteratee=getCallback(iteratee,thisArg,3);return iteratee.length==1?arraySum(isArray(collection)?collection:toIterable(collection),iteratee):baseSum(collection,iteratee)}lodash.prototype=baseLodash.prototype;LodashWrapper.prototype=baseCreate(baseLodash.prototype);LodashWrapper.prototype.constructor=LodashWrapper;LazyWrapper.prototype=baseCreate(baseLodash.prototype);LazyWrapper.prototype.constructor=LazyWrapper;MapCache.prototype["delete"]=mapDelete;MapCache.prototype.get=mapGet;MapCache.prototype.has=mapHas;MapCache.prototype.set=mapSet;SetCache.prototype.push=cachePush;memoize.Cache=MapCache;lodash.after=after;lodash.ary=ary;lodash.assign=assign;lodash.at=at;lodash.before=before;lodash.bind=bind;lodash.bindAll=bindAll;lodash.bindKey=bindKey;lodash.callback=callback;lodash.chain=chain;lodash.chunk=chunk;lodash.compact=compact;lodash.constant=constant;lodash.countBy=countBy;lodash.create=create;lodash.curry=curry;lodash.curryRight=curryRight;lodash.debounce=debounce;lodash.defaults=defaults;lodash.defaultsDeep=defaultsDeep;lodash.defer=defer;lodash.delay=delay;lodash.difference=difference;lodash.drop=drop;lodash.dropRight=dropRight;lodash.dropRightWhile=dropRightWhile;lodash.dropWhile=dropWhile;lodash.fill=fill;lodash.filter=filter;lodash.flatten=flatten;lodash.flattenDeep=flattenDeep;lodash.flow=flow;lodash.flowRight=flowRight;lodash.forEach=forEach;lodash.forEachRight=forEachRight;lodash.forIn=forIn;lodash.forInRight=forInRight;lodash.forOwn=forOwn;lodash.forOwnRight=forOwnRight;lodash.functions=functions;lodash.groupBy=groupBy;lodash.indexBy=indexBy;lodash.initial=initial;lodash.intersection=intersection;lodash.invert=invert;lodash.invoke=invoke;lodash.keys=keys;lodash.keysIn=keysIn;lodash.map=map;lodash.mapKeys=mapKeys;lodash.mapValues=mapValues;lodash.matches=matches;lodash.matchesProperty=matchesProperty;lodash.memoize=memoize;lodash.merge=merge;lodash.method=method;lodash.methodOf=methodOf;lodash.mixin=mixin;lodash.modArgs=modArgs;lodash.negate=negate;lodash.omit=omit;lodash.once=once;lodash.pairs=pairs;lodash.partial=partial;lodash.partialRight=partialRight;lodash.partition=partition;lodash.pick=pick;lodash.pluck=pluck;lodash.property=property;lodash.propertyOf=propertyOf;lodash.pull=pull;lodash.pullAt=pullAt;lodash.range=range;lodash.rearg=rearg;lodash.reject=reject;lodash.remove=remove;lodash.rest=rest;lodash.restParam=restParam;lodash.set=set;lodash.shuffle=shuffle;lodash.slice=slice;lodash.sortBy=sortBy;lodash.sortByAll=sortByAll;lodash.sortByOrder=sortByOrder;
+lodash.spread=spread;lodash.take=take;lodash.takeRight=takeRight;lodash.takeRightWhile=takeRightWhile;lodash.takeWhile=takeWhile;lodash.tap=tap;lodash.throttle=throttle;lodash.thru=thru;lodash.times=times;lodash.toArray=toArray;lodash.toPlainObject=toPlainObject;lodash.transform=transform;lodash.union=union;lodash.uniq=uniq;lodash.unzip=unzip;lodash.unzipWith=unzipWith;lodash.values=values;lodash.valuesIn=valuesIn;lodash.where=where;lodash.without=without;lodash.wrap=wrap;lodash.xor=xor;lodash.zip=zip;lodash.zipObject=zipObject;lodash.zipWith=zipWith;lodash.backflow=flowRight;lodash.collect=map;lodash.compose=flowRight;lodash.each=forEach;lodash.eachRight=forEachRight;lodash.extend=assign;lodash.iteratee=callback;lodash.methods=functions;lodash.object=zipObject;lodash.select=filter;lodash.tail=rest;lodash.unique=uniq;mixin(lodash,lodash);lodash.add=add;lodash.attempt=attempt;lodash.camelCase=camelCase;lodash.capitalize=capitalize;lodash.ceil=ceil;lodash.clone=clone;lodash.cloneDeep=cloneDeep;lodash.deburr=deburr;lodash.endsWith=endsWith;lodash.escape=escape;lodash.escapeRegExp=escapeRegExp;lodash.every=every;lodash.find=find;lodash.findIndex=findIndex;lodash.findKey=findKey;lodash.findLast=findLast;lodash.findLastIndex=findLastIndex;lodash.findLastKey=findLastKey;lodash.findWhere=findWhere;lodash.first=first;lodash.floor=floor;lodash.get=get;lodash.gt=gt;lodash.gte=gte;lodash.has=has;lodash.identity=identity;lodash.includes=includes;lodash.indexOf=indexOf;lodash.inRange=inRange;lodash.isArguments=isArguments;lodash.isArray=isArray;lodash.isBoolean=isBoolean;lodash.isDate=isDate;lodash.isElement=isElement;lodash.isEmpty=isEmpty;lodash.isEqual=isEqual;lodash.isError=isError;lodash.isFinite=isFinite;lodash.isFunction=isFunction;lodash.isMatch=isMatch;lodash.isNaN=isNaN;lodash.isNative=isNative;lodash.isNull=isNull;lodash.isNumber=isNumber;lodash.isObject=isObject;lodash.isPlainObject=isPlainObject;lodash.isRegExp=isRegExp;lodash.isString=isString;lodash.isTypedArray=isTypedArray;lodash.isUndefined=isUndefined;lodash.kebabCase=kebabCase;lodash.last=last;lodash.lastIndexOf=lastIndexOf;lodash.lt=lt;lodash.lte=lte;lodash.max=max;lodash.min=min;lodash.noConflict=noConflict;lodash.noop=noop;lodash.now=now;lodash.pad=pad;lodash.padLeft=padLeft;lodash.padRight=padRight;lodash.parseInt=parseInt;lodash.random=random;lodash.reduce=reduce;lodash.reduceRight=reduceRight;lodash.repeat=repeat;lodash.result=result;lodash.round=round;lodash.runInContext=runInContext;lodash.size=size;lodash.snakeCase=snakeCase;lodash.some=some;lodash.sortedIndex=sortedIndex;lodash.sortedLastIndex=sortedLastIndex;lodash.startCase=startCase;lodash.startsWith=startsWith;lodash.sum=sum;lodash.template=template;lodash.trim=trim;lodash.trimLeft=trimLeft;lodash.trimRight=trimRight;lodash.trunc=trunc;lodash.unescape=unescape;lodash.uniqueId=uniqueId;lodash.words=words;lodash.all=every;lodash.any=some;lodash.contains=includes;lodash.eq=isEqual;lodash.detect=find;lodash.foldl=reduce;lodash.foldr=reduceRight;lodash.head=first;lodash.include=includes;lodash.inject=reduce;mixin(lodash,function(){var source={};baseForOwn(lodash,function(func,methodName){if(!lodash.prototype[methodName]){source[methodName]=func}});return source}(),false);lodash.sample=sample;lodash.prototype.sample=function(n){if(!this.__chain__&&n==null){return sample(this.value())}return this.thru(function(value){return sample(value,n)})};lodash.VERSION=VERSION;arrayEach(["bind","bindKey","curry","curryRight","partial","partialRight"],function(methodName){lodash[methodName].placeholder=lodash});arrayEach(["drop","take"],function(methodName,index){LazyWrapper.prototype[methodName]=function(n){var filtered=this.__filtered__;if(filtered&&!index){return new LazyWrapper(this)}n=n==null?1:nativeMax(nativeFloor(n)||0,0);var result=this.clone();if(filtered){result.__takeCount__=nativeMin(result.__takeCount__,n)}else{result.__views__.push({size:n,type:methodName+(result.__dir__<0?"Right":"")})}return result};LazyWrapper.prototype[methodName+"Right"]=function(n){return this.reverse()[methodName](n).reverse()}});arrayEach(["filter","map","takeWhile"],function(methodName,index){var type=index+1,isFilter=type!=LAZY_MAP_FLAG;LazyWrapper.prototype[methodName]=function(iteratee,thisArg){var result=this.clone();result.__iteratees__.push({iteratee:getCallback(iteratee,thisArg,1),type:type});result.__filtered__=result.__filtered__||isFilter;return result}});arrayEach(["first","last"],function(methodName,index){var takeName="take"+(index?"Right":"");LazyWrapper.prototype[methodName]=function(){return this[takeName](1).value()[0]}});arrayEach(["initial","rest"],function(methodName,index){var dropName="drop"+(index?"":"Right");LazyWrapper.prototype[methodName]=function(){return this.__filtered__?new LazyWrapper(this):this[dropName](1)}});arrayEach(["pluck","where"],function(methodName,index){var operationName=index?"filter":"map",createCallback=index?baseMatches:property;LazyWrapper.prototype[methodName]=function(value){return this[operationName](createCallback(value))}});LazyWrapper.prototype.compact=function(){return this.filter(identity)};LazyWrapper.prototype.reject=function(predicate,thisArg){predicate=getCallback(predicate,thisArg,1);return this.filter(function(value){return!predicate(value)})};LazyWrapper.prototype.slice=function(start,end){start=start==null?0:+start||0;var result=this;if(result.__filtered__&&(start>0||end<0)){return new LazyWrapper(result)}if(start<0){result=result.takeRight(-start)}else if(start){result=result.drop(start)}if(end!==undefined){end=+end||0;result=end<0?result.dropRight(-end):result.take(end-start)}return result};LazyWrapper.prototype.takeRightWhile=function(predicate,thisArg){return this.reverse().takeWhile(predicate,thisArg).reverse()};LazyWrapper.prototype.toArray=function(){return this.take(POSITIVE_INFINITY)};baseForOwn(LazyWrapper.prototype,function(func,methodName){var checkIteratee=/^(?:filter|map|reject)|While$/.test(methodName),retUnwrapped=/^(?:first|last)$/.test(methodName),lodashFunc=lodash[retUnwrapped?"take"+(methodName=="last"?"Right":""):methodName];if(!lodashFunc){return}lodash.prototype[methodName]=function(){var args=retUnwrapped?[1]:arguments,chainAll=this.__chain__,value=this.__wrapped__,isHybrid=!!this.__actions__.length,isLazy=value instanceof LazyWrapper,iteratee=args[0],useLazy=isLazy||isArray(value);if(useLazy&&checkIteratee&&typeof iteratee=="function"&&iteratee.length!=1){isLazy=useLazy=false}var interceptor=function(value){return retUnwrapped&&chainAll?lodashFunc(value,1)[0]:lodashFunc.apply(undefined,arrayPush([value],args))};var action={func:thru,args:[interceptor],thisArg:undefined},onlyLazy=isLazy&&!isHybrid;if(retUnwrapped&&!chainAll){if(onlyLazy){value=value.clone();value.__actions__.push(action);return func.call(value)}return lodashFunc.call(undefined,this.value())[0]}if(!retUnwrapped&&useLazy){value=onlyLazy?value:new LazyWrapper(this);var result=func.apply(value,args);result.__actions__.push(action);return new LodashWrapper(result,chainAll)}return this.thru(interceptor)}});arrayEach(["join","pop","push","replace","shift","sort","splice","split","unshift"],function(methodName){var func=(/^(?:replace|split)$/.test(methodName)?stringProto:arrayProto)[methodName],chainName=/^(?:push|sort|unshift)$/.test(methodName)?"tap":"thru",retUnwrapped=/^(?:join|pop|replace|shift)$/.test(methodName);lodash.prototype[methodName]=function(){var args=arguments;if(retUnwrapped&&!this.__chain__){return func.apply(this.value(),args)}return this[chainName](function(value){return func.apply(value,args)})}});baseForOwn(LazyWrapper.prototype,function(func,methodName){var lodashFunc=lodash[methodName];if(lodashFunc){var key=lodashFunc.name,names=realNames[key]||(realNames[key]=[]);names.push({name:methodName,func:lodashFunc})}});realNames[createHybridWrapper(undefined,BIND_KEY_FLAG).name]=[{name:"wrapper",func:undefined}];LazyWrapper.prototype.clone=lazyClone;LazyWrapper.prototype.reverse=lazyReverse;LazyWrapper.prototype.value=lazyValue;lodash.prototype.chain=wrapperChain;lodash.prototype.commit=wrapperCommit;lodash.prototype.concat=wrapperConcat;lodash.prototype.plant=wrapperPlant;lodash.prototype.reverse=wrapperReverse;lodash.prototype.toString=wrapperToString;lodash.prototype.run=lodash.prototype.toJSON=lodash.prototype.valueOf=lodash.prototype.value=wrapperValue;lodash.prototype.collect=lodash.prototype.map;lodash.prototype.head=lodash.prototype.first;lodash.prototype.select=lodash.prototype.filter;lodash.prototype.tail=lodash.prototype.rest;return lodash}var _=runInContext();if(typeof define=="function"&&typeof define.amd=="object"&&define.amd){root._=_;define(function(){return _})}else if(freeExports&&freeModule){if(moduleExports){(freeModule.exports=_)._=_}else{freeExports._=_}}else{root._=_}}).call(this)}).call(this,typeof global!=="undefined"?global:typeof self!=="undefined"?self:typeof window!=="undefined"?window:{})},{}]},{},[1])(1)}); \ No newline at end of file
diff --git a/docs/htmldoc/js/jquery-2.0.3.js b/docs/htmldoc/js/jquery-2.0.3.js
new file mode 100644
index 0000000..ebc6c18
--- /dev/null
+++ b/docs/htmldoc/js/jquery-2.0.3.js
@@ -0,0 +1,8829 @@
+/*!
+ * jQuery JavaScript Library v2.0.3
+ * http://jquery.com/
+ *
+ * Includes Sizzle.js
+ * http://sizzlejs.com/
+ *
+ * Copyright 2005, 2013 jQuery Foundation, Inc. and other contributors
+ * Released under the MIT license
+ * http://jquery.org/license
+ *
+ * Date: 2013-07-03T13:30Z
+ */
+(function( window, undefined ) {
+
+// Can't do this because several apps including ASP.NET trace
+// the stack via arguments.caller.callee and Firefox dies if
+// you try to trace through "use strict" call chains. (#13335)
+// Support: Firefox 18+
+//"use strict";
+var
+ // A central reference to the root jQuery(document)
+ rootjQuery,
+
+ // The deferred used on DOM ready
+ readyList,
+
+ // Support: IE9
+ // For `typeof xmlNode.method` instead of `xmlNode.method !== undefined`
+ core_strundefined = typeof undefined,
+
+ // Use the correct document accordingly with window argument (sandbox)
+ location = window.location,
+ document = window.document,
+ docElem = document.documentElement,
+
+ // Map over jQuery in case of overwrite
+ _jQuery = window.jQuery,
+
+ // Map over the $ in case of overwrite
+ _$ = window.$,
+
+ // [[Class]] -> type pairs
+ class2type = {},
+
+ // List of deleted data cache ids, so we can reuse them
+ core_deletedIds = [],
+
+ core_version = "2.0.3",
+
+ // Save a reference to some core methods
+ core_concat = core_deletedIds.concat,
+ core_push = core_deletedIds.push,
+ core_slice = core_deletedIds.slice,
+ core_indexOf = core_deletedIds.indexOf,
+ core_toString = class2type.toString,
+ core_hasOwn = class2type.hasOwnProperty,
+ core_trim = core_version.trim,
+
+ // Define a local copy of jQuery
+ jQuery = function( selector, context ) {
+ // The jQuery object is actually just the init constructor 'enhanced'
+ return new jQuery.fn.init( selector, context, rootjQuery );
+ },
+
+ // Used for matching numbers
+ core_pnum = /[+-]?(?:\d*\.|)\d+(?:[eE][+-]?\d+|)/.source,
+
+ // Used for splitting on whitespace
+ core_rnotwhite = /\S+/g,
+
+ // A simple way to check for HTML strings
+ // Prioritize #id over <tag> to avoid XSS via location.hash (#9521)
+ // Strict HTML recognition (#11290: must start with <)
+ rquickExpr = /^(?:\s*(<[\w\W]+>)[^>]*|#([\w-]*))$/,
+
+ // Match a standalone tag
+ rsingleTag = /^<(\w+)\s*\/?>(?:<\/\1>|)$/,
+
+ // Matches dashed string for camelizing
+ rmsPrefix = /^-ms-/,
+ rdashAlpha = /-([\da-z])/gi,
+
+ // Used by jQuery.camelCase as callback to replace()
+ fcamelCase = function( all, letter ) {
+ return letter.toUpperCase();
+ },
+
+ // The ready event handler and self cleanup method
+ completed = function() {
+ document.removeEventListener( "DOMContentLoaded", completed, false );
+ window.removeEventListener( "load", completed, false );
+ jQuery.ready();
+ };
+
+jQuery.fn = jQuery.prototype = {
+ // The current version of jQuery being used
+ jquery: core_version,
+
+ constructor: jQuery,
+ init: function( selector, context, rootjQuery ) {
+ var match, elem;
+
+ // HANDLE: $(""), $(null), $(undefined), $(false)
+ if ( !selector ) {
+ return this;
+ }
+
+ // Handle HTML strings
+ if ( typeof selector === "string" ) {
+ if ( selector.charAt(0) === "<" && selector.charAt( selector.length - 1 ) === ">" && selector.length >= 3 ) {
+ // Assume that strings that start and end with <> are HTML and skip the regex check
+ match = [ null, selector, null ];
+
+ } else {
+ match = rquickExpr.exec( selector );
+ }
+
+ // Match html or make sure no context is specified for #id
+ if ( match && (match[1] || !context) ) {
+
+ // HANDLE: $(html) -> $(array)
+ if ( match[1] ) {
+ context = context instanceof jQuery ? context[0] : context;
+
+ // scripts is true for back-compat
+ jQuery.merge( this, jQuery.parseHTML(
+ match[1],
+ context && context.nodeType ? context.ownerDocument || context : document,
+ true
+ ) );
+
+ // HANDLE: $(html, props)
+ if ( rsingleTag.test( match[1] ) && jQuery.isPlainObject( context ) ) {
+ for ( match in context ) {
+ // Properties of context are called as methods if possible
+ if ( jQuery.isFunction( this[ match ] ) ) {
+ this[ match ]( context[ match ] );
+
+ // ...and otherwise set as attributes
+ } else {
+ this.attr( match, context[ match ] );
+ }
+ }
+ }
+
+ return this;
+
+ // HANDLE: $(#id)
+ } else {
+ elem = document.getElementById( match[2] );
+
+ // Check parentNode to catch when Blackberry 4.6 returns
+ // nodes that are no longer in the document #6963
+ if ( elem && elem.parentNode ) {
+ // Inject the element directly into the jQuery object
+ this.length = 1;
+ this[0] = elem;
+ }
+
+ this.context = document;
+ this.selector = selector;
+ return this;
+ }
+
+ // HANDLE: $(expr, $(...))
+ } else if ( !context || context.jquery ) {
+ return ( context || rootjQuery ).find( selector );
+
+ // HANDLE: $(expr, context)
+ // (which is just equivalent to: $(context).find(expr)
+ } else {
+ return this.constructor( context ).find( selector );
+ }
+
+ // HANDLE: $(DOMElement)
+ } else if ( selector.nodeType ) {
+ this.context = this[0] = selector;
+ this.length = 1;
+ return this;
+
+ // HANDLE: $(function)
+ // Shortcut for document ready
+ } else if ( jQuery.isFunction( selector ) ) {
+ return rootjQuery.ready( selector );
+ }
+
+ if ( selector.selector !== undefined ) {
+ this.selector = selector.selector;
+ this.context = selector.context;
+ }
+
+ return jQuery.makeArray( selector, this );
+ },
+
+ // Start with an empty selector
+ selector: "",
+
+ // The default length of a jQuery object is 0
+ length: 0,
+
+ toArray: function() {
+ return core_slice.call( this );
+ },
+
+ // Get the Nth element in the matched element set OR
+ // Get the whole matched element set as a clean array
+ get: function( num ) {
+ return num == null ?
+
+ // Return a 'clean' array
+ this.toArray() :
+
+ // Return just the object
+ ( num < 0 ? this[ this.length + num ] : this[ num ] );
+ },
+
+ // Take an array of elements and push it onto the stack
+ // (returning the new matched element set)
+ pushStack: function( elems ) {
+
+ // Build a new jQuery matched element set
+ var ret = jQuery.merge( this.constructor(), elems );
+
+ // Add the old object onto the stack (as a reference)
+ ret.prevObject = this;
+ ret.context = this.context;
+
+ // Return the newly-formed element set
+ return ret;
+ },
+
+ // Execute a callback for every element in the matched set.
+ // (You can seed the arguments with an array of args, but this is
+ // only used internally.)
+ each: function( callback, args ) {
+ return jQuery.each( this, callback, args );
+ },
+
+ ready: function( fn ) {
+ // Add the callback
+ jQuery.ready.promise().done( fn );
+
+ return this;
+ },
+
+ slice: function() {
+ return this.pushStack( core_slice.apply( this, arguments ) );
+ },
+
+ first: function() {
+ return this.eq( 0 );
+ },
+
+ last: function() {
+ return this.eq( -1 );
+ },
+
+ eq: function( i ) {
+ var len = this.length,
+ j = +i + ( i < 0 ? len : 0 );
+ return this.pushStack( j >= 0 && j < len ? [ this[j] ] : [] );
+ },
+
+ map: function( callback ) {
+ return this.pushStack( jQuery.map(this, function( elem, i ) {
+ return callback.call( elem, i, elem );
+ }));
+ },
+
+ end: function() {
+ return this.prevObject || this.constructor(null);
+ },
+
+ // For internal use only.
+ // Behaves like an Array's method, not like a jQuery method.
+ push: core_push,
+ sort: [].sort,
+ splice: [].splice
+};
+
+// Give the init function the jQuery prototype for later instantiation
+jQuery.fn.init.prototype = jQuery.fn;
+
+jQuery.extend = jQuery.fn.extend = function() {
+ var options, name, src, copy, copyIsArray, clone,
+ target = arguments[0] || {},
+ i = 1,
+ length = arguments.length,
+ deep = false;
+
+ // Handle a deep copy situation
+ if ( typeof target === "boolean" ) {
+ deep = target;
+ target = arguments[1] || {};
+ // skip the boolean and the target
+ i = 2;
+ }
+
+ // Handle case when target is a string or something (possible in deep copy)
+ if ( typeof target !== "object" && !jQuery.isFunction(target) ) {
+ target = {};
+ }
+
+ // extend jQuery itself if only one argument is passed
+ if ( length === i ) {
+ target = this;
+ --i;
+ }
+
+ for ( ; i < length; i++ ) {
+ // Only deal with non-null/undefined values
+ if ( (options = arguments[ i ]) != null ) {
+ // Extend the base object
+ for ( name in options ) {
+ src = target[ name ];
+ copy = options[ name ];
+
+ // Prevent never-ending loop
+ if ( target === copy ) {
+ continue;
+ }
+
+ // Recurse if we're merging plain objects or arrays
+ if ( deep && copy && ( jQuery.isPlainObject(copy) || (copyIsArray = jQuery.isArray(copy)) ) ) {
+ if ( copyIsArray ) {
+ copyIsArray = false;
+ clone = src && jQuery.isArray(src) ? src : [];
+
+ } else {
+ clone = src && jQuery.isPlainObject(src) ? src : {};
+ }
+
+ // Never move original objects, clone them
+ target[ name ] = jQuery.extend( deep, clone, copy );
+
+ // Don't bring in undefined values
+ } else if ( copy !== undefined ) {
+ target[ name ] = copy;
+ }
+ }
+ }
+ }
+
+ // Return the modified object
+ return target;
+};
+
+jQuery.extend({
+ // Unique for each copy of jQuery on the page
+ expando: "jQuery" + ( core_version + Math.random() ).replace( /\D/g, "" ),
+
+ noConflict: function( deep ) {
+ if ( window.$ === jQuery ) {
+ window.$ = _$;
+ }
+
+ if ( deep && window.jQuery === jQuery ) {
+ window.jQuery = _jQuery;
+ }
+
+ return jQuery;
+ },
+
+ // Is the DOM ready to be used? Set to true once it occurs.
+ isReady: false,
+
+ // A counter to track how many items to wait for before
+ // the ready event fires. See #6781
+ readyWait: 1,
+
+ // Hold (or release) the ready event
+ holdReady: function( hold ) {
+ if ( hold ) {
+ jQuery.readyWait++;
+ } else {
+ jQuery.ready( true );
+ }
+ },
+
+ // Handle when the DOM is ready
+ ready: function( wait ) {
+
+ // Abort if there are pending holds or we're already ready
+ if ( wait === true ? --jQuery.readyWait : jQuery.isReady ) {
+ return;
+ }
+
+ // Remember that the DOM is ready
+ jQuery.isReady = true;
+
+ // If a normal DOM Ready event fired, decrement, and wait if need be
+ if ( wait !== true && --jQuery.readyWait > 0 ) {
+ return;
+ }
+
+ // If there are functions bound, to execute
+ readyList.resolveWith( document, [ jQuery ] );
+
+ // Trigger any bound ready events
+ if ( jQuery.fn.trigger ) {
+ jQuery( document ).trigger("ready").off("ready");
+ }
+ },
+
+ // See test/unit/core.js for details concerning isFunction.
+ // Since version 1.3, DOM methods and functions like alert
+ // aren't supported. They return false on IE (#2968).
+ isFunction: function( obj ) {
+ return jQuery.type(obj) === "function";
+ },
+
+ isArray: Array.isArray,
+
+ isWindow: function( obj ) {
+ return obj != null && obj === obj.window;
+ },
+
+ isNumeric: function( obj ) {
+ return !isNaN( parseFloat(obj) ) && isFinite( obj );
+ },
+
+ type: function( obj ) {
+ if ( obj == null ) {
+ return String( obj );
+ }
+ // Support: Safari <= 5.1 (functionish RegExp)
+ return typeof obj === "object" || typeof obj === "function" ?
+ class2type[ core_toString.call(obj) ] || "object" :
+ typeof obj;
+ },
+
+ isPlainObject: function( obj ) {
+ // Not plain objects:
+ // - Any object or value whose internal [[Class]] property is not "[object Object]"
+ // - DOM nodes
+ // - window
+ if ( jQuery.type( obj ) !== "object" || obj.nodeType || jQuery.isWindow( obj ) ) {
+ return false;
+ }
+
+ // Support: Firefox <20
+ // The try/catch suppresses exceptions thrown when attempting to access
+ // the "constructor" property of certain host objects, ie. |window.location|
+ // https://bugzilla.mozilla.org/show_bug.cgi?id=814622
+ try {
+ if ( obj.constructor &&
+ !core_hasOwn.call( obj.constructor.prototype, "isPrototypeOf" ) ) {
+ return false;
+ }
+ } catch ( e ) {
+ return false;
+ }
+
+ // If the function hasn't returned already, we're confident that
+ // |obj| is a plain object, created by {} or constructed with new Object
+ return true;
+ },
+
+ isEmptyObject: function( obj ) {
+ var name;
+ for ( name in obj ) {
+ return false;
+ }
+ return true;
+ },
+
+ error: function( msg ) {
+ throw new Error( msg );
+ },
+
+ // data: string of html
+ // context (optional): If specified, the fragment will be created in this context, defaults to document
+ // keepScripts (optional): If true, will include scripts passed in the html string
+ parseHTML: function( data, context, keepScripts ) {
+ if ( !data || typeof data !== "string" ) {
+ return null;
+ }
+ if ( typeof context === "boolean" ) {
+ keepScripts = context;
+ context = false;
+ }
+ context = context || document;
+
+ var parsed = rsingleTag.exec( data ),
+ scripts = !keepScripts && [];
+
+ // Single tag
+ if ( parsed ) {
+ return [ context.createElement( parsed[1] ) ];
+ }
+
+ parsed = jQuery.buildFragment( [ data ], context, scripts );
+
+ if ( scripts ) {
+ jQuery( scripts ).remove();
+ }
+
+ return jQuery.merge( [], parsed.childNodes );
+ },
+
+ parseJSON: JSON.parse,
+
+ // Cross-browser xml parsing
+ parseXML: function( data ) {
+ var xml, tmp;
+ if ( !data || typeof data !== "string" ) {
+ return null;
+ }
+
+ // Support: IE9
+ try {
+ tmp = new DOMParser();
+ xml = tmp.parseFromString( data , "text/xml" );
+ } catch ( e ) {
+ xml = undefined;
+ }
+
+ if ( !xml || xml.getElementsByTagName( "parsererror" ).length ) {
+ jQuery.error( "Invalid XML: " + data );
+ }
+ return xml;
+ },
+
+ noop: function() {},
+
+ // Evaluates a script in a global context
+ globalEval: function( code ) {
+ var script,
+ indirect = eval;
+
+ code = jQuery.trim( code );
+
+ if ( code ) {
+ // If the code includes a valid, prologue position
+ // strict mode pragma, execute code by injecting a
+ // script tag into the document.
+ if ( code.indexOf("use strict") === 1 ) {
+ script = document.createElement("script");
+ script.text = code;
+ document.head.appendChild( script ).parentNode.removeChild( script );
+ } else {
+ // Otherwise, avoid the DOM node creation, insertion
+ // and removal by using an indirect global eval
+ indirect( code );
+ }
+ }
+ },
+
+ // Convert dashed to camelCase; used by the css and data modules
+ // Microsoft forgot to hump their vendor prefix (#9572)
+ camelCase: function( string ) {
+ return string.replace( rmsPrefix, "ms-" ).replace( rdashAlpha, fcamelCase );
+ },
+
+ nodeName: function( elem, name ) {
+ return elem.nodeName && elem.nodeName.toLowerCase() === name.toLowerCase();
+ },
+
+ // args is for internal usage only
+ each: function( obj, callback, args ) {
+ var value,
+ i = 0,
+ length = obj.length,
+ isArray = isArraylike( obj );
+
+ if ( args ) {
+ if ( isArray ) {
+ for ( ; i < length; i++ ) {
+ value = callback.apply( obj[ i ], args );
+
+ if ( value === false ) {
+ break;
+ }
+ }
+ } else {
+ for ( i in obj ) {
+ value = callback.apply( obj[ i ], args );
+
+ if ( value === false ) {
+ break;
+ }
+ }
+ }
+
+ // A special, fast, case for the most common use of each
+ } else {
+ if ( isArray ) {
+ for ( ; i < length; i++ ) {
+ value = callback.call( obj[ i ], i, obj[ i ] );
+
+ if ( value === false ) {
+ break;
+ }
+ }
+ } else {
+ for ( i in obj ) {
+ value = callback.call( obj[ i ], i, obj[ i ] );
+
+ if ( value === false ) {
+ break;
+ }
+ }
+ }
+ }
+
+ return obj;
+ },
+
+ trim: function( text ) {
+ return text == null ? "" : core_trim.call( text );
+ },
+
+ // results is for internal usage only
+ makeArray: function( arr, results ) {
+ var ret = results || [];
+
+ if ( arr != null ) {
+ if ( isArraylike( Object(arr) ) ) {
+ jQuery.merge( ret,
+ typeof arr === "string" ?
+ [ arr ] : arr
+ );
+ } else {
+ core_push.call( ret, arr );
+ }
+ }
+
+ return ret;
+ },
+
+ inArray: function( elem, arr, i ) {
+ return arr == null ? -1 : core_indexOf.call( arr, elem, i );
+ },
+
+ merge: function( first, second ) {
+ var l = second.length,
+ i = first.length,
+ j = 0;
+
+ if ( typeof l === "number" ) {
+ for ( ; j < l; j++ ) {
+ first[ i++ ] = second[ j ];
+ }
+ } else {
+ while ( second[j] !== undefined ) {
+ first[ i++ ] = second[ j++ ];
+ }
+ }
+
+ first.length = i;
+
+ return first;
+ },
+
+ grep: function( elems, callback, inv ) {
+ var retVal,
+ ret = [],
+ i = 0,
+ length = elems.length;
+ inv = !!inv;
+
+ // Go through the array, only saving the items
+ // that pass the validator function
+ for ( ; i < length; i++ ) {
+ retVal = !!callback( elems[ i ], i );
+ if ( inv !== retVal ) {
+ ret.push( elems[ i ] );
+ }
+ }
+
+ return ret;
+ },
+
+ // arg is for internal usage only
+ map: function( elems, callback, arg ) {
+ var value,
+ i = 0,
+ length = elems.length,
+ isArray = isArraylike( elems ),
+ ret = [];
+
+ // Go through the array, translating each of the items to their
+ if ( isArray ) {
+ for ( ; i < length; i++ ) {
+ value = callback( elems[ i ], i, arg );
+
+ if ( value != null ) {
+ ret[ ret.length ] = value;
+ }
+ }
+
+ // Go through every key on the object,
+ } else {
+ for ( i in elems ) {
+ value = callback( elems[ i ], i, arg );
+
+ if ( value != null ) {
+ ret[ ret.length ] = value;
+ }
+ }
+ }
+
+ // Flatten any nested arrays
+ return core_concat.apply( [], ret );
+ },
+
+ // A global GUID counter for objects
+ guid: 1,
+
+ // Bind a function to a context, optionally partially applying any
+ // arguments.
+ proxy: function( fn, context ) {
+ var tmp, args, proxy;
+
+ if ( typeof context === "string" ) {
+ tmp = fn[ context ];
+ context = fn;
+ fn = tmp;
+ }
+
+ // Quick check to determine if target is callable, in the spec
+ // this throws a TypeError, but we will just return undefined.
+ if ( !jQuery.isFunction( fn ) ) {
+ return undefined;
+ }
+
+ // Simulated bind
+ args = core_slice.call( arguments, 2 );
+ proxy = function() {
+ return fn.apply( context || this, args.concat( core_slice.call( arguments ) ) );
+ };
+
+ // Set the guid of unique handler to the same of original handler, so it can be removed
+ proxy.guid = fn.guid = fn.guid || jQuery.guid++;
+
+ return proxy;
+ },
+
+ // Multifunctional method to get and set values of a collection
+ // The value/s can optionally be executed if it's a function
+ access: function( elems, fn, key, value, chainable, emptyGet, raw ) {
+ var i = 0,
+ length = elems.length,
+ bulk = key == null;
+
+ // Sets many values
+ if ( jQuery.type( key ) === "object" ) {
+ chainable = true;
+ for ( i in key ) {
+ jQuery.access( elems, fn, i, key[i], true, emptyGet, raw );
+ }
+
+ // Sets one value
+ } else if ( value !== undefined ) {
+ chainable = true;
+
+ if ( !jQuery.isFunction( value ) ) {
+ raw = true;
+ }
+
+ if ( bulk ) {
+ // Bulk operations run against the entire set
+ if ( raw ) {
+ fn.call( elems, value );
+ fn = null;
+
+ // ...except when executing function values
+ } else {
+ bulk = fn;
+ fn = function( elem, key, value ) {
+ return bulk.call( jQuery( elem ), value );
+ };
+ }
+ }
+
+ if ( fn ) {
+ for ( ; i < length; i++ ) {
+ fn( elems[i], key, raw ? value : value.call( elems[i], i, fn( elems[i], key ) ) );
+ }
+ }
+ }
+
+ return chainable ?
+ elems :
+
+ // Gets
+ bulk ?
+ fn.call( elems ) :
+ length ? fn( elems[0], key ) : emptyGet;
+ },
+
+ now: Date.now,
+
+ // A method for quickly swapping in/out CSS properties to get correct calculations.
+ // Note: this method belongs to the css module but it's needed here for the support module.
+ // If support gets modularized, this method should be moved back to the css module.
+ swap: function( elem, options, callback, args ) {
+ var ret, name,
+ old = {};
+
+ // Remember the old values, and insert the new ones
+ for ( name in options ) {
+ old[ name ] = elem.style[ name ];
+ elem.style[ name ] = options[ name ];
+ }
+
+ ret = callback.apply( elem, args || [] );
+
+ // Revert the old values
+ for ( name in options ) {
+ elem.style[ name ] = old[ name ];
+ }
+
+ return ret;
+ }
+});
+
+jQuery.ready.promise = function( obj ) {
+ if ( !readyList ) {
+
+ readyList = jQuery.Deferred();
+
+ // Catch cases where $(document).ready() is called after the browser event has already occurred.
+ // we once tried to use readyState "interactive" here, but it caused issues like the one
+ // discovered by ChrisS here: http://bugs.jquery.com/ticket/12282#comment:15
+ if ( document.readyState === "complete" ) {
+ // Handle it asynchronously to allow scripts the opportunity to delay ready
+ setTimeout( jQuery.ready );
+
+ } else {
+
+ // Use the handy event callback
+ document.addEventListener( "DOMContentLoaded", completed, false );
+
+ // A fallback to window.onload, that will always work
+ window.addEventListener( "load", completed, false );
+ }
+ }
+ return readyList.promise( obj );
+};
+
+// Populate the class2type map
+jQuery.each("Boolean Number String Function Array Date RegExp Object Error".split(" "), function(i, name) {
+ class2type[ "[object " + name + "]" ] = name.toLowerCase();
+});
+
+function isArraylike( obj ) {
+ var length = obj.length,
+ type = jQuery.type( obj );
+
+ if ( jQuery.isWindow( obj ) ) {
+ return false;
+ }
+
+ if ( obj.nodeType === 1 && length ) {
+ return true;
+ }
+
+ return type === "array" || type !== "function" &&
+ ( length === 0 ||
+ typeof length === "number" && length > 0 && ( length - 1 ) in obj );
+}
+
+// All jQuery objects should point back to these
+rootjQuery = jQuery(document);
+/*!
+ * Sizzle CSS Selector Engine v1.9.4-pre
+ * http://sizzlejs.com/
+ *
+ * Copyright 2013 jQuery Foundation, Inc. and other contributors
+ * Released under the MIT license
+ * http://jquery.org/license
+ *
+ * Date: 2013-06-03
+ */
+(function( window, undefined ) {
+
+var i,
+ support,
+ cachedruns,
+ Expr,
+ getText,
+ isXML,
+ compile,
+ outermostContext,
+ sortInput,
+
+ // Local document vars
+ setDocument,
+ document,
+ docElem,
+ documentIsHTML,
+ rbuggyQSA,
+ rbuggyMatches,
+ matches,
+ contains,
+
+ // Instance-specific data
+ expando = "sizzle" + -(new Date()),
+ preferredDoc = window.document,
+ dirruns = 0,
+ done = 0,
+ classCache = createCache(),
+ tokenCache = createCache(),
+ compilerCache = createCache(),
+ hasDuplicate = false,
+ sortOrder = function( a, b ) {
+ if ( a === b ) {
+ hasDuplicate = true;
+ return 0;
+ }
+ return 0;
+ },
+
+ // General-purpose constants
+ strundefined = typeof undefined,
+ MAX_NEGATIVE = 1 << 31,
+
+ // Instance methods
+ hasOwn = ({}).hasOwnProperty,
+ arr = [],
+ pop = arr.pop,
+ push_native = arr.push,
+ push = arr.push,
+ slice = arr.slice,
+ // Use a stripped-down indexOf if we can't use a native one
+ indexOf = arr.indexOf || function( elem ) {
+ var i = 0,
+ len = this.length;
+ for ( ; i < len; i++ ) {
+ if ( this[i] === elem ) {
+ return i;
+ }
+ }
+ return -1;
+ },
+
+ booleans = "checked|selected|async|autofocus|autoplay|controls|defer|disabled|hidden|ismap|loop|multiple|open|readonly|required|scoped",
+
+ // Regular expressions
+
+ // Whitespace characters http://www.w3.org/TR/css3-selectors/#whitespace
+ whitespace = "[\\x20\\t\\r\\n\\f]",
+ // http://www.w3.org/TR/css3-syntax/#characters
+ characterEncoding = "(?:\\\\.|[\\w-]|[^\\x00-\\xa0])+",
+
+ // Loosely modeled on CSS identifier characters
+ // An unquoted value should be a CSS identifier http://www.w3.org/TR/css3-selectors/#attribute-selectors
+ // Proper syntax: http://www.w3.org/TR/CSS21/syndata.html#value-def-identifier
+ identifier = characterEncoding.replace( "w", "w#" ),
+
+ // Acceptable operators http://www.w3.org/TR/selectors/#attribute-selectors
+ attributes = "\\[" + whitespace + "*(" + characterEncoding + ")" + whitespace +
+ "*(?:([*^$|!~]?=)" + whitespace + "*(?:(['\"])((?:\\\\.|[^\\\\])*?)\\3|(" + identifier + ")|)|)" + whitespace + "*\\]",
+
+ // Prefer arguments quoted,
+ // then not containing pseudos/brackets,
+ // then attribute selectors/non-parenthetical expressions,
+ // then anything else
+ // These preferences are here to reduce the number of selectors
+ // needing tokenize in the PSEUDO preFilter
+ pseudos = ":(" + characterEncoding + ")(?:\\(((['\"])((?:\\\\.|[^\\\\])*?)\\3|((?:\\\\.|[^\\\\()[\\]]|" + attributes.replace( 3, 8 ) + ")*)|.*)\\)|)",
+
+ // Leading and non-escaped trailing whitespace, capturing some non-whitespace characters preceding the latter
+ rtrim = new RegExp( "^" + whitespace + "+|((?:^|[^\\\\])(?:\\\\.)*)" + whitespace + "+$", "g" ),
+
+ rcomma = new RegExp( "^" + whitespace + "*," + whitespace + "*" ),
+ rcombinators = new RegExp( "^" + whitespace + "*([>+~]|" + whitespace + ")" + whitespace + "*" ),
+
+ rsibling = new RegExp( whitespace + "*[+~]" ),
+ rattributeQuotes = new RegExp( "=" + whitespace + "*([^\\]'\"]*)" + whitespace + "*\\]", "g" ),
+
+ rpseudo = new RegExp( pseudos ),
+ ridentifier = new RegExp( "^" + identifier + "$" ),
+
+ matchExpr = {
+ "ID": new RegExp( "^#(" + characterEncoding + ")" ),
+ "CLASS": new RegExp( "^\\.(" + characterEncoding + ")" ),
+ "TAG": new RegExp( "^(" + characterEncoding.replace( "w", "w*" ) + ")" ),
+ "ATTR": new RegExp( "^" + attributes ),
+ "PSEUDO": new RegExp( "^" + pseudos ),
+ "CHILD": new RegExp( "^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\(" + whitespace +
+ "*(even|odd|(([+-]|)(\\d*)n|)" + whitespace + "*(?:([+-]|)" + whitespace +
+ "*(\\d+)|))" + whitespace + "*\\)|)", "i" ),
+ "bool": new RegExp( "^(?:" + booleans + ")$", "i" ),
+ // For use in libraries implementing .is()
+ // We use this for POS matching in `select`
+ "needsContext": new RegExp( "^" + whitespace + "*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\(" +
+ whitespace + "*((?:-\\d)?\\d*)" + whitespace + "*\\)|)(?=[^-]|$)", "i" )
+ },
+
+ rnative = /^[^{]+\{\s*\[native \w/,
+
+ // Easily-parseable/retrievable ID or TAG or CLASS selectors
+ rquickExpr = /^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/,
+
+ rinputs = /^(?:input|select|textarea|button)$/i,
+ rheader = /^h\d$/i,
+
+ rescape = /'|\\/g,
+
+ // CSS escapes http://www.w3.org/TR/CSS21/syndata.html#escaped-characters
+ runescape = new RegExp( "\\\\([\\da-f]{1,6}" + whitespace + "?|(" + whitespace + ")|.)", "ig" ),
+ funescape = function( _, escaped, escapedWhitespace ) {
+ var high = "0x" + escaped - 0x10000;
+ // NaN means non-codepoint
+ // Support: Firefox
+ // Workaround erroneous numeric interpretation of +"0x"
+ return high !== high || escapedWhitespace ?
+ escaped :
+ // BMP codepoint
+ high < 0 ?
+ String.fromCharCode( high + 0x10000 ) :
+ // Supplemental Plane codepoint (surrogate pair)
+ String.fromCharCode( high >> 10 | 0xD800, high & 0x3FF | 0xDC00 );
+ };
+
+// Optimize for push.apply( _, NodeList )
+try {
+ push.apply(
+ (arr = slice.call( preferredDoc.childNodes )),
+ preferredDoc.childNodes
+ );
+ // Support: Android<4.0
+ // Detect silently failing push.apply
+ arr[ preferredDoc.childNodes.length ].nodeType;
+} catch ( e ) {
+ push = { apply: arr.length ?
+
+ // Leverage slice if possible
+ function( target, els ) {
+ push_native.apply( target, slice.call(els) );
+ } :
+
+ // Support: IE<9
+ // Otherwise append directly
+ function( target, els ) {
+ var j = target.length,
+ i = 0;
+ // Can't trust NodeList.length
+ while ( (target[j++] = els[i++]) ) {}
+ target.length = j - 1;
+ }
+ };
+}
+
+function Sizzle( selector, context, results, seed ) {
+ var match, elem, m, nodeType,
+ // QSA vars
+ i, groups, old, nid, newContext, newSelector;
+
+ if ( ( context ? context.ownerDocument || context : preferredDoc ) !== document ) {
+ setDocument( context );
+ }
+
+ context = context || document;
+ results = results || [];
+
+ if ( !selector || typeof selector !== "string" ) {
+ return results;
+ }
+
+ if ( (nodeType = context.nodeType) !== 1 && nodeType !== 9 ) {
+ return [];
+ }
+
+ if ( documentIsHTML && !seed ) {
+
+ // Shortcuts
+ if ( (match = rquickExpr.exec( selector )) ) {
+ // Speed-up: Sizzle("#ID")
+ if ( (m = match[1]) ) {
+ if ( nodeType === 9 ) {
+ elem = context.getElementById( m );
+ // Check parentNode to catch when Blackberry 4.6 returns
+ // nodes that are no longer in the document #6963
+ if ( elem && elem.parentNode ) {
+ // Handle the case where IE, Opera, and Webkit return items
+ // by name instead of ID
+ if ( elem.id === m ) {
+ results.push( elem );
+ return results;
+ }
+ } else {
+ return results;
+ }
+ } else {
+ // Context is not a document
+ if ( context.ownerDocument && (elem = context.ownerDocument.getElementById( m )) &&
+ contains( context, elem ) && elem.id === m ) {
+ results.push( elem );
+ return results;
+ }
+ }
+
+ // Speed-up: Sizzle("TAG")
+ } else if ( match[2] ) {
+ push.apply( results, context.getElementsByTagName( selector ) );
+ return results;
+
+ // Speed-up: Sizzle(".CLASS")
+ } else if ( (m = match[3]) && support.getElementsByClassName && context.getElementsByClassName ) {
+ push.apply( results, context.getElementsByClassName( m ) );
+ return results;
+ }
+ }
+
+ // QSA path
+ if ( support.qsa && (!rbuggyQSA || !rbuggyQSA.test( selector )) ) {
+ nid = old = expando;
+ newContext = context;
+ newSelector = nodeType === 9 && selector;
+
+ // qSA works strangely on Element-rooted queries
+ // We can work around this by specifying an extra ID on the root
+ // and working up from there (Thanks to Andrew Dupont for the technique)
+ // IE 8 doesn't work on object elements
+ if ( nodeType === 1 && context.nodeName.toLowerCase() !== "object" ) {
+ groups = tokenize( selector );
+
+ if ( (old = context.getAttribute("id")) ) {
+ nid = old.replace( rescape, "\\$&" );
+ } else {
+ context.setAttribute( "id", nid );
+ }
+ nid = "[id='" + nid + "'] ";
+
+ i = groups.length;
+ while ( i-- ) {
+ groups[i] = nid + toSelector( groups[i] );
+ }
+ newContext = rsibling.test( selector ) && context.parentNode || context;
+ newSelector = groups.join(",");
+ }
+
+ if ( newSelector ) {
+ try {
+ push.apply( results,
+ newContext.querySelectorAll( newSelector )
+ );
+ return results;
+ } catch(qsaError) {
+ } finally {
+ if ( !old ) {
+ context.removeAttribute("id");
+ }
+ }
+ }
+ }
+ }
+
+ // All others
+ return select( selector.replace( rtrim, "$1" ), context, results, seed );
+}
+
+/**
+ * Create key-value caches of limited size
+ * @returns {Function(string, Object)} Returns the Object data after storing it on itself with
+ * property name the (space-suffixed) string and (if the cache is larger than Expr.cacheLength)
+ * deleting the oldest entry
+ */
+function createCache() {
+ var keys = [];
+
+ function cache( key, value ) {
+ // Use (key + " ") to avoid collision with native prototype properties (see Issue #157)
+ if ( keys.push( key += " " ) > Expr.cacheLength ) {
+ // Only keep the most recent entries
+ delete cache[ keys.shift() ];
+ }
+ return (cache[ key ] = value);
+ }
+ return cache;
+}
+
+/**
+ * Mark a function for special use by Sizzle
+ * @param {Function} fn The function to mark
+ */
+function markFunction( fn ) {
+ fn[ expando ] = true;
+ return fn;
+}
+
+/**
+ * Support testing using an element
+ * @param {Function} fn Passed the created div and expects a boolean result
+ */
+function assert( fn ) {
+ var div = document.createElement("div");
+
+ try {
+ return !!fn( div );
+ } catch (e) {
+ return false;
+ } finally {
+ // Remove from its parent by default
+ if ( div.parentNode ) {
+ div.parentNode.removeChild( div );
+ }
+ // release memory in IE
+ div = null;
+ }
+}
+
+/**
+ * Adds the same handler for all of the specified attrs
+ * @param {String} attrs Pipe-separated list of attributes
+ * @param {Function} handler The method that will be applied
+ */
+function addHandle( attrs, handler ) {
+ var arr = attrs.split("|"),
+ i = attrs.length;
+
+ while ( i-- ) {
+ Expr.attrHandle[ arr[i] ] = handler;
+ }
+}
+
+/**
+ * Checks document order of two siblings
+ * @param {Element} a
+ * @param {Element} b
+ * @returns {Number} Returns less than 0 if a precedes b, greater than 0 if a follows b
+ */
+function siblingCheck( a, b ) {
+ var cur = b && a,
+ diff = cur && a.nodeType === 1 && b.nodeType === 1 &&
+ ( ~b.sourceIndex || MAX_NEGATIVE ) -
+ ( ~a.sourceIndex || MAX_NEGATIVE );
+
+ // Use IE sourceIndex if available on both nodes
+ if ( diff ) {
+ return diff;
+ }
+
+ // Check if b follows a
+ if ( cur ) {
+ while ( (cur = cur.nextSibling) ) {
+ if ( cur === b ) {
+ return -1;
+ }
+ }
+ }
+
+ return a ? 1 : -1;
+}
+
+/**
+ * Returns a function to use in pseudos for input types
+ * @param {String} type
+ */
+function createInputPseudo( type ) {
+ return function( elem ) {
+ var name = elem.nodeName.toLowerCase();
+ return name === "input" && elem.type === type;
+ };
+}
+
+/**
+ * Returns a function to use in pseudos for buttons
+ * @param {String} type
+ */
+function createButtonPseudo( type ) {
+ return function( elem ) {
+ var name = elem.nodeName.toLowerCase();
+ return (name === "input" || name === "button") && elem.type === type;
+ };
+}
+
+/**
+ * Returns a function to use in pseudos for positionals
+ * @param {Function} fn
+ */
+function createPositionalPseudo( fn ) {
+ return markFunction(function( argument ) {
+ argument = +argument;
+ return markFunction(function( seed, matches ) {
+ var j,
+ matchIndexes = fn( [], seed.length, argument ),
+ i = matchIndexes.length;
+
+ // Match elements found at the specified indexes
+ while ( i-- ) {
+ if ( seed[ (j = matchIndexes[i]) ] ) {
+ seed[j] = !(matches[j] = seed[j]);
+ }
+ }
+ });
+ });
+}
+
+/**
+ * Detect xml
+ * @param {Element|Object} elem An element or a document
+ */
+isXML = Sizzle.isXML = function( elem ) {
+ // documentElement is verified for cases where it doesn't yet exist
+ // (such as loading iframes in IE - #4833)
+ var documentElement = elem && (elem.ownerDocument || elem).documentElement;
+ return documentElement ? documentElement.nodeName !== "HTML" : false;
+};
+
+// Expose support vars for convenience
+support = Sizzle.support = {};
+
+/**
+ * Sets document-related variables once based on the current document
+ * @param {Element|Object} [doc] An element or document object to use to set the document
+ * @returns {Object} Returns the current document
+ */
+setDocument = Sizzle.setDocument = function( node ) {
+ var doc = node ? node.ownerDocument || node : preferredDoc,
+ parent = doc.defaultView;
+
+ // If no document and documentElement is available, return
+ if ( doc === document || doc.nodeType !== 9 || !doc.documentElement ) {
+ return document;
+ }
+
+ // Set our document
+ document = doc;
+ docElem = doc.documentElement;
+
+ // Support tests
+ documentIsHTML = !isXML( doc );
+
+ // Support: IE>8
+ // If iframe document is assigned to "document" variable and if iframe has been reloaded,
+ // IE will throw "permission denied" error when accessing "document" variable, see jQuery #13936
+ // IE6-8 do not support the defaultView property so parent will be undefined
+ if ( parent && parent.attachEvent && parent !== parent.top ) {
+ parent.attachEvent( "onbeforeunload", function() {
+ setDocument();
+ });
+ }
+
+ /* Attributes
+ ---------------------------------------------------------------------- */
+
+ // Support: IE<8
+ // Verify that getAttribute really returns attributes and not properties (excepting IE8 booleans)
+ support.attributes = assert(function( div ) {
+ div.className = "i";
+ return !div.getAttribute("className");
+ });
+
+ /* getElement(s)By*
+ ---------------------------------------------------------------------- */
+
+ // Check if getElementsByTagName("*") returns only elements
+ support.getElementsByTagName = assert(function( div ) {
+ div.appendChild( doc.createComment("") );
+ return !div.getElementsByTagName("*").length;
+ });
+
+ // Check if getElementsByClassName can be trusted
+ support.getElementsByClassName = assert(function( div ) {
+ div.innerHTML = "<div class='a'></div><div class='a i'></div>";
+
+ // Support: Safari<4
+ // Catch class over-caching
+ div.firstChild.className = "i";
+ // Support: Opera<10
+ // Catch gEBCN failure to find non-leading classes
+ return div.getElementsByClassName("i").length === 2;
+ });
+
+ // Support: IE<10
+ // Check if getElementById returns elements by name
+ // The broken getElementById methods don't pick up programatically-set names,
+ // so use a roundabout getElementsByName test
+ support.getById = assert(function( div ) {
+ docElem.appendChild( div ).id = expando;
+ return !doc.getElementsByName || !doc.getElementsByName( expando ).length;
+ });
+
+ // ID find and filter
+ if ( support.getById ) {
+ Expr.find["ID"] = function( id, context ) {
+ if ( typeof context.getElementById !== strundefined && documentIsHTML ) {
+ var m = context.getElementById( id );
+ // Check parentNode to catch when Blackberry 4.6 returns
+ // nodes that are no longer in the document #6963
+ return m && m.parentNode ? [m] : [];
+ }
+ };
+ Expr.filter["ID"] = function( id ) {
+ var attrId = id.replace( runescape, funescape );
+ return function( elem ) {
+ return elem.getAttribute("id") === attrId;
+ };
+ };
+ } else {
+ // Support: IE6/7
+ // getElementById is not reliable as a find shortcut
+ delete Expr.find["ID"];
+
+ Expr.filter["ID"] = function( id ) {
+ var attrId = id.replace( runescape, funescape );
+ return function( elem ) {
+ var node = typeof elem.getAttributeNode !== strundefined && elem.getAttributeNode("id");
+ return node && node.value === attrId;
+ };
+ };
+ }
+
+ // Tag
+ Expr.find["TAG"] = support.getElementsByTagName ?
+ function( tag, context ) {
+ if ( typeof context.getElementsByTagName !== strundefined ) {
+ return context.getElementsByTagName( tag );
+ }
+ } :
+ function( tag, context ) {
+ var elem,
+ tmp = [],
+ i = 0,
+ results = context.getElementsByTagName( tag );
+
+ // Filter out possible comments
+ if ( tag === "*" ) {
+ while ( (elem = results[i++]) ) {
+ if ( elem.nodeType === 1 ) {
+ tmp.push( elem );
+ }
+ }
+
+ return tmp;
+ }
+ return results;
+ };
+
+ // Class
+ Expr.find["CLASS"] = support.getElementsByClassName && function( className, context ) {
+ if ( typeof context.getElementsByClassName !== strundefined && documentIsHTML ) {
+ return context.getElementsByClassName( className );
+ }
+ };
+
+ /* QSA/matchesSelector
+ ---------------------------------------------------------------------- */
+
+ // QSA and matchesSelector support
+
+ // matchesSelector(:active) reports false when true (IE9/Opera 11.5)
+ rbuggyMatches = [];
+
+ // qSa(:focus) reports false when true (Chrome 21)
+ // We allow this because of a bug in IE8/9 that throws an error
+ // whenever `document.activeElement` is accessed on an iframe
+ // So, we allow :focus to pass through QSA all the time to avoid the IE error
+ // See http://bugs.jquery.com/ticket/13378
+ rbuggyQSA = [];
+
+ if ( (support.qsa = rnative.test( doc.querySelectorAll )) ) {
+ // Build QSA regex
+ // Regex strategy adopted from Diego Perini
+ assert(function( div ) {
+ // Select is set to empty string on purpose
+ // This is to test IE's treatment of not explicitly
+ // setting a boolean content attribute,
+ // since its presence should be enough
+ // http://bugs.jquery.com/ticket/12359
+ div.innerHTML = "<select><option selected=''></option></select>";
+
+ // Support: IE8
+ // Boolean attributes and "value" are not treated correctly
+ if ( !div.querySelectorAll("[selected]").length ) {
+ rbuggyQSA.push( "\\[" + whitespace + "*(?:value|" + booleans + ")" );
+ }
+
+ // Webkit/Opera - :checked should return selected option elements
+ // http://www.w3.org/TR/2011/REC-css3-selectors-20110929/#checked
+ // IE8 throws error here and will not see later tests
+ if ( !div.querySelectorAll(":checked").length ) {
+ rbuggyQSA.push(":checked");
+ }
+ });
+
+ assert(function( div ) {
+
+ // Support: Opera 10-12/IE8
+ // ^= $= *= and empty values
+ // Should not select anything
+ // Support: Windows 8 Native Apps
+ // The type attribute is restricted during .innerHTML assignment
+ var input = doc.createElement("input");
+ input.setAttribute( "type", "hidden" );
+ div.appendChild( input ).setAttribute( "t", "" );
+
+ if ( div.querySelectorAll("[t^='']").length ) {
+ rbuggyQSA.push( "[*^$]=" + whitespace + "*(?:''|\"\")" );
+ }
+
+ // FF 3.5 - :enabled/:disabled and hidden elements (hidden elements are still enabled)
+ // IE8 throws error here and will not see later tests
+ if ( !div.querySelectorAll(":enabled").length ) {
+ rbuggyQSA.push( ":enabled", ":disabled" );
+ }
+
+ // Opera 10-11 does not throw on post-comma invalid pseudos
+ div.querySelectorAll("*,:x");
+ rbuggyQSA.push(",.*:");
+ });
+ }
+
+ if ( (support.matchesSelector = rnative.test( (matches = docElem.webkitMatchesSelector ||
+ docElem.mozMatchesSelector ||
+ docElem.oMatchesSelector ||
+ docElem.msMatchesSelector) )) ) {
+
+ assert(function( div ) {
+ // Check to see if it's possible to do matchesSelector
+ // on a disconnected node (IE 9)
+ support.disconnectedMatch = matches.call( div, "div" );
+
+ // This should fail with an exception
+ // Gecko does not error, returns false instead
+ matches.call( div, "[s!='']:x" );
+ rbuggyMatches.push( "!=", pseudos );
+ });
+ }
+
+ rbuggyQSA = rbuggyQSA.length && new RegExp( rbuggyQSA.join("|") );
+ rbuggyMatches = rbuggyMatches.length && new RegExp( rbuggyMatches.join("|") );
+
+ /* Contains
+ ---------------------------------------------------------------------- */
+
+ // Element contains another
+ // Purposefully does not implement inclusive descendent
+ // As in, an element does not contain itself
+ contains = rnative.test( docElem.contains ) || docElem.compareDocumentPosition ?
+ function( a, b ) {
+ var adown = a.nodeType === 9 ? a.documentElement : a,
+ bup = b && b.parentNode;
+ return a === bup || !!( bup && bup.nodeType === 1 && (
+ adown.contains ?
+ adown.contains( bup ) :
+ a.compareDocumentPosition && a.compareDocumentPosition( bup ) & 16
+ ));
+ } :
+ function( a, b ) {
+ if ( b ) {
+ while ( (b = b.parentNode) ) {
+ if ( b === a ) {
+ return true;
+ }
+ }
+ }
+ return false;
+ };
+
+ /* Sorting
+ ---------------------------------------------------------------------- */
+
+ // Document order sorting
+ sortOrder = docElem.compareDocumentPosition ?
+ function( a, b ) {
+
+ // Flag for duplicate removal
+ if ( a === b ) {
+ hasDuplicate = true;
+ return 0;
+ }
+
+ var compare = b.compareDocumentPosition && a.compareDocumentPosition && a.compareDocumentPosition( b );
+
+ if ( compare ) {
+ // Disconnected nodes
+ if ( compare & 1 ||
+ (!support.sortDetached && b.compareDocumentPosition( a ) === compare) ) {
+
+ // Choose the first element that is related to our preferred document
+ if ( a === doc || contains(preferredDoc, a) ) {
+ return -1;
+ }
+ if ( b === doc || contains(preferredDoc, b) ) {
+ return 1;
+ }
+
+ // Maintain original order
+ return sortInput ?
+ ( indexOf.call( sortInput, a ) - indexOf.call( sortInput, b ) ) :
+ 0;
+ }
+
+ return compare & 4 ? -1 : 1;
+ }
+
+ // Not directly comparable, sort on existence of method
+ return a.compareDocumentPosition ? -1 : 1;
+ } :
+ function( a, b ) {
+ var cur,
+ i = 0,
+ aup = a.parentNode,
+ bup = b.parentNode,
+ ap = [ a ],
+ bp = [ b ];
+
+ // Exit early if the nodes are identical
+ if ( a === b ) {
+ hasDuplicate = true;
+ return 0;
+
+ // Parentless nodes are either documents or disconnected
+ } else if ( !aup || !bup ) {
+ return a === doc ? -1 :
+ b === doc ? 1 :
+ aup ? -1 :
+ bup ? 1 :
+ sortInput ?
+ ( indexOf.call( sortInput, a ) - indexOf.call( sortInput, b ) ) :
+ 0;
+
+ // If the nodes are siblings, we can do a quick check
+ } else if ( aup === bup ) {
+ return siblingCheck( a, b );
+ }
+
+ // Otherwise we need full lists of their ancestors for comparison
+ cur = a;
+ while ( (cur = cur.parentNode) ) {
+ ap.unshift( cur );
+ }
+ cur = b;
+ while ( (cur = cur.parentNode) ) {
+ bp.unshift( cur );
+ }
+
+ // Walk down the tree looking for a discrepancy
+ while ( ap[i] === bp[i] ) {
+ i++;
+ }
+
+ return i ?
+ // Do a sibling check if the nodes have a common ancestor
+ siblingCheck( ap[i], bp[i] ) :
+
+ // Otherwise nodes in our document sort first
+ ap[i] === preferredDoc ? -1 :
+ bp[i] === preferredDoc ? 1 :
+ 0;
+ };
+
+ return doc;
+};
+
+Sizzle.matches = function( expr, elements ) {
+ return Sizzle( expr, null, null, elements );
+};
+
+Sizzle.matchesSelector = function( elem, expr ) {
+ // Set document vars if needed
+ if ( ( elem.ownerDocument || elem ) !== document ) {
+ setDocument( elem );
+ }
+
+ // Make sure that attribute selectors are quoted
+ expr = expr.replace( rattributeQuotes, "='$1']" );
+
+ if ( support.matchesSelector && documentIsHTML &&
+ ( !rbuggyMatches || !rbuggyMatches.test( expr ) ) &&
+ ( !rbuggyQSA || !rbuggyQSA.test( expr ) ) ) {
+
+ try {
+ var ret = matches.call( elem, expr );
+
+ // IE 9's matchesSelector returns false on disconnected nodes
+ if ( ret || support.disconnectedMatch ||
+ // As well, disconnected nodes are said to be in a document
+ // fragment in IE 9
+ elem.document && elem.document.nodeType !== 11 ) {
+ return ret;
+ }
+ } catch(e) {}
+ }
+
+ return Sizzle( expr, document, null, [elem] ).length > 0;
+};
+
+Sizzle.contains = function( context, elem ) {
+ // Set document vars if needed
+ if ( ( context.ownerDocument || context ) !== document ) {
+ setDocument( context );
+ }
+ return contains( context, elem );
+};
+
+Sizzle.attr = function( elem, name ) {
+ // Set document vars if needed
+ if ( ( elem.ownerDocument || elem ) !== document ) {
+ setDocument( elem );
+ }
+
+ var fn = Expr.attrHandle[ name.toLowerCase() ],
+ // Don't get fooled by Object.prototype properties (jQuery #13807)
+ val = fn && hasOwn.call( Expr.attrHandle, name.toLowerCase() ) ?
+ fn( elem, name, !documentIsHTML ) :
+ undefined;
+
+ return val === undefined ?
+ support.attributes || !documentIsHTML ?
+ elem.getAttribute( name ) :
+ (val = elem.getAttributeNode(name)) && val.specified ?
+ val.value :
+ null :
+ val;
+};
+
+Sizzle.error = function( msg ) {
+ throw new Error( "Syntax error, unrecognized expression: " + msg );
+};
+
+/**
+ * Document sorting and removing duplicates
+ * @param {ArrayLike} results
+ */
+Sizzle.uniqueSort = function( results ) {
+ var elem,
+ duplicates = [],
+ j = 0,
+ i = 0;
+
+ // Unless we *know* we can detect duplicates, assume their presence
+ hasDuplicate = !support.detectDuplicates;
+ sortInput = !support.sortStable && results.slice( 0 );
+ results.sort( sortOrder );
+
+ if ( hasDuplicate ) {
+ while ( (elem = results[i++]) ) {
+ if ( elem === results[ i ] ) {
+ j = duplicates.push( i );
+ }
+ }
+ while ( j-- ) {
+ results.splice( duplicates[ j ], 1 );
+ }
+ }
+
+ return results;
+};
+
+/**
+ * Utility function for retrieving the text value of an array of DOM nodes
+ * @param {Array|Element} elem
+ */
+getText = Sizzle.getText = function( elem ) {
+ var node,
+ ret = "",
+ i = 0,
+ nodeType = elem.nodeType;
+
+ if ( !nodeType ) {
+ // If no nodeType, this is expected to be an array
+ for ( ; (node = elem[i]); i++ ) {
+ // Do not traverse comment nodes
+ ret += getText( node );
+ }
+ } else if ( nodeType === 1 || nodeType === 9 || nodeType === 11 ) {
+ // Use textContent for elements
+ // innerText usage removed for consistency of new lines (see #11153)
+ if ( typeof elem.textContent === "string" ) {
+ return elem.textContent;
+ } else {
+ // Traverse its children
+ for ( elem = elem.firstChild; elem; elem = elem.nextSibling ) {
+ ret += getText( elem );
+ }
+ }
+ } else if ( nodeType === 3 || nodeType === 4 ) {
+ return elem.nodeValue;
+ }
+ // Do not include comment or processing instruction nodes
+
+ return ret;
+};
+
+Expr = Sizzle.selectors = {
+
+ // Can be adjusted by the user
+ cacheLength: 50,
+
+ createPseudo: markFunction,
+
+ match: matchExpr,
+
+ attrHandle: {},
+
+ find: {},
+
+ relative: {
+ ">": { dir: "parentNode", first: true },
+ " ": { dir: "parentNode" },
+ "+": { dir: "previousSibling", first: true },
+ "~": { dir: "previousSibling" }
+ },
+
+ preFilter: {
+ "ATTR": function( match ) {
+ match[1] = match[1].replace( runescape, funescape );
+
+ // Move the given value to match[3] whether quoted or unquoted
+ match[3] = ( match[4] || match[5] || "" ).replace( runescape, funescape );
+
+ if ( match[2] === "~=" ) {
+ match[3] = " " + match[3] + " ";
+ }
+
+ return match.slice( 0, 4 );
+ },
+
+ "CHILD": function( match ) {
+ /* matches from matchExpr["CHILD"]
+ 1 type (only|nth|...)
+ 2 what (child|of-type)
+ 3 argument (even|odd|\d*|\d*n([+-]\d+)?|...)
+ 4 xn-component of xn+y argument ([+-]?\d*n|)
+ 5 sign of xn-component
+ 6 x of xn-component
+ 7 sign of y-component
+ 8 y of y-component
+ */
+ match[1] = match[1].toLowerCase();
+
+ if ( match[1].slice( 0, 3 ) === "nth" ) {
+ // nth-* requires argument
+ if ( !match[3] ) {
+ Sizzle.error( match[0] );
+ }
+
+ // numeric x and y parameters for Expr.filter.CHILD
+ // remember that false/true cast respectively to 0/1
+ match[4] = +( match[4] ? match[5] + (match[6] || 1) : 2 * ( match[3] === "even" || match[3] === "odd" ) );
+ match[5] = +( ( match[7] + match[8] ) || match[3] === "odd" );
+
+ // other types prohibit arguments
+ } else if ( match[3] ) {
+ Sizzle.error( match[0] );
+ }
+
+ return match;
+ },
+
+ "PSEUDO": function( match ) {
+ var excess,
+ unquoted = !match[5] && match[2];
+
+ if ( matchExpr["CHILD"].test( match[0] ) ) {
+ return null;
+ }
+
+ // Accept quoted arguments as-is
+ if ( match[3] && match[4] !== undefined ) {
+ match[2] = match[4];
+
+ // Strip excess characters from unquoted arguments
+ } else if ( unquoted && rpseudo.test( unquoted ) &&
+ // Get excess from tokenize (recursively)
+ (excess = tokenize( unquoted, true )) &&
+ // advance to the next closing parenthesis
+ (excess = unquoted.indexOf( ")", unquoted.length - excess ) - unquoted.length) ) {
+
+ // excess is a negative index
+ match[0] = match[0].slice( 0, excess );
+ match[2] = unquoted.slice( 0, excess );
+ }
+
+ // Return only captures needed by the pseudo filter method (type and argument)
+ return match.slice( 0, 3 );
+ }
+ },
+
+ filter: {
+
+ "TAG": function( nodeNameSelector ) {
+ var nodeName = nodeNameSelector.replace( runescape, funescape ).toLowerCase();
+ return nodeNameSelector === "*" ?
+ function() { return true; } :
+ function( elem ) {
+ return elem.nodeName && elem.nodeName.toLowerCase() === nodeName;
+ };
+ },
+
+ "CLASS": function( className ) {
+ var pattern = classCache[ className + " " ];
+
+ return pattern ||
+ (pattern = new RegExp( "(^|" + whitespace + ")" + className + "(" + whitespace + "|$)" )) &&
+ classCache( className, function( elem ) {
+ return pattern.test( typeof elem.className === "string" && elem.className || typeof elem.getAttribute !== strundefined && elem.getAttribute("class") || "" );
+ });
+ },
+
+ "ATTR": function( name, operator, check ) {
+ return function( elem ) {
+ var result = Sizzle.attr( elem, name );
+
+ if ( result == null ) {
+ return operator === "!=";
+ }
+ if ( !operator ) {
+ return true;
+ }
+
+ result += "";
+
+ return operator === "=" ? result === check :
+ operator === "!=" ? result !== check :
+ operator === "^=" ? check && result.indexOf( check ) === 0 :
+ operator === "*=" ? check && result.indexOf( check ) > -1 :
+ operator === "$=" ? check && result.slice( -check.length ) === check :
+ operator === "~=" ? ( " " + result + " " ).indexOf( check ) > -1 :
+ operator === "|=" ? result === check || result.slice( 0, check.length + 1 ) === check + "-" :
+ false;
+ };
+ },
+
+ "CHILD": function( type, what, argument, first, last ) {
+ var simple = type.slice( 0, 3 ) !== "nth",
+ forward = type.slice( -4 ) !== "last",
+ ofType = what === "of-type";
+
+ return first === 1 && last === 0 ?
+
+ // Shortcut for :nth-*(n)
+ function( elem ) {
+ return !!elem.parentNode;
+ } :
+
+ function( elem, context, xml ) {
+ var cache, outerCache, node, diff, nodeIndex, start,
+ dir = simple !== forward ? "nextSibling" : "previousSibling",
+ parent = elem.parentNode,
+ name = ofType && elem.nodeName.toLowerCase(),
+ useCache = !xml && !ofType;
+
+ if ( parent ) {
+
+ // :(first|last|only)-(child|of-type)
+ if ( simple ) {
+ while ( dir ) {
+ node = elem;
+ while ( (node = node[ dir ]) ) {
+ if ( ofType ? node.nodeName.toLowerCase() === name : node.nodeType === 1 ) {
+ return false;
+ }
+ }
+ // Reverse direction for :only-* (if we haven't yet done so)
+ start = dir = type === "only" && !start && "nextSibling";
+ }
+ return true;
+ }
+
+ start = [ forward ? parent.firstChild : parent.lastChild ];
+
+ // non-xml :nth-child(...) stores cache data on `parent`
+ if ( forward && useCache ) {
+ // Seek `elem` from a previously-cached index
+ outerCache = parent[ expando ] || (parent[ expando ] = {});
+ cache = outerCache[ type ] || [];
+ nodeIndex = cache[0] === dirruns && cache[1];
+ diff = cache[0] === dirruns && cache[2];
+ node = nodeIndex && parent.childNodes[ nodeIndex ];
+
+ while ( (node = ++nodeIndex && node && node[ dir ] ||
+
+ // Fallback to seeking `elem` from the start
+ (diff = nodeIndex = 0) || start.pop()) ) {
+
+ // When found, cache indexes on `parent` and break
+ if ( node.nodeType === 1 && ++diff && node === elem ) {
+ outerCache[ type ] = [ dirruns, nodeIndex, diff ];
+ break;
+ }
+ }
+
+ // Use previously-cached element index if available
+ } else if ( useCache && (cache = (elem[ expando ] || (elem[ expando ] = {}))[ type ]) && cache[0] === dirruns ) {
+ diff = cache[1];
+
+ // xml :nth-child(...) or :nth-last-child(...) or :nth(-last)?-of-type(...)
+ } else {
+ // Use the same loop as above to seek `elem` from the start
+ while ( (node = ++nodeIndex && node && node[ dir ] ||
+ (diff = nodeIndex = 0) || start.pop()) ) {
+
+ if ( ( ofType ? node.nodeName.toLowerCase() === name : node.nodeType === 1 ) && ++diff ) {
+ // Cache the index of each encountered element
+ if ( useCache ) {
+ (node[ expando ] || (node[ expando ] = {}))[ type ] = [ dirruns, diff ];
+ }
+
+ if ( node === elem ) {
+ break;
+ }
+ }
+ }
+ }
+
+ // Incorporate the offset, then check against cycle size
+ diff -= last;
+ return diff === first || ( diff % first === 0 && diff / first >= 0 );
+ }
+ };
+ },
+
+ "PSEUDO": function( pseudo, argument ) {
+ // pseudo-class names are case-insensitive
+ // http://www.w3.org/TR/selectors/#pseudo-classes
+ // Prioritize by case sensitivity in case custom pseudos are added with uppercase letters
+ // Remember that setFilters inherits from pseudos
+ var args,
+ fn = Expr.pseudos[ pseudo ] || Expr.setFilters[ pseudo.toLowerCase() ] ||
+ Sizzle.error( "unsupported pseudo: " + pseudo );
+
+ // The user may use createPseudo to indicate that
+ // arguments are needed to create the filter function
+ // just as Sizzle does
+ if ( fn[ expando ] ) {
+ return fn( argument );
+ }
+
+ // But maintain support for old signatures
+ if ( fn.length > 1 ) {
+ args = [ pseudo, pseudo, "", argument ];
+ return Expr.setFilters.hasOwnProperty( pseudo.toLowerCase() ) ?
+ markFunction(function( seed, matches ) {
+ var idx,
+ matched = fn( seed, argument ),
+ i = matched.length;
+ while ( i-- ) {
+ idx = indexOf.call( seed, matched[i] );
+ seed[ idx ] = !( matches[ idx ] = matched[i] );
+ }
+ }) :
+ function( elem ) {
+ return fn( elem, 0, args );
+ };
+ }
+
+ return fn;
+ }
+ },
+
+ pseudos: {
+ // Potentially complex pseudos
+ "not": markFunction(function( selector ) {
+ // Trim the selector passed to compile
+ // to avoid treating leading and trailing
+ // spaces as combinators
+ var input = [],
+ results = [],
+ matcher = compile( selector.replace( rtrim, "$1" ) );
+
+ return matcher[ expando ] ?
+ markFunction(function( seed, matches, context, xml ) {
+ var elem,
+ unmatched = matcher( seed, null, xml, [] ),
+ i = seed.length;
+
+ // Match elements unmatched by `matcher`
+ while ( i-- ) {
+ if ( (elem = unmatched[i]) ) {
+ seed[i] = !(matches[i] = elem);
+ }
+ }
+ }) :
+ function( elem, context, xml ) {
+ input[0] = elem;
+ matcher( input, null, xml, results );
+ return !results.pop();
+ };
+ }),
+
+ "has": markFunction(function( selector ) {
+ return function( elem ) {
+ return Sizzle( selector, elem ).length > 0;
+ };
+ }),
+
+ "contains": markFunction(function( text ) {
+ return function( elem ) {
+ return ( elem.textContent || elem.innerText || getText( elem ) ).indexOf( text ) > -1;
+ };
+ }),
+
+ // "Whether an element is represented by a :lang() selector
+ // is based solely on the element's language value
+ // being equal to the identifier C,
+ // or beginning with the identifier C immediately followed by "-".
+ // The matching of C against the element's language value is performed case-insensitively.
+ // The identifier C does not have to be a valid language name."
+ // http://www.w3.org/TR/selectors/#lang-pseudo
+ "lang": markFunction( function( lang ) {
+ // lang value must be a valid identifier
+ if ( !ridentifier.test(lang || "") ) {
+ Sizzle.error( "unsupported lang: " + lang );
+ }
+ lang = lang.replace( runescape, funescape ).toLowerCase();
+ return function( elem ) {
+ var elemLang;
+ do {
+ if ( (elemLang = documentIsHTML ?
+ elem.lang :
+ elem.getAttribute("xml:lang") || elem.getAttribute("lang")) ) {
+
+ elemLang = elemLang.toLowerCase();
+ return elemLang === lang || elemLang.indexOf( lang + "-" ) === 0;
+ }
+ } while ( (elem = elem.parentNode) && elem.nodeType === 1 );
+ return false;
+ };
+ }),
+
+ // Miscellaneous
+ "target": function( elem ) {
+ var hash = window.location && window.location.hash;
+ return hash && hash.slice( 1 ) === elem.id;
+ },
+
+ "root": function( elem ) {
+ return elem === docElem;
+ },
+
+ "focus": function( elem ) {
+ return elem === document.activeElement && (!document.hasFocus || document.hasFocus()) && !!(elem.type || elem.href || ~elem.tabIndex);
+ },
+
+ // Boolean properties
+ "enabled": function( elem ) {
+ return elem.disabled === false;
+ },
+
+ "disabled": function( elem ) {
+ return elem.disabled === true;
+ },
+
+ "checked": function( elem ) {
+ // In CSS3, :checked should return both checked and selected elements
+ // http://www.w3.org/TR/2011/REC-css3-selectors-20110929/#checked
+ var nodeName = elem.nodeName.toLowerCase();
+ return (nodeName === "input" && !!elem.checked) || (nodeName === "option" && !!elem.selected);
+ },
+
+ "selected": function( elem ) {
+ // Accessing this property makes selected-by-default
+ // options in Safari work properly
+ if ( elem.parentNode ) {
+ elem.parentNode.selectedIndex;
+ }
+
+ return elem.selected === true;
+ },
+
+ // Contents
+ "empty": function( elem ) {
+ // http://www.w3.org/TR/selectors/#empty-pseudo
+ // :empty is only affected by element nodes and content nodes(including text(3), cdata(4)),
+ // not comment, processing instructions, or others
+ // Thanks to Diego Perini for the nodeName shortcut
+ // Greater than "@" means alpha characters (specifically not starting with "#" or "?")
+ for ( elem = elem.firstChild; elem; elem = elem.nextSibling ) {
+ if ( elem.nodeName > "@" || elem.nodeType === 3 || elem.nodeType === 4 ) {
+ return false;
+ }
+ }
+ return true;
+ },
+
+ "parent": function( elem ) {
+ return !Expr.pseudos["empty"]( elem );
+ },
+
+ // Element/input types
+ "header": function( elem ) {
+ return rheader.test( elem.nodeName );
+ },
+
+ "input": function( elem ) {
+ return rinputs.test( elem.nodeName );
+ },
+
+ "button": function( elem ) {
+ var name = elem.nodeName.toLowerCase();
+ return name === "input" && elem.type === "button" || name === "button";
+ },
+
+ "text": function( elem ) {
+ var attr;
+ // IE6 and 7 will map elem.type to 'text' for new HTML5 types (search, etc)
+ // use getAttribute instead to test this case
+ return elem.nodeName.toLowerCase() === "input" &&
+ elem.type === "text" &&
+ ( (attr = elem.getAttribute("type")) == null || attr.toLowerCase() === elem.type );
+ },
+
+ // Position-in-collection
+ "first": createPositionalPseudo(function() {
+ return [ 0 ];
+ }),
+
+ "last": createPositionalPseudo(function( matchIndexes, length ) {
+ return [ length - 1 ];
+ }),
+
+ "eq": createPositionalPseudo(function( matchIndexes, length, argument ) {
+ return [ argument < 0 ? argument + length : argument ];
+ }),
+
+ "even": createPositionalPseudo(function( matchIndexes, length ) {
+ var i = 0;
+ for ( ; i < length; i += 2 ) {
+ matchIndexes.push( i );
+ }
+ return matchIndexes;
+ }),
+
+ "odd": createPositionalPseudo(function( matchIndexes, length ) {
+ var i = 1;
+ for ( ; i < length; i += 2 ) {
+ matchIndexes.push( i );
+ }
+ return matchIndexes;
+ }),
+
+ "lt": createPositionalPseudo(function( matchIndexes, length, argument ) {
+ var i = argument < 0 ? argument + length : argument;
+ for ( ; --i >= 0; ) {
+ matchIndexes.push( i );
+ }
+ return matchIndexes;
+ }),
+
+ "gt": createPositionalPseudo(function( matchIndexes, length, argument ) {
+ var i = argument < 0 ? argument + length : argument;
+ for ( ; ++i < length; ) {
+ matchIndexes.push( i );
+ }
+ return matchIndexes;
+ })
+ }
+};
+
+Expr.pseudos["nth"] = Expr.pseudos["eq"];
+
+// Add button/input type pseudos
+for ( i in { radio: true, checkbox: true, file: true, password: true, image: true } ) {
+ Expr.pseudos[ i ] = createInputPseudo( i );
+}
+for ( i in { submit: true, reset: true } ) {
+ Expr.pseudos[ i ] = createButtonPseudo( i );
+}
+
+// Easy API for creating new setFilters
+function setFilters() {}
+setFilters.prototype = Expr.filters = Expr.pseudos;
+Expr.setFilters = new setFilters();
+
+function tokenize( selector, parseOnly ) {
+ var matched, match, tokens, type,
+ soFar, groups, preFilters,
+ cached = tokenCache[ selector + " " ];
+
+ if ( cached ) {
+ return parseOnly ? 0 : cached.slice( 0 );
+ }
+
+ soFar = selector;
+ groups = [];
+ preFilters = Expr.preFilter;
+
+ while ( soFar ) {
+
+ // Comma and first run
+ if ( !matched || (match = rcomma.exec( soFar )) ) {
+ if ( match ) {
+ // Don't consume trailing commas as valid
+ soFar = soFar.slice( match[0].length ) || soFar;
+ }
+ groups.push( tokens = [] );
+ }
+
+ matched = false;
+
+ // Combinators
+ if ( (match = rcombinators.exec( soFar )) ) {
+ matched = match.shift();
+ tokens.push({
+ value: matched,
+ // Cast descendant combinators to space
+ type: match[0].replace( rtrim, " " )
+ });
+ soFar = soFar.slice( matched.length );
+ }
+
+ // Filters
+ for ( type in Expr.filter ) {
+ if ( (match = matchExpr[ type ].exec( soFar )) && (!preFilters[ type ] ||
+ (match = preFilters[ type ]( match ))) ) {
+ matched = match.shift();
+ tokens.push({
+ value: matched,
+ type: type,
+ matches: match
+ });
+ soFar = soFar.slice( matched.length );
+ }
+ }
+
+ if ( !matched ) {
+ break;
+ }
+ }
+
+ // Return the length of the invalid excess
+ // if we're just parsing
+ // Otherwise, throw an error or return tokens
+ return parseOnly ?
+ soFar.length :
+ soFar ?
+ Sizzle.error( selector ) :
+ // Cache the tokens
+ tokenCache( selector, groups ).slice( 0 );
+}
+
+function toSelector( tokens ) {
+ var i = 0,
+ len = tokens.length,
+ selector = "";
+ for ( ; i < len; i++ ) {
+ selector += tokens[i].value;
+ }
+ return selector;
+}
+
+function addCombinator( matcher, combinator, base ) {
+ var dir = combinator.dir,
+ checkNonElements = base && dir === "parentNode",
+ doneName = done++;
+
+ return combinator.first ?
+ // Check against closest ancestor/preceding element
+ function( elem, context, xml ) {
+ while ( (elem = elem[ dir ]) ) {
+ if ( elem.nodeType === 1 || checkNonElements ) {
+ return matcher( elem, context, xml );
+ }
+ }
+ } :
+
+ // Check against all ancestor/preceding elements
+ function( elem, context, xml ) {
+ var data, cache, outerCache,
+ dirkey = dirruns + " " + doneName;
+
+ // We can't set arbitrary data on XML nodes, so they don't benefit from dir caching
+ if ( xml ) {
+ while ( (elem = elem[ dir ]) ) {
+ if ( elem.nodeType === 1 || checkNonElements ) {
+ if ( matcher( elem, context, xml ) ) {
+ return true;
+ }
+ }
+ }
+ } else {
+ while ( (elem = elem[ dir ]) ) {
+ if ( elem.nodeType === 1 || checkNonElements ) {
+ outerCache = elem[ expando ] || (elem[ expando ] = {});
+ if ( (cache = outerCache[ dir ]) && cache[0] === dirkey ) {
+ if ( (data = cache[1]) === true || data === cachedruns ) {
+ return data === true;
+ }
+ } else {
+ cache = outerCache[ dir ] = [ dirkey ];
+ cache[1] = matcher( elem, context, xml ) || cachedruns;
+ if ( cache[1] === true ) {
+ return true;
+ }
+ }
+ }
+ }
+ }
+ };
+}
+
+function elementMatcher( matchers ) {
+ return matchers.length > 1 ?
+ function( elem, context, xml ) {
+ var i = matchers.length;
+ while ( i-- ) {
+ if ( !matchers[i]( elem, context, xml ) ) {
+ return false;
+ }
+ }
+ return true;
+ } :
+ matchers[0];
+}
+
+function condense( unmatched, map, filter, context, xml ) {
+ var elem,
+ newUnmatched = [],
+ i = 0,
+ len = unmatched.length,
+ mapped = map != null;
+
+ for ( ; i < len; i++ ) {
+ if ( (elem = unmatched[i]) ) {
+ if ( !filter || filter( elem, context, xml ) ) {
+ newUnmatched.push( elem );
+ if ( mapped ) {
+ map.push( i );
+ }
+ }
+ }
+ }
+
+ return newUnmatched;
+}
+
+function setMatcher( preFilter, selector, matcher, postFilter, postFinder, postSelector ) {
+ if ( postFilter && !postFilter[ expando ] ) {
+ postFilter = setMatcher( postFilter );
+ }
+ if ( postFinder && !postFinder[ expando ] ) {
+ postFinder = setMatcher( postFinder, postSelector );
+ }
+ return markFunction(function( seed, results, context, xml ) {
+ var temp, i, elem,
+ preMap = [],
+ postMap = [],
+ preexisting = results.length,
+
+ // Get initial elements from seed or context
+ elems = seed || multipleContexts( selector || "*", context.nodeType ? [ context ] : context, [] ),
+
+ // Prefilter to get matcher input, preserving a map for seed-results synchronization
+ matcherIn = preFilter && ( seed || !selector ) ?
+ condense( elems, preMap, preFilter, context, xml ) :
+ elems,
+
+ matcherOut = matcher ?
+ // If we have a postFinder, or filtered seed, or non-seed postFilter or preexisting results,
+ postFinder || ( seed ? preFilter : preexisting || postFilter ) ?
+
+ // ...intermediate processing is necessary
+ [] :
+
+ // ...otherwise use results directly
+ results :
+ matcherIn;
+
+ // Find primary matches
+ if ( matcher ) {
+ matcher( matcherIn, matcherOut, context, xml );
+ }
+
+ // Apply postFilter
+ if ( postFilter ) {
+ temp = condense( matcherOut, postMap );
+ postFilter( temp, [], context, xml );
+
+ // Un-match failing elements by moving them back to matcherIn
+ i = temp.length;
+ while ( i-- ) {
+ if ( (elem = temp[i]) ) {
+ matcherOut[ postMap[i] ] = !(matcherIn[ postMap[i] ] = elem);
+ }
+ }
+ }
+
+ if ( seed ) {
+ if ( postFinder || preFilter ) {
+ if ( postFinder ) {
+ // Get the final matcherOut by condensing this intermediate into postFinder contexts
+ temp = [];
+ i = matcherOut.length;
+ while ( i-- ) {
+ if ( (elem = matcherOut[i]) ) {
+ // Restore matcherIn since elem is not yet a final match
+ temp.push( (matcherIn[i] = elem) );
+ }
+ }
+ postFinder( null, (matcherOut = []), temp, xml );
+ }
+
+ // Move matched elements from seed to results to keep them synchronized
+ i = matcherOut.length;
+ while ( i-- ) {
+ if ( (elem = matcherOut[i]) &&
+ (temp = postFinder ? indexOf.call( seed, elem ) : preMap[i]) > -1 ) {
+
+ seed[temp] = !(results[temp] = elem);
+ }
+ }
+ }
+
+ // Add elements to results, through postFinder if defined
+ } else {
+ matcherOut = condense(
+ matcherOut === results ?
+ matcherOut.splice( preexisting, matcherOut.length ) :
+ matcherOut
+ );
+ if ( postFinder ) {
+ postFinder( null, results, matcherOut, xml );
+ } else {
+ push.apply( results, matcherOut );
+ }
+ }
+ });
+}
+
+function matcherFromTokens( tokens ) {
+ var checkContext, matcher, j,
+ len = tokens.length,
+ leadingRelative = Expr.relative[ tokens[0].type ],
+ implicitRelative = leadingRelative || Expr.relative[" "],
+ i = leadingRelative ? 1 : 0,
+
+ // The foundational matcher ensures that elements are reachable from top-level context(s)
+ matchContext = addCombinator( function( elem ) {
+ return elem === checkContext;
+ }, implicitRelative, true ),
+ matchAnyContext = addCombinator( function( elem ) {
+ return indexOf.call( checkContext, elem ) > -1;
+ }, implicitRelative, true ),
+ matchers = [ function( elem, context, xml ) {
+ return ( !leadingRelative && ( xml || context !== outermostContext ) ) || (
+ (checkContext = context).nodeType ?
+ matchContext( elem, context, xml ) :
+ matchAnyContext( elem, context, xml ) );
+ } ];
+
+ for ( ; i < len; i++ ) {
+ if ( (matcher = Expr.relative[ tokens[i].type ]) ) {
+ matchers = [ addCombinator(elementMatcher( matchers ), matcher) ];
+ } else {
+ matcher = Expr.filter[ tokens[i].type ].apply( null, tokens[i].matches );
+
+ // Return special upon seeing a positional matcher
+ if ( matcher[ expando ] ) {
+ // Find the next relative operator (if any) for proper handling
+ j = ++i;
+ for ( ; j < len; j++ ) {
+ if ( Expr.relative[ tokens[j].type ] ) {
+ break;
+ }
+ }
+ return setMatcher(
+ i > 1 && elementMatcher( matchers ),
+ i > 1 && toSelector(
+ // If the preceding token was a descendant combinator, insert an implicit any-element `*`
+ tokens.slice( 0, i - 1 ).concat({ value: tokens[ i - 2 ].type === " " ? "*" : "" })
+ ).replace( rtrim, "$1" ),
+ matcher,
+ i < j && matcherFromTokens( tokens.slice( i, j ) ),
+ j < len && matcherFromTokens( (tokens = tokens.slice( j )) ),
+ j < len && toSelector( tokens )
+ );
+ }
+ matchers.push( matcher );
+ }
+ }
+
+ return elementMatcher( matchers );
+}
+
+function matcherFromGroupMatchers( elementMatchers, setMatchers ) {
+ // A counter to specify which element is currently being matched
+ var matcherCachedRuns = 0,
+ bySet = setMatchers.length > 0,
+ byElement = elementMatchers.length > 0,
+ superMatcher = function( seed, context, xml, results, expandContext ) {
+ var elem, j, matcher,
+ setMatched = [],
+ matchedCount = 0,
+ i = "0",
+ unmatched = seed && [],
+ outermost = expandContext != null,
+ contextBackup = outermostContext,
+ // We must always have either seed elements or context
+ elems = seed || byElement && Expr.find["TAG"]( "*", expandContext && context.parentNode || context ),
+ // Use integer dirruns iff this is the outermost matcher
+ dirrunsUnique = (dirruns += contextBackup == null ? 1 : Math.random() || 0.1);
+
+ if ( outermost ) {
+ outermostContext = context !== document && context;
+ cachedruns = matcherCachedRuns;
+ }
+
+ // Add elements passing elementMatchers directly to results
+ // Keep `i` a string if there are no elements so `matchedCount` will be "00" below
+ for ( ; (elem = elems[i]) != null; i++ ) {
+ if ( byElement && elem ) {
+ j = 0;
+ while ( (matcher = elementMatchers[j++]) ) {
+ if ( matcher( elem, context, xml ) ) {
+ results.push( elem );
+ break;
+ }
+ }
+ if ( outermost ) {
+ dirruns = dirrunsUnique;
+ cachedruns = ++matcherCachedRuns;
+ }
+ }
+
+ // Track unmatched elements for set filters
+ if ( bySet ) {
+ // They will have gone through all possible matchers
+ if ( (elem = !matcher && elem) ) {
+ matchedCount--;
+ }
+
+ // Lengthen the array for every element, matched or not
+ if ( seed ) {
+ unmatched.push( elem );
+ }
+ }
+ }
+
+ // Apply set filters to unmatched elements
+ matchedCount += i;
+ if ( bySet && i !== matchedCount ) {
+ j = 0;
+ while ( (matcher = setMatchers[j++]) ) {
+ matcher( unmatched, setMatched, context, xml );
+ }
+
+ if ( seed ) {
+ // Reintegrate element matches to eliminate the need for sorting
+ if ( matchedCount > 0 ) {
+ while ( i-- ) {
+ if ( !(unmatched[i] || setMatched[i]) ) {
+ setMatched[i] = pop.call( results );
+ }
+ }
+ }
+
+ // Discard index placeholder values to get only actual matches
+ setMatched = condense( setMatched );
+ }
+
+ // Add matches to results
+ push.apply( results, setMatched );
+
+ // Seedless set matches succeeding multiple successful matchers stipulate sorting
+ if ( outermost && !seed && setMatched.length > 0 &&
+ ( matchedCount + setMatchers.length ) > 1 ) {
+
+ Sizzle.uniqueSort( results );
+ }
+ }
+
+ // Override manipulation of globals by nested matchers
+ if ( outermost ) {
+ dirruns = dirrunsUnique;
+ outermostContext = contextBackup;
+ }
+
+ return unmatched;
+ };
+
+ return bySet ?
+ markFunction( superMatcher ) :
+ superMatcher;
+}
+
+compile = Sizzle.compile = function( selector, group /* Internal Use Only */ ) {
+ var i,
+ setMatchers = [],
+ elementMatchers = [],
+ cached = compilerCache[ selector + " " ];
+
+ if ( !cached ) {
+ // Generate a function of recursive functions that can be used to check each element
+ if ( !group ) {
+ group = tokenize( selector );
+ }
+ i = group.length;
+ while ( i-- ) {
+ cached = matcherFromTokens( group[i] );
+ if ( cached[ expando ] ) {
+ setMatchers.push( cached );
+ } else {
+ elementMatchers.push( cached );
+ }
+ }
+
+ // Cache the compiled function
+ cached = compilerCache( selector, matcherFromGroupMatchers( elementMatchers, setMatchers ) );
+ }
+ return cached;
+};
+
+function multipleContexts( selector, contexts, results ) {
+ var i = 0,
+ len = contexts.length;
+ for ( ; i < len; i++ ) {
+ Sizzle( selector, contexts[i], results );
+ }
+ return results;
+}
+
+function select( selector, context, results, seed ) {
+ var i, tokens, token, type, find,
+ match = tokenize( selector );
+
+ if ( !seed ) {
+ // Try to minimize operations if there is only one group
+ if ( match.length === 1 ) {
+
+ // Take a shortcut and set the context if the root selector is an ID
+ tokens = match[0] = match[0].slice( 0 );
+ if ( tokens.length > 2 && (token = tokens[0]).type === "ID" &&
+ support.getById && context.nodeType === 9 && documentIsHTML &&
+ Expr.relative[ tokens[1].type ] ) {
+
+ context = ( Expr.find["ID"]( token.matches[0].replace(runescape, funescape), context ) || [] )[0];
+ if ( !context ) {
+ return results;
+ }
+ selector = selector.slice( tokens.shift().value.length );
+ }
+
+ // Fetch a seed set for right-to-left matching
+ i = matchExpr["needsContext"].test( selector ) ? 0 : tokens.length;
+ while ( i-- ) {
+ token = tokens[i];
+
+ // Abort if we hit a combinator
+ if ( Expr.relative[ (type = token.type) ] ) {
+ break;
+ }
+ if ( (find = Expr.find[ type ]) ) {
+ // Search, expanding context for leading sibling combinators
+ if ( (seed = find(
+ token.matches[0].replace( runescape, funescape ),
+ rsibling.test( tokens[0].type ) && context.parentNode || context
+ )) ) {
+
+ // If seed is empty or no tokens remain, we can return early
+ tokens.splice( i, 1 );
+ selector = seed.length && toSelector( tokens );
+ if ( !selector ) {
+ push.apply( results, seed );
+ return results;
+ }
+
+ break;
+ }
+ }
+ }
+ }
+ }
+
+ // Compile and execute a filtering function
+ // Provide `match` to avoid retokenization if we modified the selector above
+ compile( selector, match )(
+ seed,
+ context,
+ !documentIsHTML,
+ results,
+ rsibling.test( selector )
+ );
+ return results;
+}
+
+// One-time assignments
+
+// Sort stability
+support.sortStable = expando.split("").sort( sortOrder ).join("") === expando;
+
+// Support: Chrome<14
+// Always assume duplicates if they aren't passed to the comparison function
+support.detectDuplicates = hasDuplicate;
+
+// Initialize against the default document
+setDocument();
+
+// Support: Webkit<537.32 - Safari 6.0.3/Chrome 25 (fixed in Chrome 27)
+// Detached nodes confoundingly follow *each other*
+support.sortDetached = assert(function( div1 ) {
+ // Should return 1, but returns 4 (following)
+ return div1.compareDocumentPosition( document.createElement("div") ) & 1;
+});
+
+// Support: IE<8
+// Prevent attribute/property "interpolation"
+// http://msdn.microsoft.com/en-us/library/ms536429%28VS.85%29.aspx
+if ( !assert(function( div ) {
+ div.innerHTML = "<a href='#'></a>";
+ return div.firstChild.getAttribute("href") === "#" ;
+}) ) {
+ addHandle( "type|href|height|width", function( elem, name, isXML ) {
+ if ( !isXML ) {
+ return elem.getAttribute( name, name.toLowerCase() === "type" ? 1 : 2 );
+ }
+ });
+}
+
+// Support: IE<9
+// Use defaultValue in place of getAttribute("value")
+if ( !support.attributes || !assert(function( div ) {
+ div.innerHTML = "<input/>";
+ div.firstChild.setAttribute( "value", "" );
+ return div.firstChild.getAttribute( "value" ) === "";
+}) ) {
+ addHandle( "value", function( elem, name, isXML ) {
+ if ( !isXML && elem.nodeName.toLowerCase() === "input" ) {
+ return elem.defaultValue;
+ }
+ });
+}
+
+// Support: IE<9
+// Use getAttributeNode to fetch booleans when getAttribute lies
+if ( !assert(function( div ) {
+ return div.getAttribute("disabled") == null;
+}) ) {
+ addHandle( booleans, function( elem, name, isXML ) {
+ var val;
+ if ( !isXML ) {
+ return (val = elem.getAttributeNode( name )) && val.specified ?
+ val.value :
+ elem[ name ] === true ? name.toLowerCase() : null;
+ }
+ });
+}
+
+jQuery.find = Sizzle;
+jQuery.expr = Sizzle.selectors;
+jQuery.expr[":"] = jQuery.expr.pseudos;
+jQuery.unique = Sizzle.uniqueSort;
+jQuery.text = Sizzle.getText;
+jQuery.isXMLDoc = Sizzle.isXML;
+jQuery.contains = Sizzle.contains;
+
+
+})( window );
+// String to Object options format cache
+var optionsCache = {};
+
+// Convert String-formatted options into Object-formatted ones and store in cache
+function createOptions( options ) {
+ var object = optionsCache[ options ] = {};
+ jQuery.each( options.match( core_rnotwhite ) || [], function( _, flag ) {
+ object[ flag ] = true;
+ });
+ return object;
+}
+
+/*
+ * Create a callback list using the following parameters:
+ *
+ * options: an optional list of space-separated options that will change how
+ * the callback list behaves or a more traditional option object
+ *
+ * By default a callback list will act like an event callback list and can be
+ * "fired" multiple times.
+ *
+ * Possible options:
+ *
+ * once: will ensure the callback list can only be fired once (like a Deferred)
+ *
+ * memory: will keep track of previous values and will call any callback added
+ * after the list has been fired right away with the latest "memorized"
+ * values (like a Deferred)
+ *
+ * unique: will ensure a callback can only be added once (no duplicate in the list)
+ *
+ * stopOnFalse: interrupt callings when a callback returns false
+ *
+ */
+jQuery.Callbacks = function( options ) {
+
+ // Convert options from String-formatted to Object-formatted if needed
+ // (we check in cache first)
+ options = typeof options === "string" ?
+ ( optionsCache[ options ] || createOptions( options ) ) :
+ jQuery.extend( {}, options );
+
+ var // Last fire value (for non-forgettable lists)
+ memory,
+ // Flag to know if list was already fired
+ fired,
+ // Flag to know if list is currently firing
+ firing,
+ // First callback to fire (used internally by add and fireWith)
+ firingStart,
+ // End of the loop when firing
+ firingLength,
+ // Index of currently firing callback (modified by remove if needed)
+ firingIndex,
+ // Actual callback list
+ list = [],
+ // Stack of fire calls for repeatable lists
+ stack = !options.once && [],
+ // Fire callbacks
+ fire = function( data ) {
+ memory = options.memory && data;
+ fired = true;
+ firingIndex = firingStart || 0;
+ firingStart = 0;
+ firingLength = list.length;
+ firing = true;
+ for ( ; list && firingIndex < firingLength; firingIndex++ ) {
+ if ( list[ firingIndex ].apply( data[ 0 ], data[ 1 ] ) === false && options.stopOnFalse ) {
+ memory = false; // To prevent further calls using add
+ break;
+ }
+ }
+ firing = false;
+ if ( list ) {
+ if ( stack ) {
+ if ( stack.length ) {
+ fire( stack.shift() );
+ }
+ } else if ( memory ) {
+ list = [];
+ } else {
+ self.disable();
+ }
+ }
+ },
+ // Actual Callbacks object
+ self = {
+ // Add a callback or a collection of callbacks to the list
+ add: function() {
+ if ( list ) {
+ // First, we save the current length
+ var start = list.length;
+ (function add( args ) {
+ jQuery.each( args, function( _, arg ) {
+ var type = jQuery.type( arg );
+ if ( type === "function" ) {
+ if ( !options.unique || !self.has( arg ) ) {
+ list.push( arg );
+ }
+ } else if ( arg && arg.length && type !== "string" ) {
+ // Inspect recursively
+ add( arg );
+ }
+ });
+ })( arguments );
+ // Do we need to add the callbacks to the
+ // current firing batch?
+ if ( firing ) {
+ firingLength = list.length;
+ // With memory, if we're not firing then
+ // we should call right away
+ } else if ( memory ) {
+ firingStart = start;
+ fire( memory );
+ }
+ }
+ return this;
+ },
+ // Remove a callback from the list
+ remove: function() {
+ if ( list ) {
+ jQuery.each( arguments, function( _, arg ) {
+ var index;
+ while( ( index = jQuery.inArray( arg, list, index ) ) > -1 ) {
+ list.splice( index, 1 );
+ // Handle firing indexes
+ if ( firing ) {
+ if ( index <= firingLength ) {
+ firingLength--;
+ }
+ if ( index <= firingIndex ) {
+ firingIndex--;
+ }
+ }
+ }
+ });
+ }
+ return this;
+ },
+ // Check if a given callback is in the list.
+ // If no argument is given, return whether or not list has callbacks attached.
+ has: function( fn ) {
+ return fn ? jQuery.inArray( fn, list ) > -1 : !!( list && list.length );
+ },
+ // Remove all callbacks from the list
+ empty: function() {
+ list = [];
+ firingLength = 0;
+ return this;
+ },
+ // Have the list do nothing anymore
+ disable: function() {
+ list = stack = memory = undefined;
+ return this;
+ },
+ // Is it disabled?
+ disabled: function() {
+ return !list;
+ },
+ // Lock the list in its current state
+ lock: function() {
+ stack = undefined;
+ if ( !memory ) {
+ self.disable();
+ }
+ return this;
+ },
+ // Is it locked?
+ locked: function() {
+ return !stack;
+ },
+ // Call all callbacks with the given context and arguments
+ fireWith: function( context, args ) {
+ if ( list && ( !fired || stack ) ) {
+ args = args || [];
+ args = [ context, args.slice ? args.slice() : args ];
+ if ( firing ) {
+ stack.push( args );
+ } else {
+ fire( args );
+ }
+ }
+ return this;
+ },
+ // Call all the callbacks with the given arguments
+ fire: function() {
+ self.fireWith( this, arguments );
+ return this;
+ },
+ // To know if the callbacks have already been called at least once
+ fired: function() {
+ return !!fired;
+ }
+ };
+
+ return self;
+};
+jQuery.extend({
+
+ Deferred: function( func ) {
+ var tuples = [
+ // action, add listener, listener list, final state
+ [ "resolve", "done", jQuery.Callbacks("once memory"), "resolved" ],
+ [ "reject", "fail", jQuery.Callbacks("once memory"), "rejected" ],
+ [ "notify", "progress", jQuery.Callbacks("memory") ]
+ ],
+ state = "pending",
+ promise = {
+ state: function() {
+ return state;
+ },
+ always: function() {
+ deferred.done( arguments ).fail( arguments );
+ return this;
+ },
+ then: function( /* fnDone, fnFail, fnProgress */ ) {
+ var fns = arguments;
+ return jQuery.Deferred(function( newDefer ) {
+ jQuery.each( tuples, function( i, tuple ) {
+ var action = tuple[ 0 ],
+ fn = jQuery.isFunction( fns[ i ] ) && fns[ i ];
+ // deferred[ done | fail | progress ] for forwarding actions to newDefer
+ deferred[ tuple[1] ](function() {
+ var returned = fn && fn.apply( this, arguments );
+ if ( returned && jQuery.isFunction( returned.promise ) ) {
+ returned.promise()
+ .done( newDefer.resolve )
+ .fail( newDefer.reject )
+ .progress( newDefer.notify );
+ } else {
+ newDefer[ action + "With" ]( this === promise ? newDefer.promise() : this, fn ? [ returned ] : arguments );
+ }
+ });
+ });
+ fns = null;
+ }).promise();
+ },
+ // Get a promise for this deferred
+ // If obj is provided, the promise aspect is added to the object
+ promise: function( obj ) {
+ return obj != null ? jQuery.extend( obj, promise ) : promise;
+ }
+ },
+ deferred = {};
+
+ // Keep pipe for back-compat
+ promise.pipe = promise.then;
+
+ // Add list-specific methods
+ jQuery.each( tuples, function( i, tuple ) {
+ var list = tuple[ 2 ],
+ stateString = tuple[ 3 ];
+
+ // promise[ done | fail | progress ] = list.add
+ promise[ tuple[1] ] = list.add;
+
+ // Handle state
+ if ( stateString ) {
+ list.add(function() {
+ // state = [ resolved | rejected ]
+ state = stateString;
+
+ // [ reject_list | resolve_list ].disable; progress_list.lock
+ }, tuples[ i ^ 1 ][ 2 ].disable, tuples[ 2 ][ 2 ].lock );
+ }
+
+ // deferred[ resolve | reject | notify ]
+ deferred[ tuple[0] ] = function() {
+ deferred[ tuple[0] + "With" ]( this === deferred ? promise : this, arguments );
+ return this;
+ };
+ deferred[ tuple[0] + "With" ] = list.fireWith;
+ });
+
+ // Make the deferred a promise
+ promise.promise( deferred );
+
+ // Call given func if any
+ if ( func ) {
+ func.call( deferred, deferred );
+ }
+
+ // All done!
+ return deferred;
+ },
+
+ // Deferred helper
+ when: function( subordinate /* , ..., subordinateN */ ) {
+ var i = 0,
+ resolveValues = core_slice.call( arguments ),
+ length = resolveValues.length,
+
+ // the count of uncompleted subordinates
+ remaining = length !== 1 || ( subordinate && jQuery.isFunction( subordinate.promise ) ) ? length : 0,
+
+ // the master Deferred. If resolveValues consist of only a single Deferred, just use that.
+ deferred = remaining === 1 ? subordinate : jQuery.Deferred(),
+
+ // Update function for both resolve and progress values
+ updateFunc = function( i, contexts, values ) {
+ return function( value ) {
+ contexts[ i ] = this;
+ values[ i ] = arguments.length > 1 ? core_slice.call( arguments ) : value;
+ if( values === progressValues ) {
+ deferred.notifyWith( contexts, values );
+ } else if ( !( --remaining ) ) {
+ deferred.resolveWith( contexts, values );
+ }
+ };
+ },
+
+ progressValues, progressContexts, resolveContexts;
+
+ // add listeners to Deferred subordinates; treat others as resolved
+ if ( length > 1 ) {
+ progressValues = new Array( length );
+ progressContexts = new Array( length );
+ resolveContexts = new Array( length );
+ for ( ; i < length; i++ ) {
+ if ( resolveValues[ i ] && jQuery.isFunction( resolveValues[ i ].promise ) ) {
+ resolveValues[ i ].promise()
+ .done( updateFunc( i, resolveContexts, resolveValues ) )
+ .fail( deferred.reject )
+ .progress( updateFunc( i, progressContexts, progressValues ) );
+ } else {
+ --remaining;
+ }
+ }
+ }
+
+ // if we're not waiting on anything, resolve the master
+ if ( !remaining ) {
+ deferred.resolveWith( resolveContexts, resolveValues );
+ }
+
+ return deferred.promise();
+ }
+});
+jQuery.support = (function( support ) {
+ var input = document.createElement("input"),
+ fragment = document.createDocumentFragment(),
+ div = document.createElement("div"),
+ select = document.createElement("select"),
+ opt = select.appendChild( document.createElement("option") );
+
+ // Finish early in limited environments
+ if ( !input.type ) {
+ return support;
+ }
+
+ input.type = "checkbox";
+
+ // Support: Safari 5.1, iOS 5.1, Android 4.x, Android 2.3
+ // Check the default checkbox/radio value ("" on old WebKit; "on" elsewhere)
+ support.checkOn = input.value !== "";
+
+ // Must access the parent to make an option select properly
+ // Support: IE9, IE10
+ support.optSelected = opt.selected;
+
+ // Will be defined later
+ support.reliableMarginRight = true;
+ support.boxSizingReliable = true;
+ support.pixelPosition = false;
+
+ // Make sure checked status is properly cloned
+ // Support: IE9, IE10
+ input.checked = true;
+ support.noCloneChecked = input.cloneNode( true ).checked;
+
+ // Make sure that the options inside disabled selects aren't marked as disabled
+ // (WebKit marks them as disabled)
+ select.disabled = true;
+ support.optDisabled = !opt.disabled;
+
+ // Check if an input maintains its value after becoming a radio
+ // Support: IE9, IE10
+ input = document.createElement("input");
+ input.value = "t";
+ input.type = "radio";
+ support.radioValue = input.value === "t";
+
+ // #11217 - WebKit loses check when the name is after the checked attribute
+ input.setAttribute( "checked", "t" );
+ input.setAttribute( "name", "t" );
+
+ fragment.appendChild( input );
+
+ // Support: Safari 5.1, Android 4.x, Android 2.3
+ // old WebKit doesn't clone checked state correctly in fragments
+ support.checkClone = fragment.cloneNode( true ).cloneNode( true ).lastChild.checked;
+
+ // Support: Firefox, Chrome, Safari
+ // Beware of CSP restrictions (https://developer.mozilla.org/en/Security/CSP)
+ support.focusinBubbles = "onfocusin" in window;
+
+ div.style.backgroundClip = "content-box";
+ div.cloneNode( true ).style.backgroundClip = "";
+ support.clearCloneStyle = div.style.backgroundClip === "content-box";
+
+ // Run tests that need a body at doc ready
+ jQuery(function() {
+ var container, marginDiv,
+ // Support: Firefox, Android 2.3 (Prefixed box-sizing versions).
+ divReset = "padding:0;margin:0;border:0;display:block;-webkit-box-sizing:content-box;-moz-box-sizing:content-box;box-sizing:content-box",
+ body = document.getElementsByTagName("body")[ 0 ];
+
+ if ( !body ) {
+ // Return for frameset docs that don't have a body
+ return;
+ }
+
+ container = document.createElement("div");
+ container.style.cssText = "border:0;width:0;height:0;position:absolute;top:0;left:-9999px;margin-top:1px";
+
+ // Check box-sizing and margin behavior.
+ body.appendChild( container ).appendChild( div );
+ div.innerHTML = "";
+ // Support: Firefox, Android 2.3 (Prefixed box-sizing versions).
+ div.style.cssText = "-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;padding:1px;border:1px;display:block;width:4px;margin-top:1%;position:absolute;top:1%";
+
+ // Workaround failing boxSizing test due to offsetWidth returning wrong value
+ // with some non-1 values of body zoom, ticket #13543
+ jQuery.swap( body, body.style.zoom != null ? { zoom: 1 } : {}, function() {
+ support.boxSizing = div.offsetWidth === 4;
+ });
+
+ // Use window.getComputedStyle because jsdom on node.js will break without it.
+ if ( window.getComputedStyle ) {
+ support.pixelPosition = ( window.getComputedStyle( div, null ) || {} ).top !== "1%";
+ support.boxSizingReliable = ( window.getComputedStyle( div, null ) || { width: "4px" } ).width === "4px";
+
+ // Support: Android 2.3
+ // Check if div with explicit width and no margin-right incorrectly
+ // gets computed margin-right based on width of container. (#3333)
+ // WebKit Bug 13343 - getComputedStyle returns wrong value for margin-right
+ marginDiv = div.appendChild( document.createElement("div") );
+ marginDiv.style.cssText = div.style.cssText = divReset;
+ marginDiv.style.marginRight = marginDiv.style.width = "0";
+ div.style.width = "1px";
+
+ support.reliableMarginRight =
+ !parseFloat( ( window.getComputedStyle( marginDiv, null ) || {} ).marginRight );
+ }
+
+ body.removeChild( container );
+ });
+
+ return support;
+})( {} );
+
+/*
+ Implementation Summary
+
+ 1. Enforce API surface and semantic compatibility with 1.9.x branch
+ 2. Improve the module's maintainability by reducing the storage
+ paths to a single mechanism.
+ 3. Use the same single mechanism to support "private" and "user" data.
+ 4. _Never_ expose "private" data to user code (TODO: Drop _data, _removeData)
+ 5. Avoid exposing implementation details on user objects (eg. expando properties)
+ 6. Provide a clear path for implementation upgrade to WeakMap in 2014
+*/
+var data_user, data_priv,
+ rbrace = /(?:\{[\s\S]*\}|\[[\s\S]*\])$/,
+ rmultiDash = /([A-Z])/g;
+
+function Data() {
+ // Support: Android < 4,
+ // Old WebKit does not have Object.preventExtensions/freeze method,
+ // return new empty object instead with no [[set]] accessor
+ Object.defineProperty( this.cache = {}, 0, {
+ get: function() {
+ return {};
+ }
+ });
+
+ this.expando = jQuery.expando + Math.random();
+}
+
+Data.uid = 1;
+
+Data.accepts = function( owner ) {
+ // Accepts only:
+ // - Node
+ // - Node.ELEMENT_NODE
+ // - Node.DOCUMENT_NODE
+ // - Object
+ // - Any
+ return owner.nodeType ?
+ owner.nodeType === 1 || owner.nodeType === 9 : true;
+};
+
+Data.prototype = {
+ key: function( owner ) {
+ // We can accept data for non-element nodes in modern browsers,
+ // but we should not, see #8335.
+ // Always return the key for a frozen object.
+ if ( !Data.accepts( owner ) ) {
+ return 0;
+ }
+
+ var descriptor = {},
+ // Check if the owner object already has a cache key
+ unlock = owner[ this.expando ];
+
+ // If not, create one
+ if ( !unlock ) {
+ unlock = Data.uid++;
+
+ // Secure it in a non-enumerable, non-writable property
+ try {
+ descriptor[ this.expando ] = { value: unlock };
+ Object.defineProperties( owner, descriptor );
+
+ // Support: Android < 4
+ // Fallback to a less secure definition
+ } catch ( e ) {
+ descriptor[ this.expando ] = unlock;
+ jQuery.extend( owner, descriptor );
+ }
+ }
+
+ // Ensure the cache object
+ if ( !this.cache[ unlock ] ) {
+ this.cache[ unlock ] = {};
+ }
+
+ return unlock;
+ },
+ set: function( owner, data, value ) {
+ var prop,
+ // There may be an unlock assigned to this node,
+ // if there is no entry for this "owner", create one inline
+ // and set the unlock as though an owner entry had always existed
+ unlock = this.key( owner ),
+ cache = this.cache[ unlock ];
+
+ // Handle: [ owner, key, value ] args
+ if ( typeof data === "string" ) {
+ cache[ data ] = value;
+
+ // Handle: [ owner, { properties } ] args
+ } else {
+ // Fresh assignments by object are shallow copied
+ if ( jQuery.isEmptyObject( cache ) ) {
+ jQuery.extend( this.cache[ unlock ], data );
+ // Otherwise, copy the properties one-by-one to the cache object
+ } else {
+ for ( prop in data ) {
+ cache[ prop ] = data[ prop ];
+ }
+ }
+ }
+ return cache;
+ },
+ get: function( owner, key ) {
+ // Either a valid cache is found, or will be created.
+ // New caches will be created and the unlock returned,
+ // allowing direct access to the newly created
+ // empty data object. A valid owner object must be provided.
+ var cache = this.cache[ this.key( owner ) ];
+
+ return key === undefined ?
+ cache : cache[ key ];
+ },
+ access: function( owner, key, value ) {
+ var stored;
+ // In cases where either:
+ //
+ // 1. No key was specified
+ // 2. A string key was specified, but no value provided
+ //
+ // Take the "read" path and allow the get method to determine
+ // which value to return, respectively either:
+ //
+ // 1. The entire cache object
+ // 2. The data stored at the key
+ //
+ if ( key === undefined ||
+ ((key && typeof key === "string") && value === undefined) ) {
+
+ stored = this.get( owner, key );
+
+ return stored !== undefined ?
+ stored : this.get( owner, jQuery.camelCase(key) );
+ }
+
+ // [*]When the key is not a string, or both a key and value
+ // are specified, set or extend (existing objects) with either:
+ //
+ // 1. An object of properties
+ // 2. A key and value
+ //
+ this.set( owner, key, value );
+
+ // Since the "set" path can have two possible entry points
+ // return the expected data based on which path was taken[*]
+ return value !== undefined ? value : key;
+ },
+ remove: function( owner, key ) {
+ var i, name, camel,
+ unlock = this.key( owner ),
+ cache = this.cache[ unlock ];
+
+ if ( key === undefined ) {
+ this.cache[ unlock ] = {};
+
+ } else {
+ // Support array or space separated string of keys
+ if ( jQuery.isArray( key ) ) {
+ // If "name" is an array of keys...
+ // When data is initially created, via ("key", "val") signature,
+ // keys will be converted to camelCase.
+ // Since there is no way to tell _how_ a key was added, remove
+ // both plain key and camelCase key. #12786
+ // This will only penalize the array argument path.
+ name = key.concat( key.map( jQuery.camelCase ) );
+ } else {
+ camel = jQuery.camelCase( key );
+ // Try the string as a key before any manipulation
+ if ( key in cache ) {
+ name = [ key, camel ];
+ } else {
+ // If a key with the spaces exists, use it.
+ // Otherwise, create an array by matching non-whitespace
+ name = camel;
+ name = name in cache ?
+ [ name ] : ( name.match( core_rnotwhite ) || [] );
+ }
+ }
+
+ i = name.length;
+ while ( i-- ) {
+ delete cache[ name[ i ] ];
+ }
+ }
+ },
+ hasData: function( owner ) {
+ return !jQuery.isEmptyObject(
+ this.cache[ owner[ this.expando ] ] || {}
+ );
+ },
+ discard: function( owner ) {
+ if ( owner[ this.expando ] ) {
+ delete this.cache[ owner[ this.expando ] ];
+ }
+ }
+};
+
+// These may be used throughout the jQuery core codebase
+data_user = new Data();
+data_priv = new Data();
+
+
+jQuery.extend({
+ acceptData: Data.accepts,
+
+ hasData: function( elem ) {
+ return data_user.hasData( elem ) || data_priv.hasData( elem );
+ },
+
+ data: function( elem, name, data ) {
+ return data_user.access( elem, name, data );
+ },
+
+ removeData: function( elem, name ) {
+ data_user.remove( elem, name );
+ },
+
+ // TODO: Now that all calls to _data and _removeData have been replaced
+ // with direct calls to data_priv methods, these can be deprecated.
+ _data: function( elem, name, data ) {
+ return data_priv.access( elem, name, data );
+ },
+
+ _removeData: function( elem, name ) {
+ data_priv.remove( elem, name );
+ }
+});
+
+jQuery.fn.extend({
+ data: function( key, value ) {
+ var attrs, name,
+ elem = this[ 0 ],
+ i = 0,
+ data = null;
+
+ // Gets all values
+ if ( key === undefined ) {
+ if ( this.length ) {
+ data = data_user.get( elem );
+
+ if ( elem.nodeType === 1 && !data_priv.get( elem, "hasDataAttrs" ) ) {
+ attrs = elem.attributes;
+ for ( ; i < attrs.length; i++ ) {
+ name = attrs[ i ].name;
+
+ if ( name.indexOf( "data-" ) === 0 ) {
+ name = jQuery.camelCase( name.slice(5) );
+ dataAttr( elem, name, data[ name ] );
+ }
+ }
+ data_priv.set( elem, "hasDataAttrs", true );
+ }
+ }
+
+ return data;
+ }
+
+ // Sets multiple values
+ if ( typeof key === "object" ) {
+ return this.each(function() {
+ data_user.set( this, key );
+ });
+ }
+
+ return jQuery.access( this, function( value ) {
+ var data,
+ camelKey = jQuery.camelCase( key );
+
+ // The calling jQuery object (element matches) is not empty
+ // (and therefore has an element appears at this[ 0 ]) and the
+ // `value` parameter was not undefined. An empty jQuery object
+ // will result in `undefined` for elem = this[ 0 ] which will
+ // throw an exception if an attempt to read a data cache is made.
+ if ( elem && value === undefined ) {
+ // Attempt to get data from the cache
+ // with the key as-is
+ data = data_user.get( elem, key );
+ if ( data !== undefined ) {
+ return data;
+ }
+
+ // Attempt to get data from the cache
+ // with the key camelized
+ data = data_user.get( elem, camelKey );
+ if ( data !== undefined ) {
+ return data;
+ }
+
+ // Attempt to "discover" the data in
+ // HTML5 custom data-* attrs
+ data = dataAttr( elem, camelKey, undefined );
+ if ( data !== undefined ) {
+ return data;
+ }
+
+ // We tried really hard, but the data doesn't exist.
+ return;
+ }
+
+ // Set the data...
+ this.each(function() {
+ // First, attempt to store a copy or reference of any
+ // data that might've been store with a camelCased key.
+ var data = data_user.get( this, camelKey );
+
+ // For HTML5 data-* attribute interop, we have to
+ // store property names with dashes in a camelCase form.
+ // This might not apply to all properties...*
+ data_user.set( this, camelKey, value );
+
+ // *... In the case of properties that might _actually_
+ // have dashes, we need to also store a copy of that
+ // unchanged property.
+ if ( key.indexOf("-") !== -1 && data !== undefined ) {
+ data_user.set( this, key, value );
+ }
+ });
+ }, null, value, arguments.length > 1, null, true );
+ },
+
+ removeData: function( key ) {
+ return this.each(function() {
+ data_user.remove( this, key );
+ });
+ }
+});
+
+function dataAttr( elem, key, data ) {
+ var name;
+
+ // If nothing was found internally, try to fetch any
+ // data from the HTML5 data-* attribute
+ if ( data === undefined && elem.nodeType === 1 ) {
+ name = "data-" + key.replace( rmultiDash, "-$1" ).toLowerCase();
+ data = elem.getAttribute( name );
+
+ if ( typeof data === "string" ) {
+ try {
+ data = data === "true" ? true :
+ data === "false" ? false :
+ data === "null" ? null :
+ // Only convert to a number if it doesn't change the string
+ +data + "" === data ? +data :
+ rbrace.test( data ) ? JSON.parse( data ) :
+ data;
+ } catch( e ) {}
+
+ // Make sure we set the data so it isn't changed later
+ data_user.set( elem, key, data );
+ } else {
+ data = undefined;
+ }
+ }
+ return data;
+}
+jQuery.extend({
+ queue: function( elem, type, data ) {
+ var queue;
+
+ if ( elem ) {
+ type = ( type || "fx" ) + "queue";
+ queue = data_priv.get( elem, type );
+
+ // Speed up dequeue by getting out quickly if this is just a lookup
+ if ( data ) {
+ if ( !queue || jQuery.isArray( data ) ) {
+ queue = data_priv.access( elem, type, jQuery.makeArray(data) );
+ } else {
+ queue.push( data );
+ }
+ }
+ return queue || [];
+ }
+ },
+
+ dequeue: function( elem, type ) {
+ type = type || "fx";
+
+ var queue = jQuery.queue( elem, type ),
+ startLength = queue.length,
+ fn = queue.shift(),
+ hooks = jQuery._queueHooks( elem, type ),
+ next = function() {
+ jQuery.dequeue( elem, type );
+ };
+
+ // If the fx queue is dequeued, always remove the progress sentinel
+ if ( fn === "inprogress" ) {
+ fn = queue.shift();
+ startLength--;
+ }
+
+ if ( fn ) {
+
+ // Add a progress sentinel to prevent the fx queue from being
+ // automatically dequeued
+ if ( type === "fx" ) {
+ queue.unshift( "inprogress" );
+ }
+
+ // clear up the last queue stop function
+ delete hooks.stop;
+ fn.call( elem, next, hooks );
+ }
+
+ if ( !startLength && hooks ) {
+ hooks.empty.fire();
+ }
+ },
+
+ // not intended for public consumption - generates a queueHooks object, or returns the current one
+ _queueHooks: function( elem, type ) {
+ var key = type + "queueHooks";
+ return data_priv.get( elem, key ) || data_priv.access( elem, key, {
+ empty: jQuery.Callbacks("once memory").add(function() {
+ data_priv.remove( elem, [ type + "queue", key ] );
+ })
+ });
+ }
+});
+
+jQuery.fn.extend({
+ queue: function( type, data ) {
+ var setter = 2;
+
+ if ( typeof type !== "string" ) {
+ data = type;
+ type = "fx";
+ setter--;
+ }
+
+ if ( arguments.length < setter ) {
+ return jQuery.queue( this[0], type );
+ }
+
+ return data === undefined ?
+ this :
+ this.each(function() {
+ var queue = jQuery.queue( this, type, data );
+
+ // ensure a hooks for this queue
+ jQuery._queueHooks( this, type );
+
+ if ( type === "fx" && queue[0] !== "inprogress" ) {
+ jQuery.dequeue( this, type );
+ }
+ });
+ },
+ dequeue: function( type ) {
+ return this.each(function() {
+ jQuery.dequeue( this, type );
+ });
+ },
+ // Based off of the plugin by Clint Helfers, with permission.
+ // http://blindsignals.com/index.php/2009/07/jquery-delay/
+ delay: function( time, type ) {
+ time = jQuery.fx ? jQuery.fx.speeds[ time ] || time : time;
+ type = type || "fx";
+
+ return this.queue( type, function( next, hooks ) {
+ var timeout = setTimeout( next, time );
+ hooks.stop = function() {
+ clearTimeout( timeout );
+ };
+ });
+ },
+ clearQueue: function( type ) {
+ return this.queue( type || "fx", [] );
+ },
+ // Get a promise resolved when queues of a certain type
+ // are emptied (fx is the type by default)
+ promise: function( type, obj ) {
+ var tmp,
+ count = 1,
+ defer = jQuery.Deferred(),
+ elements = this,
+ i = this.length,
+ resolve = function() {
+ if ( !( --count ) ) {
+ defer.resolveWith( elements, [ elements ] );
+ }
+ };
+
+ if ( typeof type !== "string" ) {
+ obj = type;
+ type = undefined;
+ }
+ type = type || "fx";
+
+ while( i-- ) {
+ tmp = data_priv.get( elements[ i ], type + "queueHooks" );
+ if ( tmp && tmp.empty ) {
+ count++;
+ tmp.empty.add( resolve );
+ }
+ }
+ resolve();
+ return defer.promise( obj );
+ }
+});
+var nodeHook, boolHook,
+ rclass = /[\t\r\n\f]/g,
+ rreturn = /\r/g,
+ rfocusable = /^(?:input|select|textarea|button)$/i;
+
+jQuery.fn.extend({
+ attr: function( name, value ) {
+ return jQuery.access( this, jQuery.attr, name, value, arguments.length > 1 );
+ },
+
+ removeAttr: function( name ) {
+ return this.each(function() {
+ jQuery.removeAttr( this, name );
+ });
+ },
+
+ prop: function( name, value ) {
+ return jQuery.access( this, jQuery.prop, name, value, arguments.length > 1 );
+ },
+
+ removeProp: function( name ) {
+ return this.each(function() {
+ delete this[ jQuery.propFix[ name ] || name ];
+ });
+ },
+
+ addClass: function( value ) {
+ var classes, elem, cur, clazz, j,
+ i = 0,
+ len = this.length,
+ proceed = typeof value === "string" && value;
+
+ if ( jQuery.isFunction( value ) ) {
+ return this.each(function( j ) {
+ jQuery( this ).addClass( value.call( this, j, this.className ) );
+ });
+ }
+
+ if ( proceed ) {
+ // The disjunction here is for better compressibility (see removeClass)
+ classes = ( value || "" ).match( core_rnotwhite ) || [];
+
+ for ( ; i < len; i++ ) {
+ elem = this[ i ];
+ cur = elem.nodeType === 1 && ( elem.className ?
+ ( " " + elem.className + " " ).replace( rclass, " " ) :
+ " "
+ );
+
+ if ( cur ) {
+ j = 0;
+ while ( (clazz = classes[j++]) ) {
+ if ( cur.indexOf( " " + clazz + " " ) < 0 ) {
+ cur += clazz + " ";
+ }
+ }
+ elem.className = jQuery.trim( cur );
+
+ }
+ }
+ }
+
+ return this;
+ },
+
+ removeClass: function( value ) {
+ var classes, elem, cur, clazz, j,
+ i = 0,
+ len = this.length,
+ proceed = arguments.length === 0 || typeof value === "string" && value;
+
+ if ( jQuery.isFunction( value ) ) {
+ return this.each(function( j ) {
+ jQuery( this ).removeClass( value.call( this, j, this.className ) );
+ });
+ }
+ if ( proceed ) {
+ classes = ( value || "" ).match( core_rnotwhite ) || [];
+
+ for ( ; i < len; i++ ) {
+ elem = this[ i ];
+ // This expression is here for better compressibility (see addClass)
+ cur = elem.nodeType === 1 && ( elem.className ?
+ ( " " + elem.className + " " ).replace( rclass, " " ) :
+ ""
+ );
+
+ if ( cur ) {
+ j = 0;
+ while ( (clazz = classes[j++]) ) {
+ // Remove *all* instances
+ while ( cur.indexOf( " " + clazz + " " ) >= 0 ) {
+ cur = cur.replace( " " + clazz + " ", " " );
+ }
+ }
+ elem.className = value ? jQuery.trim( cur ) : "";
+ }
+ }
+ }
+
+ return this;
+ },
+
+ toggleClass: function( value, stateVal ) {
+ var type = typeof value;
+
+ if ( typeof stateVal === "boolean" && type === "string" ) {
+ return stateVal ? this.addClass( value ) : this.removeClass( value );
+ }
+
+ if ( jQuery.isFunction( value ) ) {
+ return this.each(function( i ) {
+ jQuery( this ).toggleClass( value.call(this, i, this.className, stateVal), stateVal );
+ });
+ }
+
+ return this.each(function() {
+ if ( type === "string" ) {
+ // toggle individual class names
+ var className,
+ i = 0,
+ self = jQuery( this ),
+ classNames = value.match( core_rnotwhite ) || [];
+
+ while ( (className = classNames[ i++ ]) ) {
+ // check each className given, space separated list
+ if ( self.hasClass( className ) ) {
+ self.removeClass( className );
+ } else {
+ self.addClass( className );
+ }
+ }
+
+ // Toggle whole class name
+ } else if ( type === core_strundefined || type === "boolean" ) {
+ if ( this.className ) {
+ // store className if set
+ data_priv.set( this, "__className__", this.className );
+ }
+
+ // If the element has a class name or if we're passed "false",
+ // then remove the whole classname (if there was one, the above saved it).
+ // Otherwise bring back whatever was previously saved (if anything),
+ // falling back to the empty string if nothing was stored.
+ this.className = this.className || value === false ? "" : data_priv.get( this, "__className__" ) || "";
+ }
+ });
+ },
+
+ hasClass: function( selector ) {
+ var className = " " + selector + " ",
+ i = 0,
+ l = this.length;
+ for ( ; i < l; i++ ) {
+ if ( this[i].nodeType === 1 && (" " + this[i].className + " ").replace(rclass, " ").indexOf( className ) >= 0 ) {
+ return true;
+ }
+ }
+
+ return false;
+ },
+
+ val: function( value ) {
+ var hooks, ret, isFunction,
+ elem = this[0];
+
+ if ( !arguments.length ) {
+ if ( elem ) {
+ hooks = jQuery.valHooks[ elem.type ] || jQuery.valHooks[ elem.nodeName.toLowerCase() ];
+
+ if ( hooks && "get" in hooks && (ret = hooks.get( elem, "value" )) !== undefined ) {
+ return ret;
+ }
+
+ ret = elem.value;
+
+ return typeof ret === "string" ?
+ // handle most common string cases
+ ret.replace(rreturn, "") :
+ // handle cases where value is null/undef or number
+ ret == null ? "" : ret;
+ }
+
+ return;
+ }
+
+ isFunction = jQuery.isFunction( value );
+
+ return this.each(function( i ) {
+ var val;
+
+ if ( this.nodeType !== 1 ) {
+ return;
+ }
+
+ if ( isFunction ) {
+ val = value.call( this, i, jQuery( this ).val() );
+ } else {
+ val = value;
+ }
+
+ // Treat null/undefined as ""; convert numbers to string
+ if ( val == null ) {
+ val = "";
+ } else if ( typeof val === "number" ) {
+ val += "";
+ } else if ( jQuery.isArray( val ) ) {
+ val = jQuery.map(val, function ( value ) {
+ return value == null ? "" : value + "";
+ });
+ }
+
+ hooks = jQuery.valHooks[ this.type ] || jQuery.valHooks[ this.nodeName.toLowerCase() ];
+
+ // If set returns undefined, fall back to normal setting
+ if ( !hooks || !("set" in hooks) || hooks.set( this, val, "value" ) === undefined ) {
+ this.value = val;
+ }
+ });
+ }
+});
+
+jQuery.extend({
+ valHooks: {
+ option: {
+ get: function( elem ) {
+ // attributes.value is undefined in Blackberry 4.7 but
+ // uses .value. See #6932
+ var val = elem.attributes.value;
+ return !val || val.specified ? elem.value : elem.text;
+ }
+ },
+ select: {
+ get: function( elem ) {
+ var value, option,
+ options = elem.options,
+ index = elem.selectedIndex,
+ one = elem.type === "select-one" || index < 0,
+ values = one ? null : [],
+ max = one ? index + 1 : options.length,
+ i = index < 0 ?
+ max :
+ one ? index : 0;
+
+ // Loop through all the selected options
+ for ( ; i < max; i++ ) {
+ option = options[ i ];
+
+ // IE6-9 doesn't update selected after form reset (#2551)
+ if ( ( option.selected || i === index ) &&
+ // Don't return options that are disabled or in a disabled optgroup
+ ( jQuery.support.optDisabled ? !option.disabled : option.getAttribute("disabled") === null ) &&
+ ( !option.parentNode.disabled || !jQuery.nodeName( option.parentNode, "optgroup" ) ) ) {
+
+ // Get the specific value for the option
+ value = jQuery( option ).val();
+
+ // We don't need an array for one selects
+ if ( one ) {
+ return value;
+ }
+
+ // Multi-Selects return an array
+ values.push( value );
+ }
+ }
+
+ return values;
+ },
+
+ set: function( elem, value ) {
+ var optionSet, option,
+ options = elem.options,
+ values = jQuery.makeArray( value ),
+ i = options.length;
+
+ while ( i-- ) {
+ option = options[ i ];
+ if ( (option.selected = jQuery.inArray( jQuery(option).val(), values ) >= 0) ) {
+ optionSet = true;
+ }
+ }
+
+ // force browsers to behave consistently when non-matching value is set
+ if ( !optionSet ) {
+ elem.selectedIndex = -1;
+ }
+ return values;
+ }
+ }
+ },
+
+ attr: function( elem, name, value ) {
+ var hooks, ret,
+ nType = elem.nodeType;
+
+ // don't get/set attributes on text, comment and attribute nodes
+ if ( !elem || nType === 3 || nType === 8 || nType === 2 ) {
+ return;
+ }
+
+ // Fallback to prop when attributes are not supported
+ if ( typeof elem.getAttribute === core_strundefined ) {
+ return jQuery.prop( elem, name, value );
+ }
+
+ // All attributes are lowercase
+ // Grab necessary hook if one is defined
+ if ( nType !== 1 || !jQuery.isXMLDoc( elem ) ) {
+ name = name.toLowerCase();
+ hooks = jQuery.attrHooks[ name ] ||
+ ( jQuery.expr.match.bool.test( name ) ? boolHook : nodeHook );
+ }
+
+ if ( value !== undefined ) {
+
+ if ( value === null ) {
+ jQuery.removeAttr( elem, name );
+
+ } else if ( hooks && "set" in hooks && (ret = hooks.set( elem, value, name )) !== undefined ) {
+ return ret;
+
+ } else {
+ elem.setAttribute( name, value + "" );
+ return value;
+ }
+
+ } else if ( hooks && "get" in hooks && (ret = hooks.get( elem, name )) !== null ) {
+ return ret;
+
+ } else {
+ ret = jQuery.find.attr( elem, name );
+
+ // Non-existent attributes return null, we normalize to undefined
+ return ret == null ?
+ undefined :
+ ret;
+ }
+ },
+
+ removeAttr: function( elem, value ) {
+ var name, propName,
+ i = 0,
+ attrNames = value && value.match( core_rnotwhite );
+
+ if ( attrNames && elem.nodeType === 1 ) {
+ while ( (name = attrNames[i++]) ) {
+ propName = jQuery.propFix[ name ] || name;
+
+ // Boolean attributes get special treatment (#10870)
+ if ( jQuery.expr.match.bool.test( name ) ) {
+ // Set corresponding property to false
+ elem[ propName ] = false;
+ }
+
+ elem.removeAttribute( name );
+ }
+ }
+ },
+
+ attrHooks: {
+ type: {
+ set: function( elem, value ) {
+ if ( !jQuery.support.radioValue && value === "radio" && jQuery.nodeName(elem, "input") ) {
+ // Setting the type on a radio button after the value resets the value in IE6-9
+ // Reset value to default in case type is set after value during creation
+ var val = elem.value;
+ elem.setAttribute( "type", value );
+ if ( val ) {
+ elem.value = val;
+ }
+ return value;
+ }
+ }
+ }
+ },
+
+ propFix: {
+ "for": "htmlFor",
+ "class": "className"
+ },
+
+ prop: function( elem, name, value ) {
+ var ret, hooks, notxml,
+ nType = elem.nodeType;
+
+ // don't get/set properties on text, comment and attribute nodes
+ if ( !elem || nType === 3 || nType === 8 || nType === 2 ) {
+ return;
+ }
+
+ notxml = nType !== 1 || !jQuery.isXMLDoc( elem );
+
+ if ( notxml ) {
+ // Fix name and attach hooks
+ name = jQuery.propFix[ name ] || name;
+ hooks = jQuery.propHooks[ name ];
+ }
+
+ if ( value !== undefined ) {
+ return hooks && "set" in hooks && (ret = hooks.set( elem, value, name )) !== undefined ?
+ ret :
+ ( elem[ name ] = value );
+
+ } else {
+ return hooks && "get" in hooks && (ret = hooks.get( elem, name )) !== null ?
+ ret :
+ elem[ name ];
+ }
+ },
+
+ propHooks: {
+ tabIndex: {
+ get: function( elem ) {
+ return elem.hasAttribute( "tabindex" ) || rfocusable.test( elem.nodeName ) || elem.href ?
+ elem.tabIndex :
+ -1;
+ }
+ }
+ }
+});
+
+// Hooks for boolean attributes
+boolHook = {
+ set: function( elem, value, name ) {
+ if ( value === false ) {
+ // Remove boolean attributes when set to false
+ jQuery.removeAttr( elem, name );
+ } else {
+ elem.setAttribute( name, name );
+ }
+ return name;
+ }
+};
+jQuery.each( jQuery.expr.match.bool.source.match( /\w+/g ), function( i, name ) {
+ var getter = jQuery.expr.attrHandle[ name ] || jQuery.find.attr;
+
+ jQuery.expr.attrHandle[ name ] = function( elem, name, isXML ) {
+ var fn = jQuery.expr.attrHandle[ name ],
+ ret = isXML ?
+ undefined :
+ /* jshint eqeqeq: false */
+ // Temporarily disable this handler to check existence
+ (jQuery.expr.attrHandle[ name ] = undefined) !=
+ getter( elem, name, isXML ) ?
+
+ name.toLowerCase() :
+ null;
+
+ // Restore handler
+ jQuery.expr.attrHandle[ name ] = fn;
+
+ return ret;
+ };
+});
+
+// Support: IE9+
+// Selectedness for an option in an optgroup can be inaccurate
+if ( !jQuery.support.optSelected ) {
+ jQuery.propHooks.selected = {
+ get: function( elem ) {
+ var parent = elem.parentNode;
+ if ( parent && parent.parentNode ) {
+ parent.parentNode.selectedIndex;
+ }
+ return null;
+ }
+ };
+}
+
+jQuery.each([
+ "tabIndex",
+ "readOnly",
+ "maxLength",
+ "cellSpacing",
+ "cellPadding",
+ "rowSpan",
+ "colSpan",
+ "useMap",
+ "frameBorder",
+ "contentEditable"
+], function() {
+ jQuery.propFix[ this.toLowerCase() ] = this;
+});
+
+// Radios and checkboxes getter/setter
+jQuery.each([ "radio", "checkbox" ], function() {
+ jQuery.valHooks[ this ] = {
+ set: function( elem, value ) {
+ if ( jQuery.isArray( value ) ) {
+ return ( elem.checked = jQuery.inArray( jQuery(elem).val(), value ) >= 0 );
+ }
+ }
+ };
+ if ( !jQuery.support.checkOn ) {
+ jQuery.valHooks[ this ].get = function( elem ) {
+ // Support: Webkit
+ // "" is returned instead of "on" if a value isn't specified
+ return elem.getAttribute("value") === null ? "on" : elem.value;
+ };
+ }
+});
+var rkeyEvent = /^key/,
+ rmouseEvent = /^(?:mouse|contextmenu)|click/,
+ rfocusMorph = /^(?:focusinfocus|focusoutblur)$/,
+ rtypenamespace = /^([^.]*)(?:\.(.+)|)$/;
+
+function returnTrue() {
+ return true;
+}
+
+function returnFalse() {
+ return false;
+}
+
+function safeActiveElement() {
+ try {
+ return document.activeElement;
+ } catch ( err ) { }
+}
+
+/*
+ * Helper functions for managing events -- not part of the public interface.
+ * Props to Dean Edwards' addEvent library for many of the ideas.
+ */
+jQuery.event = {
+
+ global: {},
+
+ add: function( elem, types, handler, data, selector ) {
+
+ var handleObjIn, eventHandle, tmp,
+ events, t, handleObj,
+ special, handlers, type, namespaces, origType,
+ elemData = data_priv.get( elem );
+
+ // Don't attach events to noData or text/comment nodes (but allow plain objects)
+ if ( !elemData ) {
+ return;
+ }
+
+ // Caller can pass in an object of custom data in lieu of the handler
+ if ( handler.handler ) {
+ handleObjIn = handler;
+ handler = handleObjIn.handler;
+ selector = handleObjIn.selector;
+ }
+
+ // Make sure that the handler has a unique ID, used to find/remove it later
+ if ( !handler.guid ) {
+ handler.guid = jQuery.guid++;
+ }
+
+ // Init the element's event structure and main handler, if this is the first
+ if ( !(events = elemData.events) ) {
+ events = elemData.events = {};
+ }
+ if ( !(eventHandle = elemData.handle) ) {
+ eventHandle = elemData.handle = function( e ) {
+ // Discard the second event of a jQuery.event.trigger() and
+ // when an event is called after a page has unloaded
+ return typeof jQuery !== core_strundefined && (!e || jQuery.event.triggered !== e.type) ?
+ jQuery.event.dispatch.apply( eventHandle.elem, arguments ) :
+ undefined;
+ };
+ // Add elem as a property of the handle fn to prevent a memory leak with IE non-native events
+ eventHandle.elem = elem;
+ }
+
+ // Handle multiple events separated by a space
+ types = ( types || "" ).match( core_rnotwhite ) || [""];
+ t = types.length;
+ while ( t-- ) {
+ tmp = rtypenamespace.exec( types[t] ) || [];
+ type = origType = tmp[1];
+ namespaces = ( tmp[2] || "" ).split( "." ).sort();
+
+ // There *must* be a type, no attaching namespace-only handlers
+ if ( !type ) {
+ continue;
+ }
+
+ // If event changes its type, use the special event handlers for the changed type
+ special = jQuery.event.special[ type ] || {};
+
+ // If selector defined, determine special event api type, otherwise given type
+ type = ( selector ? special.delegateType : special.bindType ) || type;
+
+ // Update special based on newly reset type
+ special = jQuery.event.special[ type ] || {};
+
+ // handleObj is passed to all event handlers
+ handleObj = jQuery.extend({
+ type: type,
+ origType: origType,
+ data: data,
+ handler: handler,
+ guid: handler.guid,
+ selector: selector,
+ needsContext: selector && jQuery.expr.match.needsContext.test( selector ),
+ namespace: namespaces.join(".")
+ }, handleObjIn );
+
+ // Init the event handler queue if we're the first
+ if ( !(handlers = events[ type ]) ) {
+ handlers = events[ type ] = [];
+ handlers.delegateCount = 0;
+
+ // Only use addEventListener if the special events handler returns false
+ if ( !special.setup || special.setup.call( elem, data, namespaces, eventHandle ) === false ) {
+ if ( elem.addEventListener ) {
+ elem.addEventListener( type, eventHandle, false );
+ }
+ }
+ }
+
+ if ( special.add ) {
+ special.add.call( elem, handleObj );
+
+ if ( !handleObj.handler.guid ) {
+ handleObj.handler.guid = handler.guid;
+ }
+ }
+
+ // Add to the element's handler list, delegates in front
+ if ( selector ) {
+ handlers.splice( handlers.delegateCount++, 0, handleObj );
+ } else {
+ handlers.push( handleObj );
+ }
+
+ // Keep track of which events have ever been used, for event optimization
+ jQuery.event.global[ type ] = true;
+ }
+
+ // Nullify elem to prevent memory leaks in IE
+ elem = null;
+ },
+
+ // Detach an event or set of events from an element
+ remove: function( elem, types, handler, selector, mappedTypes ) {
+
+ var j, origCount, tmp,
+ events, t, handleObj,
+ special, handlers, type, namespaces, origType,
+ elemData = data_priv.hasData( elem ) && data_priv.get( elem );
+
+ if ( !elemData || !(events = elemData.events) ) {
+ return;
+ }
+
+ // Once for each type.namespace in types; type may be omitted
+ types = ( types || "" ).match( core_rnotwhite ) || [""];
+ t = types.length;
+ while ( t-- ) {
+ tmp = rtypenamespace.exec( types[t] ) || [];
+ type = origType = tmp[1];
+ namespaces = ( tmp[2] || "" ).split( "." ).sort();
+
+ // Unbind all events (on this namespace, if provided) for the element
+ if ( !type ) {
+ for ( type in events ) {
+ jQuery.event.remove( elem, type + types[ t ], handler, selector, true );
+ }
+ continue;
+ }
+
+ special = jQuery.event.special[ type ] || {};
+ type = ( selector ? special.delegateType : special.bindType ) || type;
+ handlers = events[ type ] || [];
+ tmp = tmp[2] && new RegExp( "(^|\\.)" + namespaces.join("\\.(?:.*\\.|)") + "(\\.|$)" );
+
+ // Remove matching events
+ origCount = j = handlers.length;
+ while ( j-- ) {
+ handleObj = handlers[ j ];
+
+ if ( ( mappedTypes || origType === handleObj.origType ) &&
+ ( !handler || handler.guid === handleObj.guid ) &&
+ ( !tmp || tmp.test( handleObj.namespace ) ) &&
+ ( !selector || selector === handleObj.selector || selector === "**" && handleObj.selector ) ) {
+ handlers.splice( j, 1 );
+
+ if ( handleObj.selector ) {
+ handlers.delegateCount--;
+ }
+ if ( special.remove ) {
+ special.remove.call( elem, handleObj );
+ }
+ }
+ }
+
+ // Remove generic event handler if we removed something and no more handlers exist
+ // (avoids potential for endless recursion during removal of special event handlers)
+ if ( origCount && !handlers.length ) {
+ if ( !special.teardown || special.teardown.call( elem, namespaces, elemData.handle ) === false ) {
+ jQuery.removeEvent( elem, type, elemData.handle );
+ }
+
+ delete events[ type ];
+ }
+ }
+
+ // Remove the expando if it's no longer used
+ if ( jQuery.isEmptyObject( events ) ) {
+ delete elemData.handle;
+ data_priv.remove( elem, "events" );
+ }
+ },
+
+ trigger: function( event, data, elem, onlyHandlers ) {
+
+ var i, cur, tmp, bubbleType, ontype, handle, special,
+ eventPath = [ elem || document ],
+ type = core_hasOwn.call( event, "type" ) ? event.type : event,
+ namespaces = core_hasOwn.call( event, "namespace" ) ? event.namespace.split(".") : [];
+
+ cur = tmp = elem = elem || document;
+
+ // Don't do events on text and comment nodes
+ if ( elem.nodeType === 3 || elem.nodeType === 8 ) {
+ return;
+ }
+
+ // focus/blur morphs to focusin/out; ensure we're not firing them right now
+ if ( rfocusMorph.test( type + jQuery.event.triggered ) ) {
+ return;
+ }
+
+ if ( type.indexOf(".") >= 0 ) {
+ // Namespaced trigger; create a regexp to match event type in handle()
+ namespaces = type.split(".");
+ type = namespaces.shift();
+ namespaces.sort();
+ }
+ ontype = type.indexOf(":") < 0 && "on" + type;
+
+ // Caller can pass in a jQuery.Event object, Object, or just an event type string
+ event = event[ jQuery.expando ] ?
+ event :
+ new jQuery.Event( type, typeof event === "object" && event );
+
+ // Trigger bitmask: & 1 for native handlers; & 2 for jQuery (always true)
+ event.isTrigger = onlyHandlers ? 2 : 3;
+ event.namespace = namespaces.join(".");
+ event.namespace_re = event.namespace ?
+ new RegExp( "(^|\\.)" + namespaces.join("\\.(?:.*\\.|)") + "(\\.|$)" ) :
+ null;
+
+ // Clean up the event in case it is being reused
+ event.result = undefined;
+ if ( !event.target ) {
+ event.target = elem;
+ }
+
+ // Clone any incoming data and prepend the event, creating the handler arg list
+ data = data == null ?
+ [ event ] :
+ jQuery.makeArray( data, [ event ] );
+
+ // Allow special events to draw outside the lines
+ special = jQuery.event.special[ type ] || {};
+ if ( !onlyHandlers && special.trigger && special.trigger.apply( elem, data ) === false ) {
+ return;
+ }
+
+ // Determine event propagation path in advance, per W3C events spec (#9951)
+ // Bubble up to document, then to window; watch for a global ownerDocument var (#9724)
+ if ( !onlyHandlers && !special.noBubble && !jQuery.isWindow( elem ) ) {
+
+ bubbleType = special.delegateType || type;
+ if ( !rfocusMorph.test( bubbleType + type ) ) {
+ cur = cur.parentNode;
+ }
+ for ( ; cur; cur = cur.parentNode ) {
+ eventPath.push( cur );
+ tmp = cur;
+ }
+
+ // Only add window if we got to document (e.g., not plain obj or detached DOM)
+ if ( tmp === (elem.ownerDocument || document) ) {
+ eventPath.push( tmp.defaultView || tmp.parentWindow || window );
+ }
+ }
+
+ // Fire handlers on the event path
+ i = 0;
+ while ( (cur = eventPath[i++]) && !event.isPropagationStopped() ) {
+
+ event.type = i > 1 ?
+ bubbleType :
+ special.bindType || type;
+
+ // jQuery handler
+ handle = ( data_priv.get( cur, "events" ) || {} )[ event.type ] && data_priv.get( cur, "handle" );
+ if ( handle ) {
+ handle.apply( cur, data );
+ }
+
+ // Native handler
+ handle = ontype && cur[ ontype ];
+ if ( handle && jQuery.acceptData( cur ) && handle.apply && handle.apply( cur, data ) === false ) {
+ event.preventDefault();
+ }
+ }
+ event.type = type;
+
+ // If nobody prevented the default action, do it now
+ if ( !onlyHandlers && !event.isDefaultPrevented() ) {
+
+ if ( (!special._default || special._default.apply( eventPath.pop(), data ) === false) &&
+ jQuery.acceptData( elem ) ) {
+
+ // Call a native DOM method on the target with the same name name as the event.
+ // Don't do default actions on window, that's where global variables be (#6170)
+ if ( ontype && jQuery.isFunction( elem[ type ] ) && !jQuery.isWindow( elem ) ) {
+
+ // Don't re-trigger an onFOO event when we call its FOO() method
+ tmp = elem[ ontype ];
+
+ if ( tmp ) {
+ elem[ ontype ] = null;
+ }
+
+ // Prevent re-triggering of the same event, since we already bubbled it above
+ jQuery.event.triggered = type;
+ elem[ type ]();
+ jQuery.event.triggered = undefined;
+
+ if ( tmp ) {
+ elem[ ontype ] = tmp;
+ }
+ }
+ }
+ }
+
+ return event.result;
+ },
+
+ dispatch: function( event ) {
+
+ // Make a writable jQuery.Event from the native event object
+ event = jQuery.event.fix( event );
+
+ var i, j, ret, matched, handleObj,
+ handlerQueue = [],
+ args = core_slice.call( arguments ),
+ handlers = ( data_priv.get( this, "events" ) || {} )[ event.type ] || [],
+ special = jQuery.event.special[ event.type ] || {};
+
+ // Use the fix-ed jQuery.Event rather than the (read-only) native event
+ args[0] = event;
+ event.delegateTarget = this;
+
+ // Call the preDispatch hook for the mapped type, and let it bail if desired
+ if ( special.preDispatch && special.preDispatch.call( this, event ) === false ) {
+ return;
+ }
+
+ // Determine handlers
+ handlerQueue = jQuery.event.handlers.call( this, event, handlers );
+
+ // Run delegates first; they may want to stop propagation beneath us
+ i = 0;
+ while ( (matched = handlerQueue[ i++ ]) && !event.isPropagationStopped() ) {
+ event.currentTarget = matched.elem;
+
+ j = 0;
+ while ( (handleObj = matched.handlers[ j++ ]) && !event.isImmediatePropagationStopped() ) {
+
+ // Triggered event must either 1) have no namespace, or
+ // 2) have namespace(s) a subset or equal to those in the bound event (both can have no namespace).
+ if ( !event.namespace_re || event.namespace_re.test( handleObj.namespace ) ) {
+
+ event.handleObj = handleObj;
+ event.data = handleObj.data;
+
+ ret = ( (jQuery.event.special[ handleObj.origType ] || {}).handle || handleObj.handler )
+ .apply( matched.elem, args );
+
+ if ( ret !== undefined ) {
+ if ( (event.result = ret) === false ) {
+ event.preventDefault();
+ event.stopPropagation();
+ }
+ }
+ }
+ }
+ }
+
+ // Call the postDispatch hook for the mapped type
+ if ( special.postDispatch ) {
+ special.postDispatch.call( this, event );
+ }
+
+ return event.result;
+ },
+
+ handlers: function( event, handlers ) {
+ var i, matches, sel, handleObj,
+ handlerQueue = [],
+ delegateCount = handlers.delegateCount,
+ cur = event.target;
+
+ // Find delegate handlers
+ // Black-hole SVG <use> instance trees (#13180)
+ // Avoid non-left-click bubbling in Firefox (#3861)
+ if ( delegateCount && cur.nodeType && (!event.button || event.type !== "click") ) {
+
+ for ( ; cur !== this; cur = cur.parentNode || this ) {
+
+ // Don't process clicks on disabled elements (#6911, #8165, #11382, #11764)
+ if ( cur.disabled !== true || event.type !== "click" ) {
+ matches = [];
+ for ( i = 0; i < delegateCount; i++ ) {
+ handleObj = handlers[ i ];
+
+ // Don't conflict with Object.prototype properties (#13203)
+ sel = handleObj.selector + " ";
+
+ if ( matches[ sel ] === undefined ) {
+ matches[ sel ] = handleObj.needsContext ?
+ jQuery( sel, this ).index( cur ) >= 0 :
+ jQuery.find( sel, this, null, [ cur ] ).length;
+ }
+ if ( matches[ sel ] ) {
+ matches.push( handleObj );
+ }
+ }
+ if ( matches.length ) {
+ handlerQueue.push({ elem: cur, handlers: matches });
+ }
+ }
+ }
+ }
+
+ // Add the remaining (directly-bound) handlers
+ if ( delegateCount < handlers.length ) {
+ handlerQueue.push({ elem: this, handlers: handlers.slice( delegateCount ) });
+ }
+
+ return handlerQueue;
+ },
+
+ // Includes some event props shared by KeyEvent and MouseEvent
+ props: "altKey bubbles cancelable ctrlKey currentTarget eventPhase metaKey relatedTarget shiftKey target timeStamp view which".split(" "),
+
+ fixHooks: {},
+
+ keyHooks: {
+ props: "char charCode key keyCode".split(" "),
+ filter: function( event, original ) {
+
+ // Add which for key events
+ if ( event.which == null ) {
+ event.which = original.charCode != null ? original.charCode : original.keyCode;
+ }
+
+ return event;
+ }
+ },
+
+ mouseHooks: {
+ props: "button buttons clientX clientY offsetX offsetY pageX pageY screenX screenY toElement".split(" "),
+ filter: function( event, original ) {
+ var eventDoc, doc, body,
+ button = original.button;
+
+ // Calculate pageX/Y if missing and clientX/Y available
+ if ( event.pageX == null && original.clientX != null ) {
+ eventDoc = event.target.ownerDocument || document;
+ doc = eventDoc.documentElement;
+ body = eventDoc.body;
+
+ event.pageX = original.clientX + ( doc && doc.scrollLeft || body && body.scrollLeft || 0 ) - ( doc && doc.clientLeft || body && body.clientLeft || 0 );
+ event.pageY = original.clientY + ( doc && doc.scrollTop || body && body.scrollTop || 0 ) - ( doc && doc.clientTop || body && body.clientTop || 0 );
+ }
+
+ // Add which for click: 1 === left; 2 === middle; 3 === right
+ // Note: button is not normalized, so don't use it
+ if ( !event.which && button !== undefined ) {
+ event.which = ( button & 1 ? 1 : ( button & 2 ? 3 : ( button & 4 ? 2 : 0 ) ) );
+ }
+
+ return event;
+ }
+ },
+
+ fix: function( event ) {
+ if ( event[ jQuery.expando ] ) {
+ return event;
+ }
+
+ // Create a writable copy of the event object and normalize some properties
+ var i, prop, copy,
+ type = event.type,
+ originalEvent = event,
+ fixHook = this.fixHooks[ type ];
+
+ if ( !fixHook ) {
+ this.fixHooks[ type ] = fixHook =
+ rmouseEvent.test( type ) ? this.mouseHooks :
+ rkeyEvent.test( type ) ? this.keyHooks :
+ {};
+ }
+ copy = fixHook.props ? this.props.concat( fixHook.props ) : this.props;
+
+ event = new jQuery.Event( originalEvent );
+
+ i = copy.length;
+ while ( i-- ) {
+ prop = copy[ i ];
+ event[ prop ] = originalEvent[ prop ];
+ }
+
+ // Support: Cordova 2.5 (WebKit) (#13255)
+ // All events should have a target; Cordova deviceready doesn't
+ if ( !event.target ) {
+ event.target = document;
+ }
+
+ // Support: Safari 6.0+, Chrome < 28
+ // Target should not be a text node (#504, #13143)
+ if ( event.target.nodeType === 3 ) {
+ event.target = event.target.parentNode;
+ }
+
+ return fixHook.filter? fixHook.filter( event, originalEvent ) : event;
+ },
+
+ special: {
+ load: {
+ // Prevent triggered image.load events from bubbling to window.load
+ noBubble: true
+ },
+ focus: {
+ // Fire native event if possible so blur/focus sequence is correct
+ trigger: function() {
+ if ( this !== safeActiveElement() && this.focus ) {
+ this.focus();
+ return false;
+ }
+ },
+ delegateType: "focusin"
+ },
+ blur: {
+ trigger: function() {
+ if ( this === safeActiveElement() && this.blur ) {
+ this.blur();
+ return false;
+ }
+ },
+ delegateType: "focusout"
+ },
+ click: {
+ // For checkbox, fire native event so checked state will be right
+ trigger: function() {
+ if ( this.type === "checkbox" && this.click && jQuery.nodeName( this, "input" ) ) {
+ this.click();
+ return false;
+ }
+ },
+
+ // For cross-browser consistency, don't fire native .click() on links
+ _default: function( event ) {
+ return jQuery.nodeName( event.target, "a" );
+ }
+ },
+
+ beforeunload: {
+ postDispatch: function( event ) {
+
+ // Support: Firefox 20+
+ // Firefox doesn't alert if the returnValue field is not set.
+ if ( event.result !== undefined ) {
+ event.originalEvent.returnValue = event.result;
+ }
+ }
+ }
+ },
+
+ simulate: function( type, elem, event, bubble ) {
+ // Piggyback on a donor event to simulate a different one.
+ // Fake originalEvent to avoid donor's stopPropagation, but if the
+ // simulated event prevents default then we do the same on the donor.
+ var e = jQuery.extend(
+ new jQuery.Event(),
+ event,
+ {
+ type: type,
+ isSimulated: true,
+ originalEvent: {}
+ }
+ );
+ if ( bubble ) {
+ jQuery.event.trigger( e, null, elem );
+ } else {
+ jQuery.event.dispatch.call( elem, e );
+ }
+ if ( e.isDefaultPrevented() ) {
+ event.preventDefault();
+ }
+ }
+};
+
+jQuery.removeEvent = function( elem, type, handle ) {
+ if ( elem.removeEventListener ) {
+ elem.removeEventListener( type, handle, false );
+ }
+};
+
+jQuery.Event = function( src, props ) {
+ // Allow instantiation without the 'new' keyword
+ if ( !(this instanceof jQuery.Event) ) {
+ return new jQuery.Event( src, props );
+ }
+
+ // Event object
+ if ( src && src.type ) {
+ this.originalEvent = src;
+ this.type = src.type;
+
+ // Events bubbling up the document may have been marked as prevented
+ // by a handler lower down the tree; reflect the correct value.
+ this.isDefaultPrevented = ( src.defaultPrevented ||
+ src.getPreventDefault && src.getPreventDefault() ) ? returnTrue : returnFalse;
+
+ // Event type
+ } else {
+ this.type = src;
+ }
+
+ // Put explicitly provided properties onto the event object
+ if ( props ) {
+ jQuery.extend( this, props );
+ }
+
+ // Create a timestamp if incoming event doesn't have one
+ this.timeStamp = src && src.timeStamp || jQuery.now();
+
+ // Mark it as fixed
+ this[ jQuery.expando ] = true;
+};
+
+// jQuery.Event is based on DOM3 Events as specified by the ECMAScript Language Binding
+// http://www.w3.org/TR/2003/WD-DOM-Level-3-Events-20030331/ecma-script-binding.html
+jQuery.Event.prototype = {
+ isDefaultPrevented: returnFalse,
+ isPropagationStopped: returnFalse,
+ isImmediatePropagationStopped: returnFalse,
+
+ preventDefault: function() {
+ var e = this.originalEvent;
+
+ this.isDefaultPrevented = returnTrue;
+
+ if ( e && e.preventDefault ) {
+ e.preventDefault();
+ }
+ },
+ stopPropagation: function() {
+ var e = this.originalEvent;
+
+ this.isPropagationStopped = returnTrue;
+
+ if ( e && e.stopPropagation ) {
+ e.stopPropagation();
+ }
+ },
+ stopImmediatePropagation: function() {
+ this.isImmediatePropagationStopped = returnTrue;
+ this.stopPropagation();
+ }
+};
+
+// Create mouseenter/leave events using mouseover/out and event-time checks
+// Support: Chrome 15+
+jQuery.each({
+ mouseenter: "mouseover",
+ mouseleave: "mouseout"
+}, function( orig, fix ) {
+ jQuery.event.special[ orig ] = {
+ delegateType: fix,
+ bindType: fix,
+
+ handle: function( event ) {
+ var ret,
+ target = this,
+ related = event.relatedTarget,
+ handleObj = event.handleObj;
+
+ // For mousenter/leave call the handler if related is outside the target.
+ // NB: No relatedTarget if the mouse left/entered the browser window
+ if ( !related || (related !== target && !jQuery.contains( target, related )) ) {
+ event.type = handleObj.origType;
+ ret = handleObj.handler.apply( this, arguments );
+ event.type = fix;
+ }
+ return ret;
+ }
+ };
+});
+
+// Create "bubbling" focus and blur events
+// Support: Firefox, Chrome, Safari
+if ( !jQuery.support.focusinBubbles ) {
+ jQuery.each({ focus: "focusin", blur: "focusout" }, function( orig, fix ) {
+
+ // Attach a single capturing handler while someone wants focusin/focusout
+ var attaches = 0,
+ handler = function( event ) {
+ jQuery.event.simulate( fix, event.target, jQuery.event.fix( event ), true );
+ };
+
+ jQuery.event.special[ fix ] = {
+ setup: function() {
+ if ( attaches++ === 0 ) {
+ document.addEventListener( orig, handler, true );
+ }
+ },
+ teardown: function() {
+ if ( --attaches === 0 ) {
+ document.removeEventListener( orig, handler, true );
+ }
+ }
+ };
+ });
+}
+
+jQuery.fn.extend({
+
+ on: function( types, selector, data, fn, /*INTERNAL*/ one ) {
+ var origFn, type;
+
+ // Types can be a map of types/handlers
+ if ( typeof types === "object" ) {
+ // ( types-Object, selector, data )
+ if ( typeof selector !== "string" ) {
+ // ( types-Object, data )
+ data = data || selector;
+ selector = undefined;
+ }
+ for ( type in types ) {
+ this.on( type, selector, data, types[ type ], one );
+ }
+ return this;
+ }
+
+ if ( data == null && fn == null ) {
+ // ( types, fn )
+ fn = selector;
+ data = selector = undefined;
+ } else if ( fn == null ) {
+ if ( typeof selector === "string" ) {
+ // ( types, selector, fn )
+ fn = data;
+ data = undefined;
+ } else {
+ // ( types, data, fn )
+ fn = data;
+ data = selector;
+ selector = undefined;
+ }
+ }
+ if ( fn === false ) {
+ fn = returnFalse;
+ } else if ( !fn ) {
+ return this;
+ }
+
+ if ( one === 1 ) {
+ origFn = fn;
+ fn = function( event ) {
+ // Can use an empty set, since event contains the info
+ jQuery().off( event );
+ return origFn.apply( this, arguments );
+ };
+ // Use same guid so caller can remove using origFn
+ fn.guid = origFn.guid || ( origFn.guid = jQuery.guid++ );
+ }
+ return this.each( function() {
+ jQuery.event.add( this, types, fn, data, selector );
+ });
+ },
+ one: function( types, selector, data, fn ) {
+ return this.on( types, selector, data, fn, 1 );
+ },
+ off: function( types, selector, fn ) {
+ var handleObj, type;
+ if ( types && types.preventDefault && types.handleObj ) {
+ // ( event ) dispatched jQuery.Event
+ handleObj = types.handleObj;
+ jQuery( types.delegateTarget ).off(
+ handleObj.namespace ? handleObj.origType + "." + handleObj.namespace : handleObj.origType,
+ handleObj.selector,
+ handleObj.handler
+ );
+ return this;
+ }
+ if ( typeof types === "object" ) {
+ // ( types-object [, selector] )
+ for ( type in types ) {
+ this.off( type, selector, types[ type ] );
+ }
+ return this;
+ }
+ if ( selector === false || typeof selector === "function" ) {
+ // ( types [, fn] )
+ fn = selector;
+ selector = undefined;
+ }
+ if ( fn === false ) {
+ fn = returnFalse;
+ }
+ return this.each(function() {
+ jQuery.event.remove( this, types, fn, selector );
+ });
+ },
+
+ trigger: function( type, data ) {
+ return this.each(function() {
+ jQuery.event.trigger( type, data, this );
+ });
+ },
+ triggerHandler: function( type, data ) {
+ var elem = this[0];
+ if ( elem ) {
+ return jQuery.event.trigger( type, data, elem, true );
+ }
+ }
+});
+var isSimple = /^.[^:#\[\.,]*$/,
+ rparentsprev = /^(?:parents|prev(?:Until|All))/,
+ rneedsContext = jQuery.expr.match.needsContext,
+ // methods guaranteed to produce a unique set when starting from a unique set
+ guaranteedUnique = {
+ children: true,
+ contents: true,
+ next: true,
+ prev: true
+ };
+
+jQuery.fn.extend({
+ find: function( selector ) {
+ var i,
+ ret = [],
+ self = this,
+ len = self.length;
+
+ if ( typeof selector !== "string" ) {
+ return this.pushStack( jQuery( selector ).filter(function() {
+ for ( i = 0; i < len; i++ ) {
+ if ( jQuery.contains( self[ i ], this ) ) {
+ return true;
+ }
+ }
+ }) );
+ }
+
+ for ( i = 0; i < len; i++ ) {
+ jQuery.find( selector, self[ i ], ret );
+ }
+
+ // Needed because $( selector, context ) becomes $( context ).find( selector )
+ ret = this.pushStack( len > 1 ? jQuery.unique( ret ) : ret );
+ ret.selector = this.selector ? this.selector + " " + selector : selector;
+ return ret;
+ },
+
+ has: function( target ) {
+ var targets = jQuery( target, this ),
+ l = targets.length;
+
+ return this.filter(function() {
+ var i = 0;
+ for ( ; i < l; i++ ) {
+ if ( jQuery.contains( this, targets[i] ) ) {
+ return true;
+ }
+ }
+ });
+ },
+
+ not: function( selector ) {
+ return this.pushStack( winnow(this, selector || [], true) );
+ },
+
+ filter: function( selector ) {
+ return this.pushStack( winnow(this, selector || [], false) );
+ },
+
+ is: function( selector ) {
+ return !!winnow(
+ this,
+
+ // If this is a positional/relative selector, check membership in the returned set
+ // so $("p:first").is("p:last") won't return true for a doc with two "p".
+ typeof selector === "string" && rneedsContext.test( selector ) ?
+ jQuery( selector ) :
+ selector || [],
+ false
+ ).length;
+ },
+
+ closest: function( selectors, context ) {
+ var cur,
+ i = 0,
+ l = this.length,
+ matched = [],
+ pos = ( rneedsContext.test( selectors ) || typeof selectors !== "string" ) ?
+ jQuery( selectors, context || this.context ) :
+ 0;
+
+ for ( ; i < l; i++ ) {
+ for ( cur = this[i]; cur && cur !== context; cur = cur.parentNode ) {
+ // Always skip document fragments
+ if ( cur.nodeType < 11 && (pos ?
+ pos.index(cur) > -1 :
+
+ // Don't pass non-elements to Sizzle
+ cur.nodeType === 1 &&
+ jQuery.find.matchesSelector(cur, selectors)) ) {
+
+ cur = matched.push( cur );
+ break;
+ }
+ }
+ }
+
+ return this.pushStack( matched.length > 1 ? jQuery.unique( matched ) : matched );
+ },
+
+ // Determine the position of an element within
+ // the matched set of elements
+ index: function( elem ) {
+
+ // No argument, return index in parent
+ if ( !elem ) {
+ return ( this[ 0 ] && this[ 0 ].parentNode ) ? this.first().prevAll().length : -1;
+ }
+
+ // index in selector
+ if ( typeof elem === "string" ) {
+ return core_indexOf.call( jQuery( elem ), this[ 0 ] );
+ }
+
+ // Locate the position of the desired element
+ return core_indexOf.call( this,
+
+ // If it receives a jQuery object, the first element is used
+ elem.jquery ? elem[ 0 ] : elem
+ );
+ },
+
+ add: function( selector, context ) {
+ var set = typeof selector === "string" ?
+ jQuery( selector, context ) :
+ jQuery.makeArray( selector && selector.nodeType ? [ selector ] : selector ),
+ all = jQuery.merge( this.get(), set );
+
+ return this.pushStack( jQuery.unique(all) );
+ },
+
+ addBack: function( selector ) {
+ return this.add( selector == null ?
+ this.prevObject : this.prevObject.filter(selector)
+ );
+ }
+});
+
+function sibling( cur, dir ) {
+ while ( (cur = cur[dir]) && cur.nodeType !== 1 ) {}
+
+ return cur;
+}
+
+jQuery.each({
+ parent: function( elem ) {
+ var parent = elem.parentNode;
+ return parent && parent.nodeType !== 11 ? parent : null;
+ },
+ parents: function( elem ) {
+ return jQuery.dir( elem, "parentNode" );
+ },
+ parentsUntil: function( elem, i, until ) {
+ return jQuery.dir( elem, "parentNode", until );
+ },
+ next: function( elem ) {
+ return sibling( elem, "nextSibling" );
+ },
+ prev: function( elem ) {
+ return sibling( elem, "previousSibling" );
+ },
+ nextAll: function( elem ) {
+ return jQuery.dir( elem, "nextSibling" );
+ },
+ prevAll: function( elem ) {
+ return jQuery.dir( elem, "previousSibling" );
+ },
+ nextUntil: function( elem, i, until ) {
+ return jQuery.dir( elem, "nextSibling", until );
+ },
+ prevUntil: function( elem, i, until ) {
+ return jQuery.dir( elem, "previousSibling", until );
+ },
+ siblings: function( elem ) {
+ return jQuery.sibling( ( elem.parentNode || {} ).firstChild, elem );
+ },
+ children: function( elem ) {
+ return jQuery.sibling( elem.firstChild );
+ },
+ contents: function( elem ) {
+ return elem.contentDocument || jQuery.merge( [], elem.childNodes );
+ }
+}, function( name, fn ) {
+ jQuery.fn[ name ] = function( until, selector ) {
+ var matched = jQuery.map( this, fn, until );
+
+ if ( name.slice( -5 ) !== "Until" ) {
+ selector = until;
+ }
+
+ if ( selector && typeof selector === "string" ) {
+ matched = jQuery.filter( selector, matched );
+ }
+
+ if ( this.length > 1 ) {
+ // Remove duplicates
+ if ( !guaranteedUnique[ name ] ) {
+ jQuery.unique( matched );
+ }
+
+ // Reverse order for parents* and prev-derivatives
+ if ( rparentsprev.test( name ) ) {
+ matched.reverse();
+ }
+ }
+
+ return this.pushStack( matched );
+ };
+});
+
+jQuery.extend({
+ filter: function( expr, elems, not ) {
+ var elem = elems[ 0 ];
+
+ if ( not ) {
+ expr = ":not(" + expr + ")";
+ }
+
+ return elems.length === 1 && elem.nodeType === 1 ?
+ jQuery.find.matchesSelector( elem, expr ) ? [ elem ] : [] :
+ jQuery.find.matches( expr, jQuery.grep( elems, function( elem ) {
+ return elem.nodeType === 1;
+ }));
+ },
+
+ dir: function( elem, dir, until ) {
+ var matched = [],
+ truncate = until !== undefined;
+
+ while ( (elem = elem[ dir ]) && elem.nodeType !== 9 ) {
+ if ( elem.nodeType === 1 ) {
+ if ( truncate && jQuery( elem ).is( until ) ) {
+ break;
+ }
+ matched.push( elem );
+ }
+ }
+ return matched;
+ },
+
+ sibling: function( n, elem ) {
+ var matched = [];
+
+ for ( ; n; n = n.nextSibling ) {
+ if ( n.nodeType === 1 && n !== elem ) {
+ matched.push( n );
+ }
+ }
+
+ return matched;
+ }
+});
+
+// Implement the identical functionality for filter and not
+function winnow( elements, qualifier, not ) {
+ if ( jQuery.isFunction( qualifier ) ) {
+ return jQuery.grep( elements, function( elem, i ) {
+ /* jshint -W018 */
+ return !!qualifier.call( elem, i, elem ) !== not;
+ });
+
+ }
+
+ if ( qualifier.nodeType ) {
+ return jQuery.grep( elements, function( elem ) {
+ return ( elem === qualifier ) !== not;
+ });
+
+ }
+
+ if ( typeof qualifier === "string" ) {
+ if ( isSimple.test( qualifier ) ) {
+ return jQuery.filter( qualifier, elements, not );
+ }
+
+ qualifier = jQuery.filter( qualifier, elements );
+ }
+
+ return jQuery.grep( elements, function( elem ) {
+ return ( core_indexOf.call( qualifier, elem ) >= 0 ) !== not;
+ });
+}
+var rxhtmlTag = /<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/gi,
+ rtagName = /<([\w:]+)/,
+ rhtml = /<|&#?\w+;/,
+ rnoInnerhtml = /<(?:script|style|link)/i,
+ manipulation_rcheckableType = /^(?:checkbox|radio)$/i,
+ // checked="checked" or checked
+ rchecked = /checked\s*(?:[^=]|=\s*.checked.)/i,
+ rscriptType = /^$|\/(?:java|ecma)script/i,
+ rscriptTypeMasked = /^true\/(.*)/,
+ rcleanScript = /^\s*<!(?:\[CDATA\[|--)|(?:\]\]|--)>\s*$/g,
+
+ // We have to close these tags to support XHTML (#13200)
+ wrapMap = {
+
+ // Support: IE 9
+ option: [ 1, "<select multiple='multiple'>", "</select>" ],
+
+ thead: [ 1, "<table>", "</table>" ],
+ col: [ 2, "<table><colgroup>", "</colgroup></table>" ],
+ tr: [ 2, "<table><tbody>", "</tbody></table>" ],
+ td: [ 3, "<table><tbody><tr>", "</tr></tbody></table>" ],
+
+ _default: [ 0, "", "" ]
+ };
+
+// Support: IE 9
+wrapMap.optgroup = wrapMap.option;
+
+wrapMap.tbody = wrapMap.tfoot = wrapMap.colgroup = wrapMap.caption = wrapMap.thead;
+wrapMap.th = wrapMap.td;
+
+jQuery.fn.extend({
+ text: function( value ) {
+ return jQuery.access( this, function( value ) {
+ return value === undefined ?
+ jQuery.text( this ) :
+ this.empty().append( ( this[ 0 ] && this[ 0 ].ownerDocument || document ).createTextNode( value ) );
+ }, null, value, arguments.length );
+ },
+
+ append: function() {
+ return this.domManip( arguments, function( elem ) {
+ if ( this.nodeType === 1 || this.nodeType === 11 || this.nodeType === 9 ) {
+ var target = manipulationTarget( this, elem );
+ target.appendChild( elem );
+ }
+ });
+ },
+
+ prepend: function() {
+ return this.domManip( arguments, function( elem ) {
+ if ( this.nodeType === 1 || this.nodeType === 11 || this.nodeType === 9 ) {
+ var target = manipulationTarget( this, elem );
+ target.insertBefore( elem, target.firstChild );
+ }
+ });
+ },
+
+ before: function() {
+ return this.domManip( arguments, function( elem ) {
+ if ( this.parentNode ) {
+ this.parentNode.insertBefore( elem, this );
+ }
+ });
+ },
+
+ after: function() {
+ return this.domManip( arguments, function( elem ) {
+ if ( this.parentNode ) {
+ this.parentNode.insertBefore( elem, this.nextSibling );
+ }
+ });
+ },
+
+ // keepData is for internal use only--do not document
+ remove: function( selector, keepData ) {
+ var elem,
+ elems = selector ? jQuery.filter( selector, this ) : this,
+ i = 0;
+
+ for ( ; (elem = elems[i]) != null; i++ ) {
+ if ( !keepData && elem.nodeType === 1 ) {
+ jQuery.cleanData( getAll( elem ) );
+ }
+
+ if ( elem.parentNode ) {
+ if ( keepData && jQuery.contains( elem.ownerDocument, elem ) ) {
+ setGlobalEval( getAll( elem, "script" ) );
+ }
+ elem.parentNode.removeChild( elem );
+ }
+ }
+
+ return this;
+ },
+
+ empty: function() {
+ var elem,
+ i = 0;
+
+ for ( ; (elem = this[i]) != null; i++ ) {
+ if ( elem.nodeType === 1 ) {
+
+ // Prevent memory leaks
+ jQuery.cleanData( getAll( elem, false ) );
+
+ // Remove any remaining nodes
+ elem.textContent = "";
+ }
+ }
+
+ return this;
+ },
+
+ clone: function( dataAndEvents, deepDataAndEvents ) {
+ dataAndEvents = dataAndEvents == null ? false : dataAndEvents;
+ deepDataAndEvents = deepDataAndEvents == null ? dataAndEvents : deepDataAndEvents;
+
+ return this.map( function () {
+ return jQuery.clone( this, dataAndEvents, deepDataAndEvents );
+ });
+ },
+
+ html: function( value ) {
+ return jQuery.access( this, function( value ) {
+ var elem = this[ 0 ] || {},
+ i = 0,
+ l = this.length;
+
+ if ( value === undefined && elem.nodeType === 1 ) {
+ return elem.innerHTML;
+ }
+
+ // See if we can take a shortcut and just use innerHTML
+ if ( typeof value === "string" && !rnoInnerhtml.test( value ) &&
+ !wrapMap[ ( rtagName.exec( value ) || [ "", "" ] )[ 1 ].toLowerCase() ] ) {
+
+ value = value.replace( rxhtmlTag, "<$1></$2>" );
+
+ try {
+ for ( ; i < l; i++ ) {
+ elem = this[ i ] || {};
+
+ // Remove element nodes and prevent memory leaks
+ if ( elem.nodeType === 1 ) {
+ jQuery.cleanData( getAll( elem, false ) );
+ elem.innerHTML = value;
+ }
+ }
+
+ elem = 0;
+
+ // If using innerHTML throws an exception, use the fallback method
+ } catch( e ) {}
+ }
+
+ if ( elem ) {
+ this.empty().append( value );
+ }
+ }, null, value, arguments.length );
+ },
+
+ replaceWith: function() {
+ var
+ // Snapshot the DOM in case .domManip sweeps something relevant into its fragment
+ args = jQuery.map( this, function( elem ) {
+ return [ elem.nextSibling, elem.parentNode ];
+ }),
+ i = 0;
+
+ // Make the changes, replacing each context element with the new content
+ this.domManip( arguments, function( elem ) {
+ var next = args[ i++ ],
+ parent = args[ i++ ];
+
+ if ( parent ) {
+ // Don't use the snapshot next if it has moved (#13810)
+ if ( next && next.parentNode !== parent ) {
+ next = this.nextSibling;
+ }
+ jQuery( this ).remove();
+ parent.insertBefore( elem, next );
+ }
+ // Allow new content to include elements from the context set
+ }, true );
+
+ // Force removal if there was no new content (e.g., from empty arguments)
+ return i ? this : this.remove();
+ },
+
+ detach: function( selector ) {
+ return this.remove( selector, true );
+ },
+
+ domManip: function( args, callback, allowIntersection ) {
+
+ // Flatten any nested arrays
+ args = core_concat.apply( [], args );
+
+ var fragment, first, scripts, hasScripts, node, doc,
+ i = 0,
+ l = this.length,
+ set = this,
+ iNoClone = l - 1,
+ value = args[ 0 ],
+ isFunction = jQuery.isFunction( value );
+
+ // We can't cloneNode fragments that contain checked, in WebKit
+ if ( isFunction || !( l <= 1 || typeof value !== "string" || jQuery.support.checkClone || !rchecked.test( value ) ) ) {
+ return this.each(function( index ) {
+ var self = set.eq( index );
+ if ( isFunction ) {
+ args[ 0 ] = value.call( this, index, self.html() );
+ }
+ self.domManip( args, callback, allowIntersection );
+ });
+ }
+
+ if ( l ) {
+ fragment = jQuery.buildFragment( args, this[ 0 ].ownerDocument, false, !allowIntersection && this );
+ first = fragment.firstChild;
+
+ if ( fragment.childNodes.length === 1 ) {
+ fragment = first;
+ }
+
+ if ( first ) {
+ scripts = jQuery.map( getAll( fragment, "script" ), disableScript );
+ hasScripts = scripts.length;
+
+ // Use the original fragment for the last item instead of the first because it can end up
+ // being emptied incorrectly in certain situations (#8070).
+ for ( ; i < l; i++ ) {
+ node = fragment;
+
+ if ( i !== iNoClone ) {
+ node = jQuery.clone( node, true, true );
+
+ // Keep references to cloned scripts for later restoration
+ if ( hasScripts ) {
+ // Support: QtWebKit
+ // jQuery.merge because core_push.apply(_, arraylike) throws
+ jQuery.merge( scripts, getAll( node, "script" ) );
+ }
+ }
+
+ callback.call( this[ i ], node, i );
+ }
+
+ if ( hasScripts ) {
+ doc = scripts[ scripts.length - 1 ].ownerDocument;
+
+ // Reenable scripts
+ jQuery.map( scripts, restoreScript );
+
+ // Evaluate executable scripts on first document insertion
+ for ( i = 0; i < hasScripts; i++ ) {
+ node = scripts[ i ];
+ if ( rscriptType.test( node.type || "" ) &&
+ !data_priv.access( node, "globalEval" ) && jQuery.contains( doc, node ) ) {
+
+ if ( node.src ) {
+ // Hope ajax is available...
+ jQuery._evalUrl( node.src );
+ } else {
+ jQuery.globalEval( node.textContent.replace( rcleanScript, "" ) );
+ }
+ }
+ }
+ }
+ }
+ }
+
+ return this;
+ }
+});
+
+jQuery.each({
+ appendTo: "append",
+ prependTo: "prepend",
+ insertBefore: "before",
+ insertAfter: "after",
+ replaceAll: "replaceWith"
+}, function( name, original ) {
+ jQuery.fn[ name ] = function( selector ) {
+ var elems,
+ ret = [],
+ insert = jQuery( selector ),
+ last = insert.length - 1,
+ i = 0;
+
+ for ( ; i <= last; i++ ) {
+ elems = i === last ? this : this.clone( true );
+ jQuery( insert[ i ] )[ original ]( elems );
+
+ // Support: QtWebKit
+ // .get() because core_push.apply(_, arraylike) throws
+ core_push.apply( ret, elems.get() );
+ }
+
+ return this.pushStack( ret );
+ };
+});
+
+jQuery.extend({
+ clone: function( elem, dataAndEvents, deepDataAndEvents ) {
+ var i, l, srcElements, destElements,
+ clone = elem.cloneNode( true ),
+ inPage = jQuery.contains( elem.ownerDocument, elem );
+
+ // Support: IE >= 9
+ // Fix Cloning issues
+ if ( !jQuery.support.noCloneChecked && ( elem.nodeType === 1 || elem.nodeType === 11 ) && !jQuery.isXMLDoc( elem ) ) {
+
+ // We eschew Sizzle here for performance reasons: http://jsperf.com/getall-vs-sizzle/2
+ destElements = getAll( clone );
+ srcElements = getAll( elem );
+
+ for ( i = 0, l = srcElements.length; i < l; i++ ) {
+ fixInput( srcElements[ i ], destElements[ i ] );
+ }
+ }
+
+ // Copy the events from the original to the clone
+ if ( dataAndEvents ) {
+ if ( deepDataAndEvents ) {
+ srcElements = srcElements || getAll( elem );
+ destElements = destElements || getAll( clone );
+
+ for ( i = 0, l = srcElements.length; i < l; i++ ) {
+ cloneCopyEvent( srcElements[ i ], destElements[ i ] );
+ }
+ } else {
+ cloneCopyEvent( elem, clone );
+ }
+ }
+
+ // Preserve script evaluation history
+ destElements = getAll( clone, "script" );
+ if ( destElements.length > 0 ) {
+ setGlobalEval( destElements, !inPage && getAll( elem, "script" ) );
+ }
+
+ // Return the cloned set
+ return clone;
+ },
+
+ buildFragment: function( elems, context, scripts, selection ) {
+ var elem, tmp, tag, wrap, contains, j,
+ i = 0,
+ l = elems.length,
+ fragment = context.createDocumentFragment(),
+ nodes = [];
+
+ for ( ; i < l; i++ ) {
+ elem = elems[ i ];
+
+ if ( elem || elem === 0 ) {
+
+ // Add nodes directly
+ if ( jQuery.type( elem ) === "object" ) {
+ // Support: QtWebKit
+ // jQuery.merge because core_push.apply(_, arraylike) throws
+ jQuery.merge( nodes, elem.nodeType ? [ elem ] : elem );
+
+ // Convert non-html into a text node
+ } else if ( !rhtml.test( elem ) ) {
+ nodes.push( context.createTextNode( elem ) );
+
+ // Convert html into DOM nodes
+ } else {
+ tmp = tmp || fragment.appendChild( context.createElement("div") );
+
+ // Deserialize a standard representation
+ tag = ( rtagName.exec( elem ) || ["", ""] )[ 1 ].toLowerCase();
+ wrap = wrapMap[ tag ] || wrapMap._default;
+ tmp.innerHTML = wrap[ 1 ] + elem.replace( rxhtmlTag, "<$1></$2>" ) + wrap[ 2 ];
+
+ // Descend through wrappers to the right content
+ j = wrap[ 0 ];
+ while ( j-- ) {
+ tmp = tmp.lastChild;
+ }
+
+ // Support: QtWebKit
+ // jQuery.merge because core_push.apply(_, arraylike) throws
+ jQuery.merge( nodes, tmp.childNodes );
+
+ // Remember the top-level container
+ tmp = fragment.firstChild;
+
+ // Fixes #12346
+ // Support: Webkit, IE
+ tmp.textContent = "";
+ }
+ }
+ }
+
+ // Remove wrapper from fragment
+ fragment.textContent = "";
+
+ i = 0;
+ while ( (elem = nodes[ i++ ]) ) {
+
+ // #4087 - If origin and destination elements are the same, and this is
+ // that element, do not do anything
+ if ( selection && jQuery.inArray( elem, selection ) !== -1 ) {
+ continue;
+ }
+
+ contains = jQuery.contains( elem.ownerDocument, elem );
+
+ // Append to fragment
+ tmp = getAll( fragment.appendChild( elem ), "script" );
+
+ // Preserve script evaluation history
+ if ( contains ) {
+ setGlobalEval( tmp );
+ }
+
+ // Capture executables
+ if ( scripts ) {
+ j = 0;
+ while ( (elem = tmp[ j++ ]) ) {
+ if ( rscriptType.test( elem.type || "" ) ) {
+ scripts.push( elem );
+ }
+ }
+ }
+ }
+
+ return fragment;
+ },
+
+ cleanData: function( elems ) {
+ var data, elem, events, type, key, j,
+ special = jQuery.event.special,
+ i = 0;
+
+ for ( ; (elem = elems[ i ]) !== undefined; i++ ) {
+ if ( Data.accepts( elem ) ) {
+ key = elem[ data_priv.expando ];
+
+ if ( key && (data = data_priv.cache[ key ]) ) {
+ events = Object.keys( data.events || {} );
+ if ( events.length ) {
+ for ( j = 0; (type = events[j]) !== undefined; j++ ) {
+ if ( special[ type ] ) {
+ jQuery.event.remove( elem, type );
+
+ // This is a shortcut to avoid jQuery.event.remove's overhead
+ } else {
+ jQuery.removeEvent( elem, type, data.handle );
+ }
+ }
+ }
+ if ( data_priv.cache[ key ] ) {
+ // Discard any remaining `private` data
+ delete data_priv.cache[ key ];
+ }
+ }
+ }
+ // Discard any remaining `user` data
+ delete data_user.cache[ elem[ data_user.expando ] ];
+ }
+ },
+
+ _evalUrl: function( url ) {
+ return jQuery.ajax({
+ url: url,
+ type: "GET",
+ dataType: "script",
+ async: false,
+ global: false,
+ "throws": true
+ });
+ }
+});
+
+// Support: 1.x compatibility
+// Manipulating tables requires a tbody
+function manipulationTarget( elem, content ) {
+ return jQuery.nodeName( elem, "table" ) &&
+ jQuery.nodeName( content.nodeType === 1 ? content : content.firstChild, "tr" ) ?
+
+ elem.getElementsByTagName("tbody")[0] ||
+ elem.appendChild( elem.ownerDocument.createElement("tbody") ) :
+ elem;
+}
+
+// Replace/restore the type attribute of script elements for safe DOM manipulation
+function disableScript( elem ) {
+ elem.type = (elem.getAttribute("type") !== null) + "/" + elem.type;
+ return elem;
+}
+function restoreScript( elem ) {
+ var match = rscriptTypeMasked.exec( elem.type );
+
+ if ( match ) {
+ elem.type = match[ 1 ];
+ } else {
+ elem.removeAttribute("type");
+ }
+
+ return elem;
+}
+
+// Mark scripts as having already been evaluated
+function setGlobalEval( elems, refElements ) {
+ var l = elems.length,
+ i = 0;
+
+ for ( ; i < l; i++ ) {
+ data_priv.set(
+ elems[ i ], "globalEval", !refElements || data_priv.get( refElements[ i ], "globalEval" )
+ );
+ }
+}
+
+function cloneCopyEvent( src, dest ) {
+ var i, l, type, pdataOld, pdataCur, udataOld, udataCur, events;
+
+ if ( dest.nodeType !== 1 ) {
+ return;
+ }
+
+ // 1. Copy private data: events, handlers, etc.
+ if ( data_priv.hasData( src ) ) {
+ pdataOld = data_priv.access( src );
+ pdataCur = data_priv.set( dest, pdataOld );
+ events = pdataOld.events;
+
+ if ( events ) {
+ delete pdataCur.handle;
+ pdataCur.events = {};
+
+ for ( type in events ) {
+ for ( i = 0, l = events[ type ].length; i < l; i++ ) {
+ jQuery.event.add( dest, type, events[ type ][ i ] );
+ }
+ }
+ }
+ }
+
+ // 2. Copy user data
+ if ( data_user.hasData( src ) ) {
+ udataOld = data_user.access( src );
+ udataCur = jQuery.extend( {}, udataOld );
+
+ data_user.set( dest, udataCur );
+ }
+}
+
+
+function getAll( context, tag ) {
+ var ret = context.getElementsByTagName ? context.getElementsByTagName( tag || "*" ) :
+ context.querySelectorAll ? context.querySelectorAll( tag || "*" ) :
+ [];
+
+ return tag === undefined || tag && jQuery.nodeName( context, tag ) ?
+ jQuery.merge( [ context ], ret ) :
+ ret;
+}
+
+// Support: IE >= 9
+function fixInput( src, dest ) {
+ var nodeName = dest.nodeName.toLowerCase();
+
+ // Fails to persist the checked state of a cloned checkbox or radio button.
+ if ( nodeName === "input" && manipulation_rcheckableType.test( src.type ) ) {
+ dest.checked = src.checked;
+
+ // Fails to return the selected option to the default selected state when cloning options
+ } else if ( nodeName === "input" || nodeName === "textarea" ) {
+ dest.defaultValue = src.defaultValue;
+ }
+}
+jQuery.fn.extend({
+ wrapAll: function( html ) {
+ var wrap;
+
+ if ( jQuery.isFunction( html ) ) {
+ return this.each(function( i ) {
+ jQuery( this ).wrapAll( html.call(this, i) );
+ });
+ }
+
+ if ( this[ 0 ] ) {
+
+ // The elements to wrap the target around
+ wrap = jQuery( html, this[ 0 ].ownerDocument ).eq( 0 ).clone( true );
+
+ if ( this[ 0 ].parentNode ) {
+ wrap.insertBefore( this[ 0 ] );
+ }
+
+ wrap.map(function() {
+ var elem = this;
+
+ while ( elem.firstElementChild ) {
+ elem = elem.firstElementChild;
+ }
+
+ return elem;
+ }).append( this );
+ }
+
+ return this;
+ },
+
+ wrapInner: function( html ) {
+ if ( jQuery.isFunction( html ) ) {
+ return this.each(function( i ) {
+ jQuery( this ).wrapInner( html.call(this, i) );
+ });
+ }
+
+ return this.each(function() {
+ var self = jQuery( this ),
+ contents = self.contents();
+
+ if ( contents.length ) {
+ contents.wrapAll( html );
+
+ } else {
+ self.append( html );
+ }
+ });
+ },
+
+ wrap: function( html ) {
+ var isFunction = jQuery.isFunction( html );
+
+ return this.each(function( i ) {
+ jQuery( this ).wrapAll( isFunction ? html.call(this, i) : html );
+ });
+ },
+
+ unwrap: function() {
+ return this.parent().each(function() {
+ if ( !jQuery.nodeName( this, "body" ) ) {
+ jQuery( this ).replaceWith( this.childNodes );
+ }
+ }).end();
+ }
+});
+var curCSS, iframe,
+ // swappable if display is none or starts with table except "table", "table-cell", or "table-caption"
+ // see here for display values: https://developer.mozilla.org/en-US/docs/CSS/display
+ rdisplayswap = /^(none|table(?!-c[ea]).+)/,
+ rmargin = /^margin/,
+ rnumsplit = new RegExp( "^(" + core_pnum + ")(.*)$", "i" ),
+ rnumnonpx = new RegExp( "^(" + core_pnum + ")(?!px)[a-z%]+$", "i" ),
+ rrelNum = new RegExp( "^([+-])=(" + core_pnum + ")", "i" ),
+ elemdisplay = { BODY: "block" },
+
+ cssShow = { position: "absolute", visibility: "hidden", display: "block" },
+ cssNormalTransform = {
+ letterSpacing: 0,
+ fontWeight: 400
+ },
+
+ cssExpand = [ "Top", "Right", "Bottom", "Left" ],
+ cssPrefixes = [ "Webkit", "O", "Moz", "ms" ];
+
+// return a css property mapped to a potentially vendor prefixed property
+function vendorPropName( style, name ) {
+
+ // shortcut for names that are not vendor prefixed
+ if ( name in style ) {
+ return name;
+ }
+
+ // check for vendor prefixed names
+ var capName = name.charAt(0).toUpperCase() + name.slice(1),
+ origName = name,
+ i = cssPrefixes.length;
+
+ while ( i-- ) {
+ name = cssPrefixes[ i ] + capName;
+ if ( name in style ) {
+ return name;
+ }
+ }
+
+ return origName;
+}
+
+function isHidden( elem, el ) {
+ // isHidden might be called from jQuery#filter function;
+ // in that case, element will be second argument
+ elem = el || elem;
+ return jQuery.css( elem, "display" ) === "none" || !jQuery.contains( elem.ownerDocument, elem );
+}
+
+// NOTE: we've included the "window" in window.getComputedStyle
+// because jsdom on node.js will break without it.
+function getStyles( elem ) {
+ return window.getComputedStyle( elem, null );
+}
+
+function showHide( elements, show ) {
+ var display, elem, hidden,
+ values = [],
+ index = 0,
+ length = elements.length;
+
+ for ( ; index < length; index++ ) {
+ elem = elements[ index ];
+ if ( !elem.style ) {
+ continue;
+ }
+
+ values[ index ] = data_priv.get( elem, "olddisplay" );
+ display = elem.style.display;
+ if ( show ) {
+ // Reset the inline display of this element to learn if it is
+ // being hidden by cascaded rules or not
+ if ( !values[ index ] && display === "none" ) {
+ elem.style.display = "";
+ }
+
+ // Set elements which have been overridden with display: none
+ // in a stylesheet to whatever the default browser style is
+ // for such an element
+ if ( elem.style.display === "" && isHidden( elem ) ) {
+ values[ index ] = data_priv.access( elem, "olddisplay", css_defaultDisplay(elem.nodeName) );
+ }
+ } else {
+
+ if ( !values[ index ] ) {
+ hidden = isHidden( elem );
+
+ if ( display && display !== "none" || !hidden ) {
+ data_priv.set( elem, "olddisplay", hidden ? display : jQuery.css(elem, "display") );
+ }
+ }
+ }
+ }
+
+ // Set the display of most of the elements in a second loop
+ // to avoid the constant reflow
+ for ( index = 0; index < length; index++ ) {
+ elem = elements[ index ];
+ if ( !elem.style ) {
+ continue;
+ }
+ if ( !show || elem.style.display === "none" || elem.style.display === "" ) {
+ elem.style.display = show ? values[ index ] || "" : "none";
+ }
+ }
+
+ return elements;
+}
+
+jQuery.fn.extend({
+ css: function( name, value ) {
+ return jQuery.access( this, function( elem, name, value ) {
+ var styles, len,
+ map = {},
+ i = 0;
+
+ if ( jQuery.isArray( name ) ) {
+ styles = getStyles( elem );
+ len = name.length;
+
+ for ( ; i < len; i++ ) {
+ map[ name[ i ] ] = jQuery.css( elem, name[ i ], false, styles );
+ }
+
+ return map;
+ }
+
+ return value !== undefined ?
+ jQuery.style( elem, name, value ) :
+ jQuery.css( elem, name );
+ }, name, value, arguments.length > 1 );
+ },
+ show: function() {
+ return showHide( this, true );
+ },
+ hide: function() {
+ return showHide( this );
+ },
+ toggle: function( state ) {
+ if ( typeof state === "boolean" ) {
+ return state ? this.show() : this.hide();
+ }
+
+ return this.each(function() {
+ if ( isHidden( this ) ) {
+ jQuery( this ).show();
+ } else {
+ jQuery( this ).hide();
+ }
+ });
+ }
+});
+
+jQuery.extend({
+ // Add in style property hooks for overriding the default
+ // behavior of getting and setting a style property
+ cssHooks: {
+ opacity: {
+ get: function( elem, computed ) {
+ if ( computed ) {
+ // We should always get a number back from opacity
+ var ret = curCSS( elem, "opacity" );
+ return ret === "" ? "1" : ret;
+ }
+ }
+ }
+ },
+
+ // Don't automatically add "px" to these possibly-unitless properties
+ cssNumber: {
+ "columnCount": true,
+ "fillOpacity": true,
+ "fontWeight": true,
+ "lineHeight": true,
+ "opacity": true,
+ "order": true,
+ "orphans": true,
+ "widows": true,
+ "zIndex": true,
+ "zoom": true
+ },
+
+ // Add in properties whose names you wish to fix before
+ // setting or getting the value
+ cssProps: {
+ // normalize float css property
+ "float": "cssFloat"
+ },
+
+ // Get and set the style property on a DOM Node
+ style: function( elem, name, value, extra ) {
+ // Don't set styles on text and comment nodes
+ if ( !elem || elem.nodeType === 3 || elem.nodeType === 8 || !elem.style ) {
+ return;
+ }
+
+ // Make sure that we're working with the right name
+ var ret, type, hooks,
+ origName = jQuery.camelCase( name ),
+ style = elem.style;
+
+ name = jQuery.cssProps[ origName ] || ( jQuery.cssProps[ origName ] = vendorPropName( style, origName ) );
+
+ // gets hook for the prefixed version
+ // followed by the unprefixed version
+ hooks = jQuery.cssHooks[ name ] || jQuery.cssHooks[ origName ];
+
+ // Check if we're setting a value
+ if ( value !== undefined ) {
+ type = typeof value;
+
+ // convert relative number strings (+= or -=) to relative numbers. #7345
+ if ( type === "string" && (ret = rrelNum.exec( value )) ) {
+ value = ( ret[1] + 1 ) * ret[2] + parseFloat( jQuery.css( elem, name ) );
+ // Fixes bug #9237
+ type = "number";
+ }
+
+ // Make sure that NaN and null values aren't set. See: #7116
+ if ( value == null || type === "number" && isNaN( value ) ) {
+ return;
+ }
+
+ // If a number was passed in, add 'px' to the (except for certain CSS properties)
+ if ( type === "number" && !jQuery.cssNumber[ origName ] ) {
+ value += "px";
+ }
+
+ // Fixes #8908, it can be done more correctly by specifying setters in cssHooks,
+ // but it would mean to define eight (for every problematic property) identical functions
+ if ( !jQuery.support.clearCloneStyle && value === "" && name.indexOf("background") === 0 ) {
+ style[ name ] = "inherit";
+ }
+
+ // If a hook was provided, use that value, otherwise just set the specified value
+ if ( !hooks || !("set" in hooks) || (value = hooks.set( elem, value, extra )) !== undefined ) {
+ style[ name ] = value;
+ }
+
+ } else {
+ // If a hook was provided get the non-computed value from there
+ if ( hooks && "get" in hooks && (ret = hooks.get( elem, false, extra )) !== undefined ) {
+ return ret;
+ }
+
+ // Otherwise just get the value from the style object
+ return style[ name ];
+ }
+ },
+
+ css: function( elem, name, extra, styles ) {
+ var val, num, hooks,
+ origName = jQuery.camelCase( name );
+
+ // Make sure that we're working with the right name
+ name = jQuery.cssProps[ origName ] || ( jQuery.cssProps[ origName ] = vendorPropName( elem.style, origName ) );
+
+ // gets hook for the prefixed version
+ // followed by the unprefixed version
+ hooks = jQuery.cssHooks[ name ] || jQuery.cssHooks[ origName ];
+
+ // If a hook was provided get the computed value from there
+ if ( hooks && "get" in hooks ) {
+ val = hooks.get( elem, true, extra );
+ }
+
+ // Otherwise, if a way to get the computed value exists, use that
+ if ( val === undefined ) {
+ val = curCSS( elem, name, styles );
+ }
+
+ //convert "normal" to computed value
+ if ( val === "normal" && name in cssNormalTransform ) {
+ val = cssNormalTransform[ name ];
+ }
+
+ // Return, converting to number if forced or a qualifier was provided and val looks numeric
+ if ( extra === "" || extra ) {
+ num = parseFloat( val );
+ return extra === true || jQuery.isNumeric( num ) ? num || 0 : val;
+ }
+ return val;
+ }
+});
+
+curCSS = function( elem, name, _computed ) {
+ var width, minWidth, maxWidth,
+ computed = _computed || getStyles( elem ),
+
+ // Support: IE9
+ // getPropertyValue is only needed for .css('filter') in IE9, see #12537
+ ret = computed ? computed.getPropertyValue( name ) || computed[ name ] : undefined,
+ style = elem.style;
+
+ if ( computed ) {
+
+ if ( ret === "" && !jQuery.contains( elem.ownerDocument, elem ) ) {
+ ret = jQuery.style( elem, name );
+ }
+
+ // Support: Safari 5.1
+ // A tribute to the "awesome hack by Dean Edwards"
+ // Safari 5.1.7 (at least) returns percentage for a larger set of values, but width seems to be reliably pixels
+ // this is against the CSSOM draft spec: http://dev.w3.org/csswg/cssom/#resolved-values
+ if ( rnumnonpx.test( ret ) && rmargin.test( name ) ) {
+
+ // Remember the original values
+ width = style.width;
+ minWidth = style.minWidth;
+ maxWidth = style.maxWidth;
+
+ // Put in the new values to get a computed value out
+ style.minWidth = style.maxWidth = style.width = ret;
+ ret = computed.width;
+
+ // Revert the changed values
+ style.width = width;
+ style.minWidth = minWidth;
+ style.maxWidth = maxWidth;
+ }
+ }
+
+ return ret;
+};
+
+
+function setPositiveNumber( elem, value, subtract ) {
+ var matches = rnumsplit.exec( value );
+ return matches ?
+ // Guard against undefined "subtract", e.g., when used as in cssHooks
+ Math.max( 0, matches[ 1 ] - ( subtract || 0 ) ) + ( matches[ 2 ] || "px" ) :
+ value;
+}
+
+function augmentWidthOrHeight( elem, name, extra, isBorderBox, styles ) {
+ var i = extra === ( isBorderBox ? "border" : "content" ) ?
+ // If we already have the right measurement, avoid augmentation
+ 4 :
+ // Otherwise initialize for horizontal or vertical properties
+ name === "width" ? 1 : 0,
+
+ val = 0;
+
+ for ( ; i < 4; i += 2 ) {
+ // both box models exclude margin, so add it if we want it
+ if ( extra === "margin" ) {
+ val += jQuery.css( elem, extra + cssExpand[ i ], true, styles );
+ }
+
+ if ( isBorderBox ) {
+ // border-box includes padding, so remove it if we want content
+ if ( extra === "content" ) {
+ val -= jQuery.css( elem, "padding" + cssExpand[ i ], true, styles );
+ }
+
+ // at this point, extra isn't border nor margin, so remove border
+ if ( extra !== "margin" ) {
+ val -= jQuery.css( elem, "border" + cssExpand[ i ] + "Width", true, styles );
+ }
+ } else {
+ // at this point, extra isn't content, so add padding
+ val += jQuery.css( elem, "padding" + cssExpand[ i ], true, styles );
+
+ // at this point, extra isn't content nor padding, so add border
+ if ( extra !== "padding" ) {
+ val += jQuery.css( elem, "border" + cssExpand[ i ] + "Width", true, styles );
+ }
+ }
+ }
+
+ return val;
+}
+
+function getWidthOrHeight( elem, name, extra ) {
+
+ // Start with offset property, which is equivalent to the border-box value
+ var valueIsBorderBox = true,
+ val = name === "width" ? elem.offsetWidth : elem.offsetHeight,
+ styles = getStyles( elem ),
+ isBorderBox = jQuery.support.boxSizing && jQuery.css( elem, "boxSizing", false, styles ) === "border-box";
+
+ // some non-html elements return undefined for offsetWidth, so check for null/undefined
+ // svg - https://bugzilla.mozilla.org/show_bug.cgi?id=649285
+ // MathML - https://bugzilla.mozilla.org/show_bug.cgi?id=491668
+ if ( val <= 0 || val == null ) {
+ // Fall back to computed then uncomputed css if necessary
+ val = curCSS( elem, name, styles );
+ if ( val < 0 || val == null ) {
+ val = elem.style[ name ];
+ }
+
+ // Computed unit is not pixels. Stop here and return.
+ if ( rnumnonpx.test(val) ) {
+ return val;
+ }
+
+ // we need the check for style in case a browser which returns unreliable values
+ // for getComputedStyle silently falls back to the reliable elem.style
+ valueIsBorderBox = isBorderBox && ( jQuery.support.boxSizingReliable || val === elem.style[ name ] );
+
+ // Normalize "", auto, and prepare for extra
+ val = parseFloat( val ) || 0;
+ }
+
+ // use the active box-sizing model to add/subtract irrelevant styles
+ return ( val +
+ augmentWidthOrHeight(
+ elem,
+ name,
+ extra || ( isBorderBox ? "border" : "content" ),
+ valueIsBorderBox,
+ styles
+ )
+ ) + "px";
+}
+
+// Try to determine the default display value of an element
+function css_defaultDisplay( nodeName ) {
+ var doc = document,
+ display = elemdisplay[ nodeName ];
+
+ if ( !display ) {
+ display = actualDisplay( nodeName, doc );
+
+ // If the simple way fails, read from inside an iframe
+ if ( display === "none" || !display ) {
+ // Use the already-created iframe if possible
+ iframe = ( iframe ||
+ jQuery("<iframe frameborder='0' width='0' height='0'/>")
+ .css( "cssText", "display:block !important" )
+ ).appendTo( doc.documentElement );
+
+ // Always write a new HTML skeleton so Webkit and Firefox don't choke on reuse
+ doc = ( iframe[0].contentWindow || iframe[0].contentDocument ).document;
+ doc.write("<!doctype html><html><body>");
+ doc.close();
+
+ display = actualDisplay( nodeName, doc );
+ iframe.detach();
+ }
+
+ // Store the correct default display
+ elemdisplay[ nodeName ] = display;
+ }
+
+ return display;
+}
+
+// Called ONLY from within css_defaultDisplay
+function actualDisplay( name, doc ) {
+ var elem = jQuery( doc.createElement( name ) ).appendTo( doc.body ),
+ display = jQuery.css( elem[0], "display" );
+ elem.remove();
+ return display;
+}
+
+jQuery.each([ "height", "width" ], function( i, name ) {
+ jQuery.cssHooks[ name ] = {
+ get: function( elem, computed, extra ) {
+ if ( computed ) {
+ // certain elements can have dimension info if we invisibly show them
+ // however, it must have a current display style that would benefit from this
+ return elem.offsetWidth === 0 && rdisplayswap.test( jQuery.css( elem, "display" ) ) ?
+ jQuery.swap( elem, cssShow, function() {
+ return getWidthOrHeight( elem, name, extra );
+ }) :
+ getWidthOrHeight( elem, name, extra );
+ }
+ },
+
+ set: function( elem, value, extra ) {
+ var styles = extra && getStyles( elem );
+ return setPositiveNumber( elem, value, extra ?
+ augmentWidthOrHeight(
+ elem,
+ name,
+ extra,
+ jQuery.support.boxSizing && jQuery.css( elem, "boxSizing", false, styles ) === "border-box",
+ styles
+ ) : 0
+ );
+ }
+ };
+});
+
+// These hooks cannot be added until DOM ready because the support test
+// for it is not run until after DOM ready
+jQuery(function() {
+ // Support: Android 2.3
+ if ( !jQuery.support.reliableMarginRight ) {
+ jQuery.cssHooks.marginRight = {
+ get: function( elem, computed ) {
+ if ( computed ) {
+ // Support: Android 2.3
+ // WebKit Bug 13343 - getComputedStyle returns wrong value for margin-right
+ // Work around by temporarily setting element display to inline-block
+ return jQuery.swap( elem, { "display": "inline-block" },
+ curCSS, [ elem, "marginRight" ] );
+ }
+ }
+ };
+ }
+
+ // Webkit bug: https://bugs.webkit.org/show_bug.cgi?id=29084
+ // getComputedStyle returns percent when specified for top/left/bottom/right
+ // rather than make the css module depend on the offset module, we just check for it here
+ if ( !jQuery.support.pixelPosition && jQuery.fn.position ) {
+ jQuery.each( [ "top", "left" ], function( i, prop ) {
+ jQuery.cssHooks[ prop ] = {
+ get: function( elem, computed ) {
+ if ( computed ) {
+ computed = curCSS( elem, prop );
+ // if curCSS returns percentage, fallback to offset
+ return rnumnonpx.test( computed ) ?
+ jQuery( elem ).position()[ prop ] + "px" :
+ computed;
+ }
+ }
+ };
+ });
+ }
+
+});
+
+if ( jQuery.expr && jQuery.expr.filters ) {
+ jQuery.expr.filters.hidden = function( elem ) {
+ // Support: Opera <= 12.12
+ // Opera reports offsetWidths and offsetHeights less than zero on some elements
+ return elem.offsetWidth <= 0 && elem.offsetHeight <= 0;
+ };
+
+ jQuery.expr.filters.visible = function( elem ) {
+ return !jQuery.expr.filters.hidden( elem );
+ };
+}
+
+// These hooks are used by animate to expand properties
+jQuery.each({
+ margin: "",
+ padding: "",
+ border: "Width"
+}, function( prefix, suffix ) {
+ jQuery.cssHooks[ prefix + suffix ] = {
+ expand: function( value ) {
+ var i = 0,
+ expanded = {},
+
+ // assumes a single number if not a string
+ parts = typeof value === "string" ? value.split(" ") : [ value ];
+
+ for ( ; i < 4; i++ ) {
+ expanded[ prefix + cssExpand[ i ] + suffix ] =
+ parts[ i ] || parts[ i - 2 ] || parts[ 0 ];
+ }
+
+ return expanded;
+ }
+ };
+
+ if ( !rmargin.test( prefix ) ) {
+ jQuery.cssHooks[ prefix + suffix ].set = setPositiveNumber;
+ }
+});
+var r20 = /%20/g,
+ rbracket = /\[\]$/,
+ rCRLF = /\r?\n/g,
+ rsubmitterTypes = /^(?:submit|button|image|reset|file)$/i,
+ rsubmittable = /^(?:input|select|textarea|keygen)/i;
+
+jQuery.fn.extend({
+ serialize: function() {
+ return jQuery.param( this.serializeArray() );
+ },
+ serializeArray: function() {
+ return this.map(function(){
+ // Can add propHook for "elements" to filter or add form elements
+ var elements = jQuery.prop( this, "elements" );
+ return elements ? jQuery.makeArray( elements ) : this;
+ })
+ .filter(function(){
+ var type = this.type;
+ // Use .is(":disabled") so that fieldset[disabled] works
+ return this.name && !jQuery( this ).is( ":disabled" ) &&
+ rsubmittable.test( this.nodeName ) && !rsubmitterTypes.test( type ) &&
+ ( this.checked || !manipulation_rcheckableType.test( type ) );
+ })
+ .map(function( i, elem ){
+ var val = jQuery( this ).val();
+
+ return val == null ?
+ null :
+ jQuery.isArray( val ) ?
+ jQuery.map( val, function( val ){
+ return { name: elem.name, value: val.replace( rCRLF, "\r\n" ) };
+ }) :
+ { name: elem.name, value: val.replace( rCRLF, "\r\n" ) };
+ }).get();
+ }
+});
+
+//Serialize an array of form elements or a set of
+//key/values into a query string
+jQuery.param = function( a, traditional ) {
+ var prefix,
+ s = [],
+ add = function( key, value ) {
+ // If value is a function, invoke it and return its value
+ value = jQuery.isFunction( value ) ? value() : ( value == null ? "" : value );
+ s[ s.length ] = encodeURIComponent( key ) + "=" + encodeURIComponent( value );
+ };
+
+ // Set traditional to true for jQuery <= 1.3.2 behavior.
+ if ( traditional === undefined ) {
+ traditional = jQuery.ajaxSettings && jQuery.ajaxSettings.traditional;
+ }
+
+ // If an array was passed in, assume that it is an array of form elements.
+ if ( jQuery.isArray( a ) || ( a.jquery && !jQuery.isPlainObject( a ) ) ) {
+ // Serialize the form elements
+ jQuery.each( a, function() {
+ add( this.name, this.value );
+ });
+
+ } else {
+ // If traditional, encode the "old" way (the way 1.3.2 or older
+ // did it), otherwise encode params recursively.
+ for ( prefix in a ) {
+ buildParams( prefix, a[ prefix ], traditional, add );
+ }
+ }
+
+ // Return the resulting serialization
+ return s.join( "&" ).replace( r20, "+" );
+};
+
+function buildParams( prefix, obj, traditional, add ) {
+ var name;
+
+ if ( jQuery.isArray( obj ) ) {
+ // Serialize array item.
+ jQuery.each( obj, function( i, v ) {
+ if ( traditional || rbracket.test( prefix ) ) {
+ // Treat each array item as a scalar.
+ add( prefix, v );
+
+ } else {
+ // Item is non-scalar (array or object), encode its numeric index.
+ buildParams( prefix + "[" + ( typeof v === "object" ? i : "" ) + "]", v, traditional, add );
+ }
+ });
+
+ } else if ( !traditional && jQuery.type( obj ) === "object" ) {
+ // Serialize object item.
+ for ( name in obj ) {
+ buildParams( prefix + "[" + name + "]", obj[ name ], traditional, add );
+ }
+
+ } else {
+ // Serialize scalar item.
+ add( prefix, obj );
+ }
+}
+jQuery.each( ("blur focus focusin focusout load resize scroll unload click dblclick " +
+ "mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave " +
+ "change select submit keydown keypress keyup error contextmenu").split(" "), function( i, name ) {
+
+ // Handle event binding
+ jQuery.fn[ name ] = function( data, fn ) {
+ return arguments.length > 0 ?
+ this.on( name, null, data, fn ) :
+ this.trigger( name );
+ };
+});
+
+jQuery.fn.extend({
+ hover: function( fnOver, fnOut ) {
+ return this.mouseenter( fnOver ).mouseleave( fnOut || fnOver );
+ },
+
+ bind: function( types, data, fn ) {
+ return this.on( types, null, data, fn );
+ },
+ unbind: function( types, fn ) {
+ return this.off( types, null, fn );
+ },
+
+ delegate: function( selector, types, data, fn ) {
+ return this.on( types, selector, data, fn );
+ },
+ undelegate: function( selector, types, fn ) {
+ // ( namespace ) or ( selector, types [, fn] )
+ return arguments.length === 1 ? this.off( selector, "**" ) : this.off( types, selector || "**", fn );
+ }
+});
+var
+ // Document location
+ ajaxLocParts,
+ ajaxLocation,
+
+ ajax_nonce = jQuery.now(),
+
+ ajax_rquery = /\?/,
+ rhash = /#.*$/,
+ rts = /([?&])_=[^&]*/,
+ rheaders = /^(.*?):[ \t]*([^\r\n]*)$/mg,
+ // #7653, #8125, #8152: local protocol detection
+ rlocalProtocol = /^(?:about|app|app-storage|.+-extension|file|res|widget):$/,
+ rnoContent = /^(?:GET|HEAD)$/,
+ rprotocol = /^\/\//,
+ rurl = /^([\w.+-]+:)(?:\/\/([^\/?#:]*)(?::(\d+)|)|)/,
+
+ // Keep a copy of the old load method
+ _load = jQuery.fn.load,
+
+ /* Prefilters
+ * 1) They are useful to introduce custom dataTypes (see ajax/jsonp.js for an example)
+ * 2) These are called:
+ * - BEFORE asking for a transport
+ * - AFTER param serialization (s.data is a string if s.processData is true)
+ * 3) key is the dataType
+ * 4) the catchall symbol "*" can be used
+ * 5) execution will start with transport dataType and THEN continue down to "*" if needed
+ */
+ prefilters = {},
+
+ /* Transports bindings
+ * 1) key is the dataType
+ * 2) the catchall symbol "*" can be used
+ * 3) selection will start with transport dataType and THEN go to "*" if needed
+ */
+ transports = {},
+
+ // Avoid comment-prolog char sequence (#10098); must appease lint and evade compression
+ allTypes = "*/".concat("*");
+
+// #8138, IE may throw an exception when accessing
+// a field from window.location if document.domain has been set
+try {
+ ajaxLocation = location.href;
+} catch( e ) {
+ // Use the href attribute of an A element
+ // since IE will modify it given document.location
+ ajaxLocation = document.createElement( "a" );
+ ajaxLocation.href = "";
+ ajaxLocation = ajaxLocation.href;
+}
+
+// Segment location into parts
+ajaxLocParts = rurl.exec( ajaxLocation.toLowerCase() ) || [];
+
+// Base "constructor" for jQuery.ajaxPrefilter and jQuery.ajaxTransport
+function addToPrefiltersOrTransports( structure ) {
+
+ // dataTypeExpression is optional and defaults to "*"
+ return function( dataTypeExpression, func ) {
+
+ if ( typeof dataTypeExpression !== "string" ) {
+ func = dataTypeExpression;
+ dataTypeExpression = "*";
+ }
+
+ var dataType,
+ i = 0,
+ dataTypes = dataTypeExpression.toLowerCase().match( core_rnotwhite ) || [];
+
+ if ( jQuery.isFunction( func ) ) {
+ // For each dataType in the dataTypeExpression
+ while ( (dataType = dataTypes[i++]) ) {
+ // Prepend if requested
+ if ( dataType[0] === "+" ) {
+ dataType = dataType.slice( 1 ) || "*";
+ (structure[ dataType ] = structure[ dataType ] || []).unshift( func );
+
+ // Otherwise append
+ } else {
+ (structure[ dataType ] = structure[ dataType ] || []).push( func );
+ }
+ }
+ }
+ };
+}
+
+// Base inspection function for prefilters and transports
+function inspectPrefiltersOrTransports( structure, options, originalOptions, jqXHR ) {
+
+ var inspected = {},
+ seekingTransport = ( structure === transports );
+
+ function inspect( dataType ) {
+ var selected;
+ inspected[ dataType ] = true;
+ jQuery.each( structure[ dataType ] || [], function( _, prefilterOrFactory ) {
+ var dataTypeOrTransport = prefilterOrFactory( options, originalOptions, jqXHR );
+ if( typeof dataTypeOrTransport === "string" && !seekingTransport && !inspected[ dataTypeOrTransport ] ) {
+ options.dataTypes.unshift( dataTypeOrTransport );
+ inspect( dataTypeOrTransport );
+ return false;
+ } else if ( seekingTransport ) {
+ return !( selected = dataTypeOrTransport );
+ }
+ });
+ return selected;
+ }
+
+ return inspect( options.dataTypes[ 0 ] ) || !inspected[ "*" ] && inspect( "*" );
+}
+
+// A special extend for ajax options
+// that takes "flat" options (not to be deep extended)
+// Fixes #9887
+function ajaxExtend( target, src ) {
+ var key, deep,
+ flatOptions = jQuery.ajaxSettings.flatOptions || {};
+
+ for ( key in src ) {
+ if ( src[ key ] !== undefined ) {
+ ( flatOptions[ key ] ? target : ( deep || (deep = {}) ) )[ key ] = src[ key ];
+ }
+ }
+ if ( deep ) {
+ jQuery.extend( true, target, deep );
+ }
+
+ return target;
+}
+
+jQuery.fn.load = function( url, params, callback ) {
+ if ( typeof url !== "string" && _load ) {
+ return _load.apply( this, arguments );
+ }
+
+ var selector, type, response,
+ self = this,
+ off = url.indexOf(" ");
+
+ if ( off >= 0 ) {
+ selector = url.slice( off );
+ url = url.slice( 0, off );
+ }
+
+ // If it's a function
+ if ( jQuery.isFunction( params ) ) {
+
+ // We assume that it's the callback
+ callback = params;
+ params = undefined;
+
+ // Otherwise, build a param string
+ } else if ( params && typeof params === "object" ) {
+ type = "POST";
+ }
+
+ // If we have elements to modify, make the request
+ if ( self.length > 0 ) {
+ jQuery.ajax({
+ url: url,
+
+ // if "type" variable is undefined, then "GET" method will be used
+ type: type,
+ dataType: "html",
+ data: params
+ }).done(function( responseText ) {
+
+ // Save response for use in complete callback
+ response = arguments;
+
+ self.html( selector ?
+
+ // If a selector was specified, locate the right elements in a dummy div
+ // Exclude scripts to avoid IE 'Permission Denied' errors
+ jQuery("<div>").append( jQuery.parseHTML( responseText ) ).find( selector ) :
+
+ // Otherwise use the full result
+ responseText );
+
+ }).complete( callback && function( jqXHR, status ) {
+ self.each( callback, response || [ jqXHR.responseText, status, jqXHR ] );
+ });
+ }
+
+ return this;
+};
+
+// Attach a bunch of functions for handling common AJAX events
+jQuery.each( [ "ajaxStart", "ajaxStop", "ajaxComplete", "ajaxError", "ajaxSuccess", "ajaxSend" ], function( i, type ){
+ jQuery.fn[ type ] = function( fn ){
+ return this.on( type, fn );
+ };
+});
+
+jQuery.extend({
+
+ // Counter for holding the number of active queries
+ active: 0,
+
+ // Last-Modified header cache for next request
+ lastModified: {},
+ etag: {},
+
+ ajaxSettings: {
+ url: ajaxLocation,
+ type: "GET",
+ isLocal: rlocalProtocol.test( ajaxLocParts[ 1 ] ),
+ global: true,
+ processData: true,
+ async: true,
+ contentType: "application/x-www-form-urlencoded; charset=UTF-8",
+ /*
+ timeout: 0,
+ data: null,
+ dataType: null,
+ username: null,
+ password: null,
+ cache: null,
+ throws: false,
+ traditional: false,
+ headers: {},
+ */
+
+ accepts: {
+ "*": allTypes,
+ text: "text/plain",
+ html: "text/html",
+ xml: "application/xml, text/xml",
+ json: "application/json, text/javascript"
+ },
+
+ contents: {
+ xml: /xml/,
+ html: /html/,
+ json: /json/
+ },
+
+ responseFields: {
+ xml: "responseXML",
+ text: "responseText",
+ json: "responseJSON"
+ },
+
+ // Data converters
+ // Keys separate source (or catchall "*") and destination types with a single space
+ converters: {
+
+ // Convert anything to text
+ "* text": String,
+
+ // Text to html (true = no transformation)
+ "text html": true,
+
+ // Evaluate text as a json expression
+ "text json": jQuery.parseJSON,
+
+ // Parse text as xml
+ "text xml": jQuery.parseXML
+ },
+
+ // For options that shouldn't be deep extended:
+ // you can add your own custom options here if
+ // and when you create one that shouldn't be
+ // deep extended (see ajaxExtend)
+ flatOptions: {
+ url: true,
+ context: true
+ }
+ },
+
+ // Creates a full fledged settings object into target
+ // with both ajaxSettings and settings fields.
+ // If target is omitted, writes into ajaxSettings.
+ ajaxSetup: function( target, settings ) {
+ return settings ?
+
+ // Building a settings object
+ ajaxExtend( ajaxExtend( target, jQuery.ajaxSettings ), settings ) :
+
+ // Extending ajaxSettings
+ ajaxExtend( jQuery.ajaxSettings, target );
+ },
+
+ ajaxPrefilter: addToPrefiltersOrTransports( prefilters ),
+ ajaxTransport: addToPrefiltersOrTransports( transports ),
+
+ // Main method
+ ajax: function( url, options ) {
+
+ // If url is an object, simulate pre-1.5 signature
+ if ( typeof url === "object" ) {
+ options = url;
+ url = undefined;
+ }
+
+ // Force options to be an object
+ options = options || {};
+
+ var transport,
+ // URL without anti-cache param
+ cacheURL,
+ // Response headers
+ responseHeadersString,
+ responseHeaders,
+ // timeout handle
+ timeoutTimer,
+ // Cross-domain detection vars
+ parts,
+ // To know if global events are to be dispatched
+ fireGlobals,
+ // Loop variable
+ i,
+ // Create the final options object
+ s = jQuery.ajaxSetup( {}, options ),
+ // Callbacks context
+ callbackContext = s.context || s,
+ // Context for global events is callbackContext if it is a DOM node or jQuery collection
+ globalEventContext = s.context && ( callbackContext.nodeType || callbackContext.jquery ) ?
+ jQuery( callbackContext ) :
+ jQuery.event,
+ // Deferreds
+ deferred = jQuery.Deferred(),
+ completeDeferred = jQuery.Callbacks("once memory"),
+ // Status-dependent callbacks
+ statusCode = s.statusCode || {},
+ // Headers (they are sent all at once)
+ requestHeaders = {},
+ requestHeadersNames = {},
+ // The jqXHR state
+ state = 0,
+ // Default abort message
+ strAbort = "canceled",
+ // Fake xhr
+ jqXHR = {
+ readyState: 0,
+
+ // Builds headers hashtable if needed
+ getResponseHeader: function( key ) {
+ var match;
+ if ( state === 2 ) {
+ if ( !responseHeaders ) {
+ responseHeaders = {};
+ while ( (match = rheaders.exec( responseHeadersString )) ) {
+ responseHeaders[ match[1].toLowerCase() ] = match[ 2 ];
+ }
+ }
+ match = responseHeaders[ key.toLowerCase() ];
+ }
+ return match == null ? null : match;
+ },
+
+ // Raw string
+ getAllResponseHeaders: function() {
+ return state === 2 ? responseHeadersString : null;
+ },
+
+ // Caches the header
+ setRequestHeader: function( name, value ) {
+ var lname = name.toLowerCase();
+ if ( !state ) {
+ name = requestHeadersNames[ lname ] = requestHeadersNames[ lname ] || name;
+ requestHeaders[ name ] = value;
+ }
+ return this;
+ },
+
+ // Overrides response content-type header
+ overrideMimeType: function( type ) {
+ if ( !state ) {
+ s.mimeType = type;
+ }
+ return this;
+ },
+
+ // Status-dependent callbacks
+ statusCode: function( map ) {
+ var code;
+ if ( map ) {
+ if ( state < 2 ) {
+ for ( code in map ) {
+ // Lazy-add the new callback in a way that preserves old ones
+ statusCode[ code ] = [ statusCode[ code ], map[ code ] ];
+ }
+ } else {
+ // Execute the appropriate callbacks
+ jqXHR.always( map[ jqXHR.status ] );
+ }
+ }
+ return this;
+ },
+
+ // Cancel the request
+ abort: function( statusText ) {
+ var finalText = statusText || strAbort;
+ if ( transport ) {
+ transport.abort( finalText );
+ }
+ done( 0, finalText );
+ return this;
+ }
+ };
+
+ // Attach deferreds
+ deferred.promise( jqXHR ).complete = completeDeferred.add;
+ jqXHR.success = jqXHR.done;
+ jqXHR.error = jqXHR.fail;
+
+ // Remove hash character (#7531: and string promotion)
+ // Add protocol if not provided (prefilters might expect it)
+ // Handle falsy url in the settings object (#10093: consistency with old signature)
+ // We also use the url parameter if available
+ s.url = ( ( url || s.url || ajaxLocation ) + "" ).replace( rhash, "" )
+ .replace( rprotocol, ajaxLocParts[ 1 ] + "//" );
+
+ // Alias method option to type as per ticket #12004
+ s.type = options.method || options.type || s.method || s.type;
+
+ // Extract dataTypes list
+ s.dataTypes = jQuery.trim( s.dataType || "*" ).toLowerCase().match( core_rnotwhite ) || [""];
+
+ // A cross-domain request is in order when we have a protocol:host:port mismatch
+ if ( s.crossDomain == null ) {
+ parts = rurl.exec( s.url.toLowerCase() );
+ s.crossDomain = !!( parts &&
+ ( parts[ 1 ] !== ajaxLocParts[ 1 ] || parts[ 2 ] !== ajaxLocParts[ 2 ] ||
+ ( parts[ 3 ] || ( parts[ 1 ] === "http:" ? "80" : "443" ) ) !==
+ ( ajaxLocParts[ 3 ] || ( ajaxLocParts[ 1 ] === "http:" ? "80" : "443" ) ) )
+ );
+ }
+
+ // Convert data if not already a string
+ if ( s.data && s.processData && typeof s.data !== "string" ) {
+ s.data = jQuery.param( s.data, s.traditional );
+ }
+
+ // Apply prefilters
+ inspectPrefiltersOrTransports( prefilters, s, options, jqXHR );
+
+ // If request was aborted inside a prefilter, stop there
+ if ( state === 2 ) {
+ return jqXHR;
+ }
+
+ // We can fire global events as of now if asked to
+ fireGlobals = s.global;
+
+ // Watch for a new set of requests
+ if ( fireGlobals && jQuery.active++ === 0 ) {
+ jQuery.event.trigger("ajaxStart");
+ }
+
+ // Uppercase the type
+ s.type = s.type.toUpperCase();
+
+ // Determine if request has content
+ s.hasContent = !rnoContent.test( s.type );
+
+ // Save the URL in case we're toying with the If-Modified-Since
+ // and/or If-None-Match header later on
+ cacheURL = s.url;
+
+ // More options handling for requests with no content
+ if ( !s.hasContent ) {
+
+ // If data is available, append data to url
+ if ( s.data ) {
+ cacheURL = ( s.url += ( ajax_rquery.test( cacheURL ) ? "&" : "?" ) + s.data );
+ // #9682: remove data so that it's not used in an eventual retry
+ delete s.data;
+ }
+
+ // Add anti-cache in url if needed
+ if ( s.cache === false ) {
+ s.url = rts.test( cacheURL ) ?
+
+ // If there is already a '_' parameter, set its value
+ cacheURL.replace( rts, "$1_=" + ajax_nonce++ ) :
+
+ // Otherwise add one to the end
+ cacheURL + ( ajax_rquery.test( cacheURL ) ? "&" : "?" ) + "_=" + ajax_nonce++;
+ }
+ }
+
+ // Set the If-Modified-Since and/or If-None-Match header, if in ifModified mode.
+ if ( s.ifModified ) {
+ if ( jQuery.lastModified[ cacheURL ] ) {
+ jqXHR.setRequestHeader( "If-Modified-Since", jQuery.lastModified[ cacheURL ] );
+ }
+ if ( jQuery.etag[ cacheURL ] ) {
+ jqXHR.setRequestHeader( "If-None-Match", jQuery.etag[ cacheURL ] );
+ }
+ }
+
+ // Set the correct header, if data is being sent
+ if ( s.data && s.hasContent && s.contentType !== false || options.contentType ) {
+ jqXHR.setRequestHeader( "Content-Type", s.contentType );
+ }
+
+ // Set the Accepts header for the server, depending on the dataType
+ jqXHR.setRequestHeader(
+ "Accept",
+ s.dataTypes[ 0 ] && s.accepts[ s.dataTypes[0] ] ?
+ s.accepts[ s.dataTypes[0] ] + ( s.dataTypes[ 0 ] !== "*" ? ", " + allTypes + "; q=0.01" : "" ) :
+ s.accepts[ "*" ]
+ );
+
+ // Check for headers option
+ for ( i in s.headers ) {
+ jqXHR.setRequestHeader( i, s.headers[ i ] );
+ }
+
+ // Allow custom headers/mimetypes and early abort
+ if ( s.beforeSend && ( s.beforeSend.call( callbackContext, jqXHR, s ) === false || state === 2 ) ) {
+ // Abort if not done already and return
+ return jqXHR.abort();
+ }
+
+ // aborting is no longer a cancellation
+ strAbort = "abort";
+
+ // Install callbacks on deferreds
+ for ( i in { success: 1, error: 1, complete: 1 } ) {
+ jqXHR[ i ]( s[ i ] );
+ }
+
+ // Get transport
+ transport = inspectPrefiltersOrTransports( transports, s, options, jqXHR );
+
+ // If no transport, we auto-abort
+ if ( !transport ) {
+ done( -1, "No Transport" );
+ } else {
+ jqXHR.readyState = 1;
+
+ // Send global event
+ if ( fireGlobals ) {
+ globalEventContext.trigger( "ajaxSend", [ jqXHR, s ] );
+ }
+ // Timeout
+ if ( s.async && s.timeout > 0 ) {
+ timeoutTimer = setTimeout(function() {
+ jqXHR.abort("timeout");
+ }, s.timeout );
+ }
+
+ try {
+ state = 1;
+ transport.send( requestHeaders, done );
+ } catch ( e ) {
+ // Propagate exception as error if not done
+ if ( state < 2 ) {
+ done( -1, e );
+ // Simply rethrow otherwise
+ } else {
+ throw e;
+ }
+ }
+ }
+
+ // Callback for when everything is done
+ function done( status, nativeStatusText, responses, headers ) {
+ var isSuccess, success, error, response, modified,
+ statusText = nativeStatusText;
+
+ // Called once
+ if ( state === 2 ) {
+ return;
+ }
+
+ // State is "done" now
+ state = 2;
+
+ // Clear timeout if it exists
+ if ( timeoutTimer ) {
+ clearTimeout( timeoutTimer );
+ }
+
+ // Dereference transport for early garbage collection
+ // (no matter how long the jqXHR object will be used)
+ transport = undefined;
+
+ // Cache response headers
+ responseHeadersString = headers || "";
+
+ // Set readyState
+ jqXHR.readyState = status > 0 ? 4 : 0;
+
+ // Determine if successful
+ isSuccess = status >= 200 && status < 300 || status === 304;
+
+ // Get response data
+ if ( responses ) {
+ response = ajaxHandleResponses( s, jqXHR, responses );
+ }
+
+ // Convert no matter what (that way responseXXX fields are always set)
+ response = ajaxConvert( s, response, jqXHR, isSuccess );
+
+ // If successful, handle type chaining
+ if ( isSuccess ) {
+
+ // Set the If-Modified-Since and/or If-None-Match header, if in ifModified mode.
+ if ( s.ifModified ) {
+ modified = jqXHR.getResponseHeader("Last-Modified");
+ if ( modified ) {
+ jQuery.lastModified[ cacheURL ] = modified;
+ }
+ modified = jqXHR.getResponseHeader("etag");
+ if ( modified ) {
+ jQuery.etag[ cacheURL ] = modified;
+ }
+ }
+
+ // if no content
+ if ( status === 204 || s.type === "HEAD" ) {
+ statusText = "nocontent";
+
+ // if not modified
+ } else if ( status === 304 ) {
+ statusText = "notmodified";
+
+ // If we have data, let's convert it
+ } else {
+ statusText = response.state;
+ success = response.data;
+ error = response.error;
+ isSuccess = !error;
+ }
+ } else {
+ // We extract error from statusText
+ // then normalize statusText and status for non-aborts
+ error = statusText;
+ if ( status || !statusText ) {
+ statusText = "error";
+ if ( status < 0 ) {
+ status = 0;
+ }
+ }
+ }
+
+ // Set data for the fake xhr object
+ jqXHR.status = status;
+ jqXHR.statusText = ( nativeStatusText || statusText ) + "";
+
+ // Success/Error
+ if ( isSuccess ) {
+ deferred.resolveWith( callbackContext, [ success, statusText, jqXHR ] );
+ } else {
+ deferred.rejectWith( callbackContext, [ jqXHR, statusText, error ] );
+ }
+
+ // Status-dependent callbacks
+ jqXHR.statusCode( statusCode );
+ statusCode = undefined;
+
+ if ( fireGlobals ) {
+ globalEventContext.trigger( isSuccess ? "ajaxSuccess" : "ajaxError",
+ [ jqXHR, s, isSuccess ? success : error ] );
+ }
+
+ // Complete
+ completeDeferred.fireWith( callbackContext, [ jqXHR, statusText ] );
+
+ if ( fireGlobals ) {
+ globalEventContext.trigger( "ajaxComplete", [ jqXHR, s ] );
+ // Handle the global AJAX counter
+ if ( !( --jQuery.active ) ) {
+ jQuery.event.trigger("ajaxStop");
+ }
+ }
+ }
+
+ return jqXHR;
+ },
+
+ getJSON: function( url, data, callback ) {
+ return jQuery.get( url, data, callback, "json" );
+ },
+
+ getScript: function( url, callback ) {
+ return jQuery.get( url, undefined, callback, "script" );
+ }
+});
+
+jQuery.each( [ "get", "post" ], function( i, method ) {
+ jQuery[ method ] = function( url, data, callback, type ) {
+ // shift arguments if data argument was omitted
+ if ( jQuery.isFunction( data ) ) {
+ type = type || callback;
+ callback = data;
+ data = undefined;
+ }
+
+ return jQuery.ajax({
+ url: url,
+ type: method,
+ dataType: type,
+ data: data,
+ success: callback
+ });
+ };
+});
+
+/* Handles responses to an ajax request:
+ * - finds the right dataType (mediates between content-type and expected dataType)
+ * - returns the corresponding response
+ */
+function ajaxHandleResponses( s, jqXHR, responses ) {
+
+ var ct, type, finalDataType, firstDataType,
+ contents = s.contents,
+ dataTypes = s.dataTypes;
+
+ // Remove auto dataType and get content-type in the process
+ while( dataTypes[ 0 ] === "*" ) {
+ dataTypes.shift();
+ if ( ct === undefined ) {
+ ct = s.mimeType || jqXHR.getResponseHeader("Content-Type");
+ }
+ }
+
+ // Check if we're dealing with a known content-type
+ if ( ct ) {
+ for ( type in contents ) {
+ if ( contents[ type ] && contents[ type ].test( ct ) ) {
+ dataTypes.unshift( type );
+ break;
+ }
+ }
+ }
+
+ // Check to see if we have a response for the expected dataType
+ if ( dataTypes[ 0 ] in responses ) {
+ finalDataType = dataTypes[ 0 ];
+ } else {
+ // Try convertible dataTypes
+ for ( type in responses ) {
+ if ( !dataTypes[ 0 ] || s.converters[ type + " " + dataTypes[0] ] ) {
+ finalDataType = type;
+ break;
+ }
+ if ( !firstDataType ) {
+ firstDataType = type;
+ }
+ }
+ // Or just use first one
+ finalDataType = finalDataType || firstDataType;
+ }
+
+ // If we found a dataType
+ // We add the dataType to the list if needed
+ // and return the corresponding response
+ if ( finalDataType ) {
+ if ( finalDataType !== dataTypes[ 0 ] ) {
+ dataTypes.unshift( finalDataType );
+ }
+ return responses[ finalDataType ];
+ }
+}
+
+/* Chain conversions given the request and the original response
+ * Also sets the responseXXX fields on the jqXHR instance
+ */
+function ajaxConvert( s, response, jqXHR, isSuccess ) {
+ var conv2, current, conv, tmp, prev,
+ converters = {},
+ // Work with a copy of dataTypes in case we need to modify it for conversion
+ dataTypes = s.dataTypes.slice();
+
+ // Create converters map with lowercased keys
+ if ( dataTypes[ 1 ] ) {
+ for ( conv in s.converters ) {
+ converters[ conv.toLowerCase() ] = s.converters[ conv ];
+ }
+ }
+
+ current = dataTypes.shift();
+
+ // Convert to each sequential dataType
+ while ( current ) {
+
+ if ( s.responseFields[ current ] ) {
+ jqXHR[ s.responseFields[ current ] ] = response;
+ }
+
+ // Apply the dataFilter if provided
+ if ( !prev && isSuccess && s.dataFilter ) {
+ response = s.dataFilter( response, s.dataType );
+ }
+
+ prev = current;
+ current = dataTypes.shift();
+
+ if ( current ) {
+
+ // There's only work to do if current dataType is non-auto
+ if ( current === "*" ) {
+
+ current = prev;
+
+ // Convert response if prev dataType is non-auto and differs from current
+ } else if ( prev !== "*" && prev !== current ) {
+
+ // Seek a direct converter
+ conv = converters[ prev + " " + current ] || converters[ "* " + current ];
+
+ // If none found, seek a pair
+ if ( !conv ) {
+ for ( conv2 in converters ) {
+
+ // If conv2 outputs current
+ tmp = conv2.split( " " );
+ if ( tmp[ 1 ] === current ) {
+
+ // If prev can be converted to accepted input
+ conv = converters[ prev + " " + tmp[ 0 ] ] ||
+ converters[ "* " + tmp[ 0 ] ];
+ if ( conv ) {
+ // Condense equivalence converters
+ if ( conv === true ) {
+ conv = converters[ conv2 ];
+
+ // Otherwise, insert the intermediate dataType
+ } else if ( converters[ conv2 ] !== true ) {
+ current = tmp[ 0 ];
+ dataTypes.unshift( tmp[ 1 ] );
+ }
+ break;
+ }
+ }
+ }
+ }
+
+ // Apply converter (if not an equivalence)
+ if ( conv !== true ) {
+
+ // Unless errors are allowed to bubble, catch and return them
+ if ( conv && s[ "throws" ] ) {
+ response = conv( response );
+ } else {
+ try {
+ response = conv( response );
+ } catch ( e ) {
+ return { state: "parsererror", error: conv ? e : "No conversion from " + prev + " to " + current };
+ }
+ }
+ }
+ }
+ }
+ }
+
+ return { state: "success", data: response };
+}
+// Install script dataType
+jQuery.ajaxSetup({
+ accepts: {
+ script: "text/javascript, application/javascript, application/ecmascript, application/x-ecmascript"
+ },
+ contents: {
+ script: /(?:java|ecma)script/
+ },
+ converters: {
+ "text script": function( text ) {
+ jQuery.globalEval( text );
+ return text;
+ }
+ }
+});
+
+// Handle cache's special case and crossDomain
+jQuery.ajaxPrefilter( "script", function( s ) {
+ if ( s.cache === undefined ) {
+ s.cache = false;
+ }
+ if ( s.crossDomain ) {
+ s.type = "GET";
+ }
+});
+
+// Bind script tag hack transport
+jQuery.ajaxTransport( "script", function( s ) {
+ // This transport only deals with cross domain requests
+ if ( s.crossDomain ) {
+ var script, callback;
+ return {
+ send: function( _, complete ) {
+ script = jQuery("<script>").prop({
+ async: true,
+ charset: s.scriptCharset,
+ src: s.url
+ }).on(
+ "load error",
+ callback = function( evt ) {
+ script.remove();
+ callback = null;
+ if ( evt ) {
+ complete( evt.type === "error" ? 404 : 200, evt.type );
+ }
+ }
+ );
+ document.head.appendChild( script[ 0 ] );
+ },
+ abort: function() {
+ if ( callback ) {
+ callback();
+ }
+ }
+ };
+ }
+});
+var oldCallbacks = [],
+ rjsonp = /(=)\?(?=&|$)|\?\?/;
+
+// Default jsonp settings
+jQuery.ajaxSetup({
+ jsonp: "callback",
+ jsonpCallback: function() {
+ var callback = oldCallbacks.pop() || ( jQuery.expando + "_" + ( ajax_nonce++ ) );
+ this[ callback ] = true;
+ return callback;
+ }
+});
+
+// Detect, normalize options and install callbacks for jsonp requests
+jQuery.ajaxPrefilter( "json jsonp", function( s, originalSettings, jqXHR ) {
+
+ var callbackName, overwritten, responseContainer,
+ jsonProp = s.jsonp !== false && ( rjsonp.test( s.url ) ?
+ "url" :
+ typeof s.data === "string" && !( s.contentType || "" ).indexOf("application/x-www-form-urlencoded") && rjsonp.test( s.data ) && "data"
+ );
+
+ // Handle iff the expected data type is "jsonp" or we have a parameter to set
+ if ( jsonProp || s.dataTypes[ 0 ] === "jsonp" ) {
+
+ // Get callback name, remembering preexisting value associated with it
+ callbackName = s.jsonpCallback = jQuery.isFunction( s.jsonpCallback ) ?
+ s.jsonpCallback() :
+ s.jsonpCallback;
+
+ // Insert callback into url or form data
+ if ( jsonProp ) {
+ s[ jsonProp ] = s[ jsonProp ].replace( rjsonp, "$1" + callbackName );
+ } else if ( s.jsonp !== false ) {
+ s.url += ( ajax_rquery.test( s.url ) ? "&" : "?" ) + s.jsonp + "=" + callbackName;
+ }
+
+ // Use data converter to retrieve json after script execution
+ s.converters["script json"] = function() {
+ if ( !responseContainer ) {
+ jQuery.error( callbackName + " was not called" );
+ }
+ return responseContainer[ 0 ];
+ };
+
+ // force json dataType
+ s.dataTypes[ 0 ] = "json";
+
+ // Install callback
+ overwritten = window[ callbackName ];
+ window[ callbackName ] = function() {
+ responseContainer = arguments;
+ };
+
+ // Clean-up function (fires after converters)
+ jqXHR.always(function() {
+ // Restore preexisting value
+ window[ callbackName ] = overwritten;
+
+ // Save back as free
+ if ( s[ callbackName ] ) {
+ // make sure that re-using the options doesn't screw things around
+ s.jsonpCallback = originalSettings.jsonpCallback;
+
+ // save the callback name for future use
+ oldCallbacks.push( callbackName );
+ }
+
+ // Call if it was a function and we have a response
+ if ( responseContainer && jQuery.isFunction( overwritten ) ) {
+ overwritten( responseContainer[ 0 ] );
+ }
+
+ responseContainer = overwritten = undefined;
+ });
+
+ // Delegate to script
+ return "script";
+ }
+});
+jQuery.ajaxSettings.xhr = function() {
+ try {
+ return new XMLHttpRequest();
+ } catch( e ) {}
+};
+
+var xhrSupported = jQuery.ajaxSettings.xhr(),
+ xhrSuccessStatus = {
+ // file protocol always yields status code 0, assume 200
+ 0: 200,
+ // Support: IE9
+ // #1450: sometimes IE returns 1223 when it should be 204
+ 1223: 204
+ },
+ // Support: IE9
+ // We need to keep track of outbound xhr and abort them manually
+ // because IE is not smart enough to do it all by itself
+ xhrId = 0,
+ xhrCallbacks = {};
+
+if ( window.ActiveXObject ) {
+ jQuery( window ).on( "unload", function() {
+ for( var key in xhrCallbacks ) {
+ xhrCallbacks[ key ]();
+ }
+ xhrCallbacks = undefined;
+ });
+}
+
+jQuery.support.cors = !!xhrSupported && ( "withCredentials" in xhrSupported );
+jQuery.support.ajax = xhrSupported = !!xhrSupported;
+
+jQuery.ajaxTransport(function( options ) {
+ var callback;
+ // Cross domain only allowed if supported through XMLHttpRequest
+ if ( jQuery.support.cors || xhrSupported && !options.crossDomain ) {
+ return {
+ send: function( headers, complete ) {
+ var i, id,
+ xhr = options.xhr();
+ xhr.open( options.type, options.url, options.async, options.username, options.password );
+ // Apply custom fields if provided
+ if ( options.xhrFields ) {
+ for ( i in options.xhrFields ) {
+ xhr[ i ] = options.xhrFields[ i ];
+ }
+ }
+ // Override mime type if needed
+ if ( options.mimeType && xhr.overrideMimeType ) {
+ xhr.overrideMimeType( options.mimeType );
+ }
+ // X-Requested-With header
+ // For cross-domain requests, seeing as conditions for a preflight are
+ // akin to a jigsaw puzzle, we simply never set it to be sure.
+ // (it can always be set on a per-request basis or even using ajaxSetup)
+ // For same-domain requests, won't change header if already provided.
+ if ( !options.crossDomain && !headers["X-Requested-With"] ) {
+ headers["X-Requested-With"] = "XMLHttpRequest";
+ }
+ // Set headers
+ for ( i in headers ) {
+ xhr.setRequestHeader( i, headers[ i ] );
+ }
+ // Callback
+ callback = function( type ) {
+ return function() {
+ if ( callback ) {
+ delete xhrCallbacks[ id ];
+ callback = xhr.onload = xhr.onerror = null;
+ if ( type === "abort" ) {
+ xhr.abort();
+ } else if ( type === "error" ) {
+ complete(
+ // file protocol always yields status 0, assume 404
+ xhr.status || 404,
+ xhr.statusText
+ );
+ } else {
+ complete(
+ xhrSuccessStatus[ xhr.status ] || xhr.status,
+ xhr.statusText,
+ // Support: IE9
+ // #11426: When requesting binary data, IE9 will throw an exception
+ // on any attempt to access responseText
+ typeof xhr.responseText === "string" ? {
+ text: xhr.responseText
+ } : undefined,
+ xhr.getAllResponseHeaders()
+ );
+ }
+ }
+ };
+ };
+ // Listen to events
+ xhr.onload = callback();
+ xhr.onerror = callback("error");
+ // Create the abort callback
+ callback = xhrCallbacks[( id = xhrId++ )] = callback("abort");
+ // Do send the request
+ // This may raise an exception which is actually
+ // handled in jQuery.ajax (so no try/catch here)
+ xhr.send( options.hasContent && options.data || null );
+ },
+ abort: function() {
+ if ( callback ) {
+ callback();
+ }
+ }
+ };
+ }
+});
+var fxNow, timerId,
+ rfxtypes = /^(?:toggle|show|hide)$/,
+ rfxnum = new RegExp( "^(?:([+-])=|)(" + core_pnum + ")([a-z%]*)$", "i" ),
+ rrun = /queueHooks$/,
+ animationPrefilters = [ defaultPrefilter ],
+ tweeners = {
+ "*": [function( prop, value ) {
+ var tween = this.createTween( prop, value ),
+ target = tween.cur(),
+ parts = rfxnum.exec( value ),
+ unit = parts && parts[ 3 ] || ( jQuery.cssNumber[ prop ] ? "" : "px" ),
+
+ // Starting value computation is required for potential unit mismatches
+ start = ( jQuery.cssNumber[ prop ] || unit !== "px" && +target ) &&
+ rfxnum.exec( jQuery.css( tween.elem, prop ) ),
+ scale = 1,
+ maxIterations = 20;
+
+ if ( start && start[ 3 ] !== unit ) {
+ // Trust units reported by jQuery.css
+ unit = unit || start[ 3 ];
+
+ // Make sure we update the tween properties later on
+ parts = parts || [];
+
+ // Iteratively approximate from a nonzero starting point
+ start = +target || 1;
+
+ do {
+ // If previous iteration zeroed out, double until we get *something*
+ // Use a string for doubling factor so we don't accidentally see scale as unchanged below
+ scale = scale || ".5";
+
+ // Adjust and apply
+ start = start / scale;
+ jQuery.style( tween.elem, prop, start + unit );
+
+ // Update scale, tolerating zero or NaN from tween.cur()
+ // And breaking the loop if scale is unchanged or perfect, or if we've just had enough
+ } while ( scale !== (scale = tween.cur() / target) && scale !== 1 && --maxIterations );
+ }
+
+ // Update tween properties
+ if ( parts ) {
+ start = tween.start = +start || +target || 0;
+ tween.unit = unit;
+ // If a +=/-= token was provided, we're doing a relative animation
+ tween.end = parts[ 1 ] ?
+ start + ( parts[ 1 ] + 1 ) * parts[ 2 ] :
+ +parts[ 2 ];
+ }
+
+ return tween;
+ }]
+ };
+
+// Animations created synchronously will run synchronously
+function createFxNow() {
+ setTimeout(function() {
+ fxNow = undefined;
+ });
+ return ( fxNow = jQuery.now() );
+}
+
+function createTween( value, prop, animation ) {
+ var tween,
+ collection = ( tweeners[ prop ] || [] ).concat( tweeners[ "*" ] ),
+ index = 0,
+ length = collection.length;
+ for ( ; index < length; index++ ) {
+ if ( (tween = collection[ index ].call( animation, prop, value )) ) {
+
+ // we're done with this property
+ return tween;
+ }
+ }
+}
+
+function Animation( elem, properties, options ) {
+ var result,
+ stopped,
+ index = 0,
+ length = animationPrefilters.length,
+ deferred = jQuery.Deferred().always( function() {
+ // don't match elem in the :animated selector
+ delete tick.elem;
+ }),
+ tick = function() {
+ if ( stopped ) {
+ return false;
+ }
+ var currentTime = fxNow || createFxNow(),
+ remaining = Math.max( 0, animation.startTime + animation.duration - currentTime ),
+ // archaic crash bug won't allow us to use 1 - ( 0.5 || 0 ) (#12497)
+ temp = remaining / animation.duration || 0,
+ percent = 1 - temp,
+ index = 0,
+ length = animation.tweens.length;
+
+ for ( ; index < length ; index++ ) {
+ animation.tweens[ index ].run( percent );
+ }
+
+ deferred.notifyWith( elem, [ animation, percent, remaining ]);
+
+ if ( percent < 1 && length ) {
+ return remaining;
+ } else {
+ deferred.resolveWith( elem, [ animation ] );
+ return false;
+ }
+ },
+ animation = deferred.promise({
+ elem: elem,
+ props: jQuery.extend( {}, properties ),
+ opts: jQuery.extend( true, { specialEasing: {} }, options ),
+ originalProperties: properties,
+ originalOptions: options,
+ startTime: fxNow || createFxNow(),
+ duration: options.duration,
+ tweens: [],
+ createTween: function( prop, end ) {
+ var tween = jQuery.Tween( elem, animation.opts, prop, end,
+ animation.opts.specialEasing[ prop ] || animation.opts.easing );
+ animation.tweens.push( tween );
+ return tween;
+ },
+ stop: function( gotoEnd ) {
+ var index = 0,
+ // if we are going to the end, we want to run all the tweens
+ // otherwise we skip this part
+ length = gotoEnd ? animation.tweens.length : 0;
+ if ( stopped ) {
+ return this;
+ }
+ stopped = true;
+ for ( ; index < length ; index++ ) {
+ animation.tweens[ index ].run( 1 );
+ }
+
+ // resolve when we played the last frame
+ // otherwise, reject
+ if ( gotoEnd ) {
+ deferred.resolveWith( elem, [ animation, gotoEnd ] );
+ } else {
+ deferred.rejectWith( elem, [ animation, gotoEnd ] );
+ }
+ return this;
+ }
+ }),
+ props = animation.props;
+
+ propFilter( props, animation.opts.specialEasing );
+
+ for ( ; index < length ; index++ ) {
+ result = animationPrefilters[ index ].call( animation, elem, props, animation.opts );
+ if ( result ) {
+ return result;
+ }
+ }
+
+ jQuery.map( props, createTween, animation );
+
+ if ( jQuery.isFunction( animation.opts.start ) ) {
+ animation.opts.start.call( elem, animation );
+ }
+
+ jQuery.fx.timer(
+ jQuery.extend( tick, {
+ elem: elem,
+ anim: animation,
+ queue: animation.opts.queue
+ })
+ );
+
+ // attach callbacks from options
+ return animation.progress( animation.opts.progress )
+ .done( animation.opts.done, animation.opts.complete )
+ .fail( animation.opts.fail )
+ .always( animation.opts.always );
+}
+
+function propFilter( props, specialEasing ) {
+ var index, name, easing, value, hooks;
+
+ // camelCase, specialEasing and expand cssHook pass
+ for ( index in props ) {
+ name = jQuery.camelCase( index );
+ easing = specialEasing[ name ];
+ value = props[ index ];
+ if ( jQuery.isArray( value ) ) {
+ easing = value[ 1 ];
+ value = props[ index ] = value[ 0 ];
+ }
+
+ if ( index !== name ) {
+ props[ name ] = value;
+ delete props[ index ];
+ }
+
+ hooks = jQuery.cssHooks[ name ];
+ if ( hooks && "expand" in hooks ) {
+ value = hooks.expand( value );
+ delete props[ name ];
+
+ // not quite $.extend, this wont overwrite keys already present.
+ // also - reusing 'index' from above because we have the correct "name"
+ for ( index in value ) {
+ if ( !( index in props ) ) {
+ props[ index ] = value[ index ];
+ specialEasing[ index ] = easing;
+ }
+ }
+ } else {
+ specialEasing[ name ] = easing;
+ }
+ }
+}
+
+jQuery.Animation = jQuery.extend( Animation, {
+
+ tweener: function( props, callback ) {
+ if ( jQuery.isFunction( props ) ) {
+ callback = props;
+ props = [ "*" ];
+ } else {
+ props = props.split(" ");
+ }
+
+ var prop,
+ index = 0,
+ length = props.length;
+
+ for ( ; index < length ; index++ ) {
+ prop = props[ index ];
+ tweeners[ prop ] = tweeners[ prop ] || [];
+ tweeners[ prop ].unshift( callback );
+ }
+ },
+
+ prefilter: function( callback, prepend ) {
+ if ( prepend ) {
+ animationPrefilters.unshift( callback );
+ } else {
+ animationPrefilters.push( callback );
+ }
+ }
+});
+
+function defaultPrefilter( elem, props, opts ) {
+ /* jshint validthis: true */
+ var prop, value, toggle, tween, hooks, oldfire,
+ anim = this,
+ orig = {},
+ style = elem.style,
+ hidden = elem.nodeType && isHidden( elem ),
+ dataShow = data_priv.get( elem, "fxshow" );
+
+ // handle queue: false promises
+ if ( !opts.queue ) {
+ hooks = jQuery._queueHooks( elem, "fx" );
+ if ( hooks.unqueued == null ) {
+ hooks.unqueued = 0;
+ oldfire = hooks.empty.fire;
+ hooks.empty.fire = function() {
+ if ( !hooks.unqueued ) {
+ oldfire();
+ }
+ };
+ }
+ hooks.unqueued++;
+
+ anim.always(function() {
+ // doing this makes sure that the complete handler will be called
+ // before this completes
+ anim.always(function() {
+ hooks.unqueued--;
+ if ( !jQuery.queue( elem, "fx" ).length ) {
+ hooks.empty.fire();
+ }
+ });
+ });
+ }
+
+ // height/width overflow pass
+ if ( elem.nodeType === 1 && ( "height" in props || "width" in props ) ) {
+ // Make sure that nothing sneaks out
+ // Record all 3 overflow attributes because IE9-10 do not
+ // change the overflow attribute when overflowX and
+ // overflowY are set to the same value
+ opts.overflow = [ style.overflow, style.overflowX, style.overflowY ];
+
+ // Set display property to inline-block for height/width
+ // animations on inline elements that are having width/height animated
+ if ( jQuery.css( elem, "display" ) === "inline" &&
+ jQuery.css( elem, "float" ) === "none" ) {
+
+ style.display = "inline-block";
+ }
+ }
+
+ if ( opts.overflow ) {
+ style.overflow = "hidden";
+ anim.always(function() {
+ style.overflow = opts.overflow[ 0 ];
+ style.overflowX = opts.overflow[ 1 ];
+ style.overflowY = opts.overflow[ 2 ];
+ });
+ }
+
+
+ // show/hide pass
+ for ( prop in props ) {
+ value = props[ prop ];
+ if ( rfxtypes.exec( value ) ) {
+ delete props[ prop ];
+ toggle = toggle || value === "toggle";
+ if ( value === ( hidden ? "hide" : "show" ) ) {
+
+ // If there is dataShow left over from a stopped hide or show and we are going to proceed with show, we should pretend to be hidden
+ if ( value === "show" && dataShow && dataShow[ prop ] !== undefined ) {
+ hidden = true;
+ } else {
+ continue;
+ }
+ }
+ orig[ prop ] = dataShow && dataShow[ prop ] || jQuery.style( elem, prop );
+ }
+ }
+
+ if ( !jQuery.isEmptyObject( orig ) ) {
+ if ( dataShow ) {
+ if ( "hidden" in dataShow ) {
+ hidden = dataShow.hidden;
+ }
+ } else {
+ dataShow = data_priv.access( elem, "fxshow", {} );
+ }
+
+ // store state if its toggle - enables .stop().toggle() to "reverse"
+ if ( toggle ) {
+ dataShow.hidden = !hidden;
+ }
+ if ( hidden ) {
+ jQuery( elem ).show();
+ } else {
+ anim.done(function() {
+ jQuery( elem ).hide();
+ });
+ }
+ anim.done(function() {
+ var prop;
+
+ data_priv.remove( elem, "fxshow" );
+ for ( prop in orig ) {
+ jQuery.style( elem, prop, orig[ prop ] );
+ }
+ });
+ for ( prop in orig ) {
+ tween = createTween( hidden ? dataShow[ prop ] : 0, prop, anim );
+
+ if ( !( prop in dataShow ) ) {
+ dataShow[ prop ] = tween.start;
+ if ( hidden ) {
+ tween.end = tween.start;
+ tween.start = prop === "width" || prop === "height" ? 1 : 0;
+ }
+ }
+ }
+ }
+}
+
+function Tween( elem, options, prop, end, easing ) {
+ return new Tween.prototype.init( elem, options, prop, end, easing );
+}
+jQuery.Tween = Tween;
+
+Tween.prototype = {
+ constructor: Tween,
+ init: function( elem, options, prop, end, easing, unit ) {
+ this.elem = elem;
+ this.prop = prop;
+ this.easing = easing || "swing";
+ this.options = options;
+ this.start = this.now = this.cur();
+ this.end = end;
+ this.unit = unit || ( jQuery.cssNumber[ prop ] ? "" : "px" );
+ },
+ cur: function() {
+ var hooks = Tween.propHooks[ this.prop ];
+
+ return hooks && hooks.get ?
+ hooks.get( this ) :
+ Tween.propHooks._default.get( this );
+ },
+ run: function( percent ) {
+ var eased,
+ hooks = Tween.propHooks[ this.prop ];
+
+ if ( this.options.duration ) {
+ this.pos = eased = jQuery.easing[ this.easing ](
+ percent, this.options.duration * percent, 0, 1, this.options.duration
+ );
+ } else {
+ this.pos = eased = percent;
+ }
+ this.now = ( this.end - this.start ) * eased + this.start;
+
+ if ( this.options.step ) {
+ this.options.step.call( this.elem, this.now, this );
+ }
+
+ if ( hooks && hooks.set ) {
+ hooks.set( this );
+ } else {
+ Tween.propHooks._default.set( this );
+ }
+ return this;
+ }
+};
+
+Tween.prototype.init.prototype = Tween.prototype;
+
+Tween.propHooks = {
+ _default: {
+ get: function( tween ) {
+ var result;
+
+ if ( tween.elem[ tween.prop ] != null &&
+ (!tween.elem.style || tween.elem.style[ tween.prop ] == null) ) {
+ return tween.elem[ tween.prop ];
+ }
+
+ // passing an empty string as a 3rd parameter to .css will automatically
+ // attempt a parseFloat and fallback to a string if the parse fails
+ // so, simple values such as "10px" are parsed to Float.
+ // complex values such as "rotate(1rad)" are returned as is.
+ result = jQuery.css( tween.elem, tween.prop, "" );
+ // Empty strings, null, undefined and "auto" are converted to 0.
+ return !result || result === "auto" ? 0 : result;
+ },
+ set: function( tween ) {
+ // use step hook for back compat - use cssHook if its there - use .style if its
+ // available and use plain properties where available
+ if ( jQuery.fx.step[ tween.prop ] ) {
+ jQuery.fx.step[ tween.prop ]( tween );
+ } else if ( tween.elem.style && ( tween.elem.style[ jQuery.cssProps[ tween.prop ] ] != null || jQuery.cssHooks[ tween.prop ] ) ) {
+ jQuery.style( tween.elem, tween.prop, tween.now + tween.unit );
+ } else {
+ tween.elem[ tween.prop ] = tween.now;
+ }
+ }
+ }
+};
+
+// Support: IE9
+// Panic based approach to setting things on disconnected nodes
+
+Tween.propHooks.scrollTop = Tween.propHooks.scrollLeft = {
+ set: function( tween ) {
+ if ( tween.elem.nodeType && tween.elem.parentNode ) {
+ tween.elem[ tween.prop ] = tween.now;
+ }
+ }
+};
+
+jQuery.each([ "toggle", "show", "hide" ], function( i, name ) {
+ var cssFn = jQuery.fn[ name ];
+ jQuery.fn[ name ] = function( speed, easing, callback ) {
+ return speed == null || typeof speed === "boolean" ?
+ cssFn.apply( this, arguments ) :
+ this.animate( genFx( name, true ), speed, easing, callback );
+ };
+});
+
+jQuery.fn.extend({
+ fadeTo: function( speed, to, easing, callback ) {
+
+ // show any hidden elements after setting opacity to 0
+ return this.filter( isHidden ).css( "opacity", 0 ).show()
+
+ // animate to the value specified
+ .end().animate({ opacity: to }, speed, easing, callback );
+ },
+ animate: function( prop, speed, easing, callback ) {
+ var empty = jQuery.isEmptyObject( prop ),
+ optall = jQuery.speed( speed, easing, callback ),
+ doAnimation = function() {
+ // Operate on a copy of prop so per-property easing won't be lost
+ var anim = Animation( this, jQuery.extend( {}, prop ), optall );
+
+ // Empty animations, or finishing resolves immediately
+ if ( empty || data_priv.get( this, "finish" ) ) {
+ anim.stop( true );
+ }
+ };
+ doAnimation.finish = doAnimation;
+
+ return empty || optall.queue === false ?
+ this.each( doAnimation ) :
+ this.queue( optall.queue, doAnimation );
+ },
+ stop: function( type, clearQueue, gotoEnd ) {
+ var stopQueue = function( hooks ) {
+ var stop = hooks.stop;
+ delete hooks.stop;
+ stop( gotoEnd );
+ };
+
+ if ( typeof type !== "string" ) {
+ gotoEnd = clearQueue;
+ clearQueue = type;
+ type = undefined;
+ }
+ if ( clearQueue && type !== false ) {
+ this.queue( type || "fx", [] );
+ }
+
+ return this.each(function() {
+ var dequeue = true,
+ index = type != null && type + "queueHooks",
+ timers = jQuery.timers,
+ data = data_priv.get( this );
+
+ if ( index ) {
+ if ( data[ index ] && data[ index ].stop ) {
+ stopQueue( data[ index ] );
+ }
+ } else {
+ for ( index in data ) {
+ if ( data[ index ] && data[ index ].stop && rrun.test( index ) ) {
+ stopQueue( data[ index ] );
+ }
+ }
+ }
+
+ for ( index = timers.length; index--; ) {
+ if ( timers[ index ].elem === this && (type == null || timers[ index ].queue === type) ) {
+ timers[ index ].anim.stop( gotoEnd );
+ dequeue = false;
+ timers.splice( index, 1 );
+ }
+ }
+
+ // start the next in the queue if the last step wasn't forced
+ // timers currently will call their complete callbacks, which will dequeue
+ // but only if they were gotoEnd
+ if ( dequeue || !gotoEnd ) {
+ jQuery.dequeue( this, type );
+ }
+ });
+ },
+ finish: function( type ) {
+ if ( type !== false ) {
+ type = type || "fx";
+ }
+ return this.each(function() {
+ var index,
+ data = data_priv.get( this ),
+ queue = data[ type + "queue" ],
+ hooks = data[ type + "queueHooks" ],
+ timers = jQuery.timers,
+ length = queue ? queue.length : 0;
+
+ // enable finishing flag on private data
+ data.finish = true;
+
+ // empty the queue first
+ jQuery.queue( this, type, [] );
+
+ if ( hooks && hooks.stop ) {
+ hooks.stop.call( this, true );
+ }
+
+ // look for any active animations, and finish them
+ for ( index = timers.length; index--; ) {
+ if ( timers[ index ].elem === this && timers[ index ].queue === type ) {
+ timers[ index ].anim.stop( true );
+ timers.splice( index, 1 );
+ }
+ }
+
+ // look for any animations in the old queue and finish them
+ for ( index = 0; index < length; index++ ) {
+ if ( queue[ index ] && queue[ index ].finish ) {
+ queue[ index ].finish.call( this );
+ }
+ }
+
+ // turn off finishing flag
+ delete data.finish;
+ });
+ }
+});
+
+// Generate parameters to create a standard animation
+function genFx( type, includeWidth ) {
+ var which,
+ attrs = { height: type },
+ i = 0;
+
+ // if we include width, step value is 1 to do all cssExpand values,
+ // if we don't include width, step value is 2 to skip over Left and Right
+ includeWidth = includeWidth? 1 : 0;
+ for( ; i < 4 ; i += 2 - includeWidth ) {
+ which = cssExpand[ i ];
+ attrs[ "margin" + which ] = attrs[ "padding" + which ] = type;
+ }
+
+ if ( includeWidth ) {
+ attrs.opacity = attrs.width = type;
+ }
+
+ return attrs;
+}
+
+// Generate shortcuts for custom animations
+jQuery.each({
+ slideDown: genFx("show"),
+ slideUp: genFx("hide"),
+ slideToggle: genFx("toggle"),
+ fadeIn: { opacity: "show" },
+ fadeOut: { opacity: "hide" },
+ fadeToggle: { opacity: "toggle" }
+}, function( name, props ) {
+ jQuery.fn[ name ] = function( speed, easing, callback ) {
+ return this.animate( props, speed, easing, callback );
+ };
+});
+
+jQuery.speed = function( speed, easing, fn ) {
+ var opt = speed && typeof speed === "object" ? jQuery.extend( {}, speed ) : {
+ complete: fn || !fn && easing ||
+ jQuery.isFunction( speed ) && speed,
+ duration: speed,
+ easing: fn && easing || easing && !jQuery.isFunction( easing ) && easing
+ };
+
+ opt.duration = jQuery.fx.off ? 0 : typeof opt.duration === "number" ? opt.duration :
+ opt.duration in jQuery.fx.speeds ? jQuery.fx.speeds[ opt.duration ] : jQuery.fx.speeds._default;
+
+ // normalize opt.queue - true/undefined/null -> "fx"
+ if ( opt.queue == null || opt.queue === true ) {
+ opt.queue = "fx";
+ }
+
+ // Queueing
+ opt.old = opt.complete;
+
+ opt.complete = function() {
+ if ( jQuery.isFunction( opt.old ) ) {
+ opt.old.call( this );
+ }
+
+ if ( opt.queue ) {
+ jQuery.dequeue( this, opt.queue );
+ }
+ };
+
+ return opt;
+};
+
+jQuery.easing = {
+ linear: function( p ) {
+ return p;
+ },
+ swing: function( p ) {
+ return 0.5 - Math.cos( p*Math.PI ) / 2;
+ }
+};
+
+jQuery.timers = [];
+jQuery.fx = Tween.prototype.init;
+jQuery.fx.tick = function() {
+ var timer,
+ timers = jQuery.timers,
+ i = 0;
+
+ fxNow = jQuery.now();
+
+ for ( ; i < timers.length; i++ ) {
+ timer = timers[ i ];
+ // Checks the timer has not already been removed
+ if ( !timer() && timers[ i ] === timer ) {
+ timers.splice( i--, 1 );
+ }
+ }
+
+ if ( !timers.length ) {
+ jQuery.fx.stop();
+ }
+ fxNow = undefined;
+};
+
+jQuery.fx.timer = function( timer ) {
+ if ( timer() && jQuery.timers.push( timer ) ) {
+ jQuery.fx.start();
+ }
+};
+
+jQuery.fx.interval = 13;
+
+jQuery.fx.start = function() {
+ if ( !timerId ) {
+ timerId = setInterval( jQuery.fx.tick, jQuery.fx.interval );
+ }
+};
+
+jQuery.fx.stop = function() {
+ clearInterval( timerId );
+ timerId = null;
+};
+
+jQuery.fx.speeds = {
+ slow: 600,
+ fast: 200,
+ // Default speed
+ _default: 400
+};
+
+// Back Compat <1.8 extension point
+jQuery.fx.step = {};
+
+if ( jQuery.expr && jQuery.expr.filters ) {
+ jQuery.expr.filters.animated = function( elem ) {
+ return jQuery.grep(jQuery.timers, function( fn ) {
+ return elem === fn.elem;
+ }).length;
+ };
+}
+jQuery.fn.offset = function( options ) {
+ if ( arguments.length ) {
+ return options === undefined ?
+ this :
+ this.each(function( i ) {
+ jQuery.offset.setOffset( this, options, i );
+ });
+ }
+
+ var docElem, win,
+ elem = this[ 0 ],
+ box = { top: 0, left: 0 },
+ doc = elem && elem.ownerDocument;
+
+ if ( !doc ) {
+ return;
+ }
+
+ docElem = doc.documentElement;
+
+ // Make sure it's not a disconnected DOM node
+ if ( !jQuery.contains( docElem, elem ) ) {
+ return box;
+ }
+
+ // If we don't have gBCR, just use 0,0 rather than error
+ // BlackBerry 5, iOS 3 (original iPhone)
+ if ( typeof elem.getBoundingClientRect !== core_strundefined ) {
+ box = elem.getBoundingClientRect();
+ }
+ win = getWindow( doc );
+ return {
+ top: box.top + win.pageYOffset - docElem.clientTop,
+ left: box.left + win.pageXOffset - docElem.clientLeft
+ };
+};
+
+jQuery.offset = {
+
+ setOffset: function( elem, options, i ) {
+ var curPosition, curLeft, curCSSTop, curTop, curOffset, curCSSLeft, calculatePosition,
+ position = jQuery.css( elem, "position" ),
+ curElem = jQuery( elem ),
+ props = {};
+
+ // Set position first, in-case top/left are set even on static elem
+ if ( position === "static" ) {
+ elem.style.position = "relative";
+ }
+
+ curOffset = curElem.offset();
+ curCSSTop = jQuery.css( elem, "top" );
+ curCSSLeft = jQuery.css( elem, "left" );
+ calculatePosition = ( position === "absolute" || position === "fixed" ) && ( curCSSTop + curCSSLeft ).indexOf("auto") > -1;
+
+ // Need to be able to calculate position if either top or left is auto and position is either absolute or fixed
+ if ( calculatePosition ) {
+ curPosition = curElem.position();
+ curTop = curPosition.top;
+ curLeft = curPosition.left;
+
+ } else {
+ curTop = parseFloat( curCSSTop ) || 0;
+ curLeft = parseFloat( curCSSLeft ) || 0;
+ }
+
+ if ( jQuery.isFunction( options ) ) {
+ options = options.call( elem, i, curOffset );
+ }
+
+ if ( options.top != null ) {
+ props.top = ( options.top - curOffset.top ) + curTop;
+ }
+ if ( options.left != null ) {
+ props.left = ( options.left - curOffset.left ) + curLeft;
+ }
+
+ if ( "using" in options ) {
+ options.using.call( elem, props );
+
+ } else {
+ curElem.css( props );
+ }
+ }
+};
+
+
+jQuery.fn.extend({
+
+ position: function() {
+ if ( !this[ 0 ] ) {
+ return;
+ }
+
+ var offsetParent, offset,
+ elem = this[ 0 ],
+ parentOffset = { top: 0, left: 0 };
+
+ // Fixed elements are offset from window (parentOffset = {top:0, left: 0}, because it is it's only offset parent
+ if ( jQuery.css( elem, "position" ) === "fixed" ) {
+ // We assume that getBoundingClientRect is available when computed position is fixed
+ offset = elem.getBoundingClientRect();
+
+ } else {
+ // Get *real* offsetParent
+ offsetParent = this.offsetParent();
+
+ // Get correct offsets
+ offset = this.offset();
+ if ( !jQuery.nodeName( offsetParent[ 0 ], "html" ) ) {
+ parentOffset = offsetParent.offset();
+ }
+
+ // Add offsetParent borders
+ parentOffset.top += jQuery.css( offsetParent[ 0 ], "borderTopWidth", true );
+ parentOffset.left += jQuery.css( offsetParent[ 0 ], "borderLeftWidth", true );
+ }
+
+ // Subtract parent offsets and element margins
+ return {
+ top: offset.top - parentOffset.top - jQuery.css( elem, "marginTop", true ),
+ left: offset.left - parentOffset.left - jQuery.css( elem, "marginLeft", true )
+ };
+ },
+
+ offsetParent: function() {
+ return this.map(function() {
+ var offsetParent = this.offsetParent || docElem;
+
+ while ( offsetParent && ( !jQuery.nodeName( offsetParent, "html" ) && jQuery.css( offsetParent, "position") === "static" ) ) {
+ offsetParent = offsetParent.offsetParent;
+ }
+
+ return offsetParent || docElem;
+ });
+ }
+});
+
+
+// Create scrollLeft and scrollTop methods
+jQuery.each( {scrollLeft: "pageXOffset", scrollTop: "pageYOffset"}, function( method, prop ) {
+ var top = "pageYOffset" === prop;
+
+ jQuery.fn[ method ] = function( val ) {
+ return jQuery.access( this, function( elem, method, val ) {
+ var win = getWindow( elem );
+
+ if ( val === undefined ) {
+ return win ? win[ prop ] : elem[ method ];
+ }
+
+ if ( win ) {
+ win.scrollTo(
+ !top ? val : window.pageXOffset,
+ top ? val : window.pageYOffset
+ );
+
+ } else {
+ elem[ method ] = val;
+ }
+ }, method, val, arguments.length, null );
+ };
+});
+
+function getWindow( elem ) {
+ return jQuery.isWindow( elem ) ? elem : elem.nodeType === 9 && elem.defaultView;
+}
+// Create innerHeight, innerWidth, height, width, outerHeight and outerWidth methods
+jQuery.each( { Height: "height", Width: "width" }, function( name, type ) {
+ jQuery.each( { padding: "inner" + name, content: type, "": "outer" + name }, function( defaultExtra, funcName ) {
+ // margin is only for outerHeight, outerWidth
+ jQuery.fn[ funcName ] = function( margin, value ) {
+ var chainable = arguments.length && ( defaultExtra || typeof margin !== "boolean" ),
+ extra = defaultExtra || ( margin === true || value === true ? "margin" : "border" );
+
+ return jQuery.access( this, function( elem, type, value ) {
+ var doc;
+
+ if ( jQuery.isWindow( elem ) ) {
+ // As of 5/8/2012 this will yield incorrect results for Mobile Safari, but there
+ // isn't a whole lot we can do. See pull request at this URL for discussion:
+ // https://github.com/jquery/jquery/pull/764
+ return elem.document.documentElement[ "client" + name ];
+ }
+
+ // Get document width or height
+ if ( elem.nodeType === 9 ) {
+ doc = elem.documentElement;
+
+ // Either scroll[Width/Height] or offset[Width/Height] or client[Width/Height],
+ // whichever is greatest
+ return Math.max(
+ elem.body[ "scroll" + name ], doc[ "scroll" + name ],
+ elem.body[ "offset" + name ], doc[ "offset" + name ],
+ doc[ "client" + name ]
+ );
+ }
+
+ return value === undefined ?
+ // Get width or height on the element, requesting but not forcing parseFloat
+ jQuery.css( elem, type, extra ) :
+
+ // Set width or height on the element
+ jQuery.style( elem, type, value, extra );
+ }, type, chainable ? margin : undefined, chainable, null );
+ };
+ });
+});
+// Limit scope pollution from any deprecated API
+// (function() {
+
+// The number of elements contained in the matched element set
+jQuery.fn.size = function() {
+ return this.length;
+};
+
+jQuery.fn.andSelf = jQuery.fn.addBack;
+
+// })();
+if ( typeof module === "object" && module && typeof module.exports === "object" ) {
+ // Expose jQuery as module.exports in loaders that implement the Node
+ // module pattern (including browserify). Do not create the global, since
+ // the user will be storing it themselves locally, and globals are frowned
+ // upon in the Node module world.
+ module.exports = jQuery;
+} else {
+ // Register as a named AMD module, since jQuery can be concatenated with other
+ // files that may use define, but not via a proper concatenation script that
+ // understands anonymous AMD modules. A named AMD is safest and most robust
+ // way to register. Lowercase jquery is used because AMD module names are
+ // derived from file names, and jQuery is normally delivered in a lowercase
+ // file name. Do this after creating the global so that if an AMD module wants
+ // to call noConflict to hide this version of jQuery, it will work.
+ if ( typeof define === "function" && define.amd ) {
+ define( "jquery", [], function () { return jQuery; } );
+ }
+}
+
+// If there is a window object, that at least has a document property,
+// define jQuery and $ identifiers
+if ( typeof window === "object" && typeof window.document === "object" ) {
+ window.jQuery = window.$ = jQuery;
+}
+
+})( window );
diff --git a/docs/htmldoc/js/jquery-2.0.3.min.js b/docs/htmldoc/js/jquery-2.0.3.min.js
new file mode 100644
index 0000000..2be209d
--- /dev/null
+++ b/docs/htmldoc/js/jquery-2.0.3.min.js
@@ -0,0 +1,6 @@
+/*! jQuery v2.0.3 | (c) 2005, 2013 jQuery Foundation, Inc. | jquery.org/license
+//@ sourceMappingURL=jquery-2.0.3.min.map
+*/
+(function(e,undefined){var t,n,r=typeof undefined,i=e.location,o=e.document,s=o.documentElement,a=e.jQuery,u=e.$,l={},c=[],p="2.0.3",f=c.concat,h=c.push,d=c.slice,g=c.indexOf,m=l.toString,y=l.hasOwnProperty,v=p.trim,x=function(e,n){return new x.fn.init(e,n,t)},b=/[+-]?(?:\d*\.|)\d+(?:[eE][+-]?\d+|)/.source,w=/\S+/g,T=/^(?:\s*(<[\w\W]+>)[^>]*|#([\w-]*))$/,C=/^<(\w+)\s*\/?>(?:<\/\1>|)$/,k=/^-ms-/,N=/-([\da-z])/gi,E=function(e,t){return t.toUpperCase()},S=function(){o.removeEventListener("DOMContentLoaded",S,!1),e.removeEventListener("load",S,!1),x.ready()};x.fn=x.prototype={jquery:p,constructor:x,init:function(e,t,n){var r,i;if(!e)return this;if("string"==typeof e){if(r="<"===e.charAt(0)&&">"===e.charAt(e.length-1)&&e.length>=3?[null,e,null]:T.exec(e),!r||!r[1]&&t)return!t||t.jquery?(t||n).find(e):this.constructor(t).find(e);if(r[1]){if(t=t instanceof x?t[0]:t,x.merge(this,x.parseHTML(r[1],t&&t.nodeType?t.ownerDocument||t:o,!0)),C.test(r[1])&&x.isPlainObject(t))for(r in t)x.isFunction(this[r])?this[r](t[r]):this.attr(r,t[r]);return this}return i=o.getElementById(r[2]),i&&i.parentNode&&(this.length=1,this[0]=i),this.context=o,this.selector=e,this}return e.nodeType?(this.context=this[0]=e,this.length=1,this):x.isFunction(e)?n.ready(e):(e.selector!==undefined&&(this.selector=e.selector,this.context=e.context),x.makeArray(e,this))},selector:"",length:0,toArray:function(){return d.call(this)},get:function(e){return null==e?this.toArray():0>e?this[this.length+e]:this[e]},pushStack:function(e){var t=x.merge(this.constructor(),e);return t.prevObject=this,t.context=this.context,t},each:function(e,t){return x.each(this,e,t)},ready:function(e){return x.ready.promise().done(e),this},slice:function(){return this.pushStack(d.apply(this,arguments))},first:function(){return this.eq(0)},last:function(){return this.eq(-1)},eq:function(e){var t=this.length,n=+e+(0>e?t:0);return this.pushStack(n>=0&&t>n?[this[n]]:[])},map:function(e){return this.pushStack(x.map(this,function(t,n){return e.call(t,n,t)}))},end:function(){return this.prevObject||this.constructor(null)},push:h,sort:[].sort,splice:[].splice},x.fn.init.prototype=x.fn,x.extend=x.fn.extend=function(){var e,t,n,r,i,o,s=arguments[0]||{},a=1,u=arguments.length,l=!1;for("boolean"==typeof s&&(l=s,s=arguments[1]||{},a=2),"object"==typeof s||x.isFunction(s)||(s={}),u===a&&(s=this,--a);u>a;a++)if(null!=(e=arguments[a]))for(t in e)n=s[t],r=e[t],s!==r&&(l&&r&&(x.isPlainObject(r)||(i=x.isArray(r)))?(i?(i=!1,o=n&&x.isArray(n)?n:[]):o=n&&x.isPlainObject(n)?n:{},s[t]=x.extend(l,o,r)):r!==undefined&&(s[t]=r));return s},x.extend({expando:"jQuery"+(p+Math.random()).replace(/\D/g,""),noConflict:function(t){return e.$===x&&(e.$=u),t&&e.jQuery===x&&(e.jQuery=a),x},isReady:!1,readyWait:1,holdReady:function(e){e?x.readyWait++:x.ready(!0)},ready:function(e){(e===!0?--x.readyWait:x.isReady)||(x.isReady=!0,e!==!0&&--x.readyWait>0||(n.resolveWith(o,[x]),x.fn.trigger&&x(o).trigger("ready").off("ready")))},isFunction:function(e){return"function"===x.type(e)},isArray:Array.isArray,isWindow:function(e){return null!=e&&e===e.window},isNumeric:function(e){return!isNaN(parseFloat(e))&&isFinite(e)},type:function(e){return null==e?e+"":"object"==typeof e||"function"==typeof e?l[m.call(e)]||"object":typeof e},isPlainObject:function(e){if("object"!==x.type(e)||e.nodeType||x.isWindow(e))return!1;try{if(e.constructor&&!y.call(e.constructor.prototype,"isPrototypeOf"))return!1}catch(t){return!1}return!0},isEmptyObject:function(e){var t;for(t in e)return!1;return!0},error:function(e){throw Error(e)},parseHTML:function(e,t,n){if(!e||"string"!=typeof e)return null;"boolean"==typeof t&&(n=t,t=!1),t=t||o;var r=C.exec(e),i=!n&&[];return r?[t.createElement(r[1])]:(r=x.buildFragment([e],t,i),i&&x(i).remove(),x.merge([],r.childNodes))},parseJSON:JSON.parse,parseXML:function(e){var t,n;if(!e||"string"!=typeof e)return null;try{n=new DOMParser,t=n.parseFromString(e,"text/xml")}catch(r){t=undefined}return(!t||t.getElementsByTagName("parsererror").length)&&x.error("Invalid XML: "+e),t},noop:function(){},globalEval:function(e){var t,n=eval;e=x.trim(e),e&&(1===e.indexOf("use strict")?(t=o.createElement("script"),t.text=e,o.head.appendChild(t).parentNode.removeChild(t)):n(e))},camelCase:function(e){return e.replace(k,"ms-").replace(N,E)},nodeName:function(e,t){return e.nodeName&&e.nodeName.toLowerCase()===t.toLowerCase()},each:function(e,t,n){var r,i=0,o=e.length,s=j(e);if(n){if(s){for(;o>i;i++)if(r=t.apply(e[i],n),r===!1)break}else for(i in e)if(r=t.apply(e[i],n),r===!1)break}else if(s){for(;o>i;i++)if(r=t.call(e[i],i,e[i]),r===!1)break}else for(i in e)if(r=t.call(e[i],i,e[i]),r===!1)break;return e},trim:function(e){return null==e?"":v.call(e)},makeArray:function(e,t){var n=t||[];return null!=e&&(j(Object(e))?x.merge(n,"string"==typeof e?[e]:e):h.call(n,e)),n},inArray:function(e,t,n){return null==t?-1:g.call(t,e,n)},merge:function(e,t){var n=t.length,r=e.length,i=0;if("number"==typeof n)for(;n>i;i++)e[r++]=t[i];else while(t[i]!==undefined)e[r++]=t[i++];return e.length=r,e},grep:function(e,t,n){var r,i=[],o=0,s=e.length;for(n=!!n;s>o;o++)r=!!t(e[o],o),n!==r&&i.push(e[o]);return i},map:function(e,t,n){var r,i=0,o=e.length,s=j(e),a=[];if(s)for(;o>i;i++)r=t(e[i],i,n),null!=r&&(a[a.length]=r);else for(i in e)r=t(e[i],i,n),null!=r&&(a[a.length]=r);return f.apply([],a)},guid:1,proxy:function(e,t){var n,r,i;return"string"==typeof t&&(n=e[t],t=e,e=n),x.isFunction(e)?(r=d.call(arguments,2),i=function(){return e.apply(t||this,r.concat(d.call(arguments)))},i.guid=e.guid=e.guid||x.guid++,i):undefined},access:function(e,t,n,r,i,o,s){var a=0,u=e.length,l=null==n;if("object"===x.type(n)){i=!0;for(a in n)x.access(e,t,a,n[a],!0,o,s)}else if(r!==undefined&&(i=!0,x.isFunction(r)||(s=!0),l&&(s?(t.call(e,r),t=null):(l=t,t=function(e,t,n){return l.call(x(e),n)})),t))for(;u>a;a++)t(e[a],n,s?r:r.call(e[a],a,t(e[a],n)));return i?e:l?t.call(e):u?t(e[0],n):o},now:Date.now,swap:function(e,t,n,r){var i,o,s={};for(o in t)s[o]=e.style[o],e.style[o]=t[o];i=n.apply(e,r||[]);for(o in t)e.style[o]=s[o];return i}}),x.ready.promise=function(t){return n||(n=x.Deferred(),"complete"===o.readyState?setTimeout(x.ready):(o.addEventListener("DOMContentLoaded",S,!1),e.addEventListener("load",S,!1))),n.promise(t)},x.each("Boolean Number String Function Array Date RegExp Object Error".split(" "),function(e,t){l["[object "+t+"]"]=t.toLowerCase()});function j(e){var t=e.length,n=x.type(e);return x.isWindow(e)?!1:1===e.nodeType&&t?!0:"array"===n||"function"!==n&&(0===t||"number"==typeof t&&t>0&&t-1 in e)}t=x(o),function(e,undefined){var t,n,r,i,o,s,a,u,l,c,p,f,h,d,g,m,y,v="sizzle"+-new Date,b=e.document,w=0,T=0,C=st(),k=st(),N=st(),E=!1,S=function(e,t){return e===t?(E=!0,0):0},j=typeof undefined,D=1<<31,A={}.hasOwnProperty,L=[],q=L.pop,H=L.push,O=L.push,F=L.slice,P=L.indexOf||function(e){var t=0,n=this.length;for(;n>t;t++)if(this[t]===e)return t;return-1},R="checked|selected|async|autofocus|autoplay|controls|defer|disabled|hidden|ismap|loop|multiple|open|readonly|required|scoped",M="[\\x20\\t\\r\\n\\f]",W="(?:\\\\.|[\\w-]|[^\\x00-\\xa0])+",$=W.replace("w","w#"),B="\\["+M+"*("+W+")"+M+"*(?:([*^$|!~]?=)"+M+"*(?:(['\"])((?:\\\\.|[^\\\\])*?)\\3|("+$+")|)|)"+M+"*\\]",I=":("+W+")(?:\\(((['\"])((?:\\\\.|[^\\\\])*?)\\3|((?:\\\\.|[^\\\\()[\\]]|"+B.replace(3,8)+")*)|.*)\\)|)",z=RegExp("^"+M+"+|((?:^|[^\\\\])(?:\\\\.)*)"+M+"+$","g"),_=RegExp("^"+M+"*,"+M+"*"),X=RegExp("^"+M+"*([>+~]|"+M+")"+M+"*"),U=RegExp(M+"*[+~]"),Y=RegExp("="+M+"*([^\\]'\"]*)"+M+"*\\]","g"),V=RegExp(I),G=RegExp("^"+$+"$"),J={ID:RegExp("^#("+W+")"),CLASS:RegExp("^\\.("+W+")"),TAG:RegExp("^("+W.replace("w","w*")+")"),ATTR:RegExp("^"+B),PSEUDO:RegExp("^"+I),CHILD:RegExp("^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\("+M+"*(even|odd|(([+-]|)(\\d*)n|)"+M+"*(?:([+-]|)"+M+"*(\\d+)|))"+M+"*\\)|)","i"),bool:RegExp("^(?:"+R+")$","i"),needsContext:RegExp("^"+M+"*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\("+M+"*((?:-\\d)?\\d*)"+M+"*\\)|)(?=[^-]|$)","i")},Q=/^[^{]+\{\s*\[native \w/,K=/^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/,Z=/^(?:input|select|textarea|button)$/i,et=/^h\d$/i,tt=/'|\\/g,nt=RegExp("\\\\([\\da-f]{1,6}"+M+"?|("+M+")|.)","ig"),rt=function(e,t,n){var r="0x"+t-65536;return r!==r||n?t:0>r?String.fromCharCode(r+65536):String.fromCharCode(55296|r>>10,56320|1023&r)};try{O.apply(L=F.call(b.childNodes),b.childNodes),L[b.childNodes.length].nodeType}catch(it){O={apply:L.length?function(e,t){H.apply(e,F.call(t))}:function(e,t){var n=e.length,r=0;while(e[n++]=t[r++]);e.length=n-1}}}function ot(e,t,r,i){var o,s,a,u,l,f,g,m,x,w;if((t?t.ownerDocument||t:b)!==p&&c(t),t=t||p,r=r||[],!e||"string"!=typeof e)return r;if(1!==(u=t.nodeType)&&9!==u)return[];if(h&&!i){if(o=K.exec(e))if(a=o[1]){if(9===u){if(s=t.getElementById(a),!s||!s.parentNode)return r;if(s.id===a)return r.push(s),r}else if(t.ownerDocument&&(s=t.ownerDocument.getElementById(a))&&y(t,s)&&s.id===a)return r.push(s),r}else{if(o[2])return O.apply(r,t.getElementsByTagName(e)),r;if((a=o[3])&&n.getElementsByClassName&&t.getElementsByClassName)return O.apply(r,t.getElementsByClassName(a)),r}if(n.qsa&&(!d||!d.test(e))){if(m=g=v,x=t,w=9===u&&e,1===u&&"object"!==t.nodeName.toLowerCase()){f=gt(e),(g=t.getAttribute("id"))?m=g.replace(tt,"\\$&"):t.setAttribute("id",m),m="[id='"+m+"'] ",l=f.length;while(l--)f[l]=m+mt(f[l]);x=U.test(e)&&t.parentNode||t,w=f.join(",")}if(w)try{return O.apply(r,x.querySelectorAll(w)),r}catch(T){}finally{g||t.removeAttribute("id")}}}return kt(e.replace(z,"$1"),t,r,i)}function st(){var e=[];function t(n,r){return e.push(n+=" ")>i.cacheLength&&delete t[e.shift()],t[n]=r}return t}function at(e){return e[v]=!0,e}function ut(e){var t=p.createElement("div");try{return!!e(t)}catch(n){return!1}finally{t.parentNode&&t.parentNode.removeChild(t),t=null}}function lt(e,t){var n=e.split("|"),r=e.length;while(r--)i.attrHandle[n[r]]=t}function ct(e,t){var n=t&&e,r=n&&1===e.nodeType&&1===t.nodeType&&(~t.sourceIndex||D)-(~e.sourceIndex||D);if(r)return r;if(n)while(n=n.nextSibling)if(n===t)return-1;return e?1:-1}function pt(e){return function(t){var n=t.nodeName.toLowerCase();return"input"===n&&t.type===e}}function ft(e){return function(t){var n=t.nodeName.toLowerCase();return("input"===n||"button"===n)&&t.type===e}}function ht(e){return at(function(t){return t=+t,at(function(n,r){var i,o=e([],n.length,t),s=o.length;while(s--)n[i=o[s]]&&(n[i]=!(r[i]=n[i]))})})}s=ot.isXML=function(e){var t=e&&(e.ownerDocument||e).documentElement;return t?"HTML"!==t.nodeName:!1},n=ot.support={},c=ot.setDocument=function(e){var t=e?e.ownerDocument||e:b,r=t.defaultView;return t!==p&&9===t.nodeType&&t.documentElement?(p=t,f=t.documentElement,h=!s(t),r&&r.attachEvent&&r!==r.top&&r.attachEvent("onbeforeunload",function(){c()}),n.attributes=ut(function(e){return e.className="i",!e.getAttribute("className")}),n.getElementsByTagName=ut(function(e){return e.appendChild(t.createComment("")),!e.getElementsByTagName("*").length}),n.getElementsByClassName=ut(function(e){return e.innerHTML="<div class='a'></div><div class='a i'></div>",e.firstChild.className="i",2===e.getElementsByClassName("i").length}),n.getById=ut(function(e){return f.appendChild(e).id=v,!t.getElementsByName||!t.getElementsByName(v).length}),n.getById?(i.find.ID=function(e,t){if(typeof t.getElementById!==j&&h){var n=t.getElementById(e);return n&&n.parentNode?[n]:[]}},i.filter.ID=function(e){var t=e.replace(nt,rt);return function(e){return e.getAttribute("id")===t}}):(delete i.find.ID,i.filter.ID=function(e){var t=e.replace(nt,rt);return function(e){var n=typeof e.getAttributeNode!==j&&e.getAttributeNode("id");return n&&n.value===t}}),i.find.TAG=n.getElementsByTagName?function(e,t){return typeof t.getElementsByTagName!==j?t.getElementsByTagName(e):undefined}:function(e,t){var n,r=[],i=0,o=t.getElementsByTagName(e);if("*"===e){while(n=o[i++])1===n.nodeType&&r.push(n);return r}return o},i.find.CLASS=n.getElementsByClassName&&function(e,t){return typeof t.getElementsByClassName!==j&&h?t.getElementsByClassName(e):undefined},g=[],d=[],(n.qsa=Q.test(t.querySelectorAll))&&(ut(function(e){e.innerHTML="<select><option selected=''></option></select>",e.querySelectorAll("[selected]").length||d.push("\\["+M+"*(?:value|"+R+")"),e.querySelectorAll(":checked").length||d.push(":checked")}),ut(function(e){var n=t.createElement("input");n.setAttribute("type","hidden"),e.appendChild(n).setAttribute("t",""),e.querySelectorAll("[t^='']").length&&d.push("[*^$]="+M+"*(?:''|\"\")"),e.querySelectorAll(":enabled").length||d.push(":enabled",":disabled"),e.querySelectorAll("*,:x"),d.push(",.*:")})),(n.matchesSelector=Q.test(m=f.webkitMatchesSelector||f.mozMatchesSelector||f.oMatchesSelector||f.msMatchesSelector))&&ut(function(e){n.disconnectedMatch=m.call(e,"div"),m.call(e,"[s!='']:x"),g.push("!=",I)}),d=d.length&&RegExp(d.join("|")),g=g.length&&RegExp(g.join("|")),y=Q.test(f.contains)||f.compareDocumentPosition?function(e,t){var n=9===e.nodeType?e.documentElement:e,r=t&&t.parentNode;return e===r||!(!r||1!==r.nodeType||!(n.contains?n.contains(r):e.compareDocumentPosition&&16&e.compareDocumentPosition(r)))}:function(e,t){if(t)while(t=t.parentNode)if(t===e)return!0;return!1},S=f.compareDocumentPosition?function(e,r){if(e===r)return E=!0,0;var i=r.compareDocumentPosition&&e.compareDocumentPosition&&e.compareDocumentPosition(r);return i?1&i||!n.sortDetached&&r.compareDocumentPosition(e)===i?e===t||y(b,e)?-1:r===t||y(b,r)?1:l?P.call(l,e)-P.call(l,r):0:4&i?-1:1:e.compareDocumentPosition?-1:1}:function(e,n){var r,i=0,o=e.parentNode,s=n.parentNode,a=[e],u=[n];if(e===n)return E=!0,0;if(!o||!s)return e===t?-1:n===t?1:o?-1:s?1:l?P.call(l,e)-P.call(l,n):0;if(o===s)return ct(e,n);r=e;while(r=r.parentNode)a.unshift(r);r=n;while(r=r.parentNode)u.unshift(r);while(a[i]===u[i])i++;return i?ct(a[i],u[i]):a[i]===b?-1:u[i]===b?1:0},t):p},ot.matches=function(e,t){return ot(e,null,null,t)},ot.matchesSelector=function(e,t){if((e.ownerDocument||e)!==p&&c(e),t=t.replace(Y,"='$1']"),!(!n.matchesSelector||!h||g&&g.test(t)||d&&d.test(t)))try{var r=m.call(e,t);if(r||n.disconnectedMatch||e.document&&11!==e.document.nodeType)return r}catch(i){}return ot(t,p,null,[e]).length>0},ot.contains=function(e,t){return(e.ownerDocument||e)!==p&&c(e),y(e,t)},ot.attr=function(e,t){(e.ownerDocument||e)!==p&&c(e);var r=i.attrHandle[t.toLowerCase()],o=r&&A.call(i.attrHandle,t.toLowerCase())?r(e,t,!h):undefined;return o===undefined?n.attributes||!h?e.getAttribute(t):(o=e.getAttributeNode(t))&&o.specified?o.value:null:o},ot.error=function(e){throw Error("Syntax error, unrecognized expression: "+e)},ot.uniqueSort=function(e){var t,r=[],i=0,o=0;if(E=!n.detectDuplicates,l=!n.sortStable&&e.slice(0),e.sort(S),E){while(t=e[o++])t===e[o]&&(i=r.push(o));while(i--)e.splice(r[i],1)}return e},o=ot.getText=function(e){var t,n="",r=0,i=e.nodeType;if(i){if(1===i||9===i||11===i){if("string"==typeof e.textContent)return e.textContent;for(e=e.firstChild;e;e=e.nextSibling)n+=o(e)}else if(3===i||4===i)return e.nodeValue}else for(;t=e[r];r++)n+=o(t);return n},i=ot.selectors={cacheLength:50,createPseudo:at,match:J,attrHandle:{},find:{},relative:{">":{dir:"parentNode",first:!0}," ":{dir:"parentNode"},"+":{dir:"previousSibling",first:!0},"~":{dir:"previousSibling"}},preFilter:{ATTR:function(e){return e[1]=e[1].replace(nt,rt),e[3]=(e[4]||e[5]||"").replace(nt,rt),"~="===e[2]&&(e[3]=" "+e[3]+" "),e.slice(0,4)},CHILD:function(e){return e[1]=e[1].toLowerCase(),"nth"===e[1].slice(0,3)?(e[3]||ot.error(e[0]),e[4]=+(e[4]?e[5]+(e[6]||1):2*("even"===e[3]||"odd"===e[3])),e[5]=+(e[7]+e[8]||"odd"===e[3])):e[3]&&ot.error(e[0]),e},PSEUDO:function(e){var t,n=!e[5]&&e[2];return J.CHILD.test(e[0])?null:(e[3]&&e[4]!==undefined?e[2]=e[4]:n&&V.test(n)&&(t=gt(n,!0))&&(t=n.indexOf(")",n.length-t)-n.length)&&(e[0]=e[0].slice(0,t),e[2]=n.slice(0,t)),e.slice(0,3))}},filter:{TAG:function(e){var t=e.replace(nt,rt).toLowerCase();return"*"===e?function(){return!0}:function(e){return e.nodeName&&e.nodeName.toLowerCase()===t}},CLASS:function(e){var t=C[e+" "];return t||(t=RegExp("(^|"+M+")"+e+"("+M+"|$)"))&&C(e,function(e){return t.test("string"==typeof e.className&&e.className||typeof e.getAttribute!==j&&e.getAttribute("class")||"")})},ATTR:function(e,t,n){return function(r){var i=ot.attr(r,e);return null==i?"!="===t:t?(i+="","="===t?i===n:"!="===t?i!==n:"^="===t?n&&0===i.indexOf(n):"*="===t?n&&i.indexOf(n)>-1:"$="===t?n&&i.slice(-n.length)===n:"~="===t?(" "+i+" ").indexOf(n)>-1:"|="===t?i===n||i.slice(0,n.length+1)===n+"-":!1):!0}},CHILD:function(e,t,n,r,i){var o="nth"!==e.slice(0,3),s="last"!==e.slice(-4),a="of-type"===t;return 1===r&&0===i?function(e){return!!e.parentNode}:function(t,n,u){var l,c,p,f,h,d,g=o!==s?"nextSibling":"previousSibling",m=t.parentNode,y=a&&t.nodeName.toLowerCase(),x=!u&&!a;if(m){if(o){while(g){p=t;while(p=p[g])if(a?p.nodeName.toLowerCase()===y:1===p.nodeType)return!1;d=g="only"===e&&!d&&"nextSibling"}return!0}if(d=[s?m.firstChild:m.lastChild],s&&x){c=m[v]||(m[v]={}),l=c[e]||[],h=l[0]===w&&l[1],f=l[0]===w&&l[2],p=h&&m.childNodes[h];while(p=++h&&p&&p[g]||(f=h=0)||d.pop())if(1===p.nodeType&&++f&&p===t){c[e]=[w,h,f];break}}else if(x&&(l=(t[v]||(t[v]={}))[e])&&l[0]===w)f=l[1];else while(p=++h&&p&&p[g]||(f=h=0)||d.pop())if((a?p.nodeName.toLowerCase()===y:1===p.nodeType)&&++f&&(x&&((p[v]||(p[v]={}))[e]=[w,f]),p===t))break;return f-=i,f===r||0===f%r&&f/r>=0}}},PSEUDO:function(e,t){var n,r=i.pseudos[e]||i.setFilters[e.toLowerCase()]||ot.error("unsupported pseudo: "+e);return r[v]?r(t):r.length>1?(n=[e,e,"",t],i.setFilters.hasOwnProperty(e.toLowerCase())?at(function(e,n){var i,o=r(e,t),s=o.length;while(s--)i=P.call(e,o[s]),e[i]=!(n[i]=o[s])}):function(e){return r(e,0,n)}):r}},pseudos:{not:at(function(e){var t=[],n=[],r=a(e.replace(z,"$1"));return r[v]?at(function(e,t,n,i){var o,s=r(e,null,i,[]),a=e.length;while(a--)(o=s[a])&&(e[a]=!(t[a]=o))}):function(e,i,o){return t[0]=e,r(t,null,o,n),!n.pop()}}),has:at(function(e){return function(t){return ot(e,t).length>0}}),contains:at(function(e){return function(t){return(t.textContent||t.innerText||o(t)).indexOf(e)>-1}}),lang:at(function(e){return G.test(e||"")||ot.error("unsupported lang: "+e),e=e.replace(nt,rt).toLowerCase(),function(t){var n;do if(n=h?t.lang:t.getAttribute("xml:lang")||t.getAttribute("lang"))return n=n.toLowerCase(),n===e||0===n.indexOf(e+"-");while((t=t.parentNode)&&1===t.nodeType);return!1}}),target:function(t){var n=e.location&&e.location.hash;return n&&n.slice(1)===t.id},root:function(e){return e===f},focus:function(e){return e===p.activeElement&&(!p.hasFocus||p.hasFocus())&&!!(e.type||e.href||~e.tabIndex)},enabled:function(e){return e.disabled===!1},disabled:function(e){return e.disabled===!0},checked:function(e){var t=e.nodeName.toLowerCase();return"input"===t&&!!e.checked||"option"===t&&!!e.selected},selected:function(e){return e.parentNode&&e.parentNode.selectedIndex,e.selected===!0},empty:function(e){for(e=e.firstChild;e;e=e.nextSibling)if(e.nodeName>"@"||3===e.nodeType||4===e.nodeType)return!1;return!0},parent:function(e){return!i.pseudos.empty(e)},header:function(e){return et.test(e.nodeName)},input:function(e){return Z.test(e.nodeName)},button:function(e){var t=e.nodeName.toLowerCase();return"input"===t&&"button"===e.type||"button"===t},text:function(e){var t;return"input"===e.nodeName.toLowerCase()&&"text"===e.type&&(null==(t=e.getAttribute("type"))||t.toLowerCase()===e.type)},first:ht(function(){return[0]}),last:ht(function(e,t){return[t-1]}),eq:ht(function(e,t,n){return[0>n?n+t:n]}),even:ht(function(e,t){var n=0;for(;t>n;n+=2)e.push(n);return e}),odd:ht(function(e,t){var n=1;for(;t>n;n+=2)e.push(n);return e}),lt:ht(function(e,t,n){var r=0>n?n+t:n;for(;--r>=0;)e.push(r);return e}),gt:ht(function(e,t,n){var r=0>n?n+t:n;for(;t>++r;)e.push(r);return e})}},i.pseudos.nth=i.pseudos.eq;for(t in{radio:!0,checkbox:!0,file:!0,password:!0,image:!0})i.pseudos[t]=pt(t);for(t in{submit:!0,reset:!0})i.pseudos[t]=ft(t);function dt(){}dt.prototype=i.filters=i.pseudos,i.setFilters=new dt;function gt(e,t){var n,r,o,s,a,u,l,c=k[e+" "];if(c)return t?0:c.slice(0);a=e,u=[],l=i.preFilter;while(a){(!n||(r=_.exec(a)))&&(r&&(a=a.slice(r[0].length)||a),u.push(o=[])),n=!1,(r=X.exec(a))&&(n=r.shift(),o.push({value:n,type:r[0].replace(z," ")}),a=a.slice(n.length));for(s in i.filter)!(r=J[s].exec(a))||l[s]&&!(r=l[s](r))||(n=r.shift(),o.push({value:n,type:s,matches:r}),a=a.slice(n.length));if(!n)break}return t?a.length:a?ot.error(e):k(e,u).slice(0)}function mt(e){var t=0,n=e.length,r="";for(;n>t;t++)r+=e[t].value;return r}function yt(e,t,n){var i=t.dir,o=n&&"parentNode"===i,s=T++;return t.first?function(t,n,r){while(t=t[i])if(1===t.nodeType||o)return e(t,n,r)}:function(t,n,a){var u,l,c,p=w+" "+s;if(a){while(t=t[i])if((1===t.nodeType||o)&&e(t,n,a))return!0}else while(t=t[i])if(1===t.nodeType||o)if(c=t[v]||(t[v]={}),(l=c[i])&&l[0]===p){if((u=l[1])===!0||u===r)return u===!0}else if(l=c[i]=[p],l[1]=e(t,n,a)||r,l[1]===!0)return!0}}function vt(e){return e.length>1?function(t,n,r){var i=e.length;while(i--)if(!e[i](t,n,r))return!1;return!0}:e[0]}function xt(e,t,n,r,i){var o,s=[],a=0,u=e.length,l=null!=t;for(;u>a;a++)(o=e[a])&&(!n||n(o,r,i))&&(s.push(o),l&&t.push(a));return s}function bt(e,t,n,r,i,o){return r&&!r[v]&&(r=bt(r)),i&&!i[v]&&(i=bt(i,o)),at(function(o,s,a,u){var l,c,p,f=[],h=[],d=s.length,g=o||Ct(t||"*",a.nodeType?[a]:a,[]),m=!e||!o&&t?g:xt(g,f,e,a,u),y=n?i||(o?e:d||r)?[]:s:m;if(n&&n(m,y,a,u),r){l=xt(y,h),r(l,[],a,u),c=l.length;while(c--)(p=l[c])&&(y[h[c]]=!(m[h[c]]=p))}if(o){if(i||e){if(i){l=[],c=y.length;while(c--)(p=y[c])&&l.push(m[c]=p);i(null,y=[],l,u)}c=y.length;while(c--)(p=y[c])&&(l=i?P.call(o,p):f[c])>-1&&(o[l]=!(s[l]=p))}}else y=xt(y===s?y.splice(d,y.length):y),i?i(null,s,y,u):O.apply(s,y)})}function wt(e){var t,n,r,o=e.length,s=i.relative[e[0].type],a=s||i.relative[" "],l=s?1:0,c=yt(function(e){return e===t},a,!0),p=yt(function(e){return P.call(t,e)>-1},a,!0),f=[function(e,n,r){return!s&&(r||n!==u)||((t=n).nodeType?c(e,n,r):p(e,n,r))}];for(;o>l;l++)if(n=i.relative[e[l].type])f=[yt(vt(f),n)];else{if(n=i.filter[e[l].type].apply(null,e[l].matches),n[v]){for(r=++l;o>r;r++)if(i.relative[e[r].type])break;return bt(l>1&&vt(f),l>1&&mt(e.slice(0,l-1).concat({value:" "===e[l-2].type?"*":""})).replace(z,"$1"),n,r>l&&wt(e.slice(l,r)),o>r&&wt(e=e.slice(r)),o>r&&mt(e))}f.push(n)}return vt(f)}function Tt(e,t){var n=0,o=t.length>0,s=e.length>0,a=function(a,l,c,f,h){var d,g,m,y=[],v=0,x="0",b=a&&[],T=null!=h,C=u,k=a||s&&i.find.TAG("*",h&&l.parentNode||l),N=w+=null==C?1:Math.random()||.1;for(T&&(u=l!==p&&l,r=n);null!=(d=k[x]);x++){if(s&&d){g=0;while(m=e[g++])if(m(d,l,c)){f.push(d);break}T&&(w=N,r=++n)}o&&((d=!m&&d)&&v--,a&&b.push(d))}if(v+=x,o&&x!==v){g=0;while(m=t[g++])m(b,y,l,c);if(a){if(v>0)while(x--)b[x]||y[x]||(y[x]=q.call(f));y=xt(y)}O.apply(f,y),T&&!a&&y.length>0&&v+t.length>1&&ot.uniqueSort(f)}return T&&(w=N,u=C),b};return o?at(a):a}a=ot.compile=function(e,t){var n,r=[],i=[],o=N[e+" "];if(!o){t||(t=gt(e)),n=t.length;while(n--)o=wt(t[n]),o[v]?r.push(o):i.push(o);o=N(e,Tt(i,r))}return o};function Ct(e,t,n){var r=0,i=t.length;for(;i>r;r++)ot(e,t[r],n);return n}function kt(e,t,r,o){var s,u,l,c,p,f=gt(e);if(!o&&1===f.length){if(u=f[0]=f[0].slice(0),u.length>2&&"ID"===(l=u[0]).type&&n.getById&&9===t.nodeType&&h&&i.relative[u[1].type]){if(t=(i.find.ID(l.matches[0].replace(nt,rt),t)||[])[0],!t)return r;e=e.slice(u.shift().value.length)}s=J.needsContext.test(e)?0:u.length;while(s--){if(l=u[s],i.relative[c=l.type])break;if((p=i.find[c])&&(o=p(l.matches[0].replace(nt,rt),U.test(u[0].type)&&t.parentNode||t))){if(u.splice(s,1),e=o.length&&mt(u),!e)return O.apply(r,o),r;break}}}return a(e,f)(o,t,!h,r,U.test(e)),r}n.sortStable=v.split("").sort(S).join("")===v,n.detectDuplicates=E,c(),n.sortDetached=ut(function(e){return 1&e.compareDocumentPosition(p.createElement("div"))}),ut(function(e){return e.innerHTML="<a href='#'></a>","#"===e.firstChild.getAttribute("href")})||lt("type|href|height|width",function(e,t,n){return n?undefined:e.getAttribute(t,"type"===t.toLowerCase()?1:2)}),n.attributes&&ut(function(e){return e.innerHTML="<input/>",e.firstChild.setAttribute("value",""),""===e.firstChild.getAttribute("value")})||lt("value",function(e,t,n){return n||"input"!==e.nodeName.toLowerCase()?undefined:e.defaultValue}),ut(function(e){return null==e.getAttribute("disabled")})||lt(R,function(e,t,n){var r;return n?undefined:(r=e.getAttributeNode(t))&&r.specified?r.value:e[t]===!0?t.toLowerCase():null}),x.find=ot,x.expr=ot.selectors,x.expr[":"]=x.expr.pseudos,x.unique=ot.uniqueSort,x.text=ot.getText,x.isXMLDoc=ot.isXML,x.contains=ot.contains}(e);var D={};function A(e){var t=D[e]={};return x.each(e.match(w)||[],function(e,n){t[n]=!0}),t}x.Callbacks=function(e){e="string"==typeof e?D[e]||A(e):x.extend({},e);var t,n,r,i,o,s,a=[],u=!e.once&&[],l=function(p){for(t=e.memory&&p,n=!0,s=i||0,i=0,o=a.length,r=!0;a&&o>s;s++)if(a[s].apply(p[0],p[1])===!1&&e.stopOnFalse){t=!1;break}r=!1,a&&(u?u.length&&l(u.shift()):t?a=[]:c.disable())},c={add:function(){if(a){var n=a.length;(function s(t){x.each(t,function(t,n){var r=x.type(n);"function"===r?e.unique&&c.has(n)||a.push(n):n&&n.length&&"string"!==r&&s(n)})})(arguments),r?o=a.length:t&&(i=n,l(t))}return this},remove:function(){return a&&x.each(arguments,function(e,t){var n;while((n=x.inArray(t,a,n))>-1)a.splice(n,1),r&&(o>=n&&o--,s>=n&&s--)}),this},has:function(e){return e?x.inArray(e,a)>-1:!(!a||!a.length)},empty:function(){return a=[],o=0,this},disable:function(){return a=u=t=undefined,this},disabled:function(){return!a},lock:function(){return u=undefined,t||c.disable(),this},locked:function(){return!u},fireWith:function(e,t){return!a||n&&!u||(t=t||[],t=[e,t.slice?t.slice():t],r?u.push(t):l(t)),this},fire:function(){return c.fireWith(this,arguments),this},fired:function(){return!!n}};return c},x.extend({Deferred:function(e){var t=[["resolve","done",x.Callbacks("once memory"),"resolved"],["reject","fail",x.Callbacks("once memory"),"rejected"],["notify","progress",x.Callbacks("memory")]],n="pending",r={state:function(){return n},always:function(){return i.done(arguments).fail(arguments),this},then:function(){var e=arguments;return x.Deferred(function(n){x.each(t,function(t,o){var s=o[0],a=x.isFunction(e[t])&&e[t];i[o[1]](function(){var e=a&&a.apply(this,arguments);e&&x.isFunction(e.promise)?e.promise().done(n.resolve).fail(n.reject).progress(n.notify):n[s+"With"](this===r?n.promise():this,a?[e]:arguments)})}),e=null}).promise()},promise:function(e){return null!=e?x.extend(e,r):r}},i={};return r.pipe=r.then,x.each(t,function(e,o){var s=o[2],a=o[3];r[o[1]]=s.add,a&&s.add(function(){n=a},t[1^e][2].disable,t[2][2].lock),i[o[0]]=function(){return i[o[0]+"With"](this===i?r:this,arguments),this},i[o[0]+"With"]=s.fireWith}),r.promise(i),e&&e.call(i,i),i},when:function(e){var t=0,n=d.call(arguments),r=n.length,i=1!==r||e&&x.isFunction(e.promise)?r:0,o=1===i?e:x.Deferred(),s=function(e,t,n){return function(r){t[e]=this,n[e]=arguments.length>1?d.call(arguments):r,n===a?o.notifyWith(t,n):--i||o.resolveWith(t,n)}},a,u,l;if(r>1)for(a=Array(r),u=Array(r),l=Array(r);r>t;t++)n[t]&&x.isFunction(n[t].promise)?n[t].promise().done(s(t,l,n)).fail(o.reject).progress(s(t,u,a)):--i;return i||o.resolveWith(l,n),o.promise()}}),x.support=function(t){var n=o.createElement("input"),r=o.createDocumentFragment(),i=o.createElement("div"),s=o.createElement("select"),a=s.appendChild(o.createElement("option"));return n.type?(n.type="checkbox",t.checkOn=""!==n.value,t.optSelected=a.selected,t.reliableMarginRight=!0,t.boxSizingReliable=!0,t.pixelPosition=!1,n.checked=!0,t.noCloneChecked=n.cloneNode(!0).checked,s.disabled=!0,t.optDisabled=!a.disabled,n=o.createElement("input"),n.value="t",n.type="radio",t.radioValue="t"===n.value,n.setAttribute("checked","t"),n.setAttribute("name","t"),r.appendChild(n),t.checkClone=r.cloneNode(!0).cloneNode(!0).lastChild.checked,t.focusinBubbles="onfocusin"in e,i.style.backgroundClip="content-box",i.cloneNode(!0).style.backgroundClip="",t.clearCloneStyle="content-box"===i.style.backgroundClip,x(function(){var n,r,s="padding:0;margin:0;border:0;display:block;-webkit-box-sizing:content-box;-moz-box-sizing:content-box;box-sizing:content-box",a=o.getElementsByTagName("body")[0];a&&(n=o.createElement("div"),n.style.cssText="border:0;width:0;height:0;position:absolute;top:0;left:-9999px;margin-top:1px",a.appendChild(n).appendChild(i),i.innerHTML="",i.style.cssText="-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;padding:1px;border:1px;display:block;width:4px;margin-top:1%;position:absolute;top:1%",x.swap(a,null!=a.style.zoom?{zoom:1}:{},function(){t.boxSizing=4===i.offsetWidth}),e.getComputedStyle&&(t.pixelPosition="1%"!==(e.getComputedStyle(i,null)||{}).top,t.boxSizingReliable="4px"===(e.getComputedStyle(i,null)||{width:"4px"}).width,r=i.appendChild(o.createElement("div")),r.style.cssText=i.style.cssText=s,r.style.marginRight=r.style.width="0",i.style.width="1px",t.reliableMarginRight=!parseFloat((e.getComputedStyle(r,null)||{}).marginRight)),a.removeChild(n))}),t):t}({});var L,q,H=/(?:\{[\s\S]*\}|\[[\s\S]*\])$/,O=/([A-Z])/g;function F(){Object.defineProperty(this.cache={},0,{get:function(){return{}}}),this.expando=x.expando+Math.random()}F.uid=1,F.accepts=function(e){return e.nodeType?1===e.nodeType||9===e.nodeType:!0},F.prototype={key:function(e){if(!F.accepts(e))return 0;var t={},n=e[this.expando];if(!n){n=F.uid++;try{t[this.expando]={value:n},Object.defineProperties(e,t)}catch(r){t[this.expando]=n,x.extend(e,t)}}return this.cache[n]||(this.cache[n]={}),n},set:function(e,t,n){var r,i=this.key(e),o=this.cache[i];if("string"==typeof t)o[t]=n;else if(x.isEmptyObject(o))x.extend(this.cache[i],t);else for(r in t)o[r]=t[r];return o},get:function(e,t){var n=this.cache[this.key(e)];return t===undefined?n:n[t]},access:function(e,t,n){var r;return t===undefined||t&&"string"==typeof t&&n===undefined?(r=this.get(e,t),r!==undefined?r:this.get(e,x.camelCase(t))):(this.set(e,t,n),n!==undefined?n:t)},remove:function(e,t){var n,r,i,o=this.key(e),s=this.cache[o];if(t===undefined)this.cache[o]={};else{x.isArray(t)?r=t.concat(t.map(x.camelCase)):(i=x.camelCase(t),t in s?r=[t,i]:(r=i,r=r in s?[r]:r.match(w)||[])),n=r.length;while(n--)delete s[r[n]]}},hasData:function(e){return!x.isEmptyObject(this.cache[e[this.expando]]||{})},discard:function(e){e[this.expando]&&delete this.cache[e[this.expando]]}},L=new F,q=new F,x.extend({acceptData:F.accepts,hasData:function(e){return L.hasData(e)||q.hasData(e)},data:function(e,t,n){return L.access(e,t,n)},removeData:function(e,t){L.remove(e,t)},_data:function(e,t,n){return q.access(e,t,n)},_removeData:function(e,t){q.remove(e,t)}}),x.fn.extend({data:function(e,t){var n,r,i=this[0],o=0,s=null;if(e===undefined){if(this.length&&(s=L.get(i),1===i.nodeType&&!q.get(i,"hasDataAttrs"))){for(n=i.attributes;n.length>o;o++)r=n[o].name,0===r.indexOf("data-")&&(r=x.camelCase(r.slice(5)),P(i,r,s[r]));q.set(i,"hasDataAttrs",!0)}return s}return"object"==typeof e?this.each(function(){L.set(this,e)}):x.access(this,function(t){var n,r=x.camelCase(e);if(i&&t===undefined){if(n=L.get(i,e),n!==undefined)return n;if(n=L.get(i,r),n!==undefined)return n;if(n=P(i,r,undefined),n!==undefined)return n}else this.each(function(){var n=L.get(this,r);L.set(this,r,t),-1!==e.indexOf("-")&&n!==undefined&&L.set(this,e,t)})},null,t,arguments.length>1,null,!0)},removeData:function(e){return this.each(function(){L.remove(this,e)})}});function P(e,t,n){var r;if(n===undefined&&1===e.nodeType)if(r="data-"+t.replace(O,"-$1").toLowerCase(),n=e.getAttribute(r),"string"==typeof n){try{n="true"===n?!0:"false"===n?!1:"null"===n?null:+n+""===n?+n:H.test(n)?JSON.parse(n):n}catch(i){}L.set(e,t,n)}else n=undefined;return n}x.extend({queue:function(e,t,n){var r;return e?(t=(t||"fx")+"queue",r=q.get(e,t),n&&(!r||x.isArray(n)?r=q.access(e,t,x.makeArray(n)):r.push(n)),r||[]):undefined},dequeue:function(e,t){t=t||"fx";var n=x.queue(e,t),r=n.length,i=n.shift(),o=x._queueHooks(e,t),s=function(){x.dequeue(e,t)
+};"inprogress"===i&&(i=n.shift(),r--),i&&("fx"===t&&n.unshift("inprogress"),delete o.stop,i.call(e,s,o)),!r&&o&&o.empty.fire()},_queueHooks:function(e,t){var n=t+"queueHooks";return q.get(e,n)||q.access(e,n,{empty:x.Callbacks("once memory").add(function(){q.remove(e,[t+"queue",n])})})}}),x.fn.extend({queue:function(e,t){var n=2;return"string"!=typeof e&&(t=e,e="fx",n--),n>arguments.length?x.queue(this[0],e):t===undefined?this:this.each(function(){var n=x.queue(this,e,t);x._queueHooks(this,e),"fx"===e&&"inprogress"!==n[0]&&x.dequeue(this,e)})},dequeue:function(e){return this.each(function(){x.dequeue(this,e)})},delay:function(e,t){return e=x.fx?x.fx.speeds[e]||e:e,t=t||"fx",this.queue(t,function(t,n){var r=setTimeout(t,e);n.stop=function(){clearTimeout(r)}})},clearQueue:function(e){return this.queue(e||"fx",[])},promise:function(e,t){var n,r=1,i=x.Deferred(),o=this,s=this.length,a=function(){--r||i.resolveWith(o,[o])};"string"!=typeof e&&(t=e,e=undefined),e=e||"fx";while(s--)n=q.get(o[s],e+"queueHooks"),n&&n.empty&&(r++,n.empty.add(a));return a(),i.promise(t)}});var R,M,W=/[\t\r\n\f]/g,$=/\r/g,B=/^(?:input|select|textarea|button)$/i;x.fn.extend({attr:function(e,t){return x.access(this,x.attr,e,t,arguments.length>1)},removeAttr:function(e){return this.each(function(){x.removeAttr(this,e)})},prop:function(e,t){return x.access(this,x.prop,e,t,arguments.length>1)},removeProp:function(e){return this.each(function(){delete this[x.propFix[e]||e]})},addClass:function(e){var t,n,r,i,o,s=0,a=this.length,u="string"==typeof e&&e;if(x.isFunction(e))return this.each(function(t){x(this).addClass(e.call(this,t,this.className))});if(u)for(t=(e||"").match(w)||[];a>s;s++)if(n=this[s],r=1===n.nodeType&&(n.className?(" "+n.className+" ").replace(W," "):" ")){o=0;while(i=t[o++])0>r.indexOf(" "+i+" ")&&(r+=i+" ");n.className=x.trim(r)}return this},removeClass:function(e){var t,n,r,i,o,s=0,a=this.length,u=0===arguments.length||"string"==typeof e&&e;if(x.isFunction(e))return this.each(function(t){x(this).removeClass(e.call(this,t,this.className))});if(u)for(t=(e||"").match(w)||[];a>s;s++)if(n=this[s],r=1===n.nodeType&&(n.className?(" "+n.className+" ").replace(W," "):"")){o=0;while(i=t[o++])while(r.indexOf(" "+i+" ")>=0)r=r.replace(" "+i+" "," ");n.className=e?x.trim(r):""}return this},toggleClass:function(e,t){var n=typeof e;return"boolean"==typeof t&&"string"===n?t?this.addClass(e):this.removeClass(e):x.isFunction(e)?this.each(function(n){x(this).toggleClass(e.call(this,n,this.className,t),t)}):this.each(function(){if("string"===n){var t,i=0,o=x(this),s=e.match(w)||[];while(t=s[i++])o.hasClass(t)?o.removeClass(t):o.addClass(t)}else(n===r||"boolean"===n)&&(this.className&&q.set(this,"__className__",this.className),this.className=this.className||e===!1?"":q.get(this,"__className__")||"")})},hasClass:function(e){var t=" "+e+" ",n=0,r=this.length;for(;r>n;n++)if(1===this[n].nodeType&&(" "+this[n].className+" ").replace(W," ").indexOf(t)>=0)return!0;return!1},val:function(e){var t,n,r,i=this[0];{if(arguments.length)return r=x.isFunction(e),this.each(function(n){var i;1===this.nodeType&&(i=r?e.call(this,n,x(this).val()):e,null==i?i="":"number"==typeof i?i+="":x.isArray(i)&&(i=x.map(i,function(e){return null==e?"":e+""})),t=x.valHooks[this.type]||x.valHooks[this.nodeName.toLowerCase()],t&&"set"in t&&t.set(this,i,"value")!==undefined||(this.value=i))});if(i)return t=x.valHooks[i.type]||x.valHooks[i.nodeName.toLowerCase()],t&&"get"in t&&(n=t.get(i,"value"))!==undefined?n:(n=i.value,"string"==typeof n?n.replace($,""):null==n?"":n)}}}),x.extend({valHooks:{option:{get:function(e){var t=e.attributes.value;return!t||t.specified?e.value:e.text}},select:{get:function(e){var t,n,r=e.options,i=e.selectedIndex,o="select-one"===e.type||0>i,s=o?null:[],a=o?i+1:r.length,u=0>i?a:o?i:0;for(;a>u;u++)if(n=r[u],!(!n.selected&&u!==i||(x.support.optDisabled?n.disabled:null!==n.getAttribute("disabled"))||n.parentNode.disabled&&x.nodeName(n.parentNode,"optgroup"))){if(t=x(n).val(),o)return t;s.push(t)}return s},set:function(e,t){var n,r,i=e.options,o=x.makeArray(t),s=i.length;while(s--)r=i[s],(r.selected=x.inArray(x(r).val(),o)>=0)&&(n=!0);return n||(e.selectedIndex=-1),o}}},attr:function(e,t,n){var i,o,s=e.nodeType;if(e&&3!==s&&8!==s&&2!==s)return typeof e.getAttribute===r?x.prop(e,t,n):(1===s&&x.isXMLDoc(e)||(t=t.toLowerCase(),i=x.attrHooks[t]||(x.expr.match.bool.test(t)?M:R)),n===undefined?i&&"get"in i&&null!==(o=i.get(e,t))?o:(o=x.find.attr(e,t),null==o?undefined:o):null!==n?i&&"set"in i&&(o=i.set(e,n,t))!==undefined?o:(e.setAttribute(t,n+""),n):(x.removeAttr(e,t),undefined))},removeAttr:function(e,t){var n,r,i=0,o=t&&t.match(w);if(o&&1===e.nodeType)while(n=o[i++])r=x.propFix[n]||n,x.expr.match.bool.test(n)&&(e[r]=!1),e.removeAttribute(n)},attrHooks:{type:{set:function(e,t){if(!x.support.radioValue&&"radio"===t&&x.nodeName(e,"input")){var n=e.value;return e.setAttribute("type",t),n&&(e.value=n),t}}}},propFix:{"for":"htmlFor","class":"className"},prop:function(e,t,n){var r,i,o,s=e.nodeType;if(e&&3!==s&&8!==s&&2!==s)return o=1!==s||!x.isXMLDoc(e),o&&(t=x.propFix[t]||t,i=x.propHooks[t]),n!==undefined?i&&"set"in i&&(r=i.set(e,n,t))!==undefined?r:e[t]=n:i&&"get"in i&&null!==(r=i.get(e,t))?r:e[t]},propHooks:{tabIndex:{get:function(e){return e.hasAttribute("tabindex")||B.test(e.nodeName)||e.href?e.tabIndex:-1}}}}),M={set:function(e,t,n){return t===!1?x.removeAttr(e,n):e.setAttribute(n,n),n}},x.each(x.expr.match.bool.source.match(/\w+/g),function(e,t){var n=x.expr.attrHandle[t]||x.find.attr;x.expr.attrHandle[t]=function(e,t,r){var i=x.expr.attrHandle[t],o=r?undefined:(x.expr.attrHandle[t]=undefined)!=n(e,t,r)?t.toLowerCase():null;return x.expr.attrHandle[t]=i,o}}),x.support.optSelected||(x.propHooks.selected={get:function(e){var t=e.parentNode;return t&&t.parentNode&&t.parentNode.selectedIndex,null}}),x.each(["tabIndex","readOnly","maxLength","cellSpacing","cellPadding","rowSpan","colSpan","useMap","frameBorder","contentEditable"],function(){x.propFix[this.toLowerCase()]=this}),x.each(["radio","checkbox"],function(){x.valHooks[this]={set:function(e,t){return x.isArray(t)?e.checked=x.inArray(x(e).val(),t)>=0:undefined}},x.support.checkOn||(x.valHooks[this].get=function(e){return null===e.getAttribute("value")?"on":e.value})});var I=/^key/,z=/^(?:mouse|contextmenu)|click/,_=/^(?:focusinfocus|focusoutblur)$/,X=/^([^.]*)(?:\.(.+)|)$/;function U(){return!0}function Y(){return!1}function V(){try{return o.activeElement}catch(e){}}x.event={global:{},add:function(e,t,n,i,o){var s,a,u,l,c,p,f,h,d,g,m,y=q.get(e);if(y){n.handler&&(s=n,n=s.handler,o=s.selector),n.guid||(n.guid=x.guid++),(l=y.events)||(l=y.events={}),(a=y.handle)||(a=y.handle=function(e){return typeof x===r||e&&x.event.triggered===e.type?undefined:x.event.dispatch.apply(a.elem,arguments)},a.elem=e),t=(t||"").match(w)||[""],c=t.length;while(c--)u=X.exec(t[c])||[],d=m=u[1],g=(u[2]||"").split(".").sort(),d&&(f=x.event.special[d]||{},d=(o?f.delegateType:f.bindType)||d,f=x.event.special[d]||{},p=x.extend({type:d,origType:m,data:i,handler:n,guid:n.guid,selector:o,needsContext:o&&x.expr.match.needsContext.test(o),namespace:g.join(".")},s),(h=l[d])||(h=l[d]=[],h.delegateCount=0,f.setup&&f.setup.call(e,i,g,a)!==!1||e.addEventListener&&e.addEventListener(d,a,!1)),f.add&&(f.add.call(e,p),p.handler.guid||(p.handler.guid=n.guid)),o?h.splice(h.delegateCount++,0,p):h.push(p),x.event.global[d]=!0);e=null}},remove:function(e,t,n,r,i){var o,s,a,u,l,c,p,f,h,d,g,m=q.hasData(e)&&q.get(e);if(m&&(u=m.events)){t=(t||"").match(w)||[""],l=t.length;while(l--)if(a=X.exec(t[l])||[],h=g=a[1],d=(a[2]||"").split(".").sort(),h){p=x.event.special[h]||{},h=(r?p.delegateType:p.bindType)||h,f=u[h]||[],a=a[2]&&RegExp("(^|\\.)"+d.join("\\.(?:.*\\.|)")+"(\\.|$)"),s=o=f.length;while(o--)c=f[o],!i&&g!==c.origType||n&&n.guid!==c.guid||a&&!a.test(c.namespace)||r&&r!==c.selector&&("**"!==r||!c.selector)||(f.splice(o,1),c.selector&&f.delegateCount--,p.remove&&p.remove.call(e,c));s&&!f.length&&(p.teardown&&p.teardown.call(e,d,m.handle)!==!1||x.removeEvent(e,h,m.handle),delete u[h])}else for(h in u)x.event.remove(e,h+t[l],n,r,!0);x.isEmptyObject(u)&&(delete m.handle,q.remove(e,"events"))}},trigger:function(t,n,r,i){var s,a,u,l,c,p,f,h=[r||o],d=y.call(t,"type")?t.type:t,g=y.call(t,"namespace")?t.namespace.split("."):[];if(a=u=r=r||o,3!==r.nodeType&&8!==r.nodeType&&!_.test(d+x.event.triggered)&&(d.indexOf(".")>=0&&(g=d.split("."),d=g.shift(),g.sort()),c=0>d.indexOf(":")&&"on"+d,t=t[x.expando]?t:new x.Event(d,"object"==typeof t&&t),t.isTrigger=i?2:3,t.namespace=g.join("."),t.namespace_re=t.namespace?RegExp("(^|\\.)"+g.join("\\.(?:.*\\.|)")+"(\\.|$)"):null,t.result=undefined,t.target||(t.target=r),n=null==n?[t]:x.makeArray(n,[t]),f=x.event.special[d]||{},i||!f.trigger||f.trigger.apply(r,n)!==!1)){if(!i&&!f.noBubble&&!x.isWindow(r)){for(l=f.delegateType||d,_.test(l+d)||(a=a.parentNode);a;a=a.parentNode)h.push(a),u=a;u===(r.ownerDocument||o)&&h.push(u.defaultView||u.parentWindow||e)}s=0;while((a=h[s++])&&!t.isPropagationStopped())t.type=s>1?l:f.bindType||d,p=(q.get(a,"events")||{})[t.type]&&q.get(a,"handle"),p&&p.apply(a,n),p=c&&a[c],p&&x.acceptData(a)&&p.apply&&p.apply(a,n)===!1&&t.preventDefault();return t.type=d,i||t.isDefaultPrevented()||f._default&&f._default.apply(h.pop(),n)!==!1||!x.acceptData(r)||c&&x.isFunction(r[d])&&!x.isWindow(r)&&(u=r[c],u&&(r[c]=null),x.event.triggered=d,r[d](),x.event.triggered=undefined,u&&(r[c]=u)),t.result}},dispatch:function(e){e=x.event.fix(e);var t,n,r,i,o,s=[],a=d.call(arguments),u=(q.get(this,"events")||{})[e.type]||[],l=x.event.special[e.type]||{};if(a[0]=e,e.delegateTarget=this,!l.preDispatch||l.preDispatch.call(this,e)!==!1){s=x.event.handlers.call(this,e,u),t=0;while((i=s[t++])&&!e.isPropagationStopped()){e.currentTarget=i.elem,n=0;while((o=i.handlers[n++])&&!e.isImmediatePropagationStopped())(!e.namespace_re||e.namespace_re.test(o.namespace))&&(e.handleObj=o,e.data=o.data,r=((x.event.special[o.origType]||{}).handle||o.handler).apply(i.elem,a),r!==undefined&&(e.result=r)===!1&&(e.preventDefault(),e.stopPropagation()))}return l.postDispatch&&l.postDispatch.call(this,e),e.result}},handlers:function(e,t){var n,r,i,o,s=[],a=t.delegateCount,u=e.target;if(a&&u.nodeType&&(!e.button||"click"!==e.type))for(;u!==this;u=u.parentNode||this)if(u.disabled!==!0||"click"!==e.type){for(r=[],n=0;a>n;n++)o=t[n],i=o.selector+" ",r[i]===undefined&&(r[i]=o.needsContext?x(i,this).index(u)>=0:x.find(i,this,null,[u]).length),r[i]&&r.push(o);r.length&&s.push({elem:u,handlers:r})}return t.length>a&&s.push({elem:this,handlers:t.slice(a)}),s},props:"altKey bubbles cancelable ctrlKey currentTarget eventPhase metaKey relatedTarget shiftKey target timeStamp view which".split(" "),fixHooks:{},keyHooks:{props:"char charCode key keyCode".split(" "),filter:function(e,t){return null==e.which&&(e.which=null!=t.charCode?t.charCode:t.keyCode),e}},mouseHooks:{props:"button buttons clientX clientY offsetX offsetY pageX pageY screenX screenY toElement".split(" "),filter:function(e,t){var n,r,i,s=t.button;return null==e.pageX&&null!=t.clientX&&(n=e.target.ownerDocument||o,r=n.documentElement,i=n.body,e.pageX=t.clientX+(r&&r.scrollLeft||i&&i.scrollLeft||0)-(r&&r.clientLeft||i&&i.clientLeft||0),e.pageY=t.clientY+(r&&r.scrollTop||i&&i.scrollTop||0)-(r&&r.clientTop||i&&i.clientTop||0)),e.which||s===undefined||(e.which=1&s?1:2&s?3:4&s?2:0),e}},fix:function(e){if(e[x.expando])return e;var t,n,r,i=e.type,s=e,a=this.fixHooks[i];a||(this.fixHooks[i]=a=z.test(i)?this.mouseHooks:I.test(i)?this.keyHooks:{}),r=a.props?this.props.concat(a.props):this.props,e=new x.Event(s),t=r.length;while(t--)n=r[t],e[n]=s[n];return e.target||(e.target=o),3===e.target.nodeType&&(e.target=e.target.parentNode),a.filter?a.filter(e,s):e},special:{load:{noBubble:!0},focus:{trigger:function(){return this!==V()&&this.focus?(this.focus(),!1):undefined},delegateType:"focusin"},blur:{trigger:function(){return this===V()&&this.blur?(this.blur(),!1):undefined},delegateType:"focusout"},click:{trigger:function(){return"checkbox"===this.type&&this.click&&x.nodeName(this,"input")?(this.click(),!1):undefined},_default:function(e){return x.nodeName(e.target,"a")}},beforeunload:{postDispatch:function(e){e.result!==undefined&&(e.originalEvent.returnValue=e.result)}}},simulate:function(e,t,n,r){var i=x.extend(new x.Event,n,{type:e,isSimulated:!0,originalEvent:{}});r?x.event.trigger(i,null,t):x.event.dispatch.call(t,i),i.isDefaultPrevented()&&n.preventDefault()}},x.removeEvent=function(e,t,n){e.removeEventListener&&e.removeEventListener(t,n,!1)},x.Event=function(e,t){return this instanceof x.Event?(e&&e.type?(this.originalEvent=e,this.type=e.type,this.isDefaultPrevented=e.defaultPrevented||e.getPreventDefault&&e.getPreventDefault()?U:Y):this.type=e,t&&x.extend(this,t),this.timeStamp=e&&e.timeStamp||x.now(),this[x.expando]=!0,undefined):new x.Event(e,t)},x.Event.prototype={isDefaultPrevented:Y,isPropagationStopped:Y,isImmediatePropagationStopped:Y,preventDefault:function(){var e=this.originalEvent;this.isDefaultPrevented=U,e&&e.preventDefault&&e.preventDefault()},stopPropagation:function(){var e=this.originalEvent;this.isPropagationStopped=U,e&&e.stopPropagation&&e.stopPropagation()},stopImmediatePropagation:function(){this.isImmediatePropagationStopped=U,this.stopPropagation()}},x.each({mouseenter:"mouseover",mouseleave:"mouseout"},function(e,t){x.event.special[e]={delegateType:t,bindType:t,handle:function(e){var n,r=this,i=e.relatedTarget,o=e.handleObj;return(!i||i!==r&&!x.contains(r,i))&&(e.type=o.origType,n=o.handler.apply(this,arguments),e.type=t),n}}}),x.support.focusinBubbles||x.each({focus:"focusin",blur:"focusout"},function(e,t){var n=0,r=function(e){x.event.simulate(t,e.target,x.event.fix(e),!0)};x.event.special[t]={setup:function(){0===n++&&o.addEventListener(e,r,!0)},teardown:function(){0===--n&&o.removeEventListener(e,r,!0)}}}),x.fn.extend({on:function(e,t,n,r,i){var o,s;if("object"==typeof e){"string"!=typeof t&&(n=n||t,t=undefined);for(s in e)this.on(s,t,n,e[s],i);return this}if(null==n&&null==r?(r=t,n=t=undefined):null==r&&("string"==typeof t?(r=n,n=undefined):(r=n,n=t,t=undefined)),r===!1)r=Y;else if(!r)return this;return 1===i&&(o=r,r=function(e){return x().off(e),o.apply(this,arguments)},r.guid=o.guid||(o.guid=x.guid++)),this.each(function(){x.event.add(this,e,r,n,t)})},one:function(e,t,n,r){return this.on(e,t,n,r,1)},off:function(e,t,n){var r,i;if(e&&e.preventDefault&&e.handleObj)return r=e.handleObj,x(e.delegateTarget).off(r.namespace?r.origType+"."+r.namespace:r.origType,r.selector,r.handler),this;if("object"==typeof e){for(i in e)this.off(i,t,e[i]);return this}return(t===!1||"function"==typeof t)&&(n=t,t=undefined),n===!1&&(n=Y),this.each(function(){x.event.remove(this,e,n,t)})},trigger:function(e,t){return this.each(function(){x.event.trigger(e,t,this)})},triggerHandler:function(e,t){var n=this[0];return n?x.event.trigger(e,t,n,!0):undefined}});var G=/^.[^:#\[\.,]*$/,J=/^(?:parents|prev(?:Until|All))/,Q=x.expr.match.needsContext,K={children:!0,contents:!0,next:!0,prev:!0};x.fn.extend({find:function(e){var t,n=[],r=this,i=r.length;if("string"!=typeof e)return this.pushStack(x(e).filter(function(){for(t=0;i>t;t++)if(x.contains(r[t],this))return!0}));for(t=0;i>t;t++)x.find(e,r[t],n);return n=this.pushStack(i>1?x.unique(n):n),n.selector=this.selector?this.selector+" "+e:e,n},has:function(e){var t=x(e,this),n=t.length;return this.filter(function(){var e=0;for(;n>e;e++)if(x.contains(this,t[e]))return!0})},not:function(e){return this.pushStack(et(this,e||[],!0))},filter:function(e){return this.pushStack(et(this,e||[],!1))},is:function(e){return!!et(this,"string"==typeof e&&Q.test(e)?x(e):e||[],!1).length},closest:function(e,t){var n,r=0,i=this.length,o=[],s=Q.test(e)||"string"!=typeof e?x(e,t||this.context):0;for(;i>r;r++)for(n=this[r];n&&n!==t;n=n.parentNode)if(11>n.nodeType&&(s?s.index(n)>-1:1===n.nodeType&&x.find.matchesSelector(n,e))){n=o.push(n);break}return this.pushStack(o.length>1?x.unique(o):o)},index:function(e){return e?"string"==typeof e?g.call(x(e),this[0]):g.call(this,e.jquery?e[0]:e):this[0]&&this[0].parentNode?this.first().prevAll().length:-1},add:function(e,t){var n="string"==typeof e?x(e,t):x.makeArray(e&&e.nodeType?[e]:e),r=x.merge(this.get(),n);return this.pushStack(x.unique(r))},addBack:function(e){return this.add(null==e?this.prevObject:this.prevObject.filter(e))}});function Z(e,t){while((e=e[t])&&1!==e.nodeType);return e}x.each({parent:function(e){var t=e.parentNode;return t&&11!==t.nodeType?t:null},parents:function(e){return x.dir(e,"parentNode")},parentsUntil:function(e,t,n){return x.dir(e,"parentNode",n)},next:function(e){return Z(e,"nextSibling")},prev:function(e){return Z(e,"previousSibling")},nextAll:function(e){return x.dir(e,"nextSibling")},prevAll:function(e){return x.dir(e,"previousSibling")},nextUntil:function(e,t,n){return x.dir(e,"nextSibling",n)},prevUntil:function(e,t,n){return x.dir(e,"previousSibling",n)},siblings:function(e){return x.sibling((e.parentNode||{}).firstChild,e)},children:function(e){return x.sibling(e.firstChild)},contents:function(e){return e.contentDocument||x.merge([],e.childNodes)}},function(e,t){x.fn[e]=function(n,r){var i=x.map(this,t,n);return"Until"!==e.slice(-5)&&(r=n),r&&"string"==typeof r&&(i=x.filter(r,i)),this.length>1&&(K[e]||x.unique(i),J.test(e)&&i.reverse()),this.pushStack(i)}}),x.extend({filter:function(e,t,n){var r=t[0];return n&&(e=":not("+e+")"),1===t.length&&1===r.nodeType?x.find.matchesSelector(r,e)?[r]:[]:x.find.matches(e,x.grep(t,function(e){return 1===e.nodeType}))},dir:function(e,t,n){var r=[],i=n!==undefined;while((e=e[t])&&9!==e.nodeType)if(1===e.nodeType){if(i&&x(e).is(n))break;r.push(e)}return r},sibling:function(e,t){var n=[];for(;e;e=e.nextSibling)1===e.nodeType&&e!==t&&n.push(e);return n}});function et(e,t,n){if(x.isFunction(t))return x.grep(e,function(e,r){return!!t.call(e,r,e)!==n});if(t.nodeType)return x.grep(e,function(e){return e===t!==n});if("string"==typeof t){if(G.test(t))return x.filter(t,e,n);t=x.filter(t,e)}return x.grep(e,function(e){return g.call(t,e)>=0!==n})}var tt=/<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/gi,nt=/<([\w:]+)/,rt=/<|&#?\w+;/,it=/<(?:script|style|link)/i,ot=/^(?:checkbox|radio)$/i,st=/checked\s*(?:[^=]|=\s*.checked.)/i,at=/^$|\/(?:java|ecma)script/i,ut=/^true\/(.*)/,lt=/^\s*<!(?:\[CDATA\[|--)|(?:\]\]|--)>\s*$/g,ct={option:[1,"<select multiple='multiple'>","</select>"],thead:[1,"<table>","</table>"],col:[2,"<table><colgroup>","</colgroup></table>"],tr:[2,"<table><tbody>","</tbody></table>"],td:[3,"<table><tbody><tr>","</tr></tbody></table>"],_default:[0,"",""]};ct.optgroup=ct.option,ct.tbody=ct.tfoot=ct.colgroup=ct.caption=ct.thead,ct.th=ct.td,x.fn.extend({text:function(e){return x.access(this,function(e){return e===undefined?x.text(this):this.empty().append((this[0]&&this[0].ownerDocument||o).createTextNode(e))},null,e,arguments.length)},append:function(){return this.domManip(arguments,function(e){if(1===this.nodeType||11===this.nodeType||9===this.nodeType){var t=pt(this,e);t.appendChild(e)}})},prepend:function(){return this.domManip(arguments,function(e){if(1===this.nodeType||11===this.nodeType||9===this.nodeType){var t=pt(this,e);t.insertBefore(e,t.firstChild)}})},before:function(){return this.domManip(arguments,function(e){this.parentNode&&this.parentNode.insertBefore(e,this)})},after:function(){return this.domManip(arguments,function(e){this.parentNode&&this.parentNode.insertBefore(e,this.nextSibling)})},remove:function(e,t){var n,r=e?x.filter(e,this):this,i=0;for(;null!=(n=r[i]);i++)t||1!==n.nodeType||x.cleanData(mt(n)),n.parentNode&&(t&&x.contains(n.ownerDocument,n)&&dt(mt(n,"script")),n.parentNode.removeChild(n));return this},empty:function(){var e,t=0;for(;null!=(e=this[t]);t++)1===e.nodeType&&(x.cleanData(mt(e,!1)),e.textContent="");return this},clone:function(e,t){return e=null==e?!1:e,t=null==t?e:t,this.map(function(){return x.clone(this,e,t)})},html:function(e){return x.access(this,function(e){var t=this[0]||{},n=0,r=this.length;if(e===undefined&&1===t.nodeType)return t.innerHTML;if("string"==typeof e&&!it.test(e)&&!ct[(nt.exec(e)||["",""])[1].toLowerCase()]){e=e.replace(tt,"<$1></$2>");try{for(;r>n;n++)t=this[n]||{},1===t.nodeType&&(x.cleanData(mt(t,!1)),t.innerHTML=e);t=0}catch(i){}}t&&this.empty().append(e)},null,e,arguments.length)},replaceWith:function(){var e=x.map(this,function(e){return[e.nextSibling,e.parentNode]}),t=0;return this.domManip(arguments,function(n){var r=e[t++],i=e[t++];i&&(r&&r.parentNode!==i&&(r=this.nextSibling),x(this).remove(),i.insertBefore(n,r))},!0),t?this:this.remove()},detach:function(e){return this.remove(e,!0)},domManip:function(e,t,n){e=f.apply([],e);var r,i,o,s,a,u,l=0,c=this.length,p=this,h=c-1,d=e[0],g=x.isFunction(d);if(g||!(1>=c||"string"!=typeof d||x.support.checkClone)&&st.test(d))return this.each(function(r){var i=p.eq(r);g&&(e[0]=d.call(this,r,i.html())),i.domManip(e,t,n)});if(c&&(r=x.buildFragment(e,this[0].ownerDocument,!1,!n&&this),i=r.firstChild,1===r.childNodes.length&&(r=i),i)){for(o=x.map(mt(r,"script"),ft),s=o.length;c>l;l++)a=r,l!==h&&(a=x.clone(a,!0,!0),s&&x.merge(o,mt(a,"script"))),t.call(this[l],a,l);if(s)for(u=o[o.length-1].ownerDocument,x.map(o,ht),l=0;s>l;l++)a=o[l],at.test(a.type||"")&&!q.access(a,"globalEval")&&x.contains(u,a)&&(a.src?x._evalUrl(a.src):x.globalEval(a.textContent.replace(lt,"")))}return this}}),x.each({appendTo:"append",prependTo:"prepend",insertBefore:"before",insertAfter:"after",replaceAll:"replaceWith"},function(e,t){x.fn[e]=function(e){var n,r=[],i=x(e),o=i.length-1,s=0;for(;o>=s;s++)n=s===o?this:this.clone(!0),x(i[s])[t](n),h.apply(r,n.get());return this.pushStack(r)}}),x.extend({clone:function(e,t,n){var r,i,o,s,a=e.cloneNode(!0),u=x.contains(e.ownerDocument,e);if(!(x.support.noCloneChecked||1!==e.nodeType&&11!==e.nodeType||x.isXMLDoc(e)))for(s=mt(a),o=mt(e),r=0,i=o.length;i>r;r++)yt(o[r],s[r]);if(t)if(n)for(o=o||mt(e),s=s||mt(a),r=0,i=o.length;i>r;r++)gt(o[r],s[r]);else gt(e,a);return s=mt(a,"script"),s.length>0&&dt(s,!u&&mt(e,"script")),a},buildFragment:function(e,t,n,r){var i,o,s,a,u,l,c=0,p=e.length,f=t.createDocumentFragment(),h=[];for(;p>c;c++)if(i=e[c],i||0===i)if("object"===x.type(i))x.merge(h,i.nodeType?[i]:i);else if(rt.test(i)){o=o||f.appendChild(t.createElement("div")),s=(nt.exec(i)||["",""])[1].toLowerCase(),a=ct[s]||ct._default,o.innerHTML=a[1]+i.replace(tt,"<$1></$2>")+a[2],l=a[0];while(l--)o=o.lastChild;x.merge(h,o.childNodes),o=f.firstChild,o.textContent=""}else h.push(t.createTextNode(i));f.textContent="",c=0;while(i=h[c++])if((!r||-1===x.inArray(i,r))&&(u=x.contains(i.ownerDocument,i),o=mt(f.appendChild(i),"script"),u&&dt(o),n)){l=0;while(i=o[l++])at.test(i.type||"")&&n.push(i)}return f},cleanData:function(e){var t,n,r,i,o,s,a=x.event.special,u=0;for(;(n=e[u])!==undefined;u++){if(F.accepts(n)&&(o=n[q.expando],o&&(t=q.cache[o]))){if(r=Object.keys(t.events||{}),r.length)for(s=0;(i=r[s])!==undefined;s++)a[i]?x.event.remove(n,i):x.removeEvent(n,i,t.handle);q.cache[o]&&delete q.cache[o]}delete L.cache[n[L.expando]]}},_evalUrl:function(e){return x.ajax({url:e,type:"GET",dataType:"script",async:!1,global:!1,"throws":!0})}});function pt(e,t){return x.nodeName(e,"table")&&x.nodeName(1===t.nodeType?t:t.firstChild,"tr")?e.getElementsByTagName("tbody")[0]||e.appendChild(e.ownerDocument.createElement("tbody")):e}function ft(e){return e.type=(null!==e.getAttribute("type"))+"/"+e.type,e}function ht(e){var t=ut.exec(e.type);return t?e.type=t[1]:e.removeAttribute("type"),e}function dt(e,t){var n=e.length,r=0;for(;n>r;r++)q.set(e[r],"globalEval",!t||q.get(t[r],"globalEval"))}function gt(e,t){var n,r,i,o,s,a,u,l;if(1===t.nodeType){if(q.hasData(e)&&(o=q.access(e),s=q.set(t,o),l=o.events)){delete s.handle,s.events={};for(i in l)for(n=0,r=l[i].length;r>n;n++)x.event.add(t,i,l[i][n])}L.hasData(e)&&(a=L.access(e),u=x.extend({},a),L.set(t,u))}}function mt(e,t){var n=e.getElementsByTagName?e.getElementsByTagName(t||"*"):e.querySelectorAll?e.querySelectorAll(t||"*"):[];return t===undefined||t&&x.nodeName(e,t)?x.merge([e],n):n}function yt(e,t){var n=t.nodeName.toLowerCase();"input"===n&&ot.test(e.type)?t.checked=e.checked:("input"===n||"textarea"===n)&&(t.defaultValue=e.defaultValue)}x.fn.extend({wrapAll:function(e){var t;return x.isFunction(e)?this.each(function(t){x(this).wrapAll(e.call(this,t))}):(this[0]&&(t=x(e,this[0].ownerDocument).eq(0).clone(!0),this[0].parentNode&&t.insertBefore(this[0]),t.map(function(){var e=this;while(e.firstElementChild)e=e.firstElementChild;return e}).append(this)),this)},wrapInner:function(e){return x.isFunction(e)?this.each(function(t){x(this).wrapInner(e.call(this,t))}):this.each(function(){var t=x(this),n=t.contents();n.length?n.wrapAll(e):t.append(e)})},wrap:function(e){var t=x.isFunction(e);return this.each(function(n){x(this).wrapAll(t?e.call(this,n):e)})},unwrap:function(){return this.parent().each(function(){x.nodeName(this,"body")||x(this).replaceWith(this.childNodes)}).end()}});var vt,xt,bt=/^(none|table(?!-c[ea]).+)/,wt=/^margin/,Tt=RegExp("^("+b+")(.*)$","i"),Ct=RegExp("^("+b+")(?!px)[a-z%]+$","i"),kt=RegExp("^([+-])=("+b+")","i"),Nt={BODY:"block"},Et={position:"absolute",visibility:"hidden",display:"block"},St={letterSpacing:0,fontWeight:400},jt=["Top","Right","Bottom","Left"],Dt=["Webkit","O","Moz","ms"];function At(e,t){if(t in e)return t;var n=t.charAt(0).toUpperCase()+t.slice(1),r=t,i=Dt.length;while(i--)if(t=Dt[i]+n,t in e)return t;return r}function Lt(e,t){return e=t||e,"none"===x.css(e,"display")||!x.contains(e.ownerDocument,e)}function qt(t){return e.getComputedStyle(t,null)}function Ht(e,t){var n,r,i,o=[],s=0,a=e.length;for(;a>s;s++)r=e[s],r.style&&(o[s]=q.get(r,"olddisplay"),n=r.style.display,t?(o[s]||"none"!==n||(r.style.display=""),""===r.style.display&&Lt(r)&&(o[s]=q.access(r,"olddisplay",Rt(r.nodeName)))):o[s]||(i=Lt(r),(n&&"none"!==n||!i)&&q.set(r,"olddisplay",i?n:x.css(r,"display"))));for(s=0;a>s;s++)r=e[s],r.style&&(t&&"none"!==r.style.display&&""!==r.style.display||(r.style.display=t?o[s]||"":"none"));return e}x.fn.extend({css:function(e,t){return x.access(this,function(e,t,n){var r,i,o={},s=0;if(x.isArray(t)){for(r=qt(e),i=t.length;i>s;s++)o[t[s]]=x.css(e,t[s],!1,r);return o}return n!==undefined?x.style(e,t,n):x.css(e,t)},e,t,arguments.length>1)},show:function(){return Ht(this,!0)},hide:function(){return Ht(this)},toggle:function(e){return"boolean"==typeof e?e?this.show():this.hide():this.each(function(){Lt(this)?x(this).show():x(this).hide()})}}),x.extend({cssHooks:{opacity:{get:function(e,t){if(t){var n=vt(e,"opacity");return""===n?"1":n}}}},cssNumber:{columnCount:!0,fillOpacity:!0,fontWeight:!0,lineHeight:!0,opacity:!0,order:!0,orphans:!0,widows:!0,zIndex:!0,zoom:!0},cssProps:{"float":"cssFloat"},style:function(e,t,n,r){if(e&&3!==e.nodeType&&8!==e.nodeType&&e.style){var i,o,s,a=x.camelCase(t),u=e.style;return t=x.cssProps[a]||(x.cssProps[a]=At(u,a)),s=x.cssHooks[t]||x.cssHooks[a],n===undefined?s&&"get"in s&&(i=s.get(e,!1,r))!==undefined?i:u[t]:(o=typeof n,"string"===o&&(i=kt.exec(n))&&(n=(i[1]+1)*i[2]+parseFloat(x.css(e,t)),o="number"),null==n||"number"===o&&isNaN(n)||("number"!==o||x.cssNumber[a]||(n+="px"),x.support.clearCloneStyle||""!==n||0!==t.indexOf("background")||(u[t]="inherit"),s&&"set"in s&&(n=s.set(e,n,r))===undefined||(u[t]=n)),undefined)}},css:function(e,t,n,r){var i,o,s,a=x.camelCase(t);return t=x.cssProps[a]||(x.cssProps[a]=At(e.style,a)),s=x.cssHooks[t]||x.cssHooks[a],s&&"get"in s&&(i=s.get(e,!0,n)),i===undefined&&(i=vt(e,t,r)),"normal"===i&&t in St&&(i=St[t]),""===n||n?(o=parseFloat(i),n===!0||x.isNumeric(o)?o||0:i):i}}),vt=function(e,t,n){var r,i,o,s=n||qt(e),a=s?s.getPropertyValue(t)||s[t]:undefined,u=e.style;return s&&(""!==a||x.contains(e.ownerDocument,e)||(a=x.style(e,t)),Ct.test(a)&&wt.test(t)&&(r=u.width,i=u.minWidth,o=u.maxWidth,u.minWidth=u.maxWidth=u.width=a,a=s.width,u.width=r,u.minWidth=i,u.maxWidth=o)),a};function Ot(e,t,n){var r=Tt.exec(t);return r?Math.max(0,r[1]-(n||0))+(r[2]||"px"):t}function Ft(e,t,n,r,i){var o=n===(r?"border":"content")?4:"width"===t?1:0,s=0;for(;4>o;o+=2)"margin"===n&&(s+=x.css(e,n+jt[o],!0,i)),r?("content"===n&&(s-=x.css(e,"padding"+jt[o],!0,i)),"margin"!==n&&(s-=x.css(e,"border"+jt[o]+"Width",!0,i))):(s+=x.css(e,"padding"+jt[o],!0,i),"padding"!==n&&(s+=x.css(e,"border"+jt[o]+"Width",!0,i)));return s}function Pt(e,t,n){var r=!0,i="width"===t?e.offsetWidth:e.offsetHeight,o=qt(e),s=x.support.boxSizing&&"border-box"===x.css(e,"boxSizing",!1,o);if(0>=i||null==i){if(i=vt(e,t,o),(0>i||null==i)&&(i=e.style[t]),Ct.test(i))return i;r=s&&(x.support.boxSizingReliable||i===e.style[t]),i=parseFloat(i)||0}return i+Ft(e,t,n||(s?"border":"content"),r,o)+"px"}function Rt(e){var t=o,n=Nt[e];return n||(n=Mt(e,t),"none"!==n&&n||(xt=(xt||x("<iframe frameborder='0' width='0' height='0'/>").css("cssText","display:block !important")).appendTo(t.documentElement),t=(xt[0].contentWindow||xt[0].contentDocument).document,t.write("<!doctype html><html><body>"),t.close(),n=Mt(e,t),xt.detach()),Nt[e]=n),n}function Mt(e,t){var n=x(t.createElement(e)).appendTo(t.body),r=x.css(n[0],"display");return n.remove(),r}x.each(["height","width"],function(e,t){x.cssHooks[t]={get:function(e,n,r){return n?0===e.offsetWidth&&bt.test(x.css(e,"display"))?x.swap(e,Et,function(){return Pt(e,t,r)}):Pt(e,t,r):undefined},set:function(e,n,r){var i=r&&qt(e);return Ot(e,n,r?Ft(e,t,r,x.support.boxSizing&&"border-box"===x.css(e,"boxSizing",!1,i),i):0)}}}),x(function(){x.support.reliableMarginRight||(x.cssHooks.marginRight={get:function(e,t){return t?x.swap(e,{display:"inline-block"},vt,[e,"marginRight"]):undefined}}),!x.support.pixelPosition&&x.fn.position&&x.each(["top","left"],function(e,t){x.cssHooks[t]={get:function(e,n){return n?(n=vt(e,t),Ct.test(n)?x(e).position()[t]+"px":n):undefined}}})}),x.expr&&x.expr.filters&&(x.expr.filters.hidden=function(e){return 0>=e.offsetWidth&&0>=e.offsetHeight},x.expr.filters.visible=function(e){return!x.expr.filters.hidden(e)}),x.each({margin:"",padding:"",border:"Width"},function(e,t){x.cssHooks[e+t]={expand:function(n){var r=0,i={},o="string"==typeof n?n.split(" "):[n];for(;4>r;r++)i[e+jt[r]+t]=o[r]||o[r-2]||o[0];return i}},wt.test(e)||(x.cssHooks[e+t].set=Ot)});var Wt=/%20/g,$t=/\[\]$/,Bt=/\r?\n/g,It=/^(?:submit|button|image|reset|file)$/i,zt=/^(?:input|select|textarea|keygen)/i;x.fn.extend({serialize:function(){return x.param(this.serializeArray())},serializeArray:function(){return this.map(function(){var e=x.prop(this,"elements");return e?x.makeArray(e):this}).filter(function(){var e=this.type;return this.name&&!x(this).is(":disabled")&&zt.test(this.nodeName)&&!It.test(e)&&(this.checked||!ot.test(e))}).map(function(e,t){var n=x(this).val();return null==n?null:x.isArray(n)?x.map(n,function(e){return{name:t.name,value:e.replace(Bt,"\r\n")}}):{name:t.name,value:n.replace(Bt,"\r\n")}}).get()}}),x.param=function(e,t){var n,r=[],i=function(e,t){t=x.isFunction(t)?t():null==t?"":t,r[r.length]=encodeURIComponent(e)+"="+encodeURIComponent(t)};if(t===undefined&&(t=x.ajaxSettings&&x.ajaxSettings.traditional),x.isArray(e)||e.jquery&&!x.isPlainObject(e))x.each(e,function(){i(this.name,this.value)});else for(n in e)_t(n,e[n],t,i);return r.join("&").replace(Wt,"+")};function _t(e,t,n,r){var i;if(x.isArray(t))x.each(t,function(t,i){n||$t.test(e)?r(e,i):_t(e+"["+("object"==typeof i?t:"")+"]",i,n,r)});else if(n||"object"!==x.type(t))r(e,t);else for(i in t)_t(e+"["+i+"]",t[i],n,r)}x.each("blur focus focusin focusout load resize scroll unload click dblclick mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave change select submit keydown keypress keyup error contextmenu".split(" "),function(e,t){x.fn[t]=function(e,n){return arguments.length>0?this.on(t,null,e,n):this.trigger(t)}}),x.fn.extend({hover:function(e,t){return this.mouseenter(e).mouseleave(t||e)},bind:function(e,t,n){return this.on(e,null,t,n)},unbind:function(e,t){return this.off(e,null,t)
+},delegate:function(e,t,n,r){return this.on(t,e,n,r)},undelegate:function(e,t,n){return 1===arguments.length?this.off(e,"**"):this.off(t,e||"**",n)}});var Xt,Ut,Yt=x.now(),Vt=/\?/,Gt=/#.*$/,Jt=/([?&])_=[^&]*/,Qt=/^(.*?):[ \t]*([^\r\n]*)$/gm,Kt=/^(?:about|app|app-storage|.+-extension|file|res|widget):$/,Zt=/^(?:GET|HEAD)$/,en=/^\/\//,tn=/^([\w.+-]+:)(?:\/\/([^\/?#:]*)(?::(\d+)|)|)/,nn=x.fn.load,rn={},on={},sn="*/".concat("*");try{Ut=i.href}catch(an){Ut=o.createElement("a"),Ut.href="",Ut=Ut.href}Xt=tn.exec(Ut.toLowerCase())||[];function un(e){return function(t,n){"string"!=typeof t&&(n=t,t="*");var r,i=0,o=t.toLowerCase().match(w)||[];if(x.isFunction(n))while(r=o[i++])"+"===r[0]?(r=r.slice(1)||"*",(e[r]=e[r]||[]).unshift(n)):(e[r]=e[r]||[]).push(n)}}function ln(e,t,n,r){var i={},o=e===on;function s(a){var u;return i[a]=!0,x.each(e[a]||[],function(e,a){var l=a(t,n,r);return"string"!=typeof l||o||i[l]?o?!(u=l):undefined:(t.dataTypes.unshift(l),s(l),!1)}),u}return s(t.dataTypes[0])||!i["*"]&&s("*")}function cn(e,t){var n,r,i=x.ajaxSettings.flatOptions||{};for(n in t)t[n]!==undefined&&((i[n]?e:r||(r={}))[n]=t[n]);return r&&x.extend(!0,e,r),e}x.fn.load=function(e,t,n){if("string"!=typeof e&&nn)return nn.apply(this,arguments);var r,i,o,s=this,a=e.indexOf(" ");return a>=0&&(r=e.slice(a),e=e.slice(0,a)),x.isFunction(t)?(n=t,t=undefined):t&&"object"==typeof t&&(i="POST"),s.length>0&&x.ajax({url:e,type:i,dataType:"html",data:t}).done(function(e){o=arguments,s.html(r?x("<div>").append(x.parseHTML(e)).find(r):e)}).complete(n&&function(e,t){s.each(n,o||[e.responseText,t,e])}),this},x.each(["ajaxStart","ajaxStop","ajaxComplete","ajaxError","ajaxSuccess","ajaxSend"],function(e,t){x.fn[t]=function(e){return this.on(t,e)}}),x.extend({active:0,lastModified:{},etag:{},ajaxSettings:{url:Ut,type:"GET",isLocal:Kt.test(Xt[1]),global:!0,processData:!0,async:!0,contentType:"application/x-www-form-urlencoded; charset=UTF-8",accepts:{"*":sn,text:"text/plain",html:"text/html",xml:"application/xml, text/xml",json:"application/json, text/javascript"},contents:{xml:/xml/,html:/html/,json:/json/},responseFields:{xml:"responseXML",text:"responseText",json:"responseJSON"},converters:{"* text":String,"text html":!0,"text json":x.parseJSON,"text xml":x.parseXML},flatOptions:{url:!0,context:!0}},ajaxSetup:function(e,t){return t?cn(cn(e,x.ajaxSettings),t):cn(x.ajaxSettings,e)},ajaxPrefilter:un(rn),ajaxTransport:un(on),ajax:function(e,t){"object"==typeof e&&(t=e,e=undefined),t=t||{};var n,r,i,o,s,a,u,l,c=x.ajaxSetup({},t),p=c.context||c,f=c.context&&(p.nodeType||p.jquery)?x(p):x.event,h=x.Deferred(),d=x.Callbacks("once memory"),g=c.statusCode||{},m={},y={},v=0,b="canceled",T={readyState:0,getResponseHeader:function(e){var t;if(2===v){if(!o){o={};while(t=Qt.exec(i))o[t[1].toLowerCase()]=t[2]}t=o[e.toLowerCase()]}return null==t?null:t},getAllResponseHeaders:function(){return 2===v?i:null},setRequestHeader:function(e,t){var n=e.toLowerCase();return v||(e=y[n]=y[n]||e,m[e]=t),this},overrideMimeType:function(e){return v||(c.mimeType=e),this},statusCode:function(e){var t;if(e)if(2>v)for(t in e)g[t]=[g[t],e[t]];else T.always(e[T.status]);return this},abort:function(e){var t=e||b;return n&&n.abort(t),k(0,t),this}};if(h.promise(T).complete=d.add,T.success=T.done,T.error=T.fail,c.url=((e||c.url||Ut)+"").replace(Gt,"").replace(en,Xt[1]+"//"),c.type=t.method||t.type||c.method||c.type,c.dataTypes=x.trim(c.dataType||"*").toLowerCase().match(w)||[""],null==c.crossDomain&&(a=tn.exec(c.url.toLowerCase()),c.crossDomain=!(!a||a[1]===Xt[1]&&a[2]===Xt[2]&&(a[3]||("http:"===a[1]?"80":"443"))===(Xt[3]||("http:"===Xt[1]?"80":"443")))),c.data&&c.processData&&"string"!=typeof c.data&&(c.data=x.param(c.data,c.traditional)),ln(rn,c,t,T),2===v)return T;u=c.global,u&&0===x.active++&&x.event.trigger("ajaxStart"),c.type=c.type.toUpperCase(),c.hasContent=!Zt.test(c.type),r=c.url,c.hasContent||(c.data&&(r=c.url+=(Vt.test(r)?"&":"?")+c.data,delete c.data),c.cache===!1&&(c.url=Jt.test(r)?r.replace(Jt,"$1_="+Yt++):r+(Vt.test(r)?"&":"?")+"_="+Yt++)),c.ifModified&&(x.lastModified[r]&&T.setRequestHeader("If-Modified-Since",x.lastModified[r]),x.etag[r]&&T.setRequestHeader("If-None-Match",x.etag[r])),(c.data&&c.hasContent&&c.contentType!==!1||t.contentType)&&T.setRequestHeader("Content-Type",c.contentType),T.setRequestHeader("Accept",c.dataTypes[0]&&c.accepts[c.dataTypes[0]]?c.accepts[c.dataTypes[0]]+("*"!==c.dataTypes[0]?", "+sn+"; q=0.01":""):c.accepts["*"]);for(l in c.headers)T.setRequestHeader(l,c.headers[l]);if(c.beforeSend&&(c.beforeSend.call(p,T,c)===!1||2===v))return T.abort();b="abort";for(l in{success:1,error:1,complete:1})T[l](c[l]);if(n=ln(on,c,t,T)){T.readyState=1,u&&f.trigger("ajaxSend",[T,c]),c.async&&c.timeout>0&&(s=setTimeout(function(){T.abort("timeout")},c.timeout));try{v=1,n.send(m,k)}catch(C){if(!(2>v))throw C;k(-1,C)}}else k(-1,"No Transport");function k(e,t,o,a){var l,m,y,b,w,C=t;2!==v&&(v=2,s&&clearTimeout(s),n=undefined,i=a||"",T.readyState=e>0?4:0,l=e>=200&&300>e||304===e,o&&(b=pn(c,T,o)),b=fn(c,b,T,l),l?(c.ifModified&&(w=T.getResponseHeader("Last-Modified"),w&&(x.lastModified[r]=w),w=T.getResponseHeader("etag"),w&&(x.etag[r]=w)),204===e||"HEAD"===c.type?C="nocontent":304===e?C="notmodified":(C=b.state,m=b.data,y=b.error,l=!y)):(y=C,(e||!C)&&(C="error",0>e&&(e=0))),T.status=e,T.statusText=(t||C)+"",l?h.resolveWith(p,[m,C,T]):h.rejectWith(p,[T,C,y]),T.statusCode(g),g=undefined,u&&f.trigger(l?"ajaxSuccess":"ajaxError",[T,c,l?m:y]),d.fireWith(p,[T,C]),u&&(f.trigger("ajaxComplete",[T,c]),--x.active||x.event.trigger("ajaxStop")))}return T},getJSON:function(e,t,n){return x.get(e,t,n,"json")},getScript:function(e,t){return x.get(e,undefined,t,"script")}}),x.each(["get","post"],function(e,t){x[t]=function(e,n,r,i){return x.isFunction(n)&&(i=i||r,r=n,n=undefined),x.ajax({url:e,type:t,dataType:i,data:n,success:r})}});function pn(e,t,n){var r,i,o,s,a=e.contents,u=e.dataTypes;while("*"===u[0])u.shift(),r===undefined&&(r=e.mimeType||t.getResponseHeader("Content-Type"));if(r)for(i in a)if(a[i]&&a[i].test(r)){u.unshift(i);break}if(u[0]in n)o=u[0];else{for(i in n){if(!u[0]||e.converters[i+" "+u[0]]){o=i;break}s||(s=i)}o=o||s}return o?(o!==u[0]&&u.unshift(o),n[o]):undefined}function fn(e,t,n,r){var i,o,s,a,u,l={},c=e.dataTypes.slice();if(c[1])for(s in e.converters)l[s.toLowerCase()]=e.converters[s];o=c.shift();while(o)if(e.responseFields[o]&&(n[e.responseFields[o]]=t),!u&&r&&e.dataFilter&&(t=e.dataFilter(t,e.dataType)),u=o,o=c.shift())if("*"===o)o=u;else if("*"!==u&&u!==o){if(s=l[u+" "+o]||l["* "+o],!s)for(i in l)if(a=i.split(" "),a[1]===o&&(s=l[u+" "+a[0]]||l["* "+a[0]])){s===!0?s=l[i]:l[i]!==!0&&(o=a[0],c.unshift(a[1]));break}if(s!==!0)if(s&&e["throws"])t=s(t);else try{t=s(t)}catch(p){return{state:"parsererror",error:s?p:"No conversion from "+u+" to "+o}}}return{state:"success",data:t}}x.ajaxSetup({accepts:{script:"text/javascript, application/javascript, application/ecmascript, application/x-ecmascript"},contents:{script:/(?:java|ecma)script/},converters:{"text script":function(e){return x.globalEval(e),e}}}),x.ajaxPrefilter("script",function(e){e.cache===undefined&&(e.cache=!1),e.crossDomain&&(e.type="GET")}),x.ajaxTransport("script",function(e){if(e.crossDomain){var t,n;return{send:function(r,i){t=x("<script>").prop({async:!0,charset:e.scriptCharset,src:e.url}).on("load error",n=function(e){t.remove(),n=null,e&&i("error"===e.type?404:200,e.type)}),o.head.appendChild(t[0])},abort:function(){n&&n()}}}});var hn=[],dn=/(=)\?(?=&|$)|\?\?/;x.ajaxSetup({jsonp:"callback",jsonpCallback:function(){var e=hn.pop()||x.expando+"_"+Yt++;return this[e]=!0,e}}),x.ajaxPrefilter("json jsonp",function(t,n,r){var i,o,s,a=t.jsonp!==!1&&(dn.test(t.url)?"url":"string"==typeof t.data&&!(t.contentType||"").indexOf("application/x-www-form-urlencoded")&&dn.test(t.data)&&"data");return a||"jsonp"===t.dataTypes[0]?(i=t.jsonpCallback=x.isFunction(t.jsonpCallback)?t.jsonpCallback():t.jsonpCallback,a?t[a]=t[a].replace(dn,"$1"+i):t.jsonp!==!1&&(t.url+=(Vt.test(t.url)?"&":"?")+t.jsonp+"="+i),t.converters["script json"]=function(){return s||x.error(i+" was not called"),s[0]},t.dataTypes[0]="json",o=e[i],e[i]=function(){s=arguments},r.always(function(){e[i]=o,t[i]&&(t.jsonpCallback=n.jsonpCallback,hn.push(i)),s&&x.isFunction(o)&&o(s[0]),s=o=undefined}),"script"):undefined}),x.ajaxSettings.xhr=function(){try{return new XMLHttpRequest}catch(e){}};var gn=x.ajaxSettings.xhr(),mn={0:200,1223:204},yn=0,vn={};e.ActiveXObject&&x(e).on("unload",function(){for(var e in vn)vn[e]();vn=undefined}),x.support.cors=!!gn&&"withCredentials"in gn,x.support.ajax=gn=!!gn,x.ajaxTransport(function(e){var t;return x.support.cors||gn&&!e.crossDomain?{send:function(n,r){var i,o,s=e.xhr();if(s.open(e.type,e.url,e.async,e.username,e.password),e.xhrFields)for(i in e.xhrFields)s[i]=e.xhrFields[i];e.mimeType&&s.overrideMimeType&&s.overrideMimeType(e.mimeType),e.crossDomain||n["X-Requested-With"]||(n["X-Requested-With"]="XMLHttpRequest");for(i in n)s.setRequestHeader(i,n[i]);t=function(e){return function(){t&&(delete vn[o],t=s.onload=s.onerror=null,"abort"===e?s.abort():"error"===e?r(s.status||404,s.statusText):r(mn[s.status]||s.status,s.statusText,"string"==typeof s.responseText?{text:s.responseText}:undefined,s.getAllResponseHeaders()))}},s.onload=t(),s.onerror=t("error"),t=vn[o=yn++]=t("abort"),s.send(e.hasContent&&e.data||null)},abort:function(){t&&t()}}:undefined});var xn,bn,wn=/^(?:toggle|show|hide)$/,Tn=RegExp("^(?:([+-])=|)("+b+")([a-z%]*)$","i"),Cn=/queueHooks$/,kn=[An],Nn={"*":[function(e,t){var n=this.createTween(e,t),r=n.cur(),i=Tn.exec(t),o=i&&i[3]||(x.cssNumber[e]?"":"px"),s=(x.cssNumber[e]||"px"!==o&&+r)&&Tn.exec(x.css(n.elem,e)),a=1,u=20;if(s&&s[3]!==o){o=o||s[3],i=i||[],s=+r||1;do a=a||".5",s/=a,x.style(n.elem,e,s+o);while(a!==(a=n.cur()/r)&&1!==a&&--u)}return i&&(s=n.start=+s||+r||0,n.unit=o,n.end=i[1]?s+(i[1]+1)*i[2]:+i[2]),n}]};function En(){return setTimeout(function(){xn=undefined}),xn=x.now()}function Sn(e,t,n){var r,i=(Nn[t]||[]).concat(Nn["*"]),o=0,s=i.length;for(;s>o;o++)if(r=i[o].call(n,t,e))return r}function jn(e,t,n){var r,i,o=0,s=kn.length,a=x.Deferred().always(function(){delete u.elem}),u=function(){if(i)return!1;var t=xn||En(),n=Math.max(0,l.startTime+l.duration-t),r=n/l.duration||0,o=1-r,s=0,u=l.tweens.length;for(;u>s;s++)l.tweens[s].run(o);return a.notifyWith(e,[l,o,n]),1>o&&u?n:(a.resolveWith(e,[l]),!1)},l=a.promise({elem:e,props:x.extend({},t),opts:x.extend(!0,{specialEasing:{}},n),originalProperties:t,originalOptions:n,startTime:xn||En(),duration:n.duration,tweens:[],createTween:function(t,n){var r=x.Tween(e,l.opts,t,n,l.opts.specialEasing[t]||l.opts.easing);return l.tweens.push(r),r},stop:function(t){var n=0,r=t?l.tweens.length:0;if(i)return this;for(i=!0;r>n;n++)l.tweens[n].run(1);return t?a.resolveWith(e,[l,t]):a.rejectWith(e,[l,t]),this}}),c=l.props;for(Dn(c,l.opts.specialEasing);s>o;o++)if(r=kn[o].call(l,e,c,l.opts))return r;return x.map(c,Sn,l),x.isFunction(l.opts.start)&&l.opts.start.call(e,l),x.fx.timer(x.extend(u,{elem:e,anim:l,queue:l.opts.queue})),l.progress(l.opts.progress).done(l.opts.done,l.opts.complete).fail(l.opts.fail).always(l.opts.always)}function Dn(e,t){var n,r,i,o,s;for(n in e)if(r=x.camelCase(n),i=t[r],o=e[n],x.isArray(o)&&(i=o[1],o=e[n]=o[0]),n!==r&&(e[r]=o,delete e[n]),s=x.cssHooks[r],s&&"expand"in s){o=s.expand(o),delete e[r];for(n in o)n in e||(e[n]=o[n],t[n]=i)}else t[r]=i}x.Animation=x.extend(jn,{tweener:function(e,t){x.isFunction(e)?(t=e,e=["*"]):e=e.split(" ");var n,r=0,i=e.length;for(;i>r;r++)n=e[r],Nn[n]=Nn[n]||[],Nn[n].unshift(t)},prefilter:function(e,t){t?kn.unshift(e):kn.push(e)}});function An(e,t,n){var r,i,o,s,a,u,l=this,c={},p=e.style,f=e.nodeType&&Lt(e),h=q.get(e,"fxshow");n.queue||(a=x._queueHooks(e,"fx"),null==a.unqueued&&(a.unqueued=0,u=a.empty.fire,a.empty.fire=function(){a.unqueued||u()}),a.unqueued++,l.always(function(){l.always(function(){a.unqueued--,x.queue(e,"fx").length||a.empty.fire()})})),1===e.nodeType&&("height"in t||"width"in t)&&(n.overflow=[p.overflow,p.overflowX,p.overflowY],"inline"===x.css(e,"display")&&"none"===x.css(e,"float")&&(p.display="inline-block")),n.overflow&&(p.overflow="hidden",l.always(function(){p.overflow=n.overflow[0],p.overflowX=n.overflow[1],p.overflowY=n.overflow[2]}));for(r in t)if(i=t[r],wn.exec(i)){if(delete t[r],o=o||"toggle"===i,i===(f?"hide":"show")){if("show"!==i||!h||h[r]===undefined)continue;f=!0}c[r]=h&&h[r]||x.style(e,r)}if(!x.isEmptyObject(c)){h?"hidden"in h&&(f=h.hidden):h=q.access(e,"fxshow",{}),o&&(h.hidden=!f),f?x(e).show():l.done(function(){x(e).hide()}),l.done(function(){var t;q.remove(e,"fxshow");for(t in c)x.style(e,t,c[t])});for(r in c)s=Sn(f?h[r]:0,r,l),r in h||(h[r]=s.start,f&&(s.end=s.start,s.start="width"===r||"height"===r?1:0))}}function Ln(e,t,n,r,i){return new Ln.prototype.init(e,t,n,r,i)}x.Tween=Ln,Ln.prototype={constructor:Ln,init:function(e,t,n,r,i,o){this.elem=e,this.prop=n,this.easing=i||"swing",this.options=t,this.start=this.now=this.cur(),this.end=r,this.unit=o||(x.cssNumber[n]?"":"px")},cur:function(){var e=Ln.propHooks[this.prop];return e&&e.get?e.get(this):Ln.propHooks._default.get(this)},run:function(e){var t,n=Ln.propHooks[this.prop];return this.pos=t=this.options.duration?x.easing[this.easing](e,this.options.duration*e,0,1,this.options.duration):e,this.now=(this.end-this.start)*t+this.start,this.options.step&&this.options.step.call(this.elem,this.now,this),n&&n.set?n.set(this):Ln.propHooks._default.set(this),this}},Ln.prototype.init.prototype=Ln.prototype,Ln.propHooks={_default:{get:function(e){var t;return null==e.elem[e.prop]||e.elem.style&&null!=e.elem.style[e.prop]?(t=x.css(e.elem,e.prop,""),t&&"auto"!==t?t:0):e.elem[e.prop]},set:function(e){x.fx.step[e.prop]?x.fx.step[e.prop](e):e.elem.style&&(null!=e.elem.style[x.cssProps[e.prop]]||x.cssHooks[e.prop])?x.style(e.elem,e.prop,e.now+e.unit):e.elem[e.prop]=e.now}}},Ln.propHooks.scrollTop=Ln.propHooks.scrollLeft={set:function(e){e.elem.nodeType&&e.elem.parentNode&&(e.elem[e.prop]=e.now)}},x.each(["toggle","show","hide"],function(e,t){var n=x.fn[t];x.fn[t]=function(e,r,i){return null==e||"boolean"==typeof e?n.apply(this,arguments):this.animate(qn(t,!0),e,r,i)}}),x.fn.extend({fadeTo:function(e,t,n,r){return this.filter(Lt).css("opacity",0).show().end().animate({opacity:t},e,n,r)},animate:function(e,t,n,r){var i=x.isEmptyObject(e),o=x.speed(t,n,r),s=function(){var t=jn(this,x.extend({},e),o);(i||q.get(this,"finish"))&&t.stop(!0)};return s.finish=s,i||o.queue===!1?this.each(s):this.queue(o.queue,s)},stop:function(e,t,n){var r=function(e){var t=e.stop;delete e.stop,t(n)};return"string"!=typeof e&&(n=t,t=e,e=undefined),t&&e!==!1&&this.queue(e||"fx",[]),this.each(function(){var t=!0,i=null!=e&&e+"queueHooks",o=x.timers,s=q.get(this);if(i)s[i]&&s[i].stop&&r(s[i]);else for(i in s)s[i]&&s[i].stop&&Cn.test(i)&&r(s[i]);for(i=o.length;i--;)o[i].elem!==this||null!=e&&o[i].queue!==e||(o[i].anim.stop(n),t=!1,o.splice(i,1));(t||!n)&&x.dequeue(this,e)})},finish:function(e){return e!==!1&&(e=e||"fx"),this.each(function(){var t,n=q.get(this),r=n[e+"queue"],i=n[e+"queueHooks"],o=x.timers,s=r?r.length:0;for(n.finish=!0,x.queue(this,e,[]),i&&i.stop&&i.stop.call(this,!0),t=o.length;t--;)o[t].elem===this&&o[t].queue===e&&(o[t].anim.stop(!0),o.splice(t,1));for(t=0;s>t;t++)r[t]&&r[t].finish&&r[t].finish.call(this);delete n.finish})}});function qn(e,t){var n,r={height:e},i=0;for(t=t?1:0;4>i;i+=2-t)n=jt[i],r["margin"+n]=r["padding"+n]=e;return t&&(r.opacity=r.width=e),r}x.each({slideDown:qn("show"),slideUp:qn("hide"),slideToggle:qn("toggle"),fadeIn:{opacity:"show"},fadeOut:{opacity:"hide"},fadeToggle:{opacity:"toggle"}},function(e,t){x.fn[e]=function(e,n,r){return this.animate(t,e,n,r)}}),x.speed=function(e,t,n){var r=e&&"object"==typeof e?x.extend({},e):{complete:n||!n&&t||x.isFunction(e)&&e,duration:e,easing:n&&t||t&&!x.isFunction(t)&&t};return r.duration=x.fx.off?0:"number"==typeof r.duration?r.duration:r.duration in x.fx.speeds?x.fx.speeds[r.duration]:x.fx.speeds._default,(null==r.queue||r.queue===!0)&&(r.queue="fx"),r.old=r.complete,r.complete=function(){x.isFunction(r.old)&&r.old.call(this),r.queue&&x.dequeue(this,r.queue)},r},x.easing={linear:function(e){return e},swing:function(e){return.5-Math.cos(e*Math.PI)/2}},x.timers=[],x.fx=Ln.prototype.init,x.fx.tick=function(){var e,t=x.timers,n=0;for(xn=x.now();t.length>n;n++)e=t[n],e()||t[n]!==e||t.splice(n--,1);t.length||x.fx.stop(),xn=undefined},x.fx.timer=function(e){e()&&x.timers.push(e)&&x.fx.start()},x.fx.interval=13,x.fx.start=function(){bn||(bn=setInterval(x.fx.tick,x.fx.interval))},x.fx.stop=function(){clearInterval(bn),bn=null},x.fx.speeds={slow:600,fast:200,_default:400},x.fx.step={},x.expr&&x.expr.filters&&(x.expr.filters.animated=function(e){return x.grep(x.timers,function(t){return e===t.elem}).length}),x.fn.offset=function(e){if(arguments.length)return e===undefined?this:this.each(function(t){x.offset.setOffset(this,e,t)});var t,n,i=this[0],o={top:0,left:0},s=i&&i.ownerDocument;if(s)return t=s.documentElement,x.contains(t,i)?(typeof i.getBoundingClientRect!==r&&(o=i.getBoundingClientRect()),n=Hn(s),{top:o.top+n.pageYOffset-t.clientTop,left:o.left+n.pageXOffset-t.clientLeft}):o},x.offset={setOffset:function(e,t,n){var r,i,o,s,a,u,l,c=x.css(e,"position"),p=x(e),f={};"static"===c&&(e.style.position="relative"),a=p.offset(),o=x.css(e,"top"),u=x.css(e,"left"),l=("absolute"===c||"fixed"===c)&&(o+u).indexOf("auto")>-1,l?(r=p.position(),s=r.top,i=r.left):(s=parseFloat(o)||0,i=parseFloat(u)||0),x.isFunction(t)&&(t=t.call(e,n,a)),null!=t.top&&(f.top=t.top-a.top+s),null!=t.left&&(f.left=t.left-a.left+i),"using"in t?t.using.call(e,f):p.css(f)}},x.fn.extend({position:function(){if(this[0]){var e,t,n=this[0],r={top:0,left:0};return"fixed"===x.css(n,"position")?t=n.getBoundingClientRect():(e=this.offsetParent(),t=this.offset(),x.nodeName(e[0],"html")||(r=e.offset()),r.top+=x.css(e[0],"borderTopWidth",!0),r.left+=x.css(e[0],"borderLeftWidth",!0)),{top:t.top-r.top-x.css(n,"marginTop",!0),left:t.left-r.left-x.css(n,"marginLeft",!0)}}},offsetParent:function(){return this.map(function(){var e=this.offsetParent||s;while(e&&!x.nodeName(e,"html")&&"static"===x.css(e,"position"))e=e.offsetParent;return e||s})}}),x.each({scrollLeft:"pageXOffset",scrollTop:"pageYOffset"},function(t,n){var r="pageYOffset"===n;x.fn[t]=function(i){return x.access(this,function(t,i,o){var s=Hn(t);return o===undefined?s?s[n]:t[i]:(s?s.scrollTo(r?e.pageXOffset:o,r?o:e.pageYOffset):t[i]=o,undefined)},t,i,arguments.length,null)}});function Hn(e){return x.isWindow(e)?e:9===e.nodeType&&e.defaultView}x.each({Height:"height",Width:"width"},function(e,t){x.each({padding:"inner"+e,content:t,"":"outer"+e},function(n,r){x.fn[r]=function(r,i){var o=arguments.length&&(n||"boolean"!=typeof r),s=n||(r===!0||i===!0?"margin":"border");return x.access(this,function(t,n,r){var i;return x.isWindow(t)?t.document.documentElement["client"+e]:9===t.nodeType?(i=t.documentElement,Math.max(t.body["scroll"+e],i["scroll"+e],t.body["offset"+e],i["offset"+e],i["client"+e])):r===undefined?x.css(t,n,s):x.style(t,n,r,s)},t,o?r:undefined,o,null)}})}),x.fn.size=function(){return this.length},x.fn.andSelf=x.fn.addBack,"object"==typeof module&&module&&"object"==typeof module.exports?module.exports=x:"function"==typeof define&&define.amd&&define("jquery",[],function(){return x}),"object"==typeof e&&"object"==typeof e.document&&(e.jQuery=e.$=x)})(window);
diff --git a/docs/htmldoc/js/jquery.qtip.css b/docs/htmldoc/js/jquery.qtip.css
new file mode 100644
index 0000000..c2dcb30
--- /dev/null
+++ b/docs/htmldoc/js/jquery.qtip.css
@@ -0,0 +1,623 @@
+/*
+ * qTip2 - Pretty powerful tooltips - v2.2.0
+ * http://qtip2.com
+ *
+ * Copyright (c) 2013 Craig Michael Thompson
+ * Released under the MIT, GPL licenses
+ * http://jquery.org/license
+ *
+ * Date: Thu Nov 21 2013 08:34 GMT+0000
+ * Plugins: tips modal viewport svg imagemap ie6
+ * Styles: basic css3
+ */
+.qtip{
+ position: absolute;
+ left: -28000px;
+ top: -28000px;
+ display: none;
+
+ max-width: 280px;
+ min-width: 50px;
+
+ font-size: 10.5px;
+ line-height: 12px;
+
+ direction: ltr;
+
+ box-shadow: none;
+ padding: 0;
+}
+
+ .qtip-content{
+ position: relative;
+ padding: 5px 9px;
+ overflow: hidden;
+
+ text-align: left;
+ word-wrap: break-word;
+ }
+
+ .qtip-titlebar{
+ position: relative;
+ padding: 5px 35px 5px 10px;
+ overflow: hidden;
+
+ border-width: 0 0 1px;
+ font-weight: bold;
+ }
+
+ .qtip-titlebar + .qtip-content{ border-top-width: 0 !important; }
+
+ /* Default close button class */
+ .qtip-close{
+ position: absolute;
+ right: -9px; top: -9px;
+
+ cursor: pointer;
+ outline: medium none;
+
+ border-width: 1px;
+ border-style: solid;
+ border-color: transparent;
+ }
+
+ .qtip-titlebar .qtip-close{
+ right: 4px; top: 50%;
+ margin-top: -9px;
+ }
+
+ * html .qtip-titlebar .qtip-close{ top: 16px; } /* IE fix */
+
+ .qtip-titlebar .ui-icon,
+ .qtip-icon .ui-icon{
+ display: block;
+ text-indent: -1000em;
+ direction: ltr;
+ }
+
+ .qtip-icon, .qtip-icon .ui-icon{
+ -moz-border-radius: 3px;
+ -webkit-border-radius: 3px;
+ border-radius: 3px;
+ text-decoration: none;
+ }
+
+ .qtip-icon .ui-icon{
+ width: 18px;
+ height: 14px;
+
+ line-height: 14px;
+ text-align: center;
+ text-indent: 0;
+ font: normal bold 10px/13px Tahoma,sans-serif;
+
+ color: inherit;
+ background: transparent none no-repeat -100em -100em;
+ }
+
+/* Applied to 'focused' tooltips e.g. most recently displayed/interacted with */
+.qtip-focus{}
+
+/* Applied on hover of tooltips i.e. added/removed on mouseenter/mouseleave respectively */
+.qtip-hover{}
+
+/* Default tooltip style */
+.qtip-default{
+ border-width: 1px;
+ border-style: solid;
+ border-color: #F1D031;
+
+ background-color: #FFFFA3;
+ color: #555;
+}
+
+ .qtip-default .qtip-titlebar{
+ background-color: #FFEF93;
+ }
+
+ .qtip-default .qtip-icon{
+ border-color: #CCC;
+ background: #F1F1F1;
+ color: #777;
+ }
+
+ .qtip-default .qtip-titlebar .qtip-close{
+ border-color: #AAA;
+ color: #111;
+ }
+
+
+
+/*! Light tooltip style */
+.qtip-light{
+ background-color: white;
+ border-color: #E2E2E2;
+ color: #454545;
+}
+
+ .qtip-light .qtip-titlebar{
+ background-color: #f1f1f1;
+ }
+
+
+/*! Dark tooltip style */
+.qtip-dark{
+ background-color: #505050;
+ border-color: #303030;
+ color: #f3f3f3;
+}
+
+ .qtip-dark .qtip-titlebar{
+ background-color: #404040;
+ }
+
+ .qtip-dark .qtip-icon{
+ border-color: #444;
+ }
+
+ .qtip-dark .qtip-titlebar .ui-state-hover{
+ border-color: #303030;
+ }
+
+
+/*! Cream tooltip style */
+.qtip-cream{
+ background-color: #FBF7AA;
+ border-color: #F9E98E;
+ color: #A27D35;
+}
+
+ .qtip-cream .qtip-titlebar{
+ background-color: #F0DE7D;
+ }
+
+ .qtip-cream .qtip-close .qtip-icon{
+ background-position: -82px 0;
+ }
+
+
+/*! Red tooltip style */
+.qtip-red{
+ background-color: #F78B83;
+ border-color: #D95252;
+ color: #912323;
+}
+
+ .qtip-red .qtip-titlebar{
+ background-color: #F06D65;
+ }
+
+ .qtip-red .qtip-close .qtip-icon{
+ background-position: -102px 0;
+ }
+
+ .qtip-red .qtip-icon{
+ border-color: #D95252;
+ }
+
+ .qtip-red .qtip-titlebar .ui-state-hover{
+ border-color: #D95252;
+ }
+
+
+/*! Green tooltip style */
+.qtip-green{
+ background-color: #CAED9E;
+ border-color: #90D93F;
+ color: #3F6219;
+}
+
+ .qtip-green .qtip-titlebar{
+ background-color: #B0DE78;
+ }
+
+ .qtip-green .qtip-close .qtip-icon{
+ background-position: -42px 0;
+ }
+
+
+/*! Blue tooltip style */
+.qtip-blue{
+ background-color: #E5F6FE;
+ border-color: #ADD9ED;
+ color: #5E99BD;
+}
+
+ .qtip-blue .qtip-titlebar{
+ background-color: #D0E9F5;
+ }
+
+ .qtip-blue .qtip-close .qtip-icon{
+ background-position: -2px 0;
+ }
+
+
+
+.qtip-shadow{
+ -webkit-box-shadow: 1px 1px 3px 1px rgba(0, 0, 0, 0.15);
+ -moz-box-shadow: 1px 1px 3px 1px rgba(0, 0, 0, 0.15);
+ box-shadow: 1px 1px 3px 1px rgba(0, 0, 0, 0.15);
+}
+
+/* Add rounded corners to your tooltips in: FF3+, Chrome 2+, Opera 10.6+, IE9+, Safari 2+ */
+.qtip-rounded,
+.qtip-tipsy,
+.qtip-bootstrap{
+ -moz-border-radius: 5px;
+ -webkit-border-radius: 5px;
+ border-radius: 5px;
+}
+
+.qtip-rounded .qtip-titlebar{
+ -moz-border-radius: 4px 4px 0 0;
+ -webkit-border-radius: 4px 4px 0 0;
+ border-radius: 4px 4px 0 0;
+}
+
+/* Youtube tooltip style */
+.qtip-youtube{
+ -moz-border-radius: 2px;
+ -webkit-border-radius: 2px;
+ border-radius: 2px;
+
+ -webkit-box-shadow: 0 0 3px #333;
+ -moz-box-shadow: 0 0 3px #333;
+ box-shadow: 0 0 3px #333;
+
+ color: white;
+ border-width: 0;
+
+ background: #4A4A4A;
+ background-image: -webkit-gradient(linear,left top,left bottom,color-stop(0,#4A4A4A),color-stop(100%,black));
+ background-image: -webkit-linear-gradient(top,#4A4A4A 0,black 100%);
+ background-image: -moz-linear-gradient(top,#4A4A4A 0,black 100%);
+ background-image: -ms-linear-gradient(top,#4A4A4A 0,black 100%);
+ background-image: -o-linear-gradient(top,#4A4A4A 0,black 100%);
+}
+
+ .qtip-youtube .qtip-titlebar{
+ background-color: #4A4A4A;
+ background-color: rgba(0,0,0,0);
+ }
+
+ .qtip-youtube .qtip-content{
+ padding: .75em;
+ font: 12px arial,sans-serif;
+
+ filter: progid:DXImageTransform.Microsoft.Gradient(GradientType=0,StartColorStr=#4a4a4a,EndColorStr=#000000);
+ -ms-filter: "progid:DXImageTransform.Microsoft.Gradient(GradientType=0,StartColorStr=#4a4a4a,EndColorStr=#000000);";
+ }
+
+ .qtip-youtube .qtip-icon{
+ border-color: #222;
+ }
+
+ .qtip-youtube .qtip-titlebar .ui-state-hover{
+ border-color: #303030;
+ }
+
+
+/* jQuery TOOLS Tooltip style */
+.qtip-jtools{
+ background: #232323;
+ background: rgba(0, 0, 0, 0.7);
+ background-image: -webkit-gradient(linear, left top, left bottom, from(#717171), to(#232323));
+ background-image: -moz-linear-gradient(top, #717171, #232323);
+ background-image: -webkit-linear-gradient(top, #717171, #232323);
+ background-image: -ms-linear-gradient(top, #717171, #232323);
+ background-image: -o-linear-gradient(top, #717171, #232323);
+
+ border: 2px solid #ddd;
+ border: 2px solid rgba(241,241,241,1);
+
+ -moz-border-radius: 2px;
+ -webkit-border-radius: 2px;
+ border-radius: 2px;
+
+ -webkit-box-shadow: 0 0 12px #333;
+ -moz-box-shadow: 0 0 12px #333;
+ box-shadow: 0 0 12px #333;
+}
+
+ /* IE Specific */
+ .qtip-jtools .qtip-titlebar{
+ background-color: transparent;
+ filter:progid:DXImageTransform.Microsoft.gradient(startColorstr=#717171,endColorstr=#4A4A4A);
+ -ms-filter: "progid:DXImageTransform.Microsoft.gradient(startColorstr=#717171,endColorstr=#4A4A4A)";
+ }
+ .qtip-jtools .qtip-content{
+ filter:progid:DXImageTransform.Microsoft.gradient(startColorstr=#4A4A4A,endColorstr=#232323);
+ -ms-filter: "progid:DXImageTransform.Microsoft.gradient(startColorstr=#4A4A4A,endColorstr=#232323)";
+ }
+
+ .qtip-jtools .qtip-titlebar,
+ .qtip-jtools .qtip-content{
+ background: transparent;
+ color: white;
+ border: 0 dashed transparent;
+ }
+
+ .qtip-jtools .qtip-icon{
+ border-color: #555;
+ }
+
+ .qtip-jtools .qtip-titlebar .ui-state-hover{
+ border-color: #333;
+ }
+
+
+/* Cluetip style */
+.qtip-cluetip{
+ -webkit-box-shadow: 4px 4px 5px rgba(0, 0, 0, 0.4);
+ -moz-box-shadow: 4px 4px 5px rgba(0, 0, 0, 0.4);
+ box-shadow: 4px 4px 5px rgba(0, 0, 0, 0.4);
+
+ background-color: #D9D9C2;
+ color: #111;
+ border: 0 dashed transparent;
+}
+
+ .qtip-cluetip .qtip-titlebar{
+ background-color: #87876A;
+ color: white;
+ border: 0 dashed transparent;
+ }
+
+ .qtip-cluetip .qtip-icon{
+ border-color: #808064;
+ }
+
+ .qtip-cluetip .qtip-titlebar .ui-state-hover{
+ border-color: #696952;
+ color: #696952;
+ }
+
+
+/* Tipsy style */
+.qtip-tipsy{
+ background: black;
+ background: rgba(0, 0, 0, .87);
+
+ color: white;
+ border: 0 solid transparent;
+
+ font-size: 11px;
+ font-family: 'Lucida Grande', sans-serif;
+ font-weight: bold;
+ line-height: 16px;
+ text-shadow: 0 1px black;
+}
+
+ .qtip-tipsy .qtip-titlebar{
+ padding: 6px 35px 0 10px;
+ background-color: transparent;
+ }
+
+ .qtip-tipsy .qtip-content{
+ padding: 6px 10px;
+ }
+
+ .qtip-tipsy .qtip-icon{
+ border-color: #222;
+ text-shadow: none;
+ }
+
+ .qtip-tipsy .qtip-titlebar .ui-state-hover{
+ border-color: #303030;
+ }
+
+
+/* Tipped style */
+.qtip-tipped{
+ border: 3px solid #959FA9;
+
+ -moz-border-radius: 3px;
+ -webkit-border-radius: 3px;
+ border-radius: 3px;
+
+ background-color: #F9F9F9;
+ color: #454545;
+
+ font-weight: normal;
+ font-family: serif;
+}
+
+ .qtip-tipped .qtip-titlebar{
+ border-bottom-width: 0;
+
+ color: white;
+ background: #3A79B8;
+ background-image: -webkit-gradient(linear, left top, left bottom, from(#3A79B8), to(#2E629D));
+ background-image: -webkit-linear-gradient(top, #3A79B8, #2E629D);
+ background-image: -moz-linear-gradient(top, #3A79B8, #2E629D);
+ background-image: -ms-linear-gradient(top, #3A79B8, #2E629D);
+ background-image: -o-linear-gradient(top, #3A79B8, #2E629D);
+ filter:progid:DXImageTransform.Microsoft.gradient(startColorstr=#3A79B8,endColorstr=#2E629D);
+ -ms-filter: "progid:DXImageTransform.Microsoft.gradient(startColorstr=#3A79B8,endColorstr=#2E629D)";
+ }
+
+ .qtip-tipped .qtip-icon{
+ border: 2px solid #285589;
+ background: #285589;
+ }
+
+ .qtip-tipped .qtip-icon .ui-icon{
+ background-color: #FBFBFB;
+ color: #555;
+ }
+
+
+/**
+ * Twitter Bootstrap style.
+ *
+ * Tested with IE 8, IE 9, Chrome 18, Firefox 9, Opera 11.
+ * Does not work with IE 7.
+ */
+.qtip-bootstrap{
+ /** Taken from Bootstrap body */
+ font-size: 14px;
+ line-height: 20px;
+ color: #333333;
+
+ /** Taken from Bootstrap .popover */
+ padding: 1px;
+ background-color: #ffffff;
+ border: 1px solid #ccc;
+ border: 1px solid rgba(0, 0, 0, 0.2);
+ -webkit-border-radius: 6px;
+ -moz-border-radius: 6px;
+ border-radius: 6px;
+ -webkit-box-shadow: 0 5px 10px rgba(0, 0, 0, 0.2);
+ -moz-box-shadow: 0 5px 10px rgba(0, 0, 0, 0.2);
+ box-shadow: 0 5px 10px rgba(0, 0, 0, 0.2);
+ -webkit-background-clip: padding-box;
+ -moz-background-clip: padding;
+ background-clip: padding-box;
+}
+
+ .qtip-bootstrap .qtip-titlebar{
+ /** Taken from Bootstrap .popover-title */
+ padding: 8px 14px;
+ margin: 0;
+ font-size: 14px;
+ font-weight: normal;
+ line-height: 18px;
+ background-color: #f7f7f7;
+ border-bottom: 1px solid #ebebeb;
+ -webkit-border-radius: 5px 5px 0 0;
+ -moz-border-radius: 5px 5px 0 0;
+ border-radius: 5px 5px 0 0;
+ }
+
+ .qtip-bootstrap .qtip-titlebar .qtip-close{
+ /**
+ * Overrides qTip2:
+ * .qtip-titlebar .qtip-close{
+ * [...]
+ * right: 4px;
+ * top: 50%;
+ * [...]
+ * border-style: solid;
+ * }
+ */
+ right: 11px;
+ top: 45%;
+ border-style: none;
+ }
+
+ .qtip-bootstrap .qtip-content{
+ /** Taken from Bootstrap .popover-content */
+ padding: 9px 14px;
+ }
+
+ .qtip-bootstrap .qtip-icon{
+ /**
+ * Overrides qTip2:
+ * .qtip-default .qtip-icon {
+ * border-color: #CCC;
+ * background: #F1F1F1;
+ * color: #777;
+ * }
+ */
+ background: transparent;
+ }
+
+ .qtip-bootstrap .qtip-icon .ui-icon{
+ /**
+ * Overrides qTip2:
+ * .qtip-icon .ui-icon{
+ * width: 18px;
+ * height: 14px;
+ * }
+ */
+ width: auto;
+ height: auto;
+
+ /* Taken from Bootstrap .close */
+ float: right;
+ font-size: 20px;
+ font-weight: bold;
+ line-height: 18px;
+ color: #000000;
+ text-shadow: 0 1px 0 #ffffff;
+ opacity: 0.2;
+ filter: alpha(opacity=20);
+ }
+
+ .qtip-bootstrap .qtip-icon .ui-icon:hover{
+ /* Taken from Bootstrap .close:hover */
+ color: #000000;
+ text-decoration: none;
+ cursor: pointer;
+ opacity: 0.4;
+ filter: alpha(opacity=40);
+ }
+
+
+/* IE9 fix - removes all filters */
+.qtip:not(.ie9haxors) div.qtip-content,
+.qtip:not(.ie9haxors) div.qtip-titlebar{
+ filter: none;
+ -ms-filter: none;
+}
+
+
+
+.qtip .qtip-tip{
+ margin: 0 auto;
+ overflow: hidden;
+ z-index: 10;
+
+}
+
+ /* Opera bug #357 - Incorrect tip position
+ https://github.com/Craga89/qTip2/issues/367 */
+ x:-o-prefocus, .qtip .qtip-tip{
+ visibility: hidden;
+ }
+
+ .qtip .qtip-tip,
+ .qtip .qtip-tip .qtip-vml,
+ .qtip .qtip-tip canvas{
+ position: absolute;
+
+ color: #123456;
+ background: transparent;
+ border: 0 dashed transparent;
+ }
+
+ .qtip .qtip-tip canvas{ top: 0; left: 0; }
+
+ .qtip .qtip-tip .qtip-vml{
+ behavior: url(#default#VML);
+ display: inline-block;
+ visibility: visible;
+ }
+
+#qtip-overlay{
+ position: fixed;
+ left: 0; top: 0;
+ width: 100%; height: 100%;
+}
+
+ /* Applied to modals with show.modal.blur set to true */
+ #qtip-overlay.blurs{ cursor: pointer; }
+
+ /* Change opacity of overlay here */
+ #qtip-overlay div{
+ position: absolute;
+ left: 0; top: 0;
+ width: 100%; height: 100%;
+
+ background-color: black;
+
+ opacity: 0.7;
+ filter:alpha(opacity=70);
+ -ms-filter:"progid:DXImageTransform.Microsoft.Alpha(Opacity=70)";
+ }
+
+
+
+.qtipmodal-ie6fix{
+ position: absolute !important;
+} \ No newline at end of file
diff --git a/docs/htmldoc/js/jquery.qtip.js b/docs/htmldoc/js/jquery.qtip.js
new file mode 100644
index 0000000..52443c0
--- /dev/null
+++ b/docs/htmldoc/js/jquery.qtip.js
@@ -0,0 +1,3440 @@
+/*
+ * qTip2 - Pretty powerful tooltips - v2.2.0
+ * http://qtip2.com
+ *
+ * Copyright (c) 2013 Craig Michael Thompson
+ * Released under the MIT, GPL licenses
+ * http://jquery.org/license
+ *
+ * Date: Thu Nov 21 2013 08:34 GMT+0000
+ * Plugins: tips modal viewport svg imagemap ie6
+ * Styles: basic css3
+ */
+/*global window: false, jQuery: false, console: false, define: false */
+
+/* Cache window, document, undefined */
+(function( window, document, undefined ) {
+
+// Uses AMD or browser globals to create a jQuery plugin.
+(function( factory ) {
+ "use strict";
+ if(typeof define === 'function' && define.amd) {
+ define(['jquery'], factory);
+ }
+ else if(jQuery && !jQuery.fn.qtip) {
+ factory(jQuery);
+ }
+}
+(function($) {
+ "use strict"; // Enable ECMAScript "strict" operation for this function. See more: http://ejohn.org/blog/ecmascript-5-strict-mode-json-and-more/
+
+;// Munge the primitives - Paul Irish tip
+var TRUE = true,
+FALSE = false,
+NULL = null,
+
+// Common variables
+X = 'x', Y = 'y',
+WIDTH = 'width',
+HEIGHT = 'height',
+
+// Positioning sides
+TOP = 'top',
+LEFT = 'left',
+BOTTOM = 'bottom',
+RIGHT = 'right',
+CENTER = 'center',
+
+// Position adjustment types
+FLIP = 'flip',
+FLIPINVERT = 'flipinvert',
+SHIFT = 'shift',
+
+// Shortcut vars
+QTIP, PROTOTYPE, CORNER, CHECKS,
+PLUGINS = {},
+NAMESPACE = 'qtip',
+ATTR_HAS = 'data-hasqtip',
+ATTR_ID = 'data-qtip-id',
+WIDGET = ['ui-widget', 'ui-tooltip'],
+SELECTOR = '.'+NAMESPACE,
+INACTIVE_EVENTS = 'click dblclick mousedown mouseup mousemove mouseleave mouseenter'.split(' '),
+
+CLASS_FIXED = NAMESPACE+'-fixed',
+CLASS_DEFAULT = NAMESPACE + '-default',
+CLASS_FOCUS = NAMESPACE + '-focus',
+CLASS_HOVER = NAMESPACE + '-hover',
+CLASS_DISABLED = NAMESPACE+'-disabled',
+
+replaceSuffix = '_replacedByqTip',
+oldtitle = 'oldtitle',
+trackingBound,
+
+// Browser detection
+BROWSER = {
+ /*
+ * IE version detection
+ *
+ * Adapted from: http://ajaxian.com/archives/attack-of-the-ie-conditional-comment
+ * Credit to James Padolsey for the original implemntation!
+ */
+ ie: (function(){
+ var v = 3, div = document.createElement('div');
+ while ((div.innerHTML = '<!--[if gt IE '+(++v)+']><i></i><![endif]-->')) {
+ if(!div.getElementsByTagName('i')[0]) { break; }
+ }
+ return v > 4 ? v : NaN;
+ }()),
+
+ /*
+ * iOS version detection
+ */
+ iOS: parseFloat(
+ ('' + (/CPU.*OS ([0-9_]{1,5})|(CPU like).*AppleWebKit.*Mobile/i.exec(navigator.userAgent) || [0,''])[1])
+ .replace('undefined', '3_2').replace('_', '.').replace('_', '')
+ ) || FALSE
+};
+
+;function QTip(target, options, id, attr) {
+ // Elements and ID
+ this.id = id;
+ this.target = target;
+ this.tooltip = NULL;
+ this.elements = { target: target };
+
+ // Internal constructs
+ this._id = NAMESPACE + '-' + id;
+ this.timers = { img: {} };
+ this.options = options;
+ this.plugins = {};
+
+ // Cache object
+ this.cache = {
+ event: {},
+ target: $(),
+ disabled: FALSE,
+ attr: attr,
+ onTooltip: FALSE,
+ lastClass: ''
+ };
+
+ // Set the initial flags
+ this.rendered = this.destroyed = this.disabled = this.waiting =
+ this.hiddenDuringWait = this.positioning = this.triggering = FALSE;
+}
+PROTOTYPE = QTip.prototype;
+
+PROTOTYPE._when = function(deferreds) {
+ return $.when.apply($, deferreds);
+};
+
+PROTOTYPE.render = function(show) {
+ if(this.rendered || this.destroyed) { return this; } // If tooltip has already been rendered, exit
+
+ var self = this,
+ options = this.options,
+ cache = this.cache,
+ elements = this.elements,
+ text = options.content.text,
+ title = options.content.title,
+ button = options.content.button,
+ posOptions = options.position,
+ namespace = '.'+this._id+' ',
+ deferreds = [],
+ tooltip;
+
+ // Add ARIA attributes to target
+ $.attr(this.target[0], 'aria-describedby', this._id);
+
+ // Create tooltip element
+ this.tooltip = elements.tooltip = tooltip = $('<div/>', {
+ 'id': this._id,
+ 'class': [ NAMESPACE, CLASS_DEFAULT, options.style.classes, NAMESPACE + '-pos-' + options.position.my.abbrev() ].join(' '),
+ 'width': options.style.width || '',
+ 'height': options.style.height || '',
+ 'tracking': posOptions.target === 'mouse' && posOptions.adjust.mouse,
+
+ /* ARIA specific attributes */
+ 'role': 'alert',
+ 'aria-live': 'polite',
+ 'aria-atomic': FALSE,
+ 'aria-describedby': this._id + '-content',
+ 'aria-hidden': TRUE
+ })
+ .toggleClass(CLASS_DISABLED, this.disabled)
+ .attr(ATTR_ID, this.id)
+ .data(NAMESPACE, this)
+ .appendTo(posOptions.container)
+ .append(
+ // Create content element
+ elements.content = $('<div />', {
+ 'class': NAMESPACE + '-content',
+ 'id': this._id + '-content',
+ 'aria-atomic': TRUE
+ })
+ );
+
+ // Set rendered flag and prevent redundant reposition calls for now
+ this.rendered = -1;
+ this.positioning = TRUE;
+
+ // Create title...
+ if(title) {
+ this._createTitle();
+
+ // Update title only if its not a callback (called in toggle if so)
+ if(!$.isFunction(title)) {
+ deferreds.push( this._updateTitle(title, FALSE) );
+ }
+ }
+
+ // Create button
+ if(button) { this._createButton(); }
+
+ // Set proper rendered flag and update content if not a callback function (called in toggle)
+ if(!$.isFunction(text)) {
+ deferreds.push( this._updateContent(text, FALSE) );
+ }
+ this.rendered = TRUE;
+
+ // Setup widget classes
+ this._setWidget();
+
+ // Initialize 'render' plugins
+ $.each(PLUGINS, function(name) {
+ var instance;
+ if(this.initialize === 'render' && (instance = this(self))) {
+ self.plugins[name] = instance;
+ }
+ });
+
+ // Unassign initial events and assign proper events
+ this._unassignEvents();
+ this._assignEvents();
+
+ // When deferreds have completed
+ this._when(deferreds).then(function() {
+ // tooltiprender event
+ self._trigger('render');
+
+ // Reset flags
+ self.positioning = FALSE;
+
+ // Show tooltip if not hidden during wait period
+ if(!self.hiddenDuringWait && (options.show.ready || show)) {
+ self.toggle(TRUE, cache.event, FALSE);
+ }
+ self.hiddenDuringWait = FALSE;
+ });
+
+ // Expose API
+ QTIP.api[this.id] = this;
+
+ return this;
+};
+
+PROTOTYPE.destroy = function(immediate) {
+ // Set flag the signify destroy is taking place to plugins
+ // and ensure it only gets destroyed once!
+ if(this.destroyed) { return this.target; }
+
+ function process() {
+ if(this.destroyed) { return; }
+ this.destroyed = TRUE;
+
+ var target = this.target,
+ title = target.attr(oldtitle);
+
+ // Destroy tooltip if rendered
+ if(this.rendered) {
+ this.tooltip.stop(1,0).find('*').remove().end().remove();
+ }
+
+ // Destroy all plugins
+ $.each(this.plugins, function(name) {
+ this.destroy && this.destroy();
+ });
+
+ // Clear timers and remove bound events
+ clearTimeout(this.timers.show);
+ clearTimeout(this.timers.hide);
+ this._unassignEvents();
+
+ // Remove api object and ARIA attributes
+ target.removeData(NAMESPACE)
+ .removeAttr(ATTR_ID)
+ .removeAttr(ATTR_HAS)
+ .removeAttr('aria-describedby');
+
+ // Reset old title attribute if removed
+ if(this.options.suppress && title) {
+ target.attr('title', title).removeAttr(oldtitle);
+ }
+
+ // Remove qTip events associated with this API
+ this._unbind(target);
+
+ // Remove ID from used id objects, and delete object references
+ // for better garbage collection and leak protection
+ this.options = this.elements = this.cache = this.timers =
+ this.plugins = this.mouse = NULL;
+
+ // Delete epoxsed API object
+ delete QTIP.api[this.id];
+ }
+
+ // If an immediate destory is needed
+ if((immediate !== TRUE || this.triggering === 'hide') && this.rendered) {
+ this.tooltip.one('tooltiphidden', $.proxy(process, this));
+ !this.triggering && this.hide();
+ }
+
+ // If we're not in the process of hiding... process
+ else { process.call(this); }
+
+ return this.target;
+};
+
+;function invalidOpt(a) {
+ return a === NULL || $.type(a) !== 'object';
+}
+
+function invalidContent(c) {
+ return !( $.isFunction(c) || (c && c.attr) || c.length || ($.type(c) === 'object' && (c.jquery || c.then) ));
+}
+
+// Option object sanitizer
+function sanitizeOptions(opts) {
+ var content, text, ajax, once;
+
+ if(invalidOpt(opts)) { return FALSE; }
+
+ if(invalidOpt(opts.metadata)) {
+ opts.metadata = { type: opts.metadata };
+ }
+
+ if('content' in opts) {
+ content = opts.content;
+
+ if(invalidOpt(content) || content.jquery || content.done) {
+ content = opts.content = {
+ text: (text = invalidContent(content) ? FALSE : content)
+ };
+ }
+ else { text = content.text; }
+
+ // DEPRECATED - Old content.ajax plugin functionality
+ // Converts it into the proper Deferred syntax
+ if('ajax' in content) {
+ ajax = content.ajax;
+ once = ajax && ajax.once !== FALSE;
+ delete content.ajax;
+
+ content.text = function(event, api) {
+ var loading = text || $(this).attr(api.options.content.attr) || 'Loading...',
+
+ deferred = $.ajax(
+ $.extend({}, ajax, { context: api })
+ )
+ .then(ajax.success, NULL, ajax.error)
+ .then(function(content) {
+ if(content && once) { api.set('content.text', content); }
+ return content;
+ },
+ function(xhr, status, error) {
+ if(api.destroyed || xhr.status === 0) { return; }
+ api.set('content.text', status + ': ' + error);
+ });
+
+ return !once ? (api.set('content.text', loading), deferred) : loading;
+ };
+ }
+
+ if('title' in content) {
+ if(!invalidOpt(content.title)) {
+ content.button = content.title.button;
+ content.title = content.title.text;
+ }
+
+ if(invalidContent(content.title || FALSE)) {
+ content.title = FALSE;
+ }
+ }
+ }
+
+ if('position' in opts && invalidOpt(opts.position)) {
+ opts.position = { my: opts.position, at: opts.position };
+ }
+
+ if('show' in opts && invalidOpt(opts.show)) {
+ opts.show = opts.show.jquery ? { target: opts.show } :
+ opts.show === TRUE ? { ready: TRUE } : { event: opts.show };
+ }
+
+ if('hide' in opts && invalidOpt(opts.hide)) {
+ opts.hide = opts.hide.jquery ? { target: opts.hide } : { event: opts.hide };
+ }
+
+ if('style' in opts && invalidOpt(opts.style)) {
+ opts.style = { classes: opts.style };
+ }
+
+ // Sanitize plugin options
+ $.each(PLUGINS, function() {
+ this.sanitize && this.sanitize(opts);
+ });
+
+ return opts;
+}
+
+// Setup builtin .set() option checks
+CHECKS = PROTOTYPE.checks = {
+ builtin: {
+ // Core checks
+ '^id$': function(obj, o, v, prev) {
+ var id = v === TRUE ? QTIP.nextid : v,
+ new_id = NAMESPACE + '-' + id;
+
+ if(id !== FALSE && id.length > 0 && !$('#'+new_id).length) {
+ this._id = new_id;
+
+ if(this.rendered) {
+ this.tooltip[0].id = this._id;
+ this.elements.content[0].id = this._id + '-content';
+ this.elements.title[0].id = this._id + '-title';
+ }
+ }
+ else { obj[o] = prev; }
+ },
+ '^prerender': function(obj, o, v) {
+ v && !this.rendered && this.render(this.options.show.ready);
+ },
+
+ // Content checks
+ '^content.text$': function(obj, o, v) {
+ this._updateContent(v);
+ },
+ '^content.attr$': function(obj, o, v, prev) {
+ if(this.options.content.text === this.target.attr(prev)) {
+ this._updateContent( this.target.attr(v) );
+ }
+ },
+ '^content.title$': function(obj, o, v) {
+ // Remove title if content is null
+ if(!v) { return this._removeTitle(); }
+
+ // If title isn't already created, create it now and update
+ v && !this.elements.title && this._createTitle();
+ this._updateTitle(v);
+ },
+ '^content.button$': function(obj, o, v) {
+ this._updateButton(v);
+ },
+ '^content.title.(text|button)$': function(obj, o, v) {
+ this.set('content.'+o, v); // Backwards title.text/button compat
+ },
+
+ // Position checks
+ '^position.(my|at)$': function(obj, o, v){
+ 'string' === typeof v && (obj[o] = new CORNER(v, o === 'at'));
+ },
+ '^position.container$': function(obj, o, v){
+ this.rendered && this.tooltip.appendTo(v);
+ },
+
+ // Show checks
+ '^show.ready$': function(obj, o, v) {
+ v && (!this.rendered && this.render(TRUE) || this.toggle(TRUE));
+ },
+
+ // Style checks
+ '^style.classes$': function(obj, o, v, p) {
+ this.rendered && this.tooltip.removeClass(p).addClass(v);
+ },
+ '^style.(width|height)': function(obj, o, v) {
+ this.rendered && this.tooltip.css(o, v);
+ },
+ '^style.widget|content.title': function() {
+ this.rendered && this._setWidget();
+ },
+ '^style.def': function(obj, o, v) {
+ this.rendered && this.tooltip.toggleClass(CLASS_DEFAULT, !!v);
+ },
+
+ // Events check
+ '^events.(render|show|move|hide|focus|blur)$': function(obj, o, v) {
+ this.rendered && this.tooltip[($.isFunction(v) ? '' : 'un') + 'bind']('tooltip'+o, v);
+ },
+
+ // Properties which require event reassignment
+ '^(show|hide|position).(event|target|fixed|inactive|leave|distance|viewport|adjust)': function() {
+ if(!this.rendered) { return; }
+
+ // Set tracking flag
+ var posOptions = this.options.position;
+ this.tooltip.attr('tracking', posOptions.target === 'mouse' && posOptions.adjust.mouse);
+
+ // Reassign events
+ this._unassignEvents();
+ this._assignEvents();
+ }
+ }
+};
+
+// Dot notation converter
+function convertNotation(options, notation) {
+ var i = 0, obj, option = options,
+
+ // Split notation into array
+ levels = notation.split('.');
+
+ // Loop through
+ while( option = option[ levels[i++] ] ) {
+ if(i < levels.length) { obj = option; }
+ }
+
+ return [obj || options, levels.pop()];
+}
+
+PROTOTYPE.get = function(notation) {
+ if(this.destroyed) { return this; }
+
+ var o = convertNotation(this.options, notation.toLowerCase()),
+ result = o[0][ o[1] ];
+
+ return result.precedance ? result.string() : result;
+};
+
+function setCallback(notation, args) {
+ var category, rule, match;
+
+ for(category in this.checks) {
+ for(rule in this.checks[category]) {
+ if(match = (new RegExp(rule, 'i')).exec(notation)) {
+ args.push(match);
+
+ if(category === 'builtin' || this.plugins[category]) {
+ this.checks[category][rule].apply(
+ this.plugins[category] || this, args
+ );
+ }
+ }
+ }
+ }
+}
+
+var rmove = /^position\.(my|at|adjust|target|container|viewport)|style|content|show\.ready/i,
+ rrender = /^prerender|show\.ready/i;
+
+PROTOTYPE.set = function(option, value) {
+ if(this.destroyed) { return this; }
+
+ var rendered = this.rendered,
+ reposition = FALSE,
+ options = this.options,
+ checks = this.checks,
+ name;
+
+ // Convert singular option/value pair into object form
+ if('string' === typeof option) {
+ name = option; option = {}; option[name] = value;
+ }
+ else { option = $.extend({}, option); }
+
+ // Set all of the defined options to their new values
+ $.each(option, function(notation, value) {
+ if(rendered && rrender.test(notation)) {
+ delete option[notation]; return;
+ }
+
+ // Set new obj value
+ var obj = convertNotation(options, notation.toLowerCase()), previous;
+ previous = obj[0][ obj[1] ];
+ obj[0][ obj[1] ] = value && value.nodeType ? $(value) : value;
+
+ // Also check if we need to reposition
+ reposition = rmove.test(notation) || reposition;
+
+ // Set the new params for the callback
+ option[notation] = [obj[0], obj[1], value, previous];
+ });
+
+ // Re-sanitize options
+ sanitizeOptions(options);
+
+ /*
+ * Execute any valid callbacks for the set options
+ * Also set positioning flag so we don't get loads of redundant repositioning calls.
+ */
+ this.positioning = TRUE;
+ $.each(option, $.proxy(setCallback, this));
+ this.positioning = FALSE;
+
+ // Update position if needed
+ if(this.rendered && this.tooltip[0].offsetWidth > 0 && reposition) {
+ this.reposition( options.position.target === 'mouse' ? NULL : this.cache.event );
+ }
+
+ return this;
+};
+
+;PROTOTYPE._update = function(content, element, reposition) {
+ var self = this,
+ cache = this.cache;
+
+ // Make sure tooltip is rendered and content is defined. If not return
+ if(!this.rendered || !content) { return FALSE; }
+
+ // Use function to parse content
+ if($.isFunction(content)) {
+ content = content.call(this.elements.target, cache.event, this) || '';
+ }
+
+ // Handle deferred content
+ if($.isFunction(content.then)) {
+ cache.waiting = TRUE;
+ return content.then(function(c) {
+ cache.waiting = FALSE;
+ return self._update(c, element);
+ }, NULL, function(e) {
+ return self._update(e, element);
+ });
+ }
+
+ // If content is null... return false
+ if(content === FALSE || (!content && content !== '')) { return FALSE; }
+
+ // Append new content if its a DOM array and show it if hidden
+ if(content.jquery && content.length > 0) {
+ element.empty().append(
+ content.css({ display: 'block', visibility: 'visible' })
+ );
+ }
+
+ // Content is a regular string, insert the new content
+ else { element.html(content); }
+
+ // Wait for content to be loaded, and reposition
+ return this._waitForContent(element).then(function(images) {
+ if(images.images && images.images.length && self.rendered && self.tooltip[0].offsetWidth > 0) {
+ self.reposition(cache.event, !images.length);
+ }
+ });
+};
+
+PROTOTYPE._waitForContent = function(element) {
+ var cache = this.cache;
+
+ // Set flag
+ cache.waiting = TRUE;
+
+ // If imagesLoaded is included, ensure images have loaded and return promise
+ return ( $.fn.imagesLoaded ? element.imagesLoaded() : $.Deferred().resolve([]) )
+ .done(function() { cache.waiting = FALSE; })
+ .promise();
+};
+
+PROTOTYPE._updateContent = function(content, reposition) {
+ this._update(content, this.elements.content, reposition);
+};
+
+PROTOTYPE._updateTitle = function(content, reposition) {
+ if(this._update(content, this.elements.title, reposition) === FALSE) {
+ this._removeTitle(FALSE);
+ }
+};
+
+PROTOTYPE._createTitle = function()
+{
+ var elements = this.elements,
+ id = this._id+'-title';
+
+ // Destroy previous title element, if present
+ if(elements.titlebar) { this._removeTitle(); }
+
+ // Create title bar and title elements
+ elements.titlebar = $('<div />', {
+ 'class': NAMESPACE + '-titlebar ' + (this.options.style.widget ? createWidgetClass('header') : '')
+ })
+ .append(
+ elements.title = $('<div />', {
+ 'id': id,
+ 'class': NAMESPACE + '-title',
+ 'aria-atomic': TRUE
+ })
+ )
+ .insertBefore(elements.content)
+
+ // Button-specific events
+ .delegate('.qtip-close', 'mousedown keydown mouseup keyup mouseout', function(event) {
+ $(this).toggleClass('ui-state-active ui-state-focus', event.type.substr(-4) === 'down');
+ })
+ .delegate('.qtip-close', 'mouseover mouseout', function(event){
+ $(this).toggleClass('ui-state-hover', event.type === 'mouseover');
+ });
+
+ // Create button if enabled
+ if(this.options.content.button) { this._createButton(); }
+};
+
+PROTOTYPE._removeTitle = function(reposition)
+{
+ var elements = this.elements;
+
+ if(elements.title) {
+ elements.titlebar.remove();
+ elements.titlebar = elements.title = elements.button = NULL;
+
+ // Reposition if enabled
+ if(reposition !== FALSE) { this.reposition(); }
+ }
+};
+
+;PROTOTYPE.reposition = function(event, effect) {
+ if(!this.rendered || this.positioning || this.destroyed) { return this; }
+
+ // Set positioning flag
+ this.positioning = TRUE;
+
+ var cache = this.cache,
+ tooltip = this.tooltip,
+ posOptions = this.options.position,
+ target = posOptions.target,
+ my = posOptions.my,
+ at = posOptions.at,
+ viewport = posOptions.viewport,
+ container = posOptions.container,
+ adjust = posOptions.adjust,
+ method = adjust.method.split(' '),
+ tooltipWidth = tooltip.outerWidth(FALSE),
+ tooltipHeight = tooltip.outerHeight(FALSE),
+ targetWidth = 0,
+ targetHeight = 0,
+ type = tooltip.css('position'),
+ position = { left: 0, top: 0 },
+ visible = tooltip[0].offsetWidth > 0,
+ isScroll = event && event.type === 'scroll',
+ win = $(window),
+ doc = container[0].ownerDocument,
+ mouse = this.mouse,
+ pluginCalculations, offset;
+
+ // Check if absolute position was passed
+ if($.isArray(target) && target.length === 2) {
+ // Force left top and set position
+ at = { x: LEFT, y: TOP };
+ position = { left: target[0], top: target[1] };
+ }
+
+ // Check if mouse was the target
+ else if(target === 'mouse') {
+ // Force left top to allow flipping
+ at = { x: LEFT, y: TOP };
+
+ // Use the cached mouse coordinates if available, or passed event has no coordinates
+ if(mouse && mouse.pageX && (adjust.mouse || !event || !event.pageX) ) {
+ event = mouse;
+ }
+
+ // If the passed event has no coordinates (such as a scroll event)
+ else if(!event || !event.pageX) {
+ // Use the mouse origin that caused the show event, if distance hiding is enabled
+ if((!adjust.mouse || this.options.show.distance) && cache.origin && cache.origin.pageX) {
+ event = cache.origin;
+ }
+
+ // Use cached event for resize/scroll events
+ else if(!event || (event && (event.type === 'resize' || event.type === 'scroll'))) {
+ event = cache.event;
+ }
+ }
+
+ // Calculate body and container offset and take them into account below
+ if(type !== 'static') { position = container.offset(); }
+ if(doc.body.offsetWidth !== (window.innerWidth || doc.documentElement.clientWidth)) {
+ offset = $(document.body).offset();
+ }
+
+ // Use event coordinates for position
+ position = {
+ left: event.pageX - position.left + (offset && offset.left || 0),
+ top: event.pageY - position.top + (offset && offset.top || 0)
+ };
+
+ // Scroll events are a pain, some browsers
+ if(adjust.mouse && isScroll && mouse) {
+ position.left -= (mouse.scrollX || 0) - win.scrollLeft();
+ position.top -= (mouse.scrollY || 0) - win.scrollTop();
+ }
+ }
+
+ // Target wasn't mouse or absolute...
+ else {
+ // Check if event targetting is being used
+ if(target === 'event') {
+ if(event && event.target && event.type !== 'scroll' && event.type !== 'resize') {
+ cache.target = $(event.target);
+ }
+ else if(!event.target) {
+ cache.target = this.elements.target;
+ }
+ }
+ else if(target !== 'event'){
+ cache.target = $(target.jquery ? target : this.elements.target);
+ }
+ target = cache.target;
+
+ // Parse the target into a jQuery object and make sure there's an element present
+ target = $(target).eq(0);
+ if(target.length === 0) { return this; }
+
+ // Check if window or document is the target
+ else if(target[0] === document || target[0] === window) {
+ targetWidth = BROWSER.iOS ? window.innerWidth : target.width();
+ targetHeight = BROWSER.iOS ? window.innerHeight : target.height();
+
+ if(target[0] === window) {
+ position = {
+ top: (viewport || target).scrollTop(),
+ left: (viewport || target).scrollLeft()
+ };
+ }
+ }
+
+ // Check if the target is an <AREA> element
+ else if(PLUGINS.imagemap && target.is('area')) {
+ pluginCalculations = PLUGINS.imagemap(this, target, at, PLUGINS.viewport ? method : FALSE);
+ }
+
+ // Check if the target is an SVG element
+ else if(PLUGINS.svg && target && target[0].ownerSVGElement) {
+ pluginCalculations = PLUGINS.svg(this, target, at, PLUGINS.viewport ? method : FALSE);
+ }
+
+ // Otherwise use regular jQuery methods
+ else {
+ targetWidth = target.outerWidth(FALSE);
+ targetHeight = target.outerHeight(FALSE);
+ position = target.offset();
+ }
+
+ // Parse returned plugin values into proper variables
+ if(pluginCalculations) {
+ targetWidth = pluginCalculations.width;
+ targetHeight = pluginCalculations.height;
+ offset = pluginCalculations.offset;
+ position = pluginCalculations.position;
+ }
+
+ // Adjust position to take into account offset parents
+ position = this.reposition.offset(target, position, container);
+
+ // Adjust for position.fixed tooltips (and also iOS scroll bug in v3.2-4.0 & v4.3-4.3.2)
+ if((BROWSER.iOS > 3.1 && BROWSER.iOS < 4.1) ||
+ (BROWSER.iOS >= 4.3 && BROWSER.iOS < 4.33) ||
+ (!BROWSER.iOS && type === 'fixed')
+ ){
+ position.left -= win.scrollLeft();
+ position.top -= win.scrollTop();
+ }
+
+ // Adjust position relative to target
+ if(!pluginCalculations || (pluginCalculations && pluginCalculations.adjustable !== FALSE)) {
+ position.left += at.x === RIGHT ? targetWidth : at.x === CENTER ? targetWidth / 2 : 0;
+ position.top += at.y === BOTTOM ? targetHeight : at.y === CENTER ? targetHeight / 2 : 0;
+ }
+ }
+
+ // Adjust position relative to tooltip
+ position.left += adjust.x + (my.x === RIGHT ? -tooltipWidth : my.x === CENTER ? -tooltipWidth / 2 : 0);
+ position.top += adjust.y + (my.y === BOTTOM ? -tooltipHeight : my.y === CENTER ? -tooltipHeight / 2 : 0);
+
+ // Use viewport adjustment plugin if enabled
+ if(PLUGINS.viewport) {
+ position.adjusted = PLUGINS.viewport(
+ this, position, posOptions, targetWidth, targetHeight, tooltipWidth, tooltipHeight
+ );
+
+ // Apply offsets supplied by positioning plugin (if used)
+ if(offset && position.adjusted.left) { position.left += offset.left; }
+ if(offset && position.adjusted.top) { position.top += offset.top; }
+ }
+
+ // Viewport adjustment is disabled, set values to zero
+ else { position.adjusted = { left: 0, top: 0 }; }
+
+ // tooltipmove event
+ if(!this._trigger('move', [position, viewport.elem || viewport], event)) { return this; }
+ delete position.adjusted;
+
+ // If effect is disabled, target it mouse, no animation is defined or positioning gives NaN out, set CSS directly
+ if(effect === FALSE || !visible || isNaN(position.left) || isNaN(position.top) || target === 'mouse' || !$.isFunction(posOptions.effect)) {
+ tooltip.css(position);
+ }
+
+ // Use custom function if provided
+ else if($.isFunction(posOptions.effect)) {
+ posOptions.effect.call(tooltip, this, $.extend({}, position));
+ tooltip.queue(function(next) {
+ // Reset attributes to avoid cross-browser rendering bugs
+ $(this).css({ opacity: '', height: '' });
+ if(BROWSER.ie) { this.style.removeAttribute('filter'); }
+
+ next();
+ });
+ }
+
+ // Set positioning flag
+ this.positioning = FALSE;
+
+ return this;
+};
+
+// Custom (more correct for qTip!) offset calculator
+PROTOTYPE.reposition.offset = function(elem, pos, container) {
+ if(!container[0]) { return pos; }
+
+ var ownerDocument = $(elem[0].ownerDocument),
+ quirks = !!BROWSER.ie && document.compatMode !== 'CSS1Compat',
+ parent = container[0],
+ scrolled, position, parentOffset, overflow;
+
+ function scroll(e, i) {
+ pos.left += i * e.scrollLeft();
+ pos.top += i * e.scrollTop();
+ }
+
+ // Compensate for non-static containers offset
+ do {
+ if((position = $.css(parent, 'position')) !== 'static') {
+ if(position === 'fixed') {
+ parentOffset = parent.getBoundingClientRect();
+ scroll(ownerDocument, -1);
+ }
+ else {
+ parentOffset = $(parent).position();
+ parentOffset.left += (parseFloat($.css(parent, 'borderLeftWidth')) || 0);
+ parentOffset.top += (parseFloat($.css(parent, 'borderTopWidth')) || 0);
+ }
+
+ pos.left -= parentOffset.left + (parseFloat($.css(parent, 'marginLeft')) || 0);
+ pos.top -= parentOffset.top + (parseFloat($.css(parent, 'marginTop')) || 0);
+
+ // If this is the first parent element with an overflow of "scroll" or "auto", store it
+ if(!scrolled && (overflow = $.css(parent, 'overflow')) !== 'hidden' && overflow !== 'visible') { scrolled = $(parent); }
+ }
+ }
+ while((parent = parent.offsetParent));
+
+ // Compensate for containers scroll if it also has an offsetParent (or in IE quirks mode)
+ if(scrolled && (scrolled[0] !== ownerDocument[0] || quirks)) {
+ scroll(scrolled, 1);
+ }
+
+ return pos;
+};
+
+// Corner class
+var C = (CORNER = PROTOTYPE.reposition.Corner = function(corner, forceY) {
+ corner = ('' + corner).replace(/([A-Z])/, ' $1').replace(/middle/gi, CENTER).toLowerCase();
+ this.x = (corner.match(/left|right/i) || corner.match(/center/) || ['inherit'])[0].toLowerCase();
+ this.y = (corner.match(/top|bottom|center/i) || ['inherit'])[0].toLowerCase();
+ this.forceY = !!forceY;
+
+ var f = corner.charAt(0);
+ this.precedance = (f === 't' || f === 'b' ? Y : X);
+}).prototype;
+
+C.invert = function(z, center) {
+ this[z] = this[z] === LEFT ? RIGHT : this[z] === RIGHT ? LEFT : center || this[z];
+};
+
+C.string = function() {
+ var x = this.x, y = this.y;
+ return x === y ? x : this.precedance === Y || (this.forceY && y !== 'center') ? y+' '+x : x+' '+y;
+};
+
+C.abbrev = function() {
+ var result = this.string().split(' ');
+ return result[0].charAt(0) + (result[1] && result[1].charAt(0) || '');
+};
+
+C.clone = function() {
+ return new CORNER( this.string(), this.forceY );
+};;
+PROTOTYPE.toggle = function(state, event) {
+ var cache = this.cache,
+ options = this.options,
+ tooltip = this.tooltip;
+
+ // Try to prevent flickering when tooltip overlaps show element
+ if(event) {
+ if((/over|enter/).test(event.type) && (/out|leave/).test(cache.event.type) &&
+ options.show.target.add(event.target).length === options.show.target.length &&
+ tooltip.has(event.relatedTarget).length) {
+ return this;
+ }
+
+ // Cache event
+ cache.event = cloneEvent(event);
+ }
+
+ // If we're currently waiting and we've just hidden... stop it
+ this.waiting && !state && (this.hiddenDuringWait = TRUE);
+
+ // Render the tooltip if showing and it isn't already
+ if(!this.rendered) { return state ? this.render(1) : this; }
+ else if(this.destroyed || this.disabled) { return this; }
+
+ var type = state ? 'show' : 'hide',
+ opts = this.options[type],
+ otherOpts = this.options[ !state ? 'show' : 'hide' ],
+ posOptions = this.options.position,
+ contentOptions = this.options.content,
+ width = this.tooltip.css('width'),
+ visible = this.tooltip.is(':visible'),
+ animate = state || opts.target.length === 1,
+ sameTarget = !event || opts.target.length < 2 || cache.target[0] === event.target,
+ identicalState, allow, showEvent, delay, after;
+
+ // Detect state if valid one isn't provided
+ if((typeof state).search('boolean|number')) { state = !visible; }
+
+ // Check if the tooltip is in an identical state to the new would-be state
+ identicalState = !tooltip.is(':animated') && visible === state && sameTarget;
+
+ // Fire tooltip(show/hide) event and check if destroyed
+ allow = !identicalState ? !!this._trigger(type, [90]) : NULL;
+
+ // Check to make sure the tooltip wasn't destroyed in the callback
+ if(this.destroyed) { return this; }
+
+ // If the user didn't stop the method prematurely and we're showing the tooltip, focus it
+ if(allow !== FALSE && state) { this.focus(event); }
+
+ // If the state hasn't changed or the user stopped it, return early
+ if(!allow || identicalState) { return this; }
+
+ // Set ARIA hidden attribute
+ $.attr(tooltip[0], 'aria-hidden', !!!state);
+
+ // Execute state specific properties
+ if(state) {
+ // Store show origin coordinates
+ cache.origin = cloneEvent(this.mouse);
+
+ // Update tooltip content & title if it's a dynamic function
+ if($.isFunction(contentOptions.text)) { this._updateContent(contentOptions.text, FALSE); }
+ if($.isFunction(contentOptions.title)) { this._updateTitle(contentOptions.title, FALSE); }
+
+ // Cache mousemove events for positioning purposes (if not already tracking)
+ if(!trackingBound && posOptions.target === 'mouse' && posOptions.adjust.mouse) {
+ $(document).bind('mousemove.'+NAMESPACE, this._storeMouse);
+ trackingBound = TRUE;
+ }
+
+ // Update the tooltip position (set width first to prevent viewport/max-width issues)
+ if(!width) { tooltip.css('width', tooltip.outerWidth(FALSE)); }
+ this.reposition(event, arguments[2]);
+ if(!width) { tooltip.css('width', ''); }
+
+ // Hide other tooltips if tooltip is solo
+ if(!!opts.solo) {
+ (typeof opts.solo === 'string' ? $(opts.solo) : $(SELECTOR, opts.solo))
+ .not(tooltip).not(opts.target).qtip('hide', $.Event('tooltipsolo'));
+ }
+ }
+ else {
+ // Clear show timer if we're hiding
+ clearTimeout(this.timers.show);
+
+ // Remove cached origin on hide
+ delete cache.origin;
+
+ // Remove mouse tracking event if not needed (all tracking qTips are hidden)
+ if(trackingBound && !$(SELECTOR+'[tracking="true"]:visible', opts.solo).not(tooltip).length) {
+ $(document).unbind('mousemove.'+NAMESPACE);
+ trackingBound = FALSE;
+ }
+
+ // Blur the tooltip
+ this.blur(event);
+ }
+
+ // Define post-animation, state specific properties
+ after = $.proxy(function() {
+ if(state) {
+ // Prevent antialias from disappearing in IE by removing filter
+ if(BROWSER.ie) { tooltip[0].style.removeAttribute('filter'); }
+
+ // Remove overflow setting to prevent tip bugs
+ tooltip.css('overflow', '');
+
+ // Autofocus elements if enabled
+ if('string' === typeof opts.autofocus) {
+ $(this.options.show.autofocus, tooltip).focus();
+ }
+
+ // If set, hide tooltip when inactive for delay period
+ this.options.show.target.trigger('qtip-'+this.id+'-inactive');
+ }
+ else {
+ // Reset CSS states
+ tooltip.css({
+ display: '',
+ visibility: '',
+ opacity: '',
+ left: '',
+ top: ''
+ });
+ }
+
+ // tooltipvisible/tooltiphidden events
+ this._trigger(state ? 'visible' : 'hidden');
+ }, this);
+
+ // If no effect type is supplied, use a simple toggle
+ if(opts.effect === FALSE || animate === FALSE) {
+ tooltip[ type ]();
+ after();
+ }
+
+ // Use custom function if provided
+ else if($.isFunction(opts.effect)) {
+ tooltip.stop(1, 1);
+ opts.effect.call(tooltip, this);
+ tooltip.queue('fx', function(n) {
+ after(); n();
+ });
+ }
+
+ // Use basic fade function by default
+ else { tooltip.fadeTo(90, state ? 1 : 0, after); }
+
+ // If inactive hide method is set, active it
+ if(state) { opts.target.trigger('qtip-'+this.id+'-inactive'); }
+
+ return this;
+};
+
+PROTOTYPE.show = function(event) { return this.toggle(TRUE, event); };
+
+PROTOTYPE.hide = function(event) { return this.toggle(FALSE, event); };
+
+;PROTOTYPE.focus = function(event) {
+ if(!this.rendered || this.destroyed) { return this; }
+
+ var qtips = $(SELECTOR),
+ tooltip = this.tooltip,
+ curIndex = parseInt(tooltip[0].style.zIndex, 10),
+ newIndex = QTIP.zindex + qtips.length,
+ focusedElem;
+
+ // Only update the z-index if it has changed and tooltip is not already focused
+ if(!tooltip.hasClass(CLASS_FOCUS)) {
+ // tooltipfocus event
+ if(this._trigger('focus', [newIndex], event)) {
+ // Only update z-index's if they've changed
+ if(curIndex !== newIndex) {
+ // Reduce our z-index's and keep them properly ordered
+ qtips.each(function() {
+ if(this.style.zIndex > curIndex) {
+ this.style.zIndex = this.style.zIndex - 1;
+ }
+ });
+
+ // Fire blur event for focused tooltip
+ qtips.filter('.' + CLASS_FOCUS).qtip('blur', event);
+ }
+
+ // Set the new z-index
+ tooltip.addClass(CLASS_FOCUS)[0].style.zIndex = newIndex;
+ }
+ }
+
+ return this;
+};
+
+PROTOTYPE.blur = function(event) {
+ if(!this.rendered || this.destroyed) { return this; }
+
+ // Set focused status to FALSE
+ this.tooltip.removeClass(CLASS_FOCUS);
+
+ // tooltipblur event
+ this._trigger('blur', [ this.tooltip.css('zIndex') ], event);
+
+ return this;
+};
+
+;PROTOTYPE.disable = function(state) {
+ if(this.destroyed) { return this; }
+
+ // If 'toggle' is passed, toggle the current state
+ if(state === 'toggle') {
+ state = !(this.rendered ? this.tooltip.hasClass(CLASS_DISABLED) : this.disabled);
+ }
+
+ // Disable if no state passed
+ else if('boolean' !== typeof state) {
+ state = TRUE;
+ }
+
+ if(this.rendered) {
+ this.tooltip.toggleClass(CLASS_DISABLED, state)
+ .attr('aria-disabled', state);
+ }
+
+ this.disabled = !!state;
+
+ return this;
+};
+
+PROTOTYPE.enable = function() { return this.disable(FALSE); };
+
+;PROTOTYPE._createButton = function()
+{
+ var self = this,
+ elements = this.elements,
+ tooltip = elements.tooltip,
+ button = this.options.content.button,
+ isString = typeof button === 'string',
+ close = isString ? button : 'Close tooltip';
+
+ if(elements.button) { elements.button.remove(); }
+
+ // Use custom button if one was supplied by user, else use default
+ if(button.jquery) {
+ elements.button = button;
+ }
+ else {
+ elements.button = $('<a />', {
+ 'class': 'qtip-close ' + (this.options.style.widget ? '' : NAMESPACE+'-icon'),
+ 'title': close,
+ 'aria-label': close
+ })
+ .prepend(
+ $('<span />', {
+ 'class': 'ui-icon ui-icon-close',
+ 'html': '&times;'
+ })
+ );
+ }
+
+ // Create button and setup attributes
+ elements.button.appendTo(elements.titlebar || tooltip)
+ .attr('role', 'button')
+ .click(function(event) {
+ if(!tooltip.hasClass(CLASS_DISABLED)) { self.hide(event); }
+ return FALSE;
+ });
+};
+
+PROTOTYPE._updateButton = function(button)
+{
+ // Make sure tooltip is rendered and if not, return
+ if(!this.rendered) { return FALSE; }
+
+ var elem = this.elements.button;
+ if(button) { this._createButton(); }
+ else { elem.remove(); }
+};
+
+;// Widget class creator
+function createWidgetClass(cls) {
+ return WIDGET.concat('').join(cls ? '-'+cls+' ' : ' ');
+}
+
+// Widget class setter method
+PROTOTYPE._setWidget = function()
+{
+ var on = this.options.style.widget,
+ elements = this.elements,
+ tooltip = elements.tooltip,
+ disabled = tooltip.hasClass(CLASS_DISABLED);
+
+ tooltip.removeClass(CLASS_DISABLED);
+ CLASS_DISABLED = on ? 'ui-state-disabled' : 'qtip-disabled';
+ tooltip.toggleClass(CLASS_DISABLED, disabled);
+
+ tooltip.toggleClass('ui-helper-reset '+createWidgetClass(), on).toggleClass(CLASS_DEFAULT, this.options.style.def && !on);
+
+ if(elements.content) {
+ elements.content.toggleClass( createWidgetClass('content'), on);
+ }
+ if(elements.titlebar) {
+ elements.titlebar.toggleClass( createWidgetClass('header'), on);
+ }
+ if(elements.button) {
+ elements.button.toggleClass(NAMESPACE+'-icon', !on);
+ }
+};;function cloneEvent(event) {
+ return event && {
+ type: event.type,
+ pageX: event.pageX,
+ pageY: event.pageY,
+ target: event.target,
+ relatedTarget: event.relatedTarget,
+ scrollX: event.scrollX || window.pageXOffset || document.body.scrollLeft || document.documentElement.scrollLeft,
+ scrollY: event.scrollY || window.pageYOffset || document.body.scrollTop || document.documentElement.scrollTop
+ } || {};
+}
+
+function delay(callback, duration) {
+ // If tooltip has displayed, start hide timer
+ if(duration > 0) {
+ return setTimeout(
+ $.proxy(callback, this), duration
+ );
+ }
+ else{ callback.call(this); }
+}
+
+function showMethod(event) {
+ if(this.tooltip.hasClass(CLASS_DISABLED)) { return FALSE; }
+
+ // Clear hide timers
+ clearTimeout(this.timers.show);
+ clearTimeout(this.timers.hide);
+
+ // Start show timer
+ this.timers.show = delay.call(this,
+ function() { this.toggle(TRUE, event); },
+ this.options.show.delay
+ );
+}
+
+function hideMethod(event) {
+ if(this.tooltip.hasClass(CLASS_DISABLED)) { return FALSE; }
+
+ // Check if new target was actually the tooltip element
+ var relatedTarget = $(event.relatedTarget),
+ ontoTooltip = relatedTarget.closest(SELECTOR)[0] === this.tooltip[0],
+ ontoTarget = relatedTarget[0] === this.options.show.target[0];
+
+ // Clear timers and stop animation queue
+ clearTimeout(this.timers.show);
+ clearTimeout(this.timers.hide);
+
+ // Prevent hiding if tooltip is fixed and event target is the tooltip.
+ // Or if mouse positioning is enabled and cursor momentarily overlaps
+ if(this !== relatedTarget[0] &&
+ (this.options.position.target === 'mouse' && ontoTooltip) ||
+ (this.options.hide.fixed && (
+ (/mouse(out|leave|move)/).test(event.type) && (ontoTooltip || ontoTarget))
+ ))
+ {
+ try {
+ event.preventDefault();
+ event.stopImmediatePropagation();
+ } catch(e) {}
+
+ return;
+ }
+
+ // If tooltip has displayed, start hide timer
+ this.timers.hide = delay.call(this,
+ function() { this.toggle(FALSE, event); },
+ this.options.hide.delay,
+ this
+ );
+}
+
+function inactiveMethod(event) {
+ if(this.tooltip.hasClass(CLASS_DISABLED) || !this.options.hide.inactive) { return FALSE; }
+
+ // Clear timer
+ clearTimeout(this.timers.inactive);
+
+ this.timers.inactive = delay.call(this,
+ function(){ this.hide(event); },
+ this.options.hide.inactive
+ );
+}
+
+function repositionMethod(event) {
+ if(this.rendered && this.tooltip[0].offsetWidth > 0) { this.reposition(event); }
+}
+
+// Store mouse coordinates
+PROTOTYPE._storeMouse = function(event) {
+ (this.mouse = cloneEvent(event)).type = 'mousemove';
+};
+
+// Bind events
+PROTOTYPE._bind = function(targets, events, method, suffix, context) {
+ var ns = '.' + this._id + (suffix ? '-'+suffix : '');
+ events.length && $(targets).bind(
+ (events.split ? events : events.join(ns + ' ')) + ns,
+ $.proxy(method, context || this)
+ );
+};
+PROTOTYPE._unbind = function(targets, suffix) {
+ $(targets).unbind('.' + this._id + (suffix ? '-'+suffix : ''));
+};
+
+// Apply common event handlers using delegate (avoids excessive .bind calls!)
+var ns = '.'+NAMESPACE;
+function delegate(selector, events, method) {
+ $(document.body).delegate(selector,
+ (events.split ? events : events.join(ns + ' ')) + ns,
+ function() {
+ var api = QTIP.api[ $.attr(this, ATTR_ID) ];
+ api && !api.disabled && method.apply(api, arguments);
+ }
+ );
+}
+
+$(function() {
+ delegate(SELECTOR, ['mouseenter', 'mouseleave'], function(event) {
+ var state = event.type === 'mouseenter',
+ tooltip = $(event.currentTarget),
+ target = $(event.relatedTarget || event.target),
+ options = this.options;
+
+ // On mouseenter...
+ if(state) {
+ // Focus the tooltip on mouseenter (z-index stacking)
+ this.focus(event);
+
+ // Clear hide timer on tooltip hover to prevent it from closing
+ tooltip.hasClass(CLASS_FIXED) && !tooltip.hasClass(CLASS_DISABLED) && clearTimeout(this.timers.hide);
+ }
+
+ // On mouseleave...
+ else {
+ // Hide when we leave the tooltip and not onto the show target (if a hide event is set)
+ if(options.position.target === 'mouse' && options.hide.event &&
+ options.show.target && !target.closest(options.show.target[0]).length) {
+ this.hide(event);
+ }
+ }
+
+ // Add hover class
+ tooltip.toggleClass(CLASS_HOVER, state);
+ });
+
+ // Define events which reset the 'inactive' event handler
+ delegate('['+ATTR_ID+']', INACTIVE_EVENTS, inactiveMethod);
+});
+
+// Event trigger
+PROTOTYPE._trigger = function(type, args, event) {
+ var callback = $.Event('tooltip'+type);
+ callback.originalEvent = (event && $.extend({}, event)) || this.cache.event || NULL;
+
+ this.triggering = type;
+ this.tooltip.trigger(callback, [this].concat(args || []));
+ this.triggering = FALSE;
+
+ return !callback.isDefaultPrevented();
+};
+
+PROTOTYPE._bindEvents = function(showEvents, hideEvents, showTarget, hideTarget, showMethod, hideMethod) {
+ // If hide and show targets are the same...
+ if(hideTarget.add(showTarget).length === hideTarget.length) {
+ var toggleEvents = [];
+
+ // Filter identical show/hide events
+ hideEvents = $.map(hideEvents, function(type) {
+ var showIndex = $.inArray(type, showEvents);
+
+ // Both events are identical, remove from both hide and show events
+ // and append to toggleEvents
+ if(showIndex > -1) {
+ toggleEvents.push( showEvents.splice( showIndex, 1 )[0] );
+ return;
+ }
+
+ return type;
+ });
+
+ // Toggle events are special case of identical show/hide events, which happen in sequence
+ toggleEvents.length && this._bind(showTarget, toggleEvents, function(event) {
+ var state = this.rendered ? this.tooltip[0].offsetWidth > 0 : false;
+ (state ? hideMethod : showMethod).call(this, event);
+ });
+ }
+
+ // Apply show/hide/toggle events
+ this._bind(showTarget, showEvents, showMethod);
+ this._bind(hideTarget, hideEvents, hideMethod);
+};
+
+PROTOTYPE._assignInitialEvents = function(event) {
+ var options = this.options,
+ showTarget = options.show.target,
+ hideTarget = options.hide.target,
+ showEvents = options.show.event ? $.trim('' + options.show.event).split(' ') : [],
+ hideEvents = options.hide.event ? $.trim('' + options.hide.event).split(' ') : [];
+
+ /*
+ * Make sure hoverIntent functions properly by using mouseleave as a hide event if
+ * mouseenter/mouseout is used for show.event, even if it isn't in the users options.
+ */
+ if(/mouse(over|enter)/i.test(options.show.event) && !/mouse(out|leave)/i.test(options.hide.event)) {
+ hideEvents.push('mouseleave');
+ }
+
+ /*
+ * Also make sure initial mouse targetting works correctly by caching mousemove coords
+ * on show targets before the tooltip has rendered. Also set onTarget when triggered to
+ * keep mouse tracking working.
+ */
+ this._bind(showTarget, 'mousemove', function(event) {
+ this._storeMouse(event);
+ this.cache.onTarget = TRUE;
+ });
+
+ // Define hoverIntent function
+ function hoverIntent(event) {
+ // Only continue if tooltip isn't disabled
+ if(this.disabled || this.destroyed) { return FALSE; }
+
+ // Cache the event data
+ this.cache.event = cloneEvent(event);
+ this.cache.target = event ? $(event.target) : [undefined];
+
+ // Start the event sequence
+ clearTimeout(this.timers.show);
+ this.timers.show = delay.call(this,
+ function() { this.render(typeof event === 'object' || options.show.ready); },
+ options.show.delay
+ );
+ }
+
+ // Filter and bind events
+ this._bindEvents(showEvents, hideEvents, showTarget, hideTarget, hoverIntent, function() {
+ clearTimeout(this.timers.show);
+ });
+
+ // Prerendering is enabled, create tooltip now
+ if(options.show.ready || options.prerender) { hoverIntent.call(this, event); }
+};
+
+// Event assignment method
+PROTOTYPE._assignEvents = function() {
+ var self = this,
+ options = this.options,
+ posOptions = options.position,
+
+ tooltip = this.tooltip,
+ showTarget = options.show.target,
+ hideTarget = options.hide.target,
+ containerTarget = posOptions.container,
+ viewportTarget = posOptions.viewport,
+ documentTarget = $(document),
+ bodyTarget = $(document.body),
+ windowTarget = $(window),
+
+ showEvents = options.show.event ? $.trim('' + options.show.event).split(' ') : [],
+ hideEvents = options.hide.event ? $.trim('' + options.hide.event).split(' ') : [];
+
+
+ // Assign passed event callbacks
+ $.each(options.events, function(name, callback) {
+ self._bind(tooltip, name === 'toggle' ? ['tooltipshow','tooltiphide'] : ['tooltip'+name], callback, null, tooltip);
+ });
+
+ // Hide tooltips when leaving current window/frame (but not select/option elements)
+ if(/mouse(out|leave)/i.test(options.hide.event) && options.hide.leave === 'window') {
+ this._bind(documentTarget, ['mouseout', 'blur'], function(event) {
+ if(!/select|option/.test(event.target.nodeName) && !event.relatedTarget) {
+ this.hide(event);
+ }
+ });
+ }
+
+ // Enable hide.fixed by adding appropriate class
+ if(options.hide.fixed) {
+ hideTarget = hideTarget.add( tooltip.addClass(CLASS_FIXED) );
+ }
+
+ /*
+ * Make sure hoverIntent functions properly by using mouseleave to clear show timer if
+ * mouseenter/mouseout is used for show.event, even if it isn't in the users options.
+ */
+ else if(/mouse(over|enter)/i.test(options.show.event)) {
+ this._bind(hideTarget, 'mouseleave', function() {
+ clearTimeout(this.timers.show);
+ });
+ }
+
+ // Hide tooltip on document mousedown if unfocus events are enabled
+ if(('' + options.hide.event).indexOf('unfocus') > -1) {
+ this._bind(containerTarget.closest('html'), ['mousedown', 'touchstart'], function(event) {
+ var elem = $(event.target),
+ enabled = this.rendered && !this.tooltip.hasClass(CLASS_DISABLED) && this.tooltip[0].offsetWidth > 0,
+ isAncestor = elem.parents(SELECTOR).filter(this.tooltip[0]).length > 0;
+
+ if(elem[0] !== this.target[0] && elem[0] !== this.tooltip[0] && !isAncestor &&
+ !this.target.has(elem[0]).length && enabled
+ ) {
+ this.hide(event);
+ }
+ });
+ }
+
+ // Check if the tooltip hides when inactive
+ if('number' === typeof options.hide.inactive) {
+ // Bind inactive method to show target(s) as a custom event
+ this._bind(showTarget, 'qtip-'+this.id+'-inactive', inactiveMethod);
+
+ // Define events which reset the 'inactive' event handler
+ this._bind(hideTarget.add(tooltip), QTIP.inactiveEvents, inactiveMethod, '-inactive');
+ }
+
+ // Filter and bind events
+ this._bindEvents(showEvents, hideEvents, showTarget, hideTarget, showMethod, hideMethod);
+
+ // Mouse movement bindings
+ this._bind(showTarget.add(tooltip), 'mousemove', function(event) {
+ // Check if the tooltip hides when mouse is moved a certain distance
+ if('number' === typeof options.hide.distance) {
+ var origin = this.cache.origin || {},
+ limit = this.options.hide.distance,
+ abs = Math.abs;
+
+ // Check if the movement has gone beyond the limit, and hide it if so
+ if(abs(event.pageX - origin.pageX) >= limit || abs(event.pageY - origin.pageY) >= limit) {
+ this.hide(event);
+ }
+ }
+
+ // Cache mousemove coords on show targets
+ this._storeMouse(event);
+ });
+
+ // Mouse positioning events
+ if(posOptions.target === 'mouse') {
+ // If mouse adjustment is on...
+ if(posOptions.adjust.mouse) {
+ // Apply a mouseleave event so we don't get problems with overlapping
+ if(options.hide.event) {
+ // Track if we're on the target or not
+ this._bind(showTarget, ['mouseenter', 'mouseleave'], function(event) {
+ this.cache.onTarget = event.type === 'mouseenter';
+ });
+ }
+
+ // Update tooltip position on mousemove
+ this._bind(documentTarget, 'mousemove', function(event) {
+ // Update the tooltip position only if the tooltip is visible and adjustment is enabled
+ if(this.rendered && this.cache.onTarget && !this.tooltip.hasClass(CLASS_DISABLED) && this.tooltip[0].offsetWidth > 0) {
+ this.reposition(event);
+ }
+ });
+ }
+ }
+
+ // Adjust positions of the tooltip on window resize if enabled
+ if(posOptions.adjust.resize || viewportTarget.length) {
+ this._bind( $.event.special.resize ? viewportTarget : windowTarget, 'resize', repositionMethod );
+ }
+
+ // Adjust tooltip position on scroll of the window or viewport element if present
+ if(posOptions.adjust.scroll) {
+ this._bind( windowTarget.add(posOptions.container), 'scroll', repositionMethod );
+ }
+};
+
+// Un-assignment method
+PROTOTYPE._unassignEvents = function() {
+ var targets = [
+ this.options.show.target[0],
+ this.options.hide.target[0],
+ this.rendered && this.tooltip[0],
+ this.options.position.container[0],
+ this.options.position.viewport[0],
+ this.options.position.container.closest('html')[0], // unfocus
+ window,
+ document
+ ];
+
+ this._unbind($([]).pushStack( $.grep(targets, function(i) {
+ return typeof i === 'object';
+ })));
+};
+
+;// Initialization method
+function init(elem, id, opts) {
+ var obj, posOptions, attr, config, title,
+
+ // Setup element references
+ docBody = $(document.body),
+
+ // Use document body instead of document element if needed
+ newTarget = elem[0] === document ? docBody : elem,
+
+ // Grab metadata from element if plugin is present
+ metadata = (elem.metadata) ? elem.metadata(opts.metadata) : NULL,
+
+ // If metadata type if HTML5, grab 'name' from the object instead, or use the regular data object otherwise
+ metadata5 = opts.metadata.type === 'html5' && metadata ? metadata[opts.metadata.name] : NULL,
+
+ // Grab data from metadata.name (or data-qtipopts as fallback) using .data() method,
+ html5 = elem.data(opts.metadata.name || 'qtipopts');
+
+ // If we don't get an object returned attempt to parse it manualyl without parseJSON
+ try { html5 = typeof html5 === 'string' ? $.parseJSON(html5) : html5; } catch(e) {}
+
+ // Merge in and sanitize metadata
+ config = $.extend(TRUE, {}, QTIP.defaults, opts,
+ typeof html5 === 'object' ? sanitizeOptions(html5) : NULL,
+ sanitizeOptions(metadata5 || metadata));
+
+ // Re-grab our positioning options now we've merged our metadata and set id to passed value
+ posOptions = config.position;
+ config.id = id;
+
+ // Setup missing content if none is detected
+ if('boolean' === typeof config.content.text) {
+ attr = elem.attr(config.content.attr);
+
+ // Grab from supplied attribute if available
+ if(config.content.attr !== FALSE && attr) { config.content.text = attr; }
+
+ // No valid content was found, abort render
+ else { return FALSE; }
+ }
+
+ // Setup target options
+ if(!posOptions.container.length) { posOptions.container = docBody; }
+ if(posOptions.target === FALSE) { posOptions.target = newTarget; }
+ if(config.show.target === FALSE) { config.show.target = newTarget; }
+ if(config.show.solo === TRUE) { config.show.solo = posOptions.container.closest('body'); }
+ if(config.hide.target === FALSE) { config.hide.target = newTarget; }
+ if(config.position.viewport === TRUE) { config.position.viewport = posOptions.container; }
+
+ // Ensure we only use a single container
+ posOptions.container = posOptions.container.eq(0);
+
+ // Convert position corner values into x and y strings
+ posOptions.at = new CORNER(posOptions.at, TRUE);
+ posOptions.my = new CORNER(posOptions.my);
+
+ // Destroy previous tooltip if overwrite is enabled, or skip element if not
+ if(elem.data(NAMESPACE)) {
+ if(config.overwrite) {
+ elem.qtip('destroy', true);
+ }
+ else if(config.overwrite === FALSE) {
+ return FALSE;
+ }
+ }
+
+ // Add has-qtip attribute
+ elem.attr(ATTR_HAS, id);
+
+ // Remove title attribute and store it if present
+ if(config.suppress && (title = elem.attr('title'))) {
+ // Final attr call fixes event delegatiom and IE default tooltip showing problem
+ elem.removeAttr('title').attr(oldtitle, title).attr('title', '');
+ }
+
+ // Initialize the tooltip and add API reference
+ obj = new QTip(elem, config, id, !!attr);
+ elem.data(NAMESPACE, obj);
+
+ // Catch remove/removeqtip events on target element to destroy redundant tooltip
+ elem.one('remove.qtip-'+id+' removeqtip.qtip-'+id, function() {
+ var api; if((api = $(this).data(NAMESPACE))) { api.destroy(true); }
+ });
+
+ return obj;
+}
+
+// jQuery $.fn extension method
+QTIP = $.fn.qtip = function(options, notation, newValue)
+{
+ var command = ('' + options).toLowerCase(), // Parse command
+ returned = NULL,
+ args = $.makeArray(arguments).slice(1),
+ event = args[args.length - 1],
+ opts = this[0] ? $.data(this[0], NAMESPACE) : NULL;
+
+ // Check for API request
+ if((!arguments.length && opts) || command === 'api') {
+ return opts;
+ }
+
+ // Execute API command if present
+ else if('string' === typeof options) {
+ this.each(function() {
+ var api = $.data(this, NAMESPACE);
+ if(!api) { return TRUE; }
+
+ // Cache the event if possible
+ if(event && event.timeStamp) { api.cache.event = event; }
+
+ // Check for specific API commands
+ if(notation && (command === 'option' || command === 'options')) {
+ if(newValue !== undefined || $.isPlainObject(notation)) {
+ api.set(notation, newValue);
+ }
+ else {
+ returned = api.get(notation);
+ return FALSE;
+ }
+ }
+
+ // Execute API command
+ else if(api[command]) {
+ api[command].apply(api, args);
+ }
+ });
+
+ return returned !== NULL ? returned : this;
+ }
+
+ // No API commands. validate provided options and setup qTips
+ else if('object' === typeof options || !arguments.length) {
+ // Sanitize options first
+ opts = sanitizeOptions($.extend(TRUE, {}, options));
+
+ return this.each(function(i) {
+ var api, id;
+
+ // Find next available ID, or use custom ID if provided
+ id = $.isArray(opts.id) ? opts.id[i] : opts.id;
+ id = !id || id === FALSE || id.length < 1 || QTIP.api[id] ? QTIP.nextid++ : id;
+
+ // Initialize the qTip and re-grab newly sanitized options
+ api = init($(this), id, opts);
+ if(api === FALSE) { return TRUE; }
+ else { QTIP.api[id] = api; }
+
+ // Initialize plugins
+ $.each(PLUGINS, function() {
+ if(this.initialize === 'initialize') { this(api); }
+ });
+
+ // Assign initial pre-render events
+ api._assignInitialEvents(event);
+ });
+ }
+};
+
+// Expose class
+$.qtip = QTip;
+
+// Populated in render method
+QTIP.api = {};
+;$.each({
+ /* Allow other plugins to successfully retrieve the title of an element with a qTip applied */
+ attr: function(attr, val) {
+ if(this.length) {
+ var self = this[0],
+ title = 'title',
+ api = $.data(self, 'qtip');
+
+ if(attr === title && api && 'object' === typeof api && api.options.suppress) {
+ if(arguments.length < 2) {
+ return $.attr(self, oldtitle);
+ }
+
+ // If qTip is rendered and title was originally used as content, update it
+ if(api && api.options.content.attr === title && api.cache.attr) {
+ api.set('content.text', val);
+ }
+
+ // Use the regular attr method to set, then cache the result
+ return this.attr(oldtitle, val);
+ }
+ }
+
+ return $.fn['attr'+replaceSuffix].apply(this, arguments);
+ },
+
+ /* Allow clone to correctly retrieve cached title attributes */
+ clone: function(keepData) {
+ var titles = $([]), title = 'title',
+
+ // Clone our element using the real clone method
+ elems = $.fn['clone'+replaceSuffix].apply(this, arguments);
+
+ // Grab all elements with an oldtitle set, and change it to regular title attribute, if keepData is false
+ if(!keepData) {
+ elems.filter('['+oldtitle+']').attr('title', function() {
+ return $.attr(this, oldtitle);
+ })
+ .removeAttr(oldtitle);
+ }
+
+ return elems;
+ }
+}, function(name, func) {
+ if(!func || $.fn[name+replaceSuffix]) { return TRUE; }
+
+ var old = $.fn[name+replaceSuffix] = $.fn[name];
+ $.fn[name] = function() {
+ return func.apply(this, arguments) || old.apply(this, arguments);
+ };
+});
+
+/* Fire off 'removeqtip' handler in $.cleanData if jQuery UI not present (it already does similar).
+ * This snippet is taken directly from jQuery UI source code found here:
+ * http://code.jquery.com/ui/jquery-ui-git.js
+ */
+if(!$.ui) {
+ $['cleanData'+replaceSuffix] = $.cleanData;
+ $.cleanData = function( elems ) {
+ for(var i = 0, elem; (elem = $( elems[i] )).length; i++) {
+ if(elem.attr(ATTR_HAS)) {
+ try { elem.triggerHandler('removeqtip'); }
+ catch( e ) {}
+ }
+ }
+ $['cleanData'+replaceSuffix].apply(this, arguments);
+ };
+}
+
+;// qTip version
+QTIP.version = '2.2.0';
+
+// Base ID for all qTips
+QTIP.nextid = 0;
+
+// Inactive events array
+QTIP.inactiveEvents = INACTIVE_EVENTS;
+
+// Base z-index for all qTips
+QTIP.zindex = 15000;
+
+// Define configuration defaults
+QTIP.defaults = {
+ prerender: FALSE,
+ id: FALSE,
+ overwrite: TRUE,
+ suppress: TRUE,
+ content: {
+ text: TRUE,
+ attr: 'title',
+ title: FALSE,
+ button: FALSE
+ },
+ position: {
+ my: 'top left',
+ at: 'bottom right',
+ target: FALSE,
+ container: FALSE,
+ viewport: FALSE,
+ adjust: {
+ x: 0, y: 0,
+ mouse: TRUE,
+ scroll: TRUE,
+ resize: TRUE,
+ method: 'flipinvert flipinvert'
+ },
+ effect: function(api, pos, viewport) {
+ $(this).animate(pos, {
+ duration: 200,
+ queue: FALSE
+ });
+ }
+ },
+ show: {
+ target: FALSE,
+ event: 'mouseenter',
+ effect: TRUE,
+ delay: 90,
+ solo: FALSE,
+ ready: FALSE,
+ autofocus: FALSE
+ },
+ hide: {
+ target: FALSE,
+ event: 'mouseleave',
+ effect: TRUE,
+ delay: 0,
+ fixed: FALSE,
+ inactive: FALSE,
+ leave: 'window',
+ distance: FALSE
+ },
+ style: {
+ classes: '',
+ widget: FALSE,
+ width: FALSE,
+ height: FALSE,
+ def: TRUE
+ },
+ events: {
+ render: NULL,
+ move: NULL,
+ show: NULL,
+ hide: NULL,
+ toggle: NULL,
+ visible: NULL,
+ hidden: NULL,
+ focus: NULL,
+ blur: NULL
+ }
+};
+
+;var TIP,
+
+// .bind()/.on() namespace
+TIPNS = '.qtip-tip',
+
+// Common CSS strings
+MARGIN = 'margin',
+BORDER = 'border',
+COLOR = 'color',
+BG_COLOR = 'background-color',
+TRANSPARENT = 'transparent',
+IMPORTANT = ' !important',
+
+// Check if the browser supports <canvas/> elements
+HASCANVAS = !!document.createElement('canvas').getContext,
+
+// Invalid colour values used in parseColours()
+INVALID = /rgba?\(0, 0, 0(, 0)?\)|transparent|#123456/i;
+
+// Camel-case method, taken from jQuery source
+// http://code.jquery.com/jquery-1.8.0.js
+function camel(s) { return s.charAt(0).toUpperCase() + s.slice(1); }
+
+/*
+ * Modified from Modernizr's testPropsAll()
+ * http://modernizr.com/downloads/modernizr-latest.js
+ */
+var cssProps = {}, cssPrefixes = ["Webkit", "O", "Moz", "ms"];
+function vendorCss(elem, prop) {
+ var ucProp = prop.charAt(0).toUpperCase() + prop.slice(1),
+ props = (prop + ' ' + cssPrefixes.join(ucProp + ' ') + ucProp).split(' '),
+ cur, val, i = 0;
+
+ // If the property has already been mapped...
+ if(cssProps[prop]) { return elem.css(cssProps[prop]); }
+
+ while((cur = props[i++])) {
+ if((val = elem.css(cur)) !== undefined) {
+ return cssProps[prop] = cur, val;
+ }
+ }
+}
+
+// Parse a given elements CSS property into an int
+function intCss(elem, prop) {
+ return Math.ceil(parseFloat(vendorCss(elem, prop)));
+}
+
+
+// VML creation (for IE only)
+if(!HASCANVAS) {
+ var createVML = function(tag, props, style) {
+ return '<qtipvml:'+tag+' xmlns="urn:schemas-microsoft.com:vml" class="qtip-vml" '+(props||'')+
+ ' style="behavior: url(#default#VML); '+(style||'')+ '" />';
+ };
+}
+
+// Canvas only definitions
+else {
+ var PIXEL_RATIO = window.devicePixelRatio || 1,
+ BACKING_STORE_RATIO = (function() {
+ var context = document.createElement('canvas').getContext('2d');
+ return context.backingStorePixelRatio || context.webkitBackingStorePixelRatio || context.mozBackingStorePixelRatio ||
+ context.msBackingStorePixelRatio || context.oBackingStorePixelRatio || 1;
+ }()),
+ SCALE = PIXEL_RATIO / BACKING_STORE_RATIO;
+}
+
+
+function Tip(qtip, options) {
+ this._ns = 'tip';
+ this.options = options;
+ this.offset = options.offset;
+ this.size = [ options.width, options.height ];
+
+ // Initialize
+ this.init( (this.qtip = qtip) );
+}
+
+$.extend(Tip.prototype, {
+ init: function(qtip) {
+ var context, tip;
+
+ // Create tip element and prepend to the tooltip
+ tip = this.element = qtip.elements.tip = $('<div />', { 'class': NAMESPACE+'-tip' }).prependTo(qtip.tooltip);
+
+ // Create tip drawing element(s)
+ if(HASCANVAS) {
+ // save() as soon as we create the canvas element so FF2 doesn't bork on our first restore()!
+ context = $('<canvas />').appendTo(this.element)[0].getContext('2d');
+
+ // Setup constant parameters
+ context.lineJoin = 'miter';
+ context.miterLimit = 100000;
+ context.save();
+ }
+ else {
+ context = createVML('shape', 'coordorigin="0,0"', 'position:absolute;');
+ this.element.html(context + context);
+
+ // Prevent mousing down on the tip since it causes problems with .live() handling in IE due to VML
+ qtip._bind( $('*', tip).add(tip), ['click', 'mousedown'], function(event) { event.stopPropagation(); }, this._ns);
+ }
+
+ // Bind update events
+ qtip._bind(qtip.tooltip, 'tooltipmove', this.reposition, this._ns, this);
+
+ // Create it
+ this.create();
+ },
+
+ _swapDimensions: function() {
+ this.size[0] = this.options.height;
+ this.size[1] = this.options.width;
+ },
+ _resetDimensions: function() {
+ this.size[0] = this.options.width;
+ this.size[1] = this.options.height;
+ },
+
+ _useTitle: function(corner) {
+ var titlebar = this.qtip.elements.titlebar;
+ return titlebar && (
+ corner.y === TOP || (corner.y === CENTER && this.element.position().top + (this.size[1] / 2) + this.options.offset < titlebar.outerHeight(TRUE))
+ );
+ },
+
+ _parseCorner: function(corner) {
+ var my = this.qtip.options.position.my;
+
+ // Detect corner and mimic properties
+ if(corner === FALSE || my === FALSE) {
+ corner = FALSE;
+ }
+ else if(corner === TRUE) {
+ corner = new CORNER( my.string() );
+ }
+ else if(!corner.string) {
+ corner = new CORNER(corner);
+ corner.fixed = TRUE;
+ }
+
+ return corner;
+ },
+
+ _parseWidth: function(corner, side, use) {
+ var elements = this.qtip.elements,
+ prop = BORDER + camel(side) + 'Width';
+
+ return (use ? intCss(use, prop) : (
+ intCss(elements.content, prop) ||
+ intCss(this._useTitle(corner) && elements.titlebar || elements.content, prop) ||
+ intCss(elements.tooltip, prop)
+ )) || 0;
+ },
+
+ _parseRadius: function(corner) {
+ var elements = this.qtip.elements,
+ prop = BORDER + camel(corner.y) + camel(corner.x) + 'Radius';
+
+ return BROWSER.ie < 9 ? 0 :
+ intCss(this._useTitle(corner) && elements.titlebar || elements.content, prop) ||
+ intCss(elements.tooltip, prop) || 0;
+ },
+
+ _invalidColour: function(elem, prop, compare) {
+ var val = elem.css(prop);
+ return !val || (compare && val === elem.css(compare)) || INVALID.test(val) ? FALSE : val;
+ },
+
+ _parseColours: function(corner) {
+ var elements = this.qtip.elements,
+ tip = this.element.css('cssText', ''),
+ borderSide = BORDER + camel(corner[ corner.precedance ]) + camel(COLOR),
+ colorElem = this._useTitle(corner) && elements.titlebar || elements.content,
+ css = this._invalidColour, color = [];
+
+ // Attempt to detect the background colour from various elements, left-to-right precedance
+ color[0] = css(tip, BG_COLOR) || css(colorElem, BG_COLOR) || css(elements.content, BG_COLOR) ||
+ css(elements.tooltip, BG_COLOR) || tip.css(BG_COLOR);
+
+ // Attempt to detect the correct border side colour from various elements, left-to-right precedance
+ color[1] = css(tip, borderSide, COLOR) || css(colorElem, borderSide, COLOR) ||
+ css(elements.content, borderSide, COLOR) || css(elements.tooltip, borderSide, COLOR) || elements.tooltip.css(borderSide);
+
+ // Reset background and border colours
+ $('*', tip).add(tip).css('cssText', BG_COLOR+':'+TRANSPARENT+IMPORTANT+';'+BORDER+':0'+IMPORTANT+';');
+
+ return color;
+ },
+
+ _calculateSize: function(corner) {
+ var y = corner.precedance === Y,
+ width = this.options['width'],
+ height = this.options['height'],
+ isCenter = corner.abbrev() === 'c',
+ base = (y ? width: height) * (isCenter ? 0.5 : 1),
+ pow = Math.pow,
+ round = Math.round,
+ bigHyp, ratio, result,
+
+ smallHyp = Math.sqrt( pow(base, 2) + pow(height, 2) ),
+ hyp = [ (this.border / base) * smallHyp, (this.border / height) * smallHyp ];
+
+ hyp[2] = Math.sqrt( pow(hyp[0], 2) - pow(this.border, 2) );
+ hyp[3] = Math.sqrt( pow(hyp[1], 2) - pow(this.border, 2) );
+
+ bigHyp = smallHyp + hyp[2] + hyp[3] + (isCenter ? 0 : hyp[0]);
+ ratio = bigHyp / smallHyp;
+
+ result = [ round(ratio * width), round(ratio * height) ];
+ return y ? result : result.reverse();
+ },
+
+ // Tip coordinates calculator
+ _calculateTip: function(corner, size, scale) {
+ scale = scale || 1;
+ size = size || this.size;
+
+ var width = size[0] * scale,
+ height = size[1] * scale,
+ width2 = Math.ceil(width / 2), height2 = Math.ceil(height / 2),
+
+ // Define tip coordinates in terms of height and width values
+ tips = {
+ br: [0,0, width,height, width,0],
+ bl: [0,0, width,0, 0,height],
+ tr: [0,height, width,0, width,height],
+ tl: [0,0, 0,height, width,height],
+ tc: [0,height, width2,0, width,height],
+ bc: [0,0, width,0, width2,height],
+ rc: [0,0, width,height2, 0,height],
+ lc: [width,0, width,height, 0,height2]
+ };
+
+ // Set common side shapes
+ tips.lt = tips.br; tips.rt = tips.bl;
+ tips.lb = tips.tr; tips.rb = tips.tl;
+
+ return tips[ corner.abbrev() ];
+ },
+
+ // Tip coordinates drawer (canvas)
+ _drawCoords: function(context, coords) {
+ context.beginPath();
+ context.moveTo(coords[0], coords[1]);
+ context.lineTo(coords[2], coords[3]);
+ context.lineTo(coords[4], coords[5]);
+ context.closePath();
+ },
+
+ create: function() {
+ // Determine tip corner
+ var c = this.corner = (HASCANVAS || BROWSER.ie) && this._parseCorner(this.options.corner);
+
+ // If we have a tip corner...
+ if( (this.enabled = !!this.corner && this.corner.abbrev() !== 'c') ) {
+ // Cache it
+ this.qtip.cache.corner = c.clone();
+
+ // Create it
+ this.update();
+ }
+
+ // Toggle tip element
+ this.element.toggle(this.enabled);
+
+ return this.corner;
+ },
+
+ update: function(corner, position) {
+ if(!this.enabled) { return this; }
+
+ var elements = this.qtip.elements,
+ tip = this.element,
+ inner = tip.children(),
+ options = this.options,
+ curSize = this.size,
+ mimic = options.mimic,
+ round = Math.round,
+ color, precedance, context,
+ coords, bigCoords, translate, newSize, border, BACKING_STORE_RATIO;
+
+ // Re-determine tip if not already set
+ if(!corner) { corner = this.qtip.cache.corner || this.corner; }
+
+ // Use corner property if we detect an invalid mimic value
+ if(mimic === FALSE) { mimic = corner; }
+
+ // Otherwise inherit mimic properties from the corner object as necessary
+ else {
+ mimic = new CORNER(mimic);
+ mimic.precedance = corner.precedance;
+
+ if(mimic.x === 'inherit') { mimic.x = corner.x; }
+ else if(mimic.y === 'inherit') { mimic.y = corner.y; }
+ else if(mimic.x === mimic.y) {
+ mimic[ corner.precedance ] = corner[ corner.precedance ];
+ }
+ }
+ precedance = mimic.precedance;
+
+ // Ensure the tip width.height are relative to the tip position
+ if(corner.precedance === X) { this._swapDimensions(); }
+ else { this._resetDimensions(); }
+
+ // Update our colours
+ color = this.color = this._parseColours(corner);
+
+ // Detect border width, taking into account colours
+ if(color[1] !== TRANSPARENT) {
+ // Grab border width
+ border = this.border = this._parseWidth(corner, corner[corner.precedance]);
+
+ // If border width isn't zero, use border color as fill if it's not invalid (1.0 style tips)
+ if(options.border && border < 1 && !INVALID.test(color[1])) { color[0] = color[1]; }
+
+ // Set border width (use detected border width if options.border is true)
+ this.border = border = options.border !== TRUE ? options.border : border;
+ }
+
+ // Border colour was invalid, set border to zero
+ else { this.border = border = 0; }
+
+ // Determine tip size
+ newSize = this.size = this._calculateSize(corner);
+ tip.css({
+ width: newSize[0],
+ height: newSize[1],
+ lineHeight: newSize[1]+'px'
+ });
+
+ // Calculate tip translation
+ if(corner.precedance === Y) {
+ translate = [
+ round(mimic.x === LEFT ? border : mimic.x === RIGHT ? newSize[0] - curSize[0] - border : (newSize[0] - curSize[0]) / 2),
+ round(mimic.y === TOP ? newSize[1] - curSize[1] : 0)
+ ];
+ }
+ else {
+ translate = [
+ round(mimic.x === LEFT ? newSize[0] - curSize[0] : 0),
+ round(mimic.y === TOP ? border : mimic.y === BOTTOM ? newSize[1] - curSize[1] - border : (newSize[1] - curSize[1]) / 2)
+ ];
+ }
+
+ // Canvas drawing implementation
+ if(HASCANVAS) {
+ // Grab canvas context and clear/save it
+ context = inner[0].getContext('2d');
+ context.restore(); context.save();
+ context.clearRect(0,0,6000,6000);
+
+ // Calculate coordinates
+ coords = this._calculateTip(mimic, curSize, SCALE);
+ bigCoords = this._calculateTip(mimic, this.size, SCALE);
+
+ // Set the canvas size using calculated size
+ inner.attr(WIDTH, newSize[0] * SCALE).attr(HEIGHT, newSize[1] * SCALE);
+ inner.css(WIDTH, newSize[0]).css(HEIGHT, newSize[1]);
+
+ // Draw the outer-stroke tip
+ this._drawCoords(context, bigCoords);
+ context.fillStyle = color[1];
+ context.fill();
+
+ // Draw the actual tip
+ context.translate(translate[0] * SCALE, translate[1] * SCALE);
+ this._drawCoords(context, coords);
+ context.fillStyle = color[0];
+ context.fill();
+ }
+
+ // VML (IE Proprietary implementation)
+ else {
+ // Calculate coordinates
+ coords = this._calculateTip(mimic);
+
+ // Setup coordinates string
+ coords = 'm' + coords[0] + ',' + coords[1] + ' l' + coords[2] +
+ ',' + coords[3] + ' ' + coords[4] + ',' + coords[5] + ' xe';
+
+ // Setup VML-specific offset for pixel-perfection
+ translate[2] = border && /^(r|b)/i.test(corner.string()) ?
+ BROWSER.ie === 8 ? 2 : 1 : 0;
+
+ // Set initial CSS
+ inner.css({
+ coordsize: (newSize[0]+border) + ' ' + (newSize[1]+border),
+ antialias: ''+(mimic.string().indexOf(CENTER) > -1),
+ left: translate[0] - (translate[2] * Number(precedance === X)),
+ top: translate[1] - (translate[2] * Number(precedance === Y)),
+ width: newSize[0] + border,
+ height: newSize[1] + border
+ })
+ .each(function(i) {
+ var $this = $(this);
+
+ // Set shape specific attributes
+ $this[ $this.prop ? 'prop' : 'attr' ]({
+ coordsize: (newSize[0]+border) + ' ' + (newSize[1]+border),
+ path: coords,
+ fillcolor: color[0],
+ filled: !!i,
+ stroked: !i
+ })
+ .toggle(!!(border || i));
+
+ // Check if border is enabled and add stroke element
+ !i && $this.html( createVML(
+ 'stroke', 'weight="'+(border*2)+'px" color="'+color[1]+'" miterlimit="1000" joinstyle="miter"'
+ ) );
+ });
+ }
+
+ // Opera bug #357 - Incorrect tip position
+ // https://github.com/Craga89/qTip2/issues/367
+ window.opera && setTimeout(function() {
+ elements.tip.css({
+ display: 'inline-block',
+ visibility: 'visible'
+ });
+ }, 1);
+
+ // Position if needed
+ if(position !== FALSE) { this.calculate(corner, newSize); }
+ },
+
+ calculate: function(corner, size) {
+ if(!this.enabled) { return FALSE; }
+
+ var self = this,
+ elements = this.qtip.elements,
+ tip = this.element,
+ userOffset = this.options.offset,
+ isWidget = elements.tooltip.hasClass('ui-widget'),
+ position = { },
+ precedance, corners;
+
+ // Inherit corner if not provided
+ corner = corner || this.corner;
+ precedance = corner.precedance;
+
+ // Determine which tip dimension to use for adjustment
+ size = size || this._calculateSize(corner);
+
+ // Setup corners and offset array
+ corners = [ corner.x, corner.y ];
+ if(precedance === X) { corners.reverse(); }
+
+ // Calculate tip position
+ $.each(corners, function(i, side) {
+ var b, bc, br;
+
+ if(side === CENTER) {
+ b = precedance === Y ? LEFT : TOP;
+ position[ b ] = '50%';
+ position[MARGIN+'-' + b] = -Math.round(size[ precedance === Y ? 0 : 1 ] / 2) + userOffset;
+ }
+ else {
+ b = self._parseWidth(corner, side, elements.tooltip);
+ bc = self._parseWidth(corner, side, elements.content);
+ br = self._parseRadius(corner);
+
+ position[ side ] = Math.max(-self.border, i ? bc : (userOffset + (br > b ? br : -b)));
+ }
+ });
+
+ // Adjust for tip size
+ position[ corner[precedance] ] -= size[ precedance === X ? 0 : 1 ];
+
+ // Set and return new position
+ tip.css({ margin: '', top: '', bottom: '', left: '', right: '' }).css(position);
+ return position;
+ },
+
+ reposition: function(event, api, pos, viewport) {
+ if(!this.enabled) { return; }
+
+ var cache = api.cache,
+ newCorner = this.corner.clone(),
+ adjust = pos.adjusted,
+ method = api.options.position.adjust.method.split(' '),
+ horizontal = method[0],
+ vertical = method[1] || method[0],
+ shift = { left: FALSE, top: FALSE, x: 0, y: 0 },
+ offset, css = {}, props;
+
+ function shiftflip(direction, precedance, popposite, side, opposite) {
+ // Horizontal - Shift or flip method
+ if(direction === SHIFT && newCorner.precedance === precedance && adjust[side] && newCorner[popposite] !== CENTER) {
+ newCorner.precedance = newCorner.precedance === X ? Y : X;
+ }
+ else if(direction !== SHIFT && adjust[side]){
+ newCorner[precedance] = newCorner[precedance] === CENTER ?
+ (adjust[side] > 0 ? side : opposite) : (newCorner[precedance] === side ? opposite : side);
+ }
+ }
+
+ function shiftonly(xy, side, opposite) {
+ if(newCorner[xy] === CENTER) {
+ css[MARGIN+'-'+side] = shift[xy] = offset[MARGIN+'-'+side] - adjust[side];
+ }
+ else {
+ props = offset[opposite] !== undefined ?
+ [ adjust[side], -offset[side] ] : [ -adjust[side], offset[side] ];
+
+ if( (shift[xy] = Math.max(props[0], props[1])) > props[0] ) {
+ pos[side] -= adjust[side];
+ shift[side] = FALSE;
+ }
+
+ css[ offset[opposite] !== undefined ? opposite : side ] = shift[xy];
+ }
+ }
+
+ // If our tip position isn't fixed e.g. doesn't adjust with viewport...
+ if(this.corner.fixed !== TRUE) {
+ // Perform shift/flip adjustments
+ shiftflip(horizontal, X, Y, LEFT, RIGHT);
+ shiftflip(vertical, Y, X, TOP, BOTTOM);
+
+ // Update and redraw the tip if needed (check cached details of last drawn tip)
+ if(newCorner.string() !== cache.corner.string() && (cache.cornerTop !== adjust.top || cache.cornerLeft !== adjust.left)) {
+ this.update(newCorner, FALSE);
+ }
+ }
+
+ // Setup tip offset properties
+ offset = this.calculate(newCorner);
+
+ // Readjust offset object to make it left/top
+ if(offset.right !== undefined) { offset.left = -offset.right; }
+ if(offset.bottom !== undefined) { offset.top = -offset.bottom; }
+ offset.user = this.offset;
+
+ // Perform shift adjustments
+ if(shift.left = (horizontal === SHIFT && !!adjust.left)) { shiftonly(X, LEFT, RIGHT); }
+ if(shift.top = (vertical === SHIFT && !!adjust.top)) { shiftonly(Y, TOP, BOTTOM); }
+
+ /*
+ * If the tip is adjusted in both dimensions, or in a
+ * direction that would cause it to be anywhere but the
+ * outer border, hide it!
+ */
+ this.element.css(css).toggle(
+ !((shift.x && shift.y) || (newCorner.x === CENTER && shift.y) || (newCorner.y === CENTER && shift.x))
+ );
+
+ // Adjust position to accomodate tip dimensions
+ pos.left -= offset.left.charAt ? offset.user :
+ horizontal !== SHIFT || shift.top || !shift.left && !shift.top ? offset.left + this.border : 0;
+ pos.top -= offset.top.charAt ? offset.user :
+ vertical !== SHIFT || shift.left || !shift.left && !shift.top ? offset.top + this.border : 0;
+
+ // Cache details
+ cache.cornerLeft = adjust.left; cache.cornerTop = adjust.top;
+ cache.corner = newCorner.clone();
+ },
+
+ destroy: function() {
+ // Unbind events
+ this.qtip._unbind(this.qtip.tooltip, this._ns);
+
+ // Remove the tip element(s)
+ if(this.qtip.elements.tip) {
+ this.qtip.elements.tip.find('*')
+ .remove().end().remove();
+ }
+ }
+});
+
+TIP = PLUGINS.tip = function(api) {
+ return new Tip(api, api.options.style.tip);
+};
+
+// Initialize tip on render
+TIP.initialize = 'render';
+
+// Setup plugin sanitization options
+TIP.sanitize = function(options) {
+ if(options.style && 'tip' in options.style) {
+ var opts = options.style.tip;
+ if(typeof opts !== 'object') { opts = options.style.tip = { corner: opts }; }
+ if(!(/string|boolean/i).test(typeof opts.corner)) { opts.corner = TRUE; }
+ }
+};
+
+// Add new option checks for the plugin
+CHECKS.tip = {
+ '^position.my|style.tip.(corner|mimic|border)$': function() {
+ // Make sure a tip can be drawn
+ this.create();
+
+ // Reposition the tooltip
+ this.qtip.reposition();
+ },
+ '^style.tip.(height|width)$': function(obj) {
+ // Re-set dimensions and redraw the tip
+ this.size = [ obj.width, obj.height ];
+ this.update();
+
+ // Reposition the tooltip
+ this.qtip.reposition();
+ },
+ '^content.title|style.(classes|widget)$': function() {
+ this.update();
+ }
+};
+
+// Extend original qTip defaults
+$.extend(TRUE, QTIP.defaults, {
+ style: {
+ tip: {
+ corner: TRUE,
+ mimic: FALSE,
+ width: 6,
+ height: 6,
+ border: TRUE,
+ offset: 0
+ }
+ }
+});
+
+;var MODAL, OVERLAY,
+ MODALCLASS = 'qtip-modal',
+ MODALSELECTOR = '.'+MODALCLASS;
+
+OVERLAY = function()
+{
+ var self = this,
+ focusableElems = {},
+ current, onLast,
+ prevState, elem;
+
+ // Modified code from jQuery UI 1.10.0 source
+ // http://code.jquery.com/ui/1.10.0/jquery-ui.js
+ function focusable(element) {
+ // Use the defined focusable checker when possible
+ if($.expr[':'].focusable) { return $.expr[':'].focusable; }
+
+ var isTabIndexNotNaN = !isNaN($.attr(element, 'tabindex')),
+ nodeName = element.nodeName && element.nodeName.toLowerCase(),
+ map, mapName, img;
+
+ if('area' === nodeName) {
+ map = element.parentNode;
+ mapName = map.name;
+ if(!element.href || !mapName || map.nodeName.toLowerCase() !== 'map') {
+ return false;
+ }
+ img = $('img[usemap=#' + mapName + ']')[0];
+ return !!img && img.is(':visible');
+ }
+ return (/input|select|textarea|button|object/.test( nodeName ) ?
+ !element.disabled :
+ 'a' === nodeName ?
+ element.href || isTabIndexNotNaN :
+ isTabIndexNotNaN
+ );
+ }
+
+ // Focus inputs using cached focusable elements (see update())
+ function focusInputs(blurElems) {
+ // Blurring body element in IE causes window.open windows to unfocus!
+ if(focusableElems.length < 1 && blurElems.length) { blurElems.not('body').blur(); }
+
+ // Focus the inputs
+ else { focusableElems.first().focus(); }
+ }
+
+ // Steal focus from elements outside tooltip
+ function stealFocus(event) {
+ if(!elem.is(':visible')) { return; }
+
+ var target = $(event.target),
+ tooltip = current.tooltip,
+ container = target.closest(SELECTOR),
+ targetOnTop;
+
+ // Determine if input container target is above this
+ targetOnTop = container.length < 1 ? FALSE :
+ (parseInt(container[0].style.zIndex, 10) > parseInt(tooltip[0].style.zIndex, 10));
+
+ // If we're showing a modal, but focus has landed on an input below
+ // this modal, divert focus to the first visible input in this modal
+ // or if we can't find one... the tooltip itself
+ if(!targetOnTop && target.closest(SELECTOR)[0] !== tooltip[0]) {
+ focusInputs(target);
+ }
+
+ // Detect when we leave the last focusable element...
+ onLast = event.target === focusableElems[focusableElems.length - 1];
+ }
+
+ $.extend(self, {
+ init: function() {
+ // Create document overlay
+ elem = self.elem = $('<div />', {
+ id: 'qtip-overlay',
+ html: '<div></div>',
+ mousedown: function() { return FALSE; }
+ })
+ .hide();
+
+ // Make sure we can't focus anything outside the tooltip
+ $(document.body).bind('focusin'+MODALSELECTOR, stealFocus);
+
+ // Apply keyboard "Escape key" close handler
+ $(document).bind('keydown'+MODALSELECTOR, function(event) {
+ if(current && current.options.show.modal.escape && event.keyCode === 27) {
+ current.hide(event);
+ }
+ });
+
+ // Apply click handler for blur option
+ elem.bind('click'+MODALSELECTOR, function(event) {
+ if(current && current.options.show.modal.blur) {
+ current.hide(event);
+ }
+ });
+
+ return self;
+ },
+
+ update: function(api) {
+ // Update current API reference
+ current = api;
+
+ // Update focusable elements if enabled
+ if(api.options.show.modal.stealfocus !== FALSE) {
+ focusableElems = api.tooltip.find('*').filter(function() {
+ return focusable(this);
+ });
+ }
+ else { focusableElems = []; }
+ },
+
+ toggle: function(api, state, duration) {
+ var docBody = $(document.body),
+ tooltip = api.tooltip,
+ options = api.options.show.modal,
+ effect = options.effect,
+ type = state ? 'show': 'hide',
+ visible = elem.is(':visible'),
+ visibleModals = $(MODALSELECTOR).filter(':visible:not(:animated)').not(tooltip),
+ zindex;
+
+ // Set active tooltip API reference
+ self.update(api);
+
+ // If the modal can steal the focus...
+ // Blur the current item and focus anything in the modal we an
+ if(state && options.stealfocus !== FALSE) {
+ focusInputs( $(':focus') );
+ }
+
+ // Toggle backdrop cursor style on show
+ elem.toggleClass('blurs', options.blur);
+
+ // Append to body on show
+ if(state) {
+ elem.appendTo(document.body);
+ }
+
+ // Prevent modal from conflicting with show.solo, and don't hide backdrop is other modals are visible
+ if((elem.is(':animated') && visible === state && prevState !== FALSE) || (!state && visibleModals.length)) {
+ return self;
+ }
+
+ // Stop all animations
+ elem.stop(TRUE, FALSE);
+
+ // Use custom function if provided
+ if($.isFunction(effect)) {
+ effect.call(elem, state);
+ }
+
+ // If no effect type is supplied, use a simple toggle
+ else if(effect === FALSE) {
+ elem[ type ]();
+ }
+
+ // Use basic fade function
+ else {
+ elem.fadeTo( parseInt(duration, 10) || 90, state ? 1 : 0, function() {
+ if(!state) { elem.hide(); }
+ });
+ }
+
+ // Reset position and detach from body on hide
+ if(!state) {
+ elem.queue(function(next) {
+ elem.css({ left: '', top: '' });
+ if(!$(MODALSELECTOR).length) { elem.detach(); }
+ next();
+ });
+ }
+
+ // Cache the state
+ prevState = state;
+
+ // If the tooltip is destroyed, set reference to null
+ if(current.destroyed) { current = NULL; }
+
+ return self;
+ }
+ });
+
+ self.init();
+};
+OVERLAY = new OVERLAY();
+
+function Modal(api, options) {
+ this.options = options;
+ this._ns = '-modal';
+
+ this.init( (this.qtip = api) );
+}
+
+$.extend(Modal.prototype, {
+ init: function(qtip) {
+ var tooltip = qtip.tooltip;
+
+ // If modal is disabled... return
+ if(!this.options.on) { return this; }
+
+ // Set overlay reference
+ qtip.elements.overlay = OVERLAY.elem;
+
+ // Add unique attribute so we can grab modal tooltips easily via a SELECTOR, and set z-index
+ tooltip.addClass(MODALCLASS).css('z-index', QTIP.modal_zindex + $(MODALSELECTOR).length);
+
+ // Apply our show/hide/focus modal events
+ qtip._bind(tooltip, ['tooltipshow', 'tooltiphide'], function(event, api, duration) {
+ var oEvent = event.originalEvent;
+
+ // Make sure mouseout doesn't trigger a hide when showing the modal and mousing onto backdrop
+ if(event.target === tooltip[0]) {
+ if(oEvent && event.type === 'tooltiphide' && /mouse(leave|enter)/.test(oEvent.type) && $(oEvent.relatedTarget).closest(OVERLAY.elem[0]).length) {
+ try { event.preventDefault(); } catch(e) {}
+ }
+ else if(!oEvent || (oEvent && oEvent.type !== 'tooltipsolo')) {
+ this.toggle(event, event.type === 'tooltipshow', duration);
+ }
+ }
+ }, this._ns, this);
+
+ // Adjust modal z-index on tooltip focus
+ qtip._bind(tooltip, 'tooltipfocus', function(event, api) {
+ // If focus was cancelled before it reached us, don't do anything
+ if(event.isDefaultPrevented() || event.target !== tooltip[0]) { return; }
+
+ var qtips = $(MODALSELECTOR),
+
+ // Keep the modal's lower than other, regular qtips
+ newIndex = QTIP.modal_zindex + qtips.length,
+ curIndex = parseInt(tooltip[0].style.zIndex, 10);
+
+ // Set overlay z-index
+ OVERLAY.elem[0].style.zIndex = newIndex - 1;
+
+ // Reduce modal z-index's and keep them properly ordered
+ qtips.each(function() {
+ if(this.style.zIndex > curIndex) {
+ this.style.zIndex -= 1;
+ }
+ });
+
+ // Fire blur event for focused tooltip
+ qtips.filter('.' + CLASS_FOCUS).qtip('blur', event.originalEvent);
+
+ // Set the new z-index
+ tooltip.addClass(CLASS_FOCUS)[0].style.zIndex = newIndex;
+
+ // Set current
+ OVERLAY.update(api);
+
+ // Prevent default handling
+ try { event.preventDefault(); } catch(e) {}
+ }, this._ns, this);
+
+ // Focus any other visible modals when this one hides
+ qtip._bind(tooltip, 'tooltiphide', function(event) {
+ if(event.target === tooltip[0]) {
+ $(MODALSELECTOR).filter(':visible').not(tooltip).last().qtip('focus', event);
+ }
+ }, this._ns, this);
+ },
+
+ toggle: function(event, state, duration) {
+ // Make sure default event hasn't been prevented
+ if(event && event.isDefaultPrevented()) { return this; }
+
+ // Toggle it
+ OVERLAY.toggle(this.qtip, !!state, duration);
+ },
+
+ destroy: function() {
+ // Remove modal class
+ this.qtip.tooltip.removeClass(MODALCLASS);
+
+ // Remove bound events
+ this.qtip._unbind(this.qtip.tooltip, this._ns);
+
+ // Delete element reference
+ OVERLAY.toggle(this.qtip, FALSE);
+ delete this.qtip.elements.overlay;
+ }
+});
+
+
+MODAL = PLUGINS.modal = function(api) {
+ return new Modal(api, api.options.show.modal);
+};
+
+// Setup sanitiztion rules
+MODAL.sanitize = function(opts) {
+ if(opts.show) {
+ if(typeof opts.show.modal !== 'object') { opts.show.modal = { on: !!opts.show.modal }; }
+ else if(typeof opts.show.modal.on === 'undefined') { opts.show.modal.on = TRUE; }
+ }
+};
+
+// Base z-index for all modal tooltips (use qTip core z-index as a base)
+QTIP.modal_zindex = QTIP.zindex - 200;
+
+// Plugin needs to be initialized on render
+MODAL.initialize = 'render';
+
+// Setup option set checks
+CHECKS.modal = {
+ '^show.modal.(on|blur)$': function() {
+ // Initialise
+ this.destroy();
+ this.init();
+
+ // Show the modal if not visible already and tooltip is visible
+ this.qtip.elems.overlay.toggle(
+ this.qtip.tooltip[0].offsetWidth > 0
+ );
+ }
+};
+
+// Extend original api defaults
+$.extend(TRUE, QTIP.defaults, {
+ show: {
+ modal: {
+ on: FALSE,
+ effect: TRUE,
+ blur: TRUE,
+ stealfocus: TRUE,
+ escape: TRUE
+ }
+ }
+});
+;PLUGINS.viewport = function(api, position, posOptions, targetWidth, targetHeight, elemWidth, elemHeight)
+{
+ var target = posOptions.target,
+ tooltip = api.elements.tooltip,
+ my = posOptions.my,
+ at = posOptions.at,
+ adjust = posOptions.adjust,
+ method = adjust.method.split(' '),
+ methodX = method[0],
+ methodY = method[1] || method[0],
+ viewport = posOptions.viewport,
+ container = posOptions.container,
+ cache = api.cache,
+ adjusted = { left: 0, top: 0 },
+ fixed, newMy, newClass, containerOffset, containerStatic,
+ viewportWidth, viewportHeight, viewportScroll, viewportOffset;
+
+ // If viewport is not a jQuery element, or it's the window/document, or no adjustment method is used... return
+ if(!viewport.jquery || target[0] === window || target[0] === document.body || adjust.method === 'none') {
+ return adjusted;
+ }
+
+ // Cach container details
+ containerOffset = container.offset() || adjusted;
+ containerStatic = container.css('position') === 'static';
+
+ // Cache our viewport details
+ fixed = tooltip.css('position') === 'fixed';
+ viewportWidth = viewport[0] === window ? viewport.width() : viewport.outerWidth(FALSE);
+ viewportHeight = viewport[0] === window ? viewport.height() : viewport.outerHeight(FALSE);
+ viewportScroll = { left: fixed ? 0 : viewport.scrollLeft(), top: fixed ? 0 : viewport.scrollTop() };
+ viewportOffset = viewport.offset() || adjusted;
+
+ // Generic calculation method
+ function calculate(side, otherSide, type, adjust, side1, side2, lengthName, targetLength, elemLength) {
+ var initialPos = position[side1],
+ mySide = my[side],
+ atSide = at[side],
+ isShift = type === SHIFT,
+ myLength = mySide === side1 ? elemLength : mySide === side2 ? -elemLength : -elemLength / 2,
+ atLength = atSide === side1 ? targetLength : atSide === side2 ? -targetLength : -targetLength / 2,
+ sideOffset = viewportScroll[side1] + viewportOffset[side1] - (containerStatic ? 0 : containerOffset[side1]),
+ overflow1 = sideOffset - initialPos,
+ overflow2 = initialPos + elemLength - (lengthName === WIDTH ? viewportWidth : viewportHeight) - sideOffset,
+ offset = myLength - (my.precedance === side || mySide === my[otherSide] ? atLength : 0) - (atSide === CENTER ? targetLength / 2 : 0);
+
+ // shift
+ if(isShift) {
+ offset = (mySide === side1 ? 1 : -1) * myLength;
+
+ // Adjust position but keep it within viewport dimensions
+ position[side1] += overflow1 > 0 ? overflow1 : overflow2 > 0 ? -overflow2 : 0;
+ position[side1] = Math.max(
+ -containerOffset[side1] + viewportOffset[side1],
+ initialPos - offset,
+ Math.min(
+ Math.max(
+ -containerOffset[side1] + viewportOffset[side1] + (lengthName === WIDTH ? viewportWidth : viewportHeight),
+ initialPos + offset
+ ),
+ position[side1],
+
+ // Make sure we don't adjust complete off the element when using 'center'
+ mySide === 'center' ? initialPos - myLength : 1E9
+ )
+ );
+
+ }
+
+ // flip/flipinvert
+ else {
+ // Update adjustment amount depending on if using flipinvert or flip
+ adjust *= (type === FLIPINVERT ? 2 : 0);
+
+ // Check for overflow on the left/top
+ if(overflow1 > 0 && (mySide !== side1 || overflow2 > 0)) {
+ position[side1] -= offset + adjust;
+ newMy.invert(side, side1);
+ }
+
+ // Check for overflow on the bottom/right
+ else if(overflow2 > 0 && (mySide !== side2 || overflow1 > 0) ) {
+ position[side1] -= (mySide === CENTER ? -offset : offset) + adjust;
+ newMy.invert(side, side2);
+ }
+
+ // Make sure we haven't made things worse with the adjustment and reset if so
+ if(position[side1] < viewportScroll && -position[side1] > overflow2) {
+ position[side1] = initialPos; newMy = my.clone();
+ }
+ }
+
+ return position[side1] - initialPos;
+ }
+
+ // Set newMy if using flip or flipinvert methods
+ if(methodX !== 'shift' || methodY !== 'shift') { newMy = my.clone(); }
+
+ // Adjust position based onviewport and adjustment options
+ adjusted = {
+ left: methodX !== 'none' ? calculate( X, Y, methodX, adjust.x, LEFT, RIGHT, WIDTH, targetWidth, elemWidth ) : 0,
+ top: methodY !== 'none' ? calculate( Y, X, methodY, adjust.y, TOP, BOTTOM, HEIGHT, targetHeight, elemHeight ) : 0
+ };
+
+ // Set tooltip position class if it's changed
+ if(newMy && cache.lastClass !== (newClass = NAMESPACE + '-pos-' + newMy.abbrev())) {
+ tooltip.removeClass(api.cache.lastClass).addClass( (api.cache.lastClass = newClass) );
+ }
+
+ return adjusted;
+};
+;PLUGINS.polys = {
+ // POLY area coordinate calculator
+ // Special thanks to Ed Cradock for helping out with this.
+ // Uses a binary search algorithm to find suitable coordinates.
+ polygon: function(baseCoords, corner) {
+ var result = {
+ width: 0, height: 0,
+ position: {
+ top: 1e10, right: 0,
+ bottom: 0, left: 1e10
+ },
+ adjustable: FALSE
+ },
+ i = 0, next,
+ coords = [],
+ compareX = 1, compareY = 1,
+ realX = 0, realY = 0,
+ newWidth, newHeight;
+
+ // First pass, sanitize coords and determine outer edges
+ i = baseCoords.length; while(i--) {
+ next = [ parseInt(baseCoords[--i], 10), parseInt(baseCoords[i+1], 10) ];
+
+ if(next[0] > result.position.right){ result.position.right = next[0]; }
+ if(next[0] < result.position.left){ result.position.left = next[0]; }
+ if(next[1] > result.position.bottom){ result.position.bottom = next[1]; }
+ if(next[1] < result.position.top){ result.position.top = next[1]; }
+
+ coords.push(next);
+ }
+
+ // Calculate height and width from outer edges
+ newWidth = result.width = Math.abs(result.position.right - result.position.left);
+ newHeight = result.height = Math.abs(result.position.bottom - result.position.top);
+
+ // If it's the center corner...
+ if(corner.abbrev() === 'c') {
+ result.position = {
+ left: result.position.left + (result.width / 2),
+ top: result.position.top + (result.height / 2)
+ };
+ }
+ else {
+ // Second pass, use a binary search algorithm to locate most suitable coordinate
+ while(newWidth > 0 && newHeight > 0 && compareX > 0 && compareY > 0)
+ {
+ newWidth = Math.floor(newWidth / 2);
+ newHeight = Math.floor(newHeight / 2);
+
+ if(corner.x === LEFT){ compareX = newWidth; }
+ else if(corner.x === RIGHT){ compareX = result.width - newWidth; }
+ else{ compareX += Math.floor(newWidth / 2); }
+
+ if(corner.y === TOP){ compareY = newHeight; }
+ else if(corner.y === BOTTOM){ compareY = result.height - newHeight; }
+ else{ compareY += Math.floor(newHeight / 2); }
+
+ i = coords.length; while(i--)
+ {
+ if(coords.length < 2){ break; }
+
+ realX = coords[i][0] - result.position.left;
+ realY = coords[i][1] - result.position.top;
+
+ if((corner.x === LEFT && realX >= compareX) ||
+ (corner.x === RIGHT && realX <= compareX) ||
+ (corner.x === CENTER && (realX < compareX || realX > (result.width - compareX))) ||
+ (corner.y === TOP && realY >= compareY) ||
+ (corner.y === BOTTOM && realY <= compareY) ||
+ (corner.y === CENTER && (realY < compareY || realY > (result.height - compareY)))) {
+ coords.splice(i, 1);
+ }
+ }
+ }
+ result.position = { left: coords[0][0], top: coords[0][1] };
+ }
+
+ return result;
+ },
+
+ rect: function(ax, ay, bx, by) {
+ return {
+ width: Math.abs(bx - ax),
+ height: Math.abs(by - ay),
+ position: {
+ left: Math.min(ax, bx),
+ top: Math.min(ay, by)
+ }
+ };
+ },
+
+ _angles: {
+ tc: 3 / 2, tr: 7 / 4, tl: 5 / 4,
+ bc: 1 / 2, br: 1 / 4, bl: 3 / 4,
+ rc: 2, lc: 1, c: 0
+ },
+ ellipse: function(cx, cy, rx, ry, corner) {
+ var c = PLUGINS.polys._angles[ corner.abbrev() ],
+ rxc = c === 0 ? 0 : rx * Math.cos( c * Math.PI ),
+ rys = ry * Math.sin( c * Math.PI );
+
+ return {
+ width: (rx * 2) - Math.abs(rxc),
+ height: (ry * 2) - Math.abs(rys),
+ position: {
+ left: cx + rxc,
+ top: cy + rys
+ },
+ adjustable: FALSE
+ };
+ },
+ circle: function(cx, cy, r, corner) {
+ return PLUGINS.polys.ellipse(cx, cy, r, r, corner);
+ }
+};;PLUGINS.svg = function(api, svg, corner)
+{
+ var doc = $(document),
+ elem = svg[0],
+ root = $(elem.ownerSVGElement),
+ xScale = 1, yScale = 1,
+ complex = true,
+ rootWidth, rootHeight,
+ mtx, transformed, viewBox,
+ len, next, i, points,
+ result, position, dimensions;
+
+ // Ascend the parentNode chain until we find an element with getBBox()
+ while(!elem.getBBox) { elem = elem.parentNode; }
+ if(!elem.getBBox || !elem.parentNode) { return FALSE; }
+
+ // Determine dimensions where possible
+ rootWidth = root.attr('width') || root.width() || parseInt(root.css('width'), 10);
+ rootHeight = root.attr('height') || root.height() || parseInt(root.css('height'), 10);
+
+ // Add stroke characteristics to scaling
+ var strokeWidth2 = (parseInt(svg.css('stroke-width'), 10) || 0) / 2;
+ if(strokeWidth2) {
+ xScale += strokeWidth2 / rootWidth;
+ yScale += strokeWidth2 / rootHeight;
+ }
+
+ // Determine which shape calculation to use
+ switch(elem.nodeName) {
+ case 'ellipse':
+ case 'circle':
+ result = PLUGINS.polys.ellipse(
+ elem.cx.baseVal.value,
+ elem.cy.baseVal.value,
+ (elem.rx || elem.r).baseVal.value + strokeWidth2,
+ (elem.ry || elem.r).baseVal.value + strokeWidth2,
+ corner
+ );
+ break;
+
+ case 'line':
+ case 'polygon':
+ case 'polyline':
+ // Determine points object (line has none, so mimic using array)
+ points = elem.points || [
+ { x: elem.x1.baseVal.value, y: elem.y1.baseVal.value },
+ { x: elem.x2.baseVal.value, y: elem.y2.baseVal.value }
+ ];
+
+ for(result = [], i = -1, len = points.numberOfItems || points.length; ++i < len;) {
+ next = points.getItem ? points.getItem(i) : points[i];
+ result.push.apply(result, [next.x, next.y]);
+ }
+
+ result = PLUGINS.polys.polygon(result, corner);
+ break;
+
+ // Unknown shape or rectangle? Use bounding box
+ default:
+ result = elem.getBoundingClientRect();
+ result = {
+ width: result.width, height: result.height,
+ position: {
+ left: result.left,
+ top: result.top
+ }
+ };
+ complex = false;
+ break;
+ }
+
+ // Shortcut assignments
+ position = result.position;
+ root = root[0];
+
+ // If the shape was complex (i.e. not using bounding box calculations)
+ if(complex) {
+ // Convert position into a pixel value
+ if(root.createSVGPoint) {
+ mtx = elem.getScreenCTM();
+ points = root.createSVGPoint();
+
+ points.x = position.left;
+ points.y = position.top;
+ transformed = points.matrixTransform( mtx );
+ position.left = transformed.x;
+ position.top = transformed.y;
+ }
+
+ // Calculate viewBox characteristics
+ if(root.viewBox && (viewBox = root.viewBox.baseVal) && viewBox.width && viewBox.height) {
+ xScale *= rootWidth / viewBox.width;
+ yScale *= rootHeight / viewBox.height;
+ }
+ }
+
+ // Adjust by scroll offset
+ position.left += doc.scrollLeft();
+ position.top += doc.scrollTop();
+
+ return result;
+};;PLUGINS.imagemap = function(api, area, corner, adjustMethod)
+{
+ if(!area.jquery) { area = $(area); }
+
+ var shape = area.attr('shape').toLowerCase().replace('poly', 'polygon'),
+ image = $('img[usemap="#'+area.parent('map').attr('name')+'"]'),
+ coordsString = $.trim(area.attr('coords')),
+ coordsArray = coordsString.replace(/,$/, '').split(','),
+ imageOffset, coords, i, next, result, len;
+
+ // If we can't find the image using the map...
+ if(!image.length) { return FALSE; }
+
+ // Pass coordinates string if polygon
+ if(shape === 'polygon') {
+ result = PLUGINS.polys.polygon(coordsArray, corner);
+ }
+
+ // Otherwise parse the coordinates and pass them as arguments
+ else if(PLUGINS.polys[shape]) {
+ for(i = -1, len = coordsArray.length, coords = []; ++i < len;) {
+ coords.push( parseInt(coordsArray[i], 10) );
+ }
+
+ result = PLUGINS.polys[shape].apply(
+ this, coords.concat(corner)
+ );
+ }
+
+ // If no shapre calculation method was found, return false
+ else { return FALSE; }
+
+ // Make sure we account for padding and borders on the image
+ imageOffset = image.offset();
+ imageOffset.left += Math.ceil((image.outerWidth(FALSE) - image.width()) / 2);
+ imageOffset.top += Math.ceil((image.outerHeight(FALSE) - image.height()) / 2);
+
+ // Add image position to offset coordinates
+ result.position.left += imageOffset.left;
+ result.position.top += imageOffset.top;
+
+ return result;
+};;var IE6,
+
+/*
+ * BGIFrame adaption (http://plugins.jquery.com/project/bgiframe)
+ * Special thanks to Brandon Aaron
+ */
+BGIFRAME = '<iframe class="qtip-bgiframe" frameborder="0" tabindex="-1" src="javascript:\'\';" ' +
+ ' style="display:block; position:absolute; z-index:-1; filter:alpha(opacity=0); ' +
+ '-ms-filter:"progid:DXImageTransform.Microsoft.Alpha(Opacity=0)";"></iframe>';
+
+function Ie6(api, qtip) {
+ this._ns = 'ie6';
+ this.init( (this.qtip = api) );
+}
+
+$.extend(Ie6.prototype, {
+ _scroll : function() {
+ var overlay = this.qtip.elements.overlay;
+ overlay && (overlay[0].style.top = $(window).scrollTop() + 'px');
+ },
+
+ init: function(qtip) {
+ var tooltip = qtip.tooltip,
+ scroll;
+
+ // Create the BGIFrame element if needed
+ if($('select, object').length < 1) {
+ this.bgiframe = qtip.elements.bgiframe = $(BGIFRAME).appendTo(tooltip);
+
+ // Update BGIFrame on tooltip move
+ qtip._bind(tooltip, 'tooltipmove', this.adjustBGIFrame, this._ns, this);
+ }
+
+ // redraw() container for width/height calculations
+ this.redrawContainer = $('<div/>', { id: NAMESPACE+'-rcontainer' })
+ .appendTo(document.body);
+
+ // Fixup modal plugin if present too
+ if( qtip.elements.overlay && qtip.elements.overlay.addClass('qtipmodal-ie6fix') ) {
+ qtip._bind(window, ['scroll', 'resize'], this._scroll, this._ns, this);
+ qtip._bind(tooltip, ['tooltipshow'], this._scroll, this._ns, this);
+ }
+
+ // Set dimensions
+ this.redraw();
+ },
+
+ adjustBGIFrame: function() {
+ var tooltip = this.qtip.tooltip,
+ dimensions = {
+ height: tooltip.outerHeight(FALSE),
+ width: tooltip.outerWidth(FALSE)
+ },
+ plugin = this.qtip.plugins.tip,
+ tip = this.qtip.elements.tip,
+ tipAdjust, offset;
+
+ // Adjust border offset
+ offset = parseInt(tooltip.css('borderLeftWidth'), 10) || 0;
+ offset = { left: -offset, top: -offset };
+
+ // Adjust for tips plugin
+ if(plugin && tip) {
+ tipAdjust = (plugin.corner.precedance === 'x') ? [WIDTH, LEFT] : [HEIGHT, TOP];
+ offset[ tipAdjust[1] ] -= tip[ tipAdjust[0] ]();
+ }
+
+ // Update bgiframe
+ this.bgiframe.css(offset).css(dimensions);
+ },
+
+ // Max/min width simulator function
+ redraw: function() {
+ if(this.qtip.rendered < 1 || this.drawing) { return this; }
+
+ var tooltip = this.qtip.tooltip,
+ style = this.qtip.options.style,
+ container = this.qtip.options.position.container,
+ perc, width, max, min;
+
+ // Set drawing flag
+ this.qtip.drawing = 1;
+
+ // If tooltip has a set height/width, just set it... like a boss!
+ if(style.height) { tooltip.css(HEIGHT, style.height); }
+ if(style.width) { tooltip.css(WIDTH, style.width); }
+
+ // Simulate max/min width if not set width present...
+ else {
+ // Reset width and add fluid class
+ tooltip.css(WIDTH, '').appendTo(this.redrawContainer);
+
+ // Grab our tooltip width (add 1 if odd so we don't get wrapping problems.. huzzah!)
+ width = tooltip.width();
+ if(width % 2 < 1) { width += 1; }
+
+ // Grab our max/min properties
+ max = tooltip.css('maxWidth') || '';
+ min = tooltip.css('minWidth') || '';
+
+ // Parse into proper pixel values
+ perc = (max + min).indexOf('%') > -1 ? container.width() / 100 : 0;
+ max = ((max.indexOf('%') > -1 ? perc : 1) * parseInt(max, 10)) || width;
+ min = ((min.indexOf('%') > -1 ? perc : 1) * parseInt(min, 10)) || 0;
+
+ // Determine new dimension size based on max/min/current values
+ width = max + min ? Math.min(Math.max(width, min), max) : width;
+
+ // Set the newly calculated width and remvoe fluid class
+ tooltip.css(WIDTH, Math.round(width)).appendTo(container);
+ }
+
+ // Set drawing flag
+ this.drawing = 0;
+
+ return this;
+ },
+
+ destroy: function() {
+ // Remove iframe
+ this.bgiframe && this.bgiframe.remove();
+
+ // Remove bound events
+ this.qtip._unbind([window, this.qtip.tooltip], this._ns);
+ }
+});
+
+IE6 = PLUGINS.ie6 = function(api) {
+ // Proceed only if the browser is IE6
+ return BROWSER.ie === 6 ? new Ie6(api) : FALSE;
+};
+
+IE6.initialize = 'render';
+
+CHECKS.ie6 = {
+ '^content|style$': function() {
+ this.redraw();
+ }
+};;}));
+}( window, document ));
+
+
diff --git a/docs/htmldoc/js/jquery.qtip.min.css b/docs/htmldoc/js/jquery.qtip.min.css
new file mode 100644
index 0000000..fc172a4
--- /dev/null
+++ b/docs/htmldoc/js/jquery.qtip.min.css
@@ -0,0 +1,2 @@
+/* qTip2 v2.2.0 basic css3 | qtip2.com | Licensed MIT, GPL | Thu Nov 21 2013 20:35:00 */
+.qtip{position:absolute;left:-28000px;top:-28000px;display:none;max-width:280px;min-width:50px;font-size:10.5px;line-height:12px;direction:ltr;box-shadow:none;padding:0}.qtip-content{position:relative;padding:5px 9px;overflow:hidden;text-align:left;word-wrap:break-word}.qtip-titlebar{position:relative;padding:5px 35px 5px 10px;overflow:hidden;border-width:0 0 1px;font-weight:700}.qtip-titlebar+.qtip-content{border-top-width:0!important}.qtip-close{position:absolute;right:-9px;top:-9px;cursor:pointer;outline:medium none;border-width:1px;border-style:solid;border-color:transparent}.qtip-titlebar .qtip-close{right:4px;top:50%;margin-top:-9px}* html .qtip-titlebar .qtip-close{top:16px}.qtip-titlebar .ui-icon,.qtip-icon .ui-icon{display:block;text-indent:-1000em;direction:ltr}.qtip-icon,.qtip-icon .ui-icon{-moz-border-radius:3px;-webkit-border-radius:3px;border-radius:3px;text-decoration:none}.qtip-icon .ui-icon{width:18px;height:14px;line-height:14px;text-align:center;text-indent:0;font:400 bold 10px/13px Tahoma,sans-serif;color:inherit;background:transparent none no-repeat -100em -100em}.qtip-focus{}.qtip-hover{}.qtip-default{border-width:1px;border-style:solid;border-color:#F1D031;background-color:#FFFFA3;color:#555}.qtip-default .qtip-titlebar{background-color:#FFEF93}.qtip-default .qtip-icon{border-color:#CCC;background:#F1F1F1;color:#777}.qtip-default .qtip-titlebar .qtip-close{border-color:#AAA;color:#111} .qtip-light{background-color:#fff;border-color:#E2E2E2;color:#454545}.qtip-light .qtip-titlebar{background-color:#f1f1f1} .qtip-dark{background-color:#505050;border-color:#303030;color:#f3f3f3}.qtip-dark .qtip-titlebar{background-color:#404040}.qtip-dark .qtip-icon{border-color:#444}.qtip-dark .qtip-titlebar .ui-state-hover{border-color:#303030} .qtip-cream{background-color:#FBF7AA;border-color:#F9E98E;color:#A27D35}.qtip-cream .qtip-titlebar{background-color:#F0DE7D}.qtip-cream .qtip-close .qtip-icon{background-position:-82px 0} .qtip-red{background-color:#F78B83;border-color:#D95252;color:#912323}.qtip-red .qtip-titlebar{background-color:#F06D65}.qtip-red .qtip-close .qtip-icon{background-position:-102px 0}.qtip-red .qtip-icon{border-color:#D95252}.qtip-red .qtip-titlebar .ui-state-hover{border-color:#D95252} .qtip-green{background-color:#CAED9E;border-color:#90D93F;color:#3F6219}.qtip-green .qtip-titlebar{background-color:#B0DE78}.qtip-green .qtip-close .qtip-icon{background-position:-42px 0} .qtip-blue{background-color:#E5F6FE;border-color:#ADD9ED;color:#5E99BD}.qtip-blue .qtip-titlebar{background-color:#D0E9F5}.qtip-blue .qtip-close .qtip-icon{background-position:-2px 0}.qtip-shadow{-webkit-box-shadow:1px 1px 3px 1px rgba(0,0,0,.15);-moz-box-shadow:1px 1px 3px 1px rgba(0,0,0,.15);box-shadow:1px 1px 3px 1px rgba(0,0,0,.15)}.qtip-rounded,.qtip-tipsy,.qtip-bootstrap{-moz-border-radius:5px;-webkit-border-radius:5px;border-radius:5px}.qtip-rounded .qtip-titlebar{-moz-border-radius:4px 4px 0 0;-webkit-border-radius:4px 4px 0 0;border-radius:4px 4px 0 0}.qtip-youtube{-moz-border-radius:2px;-webkit-border-radius:2px;border-radius:2px;-webkit-box-shadow:0 0 3px #333;-moz-box-shadow:0 0 3px #333;box-shadow:0 0 3px #333;color:#fff;border-width:0;background:#4A4A4A;background-image:-webkit-gradient(linear,left top,left bottom,color-stop(0,#4A4A4A),color-stop(100%,#000));background-image:-webkit-linear-gradient(top,#4A4A4A 0,#000 100%);background-image:-moz-linear-gradient(top,#4A4A4A 0,#000 100%);background-image:-ms-linear-gradient(top,#4A4A4A 0,#000 100%);background-image:-o-linear-gradient(top,#4A4A4A 0,#000 100%)}.qtip-youtube .qtip-titlebar{background-color:#4A4A4A;background-color:rgba(0,0,0,0)}.qtip-youtube .qtip-content{padding:.75em;font:12px arial,sans-serif;filter:progid:DXImageTransform.Microsoft.Gradient(GradientType=0, StartColorStr=#4a4a4a, EndColorStr=#000000);-ms-filter:"progid:DXImageTransform.Microsoft.Gradient(GradientType=0, StartColorStr=#4a4a4a, EndColorStr=#000000);"}.qtip-youtube .qtip-icon{border-color:#222}.qtip-youtube .qtip-titlebar .ui-state-hover{border-color:#303030}.qtip-jtools{background:#232323;background:rgba(0,0,0,.7);background-image:-webkit-gradient(linear,left top,left bottom,from(#717171),to(#232323));background-image:-moz-linear-gradient(top,#717171,#232323);background-image:-webkit-linear-gradient(top,#717171,#232323);background-image:-ms-linear-gradient(top,#717171,#232323);background-image:-o-linear-gradient(top,#717171,#232323);border:2px solid #ddd;border:2px solid rgba(241,241,241,1);-moz-border-radius:2px;-webkit-border-radius:2px;border-radius:2px;-webkit-box-shadow:0 0 12px #333;-moz-box-shadow:0 0 12px #333;box-shadow:0 0 12px #333}.qtip-jtools .qtip-titlebar{background-color:transparent;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr=#717171, endColorstr=#4A4A4A);-ms-filter:"progid:DXImageTransform.Microsoft.gradient(startColorstr=#717171, endColorstr=#4A4A4A)"}.qtip-jtools .qtip-content{filter:progid:DXImageTransform.Microsoft.gradient(startColorstr=#4A4A4A, endColorstr=#232323);-ms-filter:"progid:DXImageTransform.Microsoft.gradient(startColorstr=#4A4A4A, endColorstr=#232323)"}.qtip-jtools .qtip-titlebar,.qtip-jtools .qtip-content{background:transparent;color:#fff;border:0 dashed transparent}.qtip-jtools .qtip-icon{border-color:#555}.qtip-jtools .qtip-titlebar .ui-state-hover{border-color:#333}.qtip-cluetip{-webkit-box-shadow:4px 4px 5px rgba(0,0,0,.4);-moz-box-shadow:4px 4px 5px rgba(0,0,0,.4);box-shadow:4px 4px 5px rgba(0,0,0,.4);background-color:#D9D9C2;color:#111;border:0 dashed transparent}.qtip-cluetip .qtip-titlebar{background-color:#87876A;color:#fff;border:0 dashed transparent}.qtip-cluetip .qtip-icon{border-color:#808064}.qtip-cluetip .qtip-titlebar .ui-state-hover{border-color:#696952;color:#696952}.qtip-tipsy{background:#000;background:rgba(0,0,0,.87);color:#fff;border:0 solid transparent;font-size:11px;font-family:'Lucida Grande',sans-serif;font-weight:700;line-height:16px;text-shadow:0 1px #000}.qtip-tipsy .qtip-titlebar{padding:6px 35px 0 10px;background-color:transparent}.qtip-tipsy .qtip-content{padding:6px 10px}.qtip-tipsy .qtip-icon{border-color:#222;text-shadow:none}.qtip-tipsy .qtip-titlebar .ui-state-hover{border-color:#303030}.qtip-tipped{border:3px solid #959FA9;-moz-border-radius:3px;-webkit-border-radius:3px;border-radius:3px;background-color:#F9F9F9;color:#454545;font-weight:400;font-family:serif}.qtip-tipped .qtip-titlebar{border-bottom-width:0;color:#fff;background:#3A79B8;background-image:-webkit-gradient(linear,left top,left bottom,from(#3A79B8),to(#2E629D));background-image:-webkit-linear-gradient(top,#3A79B8,#2E629D);background-image:-moz-linear-gradient(top,#3A79B8,#2E629D);background-image:-ms-linear-gradient(top,#3A79B8,#2E629D);background-image:-o-linear-gradient(top,#3A79B8,#2E629D);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr=#3A79B8, endColorstr=#2E629D);-ms-filter:"progid:DXImageTransform.Microsoft.gradient(startColorstr=#3A79B8, endColorstr=#2E629D)"}.qtip-tipped .qtip-icon{border:2px solid #285589;background:#285589}.qtip-tipped .qtip-icon .ui-icon{background-color:#FBFBFB;color:#555}.qtip-bootstrap{font-size:14px;line-height:20px;color:#333;padding:1px;background-color:#fff;border:1px solid #ccc;border:1px solid rgba(0,0,0,.2);-webkit-border-radius:6px;-moz-border-radius:6px;border-radius:6px;-webkit-box-shadow:0 5px 10px rgba(0,0,0,.2);-moz-box-shadow:0 5px 10px rgba(0,0,0,.2);box-shadow:0 5px 10px rgba(0,0,0,.2);-webkit-background-clip:padding-box;-moz-background-clip:padding;background-clip:padding-box}.qtip-bootstrap .qtip-titlebar{padding:8px 14px;margin:0;font-size:14px;font-weight:400;line-height:18px;background-color:#f7f7f7;border-bottom:1px solid #ebebeb;-webkit-border-radius:5px 5px 0 0;-moz-border-radius:5px 5px 0 0;border-radius:5px 5px 0 0}.qtip-bootstrap .qtip-titlebar .qtip-close{right:11px;top:45%;border-style:none}.qtip-bootstrap .qtip-content{padding:9px 14px}.qtip-bootstrap .qtip-icon{background:transparent}.qtip-bootstrap .qtip-icon .ui-icon{width:auto;height:auto;float:right;font-size:20px;font-weight:700;line-height:18px;color:#000;text-shadow:0 1px 0 #fff;opacity:.2;filter:alpha(opacity=20)}.qtip-bootstrap .qtip-icon .ui-icon:hover{color:#000;text-decoration:none;cursor:pointer;opacity:.4;filter:alpha(opacity=40)}.qtip:not(.ie9haxors) div.qtip-content,.qtip:not(.ie9haxors) div.qtip-titlebar{filter:none;-ms-filter:none}.qtip .qtip-tip{margin:0 auto;overflow:hidden;z-index:10}x:-o-prefocus,.qtip .qtip-tip{visibility:hidden}.qtip .qtip-tip,.qtip .qtip-tip .qtip-vml,.qtip .qtip-tip canvas{position:absolute;color:#123456;background:transparent;border:0 dashed transparent}.qtip .qtip-tip canvas{top:0;left:0}.qtip .qtip-tip .qtip-vml{behavior:url(#default#VML);display:inline-block;visibility:visible}#qtip-overlay{position:fixed;left:0;top:0;width:100%;height:100%}#qtip-overlay.blurs{cursor:pointer}#qtip-overlay div{position:absolute;left:0;top:0;width:100%;height:100%;background-color:#000;opacity:.7;filter:alpha(opacity=70);-ms-filter:"alpha(Opacity=70)"}.qtipmodal-ie6fix{position:absolute!important} \ No newline at end of file
diff --git a/docs/htmldoc/js/jquery.qtip.min.js b/docs/htmldoc/js/jquery.qtip.min.js
new file mode 100644
index 0000000..3ae7bbe
--- /dev/null
+++ b/docs/htmldoc/js/jquery.qtip.min.js
@@ -0,0 +1,4 @@
+/* qTip2 v2.2.0 tips modal viewport svg imagemap ie6 | qtip2.com | Licensed MIT, GPL | Thu Nov 21 2013 20:34:59 */
+(function(t,e,i){(function(t){"use strict";"function"==typeof define&&define.amd?define(["jquery"],t):jQuery&&!jQuery.fn.qtip&&t(jQuery)})(function(s){"use strict";function o(t,e,i,o){this.id=i,this.target=t,this.tooltip=E,this.elements={target:t},this._id=X+"-"+i,this.timers={img:{}},this.options=e,this.plugins={},this.cache={event:{},target:s(),disabled:k,attr:o,onTooltip:k,lastClass:""},this.rendered=this.destroyed=this.disabled=this.waiting=this.hiddenDuringWait=this.positioning=this.triggering=k}function n(t){return t===E||"object"!==s.type(t)}function r(t){return!(s.isFunction(t)||t&&t.attr||t.length||"object"===s.type(t)&&(t.jquery||t.then))}function a(t){var e,i,o,a;return n(t)?k:(n(t.metadata)&&(t.metadata={type:t.metadata}),"content"in t&&(e=t.content,n(e)||e.jquery||e.done?e=t.content={text:i=r(e)?k:e}:i=e.text,"ajax"in e&&(o=e.ajax,a=o&&o.once!==k,delete e.ajax,e.text=function(t,e){var n=i||s(this).attr(e.options.content.attr)||"Loading...",r=s.ajax(s.extend({},o,{context:e})).then(o.success,E,o.error).then(function(t){return t&&a&&e.set("content.text",t),t},function(t,i,s){e.destroyed||0===t.status||e.set("content.text",i+": "+s)});return a?n:(e.set("content.text",n),r)}),"title"in e&&(n(e.title)||(e.button=e.title.button,e.title=e.title.text),r(e.title||k)&&(e.title=k))),"position"in t&&n(t.position)&&(t.position={my:t.position,at:t.position}),"show"in t&&n(t.show)&&(t.show=t.show.jquery?{target:t.show}:t.show===W?{ready:W}:{event:t.show}),"hide"in t&&n(t.hide)&&(t.hide=t.hide.jquery?{target:t.hide}:{event:t.hide}),"style"in t&&n(t.style)&&(t.style={classes:t.style}),s.each(R,function(){this.sanitize&&this.sanitize(t)}),t)}function h(t,e){for(var i,s=0,o=t,n=e.split(".");o=o[n[s++]];)n.length>s&&(i=o);return[i||t,n.pop()]}function l(t,e){var i,s,o;for(i in this.checks)for(s in this.checks[i])(o=RegExp(s,"i").exec(t))&&(e.push(o),("builtin"===i||this.plugins[i])&&this.checks[i][s].apply(this.plugins[i]||this,e))}function c(t){return G.concat("").join(t?"-"+t+" ":" ")}function d(i){return i&&{type:i.type,pageX:i.pageX,pageY:i.pageY,target:i.target,relatedTarget:i.relatedTarget,scrollX:i.scrollX||t.pageXOffset||e.body.scrollLeft||e.documentElement.scrollLeft,scrollY:i.scrollY||t.pageYOffset||e.body.scrollTop||e.documentElement.scrollTop}||{}}function p(t,e){return e>0?setTimeout(s.proxy(t,this),e):(t.call(this),i)}function u(t){return this.tooltip.hasClass(ee)?k:(clearTimeout(this.timers.show),clearTimeout(this.timers.hide),this.timers.show=p.call(this,function(){this.toggle(W,t)},this.options.show.delay),i)}function f(t){if(this.tooltip.hasClass(ee))return k;var e=s(t.relatedTarget),i=e.closest(U)[0]===this.tooltip[0],o=e[0]===this.options.show.target[0];if(clearTimeout(this.timers.show),clearTimeout(this.timers.hide),this!==e[0]&&"mouse"===this.options.position.target&&i||this.options.hide.fixed&&/mouse(out|leave|move)/.test(t.type)&&(i||o))try{t.preventDefault(),t.stopImmediatePropagation()}catch(n){}else this.timers.hide=p.call(this,function(){this.toggle(k,t)},this.options.hide.delay,this)}function g(t){return this.tooltip.hasClass(ee)||!this.options.hide.inactive?k:(clearTimeout(this.timers.inactive),this.timers.inactive=p.call(this,function(){this.hide(t)},this.options.hide.inactive),i)}function m(t){this.rendered&&this.tooltip[0].offsetWidth>0&&this.reposition(t)}function v(t,i,o){s(e.body).delegate(t,(i.split?i:i.join(he+" "))+he,function(){var t=T.api[s.attr(this,H)];t&&!t.disabled&&o.apply(t,arguments)})}function y(t,i,n){var r,h,l,c,d,p=s(e.body),u=t[0]===e?p:t,f=t.metadata?t.metadata(n.metadata):E,g="html5"===n.metadata.type&&f?f[n.metadata.name]:E,m=t.data(n.metadata.name||"qtipopts");try{m="string"==typeof m?s.parseJSON(m):m}catch(v){}if(c=s.extend(W,{},T.defaults,n,"object"==typeof m?a(m):E,a(g||f)),h=c.position,c.id=i,"boolean"==typeof c.content.text){if(l=t.attr(c.content.attr),c.content.attr===k||!l)return k;c.content.text=l}if(h.container.length||(h.container=p),h.target===k&&(h.target=u),c.show.target===k&&(c.show.target=u),c.show.solo===W&&(c.show.solo=h.container.closest("body")),c.hide.target===k&&(c.hide.target=u),c.position.viewport===W&&(c.position.viewport=h.container),h.container=h.container.eq(0),h.at=new z(h.at,W),h.my=new z(h.my),t.data(X))if(c.overwrite)t.qtip("destroy",!0);else if(c.overwrite===k)return k;return t.attr(Y,i),c.suppress&&(d=t.attr("title"))&&t.removeAttr("title").attr(se,d).attr("title",""),r=new o(t,c,i,!!l),t.data(X,r),t.one("remove.qtip-"+i+" removeqtip.qtip-"+i,function(){var t;(t=s(this).data(X))&&t.destroy(!0)}),r}function b(t){return t.charAt(0).toUpperCase()+t.slice(1)}function w(t,e){var s,o,n=e.charAt(0).toUpperCase()+e.slice(1),r=(e+" "+be.join(n+" ")+n).split(" "),a=0;if(ye[e])return t.css(ye[e]);for(;s=r[a++];)if((o=t.css(s))!==i)return ye[e]=s,o}function _(t,e){return Math.ceil(parseFloat(w(t,e)))}function x(t,e){this._ns="tip",this.options=e,this.offset=e.offset,this.size=[e.width,e.height],this.init(this.qtip=t)}function q(t,e){this.options=e,this._ns="-modal",this.init(this.qtip=t)}function C(t){this._ns="ie6",this.init(this.qtip=t)}var T,j,z,M,I,W=!0,k=!1,E=null,S="x",L="y",A="width",B="height",D="top",F="left",O="bottom",P="right",N="center",$="flipinvert",V="shift",R={},X="qtip",Y="data-hasqtip",H="data-qtip-id",G=["ui-widget","ui-tooltip"],U="."+X,Q="click dblclick mousedown mouseup mousemove mouseleave mouseenter".split(" "),J=X+"-fixed",K=X+"-default",Z=X+"-focus",te=X+"-hover",ee=X+"-disabled",ie="_replacedByqTip",se="oldtitle",oe={ie:function(){for(var t=3,i=e.createElement("div");(i.innerHTML="<!--[if gt IE "+ ++t+"]><i></i><![endif]-->")&&i.getElementsByTagName("i")[0];);return t>4?t:0/0}(),iOS:parseFloat((""+(/CPU.*OS ([0-9_]{1,5})|(CPU like).*AppleWebKit.*Mobile/i.exec(navigator.userAgent)||[0,""])[1]).replace("undefined","3_2").replace("_",".").replace("_",""))||k};j=o.prototype,j._when=function(t){return s.when.apply(s,t)},j.render=function(t){if(this.rendered||this.destroyed)return this;var e,i=this,o=this.options,n=this.cache,r=this.elements,a=o.content.text,h=o.content.title,l=o.content.button,c=o.position,d=("."+this._id+" ",[]);return s.attr(this.target[0],"aria-describedby",this._id),this.tooltip=r.tooltip=e=s("<div/>",{id:this._id,"class":[X,K,o.style.classes,X+"-pos-"+o.position.my.abbrev()].join(" "),width:o.style.width||"",height:o.style.height||"",tracking:"mouse"===c.target&&c.adjust.mouse,role:"alert","aria-live":"polite","aria-atomic":k,"aria-describedby":this._id+"-content","aria-hidden":W}).toggleClass(ee,this.disabled).attr(H,this.id).data(X,this).appendTo(c.container).append(r.content=s("<div />",{"class":X+"-content",id:this._id+"-content","aria-atomic":W})),this.rendered=-1,this.positioning=W,h&&(this._createTitle(),s.isFunction(h)||d.push(this._updateTitle(h,k))),l&&this._createButton(),s.isFunction(a)||d.push(this._updateContent(a,k)),this.rendered=W,this._setWidget(),s.each(R,function(t){var e;"render"===this.initialize&&(e=this(i))&&(i.plugins[t]=e)}),this._unassignEvents(),this._assignEvents(),this._when(d).then(function(){i._trigger("render"),i.positioning=k,i.hiddenDuringWait||!o.show.ready&&!t||i.toggle(W,n.event,k),i.hiddenDuringWait=k}),T.api[this.id]=this,this},j.destroy=function(t){function e(){if(!this.destroyed){this.destroyed=W;var t=this.target,e=t.attr(se);this.rendered&&this.tooltip.stop(1,0).find("*").remove().end().remove(),s.each(this.plugins,function(){this.destroy&&this.destroy()}),clearTimeout(this.timers.show),clearTimeout(this.timers.hide),this._unassignEvents(),t.removeData(X).removeAttr(H).removeAttr(Y).removeAttr("aria-describedby"),this.options.suppress&&e&&t.attr("title",e).removeAttr(se),this._unbind(t),this.options=this.elements=this.cache=this.timers=this.plugins=this.mouse=E,delete T.api[this.id]}}return this.destroyed?this.target:(t===W&&"hide"!==this.triggering||!this.rendered?e.call(this):(this.tooltip.one("tooltiphidden",s.proxy(e,this)),!this.triggering&&this.hide()),this.target)},M=j.checks={builtin:{"^id$":function(t,e,i,o){var n=i===W?T.nextid:i,r=X+"-"+n;n!==k&&n.length>0&&!s("#"+r).length?(this._id=r,this.rendered&&(this.tooltip[0].id=this._id,this.elements.content[0].id=this._id+"-content",this.elements.title[0].id=this._id+"-title")):t[e]=o},"^prerender":function(t,e,i){i&&!this.rendered&&this.render(this.options.show.ready)},"^content.text$":function(t,e,i){this._updateContent(i)},"^content.attr$":function(t,e,i,s){this.options.content.text===this.target.attr(s)&&this._updateContent(this.target.attr(i))},"^content.title$":function(t,e,s){return s?(s&&!this.elements.title&&this._createTitle(),this._updateTitle(s),i):this._removeTitle()},"^content.button$":function(t,e,i){this._updateButton(i)},"^content.title.(text|button)$":function(t,e,i){this.set("content."+e,i)},"^position.(my|at)$":function(t,e,i){"string"==typeof i&&(t[e]=new z(i,"at"===e))},"^position.container$":function(t,e,i){this.rendered&&this.tooltip.appendTo(i)},"^show.ready$":function(t,e,i){i&&(!this.rendered&&this.render(W)||this.toggle(W))},"^style.classes$":function(t,e,i,s){this.rendered&&this.tooltip.removeClass(s).addClass(i)},"^style.(width|height)":function(t,e,i){this.rendered&&this.tooltip.css(e,i)},"^style.widget|content.title":function(){this.rendered&&this._setWidget()},"^style.def":function(t,e,i){this.rendered&&this.tooltip.toggleClass(K,!!i)},"^events.(render|show|move|hide|focus|blur)$":function(t,e,i){this.rendered&&this.tooltip[(s.isFunction(i)?"":"un")+"bind"]("tooltip"+e,i)},"^(show|hide|position).(event|target|fixed|inactive|leave|distance|viewport|adjust)":function(){if(this.rendered){var t=this.options.position;this.tooltip.attr("tracking","mouse"===t.target&&t.adjust.mouse),this._unassignEvents(),this._assignEvents()}}}},j.get=function(t){if(this.destroyed)return this;var e=h(this.options,t.toLowerCase()),i=e[0][e[1]];return i.precedance?i.string():i};var ne=/^position\.(my|at|adjust|target|container|viewport)|style|content|show\.ready/i,re=/^prerender|show\.ready/i;j.set=function(t,e){if(this.destroyed)return this;var o,n=this.rendered,r=k,c=this.options;return this.checks,"string"==typeof t?(o=t,t={},t[o]=e):t=s.extend({},t),s.each(t,function(e,o){if(n&&re.test(e))return delete t[e],i;var a,l=h(c,e.toLowerCase());a=l[0][l[1]],l[0][l[1]]=o&&o.nodeType?s(o):o,r=ne.test(e)||r,t[e]=[l[0],l[1],o,a]}),a(c),this.positioning=W,s.each(t,s.proxy(l,this)),this.positioning=k,this.rendered&&this.tooltip[0].offsetWidth>0&&r&&this.reposition("mouse"===c.position.target?E:this.cache.event),this},j._update=function(t,e){var i=this,o=this.cache;return this.rendered&&t?(s.isFunction(t)&&(t=t.call(this.elements.target,o.event,this)||""),s.isFunction(t.then)?(o.waiting=W,t.then(function(t){return o.waiting=k,i._update(t,e)},E,function(t){return i._update(t,e)})):t===k||!t&&""!==t?k:(t.jquery&&t.length>0?e.empty().append(t.css({display:"block",visibility:"visible"})):e.html(t),this._waitForContent(e).then(function(t){t.images&&t.images.length&&i.rendered&&i.tooltip[0].offsetWidth>0&&i.reposition(o.event,!t.length)}))):k},j._waitForContent=function(t){var e=this.cache;return e.waiting=W,(s.fn.imagesLoaded?t.imagesLoaded():s.Deferred().resolve([])).done(function(){e.waiting=k}).promise()},j._updateContent=function(t,e){this._update(t,this.elements.content,e)},j._updateTitle=function(t,e){this._update(t,this.elements.title,e)===k&&this._removeTitle(k)},j._createTitle=function(){var t=this.elements,e=this._id+"-title";t.titlebar&&this._removeTitle(),t.titlebar=s("<div />",{"class":X+"-titlebar "+(this.options.style.widget?c("header"):"")}).append(t.title=s("<div />",{id:e,"class":X+"-title","aria-atomic":W})).insertBefore(t.content).delegate(".qtip-close","mousedown keydown mouseup keyup mouseout",function(t){s(this).toggleClass("ui-state-active ui-state-focus","down"===t.type.substr(-4))}).delegate(".qtip-close","mouseover mouseout",function(t){s(this).toggleClass("ui-state-hover","mouseover"===t.type)}),this.options.content.button&&this._createButton()},j._removeTitle=function(t){var e=this.elements;e.title&&(e.titlebar.remove(),e.titlebar=e.title=e.button=E,t!==k&&this.reposition())},j.reposition=function(i,o){if(!this.rendered||this.positioning||this.destroyed)return this;this.positioning=W;var n,r,a=this.cache,h=this.tooltip,l=this.options.position,c=l.target,d=l.my,p=l.at,u=l.viewport,f=l.container,g=l.adjust,m=g.method.split(" "),v=h.outerWidth(k),y=h.outerHeight(k),b=0,w=0,_=h.css("position"),x={left:0,top:0},q=h[0].offsetWidth>0,C=i&&"scroll"===i.type,T=s(t),j=f[0].ownerDocument,z=this.mouse;if(s.isArray(c)&&2===c.length)p={x:F,y:D},x={left:c[0],top:c[1]};else if("mouse"===c)p={x:F,y:D},!z||!z.pageX||!g.mouse&&i&&i.pageX?i&&i.pageX||((!g.mouse||this.options.show.distance)&&a.origin&&a.origin.pageX?i=a.origin:(!i||i&&("resize"===i.type||"scroll"===i.type))&&(i=a.event)):i=z,"static"!==_&&(x=f.offset()),j.body.offsetWidth!==(t.innerWidth||j.documentElement.clientWidth)&&(r=s(e.body).offset()),x={left:i.pageX-x.left+(r&&r.left||0),top:i.pageY-x.top+(r&&r.top||0)},g.mouse&&C&&z&&(x.left-=(z.scrollX||0)-T.scrollLeft(),x.top-=(z.scrollY||0)-T.scrollTop());else{if("event"===c?i&&i.target&&"scroll"!==i.type&&"resize"!==i.type?a.target=s(i.target):i.target||(a.target=this.elements.target):"event"!==c&&(a.target=s(c.jquery?c:this.elements.target)),c=a.target,c=s(c).eq(0),0===c.length)return this;c[0]===e||c[0]===t?(b=oe.iOS?t.innerWidth:c.width(),w=oe.iOS?t.innerHeight:c.height(),c[0]===t&&(x={top:(u||c).scrollTop(),left:(u||c).scrollLeft()})):R.imagemap&&c.is("area")?n=R.imagemap(this,c,p,R.viewport?m:k):R.svg&&c&&c[0].ownerSVGElement?n=R.svg(this,c,p,R.viewport?m:k):(b=c.outerWidth(k),w=c.outerHeight(k),x=c.offset()),n&&(b=n.width,w=n.height,r=n.offset,x=n.position),x=this.reposition.offset(c,x,f),(oe.iOS>3.1&&4.1>oe.iOS||oe.iOS>=4.3&&4.33>oe.iOS||!oe.iOS&&"fixed"===_)&&(x.left-=T.scrollLeft(),x.top-=T.scrollTop()),(!n||n&&n.adjustable!==k)&&(x.left+=p.x===P?b:p.x===N?b/2:0,x.top+=p.y===O?w:p.y===N?w/2:0)}return x.left+=g.x+(d.x===P?-v:d.x===N?-v/2:0),x.top+=g.y+(d.y===O?-y:d.y===N?-y/2:0),R.viewport?(x.adjusted=R.viewport(this,x,l,b,w,v,y),r&&x.adjusted.left&&(x.left+=r.left),r&&x.adjusted.top&&(x.top+=r.top)):x.adjusted={left:0,top:0},this._trigger("move",[x,u.elem||u],i)?(delete x.adjusted,o===k||!q||isNaN(x.left)||isNaN(x.top)||"mouse"===c||!s.isFunction(l.effect)?h.css(x):s.isFunction(l.effect)&&(l.effect.call(h,this,s.extend({},x)),h.queue(function(t){s(this).css({opacity:"",height:""}),oe.ie&&this.style.removeAttribute("filter"),t()})),this.positioning=k,this):this},j.reposition.offset=function(t,i,o){function n(t,e){i.left+=e*t.scrollLeft(),i.top+=e*t.scrollTop()}if(!o[0])return i;var r,a,h,l,c=s(t[0].ownerDocument),d=!!oe.ie&&"CSS1Compat"!==e.compatMode,p=o[0];do"static"!==(a=s.css(p,"position"))&&("fixed"===a?(h=p.getBoundingClientRect(),n(c,-1)):(h=s(p).position(),h.left+=parseFloat(s.css(p,"borderLeftWidth"))||0,h.top+=parseFloat(s.css(p,"borderTopWidth"))||0),i.left-=h.left+(parseFloat(s.css(p,"marginLeft"))||0),i.top-=h.top+(parseFloat(s.css(p,"marginTop"))||0),r||"hidden"===(l=s.css(p,"overflow"))||"visible"===l||(r=s(p)));while(p=p.offsetParent);return r&&(r[0]!==c[0]||d)&&n(r,1),i};var ae=(z=j.reposition.Corner=function(t,e){t=(""+t).replace(/([A-Z])/," $1").replace(/middle/gi,N).toLowerCase(),this.x=(t.match(/left|right/i)||t.match(/center/)||["inherit"])[0].toLowerCase(),this.y=(t.match(/top|bottom|center/i)||["inherit"])[0].toLowerCase(),this.forceY=!!e;var i=t.charAt(0);this.precedance="t"===i||"b"===i?L:S}).prototype;ae.invert=function(t,e){this[t]=this[t]===F?P:this[t]===P?F:e||this[t]},ae.string=function(){var t=this.x,e=this.y;return t===e?t:this.precedance===L||this.forceY&&"center"!==e?e+" "+t:t+" "+e},ae.abbrev=function(){var t=this.string().split(" ");return t[0].charAt(0)+(t[1]&&t[1].charAt(0)||"")},ae.clone=function(){return new z(this.string(),this.forceY)},j.toggle=function(t,i){var o=this.cache,n=this.options,r=this.tooltip;if(i){if(/over|enter/.test(i.type)&&/out|leave/.test(o.event.type)&&n.show.target.add(i.target).length===n.show.target.length&&r.has(i.relatedTarget).length)return this;o.event=d(i)}if(this.waiting&&!t&&(this.hiddenDuringWait=W),!this.rendered)return t?this.render(1):this;if(this.destroyed||this.disabled)return this;var a,h,l,c=t?"show":"hide",p=this.options[c],u=(this.options[t?"hide":"show"],this.options.position),f=this.options.content,g=this.tooltip.css("width"),m=this.tooltip.is(":visible"),v=t||1===p.target.length,y=!i||2>p.target.length||o.target[0]===i.target;return(typeof t).search("boolean|number")&&(t=!m),a=!r.is(":animated")&&m===t&&y,h=a?E:!!this._trigger(c,[90]),this.destroyed?this:(h!==k&&t&&this.focus(i),!h||a?this:(s.attr(r[0],"aria-hidden",!t),t?(o.origin=d(this.mouse),s.isFunction(f.text)&&this._updateContent(f.text,k),s.isFunction(f.title)&&this._updateTitle(f.title,k),!I&&"mouse"===u.target&&u.adjust.mouse&&(s(e).bind("mousemove."+X,this._storeMouse),I=W),g||r.css("width",r.outerWidth(k)),this.reposition(i,arguments[2]),g||r.css("width",""),p.solo&&("string"==typeof p.solo?s(p.solo):s(U,p.solo)).not(r).not(p.target).qtip("hide",s.Event("tooltipsolo"))):(clearTimeout(this.timers.show),delete o.origin,I&&!s(U+'[tracking="true"]:visible',p.solo).not(r).length&&(s(e).unbind("mousemove."+X),I=k),this.blur(i)),l=s.proxy(function(){t?(oe.ie&&r[0].style.removeAttribute("filter"),r.css("overflow",""),"string"==typeof p.autofocus&&s(this.options.show.autofocus,r).focus(),this.options.show.target.trigger("qtip-"+this.id+"-inactive")):r.css({display:"",visibility:"",opacity:"",left:"",top:""}),this._trigger(t?"visible":"hidden")},this),p.effect===k||v===k?(r[c](),l()):s.isFunction(p.effect)?(r.stop(1,1),p.effect.call(r,this),r.queue("fx",function(t){l(),t()})):r.fadeTo(90,t?1:0,l),t&&p.target.trigger("qtip-"+this.id+"-inactive"),this))},j.show=function(t){return this.toggle(W,t)},j.hide=function(t){return this.toggle(k,t)},j.focus=function(t){if(!this.rendered||this.destroyed)return this;var e=s(U),i=this.tooltip,o=parseInt(i[0].style.zIndex,10),n=T.zindex+e.length;return i.hasClass(Z)||this._trigger("focus",[n],t)&&(o!==n&&(e.each(function(){this.style.zIndex>o&&(this.style.zIndex=this.style.zIndex-1)}),e.filter("."+Z).qtip("blur",t)),i.addClass(Z)[0].style.zIndex=n),this},j.blur=function(t){return!this.rendered||this.destroyed?this:(this.tooltip.removeClass(Z),this._trigger("blur",[this.tooltip.css("zIndex")],t),this)},j.disable=function(t){return this.destroyed?this:("toggle"===t?t=!(this.rendered?this.tooltip.hasClass(ee):this.disabled):"boolean"!=typeof t&&(t=W),this.rendered&&this.tooltip.toggleClass(ee,t).attr("aria-disabled",t),this.disabled=!!t,this)},j.enable=function(){return this.disable(k)},j._createButton=function(){var t=this,e=this.elements,i=e.tooltip,o=this.options.content.button,n="string"==typeof o,r=n?o:"Close tooltip";e.button&&e.button.remove(),e.button=o.jquery?o:s("<a />",{"class":"qtip-close "+(this.options.style.widget?"":X+"-icon"),title:r,"aria-label":r}).prepend(s("<span />",{"class":"ui-icon ui-icon-close",html:"&times;"})),e.button.appendTo(e.titlebar||i).attr("role","button").click(function(e){return i.hasClass(ee)||t.hide(e),k})},j._updateButton=function(t){if(!this.rendered)return k;var e=this.elements.button;t?this._createButton():e.remove()},j._setWidget=function(){var t=this.options.style.widget,e=this.elements,i=e.tooltip,s=i.hasClass(ee);i.removeClass(ee),ee=t?"ui-state-disabled":"qtip-disabled",i.toggleClass(ee,s),i.toggleClass("ui-helper-reset "+c(),t).toggleClass(K,this.options.style.def&&!t),e.content&&e.content.toggleClass(c("content"),t),e.titlebar&&e.titlebar.toggleClass(c("header"),t),e.button&&e.button.toggleClass(X+"-icon",!t)},j._storeMouse=function(t){(this.mouse=d(t)).type="mousemove"},j._bind=function(t,e,i,o,n){var r="."+this._id+(o?"-"+o:"");e.length&&s(t).bind((e.split?e:e.join(r+" "))+r,s.proxy(i,n||this))},j._unbind=function(t,e){s(t).unbind("."+this._id+(e?"-"+e:""))};var he="."+X;s(function(){v(U,["mouseenter","mouseleave"],function(t){var e="mouseenter"===t.type,i=s(t.currentTarget),o=s(t.relatedTarget||t.target),n=this.options;e?(this.focus(t),i.hasClass(J)&&!i.hasClass(ee)&&clearTimeout(this.timers.hide)):"mouse"===n.position.target&&n.hide.event&&n.show.target&&!o.closest(n.show.target[0]).length&&this.hide(t),i.toggleClass(te,e)}),v("["+H+"]",Q,g)}),j._trigger=function(t,e,i){var o=s.Event("tooltip"+t);return o.originalEvent=i&&s.extend({},i)||this.cache.event||E,this.triggering=t,this.tooltip.trigger(o,[this].concat(e||[])),this.triggering=k,!o.isDefaultPrevented()},j._bindEvents=function(t,e,o,n,r,a){if(n.add(o).length===n.length){var h=[];e=s.map(e,function(e){var o=s.inArray(e,t);return o>-1?(h.push(t.splice(o,1)[0]),i):e}),h.length&&this._bind(o,h,function(t){var e=this.rendered?this.tooltip[0].offsetWidth>0:!1;(e?a:r).call(this,t)})}this._bind(o,t,r),this._bind(n,e,a)},j._assignInitialEvents=function(t){function e(t){return this.disabled||this.destroyed?k:(this.cache.event=d(t),this.cache.target=t?s(t.target):[i],clearTimeout(this.timers.show),this.timers.show=p.call(this,function(){this.render("object"==typeof t||o.show.ready)},o.show.delay),i)}var o=this.options,n=o.show.target,r=o.hide.target,a=o.show.event?s.trim(""+o.show.event).split(" "):[],h=o.hide.event?s.trim(""+o.hide.event).split(" "):[];/mouse(over|enter)/i.test(o.show.event)&&!/mouse(out|leave)/i.test(o.hide.event)&&h.push("mouseleave"),this._bind(n,"mousemove",function(t){this._storeMouse(t),this.cache.onTarget=W}),this._bindEvents(a,h,n,r,e,function(){clearTimeout(this.timers.show)}),(o.show.ready||o.prerender)&&e.call(this,t)},j._assignEvents=function(){var i=this,o=this.options,n=o.position,r=this.tooltip,a=o.show.target,h=o.hide.target,l=n.container,c=n.viewport,d=s(e),p=(s(e.body),s(t)),v=o.show.event?s.trim(""+o.show.event).split(" "):[],y=o.hide.event?s.trim(""+o.hide.event).split(" "):[];s.each(o.events,function(t,e){i._bind(r,"toggle"===t?["tooltipshow","tooltiphide"]:["tooltip"+t],e,null,r)}),/mouse(out|leave)/i.test(o.hide.event)&&"window"===o.hide.leave&&this._bind(d,["mouseout","blur"],function(t){/select|option/.test(t.target.nodeName)||t.relatedTarget||this.hide(t)}),o.hide.fixed?h=h.add(r.addClass(J)):/mouse(over|enter)/i.test(o.show.event)&&this._bind(h,"mouseleave",function(){clearTimeout(this.timers.show)}),(""+o.hide.event).indexOf("unfocus")>-1&&this._bind(l.closest("html"),["mousedown","touchstart"],function(t){var e=s(t.target),i=this.rendered&&!this.tooltip.hasClass(ee)&&this.tooltip[0].offsetWidth>0,o=e.parents(U).filter(this.tooltip[0]).length>0;e[0]===this.target[0]||e[0]===this.tooltip[0]||o||this.target.has(e[0]).length||!i||this.hide(t)}),"number"==typeof o.hide.inactive&&(this._bind(a,"qtip-"+this.id+"-inactive",g),this._bind(h.add(r),T.inactiveEvents,g,"-inactive")),this._bindEvents(v,y,a,h,u,f),this._bind(a.add(r),"mousemove",function(t){if("number"==typeof o.hide.distance){var e=this.cache.origin||{},i=this.options.hide.distance,s=Math.abs;(s(t.pageX-e.pageX)>=i||s(t.pageY-e.pageY)>=i)&&this.hide(t)}this._storeMouse(t)}),"mouse"===n.target&&n.adjust.mouse&&(o.hide.event&&this._bind(a,["mouseenter","mouseleave"],function(t){this.cache.onTarget="mouseenter"===t.type}),this._bind(d,"mousemove",function(t){this.rendered&&this.cache.onTarget&&!this.tooltip.hasClass(ee)&&this.tooltip[0].offsetWidth>0&&this.reposition(t)})),(n.adjust.resize||c.length)&&this._bind(s.event.special.resize?c:p,"resize",m),n.adjust.scroll&&this._bind(p.add(n.container),"scroll",m)},j._unassignEvents=function(){var i=[this.options.show.target[0],this.options.hide.target[0],this.rendered&&this.tooltip[0],this.options.position.container[0],this.options.position.viewport[0],this.options.position.container.closest("html")[0],t,e];this._unbind(s([]).pushStack(s.grep(i,function(t){return"object"==typeof t})))},T=s.fn.qtip=function(t,e,o){var n=(""+t).toLowerCase(),r=E,h=s.makeArray(arguments).slice(1),l=h[h.length-1],c=this[0]?s.data(this[0],X):E;return!arguments.length&&c||"api"===n?c:"string"==typeof t?(this.each(function(){var t=s.data(this,X);if(!t)return W;if(l&&l.timeStamp&&(t.cache.event=l),!e||"option"!==n&&"options"!==n)t[n]&&t[n].apply(t,h);else{if(o===i&&!s.isPlainObject(e))return r=t.get(e),k;t.set(e,o)}}),r!==E?r:this):"object"!=typeof t&&arguments.length?i:(c=a(s.extend(W,{},t)),this.each(function(t){var e,o;return o=s.isArray(c.id)?c.id[t]:c.id,o=!o||o===k||1>o.length||T.api[o]?T.nextid++:o,e=y(s(this),o,c),e===k?W:(T.api[o]=e,s.each(R,function(){"initialize"===this.initialize&&this(e)}),e._assignInitialEvents(l),i)}))},s.qtip=o,T.api={},s.each({attr:function(t,e){if(this.length){var i=this[0],o="title",n=s.data(i,"qtip");if(t===o&&n&&"object"==typeof n&&n.options.suppress)return 2>arguments.length?s.attr(i,se):(n&&n.options.content.attr===o&&n.cache.attr&&n.set("content.text",e),this.attr(se,e))}return s.fn["attr"+ie].apply(this,arguments)},clone:function(t){var e=(s([]),s.fn["clone"+ie].apply(this,arguments));return t||e.filter("["+se+"]").attr("title",function(){return s.attr(this,se)}).removeAttr(se),e}},function(t,e){if(!e||s.fn[t+ie])return W;var i=s.fn[t+ie]=s.fn[t];s.fn[t]=function(){return e.apply(this,arguments)||i.apply(this,arguments)}}),s.ui||(s["cleanData"+ie]=s.cleanData,s.cleanData=function(t){for(var e,i=0;(e=s(t[i])).length;i++)if(e.attr(Y))try{e.triggerHandler("removeqtip")}catch(o){}s["cleanData"+ie].apply(this,arguments)}),T.version="2.2.0",T.nextid=0,T.inactiveEvents=Q,T.zindex=15e3,T.defaults={prerender:k,id:k,overwrite:W,suppress:W,content:{text:W,attr:"title",title:k,button:k},position:{my:"top left",at:"bottom right",target:k,container:k,viewport:k,adjust:{x:0,y:0,mouse:W,scroll:W,resize:W,method:"flipinvert flipinvert"},effect:function(t,e){s(this).animate(e,{duration:200,queue:k})}},show:{target:k,event:"mouseenter",effect:W,delay:90,solo:k,ready:k,autofocus:k},hide:{target:k,event:"mouseleave",effect:W,delay:0,fixed:k,inactive:k,leave:"window",distance:k},style:{classes:"",widget:k,width:k,height:k,def:W},events:{render:E,move:E,show:E,hide:E,toggle:E,visible:E,hidden:E,focus:E,blur:E}};var le,ce="margin",de="border",pe="color",ue="background-color",fe="transparent",ge=" !important",me=!!e.createElement("canvas").getContext,ve=/rgba?\(0, 0, 0(, 0)?\)|transparent|#123456/i,ye={},be=["Webkit","O","Moz","ms"];if(me)var we=t.devicePixelRatio||1,_e=function(){var t=e.createElement("canvas").getContext("2d");return t.backingStorePixelRatio||t.webkitBackingStorePixelRatio||t.mozBackingStorePixelRatio||t.msBackingStorePixelRatio||t.oBackingStorePixelRatio||1}(),xe=we/_e;else var qe=function(t,e,i){return"<qtipvml:"+t+' xmlns="urn:schemas-microsoft.com:vml" class="qtip-vml" '+(e||"")+' style="behavior: url(#default#VML); '+(i||"")+'" />'};s.extend(x.prototype,{init:function(t){var e,i;i=this.element=t.elements.tip=s("<div />",{"class":X+"-tip"}).prependTo(t.tooltip),me?(e=s("<canvas />").appendTo(this.element)[0].getContext("2d"),e.lineJoin="miter",e.miterLimit=1e5,e.save()):(e=qe("shape",'coordorigin="0,0"',"position:absolute;"),this.element.html(e+e),t._bind(s("*",i).add(i),["click","mousedown"],function(t){t.stopPropagation()},this._ns)),t._bind(t.tooltip,"tooltipmove",this.reposition,this._ns,this),this.create()},_swapDimensions:function(){this.size[0]=this.options.height,this.size[1]=this.options.width},_resetDimensions:function(){this.size[0]=this.options.width,this.size[1]=this.options.height},_useTitle:function(t){var e=this.qtip.elements.titlebar;return e&&(t.y===D||t.y===N&&this.element.position().top+this.size[1]/2+this.options.offset<e.outerHeight(W))},_parseCorner:function(t){var e=this.qtip.options.position.my;return t===k||e===k?t=k:t===W?t=new z(e.string()):t.string||(t=new z(t),t.fixed=W),t},_parseWidth:function(t,e,i){var s=this.qtip.elements,o=de+b(e)+"Width";return(i?_(i,o):_(s.content,o)||_(this._useTitle(t)&&s.titlebar||s.content,o)||_(s.tooltip,o))||0},_parseRadius:function(t){var e=this.qtip.elements,i=de+b(t.y)+b(t.x)+"Radius";return 9>oe.ie?0:_(this._useTitle(t)&&e.titlebar||e.content,i)||_(e.tooltip,i)||0},_invalidColour:function(t,e,i){var s=t.css(e);return!s||i&&s===t.css(i)||ve.test(s)?k:s},_parseColours:function(t){var e=this.qtip.elements,i=this.element.css("cssText",""),o=de+b(t[t.precedance])+b(pe),n=this._useTitle(t)&&e.titlebar||e.content,r=this._invalidColour,a=[];return a[0]=r(i,ue)||r(n,ue)||r(e.content,ue)||r(e.tooltip,ue)||i.css(ue),a[1]=r(i,o,pe)||r(n,o,pe)||r(e.content,o,pe)||r(e.tooltip,o,pe)||e.tooltip.css(o),s("*",i).add(i).css("cssText",ue+":"+fe+ge+";"+de+":0"+ge+";"),a},_calculateSize:function(t){var e,i,s,o=t.precedance===L,n=this.options.width,r=this.options.height,a="c"===t.abbrev(),h=(o?n:r)*(a?.5:1),l=Math.pow,c=Math.round,d=Math.sqrt(l(h,2)+l(r,2)),p=[this.border/h*d,this.border/r*d];return p[2]=Math.sqrt(l(p[0],2)-l(this.border,2)),p[3]=Math.sqrt(l(p[1],2)-l(this.border,2)),e=d+p[2]+p[3]+(a?0:p[0]),i=e/d,s=[c(i*n),c(i*r)],o?s:s.reverse()},_calculateTip:function(t,e,i){i=i||1,e=e||this.size;var s=e[0]*i,o=e[1]*i,n=Math.ceil(s/2),r=Math.ceil(o/2),a={br:[0,0,s,o,s,0],bl:[0,0,s,0,0,o],tr:[0,o,s,0,s,o],tl:[0,0,0,o,s,o],tc:[0,o,n,0,s,o],bc:[0,0,s,0,n,o],rc:[0,0,s,r,0,o],lc:[s,0,s,o,0,r]};return a.lt=a.br,a.rt=a.bl,a.lb=a.tr,a.rb=a.tl,a[t.abbrev()]},_drawCoords:function(t,e){t.beginPath(),t.moveTo(e[0],e[1]),t.lineTo(e[2],e[3]),t.lineTo(e[4],e[5]),t.closePath()},create:function(){var t=this.corner=(me||oe.ie)&&this._parseCorner(this.options.corner);return(this.enabled=!!this.corner&&"c"!==this.corner.abbrev())&&(this.qtip.cache.corner=t.clone(),this.update()),this.element.toggle(this.enabled),this.corner},update:function(e,i){if(!this.enabled)return this;var o,n,r,a,h,l,c,d,p=this.qtip.elements,u=this.element,f=u.children(),g=this.options,m=this.size,v=g.mimic,y=Math.round;e||(e=this.qtip.cache.corner||this.corner),v===k?v=e:(v=new z(v),v.precedance=e.precedance,"inherit"===v.x?v.x=e.x:"inherit"===v.y?v.y=e.y:v.x===v.y&&(v[e.precedance]=e[e.precedance])),n=v.precedance,e.precedance===S?this._swapDimensions():this._resetDimensions(),o=this.color=this._parseColours(e),o[1]!==fe?(d=this.border=this._parseWidth(e,e[e.precedance]),g.border&&1>d&&!ve.test(o[1])&&(o[0]=o[1]),this.border=d=g.border!==W?g.border:d):this.border=d=0,c=this.size=this._calculateSize(e),u.css({width:c[0],height:c[1],lineHeight:c[1]+"px"}),l=e.precedance===L?[y(v.x===F?d:v.x===P?c[0]-m[0]-d:(c[0]-m[0])/2),y(v.y===D?c[1]-m[1]:0)]:[y(v.x===F?c[0]-m[0]:0),y(v.y===D?d:v.y===O?c[1]-m[1]-d:(c[1]-m[1])/2)],me?(r=f[0].getContext("2d"),r.restore(),r.save(),r.clearRect(0,0,6e3,6e3),a=this._calculateTip(v,m,xe),h=this._calculateTip(v,this.size,xe),f.attr(A,c[0]*xe).attr(B,c[1]*xe),f.css(A,c[0]).css(B,c[1]),this._drawCoords(r,h),r.fillStyle=o[1],r.fill(),r.translate(l[0]*xe,l[1]*xe),this._drawCoords(r,a),r.fillStyle=o[0],r.fill()):(a=this._calculateTip(v),a="m"+a[0]+","+a[1]+" l"+a[2]+","+a[3]+" "+a[4]+","+a[5]+" xe",l[2]=d&&/^(r|b)/i.test(e.string())?8===oe.ie?2:1:0,f.css({coordsize:c[0]+d+" "+(c[1]+d),antialias:""+(v.string().indexOf(N)>-1),left:l[0]-l[2]*Number(n===S),top:l[1]-l[2]*Number(n===L),width:c[0]+d,height:c[1]+d}).each(function(t){var e=s(this);e[e.prop?"prop":"attr"]({coordsize:c[0]+d+" "+(c[1]+d),path:a,fillcolor:o[0],filled:!!t,stroked:!t}).toggle(!(!d&&!t)),!t&&e.html(qe("stroke",'weight="'+2*d+'px" color="'+o[1]+'" miterlimit="1000" joinstyle="miter"'))})),t.opera&&setTimeout(function(){p.tip.css({display:"inline-block",visibility:"visible"})},1),i!==k&&this.calculate(e,c)},calculate:function(t,e){if(!this.enabled)return k;var i,o,n=this,r=this.qtip.elements,a=this.element,h=this.options.offset,l=(r.tooltip.hasClass("ui-widget"),{});return t=t||this.corner,i=t.precedance,e=e||this._calculateSize(t),o=[t.x,t.y],i===S&&o.reverse(),s.each(o,function(s,o){var a,c,d;o===N?(a=i===L?F:D,l[a]="50%",l[ce+"-"+a]=-Math.round(e[i===L?0:1]/2)+h):(a=n._parseWidth(t,o,r.tooltip),c=n._parseWidth(t,o,r.content),d=n._parseRadius(t),l[o]=Math.max(-n.border,s?c:h+(d>a?d:-a)))
+}),l[t[i]]-=e[i===S?0:1],a.css({margin:"",top:"",bottom:"",left:"",right:""}).css(l),l},reposition:function(t,e,s){function o(t,e,i,s,o){t===V&&l.precedance===e&&c[s]&&l[i]!==N?l.precedance=l.precedance===S?L:S:t!==V&&c[s]&&(l[e]=l[e]===N?c[s]>0?s:o:l[e]===s?o:s)}function n(t,e,o){l[t]===N?g[ce+"-"+e]=f[t]=r[ce+"-"+e]-c[e]:(a=r[o]!==i?[c[e],-r[e]]:[-c[e],r[e]],(f[t]=Math.max(a[0],a[1]))>a[0]&&(s[e]-=c[e],f[e]=k),g[r[o]!==i?o:e]=f[t])}if(this.enabled){var r,a,h=e.cache,l=this.corner.clone(),c=s.adjusted,d=e.options.position.adjust.method.split(" "),p=d[0],u=d[1]||d[0],f={left:k,top:k,x:0,y:0},g={};this.corner.fixed!==W&&(o(p,S,L,F,P),o(u,L,S,D,O),l.string()===h.corner.string()||h.cornerTop===c.top&&h.cornerLeft===c.left||this.update(l,k)),r=this.calculate(l),r.right!==i&&(r.left=-r.right),r.bottom!==i&&(r.top=-r.bottom),r.user=this.offset,(f.left=p===V&&!!c.left)&&n(S,F,P),(f.top=u===V&&!!c.top)&&n(L,D,O),this.element.css(g).toggle(!(f.x&&f.y||l.x===N&&f.y||l.y===N&&f.x)),s.left-=r.left.charAt?r.user:p!==V||f.top||!f.left&&!f.top?r.left+this.border:0,s.top-=r.top.charAt?r.user:u!==V||f.left||!f.left&&!f.top?r.top+this.border:0,h.cornerLeft=c.left,h.cornerTop=c.top,h.corner=l.clone()}},destroy:function(){this.qtip._unbind(this.qtip.tooltip,this._ns),this.qtip.elements.tip&&this.qtip.elements.tip.find("*").remove().end().remove()}}),le=R.tip=function(t){return new x(t,t.options.style.tip)},le.initialize="render",le.sanitize=function(t){if(t.style&&"tip"in t.style){var e=t.style.tip;"object"!=typeof e&&(e=t.style.tip={corner:e}),/string|boolean/i.test(typeof e.corner)||(e.corner=W)}},M.tip={"^position.my|style.tip.(corner|mimic|border)$":function(){this.create(),this.qtip.reposition()},"^style.tip.(height|width)$":function(t){this.size=[t.width,t.height],this.update(),this.qtip.reposition()},"^content.title|style.(classes|widget)$":function(){this.update()}},s.extend(W,T.defaults,{style:{tip:{corner:W,mimic:k,width:6,height:6,border:W,offset:0}}});var Ce,Te,je="qtip-modal",ze="."+je;Te=function(){function t(t){if(s.expr[":"].focusable)return s.expr[":"].focusable;var e,i,o,n=!isNaN(s.attr(t,"tabindex")),r=t.nodeName&&t.nodeName.toLowerCase();return"area"===r?(e=t.parentNode,i=e.name,t.href&&i&&"map"===e.nodeName.toLowerCase()?(o=s("img[usemap=#"+i+"]")[0],!!o&&o.is(":visible")):!1):/input|select|textarea|button|object/.test(r)?!t.disabled:"a"===r?t.href||n:n}function i(t){1>c.length&&t.length?t.not("body").blur():c.first().focus()}function o(t){if(h.is(":visible")){var e,o=s(t.target),a=n.tooltip,l=o.closest(U);e=1>l.length?k:parseInt(l[0].style.zIndex,10)>parseInt(a[0].style.zIndex,10),e||o.closest(U)[0]===a[0]||i(o),r=t.target===c[c.length-1]}}var n,r,a,h,l=this,c={};s.extend(l,{init:function(){return h=l.elem=s("<div />",{id:"qtip-overlay",html:"<div></div>",mousedown:function(){return k}}).hide(),s(e.body).bind("focusin"+ze,o),s(e).bind("keydown"+ze,function(t){n&&n.options.show.modal.escape&&27===t.keyCode&&n.hide(t)}),h.bind("click"+ze,function(t){n&&n.options.show.modal.blur&&n.hide(t)}),l},update:function(e){n=e,c=e.options.show.modal.stealfocus!==k?e.tooltip.find("*").filter(function(){return t(this)}):[]},toggle:function(t,o,r){var c=(s(e.body),t.tooltip),d=t.options.show.modal,p=d.effect,u=o?"show":"hide",f=h.is(":visible"),g=s(ze).filter(":visible:not(:animated)").not(c);return l.update(t),o&&d.stealfocus!==k&&i(s(":focus")),h.toggleClass("blurs",d.blur),o&&h.appendTo(e.body),h.is(":animated")&&f===o&&a!==k||!o&&g.length?l:(h.stop(W,k),s.isFunction(p)?p.call(h,o):p===k?h[u]():h.fadeTo(parseInt(r,10)||90,o?1:0,function(){o||h.hide()}),o||h.queue(function(t){h.css({left:"",top:""}),s(ze).length||h.detach(),t()}),a=o,n.destroyed&&(n=E),l)}}),l.init()},Te=new Te,s.extend(q.prototype,{init:function(t){var e=t.tooltip;return this.options.on?(t.elements.overlay=Te.elem,e.addClass(je).css("z-index",T.modal_zindex+s(ze).length),t._bind(e,["tooltipshow","tooltiphide"],function(t,i,o){var n=t.originalEvent;if(t.target===e[0])if(n&&"tooltiphide"===t.type&&/mouse(leave|enter)/.test(n.type)&&s(n.relatedTarget).closest(Te.elem[0]).length)try{t.preventDefault()}catch(r){}else(!n||n&&"tooltipsolo"!==n.type)&&this.toggle(t,"tooltipshow"===t.type,o)},this._ns,this),t._bind(e,"tooltipfocus",function(t,i){if(!t.isDefaultPrevented()&&t.target===e[0]){var o=s(ze),n=T.modal_zindex+o.length,r=parseInt(e[0].style.zIndex,10);Te.elem[0].style.zIndex=n-1,o.each(function(){this.style.zIndex>r&&(this.style.zIndex-=1)}),o.filter("."+Z).qtip("blur",t.originalEvent),e.addClass(Z)[0].style.zIndex=n,Te.update(i);try{t.preventDefault()}catch(a){}}},this._ns,this),t._bind(e,"tooltiphide",function(t){t.target===e[0]&&s(ze).filter(":visible").not(e).last().qtip("focus",t)},this._ns,this),i):this},toggle:function(t,e,s){return t&&t.isDefaultPrevented()?this:(Te.toggle(this.qtip,!!e,s),i)},destroy:function(){this.qtip.tooltip.removeClass(je),this.qtip._unbind(this.qtip.tooltip,this._ns),Te.toggle(this.qtip,k),delete this.qtip.elements.overlay}}),Ce=R.modal=function(t){return new q(t,t.options.show.modal)},Ce.sanitize=function(t){t.show&&("object"!=typeof t.show.modal?t.show.modal={on:!!t.show.modal}:t.show.modal.on===i&&(t.show.modal.on=W))},T.modal_zindex=T.zindex-200,Ce.initialize="render",M.modal={"^show.modal.(on|blur)$":function(){this.destroy(),this.init(),this.qtip.elems.overlay.toggle(this.qtip.tooltip[0].offsetWidth>0)}},s.extend(W,T.defaults,{show:{modal:{on:k,effect:W,blur:W,stealfocus:W,escape:W}}}),R.viewport=function(i,s,o,n,r,a,h){function l(t,e,i,o,n,r,a,h,l){var c=s[n],p=_[t],b=x[t],w=i===V,q=p===n?l:p===r?-l:-l/2,C=b===n?h:b===r?-h:-h/2,T=v[n]+y[n]-(f?0:u[n]),j=T-c,z=c+l-(a===A?g:m)-T,M=q-(_.precedance===t||p===_[e]?C:0)-(b===N?h/2:0);return w?(M=(p===n?1:-1)*q,s[n]+=j>0?j:z>0?-z:0,s[n]=Math.max(-u[n]+y[n],c-M,Math.min(Math.max(-u[n]+y[n]+(a===A?g:m),c+M),s[n],"center"===p?c-q:1e9))):(o*=i===$?2:0,j>0&&(p!==n||z>0)?(s[n]-=M+o,d.invert(t,n)):z>0&&(p!==r||j>0)&&(s[n]-=(p===N?-M:M)+o,d.invert(t,r)),v>s[n]&&-s[n]>z&&(s[n]=c,d=_.clone())),s[n]-c}var c,d,p,u,f,g,m,v,y,b=o.target,w=i.elements.tooltip,_=o.my,x=o.at,q=o.adjust,C=q.method.split(" "),T=C[0],j=C[1]||C[0],z=o.viewport,M=o.container,I=i.cache,W={left:0,top:0};return z.jquery&&b[0]!==t&&b[0]!==e.body&&"none"!==q.method?(u=M.offset()||W,f="static"===M.css("position"),c="fixed"===w.css("position"),g=z[0]===t?z.width():z.outerWidth(k),m=z[0]===t?z.height():z.outerHeight(k),v={left:c?0:z.scrollLeft(),top:c?0:z.scrollTop()},y=z.offset()||W,("shift"!==T||"shift"!==j)&&(d=_.clone()),W={left:"none"!==T?l(S,L,T,q.x,F,P,A,n,a):0,top:"none"!==j?l(L,S,j,q.y,D,O,B,r,h):0},d&&I.lastClass!==(p=X+"-pos-"+d.abbrev())&&w.removeClass(i.cache.lastClass).addClass(i.cache.lastClass=p),W):W},R.polys={polygon:function(t,e){var i,s,o,n={width:0,height:0,position:{top:1e10,right:0,bottom:0,left:1e10},adjustable:k},r=0,a=[],h=1,l=1,c=0,d=0;for(r=t.length;r--;)i=[parseInt(t[--r],10),parseInt(t[r+1],10)],i[0]>n.position.right&&(n.position.right=i[0]),i[0]<n.position.left&&(n.position.left=i[0]),i[1]>n.position.bottom&&(n.position.bottom=i[1]),i[1]<n.position.top&&(n.position.top=i[1]),a.push(i);if(s=n.width=Math.abs(n.position.right-n.position.left),o=n.height=Math.abs(n.position.bottom-n.position.top),"c"===e.abbrev())n.position={left:n.position.left+n.width/2,top:n.position.top+n.height/2};else{for(;s>0&&o>0&&h>0&&l>0;)for(s=Math.floor(s/2),o=Math.floor(o/2),e.x===F?h=s:e.x===P?h=n.width-s:h+=Math.floor(s/2),e.y===D?l=o:e.y===O?l=n.height-o:l+=Math.floor(o/2),r=a.length;r--&&!(2>a.length);)c=a[r][0]-n.position.left,d=a[r][1]-n.position.top,(e.x===F&&c>=h||e.x===P&&h>=c||e.x===N&&(h>c||c>n.width-h)||e.y===D&&d>=l||e.y===O&&l>=d||e.y===N&&(l>d||d>n.height-l))&&a.splice(r,1);n.position={left:a[0][0],top:a[0][1]}}return n},rect:function(t,e,i,s){return{width:Math.abs(i-t),height:Math.abs(s-e),position:{left:Math.min(t,i),top:Math.min(e,s)}}},_angles:{tc:1.5,tr:7/4,tl:5/4,bc:.5,br:.25,bl:.75,rc:2,lc:1,c:0},ellipse:function(t,e,i,s,o){var n=R.polys._angles[o.abbrev()],r=0===n?0:i*Math.cos(n*Math.PI),a=s*Math.sin(n*Math.PI);return{width:2*i-Math.abs(r),height:2*s-Math.abs(a),position:{left:t+r,top:e+a},adjustable:k}},circle:function(t,e,i,s){return R.polys.ellipse(t,e,i,i,s)}},R.svg=function(t,i,o){for(var n,r,a,h,l,c,d,p,u,f,g,m=s(e),v=i[0],y=s(v.ownerSVGElement),b=1,w=1,_=!0;!v.getBBox;)v=v.parentNode;if(!v.getBBox||!v.parentNode)return k;n=y.attr("width")||y.width()||parseInt(y.css("width"),10),r=y.attr("height")||y.height()||parseInt(y.css("height"),10);var x=(parseInt(i.css("stroke-width"),10)||0)/2;switch(x&&(b+=x/n,w+=x/r),v.nodeName){case"ellipse":case"circle":f=R.polys.ellipse(v.cx.baseVal.value,v.cy.baseVal.value,(v.rx||v.r).baseVal.value+x,(v.ry||v.r).baseVal.value+x,o);break;case"line":case"polygon":case"polyline":for(u=v.points||[{x:v.x1.baseVal.value,y:v.y1.baseVal.value},{x:v.x2.baseVal.value,y:v.y2.baseVal.value}],f=[],p=-1,c=u.numberOfItems||u.length;c>++p;)d=u.getItem?u.getItem(p):u[p],f.push.apply(f,[d.x,d.y]);f=R.polys.polygon(f,o);break;default:f=v.getBoundingClientRect(),f={width:f.width,height:f.height,position:{left:f.left,top:f.top}},_=!1}return g=f.position,y=y[0],_&&(y.createSVGPoint&&(a=v.getScreenCTM(),u=y.createSVGPoint(),u.x=g.left,u.y=g.top,h=u.matrixTransform(a),g.left=h.x,g.top=h.y),y.viewBox&&(l=y.viewBox.baseVal)&&l.width&&l.height&&(b*=n/l.width,w*=r/l.height)),g.left+=m.scrollLeft(),g.top+=m.scrollTop(),f},R.imagemap=function(t,e,i){e.jquery||(e=s(e));var o,n,r,a,h,l=e.attr("shape").toLowerCase().replace("poly","polygon"),c=s('img[usemap="#'+e.parent("map").attr("name")+'"]'),d=s.trim(e.attr("coords")),p=d.replace(/,$/,"").split(",");if(!c.length)return k;if("polygon"===l)a=R.polys.polygon(p,i);else{if(!R.polys[l])return k;for(r=-1,h=p.length,n=[];h>++r;)n.push(parseInt(p[r],10));a=R.polys[l].apply(this,n.concat(i))}return o=c.offset(),o.left+=Math.ceil((c.outerWidth(k)-c.width())/2),o.top+=Math.ceil((c.outerHeight(k)-c.height())/2),a.position.left+=o.left,a.position.top+=o.top,a};var Me,Ie='<iframe class="qtip-bgiframe" frameborder="0" tabindex="-1" src="javascript:\'\';" style="display:block; position:absolute; z-index:-1; filter:alpha(opacity=0); -ms-filter:"progid:DXImageTransform.Microsoft.Alpha(Opacity=0)";"></iframe>';s.extend(C.prototype,{_scroll:function(){var e=this.qtip.elements.overlay;e&&(e[0].style.top=s(t).scrollTop()+"px")},init:function(i){var o=i.tooltip;1>s("select, object").length&&(this.bgiframe=i.elements.bgiframe=s(Ie).appendTo(o),i._bind(o,"tooltipmove",this.adjustBGIFrame,this._ns,this)),this.redrawContainer=s("<div/>",{id:X+"-rcontainer"}).appendTo(e.body),i.elements.overlay&&i.elements.overlay.addClass("qtipmodal-ie6fix")&&(i._bind(t,["scroll","resize"],this._scroll,this._ns,this),i._bind(o,["tooltipshow"],this._scroll,this._ns,this)),this.redraw()},adjustBGIFrame:function(){var t,e,i=this.qtip.tooltip,s={height:i.outerHeight(k),width:i.outerWidth(k)},o=this.qtip.plugins.tip,n=this.qtip.elements.tip;e=parseInt(i.css("borderLeftWidth"),10)||0,e={left:-e,top:-e},o&&n&&(t="x"===o.corner.precedance?[A,F]:[B,D],e[t[1]]-=n[t[0]]()),this.bgiframe.css(e).css(s)},redraw:function(){if(1>this.qtip.rendered||this.drawing)return this;var t,e,i,s,o=this.qtip.tooltip,n=this.qtip.options.style,r=this.qtip.options.position.container;return this.qtip.drawing=1,n.height&&o.css(B,n.height),n.width?o.css(A,n.width):(o.css(A,"").appendTo(this.redrawContainer),e=o.width(),1>e%2&&(e+=1),i=o.css("maxWidth")||"",s=o.css("minWidth")||"",t=(i+s).indexOf("%")>-1?r.width()/100:0,i=(i.indexOf("%")>-1?t:1)*parseInt(i,10)||e,s=(s.indexOf("%")>-1?t:1)*parseInt(s,10)||0,e=i+s?Math.min(Math.max(e,s),i):e,o.css(A,Math.round(e)).appendTo(r)),this.drawing=0,this},destroy:function(){this.bgiframe&&this.bgiframe.remove(),this.qtip._unbind([t,this.qtip.tooltip],this._ns)}}),Me=R.ie6=function(t){return 6===oe.ie?new C(t):k},Me.initialize="render",M.ie6={"^content|style$":function(){this.redraw()}}})})(window,document);
+//@ sourceMappingURL=http://cdnjs.cloudflare.com/ajax/libs/qtip2/2.2.0/jquery.qtip.min.map \ No newline at end of file
diff --git a/docs/htmldoc/libgraph.html b/docs/htmldoc/libgraph.html
new file mode 100644
index 0000000..dbcda1f
--- /dev/null
+++ b/docs/htmldoc/libgraph.html
@@ -0,0 +1,245 @@
+<html>
+<head>
+<style>
+#cy {
+ width: 100%;
+ height: -moz-calc(100% - 2em);
+ height: -webkit-calc(100% - 2em);
+ height: -o-calc(100% - 2em);
+ height: 95%;
+ display: block;
+}
+
+.button {
+ -moz-box-shadow:inset 0px 1px 0px 0px #ffffff;
+ -webkit-box-shadow:inset 0px 1px 0px 0px #ffffff;
+ box-shadow:inset 0px 1px 0px 0px #ffffff;
+ background:-webkit-gradient(linear, left top, left bottom, color-stop(0.05, #f9f9f9), color-stop(1, #e9e9e9));
+ background:-moz-linear-gradient(top, #f9f9f9 5%, #e9e9e9 100%);
+ background:-webkit-linear-gradient(top, #f9f9f9 5%, #e9e9e9 100%);
+ background:-o-linear-gradient(top, #f9f9f9 5%, #e9e9e9 100%);
+ background:-ms-linear-gradient(top, #f9f9f9 5%, #e9e9e9 100%);
+ background:linear-gradient(to bottom, #f9f9f9 5%, #e9e9e9 100%);
+ filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#f9f9f9', endColorstr='#e9e9e9',GradientType=0);
+ background-color:#f9f9f9;
+ -moz-border-radius:6px;
+ -webkit-border-radius:6px;
+ border-radius:6px;
+ border:1px solid #dcdcdc;
+ display:inline-block;
+ cursor:pointer;
+ color:#666666;
+ font-family:Arial;
+ font-size:15px;
+ font-weight:bold;
+ padding:6px 24px;
+ text-decoration:none;
+ text-shadow:0px 1px 0px #ffffff;
+}
+.button:hover {
+ background:-webkit-gradient(linear, left top, left bottom, color-stop(0.05, #e9e9e9), color-stop(1, #f9f9f9));
+ background:-moz-linear-gradient(top, #e9e9e9 5%, #f9f9f9 100%);
+ background:-webkit-linear-gradient(top, #e9e9e9 5%, #f9f9f9 100%);
+ background:-o-linear-gradient(top, #e9e9e9 5%, #f9f9f9 100%);
+ background:-ms-linear-gradient(top, #e9e9e9 5%, #f9f9f9 100%);
+ background:linear-gradient(to bottom, #e9e9e9 5%, #f9f9f9 100%);
+ filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#e9e9e9', endColorstr='#f9f9f9',GradientType=0);
+ background-color:#e9e9e9;
+}
+.button:active {
+ position:relative;
+ top:1px;
+}
+.button-bar {
+ margin-left:auto;
+ width: auto;
+ position: absolute;
+ right: 10px;
+}
+.zoom-in:before { font-size:12pt; content: "+" }
+.zoom-out:before { font-size:12pt; content: "-" }
+.zoom-expand:before { font-size:12pt; content: "fit" }
+</style>
+<link href="js/jquery.qtip.min.css" rel="stylesheet" type="text/css" />
+<link href="js/cytoscape.js-panzoom.css" rel="stylesheet" type="text/css" />
+
+<script src="js/jquery-2.0.3.min.js"></script>
+<script src="js/cytoscape.min.js"></script>
+<script src="js/dagre.min.js"></script>
+<script src="js/cytoscape-dagre.js"></script>
+<script src="js/jquery.qtip.min.js"></script>
+<script src="js/cytoscape-qtip.js"></script>
+<script src="js/cytoscape-panzoom.js"></script>
+
+<script src="depend.js"></script>
+
+<script type="text/javascript">
+$(document).ready(function(){
+ var cy = window.cy = cytoscape({
+ container: document.getElementById('cy'), // container to render in
+ elements: depends,
+ style: [
+ { selector: '.hidden',
+ style: {
+ 'display': 'none',
+ }},
+ { selector: "node",
+ style: {
+ 'width': 'mapData(score, 0, 0.006769776522008331, 20, 60)',
+ 'height': 'mapData(score, 0, 0.006769776522008331, 20, 60)',
+ 'content':'data(name)',
+ 'font-size':'18pt',
+ 'font-weight':'bold',
+ 'text-valign':'center',
+ 'text-halign':'center',
+ 'text-outline-color': 'white',
+ 'border-color': function(e) {
+ if (e.data('released') === 'yes') {return 'green'}
+ else {return '#ccc'}
+ },
+ 'border-width': '2px',
+ 'border-style': 'dashed',
+ 'background-color': 'white',
+ 'text-outline-width':'1px',
+ 'color':'#555',
+ 'overlay-padding':'6px',
+ 'z-index':'10',
+ }},
+ { selector: '$node > node',
+ style: {
+ 'background-color': 'rgba(255,255,255,0.5)',
+ 'border-style' : 'dotted',
+ 'border-width' : '1',
+ 'border-color' : 'blue',
+ 'padding' : '1em',
+ 'label': 'data(name)',
+ 'text-valign':'top',
+ 'text-halign':'center',
+ 'z-index': 99,
+ }},
+ { selector: 'edge',
+ style: {
+ 'width': 3,
+ 'line-color': '#ccc',
+ 'target-arrow-color': '#ccc',
+ 'target-arrow-shape': 'triangle',
+ }},
+ { selector: '.red',
+ style: {
+ 'line-color': 'red',
+ 'target-arrow-color': 'red',
+ 'target-arrow-shape': 'triangle',
+ 'z-index': 100,
+ }},
+ ],
+ ready: function(){ window.cy = this; },
+ layout: {
+ name: 'dagre',
+ fit: false,
+ edgeSep: 10,
+ padding: 5,
+ animate: false,
+ },
+ textureOnViewport: true,
+ }); // end: var cy = cytoscape(...
+
+ cy.on('tap', 'node', function(evt){
+ var node = evt.cyTarget;
+ var g = node.data('name');
+ node.connectedEdges().forEach(function(e){ e.toggleClass('red') });
+ if (g == '+') { collapse_this('#' + node.parent().id()); }
+ });
+
+ cy.nodes().forEach(function(n){
+ var g = n.data('name');
+
+ if (g == '+') {
+ n.addClass('hidden');
+ n.relativePosition({ x: 0, y:0 });
+ };
+ if (g == '-') {
+ var x = n.relativePosition('x');
+ var y = n.relativePosition('y');
+ n.relativePosition({ x: -x, y: -y });
+ };
+
+ if (n.isChild() && g != '+' && g !='-') {
+ n.qtip({
+ content: [
+ { name: 'View coqdoc',
+ url: 'mathcomp.' + n.parent().data('name') + '.' + g + '.html'
+ },
+ ].map(function( link ){
+ return '<a target="_blank" href="' + link.url + '">' +
+ link.name + '</a>';
+ }).join('<br />\n'),
+ position: { my: 'top center', at: 'bottom center' },
+ style: { classes: 'qtip-bootstrap', tip: { width: 16, height: 8 } },
+ });
+ } else if (n.isParent()) {
+ n.qtip({
+ content: [
+ { name: 'Collapse',
+ url: n.id(),
+ },
+ ].map(function( link ){
+ return '<a href="#" onclick="collapse_this(\'#' + link.url +
+ '\');">' + link.name + '</a>';
+ }).join('<br />\n'),
+ position: { my: 'top center', at: 'bottom center' },
+ style: { classes: 'qtip-bootstrap', tip: { width: 16, height: 8 } },
+ });
+
+ }
+ });
+
+ cy.center();
+
+ cy.panzoom({
+ // icon class names
+ sliderHandleIcon: 'zoom-slide',
+ zoomInIcon: 'zoom-in',
+ zoomOutIcon: 'zoom-out',
+ resetIcon: 'zoom-expand'
+});
+});
+
+
+function collapse_this(id) {
+ cy.$(id).children().forEach(function(e) {
+ e.toggleClass('hidden');
+ if (e.data('name') == '+' && !e.hasClass('hidden')) {
+ e.relativePosition({ x: 0, y:0 });
+ }
+ });
+}
+
+function collapse() {
+ cy.nodes().forEach(function(n){
+ if (n.isParent()) { collapse_this('#' + n.id()) }
+ });
+ cy.layout();
+ cy.fit();
+ cy.center();
+ cy.reset();
+}
+
+function no_red() {
+ cy.edges().forEach(function(e) { e.removeClass('red'); });
+}
+</script>
+</head>
+<body>
+ <div id="cy">
+ </div>
+ <div>
+ Nodes and clusters can be dragged around and clicked.
+ When a node/cluster is clicked its links are highlighted
+ and a contextual menu pops up. Clusters can be collapsed.
+ </div>
+ <div class="button-bar">
+ <div class="button" onclick="collapse()">collapse all</div>
+ <div class="button" onclick="no_red()">clear red edges</div>
+ </div>
+</body>
+</html>