Merged hyracks_dev_next r1127:r1164.
git-svn-id: https://hyracks.googlecode.com/svn/branches/hyracks_lsm_tree@1165 123451ca-8445-de46-9d55-352943316053
diff --git a/hyracks-algebricks/hyracks-algebricks-core/src/main/java/edu/uci/ics/hyracks/algebricks/core/algebra/runtime/jobgen/impl/JobGenHelper.java b/hyracks-algebricks/hyracks-algebricks-core/src/main/java/edu/uci/ics/hyracks/algebricks/core/algebra/runtime/jobgen/impl/JobGenHelper.java
index 6814d74..90bf47c 100644
--- a/hyracks-algebricks/hyracks-algebricks-core/src/main/java/edu/uci/ics/hyracks/algebricks/core/algebra/runtime/jobgen/impl/JobGenHelper.java
+++ b/hyracks-algebricks/hyracks-algebricks-core/src/main/java/edu/uci/ics/hyracks/algebricks/core/algebra/runtime/jobgen/impl/JobGenHelper.java
@@ -36,33 +36,11 @@
import edu.uci.ics.hyracks.api.dataflow.value.ISerializerDeserializer;
import edu.uci.ics.hyracks.api.dataflow.value.ITypeTraits;
import edu.uci.ics.hyracks.api.dataflow.value.RecordDescriptor;
-import edu.uci.ics.hyracks.storage.am.btree.frames.BTreeNSMInteriorFrameFactory;
-import edu.uci.ics.hyracks.storage.am.btree.frames.BTreeNSMLeafFrameFactory;
-import edu.uci.ics.hyracks.storage.am.common.api.ITreeIndexFrameFactory;
-import edu.uci.ics.hyracks.storage.am.common.tuples.TypeAwareTupleWriterFactory;
public final class JobGenHelper {
private static final Logger LOGGER = Logger.getLogger(JobGenHelper.class.getName());
- public static ITreeIndexFrameFactory createBTreeNSMInteriorFrameFactory(ITypeTraits[] typeTraits) {
- return new BTreeNSMInteriorFrameFactory(new TypeAwareTupleWriterFactory(typeTraits));
- }
-
- public static ITreeIndexFrameFactory createBTreeNSMLeafFrameFactory(ITypeTraits[] typeTraits) {
- return new BTreeNSMLeafFrameFactory(new TypeAwareTupleWriterFactory(typeTraits));
- }
-
- // TODO: VRB: Commented out for now. Need to be uncommented once this
- // is made compatible with the RTree interfaces.
- // public static ITreeIndexFrameFactory createRTreeNSMInteriorFrameFactory(ITypeTrait[] typeTraits, int keyFields) {
- // return new RTreeNSMInteriorFrameFactory(new RTreeTypeAwareTupleWriterFactory(typeTraits), keyFields);
- // }
- //
- // public static ITreeIndexFrameFactory createRTreeNSMLeafFrameFactory(ITypeTrait[] typeTraits, int keyFields) {
- // return new RTreeNSMLeafFrameFactory(new RTreeTypeAwareTupleWriterFactory(typeTraits), keyFields);
- // }
-
@SuppressWarnings("unchecked")
public static RecordDescriptor mkRecordDescriptor(ILogicalOperator op, IOperatorSchema opSchema,
JobGenContext context) throws AlgebricksException {
diff --git a/hyracks-control-cc/src/main/java/edu/uci/ics/hyracks/control/cc/NodeControllerState.java b/hyracks-control-cc/src/main/java/edu/uci/ics/hyracks/control/cc/NodeControllerState.java
index 3c94b9e..c17acd0 100644
--- a/hyracks-control-cc/src/main/java/edu/uci/ics/hyracks/control/cc/NodeControllerState.java
+++ b/hyracks-control-cc/src/main/java/edu/uci/ics/hyracks/control/cc/NodeControllerState.java
@@ -107,6 +107,14 @@
private final long[] netSignalingBytesWritten;
+ private final long[] ipcMessagesSent;
+
+ private final long[] ipcMessageBytesSent;
+
+ private final long[] ipcMessagesReceived;
+
+ private final long[] ipcMessageBytesReceived;
+
private int rrdPtr;
private int lastHeartbeatDuration;
@@ -156,6 +164,11 @@
netPayloadBytesWritten = new long[RRD_SIZE];
netSignalingBytesRead = new long[RRD_SIZE];
netSignalingBytesWritten = new long[RRD_SIZE];
+ ipcMessagesSent = new long[RRD_SIZE];
+ ipcMessageBytesSent = new long[RRD_SIZE];
+ ipcMessagesReceived = new long[RRD_SIZE];
+ ipcMessageBytesReceived = new long[RRD_SIZE];
+
rrdPtr = 0;
}
@@ -183,6 +196,10 @@
netPayloadBytesWritten[rrdPtr] = hbData.netPayloadBytesWritten;
netSignalingBytesRead[rrdPtr] = hbData.netSignalingBytesRead;
netSignalingBytesWritten[rrdPtr] = hbData.netSignalingBytesWritten;
+ ipcMessagesSent[rrdPtr] = hbData.ipcMessagesSent;
+ ipcMessageBytesSent[rrdPtr] = hbData.ipcMessageBytesSent;
+ ipcMessagesReceived[rrdPtr] = hbData.ipcMessagesReceived;
+ ipcMessageBytesReceived[rrdPtr] = hbData.ipcMessageBytesReceived;
rrdPtr = (rrdPtr + 1) % RRD_SIZE;
}
@@ -254,6 +271,10 @@
o.put("net-payload-bytes-written", netPayloadBytesWritten);
o.put("net-signaling-bytes-read", netSignalingBytesRead);
o.put("net-signaling-bytes-written", netSignalingBytesWritten);
+ o.put("ipc-messages-sent", ipcMessagesSent);
+ o.put("ipc-message-bytes-sent", ipcMessageBytesSent);
+ o.put("ipc-messages-received", ipcMessagesReceived);
+ o.put("ipc-message-bytes-received", ipcMessageBytesReceived);
return o;
}
diff --git a/hyracks-control-cc/src/main/java/edu/uci/ics/hyracks/control/cc/adminconsole/pages/JobDetailsPage.java b/hyracks-control-cc/src/main/java/edu/uci/ics/hyracks/control/cc/adminconsole/pages/JobDetailsPage.java
index 585c7a1..1d96a71 100644
--- a/hyracks-control-cc/src/main/java/edu/uci/ics/hyracks/control/cc/adminconsole/pages/JobDetailsPage.java
+++ b/hyracks-control-cc/src/main/java/edu/uci/ics/hyracks/control/cc/adminconsole/pages/JobDetailsPage.java
@@ -284,6 +284,9 @@
+ "\" height=\"" + ((y + 2) * (HEIGHT + 1)) + "\">\n" + buffer.toString());
markup.setEscapeModelStrings(false);
add(markup);
+ } else {
+ Label markup = new Label("job-timeline", "No information available yet");
+ add(markup);
}
}
diff --git a/hyracks-control-cc/src/main/resources/edu/uci/ics/hyracks/control/cc/adminconsole/pages/AbstractPage.html b/hyracks-control-cc/src/main/resources/edu/uci/ics/hyracks/control/cc/adminconsole/pages/AbstractPage.html
index 4656f31..93cf631 100644
--- a/hyracks-control-cc/src/main/resources/edu/uci/ics/hyracks/control/cc/adminconsole/pages/AbstractPage.html
+++ b/hyracks-control-cc/src/main/resources/edu/uci/ics/hyracks/control/cc/adminconsole/pages/AbstractPage.html
@@ -6,6 +6,7 @@
<script type="text/javascript" src="/static/javascript/jquery/plugins/jquery-ui.min.js"></script>
<script type="text/javascript" src="/static/javascript/flot/jquery.flot.min.js"></script>
<script type="text/javascript" src="/static/javascript/flot/jquery.flot.resize.min.js"></script>
+ <script type="text/javascript" src="/static/javascript/jsplumb/jquery.jsPlumb-1.3.5-all-min.js"></script>
<link rel="stylesheet" type="text/css" href="/static/stylesheet/jquery-ui/themes/base/jquery-ui.css"></link>
<link rel="stylesheet" type="text/css" href="/static/stylesheet/adminconsole.css"></link>
</head>
diff --git a/hyracks-control-cc/src/main/resources/edu/uci/ics/hyracks/control/cc/adminconsole/pages/JobDetailsPage.html b/hyracks-control-cc/src/main/resources/edu/uci/ics/hyracks/control/cc/adminconsole/pages/JobDetailsPage.html
index d2068fd..df3350d 100644
--- a/hyracks-control-cc/src/main/resources/edu/uci/ics/hyracks/control/cc/adminconsole/pages/JobDetailsPage.html
+++ b/hyracks-control-cc/src/main/resources/edu/uci/ics/hyracks/control/cc/adminconsole/pages/JobDetailsPage.html
@@ -6,4 +6,8 @@
<div id="job-run" wicket:id="job-run" style="display: none;">
</div>
<div wicket:id="job-timeline" style="overflow: auto;"></div>
+ <div id="job-graph" style="position:relative"></div>
+
+ <script src="/static/javascript/adminconsole/Graphs.js" type="text/javascript"></script>
+ <script src="/static/javascript/adminconsole/JobDetailsPage.js" type="text/javascript"></script>
</wicket:extend>
\ No newline at end of file
diff --git a/hyracks-control-cc/src/main/resources/edu/uci/ics/hyracks/control/cc/adminconsole/pages/NodeDetailsPage.html b/hyracks-control-cc/src/main/resources/edu/uci/ics/hyracks/control/cc/adminconsole/pages/NodeDetailsPage.html
index 6a765e4..1d8f735 100644
--- a/hyracks-control-cc/src/main/resources/edu/uci/ics/hyracks/control/cc/adminconsole/pages/NodeDetailsPage.html
+++ b/hyracks-control-cc/src/main/resources/edu/uci/ics/hyracks/control/cc/adminconsole/pages/NodeDetailsPage.html
@@ -7,6 +7,7 @@
<li><a href="#tabs-4">Memory Usage</a></li>
<li><a href="#tabs-5">Thread Statistics</a></li>
<li><a href="#tabs-6">Network Statistics</a></li>
+ <li><a href="#tabs-7">IPC Statistics</a></li>
</ul>
<div id="tabs-1">
@@ -54,6 +55,13 @@
<div id='net-signaling-bandwidth' class="time-chart">
</div>
</div>
+
+ <div id="tabs-7">
+ <div id='ipc-messages' class="time-chart">
+ </div>
+ <div id='ipc-message-bytes' class="time-chart">
+ </div>
+ </div>
</div>
<script src="/static/javascript/adminconsole/NodeDetailsPage.js" type="text/javascript"></script>
diff --git a/hyracks-control-cc/src/main/resources/static/javascript/adminconsole/Graphs.js b/hyracks-control-cc/src/main/resources/static/javascript/adminconsole/Graphs.js
new file mode 100644
index 0000000..dcba9c0
--- /dev/null
+++ b/hyracks-control-cc/src/main/resources/static/javascript/adminconsole/Graphs.js
@@ -0,0 +1,160 @@
+Graphs = {};
+
+Graphs.DAG = function() {
+ this.nodeMap = {};
+ this.edgeMap = {};
+}
+
+Graphs.DAG.prototype.addNode = function(key, attachment) {
+ var node = new Graphs.Node(this, key, attachment);
+ this.nodeMap[key] = node;
+ return node;
+}
+
+Graphs.DAG.prototype.addEdge = function(key, attachment, sNode, sIndex, tNode, tIndex) {
+ var edge = new Graphs.DirectedEdge(this, key, attachment, sNode, sIndex, tNode, tIndex);
+ this.edgeMap[key] = edge;
+ sNode.outEdges[sIndex] = edge;
+ tNode.inEdges[tIndex] = edge;
+ return edge;
+}
+
+Graphs.DAG.prototype.lookupNode = function(key) {
+ return this.nodeMap[key];
+}
+
+Graphs.DAG.prototype.lookupEdge = function(key) {
+ return this.edgeMap[key];
+}
+
+Graphs.DAG.prototype.walkNodes = function(callback) {
+ for ( var nKey in this.nodeMap) {
+ callback(this.nodeMap[nKey]);
+ }
+}
+
+Graphs.DAG.prototype.walkEdges = function(callback) {
+ for ( var eKey in this.edgeMap) {
+ callback(this.edgeMap[eKey]);
+ }
+}
+
+Graphs.DAG.prototype.findRoots = function() {
+ var roots = [];
+ var callback = function(node) {
+ if (node.inEdges.length == 0) {
+ roots.push(node);
+ }
+ }
+ this.walkNodes(callback);
+ return roots;
+}
+
+Graphs.DAG.prototype.findLeaves = function() {
+ var leaves = [];
+ var callback = function(node) {
+ if (node.outEdges.length == 0) {
+ leaves.push(node);
+ }
+ }
+ this.walkNodes(callback);
+ return leaves;
+}
+
+Graphs.DAG.prototype.tsort = function() {
+ var sortedNodes = [];
+ var nodeState = {};
+
+ function visit(node) {
+ if (!nodeState[node.key]) {
+ nodeState[node.key] = true;
+ for ( var i = 0; i < node.inEdges.length; ++i) {
+ visit(node.inEdges[i].sNode);
+ }
+ sortedNodes.push(node);
+ }
+ }
+
+ var roots = this.findLeaves();
+ for ( var i = 0; i < roots.length; ++i) {
+ visit(roots[i]);
+ }
+ return sortedNodes;
+}
+
+Graphs.DAG.prototype.stratify = function() {
+ var sortedNodes = this.tsort();
+ var stratumMap = {};
+ var strata = [];
+ for ( var i = 0; i < sortedNodes.length; ++i) {
+ var node = sortedNodes[i];
+ var maxParentStratum = -1;
+ for ( var j = 0; j < node.inEdges.length; ++j) {
+ var edge = node.inEdges[j];
+ maxParentStratum = Math.max(maxParentStratum, stratumMap[edge.sNode.key]);
+ }
+ var stratum = maxParentStratum + 1;
+ stratumMap[node.key] = stratum;
+ var stratumList = strata[stratum];
+ if (!stratumList) {
+ stratumList = [];
+ strata[stratum] = stratumList;
+ }
+ stratumList.push(node);
+ }
+ return strata;
+}
+
+Graphs.Node = function(dag, key, attachment) {
+ this.dag = dag;
+ this.key = key;
+ this.attachment = attachment;
+ this.inEdges = [];
+ this.outEdges = [];
+}
+
+Graphs.DirectedEdge = function(dag, key, attachment, sNode, sIndex, tNode, tIndex) {
+ this.dag = dag;
+ this.key = key;
+ this.attachment = attachment;
+ this.sNode = sNode;
+ this.sIndex = sIndex;
+ this.tNode = tNode;
+ this.tIndex = tIndex;
+}
+
+Graphs.JsPlumbRenderer = function(dag, element, options) {
+ this.dag = dag;
+ this.element = element;
+ this.options = options || {
+ levelStep : 100
+ };
+}
+
+Graphs.JsPlumbRenderer.prototype.configureDiv = function(div, node, stratum, inStratumIndex, stratumWidth) {
+ div.id = node.key;
+ div.dagNode = node;
+ /*
+ * div.style.position = 'absolute'; div.style.left = (stratum *
+ * this.options.levelStep) + 'px'; div.style.top = (inStratumIndex * 100) +
+ * 'px'; div.style.width = '50px'; div.style.height = '50px';
+ * div.style.border = 'thick solid #000000';
+ */
+}
+
+Graphs.JsPlumbRenderer.prototype.refresh = function() {
+ var strata = this.dag.stratify();
+
+ while (this.element.hasChildNodes()) {
+ this.element.removeChild(this.element.lastChild);
+ }
+ for ( var i = 0; i < strata.length; ++i) {
+ var stratumList = strata[i];
+ for ( var j = 0; j < stratumList.length; ++j) {
+ var node = stratumList[j];
+ var div = document.createElement('div');
+ this.configureDiv(div, node, i, j, stratumList.length);
+ this.element.appendChild(div);
+ }
+ }
+}
\ No newline at end of file
diff --git a/hyracks-control-cc/src/main/resources/static/javascript/adminconsole/JobDetailsPage.js b/hyracks-control-cc/src/main/resources/static/javascript/adminconsole/JobDetailsPage.js
new file mode 100644
index 0000000..828e310
--- /dev/null
+++ b/hyracks-control-cc/src/main/resources/static/javascript/adminconsole/JobDetailsPage.js
@@ -0,0 +1,85 @@
+$(function() {
+ var jobSpecDAG = new Graphs.DAG();
+ var jobSpecRenderer;
+
+ function drawJobGraph() {
+ var jobGraphDiv = $('#job-graph')[0];
+ jobSpecRenderer = new Graphs.JsPlumbRenderer(jobSpecDAG, jobGraphDiv, null);
+ jobSpecRenderer.refresh();
+ }
+
+ function onJobRunDataReceived(data) {
+ var run = data.result;
+
+ if (run.status != 'TERMINATED' && run.status != 'FAILURE') {
+ setTimeout(fetchJobRun, 10000);
+ }
+ }
+
+ function fetchJobRun() {
+ $.ajax({
+ url : '/rest/jobs/' + $.getURLParam('job-id') + '/job-run',
+ method : 'GET',
+ dataType : 'json',
+ success : onJobRunDataReceived
+ });
+ }
+
+ function onJobActivityGraphDataReceived(data) {
+ var jag = data.result;
+ activityMap = new Object;
+ var activities = jag.activities;
+ for ( var i = 0; i < activities.length; ++i) {
+ var activity = activities[i];
+ }
+
+ drawJobGraph();
+
+ fetchJobRun();
+ }
+
+ function fetchJobActivityGraph() {
+ $.ajax({
+ url : '/rest/jobs/' + $.getURLParam('job-id') + '/job-activity-graph',
+ method : 'GET',
+ dataType : 'json',
+ success : onJobActivityGraphDataReceived
+ });
+ }
+
+ function onJobSpecificationDataReceived(data) {
+ var jobSpec = data.result;
+ var operators = jobSpec.operators;
+ for ( var i = 0; i < operators.length; ++i) {
+ var op = operators[i];
+ jobSpecDAG.addNode(op.id, op);
+ }
+ var connectors = jobSpec.connectors;
+ for ( var i = 0; i < connectors.length; ++i) {
+ var conn = connectors[i];
+ var sNode = jobSpecDAG.lookupNode(conn['in-operator-id']);
+ var sIndex = conn['in-operator-port'];
+ var tNode = jobSpecDAG.lookupNode(conn['out-operator-id']);
+ var tIndex = conn['out-operator-port'];
+ jobSpecDAG.addEdge(conn.id, conn, sNode, sIndex, tNode, tIndex);
+ }
+ fetchJobActivityGraph();
+ }
+
+ function fetchJobSpecification() {
+ $.ajax({
+ url : '/rest/jobs/' + $.getURLParam('job-id') + '/job-specification',
+ method : 'GET',
+ dataType : 'json',
+ success : onJobSpecificationDataReceived
+ });
+ }
+
+ function init() {
+ fetchJobSpecification();
+ }
+
+ jsPlumb.bind("ready", function() {
+ init();
+ });
+});
\ No newline at end of file
diff --git a/hyracks-control-cc/src/main/resources/static/javascript/adminconsole/NodeDetailsPage.js b/hyracks-control-cc/src/main/resources/static/javascript/adminconsole/NodeDetailsPage.js
index 1847b32..ff9d8a0 100644
--- a/hyracks-control-cc/src/main/resources/static/javascript/adminconsole/NodeDetailsPage.js
+++ b/hyracks-control-cc/src/main/resources/static/javascript/adminconsole/NodeDetailsPage.js
@@ -15,8 +15,8 @@
}
};
- function computeBandwidth(bytes, rrdPtr) {
- return (bytes[(rrdPtr + 1) % bytes.length] - bytes[rrdPtr]) / 10;
+ function computeRate(array, rrdPtr) {
+ return (array[(rrdPtr + 1) % array.length] - array[rrdPtr]) / 10;
}
function onDataReceived(data) {
@@ -58,6 +58,11 @@
var netPayloadBytesWritten = result['net-payload-bytes-written'];
var netSignalingBytesRead = result['net-signaling-bytes-read'];
var netSignalingBytesWritten = result['net-signaling-bytes-written'];
+ var ipcMessagesSent = result['ipc-messages-sent'];
+ var ipcMessageBytesSent = result['ipc-message-bytes-sent'];
+ var ipcMessagesReceived = result['ipc-messages-received'];
+ var ipcMessageBytesReceived = result['ipc-message-bytes-received'];
+
var sysLoadArray = [];
var heapUsageInitSizesArray = [];
var heapUsageUsedSizesArray = [];
@@ -75,6 +80,10 @@
var netPayloadWriteBWArray = [];
var netSignalingReadBWArray = [];
var netSignalingWriteBWArray = [];
+ var ipcMessageSendRateArray = [];
+ var ipcMessageBytesSendRateArray = [];
+ var ipcMessageReceiveRateArray = [];
+ var ipcMessageBytesReceiveRateArray = [];
var gcChartsDiv = document.getElementById('gc-charts');
for ( var i = 0; i < gcCollectionCounts.length; ++i) {
gcCollectionCountsArray.push([]);
@@ -107,10 +116,14 @@
gcCollectionTimesArray[j].push([ i, gcCollectionTimes[j][rrdPtr] ]);
}
if (i < sysLoad.length - 1) {
- netPayloadReadBWArray.push([ i, computeBandwidth(netPayloadBytesRead, rrdPtr) ]);
- netPayloadWriteBWArray.push([ i, computeBandwidth(netPayloadBytesWritten, rrdPtr) ]);
- netSignalingReadBWArray.push([ i, computeBandwidth(netSignalingBytesRead, rrdPtr) ]);
- netSignalingWriteBWArray.push([ i, computeBandwidth(netSignalingBytesWritten, rrdPtr) ]);
+ netPayloadReadBWArray.push([ i, computeRate(netPayloadBytesRead, rrdPtr) ]);
+ netPayloadWriteBWArray.push([ i, computeRate(netPayloadBytesWritten, rrdPtr) ]);
+ netSignalingReadBWArray.push([ i, computeRate(netSignalingBytesRead, rrdPtr) ]);
+ netSignalingWriteBWArray.push([ i, computeRate(netSignalingBytesWritten, rrdPtr) ]);
+ ipcMessageSendRateArray.push([ i, computeRate(ipcMessagesSent, rrdPtr) ]);
+ ipcMessageBytesSendRateArray.push([ i, computeRate(ipcMessageBytesSent, rrdPtr) ]);
+ ipcMessageReceiveRateArray.push([ i, computeRate(ipcMessagesReceived, rrdPtr) ]);
+ ipcMessageBytesReceiveRateArray.push([ i, computeRate(ipcMessageBytesReceived, rrdPtr) ]);
}
rrdPtr = (rrdPtr + 1) % sysLoad.length;
}
@@ -186,6 +199,22 @@
label : 'Signaling Write Bandwidth (bytes/sec)',
data : netSignalingWriteBWArray
} ], options);
+
+ $.plot($('#ipc-messages'), [ {
+ label : 'IPC Messages Send Rate (messages/sec)',
+ data : ipcMessageSendRateArray
+ }, {
+ label : 'IPC Messages Receive Rate (messages/sec)',
+ data : ipcMessageReceiveRateArray
+ } ], options);
+
+ $.plot($('#ipc-message-bytes'), [ {
+ label : 'IPC Message Send Bandwidth (bytes/sec)',
+ data : ipcMessageBytesSendRateArray
+ }, {
+ label : 'IPC Message Receive Bandwidth (bytes/sec)',
+ data : ipcMessageBytesReceiveRateArray
+ } ], options);
}
function fetchData() {
diff --git a/hyracks-control-cc/src/main/resources/static/javascript/jsplumb/jquery.jsPlumb-1.3.5-all-min.js b/hyracks-control-cc/src/main/resources/static/javascript/jsplumb/jquery.jsPlumb-1.3.5-all-min.js
new file mode 100644
index 0000000..47725f9
--- /dev/null
+++ b/hyracks-control-cc/src/main/resources/static/javascript/jsplumb/jquery.jsPlumb-1.3.5-all-min.js
@@ -0,0 +1 @@
+(function(){var w=!!document.createElement("canvas").getContext,e=!!window.SVGAngle||document.implementation.hasFeature("http://www.w3.org/TR/SVG11/feature#BasicStructure","1.1"),a=!(w|e);var p=function(F,G,D,J){var I=function(M,L){if(M===L){return true}else{if(typeof M=="object"&&typeof L=="object"){var N=true;for(var K in M){if(!I(M[K],L[K])){N=false;break}}for(var K in L){if(!I(L[K],M[K])){N=false;break}}return N}}};for(var H=+D||0,E=F.length;H<E;H++){if(I(F[H],G)){return H}}return -1},i=function(D,F){if(D){for(var E=0;E<D.length;E++){if(F(D[E])){return E}}}return -1},y=function(E,F){var D=i(E,F);if(D>-1){E.splice(D,1)}return D!=-1},r=function(F,E,D){if(i(F,D)==-1){F.push(E)}};if(!window.console){window.console={time:function(){},timeEnd:function(){},group:function(){},groupEnd:function(){},log:function(){}}}var l=function(G,E,F){var D=G[E];if(D==null){D=[],G[E]=D}D.push(F);return D},u=null,d=function(D,E){return n.CurrentLibrary.getAttribute(A(D),E)},f=function(E,F,D){n.CurrentLibrary.setAttribute(A(E),F,D)},x=function(E,D){n.CurrentLibrary.addClass(A(E),D)},k=function(E,D){return n.CurrentLibrary.hasClass(A(E),D)},m=function(E,D){n.CurrentLibrary.removeClass(A(E),D)},A=function(D){return n.CurrentLibrary.getElementObject(D)},s=function(D){return n.CurrentLibrary.getOffset(A(D))},b=function(D){return n.CurrentLibrary.getSize(A(D))},z=true,o=function(){if(z&&typeof console!="undefined"){try{var E=arguments[arguments.length-1];console.log(E)}catch(D){}}},C=function(D){if(z&&typeof console!="undefined"){console.group(D)}},h=function(D){if(z&&typeof console!="undefined"){console.groupEnd(D)}},B=function(D){if(z&&typeof console!="undefined"){console.time(D)}},t=function(D){if(z&&typeof console!="undefined"){console.timeEnd(D)}};EventGenerator=function(){var F={},E=this;var D=["ready"];this.bind=function(G,H){l(F,G,H)};this.fire=function(I,J,G){if(F[I]){for(var H=0;H<F[I].length;H++){if(p(D,I)!=-1){F[I][H](J,G)}else{try{F[I][H](J,G)}catch(K){o("jsPlumb: fire failed for event "+I+" : "+K)}}}}};this.clearListeners=function(G){if(G){delete F[G]}else{delete F;F={}}};this.getListener=function(G){return F[G]}},_timestamp=function(){return""+(new Date()).getTime()},jsPlumbUIComponent=function(H){var S=this,O=arguments,M=false,Q=H.parameters||{},E=S.idPrefix,G=E+(new Date()).getTime();S._jsPlumb=H._jsPlumb;S.getId=function(){return G};S.tooltip=H.tooltip;S.hoverClass=H.hoverClass;EventGenerator.apply(this);this.clone=function(){var T=new Object();S.constructor.apply(T,O);return T};this.getParameter=function(T){return Q[T]},this.getParameters=function(){return Q},this.setParameter=function(T,U){Q[T]=U},this.setParameters=function(T){Q=T},this.overlayPlacements=[],this.paintStyle=null,this.hoverPaintStyle=null;var I=H.beforeDetach;this.isDetachAllowed=function(T){var U=true;if(I){try{U=I(T)}catch(V){o("jsPlumb: beforeDetach callback failed",V)}}return U};var K=H.beforeDrop;this.isDropAllowed=function(W,T,U){var V=S._jsPlumb.checkCondition("beforeDrop",{sourceId:W,targetId:T,scope:U});if(K){try{V=K({sourceId:W,targetId:T,scope:U})}catch(X){o("jsPlumb: beforeDrop callback failed",X)}}return V};var P=function(){if(S.paintStyle&&S.hoverPaintStyle){var T={};n.extend(T,S.paintStyle);n.extend(T,S.hoverPaintStyle);delete S.hoverPaintStyle;if(T.gradient&&S.paintStyle.fillStyle){delete T.gradient}S.hoverPaintStyle=T}};this.setPaintStyle=function(T,U){S.paintStyle=T;S.paintStyleInUse=S.paintStyle;P();if(!U){S.repaint()}};this.setHoverPaintStyle=function(T,U){S.hoverPaintStyle=T;P();if(!U){S.repaint()}};this.setHover=function(T,V,U){if(!S._jsPlumb.currentlyDragging&&!S._jsPlumb.isHoverSuspended()){M=T;if(S.hoverClass!=null&&S.canvas!=null){if(T){J.addClass(S.canvas,S.hoverClass)}else{J.removeClass(S.canvas,S.hoverClass)}}if(S.hoverPaintStyle!=null){S.paintStyleInUse=T?S.hoverPaintStyle:S.paintStyle;U=U||_timestamp();S.repaint({timestamp:U,recalc:false})}if(S.getAttachedElements&&!V){N(T,_timestamp(),S)}}};this.isHover=function(){return M};var J=n.CurrentLibrary,R=["click","dblclick","mouseenter","mouseout","mousemove","mousedown","mouseup","contextmenu"],L={mouseout:"mouseexit"},F=function(V,W,U){var T=L[U]||U;J.bind(V,U,function(X){W.fire(T,W,X)})},D=function(V,U){var T=L[U]||U;J.unbind(V,U)};this.attachListeners=function(U,V){for(var T=0;T<R.length;T++){F(U,V,R[T])}};var N=function(X,W,T){var V=S.getAttachedElements();if(V){for(var U=0;U<V.length;U++){if(!T||T!=V[U]){V[U].setHover(X,true,W)}}}};this.reattachListenersForElement=function(U){if(arguments.length>1){for(var T=0;T<R.length;T++){D(U,R[T])}for(var T=1;T<arguments.length;T++){S.attachListeners(U,arguments[T])}}}},overlayCapableJsPlumbUIComponent=function(I){jsPlumbUIComponent.apply(this,arguments);var N=this;this.overlays=[];var G=function(S){var Q=null;if(S.constructor==Array){var P=S[0],R=n.extend({component:N,_jsPlumb:N._jsPlumb},S[1]);if(S.length==3){n.extend(R,S[2])}Q=new n.Overlays[N._jsPlumb.getRenderMode()][P](R);if(R.events){for(var O in R.events){Q.bind(O,R.events[O])}}}else{if(S.constructor==String){Q=new n.Overlays[N._jsPlumb.getRenderMode()][S]({component:N,_jsPlumb:N._jsPlumb})}else{Q=S}}N.overlays.push(Q)},H=function(S){var O=N.defaultOverlayKeys||[],R=S.overlays,P=function(T){return N._jsPlumb.Defaults[T]||n.Defaults[T]||[]};if(!R){R=[]}for(var Q=0;Q<O.length;Q++){R.unshift.apply(R,P(O[Q]))}return R};var E=H(I);if(E){for(var J=0;J<E.length;J++){G(E[J])}}var D=function(Q){var O=-1;for(var P=0;P<N.overlays.length;P++){if(Q===N.overlays[P].id){O=P;break}}return O};this.addOverlay=function(O){G(O);N.repaint()};this.getOverlay=function(P){var O=D(P);return O>=0?N.overlays[O]:null};this.hideOverlay=function(P){var O=N.getOverlay(P);if(O){O.hide()}};this.showOverlay=function(P){var O=N.getOverlay(P);if(O){O.show()}};this.removeAllOverlays=function(){N.overlays.splice(0,N.overlays.length);N.repaint()};this.removeOverlay=function(P){var O=D(P);if(O!=-1){var Q=N.overlays[O];Q.cleanup();N.overlays.splice(O,1)}};this.removeOverlays=function(){for(var O=0;O<arguments.length;O++){N.removeOverlay(arguments[O])}};var F="__label",M=function(Q){var O={cssClass:Q.cssClass,labelStyle:this.labelStyle,id:F,component:N,_jsPlumb:N._jsPlumb},P=n.extend(O,Q);return new n.Overlays[N._jsPlumb.getRenderMode()].Label(P)};if(I.label){var K=I.labelLocation||N.defaultLabelLocation||0.5,L=I.labelStyle||N._jsPlumb.Defaults.LabelStyle||n.Defaults.LabelStyle;this.overlays.push(M({label:I.label,location:K,labelStyle:L}))}this.setLabel=function(O){var P=N.getOverlay(F);if(!P){var Q=O.constructor==String||O.constructor==Function?{label:O}:O;P=M(Q);this.overlays.push(P)}else{if(O.constructor==String||O.constructor==Function){P.setLabel(O)}else{if(O.label){P.setLabel(O.label)}if(O.location){P.setLocation(O.location)}}}N.repaint()};this.getLabel=function(){var O=N.getOverlay(F);return O!=null?O.getLabel():null};this.getLabelOverlay=function(){return N.getOverlay(F)}},_bindListeners=function(F,D,E){F.bind("click",function(G,H){D.fire("click",D,H)});F.bind("dblclick",function(G,H){D.fire("dblclick",D,H)});F.bind("contextmenu",function(G,H){D.fire("contextmenu",D,H)});F.bind("mouseenter",function(G,H){if(!D.isHover()){E(true);D.fire("mouseenter",D,H)}});F.bind("mouseexit",function(G,H){if(D.isHover()){E(false);D.fire("mouseexit",self,H)}})};var g=0,c=function(){var D=g+1;g++;return D};var v=function(E){this.Defaults={Anchor:"BottomCenter",Anchors:[null,null],ConnectionsDetachable:true,Connector:"Bezier",Container:null,DragOptions:{},DropOptions:{},Endpoint:"Dot",Endpoints:[null,null],EndpointStyle:{fillStyle:"#456"},EndpointStyles:[null,null],EndpointHoverStyle:null,EndpointHoverStyles:[null,null],HoverPaintStyle:null,LabelStyle:{color:"black"},LogEnabled:false,Overlays:[],MaxConnections:1,MouseEventsEnabled:true,PaintStyle:{lineWidth:8,strokeStyle:"#456"},RenderMode:"svg",Scope:"jsPlumb_DefaultScope"};if(E){n.extend(this.Defaults,E)}this.logEnabled=this.Defaults.LogEnabled;EventGenerator.apply(this);var av=this.bind;this.bind=function(a7,a6){if("ready"===a7&&F){a6()}else{av(a7,a6)}};var aZ=this,at=c(),H=null,ae=function(){n.repaintEverything()},a1=true,aw=function(){if(a1){ae()}},aQ=null,F=false,aD={},az={},aA={},X={},a2={},aR={},aY={},aW=this.Defaults.MouseEventsEnabled,a5=[],U=[],I=this.Defaults.Scope,O=null,M=function(a9,a7,a8){var a6=a9[a7];if(a6==null){a6=[];a9[a7]=a6}a6.push(a8);return a6},aB=function(a7,a6){if(aZ.Defaults.Container){n.CurrentLibrary.appendElement(a7,aZ.Defaults.Container)}else{if(!a6){document.body.appendChild(a7)}else{n.CurrentLibrary.appendElement(a7,a6)}}},am=1,Z=function(){return""+am++},aq=function(a6){return a6._nodes?a6._nodes:a6},aJ=false,aS=function(a7,a6){aJ=a7;if(a6){aZ.repaintEverything()}},aM=function(a6,a8,a7){if(!aJ){var a9=d(a6,"id");aZ.anchorManager.redraw(a9,a8,a7)}},ap=function(a7,a9){var ba=null;if(a7.constructor==Array){ba=[];for(var a6=0;a6<a7.length;a6++){var a8=A(a7[a6]),bb=d(a8,"id");ba.push(a9(a8,bb))}}else{var a8=A(a7),bb=d(a8,"id");ba=a9(a8,bb)}return ba},ah=function(a6){return aA[a6]},aN=function(ba,a9,a8){var a6=a9==null?false:a9;if(a6){if(n.CurrentLibrary.isDragSupported(ba)&&!n.CurrentLibrary.isAlreadyDraggable(ba)){var a7=a8||aZ.Defaults.DragOptions||n.Defaults.DragOptions;a7=n.extend({},a7);var bc=n.CurrentLibrary.dragEvents.drag,bb=n.CurrentLibrary.dragEvents.stop;a7[bc]=ab(a7[bc],function(){var bd=n.CurrentLibrary.getUIPosition(arguments);aM(ba,bd);x(ba,"jsPlumb_dragged")});a7[bb]=ab(a7[bb],function(){var bd=n.CurrentLibrary.getUIPosition(arguments);aM(ba,bd);m(ba,"jsPlumb_dragged")});aY[D(ba)]=true;var a6=aY[D(ba)];a7.disabled=a6==null?false:!a6;n.CurrentLibrary.initDraggable(ba,a7,false)}}},al=function(bb,a7){var a6=n.extend({},bb);if(a7){n.extend(a6,a7)}if(a6.source&&a6.source.endpoint){a6.sourceEndpoint=a6.source}if(a6.source&&a6.target.endpoint){a6.targetEndpoint=a6.target}if(bb.uuids){a6.sourceEndpoint=ah(bb.uuids[0]);a6.targetEndpoint=ah(bb.uuids[1])}if(a6.sourceEndpoint&&a6.sourceEndpoint.isFull()){o(aZ,"could not add connection; source endpoint is full");return}if(a6.targetEndpoint&&a6.targetEndpoint.isFull()){o(aZ,"could not add connection; target endpoint is full");return}if(a6.sourceEndpoint&&a6.sourceEndpoint.connectorOverlays){a6.overlays=a6.overlays||[];for(var a9=0;a9<a6.sourceEndpoint.connectorOverlays.length;a9++){a6.overlays.push(a6.sourceEndpoint.connectorOverlays[a9])}}a6.tooltip=bb.tooltip;if(!a6.tooltip&&a6.sourceEndpoint&&a6.sourceEndpoint.connectorTooltip){a6.tooltip=a6.sourceEndpoint.connectorTooltip}if(a6.target&&!a6.target.endpoint){var ba=D(a6.target),bc=aE[ba];var a8=function(bf,bd,be,bg){if(bg[be]){if(a6[bd]){a6[bd][1]=bg[be]}else{if(a6[bf]){a6[bd]=[a6[bf],bg[be]];a6[bf]=null}else{a6[bd]=[null,bg[be]]}}}};if(bc){a8("endpoint","endpoints","endpoint",bc);a8("endpointStyle","endpointStyles","paintStyle",bc);a8("endpointHoverStyle","endpointHoverStyles","hoverPaintStyle",bc)}}return a6},T=function(ba){var a9=aZ.Defaults.ConnectionType||aZ.getDefaultConnectionType(),a8=aZ.Defaults.EndpointType||V,a7=n.CurrentLibrary.getParent;if(ba.container){ba.parent=ba.container}else{if(ba.sourceEndpoint){ba.parent=ba.sourceEndpoint.parent}else{if(ba.source.constructor==a8){ba.parent=ba.source.parent}else{ba.parent=a7(ba.source)}}}ba._jsPlumb=aZ;var a6=new a9(ba);a6.id="con_"+Z();a3("click","click",a6);a3("dblclick","dblclick",a6);a3("contextmenu","contextmenu",a6);return a6},a4=function(a7,a8,a6){a8=a8||{};if(!a7.suspendedEndpoint){M(aD,a7.scope,a7)}if(!a8.doNotFireConnectionEvent&&a8.fireEvent!==false){aZ.fire("jsPlumbConnection",{connection:a7,source:a7.source,target:a7.target,sourceId:a7.sourceId,targetId:a7.targetId,sourceEndpoint:a7.endpoints[0],targetEndpoint:a7.endpoints[1]},a6)}aZ.anchorManager.newConnection(a7);aM(a7.source)},a3=function(a6,a7,a8){a8.bind(a6,function(ba,a9){aZ.fire(a7,a8,a9)})},ai=function(a8){if(a8.container){return a8.container}else{var a6=n.CurrentLibrary.getTagName(a8.source),a7=n.CurrentLibrary.getParent(a8.source);if(a6&&a6.toLowerCase()==="td"){return n.CurrentLibrary.getParent(a7)}else{return a7}}},ao=function(a8){var a7=aZ.Defaults.EndpointType||V;a8.parent=ai(a8);a8._jsPlumb=aZ;var a6=new a7(a8);a6.id="ep_"+Z();a3("click","endpointClick",a6);a3("dblclick","endpointDblClick",a6);a3("contextmenu","contextmenu",a6);return a6},L=function(a8,bb,ba){var a6=az[a8];if(a6&&a6.length){for(var a9=0;a9<a6.length;a9++){for(var a7=0;a7<a6[a9].connections.length;a7++){var bc=bb(a6[a9].connections[a7]);if(bc){return}}if(ba){ba(a6[a9])}}}},P=function(a7){for(var a6 in az){L(a6,a7)}},ag=function(a6,a7){if(a6!=null&&a6.parentNode!=null){a6.parentNode.removeChild(a6)}},aC=function(a8,a7){for(var a6=0;a6<a8.length;a6++){ag(a8[a6],a7)}},aV=function(a7,a6){return ap(a7,function(a8,a9){aY[a9]=a6;if(n.CurrentLibrary.isDragSupported(a8)){n.CurrentLibrary.setDraggable(a8,a6)}})},aH=function(a8,a9,a6){a9=a9==="block";var a7=null;if(a6){if(a9){a7=function(bb){bb.setVisible(true,true,true)}}else{a7=function(bb){bb.setVisible(false,true,true)}}}var ba=d(a8,"id");L(ba,function(bc){if(a9&&a6){var bb=bc.sourceId===ba?1:0;if(bc.endpoints[bb].isVisible()){bc.setVisible(true)}}else{bc.setVisible(a9)}},a7)},aT=function(a6){return ap(a6,function(a8,a7){var a9=aY[a7]==null?false:aY[a7];a9=!a9;aY[a7]=a9;n.CurrentLibrary.setDraggable(a8,a9);return a9})},ax=function(a6,a8){var a7=null;if(a8){a7=function(a9){var ba=a9.isVisible();a9.setVisible(!ba)}}L(a6,function(ba){var a9=ba.isVisible();ba.setVisible(!a9)},a7)},N=function(bb){var a9=bb.timestamp,a6=bb.recalc,ba=bb.offset,a7=bb.elId;if(!a6){if(a9&&a9===a2[a7]){return X[a7]}}if(a6||!ba){var a8=A(a7);if(a8!=null){U[a7]=b(a8);X[a7]=s(a8);a2[a7]=a9}}else{X[a7]=ba;if(U[a7]==null){var a8=A(a7);if(a8!=null){U[a7]=b(a8)}}}if(X[a7]&&!X[a7].right){X[a7].right=X[a7].left+U[a7][0];X[a7].bottom=X[a7].top+U[a7][1];X[a7].width=U[a7][0];X[a7].height=U[a7][1];X[a7].centerx=X[a7].left+(X[a7].width/2);X[a7].centery=X[a7].top+(X[a7].height/2)}return X[a7]},au=function(a6){var a7=X[a6];if(!a7){a7=N({elId:a6})}return{o:a7,s:U[a6]}},D=function(a6,a7){var a8=A(a6);var a9=d(a8,"id");if(!a9||a9=="undefined"){if(arguments.length==2&&arguments[1]!=undefined){a9=a7}else{a9="jsPlumb_"+at+"_"+Z()}f(a8,"id",a9)}return a9},ab=function(a8,a6,a7){a8=a8||function(){};a6=a6||function(){};return function(){var a9=null;try{a9=a6.apply(this,arguments)}catch(ba){o(aZ,"jsPlumb function failed : "+ba)}if(a7==null||(a9!==a7)){try{a8.apply(this,arguments)}catch(ba){o(aZ,"wrapped function failed : "+ba)}}return a9}};this.connectorClass="_jsPlumb_connector";this.endpointClass="_jsPlumb_endpoint";this.overlayClass="_jsPlumb_overlay";this.Anchors={};this.Connectors={canvas:{},svg:{},vml:{}};this.Endpoints={canvas:{},svg:{},vml:{}};this.Overlays={canvas:{},svg:{},vml:{}};this.addClass=function(a7,a6){return n.CurrentLibrary.addClass(a7,a6)};this.removeClass=function(a7,a6){return n.CurrentLibrary.removeClass(a7,a6)};this.hasClass=function(a7,a6){return n.CurrentLibrary.hasClass(a7,a6)};this.addEndpoint=function(a8,a9,bi){bi=bi||{};var a7=n.extend({},bi);n.extend(a7,a9);a7.endpoint=a7.endpoint||aZ.Defaults.Endpoint||n.Defaults.Endpoint;a7.paintStyle=a7.paintStyle||aZ.Defaults.EndpointStyle||n.Defaults.EndpointStyle;a8=aq(a8);var ba=[],bd=a8.length&&a8.constructor!=String?a8:[a8];for(var bb=0;bb<bd.length;bb++){var bg=A(bd[bb]),a6=D(bg);a7.source=bg;N({elId:a6});var bf=ao(a7);if(a7.parentAnchor){bf.parentAnchor=a7.parentAnchor}M(az,a6,bf);var be=X[a6],bc=U[a6];var bh=bf.anchor.compute({xy:[be.left,be.top],wh:bc,element:bf});bf.paint({anchorLoc:bh});ba.push(bf)}return ba.length==1?ba[0]:ba};this.addEndpoints=function(ba,a7,a6){var a9=[];for(var a8=0;a8<a7.length;a8++){var bb=aZ.addEndpoint(ba,a7[a8],a6);if(bb.constructor==Array){Array.prototype.push.apply(a9,bb)}else{a9.push(bb)}}return a9};this.animate=function(a8,a7,a6){var a9=A(a8),bc=d(a8,"id");a6=a6||{};var bb=n.CurrentLibrary.dragEvents.step;var ba=n.CurrentLibrary.dragEvents.complete;a6[bb]=ab(a6[bb],function(){aZ.repaint(bc)});a6[ba]=ab(a6[ba],function(){aZ.repaint(bc)});n.CurrentLibrary.animate(a9,a7,a6)};this.checkCondition=function(a8,ba){var a6=aZ.getListener(a8);var a9=true;if(a6&&a6.length>0){try{for(var a7=0;a7<a6.length;a7++){a9=a9&&a6[a7](ba)}}catch(bb){o(aZ,"cannot check condition ["+a8+"]"+bb)}}return a9};this.connect=function(a9,a7){var a6=al(a9,a7);if(a6){if(a6.deleteEndpointsOnDetach==null){a6.deleteEndpointsOnDetach=true}var a8=T(a6);a4(a8,a6);return a8}};this.deleteEndpoint=function(a7){var bc=(typeof a7=="string")?aA[a7]:a7;if(bc){var a9=bc.getUuid();if(a9){aA[a9]=null}bc.detachAll();aC(bc.endpoint.getDisplayElements());aZ.anchorManager.deleteEndpoint(bc);for(var bb in az){var a6=az[bb];if(a6){var ba=[];for(var a8=0;a8<a6.length;a8++){if(a6[a8]!=bc){ba.push(a6[a8])}}az[bb]=ba}}delete bc}};this.deleteEveryEndpoint=function(){for(var a8 in az){var a6=az[a8];if(a6&&a6.length){for(var a7=0;a7<a6.length;a7++){aZ.deleteEndpoint(a6[a7])}}}delete az;az={};delete aA;aA={}};var aK=function(a8,ba){var a7=aZ.Defaults.ConnectionType||aZ.getDefaultConnectionType(),a6=a8.constructor==a7,a9=a6?{connection:a8,source:a8.source,target:a8.target,sourceId:a8.sourceId,targetId:a8.targetId,sourceEndpoint:a8.endpoints[0],targetEndpoint:a8.endpoints[1]}:a8;if(ba){aZ.fire("jsPlumbConnectionDetached",a9)}aZ.anchorManager.connectionDetached(a9)};this.detach=function(){if(arguments.length==0){return}var ba=aZ.Defaults.ConnectionType||aZ.getDefaultConnectionType(),bb=arguments[0].constructor==ba,a9=arguments.length==2?bb?(arguments[1]||{}):arguments[0]:arguments[0],be=(a9.fireEvent!==false),a8=a9.forceDetach,a7=bb?arguments[0]:a9.connection;if(a7){if(a8||(a7.isDetachAllowed(a7)&&a7.endpoints[0].isDetachAllowed(a7)&&a7.endpoints[1].isDetachAllowed(a7))){if(a8||aZ.checkCondition("beforeDetach",a7)){a7.endpoints[0].detach(a7,false,true,be)}}}else{var a6=n.extend({},a9);if(a6.uuids){ah(a6.uuids[0]).detachFrom(ah(a6.uuids[1]),be)}else{if(a6.sourceEndpoint&&a6.targetEndpoint){a6.sourceEndpoint.detachFrom(a6.targetEndpoint)}else{var bd=D(a6.source),bc=D(a6.target);L(bd,function(bf){if((bf.sourceId==bd&&bf.targetId==bc)||(bf.targetId==bd&&bf.sourceId==bc)){if(aZ.checkCondition("beforeDetach",bf)){bf.endpoints[0].detach(bf,false,true,be)}}})}}}};this.detachAllConnections=function(a8,a9){a9=a9||{};a8=A(a8);var ba=d(a8,"id"),a6=az[ba];if(a6&&a6.length){for(var a7=0;a7<a6.length;a7++){a6[a7].detachAll(a9.fireEvent)}}};this.detachEveryConnection=function(a8){a8=a8||{};for(var a9 in az){var a6=az[a9];if(a6&&a6.length){for(var a7=0;a7<a6.length;a7++){a6[a7].detachAll(a8.fireEvent)}}}delete aD;aD={}};this.draggable=function(a8,a6){if(typeof a8=="object"&&a8.length){for(var a7=0;a7<a8.length;a7++){var a9=A(a8[a7]);if(a9){aN(a9,true,a6)}}}else{if(a8._nodes){for(var a7=0;a7<a8._nodes.length;a7++){var a9=A(a8._nodes[a7]);if(a9){aN(a9,true,a6)}}}else{var a9=A(a8);if(a9){aN(a9,true,a6)}}}};this.extend=function(a7,a6){return n.CurrentLibrary.extend(a7,a6)};this.getDefaultEndpointType=function(){return V};this.getDefaultConnectionType=function(){return aj};this.getConnections=function(bh){if(!bh){bh={}}else{if(bh.constructor==String){bh={scope:bh}}}var be=function(bi){var bj=[];if(bi){if(typeof bi=="string"){bj.push(bi)}else{bj=bi}}return bj},bf=bh.scope||aZ.getDefaultScope(),bd=be(bf),a6=be(bh.source),bb=be(bh.target),a7=function(bj,bi){return bj.length>0?p(bj,bi)!=-1:true},ba=bd.length>1?{}:[],bg=function(bj,bk){if(bd.length>1){var bi=ba[bj];if(bi==null){bi=[];ba[bj]=bi}bi.push(bk)}else{ba.push(bk)}};for(var a9 in aD){if(a7(bd,a9)){for(var a8=0;a8<aD[a9].length;a8++){var bc=aD[a9][a8];if(a7(a6,bc.sourceId)&&a7(bb,bc.targetId)){bg(a9,bc)}}}}return ba};this.getAllConnections=function(){return aD};this.getDefaultScope=function(){return I};this.getEndpoint=ah;this.getEndpoints=function(a6){return az[D(a6)]};this.getId=D;this.getOffset=function(a7){var a6=X[a7];return N({elId:a7})};this.getSelector=function(a6){return n.CurrentLibrary.getSelector(a6)};this.getSize=function(a7){var a6=U[a7];if(!a6){N({elId:a7})}return U[a7]};this.appendElement=aB;var ay=false;this.isHoverSuspended=function(){return ay};this.setHoverSuspended=function(a6){ay=a6};this.hide=function(a6,a7){aH(a6,"none",a7)};this.idstamp=Z;this.init=function(){if(!F){aZ.setRenderMode(aZ.Defaults.RenderMode);var a6=function(a7){n.CurrentLibrary.bind(document,a7,function(bd){if(!aZ.currentlyDragging&&aW&&O==n.CANVAS){for(var bc in aD){var be=aD[bc];for(var ba=0;ba<be.length;ba++){var a9=be[ba].connector[a7](bd);if(a9){return}}}for(var bb in az){var a8=az[bb];for(var ba=0;ba<a8.length;ba++){if(a8[ba].endpoint[a7](bd)){return}}}}})};a6("click");a6("dblclick");a6("mousemove");a6("mousedown");a6("mouseup");a6("contextmenu");F=true;aZ.fire("ready")}};this.log=H;this.jsPlumbUIComponent=jsPlumbUIComponent;this.EventGenerator=EventGenerator;this.makeAnchor=function(){if(arguments.length==0){return null}var bb=arguments[0],a8=arguments[1],a7=arguments[2],a9=null;if(!a7){throw"NO JSPLUMB SET"}if(bb.compute&&bb.getOrientation){return bb}else{if(typeof bb=="string"){a9=n.Anchors[arguments[0]]({elementId:a8,jsPlumbInstance:aZ})}else{if(bb.constructor==Array){if(bb[0].constructor==Array||bb[0].constructor==String){if(bb.length==2&&bb[0].constructor==String&&bb[1].constructor==Object){var a6=n.extend({elementId:a8,jsPlumbInstance:aZ},bb[1]);a9=n.Anchors[bb[0]](a6)}else{a9=new ad(bb,null,a8)}}else{var ba={x:bb[0],y:bb[1],orientation:(bb.length>=4)?[bb[2],bb[3]]:[0,0],offsets:(bb.length==6)?[bb[4],bb[5]]:[0,0],elementId:a8};a9=new Q(ba);a9.clone=function(){return new Q(ba)}}}}}if(!a9.id){a9.id="anchor_"+Z()}return a9};this.makeAnchors=function(a9,a7,a6){var ba=[];for(var a8=0;a8<a9.length;a8++){if(typeof a9[a8]=="string"){ba.push(n.Anchors[a9[a8]]({elementId:a7,jsPlumbInstance:a6}))}else{if(a9[a8].constructor==Array){ba.push(aZ.makeAnchor(a9[a8],a7,a6))}}}return ba};this.makeDynamicAnchor=function(a6,a7){return new ad(a6,a7)};var aE={};var S=function(a6,a7){a6.paintStyle=a6.paintStyle||aZ.Defaults.EndpointStyles[a7]||aZ.Defaults.EndpointStyle||n.Defaults.EndpointStyles[a7]||n.Defaults.EndpointStyle;a6.hoverPaintStyle=a6.hoverPaintStyle||aZ.Defaults.EndpointHoverStyles[a7]||aZ.Defaults.EndpointHoverStyle||n.Defaults.EndpointHoverStyles[a7]||n.Defaults.EndpointHoverStyle;a6.anchor=a6.anchor||aZ.Defaults.Anchors[a7]||aZ.Defaults.Anchor||n.Defaults.Anchors[a7]||n.Defaults.Anchor};this.makeTarget=function(a8,a9,bf){var a7=n.extend({},bf);n.extend(a7,a9);var bd=n.CurrentLibrary,be=a7.scope||aZ.Defaults.Scope,ba=a7.deleteEndpointsOnDetach||true,a6=function(bk){var bi=D(bk);aE[bi]=a7.endpoint;var bh=n.extend({},a7.dropOptions||{}),bg=function(){aZ.currentlyDragging=false;var bx=A(bd.getDragObject(arguments)),bn=d(bx,"dragId"),bv=d(bx,"originalScope"),bs=aR[bn],bm=bs.endpoints[0],bl=a7.endpoint?n.extend({},a7.endpoint):{};S(bl,1);bm.anchor.locked=false;if(bv){bd.setDragScope(bx,bv)}var bq=bs.isDropAllowed(bs.sourceId,D(bk),bs.scope);if(bs.endpointsToDeleteOnDetach){if(bm===bs.endpointsToDeleteOnDetach[0]){bs.endpointsToDeleteOnDetach[0]=null}else{if(bm===bs.endpointsToDeleteOnDetach[1]){bs.endpointsToDeleteOnDetach[1]=null}}}if(bs.suspendedEndpoint){bs.targetId=bs.suspendedEndpoint.elementId;bs.target=bd.getElementObject(bs.suspendedEndpoint.elementId);bs.endpoints[1]=bs.suspendedEndpoint}if(bq){bm.detach(bs,false,true,true);var bw=aZ.addEndpoint(bk,bl);if(bw.anchor.positionFinder!=null){var bt=bd.getUIPosition(arguments),bp=bd.getOffset(bk),bu=bd.getSize(bk),bo=bw.anchor.positionFinder(bt,bp,bu,bw.anchor);bw.anchor.x=bo[0];bw.anchor.y=bo[1]}var br=aZ.connect({source:bm,target:bw,scope:bv,previousConnection:bs,container:bs.parent,doNotFireConnectionEvent:bm.endpointWillMoveAfterConnection});if(ba){br.endpointsToDeleteOnDetach=[bm,bw]}}else{if(bs.suspendedEndpoint){if(bm.isReattach){bs.setHover(false);bs.floatingAnchorIndex=null;bs.suspendedEndpoint.addConnection(bs);aZ.repaint(bm.elementId)}else{bm.detach(bs,false,true,true)}}}};var bj=bd.dragEvents.drop;bh.scope=bh.scope||be;bh[bj]=ab(bh[bj],bg);bd.initDroppable(bk,bh,true)};a8=aq(a8);var bc=a8.length&&a8.constructor!=String?a8:[a8];for(var bb=0;bb<bc.length;bb++){a6(A(bc[bb]))}};this.makeTargets=function(a8,a9,a6){for(var a7=0;a7<a8.length;a7++){aZ.makeTarget(a8[a7],a9,a6)}};var ak={};this.makeSource=function(ba,bd,a6){var bb=n.extend({},a6);n.extend(bb,bd);var a9=n.CurrentLibrary,bc=function(bk){var be=D(bk);ak[be]=bb.endpoint||{};var bf=a9.dragEvents.stop,bj=a9.dragEvents.drag,bl=n.extend({},bb.dragOptions||ak[be].dragOptions||{}),bh=bl.drag,bm=bl.stop,bn=null,bi=false;bl.scope=bl.scope||bb.scope;ak[be].endpoint=ak[be].endpoint||aZ.Defaults.Endpoints[0]||aZ.Defaults.Endpoint;S(ak[be],0);bl[bj]=ab(bl[bj],function(){if(bh){bh.apply(this,arguments)}bi=false});bl[bf]=function(){if(bm){bm.apply(this,arguments)}aZ.currentlyDragging=false;if(bn.connections.length==0){aZ.deleteEndpoint(bn)}else{a9.unbind(bn.canvas,"mousedown");var bp=ak[be].anchor||aZ.Defaults.Anchor;bn.anchor=aZ.makeAnchor(bp,be,aZ);if(bb.parent){var bq=a9.getElementObject(bb.parent);if(bq){var bo=bn.elementId;bn.setElement(bq);bn.endpointWillMoveAfterConnection=false;aZ.anchorManager.rehomeEndpoint(bo,bq);bn.connections[0].previousConnection=null;a4(bn.connections[0])}}aZ.repaint(be)}};var bg=function(bp){var bu=N({elId:be});var bt=((bp.pageX||bp.page.x)-bu.left)/bu.width,bs=((bp.pageY||bp.page.y)-bu.top)/bu.height,by=bt,bx=bs;if(bb.parent){var br=n.CurrentLibrary.getElementObject(bb.parent),bq=D(br);bu=N({elId:bq});by=((bp.pageX||bp.page.x)-bu.left)/bu.width,bx=((bp.pageY||bp.page.y)-bu.top)/bu.height}var bw={};n.extend(bw,ak[be]);bw.isSource=true;bw.anchor=[bt,bs,0,0];bw.parentAnchor=[by,bx,0,0];bw.dragOptions=bl;if(bb.parent){var bo=bw.container||aZ.Defaults.Container;if(bo){bw.container=bo}else{bw.container=n.CurrentLibrary.getParent(bb.parent)}}bn=aZ.addEndpoint(be,bw);bi=true;bn.endpointWillMoveAfterConnection=bb.parent!=null;bn.endpointWillMoveTo=bb.parent?a9.getElementObject(bb.parent):null;var bv=function(){if(bi){aZ.deleteEndpoint(bn)}};aZ.registerListener(bn.canvas,"mouseup",bv);aZ.registerListener(bk,"mouseup",bv);a9.trigger(bn.canvas,"mousedown",bp)};aZ.registerListener(bk,"mousedown",bg)};ba=aq(ba);var a7=ba.length&&ba.constructor!=String?ba:[ba];for(var a8=0;a8<a7.length;a8++){bc(A(a7[a8]))}};this.makeSources=function(a8,a9,a6){for(var a7=0;a7<a8.length;a7++){aZ.makeSource(a8[a7],a9,a6)}};this.ready=function(a6){aZ.bind("ready",a6)},this.repaint=function(a7){var a8=function(a9){aM(A(a9))};if(typeof a7=="object"){for(var a6=0;a6<a7.length;a6++){a8(a7[a6])}}else{a8(a7)}};this.repaintEverything=function(){var a7=_timestamp();for(var a6 in az){aM(A(a6),null,a7)}};this.removeAllEndpoints=function(a8){var a6=d(a8,"id"),a9=az[a6];if(a9){for(var a7=0;a7<a9.length;a7++){aZ.deleteEndpoint(a9[a7])}}az[a6]=[]};this.removeEveryEndpoint=this.deleteEveryEndpoint;this.removeEndpoint=function(a6,a7){aZ.deleteEndpoint(a7)};var W={},aP=function(){for(var a7 in W){for(var a6=0;a6<W[a7].length;a6++){var a8=W[a7][a6];n.CurrentLibrary.unbind(a8.el,a8.event,a8.listener)}}W={}};this.registerListener=function(a7,a6,a8){n.CurrentLibrary.bind(a7,a6,a8);M(W,a6,{el:a7,event:a6,listener:a8})};this.reset=function(){aZ.deleteEveryEndpoint();aZ.clearListeners();aP();aZ.anchorManager.reset()};this.setAutomaticRepaint=function(a6){a1=a6};this.setDefaultScope=function(a6){I=a6};this.setDraggable=aV;this.setDebugLog=function(a6){H=a6};this.setRepaintFunction=function(a6){ae=a6};this.setMouseEventsEnabled=function(a6){aW=a6};this.setSuspendDrawing=aS;this.CANVAS="canvas";this.SVG="svg";this.VML="vml";this.setRenderMode=function(a6){if(a6){a6=a6.toLowerCase()}else{return}if(a6!==n.CANVAS&&a6!==n.SVG&&a6!==n.VML){throw new Error("render mode must be one of jsPlumb.CANVAS, jsPlumb.SVG or jsPlumb.VML")}if(a6===n.CANVAS&&w){O=n.CANVAS}else{if(a6===n.SVG&&e){O=n.SVG}else{if(a){O=n.VML}}}return O};this.getRenderMode=function(){return O};this.show=function(a6,a7){aH(a6,"block",a7)};this.sizeCanvas=function(a8,a6,ba,a7,a9){if(a8){a8.style.height=a9+"px";a8.height=a9;a8.style.width=a7+"px";a8.width=a7;a8.style.left=a6+"px";a8.style.top=ba+"px"}};this.getTestHarness=function(){return{endpointsByElement:az,endpointCount:function(a6){var a7=az[a6];return a7?a7.length:0},connectionCount:function(a6){a6=a6||I;var a7=aD[a6];return a7?a7.length:0},findIndex:p,getId:D,makeAnchor:self.makeAnchor,makeDynamicAnchor:self.makeDynamicAnchor}};this.toggle=ax;this.toggleVisible=ax;this.toggleDraggable=aT;this.unload=function(){};this.wrap=ab;this.addListener=this.bind;var a0=function(bb,a8){var a9=null,a6=bb;if(a8.tagName.toLowerCase()==="svg"&&a8.parentNode){a9=a8.parentNode}else{if(a8.offsetParent){a9=a8.offsetParent}}if(a9!=null){var a7=a9.tagName.toLowerCase()==="body"?{left:0,top:0}:s(a9),ba=a9.tagName.toLowerCase()==="body"?{left:0,top:0}:{left:a9.scrollLeft,top:a9.scrollTop};a6[0]=bb[0]-a7.left+ba.left;a6[1]=bb[1]-a7.top+ba.top}return a6};var Q=function(ba){var a8=this;this.x=ba.x||0;this.y=ba.y||0;this.elementId=ba.elementId;var a7=ba.orientation||[0,0];var a9=null,a6=null;this.offsets=ba.offsets||[0,0];a8.timestamp=null;this.compute=function(bf){var be=bf.xy,bb=bf.wh,bc=bf.element,bd=bf.timestamp;if(bd&&bd===a8.timestamp){return a6}a6=[be[0]+(a8.x*bb[0])+a8.offsets[0],be[1]+(a8.y*bb[1])+a8.offsets[1]];a6=a0(a6,bc.canvas);a8.timestamp=bd;return a6};this.getOrientation=function(bb){return a7};this.equals=function(bb){if(!bb){return false}var bc=bb.getOrientation();var bd=this.getOrientation();return this.x==bb.x&&this.y==bb.y&&this.offsets[0]==bb.offsets[0]&&this.offsets[1]==bb.offsets[1]&&bd[0]==bc[0]&&bd[1]==bc[1]};this.getCurrentLocation=function(){return a6}};var aG=function(bc){var ba=bc.reference,bb=bc.referenceCanvas,a8=b(A(bb)),a7=0,bd=0,a6=null,a9=null;this.x=0;this.y=0;this.isFloating=true;this.compute=function(bh){var bg=bh.xy,bf=bh.element,be=[bg[0]+(a8[0]/2),bg[1]+(a8[1]/2)];be=a0(be,bf.canvas);a9=be;return be};this.getOrientation=function(bf){if(a6){return a6}else{var be=ba.getOrientation(bf);return[Math.abs(be[0])*a7*-1,Math.abs(be[1])*bd*-1]}};this.over=function(be){a6=be.getOrientation()};this.out=function(){a6=null};this.getCurrentLocation=function(){return a9}};var ad=function(a8,a7,bd){this.isSelective=true;this.isDynamic=true;var bg=[],bf=this,be=function(bh){return bh.constructor==Q?bh:aZ.makeAnchor(bh,bd,aZ)};for(var bc=0;bc<a8.length;bc++){bg[bc]=be(a8[bc])}this.addAnchor=function(bh){bg.push(be(bh))};this.getAnchors=function(){return bg};this.locked=false;var a9=bg.length>0?bg[0]:null,bb=bg.length>0?0:-1,bf=this,ba=function(bj,bh,bn,bm,bi){var bl=bm[0]+(bj.x*bi[0]),bk=bm[1]+(bj.y*bi[1]);return Math.sqrt(Math.pow(bh-bl,2)+Math.pow(bn-bk,2))},a6=a7||function(br,bi,bj,bk,bh){var bm=bj[0]+(bk[0]/2),bl=bj[1]+(bk[1]/2);var bo=-1,bq=Infinity;for(var bn=0;bn<bh.length;bn++){var bp=ba(bh[bn],bm,bl,br,bi);if(bp<bq){bo=bn+0;bq=bp}}return bh[bo]};this.compute=function(bl){var bk=bl.xy,bh=bl.wh,bj=bl.timestamp,bi=bl.txy,bm=bl.twh;if(bf.locked||bi==null||bm==null){return a9.compute(bl)}else{bl.timestamp=null}a9=a6(bk,bh,bi,bm,bg);bf.x=a9.x;bf.y=a9.y;return a9.compute(bl)};this.getCurrentLocation=function(){return a9!=null?a9.getCurrentLocation():null};this.getOrientation=function(bh){return a9!=null?a9.getOrientation(bh):[0,0]};this.over=function(bh){if(a9!=null){a9.over(bh)}};this.out=function(){if(a9!=null){a9.out()}}};var aU={},Y={},ar={},K={HORIZONTAL:"horizontal",VERTICAL:"vertical",DIAGONAL:"diagonal",IDENTITY:"identity"},aX=function(bf,bg,bc,a9){if(bf===bg){return{orientation:K.IDENTITY,a:["top","top"]}}var a7=Math.atan2((a9.centery-bc.centery),(a9.centerx-bc.centerx)),ba=Math.atan2((bc.centery-a9.centery),(bc.centerx-a9.centerx)),bb=((bc.left<=a9.left&&bc.right>=a9.left)||(bc.left<=a9.right&&bc.right>=a9.right)||(bc.left<=a9.left&&bc.right>=a9.right)||(a9.left<=bc.left&&a9.right>=bc.right)),bh=((bc.top<=a9.top&&bc.bottom>=a9.top)||(bc.top<=a9.bottom&&bc.bottom>=a9.bottom)||(bc.top<=a9.top&&bc.bottom>=a9.bottom)||(a9.top<=bc.top&&a9.bottom>=bc.bottom));if(!(bb||bh)){var be=null,a8=false,a6=false,bd=null;if(a9.left>bc.left&&a9.top>bc.top){be=["right","top"]}else{if(a9.left>bc.left&&bc.top>a9.top){be=["top","left"]}else{if(a9.left<bc.left&&a9.top<bc.top){be=["top","right"]}else{if(a9.left<bc.left&&a9.top>bc.top){be=["left","top"]}}}}return{orientation:K.DIAGONAL,a:be,theta:a7,theta2:ba}}else{if(bb){return{orientation:K.HORIZONTAL,a:bc.top<a9.top?["bottom","top"]:["top","bottom"],theta:a7,theta2:ba}}else{return{orientation:K.VERTICAL,a:bc.left<a9.left?["right","left"]:["left","right"],theta:a7,theta2:ba}}}},aI=function(bk,bg,be,bf,bl,bh,a8){var bm=[],a7=bg[bl?0:1]/(bf.length+1);for(var bi=0;bi<bf.length;bi++){var bn=(bi+1)*a7,a6=bh*bg[bl?1:0];if(a8){bn=bg[bl?0:1]-bn}var bd=(bl?bn:a6),ba=be[0]+bd,bc=bd/bg[0],bb=(bl?a6:bn),a9=be[1]+bb,bj=bb/bg[1];bm.push([ba,a9,bc,bj,bf[bi][1],bf[bi][2]])}return bm},aL=function(a7,a6){return a7[0]>a6[0]?1:-1},R=function(a6){return function(a8,a7){var a9=true;if(a6){if(a8[0][0]<a7[0][0]){a9=true}else{a9=a8[0][1]>a7[0][1]}}else{if(a8[0][0]>a7[0][0]){a9=true}else{a9=a8[0][1]>a7[0][1]}}return a9===false?-1:1}},G=function(a7,a6){var a9=a7[0][0]<0?-Math.PI-a7[0][0]:Math.PI-a7[0][0],a8=a6[0][0]<0?-Math.PI-a6[0][0]:Math.PI-a6[0][0];if(a9>a8){return 1}else{return a7[0][1]>a6[0][1]?1:-1}},aF={top:aL,right:R(true),bottom:R(true),left:G},ac=function(a6,a7){return a6.sort(a7)},aa=function(a7,a6){var a9=U[a7],ba=X[a7],a8=function(bg,bn,bc,bf,bl,bk){if(bf.length>0){var bj=ac(bf,aF[bg]),bh=bg==="right"||bg==="top",bb=aI(bg,bn,bc,bj,bl,bk,bh);var bo=function(br,bq){var bp=a0([bq[0],bq[1]],br.canvas);Y[br.id]=[bp[0],bp[1],bq[2],bq[3]]};for(var bd=0;bd<bb.length;bd++){var bi=bb[bd][4],bm=bi.endpoints[0].elementId===a7,be=bi.endpoints[1].elementId===a7;if(bm){bo(bi.endpoints[0],bb[bd])}else{if(be){bo(bi.endpoints[1],bb[bd])}}}}};a8("bottom",a9,[ba.left,ba.top],a6.bottom,true,1);a8("top",a9,[ba.left,ba.top],a6.top,true,0);a8("left",a9,[ba.left,ba.top],a6.left,false,0);a8("right",a9,[ba.left,ba.top],a6.right,false,1)},an=function(){var a6={},a8={},a9={},bc=[],a7=this,bb={};this.reset=function(){a8={};a9={};bc=[];bb={}};this.newConnection=function(bg){var bi=bg.sourceId,bf=bg.targetId,bd=bg.endpoints,bh=true,be=function(bj,bk,bm,bl,bn){if(bm.constructor==ad||bm.constructor==Q){M(a8,bl,[bn,bk,bm.constructor==ad])}else{if(bi==bf){n.CurrentLibrary.removeElement(bd[1].canvas);bh=false}M(a9,bl,bn)}};be(0,bd[0],bd[0].anchor,bf,bg);if(bh){be(1,bd[1],bd[1].anchor,bi,bg)}};this.connectionDetached=function(bd){var bi=bd.sourceId,bj=bd.targetId,bm=bd.connection.endpoints,bh=function(bn,bo,bq,bp,bs){if(bq.constructor==aG){}else{if(bq.constructor==ad||bq.constructor==Q){var br=a8[bp];if(br){y(br,function(bt){return bt[0].id==bs.id})}}else{y(a9[bp],function(bt){return bt.id==bs.id})}}};bh(1,bm[1],bm[1].anchor,bi,bd.connection);bh(0,bm[0],bm[0].anchor,bj,bd.connection);var be=bd.connection.sourceId,bf=bd.connection.targetId,bl=bd.connection.endpoints[0].id,bg=bd.connection.endpoints[1].id,bk=function(bp,bn){if(bp){var bo=function(bq){return bq[4]==bn};y(bp.top,bo);y(bp.left,bo);y(bp.bottom,bo);y(bp.right,bo)}};bk(bb[be],bl);bk(bb[bf],bg);a7.redraw(be);a7.redraw(bf)};this.add=function(be,bd){M(a6,bd,be)};this.get=function(bd){return{standard:a8[bd]||[],continuous:a9[bd]||[],endpoints:a6[bd],continuousAnchorEndpoints:bc}};this.deleteEndpoint=function(be){var bd=p(bc,be);if(bd>-1){bc.splice(bd,1)}else{y(a6[be.elementId],function(bf){return bf.id==be.id})}};this.clearFor=function(bd){delete a6[bd];a6[bd]=[]};var ba=function(bx,bk,bs,bh,bn,bo,bq,bm,bz,bp,bg,bw){var bu=-1,bf=-1,bi=bh.endpoints[bq],br=bi.id,bl=[1,0][bq],bd=[[bk,bs],bh,bn,bo,br],be=bx[bz],by=bi._continuousAnchorEdge?bx[bi._continuousAnchorEdge]:null;if(by){var bv=i(by,function(bA){return bA[4]==br});if(bv!=-1){by.splice(bv,1);for(var bt=0;bt<by.length;bt++){r(bg,by[bt][1],function(bA){return bA.id==by[bt][1].id});r(bw,by[bt][1].endpoints[bq],function(bA){return bA.id==by[bt][1].endpoints[bq].id})}}}for(var bt=0;bt<be.length;bt++){if(bq==1&&be[bt][3]===bo&&bf==-1){bf=bt}r(bg,be[bt][1],function(bA){return bA.id==be[bt][1].id});r(bw,be[bt][1].endpoints[bq],function(bA){return bA.id==be[bt][1].endpoints[bq].id})}if(bu!=-1){be[bu]=bd}else{var bj=bm?bf!=-1?bf:0:be.length;be.splice(bj,0,bd)}bi._continuousAnchorEdge=bz};this.redraw=function(bp,br,bf){var bB=a6[bp]||[],bA=a8[bp]||[],bz=a9[bp]||[],be=[],by=[],bg=[];bf=bf||_timestamp();N({elId:bp,offset:br,recalc:false,timestamp:bf});var bl=X[bp],bi=U[bp],bn={};for(var bw=0;bw<bz.length;bw++){var bj=bz[bw],bk=bj.sourceId,bh=bj.targetId,bx=bk+"_"+bh,bu=bh+"_"+bk,bt=bn[bx],bm=au(bh),bd=au(bk),bo=bj.sourceId==bp?1:0;if(!bb[bk]){bb[bk]={top:[],right:[],bottom:[],left:[]}}if(!bb[bh]){bb[bh]={top:[],right:[],bottom:[],left:[]}}if(bh==bk){ba(bb[bk],-Math.PI/2,0,bj,false,bh,0,false,"top",bk,be,by)}else{if(!bt){bt=aX(bk,bh,bd.o,bm.o);bn[bx]=bt}ba(bb[bk],bt.theta,0,bj,false,bh,0,false,bt.a[0],bk,be,by);ba(bb[bh],bt.theta2,-1,bj,true,bk,1,true,bt.a[1],bh,be,by)}r(bg,bk,function(bC){return bC===bk});r(bg,bh,function(bC){return bC===bh});r(be,bj,function(bC){return bC.id==bj.id});r(by,bj.endpoints[bo],function(bC){return bC.id==bj.endpoints[bo].id})}for(var bw=0;bw<bg.length;bw++){aa(bg[bw],bb[bg[bw]])}for(var bw=0;bw<bB.length;bw++){bB[bw].paint({timestamp:bf,offset:bl,dimensions:bi})}for(var bw=0;bw<by.length;bw++){by[bw].paint({timestamp:bf,offset:bl,dimensions:bi})}for(var bw=0;bw<bA.length;bw++){var bq=bA[bw][1];if(bq.anchor.constructor==ad){bq.paint({elementWithPrecedence:bp});r(be,bA[bw][0],function(bC){return bC.id==bA[bw][0].id});for(var bv=0;bv<bq.connections.length;bv++){if(bq.connections[bv]!==bA[bw][0]){r(be,bq.connections[bv],function(bC){return bC.id==bq.connections[bv].id})}}}else{if(bq.anchor.constructor==Q){r(be,bA[bw][0],function(bC){return bC.id==bA[bw][0].id})}}}var bs=aR[bp];if(bs){bs.paint({timestamp:bf,recalc:false,elId:bp})}for(var bw=0;bw<be.length;bw++){be[bw].paint({elId:bp,timestamp:bf,recalc:false})}};this.rehomeEndpoint=function(bd,bh){var be=a6[bd]||[],bf=aZ.getId(bh);for(var bg=0;bg<be.length;bg++){a7.add(be[bg],bf)}be.splice(0,be.length)}};aZ.anchorManager=new an();aZ.continuousAnchorFactory={get:function(a7){var a6=aU[a7.elementId];if(!a6){a6={type:"Continuous",compute:function(a8){return Y[a8.element.id]||[0,0]},getCurrentLocation:function(a8){return Y[a8.id]||[0,0]},getOrientation:function(a8){return ar[a8.id]||[0,0]},isDynamic:true,isContinuous:true};aU[a7.elementId]=a6}return a6}};var aj=function(bo){var bh=this,a8=true;bh.idPrefix="_jsplumb_c_";bh.defaultLabelLocation=0.5;bh.defaultOverlayKeys=["Overlays","ConnectionOverlays"];this.parent=bo.parent;overlayCapableJsPlumbUIComponent.apply(this,arguments);this.isVisible=function(){return a8};this.setVisible=function(bq){a8=bq;if(bh.connector&&bh.connector.canvas){bh.connector.canvas.style.display=bq?"block":"none"}};this.source=A(bo.source);this.target=A(bo.target);if(bo.sourceEndpoint){this.source=bo.sourceEndpoint.endpointWillMoveTo||bo.sourceEndpoint.getElement()}if(bo.targetEndpoint){this.target=bo.targetEndpoint.getElement()}bh.previousConnection=bo.previousConnection;var be=bo.cost;bh.getCost=function(){return be};bh.setCost=function(bq){be=bq};var bc=bo.bidirectional===true;bh.isBidirectional=function(){return bc};this.sourceId=d(this.source,"id");this.targetId=d(this.target,"id");this.getAttachedElements=function(){return bh.endpoints};this.scope=bo.scope;this.endpoints=[];this.endpointStyles=[];var bn=function(br,bq){if(br){return aZ.makeAnchor(br,bq,aZ)}},bl=function(bq,bw,br,bt,bu,bs,bv){if(bq){bh.endpoints[bw]=bq;bq.addConnection(bh)}else{if(!br.endpoints){br.endpoints=[null,null]}var bC=br.endpoints[bw]||br.endpoint||aZ.Defaults.Endpoints[bw]||n.Defaults.Endpoints[bw]||aZ.Defaults.Endpoint||n.Defaults.Endpoint;if(!br.endpointStyles){br.endpointStyles=[null,null]}if(!br.endpointHoverStyles){br.endpointHoverStyles=[null,null]}var bA=br.endpointStyles[bw]||br.endpointStyle||aZ.Defaults.EndpointStyles[bw]||n.Defaults.EndpointStyles[bw]||aZ.Defaults.EndpointStyle||n.Defaults.EndpointStyle;if(bA.fillStyle==null&&bs!=null){bA.fillStyle=bs.strokeStyle}if(bA.outlineColor==null&&bs!=null){bA.outlineColor=bs.outlineColor}if(bA.outlineWidth==null&&bs!=null){bA.outlineWidth=bs.outlineWidth}var bz=br.endpointHoverStyles[bw]||br.endpointHoverStyle||aZ.Defaults.EndpointHoverStyles[bw]||n.Defaults.EndpointHoverStyles[bw]||aZ.Defaults.EndpointHoverStyle||n.Defaults.EndpointHoverStyle;if(bv!=null){if(bz==null){bz={}}if(bz.fillStyle==null){bz.fillStyle=bv.strokeStyle}}var by=br.anchors?br.anchors[bw]:br.anchor?br.anchor:bn(aZ.Defaults.Anchors[bw],bu)||bn(n.Defaults.Anchors[bw],bu)||bn(aZ.Defaults.Anchor,bu)||bn(n.Defaults.Anchor,bu),bB=br.uuids?br.uuids[bw]:null,bx=ao({paintStyle:bA,hoverPaintStyle:bz,endpoint:bC,connections:[bh],uuid:bB,anchor:by,source:bt,container:br.container,reattach:br.reattach,detachable:br.detachable});bh.endpoints[bw]=bx;if(br.drawEndpoints===false){bx.setVisible(false,true,true)}return bx}};var bj=bl(bo.sourceEndpoint,0,bo,bh.source,bh.sourceId,bo.paintStyle,bo.hoverPaintStyle);if(bj){M(az,this.sourceId,bj)}var a9=((bh.sourceId==bh.targetId)&&bo.targetEndpoint==null)?bj:bo.targetEndpoint,bi=bl(a9,1,bo,bh.target,bh.targetId,bo.paintStyle,bo.hoverPaintStyle);if(bi){M(az,this.targetId,bi)}if(!this.scope){this.scope=this.endpoints[0].scope}if(bo.deleteEndpointsOnDetach){bh.endpointsToDeleteOnDetach=[bj,bi]}var a7=aZ.Defaults.ConnectionsDetachable;if(bo.detachable===false){a7=false}if(bh.endpoints[0].connectionsDetachable===false){a7=false}if(bh.endpoints[1].connectionsDetachable===false){a7=false}if(be==null){be=bh.endpoints[0].getConnectionCost()}if(bo.bidirectional==null){bc=bh.endpoints[0].areConnectionsBidirectional()}this.isDetachable=function(){return a7===true};this.setDetachable=function(bq){a7=bq===true};var bp=n.extend({},this.endpoints[0].getParameters());n.extend(bp,this.endpoints[1].getParameters());n.extend(bp,bh.getParameters());bh.setParameters(bp);var bf=bh.setHover;bh.setHover=function(){bh.connector.setHover.apply(bh.connector,arguments);bf.apply(bh,arguments)};var bm=function(bq){if(u==null){bh.setHover(bq,false)}};this.setConnector=function(bq,br){if(bh.connector!=null){aC(bh.connector.getDisplayElements(),bh.parent)}var bs={_jsPlumb:bh._jsPlumb,parent:bo.parent,cssClass:bo.cssClass,container:bo.container,tooltip:bh.tooltip};if(bq.constructor==String){this.connector=new n.Connectors[O][bq](bs)}else{if(bq.constructor==Array){this.connector=new n.Connectors[O][bq[0]](n.extend(bq[1],bs))}}bh.canvas=bh.connector.canvas;_bindListeners(bh.connector,bh,bm);if(!br){bh.repaint()}};bh.setConnector(this.endpoints[0].connector||this.endpoints[1].connector||bo.connector||aZ.Defaults.Connector||n.Defaults.Connector,true);this.setPaintStyle(this.endpoints[0].connectorStyle||this.endpoints[1].connectorStyle||bo.paintStyle||aZ.Defaults.PaintStyle||n.Defaults.PaintStyle,true);this.setHoverPaintStyle(this.endpoints[0].connectorHoverStyle||this.endpoints[1].connectorHoverStyle||bo.hoverPaintStyle||aZ.Defaults.HoverPaintStyle||n.Defaults.HoverPaintStyle,true);this.paintStyleInUse=this.paintStyle;this.moveParent=function(bt){var bs=n.CurrentLibrary,br=bs.getParent(bh.connector.canvas);bs.removeElement(bh.connector.canvas,br);bs.appendElement(bh.connector.canvas,bt);if(bh.connector.bgCanvas){bs.removeElement(bh.connector.bgCanvas,br);bs.appendElement(bh.connector.bgCanvas,bt)}for(var bq=0;bq<bh.overlays.length;bq++){if(bh.overlays[bq].isAppendedAtTopLevel){bs.removeElement(bh.overlays[bq].canvas,br);bs.appendElement(bh.overlays[bq].canvas,bt);if(bh.overlays[bq].reattachListeners){bh.overlays[bq].reattachListeners(bh.connector)}}}if(bh.connector.reattachListeners){bh.connector.reattachListeners()}};N({elId:this.sourceId});N({elId:this.targetId});var bb=X[this.sourceId],ba=U[this.sourceId],a6=X[this.targetId],bd=U[this.targetId],bg=_timestamp(),bk=this.endpoints[0].anchor.compute({xy:[bb.left,bb.top],wh:ba,element:this.endpoints[0],elementId:this.endpoints[0].elementId,txy:[a6.left,a6.top],twh:bd,tElement:this.endpoints[1],timestamp:bg});this.endpoints[0].paint({anchorLoc:bk,timestamp:bg});bk=this.endpoints[1].anchor.compute({xy:[a6.left,a6.top],wh:bd,element:this.endpoints[1],elementId:this.endpoints[1].elementId,txy:[bb.left,bb.top],twh:ba,tElement:this.endpoints[0],timestamp:bg});this.endpoints[1].paint({anchorLoc:bk,timestamp:bg});this.paint=function(bH){bH=bH||{};var by=bH.elId,bz=bH.ui,bw=bH.recalc,br=bH.timestamp,bA=false,bG=bA?this.sourceId:this.targetId,bv=bA?this.targetId:this.sourceId,bs=bA?0:1,bI=bA?1:0;var bJ=N({elId:by,offset:bz,recalc:bw,timestamp:br}),bx=N({elId:bG,timestamp:br});var bC=this.endpoints[bI],bq=this.endpoints[bs],bu=bC.anchor.getCurrentLocation(bC),bF=bq.anchor.getCurrentLocation(bq);var bt=0;for(var bE=0;bE<bh.overlays.length;bE++){var bB=bh.overlays[bE];if(bB.isVisible()){bt=Math.max(bt,bB.computeMaxSize(bh.connector))}}var bD=this.connector.compute(bu,bF,this.endpoints[bI],this.endpoints[bs],this.endpoints[bI].anchor,this.endpoints[bs].anchor,bh.paintStyleInUse.lineWidth,bt,bJ,bx);bh.connector.paint(bD,bh.paintStyleInUse);for(var bE=0;bE<bh.overlays.length;bE++){var bB=bh.overlays[bE];if(bB.isVisible){bh.overlayPlacements[bE]=bB.draw(bh.connector,bh.paintStyleInUse,bD)}}};this.repaint=function(br){br=br||{};var bq=!(br.recalc===false);this.paint({elId:this.sourceId,recalc:bq,timestamp:br.timestamp})};bh.repaint()};var aO=function(a7){var a6=false;return{drag:function(){if(a6){return true}var a8=n.CurrentLibrary.getUIPosition(arguments),a9=a7.element;if(a9){n.CurrentLibrary.setOffset(a9,a8);aM(A(a9),a8)}},stopDrag:function(){a6=true}}};var af=function(ba,a9,bb,a8,a6){var a7=new aG({reference:a9,referenceCanvas:a8});return ao({paintStyle:ba,endpoint:bb,anchor:a7,source:a6,scope:"__floating"})};var J=function(a8,a6){var ba=document.createElement("div");ba.style.position="absolute";var a7=A(ba);aB(ba,a6);var a9=D(a7);N({elId:a9});a8.id=a9;a8.element=a7};var V=function(bA){var bp=this;bp.idPrefix="_jsplumb_e_";bp.defaultLabelLocation=[0.5,0.5];bp.defaultOverlayKeys=["Overlays","EndpointOverlays"];this.parent=bA.parent;overlayCapableJsPlumbUIComponent.apply(this,arguments);bA=bA||{};var ba=true;this.isVisible=function(){return ba};this.setVisible=function(bD,bG,bC){ba=bD;if(bp.canvas){bp.canvas.style.display=bD?"block":"none"}if(!bG){for(var bF=0;bF<bp.connections.length;bF++){bp.connections[bF].setVisible(bD);if(!bC){var bE=bp===bp.connections[bF].endpoints[0]?1:0;if(bp.connections[bF].endpoints[bE].connections.length==1){bp.connections[bF].endpoints[bE].setVisible(bD,true,true)}}}}};var bo=bA.source,bi=bA.uuid,by=null,bc=null;if(bi){aA[bi]=bp}var bf=d(bo,"id");this.elementId=bf;this.element=bo;var a8=bA.connectionCost;this.getConnectionCost=function(){return a8};this.setConnectionCost=function(bC){a8=bC};var bx=bA.connectionsBidirectional===true;this.areConnectionsBidirectional=function(){return bx};this.setConnectionsBidirectional=function(bC){bx=bC};bp.anchor=bA.anchor?aZ.makeAnchor(bA.anchor,bf,aZ):bA.anchors?aZ.makeAnchor(bA.anchors,bf,aZ):aZ.makeAnchor("TopCenter",bf,aZ);if(!bA._transient){aZ.anchorManager.add(bp,bf)}var bm=bA.endpoint||aZ.Defaults.Endpoint||n.Defaults.Endpoint||"Dot",bg={_jsPlumb:bp._jsPlumb,parent:bA.parent,container:bA.container,tooltip:bA.tooltip,connectorTooltip:bA.connectorTooltip,endpoint:bp};if(bm.constructor==String){bm=new n.Endpoints[O][bm](bg)}else{if(bm.constructor==Array){bg=n.extend(bm[1],bg);bm=new n.Endpoints[O][bm[0]](bg)}else{bm=bm.clone()}}var bj=n.extend({},bg);bm.clone=function(){var bC=new Object();bm.constructor.apply(bC,[bj]);return bC};bp.endpoint=bm;bp.type=bp.endpoint.type;var bn=bp.setHover;bp.setHover=function(){bp.endpoint.setHover.apply(bp.endpoint,arguments);bn.apply(bp,arguments)};var bB=function(bC){if(bp.connections.length>0){bp.connections[0].setHover(bC,false)}else{bp.setHover(bC)}};_bindListeners(bp.endpoint,bp,bB);this.setPaintStyle(bA.paintStyle||bA.style||aZ.Defaults.EndpointStyle||n.Defaults.EndpointStyle,true);this.setHoverPaintStyle(bA.hoverPaintStyle||aZ.Defaults.EndpointHoverStyle||n.Defaults.EndpointHoverStyle,true);this.paintStyleInUse=this.paintStyle;this.connectorStyle=bA.connectorStyle;this.connectorHoverStyle=bA.connectorHoverStyle;this.connectorOverlays=bA.connectorOverlays;this.connector=bA.connector;this.connectorTooltip=bA.connectorTooltip;this.isSource=bA.isSource||false;this.isTarget=bA.isTarget||false;var bu=bA.maxConnections||aZ.Defaults.MaxConnections;this.getAttachedElements=function(){return bp.connections};this.canvas=this.endpoint.canvas;this.connections=bA.connections||[];this.scope=bA.scope||I;this.timestamp=null;bp.isReattach=bA.reattach||false;bp.connectionsDetachable=aZ.Defaults.ConnectionsDetachable;if(bA.connectionsDetachable===false||bA.detachable===false){bp.connectionsDetachable=false}var bk=bA.dragAllowedWhenFull||true;this.computeAnchor=function(bC){return bp.anchor.compute(bC)};this.addConnection=function(bC){bp.connections.push(bC)};this.detach=function(bC,bG,bD,bK){var bJ=i(bp.connections,function(bM){return bM.id==bC.id}),bI=false;bK=(bK!==false);if(bJ>=0){if(bD||bC._forceDetach||bC.isDetachable()||bC.isDetachAllowed(bC)){var bL=bC.endpoints[0]==bp?bC.endpoints[1]:bC.endpoints[0];if(bD||bC._forceDetach||(bp.isDetachAllowed(bC))){bp.connections.splice(bJ,1);if(!bG){bL.detach(bC,true,bD);if(bC.endpointsToDeleteOnDetach){for(var bH=0;bH<bC.endpointsToDeleteOnDetach.length;bH++){var bE=bC.endpointsToDeleteOnDetach[bH];if(bE&&bE.connections.length==0){aZ.deleteEndpoint(bE)}}}}aC(bC.connector.getDisplayElements(),bC.parent);y(aD[bC.scope],function(bM){return bM.id==bC.id});bI=true;var bF=(!bG&&bK);aK(bC,bF)}}}return bI};this.detachAll=function(bC){while(bp.connections.length>0){bp.detach(bp.connections[0],false,true,bC)}};this.detachFrom=function(bE,bD){var bF=[];for(var bC=0;bC<bp.connections.length;bC++){if(bp.connections[bC].endpoints[1]==bE||bp.connections[bC].endpoints[0]==bE){bF.push(bp.connections[bC])}}for(var bC=0;bC<bF.length;bC++){if(bp.detach(bF[bC],false,true,bD)){bF[bC].setHover(false,false)}}};this.detachFromConnection=function(bD){var bC=p(bp.connections,bD);if(bC>=0){bp.connections.splice(bC,1)}};this.getElement=function(){return bo};this.setElement=function(bE){var bG=D(bE);y(az[bf],function(bH){return bH.id==bp.id});bo=A(bE);bf=D(bo);bp.elementId=bf;var bF=ai({source:bG}),bD=a9.getParent(bp.canvas);a9.removeElement(bp.canvas,bD);a9.appendElement(bp.canvas,bF);for(var bC=0;bC<bp.connections.length;bC++){bp.connections[bC].moveParent(bF);bp.connections[bC].sourceId=bf;bp.connections[bC].source=bo}M(az,bG,bp);aZ.repaint(bG)};this.getUuid=function(){return bi};this.makeInPlaceCopy=function(){return ao({anchor:bp.anchor,source:bo,paintStyle:this.paintStyle,endpoint:bm,_transient:true,scope:bp.scope})};this.isConnectedTo=function(bE){var bD=false;if(bE){for(var bC=0;bC<bp.connections.length;bC++){if(bp.connections[bC].endpoints[1]==bE){bD=true;break}}}return bD};this.isFloating=function(){return by!=null};this.connectorSelector=function(){var bC=bp.connections[0];if(bp.isTarget&&bC){return bC}else{return(bp.connections.length<bu)||bu==-1?null:bC}};this.isFull=function(){return !(bp.isFloating()||bu<1||bp.connections.length<bu)};this.setDragAllowedWhenFull=function(bC){bk=bC};this.setStyle=bp.setPaintStyle;this.equals=function(bC){return this.anchor.equals(bC.anchor)};var bl=function(bD){var bC=0;if(bD!=null){for(var bE=0;bE<bp.connections.length;bE++){if(bp.connections[bE].sourceId==bD||bp.connections[bE].targetId==bD){bC=bE;break}}}return bp.connections[bC]};this.paint=function(bF){bF=bF||{};var bL=bF.timestamp,bK=!(bF.recalc===false);if(!bL||bp.timestamp!==bL){N({elId:bf,timestamp:bL,recalc:bK});var bR=bF.offset||X[bf];if(bR){var bI=bF.anchorPoint,bG=bF.connectorPaintStyle;if(bI==null){var bC=bF.dimensions||U[bf];if(bR==null||bC==null){N({elId:bf,timestamp:bL});bR=X[bf];bC=U[bf]}var bE={xy:[bR.left,bR.top],wh:bC,element:bp,timestamp:bL};if(bK&&bp.anchor.isDynamic&&bp.connections.length>0){var bO=bl(bF.elementWithPrecedence),bQ=bO.endpoints[0]==bp?1:0,bH=bQ==0?bO.sourceId:bO.targetId,bN=X[bH],bP=U[bH];bE.txy=[bN.left,bN.top];bE.twh=bP;bE.tElement=bO.endpoints[bQ]}bI=bp.anchor.compute(bE)}var bM=bm.compute(bI,bp.anchor.getOrientation(bm),bp.paintStyleInUse,bG||bp.paintStyleInUse);bm.paint(bM,bp.paintStyleInUse,bp.anchor);bp.timestamp=bL;for(var bJ=0;bJ<bp.overlays.length;bJ++){var bD=bp.overlays[bJ];if(bD.isVisible){bp.overlayPlacements[bJ]=bD.draw(bp.endpoint,bp.paintStyleInUse,bM)}}}}};this.repaint=this.paint;this.removeConnection=this.detach;if(n.CurrentLibrary.isDragSupported(bo)){var bt={id:null,element:null},bs=null,a7=false,bb=null,a6=aO(bt);var bd=function(){bs=bp.connectorSelector();var bC=true;if(bs==null&&!bA.isSource){bC=false}if(bA.isSource&&bp.isFull()&&!bk){bC=false}if(bs!=null&&!bs.isDetachable()){bC=false}if(bC===false){if(n.CurrentLibrary.stopDrag){n.CurrentLibrary.stopDrag()}a6.stopDrag();return false}if(bs&&!bp.isFull()&&bA.isSource){bs=null}N({elId:bf});bc=bp.makeInPlaceCopy();bc.paint();J(bt,bp.parent);var bI=A(bc.canvas),bG=n.CurrentLibrary.getOffset(bI),bD=a0([bG.left,bG.top],bc.canvas);n.CurrentLibrary.setOffset(bt.element,{left:bD[0],top:bD[1]});if(bp.parentAnchor){bp.anchor=aZ.makeAnchor(bp.parentAnchor,bp.elementId,aZ)}f(A(bp.canvas),"dragId",bt.id);f(A(bp.canvas),"elId",bf);by=af(bp.paintStyle,bp.anchor,bm,bp.canvas,bt.element);if(bs==null){bp.anchor.locked=true;bp.setHover(false,false);bs=T({sourceEndpoint:bp,targetEndpoint:by,source:bp.endpointWillMoveTo||A(bo),target:bt.element,anchors:[bp.anchor,by.anchor],paintStyle:bA.connectorStyle,hoverPaintStyle:bA.connectorHoverStyle,connector:bA.connector,overlays:bA.connectorOverlays})}else{a7=true;bs.connector.setHover(false,false);be(A(bc.canvas),false,true);var bF=bs.endpoints[0].id==bp.id?0:1;bs.floatingAnchorIndex=bF;bp.detachFromConnection(bs);var bJ=A(bp.canvas),bH=n.CurrentLibrary.getDragScope(bJ);f(bJ,"originalScope",bH);var bE=n.CurrentLibrary.getDropScope(bJ);n.CurrentLibrary.setDragScope(bJ,bE);if(bF==0){bb=[bs.source,bs.sourceId,bw,bH];bs.source=bt.element;bs.sourceId=bt.id}else{bb=[bs.target,bs.targetId,bw,bH];bs.target=bt.element;bs.targetId=bt.id}bs.endpoints[bF==0?1:0].anchor.locked=true;bs.suspendedEndpoint=bs.endpoints[bF];bs.suspendedEndpoint.setHover(false);bs.endpoints[bF]=by}aR[bt.id]=bs;by.addConnection(bs);M(az,bt.id,by);aZ.currentlyDragging=true};var a9=n.CurrentLibrary,bv=bA.dragOptions||{},bq=n.extend({},a9.defaultDragOptions),br=a9.dragEvents.start,bz=a9.dragEvents.stop,bh=a9.dragEvents.drag;bv=n.extend(bq,bv);bv.scope=bv.scope||bp.scope;bv[br]=ab(bv[br],bd);bv[bh]=ab(bv[bh],a6.drag);bv[bz]=ab(bv[bz],function(){aZ.currentlyDragging=false;y(az[bt.id],function(bD){return bD.id==by.id});aC([bt.element[0],by.canvas],bo);ag(bc.canvas,bo);aZ.anchorManager.clearFor(bt.id);var bC=bs.floatingAnchorIndex==null?1:bs.floatingAnchorIndex;bs.endpoints[bC==0?1:0].anchor.locked=false;if(bs.endpoints[bC]==by){if(a7&&bs.suspendedEndpoint){if(bC==0){bs.source=bb[0];bs.sourceId=bb[1]}else{bs.target=bb[0];bs.targetId=bb[1]}n.CurrentLibrary.setDragScope(bb[2],bb[3]);bs.endpoints[bC]=bs.suspendedEndpoint;if(bp.isReattach||bs._forceDetach||!bs.endpoints[bC==0?1:0].detach(bs)){bs.setHover(false);bs.floatingAnchorIndex=null;bs.suspendedEndpoint.addConnection(bs);aZ.repaint(bb[1])}bs._forceDetach=null}else{aC(bs.connector.getDisplayElements(),bp.parent);bp.detachFromConnection(bs)}}bp.anchor.locked=false;bp.paint({recalc:false});bs.setHover(false,false);bs=null;bc=null;delete az[by.elementId];by.anchor=null;by=null;aZ.currentlyDragging=false});var bw=A(bp.canvas);n.CurrentLibrary.initDraggable(bw,bv,true)}var be=function(bG,bJ,bE){if((bA.isTarget||bJ)&&n.CurrentLibrary.isDropSupported(bo)){var bC=bA.dropOptions||aZ.Defaults.DropOptions||n.Defaults.DropOptions;bC=n.extend({},bC);bC.scope=bC.scope||bp.scope;var bH=n.CurrentLibrary.dragEvents.drop,bI=n.CurrentLibrary.dragEvents.over,bD=n.CurrentLibrary.dragEvents.out,bF=function(bK){var bU=A(n.CurrentLibrary.getDragObject(arguments)),bL=d(bU,"dragId"),bN=d(bU,"elId"),bT=d(bU,"originalScope"),bQ=aR[bL],bR=bQ.floatingAnchorIndex==null?1:bQ.floatingAnchorIndex,bS=bR==0?1:0;if(bT){n.CurrentLibrary.setDragScope(bU,bT)}if(!bp.isFull()&&!(bR==0&&!bp.isSource)&&!(bR==1&&!bp.isTarget)){var bO=true;if(bQ.suspendedEndpoint&&bQ.suspendedEndpoint.id!=bp.id){if(!bQ.isDetachAllowed(bQ)||!bQ.endpoints[bR].isDetachAllowed(bQ)||!bQ.suspendedEndpoint.isDetachAllowed(bQ)||!aZ.checkCondition("beforeDetach",bQ)){bO=false}}if(bR==0){bQ.source=bo;bQ.sourceId=bf}else{bQ.target=bo;bQ.targetId=bf}bO=bO&&bp.isDropAllowed(bQ.sourceId,bQ.targetId,bQ.scope);if(bO){bQ.endpoints[bR].detachFromConnection(bQ);if(bQ.suspendedEndpoint){bQ.suspendedEndpoint.detachFromConnection(bQ)}bQ.endpoints[bR]=bp;bp.addConnection(bQ);if(!bQ.suspendedEndpoint){aN(bo,bA.draggable,{})}else{var bP=bQ.suspendedEndpoint.getElement(),bM=bQ.suspendedEndpoint.elementId;aK({source:bR==0?bP:bQ.source,target:bR==1?bP:bQ.target,sourceId:bR==0?bM:bQ.sourceId,targetId:bR==1?bM:bQ.targetId,sourceEndpoint:bR==0?bQ.suspendedEndpoint:bQ.endpoints[0],targetEndpoint:bR==1?bQ.suspendedEndpoint:bQ.endpoints[1],connection:bQ},true)}a4(bQ,null,bK)}else{if(bQ.suspendedEndpoint){bQ.endpoints[bR]=bQ.suspendedEndpoint;bQ.setHover(false);bQ._forceDetach=true;if(bR==0){bQ.source=bQ.suspendedEndpoint.element;bQ.sourceId=bQ.suspendedEndpoint.elementId}else{bQ.target=bQ.suspendedEndpoint.element;bQ.targetId=bQ.suspendedEndpoint.elementId}bQ.suspendedEndpoint.addConnection(bQ);bQ.endpoints[0].repaint();bQ.repaint();aZ.repaint(bQ.source.elementId);bQ._forceDetach=false}}bQ.floatingAnchorIndex=null}aZ.currentlyDragging=false;delete aR[bL]};bC[bH]=ab(bC[bH],bF);bC[bI]=ab(bC[bI],function(){if(bp.isTarget){var bL=n.CurrentLibrary.getDragObject(arguments),bN=d(A(bL),"dragId"),bM=aR[bN];if(bM!=null){var bK=bM.floatingAnchorIndex==null?1:bM.floatingAnchorIndex;bM.endpoints[bK].anchor.over(bp.anchor)}}});bC[bD]=ab(bC[bD],function(){if(bp.isTarget){var bL=n.CurrentLibrary.getDragObject(arguments),bN=d(A(bL),"dragId"),bM=aR[bN];if(bM!=null){var bK=bM.floatingAnchorIndex==null?1:bM.floatingAnchorIndex;bM.endpoints[bK].anchor.out()}}});n.CurrentLibrary.initDroppable(bG,bC,true,bE)}};be(A(bp.canvas),true,!(bA._transient||bp.anchor.isFloating));return bp}};var n=window.jsPlumb=new v();n.getInstance=function(E){var D=new v(E);D.init();return D};n.util={convertStyle:function(E,D){if("transparent"===E){return E}var J=E,I=function(K){return K.length==1?"0"+K:K},F=function(K){return I(Number(K).toString(16))},G=/(rgb[a]?\()(.*)(\))/;if(E.match(G)){var H=E.match(G)[2].split(",");J="#"+F(H[0])+F(H[1])+F(H[2]);if(!D&&H.length==4){J=J+F(H[3])}}return J},gradient:function(E,D){E=E.constructor==Array?E:[E.x,E.y];D=D.constructor==Array?D:[D.x,D.y];return(D[1]-E[1])/(D[0]-E[0])},normal:function(E,D){return -1/n.util.gradient(E,D)},segment:function(E,D){E=E.constructor==Array?E:[E.x,E.y];D=D.constructor==Array?D:[D.x,D.y];if(D[0]>E[0]){return(D[1]>E[1])?2:1}else{return(D[1]>E[1])?3:4}},segmentMultipliers:[null,[1,-1],[1,1],[-1,1],[-1,-1]],inverseSegmentMultipliers:[null,[-1,-1],[-1,1],[1,1],[1,-1]],pointOnLine:function(D,H,E){var G=n.util.gradient(D,H),L=n.util.segment(D,H),K=E>0?n.util.segmentMultipliers[L]:n.util.inverseSegmentMultipliers[L],F=Math.atan(G),I=Math.abs(E*Math.sin(F))*K[1],J=Math.abs(E*Math.cos(F))*K[0];return{x:D.x+J,y:D.y+I}},perpendicularLineTo:function(F,G,H){var E=n.util.gradient(F,G),I=Math.atan(-1/E),J=H/2*Math.sin(I),D=H/2*Math.cos(I);return[{x:G.x+D,y:G.y+J},{x:G.x-D,y:G.y-J}]}};var q=function(D,I,F,E,H,G){return function(K){K=K||{};var J=K.jsPlumbInstance.makeAnchor([D,I,F,E,0,0],K.elementId,K.jsPlumbInstance);J.type=H;if(G){G(J,K)}return J}};n.Anchors.TopCenter=q(0.5,0,0,-1,"TopCenter");n.Anchors.BottomCenter=q(0.5,1,0,1,"BottomCenter");n.Anchors.LeftMiddle=q(0,0.5,-1,0,"LeftMiddle");n.Anchors.RightMiddle=q(1,0.5,1,0,"RightMiddle");n.Anchors.Center=q(0.5,0.5,0,0,"Center");n.Anchors.TopRight=q(1,0,0,-1,"TopRight");n.Anchors.BottomRight=q(1,1,0,1,"BottomRight");n.Anchors.TopLeft=q(0,0,0,-1,"TopLeft");n.Anchors.BottomLeft=q(0,1,0,1,"BottomLeft");n.Defaults.DynamicAnchors=function(D){return D.jsPlumbInstance.makeAnchors(["TopCenter","RightMiddle","BottomCenter","LeftMiddle"],D.elementId,D.jsPlumbInstance)};n.Anchors.AutoDefault=function(E){var D=E.jsPlumbInstance.makeDynamicAnchor(n.Defaults.DynamicAnchors(E));D.type="AutoDefault";return D};n.Anchors.Assign=q(0,0,0,0,"Assign",function(E,F){var D=F.position||"Fixed";E.positionFinder=D.constructor==String?F.jsPlumbInstance.AnchorPositionFinders[D]:D;E.constructorParams=F});n.Anchors.Continuous=function(D){return D.jsPlumbInstance.continuousAnchorFactory.get(D)};n.AnchorPositionFinders={Fixed:function(G,E,F,D){return[(G.left-E.left)/F[0],(G.top-E.top)/F[1]]},Grid:function(D,M,H,E){var L=D.left-M.left,K=D.top-M.top,J=H[0]/(E.constructorParams.grid[0]),I=H[1]/(E.constructorParams.grid[1]),G=Math.floor(L/J),F=Math.floor(K/I);return[((G*J)+(J/2))/H[0],((F*I)+(I/2))/H[1]]}}})();(function(){jsPlumb.DOMElementComponent=function(c){jsPlumb.jsPlumbUIComponent.apply(this,arguments);this.mousemove=this.dblclick=this.click=this.mousedown=this.mouseup=function(d){}};jsPlumb.Connectors.Straight=function(){this.type="Straight";var r=this,i=null,e,k,p,n,l,f,q,h,g,d,c,o,m;this.compute=function(A,J,s,z,F,t,D,v){var I=Math.abs(A[0]-J[0]),C=Math.abs(A[1]-J[1]),B=0.45*I,u=0.45*C;I*=1.9;C*=1.9;var G=Math.min(A[0],J[0])-B;var E=Math.min(A[1],J[1])-u;var H=Math.max(2*D,v);if(I<H){I=H;G=A[0]+((J[0]-A[0])/2)-(H/2);B=(I-Math.abs(A[0]-J[0]))/2}if(C<H){C=H;E=A[1]+((J[1]-A[1])/2)-(H/2);u=(C-Math.abs(A[1]-J[1]))/2}h=A[0]<J[0]?B:I-B;g=A[1]<J[1]?u:C-u;d=A[0]<J[0]?I-B:B;c=A[1]<J[1]?C-u:u;i=[G,E,I,C,h,g,d,c];n=d-h,l=c-g;e=jsPlumb.util.gradient({x:h,y:g},{x:d,y:c}),k=-1/e;p=-1*((e*h)-g);f=Math.atan(e);q=Math.atan(k);m=Math.sqrt((n*n)+(l*l));return i};this.pointOnPath=function(s){if(s==0){return{x:h,y:g}}else{if(s==1){return{x:d,y:c}}else{return jsPlumb.util.pointOnLine({x:h,y:g},{x:d,y:c},s*m)}}};this.gradientAtPoint=function(s){return e};this.pointAlongPathFrom=function(s,u){var t=r.pointOnPath(s);return jsPlumb.util.pointOnLine(t,{x:d,y:c},u)}};jsPlumb.Connectors.Bezier=function(g){var q=this;g=g||{};this.majorAnchor=g.curviness||150;this.minorAnchor=10;var k=null;this.type="Bezier";this._findControlPoint=function(C,r,x,s,v,A,t){var z=A.getOrientation(s),B=t.getOrientation(v),w=z[0]!=B[0]||z[1]==B[1],u=[],D=q.majorAnchor,y=q.minorAnchor;if(!w){if(z[0]==0){u.push(r[0]<x[0]?C[0]+y:C[0]-y)}else{u.push(C[0]-(D*z[0]))}if(z[1]==0){u.push(r[1]<x[1]?C[1]+y:C[1]-y)}else{u.push(C[1]+(D*B[1]))}}else{if(B[0]==0){u.push(x[0]<r[0]?C[0]+y:C[0]-y)}else{u.push(C[0]+(D*B[0]))}if(B[1]==0){u.push(x[1]<r[1]?C[1]+y:C[1]-y)}else{u.push(C[1]+(D*z[1]))}}return u};var p,o,l,d,c,l,h,f,e,n,i;this.compute=function(N,u,H,v,L,s,r,G){r=r||0;n=Math.abs(N[0]-u[0])+r;i=Math.abs(N[1]-u[1])+r;f=Math.min(N[0],u[0])-(r/2);e=Math.min(N[1],u[1])-(r/2);l=N[0]<u[0]?n-(r/2):(r/2);h=N[1]<u[1]?i-(r/2):(r/2);d=N[0]<u[0]?(r/2):n-(r/2);c=N[1]<u[1]?(r/2):i-(r/2);p=q._findControlPoint([l,h],N,u,H,v,L,s);o=q._findControlPoint([d,c],u,N,H,v,s,L);var F=Math.min(l,d),E=Math.min(p[0],o[0]),A=Math.min(F,E),M=Math.max(l,d),J=Math.max(p[0],o[0]),x=Math.max(M,J);if(x>n){n=x}if(A<0){f+=A;var C=Math.abs(A);n+=C;p[0]+=C;l+=C;d+=C;o[0]+=C}var K=Math.min(h,c),I=Math.min(p[1],o[1]),w=Math.min(K,I),B=Math.max(h,c),z=Math.max(p[1],o[1]),t=Math.max(B,z);if(t>i){i=t}if(w<0){e+=w;var y=Math.abs(w);i+=y;p[1]+=y;h+=y;c+=y;o[1]+=y}if(G&&n<G){var D=(G-n)/2;n=G;f-=D;l=l+D;d=d+D;p[0]=p[0]+D;o[0]=o[0]+D}if(G&&i<G){var D=(G-i)/2;i=G;e-=D;h=h+D;c=c+D;p[1]=p[1]+D;o[1]=o[1]+D}k=[f,e,n,i,l,h,d,c,p[0],p[1],o[0],o[1]];return k};var m=function(){return[{x:l,y:h},{x:p[0],y:p[1]},{x:o[0],y:o[1]},{x:d,y:c}]};this.pointOnPath=function(r){return jsBezier.pointOnCurve(m(),r)};this.gradientAtPoint=function(r){return jsBezier.gradientAtPoint(m(),r)};this.pointAlongPathFrom=function(r,s){return jsBezier.pointAlongCurveFrom(m(),r,s)}};jsPlumb.Connectors.Flowchart=function(h){this.type="Flowchart";h=h||{};var p=this,d=h.stub||h.minStubLength||30,k=[],o=0,m=[],c=[],n=[],f,e,i=function(s,r,w,v){var u=0;for(var t=0;t<k.length;t++){c[t]=k[t][5]/o;m[t]=[u,(u+=(k[t][5]/o))]}},q=function(){n.push(k.length);for(var r=0;r<k.length;r++){n.push(k[r][0]);n.push(k[r][1])}},g=function(C,z,B,A,w,v){var s=k.length==0?B:k[k.length-1][0],r=k.length==0?A:k[k.length-1][1],t=C==s?Infinity:0,u=Math.abs(C==s?z-r:C-s);k.push([C,z,s,r,t,u]);o+=u},l=function(t){var r=m.length-1,s=0;for(var u=0;u<m.length;u++){if(m[u][1]>=t){r=u;s=(t-m[u][0])/c[u];break}}return{segment:k[r],proportion:s,index:r}};this.compute=function(Q,ae,r,J,ao,D,O,I,aj,ag){k=[];o=0;c=[];f=ae[0]<Q[0];e=ae[1]<Q[1];var U=O||1,B=(U/2)+(d*2),z=(U/2)+(d*2),G=ao.orientation||ao.getOrientation(r),ap=D.orientation||D.getOrientation(J),ad=f?ae[0]:Q[0],ac=e?ae[1]:Q[1],af=Math.abs(ae[0]-Q[0])+2*B,an=Math.abs(ae[1]-Q[1])+2*z;if(G[0]==0&&G[1]==0||ap[0]==0&&ap[1]==0){var W=af>an?0:1,Y=[1,0][W];G=[];ap=[];G[W]=Q[W]>ae[W]?-1:1;ap[W]=Q[W]>ae[W]?1:-1;G[Y]=0;ap[Y]=0}if(af<I){B+=(I-af)/2;af=I}if(an<I){z+=(I-an)/2;an=I}var A=f?af-B:B,v=e?an-z:z,al=f?B:af-B,ak=e?z:an-z,T=A+(G[0]*d),S=v+(G[1]*d),E=al+(ap[0]*d),C=ak+(ap[1]*d),P=Math.abs(A-al)>2*d,R=Math.abs(v-ak)>2*d,ab=T+((E-T)/2),Z=S+((C-S)/2),H=((G[0]*ap[0])+(G[1]*ap[1])),V=H==-1,X=H==0,s=H==1;ad-=B;ac-=z;n=[ad,ac,af,an,A,v,al,ak];var ai=[];g(T,S,A,v,al,ak);var L=G[0]==0?"y":"x",F=V?"opposite":s?"orthogonal":"perpendicular",t=jsPlumb.util.segment([A,v],[al,ak]),aa=G[L=="x"?0:1]==-1,K={x:[null,4,3,2,1],y:[null,2,1,4,3]};if(aa){t=K[L][t]}var N=function(aq,y,w,x){return aq+(y*((1-w)*x)+d)},u={oppositex:function(){if(r.elementId==J.elementId){var w=S+((1-ao.y)*aj.height)+d;return[[T,w],[E,w]]}else{if(P&&(t==1||t==2)){return[[ab,v],[ab,ak]]}else{return[[T,Z],[E,Z]]}}},orthogonalx:function(){if(t==1||t==2){return[[E,S]]}else{return[[T,C]]}},perpendicularx:function(){var w=(ak+v)/2;if((t==1&&ap[1]==1)||(t==2&&ap[1]==-1)){if(Math.abs(al-A)>d){return[[E,S]]}else{return[[T,S],[T,w],[E,w]]}}else{if((t==3&&ap[1]==-1)||(t==4&&ap[1]==1)){return[[T,w],[E,w]]}else{if((t==3&&ap[1]==1)||(t==4&&ap[1]==-1)){return[[T,C]]}else{if((t==1&&ap[1]==-1)||(t==2&&ap[1]==1)){if(Math.abs(al-A)>d){return[[ab,S],[ab,C]]}else{return[[T,C]]}}}}}},oppositey:function(){if(r.elementId==J.elementId){var w=T+((1-ao.x)*aj.width)+d;return[[w,S],[w,C]]}else{if(R&&(t==2||t==3)){return[[A,Z],[al,Z]]}else{return[[ab,S],[ab,C]]}}},orthogonaly:function(){if(t==2||t==3){return[[T,C]]}else{return[[E,S]]}},perpendiculary:function(){var w=(al+A)/2;if((t==2&&ap[0]==-1)||(t==3&&ap[0]==1)){if(Math.abs(al-A)>d){return[[T,C]]}else{return[[T,Z],[E,Z]]}}else{if((t==1&&ap[0]==-1)||(t==4&&ap[0]==1)){var w=(al+A)/2;return[[w,S],[w,C]]}else{if((t==1&&ap[0]==1)||(t==4&&ap[0]==-1)){return[[E,S]]}else{if((t==2&&ap[0]==1)||(t==3&&ap[0]==-1)){if(Math.abs(ak-v)>d){return[[T,Z],[E,Z]]}else{return[[E,S]]}}}}}}};var M=u[F+L];var ah=M();if(ah){for(var am=0;am<ah.length;am++){g(ah[am][0],ah[am][1],A,v,al,ak)}}g(E,C,A,v,al,ak);g(al,ak,A,v,al,ak);q();i(A,v,al,ak);return n};this.pointOnPath=function(r){return p.pointAlongPathFrom(r,0)};this.gradientAtPoint=function(r){return k[l(r)["index"]][4]};this.pointAlongPathFrom=function(v,z){var w=l(v),u=w.segment,y=w.proportion,t=k[w.index][5],r=k[w.index][4];var x={x:r==Infinity?u[2]:u[2]>u[0]?u[0]+((1-y)*t)-z:u[2]+(y*t)+z,y:r==0?u[3]:u[3]>u[1]?u[1]+((1-y)*t)-z:u[3]+(y*t)+z,segmentInfo:w};return x}};jsPlumb.Endpoints.Dot=function(d){this.type="Dot";var c=this;d=d||{};this.radius=d.radius||10;this.defaultOffset=0.5*this.radius;this.defaultInnerRadius=this.radius/3;this.compute=function(i,f,l,h){var g=l.radius||c.radius,e=i[0]-g,k=i[1]-g;return[e,k,g*2,g*2,g]}};jsPlumb.Endpoints.Rectangle=function(d){this.type="Rectangle";var c=this;d=d||{};this.width=d.width||20;this.height=d.height||20;this.compute=function(k,g,m,i){var h=m.width||c.width,f=m.height||c.height,e=k[0]-(h/2),l=k[1]-(f/2);return[e,l,h,f]}};var a=function(e){jsPlumb.DOMElementComponent.apply(this,arguments);var c=this;var d=[];this.getDisplayElements=function(){return d};this.appendDisplayElement=function(f){d.push(f)}};jsPlumb.Endpoints.Image=function(g){this.type="Image";a.apply(this,arguments);var l=this,f=false,e=g.width,d=g.height,i=null,c=g.endpoint;this.img=new Image();l.ready=false;this.img.onload=function(){l.ready=true;e=e||l.img.width;d=d||l.img.height;if(i){i(l)}};c.setImage=function(m,o){var n=m.constructor==String?m:m.src;i=o;l.img.src=m};c.setImage(g.src||g.url,g.onload);this.compute=function(o,m,p,n){l.anchorPoint=o;if(l.ready){return[o[0]-e/2,o[1]-d/2,e,d]}else{return[0,0,0,0]}};l.canvas=document.createElement("img"),f=false;l.canvas.style.margin=0;l.canvas.style.padding=0;l.canvas.style.outline=0;l.canvas.style.position="absolute";var h=g.cssClass?" "+g.cssClass:"";l.canvas.className=jsPlumb.endpointClass+h;if(e){l.canvas.setAttribute("width",e)}if(d){l.canvas.setAttribute("height",d)}jsPlumb.appendElement(l.canvas,g.parent);l.attachListeners(l.canvas,l);var k=function(p,o,n){if(!f){l.canvas.setAttribute("src",l.img.src);f=true}var m=l.anchorPoint[0]-(e/2),q=l.anchorPoint[1]-(d/2);jsPlumb.sizeCanvas(l.canvas,m,q,e,d)};this.paint=function(o,n,m){if(l.ready){k(o,n,m)}else{window.setTimeout(function(){l.paint(o,n,m)},200)}}};jsPlumb.Endpoints.Blank=function(d){var c=this;this.type="Blank";a.apply(this,arguments);this.compute=function(g,e,h,f){return[g[0],g[1],10,0]};c.canvas=document.createElement("div");c.canvas.style.display="block";c.canvas.style.width="1px";c.canvas.style.height="1px";c.canvas.style.background="transparent";c.canvas.style.position="absolute";c.canvas.className=c._jsPlumb.endpointClass;jsPlumb.appendElement(c.canvas,d.parent);this.paint=function(g,f,e){jsPlumb.sizeCanvas(c.canvas,g[0],g[1],g[2],g[3])}};jsPlumb.Endpoints.Triangle=function(c){this.type="Triangle";c=c||{};c.width=c.width||55;c.height=c.height||55;this.width=c.width;this.height=c.height;this.compute=function(i,f,l,h){var g=l.width||self.width,e=l.height||self.height,d=i[0]-(g/2),k=i[1]-(e/2);return[d,k,g,e]}};var b=function(e){var d=true,c=this;this.isAppendedAtTopLevel=true;this.component=e.component;this.loc=e.location==null?0.5:e.location;this.endpointLoc=e.endpointLocation==null?[0.5,0.5]:e.endpointLocation;this.setVisible=function(f){d=f;c.component.repaint()};this.isVisible=function(){return d};this.hide=function(){c.setVisible(false)};this.show=function(){c.setVisible(true)};this.incrementLocation=function(f){c.loc+=f;c.component.repaint()};this.setLocation=function(f){c.loc=f;c.component.repaint()};this.getLocation=function(){return c.loc}};jsPlumb.Overlays.Arrow=function(g){this.type="Arrow";b.apply(this,arguments);this.isAppendedAtTopLevel=false;g=g||{};var d=this;this.length=g.length||20;this.width=g.width||20;this.id=g.id;var f=(g.direction||1)<0?-1:1,e=g.paintStyle||{lineWidth:1},c=g.foldback||0.623;this.computeMaxSize=function(){return d.width*1.5};this.cleanup=function(){};this.draw=function(i,x,s){var m,t,h,n,l;if(i.pointAlongPathFrom){if(d.loc==1){m=i.pointOnPath(d.loc);t=i.pointAlongPathFrom(d.loc,-1);h=jsPlumb.util.pointOnLine(m,t,d.length)}else{if(d.loc==0){h=i.pointOnPath(d.loc);t=i.pointAlongPathFrom(d.loc,1);m=jsPlumb.util.pointOnLine(h,t,d.length)}else{m=i.pointAlongPathFrom(d.loc,f*d.length/2),t=i.pointOnPath(d.loc),h=jsPlumb.util.pointOnLine(m,t,d.length)}}n=jsPlumb.util.perpendicularLineTo(m,h,d.width);l=jsPlumb.util.pointOnLine(m,h,c*d.length);var w=Math.min(m.x,n[0].x,n[1].x),q=Math.max(m.x,n[0].x,n[1].x),v=Math.min(m.y,n[0].y,n[1].y),p=Math.max(m.y,n[0].y,n[1].y);var o={hxy:m,tail:n,cxy:l},r=e.strokeStyle||x.strokeStyle,u=e.fillStyle||x.strokeStyle,k=e.lineWidth||x.lineWidth;d.paint(i,o,k,r,u,s);return[w,q,v,p]}else{return[0,0,0,0]}}};jsPlumb.Overlays.PlainArrow=function(d){d=d||{};var c=jsPlumb.extend(d,{foldback:1});jsPlumb.Overlays.Arrow.call(this,c);this.type="PlainArrow"};jsPlumb.Overlays.Diamond=function(e){e=e||{};var c=e.length||40,d=jsPlumb.extend(e,{length:c/2,foldback:2});jsPlumb.Overlays.Arrow.call(this,d);this.type="Diamond"};jsPlumb.Overlays.Label=function(i){this.type="Label";jsPlumb.DOMElementComponent.apply(this,arguments);b.apply(this,arguments);this.labelStyle=i.labelStyle||jsPlumb.Defaults.LabelStyle;this.id=i.id;this.cachedDimensions=null;var e=i.label||"",c=this,f=false,k=document.createElement("div"),g=null;k.style.position="absolute";var d=i._jsPlumb.overlayClass+" "+(c.labelStyle.cssClass?c.labelStyle.cssClass:i.cssClass?i.cssClass:"");k.className=d;jsPlumb.appendElement(k,i.component.parent);jsPlumb.getId(k);c.attachListeners(k,c);c.canvas=k;var h=c.setVisible;c.setVisible=function(l){h(l);k.style.display=l?"block":"none"};this.getElement=function(){return k};this.cleanup=function(){if(k!=null){jsPlumb.CurrentLibrary.removeElement(k)}};this.setLabel=function(m){e=m;g=null;c.component.repaint()};this.getLabel=function(){return e};this.paint=function(l,n,m){if(!f){l.appendDisplayElement(k);c.attachListeners(k,l);f=true}k.style.left=(m[0]+n.minx)+"px";k.style.top=(m[1]+n.miny)+"px"};this.getTextDimensions=function(){if(typeof e=="function"){var l=e(c);k.innerHTML=l.replace(/\r\n/g,"<br/>")}else{if(g==null){g=e;k.innerHTML=g.replace(/\r\n/g,"<br/>")}}var n=jsPlumb.CurrentLibrary.getElementObject(k),m=jsPlumb.CurrentLibrary.getSize(n);return{width:m[0],height:m[1]}};this.computeMaxSize=function(l){var m=c.getTextDimensions(l);return m.width?Math.max(m.width,m.height)*1.5:0};this.draw=function(m,n,o){var q=c.getTextDimensions(m);if(q.width!=null){var p={x:0,y:0};if(m.pointOnPath){p=m.pointOnPath(c.loc)}else{var l=c.loc.constructor==Array?c.loc:c.endpointLoc;p={x:l[0]*o[2],y:l[1]*o[3]}}minx=p.x-(q.width/2),miny=p.y-(q.height/2);c.paint(m,{minx:minx,miny:miny,td:q,cxy:p},o);return[minx,minx+q.width,miny,miny+q.height]}else{return[0,0,0,0]}};this.reattachListeners=function(l){if(k){c.reattachListenersForElement(k,c,l)}}};jsPlumb.Overlays.GuideLines=function(){var c=this;c.length=50;c.lineWidth=5;this.type="GuideLines";b.apply(this,arguments);jsPlumb.jsPlumbUIComponent.apply(this,arguments);this.draw=function(e,l,k){var i=e.pointAlongPathFrom(c.loc,c.length/2),h=e.pointOnPath(c.loc),g=jsPlumb.util.pointOnLine(i,h,c.length),f=jsPlumb.util.perpendicularLineTo(i,g,40),d=jsPlumb.util.perpendicularLineTo(g,i,20);c.paint(e,[i,g,f,d],c.lineWidth,"red",null,k);return[Math.min(i.x,g.x),Math.min(i.y,g.y),Math.max(i.x,g.x),Math.max(i.y,g.y)]};this.computeMaxSize=function(){return 50};this.cleanup=function(){}}})();(function(){var c=function(e,g,d,f){this.m=(f-g)/(d-e);this.b=-1*((this.m*e)-g);this.rectIntersect=function(q,p,s,o){var n=[];var k=(p-this.b)/this.m;if(k>=q&&k<=(q+s)){n.push([k,(this.m*k)+this.b])}var t=(this.m*(q+s))+this.b;if(t>=p&&t<=(p+o)){n.push([(t-this.b)/this.m,t])}var k=((p+o)-this.b)/this.m;if(k>=q&&k<=(q+s)){n.push([k,(this.m*k)+this.b])}var t=(this.m*q)+this.b;if(t>=p&&t<=(p+o)){n.push([(t-this.b)/this.m,t])}if(n.length==2){var m=(n[0][0]+n[1][0])/2,l=(n[0][1]+n[1][1])/2;n.push([m,l]);var i=m<=q+(s/2)?-1:1,r=l<=p+(o/2)?-1:1;n.push([i,r]);return n}return null}},a=function(e,g,d,f){if(e<=d&&f<=g){return 1}else{if(e<=d&&g<=f){return 2}else{if(d<=e&&f>=g){return 3}}}return 4},b=function(g,f,i,e,h,m,l,d,k){if(d<=k){return[g,f]}if(i==1){if(e[3]<=0&&h[3]>=1){return[g+(e[2]<0.5?-1*m:m),f]}else{if(e[2]>=1&&h[2]<=0){return[g,f+(e[3]<0.5?-1*l:l)]}else{return[g+(-1*m),f+(-1*l)]}}}else{if(i==2){if(e[3]>=1&&h[3]<=0){return[g+(e[2]<0.5?-1*m:m),f]}else{if(e[2]>=1&&h[2]<=0){return[g,f+(e[3]<0.5?-1*l:l)]}else{return[g+(1*m),f+(-1*l)]}}}else{if(i==3){if(e[3]>=1&&h[3]<=0){return[g+(e[2]<0.5?-1*m:m),f]}else{if(e[2]<=0&&h[2]>=1){return[g,f+(e[3]<0.5?-1*l:l)]}else{return[g+(-1*m),f+(-1*l)]}}}else{if(i==4){if(e[3]<=0&&h[3]>=1){return[g+(e[2]<0.5?-1*m:m),f]}else{if(e[2]<=0&&h[2]>=1){return[g,f+(e[3]<0.5?-1*l:l)]}else{return[g+(1*m),f+(-1*l)]}}}}}}};jsPlumb.Connectors.StateMachine=function(l){var s=this,n=null,o,m,g,e,p=[],d=l.curviness||10,k=l.margin||5,q=l.proximityLimit||80,f=l.orientation&&l.orientation=="clockwise",i=l.loopbackRadius||25,h=false;this.type="StateMachine";l=l||{};this.compute=function(ab,F,U,G,aa,u,t,S){var O=Math.abs(ab[0]-F[0]),W=Math.abs(ab[1]-F[1]),Q=0.45*O,Z=0.45*W;O*=1.9;W*=1.9;t=t||1;var M=Math.min(ab[0],F[0])-Q,K=Math.min(ab[1],F[1])-Z;if(U.elementId!=G.elementId){h=false;o=ab[0]<F[0]?Q:O-Q;m=ab[1]<F[1]?Z:W-Z;g=ab[0]<F[0]?O-Q:Q;e=ab[1]<F[1]?W-Z:Z;if(ab[2]==0){o-=k}if(ab[2]==1){o+=k}if(ab[3]==0){m-=k}if(ab[3]==1){m+=k}if(F[2]==0){g-=k}if(F[2]==1){g+=k}if(F[3]==0){e-=k}if(F[3]==1){e+=k}var L=(o+g)/2,J=(m+e)/2,v=(-1*L)/J,T=Math.atan(v),N=(v==Infinity||v==-Infinity)?0:Math.abs(d/2*Math.sin(T)),P=(v==Infinity||v==-Infinity)?0:Math.abs(d/2*Math.cos(T)),z=a(o,m,g,e),H=Math.sqrt(Math.pow(g-o,2)+Math.pow(e-m,2));p=b(L,J,z,ab,F,d,d,H,q);var E=Math.max(Math.abs(p[0]-o)*3,Math.abs(p[0]-g)*3,Math.abs(g-o),2*t,S),I=Math.max(Math.abs(p[1]-m)*3,Math.abs(p[1]-e)*3,Math.abs(e-m),2*t,S);if(O<E){var R=E-O;M-=(R/2);o+=(R/2);g+=(R/2);O=E;p[0]+=(R/2)}if(W<I){var Y=I-W;K-=(Y/2);m+=(Y/2);e+=(Y/2);W=I;p[1]+=(Y/2)}n=[M,K,O,W,o,m,g,e,p[0],p[1]]}else{h=true;var X=ab[0],V=ab[0],D=ab[1]-k,B=ab[1]-k,C=X,A=D-i;O=((2*t)+(4*i)),W=((2*t)+(4*i));M=C-i-t-i,K=A-i-t-i;n=[M,K,O,W,C-M,A-K,i,f,X-M,D-K,V-M,B-K]}return n};var r=function(){return[{x:g,y:e},{x:p[0],y:p[1]},{x:p[0]+1,y:p[1]+1},{x:o,y:m}]};this.pointOnPath=function(v){if(h){if(v>0&&v<1){v=1-v}var w=(v*2*Math.PI)+(Math.PI/2),u=n[4]+(n[6]*Math.cos(w)),t=n[5]+(n[6]*Math.sin(w));return{x:u,y:t}}else{return jsBezier.pointOnCurve(r(),v)}};this.gradientAtPoint=function(t){if(h){return Math.atan(t*2*Math.PI)}else{return jsBezier.gradientAtPoint(r(),t)}};this.pointAlongPathFrom=function(v,z){if(h){if(v>0&&v<1){v=1-v}var w=2*Math.PI*n[6],y=z/w*2*Math.PI,x=(v*2*Math.PI)-y+(Math.PI/2),u=n[4]+(n[6]*Math.cos(x)),t=n[5]+(n[6]*Math.sin(x));return{x:u,y:t}}return jsBezier.pointAlongCurveFrom(r(),v,z)}};jsPlumb.Connectors.canvas.StateMachine=function(f){f=f||{};var d=this,g=f.drawGuideline||true,e=f.avoidSelector;jsPlumb.Connectors.StateMachine.apply(this,arguments);jsPlumb.CanvasConnector.apply(this,arguments);this._paint=function(l){if(l.length==10){d.ctx.beginPath();d.ctx.moveTo(l[4],l[5]);d.ctx.quadraticCurveTo(l[8],l[9],l[6],l[7]);d.ctx.stroke()}else{d.ctx.save();d.ctx.beginPath();var k=0,i=2*Math.PI,h=l[7];d.ctx.arc(l[4],l[5],l[6],0,i,h);d.ctx.stroke();d.ctx.closePath();d.ctx.restore()}};this.createGradient=function(i,h){return h.createLinearGradient(i[4],i[5],i[6],i[7])}};jsPlumb.Connectors.svg.StateMachine=function(){var d=this;jsPlumb.Connectors.StateMachine.apply(this,arguments);jsPlumb.SvgConnector.apply(this,arguments);this.getPath=function(e){if(e.length==10){return"M "+e[4]+" "+e[5]+" C "+e[8]+" "+e[9]+" "+e[8]+" "+e[9]+" "+e[6]+" "+e[7]}else{return"M"+(e[8]+4)+" "+e[9]+" A "+e[6]+" "+e[6]+" 0 1,0 "+(e[8]-4)+" "+e[9]}}};jsPlumb.Connectors.vml.StateMachine=function(){jsPlumb.Connectors.StateMachine.apply(this,arguments);jsPlumb.VmlConnector.apply(this,arguments);var d=jsPlumb.vml.convertValue;this.getPath=function(k){if(k.length==10){return"m"+d(k[4])+","+d(k[5])+" c"+d(k[8])+","+d(k[9])+","+d(k[8])+","+d(k[9])+","+d(k[6])+","+d(k[7])+" e"}else{var h=d(k[8]-k[6]),g=d(k[9]-(2*k[6])),f=h+d(2*k[6]),e=g+d(2*k[6]),l=h+","+g+","+f+","+e;var i="ar "+l+","+d(k[8])+","+d(k[9])+","+d(k[8])+","+d(k[9])+" e";return i}}}})();(function(){var k={"stroke-linejoin":"joinstyle",joinstyle:"joinstyle",endcap:"endcap",miterlimit:"miterlimit"};if(document.createStyleSheet){document.createStyleSheet().addRule(".jsplumb_vml","behavior:url(#default#VML);position:absolute;");document.createStyleSheet().addRule("jsplumb\\:textbox","behavior:url(#default#VML);position:absolute;");document.createStyleSheet().addRule("jsplumb\\:oval","behavior:url(#default#VML);position:absolute;");document.createStyleSheet().addRule("jsplumb\\:rect","behavior:url(#default#VML);position:absolute;");document.createStyleSheet().addRule("jsplumb\\:stroke","behavior:url(#default#VML);position:absolute;");document.createStyleSheet().addRule("jsplumb\\:shape","behavior:url(#default#VML);position:absolute;");document.createStyleSheet().addRule("jsplumb\\:group","behavior:url(#default#VML);position:absolute;");document.namespaces.add("jsplumb","urn:schemas-microsoft-com:vml")}jsPlumb.vml={};var b=1000,d={},h=function(q,p){var s=jsPlumb.getId(q),r=d[s];if(!r){r=o("group",[0,0,b,b],{"class":p});r.style.backgroundColor="red";d[s]=r;jsPlumb.appendElement(r,q)}return r},c=function(q,r){for(var p in r){q[p]=r[p]}},o=function(p,r,s){s=s||{};var q=document.createElement("jsplumb:"+p);q.className=(s["class"]?s["class"]+" ":"")+"jsplumb_vml";n(q,r);c(q,s);return q},n=function(q,p){q.style.left=p[0]+"px";q.style.top=p[1]+"px";q.style.width=p[2]+"px";q.style.height=p[3]+"px";q.style.position="absolute"},i=jsPlumb.vml.convertValue=function(p){return Math.floor(p*b)},e=function(s,q,r,p){if("transparent"===q){p.setOpacity(r,"0.0")}else{p.setOpacity(r,"1.0")}},g=function(t,p,w){var s={};if(p.strokeStyle){s.stroked="true";var x=jsPlumb.util.convertStyle(p.strokeStyle,true);s.strokecolor=x;e(s,x,"stroke",w);s.strokeweight=p.lineWidth+"px"}else{s.stroked="false"}if(p.fillStyle){s.filled="true";var q=jsPlumb.util.convertStyle(p.fillStyle,true);s.fillcolor=q;e(s,q,"fill",w)}else{s.filled="false"}if(p.dashstyle){if(w.strokeNode==null){w.strokeNode=o("stroke",[0,0,0,0],{dashstyle:p.dashstyle});t.appendChild(w.strokeNode)}else{w.strokeNode.dashstyle=p.dashstyle}}else{if(p["stroke-dasharray"]&&p.lineWidth){var y=p["stroke-dasharray"].indexOf(",")==-1?" ":",",u=p["stroke-dasharray"].split(y),r="";for(var v=0;v<u.length;v++){r+=(Math.floor(u[v]/p.lineWidth)+y)}if(w.strokeNode==null){w.strokeNode=o("stroke",[0,0,0,0],{dashstyle:r});t.appendChild(w.strokeNode)}else{w.strokeNode.dashstyle=r}}}c(t,s)},l=function(){var p=this;jsPlumb.jsPlumbUIComponent.apply(this,arguments);this.opacityNodes={stroke:null,fill:null};this.initOpacityNodes=function(r){p.opacityNodes.stroke=o("stroke",[0,0,1,1],{opacity:"0.0"});p.opacityNodes.fill=o("fill",[0,0,1,1],{opacity:"0.0"});r.appendChild(p.opacityNodes.stroke);r.appendChild(p.opacityNodes.fill)};this.setOpacity=function(r,t){var s=p.opacityNodes[r];if(s){s.opacity=""+t}};var q=[];this.getDisplayElements=function(){return q};this.appendDisplayElement=function(s,r){if(!r){p.canvas.parentNode.appendChild(s)}q.push(s)}},f=jsPlumb.VmlConnector=function(r){var p=this;p.strokeNode=null;p.canvas=null;l.apply(this,arguments);var q=p._jsPlumb.connectorClass+(r.cssClass?(" "+r.cssClass):"");this.paint=function(w,t,v){if(t!=null){var A=p.getPath(w),u={path:A};if(t.outlineColor){var y=t.outlineWidth||1,z=t.lineWidth+(2*y),x={strokeStyle:jsPlumb.util.convertStyle(t.outlineColor),lineWidth:z};for(var s in k){x[s]=t[s]}if(p.bgCanvas==null){u["class"]=q;u.coordsize=(w[2]*b)+","+(w[3]*b);p.bgCanvas=o("shape",w,u);jsPlumb.appendElement(p.bgCanvas,r.parent);n(p.bgCanvas,w);p.appendDisplayElement(p.bgCanvas,true)}else{u.coordsize=(w[2]*b)+","+(w[3]*b);n(p.bgCanvas,w);c(p.bgCanvas,u)}g(p.bgCanvas,x,p)}if(p.canvas==null){u["class"]=q;u.coordsize=(w[2]*b)+","+(w[3]*b);if(p.tooltip){u.label=p.tooltip}p.canvas=o("shape",w,u);jsPlumb.appendElement(p.canvas,r.parent);p.appendDisplayElement(p.canvas,true);p.attachListeners(p.canvas,p);p.initOpacityNodes(p.canvas,["stroke"])}else{u.coordsize=(w[2]*b)+","+(w[3]*b);n(p.canvas,w);c(p.canvas,u)}g(p.canvas,t,p)}};this.reattachListeners=function(){if(p.canvas){p.reattachListenersForElement(p.canvas,p)}}},m=function(t){l.apply(this,arguments);var p=null,r=this,q=null,s=null;r.canvas=document.createElement("div");r.canvas.style.position="absolute";jsPlumb.appendElement(r.canvas,t.parent);if(r.tooltip){r.canvas.setAttribute("label",r.tooltip)}this.paint=function(x,v,u){var w={};jsPlumb.sizeCanvas(r.canvas,x[0],x[1],x[2],x[3]);if(p==null){w["class"]=jsPlumb.endpointClass;p=r.getVml([0,0,x[2],x[3]],w,u);r.canvas.appendChild(p);r.attachListeners(p,r);r.appendDisplayElement(p,true);r.appendDisplayElement(r.canvas,true);r.initOpacityNodes(p,["fill"])}else{n(p,[0,0,x[2],x[3]]);c(p,w)}g(p,v,r)};this.reattachListeners=function(){if(p){r.reattachListenersForElement(p,r)}}};jsPlumb.Connectors.vml.Bezier=function(){jsPlumb.Connectors.Bezier.apply(this,arguments);f.apply(this,arguments);this.getPath=function(p){return"m"+i(p[4])+","+i(p[5])+" c"+i(p[8])+","+i(p[9])+","+i(p[10])+","+i(p[11])+","+i(p[6])+","+i(p[7])+" e"}};jsPlumb.Connectors.vml.Straight=function(){jsPlumb.Connectors.Straight.apply(this,arguments);f.apply(this,arguments);this.getPath=function(p){return"m"+i(p[4])+","+i(p[5])+" l"+i(p[6])+","+i(p[7])+" e"}};jsPlumb.Connectors.vml.Flowchart=function(){jsPlumb.Connectors.Flowchart.apply(this,arguments);f.apply(this,arguments);this.getPath=function(r){var s="m "+i(r[4])+","+i(r[5])+" l";for(var q=0;q<r[8];q++){s=s+" "+i(r[9+(q*2)])+","+i(r[10+(q*2)])}s=s+" "+i(r[6])+","+i(r[7])+" e";return s}};jsPlumb.Endpoints.vml.Dot=function(){jsPlumb.Endpoints.Dot.apply(this,arguments);m.apply(this,arguments);this.getVml=function(q,r,p){return o("oval",q,r)}};jsPlumb.Endpoints.vml.Rectangle=function(){jsPlumb.Endpoints.Rectangle.apply(this,arguments);m.apply(this,arguments);this.getVml=function(q,r,p){return o("rect",q,r)}};jsPlumb.Endpoints.vml.Image=jsPlumb.Endpoints.Image;jsPlumb.Endpoints.vml.Blank=jsPlumb.Endpoints.Blank;jsPlumb.Overlays.vml.Label=jsPlumb.Overlays.Label;var a=function(t,r){t.apply(this,r);l.apply(this,arguments);var q=this,s=null;q.canvas=null;var p=function(v,u){return"m "+i(v.hxy.x)+","+i(v.hxy.y)+" l "+i(v.tail[0].x)+","+i(v.tail[0].y)+" "+i(v.cxy.x)+","+i(v.cxy.y)+" "+i(v.tail[1].x)+","+i(v.tail[1].y)+" x e"};this.paint=function(y,D,C,E,I,H){var v={};if(E){v.stroked="true";v.strokecolor=jsPlumb.util.convertStyle(E,true)}if(C){v.strokeweight=C+"px"}if(I){v.filled="true";v.fillcolor=I}var u=Math.min(D.hxy.x,D.tail[0].x,D.tail[1].x,D.cxy.x),G=Math.min(D.hxy.y,D.tail[0].y,D.tail[1].y,D.cxy.y),z=Math.max(D.hxy.x,D.tail[0].x,D.tail[1].x,D.cxy.x),x=Math.max(D.hxy.y,D.tail[0].y,D.tail[1].y,D.cxy.y),F=Math.abs(z-u),B=Math.abs(x-G),A=[u,G,F,B];v.path=p(D,H);v.coordsize=(H[2]*b)+","+(H[3]*b);A[0]=H[0];A[1]=H[1];A[2]=H[2];A[3]=H[3];if(q.canvas==null){q.canvas=o("shape",A,v);y.appendDisplayElement(q.canvas);q.attachListeners(q.canvas,y)}else{n(q.canvas,A);c(q.canvas,v)}};this.reattachListeners=function(){if(q.canvas){q.reattachListenersForElement(q.canvas,q)}}};jsPlumb.Overlays.vml.Arrow=function(){a.apply(this,[jsPlumb.Overlays.Arrow,arguments])};jsPlumb.Overlays.vml.PlainArrow=function(){a.apply(this,[jsPlumb.Overlays.PlainArrow,arguments])};jsPlumb.Overlays.vml.Diamond=function(){a.apply(this,[jsPlumb.Overlays.Diamond,arguments])}})();(function(){var l={joinstyle:"stroke-linejoin","stroke-linejoin":"stroke-linejoin","stroke-dashoffset":"stroke-dashoffset","stroke-linecap":"stroke-linecap"},w="stroke-dasharray",A="dashstyle",e="linearGradient",b="radialGradient",c="fill",a="stop",z="stroke",q="stroke-width",h="style",m="none",t="jsplumb_gradient_",o="lineWidth",C={svg:"http://www.w3.org/2000/svg",xhtml:"http://www.w3.org/1999/xhtml"},g=function(F,D){for(var E in D){F.setAttribute(E,""+D[E])}},f=function(E,D){var F=document.createElementNS(C.svg,E);D=D||{};D.version="1.1";D.xmnls=C.xhtml;g(F,D);return F},n=function(D){return"position:absolute;left:"+D[0]+"px;top:"+D[1]+"px"},i=function(E){for(var D=0;D<E.childNodes.length;D++){if(E.childNodes[D].tagName==e||E.childNodes[D].tagName==b){E.removeChild(E.childNodes[D])}}},v=function(N,I,F,D,J){var G=t+J._jsPlumb.idstamp();i(N);if(!F.gradient.offset){var L=f(e,{id:G});N.appendChild(L)}else{var L=f(b,{id:G});N.appendChild(L)}for(var K=0;K<F.gradient.stops.length;K++){var H=K;if(D.length==8){H=D[4]<D[6]?K:F.gradient.stops.length-1-K}else{H=D[4]<D[6]?F.gradient.stops.length-1-K:K}var M=jsPlumb.util.convertStyle(F.gradient.stops[H][1],true);var O=f(a,{offset:Math.floor(F.gradient.stops[K][0]*100)+"%","stop-color":M});L.appendChild(O)}var E=F.strokeStyle?z:c;I.setAttribute(h,E+":url(#"+G+")")},x=function(K,G,E,D,H){if(E.gradient){v(K,G,E,D,H)}else{i(K);G.setAttribute(h,"")}G.setAttribute(c,E.fillStyle?jsPlumb.util.convertStyle(E.fillStyle,true):m);G.setAttribute(z,E.strokeStyle?jsPlumb.util.convertStyle(E.strokeStyle,true):m);if(E.lineWidth){G.setAttribute(q,E.lineWidth)}if(E[A]&&E[o]&&!E[w]){var L=E[A].indexOf(",")==-1?" ":",",I=E[A].split(L),F="";I.forEach(function(M){F+=(Math.floor(M*E.lineWidth)+L)});G.setAttribute(w,F)}else{if(E[w]){G.setAttribute(w,E[w])}}for(var J in l){if(E[J]){G.setAttribute(l[J],E[J])}}},B=function(F){var D=/([0-9].)(p[xt])\s(.*)/;var E=F.match(D);return{size:E[1]+E[2],font:E[3]}},r=function(I,J,E){var K=E.split(" "),H=I.className,G=H.baseVal.split(" ");for(var F=0;F<K.length;F++){if(J){if(G.indexOf(K[F])==-1){G.push(K[F])}}else{var D=G.indexOf(K[F]);if(D!=-1){G.splice(D,1)}}}I.className.baseVal=G.join(" ")},u=function(E,D){r(E,true,D)},k=function(E,D){r(E,false,D)};jsPlumb.util.svg={addClass:u,removeClass:k};var s=function(H){var D=this,G=H.pointerEventsSpec||"all";jsPlumb.jsPlumbUIComponent.apply(this,H.originalArgs);D.canvas=null,D.path=null,D.svg=null;var F=H.cssClass+" "+(H.originalArgs[0].cssClass||""),I={style:"",width:0,height:0,"pointer-events":G,position:"absolute"};if(D.tooltip){I.title=D.tooltip}D.svg=f("svg",I);if(H.useDivWrapper){D.canvas=document.createElement("div");D.canvas.style.position="absolute";jsPlumb.sizeCanvas(D.canvas,0,0,1,1);D.canvas.className=F;if(D.tooltip){D.canvas.setAttribute("title",D.tooltip)}}else{g(D.svg,{"class":F});D.canvas=D.svg}H._jsPlumb.appendElement(D.canvas,H.originalArgs[0]["parent"]);if(H.useDivWrapper){D.canvas.appendChild(D.svg)}var E=[D.canvas];this.getDisplayElements=function(){return E};this.appendDisplayElement=function(J){E.push(J)};this.paint=function(M,L,K){if(L!=null){var J=M[0],N=M[1];if(H.useDivWrapper){jsPlumb.sizeCanvas(D.canvas,M[0],M[1],M[2],M[3]);J=0,N=0}g(D.svg,{style:n([J,N,M[2],M[3]]),width:M[2],height:M[3]});D._paint.apply(this,arguments)}}};var d=jsPlumb.SvgConnector=function(E){var D=this;s.apply(this,[{cssClass:E._jsPlumb.connectorClass,originalArgs:arguments,pointerEventsSpec:"none",tooltip:E.tooltip,_jsPlumb:E._jsPlumb}]);this._paint=function(L,H){var K=D.getPath(L),F={d:K},J=null;F["pointer-events"]="all";if(H.outlineColor){var I=H.outlineWidth||1,G=H.lineWidth+(2*I),J=jsPlumb.CurrentLibrary.extend({},H);J.strokeStyle=jsPlumb.util.convertStyle(H.outlineColor);J.lineWidth=G;if(D.bgPath==null){D.bgPath=f("path",F);D.svg.appendChild(D.bgPath);D.attachListeners(D.bgPath,D)}else{g(D.bgPath,F)}x(D.svg,D.bgPath,J,L,D)}if(D.path==null){D.path=f("path",F);D.svg.appendChild(D.path);D.attachListeners(D.path,D)}else{g(D.path,F)}x(D.svg,D.path,H,L,D)};this.reattachListeners=function(){if(D.bgPath){D.reattachListenersForElement(D.bgPath,D)}if(D.path){D.reattachListenersForElement(D.path,D)}}};jsPlumb.Connectors.svg.Bezier=function(D){jsPlumb.Connectors.Bezier.apply(this,arguments);d.apply(this,arguments);this.getPath=function(E){return"M "+E[4]+" "+E[5]+" C "+E[8]+" "+E[9]+" "+E[10]+" "+E[11]+" "+E[6]+" "+E[7]}};jsPlumb.Connectors.svg.Straight=function(D){jsPlumb.Connectors.Straight.apply(this,arguments);d.apply(this,arguments);this.getPath=function(E){return"M "+E[4]+" "+E[5]+" L "+E[6]+" "+E[7]}};jsPlumb.Connectors.svg.Flowchart=function(){var D=this;jsPlumb.Connectors.Flowchart.apply(this,arguments);d.apply(this,arguments);this.getPath=function(F){var G="M "+F[4]+","+F[5];for(var E=0;E<F[8];E++){G=G+" L "+F[9+(E*2)]+" "+F[10+(E*2)]}G=G+" "+F[6]+","+F[7];return G}};var y=function(E){var D=this;s.apply(this,[{cssClass:E._jsPlumb.endpointClass,originalArgs:arguments,pointerEventsSpec:"all",useDivWrapper:true,_jsPlumb:E._jsPlumb}]);this._paint=function(H,G){var F=jsPlumb.extend({},G);if(F.outlineColor){F.strokeWidth=F.outlineWidth;F.strokeStyle=jsPlumb.util.convertStyle(F.outlineColor,true)}if(D.node==null){D.node=D.makeNode(H,F);D.svg.appendChild(D.node);D.attachListeners(D.node,D)}x(D.svg,D.node,F,H,D);n(D.node,H)};this.reattachListeners=function(){if(D.node){D.reattachListenersForElement(D.node,D)}}};jsPlumb.Endpoints.svg.Dot=function(){jsPlumb.Endpoints.Dot.apply(this,arguments);y.apply(this,arguments);this.makeNode=function(E,D){return f("circle",{cx:E[2]/2,cy:E[3]/2,r:E[2]/2})}};jsPlumb.Endpoints.svg.Rectangle=function(){jsPlumb.Endpoints.Rectangle.apply(this,arguments);y.apply(this,arguments);this.makeNode=function(E,D){return f("rect",{width:E[2],height:E[3]})}};jsPlumb.Endpoints.svg.Image=jsPlumb.Endpoints.Image;jsPlumb.Endpoints.svg.Blank=jsPlumb.Endpoints.Blank;jsPlumb.Overlays.svg.Label=jsPlumb.Overlays.Label;var p=function(H,F){H.apply(this,F);jsPlumb.jsPlumbUIComponent.apply(this,F);this.isAppendedAtTopLevel=false;var D=this,G=null;this.paint=function(J,M,I,N,K){if(G==null){G=f("path");J.svg.appendChild(G);D.attachListeners(G,J);D.attachListeners(G,D)}var L=F&&(F.length==1)?(F[0].cssClass||""):"";g(G,{d:E(M),"class":L,stroke:N?N:null,fill:K?K:null})};var E=function(I){return"M"+I.hxy.x+","+I.hxy.y+" L"+I.tail[0].x+","+I.tail[0].y+" L"+I.cxy.x+","+I.cxy.y+" L"+I.tail[1].x+","+I.tail[1].y+" L"+I.hxy.x+","+I.hxy.y};this.reattachListeners=function(){if(G){D.reattachListenersForElement(G,D)}}};jsPlumb.Overlays.svg.Arrow=function(){p.apply(this,[jsPlumb.Overlays.Arrow,arguments])};jsPlumb.Overlays.svg.PlainArrow=function(){p.apply(this,[jsPlumb.Overlays.PlainArrow,arguments])};jsPlumb.Overlays.svg.Diamond=function(){p.apply(this,[jsPlumb.Overlays.Diamond,arguments])};jsPlumb.Overlays.svg.GuideLines=function(){var I=null,D=this,H=null,G,F;jsPlumb.Overlays.GuideLines.apply(this,arguments);this.paint=function(K,M,J,N,L){if(I==null){I=f("path");K.svg.appendChild(I);D.attachListeners(I,K);D.attachListeners(I,D);G=f("path");K.svg.appendChild(G);D.attachListeners(G,K);D.attachListeners(G,D);F=f("path");K.svg.appendChild(F);D.attachListeners(F,K);D.attachListeners(F,D)}g(I,{d:E(M[0],M[1]),stroke:"red",fill:null});g(G,{d:E(M[2][0],M[2][1]),stroke:"blue",fill:null});g(F,{d:E(M[3][0],M[3][1]),stroke:"green",fill:null})};var E=function(K,J){return"M "+K.x+","+K.y+" L"+J.x+","+J.y}}})();(function(){var d=null,i=function(p,o){return jsPlumb.CurrentLibrary.hasClass(a(p),o)},a=function(o){return jsPlumb.CurrentLibrary.getElementObject(o)},m=function(o){return jsPlumb.CurrentLibrary.getOffset(a(o))},n=function(o){return jsPlumb.CurrentLibrary.getPageXY(o)},f=function(o){return jsPlumb.CurrentLibrary.getClientXY(o)};var k=function(){var q=this;q.overlayPlacements=[];jsPlumb.jsPlumbUIComponent.apply(this,arguments);jsPlumb.EventGenerator.apply(this,arguments);this._over=function(z){var B=m(a(q.canvas)),D=n(z),u=D[0]-B.left,C=D[1]-B.top;if(u>0&&C>0&&u<q.canvas.width&&C<q.canvas.height){for(var v=0;v<q.overlayPlacements.length;v++){var w=q.overlayPlacements[v];if(w&&(w[0]<=u&&w[1]>=u&&w[2]<=C&&w[3]>=C)){return true}}var A=q.canvas.getContext("2d").getImageData(parseInt(u),parseInt(C),1,1);return A.data[0]!=0||A.data[1]!=0||A.data[2]!=0||A.data[3]!=0}return false};var p=false,o=false,t=null,s=false,r=function(v,u){return v!=null&&i(v,u)};this.mousemove=function(x){var z=n(x),w=f(x),v=document.elementFromPoint(w[0],w[1]),y=r(v,"_jsPlumb_overlay");var u=d==null&&(r(v,"_jsPlumb_endpoint")||r(v,"_jsPlumb_connector"));if(!p&&u&&q._over(x)){p=true;q.fire("mouseenter",q,x);return true}else{if(p&&(!q._over(x)||!u)&&!y){p=false;q.fire("mouseexit",q,x)}}q.fire("mousemove",q,x)};this.click=function(u){if(p&&q._over(u)&&!s){q.fire("click",q,u)}s=false};this.dblclick=function(u){if(p&&q._over(u)&&!s){q.fire("dblclick",q,u)}s=false};this.mousedown=function(u){if(q._over(u)&&!o){o=true;t=m(a(q.canvas));q.fire("mousedown",q,u)}};this.mouseup=function(u){o=false;q.fire("mouseup",q,u)};this.contextmenu=function(u){if(p&&q._over(u)&&!s){q.fire("contextmenu",q,u)}s=false}};var c=function(p){var o=document.createElement("canvas");jsPlumb.appendElement(o,p.parent);o.style.position="absolute";if(p["class"]){o.className=p["class"]}p._jsPlumb.getId(o,p.uuid);if(p.tooltip){o.setAttribute("title",p.tooltip)}return o};var l=function(p){k.apply(this,arguments);var o=[];this.getDisplayElements=function(){return o};this.appendDisplayElement=function(q){o.push(q)}};var h=jsPlumb.CanvasConnector=function(r){l.apply(this,arguments);var o=function(v,t){p.ctx.save();jsPlumb.extend(p.ctx,t);if(t.gradient){var u=p.createGradient(v,p.ctx);for(var s=0;s<t.gradient.stops.length;s++){u.addColorStop(t.gradient.stops[s][0],t.gradient.stops[s][1])}p.ctx.strokeStyle=u}p._paint(v);p.ctx.restore()};var p=this,q=p._jsPlumb.connectorClass+" "+(r.cssClass||"");p.canvas=c({"class":q,_jsPlumb:p._jsPlumb,parent:r.parent,tooltip:r.tooltip});p.ctx=p.canvas.getContext("2d");p.appendDisplayElement(p.canvas);p.paint=function(w,t){if(t!=null){jsPlumb.sizeCanvas(p.canvas,w[0],w[1],w[2],w[3]);if(t.outlineColor!=null){var v=t.outlineWidth||1,s=t.lineWidth+(2*v),u={strokeStyle:t.outlineColor,lineWidth:s};o(w,u)}o(w,t)}}};var b=function(r){var p=this;l.apply(this,arguments);var q=p._jsPlumb.endpointClass+" "+(r.cssClass||""),o={"class":q,_jsPlumb:p._jsPlumb,parent:r.parent,tooltip:p.tooltip};p.canvas=c(o);p.ctx=p.canvas.getContext("2d");p.appendDisplayElement(p.canvas);this.paint=function(x,u,s){jsPlumb.sizeCanvas(p.canvas,x[0],x[1],x[2],x[3]);if(u.outlineColor!=null){var w=u.outlineWidth||1,t=u.lineWidth+(2*w);var v={strokeStyle:u.outlineColor,lineWidth:t}}p._paint.apply(this,arguments)}};jsPlumb.Endpoints.canvas.Dot=function(r){jsPlumb.Endpoints.Dot.apply(this,arguments);b.apply(this,arguments);var q=this,p=function(s){try{return parseInt(s)}catch(t){if(s.substring(s.length-1)=="%"){return parseInt(s.substring(0,s-1))}}},o=function(u){var s=q.defaultOffset,t=q.defaultInnerRadius;u.offset&&(s=p(u.offset));u.innerRadius&&(t=p(u.innerRadius));return[s,t]};this._paint=function(A,t,x){if(t!=null){var B=q.canvas.getContext("2d"),u=x.getOrientation(q);jsPlumb.extend(B,t);if(t.gradient){var v=o(t.gradient),y=u[1]==1?v[0]*-1:v[0],s=u[0]==1?v[0]*-1:v[0],z=B.createRadialGradient(A[4],A[4],A[4],A[4]+s,A[4]+y,v[1]);for(var w=0;w<t.gradient.stops.length;w++){z.addColorStop(t.gradient.stops[w][0],t.gradient.stops[w][1])}B.fillStyle=z}B.beginPath();B.arc(A[4],A[4],A[4],0,Math.PI*2,true);B.closePath();if(t.fillStyle||t.gradient){B.fill()}if(t.strokeStyle){B.stroke()}}}};jsPlumb.Endpoints.canvas.Rectangle=function(p){var o=this;jsPlumb.Endpoints.Rectangle.apply(this,arguments);b.apply(this,arguments);this._paint=function(x,r,v){var A=o.canvas.getContext("2d"),t=v.getOrientation(o);jsPlumb.extend(A,r);if(r.gradient){var z=t[1]==1?x[3]:t[1]==0?x[3]/2:0;var y=t[1]==-1?x[3]:t[1]==0?x[3]/2:0;var s=t[0]==1?x[2]:t[0]==0?x[2]/2:0;var q=t[0]==-1?x[2]:t[0]==0?x[2]/2:0;var w=A.createLinearGradient(s,z,q,y);for(var u=0;u<r.gradient.stops.length;u++){w.addColorStop(r.gradient.stops[u][0],r.gradient.stops[u][1])}A.fillStyle=w}A.beginPath();A.rect(0,0,x[2],x[3]);A.closePath();if(r.fillStyle||r.gradient){A.fill()}if(r.strokeStyle){A.stroke()}}};jsPlumb.Endpoints.canvas.Triangle=function(p){var o=this;jsPlumb.Endpoints.Triangle.apply(this,arguments);b.apply(this,arguments);this._paint=function(z,q,v){var s=z[2],C=z[3],B=z[0],A=z[1],D=o.canvas.getContext("2d"),w=0,u=0,t=0,r=v.getOrientation(o);if(r[0]==1){w=s;u=C;t=180}if(r[1]==-1){w=s;t=90}if(r[1]==1){u=C;t=-90}D.fillStyle=q.fillStyle;D.translate(w,u);D.rotate(t*Math.PI/180);D.beginPath();D.moveTo(0,0);D.lineTo(s/2,C/2);D.lineTo(0,C);D.closePath();if(q.fillStyle||q.gradient){D.fill()}if(q.strokeStyle){D.stroke()}}};jsPlumb.Endpoints.canvas.Image=jsPlumb.Endpoints.Image;jsPlumb.Endpoints.canvas.Blank=jsPlumb.Endpoints.Blank;jsPlumb.Connectors.canvas.Bezier=function(){var o=this;jsPlumb.Connectors.Bezier.apply(this,arguments);h.apply(this,arguments);this._paint=function(p){o.ctx.beginPath();o.ctx.moveTo(p[4],p[5]);o.ctx.bezierCurveTo(p[8],p[9],p[10],p[11],p[6],p[7]);o.ctx.stroke()};this.createGradient=function(r,p,q){return o.ctx.createLinearGradient(r[6],r[7],r[4],r[5])}};jsPlumb.Connectors.canvas.Straight=function(){var o=this;jsPlumb.Connectors.Straight.apply(this,arguments);h.apply(this,arguments);this._paint=function(p){o.ctx.beginPath();o.ctx.moveTo(p[4],p[5]);o.ctx.lineTo(p[6],p[7]);o.ctx.stroke()};this.createGradient=function(q,p){return p.createLinearGradient(q[4],q[5],q[6],q[7])}};jsPlumb.Connectors.canvas.Flowchart=function(){var o=this;jsPlumb.Connectors.Flowchart.apply(this,arguments);h.apply(this,arguments);this._paint=function(q){o.ctx.beginPath();o.ctx.moveTo(q[4],q[5]);for(var p=0;p<q[8];p++){o.ctx.lineTo(q[9+(p*2)],q[10+(p*2)])}o.ctx.lineTo(q[6],q[7]);o.ctx.stroke()};this.createGradient=function(q,p){return p.createLinearGradient(q[4],q[5],q[6],q[7])}};jsPlumb.Overlays.canvas.Label=jsPlumb.Overlays.Label;var g=function(){jsPlumb.jsPlumbUIComponent.apply(this,arguments)};var e=function(p,o){p.apply(this,o);g.apply(this,arguments);this.paint=function(s,u,q,v,t){var r=s.ctx;r.lineWidth=q;r.beginPath();r.moveTo(u.hxy.x,u.hxy.y);r.lineTo(u.tail[0].x,u.tail[0].y);r.lineTo(u.cxy.x,u.cxy.y);r.lineTo(u.tail[1].x,u.tail[1].y);r.lineTo(u.hxy.x,u.hxy.y);r.closePath();if(v){r.strokeStyle=v;r.stroke()}if(t){r.fillStyle=t;r.fill()}}};jsPlumb.Overlays.canvas.Arrow=function(){e.apply(this,[jsPlumb.Overlays.Arrow,arguments])};jsPlumb.Overlays.canvas.PlainArrow=function(){e.apply(this,[jsPlumb.Overlays.PlainArrow,arguments])};jsPlumb.Overlays.canvas.Diamond=function(){e.apply(this,[jsPlumb.Overlays.Diamond,arguments])}})();(function(a){jsPlumb.CurrentLibrary={addClass:function(c,b){c=jsPlumb.CurrentLibrary.getElementObject(c);try{if(c[0].className.constructor==SVGAnimatedString){jsPlumb.util.svg.addClass(c[0],b)}}catch(d){}c.addClass(b)},animate:function(d,c,b){d.animate(c,b)},appendElement:function(c,b){jsPlumb.CurrentLibrary.getElementObject(b).append(c)},bind:function(b,c,d){b=jsPlumb.CurrentLibrary.getElementObject(b);b.bind(c,d)},dragEvents:{start:"start",stop:"stop",drag:"drag",step:"step",over:"over",out:"out",drop:"drop",complete:"complete"},extend:function(c,b){return a.extend(c,b)},getAttribute:function(b,c){return b.attr(c)},getClientXY:function(b){return[b.clientX,b.clientY]},getDocumentElement:function(){return document},getDragObject:function(b){return b[1].draggable},getDragScope:function(b){return b.draggable("option","scope")},getDropScope:function(b){return b.droppable("option","scope")},getDOMElement:function(b){if(typeof(b)=="string"){return document.getElementById(b)}else{if(b.context){return b[0]}else{return b}}},getElementObject:function(b){return typeof(b)=="string"?a("#"+b):a(b)},getOffset:function(b){return b.offset()},getPageXY:function(b){return[b.pageX,b.pageY]},getParent:function(b){return jsPlumb.CurrentLibrary.getElementObject(b).parent()},getScrollLeft:function(b){return b.scrollLeft()},getScrollTop:function(b){return b.scrollTop()},getSelector:function(b){return a(b)},getSize:function(b){return[b.outerWidth(),b.outerHeight()]},getTagName:function(b){var c=jsPlumb.CurrentLibrary.getElementObject(b);return c.length>0?c[0].tagName:null},getUIPosition:function(c){if(c.length==1){ret={left:c[0].pageX,top:c[0].pageY}}else{var d=c[1],b=d.offset;ret=b||d.absolutePosition}return ret},hasClass:function(c,b){return c.hasClass(b)},initDraggable:function(c,b){b=b||{};b.helper=null;b.scope=b.scope||jsPlumb.Defaults.Scope;c.draggable(b)},initDroppable:function(c,b){b.scope=b.scope||jsPlumb.Defaults.Scope;c.droppable(b)},isAlreadyDraggable:function(b){b=jsPlumb.CurrentLibrary.getElementObject(b);return b.hasClass("ui-draggable")},isDragSupported:function(c,b){return c.draggable},isDropSupported:function(c,b){return c.droppable},removeClass:function(c,b){c=jsPlumb.CurrentLibrary.getElementObject(c);try{if(c[0].className.constructor==SVGAnimatedString){jsPlumb.util.svg.removeClass(c[0],b)}}catch(d){}c.removeClass(b)},removeElement:function(b,c){jsPlumb.CurrentLibrary.getElementObject(b).remove()},setAttribute:function(c,d,b){c.attr(d,b)},setDraggable:function(c,b){c.draggable("option","disabled",!b)},setDragScope:function(c,b){c.draggable("option","scope",b)},setOffset:function(b,c){jsPlumb.CurrentLibrary.getElementObject(b).offset(c)},trigger:function(d,e,b){var c=jQuery._data(jsPlumb.CurrentLibrary.getElementObject(d)[0],"handle");c(b)},unbind:function(b,c,d){b=jsPlumb.CurrentLibrary.getElementObject(b);b.unbind(c,d)}};a(document).ready(jsPlumb.init)})(jQuery);(function(){if("undefined"==typeof Math.sgn){Math.sgn=function(l){return 0==l?0:0<l?1:-1}}var d={subtract:function(m,l){return{x:m.x-l.x,y:m.y-l.y}},dotProduct:function(m,l){return m.x*l.x+m.y*l.y},square:function(l){return Math.sqrt(l.x*l.x+l.y*l.y)},scale:function(m,l){return{x:m.x*l,y:m.y*l}}},f=Math.pow(2,-65),h=function(y,x){for(var t=[],v=x.length-1,r=2*v-1,s=[],w=[],p=[],q=[],o=[[1,0.6,0.3,0.1],[0.4,0.6,0.6,0.4],[0.1,0.3,0.6,1]],u=0;u<=v;u++){s[u]=d.subtract(x[u],y)}for(u=0;u<=v-1;u++){w[u]=d.subtract(x[u+1],x[u]),w[u]=d.scale(w[u],3)}for(u=0;u<=v-1;u++){for(var l=0;l<=v;l++){p[u]||(p[u]=[]),p[u][l]=d.dotProduct(w[u],s[l])}}for(u=0;u<=r;u++){q[u]||(q[u]=[]),q[u].y=0,q[u].x=parseFloat(u)/r}r=v-1;for(s=0;s<=v+r;s++){u=Math.max(0,s-r);for(w=Math.min(s,v);u<=w;u++){j=s-u,q[u+j].y+=p[j][u]*o[j][u]}}v=x.length-1;q=b(q,2*v-1,t,0);r=d.subtract(y,x[0]);p=d.square(r);for(u=o=0;u<q;u++){r=d.subtract(y,a(x,v,t[u],null,null)),r=d.square(r),r<p&&(p=r,o=t[u])}r=d.subtract(y,x[v]);r=d.square(r);r<p&&(p=r,o=1);return{location:o,distance:p}},b=function(C,B,x,z){var v=[],w=[],A=[],t=[],u=0,r,y;y=Math.sgn(C[0].y);for(var q=1;q<=B;q++){r=Math.sgn(C[q].y),r!=y&&u++,y=r}switch(u){case 0:return 0;case 1:if(64<=z){return x[0]=(C[0].x+C[B].x)/2,1}var p,u=C[0].y-C[B].y;r=C[B].x-C[0].x;y=C[0].x*C[B].y-C[B].x*C[0].y;q=max_distance_below=0;for(p=1;p<B;p++){var s=u*C[p].x+r*C[p].y+y;s>q?q=s:s<max_distance_below&&(max_distance_below=s)}p=r;q=(1*(y-q)-0*p)*(1/(0*p-1*u));p=r;u=(1*(y-max_distance_below)-0*p)*(1/(0*p-1*u));r=Math.min(q,u);if(Math.max(q,u)-r<f){return A=C[B].x-C[0].x,t=C[B].y-C[0].y,x[0]=0+1*(A*(C[0].y-0)-t*(C[0].x-0))*(1/(0*A-1*t)),1}}a(C,B,0.5,v,w);C=b(v,B,A,z+1);B=b(w,B,t,z+1);for(z=0;z<C;z++){x[z]=A[z]}for(z=0;z<B;z++){x[z+C]=t[z]}return C+B},a=function(m,l,p,q,n){for(var o=[[]],r=0;r<=l;r++){o[0][r]=m[r]}for(m=1;m<=l;m++){for(r=0;r<=l-m;r++){o[m]||(o[m]=[]),o[m][r]||(o[m][r]={}),o[m][r].x=(1-p)*o[m-1][r].x+p*o[m-1][r+1].x,o[m][r].y=(1-p)*o[m-1][r].y+p*o[m-1][r+1].y}}if(null!=q){for(r=0;r<=l;r++){q[r]=o[r][0]}}if(null!=n){for(r=0;r<=l;r++){n[r]=o[l-r][r]}}return o[l][0]},g={},e=function(t){var s=g[t];if(!s){var s=[],p=function(u){return function(){return u}},q=function(){return function(u){return u}},n=function(){return function(u){return 1-u}},o=function(u){return function(v){for(var x=1,w=0;w<u.length;w++){x*=u[w](v)}return x}};s.push(new function(){return function(u){return Math.pow(u,t)}});for(var r=1;r<t;r++){for(var l=[new p(t)],m=0;m<t-r;m++){l.push(new q)}for(m=0;m<r;m++){l.push(new n)}s.push(new o(l))}s.push(new function(){return function(u){return Math.pow(1-u,t)}});g[t]=s}return s},c=function(m,l){for(var p=e(m.length-1),q=0,n=0,o=0;o<m.length;o++){q+=m[o].x*p[o](l),n+=m[o].y*p[o](l)}return{x:q,y:n}},k=function(m,l,p){for(var q=c(m,l),n=0,o=0<p?1:-1,r=null;n<Math.abs(p);){l+=0.005*o,r=c(m,l),n+=Math.sqrt(Math.pow(r.x-q.x,2)+Math.pow(r.y-q.y,2)),q=r}return{point:r,location:l}},i=function(m,l){var o=c(m,l),p=c(m.slice(0,m.length-1),l),n=p.y-o.y,o=p.x-o.x;return 0==n?Infinity:Math.atan(n/o)};window.jsBezier={distanceFromCurve:h,gradientAtPoint:i,gradientAtPointAlongCurveFrom:function(m,l,n){l=k(m,l,n);if(1<l.location){l.location=1}if(0>l.location){l.location=0}return i(m,l.location)},nearestPointOnCurve:function(m,l){var n=h(m,l);return{point:a(l,l.length-1,n.location,null,null),location:n.location}},pointOnCurve:c,pointAlongCurveFrom:function(m,l,n){return k(m,l,n).point},perpendicularToCurveAt:function(m,l,n,o){l=k(m,l,null==o?0:o);m=i(m,l.location);o=Math.atan(-1/m);m=n/2*Math.sin(o);n=n/2*Math.cos(o);return[{x:l.point.x+n,y:l.point.y+m},{x:l.point.x-n,y:l.point.y-m}]}}})();
\ No newline at end of file
diff --git a/hyracks-control-common/src/main/java/edu/uci/ics/hyracks/control/common/heartbeat/HeartbeatData.java b/hyracks-control-common/src/main/java/edu/uci/ics/hyracks/control/common/heartbeat/HeartbeatData.java
index 8ca0fa4..1dba3bc 100644
--- a/hyracks-control-common/src/main/java/edu/uci/ics/hyracks/control/common/heartbeat/HeartbeatData.java
+++ b/hyracks-control-common/src/main/java/edu/uci/ics/hyracks/control/common/heartbeat/HeartbeatData.java
@@ -37,4 +37,8 @@
public long netPayloadBytesWritten;
public long netSignalingBytesRead;
public long netSignalingBytesWritten;
+ public long ipcMessagesSent;
+ public long ipcMessageBytesSent;
+ public long ipcMessagesReceived;
+ public long ipcMessageBytesReceived;
}
\ No newline at end of file
diff --git a/hyracks-control-nc/src/main/java/edu/uci/ics/hyracks/control/nc/NodeControllerService.java b/hyracks-control-nc/src/main/java/edu/uci/ics/hyracks/control/nc/NodeControllerService.java
index b3eccb5..c3d3c34 100644
--- a/hyracks-control-nc/src/main/java/edu/uci/ics/hyracks/control/nc/NodeControllerService.java
+++ b/hyracks-control-nc/src/main/java/edu/uci/ics/hyracks/control/nc/NodeControllerService.java
@@ -69,8 +69,9 @@
import edu.uci.ics.hyracks.control.nc.work.StartTasksWork;
import edu.uci.ics.hyracks.ipc.api.IIPCHandle;
import edu.uci.ics.hyracks.ipc.api.IIPCI;
+import edu.uci.ics.hyracks.ipc.api.IPCPerformanceCounters;
import edu.uci.ics.hyracks.ipc.impl.IPCSystem;
-import edu.uci.ics.hyracks.net.protocols.muxdemux.PerformanceCounters;
+import edu.uci.ics.hyracks.net.protocols.muxdemux.MuxDemuxPerformanceCounters;
public class NodeControllerService extends AbstractRemoteService {
private static Logger LOGGER = Logger.getLogger(NodeControllerService.class.getName());
@@ -311,11 +312,19 @@
hbData.gcCollectionCounts[i] = gcMXBean.getCollectionCount();
hbData.gcCollectionTimes[i] = gcMXBean.getCollectionTime();
}
- PerformanceCounters netPC = netManager.getPerformanceCounters();
+
+ MuxDemuxPerformanceCounters netPC = netManager.getPerformanceCounters();
hbData.netPayloadBytesRead = netPC.getPayloadBytesRead();
hbData.netPayloadBytesWritten = netPC.getPayloadBytesWritten();
hbData.netSignalingBytesRead = netPC.getSignalingBytesRead();
hbData.netSignalingBytesWritten = netPC.getSignalingBytesWritten();
+
+ IPCPerformanceCounters ipcPC = ipc.getPerformanceCounters();
+ hbData.ipcMessagesSent = ipcPC.getMessageSentCount();
+ hbData.ipcMessageBytesSent = ipcPC.getMessageBytesSent();
+ hbData.ipcMessagesReceived = ipcPC.getMessageReceivedCount();
+ hbData.ipcMessageBytesReceived = ipcPC.getMessageBytesReceived();
+
try {
cc.nodeHeartbeat(id, hbData);
} catch (Exception e) {
diff --git a/hyracks-control-nc/src/main/java/edu/uci/ics/hyracks/control/nc/net/NetworkManager.java b/hyracks-control-nc/src/main/java/edu/uci/ics/hyracks/control/nc/net/NetworkManager.java
index 1a0a820..68e3120 100644
--- a/hyracks-control-nc/src/main/java/edu/uci/ics/hyracks/control/nc/net/NetworkManager.java
+++ b/hyracks-control-nc/src/main/java/edu/uci/ics/hyracks/control/nc/net/NetworkManager.java
@@ -35,7 +35,7 @@
import edu.uci.ics.hyracks.net.protocols.muxdemux.IChannelOpenListener;
import edu.uci.ics.hyracks.net.protocols.muxdemux.MultiplexedConnection;
import edu.uci.ics.hyracks.net.protocols.muxdemux.MuxDemux;
-import edu.uci.ics.hyracks.net.protocols.muxdemux.PerformanceCounters;
+import edu.uci.ics.hyracks.net.protocols.muxdemux.MuxDemuxPerformanceCounters;
public class NetworkManager {
private static final Logger LOGGER = Logger.getLogger(NetworkManager.class.getName());
@@ -128,7 +128,7 @@
return new PartitionId(jobId, cdid, senderIndex, receiverIndex);
}
- public PerformanceCounters getPerformanceCounters() {
+ public MuxDemuxPerformanceCounters getPerformanceCounters() {
return md.getPerformanceCounters();
}
}
\ No newline at end of file
diff --git a/hyracks-dataflow-std/src/main/java/edu/uci/ics/hyracks/dataflow/std/base/AbstractConnectorDescriptor.java b/hyracks-dataflow-std/src/main/java/edu/uci/ics/hyracks/dataflow/std/base/AbstractConnectorDescriptor.java
index 37154bc..7c50da9 100644
--- a/hyracks-dataflow-std/src/main/java/edu/uci/ics/hyracks/dataflow/std/base/AbstractConnectorDescriptor.java
+++ b/hyracks-dataflow-std/src/main/java/edu/uci/ics/hyracks/dataflow/std/base/AbstractConnectorDescriptor.java
@@ -52,7 +52,7 @@
public JSONObject toJSON() throws JSONException {
JSONObject jconn = new JSONObject();
- jconn.put("id", getConnectorId().getId());
+ jconn.put("id", String.valueOf(getConnectorId()));
jconn.put("java-class", getClass().getName());
jconn.put("display-name", displayName);
diff --git a/hyracks-dataflow-std/src/main/java/edu/uci/ics/hyracks/dataflow/std/base/AbstractOperatorDescriptor.java b/hyracks-dataflow-std/src/main/java/edu/uci/ics/hyracks/dataflow/std/base/AbstractOperatorDescriptor.java
index 1a60290..983851e 100644
--- a/hyracks-dataflow-std/src/main/java/edu/uci/ics/hyracks/dataflow/std/base/AbstractOperatorDescriptor.java
+++ b/hyracks-dataflow-std/src/main/java/edu/uci/ics/hyracks/dataflow/std/base/AbstractOperatorDescriptor.java
@@ -86,7 +86,7 @@
@Override
public JSONObject toJSON() throws JSONException {
JSONObject jop = new JSONObject();
- jop.put("id", getOperatorId().getId());
+ jop.put("id", String.valueOf(getOperatorId()));
jop.put("java-class", getClass().getName());
jop.put("in-arity", getInputArity());
jop.put("out-arity", getOutputArity());
diff --git a/hyracks-dataflow-std/src/main/java/edu/uci/ics/hyracks/dataflow/std/connectors/GlobalHashingLocalityMap.java b/hyracks-dataflow-std/src/main/java/edu/uci/ics/hyracks/dataflow/std/connectors/GlobalHashingLocalityMap.java
new file mode 100644
index 0000000..f3086f0
--- /dev/null
+++ b/hyracks-dataflow-std/src/main/java/edu/uci/ics/hyracks/dataflow/std/connectors/GlobalHashingLocalityMap.java
@@ -0,0 +1,50 @@
+/*
+ * Copyright 2009-2010 by The Regents of the University of California
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * you may obtain a copy of the License from
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package edu.uci.ics.hyracks.dataflow.std.connectors;
+
+public class GlobalHashingLocalityMap implements ILocalityMap {
+
+ private static final long serialVersionUID = 1L;
+
+ private int[] consumers;
+
+ /* (non-Javadoc)
+ * @see edu.uci.ics.hyracks.examples.text.client.aggregation.helpers.ILocalityMap#getConsumers(int)
+ */
+ @Override
+ public int[] getConsumers(int senderID, int nConsumerPartitions) {
+ if (consumers == null) {
+ consumers = new int[nConsumerPartitions];
+ for (int i = 0; i < consumers.length; i++) {
+ consumers[i] = i;
+ }
+ }
+ return consumers;
+ }
+
+ /* (non-Javadoc)
+ * @see edu.uci.ics.hyracks.examples.text.client.aggregation.helpers.ILocalityMap#getConsumerPartitionCount()
+ */
+ @Override
+ public int getConsumerPartitionCount(int nConsumerPartitions) {
+ return nConsumerPartitions;
+ }
+
+ @Override
+ public boolean isConnected(int senderID, int receiverID, int nConsumerPartitions) {
+ return true;
+ }
+
+}
diff --git a/hyracks-dataflow-std/src/main/java/edu/uci/ics/hyracks/dataflow/std/connectors/HashtableLocalityMap.java b/hyracks-dataflow-std/src/main/java/edu/uci/ics/hyracks/dataflow/std/connectors/HashtableLocalityMap.java
new file mode 100644
index 0000000..a187a59
--- /dev/null
+++ b/hyracks-dataflow-std/src/main/java/edu/uci/ics/hyracks/dataflow/std/connectors/HashtableLocalityMap.java
@@ -0,0 +1,72 @@
+/*
+ * Copyright 2009-2010 by The Regents of the University of California
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * you may obtain a copy of the License from
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package edu.uci.ics.hyracks.dataflow.std.connectors;
+
+import java.util.BitSet;
+
+public class HashtableLocalityMap implements ILocalityMap {
+
+ private static final long serialVersionUID = 1L;
+
+ private final BitSet nodeMap;
+
+ public HashtableLocalityMap(BitSet nodeMap) {
+ this.nodeMap = nodeMap;
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see
+ * edu.uci.ics.hyracks.examples.text.client.aggregation.helpers.ILocalityMap
+ * #getConsumers(int, int)
+ */
+ @Override
+ public int[] getConsumers(int senderID, int nConsumerPartitions) {
+ int consumersForSender = 0;
+ // Get the count of consumers
+ for (int i = senderID * nConsumerPartitions; i < (senderID + 1) * nConsumerPartitions; i++) {
+ if (nodeMap.get(i))
+ consumersForSender++;
+ }
+ int[] cons = new int[consumersForSender];
+ int consIdx = 0;
+ for (int i = senderID * nConsumerPartitions; i < (senderID + 1) * nConsumerPartitions; i++) {
+ if (nodeMap.get(i)) {
+ cons[consIdx] = i - senderID * nConsumerPartitions;
+ consIdx++;
+ }
+ }
+ return cons;
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see
+ * edu.uci.ics.hyracks.examples.text.client.aggregation.helpers.ILocalityMap
+ * #getConsumerPartitionCount(int)
+ */
+ @Override
+ public int getConsumerPartitionCount(int nConsumerPartitions) {
+ return nConsumerPartitions;
+ }
+
+ @Override
+ public boolean isConnected(int senderID, int receiverID, int nConsumerPartitions) {
+ return nodeMap.get(senderID * nConsumerPartitions + receiverID);
+ }
+
+}
diff --git a/hyracks-dataflow-std/src/main/java/edu/uci/ics/hyracks/dataflow/std/connectors/ILocalityMap.java b/hyracks-dataflow-std/src/main/java/edu/uci/ics/hyracks/dataflow/std/connectors/ILocalityMap.java
new file mode 100644
index 0000000..b30971d
--- /dev/null
+++ b/hyracks-dataflow-std/src/main/java/edu/uci/ics/hyracks/dataflow/std/connectors/ILocalityMap.java
@@ -0,0 +1,27 @@
+/*
+ * Copyright 2009-2010 by The Regents of the University of California
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * you may obtain a copy of the License from
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package edu.uci.ics.hyracks.dataflow.std.connectors;
+
+import java.io.Serializable;
+
+public interface ILocalityMap extends Serializable {
+
+ public int[] getConsumers(int senderID, int nConsumerPartitions);
+
+ public boolean isConnected(int senderID, int receiverID, int nConsumerPartitions);
+
+ public int getConsumerPartitionCount(int nConsumerPartitions);
+
+}
diff --git a/hyracks-dataflow-std/src/main/java/edu/uci/ics/hyracks/dataflow/std/connectors/LocalityAwareMToNPartitioningConnectorDescriptor.java b/hyracks-dataflow-std/src/main/java/edu/uci/ics/hyracks/dataflow/std/connectors/LocalityAwareMToNPartitioningConnectorDescriptor.java
new file mode 100644
index 0000000..7d92150
--- /dev/null
+++ b/hyracks-dataflow-std/src/main/java/edu/uci/ics/hyracks/dataflow/std/connectors/LocalityAwareMToNPartitioningConnectorDescriptor.java
@@ -0,0 +1,82 @@
+/*
+ * Copyright 2009-2010 by The Regents of the University of California
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * you may obtain a copy of the License from
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package edu.uci.ics.hyracks.dataflow.std.connectors;
+
+import java.util.BitSet;
+
+import edu.uci.ics.hyracks.api.comm.IFrameWriter;
+import edu.uci.ics.hyracks.api.comm.IPartitionCollector;
+import edu.uci.ics.hyracks.api.comm.IPartitionWriterFactory;
+import edu.uci.ics.hyracks.api.context.IHyracksTaskContext;
+import edu.uci.ics.hyracks.api.dataflow.value.ITuplePartitionComputerFactory;
+import edu.uci.ics.hyracks.api.dataflow.value.RecordDescriptor;
+import edu.uci.ics.hyracks.api.exceptions.HyracksDataException;
+import edu.uci.ics.hyracks.api.job.JobSpecification;
+import edu.uci.ics.hyracks.dataflow.std.base.AbstractMToNConnectorDescriptor;
+import edu.uci.ics.hyracks.dataflow.std.collectors.NonDeterministicPartitionCollector;
+
+public class LocalityAwareMToNPartitioningConnectorDescriptor extends AbstractMToNConnectorDescriptor {
+
+ private static final long serialVersionUID = 1L;
+
+ private ILocalityMap localityMap;
+
+ private ITuplePartitionComputerFactory tpcf;
+
+ public LocalityAwareMToNPartitioningConnectorDescriptor(JobSpecification spec, ITuplePartitionComputerFactory tpcf,
+ ILocalityMap localityMap) {
+ super(spec);
+ this.localityMap = localityMap;
+ this.tpcf = tpcf;
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see
+ * edu.uci.ics.hyracks.api.dataflow.IConnectorDescriptor#createPartitioner
+ * (edu.uci.ics.hyracks.api.context.IHyracksTaskContext,
+ * edu.uci.ics.hyracks.api.dataflow.value.RecordDescriptor,
+ * edu.uci.ics.hyracks.api.comm.IPartitionWriterFactory, int, int, int)
+ */
+ @Override
+ public IFrameWriter createPartitioner(IHyracksTaskContext ctx, RecordDescriptor recordDesc,
+ IPartitionWriterFactory edwFactory, int index, int nProducerPartitions, int nConsumerPartitions)
+ throws HyracksDataException {
+ return new LocalityAwarePartitionDataWriter(ctx, edwFactory, recordDesc, tpcf.createPartitioner(),
+ nConsumerPartitions, localityMap, index);
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see edu.uci.ics.hyracks.api.dataflow.IConnectorDescriptor#
+ * createPartitionCollector
+ * (edu.uci.ics.hyracks.api.context.IHyracksTaskContext,
+ * edu.uci.ics.hyracks.api.dataflow.value.RecordDescriptor, int, int, int)
+ */
+ @Override
+ public IPartitionCollector createPartitionCollector(IHyracksTaskContext ctx, RecordDescriptor recordDesc,
+ int receiverIndex, int nProducerPartitions, int nConsumerPartitions) throws HyracksDataException {
+ BitSet expectedPartitions = new BitSet(nProducerPartitions);
+ for (int i = 0; i < nProducerPartitions; i++) {
+ if (localityMap.isConnected(i, receiverIndex, nConsumerPartitions))
+ expectedPartitions.set(i);
+ }
+ return new NonDeterministicPartitionCollector(ctx, getConnectorId(), receiverIndex, nProducerPartitions,
+ expectedPartitions);
+ }
+
+}
diff --git a/hyracks-dataflow-std/src/main/java/edu/uci/ics/hyracks/dataflow/std/connectors/LocalityAwarePartitionDataWriter.java b/hyracks-dataflow-std/src/main/java/edu/uci/ics/hyracks/dataflow/std/connectors/LocalityAwarePartitionDataWriter.java
new file mode 100644
index 0000000..6ec9013
--- /dev/null
+++ b/hyracks-dataflow-std/src/main/java/edu/uci/ics/hyracks/dataflow/std/connectors/LocalityAwarePartitionDataWriter.java
@@ -0,0 +1,125 @@
+/*
+ * Copyright 2009-2010 by The Regents of the University of California
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * you may obtain a copy of the License from
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package edu.uci.ics.hyracks.dataflow.std.connectors;
+
+import java.io.IOException;
+import java.nio.ByteBuffer;
+
+import edu.uci.ics.hyracks.api.comm.IFrameWriter;
+import edu.uci.ics.hyracks.api.comm.IPartitionWriterFactory;
+import edu.uci.ics.hyracks.api.context.IHyracksTaskContext;
+import edu.uci.ics.hyracks.api.dataflow.value.ITuplePartitionComputer;
+import edu.uci.ics.hyracks.api.dataflow.value.RecordDescriptor;
+import edu.uci.ics.hyracks.api.exceptions.HyracksDataException;
+import edu.uci.ics.hyracks.dataflow.common.comm.io.FrameTupleAccessor;
+import edu.uci.ics.hyracks.dataflow.common.comm.io.FrameTupleAppender;
+
+public class LocalityAwarePartitionDataWriter implements IFrameWriter {
+
+ private final IFrameWriter[] pWriters;
+ private final FrameTupleAppender[] appenders;
+ private final FrameTupleAccessor tupleAccessor;
+ private final ITuplePartitionComputer tpc;
+
+ public LocalityAwarePartitionDataWriter(IHyracksTaskContext ctx, IPartitionWriterFactory pwFactory,
+ RecordDescriptor recordDescriptor, ITuplePartitionComputer tpc, int nConsumerPartitions,
+ ILocalityMap localityMap, int senderIndex) throws HyracksDataException {
+ int[] consumerPartitions = localityMap.getConsumers(senderIndex, nConsumerPartitions);
+ pWriters = new IFrameWriter[consumerPartitions.length];
+ appenders = new FrameTupleAppender[consumerPartitions.length];
+ for (int i = 0; i < consumerPartitions.length; ++i) {
+ try {
+ pWriters[i] = pwFactory.createFrameWriter(consumerPartitions[i]);
+ appenders[i] = new FrameTupleAppender(ctx.getFrameSize());
+ appenders[i].reset(ctx.allocateFrame(), true);
+ } catch (IOException e) {
+ throw new HyracksDataException(e);
+ }
+ }
+ tupleAccessor = new FrameTupleAccessor(ctx.getFrameSize(), recordDescriptor);
+ this.tpc = tpc;
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see edu.uci.ics.hyracks.api.comm.IFrameWriter#open()
+ */
+ @Override
+ public void open() throws HyracksDataException {
+ for (int i = 0; i < pWriters.length; ++i) {
+ pWriters[i].open();
+ appenders[i].reset(appenders[i].getBuffer(), true);
+ }
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see
+ * edu.uci.ics.hyracks.api.comm.IFrameWriter#nextFrame(java.nio.ByteBuffer)
+ */
+ @Override
+ public void nextFrame(ByteBuffer buffer) throws HyracksDataException {
+ tupleAccessor.reset(buffer);
+ int tupleCount = tupleAccessor.getTupleCount();
+ for (int i = 0; i < tupleCount; ++i) {
+ int h = pWriters.length == 1 ? 0 : tpc.partition(tupleAccessor, i, pWriters.length);
+ FrameTupleAppender appender = appenders[h];
+ if (!appender.append(tupleAccessor, i)) {
+ ByteBuffer appenderBuffer = appender.getBuffer();
+ flushFrame(appenderBuffer, pWriters[h]);
+ appender.reset(appenderBuffer, true);
+ if (!appender.append(tupleAccessor, i)) {
+ throw new IllegalStateException();
+ }
+ }
+ }
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see edu.uci.ics.hyracks.api.comm.IFrameWriter#fail()
+ */
+ @Override
+ public void fail() throws HyracksDataException {
+ for (int i = 0; i < appenders.length; ++i) {
+ pWriters[i].fail();
+ }
+ }
+
+ private void flushFrame(ByteBuffer buffer, IFrameWriter frameWriter) throws HyracksDataException {
+ buffer.position(0);
+ buffer.limit(buffer.capacity());
+ frameWriter.nextFrame(buffer);
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see edu.uci.ics.hyracks.api.comm.IFrameWriter#close()
+ */
+ @Override
+ public void close() throws HyracksDataException {
+ for (int i = 0; i < pWriters.length; ++i) {
+ if (appenders[i].getTupleCount() > 0) {
+ flushFrame(appenders[i].getBuffer(), pWriters[i]);
+ }
+ pWriters[i].close();
+ }
+ }
+
+}
diff --git a/hyracks-examples/hyracks-integration-tests/src/test/java/edu/uci/ics/hyracks/tests/integration/AbstractMultiNCIntegrationTest.java b/hyracks-examples/hyracks-integration-tests/src/test/java/edu/uci/ics/hyracks/tests/integration/AbstractMultiNCIntegrationTest.java
new file mode 100644
index 0000000..dec42c1
--- /dev/null
+++ b/hyracks-examples/hyracks-integration-tests/src/test/java/edu/uci/ics/hyracks/tests/integration/AbstractMultiNCIntegrationTest.java
@@ -0,0 +1,146 @@
+/*
+ * Copyright 2009-2010 by The Regents of the University of California
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * you may obtain a copy of the License from
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package edu.uci.ics.hyracks.tests.integration;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.EnumSet;
+import java.util.List;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+import org.apache.commons.io.FileUtils;
+import org.junit.AfterClass;
+import org.junit.BeforeClass;
+import org.junit.Rule;
+import org.junit.rules.TemporaryFolder;
+
+import edu.uci.ics.hyracks.api.client.HyracksConnection;
+import edu.uci.ics.hyracks.api.client.IHyracksClientConnection;
+import edu.uci.ics.hyracks.api.job.JobFlag;
+import edu.uci.ics.hyracks.api.job.JobId;
+import edu.uci.ics.hyracks.api.job.JobSpecification;
+import edu.uci.ics.hyracks.control.cc.ClusterControllerService;
+import edu.uci.ics.hyracks.control.common.controllers.CCConfig;
+import edu.uci.ics.hyracks.control.common.controllers.NCConfig;
+import edu.uci.ics.hyracks.control.nc.NodeControllerService;
+
+public abstract class AbstractMultiNCIntegrationTest {
+
+ private static final Logger LOGGER = Logger.getLogger(AbstractMultiNCIntegrationTest.class.getName());
+
+ public static final String[] ASTERIX_IDS = { "asterix-001", "asterix-002", "asterix-003", "asterix-004",
+ "asterix-005", "asterix-006", "asterix-007" };
+
+ private static ClusterControllerService cc;
+
+ private static NodeControllerService[] asterixNCs;
+
+ private static IHyracksClientConnection hcc;
+
+ private final List<File> outputFiles;
+
+ @Rule
+ public TemporaryFolder outputFolder = new TemporaryFolder();
+
+ public AbstractMultiNCIntegrationTest() {
+ outputFiles = new ArrayList<File>();;
+ }
+
+ @BeforeClass
+ public static void init() throws Exception {
+ CCConfig ccConfig = new CCConfig();
+ ccConfig.clientNetIpAddress = "127.0.0.1";
+ ccConfig.clientNetPort = 39000;
+ ccConfig.clusterNetIpAddress = "127.0.0.1";
+ ccConfig.clusterNetPort = 39001;
+ ccConfig.profileDumpPeriod = 10000;
+ File outDir = new File("target/ClusterController");
+ outDir.mkdirs();
+ File ccRoot = File.createTempFile(AbstractMultiNCIntegrationTest.class.getName(), ".data", outDir);
+ ccRoot.delete();
+ ccRoot.mkdir();
+ ccConfig.ccRoot = ccRoot.getAbsolutePath();
+ cc = new ClusterControllerService(ccConfig);
+ cc.start();
+
+ asterixNCs = new NodeControllerService[ASTERIX_IDS.length];
+ for (int i = 0; i < ASTERIX_IDS.length; i++) {
+ NCConfig ncConfig = new NCConfig();
+ ncConfig.ccHost = "localhost";
+ ncConfig.ccPort = 39001;
+ ncConfig.clusterNetIPAddress = "127.0.0.1";
+ ncConfig.dataIPAddress = "127.0.0.1";
+ ncConfig.nodeId = ASTERIX_IDS[i];
+ asterixNCs[i] = new NodeControllerService(ncConfig);
+ asterixNCs[i].start();
+ }
+
+ hcc = new HyracksConnection(ccConfig.clientNetIpAddress, ccConfig.clientNetPort);
+ hcc.createApplication("test", null);
+ if (LOGGER.isLoggable(Level.INFO)) {
+ LOGGER.info("Starting CC in " + ccRoot.getAbsolutePath());
+ }
+ }
+
+ @AfterClass
+ public static void deinit() throws Exception {
+ for (NodeControllerService nc : asterixNCs) {
+ nc.stop();
+ }
+ cc.stop();
+ }
+
+ protected void runTest(JobSpecification spec) throws Exception {
+ JobId jobId = hcc.createJob("test", spec, EnumSet.of(JobFlag.PROFILE_RUNTIME));
+ if (LOGGER.isLoggable(Level.INFO)) {
+ LOGGER.info(spec.toJSON().toString(2));
+ }
+ hcc.start(jobId);
+ if (LOGGER.isLoggable(Level.INFO)) {
+ LOGGER.info(jobId.toString());
+ }
+ hcc.waitForCompletion(jobId);
+ dumpOutputFiles();
+ }
+
+ private void dumpOutputFiles() {
+ if (LOGGER.isLoggable(Level.INFO)) {
+ for (File f : outputFiles) {
+ if (f.exists() && f.isFile()) {
+ try {
+ LOGGER.info("Reading file: " + f.getAbsolutePath() + " in test: " + getClass().getName());
+ String data = FileUtils.readFileToString(f);
+ LOGGER.info(data);
+ } catch (IOException e) {
+ LOGGER.info("Error reading file: " + f.getAbsolutePath());
+ LOGGER.info(e.getMessage());
+ }
+ }
+ }
+ }
+ }
+
+ protected File createTempFile() throws IOException {
+ File tempFile = File.createTempFile(getClass().getName(), ".tmp", outputFolder.getRoot());
+ if (LOGGER.isLoggable(Level.INFO)) {
+ LOGGER.info("Output file: " + tempFile.getAbsolutePath());
+ }
+ outputFiles.add(tempFile);
+ return tempFile;
+ }
+
+}
diff --git a/hyracks-examples/hyracks-integration-tests/src/test/java/edu/uci/ics/hyracks/tests/integration/LocalityAwareConnectorTest.java b/hyracks-examples/hyracks-integration-tests/src/test/java/edu/uci/ics/hyracks/tests/integration/LocalityAwareConnectorTest.java
new file mode 100644
index 0000000..a7a0a73
--- /dev/null
+++ b/hyracks-examples/hyracks-integration-tests/src/test/java/edu/uci/ics/hyracks/tests/integration/LocalityAwareConnectorTest.java
@@ -0,0 +1,254 @@
+/*
+ * Copyright 2009-2010 by The Regents of the University of California
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * you may obtain a copy of the License from
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package edu.uci.ics.hyracks.tests.integration;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.BitSet;
+
+import org.junit.Test;
+
+import edu.uci.ics.hyracks.api.constraints.PartitionConstraintHelper;
+import edu.uci.ics.hyracks.api.dataflow.IConnectorDescriptor;
+import edu.uci.ics.hyracks.api.dataflow.value.IBinaryComparatorFactory;
+import edu.uci.ics.hyracks.api.dataflow.value.IBinaryHashFunctionFactory;
+import edu.uci.ics.hyracks.api.dataflow.value.ISerializerDeserializer;
+import edu.uci.ics.hyracks.api.dataflow.value.RecordDescriptor;
+import edu.uci.ics.hyracks.api.io.FileReference;
+import edu.uci.ics.hyracks.api.job.JobSpecification;
+import edu.uci.ics.hyracks.data.std.accessors.PointableBinaryComparatorFactory;
+import edu.uci.ics.hyracks.data.std.accessors.PointableBinaryHashFunctionFactory;
+import edu.uci.ics.hyracks.data.std.primitive.UTF8StringPointable;
+import edu.uci.ics.hyracks.dataflow.common.data.marshalling.FloatSerializerDeserializer;
+import edu.uci.ics.hyracks.dataflow.common.data.marshalling.IntegerSerializerDeserializer;
+import edu.uci.ics.hyracks.dataflow.common.data.marshalling.UTF8StringSerializerDeserializer;
+import edu.uci.ics.hyracks.dataflow.common.data.parsers.FloatParserFactory;
+import edu.uci.ics.hyracks.dataflow.common.data.parsers.IValueParserFactory;
+import edu.uci.ics.hyracks.dataflow.common.data.parsers.IntegerParserFactory;
+import edu.uci.ics.hyracks.dataflow.common.data.parsers.UTF8StringParserFactory;
+import edu.uci.ics.hyracks.dataflow.common.data.partition.FieldHashPartitionComputerFactory;
+import edu.uci.ics.hyracks.dataflow.std.base.AbstractSingleActivityOperatorDescriptor;
+import edu.uci.ics.hyracks.dataflow.std.connectors.GlobalHashingLocalityMap;
+import edu.uci.ics.hyracks.dataflow.std.connectors.HashtableLocalityMap;
+import edu.uci.ics.hyracks.dataflow.std.connectors.LocalityAwareMToNPartitioningConnectorDescriptor;
+import edu.uci.ics.hyracks.dataflow.std.connectors.MToNPartitioningConnectorDescriptor;
+import edu.uci.ics.hyracks.dataflow.std.connectors.OneToOneConnectorDescriptor;
+import edu.uci.ics.hyracks.dataflow.std.file.ConstantFileSplitProvider;
+import edu.uci.ics.hyracks.dataflow.std.file.DelimitedDataTupleParserFactory;
+import edu.uci.ics.hyracks.dataflow.std.file.FileScanOperatorDescriptor;
+import edu.uci.ics.hyracks.dataflow.std.file.FileSplit;
+import edu.uci.ics.hyracks.dataflow.std.file.IFileSplitProvider;
+import edu.uci.ics.hyracks.dataflow.std.file.ITupleParserFactory;
+import edu.uci.ics.hyracks.dataflow.std.file.PlainFileWriterOperatorDescriptor;
+import edu.uci.ics.hyracks.dataflow.std.group.HashGroupOperatorDescriptor;
+import edu.uci.ics.hyracks.dataflow.std.group.IFieldAggregateDescriptorFactory;
+import edu.uci.ics.hyracks.dataflow.std.group.aggregators.FloatSumFieldAggregatorFactory;
+import edu.uci.ics.hyracks.dataflow.std.group.aggregators.IntSumFieldAggregatorFactory;
+import edu.uci.ics.hyracks.dataflow.std.group.aggregators.MultiFieldsAggregatorFactory;
+
+public class LocalityAwareConnectorTest extends AbstractMultiNCIntegrationTest {
+
+ final IFileSplitProvider splitProvider = new ConstantFileSplitProvider(new FileSplit[] {
+ new FileSplit("asterix-001", new FileReference(new File("data/tpch0.001/lineitem.tbl"))),
+ new FileSplit("asterix-002", new FileReference(new File("data/tpch0.001/lineitem.tbl"))),
+ new FileSplit("asterix-003", new FileReference(new File("data/tpch0.001/lineitem.tbl"))),
+ new FileSplit("asterix-004", new FileReference(new File("data/tpch0.001/lineitem.tbl"))) });
+
+ final RecordDescriptor desc = new RecordDescriptor(new ISerializerDeserializer[] {
+ UTF8StringSerializerDeserializer.INSTANCE, IntegerSerializerDeserializer.INSTANCE,
+ IntegerSerializerDeserializer.INSTANCE, IntegerSerializerDeserializer.INSTANCE,
+ IntegerSerializerDeserializer.INSTANCE, FloatSerializerDeserializer.INSTANCE,
+ FloatSerializerDeserializer.INSTANCE, FloatSerializerDeserializer.INSTANCE,
+ UTF8StringSerializerDeserializer.INSTANCE, UTF8StringSerializerDeserializer.INSTANCE,
+ UTF8StringSerializerDeserializer.INSTANCE, UTF8StringSerializerDeserializer.INSTANCE,
+ UTF8StringSerializerDeserializer.INSTANCE, UTF8StringSerializerDeserializer.INSTANCE,
+ UTF8StringSerializerDeserializer.INSTANCE, UTF8StringSerializerDeserializer.INSTANCE });
+
+ final ITupleParserFactory tupleParserFactory = new DelimitedDataTupleParserFactory(new IValueParserFactory[] {
+ UTF8StringParserFactory.INSTANCE, IntegerParserFactory.INSTANCE, IntegerParserFactory.INSTANCE,
+ IntegerParserFactory.INSTANCE, IntegerParserFactory.INSTANCE, FloatParserFactory.INSTANCE,
+ FloatParserFactory.INSTANCE, FloatParserFactory.INSTANCE, UTF8StringParserFactory.INSTANCE,
+ UTF8StringParserFactory.INSTANCE, UTF8StringParserFactory.INSTANCE, UTF8StringParserFactory.INSTANCE,
+ UTF8StringParserFactory.INSTANCE, UTF8StringParserFactory.INSTANCE, UTF8StringParserFactory.INSTANCE,
+ UTF8StringParserFactory.INSTANCE, }, '|');
+
+ /**
+ * Test of aggregations using locality aware connector. The output two files should be the
+ * same, each of which is the aggregation of two copies of the lineitem.tbl.
+ *
+ * Note that if the hashing connector is not working correctly, the two files may be different. This
+ * also means that even the output files are the same, the hashing may have other problems.
+ *
+ * @throws Exception
+ */
+ @Test
+ public void localityAwareAggregationTest() throws Exception {
+
+ JobSpecification spec = new JobSpecification();
+
+ FileScanOperatorDescriptor csvScanner = new FileScanOperatorDescriptor(
+ spec, splitProvider, tupleParserFactory, desc);
+
+ PartitionConstraintHelper.addAbsoluteLocationConstraint(spec,
+ csvScanner, "asterix-001", "asterix-002", "asterix-003", "asterix-004");
+
+ RecordDescriptor outputRec = new RecordDescriptor(
+ new ISerializerDeserializer[] {
+ UTF8StringSerializerDeserializer.INSTANCE,
+ IntegerSerializerDeserializer.INSTANCE,
+ IntegerSerializerDeserializer.INSTANCE,
+ FloatSerializerDeserializer.INSTANCE });
+
+ int[] keyFields = new int[] { 0 };
+ int tableSize = 8;
+
+ HashGroupOperatorDescriptor grouper = new HashGroupOperatorDescriptor(
+ spec,
+ keyFields,
+ new FieldHashPartitionComputerFactory(
+ keyFields,
+ new IBinaryHashFunctionFactory[] { PointableBinaryHashFunctionFactory
+ .of(UTF8StringPointable.FACTORY) }),
+ new IBinaryComparatorFactory[] { PointableBinaryComparatorFactory
+ .of(UTF8StringPointable.FACTORY) },
+ new MultiFieldsAggregatorFactory(
+ new IFieldAggregateDescriptorFactory[] {
+ new IntSumFieldAggregatorFactory(1, true),
+ new IntSumFieldAggregatorFactory(3, true),
+ new FloatSumFieldAggregatorFactory(5, true) }),
+ outputRec, tableSize);
+
+ PartitionConstraintHelper.addAbsoluteLocationConstraint(spec, grouper,
+ "asterix-005", "asterix-006");
+
+ BitSet nodemap = new BitSet(8);
+
+ nodemap.set(0);
+ nodemap.set(2);
+ nodemap.set(5);
+ nodemap.set(7);
+
+ IConnectorDescriptor conn1 = new LocalityAwareMToNPartitioningConnectorDescriptor(spec, new FieldHashPartitionComputerFactory(
+ keyFields,
+ new IBinaryHashFunctionFactory[] { PointableBinaryHashFunctionFactory
+ .of(UTF8StringPointable.FACTORY) }), new HashtableLocalityMap(nodemap));
+
+ new MToNPartitioningConnectorDescriptor(
+ spec,
+ new FieldHashPartitionComputerFactory(
+ keyFields,
+ new IBinaryHashFunctionFactory[] { PointableBinaryHashFunctionFactory
+ .of(UTF8StringPointable.FACTORY) }));
+ spec.connect(conn1, csvScanner, 0, grouper, 0);
+
+ AbstractSingleActivityOperatorDescriptor printer = getPrinter(spec,
+ "localityAwareSumInmemGroupTest");
+
+ PartitionConstraintHelper.addAbsoluteLocationConstraint(spec, printer,
+ "asterix-005", "asterix-006");
+
+ IConnectorDescriptor conn2 = new OneToOneConnectorDescriptor(spec);
+ spec.connect(conn2, grouper, 0, printer, 0);
+
+ spec.addRoot(printer);
+ runTest(spec);
+ }
+
+ /**
+ * Test for locality aware connector, using the global hashing node mapper. This should have
+ * the exactly the same result as using {@link MToNPartitioningConnectorDescriptor}.
+ *
+ * @throws Exception
+ */
+ @Test
+ public void globalPartitionAggregationTest() throws Exception {
+
+ JobSpecification spec = new JobSpecification();
+
+ FileScanOperatorDescriptor csvScanner = new FileScanOperatorDescriptor(
+ spec, splitProvider, tupleParserFactory, desc);
+
+ PartitionConstraintHelper.addAbsoluteLocationConstraint(spec,
+ csvScanner, "asterix-001", "asterix-002", "asterix-003", "asterix-004");
+
+ RecordDescriptor outputRec = new RecordDescriptor(
+ new ISerializerDeserializer[] {
+ UTF8StringSerializerDeserializer.INSTANCE,
+ IntegerSerializerDeserializer.INSTANCE,
+ IntegerSerializerDeserializer.INSTANCE,
+ FloatSerializerDeserializer.INSTANCE });
+
+ int[] keyFields = new int[] { 0 };
+ int tableSize = 8;
+
+ HashGroupOperatorDescriptor grouper = new HashGroupOperatorDescriptor(
+ spec,
+ keyFields,
+ new FieldHashPartitionComputerFactory(
+ keyFields,
+ new IBinaryHashFunctionFactory[] { PointableBinaryHashFunctionFactory
+ .of(UTF8StringPointable.FACTORY) }),
+ new IBinaryComparatorFactory[] { PointableBinaryComparatorFactory
+ .of(UTF8StringPointable.FACTORY) },
+ new MultiFieldsAggregatorFactory(
+ new IFieldAggregateDescriptorFactory[] {
+ new IntSumFieldAggregatorFactory(1, true),
+ new IntSumFieldAggregatorFactory(3, true),
+ new FloatSumFieldAggregatorFactory(5, true) }),
+ outputRec, tableSize);
+
+ PartitionConstraintHelper.addAbsoluteLocationConstraint(spec, grouper,
+ "asterix-005", "asterix-006");
+
+ IConnectorDescriptor conn1 = new LocalityAwareMToNPartitioningConnectorDescriptor(spec, new FieldHashPartitionComputerFactory(
+ keyFields,
+ new IBinaryHashFunctionFactory[] { PointableBinaryHashFunctionFactory
+ .of(UTF8StringPointable.FACTORY) }), new GlobalHashingLocalityMap());
+
+ new MToNPartitioningConnectorDescriptor(
+ spec,
+ new FieldHashPartitionComputerFactory(
+ keyFields,
+ new IBinaryHashFunctionFactory[] { PointableBinaryHashFunctionFactory
+ .of(UTF8StringPointable.FACTORY) }));
+ spec.connect(conn1, csvScanner, 0, grouper, 0);
+
+ AbstractSingleActivityOperatorDescriptor printer = getPrinter(spec,
+ "localityAwareSumInmemGroupTest");
+
+ PartitionConstraintHelper.addAbsoluteLocationConstraint(spec, printer,
+ "asterix-005", "asterix-006");
+
+ IConnectorDescriptor conn2 = new OneToOneConnectorDescriptor(spec);
+ spec.connect(conn2, grouper, 0, printer, 0);
+
+ spec.addRoot(printer);
+ runTest(spec);
+ }
+
+ private AbstractSingleActivityOperatorDescriptor getPrinter(
+ JobSpecification spec, String prefix) throws IOException {
+
+ AbstractSingleActivityOperatorDescriptor printer = new PlainFileWriterOperatorDescriptor(
+ spec, new ConstantFileSplitProvider(new FileSplit[] {
+ new FileSplit("asterix-005", createTempFile()
+ .getAbsolutePath()),
+ new FileSplit("asterix-006", createTempFile()
+ .getAbsolutePath()) }), "\t");
+
+ return printer;
+ }
+
+}
diff --git a/hyracks-ipc/src/main/java/edu/uci/ics/hyracks/ipc/api/IPCPerformanceCounters.java b/hyracks-ipc/src/main/java/edu/uci/ics/hyracks/ipc/api/IPCPerformanceCounters.java
new file mode 100644
index 0000000..1873378
--- /dev/null
+++ b/hyracks-ipc/src/main/java/edu/uci/ics/hyracks/ipc/api/IPCPerformanceCounters.java
@@ -0,0 +1,66 @@
+/*
+ * Copyright 2009-2010 by The Regents of the University of California
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * you may obtain a copy of the License from
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package edu.uci.ics.hyracks.ipc.api;
+
+import java.util.concurrent.atomic.AtomicLong;
+
+public class IPCPerformanceCounters {
+ private final AtomicLong nMessagesSent;
+
+ private final AtomicLong nMessageBytesSent;
+
+ private final AtomicLong nMessagesReceived;
+
+ private final AtomicLong nMessageBytesReceived;
+
+ public IPCPerformanceCounters() {
+ nMessagesSent = new AtomicLong();
+ nMessageBytesSent = new AtomicLong();
+ nMessagesReceived = new AtomicLong();
+ nMessageBytesReceived = new AtomicLong();
+ }
+
+ public long getMessageSentCount() {
+ return nMessagesSent.get();
+ }
+
+ public void addMessageSentCount(long delta) {
+ nMessagesSent.addAndGet(delta);
+ }
+
+ public long getMessageBytesSent() {
+ return nMessageBytesSent.get();
+ }
+
+ public void addMessageBytesSent(long delta) {
+ nMessageBytesSent.addAndGet(delta);
+ }
+
+ public long getMessageReceivedCount() {
+ return nMessagesReceived.get();
+ }
+
+ public void addMessageReceivedCount(long delta) {
+ nMessagesReceived.addAndGet(delta);
+ }
+
+ public long getMessageBytesReceived() {
+ return nMessageBytesReceived.get();
+ }
+
+ public void addMessageBytesReceived(long delta) {
+ nMessageBytesReceived.addAndGet(delta);
+ }
+}
\ No newline at end of file
diff --git a/hyracks-ipc/src/main/java/edu/uci/ics/hyracks/ipc/impl/IPCConnectionManager.java b/hyracks-ipc/src/main/java/edu/uci/ics/hyracks/ipc/impl/IPCConnectionManager.java
index eef068b..8e42d53 100644
--- a/hyracks-ipc/src/main/java/edu/uci/ics/hyracks/ipc/impl/IPCConnectionManager.java
+++ b/hyracks-ipc/src/main/java/edu/uci/ics/hyracks/ipc/impl/IPCConnectionManager.java
@@ -206,6 +206,7 @@
boolean success = msg.write(buffer);
buffer.flip();
if (success) {
+ system.getPerformanceCounters().addMessageSentCount(1);
SelectionKey key = handle.getKey();
key.interestOps(key.interestOps() | SelectionKey.OP_WRITE);
} else {
@@ -235,6 +236,7 @@
IPCHandle handle = (IPCHandle) key.attachment();
ByteBuffer readBuffer = handle.getInBuffer();
int len = channel.read(readBuffer);
+ system.getPerformanceCounters().addMessageBytesReceived(len);
if (len < 0) {
key.cancel();
channel.close();
@@ -250,6 +252,7 @@
IPCHandle handle = (IPCHandle) key.attachment();
ByteBuffer writeBuffer = handle.getOutBuffer();
int len = channel.write(writeBuffer);
+ system.getPerformanceCounters().addMessageBytesSent(len);
if (len < 0) {
key.cancel();
channel.close();
@@ -289,15 +292,12 @@
}
private void copyUnsentMessages(BitSet unsentMessagesBitmap, List<Message> tempUnsentMessages) {
- tempUnsentMessages.clear();
+ assert tempUnsentMessages.isEmpty();
for (int i = unsentMessagesBitmap.nextSetBit(0); i >= 0; i = unsentMessagesBitmap.nextSetBit(i + 1)) {
tempUnsentMessages.add(workingSendList.get(i));
}
workingSendList.clear();
- int tempLen = tempUnsentMessages.size();
- for (int i = 0; i < tempLen; ++i) {
- workingSendList.add(tempUnsentMessages.get(i));
- }
+ moveAll(tempUnsentMessages, workingSendList);
}
}
diff --git a/hyracks-ipc/src/main/java/edu/uci/ics/hyracks/ipc/impl/IPCHandle.java b/hyracks-ipc/src/main/java/edu/uci/ics/hyracks/ipc/impl/IPCHandle.java
index 3d3bc7a..749afe2 100644
--- a/hyracks-ipc/src/main/java/edu/uci/ics/hyracks/ipc/impl/IPCHandle.java
+++ b/hyracks-ipc/src/main/java/edu/uci/ics/hyracks/ipc/impl/IPCHandle.java
@@ -141,6 +141,7 @@
message.setFlag(Message.ERROR);
message.setPayload(e);
}
+ system.getPerformanceCounters().addMessageReceivedCount(1);
if (state == HandleState.CONNECT_RECEIVED) {
remoteAddress = (InetSocketAddress) message.getPayload();
diff --git a/hyracks-ipc/src/main/java/edu/uci/ics/hyracks/ipc/impl/IPCSystem.java b/hyracks-ipc/src/main/java/edu/uci/ics/hyracks/ipc/impl/IPCSystem.java
index 6c9c82c..d7e383d 100644
--- a/hyracks-ipc/src/main/java/edu/uci/ics/hyracks/ipc/impl/IPCSystem.java
+++ b/hyracks-ipc/src/main/java/edu/uci/ics/hyracks/ipc/impl/IPCSystem.java
@@ -20,6 +20,7 @@
import edu.uci.ics.hyracks.ipc.api.IIPCHandle;
import edu.uci.ics.hyracks.ipc.api.IIPCI;
+import edu.uci.ics.hyracks.ipc.api.IPCPerformanceCounters;
import edu.uci.ics.hyracks.ipc.api.IPayloadSerializerDeserializer;
import edu.uci.ics.hyracks.ipc.exceptions.IPCException;
@@ -32,12 +33,15 @@
private final AtomicLong midFactory;
+ private final IPCPerformanceCounters perfCounters;
+
public IPCSystem(InetSocketAddress socketAddress, IIPCI ipci, IPayloadSerializerDeserializer serde)
throws IOException {
cMgr = new IPCConnectionManager(this, socketAddress);
this.ipci = ipci;
this.serde = serde;
midFactory = new AtomicLong();
+ perfCounters = new IPCPerformanceCounters();
}
public InetSocketAddress getSocketAddress() {
@@ -82,4 +86,8 @@
IPCConnectionManager getConnectionManager() {
return cMgr;
}
+
+ public IPCPerformanceCounters getPerformanceCounters() {
+ return perfCounters;
+ }
}
\ No newline at end of file
diff --git a/hyracks-net/src/main/java/edu/uci/ics/hyracks/net/protocols/muxdemux/MuxDemux.java b/hyracks-net/src/main/java/edu/uci/ics/hyracks/net/protocols/muxdemux/MuxDemux.java
index b041e2c..64ef6ae7 100644
--- a/hyracks-net/src/main/java/edu/uci/ics/hyracks/net/protocols/muxdemux/MuxDemux.java
+++ b/hyracks-net/src/main/java/edu/uci/ics/hyracks/net/protocols/muxdemux/MuxDemux.java
@@ -32,7 +32,7 @@
private final TCPEndpoint tcpEndpoint;
- private final PerformanceCounters perfCounters;
+ private final MuxDemuxPerformanceCounters perfCounters;
public MuxDemux(InetSocketAddress localAddress, IChannelOpenListener listener, int nThreads) {
this.localAddress = localAddress;
@@ -59,7 +59,7 @@
connection.setAttachment(mConn);
}
}, nThreads);
- perfCounters = new PerformanceCounters();
+ perfCounters = new MuxDemuxPerformanceCounters();
}
public void start() throws IOException {
@@ -88,7 +88,7 @@
return tcpEndpoint.getLocalAddress();
}
- public PerformanceCounters getPerformanceCounters() {
+ public MuxDemuxPerformanceCounters getPerformanceCounters() {
return perfCounters;
}
}
\ No newline at end of file
diff --git a/hyracks-net/src/main/java/edu/uci/ics/hyracks/net/protocols/muxdemux/PerformanceCounters.java b/hyracks-net/src/main/java/edu/uci/ics/hyracks/net/protocols/muxdemux/MuxDemuxPerformanceCounters.java
similarity index 95%
rename from hyracks-net/src/main/java/edu/uci/ics/hyracks/net/protocols/muxdemux/PerformanceCounters.java
rename to hyracks-net/src/main/java/edu/uci/ics/hyracks/net/protocols/muxdemux/MuxDemuxPerformanceCounters.java
index a203f06..6bf21aa 100644
--- a/hyracks-net/src/main/java/edu/uci/ics/hyracks/net/protocols/muxdemux/PerformanceCounters.java
+++ b/hyracks-net/src/main/java/edu/uci/ics/hyracks/net/protocols/muxdemux/MuxDemuxPerformanceCounters.java
@@ -16,7 +16,7 @@
import java.util.concurrent.atomic.AtomicLong;
-public class PerformanceCounters {
+public class MuxDemuxPerformanceCounters {
private final AtomicLong payloadBytesRead;
private final AtomicLong payloadBytesWritten;
@@ -25,7 +25,7 @@
private final AtomicLong signalingBytesWritten;
- public PerformanceCounters() {
+ public MuxDemuxPerformanceCounters() {
payloadBytesRead = new AtomicLong();
payloadBytesWritten = new AtomicLong();
signalingBytesRead = new AtomicLong();