You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@airavata.apache.org by sa...@apache.org on 2012/03/31 00:25:01 UTC

svn commit: r1307642 [37/40] - in /incubator/airavata/trunk/scratch/xbaya-web: ./ components/ components/calculator/ components/logic/ core/ css/ data/ dynamic_components/ js/ js/jquery/ js/jquery/css/ js/jquery/css/ui-lightness/ js/jquery/css/ui-light...

Added: incubator/airavata/trunk/scratch/xbaya-web/js/jquery/jquery.jsPlumb-1.3.6-all.js
URL: http://svn.apache.org/viewvc/incubator/airavata/trunk/scratch/xbaya-web/js/jquery/jquery.jsPlumb-1.3.6-all.js?rev=1307642&view=auto
==============================================================================
--- incubator/airavata/trunk/scratch/xbaya-web/js/jquery/jquery.jsPlumb-1.3.6-all.js (added)
+++ incubator/airavata/trunk/scratch/xbaya-web/js/jquery/jquery.jsPlumb-1.3.6-all.js Fri Mar 30 22:24:45 2012
@@ -0,0 +1,8474 @@
+/*
+ * jsPlumb
+ * 
+ * Title:jsPlumb 1.3.6
+ * 
+ * Provides a way to visually connect elements on an HTML page, using either SVG, Canvas
+ * elements, or VML.  
+ * 
+ * This file contains the jsPlumb core code.
+ *
+ * Copyright (c) 2010 - 2012 Simon Porritt (simon.porritt@gmail.com)
+ * 
+ * http://jsplumb.org
+ * http://github.com/sporritt/jsplumb
+ * http://code.google.com/p/jsplumb
+ * 
+ * Dual licensed under the MIT and GPL2 licenses.
+ */
+
+;(function() {
+	
+	/**
+	 * Class:jsPlumb
+	 * The jsPlumb engine, registered as a static object in the window.  This object contains all of the methods you will use to
+	 * create and maintain Connections and Endpoints.
+	 */	
+	
+	var canvasAvailable = !!document.createElement('canvas').getContext,
+		svgAvailable = !!window.SVGAngle || document.implementation.hasFeature("http://www.w3.org/TR/SVG11/feature#BasicStructure", "1.1"),
+	// TODO what is a good test for VML availability? aside from just assuming its there because nothing else is.
+		vmlAvailable = !(canvasAvailable | svgAvailable);
+	
+    var _findWithFunction = function(a, f) {
+    	if (a)
+  			for (var i = 0; i < a.length; i++) if (f(a[i])) return i;
+		return -1;
+	},
+	_indexOf = function(l, v) {
+		return _findWithFunction(l, function(_v) { return _v == v; });	
+	},
+    _removeWithFunction = function(a, f) {
+        var idx = _findWithFunction(a, f);
+        if (idx > -1) a.splice(idx, 1);
+        return idx != -1;
+    },
+    _remove = function(l, v) {
+    	var idx = _indexOf(l, v);	
+    	if (idx > -1) l.splice(idx, 1);
+        return idx != -1;
+    },
+    // TODO support insert index
+    _addWithFunction = function(list, item, hashFunction) {
+        if (_findWithFunction(list, hashFunction) == -1) list.push(item);
+    },
+    _addToList = function(map, key, value) {
+		var l = map[key];
+		if (l == null) {
+			l = [], map[key] = l;
+		}
+		l.push(value);
+		return l;
+	};
+	
+	// for those browsers that dont have it.  they still don't have it! but at least they won't crash.
+	if (!window.console)
+		window.console = { time:function(){}, timeEnd:function(){}, group:function(){}, groupEnd:function(){}, log:function(){} };
+	
+	/**
+		 * helper method to add an item to a list, creating the list if it does
+		 * not yet exist.
+		 */
+		var _connectionBeingDragged = null,
+		_getAttribute = function(el, attName) { return jsPlumb.CurrentLibrary.getAttribute(_getElementObject(el), attName); },
+		_setAttribute = function(el, attName, attValue) { jsPlumb.CurrentLibrary.setAttribute(_getElementObject(el), attName, attValue); },
+		_addClass = function(el, clazz) { jsPlumb.CurrentLibrary.addClass(_getElementObject(el), clazz); },
+		_hasClass = function(el, clazz) { return jsPlumb.CurrentLibrary.hasClass(_getElementObject(el), clazz); },
+		_removeClass = function(el, clazz) { jsPlumb.CurrentLibrary.removeClass(_getElementObject(el), clazz); },
+		_getElementObject = function(el) { return jsPlumb.CurrentLibrary.getElementObject(el); },
+		_getOffset = function(el) { return jsPlumb.CurrentLibrary.getOffset(_getElementObject(el)); },		
+		_getSize = function(el) { return jsPlumb.CurrentLibrary.getSize(_getElementObject(el)); },
+		_logEnabled = true,
+		_log = function() {
+		    if (_logEnabled && typeof console != "undefined") {
+                try {
+                    var msg = arguments[arguments.length - 1];
+				    console.log(msg);
+                }
+                catch (e) {} 
+            }
+		},
+		_group = function(g) { if (_logEnabled && typeof console != "undefined") console.group(g); },
+		_groupEnd = function(g) { if (_logEnabled && typeof console != "undefined") console.groupEnd(g); },
+		_time = function(t) { if (_logEnabled && typeof console != "undefined") console.time(t); },
+		_timeEnd = function(t) { if (_logEnabled && typeof console != "undefined") console.timeEnd(t); };
+		
+		/**
+		 * EventGenerator
+		 * Superclass for objects that generate events - jsPlumb extends this, as does jsPlumbUIComponent, which all the UI elements extend.
+		 */
+		EventGenerator = function() {
+			var _listeners = {}, self = this;
+			
+			// this is a list of events that should re-throw any errors that occur during their dispatch. as of 1.3.0 this is private to
+			// jsPlumb, but it seems feasible that people might want to manipulate this list.  the thinking is that we don't want event
+			// listeners to bring down jsPlumb - or do we.  i can't make up my mind about this, but i know i want to hear about it if the "ready"
+			// event fails, because then my page has most likely not initialised.  so i have this halfway-house solution.  it will be interesting
+			// to hear what other people think.
+			var eventsToDieOn = [ "ready" ];
+								    
+			/*
+			 * Binds a listener to an event.  
+			 * 
+			 * Parameters:
+			 * 	event		-	name of the event to bind to.
+			 * 	listener	-	function to execute.
+			 */
+			this.bind = function(event, listener) {
+				_addToList(_listeners, event, listener);				
+			};
+			/*
+			 * Fires an update for the given event.
+			 * 
+			 * Parameters:
+			 * 	event				-	event to fire
+			 * 	value				-	value to pass to the event listener(s).
+			 *  originalEvent	 	- 	the original event from the browser
+			 */			
+			this.fire = function(event, value, originalEvent) {
+				if (_listeners[event]) {
+					for ( var i = 0; i < _listeners[event].length; i++) {
+						// doing it this way rather than catching and then possibly re-throwing means that an error propagated by this
+						// method will have the whole call stack available in the debugger.
+						//if (_findIndex(eventsToDieOn, event) != -1)
+						if (_findWithFunction(eventsToDieOn, function(e) { return e === event}) != -1)
+							_listeners[event][i](value, originalEvent);
+						else {
+							// for events we don't want to die on, catch and log.
+							try {
+								_listeners[event][i](value, originalEvent);
+							} catch (e) {
+								_log("jsPlumb: fire failed for event " + event + " : " + e);
+							}
+						}
+					}
+				}
+			};
+			/*
+			 * Clears either all listeners, or listeners for some specific event.
+			 * 
+			 * Parameters:
+			 * 	event	-	optional. constrains the clear to just listeners for this event.
+			 */
+			this.clearListeners = function(event) {
+				if (event)
+					delete _listeners[event];
+				else {
+					delete _listeners;
+					_listeners = {};
+				}
+			};
+			
+			this.getListener = function(forEvent) {
+				return _listeners[forEvent];
+			};		
+		},
+		
+		/**
+		 * creates a timestamp, using milliseconds since 1970, but as a string.
+		 */
+		_timestamp = function() { return "" + (new Date()).getTime(); },
+		
+		/*
+		 * Class:jsPlumbUIComponent
+		 * Abstract superclass for UI components Endpoint and Connection.  Provides the abstraction of paintStyle/hoverPaintStyle,
+		 * and also extends EventGenerator to provide the bind and fire methods.
+		 */
+		jsPlumbUIComponent = function(params) {
+			var self = this, a = arguments, _hover = false, parameters = params.parameters || {}, idPrefix = self.idPrefix,
+			id = idPrefix + (new Date()).getTime();
+			self._jsPlumb = params["_jsPlumb"];			
+			self.getId = function() { return id; };
+			self.tooltip = params.tooltip;
+			self.hoverClass = params.hoverClass;				
+			
+			// all components can generate events
+			EventGenerator.apply(this);
+			// all components get this clone function.
+			// TODO issue 116 showed a problem with this - it seems 'a' that is in
+			// the clone function's scope is shared by all invocations of it, the classic
+			// JS closure problem.  for now, jsPlumb does a version of this inline where 
+			// it used to call clone.  but it would be nice to find some time to look
+			// further at this.
+			this.clone = function() {
+				var o = new Object();
+				self.constructor.apply(o, a);
+				return o;
+			};
+			
+			this.getParameter = function(name) { return parameters[name]; },
+			this.getParameters = function() { return parameters; },
+			this.setParameter = function(name, value) { parameters[name] = value; },
+			this.setParameters = function(p) { parameters = p; },			
+			this.overlayPlacements = [], 
+			this.paintStyle = null, 
+			this.hoverPaintStyle = null;
+			
+			// user can supply a beforeDetach callback, which will be executed before a detach
+			// is performed; returning false prevents the detach.
+			var beforeDetach = params.beforeDetach;
+			this.isDetachAllowed = function(connection) {
+				var r = self._jsPlumb.checkCondition("beforeDetach", connection );
+				if (beforeDetach) {
+					try { 
+						r = beforeDetach(connection); 
+					}
+					catch (e) { _log("jsPlumb: beforeDetach callback failed", e); }
+				}
+				return r;
+			};
+			
+			// user can supply a beforeDrop callback, which will be executed before a dropped
+			// connection is confirmed. user can return false to reject connection.
+			var beforeDrop = params.beforeDrop;
+			this.isDropAllowed = function(sourceId, targetId, scope) {
+				var r = self._jsPlumb.checkCondition("beforeDrop", { sourceId:sourceId, targetId:targetId, scope:scope });
+				if (beforeDrop) {
+					try { 
+						r = beforeDrop({ sourceId:sourceId, targetId:targetId, scope:scope }); 
+					}
+					catch (e) { _log("jsPlumb: beforeDrop callback failed", e); }
+				}
+				return r;
+			};
+			
+			// helper method to update the hover style whenever it, or paintStyle, changes.
+			// we use paintStyle as the foundation and merge hoverPaintStyle over the
+			// top.
+			var _updateHoverStyle = function() {
+				if (self.paintStyle && self.hoverPaintStyle) {
+					var mergedHoverStyle = {};
+					jsPlumb.extend(mergedHoverStyle, self.paintStyle);
+					jsPlumb.extend(mergedHoverStyle, self.hoverPaintStyle);
+					delete self["hoverPaintStyle"];
+					// we want the fillStyle of paintStyle to override a gradient, if possible.
+					if (mergedHoverStyle.gradient && self.paintStyle.fillStyle)
+						delete mergedHoverStyle["gradient"];
+					self.hoverPaintStyle = mergedHoverStyle;
+				}
+			};
+			
+			/*
+		     * Sets the paint style and then repaints the element.
+		     * 
+		     * Parameters:
+		     * 	style - Style to use.
+		     */
+		    this.setPaintStyle = function(style, doNotRepaint) {
+		    	self.paintStyle = style;
+		    	self.paintStyleInUse = self.paintStyle;
+		    	_updateHoverStyle();
+		    	if (!doNotRepaint) self.repaint();
+		    };
+		    
+		    /*
+		     * Sets the paint style to use when the mouse is hovering over the element. This is null by default.
+		     * The hover paint style is applied as extensions to the paintStyle; it does not entirely replace
+		     * it.  This is because people will most likely want to change just one thing when hovering, say the
+		     * color for example, but leave the rest of the appearance the same.
+		     * 
+		     * Parameters:
+		     * 	style - Style to use when the mouse is hovering.
+		     *  doNotRepaint - if true, the component will not be repainted.  useful when setting things up initially.
+		     */
+		    this.setHoverPaintStyle = function(style, doNotRepaint) {		    	
+		    	self.hoverPaintStyle = style;
+		    	_updateHoverStyle();
+		    	if (!doNotRepaint) self.repaint();
+		    };
+		    
+		    /*
+		     * sets/unsets the hover state of this element.
+		     * 
+		     * Parameters:
+		     * 	hover - hover state boolean
+		     * 	ignoreAttachedElements - if true, does not notify any attached elements of the change in hover state.  used mostly to avoid infinite loops.
+		     */
+		    this.setHover = function(hover, ignoreAttachedElements, timestamp) {
+		    	// while dragging, we ignore these events.  this keeps the UI from flashing and
+		    	// swishing and whatevering.
+				if (!self._jsPlumb.currentlyDragging && !self._jsPlumb.isHoverSuspended()) {
+		    
+			    	_hover = hover;
+					if (self.hoverClass != null && self.canvas != null) {
+						if (hover) 
+							jpcl.addClass(self.canvas, self.hoverClass);						
+						else
+							jpcl.removeClass(self.canvas, self.hoverClass);
+					}
+		   		 	if (self.hoverPaintStyle != null) {
+						self.paintStyleInUse = hover ? self.hoverPaintStyle : self.paintStyle;
+						timestamp = timestamp || _timestamp();
+						self.repaint({timestamp:timestamp, recalc:false});
+					}
+					// get the list of other affected elements, if supported by this component.
+					// for a connection, its the endpoints.  for an endpoint, its the connections! surprise.
+					if (self.getAttachedElements && !ignoreAttachedElements)
+						_updateAttachedElements(hover, _timestamp(), self);
+				}
+		    };
+		    
+		    this.isHover = function() { return _hover; };
+
+			var jpcl = jsPlumb.CurrentLibrary,
+				events = [ "click", "dblclick", "mouseenter", "mouseout", "mousemove", "mousedown", "mouseup", "contextmenu" ],
+				eventFilters = { "mouseout":"mouseexit" },
+				bindOne = function(o, c, evt) {
+					var filteredEvent = eventFilters[evt] || evt;
+					jpcl.bind(o, evt, function(ee) {
+						c.fire(filteredEvent, c, ee);
+					});
+				},
+				unbindOne = function(o, evt) {
+					var filteredEvent = eventFilters[evt] || evt;
+					jpcl.unbind(o, evt);
+				};
+		    
+		    this.attachListeners = function(o, c) {
+				for (var i = 0; i < events.length; i++) {
+					bindOne(o, c, events[i]); 			
+				}
+			};
+		    
+		    var _updateAttachedElements = function(state, timestamp, sourceElement) {
+		    	var affectedElements = self.getAttachedElements();		// implemented in subclasses
+		    	if (affectedElements) {
+		    		for (var i = 0; i < affectedElements.length; i++) {
+		    			if (!sourceElement || sourceElement != affectedElements[i])
+		    				affectedElements[i].setHover(state, true, timestamp);			// tell the attached elements not to inform their own attached elements.
+		    		}
+		    	}
+		    };
+		    
+		    this.reattachListenersForElement = function(o) {
+			    if (arguments.length > 1) {
+		    		for (var i = 0; i < events.length; i++)
+		    			unbindOne(o, events[i]);
+			    	for (var i = 1; i < arguments.length; i++)
+		    			self.attachListeners(o, arguments[i]);
+		    	}
+		    };			
+		},
+
+		overlayCapableJsPlumbUIComponent = function(params) {
+			jsPlumbUIComponent.apply(this, arguments);
+			var self = this;
+			/*
+			 * Property: overlays
+			 * List of Overlays for this component.
+			 */
+			this.overlays = [];
+
+			var processOverlay = function(o) {
+				var _newOverlay = null;
+				if (o.constructor == Array) {	// this is for the shorthand ["Arrow", { width:50 }] syntax
+					// there's also a three arg version:
+					// ["Arrow", { width:50 }, {location:0.7}] 
+					// which merges the 3rd arg into the 2nd.
+					var type = o[0],
+						// make a copy of the object so as not to mess up anyone else's reference...
+						p = jsPlumb.extend({component:self, _jsPlumb:self._jsPlumb}, o[1]);
+					if (o.length == 3) jsPlumb.extend(p, o[2]);
+					_newOverlay = new jsPlumb.Overlays[self._jsPlumb.getRenderMode()][type](p);
+					if (p.events) {
+						for (var evt in p.events) {
+							_newOverlay.bind(evt, p.events[evt]);
+						}
+					}
+				} else if (o.constructor == String) {
+					_newOverlay = new jsPlumb.Overlays[self._jsPlumb.getRenderMode()][o]({component:self, _jsPlumb:self._jsPlumb});
+				} else {
+					_newOverlay = o;
+				}										
+					
+				self.overlays.push(_newOverlay);
+			},
+			calculateOverlaysToAdd = function(params) {
+				var defaultKeys = self.defaultOverlayKeys || [],
+					o = params.overlays,
+					checkKey = function(k) {
+						return self._jsPlumb.Defaults[k] || jsPlumb.Defaults[k] || [];
+					};
+				
+				if (!o) o = [];
+
+				for (var i = 0; i < defaultKeys.length; i++)
+					o.unshift.apply(o, checkKey(defaultKeys[i]));
+				
+				return o;
+			}
+
+			var _overlays = calculateOverlaysToAdd(params);//params.overlays || self._jsPlumb.Defaults.Overlays;
+			if (_overlays) {
+				for (var i = 0; i < _overlays.length; i++) {
+					processOverlay(_overlays[i]);
+				}
+			}
+
+		    // overlay finder helper method
+			var _getOverlayIndex = function(id) {
+				var idx = -1;
+				for (var i = 0; i < self.overlays.length; i++) {
+					if (id === self.overlays[i].id) {
+						idx = i;
+						break;
+					}
+				}
+				return idx;
+			};
+			
+			/*
+			 * Function: addOverlay
+			 * Adds an Overlay to the Connection.
+			 * 
+			 * Parameters:
+			 * 	overlay - Overlay to add.
+			 */
+			this.addOverlay = function(overlay) { 
+				processOverlay(overlay); 
+				self.repaint();
+			};
+			
+			/*
+			 * Function: getOverlay
+			 * Gets an overlay, by ID. Note: by ID.  You would pass an 'id' parameter
+			 * in to the Overlay's constructor arguments, and then use that to retrieve
+			 * it via this method.
+			 */
+			this.getOverlay = function(id) {
+				var idx = _getOverlayIndex(id);
+				return idx >= 0 ? self.overlays[idx] : null;
+			};
+			
+			/*
+			 * Function: hideOverlay
+			 * Hides the overlay specified by the given id.
+			 */
+			this.hideOverlay = function(id) {
+				var o = self.getOverlay(id);
+				if (o) o.hide();
+			};
+			
+			/*
+			 * Function: showOverlay
+			 * Shows the overlay specified by the given id.
+			 */
+			this.showOverlay = function(id) {
+				var o = self.getOverlay(id);
+				if (o) o.show();
+			};
+			
+			/**
+			 * Function: removeAllOverlays
+			 * Removes all overlays from the Connection, and then repaints.
+			 */
+			this.removeAllOverlays = function() {
+				self.overlays.splice(0, self.overlays.length);
+				self.repaint();
+			};
+			
+			/**
+			 * Function:removeOverlay
+			 * Removes an overlay by ID.  Note: by ID.  this is a string you set in the overlay spec.
+			 * Parameters:
+			 * overlayId - id of the overlay to remove.
+			 */
+			this.removeOverlay = function(overlayId) {
+				var idx = _getOverlayIndex(overlayId);
+				if (idx != -1) {
+					var o = self.overlays[idx];
+					o.cleanup();
+					self.overlays.splice(idx, 1);
+				}
+			};
+			
+			/**
+			 * Function:removeOverlays
+			 * Removes a set of overlays by ID.  Note: by ID.  this is a string you set in the overlay spec.
+			 * Parameters:
+			 * overlayIds - this function takes an arbitrary number of arguments, each of which is a single overlay id.
+			 */
+			this.removeOverlays = function() {
+				for (var i = 0; i < arguments.length; i++)
+					self.removeOverlay(arguments[i]);
+			};
+
+			// this is a shortcut helper method to let people add a label as
+			// overlay.			
+			var _internalLabelOverlayId = "__label",
+			_makeLabelOverlay = function(params) {
+
+				var _params = {
+					cssClass:params.cssClass,
+					labelStyle : this.labelStyle,					
+					id:_internalLabelOverlayId,
+					component:self,
+					_jsPlumb:self._jsPlumb
+				},
+				mergedParams = jsPlumb.extend(_params, params);
+
+				return new jsPlumb.Overlays[self._jsPlumb.getRenderMode()].Label( mergedParams );
+			};
+			if (params.label) {
+				var loc = params.labelLocation || self.defaultLabelLocation || 0.5,
+					labelStyle = params.labelStyle || self._jsPlumb.Defaults.LabelStyle || jsPlumb.Defaults.LabelStyle;			
+				this.overlays.push(_makeLabelOverlay({
+					label:params.label,
+					location:loc,
+					labelStyle:labelStyle
+				}));
+			}
+
+			/*
+			 * Function: setLabel
+			 * Sets the Connection's label.  
+			 * 
+			 * Parameters:
+			 * 	l	- label to set. May be a String, a Function that returns a String, or a params object containing { "label", "labelStyle", "location", "cssClass" }
+			 */
+			this.setLabel = function(l) {
+				var lo = self.getOverlay(_internalLabelOverlayId);
+				if (!lo) {
+					var params = l.constructor == String || l.constructor == Function ? { label:l } : l;
+					lo = _makeLabelOverlay(params);	
+					this.overlays.push(lo);
+				}
+				else {
+					if (l.constructor == String || l.constructor == Function) lo.setLabel(l);
+					else {
+						if (l.label) lo.setLabel(l.label);
+						if (l.location) lo.setLocation(l.location);
+					}
+				}
+				
+				self.repaint();
+			};
+
+			/*
+				Function:getLabel
+				Returns the label text for this component (or a function if you are labelling with a function).
+				This does not return the overlay itself; this is a convenience method which is a pair with
+				setLabel; together they allow you to add and access a Label Overlay without having to create the
+				Overlay object itself.  For access to the underlying label overlay that jsPlumb has created,
+				use getLabelOverlay.
+			*/
+			this.getLabel = function() {
+				var lo = self.getOverlay(_internalLabelOverlayId);
+				return lo != null ? lo.getLabel() : null;
+			};
+
+			/*
+				Function:getLabelOverlay
+				Returns the underlying internal label overlay, which will exist if you specified a label on
+				a connect or addEndpoint call, or have called setLabel at any stage.   
+			*/
+			this.getLabelOverlay = function() {
+				return self.getOverlay(_internalLabelOverlayId);
+			}
+		},
+		
+		_bindListeners = function(obj, _self, _hoverFunction) {
+        	obj.bind("click", function(ep, e) { _self.fire("click", _self, e); });
+			obj.bind("dblclick", function(ep, e) { _self.fire("dblclick", _self, e); });
+	        obj.bind("contextmenu", function(ep, e) { _self.fire("contextmenu", _self, e); });
+			obj.bind("mouseenter", function(ep, e) {
+				if (!_self.isHover()) {
+	                _hoverFunction(true);
+					_self.fire("mouseenter", _self, e);
+				}
+			});
+			obj.bind("mouseexit", function(ep, e) {
+				if (_self.isHover()) {
+	                _hoverFunction(false);
+					_self.fire("mouseexit", _self, e);
+				}
+			});	
+        };	
+		
+		var _jsPlumbInstanceIndex = 0,
+			getInstanceIndex = function() {
+				var i = _jsPlumbInstanceIndex + 1;
+				_jsPlumbInstanceIndex++;
+				return i;
+			};
+
+		var jsPlumbInstance = function(_defaults) {
+		
+		/*
+		 * Property: Defaults 
+		 * 
+		 * These are the default settings for jsPlumb.  They are what will be used if you do not supply specific pieces of information 
+		 * to the various API calls. A convenient way to implement your own look and feel can be to override these defaults 
+		 * by including a script somewhere after the jsPlumb include, but before you make any calls to jsPlumb.
+		 * 
+		 * Properties:
+		 * 	-	*Anchor*				    The default anchor to use for all connections (both source and target). Default is "BottomCenter".
+		 * 	-	*Anchors*				    The default anchors to use ([source, target]) for all connections. Defaults are ["BottomCenter", "BottomCenter"].
+		 *  -   *ConnectionsDetachable*		Whether or not connections are detachable by default (using the mouse). Defults to true.
+		 *  -   *ConnectionOverlays*		The default overlay definitions for Connections. Defaults to an empty list.
+		 * 	-	*Connector*				The default connector definition to use for all connections.  Default is "Bezier".
+		 *  -   *Container*				Optional selector or element id that instructs jsPlumb to append elements it creates to a specific element.
+		 * 	-	*DragOptions*			The default drag options to pass in to connect, makeTarget and addEndpoint calls. Default is empty.
+		 * 	-	*DropOptions*			The default drop options to pass in to connect, makeTarget and addEndpoint calls. Default is empty.
+		 * 	-	*Endpoint*				The default endpoint definition to use for all connections (both source and target).  Default is "Dot".
+		 *  -   *EndpointOverlays*		The default overlay definitions for Endpoints. Defaults to an empty list.
+		 * 	-	*Endpoints*				The default endpoint definitions ([ source, target ]) to use for all connections.  Defaults are ["Dot", "Dot"].
+		 * 	-	*EndpointStyle*			The default style definition to use for all endpoints. Default is fillStyle:"#456".
+		 * 	-	*EndpointStyles*		The default style definitions ([ source, target ]) to use for all endpoints.  Defaults are empty.
+		 * 	-	*EndpointHoverStyle*	The default hover style definition to use for all endpoints. Default is null.
+		 * 	-	*EndpointHoverStyles*	The default hover style definitions ([ source, target ]) to use for all endpoints. Defaults are null.
+		 * 	-	*HoverPaintStyle*		The default hover style definition to use for all connections. Defaults are null.
+		 * 	-	*LabelStyle*			The default style to use for label overlays on connections.
+		 * 	-	*LogEnabled*			Whether or not the jsPlumb log is enabled. defaults to false.
+		 * 	-	*Overlays*				The default overlay definitions (for both Connections and Endpoint). Defaults to an empty list.
+		 * 	-	*MaxConnections*		The default maximum number of connections for an Endpoint.  Defaults to 1.		 
+		 * 	-	*PaintStyle*			The default paint style for a connection. Default is line width of 8 pixels, with color "#456".
+		 * 	-	*RenderMode*			What mode to use to paint with.  If you're on IE<9, you don't really get to choose this.  You'll just get VML.  Otherwise, the jsPlumb default is to use SVG.
+		 * 	-	*Scope*				The default "scope" to use for connections. Scope lets you assign connections to different categories. 
+		 */
+		this.Defaults = {
+			Anchor : "BottomCenter",
+			Anchors : [ null, null ],
+            ConnectionsDetachable : true,
+            ConnectionOverlays : [ ],
+            Connector : "Bezier",
+			Container : null,
+			DragOptions : { },
+			DropOptions : { },
+			Endpoint : "Dot",
+			EndpointOverlays : [ ],
+			Endpoints : [ null, null ],
+			EndpointStyle : { fillStyle : "#456" },
+			EndpointStyles : [ null, null ],
+			EndpointHoverStyle : null,
+			EndpointHoverStyles : [ null, null ],
+			HoverPaintStyle : null,
+			LabelStyle : { color : "black" },
+			LogEnabled : false,
+			Overlays : [ ],
+			MaxConnections : 1, 
+			PaintStyle : { lineWidth : 8, strokeStyle : "#456" },
+            //Reattach:false,
+			RenderMode : "svg",
+			Scope : "jsPlumb_DefaultScope"
+		};
+		if (_defaults) jsPlumb.extend(this.Defaults, _defaults);
+		
+		this.logEnabled = this.Defaults.LogEnabled;		
+
+		EventGenerator.apply(this);
+		var _currentInstance = this,
+			_instanceIndex = getInstanceIndex(),
+			_bb = _currentInstance.bind,
+			_initialDefaults = {};
+
+		for (var i in this.Defaults)
+			_initialDefaults[i] = this.Defaults[i];
+
+		this.bind = function(event, fn) {		
+			if ("ready" === event && initialized) fn();
+			else _bb.apply(_currentInstance,[event, fn]);
+		};
+
+		/*
+			Function: importDefaults
+			Imports all the given defaults into this instance of jsPlumb.
+		*/
+		_currentInstance.importDefaults = function(d) {
+			for (var i in d) {
+				_currentInstance.Defaults[i] = d[i];
+			}	
+		};
+
+		/*
+			Function:restoreDefaults
+			Restores the default settings to "factory" values.
+		*/
+		_currentInstance.restoreDefaults = function() {
+			_currentInstance.Defaults = jsPlumb.extend({}, _initialDefaults);
+		};
+
+		var log = null,
+		repaintFunction = function() {
+			jsPlumb.repaintEverything();
+		},
+		automaticRepaint = true,
+		repaintEverything = function() {
+			if (automaticRepaint)
+				repaintFunction();
+		},
+		resizeTimer = null,
+		initialized = false,
+		connectionsByScope = {},
+		/**
+		 * map of element id -> endpoint lists. an element can have an arbitrary
+		 * number of endpoints on it, and not all of them have to be connected
+		 * to anything.
+		 */
+		endpointsByElement = {},
+		endpointsByUUID = {},
+		offsets = {},
+		offsetTimestamps = {},
+		floatingConnections = {},
+		draggableStates = {},		
+		canvasList = [],
+		sizes = [],
+		//listeners = {}, // a map: keys are event types, values are lists of listeners.
+		DEFAULT_SCOPE = this.Defaults.Scope,
+		renderMode = null,  // will be set in init()							
+
+		/**
+		 * helper method to add an item to a list, creating the list if it does
+		 * not yet exist.
+		 */
+		_addToList = function(map, key, value) {
+			var l = map[key];
+			if (l == null) {
+				l = [];
+				map[key] = l;
+			}
+			l.push(value);
+			return l;
+		},
+
+		/**
+		 * appends an element to some other element, which is calculated as follows:
+		 * 
+		 * 1. if _currentInstance.Defaults.Container exists, use that element.
+		 * 2. if the 'parent' parameter exists, use that.
+		 * 3. otherwise just use the document body.
+		 * 
+		 */
+		_appendElement = function(el, parent) {
+			if (_currentInstance.Defaults.Container)
+				jsPlumb.CurrentLibrary.appendElement(el, _currentInstance.Defaults.Container);
+			else if (!parent)
+				document.body.appendChild(el);
+			else
+				jsPlumb.CurrentLibrary.appendElement(el, parent);
+		},
+
+		_curIdStamp = 1,
+		_idstamp = function() { return "" + _curIdStamp++; },		
+		
+		/**
+		 * YUI, for some reason, put the result of a Y.all call into an object that contains
+		 * a '_nodes' array, instead of handing back an array-like object like the other
+		 * libraries do.
+		 */
+		_convertYUICollection = function(c) {
+			return c._nodes ? c._nodes : c;
+		},
+
+        _suspendDrawing = false,
+        /*
+        sets whether or not to suspend drawing.  you should use this if you need to connect a whole load of things in one go.
+        it will save you a lot of time.
+         */
+        _setSuspendDrawing = function(val, repaintAfterwards) {
+            _suspendDrawing = val;
+            if (repaintAfterwards) _currentInstance.repaintEverything();
+        },
+
+		/**
+		 * Draws an endpoint and its connections. this is the main entry point into drawing connections as well
+		 * as endpoints, since jsPlumb is endpoint-centric under the hood.
+		 * 
+		 * @param element element to draw (of type library specific element object)
+		 * @param ui UI object from current library's event system. optional.
+		 * @param timestamp timestamp for this paint cycle. used to speed things up a little by cutting down the amount of offset calculations we do.
+		 */
+		_draw = function(element, ui, timestamp) {
+            if (!_suspendDrawing) {
+			    var id = _getAttribute(element, "id"),
+			    	repaintEls = _currentInstance.dragManager.getElementsForDraggable(id);			    
+
+			    if (timestamp == null) timestamp = _timestamp();
+
+			    _currentInstance.anchorManager.redraw(id, ui, timestamp);
+
+			    if (repaintEls) {
+				    for (var i in repaintEls) {
+						_currentInstance.anchorManager.redraw(repaintEls[i].id, ui, timestamp, repaintEls[i].offset);			    	
+				    }
+				}
+            }
+		},
+
+		/**
+		 * executes the given function against the given element if the first
+		 * argument is an object, or the list of elements, if the first argument
+		 * is a list. the function passed in takes (element, elementId) as
+		 * arguments.
+		 */
+		_elementProxy = function(element, fn) {
+			var retVal = null;
+			if (element.constructor == Array) {
+				retVal = [];
+				for ( var i = 0; i < element.length; i++) {
+					var el = _getElementObject(element[i]), id = _getAttribute(el, "id");
+					retVal.push(fn(el, id)); // append return values to what we will return
+				}
+			} else {
+				var el = _getElementObject(element), id = _getAttribute(el, "id");
+				retVal = fn(el, id);
+			}
+			return retVal;
+		},				
+
+		/**
+		 * gets an Endpoint by uuid.
+		 */
+		_getEndpoint = function(uuid) { return endpointsByUUID[uuid]; },
+
+		/**
+		 * inits a draggable if it's not already initialised.
+		 */
+		_initDraggableIfNecessary = function(element, isDraggable, dragOptions) {
+			var draggable = isDraggable == null ? false : isDraggable,
+				jpcl = jsPlumb.CurrentLibrary;
+			if (draggable) {
+				if (jpcl.isDragSupported(element) && !jpcl.isAlreadyDraggable(element)) {
+					var options = dragOptions || _currentInstance.Defaults.DragOptions || jsPlumb.Defaults.DragOptions;
+					options = jsPlumb.extend( {}, options); // make a copy.
+					var dragEvent = jpcl.dragEvents["drag"],
+						stopEvent = jpcl.dragEvents["stop"],
+						startEvent = jpcl.dragEvents["start"];
+					options[dragEvent] = _wrap(options[dragEvent], function() {
+						var ui = jpcl.getUIPosition(arguments);
+						_draw(element, ui);
+						_addClass(element, "jsPlumb_dragged");
+					});
+					options[stopEvent] = _wrap(options[stopEvent], function() {
+						var ui = jpcl.getUIPosition(arguments);
+						_draw(element, ui);
+						_removeClass(element, "jsPlumb_dragged");
+					});
+					draggableStates[_getId(element)] = true;
+					var draggable = draggableStates[_getId(element)];
+					options.disabled = draggable == null ? false : !draggable;
+					jpcl.initDraggable(element, options, false);
+					_currentInstance.dragManager.register(element);
+				}
+			}
+		},
+		
+		/*
+		* prepares a final params object that can be passed to _newConnection, taking into account defaults, events, etc.
+		*/
+		_prepareConnectionParams = function(params, referenceParams) {
+			var _p = jsPlumb.extend( {}, params);
+			if (referenceParams) jsPlumb.extend(_p, referenceParams);
+			
+			// hotwire endpoints passed as source or target to sourceEndpoint/targetEndpoint, respectively.
+			if (_p.source && _p.source.endpoint) _p.sourceEndpoint = _p.source;
+			if (_p.source && _p.target.endpoint) _p.targetEndpoint = _p.target;
+			
+			// test for endpoint uuids to connect
+			if (params.uuids) {
+				_p.sourceEndpoint = _getEndpoint(params.uuids[0]);
+				_p.targetEndpoint = _getEndpoint(params.uuids[1]);
+			}
+
+			// now ensure that if we do have Endpoints already, they're not full.
+			// source:
+			if (_p.sourceEndpoint && _p.sourceEndpoint.isFull()) {
+				_log(_currentInstance, "could not add connection; source endpoint is full");
+				return;
+			}
+
+			// target:
+			if (_p.targetEndpoint && _p.targetEndpoint.isFull()) {
+				_log(_currentInstance, "could not add connection; target endpoint is full");
+				return;
+			}			
+			
+			// copy in any connectorOverlays that were specified on the source endpoint.
+			// it doesnt copy target endpoint overlays.  i'm not sure if we want it to or not.
+			if (_p.sourceEndpoint && _p.sourceEndpoint.connectorOverlays) {
+				_p.overlays = _p.overlays || [];
+				for (var i = 0; i < _p.sourceEndpoint.connectorOverlays.length; i++) {
+					_p.overlays.push(_p.sourceEndpoint.connectorOverlays[i]);
+				}
+			}
+			
+			// tooltip.  params.tooltip takes precedence, then sourceEndpoint.connectorTooltip.
+			_p.tooltip = params.tooltip;
+			if (!_p.tooltip && _p.sourceEndpoint && _p.sourceEndpoint.connectorTooltip)
+				_p.tooltip = _p.sourceEndpoint.connectorTooltip;
+			
+			// if there's a target specified (which of course there should be), and there is no
+			// target endpoint specified, and 'newConnection' was not set to true, then we check to
+			// see if a prior call to makeTarget has provided us with the specs for the target endpoint, and
+			// we use those if so.  additionally, if the makeTarget call was specified with 'uniqueEndpoint' set
+			// to true, then if that target endpoint has already been created, we re-use it.
+			if (_p.target && !_p.target.endpoint && !_p.targetEndpoint && !_p.newConnection) {
+				var tid = _getId(_p.target),
+					tep =_targetEndpointDefinitions[tid],
+					existingUniqueEndpoint = _targetEndpoints[tid];
+
+				if (tep) {
+				
+					var newEndpoint = existingUniqueEndpoint != null ? existingUniqueEndpoint : _currentInstance.addEndpoint(_p.target, tep);
+					if (_targetEndpointsUnique[tid]) _targetEndpoints[tid] = newEndpoint;
+					 _p.targetEndpoint = newEndpoint;
+				}
+			}
+
+			// same thing, but for source.
+			if (_p.source && !_p.source.endpoint && !_p.sourceEndpoint && !_p.newConnection) {
+				var tid = _getId(_p.source),
+					tep = _sourceEndpointDefinitions[tid],
+					existingUniqueEndpoint = _sourceEndpoints[tid];
+
+				if (tep) {
+				
+					var newEndpoint = existingUniqueEndpoint != null ? existingUniqueEndpoint : _currentInstance.addEndpoint(_p.source, tep);
+					if (_sourceEndpointsUnique[tid]) _sourceEndpoints[tid] = newEndpoint;
+					 _p.sourceEndpoint = newEndpoint;
+				}
+			}
+			
+			return _p;
+		},
+		
+		_newConnection = function(params) {
+			var connectionFunc = _currentInstance.Defaults.ConnectionType || _currentInstance.getDefaultConnectionType(),
+			    endpointFunc = _currentInstance.Defaults.EndpointType || Endpoint,
+			    parent = jsPlumb.CurrentLibrary.getParent;
+			
+			if (params.container)
+				params["parent"] = params.container;
+			else {
+				if (params.sourceEndpoint)
+					params["parent"] = params.sourceEndpoint.parent;
+				else if (params.source.constructor == endpointFunc)
+					params["parent"] = params.source.parent;
+				else params["parent"] = parent(params.source);
+			}
+			
+			params["_jsPlumb"] = _currentInstance;
+			var con = new connectionFunc(params);
+			con.id = "con_" + _idstamp();
+			_eventFireProxy("click", "click", con);
+			_eventFireProxy("dblclick", "dblclick", con);
+            _eventFireProxy("contextmenu", "contextmenu", con);
+			return con;
+		},
+		
+		/**
+		* adds the connection to the backing model, fires an event if necessary and then redraws
+		*/
+		_finaliseConnection = function(jpc, params, originalEvent) {
+            params = params || {};
+			// add to list of connections (by scope).
+            if (!jpc.suspendedEndpoint)
+			    _addToList(connectionsByScope, jpc.scope, jpc);
+			// fire an event
+			if (!params.doNotFireConnectionEvent && params.fireEvent !== false) {
+				_currentInstance.fire("jsPlumbConnection", {
+					connection:jpc,
+					source : jpc.source, target : jpc.target,
+					sourceId : jpc.sourceId, targetId : jpc.targetId,
+					sourceEndpoint : jpc.endpoints[0], targetEndpoint : jpc.endpoints[1]
+				}, originalEvent);
+			}
+            // always inform the anchor manager
+            // except that if jpc has a suspended endpoint it's not true to say the
+            // connection is new; it has just (possibly) moved. the question is whether
+            // to make that call here or in the anchor manager.  i think perhaps here.
+            _currentInstance.anchorManager.newConnection(jpc);
+			// force a paint
+			_draw(jpc.source);
+		},
+		
+		_eventFireProxy = function(event, proxyEvent, obj) {
+			obj.bind(event, function(originalObject, originalEvent) {
+				_currentInstance.fire(proxyEvent, obj, originalEvent);
+			});
+		},
+		
+		/**
+		 * for the given endpoint params, returns an appropriate parent element for the UI elements that will be added.
+		 * this function is used by _newEndpoint (directly below), and also in the makeSource function in jsPlumb.
+		 * 
+		 *   the logic is to first look for a "container" member of params, and pass that back if found.  otherwise we
+		 *   handoff to the 'getParent' function in the current library.
+		 */
+		_getParentFromParams = function(params) {
+			if (params.container)
+				return params.container;
+			else {
+                var tag = jsPlumb.CurrentLibrary.getTagName(params.source),
+                    p = jsPlumb.CurrentLibrary.getParent(params.source);
+                if (tag && tag.toLowerCase() === "td")
+                    return jsPlumb.CurrentLibrary.getParent(p);
+                else return p;
+            }
+		},
+		
+		/**
+			factory method to prepare a new endpoint.  this should always be used instead of creating Endpoints
+			manually, since this method attaches event listeners and an id.
+		*/
+		_newEndpoint = function(params) {
+			var endpointFunc = _currentInstance.Defaults.EndpointType || Endpoint;
+			params.parent = _getParentFromParams(params);
+			params["_jsPlumb"] = _currentInstance;
+			var ep = new endpointFunc(params);
+			ep.id = "ep_" + _idstamp();
+			_eventFireProxy("click", "endpointClick", ep);
+			_eventFireProxy("dblclick", "endpointDblClick", ep);
+            _eventFireProxy("contextmenu", "contextmenu", ep);
+			return ep;
+		},
+		
+		/**
+		 * performs the given function operation on all the connections found
+		 * for the given element id; this means we find all the endpoints for
+		 * the given element, and then for each endpoint find the connectors
+		 * connected to it. then we pass each connection in to the given
+		 * function.
+		 */
+		_operation = function(elId, func, endpointFunc) {
+			var endpoints = endpointsByElement[elId];
+			if (endpoints && endpoints.length) {
+				for ( var i = 0; i < endpoints.length; i++) {
+					for ( var j = 0; j < endpoints[i].connections.length; j++) {
+						var retVal = func(endpoints[i].connections[j]);
+						// if the function passed in returns true, we exit.
+						// most functions return false.
+						if (retVal) return;
+					}
+					if (endpointFunc) endpointFunc(endpoints[i]);
+				}
+			}
+		},
+		/**
+		 * perform an operation on all elements.
+		 */
+		_operationOnAll = function(func) {
+			for ( var elId in endpointsByElement) {
+				_operation(elId, func);
+			}
+		},		
+		
+		/**
+		 * helper to remove an element from the DOM.
+		 */
+		_removeElement = function(element, parent) {
+			if (element != null && element.parentNode != null) {
+				element.parentNode.removeChild(element);
+			}
+		},
+		/**
+		 * helper to remove a list of elements from the DOM.
+		 */
+		_removeElements = function(elements, parent) {
+			for ( var i = 0; i < elements.length; i++)
+				_removeElement(elements[i], parent);
+		},
+		/**
+		 * Sets whether or not the given element(s) should be draggable,
+		 * regardless of what a particular plumb command may request.
+		 * 
+		 * @param element
+		 *            May be a string, a element objects, or a list of
+		 *            strings/elements.
+		 * @param draggable
+		 *            Whether or not the given element(s) should be draggable.
+		 */
+		_setDraggable = function(element, draggable) {
+			return _elementProxy(element, function(el, id) {
+				draggableStates[id] = draggable;
+				if (jsPlumb.CurrentLibrary.isDragSupported(el)) {
+					jsPlumb.CurrentLibrary.setDraggable(el, draggable);
+				}
+			});
+		},
+		/**
+		 * private method to do the business of hiding/showing.
+		 * 
+		 * @param el
+		 *            either Id of the element in question or a library specific
+		 *            object for the element.
+		 * @param state
+		 *            String specifying a value for the css 'display' property
+		 *            ('block' or 'none').
+		 */
+		_setVisible = function(el, state, alsoChangeEndpoints) {
+			state = state === "block";
+			var endpointFunc = null;
+			if (alsoChangeEndpoints) {
+				if (state) endpointFunc = function(ep) {
+					ep.setVisible(true, true, true);
+				};
+				else endpointFunc = function(ep) {
+					ep.setVisible(false, true, true);
+				};
+			}
+			var id = _getAttribute(el, "id");
+			_operation(id, function(jpc) {
+				if (state && alsoChangeEndpoints) {		
+					// this test is necessary because this functionality is new, and i wanted to maintain backwards compatibility.
+					// this block will only set a connection to be visible if the other endpoint in the connection is also visible.
+					var oidx = jpc.sourceId === id ? 1 : 0;
+					if (jpc.endpoints[oidx].isVisible()) jpc.setVisible(true);
+				}
+				else  // the default behaviour for show, and what always happens for hide, is to just set the visibility without getting clever.
+					jpc.setVisible(state);
+			}, endpointFunc);
+		},
+		/**
+		 * toggles the draggable state of the given element(s).
+		 * 
+		 * @param el
+		 *            either an id, or an element object, or a list of
+		 *            ids/element objects.
+		 */
+		_toggleDraggable = function(el) {
+			return _elementProxy(el, function(el, elId) {
+				var state = draggableStates[elId] == null ? false : draggableStates[elId];
+				state = !state;
+				draggableStates[elId] = state;
+				jsPlumb.CurrentLibrary.setDraggable(el, state);
+				return state;
+			});
+		},
+		/**
+		 * private method to do the business of toggling hiding/showing.
+		 * 
+		 * @param elId
+		 *            Id of the element in question
+		 */
+		_toggleVisible = function(elId, changeEndpoints) {
+			var endpointFunc = null;
+			if (changeEndpoints) {
+				endpointFunc = function(ep) {
+					var state = ep.isVisible();
+					ep.setVisible(!state);
+				};
+			}
+			_operation(elId, function(jpc) {
+				var state = jpc.isVisible();
+				jpc.setVisible(!state);				
+			}, endpointFunc);
+			// todo this should call _elementProxy, and pass in the
+			// _operation(elId, f) call as a function. cos _toggleDraggable does
+			// that.
+		},
+		/**
+		 * updates the offset and size for a given element, and stores the
+		 * values. if 'offset' is not null we use that (it would have been
+		 * passed in from a drag call) because it's faster; but if it is null,
+		 * or if 'recalc' is true in order to force a recalculation, we get the current values.
+		 */
+		_updateOffset = function(params) {
+			var timestamp = params.timestamp, recalc = params.recalc, offset = params.offset, elId = params.elId;
+			if (!recalc) {
+				if (timestamp && timestamp === offsetTimestamps[elId])
+					return offsets[elId];
+			}
+			if (recalc || !offset) { // if forced repaint or no offset
+											// available, we recalculate.
+				// get the current size and offset, and store them
+				var s = _getElementObject(elId);
+				if (s != null) {
+					sizes[elId] = _getSize(s);
+					offsets[elId] = _getOffset(s);
+					offsetTimestamps[elId] = timestamp;
+				}
+			} else {
+				offsets[elId] = offset;
+                if (sizes[elId] == null) {
+                    var s = _getElementObject(elId);
+				    if (s != null)
+					    sizes[elId] = _getSize(s);
+                }
+			}
+			
+			if(offsets[elId] && !offsets[elId].right) {
+				offsets[elId].right = offsets[elId].left + sizes[elId][0];
+				offsets[elId].bottom = offsets[elId].top + sizes[elId][1];	
+				offsets[elId].width = sizes[elId][0];
+				offsets[elId].height = sizes[elId][1];	
+				offsets[elId].centerx = offsets[elId].left + (offsets[elId].width / 2);
+				offsets[elId].centery = offsets[elId].top + (offsets[elId].height / 2);				
+			}
+			return offsets[elId];
+		},
+
+		// TODO comparison performance
+		_getCachedData = function(elId) {
+			var o = offsets[elId];
+			if (!o) o = _updateOffset({elId:elId});
+			return {o:o, s:sizes[elId]};
+		},
+
+		/**
+		 * gets an id for the given element, creating and setting one if
+		 * necessary.  the id is of the form
+		 *
+		 *	jsPlumb_<instance index>_<index in instance>
+		 *
+		 * where "index in instance" is a monotonically increasing integer that starts at 0,
+		 * for each instance.  this method is used not only to assign ids to elements that do not
+		 * have them but also to connections and endpoints.
+		 */
+		_getId = function(element, uuid) {
+			var ele = _getElementObject(element);
+			var id = _getAttribute(ele, "id");
+			if (!id || id == "undefined") {
+				// check if fixed uuid parameter is given
+				if (arguments.length == 2 && arguments[1] != undefined)
+					id = uuid;
+				else
+					id = "jsPlumb_" + _instanceIndex + "_" + _idstamp();
+				_setAttribute(ele, "id", id);
+			}
+			return id;
+		},
+
+		/**
+		 * wraps one function with another, creating a placeholder for the
+		 * wrapped function if it was null. this is used to wrap the various
+		 * drag/drop event functions - to allow jsPlumb to be notified of
+		 * important lifecycle events without imposing itself on the user's
+		 * drag/drop functionality. TODO: determine whether or not we should
+		 * support an error handler concept, if one of the functions fails.
+		 * 
+		 * @param wrappedFunction original function to wrap; may be null.
+		 * @param newFunction function to wrap the original with.
+		 * @param returnOnThisValue Optional. Indicates that the wrappedFunction should 
+		 * not be executed if the newFunction returns a value matching 'returnOnThisValue'.
+		 * note that this is a simple comparison and only works for primitives right now.
+		 */
+		_wrap = function(wrappedFunction, newFunction, returnOnThisValue) {
+			wrappedFunction = wrappedFunction || function() { };
+			newFunction = newFunction || function() { };
+			return function() {
+				var r = null;
+				try {
+					r = newFunction.apply(this, arguments);
+				} catch (e) {
+					_log(_currentInstance, "jsPlumb function failed : " + e);
+				}
+				if (returnOnThisValue == null || (r !== returnOnThisValue)) {
+					try {
+						wrappedFunction.apply(this, arguments);
+					} catch (e) {
+						_log(_currentInstance, "wrapped function failed : " + e);
+					}
+				}
+				return r;
+			};
+		};	
+
+		/*
+		 * Property: connectorClass 
+		 *   The CSS class to set on Connection elements. This value is a String and can have multiple classes; the entire String is appended as-is.
+		 */
+		this.connectorClass = "_jsPlumb_connector";
+
+		/*
+		 * Property: endpointClass 
+		 *   The CSS class to set on Endpoint elements. This value is a String and can have multiple classes; the entire String is appended as-is.
+		 */
+		this.endpointClass = "_jsPlumb_endpoint";
+
+		/*
+		 * Property: overlayClass 
+		 * The CSS class to set on an Overlay that is an HTML element. This value is a String and can have multiple classes; the entire String is appended as-is.
+		 */
+		this.overlayClass = "_jsPlumb_overlay";
+		
+		this.Anchors = {};
+		
+		this.Connectors = { 
+			"canvas":{},
+			"svg":{},
+			"vml":{}
+		};
+
+		this.Endpoints = {
+			"canvas":{},
+			"svg":{},
+			"vml":{}
+		};
+
+		this.Overlays = {
+			"canvas":{},
+			"svg":{},
+			"vml":{}
+		};
+		
+// ************************ PLACEHOLDER DOC ENTRIES FOR NATURAL DOCS *****************************************
+		/*
+		 * Function: bind
+		 * Bind to an event on jsPlumb.  
+		 * 
+		 * Parameters:
+		 * 	event - the event to bind.  Available events on jsPlumb are:
+		 *         - *jsPlumbConnection* 			: 	notification that a new Connection was established.  jsPlumb passes the new Connection to the callback.
+		 *         - *jsPlumbConnectionDetached* 	: 	notification that a Connection was detached.  jsPlumb passes the detached Connection to the callback.
+		 *         - *click*						:	notification that a Connection was clicked.  jsPlumb passes the Connection that was clicked to the callback.
+		 *         - *dblclick*						:	notification that a Connection was double clicked.  jsPlumb passes the Connection that was double clicked to the callback.
+		 *         - *endpointClick*				:	notification that an Endpoint was clicked.  jsPlumb passes the Endpoint that was clicked to the callback.
+		 *         - *endpointDblClick*				:	notification that an Endpoint was double clicked.  jsPlumb passes the Endpoint that was double clicked to the callback.
+		 *         
+		 *  callback - function to callback. This function will be passed the Connection/Endpoint that caused the event, and also the original event.    
+		 */
+		
+		/*
+		 * Function: clearListeners
+		 * Clears either all listeners, or listeners for some specific event.
+		 * 
+		 * Parameters:
+		 * 	event	-	optional. constrains the clear to just listeners for this event.
+		 */				
+		
+// *************** END OF PLACEHOLDER DOC ENTRIES FOR NATURAL DOCS ***********************************************************		
+		
+		/*
+		 Function: addClass
+		 
+		 Helper method to abstract out differences in setting css classes on the different renderer types.
+		*/
+		this.addClass = function(el, clazz) {
+			return jsPlumb.CurrentLibrary.addClass(el, clazz);
+		};
+		
+		/*
+		 Function: removeClass
+		 
+		 Helper method to abstract out differences in setting css classes on the different renderer types.
+		*/
+		this.removeClass = function(el, clazz) {
+			return jsPlumb.CurrentLibrary.removeClass(el, clazz);
+		};
+		
+		/*
+		 Function: hasClass
+		 
+		 Helper method to abstract out differences in testing for css classes on the different renderer types.
+		*/
+		this.hasClass = function(el, clazz) {
+			return jsPlumb.CurrentLibrary.hasClass(el, clazz);
+		};
+		
+		/*
+		  Function: addEndpoint 
+		  	
+		  Adds an <Endpoint> to a given element or elements.
+		  			  
+		  Parameters:
+		   
+		  	el - Element to add the endpoint to. Either an element id, a selector representing some element(s), or an array of either of these. 
+		  	params - Object containing Endpoint constructor arguments.  For more information, see <Endpoint>.
+		  	referenceParams - Object containing more Endpoint constructor arguments; it will be merged with params by jsPlumb.  You would use this if you had some 
+		  					  shared parameters that you wanted to reuse when you added Endpoints to a number of elements. The allowed values in
+		  					  this object are anything that 'params' can contain.  See <Endpoint>.
+		  	 
+		  Returns: 
+		  	The newly created <Endpoint>, if el referred to a single element.  Otherwise, an array of newly created <Endpoint>s. 
+		  	
+		  See Also: 
+		  	<addEndpoints>
+		 */
+		this.addEndpoint = function(el, params, referenceParams) {
+			referenceParams = referenceParams || {};
+			var p = jsPlumb.extend({}, referenceParams);
+			jsPlumb.extend(p, params);
+			p.endpoint = p.endpoint || _currentInstance.Defaults.Endpoint || jsPlumb.Defaults.Endpoint;
+			p.paintStyle = p.paintStyle || _currentInstance.Defaults.EndpointStyle || jsPlumb.Defaults.EndpointStyle;
+            // YUI wrapper
+			el = _convertYUICollection(el);			
+			
+			var results = [], inputs = el.length && el.constructor != String ? el : [ el ];
+						
+			for (var i = 0; i < inputs.length; i++) {
+				var _el = _getElementObject(inputs[i]), id = _getId(_el);
+				p.source = _el;
+                _updateOffset({ elId : id });
+				var e = _newEndpoint(p);
+				if (p.parentAnchor) e.parentAnchor = p.parentAnchor;
+				_addToList(endpointsByElement, id, e);
+				var myOffset = offsets[id], myWH = sizes[id];
+				var anchorLoc = e.anchor.compute( { xy : [ myOffset.left, myOffset.top ], wh : myWH, element : e });
+				e.paint({ anchorLoc : anchorLoc });
+				results.push(e);
+				_currentInstance.dragManager.endpointAdded(_el);
+			}
+			
+			return results.length == 1 ? results[0] : results;
+		};
+		
+		/*
+		  Function: addEndpoints 
+		  Adds a list of <Endpoint>s to a given element or elements.
+		  
+		  Parameters: 
+		  	target - element to add the Endpoint to. Either an element id, a selector representing some element(s), or an array of either of these. 
+		  	endpoints - List of objects containing Endpoint constructor arguments. one Endpoint is created for each entry in this list.  See <Endpoint>'s constructor documentation. 
+			referenceParams - Object containing more Endpoint constructor arguments; it will be merged with params by jsPlumb.  You would use this if you had some shared parameters that you wanted to reuse when you added Endpoints to a number of elements.		  	 
+
+		  Returns: 
+		  	List of newly created <Endpoint>s, one for each entry in the 'endpoints' argument. 
+		  	
+		  See Also:
+		  	<addEndpoint>
+		 */
+		this.addEndpoints = function(el, endpoints, referenceParams) {
+			var results = [];
+			for ( var i = 0; i < endpoints.length; i++) {
+				var e = _currentInstance.addEndpoint(el, endpoints[i], referenceParams);
+				if (e.constructor == Array)
+					Array.prototype.push.apply(results, e);
+				else results.push(e);
+			}
+			return results;
+		};
+
+		/*
+		  Function: animate 
+		  This is a wrapper around the supporting library's animate function; it injects a call to jsPlumb in the 'step' function (creating
+		  the 'step' function if necessary). This only supports the two-arg version of the animate call in jQuery, the one that takes an 'options' object as
+		  the second arg. MooTools has only one method, a two arg one. Which is handy.  YUI has a one-arg method, so jsPlumb merges 'properties' and 'options' together for YUI.
+		   
+		  Parameters: 
+		  	el - Element to animate. Either an id, or a selector representing the element. 
+		  	properties - The 'properties' argument you want passed to the library's animate call. 
+		   	options - The 'options' argument you want passed to the library's animate call.
+		    
+		  Returns: 
+		  	void
+		 */
+		this.animate = function(el, properties, options) {
+			var ele = _getElementObject(el), id = _getAttribute(el, "id");
+			options = options || {};
+			var stepFunction = jsPlumb.CurrentLibrary.dragEvents['step'];
+			var completeFunction = jsPlumb.CurrentLibrary.dragEvents['complete'];
+			options[stepFunction] = _wrap(options[stepFunction], function() {
+				_currentInstance.repaint(id);
+			});
+
+			// onComplete repaints, just to make sure everything looks good at the end of the animation.
+			options[completeFunction] = _wrap(options[completeFunction],
+					function() {
+						_currentInstance.repaint(id);
+					});
+
+			jsPlumb.CurrentLibrary.animate(ele, properties, options);
+		};		
+		
+		/**
+		* checks for a listener for the given condition, executing it if found, passing in the given value.
+		* condition listeners would have been attached using "bind" (which is, you could argue, now overloaded, since
+		* firing click events etc is a bit different to what this does).  i thought about adding a "bindCondition"
+		* or something, but decided against it, for the sake of simplicity. jsPlumb will never fire one of these
+		* condition events anyway.
+		*/
+		this.checkCondition = function(conditionName, value) {
+			var l = _currentInstance.getListener(conditionName);
+			var r = true;
+			if (l && l.length > 0) {
+				try {
+					for (var i = 0 ; i < l.length; i++) {
+						r = r && l[i](value); 
+					}
+				}
+				catch (e) { 
+					_log(_currentInstance, "cannot check condition [" + conditionName + "]" + e); 
+				}
+			}
+			return r;
+		};
+
+		/*
+		  Function: connect 
+		  Establishes a <Connection> between two elements (or <Endpoint>s, which are themselves registered to elements).
+		  
+		  Parameters: 
+		    params - Object containing constructor arguments for the Connection. See <Connection>'s constructor documentation.
+		    referenceParams - Optional object containing more constructor arguments for the Connection. Typically you would pass in data that a lot of 
+		    Connections are sharing here, such as connector style etc, and then use the main params for data specific to this Connection.
+		     
+		  Returns: 
+		  	The newly created <Connection>.
+		 */
+		this.connect = function(params, referenceParams) {
+			// prepare a final set of parameters to create connection with
+			var _p = _prepareConnectionParams(params, referenceParams);
+			// TODO probably a nicer return value if the connection was not made.  _prepareConnectionParams
+			// will return null (and log something) if either endpoint was full.  what would be nicer is to 
+			// create a dedicated 'error' object.
+			if (_p) {
+				// a connect call will delete its created endpoints on detach, unless otherwise specified.
+				// this is because the endpoints belong to this connection only, and are no use to
+				// anyone else, so they hang around like a bad smell.
+				if (_p.deleteEndpointsOnDetach == null)
+					_p.deleteEndpointsOnDetach = true;
+
+				// create the connection.  it is not yet registered 
+				var jpc = _newConnection(_p);
+				// now add it the model, fire an event, and redraw
+				_finaliseConnection(jpc, _p);						
+				return jpc;
+			}
+		};
+		
+		/*
+		 Function: deleteEndpoint		 
+		 Deletes an Endpoint and removes all Connections it has (which removes the Connections from the other Endpoints involved too)
+		 
+		 Parameters:
+		 	object - either an <Endpoint> object (such as from an addEndpoint call), or a String UUID.
+		 	
+		 Returns:
+		 	void		  
+		 */
+		this.deleteEndpoint = function(object) {
+			var endpoint = (typeof object == "string") ? endpointsByUUID[object] : object;			
+			if (endpoint) {					
+				var uuid = endpoint.getUuid();
+				if (uuid) endpointsByUUID[uuid] = null;				
+				endpoint.detachAll();				
+				_removeElements(endpoint.endpoint.getDisplayElements());
+				_currentInstance.anchorManager.deleteEndpoint(endpoint);
+				for (var e in endpointsByElement) {
+					var endpoints = endpointsByElement[e];
+					if (endpoints) {
+						var newEndpoints = [];
+						for (var i = 0; i < endpoints.length; i++)
+							if (endpoints[i] != endpoint) newEndpoints.push(endpoints[i]);
+						
+						endpointsByElement[e] = newEndpoints;
+					}
+				}
+				_currentInstance.dragManager.endpointDeleted(endpoint);								
+			}									
+		};
+		
+		/*
+		 Function: deleteEveryEndpoint
+		  Deletes every <Endpoint>, and their associated <Connection>s, in this instance of jsPlumb. Does not unregister any event listeners (this is the only difference
+between this method and jsPlumb.reset).  
+		  
+		 Returns: 
+		 	void 
+		 */
+		this.deleteEveryEndpoint = function() {
+			for ( var id in endpointsByElement) {
+				var endpoints = endpointsByElement[id];
+				if (endpoints && endpoints.length) {
+					for ( var i = 0; i < endpoints.length; i++) {
+						_currentInstance.deleteEndpoint(endpoints[i]);
+					}
+				}
+			}
+			delete endpointsByElement;
+			endpointsByElement = {};
+			delete endpointsByUUID;
+			endpointsByUUID = {};
+		};
+
+		var fireDetachEvent = function(jpc, doFireEvent) {
+            // may have been given a connection, or in special cases, an object
+            var connType =  _currentInstance.Defaults.ConnectionType || _currentInstance.getDefaultConnectionType(),
+                argIsConnection = jpc.constructor == connType,
+                params = argIsConnection ? {
+                    connection:jpc,
+				    source : jpc.source, target : jpc.target,
+				    sourceId : jpc.sourceId, targetId : jpc.targetId,
+				    sourceEndpoint : jpc.endpoints[0], targetEndpoint : jpc.endpoints[1]
+                } : jpc;
+
+			if (doFireEvent) _currentInstance.fire("jsPlumbConnectionDetached", params);
+            _currentInstance.anchorManager.connectionDetached(params);
+		};
+
+		/**
+			fires an event to indicate an existing connection is being dragged.
+		*/
+		var fireConnectionDraggingEvent = function(jpc) {
+			_currentInstance.fire("connectionDrag", jpc);	
+		};
+
+		var fireConnectionDragStopEvent = function(jpc) {
+			_currentInstance.fire("connectionDragStop", jpc);
+		}
+
+
+		/*
+		  Function: detach 
+		  Detaches and then removes a <Connection>.  From 1.3.5 this method has been altered to remove support for
+		  specifying Connections by various parameters; you can now pass in a Connection as the first argument and
+		  an optional parameters object as a second argument.  If you need the functionality this method provided
+		  before 1.3.5 then you should use the getConnections method to get the list of Connections to detach, and
+		  then iterate through them, calling this for each one.
+		  		   
+		  Parameters: 
+		    connection  -   the <Connection> to detach
+		    params      -   optional parameters to the detach call.  valid values here are
+		                    fireEvent   :   defaults to false; indicates you want jsPlumb to fire a connection
+		                                    detached event. The thinking behind this is that if you made a programmatic
+		                                    call to detach an event, you probably don't need the callback.
+		                    forceDetach :   defaults to false. allows you to override any beforeDetach listeners that may be registered.
+
+		    Returns: 
+		    	true if successful, false if not.
+		 */
+		this.detach = function() {
+
+            if (arguments.length == 0) return;
+            var connType =  _currentInstance.Defaults.ConnectionType || _currentInstance.getDefaultConnectionType(),
+                firstArgIsConnection = arguments[0].constructor == connType,
+                params = arguments.length == 2 ? firstArgIsConnection ? (arguments[1] || {}) : arguments[0] : arguments[0],
+                fireEvent = (params.fireEvent !== false),
+                forceDetach = params.forceDetach,
+                connection = firstArgIsConnection ? arguments[0] : params.connection;
+
+				if (connection) {
+                    if (forceDetach || (connection.isDetachAllowed(connection)
+                                        && connection.endpoints[0].isDetachAllowed(connection)
+                                        && connection.endpoints[1].isDetachAllowed(connection))) {
+                        if (forceDetach || _currentInstance.checkCondition("beforeDetach", connection))
+						    connection.endpoints[0].detach(connection, false, true, fireEvent); // TODO check this param iscorrect for endpoint's detach method
+                    }
+                }
+                else {
+					var _p = jsPlumb.extend( {}, params); // a backwards compatibility hack: source should be thought of as 'params' in this case.
+					// test for endpoint uuids to detach
+					if (_p.uuids) {
+						_getEndpoint(_p.uuids[0]).detachFrom(_getEndpoint(_p.uuids[1]), fireEvent);
+					} else if (_p.sourceEndpoint && _p.targetEndpoint) {
+						_p.sourceEndpoint.detachFrom(_p.targetEndpoint);
+					} else {
+						var sourceId = _getId(_p.source),
+						    targetId = _getId(_p.target);
+						_operation(sourceId, function(jpc) {
+						    if ((jpc.sourceId == sourceId && jpc.targetId == targetId) || (jpc.targetId == sourceId && jpc.sourceId == targetId)) {
+							    if (_currentInstance.checkCondition("beforeDetach", jpc)) {
+                                    jpc.endpoints[0].detach(jpc, false, true, fireEvent);
+								}
+							}
+						});
+					}
+				}
+		};
+
+		/*
+		  Function: detachAllConnections
+		  Removes all an element's Connections.
+		   
+		  Parameters:
+		  	el - either the id of the element, or a selector for the element.
+		  	params - optional parameters.  alowed values:
+		  	        fireEvent : defaults to true, whether or not to fire the detach event.
+		  	
+		  Returns: 
+		  	void
+		 */
+		this.detachAllConnections = function(el, params) {
+            params = params || {};
+            el = _getElementObject(el);
+			var id = _getAttribute(el, "id"),
+                endpoints = endpointsByElement[id];
+			if (endpoints && endpoints.length) {
+				for ( var i = 0; i < endpoints.length; i++) {
+					endpoints[i].detachAll(params.fireEvent);
+				}
+			}
+		};
+
+		/*
+		  Function: detachEveryConnection 
+		  Remove all Connections from all elements, but leaves Endpoints in place.
+
+		  Parameters:
+		    params  - optional params object containing:
+		            fireEvent : whether or not to fire detach events. defaults to true.
+
+		   
+		  Returns: 
+		  	void
+		  	 
+		  See Also:
+		  	<removeEveryEndpoint>
+		 */
+		this.detachEveryConnection = function(params) {
+            params = params || {};
+			for ( var id in endpointsByElement) {
+				var endpoints = endpointsByElement[id];
+				if (endpoints && endpoints.length) {
+					for ( var i = 0; i < endpoints.length; i++) {
+						endpoints[i].detachAll(params.fireEvent);
+					}
+				}
+			}
+			delete connectionsByScope;
+			connectionsByScope = {};
+		};
+
+
+		/*
+		  Function: draggable 
+		  Initialises the draggability of some element or elements.  You should use this instead of y
+		  our library's draggable method so that jsPlumb can setup the appropriate callbacks.  Your 
+		  underlying library's drag method is always called from this method.
+		  
+		  Parameters: 
+		  	el - either an element id, a list of element ids, or a selector. 
+		  	options - options to pass through to the underlying library
+		  	 
+		  Returns: 
+		  	void
+		 */
+		 // TODO it would be nice if this supported a selector string, instead of an id.
+		this.draggable = function(el, options) {
+			if (typeof el == 'object' && el.length) {
+				for ( var i = 0; i < el.length; i++) {
+					var ele = _getElementObject(el[i]);
+					if (ele) _initDraggableIfNecessary(ele, true, options);
+				}
+			} 
+			else if (el._nodes) { 	// TODO this is YUI specific; really the logic should be forced
+				// into the library adapters (for jquery and mootools aswell)
+				for ( var i = 0; i < el._nodes.length; i++) {
+					var ele = _getElementObject(el._nodes[i]);
+					if (ele) _initDraggableIfNecessary(ele, true, options);
+				}
+			}
+			else {
+				var ele = _getElementObject(el);
+				if (ele) _initDraggableIfNecessary(ele, true, options);
+			}
+		};
+
+		/*
+		  Function: extend 
+		  Wraps the underlying library's extend functionality.
+		  
+		  Parameters: 
+		  	o1 - object to extend 
+		  	o2 - object to extend o1 with
+		  	
+		  Returns: 
+		  	o1, extended with all properties from o2.
+		 */
+		this.extend = function(o1, o2) {
+			return jsPlumb.CurrentLibrary.extend(o1, o2);
+		};
+		
+		/*
+		 * Function: getDefaultEndpointType
+		 * 	Returns the default Endpoint type. Used when someone wants to subclass Endpoint and have jsPlumb return instances of their subclass.
+		 *  you would make a call like this in your class's constructor:
+		 *    jsPlumb.getDefaultEndpointType().apply(this, arguments);
+		 * 
+		 * Returns:
+		 * 	the default Endpoint function used by jsPlumb.
+		 */
+		this.getDefaultEndpointType = function() {
+			return Endpoint;
+		};
+		
+		/*
+		 * Function: getDefaultConnectionType
+		 * 	Returns the default Connection type. Used when someone wants to subclass Connection and have jsPlumb return instances of their subclass.
+		 *  you would make a call like this in your class's constructor:
+		 *    jsPlumb.getDefaultConnectionType().apply(this, arguments);
+		 * 
+		 * Returns:
+		 * 	the default Connection function used by jsPlumb.
+		 */
+		this.getDefaultConnectionType = function() {
+			return Connection;
+		};
+
+		/*
+		 * Function: getConnections 
+		 * Gets all or a subset of connections currently managed by this jsPlumb instance.  If only one scope is passed in to this method,
+		 * the result will be a list of connections having that scope (passing in no scope at all will result in jsPlumb assuming you want the
+		 * default scope).  If multiple scopes are passed in, the return value will be a map of { scope -> [ connection... ] }.
+		 * 
+		 *  Parameters
+		 *  	scope	-	if the only argument to getConnections is a string, jsPlumb will treat that string as a scope filter, and return a list
+		 *                  of connections that are in the given scope.
+		 *      options	-	if the argument is a JS object, you can specify a finer-grained filter:
+		 *      
+		 *      		-	*scope* may be a string specifying a single scope, or an array of strings, specifying multiple scopes.
+		 *      		-	*source* either a string representing an element id, or a selector.  constrains the result to connections having this source.
+		 *      		-	*target* either a string representing an element id, or a selector.  constrains the result to connections having this target.
+		 * 
+		 */
+		this.getConnections = function(options) {
+			if (!options) {
+				options = {};
+			} else if (options.constructor == String) {
+				options = { "scope": options };
+			}
+			var prepareList = function(input) {
+				var r = [];
+				if (input) {
+					if (typeof input == 'string')
+						r.push(input);
+					else
+						r = input;
+				}
+				return r;
+			},
+			scope = options.scope || _currentInstance.getDefaultScope(),
+			scopes = prepareList(scope),
+			sources = prepareList(options.source),
+			targets = prepareList(options.target),
+			filter = function(list, value) {
+				return list.length > 0 ? _indexOf(list, value) != -1 : true;
+			},
+			results = scopes.length > 1 ? {} : [],
+			_addOne = function(scope, obj) {
+				if (scopes.length > 1) {
+					var ss = results[scope];
+					if (ss == null) {
+						ss = []; results[scope] = ss;
+					}
+					ss.push(obj);
+				} else results.push(obj);
+			};
+			for ( var i in connectionsByScope) {
+				if (filter(scopes, i)) {
+					for ( var j = 0; j < connectionsByScope[i].length; j++) {
+						var c = connectionsByScope[i][j];
+						if (filter(sources, c.sourceId) && filter(targets, c.targetId))
+							_addOne(i, c);
+					}
+				}
+			}
+			return results;
+		};
+
+		/*
+		 * Function: getAllConnections
+		 * Gets all connections, as a map of { scope -> [ connection... ] }. 
+		 */
+		this.getAllConnections = function() {
+			return connectionsByScope;
+		};
+
+		/*
+		 * Function: getDefaultScope 
+		 * Gets the default scope for connections and  endpoints. a scope defines a type of endpoint/connection; supplying a
+		 * scope to an endpoint or connection allows you to support different
+		 * types of connections in the same UI. but if you're only interested in
+		 * one type of connection, you don't need to supply a scope. this method
+		 * will probably be used by very few people; it's good for testing
+		 * though.
+		 */
+		this.getDefaultScope = function() {
+			return DEFAULT_SCOPE;
+		};
+
+		/*
+		  Function: getEndpoint 
+		  Gets an Endpoint by UUID
+		   
+		  Parameters: 
+		  	uuid - the UUID for the Endpoint
+		  	 
+		  Returns: 
+		  	Endpoint with the given UUID, null if nothing found.
+		 */
+		this.getEndpoint = _getEndpoint;
+		
+		/**
+		 * Function:getEndpoints
+		 * Gets the list of Endpoints for a given selector, or element id.
+		 * @param el
+		 * @return
+		 */
+		this.getEndpoints = function(el) {
+			return endpointsByElement[_getId(el)];
+		};
+
+		/*
+		 * Gets an element's id, creating one if necessary. really only exposed
+		 * for the lib-specific functionality to access; would be better to pass
+		 * the current instance into the lib-specific code (even though this is
+		 * a static call. i just don't want to expose it to the public API).
+		 */
+		this.getId = _getId;
+		this.getOffset = function(id) { 
+			var o = offsets[id]; 
+			return _updateOffset({elId:id});
+		};
+		
+		this.getSelector = function(spec) {
+			return jsPlumb.CurrentLibrary.getSelector(spec);
+		};
+		
+		this.getSize = function(id) { 
+			var s = sizes[id]; 
+			if (!s) _updateOffset({elId:id});
+			return sizes[id];
+		};		
+		
+		this.appendElement = _appendElement;
+		
+		var _hoverSuspended = false;
+		this.isHoverSuspended = function() { return _hoverSuspended; };
+		this.setHoverSuspended = function(s) { _hoverSuspended = s; };
+
+		/*
+		  Function: hide 
+		  Sets an element's connections to be hidden.
+		  
+		  Parameters: 
+		  	el - either the id of the element, or a selector for the element.
+		  	changeEndpoints - whether not to also hide endpoints on the element. by default this is false.  
+		  	 
+		  Returns: 
+		  	void
+		 */
+		this.hide = function(el, changeEndpoints) {
+			_setVisible(el, "none", changeEndpoints);
+		};
+		
+		// exposed for other objects to use to get a unique id.
+		this.idstamp = _idstamp;
+		
+		/**
+		 * callback from the current library to tell us to prepare ourselves (attach
+		 * mouse listeners etc; can't do that until the library has provided a bind method)
+		 * @return
+		 */
+		this.init = function() {
+			if (!initialized) {
+				_currentInstance.setRenderMode(_currentInstance.Defaults.RenderMode);  // calling the method forces the capability logic to be run.
+				
+				var bindOne = function(event) {
+						jsPlumb.CurrentLibrary.bind(document, event, function(e) {
+							if (!_currentInstance.currentlyDragging && renderMode == jsPlumb.CANVAS) {
+								// try connections first
+								for (var scope in connectionsByScope) {
+					    			var c = connectionsByScope[scope];
+					    			for (var i = 0; i < c.length; i++) {
+					    				var t = c[i].connector[event](e);
+					    				if (t) return;	
+					    			}
+					    		}
+								for (var el in endpointsByElement) {
+									var ee = endpointsByElement[el];
+									for (var i = 0; i < ee.length; i++) {
+										if (ee[i].endpoint[event](e)) return;
+									}
+								}
+							}
+						});					
+				};
+				bindOne("click");bindOne("dblclick");bindOne("mousemove");bindOne("mousedown");bindOne("mouseup");bindOne("contextmenu");
+			
+				initialized = true;
+				_currentInstance.fire("ready");
+			}
+		};
+		
+		this.log = log;
+		this.jsPlumbUIComponent = jsPlumbUIComponent;
+		this.EventGenerator = EventGenerator;
+
+		/*
+		 * Creates an anchor with the given params.
+		 * 
+		 * 
+		 * Returns: The newly created Anchor.
+		 */
+		this.makeAnchor = function() {
+			if (arguments.length == 0) return null;
+			var specimen = arguments[0], elementId = arguments[1], jsPlumbInstance = arguments[2], newAnchor = null;
+			if (!jsPlumbInstance) 
+				throw "NO JSPLUMB SET";
+			// if it appears to be an anchor already...
+			if (specimen.compute && specimen.getOrientation) return specimen;  //TODO hazy here about whether it should be added or is already added somehow.
+			// is it the name of an anchor type?
+			else if (typeof specimen == "string") {
+				newAnchor = jsPlumb.Anchors[arguments[0]]({elementId:elementId, jsPlumbInstance:_currentInstance});
+			}
+			// is it an array? it will be one of:
+			// 		an array of [name, params] - this defines a single anchor
+			//		an array of arrays - this defines some dynamic anchors
+			//		an array of numbers - this defines a single anchor.				
+			else if (specimen.constructor == Array) {					
+				if (specimen[0].constructor == Array || specimen[0].constructor == String) {
+					if (specimen.length == 2 && specimen[0].constructor == String && specimen[1].constructor == Object) {
+						var pp = jsPlumb.extend({elementId:elementId, jsPlumbInstance:_currentInstance}, specimen[1]);
+						newAnchor = jsPlumb.Anchors[specimen[0]](pp);
+					}
+					else
+						newAnchor = new DynamicAnchor(specimen, null, elementId);
+				}
+				else {
+					var anchorParams = {
+						x:specimen[0], y:specimen[1],
+						orientation : (specimen.length >= 4) ? [ specimen[2], specimen[3] ] : [0,0],
+						offsets : (specimen.length == 6) ? [ specimen[4], specimen[5] ] : [ 0, 0 ],
+						elementId:elementId
+					};						
+					newAnchor = new Anchor(anchorParams);
+					newAnchor.clone = function() { return new Anchor(anchorParams); };						 					
+				}
+			}
+			
+			if (!newAnchor.id) newAnchor.id = "anchor_" + _idstamp();
+			return newAnchor;
+		};
+
+		/**
+		 * makes a list of anchors from the given list of types or coords, eg
+		 * ["TopCenter", "RightMiddle", "BottomCenter", [0, 1, -1, -1] ]
+		 */
+		this.makeAnchors = function(types, elementId, jsPlumbInstance) {
+			var r = [];
+			for ( var i = 0; i < types.length; i++) {
+				if (typeof types[i] == "string")
+					r.push(jsPlumb.Anchors[types[i]]({elementId:elementId, jsPlumbInstance:jsPlumbInstance}));
+				else if (types[i].constructor == Array)
+					r.push(_currentInstance.makeAnchor(types[i], elementId, jsPlumbInstance));
+			}
+			return r;
+		};
+
+		/**
+		 * Makes a dynamic anchor from the given list of anchors (which may be in shorthand notation as strings or dimension arrays, or Anchor
+		 * objects themselves) and the given, optional, anchorSelector function (jsPlumb uses a default if this is not provided; most people will
+		 * not need to provide this - i think). 
+		 */
+		this.makeDynamicAnchor = function(anchors, anchorSelector) {
+			return new DynamicAnchor(anchors, anchorSelector);
+		};
+		
+		/**
+		 * Function: makeTarget
+		 * Makes some DOM element a Connection target, allowing you to drag connections to it
+		 * without having to register any Endpoints on it first.  When a Connection is established,
+		 * the endpoint spec that was passed in to this method is used to create a suitable 
+		 * Endpoint (the default will be used if you do not provide one).
+		 * 
+		 * Parameters:
+		 *  el		-	string id or element selector for the element to make a target.
+		 * 	params	-	JS object containing parameters:
+		 * 	  endpoint	optional.	specification of an endpoint to create when a connection is created.
+		 * 	  scope		optional.   scope for the drop zone.
+		 * 	  dropOptions optional. same stuff as you would pass to dropOptions of an Endpoint definition.
+		 * 	  deleteEndpointsOnDetach  optional, defaults to true. whether or not to delete
+		 *                             any Endpoints created by a connection to this target if
+		 *                             the connection is subsequently detached. this will not 
+		 *                             remove Endpoints that have had more Connections attached
+		 *                             to them after they were created.
+		 *                   	
+		 * 
+		 */
+		var _targetEndpointDefinitions = {},
+			_targetEndpoints = {},
+			_targetEndpointsUnique = {};
+		var _setEndpointPaintStylesAndAnchor = function(ep, epIndex) {
+			ep.paintStyle = ep.paintStyle ||
+			 				_currentInstance.Defaults.EndpointStyles[epIndex] ||
+                            _currentInstance.Defaults.EndpointStyle ||
+                            jsPlumb.Defaults.EndpointStyles[epIndex] ||
+                            jsPlumb.Defaults.EndpointStyle;
+			ep.hoverPaintStyle = ep.hoverPaintStyle ||
+                           _currentInstance.Defaults.EndpointHoverStyles[epIndex] ||
+                           _currentInstance.Defaults.EndpointHoverStyle ||
+                           jsPlumb.Defaults.EndpointHoverStyles[epIndex] ||
+                           jsPlumb.Defaults.EndpointHoverStyle;                            
+
+			ep.anchor = ep.anchor ||
+                      	_currentInstance.Defaults.Anchors[epIndex] ||
+                      	_currentInstance.Defaults.Anchor ||
+                      	jsPlumb.Defaults.Anchors[epIndex] ||
+                      	jsPlumb.Defaults.Anchor;                           
+				
+			ep.endpoint = ep.endpoint ||
+						  _currentInstance.Defaults.Endpoints[epIndex] ||
+						  _currentInstance.Defaults.Endpoint ||
+						  jsPlumb.Defaults.Endpoints[epIndex] ||
+						  jsPlumb.Defaults.Endpoint;
+		};
+		this.makeTarget = function(el, params, referenceParams) {						
+			
+			var p = jsPlumb.extend({}, referenceParams);
+			jsPlumb.extend(p, params);
+			_setEndpointPaintStylesAndAnchor(p, 1);                                                    
+			var jpcl = jsPlumb.CurrentLibrary,
+			    targetScope = p.scope || _currentInstance.Defaults.Scope,
+			    deleteEndpointsOnDetach = !(p.deleteEndpointsOnDetach === false),
+			_doOne = function(_el) {
+				
+				// get the element's id and store the endpoint definition for it.  jsPlumb.connect calls will look for one of these,
+				// and use the endpoint definition if found.
+				var elid = _getId(_el);
+				_targetEndpointDefinitions[elid] = p;
+				_targetEndpointsUnique[elid] = p.uniqueEndpoint;
+				
+				var dropOptions = jsPlumb.extend({}, p.dropOptions || {}),
+				_drop = function() {
+					_currentInstance.currentlyDragging = false;
+					var draggable = _getElementObject(jpcl.getDragObject(arguments)),
+						id = _getAttribute(draggable, "dragId"),				
+						// restore the original scope if necessary (issue 57)
+						scope = _getAttribute(draggable, "originalScope"),
+						jpc = floatingConnections[id],
+						source = jpc.endpoints[0],
+						_endpoint = p.endpoint ? jsPlumb.extend({}, p.endpoint) : {};                                              
+
+					// unlock the source anchor to allow it to refresh its position if necessary
+					source.anchor.locked = false;					
+										
+					if (scope) jpcl.setDragScope(draggable, scope);				
+					
+					// check if drop is allowed here.					
+					var _continue = jpc.isDropAllowed(jpc.sourceId, _getId(_el), jpc.scope);		
+					
+					// regardless of whether the connection is ok, reconfigure the existing connection to 
+					// point at the current info. we need this to be correct for the detach event that will follow.
+					// clear the source endpoint from the list to detach. we will detach this connection at this
+					// point, but we want to keep the source endpoint.  the target is a floating endpoint and should
+					// be removed.  TODO need to figure out whether this code can result in endpoints kicking around
+					// when they shouldnt be.  like is this a full detach of a connection?  can it be?
+					if (jpc.endpointsToDeleteOnDetach) {
+						if (source === jpc.endpointsToDeleteOnDetach[0])
+							jpc.endpointsToDeleteOnDetach[0] = null;
+						else if (source === jpc.endpointsToDeleteOnDetach[1])
+							jpc.endpointsToDeleteOnDetach[1] = null;
+					}
+					// reinstate any suspended endpoint; this just puts the connection back into
+					// a state in which it will report sensible values if someone asks it about
+					// its target.  we're going to throw this connection away shortly so it doesnt matter
+					// if we manipulate it a bit.
+					if (jpc.suspendedEndpoint) {
+						jpc.targetId = jpc.suspendedEndpoint.elementId;
+						jpc.target = jpcl.getElementObject(jpc.suspendedEndpoint.elementId);
+						jpc.endpoints[1] = jpc.suspendedEndpoint;
+					}																										
+					
+					if (_continue) {
+					
+						// detach this connection from the source.						
+						source.detach(jpc, false, true, false);//source.endpointWillMoveAfterConnection);
+					
+						// make a new Endpoint for the target
+						//var newEndpoint = _currentInstance.addEndpoint(_el, _endpoint);
+						
+						var newEndpoint = _targetEndpoints[elid] || _currentInstance.addEndpoint(_el, p);
+						if (p.uniqueEndpoint) _targetEndpoints[elid] = newEndpoint;  // may of course just store what it just pulled out. that's ok.
+																
+						// if the anchor has a 'positionFinder' set, then delegate to that function to find
+						// out where to locate the anchor.
+						if (newEndpoint.anchor.positionFinder != null) {
+							var dropPosition = jpcl.getUIPosition(arguments),
+							elPosition = jpcl.getOffset(_el),
+							elSize = jpcl.getSize(_el),
+							ap = newEndpoint.anchor.positionFinder(dropPosition, elPosition, elSize, newEndpoint.anchor.constructorParams);
+							newEndpoint.anchor.x = ap[0];
+							newEndpoint.anchor.y = ap[1];
+							// now figure an orientation for it..kind of hard to know what to do actually. probably the best thing i can do is to
+							// support specifying an orientation in the anchor's spec. if one is not supplied then i will make the orientation 
+							// be what will cause the most natural link to the source: it will be pointing at the source, but it needs to be
+							// specified in one axis only, and so how to make that choice? i think i will use whichever axis is the one in which
+							// the target is furthest away from the source.
+						}
+						var c = _currentInstance.connect({
+							source:source,
+							target:newEndpoint,
+							scope:scope,
+							previousConnection:jpc,
+							container:jpc.parent,
+							deleteEndpointsOnDetach:deleteEndpointsOnDetach,
+							// 'endpointWillMoveAfterConnection' is set by the makeSource function, and it indicates that the
+							// given endpoint will actually transfer from the element it is currently attached to to some other
+							// element after a connection has been established.  in that case, we do not want to fire the
+							// connection event, since it will have the wrong data in it; makeSource will do it for us.
+							// this is controlled by the 'parent' parameter on a makeSource call.
+							doNotFireConnectionEvent:source.endpointWillMoveAfterConnection
+						});
+						if (deleteEndpointsOnDetach) 
+							c.endpointsToDeleteOnDetach = [ source, newEndpoint ];
+
+						c.repaint();
+					}				
+					// if not allowed to drop...
+					else {
+						// TODO this code is identical (pretty much) to what happens when a connection
+						// dragged from a normal endpoint is in this situation. refactor.
+						// is this an existing connection, and will we reattach?
+						if (jpc.suspendedEndpoint) {
+							if (source.isReattach) {
+								jpc.setHover(false);
+								jpc.floatingAnchorIndex = null;
+								jpc.suspendedEndpoint.addConnection(jpc);
+								_currentInstance.repaint(source.elementId);
+							}
+							else
+								source.detach(jpc, false, true, true);  // otherwise, detach the connection and tell everyone about it.
+						}
+						
+					}														
+				};
+				
+				var dropEvent = jpcl.dragEvents['drop'];
+				dropOptions["scope"] = dropOptions["scope"] || targetScope;
+				dropOptions[dropEvent] = _wrap(dropOptions[dropEvent], _drop);
+				
+				jpcl.initDroppable(_el, dropOptions, true);
+			};
+			
+			el = _convertYUICollection(el);			
+			
+			var inputs = el.length && el.constructor != String ? el : [ el ];
+						
+			for (var i = 0; i < inputs.length; i++) {			
+				_doOne(_getElementObject(inputs[i]));
+			}
+		};
+		
+		/**
+		 * helper method to make a list of elements drop targets.
+		 * @param els
+		 * @param params
+		 * @param referenceParams
+		 * @return
+		 */
+		this.makeTargets = function(els, params, referenceParams) {
+			for ( var i = 0; i < els.length; i++) {
+				_currentInstance.makeTarget(els[i], params, referenceParams);				
+			}
+		};
+		
+		/**
+		 * Function: makeSource
+		 * Makes some DOM element a Connection source, allowing you to drag connections from it
+		 * without having to register any Endpoints on it first.  When a Connection is established,
+		 * the endpoint spec that was passed in to this method is used to create a suitable 
+		 * Endpoint (the default will be used if you do not provide one).
+		 * 

[... 6223 lines stripped ...]