UNPKG

bpmn-visualization

Version:

A TypeScript library for visualizing process execution data on BPMN diagrams

52,378 lines • 1.71 MB
/*
Copyright 2020-2025 Bonitasoft S.A.

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 at

http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

var bpmnvisu = (function (exports) {
  'use strict';

  exports.FitType = void 0;
  (function (FitType) {
      FitType["None"] = "None";
      FitType["HorizontalVertical"] = "HorizontalVertical";
      FitType["Horizontal"] = "Horizontal";
      FitType["Vertical"] = "Vertical";
      FitType["Center"] = "Center";
  })(exports.FitType || (exports.FitType = {}));
  exports.ZoomType = void 0;
  (function (ZoomType) {
      ZoomType["In"] = "in";
      ZoomType["Out"] = "out";
  })(exports.ZoomType || (exports.ZoomType = {}));

  function htmlElement(element) {
      if (element instanceof HTMLElement) {
          return element;
      }
      return document.querySelector(`#${element}`);
  }

  exports.ShapeBpmnElementKind = void 0;
  (function (ShapeBpmnElementKind) {
      ShapeBpmnElementKind["LANE"] = "lane";
      ShapeBpmnElementKind["POOL"] = "pool";
      ShapeBpmnElementKind["CALL_ACTIVITY"] = "callActivity";
      ShapeBpmnElementKind["SUB_PROCESS"] = "subProcess";
      ShapeBpmnElementKind["TASK"] = "task";
      ShapeBpmnElementKind["TASK_USER"] = "userTask";
      ShapeBpmnElementKind["TASK_SERVICE"] = "serviceTask";
      ShapeBpmnElementKind["TASK_RECEIVE"] = "receiveTask";
      ShapeBpmnElementKind["TASK_SEND"] = "sendTask";
      ShapeBpmnElementKind["TASK_MANUAL"] = "manualTask";
      ShapeBpmnElementKind["TASK_SCRIPT"] = "scriptTask";
      ShapeBpmnElementKind["TASK_BUSINESS_RULE"] = "businessRuleTask";
      ShapeBpmnElementKind["GLOBAL_TASK"] = "globalTask";
      ShapeBpmnElementKind["GLOBAL_TASK_USER"] = "globalUserTask";
      ShapeBpmnElementKind["GLOBAL_TASK_MANUAL"] = "globalManualTask";
      ShapeBpmnElementKind["GLOBAL_TASK_SCRIPT"] = "globalScriptTask";
      ShapeBpmnElementKind["GLOBAL_TASK_BUSINESS_RULE"] = "globalBusinessRuleTask";
      ShapeBpmnElementKind["GROUP"] = "group";
      ShapeBpmnElementKind["TEXT_ANNOTATION"] = "textAnnotation";
      ShapeBpmnElementKind["GATEWAY_PARALLEL"] = "parallelGateway";
      ShapeBpmnElementKind["GATEWAY_EXCLUSIVE"] = "exclusiveGateway";
      ShapeBpmnElementKind["GATEWAY_INCLUSIVE"] = "inclusiveGateway";
      ShapeBpmnElementKind["GATEWAY_EVENT_BASED"] = "eventBasedGateway";
      ShapeBpmnElementKind["GATEWAY_COMPLEX"] = "complexGateway";
      ShapeBpmnElementKind["EVENT_START"] = "startEvent";
      ShapeBpmnElementKind["EVENT_END"] = "endEvent";
      ShapeBpmnElementKind["EVENT_INTERMEDIATE_CATCH"] = "intermediateCatchEvent";
      ShapeBpmnElementKind["EVENT_INTERMEDIATE_THROW"] = "intermediateThrowEvent";
      ShapeBpmnElementKind["EVENT_BOUNDARY"] = "boundaryEvent";
  })(exports.ShapeBpmnElementKind || (exports.ShapeBpmnElementKind = {}));
  exports.ShapeBpmnCallActivityKind = void 0;
  (function (ShapeBpmnCallActivityKind) {
      ShapeBpmnCallActivityKind["CALLING_PROCESS"] = "process";
      ShapeBpmnCallActivityKind["CALLING_GLOBAL_TASK"] = "global task";
  })(exports.ShapeBpmnCallActivityKind || (exports.ShapeBpmnCallActivityKind = {}));
  exports.ShapeBpmnEventBasedGatewayKind = void 0;
  (function (ShapeBpmnEventBasedGatewayKind) {
      ShapeBpmnEventBasedGatewayKind["Exclusive"] = "Exclusive";
      ShapeBpmnEventBasedGatewayKind["None"] = "None";
      ShapeBpmnEventBasedGatewayKind["Parallel"] = "Parallel";
  })(exports.ShapeBpmnEventBasedGatewayKind || (exports.ShapeBpmnEventBasedGatewayKind = {}));
  exports.ShapeBpmnEventDefinitionKind = void 0;
  (function (ShapeBpmnEventDefinitionKind) {
      ShapeBpmnEventDefinitionKind["NONE"] = "none";
      ShapeBpmnEventDefinitionKind["TERMINATE"] = "terminate";
      ShapeBpmnEventDefinitionKind["CANCEL"] = "cancel";
      ShapeBpmnEventDefinitionKind["COMPENSATION"] = "compensate";
      ShapeBpmnEventDefinitionKind["CONDITIONAL"] = "conditional";
      ShapeBpmnEventDefinitionKind["ERROR"] = "error";
      ShapeBpmnEventDefinitionKind["ESCALATION"] = "escalation";
      ShapeBpmnEventDefinitionKind["LINK"] = "link";
      ShapeBpmnEventDefinitionKind["MESSAGE"] = "message";
      ShapeBpmnEventDefinitionKind["SIGNAL"] = "signal";
      ShapeBpmnEventDefinitionKind["TIMER"] = "timer";
  })(exports.ShapeBpmnEventDefinitionKind || (exports.ShapeBpmnEventDefinitionKind = {}));
  exports.ShapeBpmnMarkerKind = void 0;
  (function (ShapeBpmnMarkerKind) {
      ShapeBpmnMarkerKind["ADHOC"] = "adhoc";
      ShapeBpmnMarkerKind["COMPENSATION"] = "compensation";
      ShapeBpmnMarkerKind["EXPAND"] = "expand";
      ShapeBpmnMarkerKind["LOOP"] = "loop";
      ShapeBpmnMarkerKind["MULTI_INSTANCE_PARALLEL"] = "multi-parallel";
      ShapeBpmnMarkerKind["MULTI_INSTANCE_SEQUENTIAL"] = "multi-sequential";
  })(exports.ShapeBpmnMarkerKind || (exports.ShapeBpmnMarkerKind = {}));
  exports.ShapeBpmnSubProcessKind = void 0;
  (function (ShapeBpmnSubProcessKind) {
      ShapeBpmnSubProcessKind["AD_HOC"] = "adhoc";
      ShapeBpmnSubProcessKind["EMBEDDED"] = "embedded";
      ShapeBpmnSubProcessKind["EVENT"] = "event";
      ShapeBpmnSubProcessKind["TRANSACTION"] = "transaction";
  })(exports.ShapeBpmnSubProcessKind || (exports.ShapeBpmnSubProcessKind = {}));

  function convertEmptyStringAndObject(element, acceptEmptyString) {
      if (element === '') {
          return acceptEmptyString ? {} : undefined;
      }
      return element;
  }
  function ensureIsArray(elements, acceptEmptyString = false) {
      if (elements === undefined || elements === null) {
          return [];
      }
      return ((Array.isArray(elements) ? elements : [elements])
          .map(element => convertEmptyStringAndObject(element, acceptEmptyString))
          .filter(Boolean));
  }
  function filter(arrayToFilter, suffix, options) {
      const patterns = [];
      if (options === null || options === void 0 ? void 0 : options.startingWith) {
          patterns.push(`^(${options.startingWith}).*`);
      }
      else if (options === null || options === void 0 ? void 0 : options.notStartingWith) {
          patterns.push(`^(?!(${options.notStartingWith})).*`);
      }
      patterns.push(`${suffix}$`);
      const pattern = patterns.join('');
      return arrayToFilter.filter(element => ((options === null || options === void 0 ? void 0 : options.ignoreCase) ? new RegExp(pattern, 'i').test(element) : new RegExp(pattern).test(element)));
  }

  class ShapeUtil {
      static isEvent(kind) {
          return isKindOf(EVENT_KINDS, kind);
      }
      static eventKinds() {
          return [...EVENT_KINDS];
      }
      static isBoundaryEvent(kind) {
          return exports.ShapeBpmnElementKind.EVENT_BOUNDARY === kind;
      }
      static isStartEvent(kind) {
          return exports.ShapeBpmnElementKind.EVENT_START === kind;
      }
      static isCatchEvent(kind) {
          return exports.ShapeBpmnElementKind.EVENT_INTERMEDIATE_CATCH === kind || exports.ShapeBpmnElementKind.EVENT_BOUNDARY === kind || exports.ShapeBpmnElementKind.EVENT_START === kind;
      }
      static isIntermediateCatchEvent(kind) {
          return exports.ShapeBpmnElementKind.EVENT_INTERMEDIATE_CATCH === kind;
      }
      static isIntermediateThrowEvent(kind) {
          return exports.ShapeBpmnElementKind.EVENT_INTERMEDIATE_THROW === kind;
      }
      static isCallActivity(kind) {
          return exports.ShapeBpmnElementKind.CALL_ACTIVITY === kind;
      }
      static isSubProcess(kind) {
          return exports.ShapeBpmnElementKind.SUB_PROCESS === kind;
      }
      static canHaveNoneEvent(kind) {
          return exports.ShapeBpmnElementKind.EVENT_INTERMEDIATE_THROW === kind || exports.ShapeBpmnElementKind.EVENT_END === kind || exports.ShapeBpmnElementKind.EVENT_START === kind;
      }
      static isActivity(kind) {
          return isKindOf(ACTIVITY_KINDS, kind);
      }
      static activityKinds() {
          return [...ACTIVITY_KINDS];
      }
      static isWithDefaultSequenceFlow(kind) {
          return FLOW_NODE_WITH_DEFAULT_SEQUENCE_FLOW_KINDS.has(kind);
      }
      static isTask(kind) {
          return isKindOf(TASK_KINDS, kind);
      }
      static taskKinds() {
          return [...TASK_KINDS];
      }
      static gatewayKinds() {
          return [...GATEWAY_KINDS];
      }
      static isGateway(kind) {
          return isKindOf(GATEWAY_KINDS, kind);
      }
      static flowNodeKinds() {
          return Object.values(exports.ShapeBpmnElementKind).filter(kind => !ShapeUtil.isPoolOrLane(kind));
      }
      static isPoolOrLane(kind) {
          return kind == exports.ShapeBpmnElementKind.POOL || kind == exports.ShapeBpmnElementKind.LANE;
      }
  }
  function filterKind(suffix, options) {
      return filter(Object.values(exports.ShapeBpmnElementKind), suffix, options);
  }
  function isKindOf(referenceKinds, kind) {
      return Object.values(referenceKinds)
          .map(value => value)
          .includes(kind);
  }
  const EVENT_KINDS = filterKind('Event');
  const GATEWAY_KINDS = filterKind('Gateway');
  const TASK_KINDS = filterKind('Task', { ignoreCase: true, notStartingWith: 'global' });
  const ACTIVITY_KINDS = [...TASK_KINDS, exports.ShapeBpmnElementKind.CALL_ACTIVITY, exports.ShapeBpmnElementKind.SUB_PROCESS];
  const FLOW_NODE_WITH_DEFAULT_SEQUENCE_FLOW_KINDS = new Set([
      ...ACTIVITY_KINDS,
      exports.ShapeBpmnElementKind.GATEWAY_EXCLUSIVE,
      exports.ShapeBpmnElementKind.GATEWAY_INCLUSIVE,
      exports.ShapeBpmnElementKind.GATEWAY_COMPLEX,
  ]);
  const eventDefinitionKinds = Object.values(exports.ShapeBpmnEventDefinitionKind).filter(kind => kind != exports.ShapeBpmnEventDefinitionKind.NONE);

  exports.AssociationDirectionKind = void 0;
  (function (AssociationDirectionKind) {
      AssociationDirectionKind["NONE"] = "None";
      AssociationDirectionKind["ONE"] = "One";
      AssociationDirectionKind["BOTH"] = "Both";
  })(exports.AssociationDirectionKind || (exports.AssociationDirectionKind = {}));
  exports.FlowKind = void 0;
  (function (FlowKind) {
      FlowKind["SEQUENCE_FLOW"] = "sequenceFlow";
      FlowKind["MESSAGE_FLOW"] = "messageFlow";
      FlowKind["ASSOCIATION_FLOW"] = "association";
  })(exports.FlowKind || (exports.FlowKind = {}));
  exports.MessageVisibleKind = void 0;
  (function (MessageVisibleKind) {
      MessageVisibleKind["NONE"] = "none";
      MessageVisibleKind["INITIATING"] = "initiating";
      MessageVisibleKind["NON_INITIATING"] = "non_initiating";
  })(exports.MessageVisibleKind || (exports.MessageVisibleKind = {}));
  exports.SequenceFlowKind = void 0;
  (function (SequenceFlowKind) {
      SequenceFlowKind["NORMAL"] = "normal";
      SequenceFlowKind["DEFAULT"] = "default";
      SequenceFlowKind["CONDITIONAL_FROM_ACTIVITY"] = "conditional_from_activity";
      SequenceFlowKind["CONDITIONAL_FROM_GATEWAY"] = "conditional_from_gateway";
  })(exports.SequenceFlowKind || (exports.SequenceFlowKind = {}));

  class Flow {
      constructor(id, name, kind, sourceReferenceId, targetReferenceId) {
          Object.defineProperty(this, "id", {
              enumerable: true,
              configurable: true,
              writable: true,
              value: id
          });
          Object.defineProperty(this, "name", {
              enumerable: true,
              configurable: true,
              writable: true,
              value: name
          });
          Object.defineProperty(this, "kind", {
              enumerable: true,
              configurable: true,
              writable: true,
              value: kind
          });
          Object.defineProperty(this, "sourceReferenceId", {
              enumerable: true,
              configurable: true,
              writable: true,
              value: sourceReferenceId
          });
          Object.defineProperty(this, "targetReferenceId", {
              enumerable: true,
              configurable: true,
              writable: true,
              value: targetReferenceId
          });
      }
  }
  class SequenceFlow extends Flow {
      constructor(id, name, sourceReferenceId, targetReferenceId, sequenceFlowKind = exports.SequenceFlowKind.NORMAL) {
          super(id, name, exports.FlowKind.SEQUENCE_FLOW, sourceReferenceId, targetReferenceId);
          Object.defineProperty(this, "sequenceFlowKind", {
              enumerable: true,
              configurable: true,
              writable: true,
              value: sequenceFlowKind
          });
      }
  }
  class MessageFlow extends Flow {
      constructor(id, name, sourceReferenceId, targetReferenceId) {
          super(id, name, exports.FlowKind.MESSAGE_FLOW, sourceReferenceId, targetReferenceId);
      }
  }
  class AssociationFlow extends Flow {
      constructor(id, name, sourceReferenceId, targetReferenceId, associationDirectionKind = exports.AssociationDirectionKind.NONE) {
          super(id, name, exports.FlowKind.ASSOCIATION_FLOW, sourceReferenceId, targetReferenceId);
          Object.defineProperty(this, "associationDirectionKind", {
              enumerable: true,
              configurable: true,
              writable: true,
              value: associationDirectionKind
          });
      }
  }

  function getDefaultExportFromCjs (x) {
  	return x && x.__esModule && Object.prototype.hasOwnProperty.call(x, 'default') ? x['default'] : x;
  }

  var build$1 = {exports: {}};

  var build = build$1.exports;
  var hasRequiredBuild;
  function requireBuild () {
  	if (hasRequiredBuild) return build$1.exports;
  	hasRequiredBuild = 1;
  	(function (module) {
  		(function (root, factory) {
  		if (module.exports) {
  		module.exports = factory();
  		} else {
  		root.mxgraph = factory();
  		}
  		}(build, function () {
  		return function (opts) {
  		for (var name in opts) { this[name] = opts[name]; }
  		var __mxOutput = {};
  		var mxClient =
  		{
  			VERSION: '4.2.2',
  			IS_IE: navigator.userAgent != null && navigator.userAgent.indexOf('MSIE') >= 0,
  			IS_IE6: navigator.userAgent != null && navigator.userAgent.indexOf('MSIE 6') >= 0,
  			IS_IE11: navigator.userAgent != null && !!navigator.userAgent.match(/Trident\/7\./),
  			IS_EDGE: navigator.userAgent != null && !!navigator.userAgent.match(/Edge\//),
  			IS_QUIRKS: navigator.userAgent != null && navigator.userAgent.indexOf('MSIE') >= 0 &&
  				(document.documentMode == null || document.documentMode == 5),
  			IS_EM: 'spellcheck' in document.createElement('textarea') && document.documentMode == 8,
  			VML_PREFIX: 'v',
  			OFFICE_PREFIX: 'o',
  		  	IS_NS: navigator.userAgent != null &&
  		  		navigator.userAgent.indexOf('Mozilla/') >= 0 &&
  		  		navigator.userAgent.indexOf('MSIE') < 0 &&
  		  		navigator.userAgent.indexOf('Edge/') < 0,
  		  	IS_OP: navigator.userAgent != null &&
  		  		(navigator.userAgent.indexOf('Opera/') >= 0 ||
  		  		navigator.userAgent.indexOf('OPR/') >= 0),
  		  	IS_OT: navigator.userAgent != null &&
  		  		navigator.userAgent.indexOf('Presto/') >= 0 &&
  		  		navigator.userAgent.indexOf('Presto/2.4.') < 0 &&
  		  		navigator.userAgent.indexOf('Presto/2.3.') < 0 &&
  		  		navigator.userAgent.indexOf('Presto/2.2.') < 0 &&
  		  		navigator.userAgent.indexOf('Presto/2.1.') < 0 &&
  		  		navigator.userAgent.indexOf('Presto/2.0.') < 0 &&
  		  		navigator.userAgent.indexOf('Presto/1.') < 0,
  		  	IS_SF: /Apple Computer, Inc/.test(navigator.vendor),
  		  	IS_ANDROID: navigator.appVersion.indexOf('Android') >= 0,
  		  	IS_IOS: (/iP(hone|od|ad)/.test(navigator.platform)),
  		  	IS_GC: /Google Inc/.test(navigator.vendor),
  		  	IS_CHROMEAPP: window.chrome != null && chrome.app != null && chrome.app.runtime != null,
  		  	IS_FF: typeof InstallTrigger !== 'undefined',
  		  	IS_MT: (navigator.userAgent.indexOf('Firefox/') >= 0 &&
  				navigator.userAgent.indexOf('Firefox/1.') < 0 &&
  		  		navigator.userAgent.indexOf('Firefox/2.') < 0) ||
  		  		(navigator.userAgent.indexOf('Iceweasel/') >= 0 &&
  		  		navigator.userAgent.indexOf('Iceweasel/1.') < 0 &&
  		  		navigator.userAgent.indexOf('Iceweasel/2.') < 0) ||
  		  		(navigator.userAgent.indexOf('SeaMonkey/') >= 0 &&
  		  		navigator.userAgent.indexOf('SeaMonkey/1.') < 0) ||
  		  		(navigator.userAgent.indexOf('Iceape/') >= 0 &&
  		  		navigator.userAgent.indexOf('Iceape/1.') < 0),
  		  	IS_VML: navigator.appName.toUpperCase() == 'MICROSOFT INTERNET EXPLORER',
  		  	IS_SVG: navigator.appName.toUpperCase() != 'MICROSOFT INTERNET EXPLORER',
  		  	NO_FO: !document.createElementNS || document.createElementNS('http://www.w3.org/2000/svg',
  		  		'foreignObject') != '[object SVGForeignObjectElement]' || navigator.userAgent.indexOf('Opera/') >= 0,
  		  	IS_WIN: navigator.appVersion.indexOf('Win') > 0,
  		  	IS_MAC: navigator.appVersion.indexOf('Mac') > 0,
  		  	IS_CHROMEOS: /\bCrOS\b/.test(navigator.appVersion),
  		  	IS_TOUCH: 'ontouchstart' in document.documentElement,
  		  	IS_POINTER: window.PointerEvent != null && !(navigator.appVersion.indexOf('Mac') > 0),
  		  	IS_LOCAL: document.location.href.indexOf('http://') < 0 &&
  		  			  document.location.href.indexOf('https://') < 0,
  		  	defaultBundles: [],
  			isBrowserSupported: function()
  			{
  				return mxClient.IS_VML || mxClient.IS_SVG;
  			},
  			link: function(rel, href, doc, id)
  			{
  				doc = doc || document;
  				if (mxClient.IS_IE6)
  				{
  					doc.write('<link rel="' + rel + '" href="' + href + '" charset="UTF-8" type="text/css"/>');
  				}
  				else
  				{
  					var link = doc.createElement('link');
  					link.setAttribute('rel', rel);
  					link.setAttribute('href', href);
  					link.setAttribute('charset', 'UTF-8');
  					link.setAttribute('type', 'text/css');
  					if (id)
  					{
  						link.setAttribute('id', id);
  					}
  					var head = doc.getElementsByTagName('head')[0];
  			   		head.appendChild(link);
  				}
  			},
  			loadResources: function(fn, lan)
  			{
  				var pending = mxClient.defaultBundles.length;
  				function callback()
  				{
  					if (--pending == 0)
  					{
  						fn();
  					}
  				}
  				for (var i = 0; i < mxClient.defaultBundles.length; i++)
  				{
  					mxResources.add(mxClient.defaultBundles[i], lan, callback);
  				}
  			},
  			include: function(src)
  			{
  				document.write('<script src="'+src+'"></script>');
  			}
  		};
  		if (typeof(mxLoadResources) == 'undefined')
  		{
  			mxLoadResources = true;
  		}
  		if (typeof(mxForceIncludes) == 'undefined')
  		{
  			mxForceIncludes = false;
  		}
  		if (typeof(mxResourceExtension) == 'undefined')
  		{
  			mxResourceExtension = '.txt';
  		}
  		if (typeof(mxLoadStylesheets) == 'undefined')
  		{
  			mxLoadStylesheets = true;
  		}
  		if (typeof(mxBasePath) != 'undefined' && mxBasePath.length > 0)
  		{
  			if (mxBasePath.substring(mxBasePath.length - 1) == '/')
  			{
  				mxBasePath = mxBasePath.substring(0, mxBasePath.length - 1);
  			}
  			mxClient.basePath = mxBasePath;
  		}
  		else
  		{
  			mxClient.basePath = '.';
  		}
  		if (typeof(mxImageBasePath) != 'undefined' && mxImageBasePath.length > 0)
  		{
  			if (mxImageBasePath.substring(mxImageBasePath.length - 1) == '/')
  			{
  				mxImageBasePath = mxImageBasePath.substring(0, mxImageBasePath.length - 1);
  			}
  			mxClient.imageBasePath = mxImageBasePath;
  		}
  		else
  		{
  			mxClient.imageBasePath = mxClient.basePath + '/images';
  		}
  		if (typeof(mxLanguage) != 'undefined' && mxLanguage != null)
  		{
  			mxClient.language = mxLanguage;
  		}
  		else
  		{
  			mxClient.language = (mxClient.IS_IE) ? navigator.userLanguage : navigator.language;
  		}
  		if (typeof(mxDefaultLanguage) != 'undefined' && mxDefaultLanguage != null)
  		{
  			mxClient.defaultLanguage = mxDefaultLanguage;
  		}
  		else
  		{
  			mxClient.defaultLanguage = 'en';
  		}
  		if (mxLoadStylesheets)
  		{
  			mxClient.link('stylesheet', mxClient.basePath + '/css/common.css');
  		}
  		if (typeof(mxLanguages) != 'undefined' && mxLanguages != null)
  		{
  			mxClient.languages = mxLanguages;
  		}
  		if (mxClient.IS_VML)
  		{
  			if (mxClient.IS_SVG)
  			{
  				mxClient.IS_VML = false;
  			}
  			else
  			{
  				if (document.namespaces != null)
  				{
  					if (document.documentMode == 8)
  					{
  						document.namespaces.add(mxClient.VML_PREFIX, 'urn:schemas-microsoft-com:vml', '#default#VML');
  						document.namespaces.add(mxClient.OFFICE_PREFIX, 'urn:schemas-microsoft-com:office:office', '#default#VML');
  					}
  					else
  					{
  						document.namespaces.add(mxClient.VML_PREFIX, 'urn:schemas-microsoft-com:vml');
  						document.namespaces.add(mxClient.OFFICE_PREFIX, 'urn:schemas-microsoft-com:office:office');
  					}
  				}
  				if (mxClient.IS_QUIRKS && document.styleSheets.length >= 30)
  				{
  					(function()
  					{
  						var node = document.createElement('style');
  						node.type = 'text/css';
  						node.styleSheet.cssText = mxClient.VML_PREFIX + '\\:*{behavior:url(#default#VML)}' +
  				        	mxClient.OFFICE_PREFIX + '\\:*{behavior:url(#default#VML)}';
  				        document.getElementsByTagName('head')[0].appendChild(node);
  					})();
  				}
  				else
  				{
  					document.createStyleSheet().cssText = mxClient.VML_PREFIX + '\\:*{behavior:url(#default#VML)}' +
  				    	mxClient.OFFICE_PREFIX + '\\:*{behavior:url(#default#VML)}';
  				}
  			    if (mxLoadStylesheets)
  			    {
  			    	mxClient.link('stylesheet', mxClient.basePath + '/css/explorer.css');
  			    }
  			}
  		}
  		if (mxForceIncludes || !(module.exports != null))
  		{
  			mxClient.include(mxClient.basePath+'/js/util/mxLog.js');
  			mxClient.include(mxClient.basePath+'/js/util/mxObjectIdentity.js');
  			mxClient.include(mxClient.basePath+'/js/util/mxDictionary.js');
  			mxClient.include(mxClient.basePath+'/js/util/mxResources.js');
  			mxClient.include(mxClient.basePath+'/js/util/mxPoint.js');
  			mxClient.include(mxClient.basePath+'/js/util/mxRectangle.js');
  			mxClient.include(mxClient.basePath+'/js/util/mxEffects.js');
  			mxClient.include(mxClient.basePath+'/js/util/mxUtils.js');
  			mxClient.include(mxClient.basePath+'/js/util/mxConstants.js');
  			mxClient.include(mxClient.basePath+'/js/util/mxEventObject.js');
  			mxClient.include(mxClient.basePath+'/js/util/mxMouseEvent.js');
  			mxClient.include(mxClient.basePath+'/js/util/mxEventSource.js');
  			mxClient.include(mxClient.basePath+'/js/util/mxEvent.js');
  			mxClient.include(mxClient.basePath+'/js/util/mxXmlRequest.js');
  			mxClient.include(mxClient.basePath+'/js/util/mxClipboard.js');
  			mxClient.include(mxClient.basePath+'/js/util/mxWindow.js');
  			mxClient.include(mxClient.basePath+'/js/util/mxForm.js');
  			mxClient.include(mxClient.basePath+'/js/util/mxImage.js');
  			mxClient.include(mxClient.basePath+'/js/util/mxDivResizer.js');
  			mxClient.include(mxClient.basePath+'/js/util/mxDragSource.js');
  			mxClient.include(mxClient.basePath+'/js/util/mxToolbar.js');
  			mxClient.include(mxClient.basePath+'/js/util/mxUndoableEdit.js');
  			mxClient.include(mxClient.basePath+'/js/util/mxUndoManager.js');
  			mxClient.include(mxClient.basePath+'/js/util/mxUrlConverter.js');
  			mxClient.include(mxClient.basePath+'/js/util/mxPanningManager.js');
  			mxClient.include(mxClient.basePath+'/js/util/mxPopupMenu.js');
  			mxClient.include(mxClient.basePath+'/js/util/mxAutoSaveManager.js');
  			mxClient.include(mxClient.basePath+'/js/util/mxAnimation.js');
  			mxClient.include(mxClient.basePath+'/js/util/mxMorphing.js');
  			mxClient.include(mxClient.basePath+'/js/util/mxImageBundle.js');
  			mxClient.include(mxClient.basePath+'/js/util/mxImageExport.js');
  			mxClient.include(mxClient.basePath+'/js/util/mxAbstractCanvas2D.js');
  			mxClient.include(mxClient.basePath+'/js/util/mxXmlCanvas2D.js');
  			mxClient.include(mxClient.basePath+'/js/util/mxSvgCanvas2D.js');
  			mxClient.include(mxClient.basePath+'/js/util/mxVmlCanvas2D.js');
  			mxClient.include(mxClient.basePath+'/js/util/mxGuide.js');
  			mxClient.include(mxClient.basePath+'/js/shape/mxShape.js');
  			mxClient.include(mxClient.basePath+'/js/shape/mxStencil.js');
  			mxClient.include(mxClient.basePath+'/js/shape/mxStencilRegistry.js');
  			mxClient.include(mxClient.basePath+'/js/shape/mxMarker.js');
  			mxClient.include(mxClient.basePath+'/js/shape/mxActor.js');
  			mxClient.include(mxClient.basePath+'/js/shape/mxCloud.js');
  			mxClient.include(mxClient.basePath+'/js/shape/mxRectangleShape.js');
  			mxClient.include(mxClient.basePath+'/js/shape/mxEllipse.js');
  			mxClient.include(mxClient.basePath+'/js/shape/mxDoubleEllipse.js');
  			mxClient.include(mxClient.basePath+'/js/shape/mxRhombus.js');
  			mxClient.include(mxClient.basePath+'/js/shape/mxPolyline.js');
  			mxClient.include(mxClient.basePath+'/js/shape/mxArrow.js');
  			mxClient.include(mxClient.basePath+'/js/shape/mxArrowConnector.js');
  			mxClient.include(mxClient.basePath+'/js/shape/mxText.js');
  			mxClient.include(mxClient.basePath+'/js/shape/mxTriangle.js');
  			mxClient.include(mxClient.basePath+'/js/shape/mxHexagon.js');
  			mxClient.include(mxClient.basePath+'/js/shape/mxLine.js');
  			mxClient.include(mxClient.basePath+'/js/shape/mxImageShape.js');
  			mxClient.include(mxClient.basePath+'/js/shape/mxLabel.js');
  			mxClient.include(mxClient.basePath+'/js/shape/mxCylinder.js');
  			mxClient.include(mxClient.basePath+'/js/shape/mxConnector.js');
  			mxClient.include(mxClient.basePath+'/js/shape/mxSwimlane.js');
  			mxClient.include(mxClient.basePath+'/js/layout/mxGraphLayout.js');
  			mxClient.include(mxClient.basePath+'/js/layout/mxStackLayout.js');
  			mxClient.include(mxClient.basePath+'/js/layout/mxPartitionLayout.js');
  			mxClient.include(mxClient.basePath+'/js/layout/mxCompactTreeLayout.js');
  			mxClient.include(mxClient.basePath+'/js/layout/mxRadialTreeLayout.js');
  			mxClient.include(mxClient.basePath+'/js/layout/mxFastOrganicLayout.js');
  			mxClient.include(mxClient.basePath+'/js/layout/mxCircleLayout.js');
  			mxClient.include(mxClient.basePath+'/js/layout/mxParallelEdgeLayout.js');
  			mxClient.include(mxClient.basePath+'/js/layout/mxCompositeLayout.js');
  			mxClient.include(mxClient.basePath+'/js/layout/mxEdgeLabelLayout.js');
  			mxClient.include(mxClient.basePath+'/js/layout/hierarchical/model/mxGraphAbstractHierarchyCell.js');
  			mxClient.include(mxClient.basePath+'/js/layout/hierarchical/model/mxGraphHierarchyNode.js');
  			mxClient.include(mxClient.basePath+'/js/layout/hierarchical/model/mxGraphHierarchyEdge.js');
  			mxClient.include(mxClient.basePath+'/js/layout/hierarchical/model/mxGraphHierarchyModel.js');
  			mxClient.include(mxClient.basePath+'/js/layout/hierarchical/model/mxSwimlaneModel.js');
  			mxClient.include(mxClient.basePath+'/js/layout/hierarchical/stage/mxHierarchicalLayoutStage.js');
  			mxClient.include(mxClient.basePath+'/js/layout/hierarchical/stage/mxMedianHybridCrossingReduction.js');
  			mxClient.include(mxClient.basePath+'/js/layout/hierarchical/stage/mxMinimumCycleRemover.js');
  			mxClient.include(mxClient.basePath+'/js/layout/hierarchical/stage/mxCoordinateAssignment.js');
  			mxClient.include(mxClient.basePath+'/js/layout/hierarchical/stage/mxSwimlaneOrdering.js');
  			mxClient.include(mxClient.basePath+'/js/layout/hierarchical/mxHierarchicalLayout.js');
  			mxClient.include(mxClient.basePath+'/js/layout/hierarchical/mxSwimlaneLayout.js');
  			mxClient.include(mxClient.basePath+'/js/model/mxGraphModel.js');
  			mxClient.include(mxClient.basePath+'/js/model/mxCell.js');
  			mxClient.include(mxClient.basePath+'/js/model/mxGeometry.js');
  			mxClient.include(mxClient.basePath+'/js/model/mxCellPath.js');
  			mxClient.include(mxClient.basePath+'/js/view/mxPerimeter.js');
  			mxClient.include(mxClient.basePath+'/js/view/mxPrintPreview.js');
  			mxClient.include(mxClient.basePath+'/js/view/mxStylesheet.js');
  			mxClient.include(mxClient.basePath+'/js/view/mxCellState.js');
  			mxClient.include(mxClient.basePath+'/js/view/mxGraphSelectionModel.js');
  			mxClient.include(mxClient.basePath+'/js/view/mxCellEditor.js');
  			mxClient.include(mxClient.basePath+'/js/view/mxCellRenderer.js');
  			mxClient.include(mxClient.basePath+'/js/view/mxEdgeStyle.js');
  			mxClient.include(mxClient.basePath+'/js/view/mxStyleRegistry.js');
  			mxClient.include(mxClient.basePath+'/js/view/mxGraphView.js');
  			mxClient.include(mxClient.basePath+'/js/view/mxGraph.js');
  			mxClient.include(mxClient.basePath+'/js/view/mxCellOverlay.js');
  			mxClient.include(mxClient.basePath+'/js/view/mxOutline.js');
  			mxClient.include(mxClient.basePath+'/js/view/mxMultiplicity.js');
  			mxClient.include(mxClient.basePath+'/js/view/mxLayoutManager.js');
  			mxClient.include(mxClient.basePath+'/js/view/mxSwimlaneManager.js');
  			mxClient.include(mxClient.basePath+'/js/view/mxTemporaryCellStates.js');
  			mxClient.include(mxClient.basePath+'/js/view/mxCellStatePreview.js');
  			mxClient.include(mxClient.basePath+'/js/view/mxConnectionConstraint.js');
  			mxClient.include(mxClient.basePath+'/js/handler/mxGraphHandler.js');
  			mxClient.include(mxClient.basePath+'/js/handler/mxPanningHandler.js');
  			mxClient.include(mxClient.basePath+'/js/handler/mxPopupMenuHandler.js');
  			mxClient.include(mxClient.basePath+'/js/handler/mxCellMarker.js');
  			mxClient.include(mxClient.basePath+'/js/handler/mxSelectionCellsHandler.js');
  			mxClient.include(mxClient.basePath+'/js/handler/mxConnectionHandler.js');
  			mxClient.include(mxClient.basePath+'/js/handler/mxConstraintHandler.js');
  			mxClient.include(mxClient.basePath+'/js/handler/mxRubberband.js');
  			mxClient.include(mxClient.basePath+'/js/handler/mxHandle.js');
  			mxClient.include(mxClient.basePath+'/js/handler/mxVertexHandler.js');
  			mxClient.include(mxClient.basePath+'/js/handler/mxEdgeHandler.js');
  			mxClient.include(mxClient.basePath+'/js/handler/mxElbowEdgeHandler.js');
  			mxClient.include(mxClient.basePath+'/js/handler/mxEdgeSegmentHandler.js');
  			mxClient.include(mxClient.basePath+'/js/handler/mxKeyHandler.js');
  			mxClient.include(mxClient.basePath+'/js/handler/mxTooltipHandler.js');
  			mxClient.include(mxClient.basePath+'/js/handler/mxCellTracker.js');
  			mxClient.include(mxClient.basePath+'/js/handler/mxCellHighlight.js');
  			mxClient.include(mxClient.basePath+'/js/editor/mxDefaultKeyHandler.js');
  			mxClient.include(mxClient.basePath+'/js/editor/mxDefaultPopupMenu.js');
  			mxClient.include(mxClient.basePath+'/js/editor/mxDefaultToolbar.js');
  			mxClient.include(mxClient.basePath+'/js/editor/mxEditor.js');
  			mxClient.include(mxClient.basePath+'/js/io/mxCodecRegistry.js');
  			mxClient.include(mxClient.basePath+'/js/io/mxCodec.js');
  			mxClient.include(mxClient.basePath+'/js/io/mxObjectCodec.js');
  			mxClient.include(mxClient.basePath+'/js/io/mxCellCodec.js');
  			mxClient.include(mxClient.basePath+'/js/io/mxModelCodec.js');
  			mxClient.include(mxClient.basePath+'/js/io/mxRootChangeCodec.js');
  			mxClient.include(mxClient.basePath+'/js/io/mxChildChangeCodec.js');
  			mxClient.include(mxClient.basePath+'/js/io/mxTerminalChangeCodec.js');
  			mxClient.include(mxClient.basePath+'/js/io/mxGenericChangeCodec.js');
  			mxClient.include(mxClient.basePath+'/js/io/mxGraphCodec.js');
  			mxClient.include(mxClient.basePath+'/js/io/mxGraphViewCodec.js');
  			mxClient.include(mxClient.basePath+'/js/io/mxStylesheetCodec.js');
  			mxClient.include(mxClient.basePath+'/js/io/mxDefaultKeyHandlerCodec.js');
  			mxClient.include(mxClient.basePath+'/js/io/mxDefaultToolbarCodec.js');
  			mxClient.include(mxClient.basePath+'/js/io/mxDefaultPopupMenuCodec.js');
  			mxClient.include(mxClient.basePath+'/js/io/mxEditorCodec.js');
  		}
  		__mxOutput.mxClient = typeof mxClient !== 'undefined' ? mxClient : undefined;
  		var mxLog =
  		{
  			consoleName: 'Console',
  			TRACE: false,
  			DEBUG: true,
  			WARN: true,
  			buffer: '',
  			init: function()
  			{
  				if (mxLog.window == null && document.body != null)
  				{
  					var title = mxLog.consoleName + ' - mxGraph ' + mxClient.VERSION;
  					var table = document.createElement('table');
  					table.setAttribute('width', '100%');
  					table.setAttribute('height', '100%');
  					var tbody = document.createElement('tbody');
  					var tr = document.createElement('tr');
  					var td = document.createElement('td');
  					td.style.verticalAlign = 'top';
  					mxLog.textarea = document.createElement('textarea');
  					mxLog.textarea.setAttribute('wrap', 'off');
  					mxLog.textarea.setAttribute('readOnly', 'true');
  					mxLog.textarea.style.height = '100%';
  					mxLog.textarea.style.resize = 'none';
  					mxLog.textarea.value = mxLog.buffer;
  					if (mxClient.IS_NS && document.compatMode != 'BackCompat')
  					{
  						mxLog.textarea.style.width = '99%';
  					}
  					else
  					{
  						mxLog.textarea.style.width = '100%';
  					}
  					td.appendChild(mxLog.textarea);
  					tr.appendChild(td);
  					tbody.appendChild(tr);
  					tr = document.createElement('tr');
  					mxLog.td = document.createElement('td');
  					mxLog.td.style.verticalAlign = 'top';
  					mxLog.td.setAttribute('height', '30px');
  					tr.appendChild(mxLog.td);
  					tbody.appendChild(tr);
  					table.appendChild(tbody);
  					mxLog.addButton('Info', function (evt)
  					{
  						mxLog.info();
  					});
  					mxLog.addButton('DOM', function (evt)
  					{
  						var content = mxUtils.getInnerHtml(document.body);
  						mxLog.debug(content);
  					});
  					mxLog.addButton('Trace', function (evt)
  					{
  						mxLog.TRACE = !mxLog.TRACE;
  						if (mxLog.TRACE)
  						{
  							mxLog.debug('Tracing enabled');
  						}
  						else
  						{
  							mxLog.debug('Tracing disabled');
  						}
  					});
  					mxLog.addButton('Copy', function (evt)
  					{
  						try
  						{
  							mxUtils.copy(mxLog.textarea.value);
  						}
  						catch (err)
  						{
  							mxUtils.alert(err);
  						}
  					});
  					mxLog.addButton('Show', function (evt)
  					{
  						try
  						{
  							mxUtils.popup(mxLog.textarea.value);
  						}
  						catch (err)
  						{
  							mxUtils.alert(err);
  						}
  					});
  					mxLog.addButton('Clear', function (evt)
  					{
  						mxLog.textarea.value = '';
  					});
  					var h = 0;
  					var w = 0;
  					if (typeof(window.innerWidth) === 'number')
  					{
  						h = window.innerHeight;
  						w = window.innerWidth;
  					}
  					else
  					{
  						h = (document.documentElement.clientHeight || document.body.clientHeight);
  						w = document.body.clientWidth;
  					}
  					mxLog.window = new mxWindow(title, table, Math.max(0, w - 320), Math.max(0, h - 210), 300, 160);
  					mxLog.window.setMaximizable(true);
  					mxLog.window.setScrollable(false);
  					mxLog.window.setResizable(true);
  					mxLog.window.setClosable(true);
  					mxLog.window.destroyOnClose = false;
  					if (((mxClient.IS_NS || mxClient.IS_IE) && !mxClient.IS_GC &&
  						!mxClient.IS_SF && document.compatMode != 'BackCompat') ||
  						document.documentMode == 11)
  					{
  						var elt = mxLog.window.getElement();
  						var resizeHandler = function(sender, evt)
  						{
  							mxLog.textarea.style.height = Math.max(0, elt.offsetHeight - 70) + 'px';
  						};
  						mxLog.window.addListener(mxEvent.RESIZE_END, resizeHandler);
  						mxLog.window.addListener(mxEvent.MAXIMIZE, resizeHandler);
  						mxLog.window.addListener(mxEvent.NORMALIZE, resizeHandler);
  						mxLog.textarea.style.height = '92px';
  					}
  				}
  			},
  			info: function()
  			{
  				mxLog.writeln(mxUtils.toString(navigator));
  			},
  			addButton: function(lab, funct)
  			{
  				var button = document.createElement('button');
  				mxUtils.write(button, lab);
  				mxEvent.addListener(button, 'click', funct);
  				mxLog.td.appendChild(button);
  			},
  			isVisible: function()
  			{
  				if (mxLog.window != null)
  				{
  					return mxLog.window.isVisible();
  				}
  				return false;
  			},
  			show: function()
  			{
  				mxLog.setVisible(true);
  			},
  			setVisible: function(visible)
  			{
  				if (mxLog.window == null)
  				{
  					mxLog.init();
  				}
  				if (mxLog.window != null)
  				{
  					mxLog.window.setVisible(visible);
  				}
  			},
  			enter: function(string)
  			{
  				if (mxLog.TRACE)
  				{
  					mxLog.writeln('Entering '+string);
  					return new Date().getTime();
  				}
  			},
  			leave: function(string, t0)
  			{
  				if (mxLog.TRACE)
  				{
  					var dt = (t0 != 0) ? ' ('+(new Date().getTime() - t0)+' ms)' : '';
  					mxLog.writeln('Leaving '+string+dt);
  				}
  			},
  			debug: function()
  			{
  				if (mxLog.DEBUG)
  				{
  					mxLog.writeln.apply(this, arguments);
  				}
  			},
  			warn: function()
  			{
  				if (mxLog.WARN)
  				{
  					mxLog.writeln.apply(this, arguments);
  				}
  			},
  			write: function()
  			{
  				var string = '';
  				for (var i = 0; i < arguments.length; i++)
  				{
  					string += arguments[i];
  					if (i < arguments.length - 1)
  					{
  						string += ' ';
  					}
  				}
  				if (mxLog.textarea != null)
  				{
  					mxLog.textarea.value = mxLog.textarea.value + string;
  					if (navigator.userAgent != null &&
  						navigator.userAgent.indexOf('Presto/2.5') >= 0)
  					{
  						mxLog.textarea.style.visibility = 'hidden';
  						mxLog.textarea.style.visibility = 'visible';
  					}
  					mxLog.textarea.scrollTop = mxLog.textarea.scrollHeight;
  				}
  				else
  				{
  					mxLog.buffer += string;
  				}
  			},
  			writeln: function()
  			{
  				var string = '';
  				for (var i = 0; i < arguments.length; i++)
  				{
  					string += arguments[i];
  					if (i < arguments.length - 1)
  					{
  						string += ' ';
  					}
  				}
  				mxLog.write(string + '\n');
  			}
  		};
  		__mxOutput.mxLog = typeof mxLog !== 'undefined' ? mxLog : undefined;
  		var mxObjectIdentity =
  		{
  			FIELD_NAME: 'mxObjectId',
  			counter: 0,
  			get: function(obj)
  			{
  				if (obj != null)
  				{
  					if (obj[mxObjectIdentity.FIELD_NAME] == null)
  					{
  						if (typeof obj === 'object')
  						{
  							var ctor = mxUtils.getFunctionName(obj.constructor);
  							obj[mxObjectIdentity.FIELD_NAME] = ctor + '#' + mxObjectIdentity.counter++;
  						}
  						else if (typeof obj === 'function')
  						{
  							obj[mxObjectIdentity.FIELD_NAME] = 'Function#' + mxObjectIdentity.counter++;
  						}
  					}
  					return obj[mxObjectIdentity.FIELD_NAME];
  				}
  				return null;
  			},
  			clear: function(obj)
  			{
  				if (typeof(obj) === 'object' || typeof obj === 'function')
  				{
  					delete obj[mxObjectIdentity.FIELD_NAME];
  				}
  			}
  		};
  		__mxOutput.mxObjectIdentity = typeof mxObjectIdentity !== 'undefined' ? mxObjectIdentity : undefined;
  		function mxDictionary()
  		{
  			this.clear();
  		}		mxDictionary.prototype.map = null;
  		mxDictionary.prototype.clear = function()
  		{
  			this.map = {};
  		};
  		mxDictionary.prototype.get = function(key)
  		{
  			var id = mxObjectIdentity.get(key);
  			return this.map[id];
  		};
  		mxDictionary.prototype.put = function(key, value)
  		{
  			var id = mxObjectIdentity.get(key);
  			var previous = this.map[id];
  			this.map[id] = value;
  			return previous;
  		};
  		mxDictionary.prototype.remove = function(key)
  		{
  			var id = mxObjectIdentity.get(key);
  			var previous = this.map[id];
  			delete this.map[id];
  			return previous;
  		};
  		mxDictionary.prototype.getKeys = function()
  		{
  			var result = [];
  			for (var key in this.map)
  			{
  				result.push(key);
  			}
  			return result;
  		};
  		mxDictionary.prototype.getValues = function()
  		{
  			var result = [];
  			for (var key in this.map)
  			{
  				result.push(this.map[key]);
  			}
  			return result;
  		};
  		mxDictionary.prototype.visit = function(visitor)
  		{
  			for (var key in this.map)
  			{
  				visitor(key, this.map[key]);
  			}
  		};
  		__mxOutput.mxDictionary = typeof mxDictionary !== 'undefined' ? mxDictionary : undefined;
  		var mxResources =
  		{
  			resources: {},
  			extension: mxResourceExtension,
  			resourcesEncoded: false,
  			loadDefaultBundle: true,
  			loadSpecialBundle: true,
  			isLanguageSupported: function(lan)
  			{
  				if (mxClient.languages != null)
  				{
  					return mxUtils.indexOf(mxClient.languages, lan) >= 0;
  				}
  				return true;
  			},
  			getDefaultBundle: function(basename, lan)
  			{
  				if (mxResources.loadDefaultBundle || !mxResources.isLanguageSupported(lan))
  				{
  					return basename + mxResources.extension;
  				}
  				else
  				{
  					return null;
  				}
  			},
  			getSpecialBundle: function(basename, lan)
  			{
  				if (mxClient.languages == null || !this.isLanguageSupported(lan))
  				{
  					var dash = lan.indexOf('-');
  					if (dash > 0)
  					{
  						lan = lan.substring(0, dash);
  					}
  				}
  				if (mxResources.loadSpecialBundle && mxResources.isLanguageSupported(lan) && lan != mxClient.defaultLanguage)
  				{
  					return basename + '_' + lan + mxResources.extension;
  				}
  				else
  				{
  					return null;
  				}
  			},
  			add: function(basename, lan, callback)
  			{
  				lan = (lan != null) ? lan : ((mxClient.language != null) ?
  					mxClient.language.toLowerCase() : mxConstants.NONE);
  				if (lan != mxConstants.NONE)
  				{
  					var defaultBundle = mxResources.getDefaultBundle(basename, lan);
  					var specialBundle = mxResources.getSpecialBundle(basename, lan);
  					var loadSpecialBundle = function()
  					{
  						if (specialBundle != null)
  						{
  							if (callback)
  							{
  								mxUtils.get(specialBundle, function(req)
  								{
  									mxResources.parse(req.getText());
  									callback();
  								}, function()
  								{
  									callback();
  								});
  							}
  							else
  							{
  								try
  								{
  							   		var req = mxUtils.load(specialBundle);
  							   		if (req.isReady())
  							   		{
  							 	   		mxResources.parse(req.getText());
  							   		}
  						   		}
  						   		catch (e)
  						   		{
  							   	}
  							}
  						}
  						else if (callback != null)
  						{
  							callback();
  						}
  					};
  					if (defaultBundle != null)
  					{
  						if (callback)
  						{
  							mxUtils.get(defaultBundle, function(req)
  							{
  								mxResources.parse(req.getText());
  								loadSpecialBundle();
  							}, function()
  							{
  								loadSpecialBundle();
  							});
  						}
  						else
  						{
  							try
  							{
  						   		var req = mxUtils.load(defaultBundle);
  						   		if (req.isReady())
  						   		{
  						 	   		mxResources.parse(req.getText());
  						   		}
  						   		loadSpecialBundle();
  						  	}
  						  	catch (e)
  						  	{
  						  	}
  						}
  					}
  					else
  					{
  						loadSpecialBundle();
  					}
  				}
  			},
  			parse: function(text)
  			{
  				if (text != null)
  				{
  					var lines = text.split('\n');
  					for (var i = 0; i < lines.length; i++)
  					{
  						if (lines[i].charAt(0) != '#')
  						{
  							var index = lines[i].indexOf('=');
  							if (index > 0)
  							{
  								var key = lines[i].substring(0, index);
  								var idx = lines[i].length;
  								if (lines[i].charCodeAt(idx - 1) == 13)
  								{
  									idx--;
  								}
  								var value = lines[i].substring(index + 1, idx);
  								if (this.resourcesEncoded)
  								{
  									value = value.replace(/\\(?=u[a-fA-F\d]{4})/g,"%");
  									mxResources.resources[key] = unescape(value);
  								}
  								else
  								{
  									mxResources.resources[key] = value;
  								}
  							}
  						}
  					}
  				}
  			},
  			get: function(key, params, defaultValue)
  			{
  				var value = mxResources.resources[key];
  				if (value == null)
  				{
  					value = defaultValue;
  				}
  				if (value != null && params != null)
  				{
  					value = mxResources.replacePlaceholders(value, params);
  				}
  				return value;
  			},
  			replacePlaceholders: function(value, params)
  			{
  				var result = [];
  				var index = null;
  				for (var i = 0; i < value.length; i++)
  				{
  					var c = value.charAt(i);
  					if (c == '{')
  					{
  						index = '';
  					}
  					else if (index != null && 	c == '}')
  					{
  						index = parseInt(index)-1;
  						if (index >= 0 && index < params.length)
  						{
  							result.push(params[index]);
  						}
  						index = null;
  					}
  					else if (index != null)
  					{
  						index += c;
  					}
  					else
  					{
  						result.push(c);
  					}
  				}
  				return result.join('');
  			},
  			loadResources: function(callback)
  			{
  				mxResources.add(mxClient.basePath+'/resources/editor', null, function()
  				{
  					mxResources.add(mxClient.basePath+'/resources/graph', null, callback);
  				});
  			}
  		};
  		__mxOutput.mxResources = typeof mxResources !== 'undefined' ? mxResources : undefined;
  		function mxPoint(x, y)
  		{
  			this.x = (x != null) ? x : 0;
  			this.y = (y != null) ? y : 0;
  		}		mxPoint.prototype.x = null;
  		mxPoint.prototype.y = null;
  		mxPoint.prototype.equals = function(obj)
  		{
  			return obj != null && obj.x == this.x && obj.y == this.y;
  		};
  		mxPoint.prototype.clone = function()
  		{
  			return mxUtils.clone(this);
  		};
  		__mxOutput.mxPoint = typeof mxPoint !== 'undefined' ? mxPoint : undefined;
  		function mxRectangle(x, y, width, height)
  		{
  			mxPoint.call(this, x, y);
  			this.width = (width != null) ? width : 0;
  			this.height = (height != null) ? height : 0;
  		}		mxRectangle.prototype = new mxPoint();
  		mxRectangle.prototype.constructor = mxRectangle;
  		mxRectangle.prototype.width = null;
  		mxRectangle.prototype.height = null;
  		mxRectangle.prototype.setRect = function(x, y, w, h)
  		{
  		    this.x = x;
  		    this.y = y;
  		    this.width = w;
  		    this.height = h;
  		};
  		mxRectangle.prototype.getCenterX = function ()
  		{
  			return this.x + this.width/2;
  		};
  		mxRectangle.prototype.getCenterY = function ()
  		{
  			return this.y + this.height/2;
  		};
  		mxRectangle.prototype.add = function(rect)
  		{
  			if (rect != null)
  			{
  				var minX = Math.min(this.x, rect.x);
  				var minY = Math.min(this.y, rect.y);
  				var maxX = Math.max(this.x + this.width, rect.x + rect.width);
  				var maxY = Math.max(this.y + this.height, rect.y + rect.height);
  				this.x = minX;
  				this.y = minY;
  				this.width = maxX - minX;
  				this.height = maxY - minY;
  			}
  		};
  		mxRectangle.prototype.intersect = function(rect)
  		{
  			if (rect != null)
  			{
  				var r1 = this.x + this.width;
  				var r2 = rect.x + rect.width;
  				var b1 = this.y + this.height;
  				var b2 = rect.y + rect.height;
  				this.x = Math.max(this.x, rect.x);
  				this.y = Math.max(this.y, rect.y);
  				this.width = Math.min(r1, r2) - this.x;
  				this.height = Math.min(b1, b2) - this.y;
  			}
  		};
  		mxRectangle.prototype.grow = function(amount)
  		{
  			this.x -= amount;
  			this.y -= amount;
  			this.width += 2 * amount;
  			this.height += 2 * amount;
  			return this;
  		};
  		mxRectangle.prototype.getPoint = function()
  		{
  			return new mxPoint(this.x, this.y);
  		};
  		mxRectangle.prototype.rotate90 = function()
  		{
  			var t = (this.width - this.height) / 2;
  			this.x += t;
  			this.y -= t;
  			var tmp = this.width;
  			this.width = this.height;
  			this.height = tmp;
  		};
  		mxRectangle.prototype.equals = function(obj)
  		{
  			return obj != null && obj.x == this.x && obj.y == this.y &&
  				obj.width == this.width && obj.height == this.height;
  		};
  		mxRectangle.fromRectangle = function(rect)
  		{
  			return new mxRectangle(rect.x, rect.y, rect.width, rect.height);
  		};
  		__mxOutput.mxRectangle = typeof mxRectangle !== 'undefined' ? mxRectangle : undefined;
  		var mxEffects =
  		{
  			animateChanges: function(graph, changes, done)
  			{
  				var maxStep = 10;
  				var step = 0;
  				var animate = function()
  				{
  					var isRequired = false;
  					for (var i = 0; i < changes.length; i++)
  					{
  						var change = changes[i];
  						if (change instanceof mxGeometryChange ||
  							change instanceof mxTerminalChange ||
  							change instanceof mxValueChange ||
  							change instanceof mxChildChange ||
  							change instanceof mxStyleChange)
  						{
  							var state = graph.getView().getState(change.cell || change.child, false);
  							if (state != null)
  							{
  								isRequired = true;
  								if (change.constructor != mxGeometryChange || graph.model.isEdge(change.cell))
  								{
  									mxUtils.setOpacity(state.shape.node, 100 * step / maxStep);
  								}
  								else
  								{
  									var scale = graph.getView().scale;
  									var dx = (change.geometry.x - change.previous.x) * scale;
  									var dy = (change.geometry.y - change.previous.y) * scale;
  									var sx = (change.geometry.width - change.previous.width) * scale;
  									var sy = (change.geometry.height - change.previous.height) * scale;
  									if (step == 0)
  									{
  										state.x -= dx;
  										state.y -= dy;
  										state.width -= sx;
  										state.height -= sy;
  									}
  									else
  									{
  										state.x += dx / maxStep;
  										state.y += dy / maxStep;
  										state.width += sx / maxStep;
  										state.height += sy / maxStep;
  									}
  									graph.cellRenderer.redraw(state);
  									mxEffects.cascadeOpacity(graph, change.cell, 100 * step / maxStep);
  								}
  							}
  						}
  					}
  					if (step < maxStep && isRequired)
  					{
  						step++;
  						window.setTimeout(animate, delay);
  					}
  					else if (done != null)
  					{
  						done();
  					}
  				};
  				var delay = 30;
  				animate();
  			},
  		    cascadeOpacity: function(graph, cell, opacity)
  			{
  				var childCount = graph.model.getChildCount(cell);
  				for (var i=0; i<childCount; i++)
  				{
  					var child = graph.model.getChildAt(cell, i);
  					var childState = graph.getView().getState(child);
  					if (childState != null)
  					{
  						mxUtils.setOpacity(childState.shape.node, opacity);
  						mxEffects.cascadeOpacity(graph, child, opacity);
  					}
  				}
  				var edges = graph.model.getEdges(cell);
  				if (edges != null)
  				{
  					for (var i=0; i<edges.length; i++)
  					{
  						var edgeState = graph.getView().getState(edges[i]);
  						if (edgeState != null)
  						{
  							mxUtils.setOpacity(edgeState.shape.node, opacity);
  						}
  					}
  				}
  			},
  			fadeOut: function(node, from, remove, step, delay, isEnabled)
  			{
  				step = step || 40;
  				delay = delay || 30;
  				var opacity = from || 100;
  				mxUtils.setOpacity(node, opacity);
  				if (isEnabled || isEnabled == null)
  				{
  					var f = function()
  					{
  					    opacity = Math.max(opacity-step, 0);
  						mxUtils.setOpacity(node, opacity);
  						if (opacity > 0)
  						{
  							window.setTimeout(f, delay);
  						}
  						else
  						{
  							node.style.visibility = 'hidden';
  							if (remove && node.parentNode)
  							{
  								node.parentNode.removeChild(node);
  							}
  						}
  					};
  					window.setTimeout(f, delay);
  				}
  				else
  				{
  					node.style.visibility = 'hidden';
  					if (remove && node.parentNode)
  					{
  						node.parentNode.removeChild(node);
  					}
  				}
  			}
  		};
  		__mxOutput.mxEffects = typeof mxEffects !== 'undefined' ? mxEffects : undefined;
  		var mxUtils =
  		{
  			errorResource: (mxClient.language != 'none') ? 'error' : '',
  			closeResource: (mxClient.language != 'none') ? 'close' : '',
  			errorImage: mxClient.imageBasePath + '/error.gif',
  			removeCursors: function(element)
  			{
  				if (element.style != null)
  				{
  					element.style.cursor = '';
  				}
  				var children = element.childNodes;
  				if (children != null)
  				{
  			        var childCount = children.length;
  			        for (var i = 0; i < childCount; i += 1)
  			        {
  			            mxUtils.removeCursors(children[i]);
  			        }
  			    }
  			},
  			getCurrentStyle: function()
  			{
  				if (mxClient.IS_IE && (document.documentMode == null || document.documentMode < 9))
  				{
  					return function(element)
  					{
  						return (element != null) ? element.currentStyle : null;
  					};
  				}
  				else
  				{
  					return function(element)
  					{
  						return (element != null) ?
  							window.getComputedStyle(element, '') :
  							null;
  					};
  				}
  			}(),
  			parseCssNumber: function(value)
  			{
  				if (value == 'thin')
  				{
  					value = '2';
  				}
  				else if (value == 'medium')
  				{
  					value = '4';
  				}
  				else if (value == 'thick')
  				{
  					value = '6';
  				}
  				value = parseFloat(value);
  				if (isNaN(value))
  				{
  					value = 0;
  				}
  				return value;
  			},
  			setPrefixedStyle: function()
  			{
  				var prefix = null;
  				if (mxClient.IS_OT)
  				{
  					prefix = 'O';
  				}
  				else if (mxClient.IS_SF || mxClient.IS_GC)
  				{
  					prefix = 'Webkit';
  				}
  				else if (mxClient.IS_MT)
  				{
  					prefix = 'Moz';
  				}
  				else if (mxClient.IS_IE && document.documentMode >= 9 && document.documentMode < 10)
  				{
  					prefix = 'ms';
  				}
  				return function(style, name, value)
  				{
  					style[name] = value;
  					if (prefix != null && name.length > 0)
  					{
  						name = prefix + name.substring(0, 1).toUpperCase() + name.substring(1);
  						style[name] = value;
  					}
  				};
  			}(),
  			hasScrollbars: function(node)
  			{
  				var style = mxUtils.getCurrentStyle(node);
  				return style != null && (style.overflow == 'scroll' || style.overflow == 'auto');
  			},
  			bind: function(scope, funct)
  			{
  				return function()
  				{
  					return funct.apply(scope, arguments);
  				};
  			},
  			eval: function(expr)
  			{
  				var result = null;
  				if (expr.indexOf('function') >= 0)
  				{
  					try
  					{
  						eval('var _mxJavaScriptExpression='+expr);
  						result = _mxJavaScriptExpression;
  						_mxJavaScriptExpression = null;
  					}
  					catch (e)
  					{
  						mxLog.warn(e.message + ' while evaluating ' + expr);
  					}
  				}
  				else
  				{
  					try
  					{
  						result = eval(expr);
  					}
  					catch (e)
  					{
  						mxLog.warn(e.message + ' while evaluating ' + expr);
  					}
  				}
  				return result;
  			},
  			findNode: function(node, attr, value)
  			{
  				if (node.nodeType == mxConstants.NODETYPE_ELEMENT)
  				{
  					var tmp = node.getAttribute(attr);
  					if (tmp != null && tmp == value)
  					{
  						return node;
  					}
  				}
  				node = node.firstChild;
  				while (node != null)
  				{
  					var result = mxUtils.findNode(node, attr, value);
  					if (result != null)
  					{
  						return result;
  					}
  					node = node.nextSibling;
  				}
  				return null;
  			},
  			getFunctionName: function(f)
  			{
  				var str = null;
  				if (f != null)
  				{
  					if (f.name != null)
  					{
  						str = f.name;
  					}
  					else
  					{
  						str = mxUtils.trim(f.toString());
  						if (/^function\s/.test(str))
  						{
  							str = mxUtils.ltrim(str.substring(9));
  							var idx2 = str.indexOf('(');
  							if (idx2 > 0)
  							{
  								str = str.substring(0, idx2);
  							}
  						}
  					}
  				}
  				return str;
  			},
  			indexOf: function(array, obj)
  			{
  				if (array != null && obj != null)
  				{
  					for (var i = 0; i < array.length; i++)
  					{
  						if (array[i] == obj)
  						{
  							return i;
  						}
  					}
  				}
  				return -1;
  			},
  			forEach: function(array, fn)
  			{
  				if (array != null && fn != null)
  				{
  					for (var i = 0; i < array.length; i++)
  					{
  						fn(array[i]);
  					}
  				}
  				return array;
  			},
  			remove: function(obj, array)
  			{
  				var result = null;
  				if (typeof(array) == 'object')
  				{
  					var index = mxUtils.indexOf(array, obj);
  					while (index >= 0)
  					{
  						array.splice(index, 1);
  						result = obj;
  						index = mxUtils.indexOf(array, obj);
  					}
  				}
  				for (var key in array)
  				{
  					if (array[key] == obj)
  					{
  						delete array[key];
  						result = obj;
  					}
  				}
  				return result;
  			},
  			 isNode: function(value, nodeName, attributeName, attributeValue)
  			 {
  			 	if (value != null && !isNaN(value.nodeType) && (nodeName == null ||
  			 		value.nodeName.toLowerCase() == nodeName.toLowerCase()))
  		 		{
  		 			return attributeName == null ||
  		 				value.getAttribute(attributeName) == attributeValue;
  		 		}
  			 	return false;
  			 },
  			 isAncestorNode: function(ancestor, child)
  			 {
  			 	var parent = child;
  			 	while (parent != null)
  			 	{
  			 		if (parent == ancestor)
  			 		{
  			 			return true;
  			 		}
  			 		parent = parent.parentNode;
  			 	}
  			 	return false;
  			 },
  			getChildNodes: function(node, nodeType)
  			{
  				nodeType = nodeType || mxConstants.NODETYPE_ELEMENT;
  				var children = [];
  				var tmp = node.firstChild;
  				while (tmp != null)
  				{
  					if (tmp.nodeType == nodeType)
  					{
  						children.push(tmp);
  					}
  					tmp = tmp.nextSibling;
  				}
  				return children;
  			},
  			importNode: function(doc, node, allChildren)
  			{
  				if (mxClient.IS_IE && (document.documentMode == null || document.documentMode < 10))
  				{
  					return mxUtils.importNodeImplementation(doc, node, allChildren);
  				}
  				else
  				{
  					return doc.importNode(node, allChildren);
  				}
  			},
  			importNodeImplementation: function(doc, node, allChildren)
  			{
  				switch (node.nodeType)
  				{
  					case 1:
  					{
  						var newNode = doc.createElement(node.nodeName);
  						if (node.attributes && node.attributes.length > 0)
  						{
  							for (var i = 0; i < node.attributes.length; i++)
  							{
  								newNode.setAttribute(node.attributes[i].nodeName,
  									node.getAttribute(node.attributes[i].nodeName));
  							}
  						}
  						if (allChildren && node.childNodes && node.childNodes.length > 0)
  						{
  							for (var i = 0; i < node.childNodes.length; i++)
  							{
  								newNode.appendChild(mxUtils.importNodeImplementation(doc, node.childNodes[i], allChildren));
  							}
  						}
  						return newNode;
  					}
  					case 3:
  				    case 4:
  				    case 8:
  				    {
  				    	return doc.createTextNode((node.nodeValue != null) ? node.nodeValue : node.value);
  				    }
  				}			},
  			createXmlDocument: function()
  			{
  				var doc = null;
  				if (document.implementation && document.implementation.createDocument)
  				{
  					doc = document.implementation.createDocument('', '', null);
  				}
  				else if ("ActiveXObject" in window)
  				{
  					doc = mxUtils.createMsXmlDocument();
  			 	}
  			 	return doc;
  			},
  			createMsXmlDocument: function()
  			{
  				var doc = new ActiveXObject('Microsoft.XMLDOM');
  				doc.async = false;
  				doc.validateOnParse = false;
  				doc.resolveExternals = false;
  			 	return doc;
  			},
  			parseXml: function()
  			{
  				if (window.DOMParser)
  				{
  					return function(xml)
  					{
  						var parser = new DOMParser();
  						return parser.parseFromString(xml, 'text/xml');
  					};
  				}
  				else
  				{
  					return function(xml)
  					{
  						var doc = mxUtils.createMsXmlDocument();
  						doc.loadXML(xml);
  						return doc;
  					};
  				}
  			}(),
  			clearSelection: function()
  			{
  				if (document.selection)
  				{
  					return function()
  					{
  						document.selection.empty();
  					};
  				}
  				else if (window.getSelection)
  				{
  					return function()
  					{
  						if (window.getSelection().empty)
  						{
  							window.getSelection().empty();
  						}
  						else if (window.getSelection().removeAllRanges)
  						{
  							window.getSelection().removeAllRanges();
  						}
  					};
  				}
  				else
  				{
  					return function() { };
  				}
  			}(),
  			removeWhitespace: function(node, before)
  			{
  				var tmp = (before) ? node.previousSibling : node.nextSibling;
  				while (tmp != null && tmp.nodeType == mxConstants.NODETYPE_TEXT)
  				{
  					var next = (before) ? tmp.previousSibling : tmp.nextSibling;
  					var text = mxUtils.getTextContent(tmp);
  					if (mxUtils.trim(text).length == 0)
  					{
  						tmp.parentNode.removeChild(tmp);
  					}
  					tmp = next;
  				}
  			},
  			htmlEntities: function(s, newline)
  			{
  				s = String(s || '');
  				s = s.replace(/&/g,'&amp;');
  				s = s.replace(/"/g,'&quot;');
  				s = s.replace(/\'/g,'&#39;');
  				s = s.replace(/</g,'&lt;');
  				s = s.replace(/>/g,'&gt;');
  				if (newline == null || newline)
  				{
  					s = s.replace(/\n/g, '&#xa;');
  				}
  				return s;
  			},
  			isVml: function(node)
  			{
  				return node != null && node.tagUrn == 'urn:schemas-microsoft-com:vml';
  			},
  			getXml: function(node, linefeed)
  			{
  				var xml = '';
  				if (mxClient.IS_IE || mxClient.IS_IE11)
  				{
  					xml = mxUtils.getPrettyXml(node, '', '', '');
  				}
  				else if (window.XMLSerializer != null)
  				{
  					var xmlSerializer = new XMLSerializer();
  					xml = xmlSerializer.serializeToString(node);
  				}
  				else if (node.xml != null)
  				{
  					xml = node.xml.replace(/\r\n\t[\t]*/g, '').
  						replace(/>\r\n/g, '>').
  						replace(/\r\n/g, '\n');
  				}
  				linefeed = linefeed || '&#xa;';
  				xml = xml.replace(/\n/g, linefeed);
  				return xml;
  			},
  			getPrettyXml: function(node, tab, indent, newline, ns)
  			{
  				var result = [];
  				if (node != null)
  				{
  					tab = (tab != null) ? tab : '  ';
  					indent = (indent != null) ? indent : '';
  					newline = (newline != null) ? newline : '\n';
  					if (node.namespaceURI != null && node.namespaceURI != ns)
  					{
  						ns = node.namespaceURI;
  						if (node.getAttribute('xmlns') == null)
  						{
  							node.setAttribute('xmlns', node.namespaceURI);
  						}
  					}
  					if (node.nodeType == mxConstants.NODETYPE_DOCUMENT)
  					{
  						result.push(mxUtils.getPrettyXml(node.documentElement, tab, indent, newline, ns));
  					}
  					else if (node.nodeType == mxConstants.NODETYPE_DOCUMENT_FRAGMENT)
  					{
  						var tmp = node.firstChild;
  						if (tmp != null)
  						{
  							while (tmp != null)
  							{
  								result.push(mxUtils.getPrettyXml(tmp, tab, indent, newline, ns));
  								tmp = tmp.nextSibling;
  							}
  						}
  					}
  					else if (node.nodeType == mxConstants.NODETYPE_COMMENT)
  					{
  						var value = mxUtils.getTextContent(node);
  						if (value.length > 0)
  						{
  							result.push(indent + '<!--' + value + '-->' + newline);
  						}
  					}
  					else if (node.nodeType == mxConstants.NODETYPE_TEXT)
  					{
  						var value = mxUtils.trim(mxUtils.getTextContent(node));
  						if (value.length > 0)
  						{
  							result.push(indent + mxUtils.htmlEntities(value, false) + newline);
  						}
  					}
  					else if (node.nodeType == mxConstants.NODETYPE_CDATA)
  					{
  						var value = mxUtils.getTextContent(node);
  						if (value.length > 0)
  						{
  							result.push(indent + '<![CDATA[' + value + ']]' + newline);
  						}
  					}
  					else
  					{
  						result.push(indent + '<' + node.nodeName);
  						var attrs = node.attributes;
  						if (attrs != null)
  						{
  							for (var i = 0; i < attrs.length; i++)
  							{
  								var val = mxUtils.htmlEntities(attrs[i].value);
  								result.push(' ' + attrs[i].nodeName + '="' + val + '"');
  							}
  						}
  						var tmp = node.firstChild;
  						if (tmp != null)
  						{
  							result.push('>' + newline);
  							while (tmp != null)
  							{
  								result.push(mxUtils.getPrettyXml(tmp, tab, indent + tab, newline, ns));
  								tmp = tmp.nextSibling;
  							}
  							result.push(indent + '</'+ node.nodeName + '>' + newline);
  						}
  						else
  						{
  							result.push(' />' + newline);
  						}
  					}
  				}
  				return result.join('');
  			},
  			extractTextWithWhitespace: function(elems)
  			{
  				var blocks = ['BLOCKQUOTE', 'DIV', 'H1', 'H2', 'H3', 'H4', 'H5', 'H6', 'OL', 'P', 'PRE', 'TABLE', 'UL'];
  				var ret = [];
  				function doExtract(elts)
  				{
  					if (elts.length == 1 && (elts[0].nodeName == 'BR' ||
  						elts[0].innerHTML == '\n'))
  					{
  						return;
  					}
  				    for (var i = 0; i < elts.length; i++)
  				    {
  				        var elem = elts[i];
  						if (elem.nodeName == 'BR' || elem.innerHTML == '\n' ||
  							((elts.length == 1 || i == 0) && (elem.nodeName == 'DIV' &&
  							elem.innerHTML.toLowerCase() == '<br>')))
  				    	{
  			    			ret.push('\n');
  				    	}
  						else
  						{
  					        if (elem.nodeType === 3 || elem.nodeType === 4)
  					        {
  					        	if (elem.nodeValue.length > 0)
  					        	{
  					        		ret.push(elem.nodeValue);
  					        	}
  					        }
  					        else if (elem.nodeType !== 8 && elem.childNodes.length > 0)
  							{
  								doExtract(elem.childNodes);
  							}
  			        		if (i < elts.length - 1 && mxUtils.indexOf(blocks, elts[i + 1].nodeName) >= 0)
  			        		{
  			        			ret.push('\n');
  			        		}
  						}
  				    }
  				}				doExtract(elems);
  			    return ret.join('');
  			},
  			replaceTrailingNewlines: function(str, pattern)
  			{
  				var postfix = '';
  				while (str.length > 0 && str.charAt(str.length - 1) == '\n')
  				{
  					str = str.substring(0, str.length - 1);
  					postfix += pattern;
  				}
  				return str + postfix;
  			},
  			getTextContent: function(node)
  			{
  				if (mxClient.IS_IE && node.innerText !== undefined)
  				{
  					return node.innerText;
  				}
  				else
  				{
  					return (node != null) ? node[(node.textContent === undefined) ? 'text' : 'textContent'] : '';
  				}
  			},
  			setTextContent: function(node, text)
  			{
  				if (node.innerText !== undefined)
  				{
  					node.innerText = text;
  				}
  				else
  				{
  					node[(node.textContent === undefined) ? 'text' : 'textContent'] = text;
  				}
  			},
  			getInnerHtml: function()
  			{
  				if (mxClient.IS_IE)
  				{
  					return function(node)
  					{
  						if (node != null)
  						{
  							return node.innerHTML;
  						}
  						return '';
  					};
  				}
  				else
  				{
  					return function(node)
  					{
  						if (node != null)
  						{
  							var serializer = new XMLSerializer();
  							return serializer.serializeToString(node);
  						}
  						return '';
  					};
  				}
  			}(),
  			getOuterHtml: function()
  			{
  				if (mxClient.IS_IE)
  				{
  					return function(node)
  					{
  						if (node != null)
  						{
  							if (node.outerHTML != null)
  							{
  								return node.outerHTML;
  							}
  							else
  							{
  								var tmp = [];
  								tmp.push('<'+node.nodeName);
  								var attrs = node.attributes;
  								if (attrs != null)
  								{
  									for (var i = 0; i < attrs.length; i++)
  									{
  										var value = attrs[i].value;
  										if (value != null && value.length > 0)
  										{
  											tmp.push(' ');
  											tmp.push(attrs[i].nodeName);
  											tmp.push('="');
  											tmp.push(value);
  											tmp.push('"');
  										}
  									}
  								}
  								if (node.innerHTML.length == 0)
  								{
  									tmp.push('/>');
  								}
  								else
  								{
  									tmp.push('>');
  									tmp.push(node.innerHTML);
  									tmp.push('</'+node.nodeName+'>');
  								}
  								return tmp.join('');
  							}
  						}
  						return '';
  					};
  				}
  				else
  				{
  					return function(node)
  					{
  						if (node != null)
  						{
  							var serializer = new XMLSerializer();
  							return serializer.serializeToString(node);
  						}
  						return '';
  					};
  				}
  			}(),
  			write: function(parent, text)
  			{
  				var doc = parent.ownerDocument;
  				var node = doc.createTextNode(text);
  				if (parent != null)
  				{
  					parent.appendChild(node);
  				}
  				return node;
  			},
  			writeln: function(parent, text)
  			{
  				var doc = parent.ownerDocument;
  				var node = doc.createTextNode(text);
  				if (parent != null)
  				{
  					parent.appendChild(node);
  					parent.appendChild(document.createElement('br'));
  				}
  				return node;
  			},
  			br: function(parent, count)
  			{
  				count = count || 1;
  				var br = null;
  				for (var i = 0; i < count; i++)
  				{
  					if (parent != null)
  					{
  						br = parent.ownerDocument.createElement('br');
  						parent.appendChild(br);
  					}
  				}
  				return br;
  			},
  			button: function(label, funct, doc)
  			{
  				doc = (doc != null) ? doc : document;
  				var button = doc.createElement('button');
  				mxUtils.write(button, label);
  				mxEvent.addListener(button, 'click', function(evt)
  				{
  					funct(evt);
  				});
  				return button;
  			},
  			para: function(parent, text)
  			{
  				var p = document.createElement('p');
  				mxUtils.write(p, text);
  				if (parent != null)
  				{
  					parent.appendChild(p);
  				}
  				return p;
  			},
  			addTransparentBackgroundFilter: function(node)
  			{
  				node.style.filter += 'progid:DXImageTransform.Microsoft.AlphaImageLoader(src=\'' +
  					mxClient.imageBasePath + '/transparent.gif\', sizingMethod=\'scale\')';
  			},
  			linkAction: function(parent, text, editor, action, pad)
  			{
  				return mxUtils.link(parent, text, function()
  				{
  					editor.execute(action);
  				}, pad);
  			},
  			linkInvoke: function(parent, text, editor, functName, arg, pad)
  			{
  				return mxUtils.link(parent, text, function()
  				{
  					editor[functName](arg);
  				}, pad);
  			},
  			link: function(parent, text, funct, pad)
  			{
  				var a = document.createElement('span');
  				a.style.color = 'blue';
  				a.style.textDecoration = 'underline';
  				a.style.cursor = 'pointer';
  				if (pad != null)
  				{
  					a.style.paddingLeft = pad+'px';
  				}
  				mxEvent.addListener(a, 'click', funct);
  				mxUtils.write(a, text);
  				if (parent != null)
  				{
  					parent.appendChild(a);
  				}
  				return a;
  			},
  			getDocumentSize: function()
  			{
  				var b = document.body;
  				var d = document.documentElement;
  				try
  				{
  					return new mxRectangle(0, 0, b.clientWidth || d.clientWidth, Math.max(b.clientHeight || 0, d.clientHeight));
  				}
  				catch (e)
  				{
  					return new mxRectangle();
  				}
  			},
  			fit: function(node)
  			{
  				var ds = mxUtils.getDocumentSize();
  				var left = parseInt(node.offsetLeft);
  				var width = parseInt(node.offsetWidth);
  				var offset = mxUtils.getDocumentScrollOrigin(node.ownerDocument);
  				var sl = offset.x;
  				var st = offset.y;
  				var right = (sl) + ds.width;
  				if (left + width > right)
  				{
  					node.style.left = Math.max(sl, right - width) + 'px';
  				}
  				var top = parseInt(node.offsetTop);
  				var height = parseInt(node.offsetHeight);
  				var bottom = st + ds.height;
  				if (top + height > bottom)
  				{
  					node.style.top = Math.max(st, bottom - height) + 'px';
  				}
  			},
  			load: function(url)
  			{
  				var req = new mxXmlRequest(url, null, 'GET', false);
  				req.send();
  				return req;
  			},
  			get: function(url, onload, onerror, binary, timeout, ontimeout, headers)
  			{
  				var req = new mxXmlRequest(url, null, 'GET');
  				var setRequestHeaders = req.setRequestHeaders;
  				if (headers)
  				{
  					req.setRequestHeaders = function(request, params)
  					{
  						setRequestHeaders.apply(this, arguments);
  						for (var key in headers)
  						{
  							request.setRequestHeader(key, headers[key]);
  						}
  					};
  				}
  				if (binary != null)
  				{
  					req.setBinary(binary);
  				}
  				req.send(onload, onerror, timeout, ontimeout);
  				return req;
  			},
  			getAll: function(urls, onload, onerror)
  			{
  				var remain = urls.length;
  				var result = [];
  				var errors = 0;
  				var err = function()
  				{
  					if (errors == 0 && onerror != null)
  					{
  						onerror();
  					}
  					errors++;
  				};
  				for (var i = 0; i < urls.length; i++)
  				{
  					(function(url, index)
  					{
  						mxUtils.get(url, function(req)
  						{
  							var status = req.getStatus();
  							if (status < 200 || status > 299)
  							{
  								err();
  							}
  							else
  							{
  								result[index] = req;
  								remain--;
  								if (remain == 0)
  								{
  									onload(result);
  								}
  							}
  						}, err);
  					})(urls[i], i);
  				}
  				if (remain == 0)
  				{
  					onload(result);
  				}
  			},
  			post: function(url, params, onload, onerror)
  			{
  				return new mxXmlRequest(url, params).send(onload, onerror);
  			},
  			submit: function(url, params, doc, target)
  			{
  				return new mxXmlRequest(url, params).simulate(doc, target);
  			},
  			loadInto: function(url, doc, onload)
  			{
  				if (mxClient.IS_IE)
  				{
  					doc.onreadystatechange = function ()
  					{
  						if (doc.readyState == 4)
  						{
  							onload();
  						}
  					};
  				}
  				else
  				{
  					doc.addEventListener('load', onload, false);
  				}
  				doc.load(url);
  			},
  			getValue: function(array, key, defaultValue)
  			{
  				var value = (array != null) ? array[key] : null;
  				if (value == null)
  				{
  					value = defaultValue;
  				}
  				return value;
  			},
  			getNumber: function(array, key, defaultValue)
  			{
  				var value = (array != null) ? array[key] : null;
  				if (value == null)
  				{
  					value = defaultValue || 0;
  				}
  				return Number(value);
  			},
  			getColor: function(array, key, defaultValue)
  			{
  				var value = (array != null) ? array[key] : null;
  				if (value == null)
  				{
  					value = defaultValue;
  				}
  				else if (value == mxConstants.NONE)
  				{
  					value = null;
  				}
  				return value;
  			},
  			clone: function(obj, transients, shallow)
  			{
  				shallow = (shallow != null) ? shallow : false;
  				var clone = null;
  				if (obj != null && typeof(obj.constructor) == 'function')
  				{
  					clone = new obj.constructor();
  				    for (var i in obj)
  				    {
  				    	if (i != mxObjectIdentity.FIELD_NAME && (transients == null ||
  				    		mxUtils.indexOf(transients, i) < 0))
  				    	{
  					    	if (!shallow && typeof(obj[i]) == 'object')
  					    	{
  					            clone[i] = mxUtils.clone(obj[i]);
  					        }
  					        else
  					        {
  					            clone[i] = obj[i];
  					        }
  						}
  				    }
  				}
  			    return clone;
  			},
  			equalPoints: function(a, b)
  			{
  				if ((a == null && b != null) || (a != null && b == null) ||
  					(a != null && b != null && a.length != b.length))
  				{
  					return false;
  				}
  				else if (a != null && b != null)
  				{
  					for (var i = 0; i < a.length; i++)
  					{
  						if ((a[i] != null && b[i] == null) ||
  							(a[i] == null && b[i] != null) ||
  							(a[i] != null && b[i] != null &&
  							(a[i].x != b[i].x || a[i].y != b[i].y)))
  						{
  							return false;
  						}
  					}
  				}
  				return true;
  			},
  			equalEntries: function(a, b)
  			{
  				var count = 0;
  				if ((a == null && b != null) || (a != null && b == null) ||
  					(a != null && b != null && a.length != b.length))
  				{
  					return false;
  				}
  				else if (a != null && b != null)
  				{
  					for (var key in b)
  					{
  						count++;
  					}
  					for (var key in a)
  					{
  						count--;
  						if ((!mxUtils.isNaN(a[key]) || !mxUtils.isNaN(b[key])) && a[key] != b[key])
  						{
  							return false;
  						}
  					}
  				}
  				return count == 0;
  			},
  			removeDuplicates: function(arr)
  			{
  				var dict = new mxDictionary();
  				var result = [];
  				for (var i = 0; i < arr.length; i++)
  				{
  					if (!dict.get(arr[i]))
  					{
  						result.push(arr[i]);
  						dict.put(arr[i], true);
  					}
  				}
  				return result;
  			},
  			isNaN: function(value)
  			{
  				return typeof(value) == 'number' && isNaN(value);
  			},
  			extend: function(ctor, superCtor)
  			{
  				var f = function() {};
  				f.prototype = superCtor.prototype;
  				ctor.prototype = new f();
  				ctor.prototype.constructor = ctor;
  			},
  			toString: function(obj)
  			{
  			    var output = '';
  			    for (var i in obj)
  			    {
  			    	try
  			    	{
  					    if (obj[i] == null)
  					    {
  				            output += i + ' = [null]\n';
  					    }
  					    else if (typeof(obj[i]) == 'function')
  					    {
  				            output += i + ' => [Function]\n';
  				        }
  				        else if (typeof(obj[i]) == 'object')
  				        {
  				        	var ctor = mxUtils.getFunctionName(obj[i].constructor);
  				            output += i + ' => [' + ctor + ']\n';
  				        }
  				        else
  				        {
  				            output += i + ' = ' + obj[i] + '\n';
  				        }
  			    	}
  			    	catch (e)
  			    	{
  			    		output += i + '=' + e.message;
  			    	}
  			    }
  			    return output;
  			},
  			toRadians: function(deg)
  			{
  				return Math.PI * deg / 180;
  			},
  			toDegree: function(rad)
  			{
  				return rad * 180 / Math.PI;
  			},
  			arcToCurves: function(x0, y0, r1, r2, angle, largeArcFlag, sweepFlag, x, y)
  			{
  				x -= x0;
  				y -= y0;
  		        if (r1 === 0 || r2 === 0)
  		        {
  		        	return result;
  		        }
  		        var fS = sweepFlag;
  		        var psai = angle;
  		        r1 = Math.abs(r1);
  		        r2 = Math.abs(r2);
  		        var ctx = -x / 2;
  		        var cty = -y / 2;
  		        var cpsi = Math.cos(psai * Math.PI / 180);
  		        var spsi = Math.sin(psai * Math.PI / 180);
  		        var rxd = cpsi * ctx + spsi * cty;
  		        var ryd = -1 * spsi * ctx + cpsi * cty;
  		        var rxdd = rxd * rxd;
  		        var rydd = ryd * ryd;
  		        var r1x = r1 * r1;
  		        var r2y = r2 * r2;
  		        var lamda = rxdd / r1x + rydd / r2y;
  		        var sds;
  		        if (lamda > 1)
  		        {
  		        	r1 = Math.sqrt(lamda) * r1;
  		        	r2 = Math.sqrt(lamda) * r2;
  		        	sds = 0;
  		        }
  		        else
  		        {
  		        	var seif = 1;
  		        	if (largeArcFlag === fS)
  		        	{
  		        		seif = -1;
  		        	}
  		        	sds = seif * Math.sqrt((r1x * r2y - r1x * rydd - r2y * rxdd) / (r1x * rydd + r2y * rxdd));
  		        }
  		        var txd = sds * r1 * ryd / r2;
  		        var tyd = -1 * sds * r2 * rxd / r1;
  		        var tx = cpsi * txd - spsi * tyd + x / 2;
  		        var ty = spsi * txd + cpsi * tyd + y / 2;
  		        var rad = Math.atan2((ryd - tyd) / r2, (rxd - txd) / r1) - Math.atan2(0, 1);
  		        var s1 = (rad >= 0) ? rad : 2 * Math.PI + rad;
  		        rad = Math.atan2((-ryd - tyd) / r2, (-rxd - txd) / r1) - Math.atan2((ryd - tyd) / r2, (rxd - txd) / r1);
  		        var dr = (rad >= 0) ? rad : 2 * Math.PI + rad;
  		        if (fS == 0 && dr > 0)
  		        {
  		        	dr -= 2 * Math.PI;
  		        }
  		        else if (fS != 0 && dr < 0)
  		        {
  		        	dr += 2 * Math.PI;
  		        }
  		        var sse = dr * 2 / Math.PI;
  		        var seg = Math.ceil(sse < 0 ? -1 * sse : sse);
  		        var segr = dr / seg;
  		        var t = 8/3 * Math.sin(segr / 4) * Math.sin(segr / 4) / Math.sin(segr / 2);
  		        var cpsir1 = cpsi * r1;
  		        var cpsir2 = cpsi * r2;
  		        var spsir1 = spsi * r1;
  		        var spsir2 = spsi * r2;
  		        var mc = Math.cos(s1);
  		        var ms = Math.sin(s1);
  		        var x2 = -t * (cpsir1 * ms + spsir2 * mc);
  		        var y2 = -t * (spsir1 * ms - cpsir2 * mc);
  		        var x3 = 0;
  		        var y3 = 0;
  				var result = [];
  		        for (var n = 0; n < seg; ++n)
  		        {
  		            s1 += segr;
  		            mc = Math.cos(s1);
  		            ms = Math.sin(s1);
  		            x3 = cpsir1 * mc - spsir2 * ms + tx;
  		            y3 = spsir1 * mc + cpsir2 * ms + ty;
  		            var dx = -t * (cpsir1 * ms + spsir2 * mc);
  		            var dy = -t * (spsir1 * ms - cpsir2 * mc);
  		            var index = n * 6;
  		            result[index] = Number(x2 + x0);
  		            result[index + 1] = Number(y2 + y0);
  		            result[index + 2] = Number(x3 - dx + x0);
  		            result[index + 3] = Number(y3 - dy + y0);
  		            result[index + 4] = Number(x3 + x0);
  		            result[index + 5] = Number(y3 + y0);
  					x2 = x3 + dx;
  		            y2 = y3 + dy;
  		        }
  		        return result;
  			},
  			getBoundingBox: function(rect, rotation, cx)
  			{
  		        var result = null;
  		        if (rect != null && rotation != null && rotation != 0)
  		        {
  		            var rad = mxUtils.toRadians(rotation);
  		            var cos = Math.cos(rad);
  		            var sin = Math.sin(rad);
  		            cx = (cx != null) ? cx : new mxPoint(rect.x + rect.width / 2, rect.y + rect.height / 2);
  		            var p1 = new mxPoint(rect.x, rect.y);
  		            var p2 = new mxPoint(rect.x + rect.width, rect.y);
  		            var p3 = new mxPoint(p2.x, rect.y + rect.height);
  		            var p4 = new mxPoint(rect.x, p3.y);
  		            p1 = mxUtils.getRotatedPoint(p1, cos, sin, cx);
  		            p2 = mxUtils.getRotatedPoint(p2, cos, sin, cx);
  		            p3 = mxUtils.getRotatedPoint(p3, cos, sin, cx);
  		            p4 = mxUtils.getRotatedPoint(p4, cos, sin, cx);
  		            result = new mxRectangle(p1.x, p1.y, 0, 0);
  		            result.add(new mxRectangle(p2.x, p2.y, 0, 0));
  		            result.add(new mxRectangle(p3.x, p3.y, 0, 0));
  		            result.add(new mxRectangle(p4.x, p4.y, 0, 0));
  		        }
  		        return result;
  			},
  			getRotatedPoint: function(pt, cos, sin, c)
  			{
  				c = (c != null) ? c : new mxPoint();
  				var x = pt.x - c.x;
  				var y = pt.y - c.y;
  				var x1 = x * cos - y * sin;
  				var y1 = y * cos + x * sin;
  				return new mxPoint(x1 + c.x, y1 + c.y);
  			},
  			getPortConstraints: function(terminal, edge, source, defaultValue)
  			{
  				var value = mxUtils.getValue(terminal.style, mxConstants.STYLE_PORT_CONSTRAINT,
  					mxUtils.getValue(edge.style, (source) ? mxConstants.STYLE_SOURCE_PORT_CONSTRAINT :
  						mxConstants.STYLE_TARGET_PORT_CONSTRAINT, null));
  				if (value == null)
  				{
  					return defaultValue;
  				}
  				else
  				{
  					var directions = value.toString();
  					var returnValue = mxConstants.DIRECTION_MASK_NONE;
  					var constraintRotationEnabled = mxUtils.getValue(terminal.style, mxConstants.STYLE_PORT_CONSTRAINT_ROTATION, 0);
  					var rotation = 0;
  					if (constraintRotationEnabled == 1)
  					{
  						rotation = mxUtils.getValue(terminal.style, mxConstants.STYLE_ROTATION, 0);
  					}
  					var quad = 0;
  					if (rotation > 45)
  					{
  						quad = 1;
  						if (rotation >= 135)
  						{
  							quad = 2;
  						}
  					}
  					else if (rotation < -45)
  					{
  						quad = 3;
  						if (rotation <= -135)
  						{
  							quad = 2;
  						}
  					}
  					if (directions.indexOf(mxConstants.DIRECTION_NORTH) >= 0)
  					{
  						switch (quad)
  						{
  							case 0:
  								returnValue |= mxConstants.DIRECTION_MASK_NORTH;
  								break;
  							case 1:
  								returnValue |= mxConstants.DIRECTION_MASK_EAST;
  								break;
  							case 2:
  								returnValue |= mxConstants.DIRECTION_MASK_SOUTH;
  								break;
  							case 3:
  								returnValue |= mxConstants.DIRECTION_MASK_WEST;
  								break;
  						}
  					}
  					if (directions.indexOf(mxConstants.DIRECTION_WEST) >= 0)
  					{
  						switch (quad)
  						{
  							case 0:
  								returnValue |= mxConstants.DIRECTION_MASK_WEST;
  								break;
  							case 1:
  								returnValue |= mxConstants.DIRECTION_MASK_NORTH;
  								break;
  							case 2:
  								returnValue |= mxConstants.DIRECTION_MASK_EAST;
  								break;
  							case 3:
  								returnValue |= mxConstants.DIRECTION_MASK_SOUTH;
  								break;
  						}
  					}
  					if (directions.indexOf(mxConstants.DIRECTION_SOUTH) >= 0)
  					{
  						switch (quad)
  						{
  							case 0:
  								returnValue |= mxConstants.DIRECTION_MASK_SOUTH;
  								break;
  							case 1:
  								returnValue |= mxConstants.DIRECTION_MASK_WEST;
  								break;
  							case 2:
  								returnValue |= mxConstants.DIRECTION_MASK_NORTH;
  								break;
  							case 3:
  								returnValue |= mxConstants.DIRECTION_MASK_EAST;
  								break;
  						}
  					}
  					if (directions.indexOf(mxConstants.DIRECTION_EAST) >= 0)
  					{
  						switch (quad)
  						{
  							case 0:
  								returnValue |= mxConstants.DIRECTION_MASK_EAST;
  								break;
  							case 1:
  								returnValue |= mxConstants.DIRECTION_MASK_SOUTH;
  								break;
  							case 2:
  								returnValue |= mxConstants.DIRECTION_MASK_WEST;
  								break;
  							case 3:
  								returnValue |= mxConstants.DIRECTION_MASK_NORTH;
  								break;
  						}
  					}
  					return returnValue;
  				}
  			},
  			reversePortConstraints: function(constraint)
  			{
  				var result = 0;
  				result = (constraint & mxConstants.DIRECTION_MASK_WEST) << 3;
  				result |= (constraint & mxConstants.DIRECTION_MASK_NORTH) << 1;
  				result |= (constraint & mxConstants.DIRECTION_MASK_SOUTH) >> 1;
  				result |= (constraint & mxConstants.DIRECTION_MASK_EAST) >> 3;
  				return result;
  			},
  			findNearestSegment: function(state, x, y)
  			{
  				var index = -1;
  				if (state.absolutePoints.length > 0)
  				{
  					var last = state.absolutePoints[0];
  					var min = null;
  					for (var i = 1; i < state.absolutePoints.length; i++)
  					{
  						var current = state.absolutePoints[i];
  						var dist = mxUtils.ptSegDistSq(last.x, last.y,
  							current.x, current.y, x, y);
  						if (min == null || dist < min)
  						{
  							min = dist;
  							index = i - 1;
  						}
  						last = current;
  					}
  				}
  				return index;
  			},
  			getDirectedBounds: function (rect, m, style, flipH, flipV)
  			{
  				var d = mxUtils.getValue(style, mxConstants.STYLE_DIRECTION, mxConstants.DIRECTION_EAST);
  				flipH = (flipH != null) ? flipH : mxUtils.getValue(style, mxConstants.STYLE_FLIPH, false);
  				flipV = (flipV != null) ? flipV : mxUtils.getValue(style, mxConstants.STYLE_FLIPV, false);
  				m.x = Math.round(Math.max(0, Math.min(rect.width, m.x)));
  				m.y = Math.round(Math.max(0, Math.min(rect.height, m.y)));
  				m.width = Math.round(Math.max(0, Math.min(rect.width, m.width)));
  				m.height = Math.round(Math.max(0, Math.min(rect.height, m.height)));
  				if ((flipV && (d == mxConstants.DIRECTION_SOUTH || d == mxConstants.DIRECTION_NORTH)) ||
  					(flipH && (d == mxConstants.DIRECTION_EAST || d == mxConstants.DIRECTION_WEST)))
  				{
  					var tmp = m.x;
  					m.x = m.width;
  					m.width = tmp;
  				}
  				if ((flipH && (d == mxConstants.DIRECTION_SOUTH || d == mxConstants.DIRECTION_NORTH)) ||
  					(flipV && (d == mxConstants.DIRECTION_EAST || d == mxConstants.DIRECTION_WEST)))
  				{
  					var tmp = m.y;
  					m.y = m.height;
  					m.height = tmp;
  				}
  				var m2 = mxRectangle.fromRectangle(m);
  				if (d == mxConstants.DIRECTION_SOUTH)
  				{
  					m2.y = m.x;
  					m2.x = m.height;
  					m2.width = m.y;
  					m2.height = m.width;
  				}
  				else if (d == mxConstants.DIRECTION_WEST)
  				{
  					m2.y = m.height;
  					m2.x = m.width;
  					m2.width = m.x;
  					m2.height = m.y;
  				}
  				else if (d == mxConstants.DIRECTION_NORTH)
  				{
  					m2.y = m.width;
  					m2.x = m.y;
  					m2.width = m.height;
  					m2.height = m.x;
  				}
  				return new mxRectangle(rect.x + m2.x, rect.y + m2.y, rect.width - m2.width - m2.x, rect.height - m2.height - m2.y);
  			},
  			getPerimeterPoint: function (pts, center, point)
  			{
  				var min = null;
  				for (var i = 0; i < pts.length - 1; i++)
  				{
  					var pt = mxUtils.intersection(pts[i].x, pts[i].y, pts[i + 1].x, pts[i + 1].y,
  						center.x, center.y, point.x, point.y);
  					if (pt != null)
  					{
  						var dx = point.x - pt.x;
  						var dy = point.y - pt.y;
  						var ip = {p: pt, distSq: dy * dy + dx * dx};
  						if (ip != null && (min == null || min.distSq > ip.distSq))
  						{
  							min = ip;
  						}
  					}
  				}
  				return (min != null) ? min.p : null;
  			},
  			rectangleIntersectsSegment: function(bounds, p1, p2)
  			{
  				var top = bounds.y;
  				var left = bounds.x;
  				var bottom = top + bounds.height;
  				var right = left + bounds.width;
  				var minX = p1.x;
  				var maxX = p2.x;
  				if (p1.x > p2.x)
  				{
  				  minX = p2.x;
  				  maxX = p1.x;
  				}
  				if (maxX > right)
  				{
  				  maxX = right;
  				}
  				if (minX < left)
  				{
  				  minX = left;
  				}
  				if (minX > maxX)
  				{
  				  return false;
  				}
  				var minY = p1.y;
  				var maxY = p2.y;
  				var dx = p2.x - p1.x;
  				if (Math.abs(dx) > 0.0000001)
  				{
  				  var a = (p2.y - p1.y) / dx;
  				  var b = p1.y - a * p1.x;
  				  minY = a * minX + b;
  				  maxY = a * maxX + b;
  				}
  				if (minY > maxY)
  				{
  				  var tmp = maxY;
  				  maxY = minY;
  				  minY = tmp;
  				}
  				if (maxY > bottom)
  				{
  				  maxY = bottom;
  				}
  				if (minY < top)
  				{
  				  minY = top;
  				}
  				if (minY > maxY)
  				{
  				  return false;
  				}
  				return true;
  			},
  			contains: function(bounds, x, y)
  			{
  				return (bounds.x <= x && bounds.x + bounds.width >= x &&
  						bounds.y <= y && bounds.y + bounds.height >= y);
  			},
  			intersects: function(a, b)
  			{
  				var tw = a.width;
  				var th = a.height;
  				var rw = b.width;
  				var rh = b.height;
  				if (rw <= 0 || rh <= 0 || tw <= 0 || th <= 0)
  				{
  				    return false;
  				}
  				var tx = a.x;
  				var ty = a.y;
  				var rx = b.x;
  				var ry = b.y;
  				rw += rx;
  				rh += ry;
  				tw += tx;
  				th += ty;
  				return ((rw < rx || rw > tx) &&
  					(rh < ry || rh > ty) &&
  					(tw < tx || tw > rx) &&
  					(th < ty || th > ry));
  			},
  			intersectsHotspot: function(state, x, y, hotspot, min, max)
  			{
  				hotspot = (hotspot != null) ? hotspot : 1;
  				min = (min != null) ? min : 0;
  				max = (max != null) ? max : 0;
  				if (hotspot > 0)
  				{
  					var cx = state.getCenterX();
  					var cy = state.getCenterY();
  					var w = state.width;
  					var h = state.height;
  					var start = mxUtils.getValue(state.style, mxConstants.STYLE_STARTSIZE) * state.view.scale;
  					if (start > 0)
  					{
  						if (mxUtils.getValue(state.style, mxConstants.STYLE_HORIZONTAL, true))
  						{
  							cy = state.y + start / 2;
  							h = start;
  						}
  						else
  						{
  							cx = state.x + start / 2;
  							w = start;
  						}
  					}
  					w = Math.max(min, w * hotspot);
  					h = Math.max(min, h * hotspot);
  					if (max > 0)
  					{
  						w = Math.min(w, max);
  						h = Math.min(h, max);
  					}
  					var rect = new mxRectangle(cx - w / 2, cy - h / 2, w, h);
  					var alpha = mxUtils.toRadians(mxUtils.getValue(state.style, mxConstants.STYLE_ROTATION) || 0);
  					if (alpha != 0)
  					{
  						var cos = Math.cos(-alpha);
  						var sin = Math.sin(-alpha);
  						var cx = new mxPoint(state.getCenterX(), state.getCenterY());
  						var pt = mxUtils.getRotatedPoint(new mxPoint(x, y), cos, sin, cx);
  						x = pt.x;
  						y = pt.y;
  					}
  					return mxUtils.contains(rect, x, y);
  				}
  				return true;
  			},
  			getOffset: function(container, scrollOffset)
  			{
  				var offsetLeft = 0;
  				var offsetTop = 0;
  				var fixed = false;
  				var node = container;
  				var b = document.body;
  				var d = document.documentElement;
  				while (node != null && node != b && node != d && !fixed)
  				{
  					var style = mxUtils.getCurrentStyle(node);
  					if (style != null)
  					{
  						fixed = fixed || style.position == 'fixed';
  					}
  					node = node.parentNode;
  				}
  				if (!scrollOffset && !fixed)
  				{
  					var offset = mxUtils.getDocumentScrollOrigin(container.ownerDocument);
  					offsetLeft += offset.x;
  					offsetTop += offset.y;
  				}
  				var r = container.getBoundingClientRect();
  				if (r != null)
  				{
  					offsetLeft += r.left;
  					offsetTop += r.top;
  				}
  				return new mxPoint(offsetLeft, offsetTop);
  			},
  			getDocumentScrollOrigin: function(doc)
  			{
  				if (mxClient.IS_QUIRKS)
  				{
  					return new mxPoint(doc.body.scrollLeft, doc.body.scrollTop);
  				}
  				else
  				{
  					var wnd = doc.defaultView || doc.parentWindow;
  					var x = (wnd != null && window.pageXOffset !== undefined) ? window.pageXOffset : (document.documentElement || document.body.parentNode || document.body).scrollLeft;
  					var y = (wnd != null && window.pageYOffset !== undefined) ? window.pageYOffset : (document.documentElement || document.body.parentNode || document.body).scrollTop;
  					return new mxPoint(x, y);
  				}
  			},
  			getScrollOrigin: function(node, includeAncestors, includeDocument)
  			{
  				includeAncestors = (includeAncestors != null) ? includeAncestors : false;
  				includeDocument = (includeDocument != null) ? includeDocument : true;
  				var doc = (node != null) ? node.ownerDocument : document;
  				var b = doc.body;
  				var d = doc.documentElement;
  				var result = new mxPoint();
  				var fixed = false;
  				while (node != null && node != b && node != d)
  				{
  					if (!isNaN(node.scrollLeft) && !isNaN(node.scrollTop))
  					{
  						result.x += node.scrollLeft;
  						result.y += node.scrollTop;
  					}
  					var style = mxUtils.getCurrentStyle(node);
  					if (style != null)
  					{
  						fixed = fixed || style.position == 'fixed';
  					}
  					node = (includeAncestors) ? node.parentNode : null;
  				}
  				if (!fixed && includeDocument)
  				{
  					var origin = mxUtils.getDocumentScrollOrigin(doc);
  					result.x += origin.x;
  					result.y += origin.y;
  				}
  				return result;
  			},
  			convertPoint: function(container, x, y)
  			{
  				var origin = mxUtils.getScrollOrigin(container, false);
  				var offset = mxUtils.getOffset(container);
  				offset.x -= origin.x;
  				offset.y -= origin.y;
  				return new mxPoint(x - offset.x, y - offset.y);
  			},
  			ltrim: function(str, chars)
  			{
  				chars = chars || "\\s";
  				return (str != null) ? str.replace(new RegExp("^[" + chars + "]+", "g"), "") : null;
  			},
  			rtrim: function(str, chars)
  			{
  				chars = chars || "\\s";
  				return (str != null) ? str.replace(new RegExp("[" + chars + "]+$", "g"), "") : null;
  			},
  			trim: function(str, chars)
  			{
  				return mxUtils.ltrim(mxUtils.rtrim(str, chars), chars);
  			},
  			isNumeric: function(n)
  			{
  				return !isNaN(parseFloat(n)) && isFinite(n) && (typeof(n) != 'string' || n.toLowerCase().indexOf('0x') < 0);
  			},
  			isInteger: function(n)
  			{
  				return String(parseInt(n)) === String(n);
  			},
  			mod: function(n, m)
  			{
  				return ((n % m) + m) % m;
  			},
  			intersection: function (x0, y0, x1, y1, x2, y2, x3, y3)
  			{
  				var denom = ((y3 - y2) * (x1 - x0)) - ((x3 - x2) * (y1 - y0));
  				var nume_a = ((x3 - x2) * (y0 - y2)) - ((y3 - y2) * (x0 - x2));
  				var nume_b = ((x1 - x0) * (y0 - y2)) - ((y1 - y0) * (x0 - x2));
  				var ua = nume_a / denom;
  				var ub = nume_b / denom;
  				if(ua >= 0.0 && ua <= 1.0 && ub >= 0.0 && ub <= 1.0)
  				{
  					var x = x0 + ua * (x1 - x0);
  					var y = y0 + ua * (y1 - y0);
  					return new mxPoint(x, y);
  				}
  				return null;
  			},
  			ptSegDistSq: function(x1, y1, x2, y2, px, py)
  		    {
  				x2 -= x1;
  				y2 -= y1;
  				px -= x1;
  				py -= y1;
  				var dotprod = px * x2 + py * y2;
  				var projlenSq;
  				if (dotprod <= 0.0)
  				{
  				    projlenSq = 0.0;
  				}
  				else
  				{
  				    px = x2 - px;
  				    py = y2 - py;
  				    dotprod = px * x2 + py * y2;
  				    if (dotprod <= 0.0)
  				    {
  						projlenSq = 0.0;
  				    }
  				    else
  				    {
  						projlenSq = dotprod * dotprod / (x2 * x2 + y2 * y2);
  				    }
  				}
  				var lenSq = px * px + py * py - projlenSq;
  				if (lenSq < 0)
  				{
  				    lenSq = 0;
  				}
  				return lenSq;
  		    },
  		    ptLineDist: function(x1, y1, x2, y2, px, py)
  		    {
  				return Math.abs((y2 - y1) * px - (x2 - x1) * py + x2 * y1 - y2 * x1) /
  					Math.sqrt((y2 - y1) * (y2 - y1) + (x2 - x1) * (x2 - x1));
  		    },
  			relativeCcw: function(x1, y1, x2, y2, px, py)
  		    {
  				x2 -= x1;
  				y2 -= y1;
  				px -= x1;
  				py -= y1;
  				var ccw = px * y2 - py * x2;
  				if (ccw == 0.0)
  				{
  				    ccw = px * x2 + py * y2;
  				    if (ccw > 0.0)
  				    {
  						px -= x2;
  						py -= y2;
  						ccw = px * x2 + py * y2;
  						if (ccw < 0.0)
  						{
  						    ccw = 0.0;
  						}
  				    }
  				}
  				return (ccw < 0.0) ? -1 : ((ccw > 0.0) ? 1 : 0);
  		    },
  			animateChanges: function(graph, changes)
  			{
  		    	mxEffects.animateChanges.apply(this, arguments);
  			},
  		    cascadeOpacity: function(graph, cell, opacity)
  			{
  				mxEffects.cascadeOpacity.apply(this, arguments);
  			},
  			fadeOut: function(node, from, remove, step, delay, isEnabled)
  			{
  				mxEffects.fadeOut.apply(this, arguments);
  			},
  			setOpacity: function(node, value)
  			{
  				if (mxUtils.isVml(node))
  				{
  			    	if (value >= 100)
  			    	{
  			    		node.style.filter = '';
  			    	}
  			    	else
  			    	{
  					    node.style.filter = 'alpha(opacity=' + (value/5) + ')';
  			    	}
  				}
  				else if (mxClient.IS_IE && (typeof(document.documentMode) === 'undefined' || document.documentMode < 9))
  			    {
  			    	if (value >= 100)
  			    	{
  			    		node.style.filter = '';
  			    	}
  			    	else
  			    	{
  					    node.style.filter = 'alpha(opacity=' + value + ')';
  			    	}
  				}
  				else
  				{
  				    node.style.opacity = (value / 100);
  				}
  			},
  			createImage: function(src)
  			{
  		        var imageNode = null;
  				if (mxClient.IS_IE6 && document.compatMode != 'CSS1Compat')
  				{
  		        	imageNode = document.createElement(mxClient.VML_PREFIX + ':image');
  		        	imageNode.setAttribute('src', src);
  		        	imageNode.style.borderStyle = 'none';
  		        }
  				else
  				{
  					imageNode = document.createElement('img');
  					imageNode.setAttribute('src', src);
  					imageNode.setAttribute('border', '0');
  				}
  				return imageNode;
  			},
  			sortCells: function(cells, ascending)
  			{
  				ascending = (ascending != null) ? ascending : true;
  				var lookup = new mxDictionary();
  				cells.sort(function(o1, o2)
  				{
  					var p1 = lookup.get(o1);
  					if (p1 == null)
  					{
  						p1 = mxCellPath.create(o1).split(mxCellPath.PATH_SEPARATOR);
  						lookup.put(o1, p1);
  					}
  					var p2 = lookup.get(o2);
  					if (p2 == null)
  					{
  						p2 = mxCellPath.create(o2).split(mxCellPath.PATH_SEPARATOR);
  						lookup.put(o2, p2);
  					}
  					var comp = mxCellPath.compare(p1, p2);
  					return (comp == 0) ? 0 : (((comp > 0) == ascending) ? 1 : -1);
  				});
  				return cells;
  			},
  			getStylename: function(style)
  			{
  				if (style != null)
  				{
  					var pairs = style.split(';');
  					var stylename = pairs[0];
  					if (stylename.indexOf('=') < 0)
  					{
  						return stylename;
  					}
  				}
  				return '';
  			},
  			getStylenames: function(style)
  			{
  				var result = [];
  				if (style != null)
  				{
  					var pairs = style.split(';');
  					for (var i = 0; i < pairs.length; i++)
  					{
  						if (pairs[i].indexOf('=') < 0)
  						{
  							result.push(pairs[i]);
  						}
  					}
  				}
  				return result;
  			},
  			indexOfStylename: function(style, stylename)
  			{
  				if (style != null && stylename != null)
  				{
  					var tokens = style.split(';');
  					var pos = 0;
  					for (var i = 0; i < tokens.length; i++)
  					{
  						if (tokens[i] == stylename)
  						{
  							return pos;
  						}
  						pos += tokens[i].length + 1;
  					}
  				}
  				return -1;
  			},
  			addStylename: function(style, stylename)
  			{
  				if (mxUtils.indexOfStylename(style, stylename) < 0)
  				{
  					if (style == null)
  					{
  						style = '';
  					}
  					else if (style.length > 0 && style.charAt(style.length - 1) != ';')
  					{
  						style += ';';
  					}
  					style += stylename;
  				}
  				return style;
  			},
  			removeStylename: function(style, stylename)
  			{
  				var result = [];
  				if (style != null)
  				{
  					var tokens = style.split(';');
  					for (var i = 0; i < tokens.length; i++)
  					{
  						if (tokens[i] != stylename)
  						{
  							result.push(tokens[i]);
  						}
  					}
  				}
  				return result.join(';');
  			},
  			removeAllStylenames: function(style)
  			{
  				var result = [];
  				if (style != null)
  				{
  					var tokens = style.split(';');
  					for (var i = 0; i < tokens.length; i++)
  					{
  						if (tokens[i].indexOf('=') >= 0)
  						{
  							result.push(tokens[i]);
  						}
  					}
  				}
  				return result.join(';');
  			},
  			setCellStyles: function(model, cells, key, value)
  			{
  				if (cells != null && cells.length > 0)
  				{
  					model.beginUpdate();
  					try
  					{
  						for (var i = 0; i < cells.length; i++)
  						{
  							if (cells[i] != null)
  							{
  								var style = mxUtils.setStyle(model.getStyle(cells[i]), key, value);
  								model.setStyle(cells[i], style);
  							}
  						}
  					}
  					finally
  					{
  						model.endUpdate();
  					}
  				}
  			},
  			setStyle: function(style, key, value)
  			{
  				var isValue = value != null && (typeof(value.length) == 'undefined' || value.length > 0);
  				if (style == null || style.length == 0)
  				{
  					if (isValue)
  					{
  						style = key + '=' + value + ';';
  					}
  				}
  				else
  				{
  					if (style.substring(0, key.length + 1) == key + '=')
  					{
  						var next = style.indexOf(';');
  						if (isValue)
  						{
  							style = key + '=' + value + ((next < 0) ? ';' : style.substring(next));
  						}
  						else
  						{
  							style = (next < 0 || next == style.length - 1) ? '' : style.substring(next + 1);
  						}
  					}
  					else
  					{
  						var index = style.indexOf(';' + key + '=');
  						if (index < 0)
  						{
  							if (isValue)
  							{
  								var sep = (style.charAt(style.length - 1) == ';') ? '' : ';';
  								style = style + sep + key + '=' + value + ';';
  							}
  						}
  						else
  						{
  							var next = style.indexOf(';', index + 1);
  							if (isValue)
  							{
  								style = style.substring(0, index + 1) + key + '=' + value + ((next < 0) ? ';' : style.substring(next));
  							}
  							else
  							{
  								style = style.substring(0, index) + ((next < 0) ? ';' : style.substring(next));
  							}
  						}
  					}
  				}
  				return style;
  			},
  			setCellStyleFlags: function(model, cells, key, flag, value)
  			{
  				if (cells != null && cells.length > 0)
  				{
  					model.beginUpdate();
  					try
  					{
  						for (var i = 0; i < cells.length; i++)
  						{
  							if (cells[i] != null)
  							{
  								var style = mxUtils.setStyleFlag(
  									model.getStyle(cells[i]),
  									key, flag, value);
  								model.setStyle(cells[i], style);
  							}
  						}
  					}
  					finally
  					{
  						model.endUpdate();
  					}
  				}
  			},
  			setStyleFlag: function(style, key, flag, value)
  			{
  				if (style == null || style.length == 0)
  				{
  					if (value || value == null)
  					{
  						style = key+'='+flag;
  					}
  					else
  					{
  						style = key+'=0';
  					}
  				}
  				else
  				{
  					var index = style.indexOf(key+'=');
  					if (index < 0)
  					{
  						var sep = (style.charAt(style.length-1) == ';') ? '' : ';';
  						if (value || value == null)
  						{
  							style = style + sep + key + '=' + flag;
  						}
  						else
  						{
  							style = style + sep + key + '=0';
  						}
  					}
  					else
  					{
  						var cont = style.indexOf(';', index);
  						var tmp = '';
  						if (cont < 0)
  						{
  							tmp  = style.substring(index+key.length+1);
  						}
  						else
  						{
  							tmp = style.substring(index+key.length+1, cont);
  						}
  						if (value == null)
  						{
  							tmp = parseInt(tmp) ^ flag;
  						}
  						else if (value)
  						{
  							tmp = parseInt(tmp) | flag;
  						}
  						else
  						{
  							tmp = parseInt(tmp) & ~flag;
  						}
  						style = style.substring(0, index) + key + '=' + tmp +
  							((cont >= 0) ? style.substring(cont) : '');
  					}
  				}
  				return style;
  			},
  			getAlignmentAsPoint: function(align, valign)
  			{
  				var dx = -0.5;
  				var dy = -0.5;
  				if (align == mxConstants.ALIGN_LEFT)
  				{
  					dx = 0;
  				}
  				else if (align == mxConstants.ALIGN_RIGHT)
  				{
  					dx = -1;
  				}
  				if (valign == mxConstants.ALIGN_TOP)
  				{
  					dy = 0;
  				}
  				else if (valign == mxConstants.ALIGN_BOTTOM)
  				{
  					dy = -1;
  				}
  				return new mxPoint(dx, dy);
  			},
  			getSizeForString: function(text, fontSize, fontFamily, textWidth, fontStyle)
  			{
  				fontSize = (fontSize != null) ? fontSize : mxConstants.DEFAULT_FONTSIZE;
  				fontFamily = (fontFamily != null) ? fontFamily : mxConstants.DEFAULT_FONTFAMILY;
  				var div = document.createElement('div');
  				div.style.fontFamily = fontFamily;
  				div.style.fontSize = Math.round(fontSize) + 'px';
  				div.style.lineHeight = Math.round(fontSize * mxConstants.LINE_HEIGHT) + 'px';
  				if (fontStyle != null)
  				{
  					if ((fontStyle & mxConstants.FONT_BOLD) == mxConstants.FONT_BOLD)
  					{
  						div.style.fontWeight = 'bold';
  					}
  					if ((fontStyle & mxConstants.FONT_ITALIC) == mxConstants.FONT_ITALIC)
  					{
  						div.style.fontStyle = 'italic';
  					}
  					var txtDecor = [];
  					if ((fontStyle & mxConstants.FONT_UNDERLINE) == mxConstants.FONT_UNDERLINE)
  					{
  						txtDecor.push('underline');
  					}
  					if ((fontStyle & mxConstants.FONT_STRIKETHROUGH) == mxConstants.FONT_STRIKETHROUGH)
  					{
  						txtDecor.push('line-through');
  					}
  					if (txtDecor.length > 0)
  					{
  						div.style.textDecoration = txtDecor.join(' ');
  					}
  				}
  				div.style.position = 'absolute';
  				div.style.visibility = 'hidden';
  				div.style.display = (mxClient.IS_QUIRKS) ? 'inline' : 'inline-block';
  				div.style.zoom = '1';
  				if (textWidth != null)
  				{
  					div.style.width = textWidth + 'px';
  					div.style.whiteSpace = 'normal';
  				}
  				else
  				{
  					div.style.whiteSpace = 'nowrap';
  				}
  				div.innerHTML = text;
  				document.body.appendChild(div);
  				var size = new mxRectangle(0, 0, div.offsetWidth, div.offsetHeight);
  				document.body.removeChild(div);
  				return size;
  			},
  			getViewXml: function(graph, scale, cells, x0, y0)
  			{
  				x0 = (x0 != null) ? x0 : 0;
  				y0 = (y0 != null) ? y0 : 0;
  				scale = (scale != null) ? scale : 1;
  				if (cells == null)
  				{
  					var model = graph.getModel();
  					cells = [model.getRoot()];
  				}
  				var view = graph.getView();
  				var result = null;
  				var eventsEnabled = view.isEventsEnabled();
  				view.setEventsEnabled(false);
  				var drawPane = view.drawPane;
  				var overlayPane = view.overlayPane;
  				if (graph.dialect == mxConstants.DIALECT_SVG)
  				{
  					view.drawPane = document.createElementNS(mxConstants.NS_SVG, 'g');
  					view.canvas.appendChild(view.drawPane);
  					view.overlayPane = document.createElementNS(mxConstants.NS_SVG, 'g');
  					view.canvas.appendChild(view.overlayPane);
  				}
  				else
  				{
  					view.drawPane = view.drawPane.cloneNode(false);
  					view.canvas.appendChild(view.drawPane);
  					view.overlayPane = view.overlayPane.cloneNode(false);
  					view.canvas.appendChild(view.overlayPane);
  				}
  				var translate = view.getTranslate();
  				view.translate = new mxPoint(x0, y0);
  				var temp = new mxTemporaryCellStates(graph.getView(), scale, cells);
  				try
  				{
  					var enc = new mxCodec();
  					result = enc.encode(graph.getView());
  				}
  				finally
  				{
  					temp.destroy();
  					view.translate = translate;
  					view.canvas.removeChild(view.drawPane);
  					view.canvas.removeChild(view.overlayPane);
  					view.drawPane = drawPane;
  					view.overlayPane = overlayPane;
  					view.setEventsEnabled(eventsEnabled);
  				}
  				return result;
  			},
  			getScaleForPageCount: function(pageCount, graph, pageFormat, border)
  			{
  				if (pageCount < 1)
  				{
  					return 1;
  				}
  				pageFormat = (pageFormat != null) ? pageFormat : mxConstants.PAGE_FORMAT_A4_PORTRAIT;
  				border = (border != null) ? border : 0;
  				var availablePageWidth = pageFormat.width - (border * 2);
  				var availablePageHeight = pageFormat.height - (border * 2);
  				var graphBounds = graph.getGraphBounds().clone();
  				var sc = graph.getView().getScale();
  				graphBounds.width /= sc;
  				graphBounds.height /= sc;
  				var graphWidth = graphBounds.width;
  				var graphHeight = graphBounds.height;
  				var scale = 1;
  				var pageFormatAspectRatio = availablePageWidth / availablePageHeight;
  				var graphAspectRatio = graphWidth / graphHeight;
  				var pagesAspectRatio = graphAspectRatio / pageFormatAspectRatio;
  				var pageRoot = Math.sqrt(pageCount);
  				var pagesAspectRatioSqrt = Math.sqrt(pagesAspectRatio);
  				var numRowPages = pageRoot * pagesAspectRatioSqrt;
  				var numColumnPages = pageRoot / pagesAspectRatioSqrt;
  				if (numRowPages < 1 && numColumnPages > pageCount)
  				{
  					var scaleChange = numColumnPages / pageCount;
  					numColumnPages = pageCount;
  					numRowPages /= scaleChange;
  				}
  				if (numColumnPages < 1 && numRowPages > pageCount)
  				{
  					var scaleChange = numRowPages / pageCount;
  					numRowPages = pageCount;
  					numColumnPages /= scaleChange;
  				}
  				var currentTotalPages = Math.ceil(numRowPages) * Math.ceil(numColumnPages);
  				var numLoops = 0;
  				while (currentTotalPages > pageCount)
  				{
  					var roundRowDownProportion = Math.floor(numRowPages) / numRowPages;
  					var roundColumnDownProportion = Math.floor(numColumnPages) / numColumnPages;
  					if (roundRowDownProportion == 1)
  					{
  						roundRowDownProportion = Math.floor(numRowPages-1) / numRowPages;
  					}
  					if (roundColumnDownProportion == 1)
  					{
  						roundColumnDownProportion = Math.floor(numColumnPages-1) / numColumnPages;
  					}
  					var scaleChange = 1;
  					if (roundRowDownProportion > roundColumnDownProportion)
  					{
  						scaleChange = roundRowDownProportion;
  					}
  					else
  					{
  						scaleChange = roundColumnDownProportion;
  					}
  					numRowPages = numRowPages * scaleChange;
  					numColumnPages = numColumnPages * scaleChange;
  					currentTotalPages = Math.ceil(numRowPages) * Math.ceil(numColumnPages);
  					numLoops++;
  					if (numLoops > 10)
  					{
  						break;
  					}
  				}
  				var posterWidth = availablePageWidth * numRowPages;
  				scale = posterWidth / graphWidth;
  				return scale * 0.99999;
  			},
  			show: function(graph, doc, x0, y0, w, h)
  			{
  				x0 = (x0 != null) ? x0 : 0;
  				y0 = (y0 != null) ? y0 : 0;
  				if (doc == null)
  				{
  					var wnd = window.open();
  					doc = wnd.document;
  				}
  				else
  				{
  					doc.open();
  				}
  				if (document.documentMode == 9)
  				{
  					doc.writeln('<!--[if IE]><meta http-equiv="X-UA-Compatible" content="IE=9"><![endif]-->');
  				}
  				var bounds = graph.getGraphBounds();
  				var dx = Math.ceil(x0 - bounds.x);
  				var dy = Math.ceil(y0 - bounds.y);
  				if (w == null)
  				{
  					w = Math.ceil(bounds.width + x0) + Math.ceil(Math.ceil(bounds.x) - bounds.x);
  				}
  				if (h == null)
  				{
  					h = Math.ceil(bounds.height + y0) + Math.ceil(Math.ceil(bounds.y) - bounds.y);
  				}
  				if (mxClient.IS_IE || document.documentMode == 11)
  				{
  					var html = '<html><head>';
  					var base = document.getElementsByTagName('base');
  					for (var i = 0; i < base.length; i++)
  					{
  						html += base[i].outerHTML;
  					}
  					html += '<style>';
  					for (var i = 0; i < document.styleSheets.length; i++)
  					{
  						try
  						{
  							html += document.styleSheets[i].cssText;
  						}
  						catch (e)
  						{
  						}
  					}
  					html += '</style></head><body style="margin:0px;">';
  					html += '<div style="position:absolute;overflow:hidden;width:' + w + 'px;height:' + h + 'px;"><div style="position:relative;left:' + dx + 'px;top:' + dy + 'px;">';
  					html += graph.container.innerHTML;
  					html += '</div></div></body><html>';
  					doc.writeln(html);
  					doc.close();
  				}
  				else
  				{
  					doc.writeln('<html><head>');
  					var base = document.getElementsByTagName('base');
  					for (var i = 0; i < base.length; i++)
  					{
  						doc.writeln(mxUtils.getOuterHtml(base[i]));
  					}
  					var links = document.getElementsByTagName('link');
  					for (var i = 0; i < links.length; i++)
  					{
  						doc.writeln(mxUtils.getOuterHtml(links[i]));
  					}
  					var styles = document.getElementsByTagName('style');
  					for (var i = 0; i < styles.length; i++)
  					{
  						doc.writeln(mxUtils.getOuterHtml(styles[i]));
  					}
  					doc.writeln('</head><body style="margin:0px;"></body></html>');
  					doc.close();
  					var outer = doc.createElement('div');
  					outer.position = 'absolute';
  					outer.overflow = 'hidden';
  					outer.style.width = w + 'px';
  					outer.style.height = h + 'px';
  					var div = doc.createElement('div');
  					div.style.position = 'absolute';
  					div.style.left = dx + 'px';
  					div.style.top = dy + 'px';
  					var node = graph.container.firstChild;
  					var svg = null;
  					while (node != null)
  					{
  						var clone = node.cloneNode(true);
  						if (node == graph.view.drawPane.ownerSVGElement)
  						{
  							outer.appendChild(clone);
  							svg = clone;
  						}
  						else
  						{
  							div.appendChild(clone);
  						}
  						node = node.nextSibling;
  					}
  					doc.body.appendChild(outer);
  					if (div.firstChild != null)
  					{
  						doc.body.appendChild(div);
  					}
  					if (svg != null)
  					{
  						svg.style.minWidth = '';
  						svg.style.minHeight = '';
  						svg.firstChild.setAttribute('transform', 'translate(' + dx + ',' + dy + ')');
  					}
  				}
  				mxUtils.removeCursors(doc.body);
  				return doc;
  			},
  			printScreen: function(graph)
  			{
  				var wnd = window.open();
  				graph.getGraphBounds();
  				mxUtils.show(graph, wnd.document);
  				var print = function()
  				{
  					wnd.focus();
  					wnd.print();
  					wnd.close();
  				};
  				if (mxClient.IS_GC)
  				{
  					wnd.setTimeout(print, 500);
  				}
  				else
  				{
  					print();
  				}
  			},
  			popup: function(content, isInternalWindow)
  			{
  			   	if (isInternalWindow)
  			   	{
  					var div = document.createElement('div');
  					div.style.overflow = 'scroll';
  					div.style.width = '636px';
  					div.style.height = '460px';
  					var pre = document.createElement('pre');
  				    pre.innerHTML = mxUtils.htmlEntities(content, false).
  				    	replace(/\n/g,'<br>').replace(/ /g, '&nbsp;');
  					div.appendChild(pre);
  					var w = document.body.clientWidth;
  					var h = Math.max(document.body.clientHeight || 0, document.documentElement.clientHeight);
  					var wnd = new mxWindow('Popup Window', div,
  						w/2-320, h/2-240, 640, 480, false, true);
  					wnd.setClosable(true);
  					wnd.setVisible(true);
  				}
  				else
  				{
  					if (mxClient.IS_NS)
  					{
  					    var wnd = window.open();
  						wnd.document.writeln('<pre>'+mxUtils.htmlEntities(content)+'</pre');
  					   	wnd.document.close();
  					}
  					else
  					{
  					    var wnd = window.open();
  					    var pre = wnd.document.createElement('pre');
  					    pre.innerHTML = mxUtils.htmlEntities(content, false).
  					    	replace(/\n/g,'<br>').replace(/ /g, '&nbsp;');
  					   	wnd.document.body.appendChild(pre);
  					}
  			   	}
  			},
  			alert: function(message)
  			{
  				alert(message);
  			},
  			prompt: function(message, defaultValue)
  			{
  				return prompt(message, (defaultValue != null) ? defaultValue : '');
  			},
  			confirm: function(message)
  			{
  				return confirm(message);
  			},
  			error: function(message, width, close, icon)
  			{
  				var div = document.createElement('div');
  				div.style.padding = '20px';
  				var img = document.createElement('img');
  				img.setAttribute('src', icon || mxUtils.errorImage);
  				img.setAttribute('valign', 'bottom');
  				img.style.verticalAlign = 'middle';
  				div.appendChild(img);
  				div.appendChild(document.createTextNode('\u00a0'));
  				div.appendChild(document.createTextNode('\u00a0'));
  				div.appendChild(document.createTextNode('\u00a0'));
  				mxUtils.write(div, message);
  				var w = document.body.clientWidth;
  				var h = (document.body.clientHeight || document.documentElement.clientHeight);
  				var warn = new mxWindow(mxResources.get(mxUtils.errorResource) ||
  					mxUtils.errorResource, div, (w-width)/2, h/4, width, null,
  					false, true);
  				if (close)
  				{
  					mxUtils.br(div);
  					var tmp = document.createElement('p');
  					var button = document.createElement('button');
  					if (mxClient.IS_IE)
  					{
  						button.style.cssText = 'float:right';
  					}
  					else
  					{
  						button.setAttribute('style', 'float:right');
  					}
  					mxEvent.addListener(button, 'click', function(evt)
  					{
  						warn.destroy();
  					});
  					mxUtils.write(button, mxResources.get(mxUtils.closeResource) ||
  						mxUtils.closeResource);
  					tmp.appendChild(button);
  					div.appendChild(tmp);
  					mxUtils.br(div);
  					warn.setClosable(true);
  				}
  				warn.setVisible(true);
  				return warn;
  			},
  			makeDraggable: function(element, graphF, funct, dragElement, dx, dy, autoscroll,
  					scalePreview, highlightDropTargets, getDropTarget)
  			{
  				var dragSource = new mxDragSource(element, funct);
  				dragSource.dragOffset = new mxPoint((dx != null) ? dx : 0,
  					(dy != null) ? dy : mxConstants.TOOLTIP_VERTICAL_OFFSET);
  				dragSource.autoscroll = autoscroll;
  				dragSource.setGuidesEnabled(false);
  				if (highlightDropTargets != null)
  				{
  					dragSource.highlightDropTargets = highlightDropTargets;
  				}
  				if (getDropTarget != null)
  				{
  					dragSource.getDropTarget = getDropTarget;
  				}
  				dragSource.getGraphForEvent = function(evt)
  				{
  					return (typeof(graphF) == 'function') ? graphF(evt) : graphF;
  				};
  				if (dragElement != null)
  				{
  					dragSource.createDragElement = function()
  					{
  						return dragElement.cloneNode(true);
  					};
  					if (scalePreview)
  					{
  						dragSource.createPreviewElement = function(graph)
  						{
  							var elt = dragElement.cloneNode(true);
  							var w = parseInt(elt.style.width);
  							var h = parseInt(elt.style.height);
  							elt.style.width = Math.round(w * graph.view.scale) + 'px';
  							elt.style.height = Math.round(h * graph.view.scale) + 'px';
  							return elt;
  						};
  					}
  				}
  				return dragSource;
  			}
  		};
  		__mxOutput.mxUtils = typeof mxUtils !== 'undefined' ? mxUtils : undefined;
  		 var mxConstants =
  		 {
  			DEFAULT_HOTSPOT: 0.3,
  			MIN_HOTSPOT_SIZE: 8,
  			MAX_HOTSPOT_SIZE: 0,
  			RENDERING_HINT_EXACT: 'exact',
  			RENDERING_HINT_FASTER: 'faster',
  			RENDERING_HINT_FASTEST: 'fastest',
  			DIALECT_SVG: 'svg',
  			DIALECT_VML: 'vml',
  			DIALECT_MIXEDHTML: 'mixedHtml',
  			DIALECT_PREFERHTML: 'preferHtml',
  			DIALECT_STRICTHTML: 'strictHtml',
  			NS_SVG: 'http://www.w3.org/2000/svg',
  			NS_XHTML: 'http://www.w3.org/1999/xhtml',
  			NS_XLINK: 'http://www.w3.org/1999/xlink',
  			SHADOWCOLOR: 'gray',
  			VML_SHADOWCOLOR: 'gray',
  			SHADOW_OFFSET_X: 2,
  			SHADOW_OFFSET_Y: 3,
  			SHADOW_OPACITY: 1,
  			NODETYPE_ELEMENT: 1,
  			NODETYPE_ATTRIBUTE: 2,
  			NODETYPE_TEXT: 3,
  			NODETYPE_CDATA: 4,
  			NODETYPE_ENTITY_REFERENCE: 5,
  			NODETYPE_ENTITY: 6,
  			NODETYPE_PROCESSING_INSTRUCTION: 7,
  			NODETYPE_COMMENT: 8,
  			NODETYPE_DOCUMENT: 9,
  			NODETYPE_DOCUMENTTYPE: 10,
  			NODETYPE_DOCUMENT_FRAGMENT: 11,
  			NODETYPE_NOTATION: 12,
  			TOOLTIP_VERTICAL_OFFSET: 16,
  			DEFAULT_VALID_COLOR: '#00FF00',
  			DEFAULT_INVALID_COLOR: '#FF0000',
  			OUTLINE_HIGHLIGHT_COLOR: '#00FF00',
  			OUTLINE_HIGHLIGHT_STROKEWIDTH: 5,
  			HIGHLIGHT_STROKEWIDTH: 3,
  			HIGHLIGHT_SIZE: 2,
  			HIGHLIGHT_OPACITY: 100,
  			CURSOR_MOVABLE_VERTEX: 'move',
  			CURSOR_MOVABLE_EDGE: 'move',
  			CURSOR_LABEL_HANDLE: 'default',
  			CURSOR_TERMINAL_HANDLE: 'pointer',
  			CURSOR_BEND_HANDLE: 'crosshair',
  			CURSOR_VIRTUAL_BEND_HANDLE: 'crosshair',
  			CURSOR_CONNECT: 'pointer',
  			HIGHLIGHT_COLOR: '#00FF00',
  			CONNECT_TARGET_COLOR: '#0000FF',
  			INVALID_CONNECT_TARGET_COLOR: '#FF0000',
  			DROP_TARGET_COLOR: '#0000FF',
  			VALID_COLOR: '#00FF00',
  			INVALID_COLOR: '#FF0000',
  			EDGE_SELECTION_COLOR: '#00FF00',
  			VERTEX_SELECTION_COLOR: '#00FF00',
  			VERTEX_SELECTION_STROKEWIDTH: 1,
  			EDGE_SELECTION_STROKEWIDTH: 1,
  			VERTEX_SELECTION_DASHED: true,
  			EDGE_SELECTION_DASHED: true,
  			GUIDE_COLOR: '#FF0000',
  			GUIDE_STROKEWIDTH: 1,
  			OUTLINE_COLOR: '#0099FF',
  			OUTLINE_STROKEWIDTH: (mxClient.IS_IE) ? 2 : 3,
  			HANDLE_SIZE: 6,
  			LABEL_HANDLE_SIZE: 4,
  			HANDLE_FILLCOLOR: '#00FF00',
  			HANDLE_STROKECOLOR: 'black',
  			LABEL_HANDLE_FILLCOLOR: 'yellow',
  			CONNECT_HANDLE_FILLCOLOR: '#0000FF',
  			LOCKED_HANDLE_FILLCOLOR: '#FF0000',
  			OUTLINE_HANDLE_FILLCOLOR: '#00FFFF',
  			OUTLINE_HANDLE_STROKECOLOR: '#0033FF',
  			DEFAULT_FONTFAMILY: 'Arial,Helvetica',
  			DEFAULT_FONTSIZE: 11,
  			DEFAULT_TEXT_DIRECTION: '',
  			LINE_HEIGHT: 1.2,
  			WORD_WRAP: 'normal',
  			ABSOLUTE_LINE_HEIGHT: false,
  			DEFAULT_FONTSTYLE: 0,
  			DEFAULT_STARTSIZE: 40,
  			DEFAULT_MARKERSIZE: 6,
  			DEFAULT_IMAGESIZE: 24,
  			ENTITY_SEGMENT: 30,
  			RECTANGLE_ROUNDING_FACTOR: 0.15,
  			LINE_ARCSIZE: 20,
  			ARROW_SPACING: 0,
  			ARROW_WIDTH: 30,
  			ARROW_SIZE: 30,
  			PAGE_FORMAT_A4_PORTRAIT: new mxRectangle(0, 0, 827, 1169),
  			PAGE_FORMAT_A4_LANDSCAPE: new mxRectangle(0, 0, 1169, 827),
  			PAGE_FORMAT_LETTER_PORTRAIT: new mxRectangle(0, 0, 850, 1100),
  			PAGE_FORMAT_LETTER_LANDSCAPE: new mxRectangle(0, 0, 1100, 850),
  			NONE: 'none',
  			STYLE_PERIMETER: 'perimeter',
  			STYLE_SOURCE_PORT: 'sourcePort',
  			STYLE_TARGET_PORT: 'targetPort',
  			STYLE_PORT_CONSTRAINT: 'portConstraint',
  			STYLE_PORT_CONSTRAINT_ROTATION: 'portConstraintRotation',
  			STYLE_SOURCE_PORT_CONSTRAINT: 'sourcePortConstraint',
  			STYLE_TARGET_PORT_CONSTRAINT: 'targetPortConstraint',
  			STYLE_OPACITY: 'opacity',
  			STYLE_FILL_OPACITY: 'fillOpacity',
  			STYLE_STROKE_OPACITY: 'strokeOpacity',
  			STYLE_TEXT_OPACITY: 'textOpacity',
  			STYLE_TEXT_DIRECTION: 'textDirection',
  			STYLE_OVERFLOW: 'overflow',
  			STYLE_ORTHOGONAL: 'orthogonal',
  			STYLE_EXIT_X: 'exitX',
  			STYLE_EXIT_Y: 'exitY',
  			STYLE_EXIT_DX: 'exitDx',
  			STYLE_EXIT_DY: 'exitDy',
  			STYLE_EXIT_PERIMETER: 'exitPerimeter',
  			STYLE_ENTRY_X: 'entryX',
  			STYLE_ENTRY_Y: 'entryY',
  			STYLE_ENTRY_DX: 'entryDx',
  			STYLE_ENTRY_DY: 'entryDy',
  			STYLE_ENTRY_PERIMETER: 'entryPerimeter',
  			STYLE_WHITE_SPACE: 'whiteSpace',
  			STYLE_ROTATION: 'rotation',
  			STYLE_FILLCOLOR: 'fillColor',
  			STYLE_POINTER_EVENTS: 'pointerEvents',
  			STYLE_SWIMLANE_FILLCOLOR: 'swimlaneFillColor',
  			STYLE_MARGIN: 'margin',
  			STYLE_GRADIENTCOLOR: 'gradientColor',
  			STYLE_GRADIENT_DIRECTION: 'gradientDirection',
  			STYLE_STROKECOLOR: 'strokeColor',
  			STYLE_SEPARATORCOLOR: 'separatorColor',
  			STYLE_STROKEWIDTH: 'strokeWidth',
  			STYLE_ALIGN: 'align',
  			STYLE_VERTICAL_ALIGN: 'verticalAlign',
  			STYLE_LABEL_WIDTH: 'labelWidth',
  			STYLE_LABEL_POSITION: 'labelPosition',
  			STYLE_VERTICAL_LABEL_POSITION: 'verticalLabelPosition',
  			STYLE_IMAGE_ASPECT: 'imageAspect',
  			STYLE_IMAGE_ALIGN: 'imageAlign',
  			STYLE_IMAGE_VERTICAL_ALIGN: 'imageVerticalAlign',
  			STYLE_GLASS: 'glass',
  			STYLE_IMAGE: 'image',
  			STYLE_IMAGE_WIDTH: 'imageWidth',
  			STYLE_IMAGE_HEIGHT: 'imageHeight',
  			STYLE_IMAGE_BACKGROUND: 'imageBackground',
  			STYLE_IMAGE_BORDER: 'imageBorder',
  			STYLE_FLIPH: 'flipH',
  			STYLE_FLIPV: 'flipV',
  			STYLE_NOLABEL: 'noLabel',
  			STYLE_NOEDGESTYLE: 'noEdgeStyle',
  			STYLE_LABEL_BACKGROUNDCOLOR: 'labelBackgroundColor',
  			STYLE_LABEL_BORDERCOLOR: 'labelBorderColor',
  			STYLE_LABEL_PADDING: 'labelPadding',
  			STYLE_INDICATOR_SHAPE: 'indicatorShape',
  			STYLE_INDICATOR_IMAGE: 'indicatorImage',
  			STYLE_INDICATOR_COLOR: 'indicatorColor',
  			STYLE_INDICATOR_STROKECOLOR: 'indicatorStrokeColor',
  			STYLE_INDICATOR_GRADIENTCOLOR: 'indicatorGradientColor',
  			STYLE_INDICATOR_SPACING: 'indicatorSpacing',
  			STYLE_INDICATOR_WIDTH: 'indicatorWidth',
  			STYLE_INDICATOR_HEIGHT: 'indicatorHeight',
  			STYLE_INDICATOR_DIRECTION: 'indicatorDirection',
  			STYLE_SHADOW: 'shadow',
  			STYLE_SEGMENT: 'segment',
  			STYLE_ENDARROW: 'endArrow',
  			STYLE_STARTARROW: 'startArrow',
  			STYLE_ENDSIZE: 'endSize',
  			STYLE_STARTSIZE: 'startSize',
  			STYLE_SWIMLANE_LINE: 'swimlaneLine',
  			STYLE_ENDFILL: 'endFill',
  			STYLE_STARTFILL: 'startFill',
  			STYLE_DASHED: 'dashed',
  			STYLE_DASH_PATTERN: 'dashPattern',
  			STYLE_FIX_DASH: 'fixDash',
  			STYLE_ROUNDED: 'rounded',
  			STYLE_CURVED: 'curved',
  			STYLE_ARCSIZE: 'arcSize',
  			STYLE_ABSOLUTE_ARCSIZE: 'absoluteArcSize',
  			STYLE_SOURCE_PERIMETER_SPACING: 'sourcePerimeterSpacing',
  			STYLE_TARGET_PERIMETER_SPACING: 'targetPerimeterSpacing',
  			STYLE_PERIMETER_SPACING: 'perimeterSpacing',
  			STYLE_SPACING: 'spacing',
  			STYLE_SPACING_TOP: 'spacingTop',
  			STYLE_SPACING_LEFT: 'spacingLeft',
  			STYLE_SPACING_BOTTOM: 'spacingBottom',
  			STYLE_SPACING_RIGHT: 'spacingRight',
  			STYLE_HORIZONTAL: 'horizontal',
  			STYLE_DIRECTION: 'direction',
  			STYLE_ANCHOR_POINT_DIRECTION: 'anchorPointDirection',
  			STYLE_ELBOW: 'elbow',
  			STYLE_FONTCOLOR: 'fontColor',
  			STYLE_FONTFAMILY: 'fontFamily',
  			STYLE_FONTSIZE: 'fontSize',
  			STYLE_FONTSTYLE: 'fontStyle',
  			STYLE_ASPECT: 'aspect',
  			STYLE_AUTOSIZE: 'autosize',
  			STYLE_FOLDABLE: 'foldable',
  			STYLE_EDITABLE: 'editable',
  			STYLE_BACKGROUND_OUTLINE: 'backgroundOutline',
  			STYLE_BENDABLE: 'bendable',
  			STYLE_MOVABLE: 'movable',
  			STYLE_RESIZABLE: 'resizable',
  			STYLE_RESIZE_WIDTH: 'resizeWidth',
  			STYLE_RESIZE_HEIGHT: 'resizeHeight',
  			STYLE_ROTATABLE: 'rotatable',
  			STYLE_CLONEABLE: 'cloneable',
  			STYLE_DELETABLE: 'deletable',
  			STYLE_SHAPE: 'shape',
  			STYLE_EDGE: 'edgeStyle',
  			STYLE_JETTY_SIZE: 'jettySize',
  			STYLE_SOURCE_JETTY_SIZE: 'sourceJettySize',
  			STYLE_TARGET_JETTY_SIZE: 'targetJettySize',
  			STYLE_LOOP: 'loopStyle',
  			STYLE_ORTHOGONAL_LOOP: 'orthogonalLoop',
  			STYLE_ROUTING_CENTER_X: 'routingCenterX',
  			STYLE_ROUTING_CENTER_Y: 'routingCenterY',
  			FONT_BOLD: 1,
  			FONT_ITALIC: 2,
  			FONT_UNDERLINE: 4,
  			FONT_STRIKETHROUGH: 8,
  			SHAPE_RECTANGLE: 'rectangle',
  			SHAPE_ELLIPSE: 'ellipse',
  			SHAPE_DOUBLE_ELLIPSE: 'doubleEllipse',
  			SHAPE_RHOMBUS: 'rhombus',
  			SHAPE_LINE: 'line',
  			SHAPE_IMAGE: 'image',
  			SHAPE_ARROW: 'arrow',
  			SHAPE_ARROW_CONNECTOR: 'arrowConnector',
  			SHAPE_LABEL: 'label',
  			SHAPE_CYLINDER: 'cylinder',
  			SHAPE_SWIMLANE: 'swimlane',
  			SHAPE_CONNECTOR: 'connector',
  			SHAPE_ACTOR: 'actor',
  			SHAPE_CLOUD: 'cloud',
  			SHAPE_TRIANGLE: 'triangle',
  			SHAPE_HEXAGON: 'hexagon',
  			ARROW_CLASSIC: 'classic',
  			ARROW_CLASSIC_THIN: 'classicThin',
  			ARROW_BLOCK: 'block',
  			ARROW_BLOCK_THIN: 'blockThin',
  			ARROW_OPEN: 'open',
  			ARROW_OPEN_THIN: 'openThin',
  			ARROW_OVAL: 'oval',
  			ARROW_DIAMOND: 'diamond',
  			ARROW_DIAMOND_THIN: 'diamondThin',
  			ALIGN_LEFT: 'left',
  			ALIGN_CENTER: 'center',
  			ALIGN_RIGHT: 'right',
  			ALIGN_TOP: 'top',
  			ALIGN_MIDDLE: 'middle',
  			ALIGN_BOTTOM: 'bottom',
  			DIRECTION_NORTH: 'north',
  			DIRECTION_SOUTH: 'south',
  			DIRECTION_EAST: 'east',
  			DIRECTION_WEST: 'west',
  			TEXT_DIRECTION_DEFAULT: '',
  			TEXT_DIRECTION_AUTO: 'auto',
  			TEXT_DIRECTION_LTR: 'ltr',
  			TEXT_DIRECTION_RTL: 'rtl',
  			DIRECTION_MASK_NONE: 0,
  			DIRECTION_MASK_WEST: 1,
  			DIRECTION_MASK_NORTH: 2,
  			DIRECTION_MASK_SOUTH: 4,
  			DIRECTION_MASK_EAST: 8,
  			DIRECTION_MASK_ALL: 15,
  			ELBOW_VERTICAL: 'vertical',
  			ELBOW_HORIZONTAL: 'horizontal',
  			EDGESTYLE_ELBOW: 'elbowEdgeStyle',
  			EDGESTYLE_ENTITY_RELATION: 'entityRelationEdgeStyle',
  			EDGESTYLE_LOOP: 'loopEdgeStyle',
  			EDGESTYLE_SIDETOSIDE: 'sideToSideEdgeStyle',
  			EDGESTYLE_TOPTOBOTTOM: 'topToBottomEdgeStyle',
  			EDGESTYLE_ORTHOGONAL: 'orthogonalEdgeStyle',
  			EDGESTYLE_SEGMENT: 'segmentEdgeStyle',
  			PERIMETER_ELLIPSE: 'ellipsePerimeter',
  			PERIMETER_RECTANGLE: 'rectanglePerimeter',
  			PERIMETER_RHOMBUS: 'rhombusPerimeter',
  			PERIMETER_HEXAGON: 'hexagonPerimeter',
  			PERIMETER_TRIANGLE: 'trianglePerimeter'
  		};
  		__mxOutput.mxConstants = typeof mxConstants !== 'undefined' ? mxConstants : undefined;
  		function mxEventObject(name)
  		{
  			this.name = name;
  			this.properties = [];
  			for (var i = 1; i < arguments.length; i += 2)
  			{
  				if (arguments[i + 1] != null)
  				{
  					this.properties[arguments[i]] = arguments[i + 1];
  				}
  			}
  		}		mxEventObject.prototype.name = null;
  		mxEventObject.prototype.properties = null;
  		mxEventObject.prototype.consumed = false;
  		mxEventObject.prototype.getName = function()
  		{
  			return this.name;
  		};
  		mxEventObject.prototype.getProperties = function()
  		{
  			return this.properties;
  		};
  		mxEventObject.prototype.getProperty = function(key)
  		{
  			return this.properties[key];
  		};
  		mxEventObject.prototype.isConsumed = function()
  		{
  			return this.consumed;
  		};
  		mxEventObject.prototype.consume = function()
  		{
  			this.consumed = true;
  		};
  		__mxOutput.mxEventObject = typeof mxEventObject !== 'undefined' ? mxEventObject : undefined;
  		function mxMouseEvent(evt, state)
  		{
  			this.evt = evt;
  			this.state = state;
  			this.sourceState = state;
  		}		mxMouseEvent.prototype.consumed = false;
  		mxMouseEvent.prototype.evt = null;
  		mxMouseEvent.prototype.graphX = null;
  		mxMouseEvent.prototype.graphY = null;
  		mxMouseEvent.prototype.state = null;
  		mxMouseEvent.prototype.sourceState = null;
  		mxMouseEvent.prototype.getEvent = function()
  		{
  			return this.evt;
  		};
  		mxMouseEvent.prototype.getSource = function()
  		{
  			return mxEvent.getSource(this.evt);
  		};
  		mxMouseEvent.prototype.isSource = function(shape)
  		{
  			if (shape != null)
  			{
  				return mxUtils.isAncestorNode(shape.node, this.getSource());
  			}
  			return false;
  		};
  		mxMouseEvent.prototype.getX = function()
  		{
  			return mxEvent.getClientX(this.getEvent());
  		};
  		mxMouseEvent.prototype.getY = function()
  		{
  			return mxEvent.getClientY(this.getEvent());
  		};
  		mxMouseEvent.prototype.getGraphX = function()
  		{
  			return this.graphX;
  		};
  		mxMouseEvent.prototype.getGraphY = function()
  		{
  			return this.graphY;
  		};
  		mxMouseEvent.prototype.getState = function()
  		{
  			return this.state;
  		};
  		mxMouseEvent.prototype.getCell = function()
  		{
  			var state = this.getState();
  			if (state != null)
  			{
  				return state.cell;
  			}
  			return null;
  		};
  		mxMouseEvent.prototype.isPopupTrigger = function()
  		{
  			return mxEvent.isPopupTrigger(this.getEvent());
  		};
  		mxMouseEvent.prototype.isConsumed = function()
  		{
  			return this.consumed;
  		};
  		mxMouseEvent.prototype.consume = function(preventDefault)
  		{
  			preventDefault = (preventDefault != null) ? preventDefault :
  				(this.evt.touches != null || mxEvent.isMouseEvent(this.evt));
  			if (preventDefault && this.evt.preventDefault)
  			{
  				this.evt.preventDefault();
  			}
  			if (mxClient.IS_IE)
  			{
  				this.evt.returnValue = true;
  			}
  			this.consumed = true;
  		};
  		__mxOutput.mxMouseEvent = typeof mxMouseEvent !== 'undefined' ? mxMouseEvent : undefined;
  		function mxEventSource(eventSource)
  		{
  			this.setEventSource(eventSource);
  		}		mxEventSource.prototype.eventListeners = null;
  		mxEventSource.prototype.eventsEnabled = true;
  		mxEventSource.prototype.eventSource = null;
  		mxEventSource.prototype.isEventsEnabled = function()
  		{
  			return this.eventsEnabled;
  		};
  		mxEventSource.prototype.setEventsEnabled = function(value)
  		{
  			this.eventsEnabled = value;
  		};
  		mxEventSource.prototype.getEventSource = function()
  		{
  			return this.eventSource;
  		};
  		mxEventSource.prototype.setEventSource = function(value)
  		{
  			this.eventSource = value;
  		};
  		mxEventSource.prototype.addListener = function(name, funct)
  		{
  			if (this.eventListeners == null)
  			{
  				this.eventListeners = [];
  			}
  			this.eventListeners.push(name);
  			this.eventListeners.push(funct);
  		};
  		mxEventSource.prototype.removeListener = function(funct)
  		{
  			if (this.eventListeners != null)
  			{
  				var i = 0;
  				while (i < this.eventListeners.length)
  				{
  					if (this.eventListeners[i+1] == funct)
  					{
  						this.eventListeners.splice(i, 2);
  					}
  					else
  					{
  						i += 2;
  					}
  				}
  			}
  		};
  		mxEventSource.prototype.fireEvent = function(evt, sender)
  		{
  			if (this.eventListeners != null && this.isEventsEnabled())
  			{
  				if (evt == null)
  				{
  					evt = new mxEventObject();
  				}
  				if (sender == null)
  				{
  					sender = this.getEventSource();
  				}
  				if (sender == null)
  				{
  					sender = this;
  				}
  				var args = [sender, evt];
  				for (var i = 0; i < this.eventListeners.length; i += 2)
  				{
  					var listen = this.eventListeners[i];
  					if (listen == null || listen == evt.getName())
  					{
  						this.eventListeners[i+1].apply(this, args);
  					}
  				}
  			}
  		};
  		__mxOutput.mxEventSource = typeof mxEventSource !== 'undefined' ? mxEventSource : undefined;
  		var mxEvent =
  		{
  			addListener: function()
  			{
  				var updateListenerList = function(element, eventName, funct)
  				{
  					if (element.mxListenerList == null)
  					{
  						element.mxListenerList = [];
  					}
  					var entry = {name: eventName, f: funct};
  					element.mxListenerList.push(entry);
  				};
  				if (window.addEventListener)
  				{
  					return function(element, eventName, funct)
  					{
  						element.addEventListener(eventName, funct, false);
  						updateListenerList(element, eventName, funct);
  					};
  				}
  				else
  				{
  					return function(element, eventName, funct)
  					{
  						element.attachEvent('on' + eventName, funct);
  						updateListenerList(element, eventName, funct);
  					};
  				}
  			}(),
  			removeListener: function()
  			{
  				var updateListener = function(element, eventName, funct)
  				{
  					if (element.mxListenerList != null)
  					{
  						var listenerCount = element.mxListenerList.length;
  						for (var i = 0; i < listenerCount; i++)
  						{
  							var entry = element.mxListenerList[i];
  							if (entry.f == funct)
  							{
  								element.mxListenerList.splice(i, 1);
  								break;
  							}
  						}
  						if (element.mxListenerList.length == 0)
  						{
  							element.mxListenerList = null;
  						}
  					}
  				};
  				if (window.removeEventListener)
  				{
  					return function(element, eventName, funct)
  					{
  						element.removeEventListener(eventName, funct, false);
  						updateListener(element, eventName, funct);
  					};
  				}
  				else
  				{
  					return function(element, eventName, funct)
  					{
  						element.detachEvent('on' + eventName, funct);
  						updateListener(element, eventName, funct);
  					};
  				}
  			}(),
  			removeAllListeners: function(element)
  			{
  				var list = element.mxListenerList;
  				if (list != null)
  				{
  					while (list.length > 0)
  					{
  						var entry = list[0];
  						mxEvent.removeListener(element, entry.name, entry.f);
  					}
  				}
  			},
  			addGestureListeners: function(node, startListener, moveListener, endListener)
  			{
  				if (startListener != null)
  				{
  					mxEvent.addListener(node, (mxClient.IS_POINTER) ? 'pointerdown' : 'mousedown', startListener);
  				}
  				if (moveListener != null)
  				{
  					mxEvent.addListener(node, (mxClient.IS_POINTER) ? 'pointermove' : 'mousemove', moveListener);
  				}
  				if (endListener != null)
  				{
  					mxEvent.addListener(node, (mxClient.IS_POINTER) ? 'pointerup' : 'mouseup', endListener);
  				}
  				if (!mxClient.IS_POINTER && mxClient.IS_TOUCH)
  				{
  					if (startListener != null)
  					{
  						mxEvent.addListener(node, 'touchstart', startListener);
  					}
  					if (moveListener != null)
  					{
  						mxEvent.addListener(node, 'touchmove', moveListener);
  					}
  					if (endListener != null)
  					{
  						mxEvent.addListener(node, 'touchend', endListener);
  					}
  				}
  			},
  			removeGestureListeners: function(node, startListener, moveListener, endListener)
  			{
  				if (startListener != null)
  				{
  					mxEvent.removeListener(node, (mxClient.IS_POINTER) ? 'pointerdown' : 'mousedown', startListener);
  				}
  				if (moveListener != null)
  				{
  					mxEvent.removeListener(node, (mxClient.IS_POINTER) ? 'pointermove' : 'mousemove', moveListener);
  				}
  				if (endListener != null)
  				{
  					mxEvent.removeListener(node, (mxClient.IS_POINTER) ? 'pointerup' : 'mouseup', endListener);
  				}
  				if (!mxClient.IS_POINTER && mxClient.IS_TOUCH)
  				{
  					if (startListener != null)
  					{
  						mxEvent.removeListener(node, 'touchstart', startListener);
  					}
  					if (moveListener != null)
  					{
  						mxEvent.removeListener(node, 'touchmove', moveListener);
  					}
  					if (endListener != null)
  					{
  						mxEvent.removeListener(node, 'touchend', endListener);
  					}
  				}
  			},
  			redirectMouseEvents: function(node, graph, state, down, move, up, dblClick)
  			{
  				var getState = function(evt)
  				{
  					return (typeof(state) == 'function') ? state(evt) : state;
  				};
  				mxEvent.addGestureListeners(node, function (evt)
  				{
  					if (down != null)
  					{
  						down(evt);
  					}
  					else if (!mxEvent.isConsumed(evt))
  					{
  						graph.fireMouseEvent(mxEvent.MOUSE_DOWN, new mxMouseEvent(evt, getState(evt)));
  					}
  				},
  				function (evt)
  				{
  					if (move != null)
  					{
  						move(evt);
  					}
  					else if (!mxEvent.isConsumed(evt))
  					{
  						graph.fireMouseEvent(mxEvent.MOUSE_MOVE, new mxMouseEvent(evt, getState(evt)));
  					}
  				},
  				function (evt)
  				{
  					if (up != null)
  					{
  						up(evt);
  					}
  					else if (!mxEvent.isConsumed(evt))
  					{
  						graph.fireMouseEvent(mxEvent.MOUSE_UP, new mxMouseEvent(evt, getState(evt)));
  					}
  				});
  				mxEvent.addListener(node, 'dblclick', function (evt)
  				{
  					if (dblClick != null)
  					{
  						dblClick(evt);
  					}
  					else if (!mxEvent.isConsumed(evt))
  					{
  						var tmp = getState(evt);
  						graph.dblClick(evt, (tmp != null) ? tmp.cell : null);
  					}
  				});
  			},
  			release: function(element)
  			{
  				try
  				{
  					if (element != null)
  					{
  						mxEvent.removeAllListeners(element);
  						var children = element.childNodes;
  						if (children != null)
  						{
  					        var childCount = children.length;
  					        for (var i = 0; i < childCount; i += 1)
  					        {
  					        	mxEvent.release(children[i]);
  					        }
  					    }
  					}
  				}
  				catch (e)
  				{
  				}
  			},
  			addMouseWheelListener: function(funct, target)
  			{
  				if (funct != null)
  				{
  					var wheelHandler = function(evt)
  					{
  						if (evt == null)
  						{
  							evt = window.event;
  						}
  						if (evt.ctrlKey)
  						{
  							evt.preventDefault();
  						}
  						-evt.deltaY;
  						if (Math.abs(evt.deltaX) > 0.5 || Math.abs(evt.deltaY) > 0.5)
  						{
  							funct(evt, (evt.deltaY == 0) ?  -evt.deltaX > 0 : -evt.deltaY > 0);
  						}
  					};
  					target = target != null ? target : window;
  					if (mxClient.IS_SF && !mxClient.IS_TOUCH)
  					{
  						var scale = 1;
  						mxEvent.addListener(target, 'gesturestart', function(evt)
  						{
  							mxEvent.consume(evt);
  							scale = 1;
  						});
  						mxEvent.addListener(target, 'gesturechange', function(evt)
  						{
  							mxEvent.consume(evt);
  							var diff = scale - evt.scale;
  							if (Math.abs(diff) > 0.2)
  							{
  								funct(evt, diff < 0, true);
  								scale = evt.scale;
  							}
  						});
  						mxEvent.addListener(target, 'gestureend', function(evt)
  						{
  							mxEvent.consume(evt);
  						});
  					}
  					else
  					{
  						var evtCache = [];
  						var dx0 = 0;
  						var dy0 = 0;
  						mxEvent.addGestureListeners(target, mxUtils.bind(this, function(evt)
  						{
  							if (!mxEvent.isMouseEvent(evt) && evt.pointerId != null)
  							{
  								evtCache.push(evt);
  							}
  						}),
  						mxUtils.bind(this, function(evt)
  						{
  							if (!mxEvent.isMouseEvent(evt) && evtCache.length == 2)
  							{
  								for (var i = 0; i < evtCache.length; i++)
  								{
  									if (evt.pointerId == evtCache[i].pointerId)
  									{
  										evtCache[i] = evt;
  										break;
  									}
  								}
  								var dx = Math.abs(evtCache[0].clientX - evtCache[1].clientX);
  								var dy = Math.abs(evtCache[0].clientY - evtCache[1].clientY);
  								var tx = Math.abs(dx - dx0);
  								var ty = Math.abs(dy - dy0);
  								if (tx > mxEvent.PINCH_THRESHOLD || ty > mxEvent.PINCH_THRESHOLD)
  								{
  									var cx = evtCache[0].clientX + (evtCache[1].clientX - evtCache[0].clientX) / 2;
  									var cy = evtCache[0].clientY + (evtCache[1].clientY - evtCache[0].clientY) / 2;
  									funct(evtCache[0], (tx > ty) ? dx > dx0 : dy > dy0, true, cx, cy);
  									dx0 = dx;
  									dy0 = dy;
  								}
  							}
  						}),
  						mxUtils.bind(this, function(evt)
  						{
  							evtCache = [];
  							dx0 = 0;
  							dy0 = 0;
  						}));
  					}
  					mxEvent.addListener(target, 'wheel', wheelHandler);
  				}
  			},
  			disableContextMenu: function(element)
  			{
  				mxEvent.addListener(element, 'contextmenu', function(evt)
  				{
  					if (evt.preventDefault)
  					{
  						evt.preventDefault();
  					}
  					return false;
  				});
  			},
  			getSource: function(evt)
  			{
  				return (evt.srcElement != null) ? evt.srcElement : evt.target;
  			},
  			isConsumed: function(evt)
  			{
  				return evt.isConsumed != null && evt.isConsumed;
  			},
  			isTouchEvent: function(evt)
  			{
  				return (evt.pointerType != null) ? (evt.pointerType == 'touch' || evt.pointerType ===
  					evt.MSPOINTER_TYPE_TOUCH) : ((evt.mozInputSource != null) ?
  							evt.mozInputSource == 5 : evt.type.indexOf('touch') == 0);
  			},
  			isPenEvent: function(evt)
  			{
  				return (evt.pointerType != null) ? (evt.pointerType == 'pen' || evt.pointerType ===
  					evt.MSPOINTER_TYPE_PEN) : ((evt.mozInputSource != null) ?
  							evt.mozInputSource == 2 : evt.type.indexOf('pen') == 0);
  			},
  			isMultiTouchEvent: function(evt)
  			{
  				return (evt.type != null && evt.type.indexOf('touch') == 0 && evt.touches != null && evt.touches.length > 1);
  			},
  			isMouseEvent: function(evt)
  			{
  				return (evt.pointerType != null) ? (evt.pointerType == 'mouse' || evt.pointerType ===
  					evt.MSPOINTER_TYPE_MOUSE) : ((evt.mozInputSource != null) ?
  						evt.mozInputSource == 1 : evt.type.indexOf('mouse') == 0);
  			},
  			isLeftMouseButton: function(evt)
  			{
  				if ('buttons' in evt && (evt.type == 'mousedown' || evt.type == 'mousemove'))
  				{
  					return evt.buttons == 1;
  				}
  				else if ('which' in evt)
  				{
  			        return evt.which === 1;
  			    }
  				else
  				{
  			        return evt.button === 1;
  			    }
  			},
  			isMiddleMouseButton: function(evt)
  			{
  				if ('which' in evt)
  				{
  			        return evt.which === 2;
  			    }
  				else
  				{
  			        return evt.button === 4;
  			    }
  			},
  			isRightMouseButton: function(evt)
  			{
  				if ('which' in evt)
  				{
  			        return evt.which === 3;
  			    }
  				else
  				{
  			        return evt.button === 2;
  			    }
  			},
  			isPopupTrigger: function(evt)
  			{
  				return mxEvent.isRightMouseButton(evt) || (mxClient.IS_MAC && mxEvent.isControlDown(evt) &&
  					!mxEvent.isShiftDown(evt) && !mxEvent.isMetaDown(evt) && !mxEvent.isAltDown(evt));
  			},
  			isShiftDown: function(evt)
  			{
  				return (evt != null) ? evt.shiftKey : false;
  			},
  			isAltDown: function(evt)
  			{
  				return (evt != null) ? evt.altKey : false;
  			},
  			isControlDown: function(evt)
  			{
  				return (evt != null) ? evt.ctrlKey : false;
  			},
  			isMetaDown: function(evt)
  			{
  				return (evt != null) ? evt.metaKey : false;
  			},
  			getMainEvent: function(e)
  			{
  				if ((e.type == 'touchstart' || e.type == 'touchmove') && e.touches != null && e.touches[0] != null)
  				{
  					e = e.touches[0];
  				}
  				else if (e.type == 'touchend' && e.changedTouches != null && e.changedTouches[0] != null)
  				{
  					e = e.changedTouches[0];
  				}
  				return e;
  			},
  			getClientX: function(e)
  			{
  				return mxEvent.getMainEvent(e).clientX;
  			},
  			getClientY: function(e)
  			{
  				return mxEvent.getMainEvent(e).clientY;
  			},
  			consume: function(evt, preventDefault, stopPropagation)
  			{
  				preventDefault = (preventDefault != null) ? preventDefault : true;
  				stopPropagation = (stopPropagation != null) ? stopPropagation : true;
  				if (preventDefault)
  				{
  					if (evt.preventDefault)
  					{
  						if (stopPropagation)
  						{
  							evt.stopPropagation();
  						}
  						evt.preventDefault();
  					}
  					else if (stopPropagation)
  					{
  						evt.cancelBubble = true;
  					}
  				}
  				evt.isConsumed = true;
  				if (!evt.preventDefault)
  				{
  					evt.returnValue = false;
  				}
  			},
  			LABEL_HANDLE: -1,
  			ROTATION_HANDLE: -2,
  			CUSTOM_HANDLE: -100,
  			VIRTUAL_HANDLE: -1e5,
  			MOUSE_DOWN: 'mouseDown',
  			MOUSE_MOVE: 'mouseMove',
  			MOUSE_UP: 'mouseUp',
  			ACTIVATE: 'activate',
  			RESIZE_START: 'resizeStart',
  			RESIZE: 'resize',
  			RESIZE_END: 'resizeEnd',
  			MOVE_START: 'moveStart',
  			MOVE: 'move',
  			MOVE_END: 'moveEnd',
  			PAN_START: 'panStart',
  			PAN: 'pan',
  			PAN_END: 'panEnd',
  			MINIMIZE: 'minimize',
  			NORMALIZE: 'normalize',
  			MAXIMIZE: 'maximize',
  			HIDE: 'hide',
  			SHOW: 'show',
  			CLOSE: 'close',
  			DESTROY: 'destroy',
  			REFRESH: 'refresh',
  			SIZE: 'size',
  			SELECT: 'select',
  			FIRED: 'fired',
  			FIRE_MOUSE_EVENT: 'fireMouseEvent',
  			GESTURE: 'gesture',
  			TAP_AND_HOLD: 'tapAndHold',
  			GET: 'get',
  			RECEIVE: 'receive',
  			CONNECT: 'connect',
  			DISCONNECT: 'disconnect',
  			SUSPEND: 'suspend',
  			RESUME: 'resume',
  			MARK: 'mark',
  			ROOT: 'root',
  			POST: 'post',
  			OPEN: 'open',
  			SAVE: 'save',
  			BEFORE_ADD_VERTEX: 'beforeAddVertex',
  			ADD_VERTEX: 'addVertex',
  			AFTER_ADD_VERTEX: 'afterAddVertex',
  			DONE: 'done',
  			EXECUTE: 'execute',
  			EXECUTED: 'executed',
  			BEGIN_UPDATE: 'beginUpdate',
  			START_EDIT: 'startEdit',
  			END_UPDATE: 'endUpdate',
  			END_EDIT: 'endEdit',
  			BEFORE_UNDO: 'beforeUndo',
  			UNDO: 'undo',
  			REDO: 'redo',
  			CHANGE: 'change',
  			NOTIFY: 'notify',
  			LAYOUT_CELLS: 'layoutCells',
  			CLICK: 'click',
  			SCALE: 'scale',
  			TRANSLATE: 'translate',
  			SCALE_AND_TRANSLATE: 'scaleAndTranslate',
  			UP: 'up',
  			DOWN: 'down',
  			ADD: 'add',
  			REMOVE: 'remove',
  			CLEAR: 'clear',
  			ADD_CELLS: 'addCells',
  			CELLS_ADDED: 'cellsAdded',
  			MOVE_CELLS: 'moveCells',
  			CELLS_MOVED: 'cellsMoved',
  			RESIZE_CELLS: 'resizeCells',
  			CELLS_RESIZED: 'cellsResized',
  			TOGGLE_CELLS: 'toggleCells',
  			CELLS_TOGGLED: 'cellsToggled',
  			ORDER_CELLS: 'orderCells',
  			CELLS_ORDERED: 'cellsOrdered',
  			REMOVE_CELLS: 'removeCells',
  			CELLS_REMOVED: 'cellsRemoved',
  			GROUP_CELLS: 'groupCells',
  			UNGROUP_CELLS: 'ungroupCells',
  			REMOVE_CELLS_FROM_PARENT: 'removeCellsFromParent',
  			FOLD_CELLS: 'foldCells',
  			CELLS_FOLDED: 'cellsFolded',
  			ALIGN_CELLS: 'alignCells',
  			LABEL_CHANGED: 'labelChanged',
  			CONNECT_CELL: 'connectCell',
  			CELL_CONNECTED: 'cellConnected',
  			SPLIT_EDGE: 'splitEdge',
  			FLIP_EDGE: 'flipEdge',
  			START_EDITING: 'startEditing',
  			EDITING_STARTED: 'editingStarted',
  			EDITING_STOPPED: 'editingStopped',
  			ADD_OVERLAY: 'addOverlay',
  			REMOVE_OVERLAY: 'removeOverlay',
  			UPDATE_CELL_SIZE: 'updateCellSize',
  			ESCAPE: 'escape',
  			DOUBLE_CLICK: 'doubleClick',
  			START: 'start',
  			RESET: 'reset',
  			PINCH_THRESHOLD: 10
  		};
  		__mxOutput.mxEvent = typeof mxEvent !== 'undefined' ? mxEvent : undefined;
  		function mxXmlRequest(url, params, method, async, username, password)
  		{
  			this.url = url;
  			this.params = params;
  			this.method = method || 'POST';
  			this.async = (async != null) ? async : true;
  			this.username = username;
  			this.password = password;
  		}		mxXmlRequest.prototype.url = null;
  		mxXmlRequest.prototype.params = null;
  		mxXmlRequest.prototype.method = null;
  		mxXmlRequest.prototype.async = null;
  		mxXmlRequest.prototype.binary = false;
  		mxXmlRequest.prototype.withCredentials = false;
  		mxXmlRequest.prototype.username = null;
  		mxXmlRequest.prototype.password = null;
  		mxXmlRequest.prototype.request = null;
  		mxXmlRequest.prototype.decodeSimulateValues = false;
  		mxXmlRequest.prototype.isBinary = function()
  		{
  			return this.binary;
  		};
  		mxXmlRequest.prototype.setBinary = function(value)
  		{
  			this.binary = value;
  		};
  		mxXmlRequest.prototype.getText = function()
  		{
  			return this.request.responseText;
  		};
  		mxXmlRequest.prototype.isReady = function()
  		{
  			return this.request.readyState == 4;
  		};
  		mxXmlRequest.prototype.getDocumentElement = function()
  		{
  			var doc = this.getXml();
  			if (doc != null)
  			{
  				return doc.documentElement;
  			}
  			return null;
  		};
  		mxXmlRequest.prototype.getXml = function()
  		{
  			var xml = this.request.responseXML;
  			if (document.documentMode >= 9 || xml == null || xml.documentElement == null)
  			{
  				xml = mxUtils.parseXml(this.request.responseText);
  			}
  			return xml;
  		};
  		mxXmlRequest.prototype.getStatus = function()
  		{
  			return (this.request != null) ? this.request.status : null;
  		};
  		mxXmlRequest.prototype.create = function()
  		{
  			if (window.XMLHttpRequest)
  			{
  				return function()
  				{
  					var req = new XMLHttpRequest();
  					if (this.isBinary() && req.overrideMimeType)
  					{
  						req.overrideMimeType('text/plain; charset=x-user-defined');
  					}
  					return req;
  				};
  			}
  			else if (typeof(ActiveXObject) != 'undefined')
  			{
  				return function()
  				{
  					return new ActiveXObject('Microsoft.XMLHTTP');
  				};
  			}
  		}();
  		mxXmlRequest.prototype.send = function(onload, onerror, timeout, ontimeout)
  		{
  			this.request = this.create();
  			if (this.request != null)
  			{
  				if (onload != null)
  				{
  					this.request.onreadystatechange = mxUtils.bind(this, function()
  					{
  						if (this.isReady())
  						{
  							onload(this);
  							this.request.onreadystatechange = null;
  						}
  					});
  				}
  				this.request.open(this.method, this.url, this.async,
  					this.username, this.password);
  				this.setRequestHeaders(this.request, this.params);
  				if (window.XMLHttpRequest && this.withCredentials)
  				{
  					this.request.withCredentials = 'true';
  				}
  				if (!mxClient.IS_QUIRKS && (document.documentMode == null || document.documentMode > 9) &&
  					window.XMLHttpRequest && timeout != null && ontimeout != null)
  				{
  					this.request.timeout = timeout;
  					this.request.ontimeout = ontimeout;
  				}
  				this.request.send(this.params);
  			}
  		};
  		mxXmlRequest.prototype.setRequestHeaders = function(request, params)
  		{
  			if (params != null)
  			{
  				request.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
  			}
  		};
  		mxXmlRequest.prototype.simulate = function(doc, target)
  		{
  			doc = doc || document;
  			var old = null;
  			if (doc == document)
  			{
  				old = window.onbeforeunload;
  				window.onbeforeunload = null;
  			}
  			var form = doc.createElement('form');
  			form.setAttribute('method', this.method);
  			form.setAttribute('action', this.url);
  			if (target != null)
  			{
  				form.setAttribute('target', target);
  			}
  			form.style.display = 'none';
  			form.style.visibility = 'hidden';
  			var pars = (this.params.indexOf('&') > 0) ?
  				this.params.split('&') :
  				this.params.split();
  			for (var i=0; i<pars.length; i++)
  			{
  				var pos = pars[i].indexOf('=');
  				if (pos > 0)
  				{
  					var name = pars[i].substring(0, pos);
  					var value = pars[i].substring(pos+1);
  					if (this.decodeSimulateValues)
  					{
  						value = decodeURIComponent(value);
  					}
  					var textarea = doc.createElement('textarea');
  					textarea.setAttribute('wrap', 'off');
  					textarea.setAttribute('name', name);
  					mxUtils.write(textarea, value);
  					form.appendChild(textarea);
  				}
  			}
  			doc.body.appendChild(form);
  			form.submit();
  			if (form.parentNode != null)
  			{
  				form.parentNode.removeChild(form);
  			}
  			if (old != null)
  			{
  				window.onbeforeunload = old;
  			}
  		};
  		__mxOutput.mxXmlRequest = typeof mxXmlRequest !== 'undefined' ? mxXmlRequest : undefined;
  		var mxClipboard =
  		{
  			STEPSIZE: 10,
  			insertCount: 1,
  			cells: null,
  			setCells: function(cells)
  			{
  				mxClipboard.cells = cells;
  			},
  			getCells: function()
  			{
  				return mxClipboard.cells;
  			},
  			isEmpty: function()
  			{
  				return mxClipboard.getCells() == null;
  			},
  			cut: function(graph, cells)
  			{
  				cells = mxClipboard.copy(graph, cells);
  				mxClipboard.insertCount = 0;
  				mxClipboard.removeCells(graph, cells);
  				return cells;
  			},
  			removeCells: function(graph, cells)
  			{
  				graph.removeCells(cells);
  			},
  			copy: function(graph, cells)
  			{
  				cells = cells || graph.getSelectionCells();
  				var result = graph.getExportableCells(graph.model.getTopmostCells(cells));
  				mxClipboard.insertCount = 1;
  				mxClipboard.setCells(graph.cloneCells(result));
  				return result;
  			},
  			paste: function(graph)
  			{
  				var cells = null;
  				if (!mxClipboard.isEmpty())
  				{
  					cells = graph.getImportableCells(mxClipboard.getCells());
  					var delta = mxClipboard.insertCount * mxClipboard.STEPSIZE;
  					var parent = graph.getDefaultParent();
  					cells = graph.importCells(cells, delta, delta, parent);
  					mxClipboard.insertCount++;
  					graph.setSelectionCells(cells);
  				}
  				return cells;
  			}
  		};
  		__mxOutput.mxClipboard = typeof mxClipboard !== 'undefined' ? mxClipboard : undefined;
  		function mxWindow(title, content, x, y, width, height, minimizable, movable, replaceNode, style)
  		{
  			if (content != null)
  			{
  				minimizable = (minimizable != null) ? minimizable : true;
  				this.content = content;
  				this.init(x, y, width, height, style);
  				this.installMaximizeHandler();
  				this.installMinimizeHandler();
  				this.installCloseHandler();
  				this.setMinimizable(minimizable);
  				this.setTitle(title);
  				if (movable == null || movable)
  				{
  					this.installMoveHandler();
  				}
  				if (replaceNode != null && replaceNode.parentNode != null)
  				{
  					replaceNode.parentNode.replaceChild(this.div, replaceNode);
  				}
  				else
  				{
  					document.body.appendChild(this.div);
  				}
  			}
  		}		mxWindow.prototype = new mxEventSource();
  		mxWindow.prototype.constructor = mxWindow;
  		mxWindow.prototype.closeImage = mxClient.imageBasePath + '/close.gif';
  		mxWindow.prototype.minimizeImage = mxClient.imageBasePath + '/minimize.gif';
  		mxWindow.prototype.normalizeImage = mxClient.imageBasePath + '/normalize.gif';
  		mxWindow.prototype.maximizeImage = mxClient.imageBasePath + '/maximize.gif';
  		mxWindow.prototype.resizeImage = mxClient.imageBasePath + '/resize.gif';
  		mxWindow.prototype.visible = false;
  		mxWindow.prototype.minimumSize = new mxRectangle(0, 0, 50, 40);
  		mxWindow.prototype.destroyOnClose = true;
  		mxWindow.prototype.contentHeightCorrection = (document.documentMode == 8 || document.documentMode == 7) ? 6 : 2;
  		mxWindow.prototype.title = null;
  		mxWindow.prototype.content = null;
  		mxWindow.prototype.init = function(x, y, width, height, style)
  		{
  			style = (style != null) ? style : 'mxWindow';
  			this.div = document.createElement('div');
  			this.div.className = style;
  			this.div.style.left = x + 'px';
  			this.div.style.top = y + 'px';
  			this.table = document.createElement('table');
  			this.table.className = style;
  			if (mxClient.IS_POINTER)
  			{
  				this.div.style.touchAction = 'none';
  			}
  			if (width != null)
  			{
  				if (!mxClient.IS_QUIRKS)
  				{
  					this.div.style.width = width + 'px';
  				}
  				this.table.style.width = width + 'px';
  			}
  			if (height != null)
  			{
  				if (!mxClient.IS_QUIRKS)
  				{
  					this.div.style.height = height + 'px';
  				}
  				this.table.style.height = height + 'px';
  			}
  			var tbody = document.createElement('tbody');
  			var tr = document.createElement('tr');
  			this.title = document.createElement('td');
  			this.title.className = style + 'Title';
  			this.buttons = document.createElement('div');
  			this.buttons.style.position = 'absolute';
  			this.buttons.style.display = 'inline-block';
  			this.buttons.style.right = '4px';
  			this.buttons.style.top = '5px';
  			this.title.appendChild(this.buttons);
  			tr.appendChild(this.title);
  			tbody.appendChild(tr);
  			tr = document.createElement('tr');
  			this.td = document.createElement('td');
  			this.td.className = style + 'Pane';
  			if (document.documentMode == 7)
  			{
  				this.td.style.height = '100%';
  			}
  			this.contentWrapper = document.createElement('div');
  			this.contentWrapper.className = style + 'Pane';
  			this.contentWrapper.style.width = '100%';
  			this.contentWrapper.appendChild(this.content);
  			if (mxClient.IS_QUIRKS || this.content.nodeName.toUpperCase() != 'DIV')
  			{
  				this.contentWrapper.style.height = '100%';
  			}
  			this.td.appendChild(this.contentWrapper);
  			tr.appendChild(this.td);
  			tbody.appendChild(tr);
  			this.table.appendChild(tbody);
  			this.div.appendChild(this.table);
  			var activator = mxUtils.bind(this, function(evt)
  			{
  				this.activate();
  			});
  			mxEvent.addGestureListeners(this.title, activator);
  			mxEvent.addGestureListeners(this.table, activator);
  			this.hide();
  		};
  		mxWindow.prototype.setTitle = function(title)
  		{
  			var child = this.title.firstChild;
  			while (child != null)
  			{
  				var next = child.nextSibling;
  				if (child.nodeType == mxConstants.NODETYPE_TEXT)
  				{
  					child.parentNode.removeChild(child);
  				}
  				child = next;
  			}
  			mxUtils.write(this.title, title || '');
  			this.title.appendChild(this.buttons);
  		};
  		mxWindow.prototype.setScrollable = function(scrollable)
  		{
  			if (navigator.userAgent == null ||
  				navigator.userAgent.indexOf('Presto/2.5') < 0)
  			{
  				if (scrollable)
  				{
  					this.contentWrapper.style.overflow = 'auto';
  				}
  				else
  				{
  					this.contentWrapper.style.overflow = 'hidden';
  				}
  			}
  		};
  		mxWindow.prototype.activate = function()
  		{
  			if (mxWindow.activeWindow != this)
  			{
  				var style = mxUtils.getCurrentStyle(this.getElement());
  				var index = (style != null) ? style.zIndex : 3;
  				if (mxWindow.activeWindow)
  				{
  					var elt = mxWindow.activeWindow.getElement();
  					if (elt != null && elt.style != null)
  					{
  						elt.style.zIndex = index;
  					}
  				}
  				var previousWindow = mxWindow.activeWindow;
  				this.getElement().style.zIndex = parseInt(index) + 1;
  				mxWindow.activeWindow = this;
  				this.fireEvent(new mxEventObject(mxEvent.ACTIVATE, 'previousWindow', previousWindow));
  			}
  		};
  		mxWindow.prototype.getElement = function()
  		{
  			return this.div;
  		};
  		mxWindow.prototype.fit = function()
  		{
  			mxUtils.fit(this.div);
  		};
  		mxWindow.prototype.isResizable = function()
  		{
  			if (this.resize != null)
  			{
  				return this.resize.style.display != 'none';
  			}
  			return false;
  		};
  		mxWindow.prototype.setResizable = function(resizable)
  		{
  			if (resizable)
  			{
  				if (this.resize == null)
  				{
  					this.resize = document.createElement('img');
  					this.resize.style.position = 'absolute';
  					this.resize.style.bottom = '2px';
  					this.resize.style.right = '2px';
  					this.resize.setAttribute('src', this.resizeImage);
  					this.resize.style.cursor = 'nw-resize';
  					var startX = null;
  					var startY = null;
  					var width = null;
  					var height = null;
  					var start = mxUtils.bind(this, function(evt)
  					{
  						this.activate();
  						startX = mxEvent.getClientX(evt);
  						startY = mxEvent.getClientY(evt);
  						width = this.div.offsetWidth;
  						height = this.div.offsetHeight;
  						mxEvent.addGestureListeners(document, null, dragHandler, dropHandler);
  						this.fireEvent(new mxEventObject(mxEvent.RESIZE_START, 'event', evt));
  						mxEvent.consume(evt);
  					});
  					var dragHandler = mxUtils.bind(this, function(evt)
  					{
  						if (startX != null && startY != null)
  						{
  							var dx = mxEvent.getClientX(evt) - startX;
  							var dy = mxEvent.getClientY(evt) - startY;
  							this.setSize(width + dx, height + dy);
  							this.fireEvent(new mxEventObject(mxEvent.RESIZE, 'event', evt));
  							mxEvent.consume(evt);
  						}
  					});
  					var dropHandler = mxUtils.bind(this, function(evt)
  					{
  						if (startX != null && startY != null)
  						{
  							startX = null;
  							startY = null;
  							mxEvent.removeGestureListeners(document, null, dragHandler, dropHandler);
  							this.fireEvent(new mxEventObject(mxEvent.RESIZE_END, 'event', evt));
  							mxEvent.consume(evt);
  						}
  					});
  					mxEvent.addGestureListeners(this.resize, start, dragHandler, dropHandler);
  					this.div.appendChild(this.resize);
  				}
  				else
  				{
  					this.resize.style.display = 'inline';
  				}
  			}
  			else if (this.resize != null)
  			{
  				this.resize.style.display = 'none';
  			}
  		};
  		mxWindow.prototype.setSize = function(width, height)
  		{
  			width = Math.max(this.minimumSize.width, width);
  			height = Math.max(this.minimumSize.height, height);
  			if (!mxClient.IS_QUIRKS)
  			{
  				this.div.style.width =  width + 'px';
  				this.div.style.height = height + 'px';
  			}
  			this.table.style.width =  width + 'px';
  			this.table.style.height = height + 'px';
  			if (!mxClient.IS_QUIRKS)
  			{
  				this.contentWrapper.style.height = (this.div.offsetHeight -
  					this.title.offsetHeight - this.contentHeightCorrection) + 'px';
  			}
  		};
  		mxWindow.prototype.setMinimizable = function(minimizable)
  		{
  			this.minimize.style.display = (minimizable) ? '' : 'none';
  		};
  		mxWindow.prototype.getMinimumSize = function()
  		{
  			return new mxRectangle(0, 0, 0, this.title.offsetHeight);
  		};
  		mxWindow.prototype.installMinimizeHandler = function()
  		{
  			this.minimize = document.createElement('img');
  			this.minimize.setAttribute('src', this.minimizeImage);
  			this.minimize.setAttribute('title', 'Minimize');
  			this.minimize.style.cursor = 'pointer';
  			this.minimize.style.marginLeft = '2px';
  			this.minimize.style.display = 'none';
  			this.buttons.appendChild(this.minimize);
  			var minimized = false;
  			var maxDisplay = null;
  			var height = null;
  			var funct = mxUtils.bind(this, function(evt)
  			{
  				this.activate();
  				if (!minimized)
  				{
  					minimized = true;
  					this.minimize.setAttribute('src', this.normalizeImage);
  					this.minimize.setAttribute('title', 'Normalize');
  					this.contentWrapper.style.display = 'none';
  					maxDisplay = this.maximize.style.display;
  					this.maximize.style.display = 'none';
  					height = this.table.style.height;
  					var minSize = this.getMinimumSize();
  					if (minSize.height > 0)
  					{
  						if (!mxClient.IS_QUIRKS)
  						{
  							this.div.style.height = minSize.height + 'px';
  						}
  						this.table.style.height = minSize.height + 'px';
  					}
  					if (minSize.width > 0)
  					{
  						if (!mxClient.IS_QUIRKS)
  						{
  							this.div.style.width = minSize.width + 'px';
  						}
  						this.table.style.width = minSize.width + 'px';
  					}
  					if (this.resize != null)
  					{
  						this.resize.style.visibility = 'hidden';
  					}
  					this.fireEvent(new mxEventObject(mxEvent.MINIMIZE, 'event', evt));
  				}
  				else
  				{
  					minimized = false;
  					this.minimize.setAttribute('src', this.minimizeImage);
  					this.minimize.setAttribute('title', 'Minimize');
  					this.contentWrapper.style.display = '';
  					this.maximize.style.display = maxDisplay;
  					if (!mxClient.IS_QUIRKS)
  					{
  						this.div.style.height = height;
  					}
  					this.table.style.height = height;
  					if (this.resize != null)
  					{
  						this.resize.style.visibility = '';
  					}
  					this.fireEvent(new mxEventObject(mxEvent.NORMALIZE, 'event', evt));
  				}
  				mxEvent.consume(evt);
  			});
  			mxEvent.addGestureListeners(this.minimize, funct);
  		};
  		mxWindow.prototype.setMaximizable = function(maximizable)
  		{
  			this.maximize.style.display = (maximizable) ? '' : 'none';
  		};
  		mxWindow.prototype.installMaximizeHandler = function()
  		{
  			this.maximize = document.createElement('img');
  			this.maximize.setAttribute('src', this.maximizeImage);
  			this.maximize.setAttribute('title', 'Maximize');
  			this.maximize.style.cursor = 'default';
  			this.maximize.style.marginLeft = '2px';
  			this.maximize.style.cursor = 'pointer';
  			this.maximize.style.display = 'none';
  			this.buttons.appendChild(this.maximize);
  			var maximized = false;
  			var x = null;
  			var y = null;
  			var height = null;
  			var width = null;
  			var minDisplay = null;
  			var funct = mxUtils.bind(this, function(evt)
  			{
  				this.activate();
  				if (this.maximize.style.display != 'none')
  				{
  					if (!maximized)
  					{
  						maximized = true;
  						this.maximize.setAttribute('src', this.normalizeImage);
  						this.maximize.setAttribute('title', 'Normalize');
  						this.contentWrapper.style.display = '';
  						minDisplay = this.minimize.style.display;
  						this.minimize.style.display = 'none';
  						x = parseInt(this.div.style.left);
  						y = parseInt(this.div.style.top);
  						height = this.table.style.height;
  						width = this.table.style.width;
  						this.div.style.left = '0px';
  						this.div.style.top = '0px';
  						var docHeight = Math.max(document.body.clientHeight || 0, document.documentElement.clientHeight || 0);
  						if (!mxClient.IS_QUIRKS)
  						{
  							this.div.style.width = (document.body.clientWidth - 2) + 'px';
  							this.div.style.height = (docHeight - 2) + 'px';
  						}
  						this.table.style.width = (document.body.clientWidth - 2) + 'px';
  						this.table.style.height = (docHeight - 2) + 'px';
  						if (this.resize != null)
  						{
  							this.resize.style.visibility = 'hidden';
  						}
  						if (!mxClient.IS_QUIRKS)
  						{
  							var style = mxUtils.getCurrentStyle(this.contentWrapper);
  							if (style.overflow == 'auto' || this.resize != null)
  							{
  								this.contentWrapper.style.height = (this.div.offsetHeight -
  									this.title.offsetHeight - this.contentHeightCorrection) + 'px';
  							}
  						}
  						this.fireEvent(new mxEventObject(mxEvent.MAXIMIZE, 'event', evt));
  					}
  					else
  					{
  						maximized = false;
  						this.maximize.setAttribute('src', this.maximizeImage);
  						this.maximize.setAttribute('title', 'Maximize');
  						this.contentWrapper.style.display = '';
  						this.minimize.style.display = minDisplay;
  						this.div.style.left = x+'px';
  						this.div.style.top = y+'px';
  						if (!mxClient.IS_QUIRKS)
  						{
  							this.div.style.height = height;
  							this.div.style.width = width;
  							var style = mxUtils.getCurrentStyle(this.contentWrapper);
  							if (style.overflow == 'auto' || this.resize != null)
  							{
  								this.contentWrapper.style.height = (this.div.offsetHeight -
  									this.title.offsetHeight - this.contentHeightCorrection) + 'px';
  							}
  						}
  						this.table.style.height = height;
  						this.table.style.width = width;
  						if (this.resize != null)
  						{
  							this.resize.style.visibility = '';
  						}
  						this.fireEvent(new mxEventObject(mxEvent.NORMALIZE, 'event', evt));
  					}
  					mxEvent.consume(evt);
  				}
  			});
  			mxEvent.addGestureListeners(this.maximize, funct);
  			mxEvent.addListener(this.title, 'dblclick', funct);
  		};
  		mxWindow.prototype.installMoveHandler = function()
  		{
  			this.title.style.cursor = 'move';
  			mxEvent.addGestureListeners(this.title,
  				mxUtils.bind(this, function(evt)
  				{
  					var startX = mxEvent.getClientX(evt);
  					var startY = mxEvent.getClientY(evt);
  					var x = this.getX();
  					var y = this.getY();
  					var dragHandler = mxUtils.bind(this, function(evt)
  					{
  						var dx = mxEvent.getClientX(evt) - startX;
  						var dy = mxEvent.getClientY(evt) - startY;
  						this.setLocation(x + dx, y + dy);
  						this.fireEvent(new mxEventObject(mxEvent.MOVE, 'event', evt));
  						mxEvent.consume(evt);
  					});
  					var dropHandler = mxUtils.bind(this, function(evt)
  					{
  						mxEvent.removeGestureListeners(document, null, dragHandler, dropHandler);
  						this.fireEvent(new mxEventObject(mxEvent.MOVE_END, 'event', evt));
  						mxEvent.consume(evt);
  					});
  					mxEvent.addGestureListeners(document, null, dragHandler, dropHandler);
  					this.fireEvent(new mxEventObject(mxEvent.MOVE_START, 'event', evt));
  					mxEvent.consume(evt);
  				}));
  			if (mxClient.IS_POINTER)
  			{
  				this.title.style.touchAction = 'none';
  			}
  		};
  		 mxWindow.prototype.setLocation = function(x, y)
  		 {
  			this.div.style.left = x + 'px';
  			this.div.style.top = y + 'px';
  		 };
  		mxWindow.prototype.getX = function()
  		{
  			return parseInt(this.div.style.left);
  		};
  		mxWindow.prototype.getY = function()
  		{
  			return parseInt(this.div.style.top);
  		};
  		mxWindow.prototype.installCloseHandler = function()
  		{
  			this.closeImg = document.createElement('img');
  			this.closeImg.setAttribute('src', this.closeImage);
  			this.closeImg.setAttribute('title', 'Close');
  			this.closeImg.style.marginLeft = '2px';
  			this.closeImg.style.cursor = 'pointer';
  			this.closeImg.style.display = 'none';
  			this.buttons.appendChild(this.closeImg);
  			mxEvent.addGestureListeners(this.closeImg,
  				mxUtils.bind(this, function(evt)
  				{
  					this.fireEvent(new mxEventObject(mxEvent.CLOSE, 'event', evt));
  					if (this.destroyOnClose)
  					{
  						this.destroy();
  					}
  					else
  					{
  						this.setVisible(false);
  					}
  					mxEvent.consume(evt);
  				}));
  		};
  		mxWindow.prototype.setImage = function(image)
  		{
  			this.image = document.createElement('img');
  			this.image.setAttribute('src', image);
  			this.image.setAttribute('align', 'left');
  			this.image.style.marginRight = '4px';
  			this.image.style.marginLeft = '0px';
  			this.image.style.marginTop = '-2px';
  			this.title.insertBefore(this.image, this.title.firstChild);
  		};
  		mxWindow.prototype.setClosable = function(closable)
  		{
  			this.closeImg.style.display = (closable) ? '' : 'none';
  		};
  		mxWindow.prototype.isVisible = function()
  		{
  			if (this.div != null)
  			{
  				return this.div.style.display != 'none';
  			}
  			return false;
  		};
  		mxWindow.prototype.setVisible = function(visible)
  		{
  			if (this.div != null && this.isVisible() != visible)
  			{
  				if (visible)
  				{
  					this.show();
  				}
  				else
  				{
  					this.hide();
  				}
  			}
  		};
  		mxWindow.prototype.show = function()
  		{
  			this.div.style.display = '';
  			this.activate();
  			var style = mxUtils.getCurrentStyle(this.contentWrapper);
  			if (!mxClient.IS_QUIRKS && (style.overflow == 'auto' || this.resize != null) &&
  				this.contentWrapper.style.display != 'none')
  			{
  				this.contentWrapper.style.height = (this.div.offsetHeight -
  						this.title.offsetHeight - this.contentHeightCorrection) + 'px';
  			}
  			this.fireEvent(new mxEventObject(mxEvent.SHOW));
  		};
  		mxWindow.prototype.hide = function()
  		{
  			this.div.style.display = 'none';
  			this.fireEvent(new mxEventObject(mxEvent.HIDE));
  		};
  		mxWindow.prototype.destroy = function()
  		{
  			this.fireEvent(new mxEventObject(mxEvent.DESTROY));
  			if (this.div != null)
  			{
  				mxEvent.release(this.div);
  				this.div.parentNode.removeChild(this.div);
  				this.div = null;
  			}
  			this.title = null;
  			this.content = null;
  			this.contentWrapper = null;
  		};
  		__mxOutput.mxWindow = typeof mxWindow !== 'undefined' ? mxWindow : undefined;
  		function mxForm(className)
  		{
  			this.table = document.createElement('table');
  			this.table.className = className;
  			this.body = document.createElement('tbody');
  			this.table.appendChild(this.body);
  		}		mxForm.prototype.table = null;
  		mxForm.prototype.body = false;
  		mxForm.prototype.getTable = function()
  		{
  			return this.table;
  		};
  		mxForm.prototype.addButtons = function(okFunct, cancelFunct)
  		{
  			var tr = document.createElement('tr');
  			var td = document.createElement('td');
  			tr.appendChild(td);
  			td = document.createElement('td');
  			var button = document.createElement('button');
  			mxUtils.write(button, mxResources.get('ok') || 'OK');
  			td.appendChild(button);
  			mxEvent.addListener(button, 'click', function()
  			{
  				okFunct();
  			});
  			button = document.createElement('button');
  			mxUtils.write(button, mxResources.get('cancel') || 'Cancel');
  			td.appendChild(button);
  			mxEvent.addListener(button, 'click', function()
  			{
  				cancelFunct();
  			});
  			tr.appendChild(td);
  			this.body.appendChild(tr);
  		};
  		mxForm.prototype.addText = function(name, value, type)
  		{
  			var input = document.createElement('input');
  			input.setAttribute('type', type || 'text');
  			input.value = value;
  			return this.addField(name, input);
  		};
  		mxForm.prototype.addCheckbox = function(name, value)
  		{
  			var input = document.createElement('input');
  			input.setAttribute('type', 'checkbox');
  			this.addField(name, input);
  			if (value)
  			{
  				input.checked = true;
  			}
  			return input;
  		};
  		mxForm.prototype.addTextarea = function(name, value, rows)
  		{
  			var input = document.createElement('textarea');
  			if (mxClient.IS_NS)
  			{
  				rows--;
  			}
  			input.setAttribute('rows', rows || 2);
  			input.value = value;
  			return this.addField(name, input);
  		};
  		mxForm.prototype.addCombo = function(name, isMultiSelect, size)
  		{
  			var select = document.createElement('select');
  			if (size != null)
  			{
  				select.setAttribute('size', size);
  			}
  			if (isMultiSelect)
  			{
  				select.setAttribute('multiple', 'true');
  			}
  			return this.addField(name, select);
  		};
  		mxForm.prototype.addOption = function(combo, label, value, isSelected)
  		{
  			var option = document.createElement('option');
  			mxUtils.writeln(option, label);
  			option.setAttribute('value', value);
  			if (isSelected)
  			{
  				option.setAttribute('selected', isSelected);
  			}
  			combo.appendChild(option);
  		};
  		mxForm.prototype.addField = function(name, input)
  		{
  			var tr = document.createElement('tr');
  			var td = document.createElement('td');
  			mxUtils.write(td, name);
  			tr.appendChild(td);
  			td = document.createElement('td');
  			td.appendChild(input);
  			tr.appendChild(td);
  			this.body.appendChild(tr);
  			return input;
  		};
  		__mxOutput.mxForm = typeof mxForm !== 'undefined' ? mxForm : undefined;
  		function mxImage(src, width, height)
  		{
  			this.src = src;
  			this.width = width;
  			this.height = height;
  		}		mxImage.prototype.src = null;
  		mxImage.prototype.width = null;
  		mxImage.prototype.height = null;
  		__mxOutput.mxImage = typeof mxImage !== 'undefined' ? mxImage : undefined;
  		function mxDivResizer(div, container)
  		{
  			if (div.nodeName.toLowerCase() == 'div')
  			{
  				if (container == null)
  				{
  					container = window;
  				}
  				this.div = div;
  				var style = mxUtils.getCurrentStyle(div);
  				if (style != null)
  				{
  					this.resizeWidth = style.width == 'auto';
  					this.resizeHeight = style.height == 'auto';
  				}
  				mxEvent.addListener(container, 'resize',
  					mxUtils.bind(this, function(evt)
  					{
  						if (!this.handlingResize)
  						{
  							this.handlingResize = true;
  							this.resize();
  							this.handlingResize = false;
  						}
  					})
  				);
  				this.resize();
  			}
  		}		mxDivResizer.prototype.resizeWidth = true;
  		mxDivResizer.prototype.resizeHeight = true;
  		mxDivResizer.prototype.handlingResize = false;
  		mxDivResizer.prototype.resize = function()
  		{
  			var w = this.getDocumentWidth();
  			var h = this.getDocumentHeight();
  			var l = parseInt(this.div.style.left);
  			var r = parseInt(this.div.style.right);
  			var t = parseInt(this.div.style.top);
  			var b = parseInt(this.div.style.bottom);
  			if (this.resizeWidth &&
  				!isNaN(l) &&
  				!isNaN(r) &&
  				l >= 0 &&
  				r >= 0 &&
  				w - r - l > 0)
  			{
  				this.div.style.width = (w - r - l)+'px';
  			}
  			if (this.resizeHeight &&
  				!isNaN(t) &&
  				!isNaN(b) &&
  				t >= 0 &&
  				b >= 0 &&
  				h - t - b > 0)
  			{
  				this.div.style.height = (h - t - b)+'px';
  			}
  		};
  		mxDivResizer.prototype.getDocumentWidth = function()
  		{
  			return document.body.clientWidth;
  		};
  		mxDivResizer.prototype.getDocumentHeight = function()
  		{
  			return document.body.clientHeight;
  		};
  		__mxOutput.mxDivResizer = typeof mxDivResizer !== 'undefined' ? mxDivResizer : undefined;
  		function mxDragSource(element, dropHandler)
  		{
  			this.element = element;
  			this.dropHandler = dropHandler;
  			mxEvent.addGestureListeners(element, mxUtils.bind(this, function(evt)
  			{
  				this.mouseDown(evt);
  			}));
  			mxEvent.addListener(element, 'dragstart', function(evt)
  			{
  				mxEvent.consume(evt);
  			});
  			this.eventConsumer = function(sender, evt)
  			{
  				var evtName = evt.getProperty('eventName');
  				var me = evt.getProperty('event');
  				if (evtName != mxEvent.MOUSE_DOWN)
  				{
  					me.consume();
  				}
  			};
  		}		mxDragSource.prototype.element = null;
  		mxDragSource.prototype.dropHandler = null;
  		mxDragSource.prototype.dragOffset = null;
  		mxDragSource.prototype.dragElement = null;
  		mxDragSource.prototype.previewElement = null;
  		mxDragSource.prototype.previewOffset = null;
  		mxDragSource.prototype.enabled = true;
  		mxDragSource.prototype.currentGraph = null;
  		mxDragSource.prototype.currentDropTarget = null;
  		mxDragSource.prototype.currentPoint = null;
  		mxDragSource.prototype.currentGuide = null;
  		mxDragSource.prototype.currentHighlight = null;
  		mxDragSource.prototype.autoscroll = true;
  		mxDragSource.prototype.guidesEnabled = true;
  		mxDragSource.prototype.gridEnabled = true;
  		mxDragSource.prototype.highlightDropTargets = true;
  		mxDragSource.prototype.dragElementZIndex = 100;
  		mxDragSource.prototype.dragElementOpacity = 70;
  		mxDragSource.prototype.checkEventSource = true;
  		mxDragSource.prototype.isEnabled = function()
  		{
  			return this.enabled;
  		};
  		mxDragSource.prototype.setEnabled = function(value)
  		{
  			this.enabled = value;
  		};
  		mxDragSource.prototype.isGuidesEnabled = function()
  		{
  			return this.guidesEnabled;
  		};
  		mxDragSource.prototype.setGuidesEnabled = function(value)
  		{
  			this.guidesEnabled = value;
  		};
  		mxDragSource.prototype.isGridEnabled = function()
  		{
  			return this.gridEnabled;
  		};
  		mxDragSource.prototype.setGridEnabled = function(value)
  		{
  			this.gridEnabled = value;
  		};
  		mxDragSource.prototype.getGraphForEvent = function(evt)
  		{
  			return null;
  		};
  		mxDragSource.prototype.getDropTarget = function(graph, x, y, evt)
  		{
  			return graph.getCellAt(x, y);
  		};
  		mxDragSource.prototype.createDragElement = function(evt)
  		{
  			return this.element.cloneNode(true);
  		};
  		mxDragSource.prototype.createPreviewElement = function(graph)
  		{
  			return null;
  		};
  		mxDragSource.prototype.isActive = function()
  		{
  			return this.mouseMoveHandler != null;
  		};
  		mxDragSource.prototype.reset = function()
  		{
  			if (this.currentGraph != null)
  			{
  				this.dragExit(this.currentGraph);
  				this.currentGraph = null;
  			}
  			this.removeDragElement();
  			this.removeListeners();
  			this.stopDrag();
  		};
  		mxDragSource.prototype.mouseDown = function(evt)
  		{
  			if (this.enabled && !mxEvent.isConsumed(evt) && this.mouseMoveHandler == null)
  			{
  				this.startDrag(evt);
  				this.mouseMoveHandler = mxUtils.bind(this, this.mouseMove);
  				this.mouseUpHandler = mxUtils.bind(this, this.mouseUp);
  				mxEvent.addGestureListeners(document, null, this.mouseMoveHandler, this.mouseUpHandler);
  				if (mxClient.IS_TOUCH && !mxEvent.isMouseEvent(evt))
  				{
  					this.eventSource = mxEvent.getSource(evt);
  					mxEvent.addGestureListeners(this.eventSource, null, this.mouseMoveHandler, this.mouseUpHandler);
  				}
  			}
  		};
  		mxDragSource.prototype.startDrag = function(evt)
  		{
  			this.dragElement = this.createDragElement(evt);
  			this.dragElement.style.position = 'absolute';
  			this.dragElement.style.zIndex = this.dragElementZIndex;
  			mxUtils.setOpacity(this.dragElement, this.dragElementOpacity);
  			if (this.checkEventSource && mxClient.IS_SVG)
  			{
  				this.dragElement.style.pointerEvents = 'none';
  			}
  		};
  		mxDragSource.prototype.stopDrag = function()
  		{
  			this.removeDragElement();
  		};
  		mxDragSource.prototype.removeDragElement = function()
  		{
  			if (this.dragElement != null)
  			{
  				if (this.dragElement.parentNode != null)
  				{
  					this.dragElement.parentNode.removeChild(this.dragElement);
  				}
  				this.dragElement = null;
  			}
  		};
  		mxDragSource.prototype.getElementForEvent = function(evt)
  		{
  			return ((mxEvent.isTouchEvent(evt) || mxEvent.isPenEvent(evt)) ?
  					document.elementFromPoint(mxEvent.getClientX(evt), mxEvent.getClientY(evt)) :
  						mxEvent.getSource(evt));
  		};
  		mxDragSource.prototype.graphContainsEvent = function(graph, evt)
  		{
  			var x = mxEvent.getClientX(evt);
  			var y = mxEvent.getClientY(evt);
  			var offset = mxUtils.getOffset(graph.container);
  			var origin = mxUtils.getScrollOrigin();
  			var elt = this.getElementForEvent(evt);
  			if (this.checkEventSource)
  			{
  				while (elt != null && elt != graph.container)
  				{
  					elt = elt.parentNode;
  				}
  			}
  			return elt != null && x >= offset.x - origin.x && y >= offset.y - origin.y &&
  				x <= offset.x - origin.x + graph.container.offsetWidth &&
  				y <= offset.y - origin.y + graph.container.offsetHeight;
  		};
  		mxDragSource.prototype.mouseMove = function(evt)
  		{
  			var graph = this.getGraphForEvent(evt);
  			if (graph != null && !this.graphContainsEvent(graph, evt))
  			{
  				graph = null;
  			}
  			if (graph != this.currentGraph)
  			{
  				if (this.currentGraph != null)
  				{
  					this.dragExit(this.currentGraph, evt);
  				}
  				this.currentGraph = graph;
  				if (this.currentGraph != null)
  				{
  					this.dragEnter(this.currentGraph, evt);
  				}
  			}
  			if (this.currentGraph != null)
  			{
  				this.dragOver(this.currentGraph, evt);
  			}
  			if (this.dragElement != null && (this.previewElement == null || this.previewElement.style.visibility != 'visible'))
  			{
  				var x = mxEvent.getClientX(evt);
  				var y = mxEvent.getClientY(evt);
  				if (this.dragElement.parentNode == null)
  				{
  					document.body.appendChild(this.dragElement);
  				}
  				this.dragElement.style.visibility = 'visible';
  				if (this.dragOffset != null)
  				{
  					x += this.dragOffset.x;
  					y += this.dragOffset.y;
  				}
  				var offset = mxUtils.getDocumentScrollOrigin(document);
  				this.dragElement.style.left = (x + offset.x) + 'px';
  				this.dragElement.style.top = (y + offset.y) + 'px';
  			}
  			else if (this.dragElement != null)
  			{
  				this.dragElement.style.visibility = 'hidden';
  			}
  			mxEvent.consume(evt);
  		};
  		mxDragSource.prototype.mouseUp = function(evt)
  		{
  			if (this.currentGraph != null)
  			{
  				if (this.currentPoint != null && (this.previewElement == null ||
  					this.previewElement.style.visibility != 'hidden'))
  				{
  					var scale = this.currentGraph.view.scale;
  					var tr = this.currentGraph.view.translate;
  					var x = this.currentPoint.x / scale - tr.x;
  					var y = this.currentPoint.y / scale - tr.y;
  					this.drop(this.currentGraph, evt, this.currentDropTarget, x, y);
  				}
  				this.dragExit(this.currentGraph);
  				this.currentGraph = null;
  			}
  			this.stopDrag();
  			this.removeListeners();
  			mxEvent.consume(evt);
  		};
  		mxDragSource.prototype.removeListeners = function()
  		{
  			if (this.eventSource != null)
  			{
  				mxEvent.removeGestureListeners(this.eventSource, null, this.mouseMoveHandler, this.mouseUpHandler);
  				this.eventSource = null;
  			}
  			mxEvent.removeGestureListeners(document, null, this.mouseMoveHandler, this.mouseUpHandler);
  			this.mouseMoveHandler = null;
  			this.mouseUpHandler = null;
  		};
  		mxDragSource.prototype.dragEnter = function(graph, evt)
  		{
  			graph.isMouseDown = true;
  			graph.isMouseTrigger = mxEvent.isMouseEvent(evt);
  			this.previewElement = this.createPreviewElement(graph);
  			if (this.previewElement != null && this.checkEventSource && mxClient.IS_SVG)
  			{
  				this.previewElement.style.pointerEvents = 'none';
  			}
  			if (this.isGuidesEnabled() && this.previewElement != null)
  			{
  				this.currentGuide = new mxGuide(graph, graph.graphHandler.getGuideStates());
  			}
  			if (this.highlightDropTargets)
  			{
  				this.currentHighlight = new mxCellHighlight(graph, mxConstants.DROP_TARGET_COLOR);
  			}
  			graph.addListener(mxEvent.FIRE_MOUSE_EVENT, this.eventConsumer);
  		};
  		mxDragSource.prototype.dragExit = function(graph, evt)
  		{
  			this.currentDropTarget = null;
  			this.currentPoint = null;
  			graph.isMouseDown = false;
  			graph.removeListener(this.eventConsumer);
  			if (this.previewElement != null)
  			{
  				if (this.previewElement.parentNode != null)
  				{
  					this.previewElement.parentNode.removeChild(this.previewElement);
  				}
  				this.previewElement = null;
  			}
  			if (this.currentGuide != null)
  			{
  				this.currentGuide.destroy();
  				this.currentGuide = null;
  			}
  			if (this.currentHighlight != null)
  			{
  				this.currentHighlight.destroy();
  				this.currentHighlight = null;
  			}
  		};
  		mxDragSource.prototype.dragOver = function(graph, evt)
  		{
  			var offset = mxUtils.getOffset(graph.container);
  			var origin = mxUtils.getScrollOrigin(graph.container);
  			var x = mxEvent.getClientX(evt) - offset.x + origin.x - graph.panDx;
  			var y = mxEvent.getClientY(evt) - offset.y + origin.y - graph.panDy;
  			if (graph.autoScroll && (this.autoscroll == null || this.autoscroll))
  			{
  				graph.scrollPointToVisible(x, y, graph.autoExtend);
  			}
  			if (this.currentHighlight != null && graph.isDropEnabled())
  			{
  				this.currentDropTarget = this.getDropTarget(graph, x, y, evt);
  				var state = graph.getView().getState(this.currentDropTarget);
  				this.currentHighlight.highlight(state);
  			}
  			if (this.previewElement != null)
  			{
  				if (this.previewElement.parentNode == null)
  				{
  					graph.container.appendChild(this.previewElement);
  					this.previewElement.style.zIndex = '3';
  					this.previewElement.style.position = 'absolute';
  				}
  				var gridEnabled = this.isGridEnabled() && graph.isGridEnabledEvent(evt);
  				var hideGuide = true;
  				if (this.currentGuide != null && this.currentGuide.isEnabledForEvent(evt))
  				{
  					var w = parseInt(this.previewElement.style.width);
  					var h = parseInt(this.previewElement.style.height);
  					var bounds = new mxRectangle(0, 0, w, h);
  					var delta = new mxPoint(x, y);
  					delta = this.currentGuide.move(bounds, delta, gridEnabled, true);
  					hideGuide = false;
  					x = delta.x;
  					y = delta.y;
  				}
  				else if (gridEnabled)
  				{
  					var scale = graph.view.scale;
  					var tr = graph.view.translate;
  					var off = graph.gridSize / 2;
  					x = (graph.snap(x / scale - tr.x - off) + tr.x) * scale;
  					y = (graph.snap(y / scale - tr.y - off) + tr.y) * scale;
  				}
  				if (this.currentGuide != null && hideGuide)
  				{
  					this.currentGuide.hide();
  				}
  				if (this.previewOffset != null)
  				{
  					x += this.previewOffset.x;
  					y += this.previewOffset.y;
  				}
  				this.previewElement.style.left = Math.round(x) + 'px';
  				this.previewElement.style.top = Math.round(y) + 'px';
  				this.previewElement.style.visibility = 'visible';
  			}
  			this.currentPoint = new mxPoint(x, y);
  		};
  		mxDragSource.prototype.drop = function(graph, evt, dropTarget, x, y)
  		{
  			this.dropHandler.apply(this, arguments);
  			if (graph.container.style.visibility != 'hidden')
  			{
  				graph.container.focus();
  			}
  		};
  		__mxOutput.mxDragSource = typeof mxDragSource !== 'undefined' ? mxDragSource : undefined;
  		function mxToolbar(container)
  		{
  			this.container = container;
  		}		mxToolbar.prototype = new mxEventSource();
  		mxToolbar.prototype.constructor = mxToolbar;
  		mxToolbar.prototype.container = null;
  		mxToolbar.prototype.enabled = true;
  		mxToolbar.prototype.noReset = false;
  		mxToolbar.prototype.updateDefaultMode = true;
  		mxToolbar.prototype.addItem = function(title, icon, funct, pressedIcon, style, factoryMethod)
  		{
  			var img = document.createElement((icon != null) ? 'img' : 'button');
  			var initialClassName = style || ((factoryMethod != null) ?
  					'mxToolbarMode' : 'mxToolbarItem');
  			img.className = initialClassName;
  			img.setAttribute('src', icon);
  			if (title != null)
  			{
  				if (icon != null)
  				{
  					img.setAttribute('title', title);
  				}
  				else
  				{
  					mxUtils.write(img, title);
  				}
  			}
  			this.container.appendChild(img);
  			if (funct != null)
  			{
  				mxEvent.addListener(img, 'click', funct);
  				if (mxClient.IS_TOUCH)
  				{
  					mxEvent.addListener(img, 'touchend', funct);
  				}
  			}
  			var mouseHandler = mxUtils.bind(this, function(evt)
  			{
  				if (pressedIcon != null)
  				{
  					img.setAttribute('src', icon);
  				}
  				else
  				{
  					img.style.backgroundColor = '';
  				}
  			});
  			mxEvent.addGestureListeners(img, mxUtils.bind(this, function(evt)
  			{
  				if (pressedIcon != null)
  				{
  					img.setAttribute('src', pressedIcon);
  				}
  				else
  				{
  					img.style.backgroundColor = 'gray';
  				}
  				if (factoryMethod != null)
  				{
  					if (this.menu == null)
  					{
  						this.menu = new mxPopupMenu();
  						this.menu.init();
  					}
  					var last = this.currentImg;
  					if (this.menu.isMenuShowing())
  					{
  						this.menu.hideMenu();
  					}
  					if (last != img)
  					{
  						this.currentImg = img;
  						this.menu.factoryMethod = factoryMethod;
  						var point = new mxPoint(
  							img.offsetLeft,
  							img.offsetTop + img.offsetHeight);
  						this.menu.popup(point.x, point.y, null, evt);
  						if (this.menu.isMenuShowing())
  						{
  							img.className = initialClassName + 'Selected';
  							this.menu.hideMenu = function()
  							{
  								mxPopupMenu.prototype.hideMenu.apply(this);
  								img.className = initialClassName;
  								this.currentImg = null;
  							};
  						}
  					}
  				}
  			}), null, mouseHandler);
  			mxEvent.addListener(img, 'mouseout', mouseHandler);
  			return img;
  		};
  		mxToolbar.prototype.addCombo = function(style)
  		{
  			var div = document.createElement('div');
  			div.style.display = 'inline';
  			div.className = 'mxToolbarComboContainer';
  			var select = document.createElement('select');
  			select.className = style || 'mxToolbarCombo';
  			div.appendChild(select);
  			this.container.appendChild(div);
  			return select;
  		};
  		mxToolbar.prototype.addActionCombo = function(title, style)
  		{
  			var select = document.createElement('select');
  			select.className = style || 'mxToolbarCombo';
  			this.addOption(select, title, null);
  			mxEvent.addListener(select, 'change', function(evt)
  			{
  				var value = select.options[select.selectedIndex];
  				select.selectedIndex = 0;
  				if (value.funct != null)
  				{
  					value.funct(evt);
  				}
  			});
  			this.container.appendChild(select);
  			return select;
  		};
  		mxToolbar.prototype.addOption = function(combo, title, value)
  		{
  			var option = document.createElement('option');
  			mxUtils.writeln(option, title);
  			if (typeof(value) == 'function')
  			{
  				option.funct = value;
  			}
  			else
  			{
  				option.setAttribute('value', value);
  			}
  			combo.appendChild(option);
  			return option;
  		};
  		mxToolbar.prototype.addSwitchMode = function(title, icon, funct, pressedIcon, style)
  		{
  			var img = document.createElement('img');
  			img.initialClassName = style || 'mxToolbarMode';
  			img.className = img.initialClassName;
  			img.setAttribute('src', icon);
  			img.altIcon = pressedIcon;
  			if (title != null)
  			{
  				img.setAttribute('title', title);
  			}
  			mxEvent.addListener(img, 'click', mxUtils.bind(this, function(evt)
  			{
  				var tmp = this.selectedMode.altIcon;
  				if (tmp != null)
  				{
  					this.selectedMode.altIcon = this.selectedMode.getAttribute('src');
  					this.selectedMode.setAttribute('src', tmp);
  				}
  				else
  				{
  					this.selectedMode.className = this.selectedMode.initialClassName;
  				}
  				if (this.updateDefaultMode)
  				{
  					this.defaultMode = img;
  				}
  				this.selectedMode = img;
  				var tmp = img.altIcon;
  				if (tmp != null)
  				{
  					img.altIcon = img.getAttribute('src');
  					img.setAttribute('src', tmp);
  				}
  				else
  				{
  					img.className = img.initialClassName+'Selected';
  				}
  				this.fireEvent(new mxEventObject(mxEvent.SELECT));
  				funct();
  			}));
  			this.container.appendChild(img);
  			if (this.defaultMode == null)
  			{
  				this.defaultMode = img;
  				this.selectMode(img);
  				funct();
  			}
  			return img;
  		};
  		mxToolbar.prototype.addMode = function(title, icon, funct, pressedIcon, style, toggle)
  		{
  			toggle = (toggle != null) ? toggle : true;
  			var img = document.createElement((icon != null) ? 'img' : 'button');
  			img.initialClassName = style || 'mxToolbarMode';
  			img.className = img.initialClassName;
  			img.setAttribute('src', icon);
  			img.altIcon = pressedIcon;
  			if (title != null)
  			{
  				img.setAttribute('title', title);
  			}
  			if (this.enabled && toggle)
  			{
  				mxEvent.addListener(img, 'click', mxUtils.bind(this, function(evt)
  				{
  					this.selectMode(img, funct);
  					this.noReset = false;
  				}));
  				mxEvent.addListener(img, 'dblclick', mxUtils.bind(this, function(evt)
  				{
  					this.selectMode(img, funct);
  					this.noReset = true;
  				}));
  				if (this.defaultMode == null)
  				{
  					this.defaultMode = img;
  					this.defaultFunction = funct;
  					this.selectMode(img, funct);
  				}
  			}
  			this.container.appendChild(img);
  			return img;
  		};
  		mxToolbar.prototype.selectMode = function(domNode, funct)
  		{
  			if (this.selectedMode != domNode)
  			{
  				if (this.selectedMode != null)
  				{
  					var tmp = this.selectedMode.altIcon;
  					if (tmp != null)
  					{
  						this.selectedMode.altIcon = this.selectedMode.getAttribute('src');
  						this.selectedMode.setAttribute('src', tmp);
  					}
  					else
  					{
  						this.selectedMode.className = this.selectedMode.initialClassName;
  					}
  				}
  				this.selectedMode = domNode;
  				var tmp = this.selectedMode.altIcon;
  				if (tmp != null)
  				{
  					this.selectedMode.altIcon = this.selectedMode.getAttribute('src');
  					this.selectedMode.setAttribute('src', tmp);
  				}
  				else
  				{
  					this.selectedMode.className = this.selectedMode.initialClassName+'Selected';
  				}
  				this.fireEvent(new mxEventObject(mxEvent.SELECT, "function", funct));
  			}
  		};
  		mxToolbar.prototype.resetMode = function(forced)
  		{
  			if ((forced || !this.noReset) && this.selectedMode != this.defaultMode)
  			{
  				this.selectMode(this.defaultMode, this.defaultFunction);
  			}
  		};
  		mxToolbar.prototype.addSeparator = function(icon)
  		{
  			return this.addItem(null, icon, null);
  		};
  		mxToolbar.prototype.addBreak = function()
  		{
  			mxUtils.br(this.container);
  		};
  		mxToolbar.prototype.addLine = function()
  		{
  			var hr = document.createElement('hr');
  			hr.style.marginRight = '6px';
  			hr.setAttribute('size', '1');
  			this.container.appendChild(hr);
  		};
  		mxToolbar.prototype.destroy = function ()
  		{
  			mxEvent.release(this.container);
  			this.container = null;
  			this.defaultMode = null;
  			this.defaultFunction = null;
  			this.selectedMode = null;
  			if (this.menu != null)
  			{
  				this.menu.destroy();
  			}
  		};
  		__mxOutput.mxToolbar = typeof mxToolbar !== 'undefined' ? mxToolbar : undefined;
  		function mxUndoableEdit(source, significant)
  		{
  			this.source = source;
  			this.changes = [];
  			this.significant = (significant != null) ? significant : true;
  		}		mxUndoableEdit.prototype.source = null;
  		mxUndoableEdit.prototype.changes = null;
  		mxUndoableEdit.prototype.significant = null;
  		mxUndoableEdit.prototype.undone = false;
  		mxUndoableEdit.prototype.redone = false;
  		mxUndoableEdit.prototype.isEmpty = function()
  		{
  			return this.changes.length == 0;
  		};
  		mxUndoableEdit.prototype.isSignificant = function()
  		{
  			return this.significant;
  		};
  		mxUndoableEdit.prototype.add = function(change)
  		{
  			this.changes.push(change);
  		};
  		mxUndoableEdit.prototype.notify = function() { };
  		mxUndoableEdit.prototype.die = function() { };
  		mxUndoableEdit.prototype.undo = function()
  		{
  			if (!this.undone)
  			{
  				this.source.fireEvent(new mxEventObject(mxEvent.START_EDIT));
  				var count = this.changes.length;
  				for (var i = count - 1; i >= 0; i--)
  				{
  					var change = this.changes[i];
  					if (change.execute != null)
  					{
  						change.execute();
  					}
  					else if (change.undo != null)
  					{
  						change.undo();
  					}
  					this.source.fireEvent(new mxEventObject(mxEvent.EXECUTED, 'change', change));
  				}
  				this.undone = true;
  				this.redone = false;
  				this.source.fireEvent(new mxEventObject(mxEvent.END_EDIT));
  			}
  			this.notify();
  		};
  		mxUndoableEdit.prototype.redo = function()
  		{
  			if (!this.redone)
  			{
  				this.source.fireEvent(new mxEventObject(mxEvent.START_EDIT));
  				var count = this.changes.length;
  				for (var i = 0; i < count; i++)
  				{
  					var change = this.changes[i];
  					if (change.execute != null)
  					{
  						change.execute();
  					}
  					else if (change.redo != null)
  					{
  						change.redo();
  					}
  					this.source.fireEvent(new mxEventObject(mxEvent.EXECUTED, 'change', change));
  				}
  				this.undone = false;
  				this.redone = true;
  				this.source.fireEvent(new mxEventObject(mxEvent.END_EDIT));
  			}
  			this.notify();
  		};
  		__mxOutput.mxUndoableEdit = typeof mxUndoableEdit !== 'undefined' ? mxUndoableEdit : undefined;
  		function mxUndoManager(size)
  		{
  			this.size = (size != null) ? size : 100;
  			this.clear();
  		}		mxUndoManager.prototype = new mxEventSource();
  		mxUndoManager.prototype.constructor = mxUndoManager;
  		mxUndoManager.prototype.size = null;
  		mxUndoManager.prototype.history = null;
  		mxUndoManager.prototype.indexOfNextAdd = 0;
  		mxUndoManager.prototype.isEmpty = function()
  		{
  			return this.history.length == 0;
  		};
  		mxUndoManager.prototype.clear = function()
  		{
  			this.history = [];
  			this.indexOfNextAdd = 0;
  			this.fireEvent(new mxEventObject(mxEvent.CLEAR));
  		};
  		mxUndoManager.prototype.canUndo = function()
  		{
  			return this.indexOfNextAdd > 0;
  		};
  		mxUndoManager.prototype.undo = function()
  		{
  		    while (this.indexOfNextAdd > 0)
  		    {
  		        var edit = this.history[--this.indexOfNextAdd];
  		        edit.undo();
  				if (edit.isSignificant())
  		        {
  		        	this.fireEvent(new mxEventObject(mxEvent.UNDO, 'edit', edit));
  		            break;
  		        }
  		    }
  		};
  		mxUndoManager.prototype.canRedo = function()
  		{
  			return this.indexOfNextAdd < this.history.length;
  		};
  		mxUndoManager.prototype.redo = function()
  		{
  		    var n = this.history.length;
  		    while (this.indexOfNextAdd < n)
  		    {
  		        var edit =  this.history[this.indexOfNextAdd++];
  		        edit.redo();
  		        if (edit.isSignificant())
  		        {
  		        	this.fireEvent(new mxEventObject(mxEvent.REDO, 'edit', edit));
  		            break;
  		        }
  		    }
  		};
  		mxUndoManager.prototype.undoableEditHappened = function(undoableEdit)
  		{
  			this.trim();
  			if (this.size > 0 &&
  				this.size == this.history.length)
  			{
  				this.history.shift();
  			}
  			this.history.push(undoableEdit);
  			this.indexOfNextAdd = this.history.length;
  			this.fireEvent(new mxEventObject(mxEvent.ADD, 'edit', undoableEdit));
  		};
  		mxUndoManager.prototype.trim = function()
  		{
  			if (this.history.length > this.indexOfNextAdd)
  			{
  				var edits = this.history.splice(this.indexOfNextAdd,
  					this.history.length - this.indexOfNextAdd);
  				for (var i = 0; i < edits.length; i++)
  				{
  					edits[i].die();
  				}
  			}
  		};
  		__mxOutput.mxUndoManager = typeof mxUndoManager !== 'undefined' ? mxUndoManager : undefined;
  		var mxUrlConverter = function()
  		{
  		};
  		mxUrlConverter.prototype.enabled = true;
  		mxUrlConverter.prototype.baseUrl = null;
  		mxUrlConverter.prototype.baseDomain = null;
  		mxUrlConverter.prototype.updateBaseUrl = function()
  		{
  			this.baseDomain = location.protocol + '//' + location.host;
  			this.baseUrl = this.baseDomain + location.pathname;
  			var tmp = this.baseUrl.lastIndexOf('/');
  			if (tmp > 0)
  			{
  				this.baseUrl = this.baseUrl.substring(0, tmp + 1);
  			}
  		};
  		mxUrlConverter.prototype.isEnabled = function()
  		{
  			return this.enabled;
  		};
  		mxUrlConverter.prototype.setEnabled = function(value)
  		{
  			this.enabled = value;
  		};
  		mxUrlConverter.prototype.getBaseUrl = function()
  		{
  			return this.baseUrl;
  		};
  		mxUrlConverter.prototype.setBaseUrl = function(value)
  		{
  			this.baseUrl = value;
  		};
  		mxUrlConverter.prototype.getBaseDomain = function()
  		{
  			return this.baseDomain;
  		};
  		mxUrlConverter.prototype.setBaseDomain = function(value)
  		{
  			this.baseDomain = value;
  		};
  		mxUrlConverter.prototype.isRelativeUrl = function(url)
  		{
  			return url != null && url.substring(0, 2) != '//' && url.substring(0, 7) != 'http://' &&
  				url.substring(0, 8) != 'https://' && url.substring(0, 10) != 'data:image' &&
  				url.substring(0, 7) != 'file://';
  		};
  		mxUrlConverter.prototype.convert = function(url)
  		{
  			if (this.isEnabled() && this.isRelativeUrl(url))
  			{
  				if (this.getBaseUrl() == null)
  				{
  					this.updateBaseUrl();
  				}
  				if (url.charAt(0) == '/')
  				{
  					url = this.getBaseDomain() + url;
  				}
  				else
  				{
  					url = this.getBaseUrl() + url;
  				}
  			}
  			return url;
  		};
  		__mxOutput.mxUrlConverter = typeof mxUrlConverter !== 'undefined' ? mxUrlConverter : undefined;
  		function mxPanningManager(graph)
  		{
  			this.thread = null;
  			this.active = false;
  			this.tdx = 0;
  			this.tdy = 0;
  			this.t0x = 0;
  			this.t0y = 0;
  			this.dx = 0;
  			this.dy = 0;
  			this.scrollbars = false;
  			this.scrollLeft = 0;
  			this.scrollTop = 0;
  			this.mouseListener =
  			{
  			    mouseDown: function(sender, me) { },
  			    mouseMove: function(sender, me) { },
  			    mouseUp: mxUtils.bind(this, function(sender, me)
  			    {
  			    	if (this.active)
  			    	{
  			    		this.stop();
  			    	}
  			    })
  			};
  			graph.addMouseListener(this.mouseListener);
  			this.mouseUpListener = mxUtils.bind(this, function()
  			{
  			    	if (this.active)
  			    	{
  			    		this.stop();
  			    	}
  			});
  			mxEvent.addListener(document, 'mouseup', this.mouseUpListener);
  			var createThread = mxUtils.bind(this, function()
  			{
  			    	this.scrollbars = mxUtils.hasScrollbars(graph.container);
  			    	this.scrollLeft = graph.container.scrollLeft;
  			    	this.scrollTop = graph.container.scrollTop;
  			    	return window.setInterval(mxUtils.bind(this, function()
  				{
  					this.tdx -= this.dx;
  					this.tdy -= this.dy;
  					if (this.scrollbars)
  					{
  						var left = -graph.container.scrollLeft - Math.ceil(this.dx);
  						var top = -graph.container.scrollTop - Math.ceil(this.dy);
  						graph.panGraph(left, top);
  						graph.panDx = this.scrollLeft - graph.container.scrollLeft;
  						graph.panDy = this.scrollTop - graph.container.scrollTop;
  						graph.fireEvent(new mxEventObject(mxEvent.PAN));
  					}
  					else
  					{
  						graph.panGraph(this.getDx(), this.getDy());
  					}
  				}), this.delay);
  			});
  			this.isActive = function()
  			{
  				return active;
  			};
  			this.getDx = function()
  			{
  				return Math.round(this.tdx);
  			};
  			this.getDy = function()
  			{
  				return Math.round(this.tdy);
  			};
  			this.start = function()
  			{
  				this.t0x = graph.view.translate.x;
  				this.t0y = graph.view.translate.y;
  				this.active = true;
  			};
  			this.panTo = function(x, y, w, h)
  			{
  				if (!this.active)
  				{
  					this.start();
  				}
  		    	this.scrollLeft = graph.container.scrollLeft;
  		    	this.scrollTop = graph.container.scrollTop;
  				w = (w != null) ? w : 0;
  				h = (h != null) ? h : 0;
  				var c = graph.container;
  				this.dx = x + w - c.scrollLeft - c.clientWidth;
  				if (this.dx < 0 && Math.abs(this.dx) < this.border)
  				{
  					this.dx = this.border + this.dx;
  				}
  				else if (this.handleMouseOut)
  				{
  					this.dx = Math.max(this.dx, 0);
  				}
  				else
  				{
  					this.dx = 0;
  				}
  				if (this.dx == 0)
  				{
  					this.dx = x - c.scrollLeft;
  					if (this.dx > 0 && this.dx < this.border)
  					{
  						this.dx = this.dx - this.border;
  					}
  					else if (this.handleMouseOut)
  					{
  						this.dx = Math.min(0, this.dx);
  					}
  					else
  					{
  						this.dx = 0;
  					}
  				}
  				this.dy = y + h - c.scrollTop - c.clientHeight;
  				if (this.dy < 0 && Math.abs(this.dy) < this.border)
  				{
  					this.dy = this.border + this.dy;
  				}
  				else if (this.handleMouseOut)
  				{
  					this.dy = Math.max(this.dy, 0);
  				}
  				else
  				{
  					this.dy = 0;
  				}
  				if (this.dy == 0)
  				{
  					this.dy = y - c.scrollTop;
  					if (this.dy > 0 && this.dy < this.border)
  					{
  						this.dy = this.dy - this.border;
  					}
  					else if (this.handleMouseOut)
  					{
  						this.dy = Math.min(0, this.dy);
  					}
  					else
  					{
  						this.dy = 0;
  					}
  				}
  				if (this.dx != 0 || this.dy != 0)
  				{
  					this.dx *= this.damper;
  					this.dy *= this.damper;
  					if (this.thread == null)
  					{
  						this.thread = createThread();
  					}
  				}
  				else if (this.thread != null)
  				{
  					window.clearInterval(this.thread);
  					this.thread = null;
  				}
  			};
  			this.stop = function()
  			{
  				if (this.active)
  				{
  					this.active = false;
  					if (this.thread != null)
  			    	{
  						window.clearInterval(this.thread);
  						this.thread = null;
  			    	}
  					this.tdx = 0;
  					this.tdy = 0;
  					if (!this.scrollbars)
  					{
  						var px = graph.panDx;
  						var py = graph.panDy;
  				    	if (px != 0 || py != 0)
  				    	{
  				    		graph.panGraph(0, 0);
  					    	graph.view.setTranslate(this.t0x + px / graph.view.scale, this.t0y + py / graph.view.scale);
  				    	}
  					}
  					else
  					{
  						graph.panDx = 0;
  						graph.panDy = 0;
  						graph.fireEvent(new mxEventObject(mxEvent.PAN));
  					}
  				}
  			};
  			this.destroy = function()
  			{
  				graph.removeMouseListener(this.mouseListener);
  				mxEvent.removeListener(document, 'mouseup', this.mouseUpListener);
  			};
  		}		mxPanningManager.prototype.damper = 1/6;
  		mxPanningManager.prototype.delay = 10;
  		mxPanningManager.prototype.handleMouseOut = true;
  		mxPanningManager.prototype.border = 0;
  		__mxOutput.mxPanningManager = typeof mxPanningManager !== 'undefined' ? mxPanningManager : undefined;
  		function mxPopupMenu(factoryMethod)
  		{
  			this.factoryMethod = factoryMethod;
  			if (factoryMethod != null)
  			{
  				this.init();
  			}
  		}		mxPopupMenu.prototype = new mxEventSource();
  		mxPopupMenu.prototype.constructor = mxPopupMenu;
  		mxPopupMenu.prototype.submenuImage = mxClient.imageBasePath + '/submenu.gif';
  		mxPopupMenu.prototype.zIndex = 10006;
  		mxPopupMenu.prototype.factoryMethod = null;
  		mxPopupMenu.prototype.useLeftButtonForPopup = false;
  		mxPopupMenu.prototype.enabled = true;
  		mxPopupMenu.prototype.itemCount = 0;
  		mxPopupMenu.prototype.autoExpand = false;
  		mxPopupMenu.prototype.smartSeparators = false;
  		mxPopupMenu.prototype.labels = true;
  		mxPopupMenu.prototype.init = function()
  		{
  			this.table = document.createElement('table');
  			this.table.className = 'mxPopupMenu';
  			this.tbody = document.createElement('tbody');
  			this.table.appendChild(this.tbody);
  			this.div = document.createElement('div');
  			this.div.className = 'mxPopupMenu';
  			this.div.style.display = 'inline';
  			this.div.style.zIndex = this.zIndex;
  			this.div.appendChild(this.table);
  			mxEvent.disableContextMenu(this.div);
  		};
  		mxPopupMenu.prototype.isEnabled = function()
  		{
  			return this.enabled;
  		};
  		mxPopupMenu.prototype.setEnabled = function(enabled)
  		{
  			this.enabled = enabled;
  		};
  		mxPopupMenu.prototype.isPopupTrigger = function(me)
  		{
  			return me.isPopupTrigger() || (this.useLeftButtonForPopup && mxEvent.isLeftMouseButton(me.getEvent()));
  		};
  		mxPopupMenu.prototype.addItem = function(title, image, funct, parent, iconCls, enabled, active, noHover)
  		{
  			parent = parent || this;
  			this.itemCount++;
  			if (parent.willAddSeparator)
  			{
  				if (parent.containsItems)
  				{
  					this.addSeparator(parent, true);
  				}
  				parent.willAddSeparator = false;
  			}
  			parent.containsItems = true;
  			var tr = document.createElement('tr');
  			tr.className = 'mxPopupMenuItem';
  			var col1 = document.createElement('td');
  			col1.className = 'mxPopupMenuIcon';
  			if (image != null)
  			{
  				var img = document.createElement('img');
  				img.src = image;
  				col1.appendChild(img);
  			}
  			else if (iconCls != null)
  			{
  				var div = document.createElement('div');
  				div.className = iconCls;
  				col1.appendChild(div);
  			}
  			tr.appendChild(col1);
  			if (this.labels)
  			{
  				var col2 = document.createElement('td');
  				col2.className = 'mxPopupMenuItem' +
  					((enabled != null && !enabled) ? ' mxDisabled' : '');
  				mxUtils.write(col2, title);
  				col2.align = 'left';
  				tr.appendChild(col2);
  				var col3 = document.createElement('td');
  				col3.className = 'mxPopupMenuItem' +
  					((enabled != null && !enabled) ? ' mxDisabled' : '');
  				col3.style.paddingRight = '6px';
  				col3.style.textAlign = 'right';
  				tr.appendChild(col3);
  				if (parent.div == null)
  				{
  					this.createSubmenu(parent);
  				}
  			}
  			parent.tbody.appendChild(tr);
  			if (active != false && enabled != false)
  			{
  				var currentSelection = null;
  				mxEvent.addGestureListeners(tr,
  					mxUtils.bind(this, function(evt)
  					{
  						this.eventReceiver = tr;
  						if (parent.activeRow != tr && parent.activeRow != parent)
  						{
  							if (parent.activeRow != null && parent.activeRow.div.parentNode != null)
  							{
  								this.hideSubmenu(parent);
  							}
  							if (tr.div != null)
  							{
  								this.showSubmenu(parent, tr);
  								parent.activeRow = tr;
  							}
  						}
  						if (document.selection != null && (mxClient.IS_QUIRKS || document.documentMode == 8))
  						{
  							currentSelection = document.selection.createRange();
  						}
  						mxEvent.consume(evt);
  					}),
  					mxUtils.bind(this, function(evt)
  					{
  						if (parent.activeRow != tr && parent.activeRow != parent)
  						{
  							if (parent.activeRow != null && parent.activeRow.div.parentNode != null)
  							{
  								this.hideSubmenu(parent);
  							}
  							if (this.autoExpand && tr.div != null)
  							{
  								this.showSubmenu(parent, tr);
  								parent.activeRow = tr;
  							}
  						}
  						if (!noHover)
  						{
  							tr.className = 'mxPopupMenuItemHover';
  						}
  					}),
  					mxUtils.bind(this, function(evt)
  					{
  						if (this.eventReceiver == tr)
  						{
  							if (parent.activeRow != tr)
  							{
  								this.hideMenu();
  							}
  							if (currentSelection != null)
  							{
  								try
  								{
  									currentSelection.select();
  								}
  								catch (e)
  								{
  								}
  								currentSelection = null;
  							}
  							if (funct != null)
  							{
  								funct(evt);
  							}
  						}
  						this.eventReceiver = null;
  						mxEvent.consume(evt);
  					})
  				);
  				if (!noHover)
  				{
  					mxEvent.addListener(tr, 'mouseout',
  						mxUtils.bind(this, function(evt)
  						{
  							tr.className = 'mxPopupMenuItem';
  						})
  					);
  				}
  			}
  			return tr;
  		};
  		mxPopupMenu.prototype.addCheckmark = function(item, img)
  		{
  			var td = item.firstChild.nextSibling;
  			td.style.backgroundImage = 'url(\'' + img + '\')';
  			td.style.backgroundRepeat = 'no-repeat';
  			td.style.backgroundPosition = '2px 50%';
  		};
  		mxPopupMenu.prototype.createSubmenu = function(parent)
  		{
  			parent.table = document.createElement('table');
  			parent.table.className = 'mxPopupMenu';
  			parent.tbody = document.createElement('tbody');
  			parent.table.appendChild(parent.tbody);
  			parent.div = document.createElement('div');
  			parent.div.className = 'mxPopupMenu';
  			parent.div.style.position = 'absolute';
  			parent.div.style.display = 'inline';
  			parent.div.style.zIndex = this.zIndex;
  			parent.div.appendChild(parent.table);
  			var img = document.createElement('img');
  			img.setAttribute('src', this.submenuImage);
  			td = parent.firstChild.nextSibling.nextSibling;
  			td.appendChild(img);
  		};
  		mxPopupMenu.prototype.showSubmenu = function(parent, row)
  		{
  			if (row.div != null)
  			{
  				row.div.style.left = (parent.div.offsetLeft +
  					row.offsetLeft+row.offsetWidth - 1) + 'px';
  				row.div.style.top = (parent.div.offsetTop+row.offsetTop) + 'px';
  				document.body.appendChild(row.div);
  				var left = parseInt(row.div.offsetLeft);
  				var width = parseInt(row.div.offsetWidth);
  				var offset = mxUtils.getDocumentScrollOrigin(document);
  				var b = document.body;
  				var d = document.documentElement;
  				var right = offset.x + (b.clientWidth || d.clientWidth);
  				if (left + width > right)
  				{
  					row.div.style.left = Math.max(0, (parent.div.offsetLeft - width + ((mxClient.IS_IE) ? 6 : -6))) + 'px';
  				}
  				mxUtils.fit(row.div);
  			}
  		};
  		mxPopupMenu.prototype.addSeparator = function(parent, force)
  		{
  			parent = parent || this;
  			if (this.smartSeparators && !force)
  			{
  				parent.willAddSeparator = true;
  			}
  			else if (parent.tbody != null)
  			{
  				parent.willAddSeparator = false;
  				var tr = document.createElement('tr');
  				var col1 = document.createElement('td');
  				col1.className = 'mxPopupMenuIcon';
  				col1.style.padding = '0 0 0 0px';
  				tr.appendChild(col1);
  				var col2 = document.createElement('td');
  				col2.style.padding = '0 0 0 0px';
  				col2.setAttribute('colSpan', '2');
  				var hr = document.createElement('hr');
  				hr.setAttribute('size', '1');
  				col2.appendChild(hr);
  				tr.appendChild(col2);
  				parent.tbody.appendChild(tr);
  			}
  		};
  		mxPopupMenu.prototype.popup = function(x, y, cell, evt)
  		{
  			if (this.div != null && this.tbody != null && this.factoryMethod != null)
  			{
  				this.div.style.left = x + 'px';
  				this.div.style.top = y + 'px';
  				while (this.tbody.firstChild != null)
  				{
  					mxEvent.release(this.tbody.firstChild);
  					this.tbody.removeChild(this.tbody.firstChild);
  				}
  				this.itemCount = 0;
  				this.factoryMethod(this, cell, evt);
  				if (this.itemCount > 0)
  				{
  					this.showMenu();
  					this.fireEvent(new mxEventObject(mxEvent.SHOW));
  				}
  			}
  		};
  		mxPopupMenu.prototype.isMenuShowing = function()
  		{
  			return this.div != null && this.div.parentNode == document.body;
  		};
  		mxPopupMenu.prototype.showMenu = function()
  		{
  			if (document.documentMode >= 9)
  			{
  				this.div.style.filter = 'none';
  			}
  			document.body.appendChild(this.div);
  			mxUtils.fit(this.div);
  		};
  		mxPopupMenu.prototype.hideMenu = function()
  		{
  			if (this.div != null)
  			{
  				if (this.div.parentNode != null)
  				{
  					this.div.parentNode.removeChild(this.div);
  				}
  				this.hideSubmenu(this);
  				this.containsItems = false;
  				this.fireEvent(new mxEventObject(mxEvent.HIDE));
  			}
  		};
  		mxPopupMenu.prototype.hideSubmenu = function(parent)
  		{
  			if (parent.activeRow != null)
  			{
  				this.hideSubmenu(parent.activeRow);
  				if (parent.activeRow.div.parentNode != null)
  				{
  					parent.activeRow.div.parentNode.removeChild(parent.activeRow.div);
  				}
  				parent.activeRow = null;
  			}
  		};
  		mxPopupMenu.prototype.destroy = function()
  		{
  			if (this.div != null)
  			{
  				mxEvent.release(this.div);
  				if (this.div.parentNode != null)
  				{
  					this.div.parentNode.removeChild(this.div);
  				}
  				this.div = null;
  			}
  		};
  		__mxOutput.mxPopupMenu = typeof mxPopupMenu !== 'undefined' ? mxPopupMenu : undefined;
  		function mxAutoSaveManager(graph)
  		{
  			this.changeHandler = mxUtils.bind(this, function(sender, evt)
  			{
  				if (this.isEnabled())
  				{
  					this.graphModelChanged(evt.getProperty('edit').changes);
  				}
  			});
  			this.setGraph(graph);
  		}		mxAutoSaveManager.prototype = new mxEventSource();
  		mxAutoSaveManager.prototype.constructor = mxAutoSaveManager;
  		mxAutoSaveManager.prototype.graph = null;
  		mxAutoSaveManager.prototype.autoSaveDelay = 10;
  		mxAutoSaveManager.prototype.autoSaveThrottle = 2;
  		mxAutoSaveManager.prototype.autoSaveThreshold = 5;
  		mxAutoSaveManager.prototype.ignoredChanges = 0;
  		mxAutoSaveManager.prototype.lastSnapshot = 0;
  		mxAutoSaveManager.prototype.enabled = true;
  		mxAutoSaveManager.prototype.changeHandler = null;
  		mxAutoSaveManager.prototype.isEnabled = function()
  		{
  			return this.enabled;
  		};
  		mxAutoSaveManager.prototype.setEnabled = function(value)
  		{
  			this.enabled = value;
  		};
  		mxAutoSaveManager.prototype.setGraph = function(graph)
  		{
  			if (this.graph != null)
  			{
  				this.graph.getModel().removeListener(this.changeHandler);
  			}
  			this.graph = graph;
  			if (this.graph != null)
  			{
  				this.graph.getModel().addListener(mxEvent.CHANGE, this.changeHandler);
  			}
  		};
  		mxAutoSaveManager.prototype.save = function()
  		{
  		};
  		mxAutoSaveManager.prototype.graphModelChanged = function(changes)
  		{
  			var now = new Date().getTime();
  			var dt = (now - this.lastSnapshot) / 1000;
  			if (dt > this.autoSaveDelay ||
  				(this.ignoredChanges >= this.autoSaveThreshold &&
  				 dt > this.autoSaveThrottle))
  			{
  				this.save();
  				this.reset();
  			}
  			else
  			{
  				this.ignoredChanges++;
  			}
  		};
  		mxAutoSaveManager.prototype.reset = function()
  		{
  			this.lastSnapshot = new Date().getTime();
  			this.ignoredChanges = 0;
  		};
  		mxAutoSaveManager.prototype.destroy = function()
  		{
  			this.setGraph(null);
  		};
  		__mxOutput.mxAutoSaveManager = typeof mxAutoSaveManager !== 'undefined' ? mxAutoSaveManager : undefined;
  		function mxAnimation(delay)
  		{
  			this.delay = (delay != null) ? delay : 20;
  		}		mxAnimation.prototype = new mxEventSource();
  		mxAnimation.prototype.constructor = mxAnimation;
  		mxAnimation.prototype.delay = null;
  		mxAnimation.prototype.thread = null;
  		mxAnimation.prototype.isRunning = function()
  		{
  			return this.thread != null;
  		};
  		mxAnimation.prototype.startAnimation = function()
  		{
  			if (this.thread == null)
  			{
  				this.thread = window.setInterval(mxUtils.bind(this, this.updateAnimation), this.delay);
  			}
  		};
  		mxAnimation.prototype.updateAnimation = function()
  		{
  			this.fireEvent(new mxEventObject(mxEvent.EXECUTE));
  		};
  		mxAnimation.prototype.stopAnimation = function()
  		{
  			if (this.thread != null)
  			{
  				window.clearInterval(this.thread);
  				this.thread = null;
  				this.fireEvent(new mxEventObject(mxEvent.DONE));
  			}
  		};
  		__mxOutput.mxAnimation = typeof mxAnimation !== 'undefined' ? mxAnimation : undefined;
  		function mxMorphing(graph, steps, ease, delay)
  		{
  			mxAnimation.call(this, delay);
  			this.graph = graph;
  			this.steps = (steps != null) ? steps : 6;
  			this.ease = (ease != null) ? ease : 1.5;
  		}		mxMorphing.prototype = new mxAnimation();
  		mxMorphing.prototype.constructor = mxMorphing;
  		mxMorphing.prototype.graph = null;
  		mxMorphing.prototype.steps = null;
  		mxMorphing.prototype.step = 0;
  		mxMorphing.prototype.ease = null;
  		mxMorphing.prototype.cells = null;
  		mxMorphing.prototype.updateAnimation = function()
  		{
  			mxAnimation.prototype.updateAnimation.apply(this, arguments);
  			var move = new mxCellStatePreview(this.graph);
  			if (this.cells != null)
  			{
  				for (var i = 0; i < this.cells.length; i++)
  				{
  					this.animateCell(this.cells[i], move, false);
  				}
  			}
  			else
  			{
  				this.animateCell(this.graph.getModel().getRoot(), move, true);
  			}
  			this.show(move);
  			if (move.isEmpty() || this.step++ >= this.steps)
  			{
  				this.stopAnimation();
  			}
  		};
  		mxMorphing.prototype.show = function(move)
  		{
  			move.show();
  		};
  		mxMorphing.prototype.animateCell = function(cell, move, recurse)
  		{
  			var state = this.graph.getView().getState(cell);
  			var delta = null;
  			if (state != null)
  			{
  				delta = this.getDelta(state);
  				if (this.graph.getModel().isVertex(cell) && (delta.x != 0 || delta.y != 0))
  				{
  					var translate = this.graph.view.getTranslate();
  					var scale = this.graph.view.getScale();
  					delta.x += translate.x * scale;
  					delta.y += translate.y * scale;
  					move.moveState(state, -delta.x / this.ease, -delta.y / this.ease);
  				}
  			}
  			if (recurse && !this.stopRecursion(state, delta))
  			{
  				var childCount = this.graph.getModel().getChildCount(cell);
  				for (var i = 0; i < childCount; i++)
  				{
  					this.animateCell(this.graph.getModel().getChildAt(cell, i), move, recurse);
  				}
  			}
  		};
  		mxMorphing.prototype.stopRecursion = function(state, delta)
  		{
  			return delta != null && (delta.x != 0 || delta.y != 0);
  		};
  		mxMorphing.prototype.getDelta = function(state)
  		{
  			var origin = this.getOriginForCell(state.cell);
  			var translate = this.graph.getView().getTranslate();
  			var scale = this.graph.getView().getScale();
  			var x = state.x / scale - translate.x;
  			var y = state.y / scale - translate.y;
  			return new mxPoint((origin.x - x) * scale, (origin.y - y) * scale);
  		};
  		mxMorphing.prototype.getOriginForCell = function(cell)
  		{
  			var result = null;
  			if (cell != null)
  			{
  				var parent = this.graph.getModel().getParent(cell);
  				var geo = this.graph.getCellGeometry(cell);
  				result = this.getOriginForCell(parent);
  				if (geo != null)
  				{
  					if (geo.relative)
  					{
  						var pgeo = this.graph.getCellGeometry(parent);
  						if (pgeo != null)
  						{
  							result.x += geo.x * pgeo.width;
  							result.y += geo.y * pgeo.height;
  						}
  					}
  					else
  					{
  						result.x += geo.x;
  						result.y += geo.y;
  					}
  				}
  			}
  			if (result == null)
  			{
  				var t = this.graph.view.getTranslate();
  				result = new mxPoint(-t.x, -t.y);
  			}
  			return result;
  		};
  		__mxOutput.mxMorphing = typeof mxMorphing !== 'undefined' ? mxMorphing : undefined;
  		function mxImageBundle(alt)
  		{
  			this.images = [];
  			this.alt = (alt != null) ? alt : false;
  		}		mxImageBundle.prototype.images = null;
  		mxImageBundle.prototype.alt = null;
  		mxImageBundle.prototype.putImage = function(key, value, fallback)
  		{
  			this.images[key] = {value: value, fallback: fallback};
  		};
  		mxImageBundle.prototype.getImage = function(key)
  		{
  			var result = null;
  			if (key != null)
  			{
  				var img = this.images[key];
  				if (img != null)
  				{
  					result = (this.alt) ? img.fallback : img.value;
  				}
  			}
  			return result;
  		};
  		__mxOutput.mxImageBundle = typeof mxImageBundle !== 'undefined' ? mxImageBundle : undefined;
  		function mxImageExport() { }		mxImageExport.prototype.includeOverlays = false;
  		mxImageExport.prototype.drawState = function(state, canvas)
  		{
  			if (state != null)
  			{
  				this.visitStatesRecursive(state, canvas, mxUtils.bind(this, function()
  				{
  					this.drawCellState.apply(this, arguments);
  				}));
  				if (this.includeOverlays)
  				{
  					this.visitStatesRecursive(state, canvas, mxUtils.bind(this, function()
  					{
  						this.drawOverlays.apply(this, arguments);
  					}));
  				}
  			}
  		};
  		mxImageExport.prototype.visitStatesRecursive = function(state, canvas, visitor)
  		{
  			if (state != null)
  			{
  				visitor(state, canvas);
  				var graph = state.view.graph;
  				var childCount = graph.model.getChildCount(state.cell);
  				for (var i = 0; i < childCount; i++)
  				{
  					var childState = graph.view.getState(graph.model.getChildAt(state.cell, i));
  					this.visitStatesRecursive(childState, canvas, visitor);
  				}
  			}
  		};
  		mxImageExport.prototype.getLinkForCellState = function(state, canvas)
  		{
  			return null;
  		};
  		mxImageExport.prototype.drawCellState = function(state, canvas)
  		{
  			var link = this.getLinkForCellState(state, canvas);
  			if (link != null)
  			{
  				canvas.setLink(link);
  			}
  			this.drawShape(state, canvas);
  			this.drawText(state, canvas);
  			if (link != null)
  			{
  				canvas.setLink(null);
  			}
  		};
  		mxImageExport.prototype.drawShape = function(state, canvas)
  		{
  			if (state.shape instanceof mxShape && state.shape.checkBounds())
  			{
  				canvas.save();
  				state.shape.beforePaint(canvas);
  				state.shape.paint(canvas);
  				state.shape.afterPaint(canvas);
  				canvas.restore();
  			}
  		};
  		mxImageExport.prototype.drawText = function(state, canvas)
  		{
  			if (state.text != null && state.text.checkBounds())
  			{
  				canvas.save();
  				state.text.beforePaint(canvas);
  				state.text.paint(canvas);
  				state.text.afterPaint(canvas);
  				canvas.restore();
  			}
  		};
  		mxImageExport.prototype.drawOverlays = function(state, canvas)
  		{
  			if (state.overlays != null)
  			{
  				state.overlays.visit(function(id, shape)
  				{
  					if (shape instanceof mxShape)
  					{
  						shape.paint(canvas);
  					}
  				});
  			}
  		};
  		__mxOutput.mxImageExport = typeof mxImageExport !== 'undefined' ? mxImageExport : undefined;
  		function mxAbstractCanvas2D()
  		{
  			this.converter = this.createUrlConverter();
  			this.reset();
  		}		mxAbstractCanvas2D.prototype.state = null;
  		mxAbstractCanvas2D.prototype.states = null;
  		mxAbstractCanvas2D.prototype.path = null;
  		mxAbstractCanvas2D.prototype.rotateHtml = true;
  		mxAbstractCanvas2D.prototype.lastX = 0;
  		mxAbstractCanvas2D.prototype.lastY = 0;
  		mxAbstractCanvas2D.prototype.moveOp = 'M';
  		mxAbstractCanvas2D.prototype.lineOp = 'L';
  		mxAbstractCanvas2D.prototype.quadOp = 'Q';
  		mxAbstractCanvas2D.prototype.curveOp = 'C';
  		mxAbstractCanvas2D.prototype.closeOp = 'Z';
  		mxAbstractCanvas2D.prototype.pointerEvents = false;
  		mxAbstractCanvas2D.prototype.createUrlConverter = function()
  		{
  			return new mxUrlConverter();
  		};
  		mxAbstractCanvas2D.prototype.reset = function()
  		{
  			this.state = this.createState();
  			this.states = [];
  		};
  		mxAbstractCanvas2D.prototype.createState = function()
  		{
  			return {
  				dx: 0,
  				dy: 0,
  				scale: 1,
  				alpha: 1,
  				fillAlpha: 1,
  				strokeAlpha: 1,
  				fillColor: null,
  				gradientFillAlpha: 1,
  				gradientColor: null,
  				gradientAlpha: 1,
  				gradientDirection: null,
  				strokeColor: null,
  				strokeWidth: 1,
  				dashed: false,
  				dashPattern: '3 3',
  				fixDash: false,
  				lineCap: 'flat',
  				lineJoin: 'miter',
  				miterLimit: 10,
  				fontColor: '#000000',
  				fontBackgroundColor: null,
  				fontBorderColor: null,
  				fontSize: mxConstants.DEFAULT_FONTSIZE,
  				fontFamily: mxConstants.DEFAULT_FONTFAMILY,
  				fontStyle: 0,
  				shadow: false,
  				shadowColor: mxConstants.SHADOWCOLOR,
  				shadowAlpha: mxConstants.SHADOW_OPACITY,
  				shadowDx: mxConstants.SHADOW_OFFSET_X,
  				shadowDy: mxConstants.SHADOW_OFFSET_Y,
  				rotation: 0,
  				rotationCx: 0,
  				rotationCy: 0
  			};
  		};
  		mxAbstractCanvas2D.prototype.format = function(value)
  		{
  			return Math.round(parseFloat(value));
  		};
  		mxAbstractCanvas2D.prototype.addOp = function()
  		{
  			if (this.path != null)
  			{
  				this.path.push(arguments[0]);
  				if (arguments.length > 2)
  				{
  					var s = this.state;
  					for (var i = 2; i < arguments.length; i += 2)
  					{
  						this.lastX = arguments[i - 1];
  						this.lastY = arguments[i];
  						this.path.push(this.format((this.lastX + s.dx) * s.scale));
  						this.path.push(this.format((this.lastY + s.dy) * s.scale));
  					}
  				}
  			}
  		};
  		mxAbstractCanvas2D.prototype.rotatePoint = function(x, y, theta, cx, cy)
  		{
  			var rad = theta * (Math.PI / 180);
  			return mxUtils.getRotatedPoint(new mxPoint(x, y), Math.cos(rad),
  				Math.sin(rad), new mxPoint(cx, cy));
  		};
  		mxAbstractCanvas2D.prototype.save = function()
  		{
  			this.states.push(this.state);
  			this.state = mxUtils.clone(this.state);
  		};
  		mxAbstractCanvas2D.prototype.restore = function()
  		{
  			if (this.states.length > 0)
  			{
  				this.state = this.states.pop();
  			}
  		};
  		mxAbstractCanvas2D.prototype.setLink = function(link)
  		{
  		};
  		mxAbstractCanvas2D.prototype.scale = function(value)
  		{
  			this.state.scale *= value;
  			this.state.strokeWidth *= value;
  		};
  		mxAbstractCanvas2D.prototype.translate = function(dx, dy)
  		{
  			this.state.dx += dx;
  			this.state.dy += dy;
  		};
  		mxAbstractCanvas2D.prototype.rotate = function(theta, flipH, flipV, cx, cy)
  		{
  		};
  		mxAbstractCanvas2D.prototype.setAlpha = function(value)
  		{
  			this.state.alpha = value;
  		};
  		mxAbstractCanvas2D.prototype.setFillAlpha = function(value)
  		{
  			this.state.fillAlpha = value;
  		};
  		mxAbstractCanvas2D.prototype.setStrokeAlpha = function(value)
  		{
  			this.state.strokeAlpha = value;
  		};
  		mxAbstractCanvas2D.prototype.setFillColor = function(value)
  		{
  			if (value == mxConstants.NONE)
  			{
  				value = null;
  			}
  			this.state.fillColor = value;
  			this.state.gradientColor = null;
  		};
  		mxAbstractCanvas2D.prototype.setGradient = function(color1, color2, x, y, w, h, direction, alpha1, alpha2)
  		{
  			var s = this.state;
  			s.fillColor = color1;
  			s.gradientFillAlpha = (alpha1 != null) ? alpha1 : 1;
  			s.gradientColor = color2;
  			s.gradientAlpha = (alpha2 != null) ? alpha2 : 1;
  			s.gradientDirection = direction;
  		};
  		mxAbstractCanvas2D.prototype.setStrokeColor = function(value)
  		{
  			if (value == mxConstants.NONE)
  			{
  				value = null;
  			}
  			this.state.strokeColor = value;
  		};
  		mxAbstractCanvas2D.prototype.setStrokeWidth = function(value)
  		{
  			this.state.strokeWidth = value;
  		};
  		mxAbstractCanvas2D.prototype.setDashed = function(value, fixDash)
  		{
  			this.state.dashed = value;
  			this.state.fixDash = fixDash;
  		};
  		mxAbstractCanvas2D.prototype.setDashPattern = function(value)
  		{
  			this.state.dashPattern = value;
  		};
  		mxAbstractCanvas2D.prototype.setLineCap = function(value)
  		{
  			this.state.lineCap = value;
  		};
  		mxAbstractCanvas2D.prototype.setLineJoin = function(value)
  		{
  			this.state.lineJoin = value;
  		};
  		mxAbstractCanvas2D.prototype.setMiterLimit = function(value)
  		{
  			this.state.miterLimit = value;
  		};
  		mxAbstractCanvas2D.prototype.setFontColor = function(value)
  		{
  			if (value == mxConstants.NONE)
  			{
  				value = null;
  			}
  			this.state.fontColor = value;
  		};
  		mxAbstractCanvas2D.prototype.setFontBackgroundColor = function(value)
  		{
  			if (value == mxConstants.NONE)
  			{
  				value = null;
  			}
  			this.state.fontBackgroundColor = value;
  		};
  		mxAbstractCanvas2D.prototype.setFontBorderColor = function(value)
  		{
  			if (value == mxConstants.NONE)
  			{
  				value = null;
  			}
  			this.state.fontBorderColor = value;
  		};
  		mxAbstractCanvas2D.prototype.setFontSize = function(value)
  		{
  			this.state.fontSize = parseFloat(value);
  		};
  		mxAbstractCanvas2D.prototype.setFontFamily = function(value)
  		{
  			this.state.fontFamily = value;
  		};
  		mxAbstractCanvas2D.prototype.setFontStyle = function(value)
  		{
  			if (value == null)
  			{
  				value = 0;
  			}
  			this.state.fontStyle = value;
  		};
  		mxAbstractCanvas2D.prototype.setShadow = function(enabled)
  		{
  			this.state.shadow = enabled;
  		};
  		mxAbstractCanvas2D.prototype.setShadowColor = function(value)
  		{
  			if (value == mxConstants.NONE)
  			{
  				value = null;
  			}
  			this.state.shadowColor = value;
  		};
  		mxAbstractCanvas2D.prototype.setShadowAlpha = function(value)
  		{
  			this.state.shadowAlpha = value;
  		};
  		mxAbstractCanvas2D.prototype.setShadowOffset = function(dx, dy)
  		{
  			this.state.shadowDx = dx;
  			this.state.shadowDy = dy;
  		};
  		mxAbstractCanvas2D.prototype.begin = function()
  		{
  			this.lastX = 0;
  			this.lastY = 0;
  			this.path = [];
  		};
  		mxAbstractCanvas2D.prototype.moveTo = function(x, y)
  		{
  			this.addOp(this.moveOp, x, y);
  		};
  		mxAbstractCanvas2D.prototype.lineTo = function(x, y)
  		{
  			this.addOp(this.lineOp, x, y);
  		};
  		mxAbstractCanvas2D.prototype.quadTo = function(x1, y1, x2, y2)
  		{
  			this.addOp(this.quadOp, x1, y1, x2, y2);
  		};
  		mxAbstractCanvas2D.prototype.curveTo = function(x1, y1, x2, y2, x3, y3)
  		{
  			this.addOp(this.curveOp, x1, y1, x2, y2, x3, y3);
  		};
  		mxAbstractCanvas2D.prototype.arcTo = function(rx, ry, angle, largeArcFlag, sweepFlag, x, y)
  		{
  			var curves = mxUtils.arcToCurves(this.lastX, this.lastY, rx, ry, angle, largeArcFlag, sweepFlag, x, y);
  			if (curves != null)
  			{
  				for (var i = 0; i < curves.length; i += 6)
  				{
  					this.curveTo(curves[i], curves[i + 1], curves[i + 2],
  						curves[i + 3], curves[i + 4], curves[i + 5]);
  				}
  			}
  		};
  		mxAbstractCanvas2D.prototype.close = function(x1, y1, x2, y2, x3, y3)
  		{
  			this.addOp(this.closeOp);
  		};
  		mxAbstractCanvas2D.prototype.end = function() { };
  		__mxOutput.mxAbstractCanvas2D = typeof mxAbstractCanvas2D !== 'undefined' ? mxAbstractCanvas2D : undefined;
  		function mxXmlCanvas2D(root)
  		{
  			mxAbstractCanvas2D.call(this);
  			this.root = root;
  			this.writeDefaults();
  		}		mxUtils.extend(mxXmlCanvas2D, mxAbstractCanvas2D);
  		mxXmlCanvas2D.prototype.textEnabled = true;
  		mxXmlCanvas2D.prototype.compressed = true;
  		mxXmlCanvas2D.prototype.writeDefaults = function()
  		{
  			var elem;
  			elem = this.createElement('fontfamily');
  			elem.setAttribute('family', mxConstants.DEFAULT_FONTFAMILY);
  			this.root.appendChild(elem);
  			elem = this.createElement('fontsize');
  			elem.setAttribute('size', mxConstants.DEFAULT_FONTSIZE);
  			this.root.appendChild(elem);
  			elem = this.createElement('shadowcolor');
  			elem.setAttribute('color', mxConstants.SHADOWCOLOR);
  			this.root.appendChild(elem);
  			elem = this.createElement('shadowalpha');
  			elem.setAttribute('alpha', mxConstants.SHADOW_OPACITY);
  			this.root.appendChild(elem);
  			elem = this.createElement('shadowoffset');
  			elem.setAttribute('dx', mxConstants.SHADOW_OFFSET_X);
  			elem.setAttribute('dy', mxConstants.SHADOW_OFFSET_Y);
  			this.root.appendChild(elem);
  		};
  		mxXmlCanvas2D.prototype.format = function(value)
  		{
  			return parseFloat(parseFloat(value).toFixed(2));
  		};
  		mxXmlCanvas2D.prototype.createElement = function(name)
  		{
  			return this.root.ownerDocument.createElement(name);
  		};
  		mxXmlCanvas2D.prototype.save = function()
  		{
  			if (this.compressed)
  			{
  				mxAbstractCanvas2D.prototype.save.apply(this, arguments);
  			}
  			this.root.appendChild(this.createElement('save'));
  		};
  		mxXmlCanvas2D.prototype.restore = function()
  		{
  			if (this.compressed)
  			{
  				mxAbstractCanvas2D.prototype.restore.apply(this, arguments);
  			}
  			this.root.appendChild(this.createElement('restore'));
  		};
  		mxXmlCanvas2D.prototype.scale = function(value)
  		{
  		        var elem = this.createElement('scale');
  		        elem.setAttribute('scale', value);
  		        this.root.appendChild(elem);
  		};
  		mxXmlCanvas2D.prototype.translate = function(dx, dy)
  		{
  			var elem = this.createElement('translate');
  			elem.setAttribute('dx', this.format(dx));
  			elem.setAttribute('dy', this.format(dy));
  			this.root.appendChild(elem);
  		};
  		mxXmlCanvas2D.prototype.rotate = function(theta, flipH, flipV, cx, cy)
  		{
  			var elem = this.createElement('rotate');
  			if (theta != 0 || flipH || flipV)
  			{
  				elem.setAttribute('theta', this.format(theta));
  				elem.setAttribute('flipH', (flipH) ? '1' : '0');
  				elem.setAttribute('flipV', (flipV) ? '1' : '0');
  				elem.setAttribute('cx', this.format(cx));
  				elem.setAttribute('cy', this.format(cy));
  				this.root.appendChild(elem);
  			}
  		};
  		mxXmlCanvas2D.prototype.setAlpha = function(value)
  		{
  			if (this.compressed)
  			{
  				if (this.state.alpha == value)
  				{
  					return;
  				}
  				mxAbstractCanvas2D.prototype.setAlpha.apply(this, arguments);
  			}
  			var elem = this.createElement('alpha');
  			elem.setAttribute('alpha', this.format(value));
  			this.root.appendChild(elem);
  		};
  		mxXmlCanvas2D.prototype.setFillAlpha = function(value)
  		{
  			if (this.compressed)
  			{
  				if (this.state.fillAlpha == value)
  				{
  					return;
  				}
  				mxAbstractCanvas2D.prototype.setFillAlpha.apply(this, arguments);
  			}
  			var elem = this.createElement('fillalpha');
  			elem.setAttribute('alpha', this.format(value));
  			this.root.appendChild(elem);
  		};
  		mxXmlCanvas2D.prototype.setStrokeAlpha = function(value)
  		{
  			if (this.compressed)
  			{
  				if (this.state.strokeAlpha == value)
  				{
  					return;
  				}
  				mxAbstractCanvas2D.prototype.setStrokeAlpha.apply(this, arguments);
  			}
  			var elem = this.createElement('strokealpha');
  			elem.setAttribute('alpha', this.format(value));
  			this.root.appendChild(elem);
  		};
  		mxXmlCanvas2D.prototype.setFillColor = function(value)
  		{
  			if (value == mxConstants.NONE)
  			{
  				value = null;
  			}
  			if (this.compressed)
  			{
  				if (this.state.fillColor == value)
  				{
  					return;
  				}
  				mxAbstractCanvas2D.prototype.setFillColor.apply(this, arguments);
  			}
  			var elem = this.createElement('fillcolor');
  			elem.setAttribute('color', (value != null) ? value : mxConstants.NONE);
  			this.root.appendChild(elem);
  		};
  		mxXmlCanvas2D.prototype.setGradient = function(color1, color2, x, y, w, h, direction, alpha1, alpha2)
  		{
  			if (color1 != null && color2 != null)
  			{
  				mxAbstractCanvas2D.prototype.setGradient.apply(this, arguments);
  				var elem = this.createElement('gradient');
  				elem.setAttribute('c1', color1);
  				elem.setAttribute('c2', color2);
  				elem.setAttribute('x', this.format(x));
  				elem.setAttribute('y', this.format(y));
  				elem.setAttribute('w', this.format(w));
  				elem.setAttribute('h', this.format(h));
  				if (direction != null)
  				{
  					elem.setAttribute('direction', direction);
  				}
  				if (alpha1 != null)
  				{
  					elem.setAttribute('alpha1', alpha1);
  				}
  				if (alpha2 != null)
  				{
  					elem.setAttribute('alpha2', alpha2);
  				}
  				this.root.appendChild(elem);
  			}
  		};
  		mxXmlCanvas2D.prototype.setStrokeColor = function(value)
  		{
  			if (value == mxConstants.NONE)
  			{
  				value = null;
  			}
  			if (this.compressed)
  			{
  				if (this.state.strokeColor == value)
  				{
  					return;
  				}
  				mxAbstractCanvas2D.prototype.setStrokeColor.apply(this, arguments);
  			}
  			var elem = this.createElement('strokecolor');
  			elem.setAttribute('color', (value != null) ? value : mxConstants.NONE);
  			this.root.appendChild(elem);
  		};
  		mxXmlCanvas2D.prototype.setStrokeWidth = function(value)
  		{
  			if (this.compressed)
  			{
  				if (this.state.strokeWidth == value)
  				{
  					return;
  				}
  				mxAbstractCanvas2D.prototype.setStrokeWidth.apply(this, arguments);
  			}
  			var elem = this.createElement('strokewidth');
  			elem.setAttribute('width', this.format(value));
  			this.root.appendChild(elem);
  		};
  		mxXmlCanvas2D.prototype.setDashed = function(value, fixDash)
  		{
  			if (this.compressed)
  			{
  				if (this.state.dashed == value)
  				{
  					return;
  				}
  				mxAbstractCanvas2D.prototype.setDashed.apply(this, arguments);
  			}
  			var elem = this.createElement('dashed');
  			elem.setAttribute('dashed', (value) ? '1' : '0');
  			if (fixDash != null)
  			{
  				elem.setAttribute('fixDash', (fixDash) ? '1' : '0');
  			}
  			this.root.appendChild(elem);
  		};
  		mxXmlCanvas2D.prototype.setDashPattern = function(value)
  		{
  			if (this.compressed)
  			{
  				if (this.state.dashPattern == value)
  				{
  					return;
  				}
  				mxAbstractCanvas2D.prototype.setDashPattern.apply(this, arguments);
  			}
  			var elem = this.createElement('dashpattern');
  			elem.setAttribute('pattern', value);
  			this.root.appendChild(elem);
  		};
  		mxXmlCanvas2D.prototype.setLineCap = function(value)
  		{
  			if (this.compressed)
  			{
  				if (this.state.lineCap == value)
  				{
  					return;
  				}
  				mxAbstractCanvas2D.prototype.setLineCap.apply(this, arguments);
  			}
  			var elem = this.createElement('linecap');
  			elem.setAttribute('cap', value);
  			this.root.appendChild(elem);
  		};
  		mxXmlCanvas2D.prototype.setLineJoin = function(value)
  		{
  			if (this.compressed)
  			{
  				if (this.state.lineJoin == value)
  				{
  					return;
  				}
  				mxAbstractCanvas2D.prototype.setLineJoin.apply(this, arguments);
  			}
  			var elem = this.createElement('linejoin');
  			elem.setAttribute('join', value);
  			this.root.appendChild(elem);
  		};
  		mxXmlCanvas2D.prototype.setMiterLimit = function(value)
  		{
  			if (this.compressed)
  			{
  				if (this.state.miterLimit == value)
  				{
  					return;
  				}
  				mxAbstractCanvas2D.prototype.setMiterLimit.apply(this, arguments);
  			}
  			var elem = this.createElement('miterlimit');
  			elem.setAttribute('limit', value);
  			this.root.appendChild(elem);
  		};
  		mxXmlCanvas2D.prototype.setFontColor = function(value)
  		{
  			if (this.textEnabled)
  			{
  				if (value == mxConstants.NONE)
  				{
  					value = null;
  				}
  				if (this.compressed)
  				{
  					if (this.state.fontColor == value)
  					{
  						return;
  					}
  					mxAbstractCanvas2D.prototype.setFontColor.apply(this, arguments);
  				}
  				var elem = this.createElement('fontcolor');
  				elem.setAttribute('color', (value != null) ? value : mxConstants.NONE);
  				this.root.appendChild(elem);
  			}
  		};
  		mxXmlCanvas2D.prototype.setFontBackgroundColor = function(value)
  		{
  			if (this.textEnabled)
  			{
  				if (value == mxConstants.NONE)
  				{
  					value = null;
  				}
  				if (this.compressed)
  				{
  					if (this.state.fontBackgroundColor == value)
  					{
  						return;
  					}
  					mxAbstractCanvas2D.prototype.setFontBackgroundColor.apply(this, arguments);
  				}
  				var elem = this.createElement('fontbackgroundcolor');
  				elem.setAttribute('color', (value != null) ? value : mxConstants.NONE);
  				this.root.appendChild(elem);
  			}
  		};
  		mxXmlCanvas2D.prototype.setFontBorderColor = function(value)
  		{
  			if (this.textEnabled)
  			{
  				if (value == mxConstants.NONE)
  				{
  					value = null;
  				}
  				if (this.compressed)
  				{
  					if (this.state.fontBorderColor == value)
  					{
  						return;
  					}
  					mxAbstractCanvas2D.prototype.setFontBorderColor.apply(this, arguments);
  				}
  				var elem = this.createElement('fontbordercolor');
  				elem.setAttribute('color', (value != null) ? value : mxConstants.NONE);
  				this.root.appendChild(elem);
  			}
  		};
  		mxXmlCanvas2D.prototype.setFontSize = function(value)
  		{
  			if (this.textEnabled)
  			{
  				if (this.compressed)
  				{
  					if (this.state.fontSize == value)
  					{
  						return;
  					}
  					mxAbstractCanvas2D.prototype.setFontSize.apply(this, arguments);
  				}
  				var elem = this.createElement('fontsize');
  				elem.setAttribute('size', value);
  				this.root.appendChild(elem);
  			}
  		};
  		mxXmlCanvas2D.prototype.setFontFamily = function(value)
  		{
  			if (this.textEnabled)
  			{
  				if (this.compressed)
  				{
  					if (this.state.fontFamily == value)
  					{
  						return;
  					}
  					mxAbstractCanvas2D.prototype.setFontFamily.apply(this, arguments);
  				}
  				var elem = this.createElement('fontfamily');
  				elem.setAttribute('family', value);
  				this.root.appendChild(elem);
  			}
  		};
  		mxXmlCanvas2D.prototype.setFontStyle = function(value)
  		{
  			if (this.textEnabled)
  			{
  				if (value == null)
  				{
  					value = 0;
  				}
  				if (this.compressed)
  				{
  					if (this.state.fontStyle == value)
  					{
  						return;
  					}
  					mxAbstractCanvas2D.prototype.setFontStyle.apply(this, arguments);
  				}
  				var elem = this.createElement('fontstyle');
  				elem.setAttribute('style', value);
  				this.root.appendChild(elem);
  			}
  		};
  		mxXmlCanvas2D.prototype.setShadow = function(value)
  		{
  			if (this.compressed)
  			{
  				if (this.state.shadow == value)
  				{
  					return;
  				}
  				mxAbstractCanvas2D.prototype.setShadow.apply(this, arguments);
  			}
  			var elem = this.createElement('shadow');
  			elem.setAttribute('enabled', (value) ? '1' : '0');
  			this.root.appendChild(elem);
  		};
  		mxXmlCanvas2D.prototype.setShadowColor = function(value)
  		{
  			if (this.compressed)
  			{
  				if (value == mxConstants.NONE)
  				{
  					value = null;
  				}
  				if (this.state.shadowColor == value)
  				{
  					return;
  				}
  				mxAbstractCanvas2D.prototype.setShadowColor.apply(this, arguments);
  			}
  			var elem = this.createElement('shadowcolor');
  			elem.setAttribute('color', (value != null) ? value : mxConstants.NONE);
  			this.root.appendChild(elem);
  		};
  		mxXmlCanvas2D.prototype.setShadowAlpha = function(value)
  		{
  			if (this.compressed)
  			{
  				if (this.state.shadowAlpha == value)
  				{
  					return;
  				}
  				mxAbstractCanvas2D.prototype.setShadowAlpha.apply(this, arguments);
  			}
  			var elem = this.createElement('shadowalpha');
  			elem.setAttribute('alpha', value);
  			this.root.appendChild(elem);
  		};
  		mxXmlCanvas2D.prototype.setShadowOffset = function(dx, dy)
  		{
  			if (this.compressed)
  			{
  				if (this.state.shadowDx == dx && this.state.shadowDy == dy)
  				{
  					return;
  				}
  				mxAbstractCanvas2D.prototype.setShadowOffset.apply(this, arguments);
  			}
  			var elem = this.createElement('shadowoffset');
  			elem.setAttribute('dx', dx);
  			elem.setAttribute('dy', dy);
  			this.root.appendChild(elem);
  		};
  		mxXmlCanvas2D.prototype.rect = function(x, y, w, h)
  		{
  			var elem = this.createElement('rect');
  			elem.setAttribute('x', this.format(x));
  			elem.setAttribute('y', this.format(y));
  			elem.setAttribute('w', this.format(w));
  			elem.setAttribute('h', this.format(h));
  			this.root.appendChild(elem);
  		};
  		mxXmlCanvas2D.prototype.roundrect = function(x, y, w, h, dx, dy)
  		{
  			var elem = this.createElement('roundrect');
  			elem.setAttribute('x', this.format(x));
  			elem.setAttribute('y', this.format(y));
  			elem.setAttribute('w', this.format(w));
  			elem.setAttribute('h', this.format(h));
  			elem.setAttribute('dx', this.format(dx));
  			elem.setAttribute('dy', this.format(dy));
  			this.root.appendChild(elem);
  		};
  		mxXmlCanvas2D.prototype.ellipse = function(x, y, w, h)
  		{
  			var elem = this.createElement('ellipse');
  			elem.setAttribute('x', this.format(x));
  			elem.setAttribute('y', this.format(y));
  			elem.setAttribute('w', this.format(w));
  			elem.setAttribute('h', this.format(h));
  			this.root.appendChild(elem);
  		};
  		mxXmlCanvas2D.prototype.image = function(x, y, w, h, src, aspect, flipH, flipV)
  		{
  			src = this.converter.convert(src);
  			var elem = this.createElement('image');
  			elem.setAttribute('x', this.format(x));
  			elem.setAttribute('y', this.format(y));
  			elem.setAttribute('w', this.format(w));
  			elem.setAttribute('h', this.format(h));
  			elem.setAttribute('src', src);
  			elem.setAttribute('aspect', (aspect) ? '1' : '0');
  			elem.setAttribute('flipH', (flipH) ? '1' : '0');
  			elem.setAttribute('flipV', (flipV) ? '1' : '0');
  			this.root.appendChild(elem);
  		};
  		mxXmlCanvas2D.prototype.begin = function()
  		{
  			this.root.appendChild(this.createElement('begin'));
  			this.lastX = 0;
  			this.lastY = 0;
  		};
  		mxXmlCanvas2D.prototype.moveTo = function(x, y)
  		{
  			var elem = this.createElement('move');
  			elem.setAttribute('x', this.format(x));
  			elem.setAttribute('y', this.format(y));
  			this.root.appendChild(elem);
  			this.lastX = x;
  			this.lastY = y;
  		};
  		mxXmlCanvas2D.prototype.lineTo = function(x, y)
  		{
  			var elem = this.createElement('line');
  			elem.setAttribute('x', this.format(x));
  			elem.setAttribute('y', this.format(y));
  			this.root.appendChild(elem);
  			this.lastX = x;
  			this.lastY = y;
  		};
  		mxXmlCanvas2D.prototype.quadTo = function(x1, y1, x2, y2)
  		{
  			var elem = this.createElement('quad');
  			elem.setAttribute('x1', this.format(x1));
  			elem.setAttribute('y1', this.format(y1));
  			elem.setAttribute('x2', this.format(x2));
  			elem.setAttribute('y2', this.format(y2));
  			this.root.appendChild(elem);
  			this.lastX = x2;
  			this.lastY = y2;
  		};
  		mxXmlCanvas2D.prototype.curveTo = function(x1, y1, x2, y2, x3, y3)
  		{
  			var elem = this.createElement('curve');
  			elem.setAttribute('x1', this.format(x1));
  			elem.setAttribute('y1', this.format(y1));
  			elem.setAttribute('x2', this.format(x2));
  			elem.setAttribute('y2', this.format(y2));
  			elem.setAttribute('x3', this.format(x3));
  			elem.setAttribute('y3', this.format(y3));
  			this.root.appendChild(elem);
  			this.lastX = x3;
  			this.lastY = y3;
  		};
  		mxXmlCanvas2D.prototype.close = function()
  		{
  			this.root.appendChild(this.createElement('close'));
  		};
  		mxXmlCanvas2D.prototype.text = function(x, y, w, h, str, align, valign, wrap, format, overflow, clip, rotation, dir)
  		{
  			if (this.textEnabled && str != null)
  			{
  				if (mxUtils.isNode(str))
  				{
  					str = mxUtils.getOuterHtml(str);
  				}
  				var elem = this.createElement('text');
  				elem.setAttribute('x', this.format(x));
  				elem.setAttribute('y', this.format(y));
  				elem.setAttribute('w', this.format(w));
  				elem.setAttribute('h', this.format(h));
  				elem.setAttribute('str', str);
  				if (align != null)
  				{
  					elem.setAttribute('align', align);
  				}
  				if (valign != null)
  				{
  					elem.setAttribute('valign', valign);
  				}
  				elem.setAttribute('wrap', (wrap) ? '1' : '0');
  				if (format == null)
  				{
  					format = '';
  				}
  				elem.setAttribute('format', format);
  				if (overflow != null)
  				{
  					elem.setAttribute('overflow', overflow);
  				}
  				if (clip != null)
  				{
  					elem.setAttribute('clip', (clip) ? '1' : '0');
  				}
  				if (rotation != null)
  				{
  					elem.setAttribute('rotation', rotation);
  				}
  				if (dir != null)
  				{
  					elem.setAttribute('dir', dir);
  				}
  				this.root.appendChild(elem);
  			}
  		};
  		mxXmlCanvas2D.prototype.stroke = function()
  		{
  			this.root.appendChild(this.createElement('stroke'));
  		};
  		mxXmlCanvas2D.prototype.fill = function()
  		{
  			this.root.appendChild(this.createElement('fill'));
  		};
  		mxXmlCanvas2D.prototype.fillAndStroke = function()
  		{
  			this.root.appendChild(this.createElement('fillstroke'));
  		};
  		__mxOutput.mxXmlCanvas2D = typeof mxXmlCanvas2D !== 'undefined' ? mxXmlCanvas2D : undefined;
  		function mxSvgCanvas2D(root, styleEnabled)
  		{
  			mxAbstractCanvas2D.call(this);
  			this.root = root;
  			this.gradients = [];
  			this.defs = null;
  			this.styleEnabled = (styleEnabled != null) ? styleEnabled : false;
  			var svg = null;
  			if (root.ownerDocument != document)
  			{
  				var node = root;
  				while (node != null && node.nodeName != 'svg')
  				{
  					node = node.parentNode;
  				}
  				svg = node;
  			}
  			if (svg != null)
  			{
  				var tmp = svg.getElementsByTagName('defs');
  				if (tmp.length > 0)
  				{
  					this.defs = svg.getElementsByTagName('defs')[0];
  				}
  				if (this.defs == null)
  				{
  					this.defs = this.createElement('defs');
  					if (svg.firstChild != null)
  					{
  						svg.insertBefore(this.defs, svg.firstChild);
  					}
  					else
  					{
  						svg.appendChild(this.defs);
  					}
  				}
  				if (this.styleEnabled)
  				{
  					this.defs.appendChild(this.createStyle());
  				}
  			}
  		}		mxUtils.extend(mxSvgCanvas2D, mxAbstractCanvas2D);
  		(function()
  		{
  			mxSvgCanvas2D.prototype.useDomParser = !mxClient.IS_IE && typeof DOMParser === 'function' && typeof XMLSerializer === 'function';
  			if (mxSvgCanvas2D.prototype.useDomParser)
  			{
  				try
  				{
  					var doc = new DOMParser().parseFromString('test text', 'text/html');
  					mxSvgCanvas2D.prototype.useDomParser = doc != null;
  				}
  				catch (e)
  				{
  					mxSvgCanvas2D.prototype.useDomParser = false;
  				}
  			}
  			mxSvgCanvas2D.prototype.useAbsoluteIds = !mxClient.IS_CHROMEAPP && !mxClient.IS_IE && !mxClient.IS_IE11 &&
  				!mxClient.IS_EDGE && document.getElementsByTagName('base').length > 0;
  		})();
  		mxSvgCanvas2D.prototype.node = null;
  		mxSvgCanvas2D.prototype.matchHtmlAlignment = true;
  		mxSvgCanvas2D.prototype.textEnabled = true;
  		mxSvgCanvas2D.prototype.foEnabled = true;
  		mxSvgCanvas2D.prototype.foAltText = '[Object]';
  		mxSvgCanvas2D.prototype.foOffset = 0;
  		mxSvgCanvas2D.prototype.textOffset = 0;
  		mxSvgCanvas2D.prototype.imageOffset = 0;
  		mxSvgCanvas2D.prototype.strokeTolerance = 0;
  		mxSvgCanvas2D.prototype.minStrokeWidth = 1;
  		mxSvgCanvas2D.prototype.refCount = 0;
  		mxSvgCanvas2D.prototype.lineHeightCorrection = 1;
  		mxSvgCanvas2D.prototype.pointerEventsValue = 'all';
  		mxSvgCanvas2D.prototype.fontMetricsPadding = 10;
  		mxSvgCanvas2D.prototype.cacheOffsetSize = true;
  		mxSvgCanvas2D.prototype.format = function(value)
  		{
  			return parseFloat(parseFloat(value).toFixed(2));
  		};
  		mxSvgCanvas2D.prototype.getBaseUrl = function()
  		{
  			var href = window.location.href;
  			var hash = href.lastIndexOf('#');
  			if (hash > 0)
  			{
  				href = href.substring(0, hash);
  			}
  			return href;
  		};
  		mxSvgCanvas2D.prototype.reset = function()
  		{
  			mxAbstractCanvas2D.prototype.reset.apply(this, arguments);
  			this.gradients = [];
  		};
  		mxSvgCanvas2D.prototype.createStyle = function(x)
  		{
  			var style = this.createElement('style');
  			style.setAttribute('type', 'text/css');
  			mxUtils.write(style, 'svg{font-family:' + mxConstants.DEFAULT_FONTFAMILY +
  					';font-size:' + mxConstants.DEFAULT_FONTSIZE +
  					';fill:none;stroke-miterlimit:10}');
  			return style;
  		};
  		mxSvgCanvas2D.prototype.createElement = function(tagName, namespace)
  		{
  			if (this.root.ownerDocument.createElementNS != null)
  			{
  				return this.root.ownerDocument.createElementNS(namespace || mxConstants.NS_SVG, tagName);
  			}
  			else
  			{
  				var elt = this.root.ownerDocument.createElement(tagName);
  				if (namespace != null)
  				{
  					elt.setAttribute('xmlns', namespace);
  				}
  				return elt;
  			}
  		};
  		mxSvgCanvas2D.prototype.getAlternateText = function(fo, x, y, w, h, str, align, valign, wrap, format, overflow, clip, rotation)
  		{
  			return (str != null) ? this.foAltText : null;
  		};
  		mxSvgCanvas2D.prototype.createAlternateContent = function(fo, x, y, w, h, str, align, valign, wrap, format, overflow, clip, rotation)
  		{
  			var text = this.getAlternateText(fo, x, y, w, h, str, align, valign, wrap, format, overflow, clip, rotation);
  			var s = this.state;
  			if (text != null && s.fontSize > 0)
  			{
  				var dy = (valign == mxConstants.ALIGN_TOP) ? 1 :
  					(valign == mxConstants.ALIGN_BOTTOM) ? 0 : 0.3;
  				var anchor = (align == mxConstants.ALIGN_RIGHT) ? 'end' :
  					(align == mxConstants.ALIGN_LEFT) ? 'start' :
  					'middle';
  				var alt = this.createElement('text');
  				alt.setAttribute('x', Math.round(x + s.dx));
  				alt.setAttribute('y', Math.round(y + s.dy + dy * s.fontSize));
  				alt.setAttribute('fill', s.fontColor || 'black');
  				alt.setAttribute('font-family', s.fontFamily);
  				alt.setAttribute('font-size', Math.round(s.fontSize) + 'px');
  				if (anchor != 'start')
  				{
  					alt.setAttribute('text-anchor', anchor);
  				}
  				if ((s.fontStyle & mxConstants.FONT_BOLD) == mxConstants.FONT_BOLD)
  				{
  					alt.setAttribute('font-weight', 'bold');
  				}
  				if ((s.fontStyle & mxConstants.FONT_ITALIC) == mxConstants.FONT_ITALIC)
  				{
  					alt.setAttribute('font-style', 'italic');
  				}
  				var txtDecor = [];
  				if ((s.fontStyle & mxConstants.FONT_UNDERLINE) == mxConstants.FONT_UNDERLINE)
  				{
  					txtDecor.push('underline');
  				}
  				if ((s.fontStyle & mxConstants.FONT_STRIKETHROUGH) == mxConstants.FONT_STRIKETHROUGH)
  				{
  					txtDecor.push('line-through');
  				}
  				if (txtDecor.length > 0)
  				{
  					alt.setAttribute('text-decoration', txtDecor.join(' '));
  				}
  				mxUtils.write(alt, text);
  				return alt;
  			}
  			else
  			{
  				return null;
  			}
  		};
  		mxSvgCanvas2D.prototype.createGradientId = function(start, end, alpha1, alpha2, direction)
  		{
  			if (start.charAt(0) == '#')
  			{
  				start = start.substring(1);
  			}
  			if (end.charAt(0) == '#')
  			{
  				end = end.substring(1);
  			}
  			start = start.toLowerCase() + '-' + alpha1;
  			end = end.toLowerCase() + '-' + alpha2;
  			var dir = null;
  			if (direction == null || direction == mxConstants.DIRECTION_SOUTH)
  			{
  				dir = 's';
  			}
  			else if (direction == mxConstants.DIRECTION_EAST)
  			{
  				dir = 'e';
  			}
  			else
  			{
  				var tmp = start;
  				start = end;
  				end = tmp;
  				if (direction == mxConstants.DIRECTION_NORTH)
  				{
  					dir = 's';
  				}
  				else if (direction == mxConstants.DIRECTION_WEST)
  				{
  					dir = 'e';
  				}
  			}
  			return 'mx-gradient-' + start + '-' + end + '-' + dir;
  		};
  		mxSvgCanvas2D.prototype.getSvgGradient = function(start, end, alpha1, alpha2, direction)
  		{
  			var id = this.createGradientId(start, end, alpha1, alpha2, direction);
  			var gradient = this.gradients[id];
  			if (gradient == null)
  			{
  				var svg = this.root.ownerSVGElement;
  				var counter = 0;
  				var tmpId = id + '-' + counter;
  				if (svg != null)
  				{
  					gradient = svg.ownerDocument.getElementById(tmpId);
  					while (gradient != null && gradient.ownerSVGElement != svg)
  					{
  						tmpId = id + '-' + counter++;
  						gradient = svg.ownerDocument.getElementById(tmpId);
  					}
  				}
  				else
  				{
  					tmpId = 'id' + (++this.refCount);
  				}
  				if (gradient == null)
  				{
  					gradient = this.createSvgGradient(start, end, alpha1, alpha2, direction);
  					gradient.setAttribute('id', tmpId);
  					if (this.defs != null)
  					{
  						this.defs.appendChild(gradient);
  					}
  					else
  					{
  						svg.appendChild(gradient);
  					}
  				}
  				this.gradients[id] = gradient;
  			}
  			return gradient.getAttribute('id');
  		};
  		mxSvgCanvas2D.prototype.createSvgGradient = function(start, end, alpha1, alpha2, direction)
  		{
  			var gradient = this.createElement('linearGradient');
  			gradient.setAttribute('x1', '0%');
  			gradient.setAttribute('y1', '0%');
  			gradient.setAttribute('x2', '0%');
  			gradient.setAttribute('y2', '0%');
  			if (direction == null || direction == mxConstants.DIRECTION_SOUTH)
  			{
  				gradient.setAttribute('y2', '100%');
  			}
  			else if (direction == mxConstants.DIRECTION_EAST)
  			{
  				gradient.setAttribute('x2', '100%');
  			}
  			else if (direction == mxConstants.DIRECTION_NORTH)
  			{
  				gradient.setAttribute('y1', '100%');
  			}
  			else if (direction == mxConstants.DIRECTION_WEST)
  			{
  				gradient.setAttribute('x1', '100%');
  			}
  			var op = (alpha1 < 1) ? ';stop-opacity:' + alpha1 : '';
  			var stop = this.createElement('stop');
  			stop.setAttribute('offset', '0%');
  			stop.setAttribute('style', 'stop-color:' + start + op);
  			gradient.appendChild(stop);
  			op = (alpha2 < 1) ? ';stop-opacity:' + alpha2 : '';
  			stop = this.createElement('stop');
  			stop.setAttribute('offset', '100%');
  			stop.setAttribute('style', 'stop-color:' + end + op);
  			gradient.appendChild(stop);
  			return gradient;
  		};
  		mxSvgCanvas2D.prototype.addNode = function(filled, stroked)
  		{
  			var node = this.node;
  			var s = this.state;
  			if (node != null)
  			{
  				if (node.nodeName == 'path')
  				{
  					if (this.path != null && this.path.length > 0)
  					{
  						node.setAttribute('d', this.path.join(' '));
  					}
  					else
  					{
  						return;
  					}
  				}
  				if (filled && s.fillColor != null)
  				{
  					this.updateFill();
  				}
  				else if (!this.styleEnabled)
  				{
  					if (node.nodeName == 'ellipse' && mxClient.IS_FF)
  					{
  						node.setAttribute('fill', 'transparent');
  					}
  					else
  					{
  						node.setAttribute('fill', 'none');
  					}
  					filled = false;
  				}
  				if (stroked && s.strokeColor != null)
  				{
  					this.updateStroke();
  				}
  				else if (!this.styleEnabled)
  				{
  					node.setAttribute('stroke', 'none');
  				}
  				if (s.transform != null && s.transform.length > 0)
  				{
  					node.setAttribute('transform', s.transform);
  				}
  				if (s.shadow)
  				{
  					this.root.appendChild(this.createShadow(node));
  				}
  				if (this.strokeTolerance > 0 && !filled)
  				{
  					this.root.appendChild(this.createTolerance(node));
  				}
  				if (this.pointerEvents)
  				{
  					node.setAttribute('pointer-events', this.pointerEventsValue);
  				}
  				else if (!this.pointerEvents && this.originalRoot == null)
  				{
  					node.setAttribute('pointer-events', 'none');
  				}
  				if ((node.nodeName != 'rect' && node.nodeName != 'path' && node.nodeName != 'ellipse') ||
  					(node.getAttribute('fill') != 'none' && node.getAttribute('fill') != 'transparent') ||
  					node.getAttribute('stroke') != 'none' || node.getAttribute('pointer-events') != 'none')
  				{
  					this.root.appendChild(node);
  				}
  				this.node = null;
  			}
  		};
  		mxSvgCanvas2D.prototype.updateFill = function()
  		{
  			var s = this.state;
  			if (s.alpha < 1 || s.fillAlpha < 1)
  			{
  				this.node.setAttribute('fill-opacity', s.alpha * s.fillAlpha);
  			}
  			if (s.fillColor != null)
  			{
  				if (s.gradientColor != null)
  				{
  					var id = this.getSvgGradient(String(s.fillColor), String(s.gradientColor),
  						s.gradientFillAlpha, s.gradientAlpha, s.gradientDirection);
  					if (this.root.ownerDocument == document && this.useAbsoluteIds)
  					{
  						var base = this.getBaseUrl().replace(/([\(\)])/g, '\\$1');
  						this.node.setAttribute('fill', 'url(' + base + '#' + id + ')');
  					}
  					else
  					{
  						this.node.setAttribute('fill', 'url(#' + id + ')');
  					}
  				}
  				else
  				{
  					this.node.setAttribute('fill', String(s.fillColor).toLowerCase());
  				}
  			}
  		};
  		mxSvgCanvas2D.prototype.getCurrentStrokeWidth = function()
  		{
  			return Math.max(this.minStrokeWidth, Math.max(0.01, this.format(this.state.strokeWidth * this.state.scale)));
  		};
  		mxSvgCanvas2D.prototype.updateStroke = function()
  		{
  			var s = this.state;
  			this.node.setAttribute('stroke', String(s.strokeColor).toLowerCase());
  			if (s.alpha < 1 || s.strokeAlpha < 1)
  			{
  				this.node.setAttribute('stroke-opacity', s.alpha * s.strokeAlpha);
  			}
  			var sw = this.getCurrentStrokeWidth();
  			if (sw != 1)
  			{
  				this.node.setAttribute('stroke-width', sw);
  			}
  			if (this.node.nodeName == 'path')
  			{
  				this.updateStrokeAttributes();
  			}
  			if (s.dashed)
  			{
  				this.node.setAttribute('stroke-dasharray', this.createDashPattern(
  					((s.fixDash) ? 1 : s.strokeWidth) * s.scale));
  			}
  		};
  		mxSvgCanvas2D.prototype.updateStrokeAttributes = function()
  		{
  			var s = this.state;
  			if (s.lineJoin != null && s.lineJoin != 'miter')
  			{
  				this.node.setAttribute('stroke-linejoin', s.lineJoin);
  			}
  			if (s.lineCap != null)
  			{
  				var value = s.lineCap;
  				if (value == 'flat')
  				{
  					value = 'butt';
  				}
  				if (value != 'butt')
  				{
  					this.node.setAttribute('stroke-linecap', value);
  				}
  			}
  			if (s.miterLimit != null && (!this.styleEnabled || s.miterLimit != 10))
  			{
  				this.node.setAttribute('stroke-miterlimit', s.miterLimit);
  			}
  		};
  		mxSvgCanvas2D.prototype.createDashPattern = function(scale)
  		{
  			var pat = [];
  			if (typeof(this.state.dashPattern) === 'string')
  			{
  				var dash = this.state.dashPattern.split(' ');
  				if (dash.length > 0)
  				{
  					for (var i = 0; i < dash.length; i++)
  					{
  						pat[i] = Number(dash[i]) * scale;
  					}
  				}
  			}
  			return pat.join(' ');
  		};
  		mxSvgCanvas2D.prototype.createTolerance = function(node)
  		{
  			var tol = node.cloneNode(true);
  			var sw = parseFloat(tol.getAttribute('stroke-width') || 1) + this.strokeTolerance;
  			tol.setAttribute('pointer-events', 'stroke');
  			tol.setAttribute('visibility', 'hidden');
  			tol.removeAttribute('stroke-dasharray');
  			tol.setAttribute('stroke-width', sw);
  			tol.setAttribute('fill', 'none');
  			tol.setAttribute('stroke', (mxClient.IS_OT) ? 'none' : 'white');
  			return tol;
  		};
  		mxSvgCanvas2D.prototype.createShadow = function(node)
  		{
  			var shadow = node.cloneNode(true);
  			var s = this.state;
  			if (shadow.getAttribute('fill') != 'none' && (!mxClient.IS_FF || shadow.getAttribute('fill') != 'transparent'))
  			{
  				shadow.setAttribute('fill', s.shadowColor);
  			}
  			if (shadow.getAttribute('stroke') != 'none')
  			{
  				shadow.setAttribute('stroke', s.shadowColor);
  			}
  			shadow.setAttribute('transform', 'translate(' + this.format(s.shadowDx * s.scale) +
  				',' + this.format(s.shadowDy * s.scale) + ')' + (s.transform || ''));
  			shadow.setAttribute('opacity', s.shadowAlpha);
  			return shadow;
  		};
  		mxSvgCanvas2D.prototype.setLink = function(link)
  		{
  			if (link == null)
  			{
  				this.root = this.originalRoot;
  			}
  			else
  			{
  				this.originalRoot = this.root;
  				var node = this.createElement('a');
  				if (node.setAttributeNS == null || (this.root.ownerDocument != document && document.documentMode == null))
  				{
  					node.setAttribute('xlink:href', link);
  				}
  				else
  				{
  					node.setAttributeNS(mxConstants.NS_XLINK, 'xlink:href', link);
  				}
  				this.root.appendChild(node);
  				this.root = node;
  			}
  		};
  		mxSvgCanvas2D.prototype.rotate = function(theta, flipH, flipV, cx, cy)
  		{
  			if (theta != 0 || flipH || flipV)
  			{
  				var s = this.state;
  				cx += s.dx;
  				cy += s.dy;
  				cx *= s.scale;
  				cy *= s.scale;
  				s.transform = s.transform || '';
  				if (flipH && flipV)
  				{
  					theta += 180;
  				}
  				else if (flipH != flipV)
  				{
  					var tx = (flipH) ? cx : 0;
  					var sx = (flipH) ? -1 : 1;
  					var ty = (flipV) ? cy : 0;
  					var sy = (flipV) ? -1 : 1;
  					s.transform += 'translate(' + this.format(tx) + ',' + this.format(ty) + ')' +
  						'scale(' + this.format(sx) + ',' + this.format(sy) + ')' +
  						'translate(' + this.format(-tx) + ',' + this.format(-ty) + ')';
  				}
  				if (flipH ? !flipV : flipV)
  				{
  					theta *= -1;
  				}
  				if (theta != 0)
  				{
  					s.transform += 'rotate(' + this.format(theta) + ',' + this.format(cx) + ',' + this.format(cy) + ')';
  				}
  				s.rotation = s.rotation + theta;
  				s.rotationCx = cx;
  				s.rotationCy = cy;
  			}
  		};
  		mxSvgCanvas2D.prototype.begin = function()
  		{
  			mxAbstractCanvas2D.prototype.begin.apply(this, arguments);
  			this.node = this.createElement('path');
  		};
  		mxSvgCanvas2D.prototype.rect = function(x, y, w, h)
  		{
  			var s = this.state;
  			var n = this.createElement('rect');
  			n.setAttribute('x', this.format((x + s.dx) * s.scale));
  			n.setAttribute('y', this.format((y + s.dy) * s.scale));
  			n.setAttribute('width', this.format(w * s.scale));
  			n.setAttribute('height', this.format(h * s.scale));
  			this.node = n;
  		};
  		mxSvgCanvas2D.prototype.roundrect = function(x, y, w, h, dx, dy)
  		{
  			this.rect(x, y, w, h);
  			if (dx > 0)
  			{
  				this.node.setAttribute('rx', this.format(dx * this.state.scale));
  			}
  			if (dy > 0)
  			{
  				this.node.setAttribute('ry', this.format(dy * this.state.scale));
  			}
  		};
  		mxSvgCanvas2D.prototype.ellipse = function(x, y, w, h)
  		{
  			var s = this.state;
  			var n = this.createElement('ellipse');
  			n.setAttribute('cx', this.format((x + w / 2 + s.dx) * s.scale));
  			n.setAttribute('cy', this.format((y + h / 2 + s.dy) * s.scale));
  			n.setAttribute('rx', w / 2 * s.scale);
  			n.setAttribute('ry', h / 2 * s.scale);
  			this.node = n;
  		};
  		mxSvgCanvas2D.prototype.image = function(x, y, w, h, src, aspect, flipH, flipV)
  		{
  			src = this.converter.convert(src);
  			aspect = (aspect != null) ? aspect : true;
  			flipH = (flipH != null) ? flipH : false;
  			flipV = (flipV != null) ? flipV : false;
  			var s = this.state;
  			x += s.dx;
  			y += s.dy;
  			var node = this.createElement('image');
  			node.setAttribute('x', this.format(x * s.scale) + this.imageOffset);
  			node.setAttribute('y', this.format(y * s.scale) + this.imageOffset);
  			node.setAttribute('width', this.format(w * s.scale));
  			node.setAttribute('height', this.format(h * s.scale));
  			if (node.setAttributeNS == null)
  			{
  				node.setAttribute('xlink:href', src);
  			}
  			else
  			{
  				node.setAttributeNS(mxConstants.NS_XLINK, 'xlink:href', src);
  			}
  			if (!aspect)
  			{
  				node.setAttribute('preserveAspectRatio', 'none');
  			}
  			if (s.alpha < 1 || s.fillAlpha < 1)
  			{
  				node.setAttribute('opacity', s.alpha * s.fillAlpha);
  			}
  			var tr = this.state.transform || '';
  			if (flipH || flipV)
  			{
  				var sx = 1;
  				var sy = 1;
  				var dx = 0;
  				var dy = 0;
  				if (flipH)
  				{
  					sx = -1;
  					dx = -w - 2 * x;
  				}
  				if (flipV)
  				{
  					sy = -1;
  					dy = -h - 2 * y;
  				}
  				tr += 'scale(' + sx + ',' + sy + ')translate(' + (dx * s.scale) + ',' + (dy * s.scale) + ')';
  			}
  			if (tr.length > 0)
  			{
  				node.setAttribute('transform', tr);
  			}
  			if (!this.pointerEvents)
  			{
  				node.setAttribute('pointer-events', 'none');
  			}
  			this.root.appendChild(node);
  		};
  		mxSvgCanvas2D.prototype.convertHtml = function(val)
  		{
  			if (this.useDomParser)
  			{
  				var doc = new DOMParser().parseFromString(val, 'text/html');
  				if (doc != null)
  				{
  					val = new XMLSerializer().serializeToString(doc.body);
  					if (val.substring(0, 5) == '<body')
  					{
  						val = val.substring(val.indexOf('>', 5) + 1);
  					}
  					if (val.substring(val.length - 7, val.length) == '</body>')
  					{
  						val = val.substring(0, val.length - 7);
  					}
  				}
  			}
  			else if (document.implementation != null && document.implementation.createDocument != null)
  			{
  				var xd = document.implementation.createDocument('http://www.w3.org/1999/xhtml', 'html', null);
  				var xb = xd.createElement('body');
  				xd.documentElement.appendChild(xb);
  				var div = document.createElement('div');
  				div.innerHTML = val;
  				var child = div.firstChild;
  				while (child != null)
  				{
  					var next = child.nextSibling;
  					xb.appendChild(xd.adoptNode(child));
  					child = next;
  				}
  				return xb.innerHTML;
  			}
  			else
  			{
  				var ta = document.createElement('textarea');
  				ta.innerHTML = val.replace(/&amp;/g, '&amp;amp;').
  					replace(/&#60;/g, '&amp;lt;').replace(/&#62;/g, '&amp;gt;').
  					replace(/&lt;/g, '&amp;lt;').replace(/&gt;/g, '&amp;gt;').
  					replace(/</g, '&lt;').replace(/>/g, '&gt;');
  				val = ta.value.replace(/&/g, '&amp;').replace(/&amp;lt;/g, '&lt;').
  					replace(/&amp;gt;/g, '&gt;').replace(/&amp;amp;/g, '&amp;').
  					replace(/<br>/g, '<br />').replace(/<hr>/g, '<hr />').
  					replace(/(<img[^>]+)>/gm, "$1 />");
  			}
  			return val;
  		};
  		mxSvgCanvas2D.prototype.createDiv = function(str)
  		{
  			var val = str;
  			if (!mxUtils.isNode(val))
  			{
  				val = '<div><div>' + this.convertHtml(val) + '</div></div>';
  			}
  			if (!mxClient.IS_IE && !mxClient.IS_IE11 && document.createElementNS)
  			{
  				var div = document.createElementNS('http://www.w3.org/1999/xhtml', 'div');
  				if (mxUtils.isNode(val))
  				{
  					var div2 = document.createElement('div');
  					var div3 = div2.cloneNode(false);
  					if (this.root.ownerDocument != document)
  					{
  						div2.appendChild(val.cloneNode(true));
  					}
  					else
  					{
  						div2.appendChild(val);
  					}
  					div3.appendChild(div2);
  					div.appendChild(div3);
  				}
  				else
  				{
  					div.innerHTML = val;
  				}
  				return div;
  			}
  			else
  			{
  				if (mxUtils.isNode(val))
  				{
  					val = '<div><div>' + mxUtils.getXml(val) + '</div></div>';
  				}
  				val = '<div xmlns="http://www.w3.org/1999/xhtml">' + val + '</div>';
  				return  mxUtils.parseXml(val).documentElement;
  			}
  		};
  		mxSvgCanvas2D.prototype.updateText = function(x, y, w, h, align, valign, wrap, overflow, clip, rotation, node)
  		{
  			if (node != null && node.firstChild != null && node.firstChild.firstChild != null)
  			{
  				this.updateTextNodes(x, y, w, h, align, valign, wrap, overflow, clip, rotation, node.firstChild);
  			}
  		};
  		mxSvgCanvas2D.prototype.addForeignObject = function(x, y, w, h, str, align, valign, wrap, format, overflow, clip, rotation, dir, div, root)
  		{
  			var group = this.createElement('g');
  			var fo = this.createElement('foreignObject');
  			fo.setAttribute('style', 'overflow: visible; text-align: left;');
  			fo.setAttribute('pointer-events', 'none');
  			if (div.ownerDocument != document)
  			{
  				div = mxUtils.importNodeImplementation(fo.ownerDocument, div, true);
  			}
  			fo.appendChild(div);
  			group.appendChild(fo);
  			this.updateTextNodes(x, y, w, h, align, valign, wrap, overflow, clip, rotation, group);
  			if (this.root.ownerDocument != document)
  			{
  				var alt = this.createAlternateContent(fo, x, y, w, h, str, align, valign, wrap, format, overflow, clip, rotation);
  				if (alt != null)
  				{
  					fo.setAttribute('requiredFeatures', 'http://www.w3.org/TR/SVG11/feature#Extensibility');
  					var sw = this.createElement('switch');
  					sw.appendChild(fo);
  					sw.appendChild(alt);
  					group.appendChild(sw);
  				}
  			}
  			root.appendChild(group);
  		};
  		mxSvgCanvas2D.prototype.updateTextNodes = function(x, y, w, h, align, valign, wrap, overflow, clip, rotation, g)
  		{
  			var s = this.state.scale;
  			mxSvgCanvas2D.createCss(w + 2, h, align, valign, wrap, overflow, clip,
  				(this.state.fontBackgroundColor != null) ? this.state.fontBackgroundColor : null,
  				(this.state.fontBorderColor != null) ? this.state.fontBorderColor : null,
  				'display: flex; align-items: unsafe ' +
  				((valign == mxConstants.ALIGN_TOP) ? 'flex-start' :
  				((valign == mxConstants.ALIGN_BOTTOM) ? 'flex-end' : 'center'))  + '; ' +
  				'justify-content: unsafe ' + ((align == mxConstants.ALIGN_LEFT) ? 'flex-start' :
  				((align == mxConstants.ALIGN_RIGHT) ? 'flex-end' : 'center'))  + '; ',
  				this.getTextCss(), s, mxUtils.bind(this, function(dx, dy, flex, item, block)
  			{
  				x += this.state.dx;
  				y += this.state.dy;
  				var fo = g.firstChild;
  				var div = fo.firstChild;
  				var box = div.firstChild;
  				var text = box.firstChild;
  				var r = ((this.rotateHtml) ? this.state.rotation : 0) + ((rotation != null) ? rotation : 0);
  				var t = ((this.foOffset != 0) ? 'translate(' + this.foOffset + ' ' + this.foOffset + ')' : '') +
  					((s != 1) ? 'scale(' + s + ')' : '');
  				text.setAttribute('style', block);
  				box.setAttribute('style', item);
  				fo.setAttribute('width', Math.ceil(1 / Math.min(1, s) * 100) + '%');
  				fo.setAttribute('height', Math.ceil(1 / Math.min(1, s) * 100) + '%');
  				var yp = Math.round(y + dy);
  				if (yp < 0)
  				{
  					fo.setAttribute('y', yp);
  				}
  				else
  				{
  					fo.removeAttribute('y');
  					flex += 'padding-top: ' + yp + 'px; ';
  				}
  				div.setAttribute('style', flex + 'margin-left: ' + Math.round(x + dx) + 'px;');
  				t += ((r != 0) ? ('rotate(' + r + ' ' + x + ' ' + y + ')') : '');
  				if (t != '')
  				{
  					g.setAttribute('transform', t);
  				}
  				else
  				{
  					g.removeAttribute('transform');
  				}
  				if (this.state.alpha != 1)
  				{
  					g.setAttribute('opacity', this.state.alpha);
  				}
  				else
  				{
  					g.removeAttribute('opacity');
  				}
  			}));
  		};
  		mxSvgCanvas2D.createCss = function(w, h, align, valign, wrap, overflow, clip, bg, border, flex, block, s, callback)
  		{
  			var item = 'box-sizing: border-box; font-size: 0; text-align: ' + ((align == mxConstants.ALIGN_LEFT) ? 'left' :
  				((align == mxConstants.ALIGN_RIGHT) ? 'right' : 'center')) + '; ';
  			var pt = mxUtils.getAlignmentAsPoint(align, valign);
  			var ofl = 'overflow: hidden; ';
  			var fw = 'width: 1px; ';
  			var fh = 'height: 1px; ';
  			var dx = pt.x * w;
  			var dy = pt.y * h;
  			if (clip)
  			{
  				fw = 'width: ' + Math.round(w) + 'px; ';
  				item += 'max-height: ' + Math.round(h) + 'px; ';
  				dy = 0;
  			}
  			else if (overflow == 'fill')
  			{
  				fw = 'width: ' + Math.round(w) + 'px; ';
  				fh = 'height: ' + Math.round(h) + 'px; ';
  				block += 'width: 100%; height: 100%; ';
  				item += fw + fh;
  			}
  			else if (overflow == 'width')
  			{
  				fw = 'width: ' + Math.round(w) + 'px; ';
  				block += 'width: 100%; ';
  				item += fw;
  				dy = 0;
  				if (h > 0)
  				{
  					item += 'max-height: ' + Math.round(h) + 'px; ';
  				}
  			}
  			else
  			{
  				ofl = '';
  				dy = 0;
  			}
  			var bgc = '';
  			if (bg != null)
  			{
  				bgc += 'background-color: ' + bg + '; ';
  			}
  			if (border != null)
  			{
  				bgc += 'border: 1px solid ' + border + '; ';
  			}
  			if (ofl == '' || clip)
  			{
  				block += bgc;
  			}
  			else
  			{
  				item += bgc;
  			}
  			if (wrap && w > 0)
  			{
  				block += 'white-space: normal; word-wrap: ' + mxConstants.WORD_WRAP + '; ';
  				fw = 'width: ' + Math.round(w) + 'px; ';
  				if (ofl != '' && overflow != 'fill')
  				{
  					dy = 0;
  				}
  			}
  			else
  			{
  				block += 'white-space: nowrap; ';
  				if (ofl == '')
  				{
  					dx = 0;
  				}
  			}
  			callback(dx, dy, flex + fw + fh, item + ofl, block, ofl);
  		};
  		mxSvgCanvas2D.prototype.getTextCss = function()
  		{
  			var s = this.state;
  			var lh = (mxConstants.ABSOLUTE_LINE_HEIGHT) ? (s.fontSize * mxConstants.LINE_HEIGHT) + 'px' :
  				(mxConstants.LINE_HEIGHT * this.lineHeightCorrection);
  			var css = 'display: inline-block; font-size: ' + s.fontSize + 'px; ' +
  				'font-family: ' + s.fontFamily + '; color: ' + s.fontColor + '; line-height: ' + lh +
  				'; pointer-events: ' + ((this.pointerEvents) ? this.pointerEventsValue : 'none') + '; ';
  			if ((s.fontStyle & mxConstants.FONT_BOLD) == mxConstants.FONT_BOLD)
  			{
  				css += 'font-weight: bold; ';
  			}
  			if ((s.fontStyle & mxConstants.FONT_ITALIC) == mxConstants.FONT_ITALIC)
  			{
  				css += 'font-style: italic; ';
  			}
  			var deco = [];
  			if ((s.fontStyle & mxConstants.FONT_UNDERLINE) == mxConstants.FONT_UNDERLINE)
  			{
  				deco.push('underline');
  			}
  			if ((s.fontStyle & mxConstants.FONT_STRIKETHROUGH) == mxConstants.FONT_STRIKETHROUGH)
  			{
  				deco.push('line-through');
  			}
  			if (deco.length > 0)
  			{
  				css += 'text-decoration: ' + deco.join(' ') + '; ';
  			}
  			return css;
  		};
  		mxSvgCanvas2D.prototype.text = function(x, y, w, h, str, align, valign, wrap, format, overflow, clip, rotation, dir)
  		{
  			if (this.textEnabled && str != null)
  			{
  				rotation = (rotation != null) ? rotation : 0;
  				if (this.foEnabled && format == 'html')
  				{
  					var div = this.createDiv(str);
  					if (div != null)
  					{
  						if (dir != null)
  						{
  							div.setAttribute('dir', dir);
  						}
  						this.addForeignObject(x, y, w, h, str, align, valign, wrap,
  							format, overflow, clip, rotation, dir, div, this.root);
  					}
  				}
  				else
  				{
  					this.plainText(x + this.state.dx, y + this.state.dy, w, h, str,
  						align, valign, wrap, overflow, clip, rotation, dir);
  				}
  			}
  		};
  		mxSvgCanvas2D.prototype.createClip = function(x, y, w, h)
  		{
  			x = Math.round(x);
  			y = Math.round(y);
  			w = Math.round(w);
  			h = Math.round(h);
  			var id = 'mx-clip-' + x + '-' + y + '-' + w + '-' + h;
  			var counter = 0;
  			var tmp = id + '-' + counter;
  			while (document.getElementById(tmp) != null)
  			{
  				tmp = id + '-' + (++counter);
  			}
  			clip = this.createElement('clipPath');
  			clip.setAttribute('id', tmp);
  			var rect = this.createElement('rect');
  			rect.setAttribute('x', x);
  			rect.setAttribute('y', y);
  			rect.setAttribute('width', w);
  			rect.setAttribute('height', h);
  			clip.appendChild(rect);
  			return clip;
  		};
  		mxSvgCanvas2D.prototype.plainText = function(x, y, w, h, str, align, valign, wrap, overflow, clip, rotation, dir)
  		{
  			rotation = (rotation != null) ? rotation : 0;
  			var s = this.state;
  			var size = s.fontSize;
  			var node = this.createElement('g');
  			var tr = s.transform || '';
  			this.updateFont(node);
  			if (!this.pointerEvents && this.originalRoot == null)
  			{
  				node.setAttribute('pointer-events', 'none');
  			}
  			if (rotation != 0)
  			{
  				tr += 'rotate(' + rotation  + ',' + this.format(x * s.scale) + ',' + this.format(y * s.scale) + ')';
  			}
  			if (dir != null)
  			{
  				node.setAttribute('direction', dir);
  			}
  			if (clip && w > 0 && h > 0)
  			{
  				var cx = x;
  				var cy = y;
  				if (align == mxConstants.ALIGN_CENTER)
  				{
  					cx -= w / 2;
  				}
  				else if (align == mxConstants.ALIGN_RIGHT)
  				{
  					cx -= w;
  				}
  				if (overflow != 'fill')
  				{
  					if (valign == mxConstants.ALIGN_MIDDLE)
  					{
  						cy -= h / 2;
  					}
  					else if (valign == mxConstants.ALIGN_BOTTOM)
  					{
  						cy -= h;
  					}
  				}
  				var c = this.createClip(cx * s.scale - 2, cy * s.scale - 2, w * s.scale + 4, h * s.scale + 4);
  				if (this.defs != null)
  				{
  					this.defs.appendChild(c);
  				}
  				else
  				{
  					this.root.appendChild(c);
  				}
  				if (!mxClient.IS_CHROMEAPP && !mxClient.IS_IE && !mxClient.IS_IE11 &&
  					!mxClient.IS_EDGE && this.root.ownerDocument == document)
  				{
  					var base = this.getBaseUrl().replace(/([\(\)])/g, '\\$1');
  					node.setAttribute('clip-path', 'url(' + base + '#' + c.getAttribute('id') + ')');
  				}
  				else
  				{
  					node.setAttribute('clip-path', 'url(#' + c.getAttribute('id') + ')');
  				}
  			}
  			var anchor = (align == mxConstants.ALIGN_RIGHT) ? 'end' :
  							(align == mxConstants.ALIGN_CENTER) ? 'middle' :
  							'start';
  			if (anchor != 'start')
  			{
  				node.setAttribute('text-anchor', anchor);
  			}
  			if (!this.styleEnabled || size != mxConstants.DEFAULT_FONTSIZE)
  			{
  				node.setAttribute('font-size', (size * s.scale) + 'px');
  			}
  			if (tr.length > 0)
  			{
  				node.setAttribute('transform', tr);
  			}
  			if (s.alpha < 1)
  			{
  				node.setAttribute('opacity', s.alpha);
  			}
  			var lines = str.split('\n');
  			var lh = Math.round(size * mxConstants.LINE_HEIGHT);
  			var textHeight = size + (lines.length - 1) * lh;
  			var cy = y + size - 1;
  			if (valign == mxConstants.ALIGN_MIDDLE)
  			{
  				if (overflow == 'fill')
  				{
  					cy -= h / 2;
  				}
  				else
  				{
  					var dy = ((this.matchHtmlAlignment && clip && h > 0) ? Math.min(textHeight, h) : textHeight) / 2;
  					cy -= dy;
  				}
  			}
  			else if (valign == mxConstants.ALIGN_BOTTOM)
  			{
  				if (overflow == 'fill')
  				{
  					cy -= h;
  				}
  				else
  				{
  					var dy = (this.matchHtmlAlignment && clip && h > 0) ? Math.min(textHeight, h) : textHeight;
  					cy -= dy + 1;
  				}
  			}
  			for (var i = 0; i < lines.length; i++)
  			{
  				if (lines[i].length > 0 && mxUtils.trim(lines[i]).length > 0)
  				{
  					var text = this.createElement('text');
  					text.setAttribute('x', this.format(x * s.scale) + this.textOffset);
  					text.setAttribute('y', this.format(cy * s.scale) + this.textOffset);
  					mxUtils.write(text, lines[i]);
  					node.appendChild(text);
  				}
  				cy += lh;
  			}
  			this.root.appendChild(node);
  			this.addTextBackground(node, str, x, y, w, (overflow == 'fill') ? h : textHeight, align, valign, overflow);
  		};
  		mxSvgCanvas2D.prototype.updateFont = function(node)
  		{
  			var s = this.state;
  			node.setAttribute('fill', s.fontColor);
  			if (!this.styleEnabled || s.fontFamily != mxConstants.DEFAULT_FONTFAMILY)
  			{
  				node.setAttribute('font-family', s.fontFamily);
  			}
  			if ((s.fontStyle & mxConstants.FONT_BOLD) == mxConstants.FONT_BOLD)
  			{
  				node.setAttribute('font-weight', 'bold');
  			}
  			if ((s.fontStyle & mxConstants.FONT_ITALIC) == mxConstants.FONT_ITALIC)
  			{
  				node.setAttribute('font-style', 'italic');
  			}
  			var txtDecor = [];
  			if ((s.fontStyle & mxConstants.FONT_UNDERLINE) == mxConstants.FONT_UNDERLINE)
  			{
  				txtDecor.push('underline');
  			}
  			if ((s.fontStyle & mxConstants.FONT_STRIKETHROUGH) == mxConstants.FONT_STRIKETHROUGH)
  			{
  				txtDecor.push('line-through');
  			}
  			if (txtDecor.length > 0)
  			{
  				node.setAttribute('text-decoration', txtDecor.join(' '));
  			}
  		};
  		mxSvgCanvas2D.prototype.addTextBackground = function(node, str, x, y, w, h, align, valign, overflow)
  		{
  			var s = this.state;
  			if (s.fontBackgroundColor != null || s.fontBorderColor != null)
  			{
  				var bbox = null;
  				if (overflow == 'fill' || overflow == 'width')
  				{
  					if (align == mxConstants.ALIGN_CENTER)
  					{
  						x -= w / 2;
  					}
  					else if (align == mxConstants.ALIGN_RIGHT)
  					{
  						x -= w;
  					}
  					if (valign == mxConstants.ALIGN_MIDDLE)
  					{
  						y -= h / 2;
  					}
  					else if (valign == mxConstants.ALIGN_BOTTOM)
  					{
  						y -= h;
  					}
  					bbox = new mxRectangle((x + 1) * s.scale, y * s.scale, (w - 2) * s.scale, (h + 2) * s.scale);
  				}
  				else if (node.getBBox != null && this.root.ownerDocument == document)
  				{
  					try
  					{
  						bbox = node.getBBox();
  						var ie = mxClient.IS_IE && mxClient.IS_SVG;
  						bbox = new mxRectangle(bbox.x, bbox.y + ((ie) ? 0 : 1), bbox.width, bbox.height + ((ie) ? 1 : 0));
  					}
  					catch (e)
  					{
  					}
  				}
  				if (bbox == null || bbox.width == 0 || bbox.height == 0)
  				{
  					var div = document.createElement('div');
  					div.style.lineHeight = (mxConstants.ABSOLUTE_LINE_HEIGHT) ? (s.fontSize * mxConstants.LINE_HEIGHT) + 'px' : mxConstants.LINE_HEIGHT;
  					div.style.fontSize = s.fontSize + 'px';
  					div.style.fontFamily = s.fontFamily;
  					div.style.whiteSpace = 'nowrap';
  					div.style.position = 'absolute';
  					div.style.visibility = 'hidden';
  					div.style.display = (mxClient.IS_QUIRKS) ? 'inline' : 'inline-block';
  					div.style.zoom = '1';
  					if ((s.fontStyle & mxConstants.FONT_BOLD) == mxConstants.FONT_BOLD)
  					{
  						div.style.fontWeight = 'bold';
  					}
  					if ((s.fontStyle & mxConstants.FONT_ITALIC) == mxConstants.FONT_ITALIC)
  					{
  						div.style.fontStyle = 'italic';
  					}
  					str = mxUtils.htmlEntities(str, false);
  					div.innerHTML = str.replace(/\n/g, '<br/>');
  					document.body.appendChild(div);
  					var w = div.offsetWidth;
  					var h = div.offsetHeight;
  					div.parentNode.removeChild(div);
  					if (align == mxConstants.ALIGN_CENTER)
  					{
  						x -= w / 2;
  					}
  					else if (align == mxConstants.ALIGN_RIGHT)
  					{
  						x -= w;
  					}
  					if (valign == mxConstants.ALIGN_MIDDLE)
  					{
  						y -= h / 2;
  					}
  					else if (valign == mxConstants.ALIGN_BOTTOM)
  					{
  						y -= h;
  					}
  					bbox = new mxRectangle((x + 1) * s.scale, (y + 2) * s.scale, w * s.scale, (h + 1) * s.scale);
  				}
  				if (bbox != null)
  				{
  					var n = this.createElement('rect');
  					n.setAttribute('fill', s.fontBackgroundColor || 'none');
  					n.setAttribute('stroke', s.fontBorderColor || 'none');
  					n.setAttribute('x', Math.floor(bbox.x - 1));
  					n.setAttribute('y', Math.floor(bbox.y - 1));
  					n.setAttribute('width', Math.ceil(bbox.width + 2));
  					n.setAttribute('height', Math.ceil(bbox.height));
  					var sw = (s.fontBorderColor != null) ? Math.max(1, this.format(s.scale)) : 0;
  					n.setAttribute('stroke-width', sw);
  					if (this.root.ownerDocument == document && mxUtils.mod(sw, 2) == 1)
  					{
  						n.setAttribute('transform', 'translate(0.5, 0.5)');
  					}
  					node.insertBefore(n, node.firstChild);
  				}
  			}
  		};
  		mxSvgCanvas2D.prototype.stroke = function()
  		{
  			this.addNode(false, true);
  		};
  		mxSvgCanvas2D.prototype.fill = function()
  		{
  			this.addNode(true, false);
  		};
  		mxSvgCanvas2D.prototype.fillAndStroke = function()
  		{
  			this.addNode(true, true);
  		};
  		__mxOutput.mxSvgCanvas2D = typeof mxSvgCanvas2D !== 'undefined' ? mxSvgCanvas2D : undefined;
  		var mxVmlCanvas2D = function(root)
  		{
  			mxAbstractCanvas2D.call(this);
  			this.root = root;
  		};
  		mxUtils.extend(mxVmlCanvas2D, mxAbstractCanvas2D);
  		mxVmlCanvas2D.prototype.node = null;
  		mxVmlCanvas2D.prototype.textEnabled = true;
  		mxVmlCanvas2D.prototype.moveOp = 'm';
  		mxVmlCanvas2D.prototype.lineOp = 'l';
  		mxVmlCanvas2D.prototype.curveOp = 'c';
  		mxVmlCanvas2D.prototype.closeOp = 'x';
  		mxVmlCanvas2D.prototype.rotatedHtmlBackground = '';
  		mxVmlCanvas2D.prototype.vmlScale = 1;
  		mxVmlCanvas2D.prototype.createElement = function(name)
  		{
  			return document.createElement(name);
  		};
  		mxVmlCanvas2D.prototype.createVmlElement = function(name)
  		{
  			return this.createElement(mxClient.VML_PREFIX + ':' + name);
  		};
  		mxVmlCanvas2D.prototype.addNode = function(filled, stroked)
  		{
  			var node = this.node;
  			var s = this.state;
  			if (node != null)
  			{
  				if (node.nodeName == 'shape')
  				{
  					if (this.path != null && this.path.length > 0)
  					{
  						node.path = this.path.join(' ') + ' e';
  						node.style.width = this.root.style.width;
  						node.style.height = this.root.style.height;
  						node.coordsize = parseInt(node.style.width) + ' ' + parseInt(node.style.height);
  					}
  					else
  					{
  						return;
  					}
  				}
  				node.strokeweight = this.format(Math.max(1, s.strokeWidth * s.scale / this.vmlScale)) + 'px';
  				if (s.shadow)
  				{
  					this.root.appendChild(this.createShadow(node,
  						filled && s.fillColor != null,
  						stroked && s.strokeColor != null));
  				}
  				if (stroked && s.strokeColor != null)
  				{
  					node.stroked = 'true';
  					node.strokecolor = s.strokeColor;
  				}
  				else
  				{
  					node.stroked = 'false';
  				}
  				node.appendChild(this.createStroke());
  				if (filled && s.fillColor != null)
  				{
  					node.appendChild(this.createFill());
  				}
  				else if (this.pointerEvents && (node.nodeName != 'shape' ||
  					this.path[this.path.length - 1] == this.closeOp))
  				{
  					node.appendChild(this.createTransparentFill());
  				}
  				else
  				{
  					node.filled = 'false';
  				}
  				this.root.appendChild(node);
  			}
  		};
  		mxVmlCanvas2D.prototype.createTransparentFill = function()
  		{
  			var fill = this.createVmlElement('fill');
  			fill.src = mxClient.imageBasePath + '/transparent.gif';
  			fill.type = 'tile';
  			return fill;
  		};
  		mxVmlCanvas2D.prototype.createFill = function()
  		{
  			var s = this.state;
  			var fill = this.createVmlElement('fill');
  			fill.color = s.fillColor;
  			if (s.gradientColor != null)
  			{
  				fill.type = 'gradient';
  				fill.method = 'none';
  				fill.color2 = s.gradientColor;
  				var angle = 180 - s.rotation;
  				if (s.gradientDirection == mxConstants.DIRECTION_WEST)
  				{
  					angle -= 90 + ((this.root.style.flip == 'x') ? 180 : 0);
  				}
  				else if (s.gradientDirection == mxConstants.DIRECTION_EAST)
  				{
  					angle += 90 + ((this.root.style.flip == 'x') ? 180 : 0);
  				}
  				else if (s.gradientDirection == mxConstants.DIRECTION_NORTH)
  				{
  					angle -= 180 + ((this.root.style.flip == 'y') ? -180 : 0);
  				}
  				else
  				{
  					 angle += ((this.root.style.flip == 'y') ? -180 : 0);
  				}
  				if (this.root.style.flip == 'x' || this.root.style.flip == 'y')
  				{
  					angle *= -1;
  				}
  				fill.angle = mxUtils.mod(angle, 360);
  				fill.opacity = (s.alpha * s.gradientFillAlpha * 100) + '%';
  				fill.setAttribute(mxClient.OFFICE_PREFIX + ':opacity2', (s.alpha * s.gradientAlpha * 100) + '%');
  			}
  			else if (s.alpha < 1 || s.fillAlpha < 1)
  			{
  				fill.opacity = (s.alpha * s.fillAlpha * 100) + '%';
  			}
  			return fill;
  		};
  		mxVmlCanvas2D.prototype.createStroke = function()
  		{
  			var s = this.state;
  			var stroke = this.createVmlElement('stroke');
  			stroke.endcap = s.lineCap || 'flat';
  			stroke.joinstyle = s.lineJoin || 'miter';
  			stroke.miterlimit = s.miterLimit || '10';
  			if (s.alpha < 1 || s.strokeAlpha < 1)
  			{
  				stroke.opacity = (s.alpha * s.strokeAlpha * 100) + '%';
  			}
  			if (s.dashed)
  			{
  				stroke.dashstyle = this.getVmlDashStyle();
  			}
  			return stroke;
  		};
  		mxVmlCanvas2D.prototype.getVmlDashStyle = function()
  		{
  			var result = 'dash';
  			if (typeof(this.state.dashPattern) === 'string')
  			{
  				var tok = this.state.dashPattern.split(' ');
  				if (tok.length > 0 && tok[0] == 1)
  				{
  					result = '0 2';
  				}
  			}
  			return result;
  		};
  		mxVmlCanvas2D.prototype.createShadow = function(node, filled, stroked)
  		{
  			var s = this.state;
  			var rad = -s.rotation * (Math.PI / 180);
  			var cos = Math.cos(rad);
  			var sin = Math.sin(rad);
  			var dx = s.shadowDx * s.scale;
  			var dy = s.shadowDy * s.scale;
  			if (this.root.style.flip == 'x')
  			{
  				dx *= -1;
  			}
  			else if (this.root.style.flip == 'y')
  			{
  				dy *= -1;
  			}
  			var shadow = node.cloneNode(true);
  			shadow.style.marginLeft = Math.round(dx * cos - dy * sin) + 'px';
  			shadow.style.marginTop = Math.round(dx * sin + dy * cos) + 'px';
  			if (document.documentMode == 8)
  			{
  				shadow.strokeweight = node.strokeweight;
  				if (node.nodeName == 'shape')
  				{
  					shadow.path = this.path.join(' ') + ' e';
  					shadow.style.width = this.root.style.width;
  					shadow.style.height = this.root.style.height;
  					shadow.coordsize = parseInt(node.style.width) + ' ' + parseInt(node.style.height);
  				}
  			}
  			if (stroked)
  			{
  				shadow.strokecolor = s.shadowColor;
  				shadow.appendChild(this.createShadowStroke());
  			}
  			else
  			{
  				shadow.stroked = 'false';
  			}
  			if (filled)
  			{
  				shadow.appendChild(this.createShadowFill());
  			}
  			else
  			{
  				shadow.filled = 'false';
  			}
  			return shadow;
  		};
  		mxVmlCanvas2D.prototype.createShadowFill = function()
  		{
  			var fill = this.createVmlElement('fill');
  			fill.color = this.state.shadowColor;
  			fill.opacity = (this.state.alpha * this.state.shadowAlpha * 100) + '%';
  			return fill;
  		};
  		mxVmlCanvas2D.prototype.createShadowStroke = function()
  		{
  			var stroke = this.createStroke();
  			stroke.opacity = (this.state.alpha * this.state.shadowAlpha * 100) + '%';
  			return stroke;
  		};
  		mxVmlCanvas2D.prototype.rotate = function(theta, flipH, flipV, cx, cy)
  		{
  			if (flipH && flipV)
  			{
  				theta += 180;
  			}
  			else if (flipH)
  			{
  				this.root.style.flip = 'x';
  			}
  			else if (flipV)
  			{
  				this.root.style.flip = 'y';
  			}
  			if (flipH ? !flipV : flipV)
  			{
  				theta *= -1;
  			}
  			this.root.style.rotation = theta;
  			this.state.rotation = this.state.rotation + theta;
  			this.state.rotationCx = cx;
  			this.state.rotationCy = cy;
  		};
  		mxVmlCanvas2D.prototype.begin = function()
  		{
  			mxAbstractCanvas2D.prototype.begin.apply(this, arguments);
  			this.node = this.createVmlElement('shape');
  			this.node.style.position = 'absolute';
  		};
  		mxVmlCanvas2D.prototype.quadTo = function(x1, y1, x2, y2)
  		{
  			var s = this.state;
  			var cpx0 = (this.lastX + s.dx) * s.scale;
  			var cpy0 = (this.lastY + s.dy) * s.scale;
  			var qpx1 = (x1 + s.dx) * s.scale;
  			var qpy1 = (y1 + s.dy) * s.scale;
  			var cpx3 = (x2 + s.dx) * s.scale;
  			var cpy3 = (y2 + s.dy) * s.scale;
  			var cpx1 = cpx0 + 2/3 * (qpx1 - cpx0);
  			var cpy1 = cpy0 + 2/3 * (qpy1 - cpy0);
  			var cpx2 = cpx3 + 2/3 * (qpx1 - cpx3);
  			var cpy2 = cpy3 + 2/3 * (qpy1 - cpy3);
  			this.path.push('c ' + this.format(cpx1) + ' ' + this.format(cpy1) +
  					' ' + this.format(cpx2) + ' ' + this.format(cpy2) +
  					' ' + this.format(cpx3) + ' ' + this.format(cpy3));
  			this.lastX = (cpx3 / s.scale) - s.dx;
  			this.lastY = (cpy3 / s.scale) - s.dy;
  		};
  		mxVmlCanvas2D.prototype.createRect = function(nodeName, x, y, w, h)
  		{
  			var s = this.state;
  			var n = this.createVmlElement(nodeName);
  			n.style.position = 'absolute';
  			n.style.left = this.format((x + s.dx) * s.scale) + 'px';
  			n.style.top = this.format((y + s.dy) * s.scale) + 'px';
  			n.style.width = this.format(w * s.scale) + 'px';
  			n.style.height = this.format(h * s.scale) + 'px';
  			return n;
  		};
  		mxVmlCanvas2D.prototype.rect = function(x, y, w, h)
  		{
  			this.node = this.createRect('rect', x, y, w, h);
  		};
  		mxVmlCanvas2D.prototype.roundrect = function(x, y, w, h, dx, dy)
  		{
  			this.node = this.createRect('roundrect', x, y, w, h);
  			this.node.setAttribute('arcsize', Math.max(dx * 100 / w, dy * 100 / h) + '%');
  		};
  		mxVmlCanvas2D.prototype.ellipse = function(x, y, w, h)
  		{
  			this.node = this.createRect('oval', x, y, w, h);
  		};
  		mxVmlCanvas2D.prototype.image = function(x, y, w, h, src, aspect, flipH, flipV)
  		{
  			var node = null;
  			if (!aspect)
  			{
  				node = this.createRect('image', x, y, w, h);
  				node.src = src;
  			}
  			else
  			{
  				node = this.createRect('rect', x, y, w, h);
  				node.stroked = 'false';
  				var fill = this.createVmlElement('fill');
  				fill.aspect = (aspect) ? 'atmost' : 'ignore';
  				fill.rotate = 'true';
  				fill.type = 'frame';
  				fill.src = src;
  				node.appendChild(fill);
  			}
  			if (flipH && flipV)
  			{
  				node.style.rotation = '180';
  			}
  			else if (flipH)
  			{
  				node.style.flip = 'x';
  			}
  			else if (flipV)
  			{
  				node.style.flip = 'y';
  			}
  			if (this.state.alpha < 1 || this.state.fillAlpha < 1)
  			{
  				node.style.filter += 'alpha(opacity=' + (this.state.alpha * this.state.fillAlpha * 100) + ')';
  			}
  			this.root.appendChild(node);
  		};
  		mxVmlCanvas2D.prototype.createDiv = function(str, align, valign, overflow)
  		{
  			var div = this.createElement('div');
  			var state = this.state;
  			var css = '';
  			if (state.fontBackgroundColor != null)
  			{
  				css += 'background-color:' + mxUtils.htmlEntities(state.fontBackgroundColor) + ';';
  			}
  			if (state.fontBorderColor != null)
  			{
  				css += 'border:1px solid ' + mxUtils.htmlEntities(state.fontBorderColor) + ';';
  			}
  			if (mxUtils.isNode(str))
  			{
  				div.appendChild(str);
  			}
  			else
  			{
  				if (overflow != 'fill' && overflow != 'width')
  				{
  					var div2 = this.createElement('div');
  					div2.style.cssText = css;
  					div2.style.display = (mxClient.IS_QUIRKS) ? 'inline' : 'inline-block';
  					div2.style.zoom = '1';
  					div2.style.textDecoration = 'inherit';
  					div2.innerHTML = str;
  					div.appendChild(div2);
  				}
  				else
  				{
  					div.style.cssText = css;
  					div.innerHTML = str;
  				}
  			}
  			var style = div.style;
  			style.fontSize = (state.fontSize / this.vmlScale) + 'px';
  			style.fontFamily = state.fontFamily;
  			style.color = state.fontColor;
  			style.verticalAlign = 'top';
  			style.textAlign = align || 'left';
  			style.lineHeight = (mxConstants.ABSOLUTE_LINE_HEIGHT) ? (state.fontSize * mxConstants.LINE_HEIGHT / this.vmlScale) + 'px' : mxConstants.LINE_HEIGHT;
  			if ((state.fontStyle & mxConstants.FONT_BOLD) == mxConstants.FONT_BOLD)
  			{
  				style.fontWeight = 'bold';
  			}
  			if ((state.fontStyle & mxConstants.FONT_ITALIC) == mxConstants.FONT_ITALIC)
  			{
  				style.fontStyle = 'italic';
  			}
  			if ((state.fontStyle & mxConstants.FONT_UNDERLINE) == mxConstants.FONT_UNDERLINE)
  			{
  				style.textDecoration = 'underline';
  			}
  			return div;
  		};
  		mxVmlCanvas2D.prototype.text = function(x, y, w, h, str, align, valign, wrap, format, overflow, clip, rotation, dir)
  		{
  			if (this.textEnabled && str != null)
  			{
  				var s = this.state;
  				if (format == 'html')
  				{
  					if (s.rotation != null)
  					{
  						var pt = this.rotatePoint(x, y, s.rotation, s.rotationCx, s.rotationCy);
  						x = pt.x;
  						y = pt.y;
  					}
  					if (document.documentMode == 8 && !mxClient.IS_EM)
  					{
  						x += s.dx;
  						y += s.dy;
  						if (overflow != 'fill' && valign == mxConstants.ALIGN_TOP)
  						{
  							y -= 1;
  						}
  					}
  					else
  					{
  						x *= s.scale;
  						y *= s.scale;
  					}
  					var abs = (document.documentMode == 8 && !mxClient.IS_EM) ? this.createVmlElement('group') : this.createElement('div');
  					abs.style.position = 'absolute';
  					abs.style.display = 'inline';
  					abs.style.left = this.format(x) + 'px';
  					abs.style.top = this.format(y) + 'px';
  					abs.style.zoom = s.scale;
  					var box = this.createElement('div');
  					box.style.position = 'relative';
  					box.style.display = 'inline';
  					var margin = mxUtils.getAlignmentAsPoint(align, valign);
  					var dx = margin.x;
  					var dy = margin.y;
  					var div = this.createDiv(str, align, valign, overflow);
  					var inner = this.createElement('div');
  					if (dir != null)
  					{
  						div.setAttribute('dir', dir);
  					}
  					if (wrap && w > 0)
  					{
  						if (!clip)
  						{
  							div.style.width = Math.round(w) + 'px';
  						}
  						div.style.wordWrap = mxConstants.WORD_WRAP;
  						div.style.whiteSpace = 'normal';
  						if (div.style.wordWrap == 'break-word')
  						{
  							var tmp = div;
  							if (tmp.firstChild != null && tmp.firstChild.nodeName == 'DIV')
  							{
  								tmp.firstChild.style.width = '100%';
  							}
  						}
  					}
  					else
  					{
  						div.style.whiteSpace = 'nowrap';
  					}
  					var rot = s.rotation + (rotation || 0);
  					if (this.rotateHtml && rot != 0)
  					{
  						inner.style.display = 'inline';
  						inner.style.zoom = '1';
  						inner.appendChild(div);
  						if (document.documentMode == 8 && !mxClient.IS_EM && this.root.nodeName != 'DIV')
  						{
  							box.appendChild(inner);
  							abs.appendChild(box);
  						}
  						else
  						{
  							abs.appendChild(inner);
  						}
  					}
  					else if (document.documentMode == 8 && !mxClient.IS_EM)
  					{
  						box.appendChild(div);
  						abs.appendChild(box);
  					}
  					else
  					{
  						div.style.display = 'inline';
  						abs.appendChild(div);
  					}
  					if (this.root.nodeName != 'DIV')
  					{
  						var rect = this.createVmlElement('rect');
  						rect.stroked = 'false';
  						rect.filled = 'false';
  						rect.appendChild(abs);
  						this.root.appendChild(rect);
  					}
  					else
  					{
  						this.root.appendChild(abs);
  					}
  					if (clip)
  					{
  						div.style.overflow = 'hidden';
  						div.style.width = Math.round(w) + 'px';
  						if (!mxClient.IS_QUIRKS)
  						{
  							div.style.maxHeight = Math.round(h) + 'px';
  						}
  					}
  					else if (overflow == 'fill')
  					{
  						div.style.overflow = 'hidden';
  						div.style.width = (Math.max(0, w) + 1) + 'px';
  						div.style.height = (Math.max(0, h) + 1) + 'px';
  					}
  					else if (overflow == 'width')
  					{
  						div.style.overflow = 'hidden';
  						div.style.width = (Math.max(0, w) + 1) + 'px';
  						div.style.maxHeight = (Math.max(0, h) + 1) + 'px';
  					}
  					if (this.rotateHtml && rot != 0)
  					{
  						var rad = rot * (Math.PI / 180);
  						var real_cos = parseFloat(parseFloat(Math.cos(rad)).toFixed(8));
  						var real_sin = parseFloat(parseFloat(Math.sin(-rad)).toFixed(8));
  						rad %= 2 * Math.PI;
  						if (rad < 0) rad += 2 * Math.PI;
  						rad %= Math.PI;
  						if (rad > Math.PI / 2) rad = Math.PI - rad;
  						var cos = Math.cos(rad);
  						var sin = Math.sin(rad);
  						if (document.documentMode == 8 && !mxClient.IS_EM)
  						{
  							div.style.display = 'inline-block';
  							inner.style.display = 'inline-block';
  							box.style.display = 'inline-block';
  						}
  						div.style.visibility = 'hidden';
  						div.style.position = 'absolute';
  						document.body.appendChild(div);
  						var sizeDiv = div;
  						if (sizeDiv.firstChild != null && sizeDiv.firstChild.nodeName == 'DIV')
  						{
  							sizeDiv = sizeDiv.firstChild;
  						}
  						var tmp = sizeDiv.offsetWidth + 3;
  						var oh = sizeDiv.offsetHeight;
  						if (clip)
  						{
  							w = Math.min(w, tmp);
  							oh = Math.min(oh, h);
  						}
  						else
  						{
  							w = tmp;
  						}
  						if (wrap)
  						{
  							div.style.width = w + 'px';
  						}
  						if (mxClient.IS_QUIRKS && (clip || overflow == 'width') && oh > h)
  						{
  							oh = h;
  							div.style.height = oh + 'px';
  						}
  						h = oh;
  						var top_fix = (h - h * cos + w * -sin) / 2 - real_sin * w * (dx + 0.5) + real_cos * h * (dy + 0.5);
  						var left_fix = (w - w * cos + h * -sin) / 2 + real_cos * w * (dx + 0.5) + real_sin * h * (dy + 0.5);
  						if (abs.nodeName == 'group' && this.root.nodeName == 'DIV')
  						{
  							var pos = this.createElement('div');
  							pos.style.display = 'inline-block';
  							pos.style.position = 'absolute';
  							pos.style.left = this.format(x + (left_fix - w / 2) * s.scale) + 'px';
  							pos.style.top = this.format(y + (top_fix - h / 2) * s.scale) + 'px';
  							abs.parentNode.appendChild(pos);
  							pos.appendChild(abs);
  						}
  						else
  						{
  							var sc = (document.documentMode == 8 && !mxClient.IS_EM) ? 1 : s.scale;
  							abs.style.left = this.format(x + (left_fix - w / 2) * sc) + 'px';
  							abs.style.top = this.format(y + (top_fix - h / 2) * sc) + 'px';
  						}
  						inner.style.filter = "progid:DXImageTransform.Microsoft.Matrix(M11="+real_cos+", M12="+
  							real_sin+", M21="+(-real_sin)+", M22="+real_cos+", sizingMethod='auto expand')";
  						inner.style.backgroundColor = this.rotatedHtmlBackground;
  						if (this.state.alpha < 1)
  						{
  							inner.style.filter += 'alpha(opacity=' + (this.state.alpha * 100) + ')';
  						}
  						inner.appendChild(div);
  						div.style.position = '';
  						div.style.visibility = '';
  					}
  					else if (document.documentMode != 8 || mxClient.IS_EM)
  					{
  						div.style.verticalAlign = 'top';
  						if (this.state.alpha < 1)
  						{
  							abs.style.filter = 'alpha(opacity=' + (this.state.alpha * 100) + ')';
  						}
  						var divParent = div.parentNode;
  						div.style.visibility = 'hidden';
  						document.body.appendChild(div);
  						w = div.offsetWidth;
  						var oh = div.offsetHeight;
  						if (mxClient.IS_QUIRKS && clip && oh > h)
  						{
  							oh = h;
  							div.style.height = oh + 'px';
  						}
  						h = oh;
  						div.style.visibility = '';
  						divParent.appendChild(div);
  						abs.style.left = this.format(x + w * dx * this.state.scale) + 'px';
  						abs.style.top = this.format(y + h * dy * this.state.scale) + 'px';
  					}
  					else
  					{
  						if (this.state.alpha < 1)
  						{
  							div.style.filter = 'alpha(opacity=' + (this.state.alpha * 100) + ')';
  						}
  						box.style.left = (dx * 100) + '%';
  						box.style.top = (dy * 100) + '%';
  					}
  				}
  				else
  				{
  					this.plainText(x, y, w, h, mxUtils.htmlEntities(str, false), align, valign, wrap, format, overflow, clip, rotation, dir);
  				}
  			}
  		};
  		mxVmlCanvas2D.prototype.plainText = function(x, y, w, h, str, align, valign, wrap, format, overflow, clip, rotation, dir)
  		{
  			var s = this.state;
  			x = (x + s.dx) * s.scale;
  			y = (y + s.dy) * s.scale;
  			var node = this.createVmlElement('shape');
  			node.style.width = '1px';
  			node.style.height = '1px';
  			node.stroked = 'false';
  			var fill = this.createVmlElement('fill');
  			fill.color = s.fontColor;
  			fill.opacity = (s.alpha * 100) + '%';
  			node.appendChild(fill);
  			var path = this.createVmlElement('path');
  			path.textpathok = 'true';
  			path.v = 'm ' + this.format(0) + ' ' + this.format(0) + ' l ' + this.format(1) + ' ' + this.format(0);
  			node.appendChild(path);
  			var tp = this.createVmlElement('textpath');
  			tp.style.cssText = 'v-text-align:' + align;
  			tp.style.align = align;
  			tp.style.fontFamily = s.fontFamily;
  			tp.string = str;
  			tp.on = 'true';
  			var size = s.fontSize * s.scale / this.vmlScale;
  			tp.style.fontSize = size + 'px';
  			if ((s.fontStyle & mxConstants.FONT_BOLD) == mxConstants.FONT_BOLD)
  			{
  				tp.style.fontWeight = 'bold';
  			}
  			if ((s.fontStyle & mxConstants.FONT_ITALIC) == mxConstants.FONT_ITALIC)
  			{
  				tp.style.fontStyle = 'italic';
  			}
  			if ((s.fontStyle & mxConstants.FONT_UNDERLINE) == mxConstants.FONT_UNDERLINE)
  			{
  				tp.style.textDecoration = 'underline';
  			}
  			var lines = str.split('\n');
  			var textHeight = size + (lines.length - 1) * size * mxConstants.LINE_HEIGHT;
  			var dx = 0;
  			var dy = 0;
  			if (valign == mxConstants.ALIGN_BOTTOM)
  			{
  				dy = - textHeight / 2;
  			}
  			else if (valign != mxConstants.ALIGN_MIDDLE)
  			{
  				dy = textHeight / 2;
  			}
  			if (rotation != null)
  			{
  				node.style.rotation = rotation;
  				var rad = rotation * (Math.PI / 180);
  				dx = Math.sin(rad) * dy;
  				dy = Math.cos(rad) * dy;
  			}
  			node.appendChild(tp);
  			node.style.left = this.format(x - dx) + 'px';
  			node.style.top = this.format(y + dy) + 'px';
  			this.root.appendChild(node);
  		};
  		mxVmlCanvas2D.prototype.stroke = function()
  		{
  			this.addNode(false, true);
  		};
  		mxVmlCanvas2D.prototype.fill = function()
  		{
  			this.addNode(true, false);
  		};
  		mxVmlCanvas2D.prototype.fillAndStroke = function()
  		{
  			this.addNode(true, true);
  		};
  		__mxOutput.mxVmlCanvas2D = typeof mxVmlCanvas2D !== 'undefined' ? mxVmlCanvas2D : undefined;
  		function mxGuide(graph, states)
  		{
  			this.graph = graph;
  			this.setStates(states);
  		}		mxGuide.prototype.graph = null;
  		mxGuide.prototype.states = null;
  		mxGuide.prototype.horizontal = true;
  		mxGuide.prototype.vertical = true;
  		mxGuide.prototype.guideX = null;
  		mxGuide.prototype.guideY = null;
  		mxGuide.prototype.rounded = false;
  		mxGuide.prototype.tolerance = 2;
  		mxGuide.prototype.setStates = function(states)
  		{
  			this.states = states;
  		};
  		mxGuide.prototype.isEnabledForEvent = function(evt)
  		{
  			return true;
  		};
  		mxGuide.prototype.getGuideTolerance = function(gridEnabled)
  		{
  			return (gridEnabled && this.graph.gridEnabled) ? this.graph.gridSize / 2 : this.tolerance;
  		};
  		mxGuide.prototype.createGuideShape = function(horizontal)
  		{
  			var guide = new mxPolyline([], mxConstants.GUIDE_COLOR, mxConstants.GUIDE_STROKEWIDTH);
  			guide.isDashed = true;
  			return guide;
  		};
  		mxGuide.prototype.isStateIgnored = function(state)
  		{
  			return false;
  		};
  		mxGuide.prototype.move = function(bounds, delta, gridEnabled, clone)
  		{
  			if (this.states != null && (this.horizontal || this.vertical) && bounds != null && delta != null)
  			{
  				var scale = this.graph.getView().scale;
  				var tt = this.getGuideTolerance(gridEnabled) * scale;
  				var b = bounds.clone();
  				b.x += delta.x;
  				b.y += delta.y;
  				var overrideX = false;
  				var stateX = null;
  				var valueX = null;
  				var overrideY = false;
  				var stateY = null;
  				var valueY = null;
  				var ttX = tt;
  				var ttY = tt;
  				var left = b.x;
  				var right = b.x + b.width;
  				var center = b.getCenterX();
  				var top = b.y;
  				var bottom = b.y + b.height;
  				var middle = b.getCenterY();
  				function snapX(x, state, centerAlign)
  				{
  					var override = false;
  					if (centerAlign && Math.abs(x - center) < ttX)
  					{
  						delta.x = x - bounds.getCenterX();
  						ttX = Math.abs(x - center);
  						override = true;
  					}
  					else if (!centerAlign)
  					{
  						if (Math.abs(x - left) < ttX)
  						{
  							delta.x = x - bounds.x;
  							ttX = Math.abs(x - left);
  							override = true;
  						}
  						else if (Math.abs(x - right) < ttX)
  						{
  							delta.x = x - bounds.x - bounds.width;
  							ttX = Math.abs(x - right);
  							override = true;
  						}
  					}
  					if (override)
  					{
  						stateX = state;
  						valueX = x;
  						if (this.guideX == null)
  						{
  							this.guideX = this.createGuideShape(true);
  							this.guideX.dialect = (this.graph.dialect != mxConstants.DIALECT_SVG) ?
  								mxConstants.DIALECT_VML : mxConstants.DIALECT_SVG;
  							this.guideX.pointerEvents = false;
  							this.guideX.init(this.graph.getView().getOverlayPane());
  						}
  					}
  					overrideX = overrideX || override;
  				}				function snapY(y, state, centerAlign)
  				{
  					var override = false;
  					if (centerAlign && Math.abs(y - middle) < ttY)
  					{
  						delta.y = y - bounds.getCenterY();
  						ttY = Math.abs(y -  middle);
  						override = true;
  					}
  					else if (!centerAlign)
  					{
  						if (Math.abs(y - top) < ttY)
  						{
  							delta.y = y - bounds.y;
  							ttY = Math.abs(y - top);
  							override = true;
  						}
  						else if (Math.abs(y - bottom) < ttY)
  						{
  							delta.y = y - bounds.y - bounds.height;
  							ttY = Math.abs(y - bottom);
  							override = true;
  						}
  					}
  					if (override)
  					{
  						stateY = state;
  						valueY = y;
  						if (this.guideY == null)
  						{
  							this.guideY = this.createGuideShape(false);
  							this.guideY.dialect = (this.graph.dialect != mxConstants.DIALECT_SVG) ?
  								mxConstants.DIALECT_VML : mxConstants.DIALECT_SVG;
  							this.guideY.pointerEvents = false;
  							this.guideY.init(this.graph.getView().getOverlayPane());
  						}
  					}
  					overrideY = overrideY || override;
  				}				for (var i = 0; i < this.states.length; i++)
  				{
  					var state =  this.states[i];
  					if (state != null && !this.isStateIgnored(state))
  					{
  						if (this.horizontal)
  						{
  							snapX.call(this, state.getCenterX(), state, true);
  							snapX.call(this, state.x, state, false);
  							snapX.call(this, state.x + state.width, state, false);
  							if (state.cell == null)
  							{
  								snapX.call(this, state.getCenterX(), state, false);
  							}
  						}
  						if (this.vertical)
  						{
  							snapY.call(this, state.getCenterY(), state, true);
  							snapY.call(this, state.y, state, false);
  							snapY.call(this, state.y + state.height, state, false);
  							if (state.cell == null)
  							{
  								snapY.call(this, state.getCenterY(), state, false);
  							}
  						}
  					}
  				}
  				this.graph.snapDelta(delta, bounds, !gridEnabled, overrideX, overrideY);
  				delta = this.getDelta(bounds, stateX, delta.x, stateY, delta.y);
  				var c = this.graph.container;
  				if (!overrideX && this.guideX != null)
  				{
  					this.guideX.node.style.visibility = 'hidden';
  				}
  				else if (this.guideX != null)
  				{
  					var minY = null;
  		        	var maxY = null;
  					if (stateX != null && bounds != null)
  					{
  						minY = Math.min(bounds.y + delta.y - this.graph.panDy, stateX.y);
  						maxY = Math.max(bounds.y + bounds.height + delta.y - this.graph.panDy, stateX.y + stateX.height);
  					}
  					if (minY != null && maxY != null)
  					{
  						this.guideX.points = [new mxPoint(valueX, minY), new mxPoint(valueX, maxY)];
  					}
  					else
  					{
  						this.guideX.points = [new mxPoint(valueX, -this.graph.panDy),
  							new mxPoint(valueX, c.scrollHeight - 3 - this.graph.panDy)];
  					}
  					this.guideX.stroke = this.getGuideColor(stateX, true);
  					this.guideX.node.style.visibility = 'visible';
  					this.guideX.redraw();
  				}
  				if (!overrideY && this.guideY != null)
  				{
  					this.guideY.node.style.visibility = 'hidden';
  				}
  				else if (this.guideY != null)
  				{
  					var minX = null;
  		        	var maxX = null;
  					if (stateY != null && bounds != null)
  					{
  						minX = Math.min(bounds.x + delta.x - this.graph.panDx, stateY.x);
  						maxX = Math.max(bounds.x + bounds.width + delta.x - this.graph.panDx, stateY.x + stateY.width);
  					}
  					if (minX != null && maxX != null)
  					{
  						this.guideY.points = [new mxPoint(minX, valueY), new mxPoint(maxX, valueY)];
  					}
  					else
  					{
  						this.guideY.points = [new mxPoint(-this.graph.panDx, valueY),
  							new mxPoint(c.scrollWidth - 3 - this.graph.panDx, valueY)];
  					}
  					this.guideY.stroke = this.getGuideColor(stateY, false);
  					this.guideY.node.style.visibility = 'visible';
  					this.guideY.redraw();
  				}
  			}
  			return delta;
  		};
  		mxGuide.prototype.getDelta = function(bounds, stateX, dx, stateY, dy)
  		{
  			var s = this.graph.view.scale;
  			if (this.rounded || (stateX != null && stateX.cell == null))
  			{
  				dx = Math.round((bounds.x + dx) / s) * s - bounds.x;
  			}
  			if (this.rounded || (stateY != null && stateY.cell == null))
  			{
  				dy = Math.round((bounds.y + dy) / s) * s - bounds.y;
  			}
  			return new mxPoint(dx, dy);
  		};
  		mxGuide.prototype.getGuideColor = function(state, horizontal)
  		{
  			return mxConstants.GUIDE_COLOR;
  		};
  		mxGuide.prototype.hide = function()
  		{
  			this.setVisible(false);
  		};
  		mxGuide.prototype.setVisible = function(visible)
  		{
  			if (this.guideX != null)
  			{
  				this.guideX.node.style.visibility = (visible) ? 'visible' : 'hidden';
  			}
  			if (this.guideY != null)
  			{
  				this.guideY.node.style.visibility = (visible) ? 'visible' : 'hidden';
  			}
  		};
  		mxGuide.prototype.destroy = function()
  		{
  			if (this.guideX != null)
  			{
  				this.guideX.destroy();
  				this.guideX = null;
  			}
  			if (this.guideY != null)
  			{
  				this.guideY.destroy();
  				this.guideY = null;
  			}
  		};
  		__mxOutput.mxGuide = typeof mxGuide !== 'undefined' ? mxGuide : undefined;
  		function mxShape(stencil)
  		{
  			this.stencil = stencil;
  			this.initStyles();
  		}		mxShape.prototype.dialect = null;
  		mxShape.prototype.scale = 1;
  		mxShape.prototype.antiAlias = true;
  		mxShape.prototype.minSvgStrokeWidth = 1;
  		mxShape.prototype.bounds = null;
  		mxShape.prototype.points = null;
  		mxShape.prototype.node = null;
  		mxShape.prototype.state = null;
  		mxShape.prototype.style = null;
  		mxShape.prototype.boundingBox = null;
  		mxShape.prototype.stencil = null;
  		mxShape.prototype.svgStrokeTolerance = 8;
  		mxShape.prototype.pointerEvents = true;
  		mxShape.prototype.svgPointerEvents = 'all';
  		mxShape.prototype.shapePointerEvents = false;
  		mxShape.prototype.stencilPointerEvents = false;
  		mxShape.prototype.vmlScale = 1;
  		mxShape.prototype.outline = false;
  		mxShape.prototype.visible = true;
  		mxShape.prototype.useSvgBoundingBox = false;
  		mxShape.prototype.init = function(container)
  		{
  			if (this.node == null)
  			{
  				this.node = this.create(container);
  				if (container != null)
  				{
  					container.appendChild(this.node);
  				}
  			}
  		};
  		mxShape.prototype.initStyles = function(container)
  		{
  			this.strokewidth = 1;
  			this.rotation = 0;
  			this.opacity = 100;
  			this.fillOpacity = 100;
  			this.strokeOpacity = 100;
  			this.flipH = false;
  			this.flipV = false;
  		};
  		mxShape.prototype.isParseVml = function()
  		{
  			return true;
  		};
  		mxShape.prototype.isHtmlAllowed = function()
  		{
  			return false;
  		};
  		mxShape.prototype.getSvgScreenOffset = function()
  		{
  			var sw = this.stencil && this.stencil.strokewidth != 'inherit' ? Number(this.stencil.strokewidth) : this.strokewidth;
  			return (mxUtils.mod(Math.max(1, Math.round(sw * this.scale)), 2) == 1) ? 0.5 : 0;
  		};
  		mxShape.prototype.create = function(container)
  		{
  			var node = null;
  			if (container != null && container.ownerSVGElement != null)
  			{
  				node = this.createSvg(container);
  			}
  			else if (document.documentMode == 8 || !mxClient.IS_VML ||
  				(this.dialect != mxConstants.DIALECT_VML && this.isHtmlAllowed()))
  			{
  				node = this.createHtml(container);
  			}
  			else
  			{
  				node = this.createVml(container);
  			}
  			return node;
  		};
  		mxShape.prototype.createSvg = function()
  		{
  			return document.createElementNS(mxConstants.NS_SVG, 'g');
  		};
  		mxShape.prototype.createVml = function()
  		{
  			var node = document.createElement(mxClient.VML_PREFIX + ':group');
  			node.style.position = 'absolute';
  			return node;
  		};
  		mxShape.prototype.createHtml = function()
  		{
  			var node = document.createElement('div');
  			node.style.position = 'absolute';
  			return node;
  		};
  		mxShape.prototype.reconfigure = function()
  		{
  			this.redraw();
  		};
  		mxShape.prototype.redraw = function()
  		{
  			this.updateBoundsFromPoints();
  			if (this.visible && this.checkBounds())
  			{
  				this.node.style.visibility = 'visible';
  				this.clear();
  				if (this.node.nodeName == 'DIV' && (this.isHtmlAllowed() || !mxClient.IS_VML))
  				{
  					this.redrawHtmlShape();
  				}
  				else
  				{
  					this.redrawShape();
  				}
  				this.updateBoundingBox();
  			}
  			else
  			{
  				this.node.style.visibility = 'hidden';
  				this.boundingBox = null;
  			}
  		};
  		mxShape.prototype.clear = function()
  		{
  			if (this.node.ownerSVGElement != null)
  			{
  				while (this.node.lastChild != null)
  				{
  					this.node.removeChild(this.node.lastChild);
  				}
  			}
  			else
  			{
  				this.node.style.cssText = 'position:absolute;' + ((this.cursor != null) ?
  					('cursor:' + this.cursor + ';') : '');
  				this.node.innerHTML = '';
  			}
  		};
  		mxShape.prototype.updateBoundsFromPoints = function()
  		{
  			var pts = this.points;
  			if (pts != null && pts.length > 0 && pts[0] != null)
  			{
  				this.bounds = new mxRectangle(Number(pts[0].x), Number(pts[0].y), 1, 1);
  				for (var i = 1; i < this.points.length; i++)
  				{
  					if (pts[i] != null)
  					{
  						this.bounds.add(new mxRectangle(Number(pts[i].x), Number(pts[i].y), 1, 1));
  					}
  				}
  			}
  		};
  		mxShape.prototype.getLabelBounds = function(rect)
  		{
  			var d = mxUtils.getValue(this.style, mxConstants.STYLE_DIRECTION, mxConstants.DIRECTION_EAST);
  			var bounds = rect;
  			if (d != mxConstants.DIRECTION_SOUTH && d != mxConstants.DIRECTION_NORTH &&
  				this.state != null && this.state.text != null &&
  				this.state.text.isPaintBoundsInverted())
  			{
  				bounds = bounds.clone();
  				var tmp = bounds.width;
  				bounds.width = bounds.height;
  				bounds.height = tmp;
  			}
  			var m = this.getLabelMargins(bounds);
  			if (m != null)
  			{
  				var flipH = mxUtils.getValue(this.style, mxConstants.STYLE_FLIPH, false) == '1';
  				var flipV = mxUtils.getValue(this.style, mxConstants.STYLE_FLIPV, false) == '1';
  				if (this.state != null && this.state.text != null &&
  					this.state.text.isPaintBoundsInverted())
  				{
  					var tmp = m.x;
  					m.x = m.height;
  					m.height = m.width;
  					m.width = m.y;
  					m.y = tmp;
  					tmp = flipH;
  					flipH = flipV;
  					flipV = tmp;
  				}
  				return mxUtils.getDirectedBounds(rect, m, this.style, flipH, flipV);
  			}
  			return rect;
  		};
  		mxShape.prototype.getLabelMargins= function(rect)
  		{
  			return null;
  		};
  		mxShape.prototype.checkBounds = function()
  		{
  			return (!isNaN(this.scale) && isFinite(this.scale) && this.scale > 0 &&
  					this.bounds != null && !isNaN(this.bounds.x) && !isNaN(this.bounds.y) &&
  					!isNaN(this.bounds.width) && !isNaN(this.bounds.height) &&
  					this.bounds.width > 0 && this.bounds.height > 0);
  		};
  		mxShape.prototype.createVmlGroup = function()
  		{
  			var node = document.createElement(mxClient.VML_PREFIX + ':group');
  			node.style.position = 'absolute';
  			node.style.width = this.node.style.width;
  			node.style.height = this.node.style.height;
  			return node;
  		};
  		mxShape.prototype.redrawShape = function()
  		{
  			var canvas = this.createCanvas();
  			if (canvas != null)
  			{
  				canvas.pointerEvents = this.pointerEvents;
  				this.beforePaint(canvas);
  				this.paint(canvas);
  				this.afterPaint(canvas);
  				if (this.node != canvas.root)
  				{
  					this.node.insertAdjacentHTML('beforeend', canvas.root.outerHTML);
  				}
  				if (this.node.nodeName == 'DIV' && document.documentMode == 8)
  				{
  					this.node.style.filter = '';
  					mxUtils.addTransparentBackgroundFilter(this.node);
  				}
  				this.destroyCanvas(canvas);
  			}
  		};
  		mxShape.prototype.createCanvas = function()
  		{
  			var canvas = null;
  			if (this.node.ownerSVGElement != null)
  			{
  				canvas = this.createSvgCanvas();
  			}
  			else if (mxClient.IS_VML)
  			{
  				this.updateVmlContainer();
  				canvas = this.createVmlCanvas();
  			}
  			if (canvas != null && this.outline)
  			{
  				canvas.setStrokeWidth(this.strokewidth);
  				canvas.setStrokeColor(this.stroke);
  				if (this.isDashed != null)
  				{
  					canvas.setDashed(this.isDashed);
  				}
  				canvas.setStrokeWidth = function() {};
  				canvas.setStrokeColor = function() {};
  				canvas.setFillColor = function() {};
  				canvas.setGradient = function() {};
  				canvas.setDashed = function() {};
  				canvas.text = function() {};
  			}
  			return canvas;
  		};
  		mxShape.prototype.createSvgCanvas = function()
  		{
  			var canvas = new mxSvgCanvas2D(this.node, false);
  			canvas.strokeTolerance = (this.pointerEvents) ? this.svgStrokeTolerance : 0;
  			canvas.pointerEventsValue = this.svgPointerEvents;
  			var off = this.getSvgScreenOffset();
  			if (off != 0)
  			{
  				this.node.setAttribute('transform', 'translate(' + off + ',' + off + ')');
  			}
  			else
  			{
  				this.node.removeAttribute('transform');
  			}
  			canvas.minStrokeWidth = this.minSvgStrokeWidth;
  			if (!this.antiAlias)
  			{
  				canvas.format = function(value)
  				{
  					return Math.round(parseFloat(value));
  				};
  			}
  			return canvas;
  		};
  		mxShape.prototype.createVmlCanvas = function()
  		{
  			var node = (document.documentMode == 8 && this.isParseVml()) ? this.createVmlGroup() : this.node;
  			var canvas = new mxVmlCanvas2D(node);
  			if (node.tagUrn != '')
  			{
  				var w = Math.max(1, Math.round(this.bounds.width));
  				var h = Math.max(1, Math.round(this.bounds.height));
  				node.coordsize = (w * this.vmlScale) + ',' + (h * this.vmlScale);
  				canvas.scale(this.vmlScale);
  				canvas.vmlScale = this.vmlScale;
  			}
  			var s = this.scale;
  			canvas.translate(-Math.round(this.bounds.x / s), -Math.round(this.bounds.y / s));
  			return canvas;
  		};
  		mxShape.prototype.updateVmlContainer = function()
  		{
  			this.node.style.left = Math.round(this.bounds.x) + 'px';
  			this.node.style.top = Math.round(this.bounds.y) + 'px';
  			var w = Math.max(1, Math.round(this.bounds.width));
  			var h = Math.max(1, Math.round(this.bounds.height));
  			this.node.style.width = w + 'px';
  			this.node.style.height = h + 'px';
  			this.node.style.overflow = 'visible';
  		};
  		mxShape.prototype.redrawHtmlShape = function()
  		{
  			this.updateHtmlBounds(this.node);
  			this.updateHtmlFilters(this.node);
  			this.updateHtmlColors(this.node);
  		};
  		mxShape.prototype.updateHtmlFilters = function(node)
  		{
  			var f = '';
  			if (this.opacity < 100)
  			{
  				f += 'alpha(opacity=' + (this.opacity) + ')';
  			}
  			if (this.isShadow)
  			{
  				f += 'progid:DXImageTransform.Microsoft.dropShadow (' +
  					'OffX=\'' + Math.round(mxConstants.SHADOW_OFFSET_X * this.scale) + '\', ' +
  					'OffY=\'' + Math.round(mxConstants.SHADOW_OFFSET_Y * this.scale) + '\', ' +
  					'Color=\'' + mxConstants.VML_SHADOWCOLOR + '\')';
  			}
  			if (this.fill != null && this.fill != mxConstants.NONE && this.gradient && this.gradient != mxConstants.NONE)
  			{
  				var start = this.fill;
  				var end = this.gradient;
  				var type = '0';
  				var lookup = {east:0,south:1,west:2,north:3};
  				var dir = (this.direction != null) ? lookup[this.direction] : 0;
  				if (this.gradientDirection != null)
  				{
  					dir = mxUtils.mod(dir + lookup[this.gradientDirection] - 1, 4);
  				}
  				if (dir == 1)
  				{
  					type = '1';
  					var tmp = start;
  					start = end;
  					end = tmp;
  				}
  				else if (dir == 2)
  				{
  					var tmp = start;
  					start = end;
  					end = tmp;
  				}
  				else if (dir == 3)
  				{
  					type = '1';
  				}
  				f += 'progid:DXImageTransform.Microsoft.gradient(' +
  					'startColorStr=\'' + start + '\', endColorStr=\'' + end +
  					'\', gradientType=\'' + type + '\')';
  			}
  			node.style.filter = f;
  		};
  		mxShape.prototype.updateHtmlColors = function(node)
  		{
  			var color = this.stroke;
  			if (color != null && color != mxConstants.NONE)
  			{
  				node.style.borderColor = color;
  				if (this.isDashed)
  				{
  					node.style.borderStyle = 'dashed';
  				}
  				else if (this.strokewidth > 0)
  				{
  					node.style.borderStyle = 'solid';
  				}
  				node.style.borderWidth = Math.max(1, Math.ceil(this.strokewidth * this.scale)) + 'px';
  			}
  			else
  			{
  				node.style.borderWidth = '0px';
  			}
  			color = (this.outline) ? null : this.fill;
  			if (color != null && color != mxConstants.NONE)
  			{
  				node.style.backgroundColor = color;
  				node.style.backgroundImage = 'none';
  			}
  			else if (this.pointerEvents)
  			{
  				 node.style.backgroundColor = 'transparent';
  			}
  			else if (document.documentMode == 8)
  			{
  				mxUtils.addTransparentBackgroundFilter(node);
  			}
  			else
  			{
  				this.setTransparentBackgroundImage(node);
  			}
  		};
  		mxShape.prototype.updateHtmlBounds = function(node)
  		{
  			var sw = (document.documentMode >= 9) ? 0 : Math.ceil(this.strokewidth * this.scale);
  			node.style.borderWidth = Math.max(1, sw) + 'px';
  			node.style.overflow = 'hidden';
  			node.style.left = Math.round(this.bounds.x - sw / 2) + 'px';
  			node.style.top = Math.round(this.bounds.y - sw / 2) + 'px';
  			if (document.compatMode == 'CSS1Compat')
  			{
  				sw = -sw;
  			}
  			node.style.width = Math.round(Math.max(0, this.bounds.width + sw)) + 'px';
  			node.style.height = Math.round(Math.max(0, this.bounds.height + sw)) + 'px';
  		};
  		mxShape.prototype.destroyCanvas = function(canvas)
  		{
  			if (canvas instanceof mxSvgCanvas2D)
  			{
  				for (var key in canvas.gradients)
  				{
  					var gradient = canvas.gradients[key];
  					if (gradient != null)
  					{
  						gradient.mxRefCount = (gradient.mxRefCount || 0) + 1;
  					}
  				}
  				this.releaseSvgGradients(this.oldGradients);
  				this.oldGradients = canvas.gradients;
  			}
  		};
  		mxShape.prototype.beforePaint = function(c) { };
  		mxShape.prototype.afterPaint = function(c) { };
  		mxShape.prototype.paint = function(c)
  		{
  			var strokeDrawn = false;
  			if (c != null && this.outline)
  			{
  				var stroke = c.stroke;
  				c.stroke = function()
  				{
  					strokeDrawn = true;
  					stroke.apply(this, arguments);
  				};
  				var fillAndStroke = c.fillAndStroke;
  				c.fillAndStroke = function()
  				{
  					strokeDrawn = true;
  					fillAndStroke.apply(this, arguments);
  				};
  			}
  			var s = this.scale;
  			var x = this.bounds.x / s;
  			var y = this.bounds.y / s;
  			var w = this.bounds.width / s;
  			var h = this.bounds.height / s;
  			if (this.isPaintBoundsInverted())
  			{
  				var t = (w - h) / 2;
  				x += t;
  				y -= t;
  				var tmp = w;
  				w = h;
  				h = tmp;
  			}
  			this.updateTransform(c, x, y, w, h);
  			this.configureCanvas(c, x, y, w, h);
  			var bg = null;
  			if ((this.stencil == null && this.points == null && this.shapePointerEvents) ||
  				(this.stencil != null && this.stencilPointerEvents))
  			{
  				var bb = this.createBoundingBox();
  				if (this.dialect == mxConstants.DIALECT_SVG)
  				{
  					bg = this.createTransparentSvgRectangle(bb.x, bb.y, bb.width, bb.height);
  					this.node.appendChild(bg);
  				}
  				else
  				{
  					var rect = c.createRect('rect', bb.x / s, bb.y / s, bb.width / s, bb.height / s);
  					rect.appendChild(c.createTransparentFill());
  					rect.stroked = 'false';
  					c.root.appendChild(rect);
  				}
  			}
  			if (this.stencil != null)
  			{
  				this.stencil.drawShape(c, this, x, y, w, h);
  			}
  			else
  			{
  				c.setStrokeWidth(this.strokewidth);
  				if (this.points != null)
  				{
  					var pts = [];
  					for (var i = 0; i < this.points.length; i++)
  					{
  						if (this.points[i] != null)
  						{
  							pts.push(new mxPoint(this.points[i].x / s, this.points[i].y / s));
  						}
  					}
  					this.paintEdgeShape(c, pts);
  				}
  				else
  				{
  					this.paintVertexShape(c, x, y, w, h);
  				}
  			}
  			if (bg != null && c.state != null && c.state.transform != null)
  			{
  				bg.setAttribute('transform', c.state.transform);
  			}
  			if (c != null && this.outline && !strokeDrawn)
  			{
  				c.rect(x, y, w, h);
  				c.stroke();
  			}
  		};
  		mxShape.prototype.configureCanvas = function(c, x, y, w, h)
  		{
  			var dash = null;
  			if (this.style != null)
  			{
  				dash = this.style['dashPattern'];
  			}
  			c.setAlpha(this.opacity / 100);
  			c.setFillAlpha(this.fillOpacity / 100);
  			c.setStrokeAlpha(this.strokeOpacity / 100);
  			if (this.isShadow != null)
  			{
  				c.setShadow(this.isShadow);
  			}
  			if (this.isDashed != null)
  			{
  				c.setDashed(this.isDashed, (this.style != null) ?
  					mxUtils.getValue(this.style, mxConstants.STYLE_FIX_DASH, false) == 1 : false);
  			}
  			if (dash != null)
  			{
  				c.setDashPattern(dash);
  			}
  			if (this.fill != null && this.fill != mxConstants.NONE && this.gradient && this.gradient != mxConstants.NONE)
  			{
  				var b = this.getGradientBounds(c, x, y, w, h);
  				c.setGradient(this.fill, this.gradient, b.x, b.y, b.width, b.height, this.gradientDirection);
  			}
  			else
  			{
  				c.setFillColor(this.fill);
  			}
  			c.setStrokeColor(this.stroke);
  		};
  		mxShape.prototype.getGradientBounds = function(c, x, y, w, h)
  		{
  			return new mxRectangle(x, y, w, h);
  		};
  		mxShape.prototype.updateTransform = function(c, x, y, w, h)
  		{
  			c.scale(this.scale);
  			c.rotate(this.getShapeRotation(), this.flipH, this.flipV, x + w / 2, y + h / 2);
  		};
  		mxShape.prototype.paintVertexShape = function(c, x, y, w, h)
  		{
  			this.paintBackground(c, x, y, w, h);
  			if (!this.outline || this.style == null || mxUtils.getValue(
  				this.style, mxConstants.STYLE_BACKGROUND_OUTLINE, 0) == 0)
  			{
  				c.setShadow(false);
  				this.paintForeground(c, x, y, w, h);
  			}
  		};
  		mxShape.prototype.paintBackground = function(c, x, y, w, h) { };
  		mxShape.prototype.paintForeground = function(c, x, y, w, h) { };
  		mxShape.prototype.paintEdgeShape = function(c, pts) { };
  		mxShape.prototype.getArcSize = function(w, h)
  		{
  			var r = 0;
  			if (mxUtils.getValue(this.style, mxConstants.STYLE_ABSOLUTE_ARCSIZE, 0) == '1')
  			{
  				r = Math.min(w / 2, Math.min(h / 2, mxUtils.getValue(this.style,
  					mxConstants.STYLE_ARCSIZE, mxConstants.LINE_ARCSIZE) / 2));
  			}
  			else
  			{
  				var f = mxUtils.getValue(this.style, mxConstants.STYLE_ARCSIZE,
  					mxConstants.RECTANGLE_ROUNDING_FACTOR * 100) / 100;
  				r = Math.min(w * f, h * f);
  			}
  			return r;
  		};
  		mxShape.prototype.paintGlassEffect = function(c, x, y, w, h, arc)
  		{
  			var sw = Math.ceil(this.strokewidth / 2);
  			var size = 0.4;
  			c.setGradient('#ffffff', '#ffffff', x, y, w, h * 0.6, 'south', 0.9, 0.1);
  			c.begin();
  			arc += 2 * sw;
  			if (this.isRounded)
  			{
  				c.moveTo(x - sw + arc, y - sw);
  				c.quadTo(x - sw, y - sw, x - sw, y - sw + arc);
  				c.lineTo(x - sw, y + h * size);
  				c.quadTo(x + w * 0.5, y + h * 0.7, x + w + sw, y + h * size);
  				c.lineTo(x + w + sw, y - sw + arc);
  				c.quadTo(x + w + sw, y - sw, x + w + sw - arc, y - sw);
  			}
  			else
  			{
  				c.moveTo(x - sw, y - sw);
  				c.lineTo(x - sw, y + h * size);
  				c.quadTo(x + w * 0.5, y + h * 0.7, x + w + sw, y + h * size);
  				c.lineTo(x + w + sw, y - sw);
  			}
  			c.close();
  			c.fill();
  		};
  		mxShape.prototype.addPoints = function(c, pts, rounded, arcSize, close, exclude, initialMove)
  		{
  			if (pts != null && pts.length > 0)
  			{
  				initialMove = (initialMove != null) ? initialMove : true;
  				var pe = pts[pts.length - 1];
  				if (close && rounded)
  				{
  					pts = pts.slice();
  					var p0 = pts[0];
  					var wp = new mxPoint(pe.x + (p0.x - pe.x) / 2, pe.y + (p0.y - pe.y) / 2);
  					pts.splice(0, 0, wp);
  				}
  				var pt = pts[0];
  				var i = 1;
  				if (initialMove)
  				{
  					c.moveTo(pt.x, pt.y);
  				}
  				else
  				{
  					c.lineTo(pt.x, pt.y);
  				}
  				while (i < ((close) ? pts.length : pts.length - 1))
  				{
  					var tmp = pts[mxUtils.mod(i, pts.length)];
  					var dx = pt.x - tmp.x;
  					var dy = pt.y - tmp.y;
  					if (rounded && (dx != 0 || dy != 0) && (exclude == null || mxUtils.indexOf(exclude, i - 1) < 0))
  					{
  						var dist = Math.sqrt(dx * dx + dy * dy);
  						var nx1 = dx * Math.min(arcSize, dist / 2) / dist;
  						var ny1 = dy * Math.min(arcSize, dist / 2) / dist;
  						var x1 = tmp.x + nx1;
  						var y1 = tmp.y + ny1;
  						c.lineTo(x1, y1);
  						var next = pts[mxUtils.mod(i + 1, pts.length)];
  						while (i < pts.length - 2 && Math.round(next.x - tmp.x) == 0 && Math.round(next.y - tmp.y) == 0)
  						{
  							next = pts[mxUtils.mod(i + 2, pts.length)];
  							i++;
  						}
  						dx = next.x - tmp.x;
  						dy = next.y - tmp.y;
  						dist = Math.max(1, Math.sqrt(dx * dx + dy * dy));
  						var nx2 = dx * Math.min(arcSize, dist / 2) / dist;
  						var ny2 = dy * Math.min(arcSize, dist / 2) / dist;
  						var x2 = tmp.x + nx2;
  						var y2 = tmp.y + ny2;
  						c.quadTo(tmp.x, tmp.y, x2, y2);
  						tmp = new mxPoint(x2, y2);
  					}
  					else
  					{
  						c.lineTo(tmp.x, tmp.y);
  					}
  					pt = tmp;
  					i++;
  				}
  				if (close)
  				{
  					c.close();
  				}
  				else
  				{
  					c.lineTo(pe.x, pe.y);
  				}
  			}
  		};
  		mxShape.prototype.resetStyles = function()
  		{
  			this.initStyles();
  			this.spacing = 0;
  			delete this.fill;
  			delete this.gradient;
  			delete this.gradientDirection;
  			delete this.stroke;
  			delete this.startSize;
  			delete this.endSize;
  			delete this.startArrow;
  			delete this.endArrow;
  			delete this.direction;
  			delete this.isShadow;
  			delete this.isDashed;
  			delete this.isRounded;
  			delete this.glass;
  		};
  		mxShape.prototype.apply = function(state)
  		{
  			this.state = state;
  			this.style = state.style;
  			if (this.style != null)
  			{
  				this.fill = mxUtils.getValue(this.style, mxConstants.STYLE_FILLCOLOR, this.fill);
  				this.gradient = mxUtils.getValue(this.style, mxConstants.STYLE_GRADIENTCOLOR, this.gradient);
  				this.gradientDirection = mxUtils.getValue(this.style, mxConstants.STYLE_GRADIENT_DIRECTION, this.gradientDirection);
  				this.opacity = mxUtils.getValue(this.style, mxConstants.STYLE_OPACITY, this.opacity);
  				this.fillOpacity = mxUtils.getValue(this.style, mxConstants.STYLE_FILL_OPACITY, this.fillOpacity);
  				this.strokeOpacity = mxUtils.getValue(this.style, mxConstants.STYLE_STROKE_OPACITY, this.strokeOpacity);
  				this.stroke = mxUtils.getValue(this.style, mxConstants.STYLE_STROKECOLOR, this.stroke);
  				this.strokewidth = mxUtils.getNumber(this.style, mxConstants.STYLE_STROKEWIDTH, this.strokewidth);
  				this.spacing = mxUtils.getValue(this.style, mxConstants.STYLE_SPACING, this.spacing);
  				this.startSize = mxUtils.getNumber(this.style, mxConstants.STYLE_STARTSIZE, this.startSize);
  				this.endSize = mxUtils.getNumber(this.style, mxConstants.STYLE_ENDSIZE, this.endSize);
  				this.startArrow = mxUtils.getValue(this.style, mxConstants.STYLE_STARTARROW, this.startArrow);
  				this.endArrow = mxUtils.getValue(this.style, mxConstants.STYLE_ENDARROW, this.endArrow);
  				this.rotation = mxUtils.getValue(this.style, mxConstants.STYLE_ROTATION, this.rotation);
  				this.direction = mxUtils.getValue(this.style, mxConstants.STYLE_DIRECTION, this.direction);
  				this.flipH = mxUtils.getValue(this.style, mxConstants.STYLE_FLIPH, 0) == 1;
  				this.flipV = mxUtils.getValue(this.style, mxConstants.STYLE_FLIPV, 0) == 1;
  				if (this.stencil != null)
  				{
  					this.flipH = mxUtils.getValue(this.style, 'stencilFlipH', 0) == 1 || this.flipH;
  					this.flipV = mxUtils.getValue(this.style, 'stencilFlipV', 0) == 1 || this.flipV;
  				}
  				if (this.direction == mxConstants.DIRECTION_NORTH || this.direction == mxConstants.DIRECTION_SOUTH)
  				{
  					var tmp = this.flipH;
  					this.flipH = this.flipV;
  					this.flipV = tmp;
  				}
  				this.isShadow = mxUtils.getValue(this.style, mxConstants.STYLE_SHADOW, this.isShadow) == 1;
  				this.isDashed = mxUtils.getValue(this.style, mxConstants.STYLE_DASHED, this.isDashed) == 1;
  				this.isRounded = mxUtils.getValue(this.style, mxConstants.STYLE_ROUNDED, this.isRounded) == 1;
  				this.glass = mxUtils.getValue(this.style, mxConstants.STYLE_GLASS, this.glass) == 1;
  				if (this.fill == mxConstants.NONE)
  				{
  					this.fill = null;
  				}
  				if (this.gradient == mxConstants.NONE)
  				{
  					this.gradient = null;
  				}
  				if (this.stroke == mxConstants.NONE)
  				{
  					this.stroke = null;
  				}
  			}
  		};
  		mxShape.prototype.setCursor = function(cursor)
  		{
  			if (cursor == null)
  			{
  				cursor = '';
  			}
  			this.cursor = cursor;
  			if (this.node != null)
  			{
  				this.node.style.cursor = cursor;
  			}
  		};
  		mxShape.prototype.getCursor = function()
  		{
  			return this.cursor;
  		};
  		mxShape.prototype.isRoundable = function()
  		{
  			return false;
  		};
  		mxShape.prototype.updateBoundingBox = function()
  		{
  			if (this.useSvgBoundingBox && this.node != null && this.node.ownerSVGElement != null)
  			{
  				try
  				{
  					var b = this.node.getBBox();
  					if (b.width > 0 && b.height > 0)
  					{
  						this.boundingBox = new mxRectangle(b.x, b.y, b.width, b.height);
  						this.boundingBox.grow(this.strokewidth * this.scale / 2);
  						return;
  					}
  				}
  				catch(e)
  				{
  				}
  			}
  			if (this.bounds != null)
  			{
  				var bbox = this.createBoundingBox();
  				if (bbox != null)
  				{
  					this.augmentBoundingBox(bbox);
  					var rot = this.getShapeRotation();
  					if (rot != 0)
  					{
  						bbox = mxUtils.getBoundingBox(bbox, rot);
  					}
  				}
  				this.boundingBox = bbox;
  			}
  		};
  		mxShape.prototype.createBoundingBox = function()
  		{
  			var bb = this.bounds.clone();
  			if ((this.stencil != null && (this.direction == mxConstants.DIRECTION_NORTH ||
  				this.direction == mxConstants.DIRECTION_SOUTH)) || this.isPaintBoundsInverted())
  			{
  				bb.rotate90();
  			}
  			return bb;
  		};
  		mxShape.prototype.augmentBoundingBox = function(bbox)
  		{
  			if (this.isShadow)
  			{
  				bbox.width += Math.ceil(mxConstants.SHADOW_OFFSET_X * this.scale);
  				bbox.height += Math.ceil(mxConstants.SHADOW_OFFSET_Y * this.scale);
  			}
  			bbox.grow(this.strokewidth * this.scale / 2);
  		};
  		mxShape.prototype.isPaintBoundsInverted = function()
  		{
  			return this.stencil == null && (this.direction == mxConstants.DIRECTION_NORTH ||
  					this.direction == mxConstants.DIRECTION_SOUTH);
  		};
  		mxShape.prototype.getRotation = function()
  		{
  			return (this.rotation != null) ? this.rotation : 0;
  		};
  		mxShape.prototype.getTextRotation = function()
  		{
  			var rot = this.getRotation();
  			if (mxUtils.getValue(this.style, mxConstants.STYLE_HORIZONTAL, 1) != 1)
  			{
  				rot += mxText.prototype.verticalTextRotation;
  			}
  			return rot;
  		};
  		mxShape.prototype.getShapeRotation = function()
  		{
  			var rot = this.getRotation();
  			if (this.direction != null)
  			{
  				if (this.direction == mxConstants.DIRECTION_NORTH)
  				{
  					rot += 270;
  				}
  				else if (this.direction == mxConstants.DIRECTION_WEST)
  				{
  					rot += 180;
  				}
  				else if (this.direction == mxConstants.DIRECTION_SOUTH)
  				{
  					rot += 90;
  				}
  			}
  			return rot;
  		};
  		mxShape.prototype.createTransparentSvgRectangle = function(x, y, w, h)
  		{
  			var rect = document.createElementNS(mxConstants.NS_SVG, 'rect');
  			rect.setAttribute('x', x);
  			rect.setAttribute('y', y);
  			rect.setAttribute('width', w);
  			rect.setAttribute('height', h);
  			rect.setAttribute('fill', 'none');
  			rect.setAttribute('stroke', 'none');
  			rect.setAttribute('pointer-events', 'all');
  			return rect;
  		};
  		mxShape.prototype.setTransparentBackgroundImage = function(node)
  		{
  			node.style.backgroundImage = 'url(\'' + mxClient.imageBasePath + '/transparent.gif\')';
  		};
  		mxShape.prototype.releaseSvgGradients = function(grads)
  		{
  			if (grads != null)
  			{
  				for (var key in grads)
  				{
  					var gradient = grads[key];
  					if (gradient != null)
  					{
  						gradient.mxRefCount = (gradient.mxRefCount || 0) - 1;
  						if (gradient.mxRefCount == 0 && gradient.parentNode != null)
  						{
  							gradient.parentNode.removeChild(gradient);
  						}
  					}
  				}
  			}
  		};
  		mxShape.prototype.destroy = function()
  		{
  			if (this.node != null)
  			{
  				mxEvent.release(this.node);
  				if (this.node.parentNode != null)
  				{
  					this.node.parentNode.removeChild(this.node);
  				}
  				this.node = null;
  			}
  			this.releaseSvgGradients(this.oldGradients);
  			this.oldGradients = null;
  		};
  		__mxOutput.mxShape = typeof mxShape !== 'undefined' ? mxShape : undefined;
  		function mxStencil(desc)
  		{
  			this.desc = desc;
  			this.parseDescription();
  			this.parseConstraints();
  		}		mxUtils.extend(mxStencil, mxShape);
  		mxStencil.defaultLocalized = false;
  		mxStencil.allowEval = false;
  		mxStencil.prototype.desc = null;
  		mxStencil.prototype.constraints = null;
  		mxStencil.prototype.aspect = null;
  		mxStencil.prototype.w0 = null;
  		mxStencil.prototype.h0 = null;
  		mxStencil.prototype.bgNode = null;
  		mxStencil.prototype.fgNode = null;
  		mxStencil.prototype.strokewidth = null;
  		mxStencil.prototype.parseDescription = function()
  		{
  			this.fgNode = this.desc.getElementsByTagName('foreground')[0];
  			this.bgNode = this.desc.getElementsByTagName('background')[0];
  			this.w0 = Number(this.desc.getAttribute('w') || 100);
  			this.h0 = Number(this.desc.getAttribute('h') || 100);
  			var aspect = this.desc.getAttribute('aspect');
  			this.aspect = (aspect != null) ? aspect : 'variable';
  			var sw = this.desc.getAttribute('strokewidth');
  			this.strokewidth = (sw != null) ? sw : '1';
  		};
  		mxStencil.prototype.parseConstraints = function()
  		{
  			var conns = this.desc.getElementsByTagName('connections')[0];
  			if (conns != null)
  			{
  				var tmp = mxUtils.getChildNodes(conns);
  				if (tmp != null && tmp.length > 0)
  				{
  					this.constraints = [];
  					for (var i = 0; i < tmp.length; i++)
  					{
  						this.constraints.push(this.parseConstraint(tmp[i]));
  					}
  				}
  			}
  		};
  		mxStencil.prototype.parseConstraint = function(node)
  		{
  			var x = Number(node.getAttribute('x'));
  			var y = Number(node.getAttribute('y'));
  			var perimeter = node.getAttribute('perimeter') == '1';
  			var name = node.getAttribute('name');
  			return new mxConnectionConstraint(new mxPoint(x, y), perimeter, name);
  		};
  		mxStencil.prototype.evaluateTextAttribute = function(node, attribute, shape)
  		{
  			var result = this.evaluateAttribute(node, attribute, shape);
  			var loc = node.getAttribute('localized');
  			if ((mxStencil.defaultLocalized && loc == null) || loc == '1')
  			{
  				result = mxResources.get(result);
  			}
  			return result;
  		};
  		mxStencil.prototype.evaluateAttribute = function(node, attribute, shape)
  		{
  			var result = node.getAttribute(attribute);
  			if (result == null)
  			{
  				var text = mxUtils.getTextContent(node);
  				if (text != null && mxStencil.allowEval)
  				{
  					var funct = mxUtils.eval(text);
  					if (typeof(funct) == 'function')
  					{
  						result = funct(shape);
  					}
  				}
  			}
  			return result;
  		};
  		mxStencil.prototype.drawShape = function(canvas, shape, x, y, w, h)
  		{
  			var stack = canvas.states.slice();
  			var direction = mxUtils.getValue(shape.style, mxConstants.STYLE_DIRECTION, null);
  			var aspect = this.computeAspect(shape.style, x, y, w, h, direction);
  			var minScale = Math.min(aspect.width, aspect.height);
  			var sw = (this.strokewidth == 'inherit') ?
  					Number(mxUtils.getNumber(shape.style, mxConstants.STYLE_STROKEWIDTH, 1)) :
  					Number(this.strokewidth) * minScale;
  			canvas.setStrokeWidth(sw);
  			if (shape.style != null && mxUtils.getValue(shape.style, mxConstants.STYLE_POINTER_EVENTS, '0') == '1')
  			{
  				canvas.setStrokeColor(mxConstants.NONE);
  				canvas.rect(x, y, w, h);
  				canvas.stroke();
  				canvas.setStrokeColor(shape.stroke);
  			}
  			this.drawChildren(canvas, shape, x, y, w, h, this.bgNode, aspect, false, true);
  			this.drawChildren(canvas, shape, x, y, w, h, this.fgNode, aspect, true,
  				!shape.outline || shape.style == null || mxUtils.getValue(
  				shape.style, mxConstants.STYLE_BACKGROUND_OUTLINE, 0) == 0);
  			if (canvas.states.length != stack.length)
  			{
  				canvas.states = stack;
  			}
  		};
  		mxStencil.prototype.drawChildren = function(canvas, shape, x, y, w, h, node, aspect, disableShadow, paint)
  		{
  			if (node != null && w > 0 && h > 0)
  			{
  				var tmp = node.firstChild;
  				while (tmp != null)
  				{
  					if (tmp.nodeType == mxConstants.NODETYPE_ELEMENT)
  					{
  						this.drawNode(canvas, shape, tmp, aspect, disableShadow, paint);
  					}
  					tmp = tmp.nextSibling;
  				}
  			}
  		};
  		mxStencil.prototype.computeAspect = function(shape, x, y, w, h, direction)
  		{
  			var x0 = x;
  			var y0 = y;
  			var sx = w / this.w0;
  			var sy = h / this.h0;
  			var inverse = (direction == mxConstants.DIRECTION_NORTH || direction == mxConstants.DIRECTION_SOUTH);
  			if (inverse)
  			{
  				sy = w / this.h0;
  				sx = h / this.w0;
  				var delta = (w - h) / 2;
  				x0 += delta;
  				y0 -= delta;
  			}
  			if (this.aspect == 'fixed')
  			{
  				sy = Math.min(sx, sy);
  				sx = sy;
  				if (inverse)
  				{
  					x0 += (h - this.w0 * sx) / 2;
  					y0 += (w - this.h0 * sy) / 2;
  				}
  				else
  				{
  					x0 += (w - this.w0 * sx) / 2;
  					y0 += (h - this.h0 * sy) / 2;
  				}
  			}
  			return new mxRectangle(x0, y0, sx, sy);
  		};
  		mxStencil.prototype.drawNode = function(canvas, shape, node, aspect, disableShadow, paint)
  		{
  			var name = node.nodeName;
  			var x0 = aspect.x;
  			var y0 = aspect.y;
  			var sx = aspect.width;
  			var sy = aspect.height;
  			var minScale = Math.min(sx, sy);
  			if (name == 'save')
  			{
  				canvas.save();
  			}
  			else if (name == 'restore')
  			{
  				canvas.restore();
  			}
  			else if (paint)
  			{
  				if (name == 'path')
  				{
  					canvas.begin();
  					var parseRegularly = true;
  					if (node.getAttribute('rounded') == '1')
  					{
  						parseRegularly = false;
  						var arcSize = Number(node.getAttribute('arcSize'));
  						var pointCount = 0;
  						var segs = [];
  						var childNode = node.firstChild;
  						while (childNode != null)
  						{
  							if (childNode.nodeType == mxConstants.NODETYPE_ELEMENT)
  							{
  								var childName = childNode.nodeName;
  								if (childName == 'move' || childName == 'line')
  								{
  									if (childName == 'move' || segs.length == 0)
  									{
  										segs.push([]);
  									}
  									segs[segs.length - 1].push(new mxPoint(x0 + Number(childNode.getAttribute('x')) * sx,
  										y0 + Number(childNode.getAttribute('y')) * sy));
  									pointCount++;
  								}
  								else
  								{
  									parseRegularly = true;
  									break;
  								}
  							}
  							childNode = childNode.nextSibling;
  						}
  						if (!parseRegularly && pointCount > 0)
  						{
  							for (var i = 0; i < segs.length; i++)
  							{
  								var close = false, ps = segs[i][0], pe = segs[i][segs[i].length - 1];
  								if (ps.x == pe.x && ps.y == pe.y)
  								{
  									segs[i].pop();
  									close = true;
  								}
  								this.addPoints(canvas, segs[i], true, arcSize, close);
  							}
  						}
  						else
  						{
  							parseRegularly = true;
  						}
  					}
  					if (parseRegularly)
  					{
  						var childNode = node.firstChild;
  						while (childNode != null)
  						{
  							if (childNode.nodeType == mxConstants.NODETYPE_ELEMENT)
  							{
  								this.drawNode(canvas, shape, childNode, aspect, disableShadow, paint);
  							}
  							childNode = childNode.nextSibling;
  						}
  					}
  				}
  				else if (name == 'close')
  				{
  					canvas.close();
  				}
  				else if (name == 'move')
  				{
  					canvas.moveTo(x0 + Number(node.getAttribute('x')) * sx, y0 + Number(node.getAttribute('y')) * sy);
  				}
  				else if (name == 'line')
  				{
  					canvas.lineTo(x0 + Number(node.getAttribute('x')) * sx, y0 + Number(node.getAttribute('y')) * sy);
  				}
  				else if (name == 'quad')
  				{
  					canvas.quadTo(x0 + Number(node.getAttribute('x1')) * sx,
  							y0 + Number(node.getAttribute('y1')) * sy,
  							x0 + Number(node.getAttribute('x2')) * sx,
  							y0 + Number(node.getAttribute('y2')) * sy);
  				}
  				else if (name == 'curve')
  				{
  					canvas.curveTo(x0 + Number(node.getAttribute('x1')) * sx,
  							y0 + Number(node.getAttribute('y1')) * sy,
  							x0 + Number(node.getAttribute('x2')) * sx,
  							y0 + Number(node.getAttribute('y2')) * sy,
  							x0 + Number(node.getAttribute('x3')) * sx,
  							y0 + Number(node.getAttribute('y3')) * sy);
  				}
  				else if (name == 'arc')
  				{
  					canvas.arcTo(Number(node.getAttribute('rx')) * sx,
  							Number(node.getAttribute('ry')) * sy,
  							Number(node.getAttribute('x-axis-rotation')),
  							Number(node.getAttribute('large-arc-flag')),
  							Number(node.getAttribute('sweep-flag')),
  							x0 + Number(node.getAttribute('x')) * sx,
  							y0 + Number(node.getAttribute('y')) * sy);
  				}
  				else if (name == 'rect')
  				{
  					canvas.rect(x0 + Number(node.getAttribute('x')) * sx,
  							y0 + Number(node.getAttribute('y')) * sy,
  							Number(node.getAttribute('w')) * sx,
  							Number(node.getAttribute('h')) * sy);
  				}
  				else if (name == 'roundrect')
  				{
  					var arcsize = Number(node.getAttribute('arcsize'));
  					if (arcsize == 0)
  					{
  						arcsize = mxConstants.RECTANGLE_ROUNDING_FACTOR * 100;
  					}
  					var w = Number(node.getAttribute('w')) * sx;
  					var h = Number(node.getAttribute('h')) * sy;
  					var factor = Number(arcsize) / 100;
  					var r = Math.min(w * factor, h * factor);
  					canvas.roundrect(x0 + Number(node.getAttribute('x')) * sx,
  							y0 + Number(node.getAttribute('y')) * sy,
  							w, h, r, r);
  				}
  				else if (name == 'ellipse')
  				{
  					canvas.ellipse(x0 + Number(node.getAttribute('x')) * sx,
  						y0 + Number(node.getAttribute('y')) * sy,
  						Number(node.getAttribute('w')) * sx,
  						Number(node.getAttribute('h')) * sy);
  				}
  				else if (name == 'image')
  				{
  					if (!shape.outline)
  					{
  						var src = this.evaluateAttribute(node, 'src', shape);
  						canvas.image(x0 + Number(node.getAttribute('x')) * sx,
  							y0 + Number(node.getAttribute('y')) * sy,
  							Number(node.getAttribute('w')) * sx,
  							Number(node.getAttribute('h')) * sy,
  							src, false, node.getAttribute('flipH') == '1',
  							node.getAttribute('flipV') == '1');
  					}
  				}
  				else if (name == 'text')
  				{
  					if (!shape.outline)
  					{
  						var str = this.evaluateTextAttribute(node, 'str', shape);
  						var rotation = node.getAttribute('vertical') == '1' ? -90 : 0;
  						if (node.getAttribute('align-shape') == '0')
  						{
  							var dr = shape.rotation;
  							var flipH = mxUtils.getValue(shape.style, mxConstants.STYLE_FLIPH, 0) == 1;
  							var flipV = mxUtils.getValue(shape.style, mxConstants.STYLE_FLIPV, 0) == 1;
  							if (flipH && flipV)
  							{
  								rotation -= dr;
  							}
  							else if (flipH || flipV)
  							{
  								rotation += dr;
  							}
  							else
  							{
  								rotation -= dr;
  							}
  						}
  						rotation -= node.getAttribute('rotation');
  						canvas.text(x0 + Number(node.getAttribute('x')) * sx,
  								y0 + Number(node.getAttribute('y')) * sy,
  								0, 0, str, node.getAttribute('align') || 'left',
  								node.getAttribute('valign') || 'top', false, '',
  								null, false, rotation);
  					}
  				}
  				else if (name == 'include-shape')
  				{
  					var stencil = mxStencilRegistry.getStencil(node.getAttribute('name'));
  					if (stencil != null)
  					{
  						var x = x0 + Number(node.getAttribute('x')) * sx;
  						var y = y0 + Number(node.getAttribute('y')) * sy;
  						var w = Number(node.getAttribute('w')) * sx;
  						var h = Number(node.getAttribute('h')) * sy;
  						stencil.drawShape(canvas, shape, x, y, w, h);
  					}
  				}
  				else if (name == 'fillstroke')
  				{
  					canvas.fillAndStroke();
  				}
  				else if (name == 'fill')
  				{
  					canvas.fill();
  				}
  				else if (name == 'stroke')
  				{
  					canvas.stroke();
  				}
  				else if (name == 'strokewidth')
  				{
  					var s = (node.getAttribute('fixed') == '1') ? 1 : minScale;
  					canvas.setStrokeWidth(Number(node.getAttribute('width')) * s);
  				}
  				else if (name == 'dashed')
  				{
  					canvas.setDashed(node.getAttribute('dashed') == '1');
  				}
  				else if (name == 'dashpattern')
  				{
  					var value = node.getAttribute('pattern');
  					if (value != null)
  					{
  						var tmp = value.split(' ');
  						var pat = [];
  						for (var i = 0; i < tmp.length; i++)
  						{
  							if (tmp[i].length > 0)
  							{
  								pat.push(Number(tmp[i]) * minScale);
  							}
  						}
  						value = pat.join(' ');
  						canvas.setDashPattern(value);
  					}
  				}
  				else if (name == 'strokecolor')
  				{
  					canvas.setStrokeColor(node.getAttribute('color'));
  				}
  				else if (name == 'linecap')
  				{
  					canvas.setLineCap(node.getAttribute('cap'));
  				}
  				else if (name == 'linejoin')
  				{
  					canvas.setLineJoin(node.getAttribute('join'));
  				}
  				else if (name == 'miterlimit')
  				{
  					canvas.setMiterLimit(Number(node.getAttribute('limit')));
  				}
  				else if (name == 'fillcolor')
  				{
  					canvas.setFillColor(node.getAttribute('color'));
  				}
  				else if (name == 'alpha')
  				{
  					canvas.setAlpha(node.getAttribute('alpha'));
  				}
  				else if (name == 'fillalpha')
  				{
  					canvas.setAlpha(node.getAttribute('alpha'));
  				}
  				else if (name == 'strokealpha')
  				{
  					canvas.setAlpha(node.getAttribute('alpha'));
  				}
  				else if (name == 'fontcolor')
  				{
  					canvas.setFontColor(node.getAttribute('color'));
  				}
  				else if (name == 'fontstyle')
  				{
  					canvas.setFontStyle(node.getAttribute('style'));
  				}
  				else if (name == 'fontfamily')
  				{
  					canvas.setFontFamily(node.getAttribute('family'));
  				}
  				else if (name == 'fontsize')
  				{
  					canvas.setFontSize(Number(node.getAttribute('size')) * minScale);
  				}
  				if (disableShadow && (name == 'fillstroke' || name == 'fill' || name == 'stroke'))
  				{
  					disableShadow = false;
  					canvas.setShadow(false);
  				}
  			}
  		};
  		__mxOutput.mxStencil = typeof mxStencil !== 'undefined' ? mxStencil : undefined;
  		var mxStencilRegistry =
  		{
  			stencils: {},
  			addStencil: function(name, stencil)
  			{
  				mxStencilRegistry.stencils[name] = stencil;
  			},
  			getStencil: function(name)
  			{
  				return mxStencilRegistry.stencils[name];
  			}
  		};
  		__mxOutput.mxStencilRegistry = typeof mxStencilRegistry !== 'undefined' ? mxStencilRegistry : undefined;
  		var mxMarker =
  		{
  			markers: [],
  			addMarker: function(type, funct)
  			{
  				mxMarker.markers[type] = funct;
  			},
  			createMarker: function(canvas, shape, type, pe, unitX, unitY, size, source, sw, filled)
  			{
  				var funct = mxMarker.markers[type];
  				return (funct != null) ? funct(canvas, shape, type, pe, unitX, unitY, size, source, sw, filled) : null;
  			}
  		};
  		(function()
  		{
  			function createArrow(widthFactor)
  			{
  				widthFactor = (widthFactor != null) ? widthFactor : 2;
  				return function(canvas, shape, type, pe, unitX, unitY, size, source, sw, filled)
  				{
  					var endOffsetX = unitX * sw * 1.118;
  					var endOffsetY = unitY * sw * 1.118;
  					unitX = unitX * (size + sw);
  					unitY = unitY * (size + sw);
  					var pt = pe.clone();
  					pt.x -= endOffsetX;
  					pt.y -= endOffsetY;
  					var f = (type != mxConstants.ARROW_CLASSIC && type != mxConstants.ARROW_CLASSIC_THIN) ? 1 : 3 / 4;
  					pe.x += -unitX * f - endOffsetX;
  					pe.y += -unitY * f - endOffsetY;
  					return function()
  					{
  						canvas.begin();
  						canvas.moveTo(pt.x, pt.y);
  						canvas.lineTo(pt.x - unitX - unitY / widthFactor, pt.y - unitY + unitX / widthFactor);
  						if (type == mxConstants.ARROW_CLASSIC || type == mxConstants.ARROW_CLASSIC_THIN)
  						{
  							canvas.lineTo(pt.x - unitX * 3 / 4, pt.y - unitY * 3 / 4);
  						}
  						canvas.lineTo(pt.x + unitY / widthFactor - unitX, pt.y - unitY - unitX / widthFactor);
  						canvas.close();
  						if (filled)
  						{
  							canvas.fillAndStroke();
  						}
  						else
  						{
  							canvas.stroke();
  						}
  					};
  				}
  			}			mxMarker.addMarker('classic', createArrow(2));
  			mxMarker.addMarker('classicThin', createArrow(3));
  			mxMarker.addMarker('block', createArrow(2));
  			mxMarker.addMarker('blockThin', createArrow(3));
  			function createOpenArrow(widthFactor)
  			{
  				widthFactor = (widthFactor != null) ? widthFactor : 2;
  				return function(canvas, shape, type, pe, unitX, unitY, size, source, sw, filled)
  				{
  					var endOffsetX = unitX * sw * 1.118;
  					var endOffsetY = unitY * sw * 1.118;
  					unitX = unitX * (size + sw);
  					unitY = unitY * (size + sw);
  					var pt = pe.clone();
  					pt.x -= endOffsetX;
  					pt.y -= endOffsetY;
  					pe.x += -endOffsetX * 2;
  					pe.y += -endOffsetY * 2;
  					return function()
  					{
  						canvas.begin();
  						canvas.moveTo(pt.x - unitX - unitY / widthFactor, pt.y - unitY + unitX / widthFactor);
  						canvas.lineTo(pt.x, pt.y);
  						canvas.lineTo(pt.x + unitY / widthFactor - unitX, pt.y - unitY - unitX / widthFactor);
  						canvas.stroke();
  					};
  				}
  			}			mxMarker.addMarker('open', createOpenArrow(2));
  			mxMarker.addMarker('openThin', createOpenArrow(3));
  			mxMarker.addMarker('oval', function(canvas, shape, type, pe, unitX, unitY, size, source, sw, filled)
  			{
  				var a = size / 2;
  				var pt = pe.clone();
  				pe.x -= unitX * a;
  				pe.y -= unitY * a;
  				return function()
  				{
  					canvas.ellipse(pt.x - a, pt.y - a, size, size);
  					if (filled)
  					{
  						canvas.fillAndStroke();
  					}
  					else
  					{
  						canvas.stroke();
  					}
  				};
  			});
  			function diamond(canvas, shape, type, pe, unitX, unitY, size, source, sw, filled)
  			{
  				var swFactor = (type == mxConstants.ARROW_DIAMOND) ?  0.7071 : 0.9862;
  				var endOffsetX = unitX * sw * swFactor;
  				var endOffsetY = unitY * sw * swFactor;
  				unitX = unitX * (size + sw);
  				unitY = unitY * (size + sw);
  				var pt = pe.clone();
  				pt.x -= endOffsetX;
  				pt.y -= endOffsetY;
  				pe.x += -unitX - endOffsetX;
  				pe.y += -unitY - endOffsetY;
  				var tk = ((type == mxConstants.ARROW_DIAMOND) ?  2 : 3.4);
  				return function()
  				{
  					canvas.begin();
  					canvas.moveTo(pt.x, pt.y);
  					canvas.lineTo(pt.x - unitX / 2 - unitY / tk, pt.y + unitX / tk - unitY / 2);
  					canvas.lineTo(pt.x - unitX, pt.y - unitY);
  					canvas.lineTo(pt.x - unitX / 2 + unitY / tk, pt.y - unitY / 2 - unitX / tk);
  					canvas.close();
  					if (filled)
  					{
  						canvas.fillAndStroke();
  					}
  					else
  					{
  						canvas.stroke();
  					}
  				};
  			}			mxMarker.addMarker('diamond', diamond);
  			mxMarker.addMarker('diamondThin', diamond);
  		})();
  		__mxOutput.mxMarker = typeof mxMarker !== 'undefined' ? mxMarker : undefined;
  		function mxActor(bounds, fill, stroke, strokewidth)
  		{
  			mxShape.call(this);
  			this.bounds = bounds;
  			this.fill = fill;
  			this.stroke = stroke;
  			this.strokewidth = (strokewidth != null) ? strokewidth : 1;
  		}		mxUtils.extend(mxActor, mxShape);
  		mxActor.prototype.paintVertexShape = function(c, x, y, w, h)
  		{
  			c.translate(x, y);
  			c.begin();
  			this.redrawPath(c, x, y, w, h);
  			c.fillAndStroke();
  		};
  		mxActor.prototype.redrawPath = function(c, x, y, w, h)
  		{
  			var width = w/3;
  			c.moveTo(0, h);
  			c.curveTo(0, 3 * h / 5, 0, 2 * h / 5, w / 2, 2 * h / 5);
  			c.curveTo(w / 2 - width, 2 * h / 5, w / 2 - width, 0, w / 2, 0);
  			c.curveTo(w / 2 + width, 0, w / 2 + width, 2 * h / 5, w / 2, 2 * h / 5);
  			c.curveTo(w, 2 * h / 5, w, 3 * h / 5, w, h);
  			c.close();
  		};
  		__mxOutput.mxActor = typeof mxActor !== 'undefined' ? mxActor : undefined;
  		function mxCloud(bounds, fill, stroke, strokewidth)
  		{
  			mxActor.call(this);
  			this.bounds = bounds;
  			this.fill = fill;
  			this.stroke = stroke;
  			this.strokewidth = (strokewidth != null) ? strokewidth : 1;
  		}		mxUtils.extend(mxCloud, mxActor);
  		mxCloud.prototype.redrawPath = function(c, x, y, w, h)
  		{
  			c.moveTo(0.25 * w, 0.25 * h);
  			c.curveTo(0.05 * w, 0.25 * h, 0, 0.5 * h, 0.16 * w, 0.55 * h);
  			c.curveTo(0, 0.66 * h, 0.18 * w, 0.9 * h, 0.31 * w, 0.8 * h);
  			c.curveTo(0.4 * w, h, 0.7 * w, h, 0.8 * w, 0.8 * h);
  			c.curveTo(w, 0.8 * h, w, 0.6 * h, 0.875 * w, 0.5 * h);
  			c.curveTo(w, 0.3 * h, 0.8 * w, 0.1 * h, 0.625 * w, 0.2 * h);
  			c.curveTo(0.5 * w, 0.05 * h, 0.3 * w, 0.05 * h, 0.25 * w, 0.25 * h);
  			c.close();
  		};
  		__mxOutput.mxCloud = typeof mxCloud !== 'undefined' ? mxCloud : undefined;
  		function mxRectangleShape(bounds, fill, stroke, strokewidth)
  		{
  			mxShape.call(this);
  			this.bounds = bounds;
  			this.fill = fill;
  			this.stroke = stroke;
  			this.strokewidth = (strokewidth != null) ? strokewidth : 1;
  		}		mxUtils.extend(mxRectangleShape, mxShape);
  		mxRectangleShape.prototype.isHtmlAllowed = function()
  		{
  			var events = true;
  			if (this.style != null)
  			{
  				events = mxUtils.getValue(this.style, mxConstants.STYLE_POINTER_EVENTS, '1') == '1';
  			}
  			return !this.isRounded && !this.glass && this.rotation == 0 && (events ||
  				(this.fill != null && this.fill != mxConstants.NONE));
  		};
  		mxRectangleShape.prototype.paintBackground = function(c, x, y, w, h)
  		{
  			var events = true;
  			if (this.style != null)
  			{
  				events = mxUtils.getValue(this.style, mxConstants.STYLE_POINTER_EVENTS, '1') == '1';
  			}
  			if (events || (this.fill != null && this.fill != mxConstants.NONE) ||
  				(this.stroke != null && this.stroke != mxConstants.NONE))
  			{
  				if (!events && (this.fill == null || this.fill == mxConstants.NONE))
  				{
  					c.pointerEvents = false;
  				}
  				if (this.isRounded)
  				{
  					var r = 0;
  					if (mxUtils.getValue(this.style, mxConstants.STYLE_ABSOLUTE_ARCSIZE, 0) == '1')
  					{
  						r = Math.min(w / 2, Math.min(h / 2, mxUtils.getValue(this.style,
  							mxConstants.STYLE_ARCSIZE, mxConstants.LINE_ARCSIZE) / 2));
  					}
  					else
  					{
  						var f = mxUtils.getValue(this.style, mxConstants.STYLE_ARCSIZE,
  							mxConstants.RECTANGLE_ROUNDING_FACTOR * 100) / 100;
  						r = Math.min(w * f, h * f);
  					}
  					c.roundrect(x, y, w, h, r, r);
  				}
  				else
  				{
  					c.rect(x, y, w, h);
  				}
  				c.fillAndStroke();
  			}
  		};
  		mxRectangleShape.prototype.isRoundable = function(c, x, y, w, h)
  		{
  			return true;
  		};
  		mxRectangleShape.prototype.paintForeground = function(c, x, y, w, h)
  		{
  			if (this.glass && !this.outline && this.fill != null && this.fill != mxConstants.NONE)
  			{
  				this.paintGlassEffect(c, x, y, w, h, this.getArcSize(w + this.strokewidth, h + this.strokewidth));
  			}
  		};
  		__mxOutput.mxRectangleShape = typeof mxRectangleShape !== 'undefined' ? mxRectangleShape : undefined;
  		function mxEllipse(bounds, fill, stroke, strokewidth)
  		{
  			mxShape.call(this);
  			this.bounds = bounds;
  			this.fill = fill;
  			this.stroke = stroke;
  			this.strokewidth = (strokewidth != null) ? strokewidth : 1;
  		}		mxUtils.extend(mxEllipse, mxShape);
  		mxEllipse.prototype.paintVertexShape = function(c, x, y, w, h)
  		{
  			c.ellipse(x, y, w, h);
  			c.fillAndStroke();
  		};
  		__mxOutput.mxEllipse = typeof mxEllipse !== 'undefined' ? mxEllipse : undefined;
  		function mxDoubleEllipse(bounds, fill, stroke, strokewidth)
  		{
  			mxShape.call(this);
  			this.bounds = bounds;
  			this.fill = fill;
  			this.stroke = stroke;
  			this.strokewidth = (strokewidth != null) ? strokewidth : 1;
  		}		mxUtils.extend(mxDoubleEllipse, mxShape);
  		mxDoubleEllipse.prototype.vmlScale = 10;
  		mxDoubleEllipse.prototype.paintBackground = function(c, x, y, w, h)
  		{
  			c.ellipse(x, y, w, h);
  			c.fillAndStroke();
  		};
  		mxDoubleEllipse.prototype.paintForeground = function(c, x, y, w, h)
  		{
  			if (!this.outline)
  			{
  				var margin = mxUtils.getValue(this.style, mxConstants.STYLE_MARGIN, Math.min(3 + this.strokewidth, Math.min(w / 5, h / 5)));
  				x += margin;
  				y += margin;
  				w -= 2 * margin;
  				h -= 2 * margin;
  				if (w > 0 && h > 0)
  				{
  					c.ellipse(x, y, w, h);
  				}
  				c.stroke();
  			}
  		};
  		mxDoubleEllipse.prototype.getLabelBounds = function(rect)
  		{
  			var margin = (mxUtils.getValue(this.style, mxConstants.STYLE_MARGIN, Math.min(3 + this.strokewidth,
  					Math.min(rect.width / 5 / this.scale, rect.height / 5 / this.scale)))) * this.scale;
  			return new mxRectangle(rect.x + margin, rect.y + margin, rect.width - 2 * margin, rect.height - 2 * margin);
  		};
  		__mxOutput.mxDoubleEllipse = typeof mxDoubleEllipse !== 'undefined' ? mxDoubleEllipse : undefined;
  		function mxRhombus(bounds, fill, stroke, strokewidth)
  		{
  			mxShape.call(this);
  			this.bounds = bounds;
  			this.fill = fill;
  			this.stroke = stroke;
  			this.strokewidth = (strokewidth != null) ? strokewidth : 1;
  		}		mxUtils.extend(mxRhombus, mxShape);
  		mxRhombus.prototype.isRoundable = function()
  		{
  			return true;
  		};
  		mxRhombus.prototype.paintVertexShape = function(c, x, y, w, h)
  		{
  			var hw = w / 2;
  			var hh = h / 2;
  			var arcSize = mxUtils.getValue(this.style, mxConstants.STYLE_ARCSIZE, mxConstants.LINE_ARCSIZE) / 2;
  			c.begin();
  			this.addPoints(c, [new mxPoint(x + hw, y), new mxPoint(x + w, y + hh), new mxPoint(x + hw, y + h),
  			     new mxPoint(x, y + hh)], this.isRounded, arcSize, true);
  			c.fillAndStroke();
  		};
  		__mxOutput.mxRhombus = typeof mxRhombus !== 'undefined' ? mxRhombus : undefined;
  		function mxPolyline(points, stroke, strokewidth)
  		{
  			mxShape.call(this);
  			this.points = points;
  			this.stroke = stroke;
  			this.strokewidth = (strokewidth != null) ? strokewidth : 1;
  		}		mxUtils.extend(mxPolyline, mxShape);
  		mxPolyline.prototype.getRotation = function()
  		{
  			return 0;
  		};
  		mxPolyline.prototype.getShapeRotation = function()
  		{
  			return 0;
  		};
  		mxPolyline.prototype.isPaintBoundsInverted = function()
  		{
  			return false;
  		};
  		mxPolyline.prototype.paintEdgeShape = function(c, pts)
  		{
  			var prev = c.pointerEventsValue;
  			c.pointerEventsValue = 'stroke';
  			if (this.style == null || this.style[mxConstants.STYLE_CURVED] != 1)
  			{
  				this.paintLine(c, pts, this.isRounded);
  			}
  			else
  			{
  				this.paintCurvedLine(c, pts);
  			}
  			c.pointerEventsValue = prev;
  		};
  		mxPolyline.prototype.paintLine = function(c, pts, rounded)
  		{
  			var arcSize = mxUtils.getValue(this.style, mxConstants.STYLE_ARCSIZE, mxConstants.LINE_ARCSIZE) / 2;
  			c.begin();
  			this.addPoints(c, pts, rounded, arcSize, false);
  			c.stroke();
  		};
  		mxPolyline.prototype.paintCurvedLine = function(c, pts)
  		{
  			c.begin();
  			var pt = pts[0];
  			var n = pts.length;
  			c.moveTo(pt.x, pt.y);
  			for (var i = 1; i < n - 2; i++)
  			{
  				var p0 = pts[i];
  				var p1 = pts[i + 1];
  				var ix = (p0.x + p1.x) / 2;
  				var iy = (p0.y + p1.y) / 2;
  				c.quadTo(p0.x, p0.y, ix, iy);
  			}
  			var p0 = pts[n - 2];
  			var p1 = pts[n - 1];
  			c.quadTo(p0.x, p0.y, p1.x, p1.y);
  			c.stroke();
  		};
  		__mxOutput.mxPolyline = typeof mxPolyline !== 'undefined' ? mxPolyline : undefined;
  		function mxArrow(points, fill, stroke, strokewidth, arrowWidth, spacing, endSize)
  		{
  			mxShape.call(this);
  			this.points = points;
  			this.fill = fill;
  			this.stroke = stroke;
  			this.strokewidth = (strokewidth != null) ? strokewidth : 1;
  			this.arrowWidth = (arrowWidth != null) ? arrowWidth : mxConstants.ARROW_WIDTH;
  			this.spacing = (spacing != null) ? spacing : mxConstants.ARROW_SPACING;
  			this.endSize = (endSize != null) ? endSize : mxConstants.ARROW_SIZE;
  		}		mxUtils.extend(mxArrow, mxShape);
  		mxArrow.prototype.augmentBoundingBox = function(bbox)
  		{
  			mxShape.prototype.augmentBoundingBox.apply(this, arguments);
  			var w = Math.max(this.arrowWidth, this.endSize);
  			bbox.grow((w / 2 + this.strokewidth) * this.scale);
  		};
  		mxArrow.prototype.paintEdgeShape = function(c, pts)
  		{
  			var spacing =  mxConstants.ARROW_SPACING;
  			var width = mxConstants.ARROW_WIDTH;
  			var arrow = mxConstants.ARROW_SIZE;
  			var p0 = pts[0];
  			var pe = pts[pts.length - 1];
  			var dx = pe.x - p0.x;
  			var dy = pe.y - p0.y;
  			var dist = Math.sqrt(dx * dx + dy * dy);
  			var length = dist - 2 * spacing - arrow;
  			var nx = dx / dist;
  			var ny = dy / dist;
  			var basex = length * nx;
  			var basey = length * ny;
  			var floorx = width * ny/3;
  			var floory = -width * nx/3;
  			var p0x = p0.x - floorx / 2 + spacing * nx;
  			var p0y = p0.y - floory / 2 + spacing * ny;
  			var p1x = p0x + floorx;
  			var p1y = p0y + floory;
  			var p2x = p1x + basex;
  			var p2y = p1y + basey;
  			var p3x = p2x + floorx;
  			var p3y = p2y + floory;
  			var p5x = p3x - 3 * floorx;
  			var p5y = p3y - 3 * floory;
  			c.begin();
  			c.moveTo(p0x, p0y);
  			c.lineTo(p1x, p1y);
  			c.lineTo(p2x, p2y);
  			c.lineTo(p3x, p3y);
  			c.lineTo(pe.x - spacing * nx, pe.y - spacing * ny);
  			c.lineTo(p5x, p5y);
  			c.lineTo(p5x + floorx, p5y + floory);
  			c.close();
  			c.fillAndStroke();
  		};
  		__mxOutput.mxArrow = typeof mxArrow !== 'undefined' ? mxArrow : undefined;
  		function mxArrowConnector(points, fill, stroke, strokewidth, arrowWidth, spacing, endSize)
  		{
  			mxShape.call(this);
  			this.points = points;
  			this.fill = fill;
  			this.stroke = stroke;
  			this.strokewidth = (strokewidth != null) ? strokewidth : 1;
  			this.arrowWidth = (arrowWidth != null) ? arrowWidth : mxConstants.ARROW_WIDTH;
  			this.arrowSpacing = (spacing != null) ? spacing : mxConstants.ARROW_SPACING;
  			this.startSize = mxConstants.ARROW_SIZE / 5;
  			this.endSize = mxConstants.ARROW_SIZE / 5;
  		}		mxUtils.extend(mxArrowConnector, mxShape);
  		mxArrowConnector.prototype.useSvgBoundingBox = true;
  		mxArrowConnector.prototype.isRoundable = function()
  		{
  			return true;
  		};
  		mxArrowConnector.prototype.resetStyles = function()
  		{
  			mxShape.prototype.resetStyles.apply(this, arguments);
  			this.arrowSpacing = mxConstants.ARROW_SPACING;
  		};
  		mxArrowConnector.prototype.apply = function(state)
  		{
  			mxShape.prototype.apply.apply(this, arguments);
  			if (this.style != null)
  			{
  				this.startSize = mxUtils.getNumber(this.style, mxConstants.STYLE_STARTSIZE, mxConstants.ARROW_SIZE / 5) * 3;
  				this.endSize = mxUtils.getNumber(this.style, mxConstants.STYLE_ENDSIZE, mxConstants.ARROW_SIZE / 5) * 3;
  			}
  		};
  		mxArrowConnector.prototype.augmentBoundingBox = function(bbox)
  		{
  			mxShape.prototype.augmentBoundingBox.apply(this, arguments);
  			var w = this.getEdgeWidth();
  			if (this.isMarkerStart())
  			{
  				w = Math.max(w, this.getStartArrowWidth());
  			}
  			if (this.isMarkerEnd())
  			{
  				w = Math.max(w, this.getEndArrowWidth());
  			}
  			bbox.grow((w / 2 + this.strokewidth) * this.scale);
  		};
  		mxArrowConnector.prototype.paintEdgeShape = function(c, pts)
  		{
  			var strokeWidth = this.strokewidth;
  			if (this.outline)
  			{
  				strokeWidth = Math.max(1, mxUtils.getNumber(this.style, mxConstants.STYLE_STROKEWIDTH, this.strokewidth));
  			}
  			var startWidth = this.getStartArrowWidth() + strokeWidth;
  			var endWidth = this.getEndArrowWidth() + strokeWidth;
  			var edgeWidth = this.outline ? this.getEdgeWidth() + strokeWidth : this.getEdgeWidth();
  			var openEnded = this.isOpenEnded();
  			var markerStart = this.isMarkerStart();
  			var markerEnd = this.isMarkerEnd();
  			var spacing = (openEnded) ? 0 : this.arrowSpacing + strokeWidth / 2;
  			var startSize = this.startSize + strokeWidth;
  			var endSize = this.endSize + strokeWidth;
  			var isRounded = this.isArrowRounded();
  			var pe = pts[pts.length - 1];
  			var i0 = 1;
  			while (i0 < pts.length - 1 && pts[i0].x == pts[0].x && pts[i0].y == pts[0].y)
  			{
  				i0++;
  			}
  			var dx = pts[i0].x - pts[0].x;
  			var dy = pts[i0].y - pts[0].y;
  			var dist = Math.sqrt(dx * dx + dy * dy);
  			if (dist == 0)
  			{
  				return;
  			}
  			var nx = dx / dist;
  			var nx2, nx1 = nx;
  			var ny = dy / dist;
  			var ny2, ny1 = ny;
  			var orthx = edgeWidth * ny;
  			var orthy = -edgeWidth * nx;
  			var fns = [];
  			if (isRounded)
  			{
  				c.setLineJoin('round');
  			}
  			else if (pts.length > 2)
  			{
  				c.setMiterLimit(1.42);
  			}
  			c.begin();
  			var startNx = nx;
  			var startNy = ny;
  			if (markerStart && !openEnded)
  			{
  				this.paintMarker(c, pts[0].x, pts[0].y, nx, ny, startSize, startWidth, edgeWidth, spacing, true);
  			}
  			else
  			{
  				var outStartX = pts[0].x + orthx / 2 + spacing * nx;
  				var outStartY = pts[0].y + orthy / 2 + spacing * ny;
  				var inEndX = pts[0].x - orthx / 2 + spacing * nx;
  				var inEndY = pts[0].y - orthy / 2 + spacing * ny;
  				if (openEnded)
  				{
  					c.moveTo(outStartX, outStartY);
  					fns.push(function()
  					{
  						c.lineTo(inEndX, inEndY);
  					});
  				}
  				else
  				{
  					c.moveTo(inEndX, inEndY);
  					c.lineTo(outStartX, outStartY);
  				}
  			}
  			var dx1 = 0;
  			var dy1 = 0;
  			var dist1 = 0;
  			for (var i = 0; i < pts.length - 2; i++)
  			{
  				var pos = mxUtils.relativeCcw(pts[i].x, pts[i].y, pts[i+1].x, pts[i+1].y, pts[i+2].x, pts[i+2].y);
  				dx1 = pts[i+2].x - pts[i+1].x;
  				dy1 = pts[i+2].y - pts[i+1].y;
  				dist1 = Math.sqrt(dx1 * dx1 + dy1 * dy1);
  				if (dist1 != 0)
  				{
  					nx1 = dx1 / dist1;
  					ny1 = dy1 / dist1;
  					var tmp1 = nx * nx1 + ny * ny1;
  					var tmp = Math.max(Math.sqrt((tmp1 + 1) / 2), 0.04);
  					nx2 = (nx + nx1);
  					ny2 = (ny + ny1);
  					var dist2 = Math.sqrt(nx2 * nx2 + ny2 * ny2);
  					if (dist2 != 0)
  					{
  						nx2 = nx2 / dist2;
  						ny2 = ny2 / dist2;
  						var strokeWidthFactor = Math.max(tmp, Math.min(this.strokewidth / 200 + 0.04, 0.35));
  						var angleFactor = (pos != 0 && isRounded) ? Math.max(0.1, strokeWidthFactor) : Math.max(tmp, 0.06);
  						var outX = pts[i+1].x + ny2 * edgeWidth / 2 / angleFactor;
  						var outY = pts[i+1].y - nx2 * edgeWidth / 2 / angleFactor;
  						var inX = pts[i+1].x - ny2 * edgeWidth / 2 / angleFactor;
  						var inY = pts[i+1].y + nx2 * edgeWidth / 2 / angleFactor;
  						if (pos == 0 || !isRounded)
  						{
  							c.lineTo(outX, outY);
  							(function(x, y)
  							{
  								fns.push(function()
  								{
  									c.lineTo(x, y);
  								});
  							})(inX, inY);
  						}
  						else if (pos == -1)
  						{
  							var c1x = inX + ny * edgeWidth;
  							var c1y = inY - nx * edgeWidth;
  							var c2x = inX + ny1 * edgeWidth;
  							var c2y = inY - nx1 * edgeWidth;
  							c.lineTo(c1x, c1y);
  							c.quadTo(outX, outY, c2x, c2y);
  							(function(x, y)
  							{
  								fns.push(function()
  								{
  									c.lineTo(x, y);
  								});
  							})(inX, inY);
  						}
  						else
  						{
  							c.lineTo(outX, outY);
  							(function(x, y)
  							{
  								var c1x = outX - ny * edgeWidth;
  								var c1y = outY + nx * edgeWidth;
  								var c2x = outX - ny1 * edgeWidth;
  								var c2y = outY + nx1 * edgeWidth;
  								fns.push(function()
  								{
  									c.quadTo(x, y, c1x, c1y);
  								});
  								fns.push(function()
  								{
  									c.lineTo(c2x, c2y);
  								});
  							})(inX, inY);
  						}
  						nx = nx1;
  						ny = ny1;
  					}
  				}
  			}
  			orthx = edgeWidth * ny1;
  			orthy = - edgeWidth * nx1;
  			if (markerEnd && !openEnded)
  			{
  				this.paintMarker(c, pe.x, pe.y, -nx, -ny, endSize, endWidth, edgeWidth, spacing, false);
  			}
  			else
  			{
  				c.lineTo(pe.x - spacing * nx1 + orthx / 2, pe.y - spacing * ny1 + orthy / 2);
  				var inStartX = pe.x - spacing * nx1 - orthx / 2;
  				var inStartY = pe.y - spacing * ny1 - orthy / 2;
  				if (!openEnded)
  				{
  					c.lineTo(inStartX, inStartY);
  				}
  				else
  				{
  					c.moveTo(inStartX, inStartY);
  					fns.splice(0, 0, function()
  					{
  						c.moveTo(inStartX, inStartY);
  					});
  				}
  			}
  			for (var i = fns.length - 1; i >= 0; i--)
  			{
  				fns[i]();
  			}
  			if (openEnded)
  			{
  				c.end();
  				c.stroke();
  			}
  			else
  			{
  				c.close();
  				c.fillAndStroke();
  			}
  			c.setShadow(false);
  			c.setMiterLimit(4);
  			if (isRounded)
  			{
  				c.setLineJoin('flat');
  			}
  			if (pts.length > 2)
  			{
  				c.setMiterLimit(4);
  				if (markerStart && !openEnded)
  				{
  					c.begin();
  					this.paintMarker(c, pts[0].x, pts[0].y, startNx, startNy, startSize, startWidth, edgeWidth, spacing, true);
  					c.stroke();
  					c.end();
  				}
  				if (markerEnd && !openEnded)
  				{
  					c.begin();
  					this.paintMarker(c, pe.x, pe.y, -nx, -ny, endSize, endWidth, edgeWidth, spacing, true);
  					c.stroke();
  					c.end();
  				}
  			}
  		};
  		mxArrowConnector.prototype.paintMarker = function(c, ptX, ptY, nx, ny, size, arrowWidth, edgeWidth, spacing, initialMove)
  		{
  			var widthArrowRatio = edgeWidth / arrowWidth;
  			var orthx = edgeWidth * ny / 2;
  			var orthy = -edgeWidth * nx / 2;
  			var spaceX = (spacing + size) * nx;
  			var spaceY = (spacing + size) * ny;
  			if (initialMove)
  			{
  				c.moveTo(ptX - orthx + spaceX, ptY - orthy + spaceY);
  			}
  			else
  			{
  				c.lineTo(ptX - orthx + spaceX, ptY - orthy + spaceY);
  			}
  			c.lineTo(ptX - orthx / widthArrowRatio + spaceX, ptY - orthy / widthArrowRatio + spaceY);
  			c.lineTo(ptX + spacing * nx, ptY + spacing * ny);
  			c.lineTo(ptX + orthx / widthArrowRatio + spaceX, ptY + orthy / widthArrowRatio + spaceY);
  			c.lineTo(ptX + orthx + spaceX, ptY + orthy + spaceY);
  		};
  		mxArrowConnector.prototype.isArrowRounded = function()
  		{
  			return this.isRounded;
  		};
  		mxArrowConnector.prototype.getStartArrowWidth = function()
  		{
  			return mxConstants.ARROW_WIDTH;
  		};
  		mxArrowConnector.prototype.getEndArrowWidth = function()
  		{
  			return mxConstants.ARROW_WIDTH;
  		};
  		mxArrowConnector.prototype.getEdgeWidth = function()
  		{
  			return mxConstants.ARROW_WIDTH / 3;
  		};
  		mxArrowConnector.prototype.isOpenEnded = function()
  		{
  			return false;
  		};
  		mxArrowConnector.prototype.isMarkerStart = function()
  		{
  			return (mxUtils.getValue(this.style, mxConstants.STYLE_STARTARROW, mxConstants.NONE) != mxConstants.NONE);
  		};
  		mxArrowConnector.prototype.isMarkerEnd = function()
  		{
  			return (mxUtils.getValue(this.style, mxConstants.STYLE_ENDARROW, mxConstants.NONE) != mxConstants.NONE);
  		};
  		__mxOutput.mxArrowConnector = typeof mxArrowConnector !== 'undefined' ? mxArrowConnector : undefined;
  		function mxText(value, bounds, align, valign, color,
  			family,	size, fontStyle, spacing, spacingTop, spacingRight,
  			spacingBottom, spacingLeft, horizontal, background, border,
  			wrap, clipped, overflow, labelPadding, textDirection)
  		{
  			mxShape.call(this);
  			this.value = value;
  			this.bounds = bounds;
  			this.color = (color != null) ? color : 'black';
  			this.align = (align != null) ? align : mxConstants.ALIGN_CENTER;
  			this.valign = (valign != null) ? valign : mxConstants.ALIGN_MIDDLE;
  			this.family = (family != null) ? family : mxConstants.DEFAULT_FONTFAMILY;
  			this.size = (size != null) ? size : mxConstants.DEFAULT_FONTSIZE;
  			this.fontStyle = (fontStyle != null) ? fontStyle : mxConstants.DEFAULT_FONTSTYLE;
  			this.spacing = parseInt(spacing || 2);
  			this.spacingTop = this.spacing + parseInt(spacingTop || 0);
  			this.spacingRight = this.spacing + parseInt(spacingRight || 0);
  			this.spacingBottom = this.spacing + parseInt(spacingBottom || 0);
  			this.spacingLeft = this.spacing + parseInt(spacingLeft || 0);
  			this.horizontal = (horizontal != null) ? horizontal : true;
  			this.background = background;
  			this.border = border;
  			this.wrap = (wrap != null) ? wrap : false;
  			this.clipped = (clipped != null) ? clipped : false;
  			this.overflow = (overflow != null) ? overflow : 'visible';
  			this.labelPadding = (labelPadding != null) ? labelPadding : 0;
  			this.textDirection = textDirection;
  			this.rotation = 0;
  			this.updateMargin();
  		}		mxUtils.extend(mxText, mxShape);
  		mxText.prototype.baseSpacingTop = 0;
  		mxText.prototype.baseSpacingBottom = 0;
  		mxText.prototype.baseSpacingLeft = 0;
  		mxText.prototype.baseSpacingRight = 0;
  		mxText.prototype.replaceLinefeeds = true;
  		mxText.prototype.verticalTextRotation = -90;
  		mxText.prototype.ignoreClippedStringSize = true;
  		mxText.prototype.ignoreStringSize = false;
  		mxText.prototype.textWidthPadding = (document.documentMode == 8 && !mxClient.IS_EM) ? 4 : 3;
  		mxText.prototype.lastValue = null;
  		mxText.prototype.cacheEnabled = true;
  		mxText.prototype.isParseVml = function()
  		{
  			return false;
  		};
  		mxText.prototype.isHtmlAllowed = function()
  		{
  			return document.documentMode != 8 || mxClient.IS_EM;
  		};
  		mxText.prototype.getSvgScreenOffset = function()
  		{
  			return 0;
  		};
  		mxText.prototype.checkBounds = function()
  		{
  			return (!isNaN(this.scale) && isFinite(this.scale) && this.scale > 0 &&
  					this.bounds != null && !isNaN(this.bounds.x) && !isNaN(this.bounds.y) &&
  					!isNaN(this.bounds.width) && !isNaN(this.bounds.height));
  		};
  		mxText.prototype.paint = function(c, update)
  		{
  			var s = this.scale;
  			var x = this.bounds.x / s;
  			var y = this.bounds.y / s;
  			var w = this.bounds.width / s;
  			var h = this.bounds.height / s;
  			this.updateTransform(c, x, y, w, h);
  			this.configureCanvas(c, x, y, w, h);
  			if (update)
  			{
  				c.updateText(x, y, w, h, this.align, this.valign, this.wrap, this.overflow,
  						this.clipped, this.getTextRotation(), this.node);
  			}
  			else
  			{
  				var realHtml = mxUtils.isNode(this.value) || this.dialect == mxConstants.DIALECT_STRICTHTML;
  				var fmt = (realHtml || c instanceof mxVmlCanvas2D) ? 'html' : '';
  				var val = this.value;
  				if (!realHtml && fmt == 'html')
  				{
  					val = mxUtils.htmlEntities(val, false);
  				}
  				if (fmt == 'html' && !mxUtils.isNode(this.value))
  				{
  					val = mxUtils.replaceTrailingNewlines(val, '<div><br></div>');
  				}
  				val = (!mxUtils.isNode(this.value) && this.replaceLinefeeds && fmt == 'html') ?
  					val.replace(/\n/g, '<br/>') : val;
  				var dir = this.textDirection;
  				if (dir == mxConstants.TEXT_DIRECTION_AUTO && !realHtml)
  				{
  					dir = this.getAutoDirection();
  				}
  				if (dir != mxConstants.TEXT_DIRECTION_LTR && dir != mxConstants.TEXT_DIRECTION_RTL)
  				{
  					dir = null;
  				}
  				c.text(x, y, w, h, val, this.align, this.valign, this.wrap, fmt,
  					this.overflow, this.clipped, this.getTextRotation(), dir);
  			}
  		};
  		mxText.prototype.redraw = function()
  		{
  			if (this.visible && this.checkBounds() && this.cacheEnabled && this.lastValue == this.value &&
  				(mxUtils.isNode(this.value) || this.dialect == mxConstants.DIALECT_STRICTHTML))
  			{
  				if (this.node.nodeName == 'DIV' && (this.isHtmlAllowed() || !mxClient.IS_VML))
  				{
  					if (mxClient.IS_SVG)
  					{
  						this.redrawHtmlShapeWithCss3();
  					}
  					else
  					{
  						this.updateSize(this.node, (this.state == null || this.state.view.textDiv == null));
  						if (mxClient.IS_IE && (document.documentMode == null || document.documentMode <= 8))
  						{
  							this.updateHtmlFilter();
  						}
  						else
  						{
  							this.updateHtmlTransform();
  						}
  					}
  					this.updateBoundingBox();
  				}
  				else
  				{
  					var canvas = this.createCanvas();
  					if (canvas != null && canvas.updateText != null)
  					{
  						canvas.pointerEvents = this.pointerEvents;
  						this.paint(canvas, true);
  						this.destroyCanvas(canvas);
  						this.updateBoundingBox();
  					}
  					else
  					{
  						mxShape.prototype.redraw.apply(this, arguments);
  					}
  				}
  			}
  			else
  			{
  				mxShape.prototype.redraw.apply(this, arguments);
  				if (mxUtils.isNode(this.value) || this.dialect == mxConstants.DIALECT_STRICTHTML)
  				{
  					this.lastValue = this.value;
  				}
  				else
  				{
  					this.lastValue = null;
  				}
  			}
  		};
  		mxText.prototype.resetStyles = function()
  		{
  			mxShape.prototype.resetStyles.apply(this, arguments);
  			this.color = 'black';
  			this.align = mxConstants.ALIGN_CENTER;
  			this.valign = mxConstants.ALIGN_MIDDLE;
  			this.family = mxConstants.DEFAULT_FONTFAMILY;
  			this.size = mxConstants.DEFAULT_FONTSIZE;
  			this.fontStyle = mxConstants.DEFAULT_FONTSTYLE;
  			this.spacing = 2;
  			this.spacingTop = 2;
  			this.spacingRight = 2;
  			this.spacingBottom = 2;
  			this.spacingLeft = 2;
  			this.horizontal = true;
  			delete this.background;
  			delete this.border;
  			this.textDirection = mxConstants.DEFAULT_TEXT_DIRECTION;
  			delete this.margin;
  		};
  		mxText.prototype.apply = function(state)
  		{
  			var old = this.spacing;
  			mxShape.prototype.apply.apply(this, arguments);
  			if (this.style != null)
  			{
  				this.fontStyle = mxUtils.getValue(this.style, mxConstants.STYLE_FONTSTYLE, this.fontStyle);
  				this.family = mxUtils.getValue(this.style, mxConstants.STYLE_FONTFAMILY, this.family);
  				this.size = mxUtils.getValue(this.style, mxConstants.STYLE_FONTSIZE, this.size);
  				this.color = mxUtils.getValue(this.style, mxConstants.STYLE_FONTCOLOR, this.color);
  				this.align = mxUtils.getValue(this.style, mxConstants.STYLE_ALIGN, this.align);
  				this.valign = mxUtils.getValue(this.style, mxConstants.STYLE_VERTICAL_ALIGN, this.valign);
  				this.spacing = parseInt(mxUtils.getValue(this.style, mxConstants.STYLE_SPACING, this.spacing));
  				this.spacingTop = parseInt(mxUtils.getValue(this.style, mxConstants.STYLE_SPACING_TOP, this.spacingTop - old)) + this.spacing;
  				this.spacingRight = parseInt(mxUtils.getValue(this.style, mxConstants.STYLE_SPACING_RIGHT, this.spacingRight - old)) + this.spacing;
  				this.spacingBottom = parseInt(mxUtils.getValue(this.style, mxConstants.STYLE_SPACING_BOTTOM, this.spacingBottom - old)) + this.spacing;
  				this.spacingLeft = parseInt(mxUtils.getValue(this.style, mxConstants.STYLE_SPACING_LEFT, this.spacingLeft - old)) + this.spacing;
  				this.horizontal = mxUtils.getValue(this.style, mxConstants.STYLE_HORIZONTAL, this.horizontal);
  				this.background = mxUtils.getValue(this.style, mxConstants.STYLE_LABEL_BACKGROUNDCOLOR, this.background);
  				this.border = mxUtils.getValue(this.style, mxConstants.STYLE_LABEL_BORDERCOLOR, this.border);
  				this.textDirection = mxUtils.getValue(this.style, mxConstants.STYLE_TEXT_DIRECTION, mxConstants.DEFAULT_TEXT_DIRECTION);
  				this.opacity = mxUtils.getValue(this.style, mxConstants.STYLE_TEXT_OPACITY, 100);
  				this.updateMargin();
  			}
  			this.flipV = null;
  			this.flipH = null;
  		};
  		mxText.prototype.getAutoDirection = function()
  		{
  			var tmp = /[A-Za-z\u05d0-\u065f\u066a-\u06ef\u06fa-\u07ff\ufb1d-\ufdff\ufe70-\ufefc]/.exec(this.value);
  			return (tmp != null && tmp.length > 0 && tmp[0] > 'z') ?
  				mxConstants.TEXT_DIRECTION_RTL : mxConstants.TEXT_DIRECTION_LTR;
  		};
  		mxText.prototype.getContentNode = function()
  		{
  			var result = this.node;
  			if (result != null)
  			{
  				if (result.ownerSVGElement == null)
  				{
  					result = this.node.firstChild.firstChild;
  				}
  				else
  				{
  					result = result.firstChild.firstChild.firstChild.firstChild.firstChild;
  				}
  			}
  			return result;
  		};
  		mxText.prototype.updateBoundingBox = function()
  		{
  			var node = this.node;
  			this.boundingBox = this.bounds.clone();
  			var rot = this.getTextRotation();
  			var h = (this.style != null) ? mxUtils.getValue(this.style, mxConstants.STYLE_LABEL_POSITION, mxConstants.ALIGN_CENTER) : null;
  			var v = (this.style != null) ? mxUtils.getValue(this.style, mxConstants.STYLE_VERTICAL_LABEL_POSITION, mxConstants.ALIGN_MIDDLE) : null;
  			if (!this.ignoreStringSize && node != null && this.overflow != 'fill' && (!this.clipped ||
  				!this.ignoreClippedStringSize || h != mxConstants.ALIGN_CENTER || v != mxConstants.ALIGN_MIDDLE))
  			{
  				var ow = null;
  				var oh = null;
  				if (node.ownerSVGElement != null)
  				{
  					if (node.firstChild != null && node.firstChild.firstChild != null &&
  						node.firstChild.firstChild.nodeName == 'foreignObject')
  					{
  						node = node.firstChild.firstChild.firstChild.firstChild;
  						oh = node.offsetHeight * this.scale;
  						if (this.overflow == 'width')
  						{
  							ow = this.boundingBox.width;
  						}
  						else
  						{
  							ow = node.offsetWidth * this.scale;
  						}
  					}
  					else
  					{
  						try
  						{
  							var b = node.getBBox();
  							if (typeof(this.value) == 'string' && mxUtils.trim(this.value) == 0)
  							{
  								this.boundingBox = null;
  							}
  							else if (b.width == 0 && b.height == 0)
  							{
  								this.boundingBox = null;
  							}
  							else
  							{
  								this.boundingBox = new mxRectangle(b.x, b.y, b.width, b.height);
  							}
  							return;
  						}
  						catch (e)
  						{
  						}
  					}
  				}
  				else
  				{
  					var td = (this.state != null) ? this.state.view.textDiv : null;
  					if (this.offsetWidth != null && this.offsetHeight != null)
  					{
  						ow = this.offsetWidth * this.scale;
  						oh = this.offsetHeight * this.scale;
  					}
  					else
  					{
  						if (td != null)
  						{
  							this.updateFont(td);
  							this.updateSize(td, false);
  							this.updateInnerHtml(td);
  							node = td;
  						}
  						var sizeDiv = node;
  						if (document.documentMode == 8 && !mxClient.IS_EM)
  						{
  							var w = Math.round(this.bounds.width / this.scale);
  							if (this.wrap && w > 0)
  							{
  								node.style.wordWrap = mxConstants.WORD_WRAP;
  								node.style.whiteSpace = 'normal';
  								if (node.style.wordWrap != 'break-word')
  								{
  									var divs = sizeDiv.getElementsByTagName('div');
  									if (divs.length > 0)
  									{
  										sizeDiv = divs[divs.length - 1];
  									}
  									ow = sizeDiv.offsetWidth + 2;
  									divs = this.node.getElementsByTagName('div');
  									if (this.clipped)
  									{
  										ow = Math.min(w, ow);
  									}
  									if (divs.length > 1)
  									{
  										divs[divs.length - 2].style.width = ow + 'px';
  									}
  								}
  							}
  							else
  							{
  								node.style.whiteSpace = 'nowrap';
  							}
  						}
  						else if (sizeDiv.firstChild != null && sizeDiv.firstChild.nodeName == 'DIV')
  						{
  							sizeDiv = sizeDiv.firstChild;
  						}
  						this.offsetWidth = sizeDiv.offsetWidth + this.textWidthPadding;
  						this.offsetHeight = sizeDiv.offsetHeight;
  						ow = this.offsetWidth * this.scale;
  						oh = this.offsetHeight * this.scale;
  					}
  				}
  				if (ow != null && oh != null)
  				{
  					this.boundingBox = new mxRectangle(this.bounds.x,
  						this.bounds.y, ow, oh);
  				}
  			}
  			if (this.boundingBox != null)
  			{
  				if (rot != 0)
  				{
  					var bbox = mxUtils.getBoundingBox(new mxRectangle(
  						this.margin.x * this.boundingBox.width,
  						this.margin.y * this.boundingBox.height,
  						this.boundingBox.width, this.boundingBox.height),
  						rot, new mxPoint(0, 0));
  					this.unrotatedBoundingBox = mxRectangle.fromRectangle(this.boundingBox);
  					this.unrotatedBoundingBox.x += this.margin.x * this.unrotatedBoundingBox.width;
  					this.unrotatedBoundingBox.y += this.margin.y * this.unrotatedBoundingBox.height;
  					this.boundingBox.x += bbox.x;
  					this.boundingBox.y += bbox.y;
  					this.boundingBox.width = bbox.width;
  					this.boundingBox.height = bbox.height;
  				}
  				else
  				{
  					this.boundingBox.x += this.margin.x * this.boundingBox.width;
  					this.boundingBox.y += this.margin.y * this.boundingBox.height;
  					this.unrotatedBoundingBox = null;
  				}
  			}
  		};
  		mxText.prototype.getShapeRotation = function()
  		{
  			return 0;
  		};
  		mxText.prototype.getTextRotation = function()
  		{
  			return (this.state != null && this.state.shape != null) ? this.state.shape.getTextRotation() : 0;
  		};
  		mxText.prototype.isPaintBoundsInverted = function()
  		{
  			return !this.horizontal && this.state != null && this.state.view.graph.model.isVertex(this.state.cell);
  		};
  		mxText.prototype.configureCanvas = function(c, x, y, w, h)
  		{
  			mxShape.prototype.configureCanvas.apply(this, arguments);
  			c.setFontColor(this.color);
  			c.setFontBackgroundColor(this.background);
  			c.setFontBorderColor(this.border);
  			c.setFontFamily(this.family);
  			c.setFontSize(this.size);
  			c.setFontStyle(this.fontStyle);
  		};
  		mxText.prototype.updateVmlContainer = function()
  		{
  			this.node.style.left = Math.round(this.bounds.x) + 'px';
  			this.node.style.top = Math.round(this.bounds.y) + 'px';
  			this.node.style.width = '1px';
  			this.node.style.height = '1px';
  			this.node.style.overflow = 'visible';
  		};
  		mxText.prototype.getHtmlValue = function()
  		{
  			var val = this.value;
  			if (this.dialect != mxConstants.DIALECT_STRICTHTML)
  			{
  				val = mxUtils.htmlEntities(val, false);
  			}
  			val = mxUtils.replaceTrailingNewlines(val, '<div><br></div>');
  			val = (this.replaceLinefeeds) ? val.replace(/\n/g, '<br/>') : val;
  			return val;
  		};
  		mxText.prototype.getTextCss = function()
  		{
  			var lh = (mxConstants.ABSOLUTE_LINE_HEIGHT) ? (this.size * mxConstants.LINE_HEIGHT) + 'px' :
  				mxConstants.LINE_HEIGHT;
  			var css = 'display: inline-block; font-size: ' + this.size + 'px; ' +
  				'font-family: ' + this.family + '; color: ' + this.color + '; line-height: ' + lh +
  				'; pointer-events: ' + ((this.pointerEvents) ? 'all' : 'none') + '; ';
  			if ((this.fontStyle & mxConstants.FONT_BOLD) == mxConstants.FONT_BOLD)
  			{
  				css += 'font-weight: bold; ';
  			}
  			if ((this.fontStyle & mxConstants.FONT_ITALIC) == mxConstants.FONT_ITALIC)
  			{
  				css += 'font-style: italic; ';
  			}
  			var deco = [];
  			if ((this.fontStyle & mxConstants.FONT_UNDERLINE) == mxConstants.FONT_UNDERLINE)
  			{
  				deco.push('underline');
  			}
  			if ((this.fontStyle & mxConstants.FONT_STRIKETHROUGH) == mxConstants.FONT_STRIKETHROUGH)
  			{
  				deco.push('line-through');
  			}
  			if (deco.length > 0)
  			{
  				css += 'text-decoration: ' + deco.join(' ') + '; ';
  			}
  			return css;
  		};
  		mxText.prototype.redrawHtmlShape = function()
  		{
  			if (mxClient.IS_SVG)
  			{
  				this.redrawHtmlShapeWithCss3();
  			}
  			else
  			{
  				var style = this.node.style;
  				style.whiteSpace = 'normal';
  				style.overflow = '';
  				style.width = '';
  				style.height = '';
  				this.updateValue();
  				this.updateFont(this.node);
  				this.updateSize(this.node, (this.state == null || this.state.view.textDiv == null));
  				this.offsetWidth = null;
  				this.offsetHeight = null;
  				if (mxClient.IS_IE && (document.documentMode == null || document.documentMode <= 8))
  				{
  					this.updateHtmlFilter();
  				}
  				else
  				{
  					this.updateHtmlTransform();
  				}
  			}
  		};
  		mxText.prototype.redrawHtmlShapeWithCss3 = function()
  		{
  			var w = Math.max(0, Math.round(this.bounds.width / this.scale));
  			var h = Math.max(0, Math.round(this.bounds.height / this.scale));
  			var flex = 'position: absolute; left: ' + Math.round(this.bounds.x) + 'px; ' +
  				'top: ' + Math.round(this.bounds.y) + 'px; pointer-events: none; ';
  			var block = this.getTextCss();
  			mxSvgCanvas2D.createCss(w + 2, h, this.align, this.valign, this.wrap, this.overflow, this.clipped,
  				(this.background != null) ? mxUtils.htmlEntities(this.background) : null,
  				(this.border != null) ? mxUtils.htmlEntities(this.border) : null,
  				flex, block, this.scale, mxUtils.bind(this, function(dx, dy, flex, item, block, ofl)
  			{
  				var r = this.getTextRotation();
  				var tr = ((this.scale != 1) ? 'scale(' + this.scale + ') ' : '') +
  					((r != 0) ? 'rotate(' + r + 'deg) ' : '') +
  					((this.margin.x != 0 || this.margin.y != 0) ?
  						'translate(' + (this.margin.x * 100) + '%,' +
  							(this.margin.y * 100) + '%)' : '');
  				if (tr != '')
  				{
  					tr = 'transform-origin: 0 0; transform: ' + tr + '; ';
  				}
  				if (ofl == '')
  				{
  					flex += item;
  					item = 'display:inline-block; min-width: 100%; ' + tr;
  				}
  				else
  				{
  					item += tr;
  					if (mxClient.IS_SF)
  					{
  						item += '-webkit-clip-path: content-box;';
  					}
  				}
  				if (this.opacity < 100)
  				{
  					block += 'opacity: ' + (this.opacity / 100) + '; ';
  				}
  				this.node.setAttribute('style', flex);
  				var html = (mxUtils.isNode(this.value)) ? this.value.outerHTML : this.getHtmlValue();
  				if (this.node.firstChild == null)
  				{
  					this.node.innerHTML = '<div><div>' + html +'</div></div>';
  				}
  				this.node.firstChild.firstChild.setAttribute('style', block);
  				this.node.firstChild.setAttribute('style', item);
  			}));
  		};
  		mxText.prototype.updateHtmlTransform = function()
  		{
  			var theta = this.getTextRotation();
  			var style = this.node.style;
  			var dx = this.margin.x;
  			var dy = this.margin.y;
  			if (theta != 0)
  			{
  				mxUtils.setPrefixedStyle(style, 'transformOrigin', (-dx * 100) + '%' + ' ' + (-dy * 100) + '%');
  				mxUtils.setPrefixedStyle(style, 'transform', 'translate(' + (dx * 100) + '%' + ',' + (dy * 100) + '%) ' +
  					'scale(' + this.scale + ') rotate(' + theta + 'deg)');
  			}
  			else
  			{
  				mxUtils.setPrefixedStyle(style, 'transformOrigin', '0% 0%');
  				mxUtils.setPrefixedStyle(style, 'transform', 'scale(' + this.scale + ') ' +
  					'translate(' + (dx * 100) + '%' + ',' + (dy * 100) + '%)');
  			}
  			style.left = Math.round(this.bounds.x - Math.ceil(dx * ((this.overflow != 'fill' &&
  				this.overflow != 'width') ? 3 : 1))) + 'px';
  			style.top = Math.round(this.bounds.y - dy * ((this.overflow != 'fill') ? 3 : 1)) + 'px';
  			if (this.opacity < 100)
  			{
  				style.opacity = this.opacity / 100;
  			}
  			else
  			{
  				style.opacity = '';
  			}
  		};
  		mxText.prototype.updateInnerHtml = function(elt)
  		{
  			if (mxUtils.isNode(this.value))
  			{
  				elt.innerHTML = this.value.outerHTML;
  			}
  			else
  			{
  				var val = this.value;
  				if (this.dialect != mxConstants.DIALECT_STRICTHTML)
  				{
  					val = mxUtils.htmlEntities(val, false);
  				}
  				val = mxUtils.replaceTrailingNewlines(val, '<div>&nbsp;</div>');
  				val = (this.replaceLinefeeds) ? val.replace(/\n/g, '<br/>') : val;
  				val = '<div style="display:inline-block;_display:inline;">' + val + '</div>';
  				elt.innerHTML = val;
  			}
  		};
  		mxText.prototype.updateHtmlFilter = function()
  		{
  			var style = this.node.style;
  			var dx = this.margin.x;
  			var dy = this.margin.y;
  			var s = this.scale;
  			mxUtils.setOpacity(this.node, this.opacity);
  			var ow = 0;
  			var oh = 0;
  			var td = (this.state != null) ? this.state.view.textDiv : null;
  			var sizeDiv = this.node;
  			if (td != null)
  			{
  				td.style.overflow = '';
  				td.style.height = '';
  				td.style.width = '';
  				this.updateFont(td);
  				this.updateSize(td, false);
  				this.updateInnerHtml(td);
  				var w = Math.round(this.bounds.width / this.scale);
  				if (this.wrap && w > 0)
  				{
  					td.style.whiteSpace = 'normal';
  					td.style.wordWrap = mxConstants.WORD_WRAP;
  					ow = w;
  					if (this.clipped)
  					{
  						ow = Math.min(ow, this.bounds.width);
  					}
  					td.style.width = ow + 'px';
  				}
  				else
  				{
  					td.style.whiteSpace = 'nowrap';
  				}
  				sizeDiv = td;
  				if (sizeDiv.firstChild != null && sizeDiv.firstChild.nodeName == 'DIV')
  				{
  					sizeDiv = sizeDiv.firstChild;
  					if (this.wrap && td.style.wordWrap == 'break-word')
  					{
  						sizeDiv.style.width = '100%';
  					}
  				}
  				if (!this.clipped && this.wrap && w > 0)
  				{
  					ow = sizeDiv.offsetWidth + this.textWidthPadding;
  					td.style.width = ow + 'px';
  				}
  				oh = sizeDiv.offsetHeight + 2;
  				if (mxClient.IS_QUIRKS && this.border != null && this.border != mxConstants.NONE)
  				{
  					oh += 3;
  				}
  			}
  			else if (sizeDiv.firstChild != null && sizeDiv.firstChild.nodeName == 'DIV')
  			{
  				sizeDiv = sizeDiv.firstChild;
  				oh = sizeDiv.offsetHeight;
  			}
  			ow = sizeDiv.offsetWidth + this.textWidthPadding;
  			if (this.clipped)
  			{
  				oh = Math.min(oh, this.bounds.height);
  			}
  			var w = this.bounds.width / s;
  			var h = this.bounds.height / s;
  			if (this.overflow == 'fill')
  			{
  				oh = h;
  				ow = w;
  			}
  			else if (this.overflow == 'width')
  			{
  				oh = sizeDiv.scrollHeight;
  				ow = w;
  			}
  			this.offsetWidth = ow;
  			this.offsetHeight = oh;
  			if (mxClient.IS_QUIRKS && (this.clipped || (this.overflow == 'width' && h > 0)))
  			{
  				h = Math.min(h, oh);
  				style.height = Math.round(h) + 'px';
  			}
  			else
  			{
  				h = oh;
  			}
  			if (this.overflow != 'fill' && this.overflow != 'width')
  			{
  				if (this.clipped)
  				{
  					ow = Math.min(w, ow);
  				}
  				w = ow;
  				if ((mxClient.IS_QUIRKS && this.clipped) || this.wrap)
  				{
  					style.width = Math.round(w) + 'px';
  				}
  			}
  			h *= s;
  			w *= s;
  			var rad = this.getTextRotation() * (Math.PI / 180);
  			var real_cos = parseFloat(parseFloat(Math.cos(rad)).toFixed(8));
  			var real_sin = parseFloat(parseFloat(Math.sin(-rad)).toFixed(8));
  			rad %= 2 * Math.PI;
  			if (rad < 0)
  			{
  				rad += 2 * Math.PI;
  			}
  			rad %= Math.PI;
  			if (rad > Math.PI / 2)
  			{
  				rad = Math.PI - rad;
  			}
  			var cos = Math.cos(rad);
  			var sin = Math.sin(-rad);
  			var tx = w * -(dx + 0.5);
  			var ty = h * -(dy + 0.5);
  			var top_fix = (h - h * cos + w * sin) / 2 + real_sin * tx - real_cos * ty;
  			var left_fix = (w - w * cos + h * sin) / 2 - real_cos * tx - real_sin * ty;
  			if (rad != 0)
  			{
  				var f = 'progid:DXImageTransform.Microsoft.Matrix(M11=' + real_cos + ', M12='+
  					real_sin + ', M21=' + (-real_sin) + ', M22=' + real_cos + ', sizingMethod=\'auto expand\')';
  				if (style.filter != null && style.filter.length > 0)
  				{
  					style.filter += ' ' + f;
  				}
  				else
  				{
  					style.filter = f;
  				}
  			}
  			var dy = 0;
  			if (this.overflow != 'fill' && mxClient.IS_QUIRKS)
  			{
  				if (this.valign == mxConstants.ALIGN_TOP)
  				{
  					dy -= 1;
  				}
  				else if (this.valign == mxConstants.ALIGN_BOTTOM)
  				{
  					dy += 2;
  				}
  				else
  				{
  					dy += 1;
  				}
  			}
  			style.zoom = s;
  			style.left = Math.round(this.bounds.x + left_fix - w / 2) + 'px';
  			style.top = Math.round(this.bounds.y + top_fix - h / 2 + dy) + 'px';
  		};
  		mxText.prototype.updateValue = function()
  		{
  			if (mxUtils.isNode(this.value))
  			{
  				this.node.innerHTML = '';
  				this.node.appendChild(this.value);
  			}
  			else
  			{
  				var val = this.value;
  				if (this.dialect != mxConstants.DIALECT_STRICTHTML)
  				{
  					val = mxUtils.htmlEntities(val, false);
  				}
  				val = mxUtils.replaceTrailingNewlines(val, '<div><br></div>');
  				val = (this.replaceLinefeeds) ? val.replace(/\n/g, '<br/>') : val;
  				var bg = (this.background != null && this.background != mxConstants.NONE) ? this.background : null;
  				var bd = (this.border != null && this.border != mxConstants.NONE) ? this.border : null;
  				if (this.overflow == 'fill' || this.overflow == 'width')
  				{
  					if (bg != null)
  					{
  						this.node.style.backgroundColor = bg;
  					}
  					if (bd != null)
  					{
  						this.node.style.border = '1px solid ' + bd;
  					}
  				}
  				else
  				{
  					var css = '';
  					if (bg != null)
  					{
  						css += 'background-color:' + mxUtils.htmlEntities(bg) + ';';
  					}
  					if (bd != null)
  					{
  						css += 'border:1px solid ' + mxUtils.htmlEntities(bd) + ';';
  					}
  					var lh = (mxConstants.ABSOLUTE_LINE_HEIGHT) ? (this.size * mxConstants.LINE_HEIGHT) + 'px' :
  						mxConstants.LINE_HEIGHT;
  					val = '<div style="zoom:1;' + css + 'display:inline-block;_display:inline;text-decoration:inherit;' +
  						'padding-bottom:1px;padding-right:1px;line-height:' + lh + '">' + val + '</div>';
  				}
  				this.node.innerHTML = val;
  				var divs = this.node.getElementsByTagName('div');
  				if (divs.length > 0)
  				{
  					var dir = this.textDirection;
  					if (dir == mxConstants.TEXT_DIRECTION_AUTO && this.dialect != mxConstants.DIALECT_STRICTHTML)
  					{
  						dir = this.getAutoDirection();
  					}
  					if (dir == mxConstants.TEXT_DIRECTION_LTR || dir == mxConstants.TEXT_DIRECTION_RTL)
  					{
  						divs[divs.length - 1].setAttribute('dir', dir);
  					}
  					else
  					{
  						divs[divs.length - 1].removeAttribute('dir');
  					}
  				}
  			}
  		};
  		mxText.prototype.updateFont = function(node)
  		{
  			var style = node.style;
  			style.lineHeight = (mxConstants.ABSOLUTE_LINE_HEIGHT) ? (this.size * mxConstants.LINE_HEIGHT) + 'px' : mxConstants.LINE_HEIGHT;
  			style.fontSize = this.size + 'px';
  			style.fontFamily = this.family;
  			style.verticalAlign = 'top';
  			style.color = this.color;
  			if ((this.fontStyle & mxConstants.FONT_BOLD) == mxConstants.FONT_BOLD)
  			{
  				style.fontWeight = 'bold';
  			}
  			else
  			{
  				style.fontWeight = '';
  			}
  			if ((this.fontStyle & mxConstants.FONT_ITALIC) == mxConstants.FONT_ITALIC)
  			{
  				style.fontStyle = 'italic';
  			}
  			else
  			{
  				style.fontStyle = '';
  			}
  			var txtDecor = [];
  			if ((this.fontStyle & mxConstants.FONT_UNDERLINE) == mxConstants.FONT_UNDERLINE)
  			{
  				txtDecor.push('underline');
  			}
  			if ((this.fontStyle & mxConstants.FONT_STRIKETHROUGH) == mxConstants.FONT_STRIKETHROUGH)
  			{
  				txtDecor.push('line-through');
  			}
  			style.textDecoration = txtDecor.join(' ');
  			if (this.align == mxConstants.ALIGN_CENTER)
  			{
  				style.textAlign = 'center';
  			}
  			else if (this.align == mxConstants.ALIGN_RIGHT)
  			{
  				style.textAlign = 'right';
  			}
  			else
  			{
  				style.textAlign = 'left';
  			}
  		};
  		mxText.prototype.updateSize = function(node, enableWrap)
  		{
  			var w = Math.max(0, Math.round(this.bounds.width / this.scale));
  			var h = Math.max(0, Math.round(this.bounds.height / this.scale));
  			var style = node.style;
  			if (this.clipped)
  			{
  				style.overflow = 'hidden';
  				if (!mxClient.IS_QUIRKS)
  				{
  					style.maxHeight = h + 'px';
  					style.maxWidth = w + 'px';
  				}
  				else
  				{
  					style.width = w + 'px';
  				}
  			}
  			else if (this.overflow == 'fill')
  			{
  				style.width = (w + 1) + 'px';
  				style.height = (h + 1) + 'px';
  				style.overflow = 'hidden';
  			}
  			else if (this.overflow == 'width')
  			{
  				style.width = (w + 1) + 'px';
  				style.maxHeight = (h + 1) + 'px';
  				style.overflow = 'hidden';
  			}
  			if (this.wrap && w > 0)
  			{
  				style.wordWrap = mxConstants.WORD_WRAP;
  				style.whiteSpace = 'normal';
  				style.width = w + 'px';
  				if (enableWrap && this.overflow != 'fill' && this.overflow != 'width')
  				{
  					var sizeDiv = node;
  					if (sizeDiv.firstChild != null && sizeDiv.firstChild.nodeName == 'DIV')
  					{
  						sizeDiv = sizeDiv.firstChild;
  						if (node.style.wordWrap == 'break-word')
  						{
  							sizeDiv.style.width = '100%';
  						}
  					}
  					var tmp = sizeDiv.offsetWidth;
  					if (tmp == 0)
  					{
  						var prev = node.parentNode;
  						node.style.visibility = 'hidden';
  						document.body.appendChild(node);
  						tmp = sizeDiv.offsetWidth;
  						node.style.visibility = '';
  						prev.appendChild(node);
  					}
  					tmp += 3;
  					if (this.clipped)
  					{
  						tmp = Math.min(tmp, w);
  					}
  					style.width = tmp + 'px';
  				}
  			}
  			else
  			{
  				style.whiteSpace = 'nowrap';
  			}
  		};
  		mxText.prototype.updateMargin = function()
  		{
  			this.margin = mxUtils.getAlignmentAsPoint(this.align, this.valign);
  		};
  		mxText.prototype.getSpacing = function()
  		{
  			var dx = 0;
  			var dy = 0;
  			if (this.align == mxConstants.ALIGN_CENTER)
  			{
  				dx = (this.spacingLeft - this.spacingRight) / 2;
  			}
  			else if (this.align == mxConstants.ALIGN_RIGHT)
  			{
  				dx = -this.spacingRight - this.baseSpacingRight;
  			}
  			else
  			{
  				dx = this.spacingLeft + this.baseSpacingLeft;
  			}
  			if (this.valign == mxConstants.ALIGN_MIDDLE)
  			{
  				dy = (this.spacingTop - this.spacingBottom) / 2;
  			}
  			else if (this.valign == mxConstants.ALIGN_BOTTOM)
  			{
  				dy = -this.spacingBottom - this.baseSpacingBottom;			}
  			else
  			{
  				dy = this.spacingTop + this.baseSpacingTop;
  			}
  			return new mxPoint(dx, dy);
  		};
  		__mxOutput.mxText = typeof mxText !== 'undefined' ? mxText : undefined;
  		function mxTriangle()
  		{
  			mxActor.call(this);
  		}		mxUtils.extend(mxTriangle, mxActor);
  		mxTriangle.prototype.isRoundable = function()
  		{
  			return true;
  		};
  		mxTriangle.prototype.redrawPath = function(c, x, y, w, h)
  		{
  			var arcSize = mxUtils.getValue(this.style, mxConstants.STYLE_ARCSIZE, mxConstants.LINE_ARCSIZE) / 2;
  			this.addPoints(c, [new mxPoint(0, 0), new mxPoint(w, 0.5 * h), new mxPoint(0, h)], this.isRounded, arcSize, true);
  		};
  		__mxOutput.mxTriangle = typeof mxTriangle !== 'undefined' ? mxTriangle : undefined;
  		function mxHexagon()
  		{
  			mxActor.call(this);
  		}		mxUtils.extend(mxHexagon, mxActor);
  		mxHexagon.prototype.redrawPath = function(c, x, y, w, h)
  		{
  			var arcSize = mxUtils.getValue(this.style, mxConstants.STYLE_ARCSIZE, mxConstants.LINE_ARCSIZE) / 2;
  			this.addPoints(c, [new mxPoint(0.25 * w, 0), new mxPoint(0.75 * w, 0), new mxPoint(w, 0.5 * h), new mxPoint(0.75 * w, h),
  			                   new mxPoint(0.25 * w, h), new mxPoint(0, 0.5 * h)], this.isRounded, arcSize, true);
  		};
  		__mxOutput.mxHexagon = typeof mxHexagon !== 'undefined' ? mxHexagon : undefined;
  		function mxLine(bounds, stroke, strokewidth, vertical)
  		{
  			mxShape.call(this);
  			this.bounds = bounds;
  			this.stroke = stroke;
  			this.strokewidth = (strokewidth != null) ? strokewidth : 1;
  			this.vertical = (vertical != null) ? vertical : this.vertical;
  		}		mxUtils.extend(mxLine, mxShape);
  		mxLine.prototype.vertical = false;
  		mxLine.prototype.paintVertexShape = function(c, x, y, w, h)
  		{
  			c.begin();
  			if (this.vertical)
  			{
  				var mid = x + w / 2;
  				c.moveTo(mid, y);
  				c.lineTo(mid, y + h);
  			}
  			else
  			{
  				var mid = y + h / 2;
  				c.moveTo(x, mid);
  				c.lineTo(x + w, mid);
  			}
  			c.stroke();
  		};
  		__mxOutput.mxLine = typeof mxLine !== 'undefined' ? mxLine : undefined;
  		function mxImageShape(bounds, image, fill, stroke, strokewidth)
  		{
  			mxShape.call(this);
  			this.bounds = bounds;
  			this.image = image;
  			this.fill = fill;
  			this.stroke = stroke;
  			this.strokewidth = (strokewidth != null) ? strokewidth : 1;
  			this.shadow = false;
  		}		mxUtils.extend(mxImageShape, mxRectangleShape);
  		mxImageShape.prototype.preserveImageAspect = true;
  		mxImageShape.prototype.getSvgScreenOffset = function()
  		{
  			return 0;
  		};
  		mxImageShape.prototype.apply = function(state)
  		{
  			mxShape.prototype.apply.apply(this, arguments);
  			this.fill = null;
  			this.stroke = null;
  			this.gradient = null;
  			if (this.style != null)
  			{
  				this.preserveImageAspect = mxUtils.getNumber(this.style, mxConstants.STYLE_IMAGE_ASPECT, 1) == 1;
  				this.flipH = this.flipH || mxUtils.getValue(this.style, 'imageFlipH', 0) == 1;
  				this.flipV = this.flipV || mxUtils.getValue(this.style, 'imageFlipV', 0) == 1;
  			}
  		};
  		mxImageShape.prototype.isHtmlAllowed = function()
  		{
  			return !this.preserveImageAspect;
  		};
  		mxImageShape.prototype.createHtml = function()
  		{
  			var node = document.createElement('div');
  			node.style.position = 'absolute';
  			return node;
  		};
  		mxImageShape.prototype.isRoundable = function(c, x, y, w, h)
  		{
  			return false;
  		};
  		mxImageShape.prototype.paintVertexShape = function(c, x, y, w, h)
  		{
  			if (this.image != null)
  			{
  				var fill = mxUtils.getValue(this.style, mxConstants.STYLE_IMAGE_BACKGROUND, null);
  				var stroke = mxUtils.getValue(this.style, mxConstants.STYLE_IMAGE_BORDER, null);
  				if (fill != null)
  				{
  					c.setFillColor(fill);
  					c.setStrokeColor(stroke);
  					c.rect(x, y, w, h);
  					c.fillAndStroke();
  				}
  				c.image(x, y, w, h, this.image, this.preserveImageAspect, false, false);
  				var stroke = mxUtils.getValue(this.style, mxConstants.STYLE_IMAGE_BORDER, null);
  				if (stroke != null)
  				{
  					c.setShadow(false);
  					c.setStrokeColor(stroke);
  					c.rect(x, y, w, h);
  					c.stroke();
  				}
  			}
  			else
  			{
  				mxRectangleShape.prototype.paintBackground.apply(this, arguments);
  			}
  		};
  		mxImageShape.prototype.redrawHtmlShape = function()
  		{
  			this.node.style.left = Math.round(this.bounds.x) + 'px';
  			this.node.style.top = Math.round(this.bounds.y) + 'px';
  			this.node.style.width = Math.max(0, Math.round(this.bounds.width)) + 'px';
  			this.node.style.height = Math.max(0, Math.round(this.bounds.height)) + 'px';
  			this.node.innerHTML = '';
  			if (this.image != null)
  			{
  				var fill = mxUtils.getValue(this.style, mxConstants.STYLE_IMAGE_BACKGROUND, '');
  				var stroke = mxUtils.getValue(this.style, mxConstants.STYLE_IMAGE_BORDER, '');
  				this.node.style.backgroundColor = fill;
  				this.node.style.borderColor = stroke;
  				var useVml = mxClient.IS_IE6 || ((document.documentMode == null || document.documentMode <= 8) && this.rotation != 0);
  				var img = document.createElement((useVml) ? mxClient.VML_PREFIX + ':image' : 'img');
  				img.setAttribute('border', '0');
  				img.style.position = 'absolute';
  				img.src = this.image;
  				var filter = (this.opacity < 100) ? 'alpha(opacity=' + this.opacity + ')' : '';
  				this.node.style.filter = filter;
  				if (this.flipH && this.flipV)
  				{
  					filter += 'progid:DXImageTransform.Microsoft.BasicImage(rotation=2)';
  				}
  				else if (this.flipH)
  				{
  					filter += 'progid:DXImageTransform.Microsoft.BasicImage(mirror=1)';
  				}
  				else if (this.flipV)
  				{
  					filter += 'progid:DXImageTransform.Microsoft.BasicImage(rotation=2, mirror=1)';
  				}
  				if (img.style.filter != filter)
  				{
  					img.style.filter = filter;
  				}
  				if (img.nodeName == 'image')
  				{
  					img.style.rotation = this.rotation;
  				}
  				else if (this.rotation != 0)
  				{
  					mxUtils.setPrefixedStyle(img.style, 'transform', 'rotate(' + this.rotation + 'deg)');
  				}
  				else
  				{
  					mxUtils.setPrefixedStyle(img.style, 'transform', '');
  				}
  				img.style.width = this.node.style.width;
  				img.style.height = this.node.style.height;
  				this.node.style.backgroundImage = '';
  				this.node.appendChild(img);
  			}
  			else
  			{
  				this.setTransparentBackgroundImage(this.node);
  			}
  		};
  		__mxOutput.mxImageShape = typeof mxImageShape !== 'undefined' ? mxImageShape : undefined;
  		function mxLabel(bounds, fill, stroke, strokewidth)
  		{
  			mxRectangleShape.call(this, bounds, fill, stroke, strokewidth);
  		}		mxUtils.extend(mxLabel, mxRectangleShape);
  		mxLabel.prototype.imageSize = mxConstants.DEFAULT_IMAGESIZE;
  		mxLabel.prototype.spacing = 2;
  		mxLabel.prototype.indicatorSize = 10;
  		mxLabel.prototype.indicatorSpacing = 2;
  		mxLabel.prototype.init = function(container)
  		{
  			mxShape.prototype.init.apply(this, arguments);
  			if (this.indicatorShape != null)
  			{
  				this.indicator = new this.indicatorShape();
  				this.indicator.dialect = this.dialect;
  				this.indicator.init(this.node);
  			}
  		};
  		mxLabel.prototype.redraw = function()
  		{
  			if (this.indicator != null)
  			{
  				this.indicator.fill = this.indicatorColor;
  				this.indicator.stroke = this.indicatorStrokeColor;
  				this.indicator.gradient = this.indicatorGradientColor;
  				this.indicator.direction = this.indicatorDirection;
  				this.indicator.redraw();
  			}
  			mxShape.prototype.redraw.apply(this, arguments);
  		};
  		mxLabel.prototype.isHtmlAllowed = function()
  		{
  			return mxRectangleShape.prototype.isHtmlAllowed.apply(this, arguments) &&
  				this.indicatorColor == null && this.indicatorShape == null;
  		};
  		mxLabel.prototype.paintForeground = function(c, x, y, w, h)
  		{
  			this.paintImage(c, x, y, w, h);
  			this.paintIndicator(c, x, y, w, h);
  			mxRectangleShape.prototype.paintForeground.apply(this, arguments);
  		};
  		mxLabel.prototype.paintImage = function(c, x, y, w, h)
  		{
  			if (this.image != null)
  			{
  				var bounds = this.getImageBounds(x, y, w, h);
  				c.image(bounds.x, bounds.y, bounds.width, bounds.height, this.image, false, false, false);
  			}
  		};
  		mxLabel.prototype.getImageBounds = function(x, y, w, h)
  		{
  			var align = mxUtils.getValue(this.style, mxConstants.STYLE_IMAGE_ALIGN, mxConstants.ALIGN_LEFT);
  			var valign = mxUtils.getValue(this.style, mxConstants.STYLE_IMAGE_VERTICAL_ALIGN, mxConstants.ALIGN_MIDDLE);
  			var width = mxUtils.getNumber(this.style, mxConstants.STYLE_IMAGE_WIDTH, mxConstants.DEFAULT_IMAGESIZE);
  			var height = mxUtils.getNumber(this.style, mxConstants.STYLE_IMAGE_HEIGHT, mxConstants.DEFAULT_IMAGESIZE);
  			var spacing = mxUtils.getNumber(this.style, mxConstants.STYLE_SPACING, this.spacing) + 5;
  			if (align == mxConstants.ALIGN_CENTER)
  			{
  				x += (w - width) / 2;
  			}
  			else if (align == mxConstants.ALIGN_RIGHT)
  			{
  				x += w - width - spacing;
  			}
  			else
  			{
  				x += spacing;
  			}
  			if (valign == mxConstants.ALIGN_TOP)
  			{
  				y += spacing;
  			}
  			else if (valign == mxConstants.ALIGN_BOTTOM)
  			{
  				y += h - height - spacing;
  			}
  			else
  			{
  				y += (h - height) / 2;
  			}
  			return new mxRectangle(x, y, width, height);
  		};
  		mxLabel.prototype.paintIndicator = function(c, x, y, w, h)
  		{
  			if (this.indicator != null)
  			{
  				this.indicator.bounds = this.getIndicatorBounds(x, y, w, h);
  				this.indicator.paint(c);
  			}
  			else if (this.indicatorImage != null)
  			{
  				var bounds = this.getIndicatorBounds(x, y, w, h);
  				c.image(bounds.x, bounds.y, bounds.width, bounds.height, this.indicatorImage, false, false, false);
  			}
  		};
  		mxLabel.prototype.getIndicatorBounds = function(x, y, w, h)
  		{
  			var align = mxUtils.getValue(this.style, mxConstants.STYLE_IMAGE_ALIGN, mxConstants.ALIGN_LEFT);
  			var valign = mxUtils.getValue(this.style, mxConstants.STYLE_IMAGE_VERTICAL_ALIGN, mxConstants.ALIGN_MIDDLE);
  			var width = mxUtils.getNumber(this.style, mxConstants.STYLE_INDICATOR_WIDTH, this.indicatorSize);
  			var height = mxUtils.getNumber(this.style, mxConstants.STYLE_INDICATOR_HEIGHT, this.indicatorSize);
  			var spacing = this.spacing + 5;
  			if (align == mxConstants.ALIGN_RIGHT)
  			{
  				x += w - width - spacing;
  			}
  			else if (align == mxConstants.ALIGN_CENTER)
  			{
  				x += (w - width) / 2;
  			}
  			else
  			{
  				x += spacing;
  			}
  			if (valign == mxConstants.ALIGN_BOTTOM)
  			{
  				y += h - height - spacing;
  			}
  			else if (valign == mxConstants.ALIGN_TOP)
  			{
  				y += spacing;
  			}
  			else
  			{
  				y += (h - height) / 2;
  			}
  			return new mxRectangle(x, y, width, height);
  		};
  		mxLabel.prototype.redrawHtmlShape = function()
  		{
  			mxRectangleShape.prototype.redrawHtmlShape.apply(this, arguments);
  			while(this.node.hasChildNodes())
  			{
  				this.node.removeChild(this.node.lastChild);
  			}
  			if (this.image != null)
  			{
  				var node = document.createElement('img');
  				node.style.position = 'relative';
  				node.setAttribute('border', '0');
  				var bounds = this.getImageBounds(this.bounds.x, this.bounds.y, this.bounds.width, this.bounds.height);
  				bounds.x -= this.bounds.x;
  				bounds.y -= this.bounds.y;
  				node.style.left = Math.round(bounds.x) + 'px';
  				node.style.top = Math.round(bounds.y) + 'px';
  				node.style.width = Math.round(bounds.width) + 'px';
  				node.style.height = Math.round(bounds.height) + 'px';
  				node.src = this.image;
  				this.node.appendChild(node);
  			}
  		};
  		__mxOutput.mxLabel = typeof mxLabel !== 'undefined' ? mxLabel : undefined;
  		function mxCylinder(bounds, fill, stroke, strokewidth)
  		{
  			mxShape.call(this);
  			this.bounds = bounds;
  			this.fill = fill;
  			this.stroke = stroke;
  			this.strokewidth = (strokewidth != null) ? strokewidth : 1;
  		}		mxUtils.extend(mxCylinder, mxShape);
  		mxCylinder.prototype.maxHeight = 40;
  		mxCylinder.prototype.svgStrokeTolerance = 0;
  		mxCylinder.prototype.paintVertexShape = function(c, x, y, w, h)
  		{
  			c.translate(x, y);
  			c.begin();
  			this.redrawPath(c, x, y, w, h, false);
  			c.fillAndStroke();
  			if (!this.outline || this.style == null || mxUtils.getValue(
  				this.style, mxConstants.STYLE_BACKGROUND_OUTLINE, 0) == 0)
  			{
  				c.setShadow(false);
  				c.begin();
  				this.redrawPath(c, x, y, w, h, true);
  				c.stroke();
  			}
  		};
  		mxCylinder.prototype.getCylinderSize = function(x, y, w, h)
  		{
  			return Math.min(this.maxHeight, Math.round(h / 5));
  		};
  		mxCylinder.prototype.redrawPath = function(c, x, y, w, h, isForeground)
  		{
  			var dy = this.getCylinderSize(x, y, w, h);
  			if ((isForeground && this.fill != null) || (!isForeground && this.fill == null))
  			{
  				c.moveTo(0, dy);
  				c.curveTo(0, 2 * dy, w, 2 * dy, w, dy);
  				if (!isForeground)
  				{
  					c.stroke();
  					c.begin();
  				}
  			}
  			if (!isForeground)
  			{
  				c.moveTo(0, dy);
  				c.curveTo(0, -dy / 3, w, -dy / 3, w, dy);
  				c.lineTo(w, h - dy);
  				c.curveTo(w, h + dy / 3, 0, h + dy / 3, 0, h - dy);
  				c.close();
  			}
  		};
  		__mxOutput.mxCylinder = typeof mxCylinder !== 'undefined' ? mxCylinder : undefined;
  		function mxConnector(points, stroke, strokewidth)
  		{
  			mxPolyline.call(this, points, stroke, strokewidth);
  		}		mxUtils.extend(mxConnector, mxPolyline);
  		mxConnector.prototype.updateBoundingBox = function()
  		{
  			this.useSvgBoundingBox = this.style != null && this.style[mxConstants.STYLE_CURVED] == 1;
  			mxShape.prototype.updateBoundingBox.apply(this, arguments);
  		};
  		mxConnector.prototype.paintEdgeShape = function(c, pts)
  		{
  			var sourceMarker = this.createMarker(c, pts, true);
  			var targetMarker = this.createMarker(c, pts, false);
  			mxPolyline.prototype.paintEdgeShape.apply(this, arguments);
  			c.setFillColor(this.stroke);
  			c.setShadow(false);
  			c.setDashed(false);
  			if (sourceMarker != null)
  			{
  				sourceMarker();
  			}
  			if (targetMarker != null)
  			{
  				targetMarker();
  			}
  		};
  		mxConnector.prototype.createMarker = function(c, pts, source)
  		{
  			var result = null;
  			var n = pts.length;
  			var type = mxUtils.getValue(this.style, (source) ? mxConstants.STYLE_STARTARROW : mxConstants.STYLE_ENDARROW);
  			var p0 = (source) ? pts[1] : pts[n - 2];
  			var pe = (source) ? pts[0] : pts[n - 1];
  			if (type != null && p0 != null && pe != null)
  			{
  				var count = 1;
  				while (count < n - 1 && Math.round(p0.x - pe.x) == 0 && Math.round(p0.y - pe.y) == 0)
  				{
  					p0 = (source) ? pts[1 + count] : pts[n - 2 - count];
  					count++;
  				}
  				var dx = pe.x - p0.x;
  				var dy = pe.y - p0.y;
  				var dist = Math.max(1, Math.sqrt(dx * dx + dy * dy));
  				var unitX = dx / dist;
  				var unitY = dy / dist;
  				var size = mxUtils.getNumber(this.style, (source) ? mxConstants.STYLE_STARTSIZE : mxConstants.STYLE_ENDSIZE, mxConstants.DEFAULT_MARKERSIZE);
  				var filled = this.style[(source) ? mxConstants.STYLE_STARTFILL : mxConstants.STYLE_ENDFILL] != 0;
  				result = mxMarker.createMarker(c, this, type, pe, unitX, unitY, size, source, this.strokewidth, filled);
  			}
  			return result;
  		};
  		mxConnector.prototype.augmentBoundingBox = function(bbox)
  		{
  			mxShape.prototype.augmentBoundingBox.apply(this, arguments);
  			var size = 0;
  			if (mxUtils.getValue(this.style, mxConstants.STYLE_STARTARROW, mxConstants.NONE) != mxConstants.NONE)
  			{
  				size = mxUtils.getNumber(this.style, mxConstants.STYLE_STARTSIZE, mxConstants.DEFAULT_MARKERSIZE) + 1;
  			}
  			if (mxUtils.getValue(this.style, mxConstants.STYLE_ENDARROW, mxConstants.NONE) != mxConstants.NONE)
  			{
  				size = Math.max(size, mxUtils.getNumber(this.style, mxConstants.STYLE_ENDSIZE, mxConstants.DEFAULT_MARKERSIZE)) + 1;
  			}
  			bbox.grow(size * this.scale);
  		};
  		__mxOutput.mxConnector = typeof mxConnector !== 'undefined' ? mxConnector : undefined;
  		function mxSwimlane(bounds, fill, stroke, strokewidth)
  		{
  			mxShape.call(this);
  			this.bounds = bounds;
  			this.fill = fill;
  			this.stroke = stroke;
  			this.strokewidth = (strokewidth != null) ? strokewidth : 1;
  		}		mxUtils.extend(mxSwimlane, mxShape);
  		mxSwimlane.prototype.imageSize = 16;
  		mxSwimlane.prototype.isRoundable = function(c, x, y, w, h)
  		{
  			return true;
  		};
  		mxSwimlane.prototype.getTitleSize = function()
  		{
  			return Math.max(0, mxUtils.getValue(this.style, mxConstants.STYLE_STARTSIZE, mxConstants.DEFAULT_STARTSIZE));
  		};
  		mxSwimlane.prototype.getLabelBounds = function(rect)
  		{
  			var start = this.getTitleSize();
  			var bounds = new mxRectangle(rect.x, rect.y, rect.width, rect.height);
  			var horizontal = this.isHorizontal();
  			var flipH = mxUtils.getValue(this.style, mxConstants.STYLE_FLIPH, 0) == 1;
  			var flipV = mxUtils.getValue(this.style, mxConstants.STYLE_FLIPV, 0) == 1;
  			var shapeVertical = (this.direction == mxConstants.DIRECTION_NORTH ||
  					this.direction == mxConstants.DIRECTION_SOUTH);
  			var realHorizontal = horizontal == !shapeVertical;
  			var realFlipH = !realHorizontal && flipH != (this.direction == mxConstants.DIRECTION_SOUTH ||
  					this.direction == mxConstants.DIRECTION_WEST);
  			var realFlipV = realHorizontal && flipV != (this.direction == mxConstants.DIRECTION_SOUTH ||
  					this.direction == mxConstants.DIRECTION_WEST);
  			if (!shapeVertical)
  			{
  				var tmp = Math.min(bounds.height, start * this.scale);
  				if (realFlipH || realFlipV)
  				{
  					bounds.y += bounds.height - tmp;
  				}
  				bounds.height = tmp;
  			}
  			else
  			{
  				var tmp = Math.min(bounds.width, start * this.scale);
  				if (realFlipH || realFlipV)
  				{
  					bounds.x += bounds.width - tmp;
  				}
  				bounds.width = tmp;
  			}
  			return bounds;
  		};
  		mxSwimlane.prototype.getGradientBounds = function(c, x, y, w, h)
  		{
  			var start = this.getTitleSize();
  			if (this.isHorizontal())
  			{
  				start = Math.min(start, h);
  				return new mxRectangle(x, y, w, start);
  			}
  			else
  			{
  				start = Math.min(start, w);
  				return new mxRectangle(x, y, start, h);
  			}
  		};
  		mxSwimlane.prototype.getSwimlaneArcSize = function(w, h, start)
  		{
  			if (mxUtils.getValue(this.style, mxConstants.STYLE_ABSOLUTE_ARCSIZE, 0) == '1')
  			{
  				return Math.min(w / 2, Math.min(h / 2, mxUtils.getValue(this.style,
  					mxConstants.STYLE_ARCSIZE, mxConstants.LINE_ARCSIZE) / 2));
  			}
  			else
  			{
  				var f = mxUtils.getValue(this.style, mxConstants.STYLE_ARCSIZE, mxConstants.RECTANGLE_ROUNDING_FACTOR * 100) / 100;
  				return start * f * 3;
  			}
  		};
  		mxSwimlane.prototype.isHorizontal = function()
  		{
  			return mxUtils.getValue(this.style, mxConstants.STYLE_HORIZONTAL, 1) == 1;
  		};
  		mxSwimlane.prototype.paintVertexShape = function(c, x, y, w, h)
  		{
  			var start = this.getTitleSize();
  			var fill = mxUtils.getValue(this.style, mxConstants.STYLE_SWIMLANE_FILLCOLOR, mxConstants.NONE);
  			var swimlaneLine = mxUtils.getValue(this.style, mxConstants.STYLE_SWIMLANE_LINE, 1) == 1;
  			var r = 0;
  			if (this.isHorizontal())
  			{
  				start = Math.min(start, h);
  			}
  			else
  			{
  				start = Math.min(start, w);
  			}
  			c.translate(x, y);
  			if (!this.isRounded)
  			{
  				this.paintSwimlane(c, x, y, w, h, start, fill, swimlaneLine);
  			}
  			else
  			{
  				r = this.getSwimlaneArcSize(w, h, start);
  				r = Math.min(((this.isHorizontal()) ? h : w) - start, Math.min(start, r));
  				this.paintRoundedSwimlane(c, x, y, w, h, start, r, fill, swimlaneLine);
  			}
  			var sep = mxUtils.getValue(this.style, mxConstants.STYLE_SEPARATORCOLOR, mxConstants.NONE);
  			this.paintSeparator(c, x, y, w, h, start, sep);
  			if (this.image != null)
  			{
  				var bounds = this.getImageBounds(x, y, w, h);
  				c.image(bounds.x - x, bounds.y - y, bounds.width, bounds.height,
  						this.image, false, false, false);
  			}
  			if (this.glass)
  			{
  				c.setShadow(false);
  				this.paintGlassEffect(c, 0, 0, w, start, r);
  			}
  		};
  		mxSwimlane.prototype.paintSwimlane = function(c, x, y, w, h, start, fill, swimlaneLine)
  		{
  			c.begin();
  			var events = true;
  			if (this.style != null)
  			{
  				events = mxUtils.getValue(this.style, mxConstants.STYLE_POINTER_EVENTS, '1') == '1';
  			}
  			if (!events && (this.fill == null || this.fill == mxConstants.NONE))
  			{
  				c.pointerEvents = false;
  			}
  			if (this.isHorizontal())
  			{
  				c.moveTo(0, start);
  				c.lineTo(0, 0);
  				c.lineTo(w, 0);
  				c.lineTo(w, start);
  				c.fillAndStroke();
  				if (start < h)
  				{
  					if (fill == mxConstants.NONE || !events)
  					{
  						c.pointerEvents = false;
  					}
  					if (fill != mxConstants.NONE)
  					{
  						c.setFillColor(fill);
  					}
  					c.begin();
  					c.moveTo(0, start);
  					c.lineTo(0, h);
  					c.lineTo(w, h);
  					c.lineTo(w, start);
  					if (fill == mxConstants.NONE)
  					{
  						c.stroke();
  					}
  					else
  					{
  						c.fillAndStroke();
  					}
  				}
  			}
  			else
  			{
  				c.moveTo(start, 0);
  				c.lineTo(0, 0);
  				c.lineTo(0, h);
  				c.lineTo(start, h);
  				c.fillAndStroke();
  				if (start < w)
  				{
  					if (fill == mxConstants.NONE || !events)
  					{
  						c.pointerEvents = false;
  					}
  					if (fill != mxConstants.NONE)
  					{
  						c.setFillColor(fill);
  					}
  					c.begin();
  					c.moveTo(start, 0);
  					c.lineTo(w, 0);
  					c.lineTo(w, h);
  					c.lineTo(start, h);
  					if (fill == mxConstants.NONE)
  					{
  						c.stroke();
  					}
  					else
  					{
  						c.fillAndStroke();
  					}
  				}
  			}
  			if (swimlaneLine)
  			{
  				this.paintDivider(c, x, y, w, h, start, fill == mxConstants.NONE);
  			}
  		};
  		mxSwimlane.prototype.paintRoundedSwimlane = function(c, x, y, w, h, start, r, fill, swimlaneLine)
  		{
  			c.begin();
  			var events = true;
  			if (this.style != null)
  			{
  				events = mxUtils.getValue(this.style, mxConstants.STYLE_POINTER_EVENTS, '1') == '1';
  			}
  			if (!events && (this.fill == null || this.fill == mxConstants.NONE))
  			{
  				c.pointerEvents = false;
  			}
  			if (this.isHorizontal())
  			{
  				c.moveTo(w, start);
  				c.lineTo(w, r);
  				c.quadTo(w, 0, w - Math.min(w / 2, r), 0);
  				c.lineTo(Math.min(w / 2, r), 0);
  				c.quadTo(0, 0, 0, r);
  				c.lineTo(0, start);
  				c.fillAndStroke();
  				if (start < h)
  				{
  					if (fill == mxConstants.NONE || !events)
  					{
  						c.pointerEvents = false;
  					}
  					if (fill != mxConstants.NONE)
  					{
  						c.setFillColor(fill);
  					}
  					c.begin();
  					c.moveTo(0, start);
  					c.lineTo(0, h - r);
  					c.quadTo(0, h, Math.min(w / 2, r), h);
  					c.lineTo(w - Math.min(w / 2, r), h);
  					c.quadTo(w, h, w, h - r);
  					c.lineTo(w, start);
  					if (fill == mxConstants.NONE)
  					{
  						c.stroke();
  					}
  					else
  					{
  						c.fillAndStroke();
  					}
  				}
  			}
  			else
  			{
  				c.moveTo(start, 0);
  				c.lineTo(r, 0);
  				c.quadTo(0, 0, 0, Math.min(h / 2, r));
  				c.lineTo(0, h - Math.min(h / 2, r));
  				c.quadTo(0, h, r, h);
  				c.lineTo(start, h);
  				c.fillAndStroke();
  				if (start < w)
  				{
  					if (fill == mxConstants.NONE || !events)
  					{
  						c.pointerEvents = false;
  					}
  					if (fill != mxConstants.NONE)
  					{
  						c.setFillColor(fill);
  					}
  					c.begin();
  					c.moveTo(start, h);
  					c.lineTo(w - r, h);
  					c.quadTo(w, h, w, h - Math.min(h / 2, r));
  					c.lineTo(w, Math.min(h / 2, r));
  					c.quadTo(w, 0, w - r, 0);
  					c.lineTo(start, 0);
  					if (fill == mxConstants.NONE)
  					{
  						c.stroke();
  					}
  					else
  					{
  						c.fillAndStroke();
  					}
  				}
  			}
  			if (swimlaneLine)
  			{
  				this.paintDivider(c, x, y, w, h, start, fill == mxConstants.NONE);
  			}
  		};
  		mxSwimlane.prototype.paintDivider = function(c, x, y, w, h, start, shadow)
  		{
  			if (!shadow)
  			{
  				c.setShadow(false);
  			}
  			c.begin();
  			if (this.isHorizontal())
  			{
  				c.moveTo(0, start);
  				c.lineTo(w, start);
  			}
  			else
  			{
  				c.moveTo(start, 0);
  				c.lineTo(start, h);
  			}
  			c.stroke();
  		};
  		mxSwimlane.prototype.paintSeparator = function(c, x, y, w, h, start, color)
  		{
  			if (color != mxConstants.NONE)
  			{
  				c.setStrokeColor(color);
  				c.setDashed(true);
  				c.begin();
  				if (this.isHorizontal())
  				{
  					c.moveTo(w, start);
  					c.lineTo(w, h);
  				}
  				else
  				{
  					c.moveTo(start, 0);
  					c.lineTo(w, 0);
  				}
  				c.stroke();
  				c.setDashed(false);
  			}
  		};
  		mxSwimlane.prototype.getImageBounds = function(x, y, w, h)
  		{
  			if (this.isHorizontal())
  			{
  				return new mxRectangle(x + w - this.imageSize, y, this.imageSize, this.imageSize);
  			}
  			else
  			{
  				return new mxRectangle(x, y, this.imageSize, this.imageSize);
  			}
  		};
  		__mxOutput.mxSwimlane = typeof mxSwimlane !== 'undefined' ? mxSwimlane : undefined;
  		function mxGraphLayout(graph)
  		{
  			this.graph = graph;
  		}		mxGraphLayout.prototype.graph = null;
  		mxGraphLayout.prototype.useBoundingBox = true;
  		mxGraphLayout.prototype.parent = null;
  		mxGraphLayout.prototype.moveCell = function(cell, x, y) { };
  		mxGraphLayout.prototype.resizeCell = function(cell, bounds) { };
  		mxGraphLayout.prototype.execute = function(parent) { };
  		mxGraphLayout.prototype.getGraph = function()
  		{
  			return this.graph;
  		};
  		mxGraphLayout.prototype.getConstraint = function(key, cell, edge, source)
  		{
  			return this.graph.getCurrentCellStyle(cell)[key]
  		};
  		mxGraphLayout.traverse = function(vertex, directed, func, edge, visited)
  		{
  			if (func != null && vertex != null)
  			{
  				directed = (directed != null) ? directed : true;
  				visited = visited || new mxDictionary();
  				if (!visited.get(vertex))
  				{
  					visited.put(vertex, true);
  					var result = func(vertex, edge);
  					if (result == null || result)
  					{
  						var edgeCount = this.graph.model.getEdgeCount(vertex);
  						if (edgeCount > 0)
  						{
  							for (var i = 0; i < edgeCount; i++)
  							{
  								var e = this.graph.model.getEdgeAt(vertex, i);
  								var isSource = this.graph.model.getTerminal(e, true) == vertex;
  								if (!directed || isSource)
  								{
  									var next = this.graph.view.getVisibleTerminal(e, !isSource);
  									this.traverse(next, directed, func, e, visited);
  								}
  							}
  						}
  					}
  				}
  			}
  		};
  		mxGraphLayout.prototype.isAncestor = function(parent, child, traverseAncestors)
  		{
  			if (!traverseAncestors)
  			{
  				return (this.graph.model.getParent(child) == parent);
  			}
  			if (child == parent)
  			{
  				return false;
  			}
  			while (child != null && child != parent)
  			{
  				child = this.graph.model.getParent(child);
  			}
  			return child == parent;
  		};
  		mxGraphLayout.prototype.isVertexMovable = function(cell)
  		{
  			return this.graph.isCellMovable(cell);
  		};
  		mxGraphLayout.prototype.isVertexIgnored = function(vertex)
  		{
  			return !this.graph.getModel().isVertex(vertex) ||
  				!this.graph.isCellVisible(vertex);
  		};
  		mxGraphLayout.prototype.isEdgeIgnored = function(edge)
  		{
  			var model = this.graph.getModel();
  			return !model.isEdge(edge) ||
  				!this.graph.isCellVisible(edge) ||
  				model.getTerminal(edge, true) == null ||
  				model.getTerminal(edge, false) == null;
  		};
  		mxGraphLayout.prototype.setEdgeStyleEnabled = function(edge, value)
  		{
  			this.graph.setCellStyles(mxConstants.STYLE_NOEDGESTYLE,
  					(value) ? '0' : '1', [edge]);
  		};
  		mxGraphLayout.prototype.setOrthogonalEdge = function(edge, value)
  		{
  			this.graph.setCellStyles(mxConstants.STYLE_ORTHOGONAL,
  					(value) ? '1' : '0', [edge]);
  		};
  		mxGraphLayout.prototype.getParentOffset = function(parent)
  		{
  			var result = new mxPoint();
  			if (parent != null && parent != this.parent)
  			{
  				var model = this.graph.getModel();
  				if (model.isAncestor(this.parent, parent))
  				{
  					var parentGeo = model.getGeometry(parent);
  					while (parent != this.parent)
  					{
  						result.x = result.x + parentGeo.x;
  						result.y = result.y + parentGeo.y;
  						parent = model.getParent(parent);						parentGeo = model.getGeometry(parent);
  					}
  				}
  			}
  			return result;
  		};
  		mxGraphLayout.prototype.setEdgePoints = function(edge, points)
  		{
  			if (edge != null)
  			{
  				var model = this.graph.model;
  				var geometry = model.getGeometry(edge);
  				if (geometry == null)
  				{
  					geometry = new mxGeometry();
  					geometry.setRelative(true);
  				}
  				else
  				{
  					geometry = geometry.clone();
  				}
  				if (this.parent != null && points != null)
  				{
  					var parent = model.getParent(edge);
  					var parentOffset = this.getParentOffset(parent);
  					for (var i = 0; i < points.length; i++)
  					{
  						points[i].x = points[i].x - parentOffset.x;
  						points[i].y = points[i].y - parentOffset.y;
  					}
  				}
  				geometry.points = points;
  				model.setGeometry(edge, geometry);
  			}
  		};
  		mxGraphLayout.prototype.setVertexLocation = function(cell, x, y)
  		{
  			var model = this.graph.getModel();
  			var geometry = model.getGeometry(cell);
  			var result = null;
  			if (geometry != null)
  			{
  				result = new mxRectangle(x, y, geometry.width, geometry.height);
  				if (this.useBoundingBox)
  				{
  					var state = this.graph.getView().getState(cell);
  					if (state != null && state.text != null && state.text.boundingBox != null)
  					{
  						var scale = this.graph.getView().scale;
  						var box = state.text.boundingBox;
  						if (state.text.boundingBox.x < state.x)
  						{
  							x += (state.x - box.x) / scale;
  							result.width = box.width;
  						}
  						if (state.text.boundingBox.y < state.y)
  						{
  							y += (state.y - box.y) / scale;
  							result.height = box.height;
  						}
  					}
  				}
  				if (this.parent != null)
  				{
  					var parent = model.getParent(cell);
  					if (parent != null && parent != this.parent)
  					{
  						var parentOffset = this.getParentOffset(parent);
  						x = x - parentOffset.x;
  						y = y - parentOffset.y;
  					}
  				}
  				if (geometry.x != x || geometry.y != y)
  				{
  					geometry = geometry.clone();
  					geometry.x = x;
  					geometry.y = y;
  					model.setGeometry(cell, geometry);
  				}
  			}
  			return result;
  		};
  		mxGraphLayout.prototype.getVertexBounds = function(cell)
  		{
  			var geo = this.graph.getModel().getGeometry(cell);
  			if (this.useBoundingBox)
  			{
  				var state = this.graph.getView().getState(cell);
  				if (state != null && state.text != null && state.text.boundingBox != null)
  				{
  					var scale = this.graph.getView().scale;
  					var tmp = state.text.boundingBox;
  					var dx0 = Math.max(state.x - tmp.x, 0) / scale;
  					var dy0 = Math.max(state.y - tmp.y, 0) / scale;
  					var dx1 = Math.max((tmp.x + tmp.width) - (state.x + state.width), 0) / scale;
  		  			var dy1 = Math.max((tmp.y + tmp.height) - (state.y + state.height), 0) / scale;
  					geo = new mxRectangle(geo.x - dx0, geo.y - dy0, geo.width + dx0 + dx1, geo.height + dy0 + dy1);
  				}
  			}
  			if (this.parent != null)
  			{
  				var parent = this.graph.getModel().getParent(cell);
  				geo = geo.clone();
  				if (parent != null && parent != this.parent)
  				{
  					var parentOffset = this.getParentOffset(parent);
  					geo.x = geo.x + parentOffset.x;
  					geo.y = geo.y + parentOffset.y;
  				}
  			}
  			return new mxRectangle(geo.x, geo.y, geo.width, geo.height);
  		};
  		mxGraphLayout.prototype.arrangeGroups = function(cells, border, topBorder, rightBorder, bottomBorder, leftBorder)
  		{
  			return this.graph.updateGroupBounds(cells, border, true, topBorder, rightBorder, bottomBorder, leftBorder);
  		};
  		function WeightedCellSorter(cell, weightedValue)
  		{
  			this.cell = cell;
  			this.weightedValue = weightedValue;
  		}		WeightedCellSorter.prototype.weightedValue = 0;
  		WeightedCellSorter.prototype.nudge = false;
  		WeightedCellSorter.prototype.visited = false;
  		WeightedCellSorter.prototype.rankIndex = null;
  		WeightedCellSorter.prototype.cell = null;
  		WeightedCellSorter.prototype.compare = function(a, b)
  		{
  			if (a != null && b != null)
  			{
  				if (b.weightedValue > a.weightedValue)
  				{
  					return -1;
  				}
  				else if (b.weightedValue < a.weightedValue)
  				{
  					return 1;
  				}
  				else
  				{
  					if (b.nudge)
  					{
  						return -1;
  					}
  					else
  					{
  						return 1;
  					}
  				}
  			}
  			else
  			{
  				return 0;
  			}
  		};
  		__mxOutput.mxGraphLayout = typeof mxGraphLayout !== 'undefined' ? mxGraphLayout : undefined;
  		function mxStackLayout(graph, horizontal, spacing, x0, y0, border)
  		{
  			mxGraphLayout.call(this, graph);
  			this.horizontal = (horizontal != null) ? horizontal : true;
  			this.spacing = (spacing != null) ? spacing : 0;
  			this.x0 = (x0 != null) ? x0 : 0;
  			this.y0 = (y0 != null) ? y0 : 0;
  			this.border = (border != null) ? border : 0;
  		}		mxStackLayout.prototype = new mxGraphLayout();
  		mxStackLayout.prototype.constructor = mxStackLayout;
  		mxStackLayout.prototype.horizontal = null;
  		mxStackLayout.prototype.spacing = null;
  		mxStackLayout.prototype.x0 = null;
  		mxStackLayout.prototype.y0 = null;
  		mxStackLayout.prototype.border = 0;
  		mxStackLayout.prototype.marginTop = 0;
  		mxStackLayout.prototype.marginLeft = 0;
  		mxStackLayout.prototype.marginRight = 0;
  		mxStackLayout.prototype.marginBottom = 0;
  		mxStackLayout.prototype.keepFirstLocation = false;
  		mxStackLayout.prototype.fill = false;
  		mxStackLayout.prototype.resizeParent = false;
  		mxStackLayout.prototype.resizeParentMax = false;
  		mxStackLayout.prototype.resizeLast = false;
  		mxStackLayout.prototype.wrap = null;
  		mxStackLayout.prototype.borderCollapse = true;
  		mxStackLayout.prototype.allowGaps = false;
  		mxStackLayout.prototype.gridSize = 0;
  		mxStackLayout.prototype.isHorizontal = function()
  		{
  			return this.horizontal;
  		};
  		mxStackLayout.prototype.moveCell = function(cell, x, y)
  		{
  			var model = this.graph.getModel();
  			var parent = model.getParent(cell);
  			var horizontal = this.isHorizontal();
  			if (cell != null && parent != null)
  			{
  				var i = 0;
  				var last = 0;
  				var childCount = model.getChildCount(parent);
  				var value = (horizontal) ? x : y;
  				var pstate = this.graph.getView().getState(parent);
  				if (pstate != null)
  				{
  					value -= (horizontal) ? pstate.x : pstate.y;
  				}
  				value /= this.graph.view.scale;
  				for (i = 0; i < childCount; i++)
  				{
  					var child = model.getChildAt(parent, i);
  					if (child != cell)
  					{
  						var bounds = model.getGeometry(child);
  						if (bounds != null)
  						{
  							var tmp = (horizontal) ?
  								bounds.x + bounds.width / 2 :
  								bounds.y + bounds.height / 2;
  							if (last <= value && tmp > value)
  							{
  								break;
  							}
  							last = tmp;
  						}
  					}
  				}
  				var idx = parent.getIndex(cell);
  				idx = Math.max(0, i - ((i > idx) ? 1 : 0));
  				model.add(parent, cell, idx);
  			}
  		};
  		mxStackLayout.prototype.getParentSize = function(parent)
  		{
  			var model = this.graph.getModel();
  			var pgeo = model.getGeometry(parent);
  			if (this.graph.container != null && ((pgeo == null &&
  				model.isLayer(parent)) || parent == this.graph.getView().currentRoot))
  			{
  				var width = this.graph.container.offsetWidth - 1;
  				var height = this.graph.container.offsetHeight - 1;
  				pgeo = new mxRectangle(0, 0, width, height);
  			}
  			return pgeo;
  		};
  		mxStackLayout.prototype.getLayoutCells = function(parent)
  		{
  			var model = this.graph.getModel();
  			var childCount = model.getChildCount(parent);
  			var cells = [];
  			for (var i = 0; i < childCount; i++)
  			{
  				var child = model.getChildAt(parent, i);
  				if (!this.isVertexIgnored(child) && this.isVertexMovable(child))
  				{
  					cells.push(child);
  				}
  			}
  			if (this.allowGaps)
  			{
  				cells.sort(mxUtils.bind(this, function(c1, c2)
  				{
  					var geo1 = this.graph.getCellGeometry(c1);
  					var geo2 = this.graph.getCellGeometry(c2);
  					return (this.horizontal) ?
  						((geo1.x == geo2.x) ? 0 : ((geo1.x > geo2.x > 0) ? 1 : -1)) :
  						((geo1.y == geo2.y) ? 0 : ((geo1.y > geo2.y > 0) ? 1 : -1));
  				}));
  			}
  			return cells;
  		};
  		mxStackLayout.prototype.snap = function(value)
  		{
  			if (this.gridSize != null && this.gridSize > 0)
  			{
  				value = Math.max(value, this.gridSize);
  				if (value / this.gridSize > 1)
  				{
  					var mod = value % this.gridSize;
  					value += mod > this.gridSize / 2 ? (this.gridSize - mod) : -mod;
  				}
  			}
  			return value;
  		};
  		mxStackLayout.prototype.execute = function(parent)
  		{
  			if (parent != null)
  			{
  				var pgeo = this.getParentSize(parent);
  				var horizontal = this.isHorizontal();
  				var model = this.graph.getModel();
  				var fillValue = null;
  				if (pgeo != null)
  				{
  					fillValue = (horizontal) ? pgeo.height - this.marginTop - this.marginBottom :
  						pgeo.width - this.marginLeft - this.marginRight;
  				}
  				fillValue -= 2 * this.border;
  				var x0 = this.x0 + this.border + this.marginLeft;
  				var y0 = this.y0 + this.border + this.marginTop;
  				if (this.graph.isSwimlane(parent))
  				{
  					var style = this.graph.getCellStyle(parent);
  					var start = mxUtils.getNumber(style, mxConstants.STYLE_STARTSIZE, mxConstants.DEFAULT_STARTSIZE);
  					var horz = mxUtils.getValue(style, mxConstants.STYLE_HORIZONTAL, true) == 1;
  					if (pgeo != null)
  					{
  						if (horz)
  						{
  							start = Math.min(start, pgeo.height);
  						}
  						else
  						{
  							start = Math.min(start, pgeo.width);
  						}
  					}
  					if (horizontal == horz)
  					{
  						fillValue -= start;
  					}
  					if (horz)
  					{
  						y0 += start;
  					}
  					else
  					{
  						x0 += start;
  					}
  				}
  				model.beginUpdate();
  				try
  				{
  					var tmp = 0;
  					var last = null;
  					var lastValue = 0;
  					var lastChild = null;
  					var cells = this.getLayoutCells(parent);
  					for (var i = 0; i < cells.length; i++)
  					{
  						var child = cells[i];
  						var geo = model.getGeometry(child);
  						if (geo != null)
  						{
  							geo = geo.clone();
  							if (this.wrap != null && last != null)
  							{
  								if ((horizontal && last.x + last.width +
  									geo.width + 2 * this.spacing > this.wrap) ||
  									(!horizontal && last.y + last.height +
  									geo.height + 2 * this.spacing > this.wrap))
  								{
  									last = null;
  									if (horizontal)
  									{
  										y0 += tmp + this.spacing;
  									}
  									else
  									{
  										x0 += tmp + this.spacing;
  									}
  									tmp = 0;
  								}
  							}
  							tmp = Math.max(tmp, (horizontal) ? geo.height : geo.width);
  							var sw = 0;
  							if (!this.borderCollapse)
  							{
  								var childStyle = this.graph.getCellStyle(child);
  								sw = mxUtils.getNumber(childStyle, mxConstants.STYLE_STROKEWIDTH, 1);
  							}
  							if (last != null)
  							{
  								var temp = lastValue + this.spacing + Math.floor(sw / 2);
  								if (horizontal)
  								{
  									geo.x = this.snap(((this.allowGaps) ? Math.max(temp, geo.x) :
  										temp) - this.marginLeft) + this.marginLeft;
  								}
  								else
  								{
  									geo.y = this.snap(((this.allowGaps) ? Math.max(temp, geo.y) :
  										temp) - this.marginTop) + this.marginTop;
  								}
  							}
  							else if (!this.keepFirstLocation)
  							{
  								if (horizontal)
  								{
  									geo.x = (this.allowGaps && geo.x > x0) ? Math.max(this.snap(geo.x -
  										this.marginLeft) + this.marginLeft, x0) : x0;
  								}
  								else
  								{
  									geo.y = (this.allowGaps && geo.y > y0) ? Math.max(this.snap(geo.y -
  										this.marginTop) + this.marginTop, y0) : y0;
  								}
  							}
  							if (horizontal)
  							{
  								geo.y = y0;
  							}
  							else
  							{
  								geo.x = x0;
  							}
  							if (this.fill && fillValue != null)
  							{
  								if (horizontal)
  								{
  									geo.height = fillValue;
  								}
  								else
  								{
  									geo.width = fillValue;
  								}
  							}
  							if (horizontal)
  							{
  								geo.width = this.snap(geo.width);
  							}
  							else
  							{
  								geo.height = this.snap(geo.height);
  							}
  							this.setChildGeometry(child, geo);
  							lastChild = child;
  							last = geo;
  							if (horizontal)
  							{
  								lastValue = last.x + last.width + Math.floor(sw / 2);
  							}
  							else
  							{
  								lastValue = last.y + last.height + Math.floor(sw / 2);
  							}
  						}
  					}
  					if (this.resizeParent && pgeo != null && last != null && !this.graph.isCellCollapsed(parent))
  					{
  						this.updateParentGeometry(parent, pgeo, last);
  					}
  					else if (this.resizeLast && pgeo != null && last != null && lastChild != null)
  					{
  						if (horizontal)
  						{
  							last.width = pgeo.width - last.x - this.spacing - this.marginRight - this.marginLeft;
  						}
  						else
  						{
  							last.height = pgeo.height - last.y - this.spacing - this.marginBottom;
  						}
  						this.setChildGeometry(lastChild, last);
  					}
  				}
  				finally
  				{
  					model.endUpdate();
  				}
  			}
  		};
  		mxStackLayout.prototype.setChildGeometry = function(child, geo)
  		{
  			var geo2 = this.graph.getCellGeometry(child);
  			if (geo2 == null || geo.x != geo2.x || geo.y != geo2.y ||
  				geo.width != geo2.width || geo.height != geo2.height)
  			{
  				this.graph.getModel().setGeometry(child, geo);
  			}
  		};
  		mxStackLayout.prototype.updateParentGeometry = function(parent, pgeo, last)
  		{
  			var horizontal = this.isHorizontal();
  			var model = this.graph.getModel();
  			var pgeo2 = pgeo.clone();
  			if (horizontal)
  			{
  				var tmp = last.x + last.width + this.marginRight + this.border;
  				if (this.resizeParentMax)
  				{
  					pgeo2.width = Math.max(pgeo2.width, tmp);
  				}
  				else
  				{
  					pgeo2.width = tmp;
  				}
  			}
  			else
  			{
  				var tmp = last.y + last.height + this.marginBottom + this.border;
  				if (this.resizeParentMax)
  				{
  					pgeo2.height = Math.max(pgeo2.height, tmp);
  				}
  				else
  				{
  					pgeo2.height = tmp;
  				}
  			}
  			if (pgeo.x != pgeo2.x || pgeo.y != pgeo2.y ||
  				pgeo.width != pgeo2.width || pgeo.height != pgeo2.height)
  			{
  				model.setGeometry(parent, pgeo2);
  			}
  		};
  		__mxOutput.mxStackLayout = typeof mxStackLayout !== 'undefined' ? mxStackLayout : undefined;
  		function mxPartitionLayout(graph, horizontal, spacing, border)
  		{
  			mxGraphLayout.call(this, graph);
  			this.horizontal = (horizontal != null) ? horizontal : true;
  			this.spacing = spacing || 0;
  			this.border = border || 0;
  		}		mxPartitionLayout.prototype = new mxGraphLayout();
  		mxPartitionLayout.prototype.constructor = mxPartitionLayout;
  		mxPartitionLayout.prototype.horizontal = null;
  		mxPartitionLayout.prototype.spacing = null;
  		mxPartitionLayout.prototype.border = null;
  		mxPartitionLayout.prototype.resizeVertices = true;
  		mxPartitionLayout.prototype.isHorizontal = function()
  		{
  			return this.horizontal;
  		};
  		mxPartitionLayout.prototype.moveCell = function(cell, x, y)
  		{
  			var model = this.graph.getModel();
  			var parent = model.getParent(cell);
  			if (cell != null &&
  				parent != null)
  			{
  				var i = 0;
  				var last = 0;
  				var childCount = model.getChildCount(parent);
  				for (i = 0; i < childCount; i++)
  				{
  					var child = model.getChildAt(parent, i);
  					var bounds = this.getVertexBounds(child);
  					if (bounds != null)
  					{
  						var tmp = bounds.x + bounds.width / 2;
  						if (last < x && tmp > x)
  						{
  							break;
  						}
  						last = tmp;
  					}
  				}
  				var idx = parent.getIndex(cell);
  				idx = Math.max(0, i - ((i > idx) ? 1 : 0));
  				model.add(parent, cell, idx);
  			}
  		};
  		mxPartitionLayout.prototype.execute = function(parent)
  		{
  			var horizontal = this.isHorizontal();
  			var model = this.graph.getModel();
  			var pgeo = model.getGeometry(parent);
  			if (this.graph.container != null &&
  				((pgeo == null &&
  				model.isLayer(parent)) ||
  				parent == this.graph.getView().currentRoot))
  			{
  				var width = this.graph.container.offsetWidth - 1;
  				var height = this.graph.container.offsetHeight - 1;
  				pgeo = new mxRectangle(0, 0, width, height);
  			}
  			if (pgeo != null)
  			{
  				var children = [];
  				var childCount = model.getChildCount(parent);
  				for (var i = 0; i < childCount; i++)
  				{
  					var child = model.getChildAt(parent, i);
  					if (!this.isVertexIgnored(child) &&
  						this.isVertexMovable(child))
  					{
  						children.push(child);
  					}
  				}
  				var n = children.length;
  				if (n > 0)
  				{
  					var x0 = this.border;
  					var y0 = this.border;
  					var other = (horizontal) ? pgeo.height : pgeo.width;
  					other -= 2 * this.border;
  					var size = (this.graph.isSwimlane(parent)) ?
  						this.graph.getStartSize(parent) :
  						new mxRectangle();
  					other -= (horizontal) ? size.height : size.width;
  					x0 = x0 + size.width;
  					y0 = y0 + size.height;
  					var tmp = this.border + (n - 1) * this.spacing;
  					var value = (horizontal) ?
  						((pgeo.width - x0 - tmp) / n) :
  						((pgeo.height - y0 - tmp) / n);
  					if (value > 0)
  					{
  						model.beginUpdate();
  						try
  						{
  							for (var i = 0; i < n; i++)
  							{
  								var child = children[i];
  								var geo = model.getGeometry(child);
  								if (geo != null)
  								{
  									geo = geo.clone();
  									geo.x = x0;
  									geo.y = y0;
  									if (horizontal)
  									{
  										if (this.resizeVertices)
  										{
  											geo.width = value;
  											geo.height = other;
  										}
  										x0 += value + this.spacing;
  									}
  									else
  									{
  										if (this.resizeVertices)
  										{
  											geo.height = value;
  											geo.width = other;
  										}
  										y0 += value + this.spacing;
  									}
  									model.setGeometry(child, geo);
  								}
  							}
  						}
  						finally
  						{
  							model.endUpdate();
  						}
  					}
  				}
  			}
  		};
  		__mxOutput.mxPartitionLayout = typeof mxPartitionLayout !== 'undefined' ? mxPartitionLayout : undefined;
  		function mxCompactTreeLayout(graph, horizontal, invert)
  		{
  			mxGraphLayout.call(this, graph);
  			this.horizontal = (horizontal != null) ? horizontal : true;
  			this.invert = (invert != null) ? invert : false;
  		}		mxCompactTreeLayout.prototype = new mxGraphLayout();
  		mxCompactTreeLayout.prototype.constructor = mxCompactTreeLayout;
  		mxCompactTreeLayout.prototype.horizontal = null;
  		mxCompactTreeLayout.prototype.invert = null;
  		mxCompactTreeLayout.prototype.resizeParent = true;
  		mxCompactTreeLayout.prototype.maintainParentLocation = false;
  		mxCompactTreeLayout.prototype.groupPadding = 10;
  		mxCompactTreeLayout.prototype.groupPaddingTop = 0;
  		mxCompactTreeLayout.prototype.groupPaddingRight = 0;
  		mxCompactTreeLayout.prototype.groupPaddingBottom = 0;
  		mxCompactTreeLayout.prototype.groupPaddingLeft = 0;
  		mxCompactTreeLayout.prototype.parentsChanged = null;
  		mxCompactTreeLayout.prototype.moveTree = false;
  		mxCompactTreeLayout.prototype.visited = null;
  		mxCompactTreeLayout.prototype.levelDistance = 10;
  		mxCompactTreeLayout.prototype.nodeDistance = 20;
  		mxCompactTreeLayout.prototype.resetEdges = true;
  		mxCompactTreeLayout.prototype.prefHozEdgeSep = 5;
  		mxCompactTreeLayout.prototype.prefVertEdgeOff = 4;
  		mxCompactTreeLayout.prototype.minEdgeJetty = 8;
  		mxCompactTreeLayout.prototype.channelBuffer = 4;
  		mxCompactTreeLayout.prototype.edgeRouting = true;
  		mxCompactTreeLayout.prototype.sortEdges = false;
  		mxCompactTreeLayout.prototype.alignRanks = false;
  		mxCompactTreeLayout.prototype.maxRankHeight = null;
  		mxCompactTreeLayout.prototype.root = null;
  		mxCompactTreeLayout.prototype.node = null;
  		mxCompactTreeLayout.prototype.isVertexIgnored = function(vertex)
  		{
  			return mxGraphLayout.prototype.isVertexIgnored.apply(this, arguments) ||
  				this.graph.getConnections(vertex).length == 0;
  		};
  		mxCompactTreeLayout.prototype.isHorizontal = function()
  		{
  			return this.horizontal;
  		};
  		mxCompactTreeLayout.prototype.execute = function(parent, root)
  		{
  			this.parent = parent;
  			var model = this.graph.getModel();
  			if (root == null)
  			{
  				if (this.graph.getEdges(parent, model.getParent(parent),
  					this.invert, !this.invert, false).length > 0)
  				{
  					this.root = parent;
  				}
  				else
  				{
  					var roots = this.graph.findTreeRoots(parent, true, this.invert);
  					if (roots.length > 0)
  					{
  						for (var i = 0; i < roots.length; i++)
  						{
  							if (!this.isVertexIgnored(roots[i]) &&
  								this.graph.getEdges(roots[i], null,
  									this.invert, !this.invert, false).length > 0)
  							{
  								this.root = roots[i];
  								break;
  							}
  						}
  					}
  				}
  			}
  			else
  			{
  				this.root = root;
  			}
  			if (this.root != null)
  			{
  				if (this.resizeParent)
  				{
  					this.parentsChanged = new Object();
  				}
  				else
  				{
  					this.parentsChanged = null;
  				}
  				this.parentX = null;
  				this.parentY = null;
  				if (parent != this.root && model.isVertex(parent) != null && this.maintainParentLocation)
  				{
  					var geo = this.graph.getCellGeometry(parent);
  					if (geo != null)
  					{
  						this.parentX = geo.x;
  						this.parentY = geo.y;
  					}
  				}
  				model.beginUpdate();
  				try
  				{
  					this.visited = new Object();
  					this.node = this.dfs(this.root, parent);
  					if (this.alignRanks)
  					{
  						this.maxRankHeight = [];
  						this.findRankHeights(this.node, 0);
  						this.setCellHeights(this.node, 0);
  					}
  					if (this.node != null)
  					{
  						this.layout(this.node);
  						var x0 = this.graph.gridSize;
  						var y0 = x0;
  						if (!this.moveTree)
  						{
  							var g = this.getVertexBounds(this.root);
  							if (g != null)
  							{
  								x0 = g.x;
  								y0 = g.y;
  							}
  						}
  						var bounds = null;
  						if (this.isHorizontal())
  						{
  							bounds = this.horizontalLayout(this.node, x0, y0);
  						}
  						else
  						{
  							bounds = this.verticalLayout(this.node, null, x0, y0);
  						}
  						if (bounds != null)
  						{
  							var dx = 0;
  							var dy = 0;
  							if (bounds.x < 0)
  							{
  								dx = Math.abs(x0 - bounds.x);
  							}
  							if (bounds.y < 0)
  							{
  								dy = Math.abs(y0 - bounds.y);
  							}
  							if (dx != 0 || dy != 0)
  							{
  								this.moveNode(this.node, dx, dy);
  							}
  							if (this.resizeParent)
  							{
  								this.adjustParents();
  							}
  							if (this.edgeRouting)
  							{
  								this.localEdgeProcessing(this.node);
  							}
  						}
  						if (this.parentX != null && this.parentY != null)
  						{
  							var geo = this.graph.getCellGeometry(parent);
  							if (geo != null)
  							{
  								geo = geo.clone();
  								geo.x = this.parentX;
  								geo.y = this.parentY;
  								model.setGeometry(parent, geo);
  							}
  						}
  					}
  				}
  				finally
  				{
  					model.endUpdate();
  				}
  			}
  		};
  		mxCompactTreeLayout.prototype.moveNode = function(node, dx, dy)
  		{
  			node.x += dx;
  			node.y += dy;
  			this.apply(node);
  			var child = node.child;
  			while (child != null)
  			{
  				this.moveNode(child, dx, dy);
  				child = child.next;
  			}
  		};
  		mxCompactTreeLayout.prototype.sortOutgoingEdges = function(source, edges)
  		{
  			var lookup = new mxDictionary();
  			edges.sort(function(e1, e2)
  			{
  				var end1 = e1.getTerminal(e1.getTerminal(false) == source);
  				var p1 = lookup.get(end1);
  				if (p1 == null)
  				{
  					p1 = mxCellPath.create(end1).split(mxCellPath.PATH_SEPARATOR);
  					lookup.put(end1, p1);
  				}
  				var end2 = e2.getTerminal(e2.getTerminal(false) == source);
  				var p2 = lookup.get(end2);
  				if (p2 == null)
  				{
  					p2 = mxCellPath.create(end2).split(mxCellPath.PATH_SEPARATOR);
  					lookup.put(end2, p2);
  				}
  				return mxCellPath.compare(p1, p2);
  			});
  		};
  		mxCompactTreeLayout.prototype.findRankHeights = function(node, rank)
  		{
  			if (this.maxRankHeight[rank] == null || this.maxRankHeight[rank] < node.height)
  			{
  				this.maxRankHeight[rank] = node.height;
  			}
  			var child = node.child;
  			while (child != null)
  			{
  				this.findRankHeights(child, rank + 1);
  				child = child.next;
  			}
  		};
  		mxCompactTreeLayout.prototype.setCellHeights = function(node, rank)
  		{
  			if (this.maxRankHeight[rank] != null && this.maxRankHeight[rank] > node.height)
  			{
  				node.height = this.maxRankHeight[rank];
  			}
  			var child = node.child;
  			while (child != null)
  			{
  				this.setCellHeights(child, rank + 1);
  				child = child.next;
  			}
  		};
  		mxCompactTreeLayout.prototype.dfs = function(cell, parent)
  		{
  			var id = mxCellPath.create(cell);
  			var node = null;
  			if (cell != null && this.visited[id] == null && !this.isVertexIgnored(cell))
  			{
  				this.visited[id] = cell;
  				node = this.createNode(cell);
  				var model = this.graph.getModel();
  				var prev = null;
  				var out = this.graph.getEdges(cell, parent, this.invert, !this.invert, false, true);
  				var view = this.graph.getView();
  				if (this.sortEdges)
  				{
  					this.sortOutgoingEdges(cell, out);
  				}
  				for (var i = 0; i < out.length; i++)
  				{
  					var edge = out[i];
  					if (!this.isEdgeIgnored(edge))
  					{
  						if (this.resetEdges)
  						{
  							this.setEdgePoints(edge, null);
  						}
  						if (this.edgeRouting)
  						{
  							this.setEdgeStyleEnabled(edge, false);
  							this.setEdgePoints(edge, null);
  						}
  						var state = view.getState(edge);
  						var target = (state != null) ? state.getVisibleTerminal(this.invert) : view.getVisibleTerminal(edge, this.invert);
  						var tmp = this.dfs(target, parent);
  						if (tmp != null && model.getGeometry(target) != null)
  						{
  							if (prev == null)
  							{
  								node.child = tmp;
  							}
  							else
  							{
  								prev.next = tmp;
  							}
  							prev = tmp;
  						}
  					}
  				}
  			}
  			return node;
  		};
  		mxCompactTreeLayout.prototype.layout = function(node)
  		{
  			if (node != null)
  			{
  				var child = node.child;
  				while (child != null)
  				{
  					this.layout(child);
  					child = child.next;
  				}
  				if (node.child != null)
  				{
  					this.attachParent(node, this.join(node));
  				}
  				else
  				{
  					this.layoutLeaf(node);
  				}
  			}
  		};
  		mxCompactTreeLayout.prototype.horizontalLayout = function(node, x0, y0, bounds)
  		{
  			node.x += x0 + node.offsetX;
  			node.y += y0 + node.offsetY;
  			bounds = this.apply(node, bounds);
  			var child = node.child;
  			if (child != null)
  			{
  				bounds = this.horizontalLayout(child, node.x, node.y, bounds);
  				var siblingOffset = node.y + child.offsetY;
  				var s = child.next;
  				while (s != null)
  				{
  					bounds = this.horizontalLayout(s, node.x + child.offsetX, siblingOffset, bounds);
  					siblingOffset += s.offsetY;
  					s = s.next;
  				}
  			}
  			return bounds;
  		};
  		mxCompactTreeLayout.prototype.verticalLayout = function(node, parent, x0, y0, bounds)
  		{
  			node.x += x0 + node.offsetY;
  			node.y += y0 + node.offsetX;
  			bounds = this.apply(node, bounds);
  			var child = node.child;
  			if (child != null)
  			{
  				bounds = this.verticalLayout(child, node, node.x, node.y, bounds);
  				var siblingOffset = node.x + child.offsetY;
  				var s = child.next;
  				while (s != null)
  				{
  					bounds = this.verticalLayout(s, node, siblingOffset, node.y + child.offsetX, bounds);
  					siblingOffset += s.offsetY;
  					s = s.next;
  				}
  			}
  			return bounds;
  		};
  		mxCompactTreeLayout.prototype.attachParent = function(node, height)
  		{
  			var x = this.nodeDistance + this.levelDistance;
  			var y2 = (height - node.width) / 2 - this.nodeDistance;
  			var y1 = y2 + node.width + 2 * this.nodeDistance - height;
  			node.child.offsetX = x + node.height;
  			node.child.offsetY = y1;
  			node.contour.upperHead = this.createLine(node.height, 0,
  				this.createLine(x, y1, node.contour.upperHead));
  			node.contour.lowerHead = this.createLine(node.height, 0,
  				this.createLine(x, y2, node.contour.lowerHead));
  		};
  		mxCompactTreeLayout.prototype.layoutLeaf = function(node)
  		{
  			var dist = 2 * this.nodeDistance;
  			node.contour.upperTail = this.createLine(
  				node.height + dist, 0);
  			node.contour.upperHead = node.contour.upperTail;
  			node.contour.lowerTail = this.createLine(
  				0, -node.width - dist);
  			node.contour.lowerHead = this.createLine(
  				node.height + dist, 0, node.contour.lowerTail);
  		};
  		mxCompactTreeLayout.prototype.join = function(node)
  		{
  			var dist = 2 * this.nodeDistance;
  			var child = node.child;
  			node.contour = child.contour;
  			var h = child.width + dist;
  			var sum = h;
  			child = child.next;
  			while (child != null)
  			{
  				var d = this.merge(node.contour, child.contour);
  				child.offsetY = d + h;
  				child.offsetX = 0;
  				h = child.width + dist;
  				sum += d + h;
  				child = child.next;
  			}
  			return sum;
  		};
  		mxCompactTreeLayout.prototype.merge = function(p1, p2)
  		{
  			var x = 0;
  			var y = 0;
  			var total = 0;
  			var upper = p1.lowerHead;
  			var lower = p2.upperHead;
  			while (lower != null && upper != null)
  			{
  				var d = this.offset(x, y, lower.dx, lower.dy,
  					upper.dx, upper.dy);
  				y += d;
  				total += d;
  				if (x + lower.dx <= upper.dx)
  				{
  					x += lower.dx;
  					y += lower.dy;
  					lower = lower.next;
  				}
  				else
  				{
  					x -= upper.dx;
  					y -= upper.dy;
  					upper = upper.next;
  				}
  			}
  			if (lower != null)
  			{
  				var b = this.bridge(p1.upperTail, 0, 0, lower, x, y);
  				p1.upperTail = (b.next != null) ? p2.upperTail : b;
  				p1.lowerTail = p2.lowerTail;
  			}
  			else
  			{
  				var b = this.bridge(p2.lowerTail, x, y, upper, 0, 0);
  				if (b.next == null)
  				{
  					p1.lowerTail = b;
  				}
  			}
  			p1.lowerHead = p2.lowerHead;
  			return total;
  		};
  		mxCompactTreeLayout.prototype.offset = function(p1, p2, a1, a2, b1, b2)
  		{
  			var d = 0;
  			if (b1 <= p1 || p1 + a1 <= 0)
  			{
  				return 0;
  			}
  			var t = b1 * a2 - a1 * b2;
  			if (t > 0)
  			{
  				if (p1 < 0)
  				{
  					var s = p1 * a2;
  					d = s / a1 - p2;
  				}
  				else if (p1 > 0)
  				{
  					var s = p1 * b2;
  					d = s / b1 - p2;
  				}
  				else
  				{
  					d = -p2;
  				}
  			}
  			else if (b1 < p1 + a1)
  			{
  				var s = (b1 - p1) * a2;
  				d = b2 - (p2 + s / a1);
  			}
  			else if (b1 > p1 + a1)
  			{
  				var s = (a1 + p1) * b2;
  				d = s / b1 - (p2 + a2);
  			}
  			else
  			{
  				d = b2 - (p2 + a2);
  			}
  			if (d > 0)
  			{
  				return d;
  			}
  			else
  			{
  				return 0;
  			}
  		};
  		mxCompactTreeLayout.prototype.bridge = function(line1, x1, y1, line2, x2, y2)
  		{
  			var dx = x2 + line2.dx - x1;
  			var dy = 0;
  			var s = 0;
  			if (line2.dx == 0)
  			{
  				dy = line2.dy;
  			}
  			else
  			{
  				s = dx * line2.dy;
  				dy = s / line2.dx;
  			}
  			var r = this.createLine(dx, dy, line2.next);
  			line1.next = this.createLine(0, y2 + line2.dy - dy - y1, r);
  			return r;
  		};
  		mxCompactTreeLayout.prototype.createNode = function(cell)
  		{
  			var node = new Object();
  			node.cell = cell;
  			node.x = 0;
  			node.y = 0;
  			node.width = 0;
  			node.height = 0;
  			var geo = this.getVertexBounds(cell);
  			if (geo != null)
  			{
  				if (this.isHorizontal())
  				{
  					node.width = geo.height;
  					node.height = geo.width;
  				}
  				else
  				{
  					node.width = geo.width;
  					node.height = geo.height;
  				}
  			}
  			node.offsetX = 0;
  			node.offsetY = 0;
  			node.contour = new Object();
  			return node;
  		};
  		mxCompactTreeLayout.prototype.apply = function(node, bounds)
  		{
  			var model = this.graph.getModel();
  			var cell = node.cell;
  			var g = model.getGeometry(cell);
  			if (cell != null && g != null)
  			{
  				if (this.isVertexMovable(cell))
  				{
  					g = this.setVertexLocation(cell, node.x, node.y);
  					if (this.resizeParent)
  					{
  						var parent = model.getParent(cell);
  						var id = mxCellPath.create(parent);
  						if (this.parentsChanged[id] == null)
  						{
  							this.parentsChanged[id] = parent;
  						}
  					}
  				}
  				if (bounds == null)
  				{
  					bounds = new mxRectangle(g.x, g.y, g.width, g.height);
  				}
  				else
  				{
  					bounds = new mxRectangle(Math.min(bounds.x, g.x),
  						Math.min(bounds.y, g.y),
  						Math.max(bounds.x + bounds.width, g.x + g.width),
  						Math.max(bounds.y + bounds.height, g.y + g.height));
  				}
  			}
  			return bounds;
  		};
  		mxCompactTreeLayout.prototype.createLine = function(dx, dy, next)
  		{
  			var line = new Object();
  			line.dx = dx;
  			line.dy = dy;
  			line.next = next;
  			return line;
  		};
  		mxCompactTreeLayout.prototype.adjustParents = function()
  		{
  			var tmp = [];
  			for (var id in this.parentsChanged)
  			{
  				tmp.push(this.parentsChanged[id]);
  			}
  			this.arrangeGroups(mxUtils.sortCells(tmp, true), this.groupPadding, this.groupPaddingTop,
  				this.groupPaddingRight, this.groupPaddingBottom, this.groupPaddingLeft);
  		};
  		mxCompactTreeLayout.prototype.localEdgeProcessing = function(node)
  		{
  			this.processNodeOutgoing(node);
  			var child = node.child;
  			while (child != null)
  			{
  				this.localEdgeProcessing(child);
  				child = child.next;
  			}
  		};
  		mxCompactTreeLayout.prototype.processNodeOutgoing = function(node)
  		{
  			var child = node.child;
  			var parentCell = node.cell;
  			var childCount = 0;
  			var sortedCells = [];
  			while (child != null)
  			{
  				childCount++;
  				var sortingCriterion = child.x;
  				if (this.horizontal)
  				{
  					sortingCriterion = child.y;
  				}
  				sortedCells.push(new WeightedCellSorter(child, sortingCriterion));
  				child = child.next;
  			}
  			sortedCells.sort(WeightedCellSorter.prototype.compare);
  			var availableWidth = node.width;
  			var requiredWidth = (childCount + 1) * this.prefHozEdgeSep;
  			if (availableWidth > requiredWidth + (2 * this.prefHozEdgeSep))
  			{
  				availableWidth -= 2 * this.prefHozEdgeSep;
  			}
  			var edgeSpacing = availableWidth / childCount;
  			var currentXOffset = edgeSpacing / 2.0;
  			if (availableWidth > requiredWidth + (2 * this.prefHozEdgeSep))
  			{
  				currentXOffset += this.prefHozEdgeSep;
  			}
  			var currentYOffset = this.minEdgeJetty - this.prefVertEdgeOff;
  			var parentBounds = this.getVertexBounds(parentCell);
  			child = node.child;
  			for (var j = 0; j < sortedCells.length; j++)
  			{
  				var childCell = sortedCells[j].cell.cell;
  				var childBounds = this.getVertexBounds(childCell);
  				var edges = this.graph.getEdgesBetween(parentCell,
  						childCell, false);
  				var newPoints = [];
  				var x = 0;
  				var y = 0;
  				for (var i = 0; i < edges.length; i++)
  				{
  					if (this.horizontal)
  					{
  						x = parentBounds.x + parentBounds.width;
  						y = parentBounds.y + currentXOffset;
  						newPoints.push(new mxPoint(x, y));
  						x = parentBounds.x + parentBounds.width
  								+ currentYOffset;
  						newPoints.push(new mxPoint(x, y));
  						y = childBounds.y + childBounds.height / 2.0;
  						newPoints.push(new mxPoint(x, y));
  						this.setEdgePoints(edges[i], newPoints);
  					}
  					else
  					{
  						x = parentBounds.x + currentXOffset;
  						y = parentBounds.y + parentBounds.height;
  						newPoints.push(new mxPoint(x, y));
  						y = parentBounds.y + parentBounds.height
  								+ currentYOffset;
  						newPoints.push(new mxPoint(x, y));
  						x = childBounds.x + childBounds.width / 2.0;
  						newPoints.push(new mxPoint(x, y));
  						this.setEdgePoints(edges[i], newPoints);
  					}
  				}
  				if (j < childCount / 2)
  				{
  					currentYOffset += this.prefVertEdgeOff;
  				}
  				else if (j > childCount / 2)
  				{
  					currentYOffset -= this.prefVertEdgeOff;
  				}
  				currentXOffset += edgeSpacing;
  			}
  		};
  		__mxOutput.mxCompactTreeLayout = typeof mxCompactTreeLayout !== 'undefined' ? mxCompactTreeLayout : undefined;
  		function mxRadialTreeLayout(graph)
  		{
  			mxCompactTreeLayout.call(this, graph , false);
  		}		mxUtils.extend(mxRadialTreeLayout, mxCompactTreeLayout);
  		mxRadialTreeLayout.prototype.angleOffset = 0.5;
  		mxRadialTreeLayout.prototype.rootx = 0;
  		mxRadialTreeLayout.prototype.rooty = 0;
  		mxRadialTreeLayout.prototype.levelDistance = 120;
  		mxRadialTreeLayout.prototype.nodeDistance = 10;
  		mxRadialTreeLayout.prototype.autoRadius = false;
  		mxRadialTreeLayout.prototype.sortEdges = false;
  		mxRadialTreeLayout.prototype.rowMinX = [];
  		mxRadialTreeLayout.prototype.rowMaxX = [];
  		mxRadialTreeLayout.prototype.rowMinCenX = [];
  		mxRadialTreeLayout.prototype.rowMaxCenX = [];
  		mxRadialTreeLayout.prototype.rowRadi = [];
  		mxRadialTreeLayout.prototype.row = [];
  		mxRadialTreeLayout.prototype.isVertexIgnored = function(vertex)
  		{
  			return mxGraphLayout.prototype.isVertexIgnored.apply(this, arguments) ||
  				this.graph.getConnections(vertex).length == 0;
  		};
  		mxRadialTreeLayout.prototype.execute = function(parent, root)
  		{
  			this.parent = parent;
  			this.useBoundingBox = false;
  			this.edgeRouting = false;
  			mxCompactTreeLayout.prototype.execute.apply(this, arguments);
  			var bounds = null;
  			var rootBounds = this.getVertexBounds(this.root);
  			this.centerX = rootBounds.x + rootBounds.width / 2;
  			this.centerY = rootBounds.y + rootBounds.height / 2;
  			for (var vertex in this.visited)
  			{
  				var vertexBounds = this.getVertexBounds(this.visited[vertex]);
  				bounds = (bounds != null) ? bounds : vertexBounds.clone();
  				bounds.add(vertexBounds);
  			}
  			this.calcRowDims([this.node], 0);
  			var maxLeftGrad = 0;
  			var maxRightGrad = 0;
  			for (var i = 0; i < this.row.length; i++)
  			{
  				var leftGrad = (this.centerX - this.rowMinX[i] - this.nodeDistance) / this.rowRadi[i];
  				var rightGrad = (this.rowMaxX[i] - this.centerX - this.nodeDistance) / this.rowRadi[i];
  				maxLeftGrad = Math.max (maxLeftGrad, leftGrad);
  				maxRightGrad = Math.max (maxRightGrad, rightGrad);
  			}
  			for (var i = 0; i < this.row.length; i++)
  			{
  				var xLeftLimit = this.centerX - this.nodeDistance - maxLeftGrad * this.rowRadi[i];
  				var xRightLimit = this.centerX + this.nodeDistance + maxRightGrad * this.rowRadi[i];
  				var fullWidth = xRightLimit - xLeftLimit;
  				for (var j = 0; j < this.row[i].length; j ++)
  				{
  					var row = this.row[i];
  					var node = row[j];
  					var vertexBounds = this.getVertexBounds(node.cell);
  					var xProportion = (vertexBounds.x + vertexBounds.width / 2 - xLeftLimit) / (fullWidth);
  					var theta =  2 * Math.PI * xProportion;
  					node.theta = theta;
  				}
  			}
  			for (var i = this.row.length - 2; i >= 0; i--)
  			{
  				var row = this.row[i];
  				for (var j = 0; j < row.length; j++)
  				{
  					var node = row[j];
  					var child = node.child;
  					var counter = 0;
  					var totalTheta = 0;
  					while (child != null)
  					{
  						totalTheta += child.theta;
  						counter++;
  						child = child.next;
  					}
  					if (counter > 0)
  					{
  						var averTheta = totalTheta / counter;
  						if (averTheta > node.theta && j < row.length - 1)
  						{
  							var nextTheta = row[j+1].theta;
  							node.theta = Math.min (averTheta, nextTheta - Math.PI/10);
  						}
  						else if (averTheta < node.theta && j > 0 )
  						{
  							var lastTheta = row[j-1].theta;
  							node.theta = Math.max (averTheta, lastTheta + Math.PI/10);
  						}
  					}
  				}
  			}
  			for (var i = 0; i < this.row.length; i++)
  			{
  				for (var j = 0; j < this.row[i].length; j ++)
  				{
  					var row = this.row[i];
  					var node = row[j];
  					var vertexBounds = this.getVertexBounds(node.cell);
  					this.setVertexLocation(node.cell,
  											this.centerX - vertexBounds.width / 2 + this.rowRadi[i] * Math.cos(node.theta),
  											this.centerY - vertexBounds.height / 2 + this.rowRadi[i] * Math.sin(node.theta));
  				}
  			}
  		};
  		mxRadialTreeLayout.prototype.calcRowDims = function(row, rowNum)
  		{
  			if (row == null || row.length == 0)
  			{
  				return;
  			}
  			this.rowMinX[rowNum] = this.centerX;
  			this.rowMaxX[rowNum] = this.centerX;
  			this.rowMinCenX[rowNum] = this.centerX;
  			this.rowMaxCenX[rowNum] = this.centerX;
  			this.row[rowNum] = [];
  			var rowHasChildren = false;
  			for (var i = 0; i < row.length; i++)
  			{
  				var child = row[i] != null ? row[i].child : null;
  				while (child != null)
  				{
  					var cell = child.cell;
  					var vertexBounds = this.getVertexBounds(cell);
  					this.rowMinX[rowNum] = Math.min(vertexBounds.x, this.rowMinX[rowNum]);
  					this.rowMaxX[rowNum] = Math.max(vertexBounds.x + vertexBounds.width, this.rowMaxX[rowNum]);
  					this.rowMinCenX[rowNum] = Math.min(vertexBounds.x + vertexBounds.width / 2, this.rowMinCenX[rowNum]);
  					this.rowMaxCenX[rowNum] = Math.max(vertexBounds.x + vertexBounds.width / 2, this.rowMaxCenX[rowNum]);
  					this.rowRadi[rowNum] = vertexBounds.y - this.getVertexBounds(this.root).y;
  					if (child.child != null)
  					{
  						rowHasChildren = true;
  					}
  					this.row[rowNum].push(child);
  					child = child.next;
  				}
  			}
  			if (rowHasChildren)
  			{
  				this.calcRowDims(this.row[rowNum], rowNum + 1);
  			}
  		};
  		__mxOutput.mxRadialTreeLayout = typeof mxRadialTreeLayout !== 'undefined' ? mxRadialTreeLayout : undefined;
  		function mxFastOrganicLayout(graph)
  		{
  			mxGraphLayout.call(this, graph);
  		}		mxFastOrganicLayout.prototype = new mxGraphLayout();
  		mxFastOrganicLayout.prototype.constructor = mxFastOrganicLayout;
  		mxFastOrganicLayout.prototype.useInputOrigin = true;
  		mxFastOrganicLayout.prototype.resetEdges = true;
  		mxFastOrganicLayout.prototype.disableEdgeStyle = true;
  		mxFastOrganicLayout.prototype.forceConstant = 50;
  		mxFastOrganicLayout.prototype.forceConstantSquared = 0;
  		mxFastOrganicLayout.prototype.minDistanceLimit = 2;
  		mxFastOrganicLayout.prototype.maxDistanceLimit = 500;
  		mxFastOrganicLayout.prototype.minDistanceLimitSquared = 4;
  		mxFastOrganicLayout.prototype.initialTemp = 200;
  		mxFastOrganicLayout.prototype.temperature = 0;
  		mxFastOrganicLayout.prototype.maxIterations = 0;
  		mxFastOrganicLayout.prototype.iteration = 0;
  		mxFastOrganicLayout.prototype.vertexArray;
  		mxFastOrganicLayout.prototype.dispX;
  		mxFastOrganicLayout.prototype.dispY;
  		mxFastOrganicLayout.prototype.cellLocation;
  		mxFastOrganicLayout.prototype.radius;
  		mxFastOrganicLayout.prototype.radiusSquared;
  		mxFastOrganicLayout.prototype.isMoveable;
  		mxFastOrganicLayout.prototype.neighbours;
  		mxFastOrganicLayout.prototype.indices;
  		mxFastOrganicLayout.prototype.allowedToRun = true;
  		mxFastOrganicLayout.prototype.isVertexIgnored = function(vertex)
  		{
  			return mxGraphLayout.prototype.isVertexIgnored.apply(this, arguments) ||
  				this.graph.getConnections(vertex).length == 0;
  		};
  		mxFastOrganicLayout.prototype.execute = function(parent)
  		{
  			var model = this.graph.getModel();
  			this.vertexArray = [];
  			var cells = this.graph.getChildVertices(parent);
  			for (var i = 0; i < cells.length; i++)
  			{
  				if (!this.isVertexIgnored(cells[i]))
  				{
  					this.vertexArray.push(cells[i]);
  				}
  			}
  			var initialBounds = (this.useInputOrigin) ?
  					this.graph.getBoundingBoxFromGeometry(this.vertexArray) :
  						null;
  			var n = this.vertexArray.length;
  			this.indices = [];
  			this.dispX = [];
  			this.dispY = [];
  			this.cellLocation = [];
  			this.isMoveable = [];
  			this.neighbours = [];
  			this.radius = [];
  			this.radiusSquared = [];
  			if (this.forceConstant < 0.001)
  			{
  				this.forceConstant = 0.001;
  			}
  			this.forceConstantSquared = this.forceConstant * this.forceConstant;
  			for (var i = 0; i < this.vertexArray.length; i++)
  			{
  				var vertex = this.vertexArray[i];
  				this.cellLocation[i] = [];
  				var id = mxObjectIdentity.get(vertex);
  				this.indices[id] = i;
  				var bounds = this.getVertexBounds(vertex);
  				var width = bounds.width;
  				var height = bounds.height;
  				var x = bounds.x;
  				var y = bounds.y;
  				this.cellLocation[i][0] = x + width / 2.0;
  				this.cellLocation[i][1] = y + height / 2.0;
  				this.radius[i] = Math.min(width, height);
  				this.radiusSquared[i] = this.radius[i] * this.radius[i];
  			}
  			model.beginUpdate();
  			try
  			{
  				for (var i = 0; i < n; i++)
  				{
  					this.dispX[i] = 0;
  					this.dispY[i] = 0;
  					this.isMoveable[i] = this.isVertexMovable(this.vertexArray[i]);
  					var edges = this.graph.getConnections(this.vertexArray[i], parent);
  					var cells = this.graph.getOpposites(edges, this.vertexArray[i]);
  					this.neighbours[i] = [];
  					for (var j = 0; j < cells.length; j++)
  					{
  						if (this.resetEdges)
  						{
  							this.graph.resetEdge(edges[j]);
  						}
  					    if (this.disableEdgeStyle)
  					    {
  					    	this.setEdgeStyleEnabled(edges[j], false);
  					    }
  						var id = mxObjectIdentity.get(cells[j]);
  						var index = this.indices[id];
  						if (index != null)
  						{
  							this.neighbours[i][j] = index;
  						}
  						else
  						{
  							this.neighbours[i][j] = i;
  						}
  					}
  				}
  				this.temperature = this.initialTemp;
  				if (this.maxIterations == 0)
  				{
  					this.maxIterations = 20 * Math.sqrt(n);
  				}
  				for (this.iteration = 0; this.iteration < this.maxIterations; this.iteration++)
  				{
  					if (!this.allowedToRun)
  					{
  						return;
  					}
  					this.calcRepulsion();
  					this.calcAttraction();
  					this.calcPositions();
  					this.reduceTemperature();
  				}
  				var minx = null;
  				var miny = null;
  				for (var i = 0; i < this.vertexArray.length; i++)
  				{
  					var vertex = this.vertexArray[i];
  					if (this.isVertexMovable(vertex))
  					{
  						var bounds = this.getVertexBounds(vertex);
  						if (bounds != null)
  						{
  							this.cellLocation[i][0] -= bounds.width / 2.0;
  							this.cellLocation[i][1] -= bounds.height / 2.0;
  							var x = this.graph.snap(Math.round(this.cellLocation[i][0]));
  							var y = this.graph.snap(Math.round(this.cellLocation[i][1]));
  							this.setVertexLocation(vertex, x, y);
  							if (minx == null)
  							{
  								minx = x;
  							}
  							else
  							{
  								minx = Math.min(minx, x);
  							}
  							if (miny == null)
  							{
  								miny = y;
  							}
  							else
  							{
  								miny = Math.min(miny, y);
  							}
  						}
  					}
  				}
  				var dx = -(minx || 0) + 1;
  				var dy = -(miny || 0) + 1;
  				if (initialBounds != null)
  				{
  					dx += initialBounds.x;
  					dy += initialBounds.y;
  				}
  				this.graph.moveCells(this.vertexArray, dx, dy);
  			}
  			finally
  			{
  				model.endUpdate();
  			}
  		};
  		mxFastOrganicLayout.prototype.calcPositions = function()
  		{
  			for (var index = 0; index < this.vertexArray.length; index++)
  			{
  				if (this.isMoveable[index])
  				{
  					var deltaLength = Math.sqrt(this.dispX[index] * this.dispX[index] +
  						this.dispY[index] * this.dispY[index]);
  					if (deltaLength < 0.001)
  					{
  						deltaLength = 0.001;
  					}
  					var newXDisp = this.dispX[index] / deltaLength
  						* Math.min(deltaLength, this.temperature);
  					var newYDisp = this.dispY[index] / deltaLength
  						* Math.min(deltaLength, this.temperature);
  					this.dispX[index] = 0;
  					this.dispY[index] = 0;
  					this.cellLocation[index][0] += newXDisp;
  					this.cellLocation[index][1] += newYDisp;
  				}
  			}
  		};
  		mxFastOrganicLayout.prototype.calcAttraction = function()
  		{
  			for (var i = 0; i < this.vertexArray.length; i++)
  			{
  				for (var k = 0; k < this.neighbours[i].length; k++)
  				{
  					var j = this.neighbours[i][k];
  					if (i != j &&
  						this.isMoveable[i] &&
  						this.isMoveable[j])
  					{
  						var xDelta = this.cellLocation[i][0] - this.cellLocation[j][0];
  						var yDelta = this.cellLocation[i][1] - this.cellLocation[j][1];
  						var deltaLengthSquared = xDelta * xDelta + yDelta
  								* yDelta - this.radiusSquared[i] - this.radiusSquared[j];
  						if (deltaLengthSquared < this.minDistanceLimitSquared)
  						{
  							deltaLengthSquared = this.minDistanceLimitSquared;
  						}
  						var deltaLength = Math.sqrt(deltaLengthSquared);
  						var force = (deltaLengthSquared) / this.forceConstant;
  						var displacementX = (xDelta / deltaLength) * force;
  						var displacementY = (yDelta / deltaLength) * force;
  						this.dispX[i] -= displacementX;
  						this.dispY[i] -= displacementY;
  						this.dispX[j] += displacementX;
  						this.dispY[j] += displacementY;
  					}
  				}
  			}
  		};
  		mxFastOrganicLayout.prototype.calcRepulsion = function()
  		{
  			var vertexCount = this.vertexArray.length;
  			for (var i = 0; i < vertexCount; i++)
  			{
  				for (var j = i; j < vertexCount; j++)
  				{
  					if (!this.allowedToRun)
  					{
  						return;
  					}
  					if (j != i &&
  						this.isMoveable[i] &&
  						this.isMoveable[j])
  					{
  						var xDelta = this.cellLocation[i][0] - this.cellLocation[j][0];
  						var yDelta = this.cellLocation[i][1] - this.cellLocation[j][1];
  						if (xDelta == 0)
  						{
  							xDelta = 0.01 + Math.random();
  						}
  						if (yDelta == 0)
  						{
  							yDelta = 0.01 + Math.random();
  						}
  						var deltaLength = Math.sqrt((xDelta * xDelta)
  								+ (yDelta * yDelta));
  						var deltaLengthWithRadius = deltaLength - this.radius[i]
  								- this.radius[j];
  						if (deltaLengthWithRadius > this.maxDistanceLimit)
  						{
  							continue;
  						}
  						if (deltaLengthWithRadius < this.minDistanceLimit)
  						{
  							deltaLengthWithRadius = this.minDistanceLimit;
  						}
  						var force = this.forceConstantSquared / deltaLengthWithRadius;
  						var displacementX = (xDelta / deltaLength) * force;
  						var displacementY = (yDelta / deltaLength) * force;
  						this.dispX[i] += displacementX;
  						this.dispY[i] += displacementY;
  						this.dispX[j] -= displacementX;
  						this.dispY[j] -= displacementY;
  					}
  				}
  			}
  		};
  		mxFastOrganicLayout.prototype.reduceTemperature = function()
  		{
  			this.temperature = this.initialTemp * (1.0 - this.iteration / this.maxIterations);
  		};
  		__mxOutput.mxFastOrganicLayout = typeof mxFastOrganicLayout !== 'undefined' ? mxFastOrganicLayout : undefined;
  		function mxCircleLayout(graph, radius)
  		{
  			mxGraphLayout.call(this, graph);
  			this.radius = (radius != null) ? radius : 100;
  		}		mxCircleLayout.prototype = new mxGraphLayout();
  		mxCircleLayout.prototype.constructor = mxCircleLayout;
  		mxCircleLayout.prototype.radius = null;
  		mxCircleLayout.prototype.moveCircle = false;
  		mxCircleLayout.prototype.x0 = 0;
  		mxCircleLayout.prototype.y0 = 0;
  		mxCircleLayout.prototype.resetEdges = true;
  		mxCircleLayout.prototype.disableEdgeStyle = true;
  		mxCircleLayout.prototype.execute = function(parent)
  		{
  			var model = this.graph.getModel();
  			model.beginUpdate();
  			try
  			{
  				var max = 0;
  				var top = null;
  				var left = null;
  				var vertices = [];
  				var childCount = model.getChildCount(parent);
  				for (var i = 0; i < childCount; i++)
  				{
  					var cell = model.getChildAt(parent, i);
  					if (!this.isVertexIgnored(cell))
  					{
  						vertices.push(cell);
  						var bounds = this.getVertexBounds(cell);
  						if (top == null)
  						{
  							top = bounds.y;
  						}
  						else
  						{
  							top = Math.min(top, bounds.y);
  						}
  						if (left == null)
  						{
  							left = bounds.x;
  						}
  						else
  						{
  							left = Math.min(left, bounds.x);
  						}
  						max = Math.max(max, Math.max(bounds.width, bounds.height));
  					}
  					else if (!this.isEdgeIgnored(cell))
  					{
  						if (this.resetEdges)
  						{
  							this.graph.resetEdge(cell);
  						}
  					    if (this.disableEdgeStyle)
  					    {
  					    		this.setEdgeStyleEnabled(cell, false);
  					    }
  					}
  				}
  				var r = this.getRadius(vertices.length, max);
  				if (this.moveCircle)
  				{
  					left = this.x0;
  					top = this.y0;
  				}
  				this.circle(vertices, r, left, top);
  			}
  			finally
  			{
  				model.endUpdate();
  			}
  		};
  		mxCircleLayout.prototype.getRadius = function(count, max)
  		{
  			return Math.max(count * max / Math.PI, this.radius);
  		};
  		mxCircleLayout.prototype.circle = function(vertices, r, left, top)
  		{
  			var vertexCount = vertices.length;
  			var phi = 2 * Math.PI / vertexCount;
  			for (var i = 0; i < vertexCount; i++)
  			{
  				if (this.isVertexMovable(vertices[i]))
  				{
  					this.setVertexLocation(vertices[i],
  						Math.round(left + r + r * Math.sin(i * phi)),
  						Math.round(top + r + r * Math.cos(i * phi)));
  				}
  			}
  		};
  		__mxOutput.mxCircleLayout = typeof mxCircleLayout !== 'undefined' ? mxCircleLayout : undefined;
  		function mxParallelEdgeLayout(graph)
  		{
  			mxGraphLayout.call(this, graph);
  		}		mxParallelEdgeLayout.prototype = new mxGraphLayout();
  		mxParallelEdgeLayout.prototype.constructor = mxParallelEdgeLayout;
  		mxParallelEdgeLayout.prototype.spacing = 20;
  		mxParallelEdgeLayout.prototype.checkOverlap = false;
  		mxParallelEdgeLayout.prototype.execute = function(parent, cells)
  		{
  			var lookup = this.findParallels(parent, cells);
  			this.graph.model.beginUpdate();
  			try
  			{
  				for (var i in lookup)
  				{
  					var parallels = lookup[i];
  					if (parallels.length > 1)
  					{
  						this.layout(parallels);
  					}
  				}
  			}
  			finally
  			{
  				this.graph.model.endUpdate();
  			}
  		};
  		mxParallelEdgeLayout.prototype.findParallels = function(parent, cells)
  		{
  			var lookup = [];
  			var addCell = mxUtils.bind(this, function(cell)
  			{
  				if (!this.isEdgeIgnored(cell))
  				{
  					var id = this.getEdgeId(cell);
  					if (id != null)
  					{
  						if (lookup[id] == null)
  						{
  							lookup[id] = [];
  						}
  						lookup[id].push(cell);
  					}
  				}
  			});
  			if (cells != null)
  			{
  				for (var i = 0; i < cells.length; i++)
  				{
  					addCell(cells[i]);
  				}
  			}
  			else
  			{
  				var model = this.graph.getModel();
  				var childCount = model.getChildCount(parent);
  				for (var i = 0; i < childCount; i++)
  				{
  					addCell(model.getChildAt(parent, i));
  				}
  			}
  			return lookup;
  		};
  		mxParallelEdgeLayout.prototype.getEdgeId = function(edge)
  		{
  			var view = this.graph.getView();
  			var src = view.getVisibleTerminal(edge, true);
  			var trg = view.getVisibleTerminal(edge, false);
  			var pts = '';
  			if (src != null && trg != null)
  			{
  				src = mxObjectIdentity.get(src);
  				trg = mxObjectIdentity.get(trg);
  				if (this.checkOverlap)
  				{
  					var state = this.graph.view.getState(edge);
  					if (state != null && state.absolutePoints != null)
  					{
  						var tmp = [];
  						for (var i = 0; i < state.absolutePoints.length; i++)
  						{
  							var pt = state.absolutePoints[i];
  							if (pt != null)
  							{
  								tmp.push(pt.x, pt.y);
  							}
  						}
  						pts = tmp.join(',');
  					}
  				}				return ((src > trg) ? trg + '-' + src : src + '-' + trg) + pts;
  			}
  			return null;
  		};
  		mxParallelEdgeLayout.prototype.layout = function(parallels)
  		{
  			var edge = parallels[0];
  			var view = this.graph.getView();
  			var model = this.graph.getModel();
  			var src = model.getGeometry(view.getVisibleTerminal(edge, true));
  			var trg = model.getGeometry(view.getVisibleTerminal(edge, false));
  			if (src == trg)
  			{
  				var x0 = src.x + src.width + this.spacing;
  				var y0 = src.y + src.height / 2;
  				for (var i = 0; i < parallels.length; i++)
  				{
  					this.route(parallels[i], x0, y0);
  					x0 += this.spacing;
  				}
  			}
  			else if (src != null && trg != null)
  			{
  				var scx = src.x + src.width / 2;
  				var scy = src.y + src.height / 2;
  				var tcx = trg.x + trg.width / 2;
  				var tcy = trg.y + trg.height / 2;
  				var dx = tcx - scx;
  				var dy = tcy - scy;
  				var len = Math.sqrt(dx * dx + dy * dy);
  				if (len > 0)
  				{
  					var x0 = scx + dx / 2;
  					var y0 = scy + dy / 2;
  					var nx = dy * this.spacing / len;
  					var ny = dx * this.spacing / len;
  					x0 += nx * (parallels.length - 1) / 2;
  					y0 -= ny * (parallels.length - 1) / 2;
  					for (var i = 0; i < parallels.length; i++)
  					{
  						this.route(parallels[i], x0, y0);
  						x0 -= nx;
  						y0 += ny;
  					}
  				}
  			}
  		};
  		mxParallelEdgeLayout.prototype.route = function(edge, x, y)
  		{
  			if (this.graph.isCellMovable(edge))
  			{
  				this.setEdgePoints(edge, [new mxPoint(x, y)]);
  			}
  		};
  		__mxOutput.mxParallelEdgeLayout = typeof mxParallelEdgeLayout !== 'undefined' ? mxParallelEdgeLayout : undefined;
  		function mxCompositeLayout(graph, layouts, master)
  		{
  			mxGraphLayout.call(this, graph);
  			this.layouts = layouts;
  			this.master = master;
  		}		mxCompositeLayout.prototype = new mxGraphLayout();
  		mxCompositeLayout.prototype.constructor = mxCompositeLayout;
  		mxCompositeLayout.prototype.layouts = null;
  		mxCompositeLayout.prototype.master = null;
  		mxCompositeLayout.prototype.moveCell = function(cell, x, y)
  		{
  			if (this.master != null)
  			{
  				this.master.moveCell.apply(this.master, arguments);
  			}
  			else
  			{
  				this.layouts[0].moveCell.apply(this.layouts[0], arguments);
  			}
  		};
  		mxCompositeLayout.prototype.execute = function(parent)
  		{
  			var model = this.graph.getModel();
  			model.beginUpdate();
  			try
  			{
  				for (var i = 0; i < this.layouts.length; i++)
  				{
  					this.layouts[i].execute.apply(this.layouts[i], arguments);
  				}
  			}
  			finally
  			{
  				model.endUpdate();
  			}
  		};
  		__mxOutput.mxCompositeLayout = typeof mxCompositeLayout !== 'undefined' ? mxCompositeLayout : undefined;
  		function mxEdgeLabelLayout(graph, radius)
  		{
  			mxGraphLayout.call(this, graph);
  		}		mxEdgeLabelLayout.prototype = new mxGraphLayout();
  		mxEdgeLabelLayout.prototype.constructor = mxEdgeLabelLayout;
  		mxEdgeLabelLayout.prototype.execute = function(parent)
  		{
  			var view = this.graph.view;
  			var model = this.graph.getModel();
  			var edges = [];
  			var vertices = [];
  			var childCount = model.getChildCount(parent);
  			for (var i = 0; i < childCount; i++)
  			{
  				var cell = model.getChildAt(parent, i);
  				var state = view.getState(cell);
  				if (state != null)
  				{
  					if (!this.isVertexIgnored(cell))
  					{
  						vertices.push(state);
  					}
  					else if (!this.isEdgeIgnored(cell))
  					{
  						edges.push(state);
  					}
  				}
  			}
  			this.placeLabels(vertices, edges);
  		};
  		mxEdgeLabelLayout.prototype.placeLabels = function(v, e)
  		{
  			var model = this.graph.getModel();
  			model.beginUpdate();
  			try
  			{
  				for (var i = 0; i < e.length; i++)
  				{
  					var edge = e[i];
  					if (edge != null && edge.text != null &&
  						edge.text.boundingBox != null)
  					{
  						for (var j = 0; j < v.length; j++)
  						{
  							var vertex = v[j];
  							if (vertex != null)
  							{
  								this.avoid(edge, vertex);
  							}
  						}
  					}
  				}
  			}
  			finally
  			{
  				model.endUpdate();
  			}
  		};
  		mxEdgeLabelLayout.prototype.avoid = function(edge, vertex)
  		{
  			var model = this.graph.getModel();
  			var labRect = edge.text.boundingBox;
  			if (mxUtils.intersects(labRect, vertex))
  			{
  				var dy1 = -labRect.y - labRect.height + vertex.y;
  				var dy2 = -labRect.y + vertex.y + vertex.height;
  				var dy = (Math.abs(dy1) < Math.abs(dy2)) ? dy1 : dy2;
  				var dx1 = -labRect.x - labRect.width + vertex.x;
  				var dx2 = -labRect.x + vertex.x + vertex.width;
  				var dx = (Math.abs(dx1) < Math.abs(dx2)) ? dx1 : dx2;
  				if (Math.abs(dx) < Math.abs(dy))
  				{
  					dy = 0;
  				}
  				else
  				{
  					dx = 0;
  				}
  				var g = model.getGeometry(edge.cell);
  				if (g != null)
  				{
  					g = g.clone();
  					if (g.offset != null)
  					{
  						g.offset.x += dx;
  						g.offset.y += dy;
  					}
  					else
  					{
  						g.offset = new mxPoint(dx, dy);
  					}
  					model.setGeometry(edge.cell, g);
  				}
  			}
  		};
  		__mxOutput.mxEdgeLabelLayout = typeof mxEdgeLabelLayout !== 'undefined' ? mxEdgeLabelLayout : undefined;
  		function mxGraphAbstractHierarchyCell()
  		{
  			this.x = [];
  			this.y = [];
  			this.temp = [];
  		}		mxGraphAbstractHierarchyCell.prototype.maxRank = -1;
  		mxGraphAbstractHierarchyCell.prototype.minRank = -1;
  		mxGraphAbstractHierarchyCell.prototype.x = null;
  		mxGraphAbstractHierarchyCell.prototype.y = null;
  		mxGraphAbstractHierarchyCell.prototype.width = 0;
  		mxGraphAbstractHierarchyCell.prototype.height = 0;
  		mxGraphAbstractHierarchyCell.prototype.nextLayerConnectedCells = null;
  		mxGraphAbstractHierarchyCell.prototype.previousLayerConnectedCells = null;
  		mxGraphAbstractHierarchyCell.prototype.temp = null;
  		mxGraphAbstractHierarchyCell.prototype.getNextLayerConnectedCells = function(layer)
  		{
  			return null;
  		};
  		mxGraphAbstractHierarchyCell.prototype.getPreviousLayerConnectedCells = function(layer)
  		{
  			return null;
  		};
  		mxGraphAbstractHierarchyCell.prototype.isEdge = function()
  		{
  			return false;
  		};
  		mxGraphAbstractHierarchyCell.prototype.isVertex = function()
  		{
  			return false;
  		};
  		mxGraphAbstractHierarchyCell.prototype.getGeneralPurposeVariable = function(layer)
  		{
  			return null;
  		};
  		mxGraphAbstractHierarchyCell.prototype.setGeneralPurposeVariable = function(layer, value)
  		{
  			return null;
  		};
  		mxGraphAbstractHierarchyCell.prototype.setX = function(layer, value)
  		{
  			if (this.isVertex())
  			{
  				this.x[0] = value;
  			}
  			else if (this.isEdge())
  			{
  				this.x[layer - this.minRank - 1] = value;
  			}
  		};
  		mxGraphAbstractHierarchyCell.prototype.getX = function(layer)
  		{
  			if (this.isVertex())
  			{
  				return this.x[0];
  			}
  			else if (this.isEdge())
  			{
  				return this.x[layer - this.minRank - 1];
  			}
  			return 0.0;
  		};
  		mxGraphAbstractHierarchyCell.prototype.setY = function(layer, value)
  		{
  			if (this.isVertex())
  			{
  				this.y[0] = value;
  			}
  			else if (this.isEdge())
  			{
  				this.y[layer -this. minRank - 1] = value;
  			}
  		};
  		__mxOutput.mxGraphAbstractHierarchyCell = typeof mxGraphAbstractHierarchyCell !== 'undefined' ? mxGraphAbstractHierarchyCell : undefined;
  		function mxGraphHierarchyNode(cell)
  		{
  			mxGraphAbstractHierarchyCell.apply(this, arguments);
  			this.cell = cell;
  			this.id = mxObjectIdentity.get(cell);
  			this.connectsAsTarget = [];
  			this.connectsAsSource = [];
  		}		mxGraphHierarchyNode.prototype = new mxGraphAbstractHierarchyCell();
  		mxGraphHierarchyNode.prototype.constructor = mxGraphHierarchyNode;
  		mxGraphHierarchyNode.prototype.cell = null;
  		mxGraphHierarchyNode.prototype.id = null;
  		mxGraphHierarchyNode.prototype.connectsAsTarget = null;
  		mxGraphHierarchyNode.prototype.connectsAsSource = null;
  		mxGraphHierarchyNode.prototype.hashCode = false;
  		mxGraphHierarchyNode.prototype.getRankValue = function(layer)
  		{
  			return this.maxRank;
  		};
  		mxGraphHierarchyNode.prototype.getNextLayerConnectedCells = function(layer)
  		{
  			if (this.nextLayerConnectedCells == null)
  			{
  				this.nextLayerConnectedCells = [];
  				this.nextLayerConnectedCells[0] = [];
  				for (var i = 0; i < this.connectsAsTarget.length; i++)
  				{
  					var edge = this.connectsAsTarget[i];
  					if (edge.maxRank == -1 || edge.maxRank == layer + 1)
  					{
  						this.nextLayerConnectedCells[0].push(edge.source);
  					}
  					else
  					{
  						this.nextLayerConnectedCells[0].push(edge);
  					}
  				}
  			}
  			return this.nextLayerConnectedCells[0];
  		};
  		mxGraphHierarchyNode.prototype.getPreviousLayerConnectedCells = function(layer)
  		{
  			if (this.previousLayerConnectedCells == null)
  			{
  				this.previousLayerConnectedCells = [];
  				this.previousLayerConnectedCells[0] = [];
  				for (var i = 0; i < this.connectsAsSource.length; i++)
  				{
  					var edge = this.connectsAsSource[i];
  					if (edge.minRank == -1 || edge.minRank == layer - 1)
  					{
  						this.previousLayerConnectedCells[0].push(edge.target);
  					}
  					else
  					{
  						this.previousLayerConnectedCells[0].push(edge);
  					}
  				}
  			}
  			return this.previousLayerConnectedCells[0];
  		};
  		mxGraphHierarchyNode.prototype.isVertex = function()
  		{
  			return true;
  		};
  		mxGraphHierarchyNode.prototype.getGeneralPurposeVariable = function(layer)
  		{
  			return this.temp[0];
  		};
  		mxGraphHierarchyNode.prototype.setGeneralPurposeVariable = function(layer, value)
  		{
  			this.temp[0] = value;
  		};
  		mxGraphHierarchyNode.prototype.isAncestor = function(otherNode)
  		{
  			if (otherNode != null && this.hashCode != null && otherNode.hashCode != null
  					&& this.hashCode.length < otherNode.hashCode.length)
  			{
  				if (this.hashCode == otherNode.hashCode)
  				{
  					return true;
  				}
  				if (this.hashCode == null || this.hashCode == null)
  				{
  					return false;
  				}
  				for (var i = 0; i < this.hashCode.length; i++)
  				{
  					if (this.hashCode[i] != otherNode.hashCode[i])
  					{
  						return false;
  					}
  				}
  				return true;
  			}
  			return false;
  		};
  		mxGraphHierarchyNode.prototype.getCoreCell = function()
  		{
  			return this.cell;
  		};
  		__mxOutput.mxGraphHierarchyNode = typeof mxGraphHierarchyNode !== 'undefined' ? mxGraphHierarchyNode : undefined;
  		function mxGraphHierarchyEdge(edges)
  		{
  			mxGraphAbstractHierarchyCell.apply(this, arguments);
  			this.edges = edges;
  			this.ids = [];
  			for (var i = 0; i < edges.length; i++)
  			{
  				this.ids.push(mxObjectIdentity.get(edges[i]));
  			}
  		}		mxGraphHierarchyEdge.prototype = new mxGraphAbstractHierarchyCell();
  		mxGraphHierarchyEdge.prototype.constructor = mxGraphHierarchyEdge;
  		mxGraphHierarchyEdge.prototype.edges = null;
  		mxGraphHierarchyEdge.prototype.ids = null;
  		mxGraphHierarchyEdge.prototype.source = null;
  		mxGraphHierarchyEdge.prototype.target = null;
  		mxGraphHierarchyEdge.prototype.isReversed = false;
  		mxGraphHierarchyEdge.prototype.invert = function(layer)
  		{
  			var temp = this.source;
  			this.source = this.target;
  			this.target = temp;
  			this.isReversed = !this.isReversed;
  		};
  		mxGraphHierarchyEdge.prototype.getNextLayerConnectedCells = function(layer)
  		{
  			if (this.nextLayerConnectedCells == null)
  			{
  				this.nextLayerConnectedCells = [];
  				for (var i = 0; i < this.temp.length; i++)
  				{
  					this.nextLayerConnectedCells[i] = [];
  					if (i == this.temp.length - 1)
  					{
  						this.nextLayerConnectedCells[i].push(this.source);
  					}
  					else
  					{
  						this.nextLayerConnectedCells[i].push(this);
  					}
  				}
  			}
  			return this.nextLayerConnectedCells[layer - this.minRank - 1];
  		};
  		mxGraphHierarchyEdge.prototype.getPreviousLayerConnectedCells = function(layer)
  		{
  			if (this.previousLayerConnectedCells == null)
  			{
  				this.previousLayerConnectedCells = [];
  				for (var i = 0; i < this.temp.length; i++)
  				{
  					this.previousLayerConnectedCells[i] = [];
  					if (i == 0)
  					{
  						this.previousLayerConnectedCells[i].push(this.target);
  					}
  					else
  					{
  						this.previousLayerConnectedCells[i].push(this);
  					}
  				}
  			}
  			return this.previousLayerConnectedCells[layer - this.minRank - 1];
  		};
  		mxGraphHierarchyEdge.prototype.isEdge = function()
  		{
  			return true;
  		};
  		mxGraphHierarchyEdge.prototype.getGeneralPurposeVariable = function(layer)
  		{
  			return this.temp[layer - this.minRank - 1];
  		};
  		mxGraphHierarchyEdge.prototype.setGeneralPurposeVariable = function(layer, value)
  		{
  			this.temp[layer - this.minRank - 1] = value;
  		};
  		mxGraphHierarchyEdge.prototype.getCoreCell = function()
  		{
  			if (this.edges != null && this.edges.length > 0)
  			{
  				return this.edges[0];
  			}
  			return null;
  		};
  		__mxOutput.mxGraphHierarchyEdge = typeof mxGraphHierarchyEdge !== 'undefined' ? mxGraphHierarchyEdge : undefined;
  		function mxGraphHierarchyModel(layout, vertices, roots, parent, tightenToSource)
  		{
  			layout.getGraph();
  			this.tightenToSource = tightenToSource;
  			this.roots = roots;
  			this.parent = parent;
  			this.vertexMapper = new mxDictionary();
  			this.edgeMapper = new mxDictionary();
  			this.maxRank = 0;
  			var internalVertices = [];
  			if (vertices == null)
  			{
  				vertices = this.graph.getChildVertices(parent);
  			}
  			this.maxRank = this.SOURCESCANSTARTRANK;
  			this.createInternalCells(layout, vertices, internalVertices);
  			for (var i = 0; i < vertices.length; i++)
  			{
  				var edges = internalVertices[i].connectsAsSource;
  				for (var j = 0; j < edges.length; j++)
  				{
  					var internalEdge = edges[j];
  					var realEdges = internalEdge.edges;
  					if (realEdges != null && realEdges.length > 0)
  					{
  						var realEdge = realEdges[0];
  						var targetCell = layout.getVisibleTerminal(
  								realEdge, false);
  						var internalTargetCell = this.vertexMapper.get(targetCell);
  						if (internalVertices[i] == internalTargetCell)
  						{
  							targetCell = layout.getVisibleTerminal(
  									realEdge, true);
  							internalTargetCell = this.vertexMapper.get(targetCell);
  						}
  						if (internalTargetCell != null
  								&& internalVertices[i] != internalTargetCell)
  						{
  							internalEdge.target = internalTargetCell;
  							if (internalTargetCell.connectsAsTarget.length == 0)
  							{
  								internalTargetCell.connectsAsTarget = [];
  							}
  							if (mxUtils.indexOf(internalTargetCell.connectsAsTarget, internalEdge) < 0)
  							{
  								internalTargetCell.connectsAsTarget.push(internalEdge);
  							}
  						}
  					}
  				}
  				internalVertices[i].temp[0] = 1;
  			}
  		}		mxGraphHierarchyModel.prototype.maxRank = null;
  		mxGraphHierarchyModel.prototype.vertexMapper = null;
  		mxGraphHierarchyModel.prototype.edgeMapper = null;
  		mxGraphHierarchyModel.prototype.ranks = null;
  		mxGraphHierarchyModel.prototype.roots = null;
  		mxGraphHierarchyModel.prototype.parent = null;
  		mxGraphHierarchyModel.prototype.dfsCount = 0;
  		mxGraphHierarchyModel.prototype.SOURCESCANSTARTRANK = 100000000;
  		mxGraphHierarchyModel.prototype.tightenToSource = false;
  		mxGraphHierarchyModel.prototype.createInternalCells = function(layout, vertices, internalVertices)
  		{
  			var graph = layout.getGraph();
  			for (var i = 0; i < vertices.length; i++)
  			{
  				internalVertices[i] = new mxGraphHierarchyNode(vertices[i]);
  				this.vertexMapper.put(vertices[i], internalVertices[i]);
  				var conns = layout.getEdges(vertices[i]);
  				internalVertices[i].connectsAsSource = [];
  				for (var j = 0; j < conns.length; j++)
  				{
  					var cell = layout.getVisibleTerminal(conns[j], false);
  					if (cell != vertices[i] && layout.graph.model.isVertex(cell) &&
  							!layout.isVertexIgnored(cell))
  					{
  						var undirectedEdges = layout.getEdgesBetween(vertices[i],
  								cell, false);
  						var directedEdges = layout.getEdgesBetween(vertices[i],
  								cell, true);
  						if (undirectedEdges != null &&
  								undirectedEdges.length > 0 &&
  								this.edgeMapper.get(undirectedEdges[0]) == null &&
  								directedEdges.length * 2 >= undirectedEdges.length)
  						{
  							var internalEdge = new mxGraphHierarchyEdge(undirectedEdges);
  							for (var k = 0; k < undirectedEdges.length; k++)
  							{
  								var edge = undirectedEdges[k];
  								this.edgeMapper.put(edge, internalEdge);
  								graph.resetEdge(edge);
  							    if (layout.disableEdgeStyle)
  							    {
  							    	layout.setEdgeStyleEnabled(edge, false);
  							    	layout.setOrthogonalEdge(edge,true);
  							    }
  							}
  							internalEdge.source = internalVertices[i];
  							if (mxUtils.indexOf(internalVertices[i].connectsAsSource, internalEdge) < 0)
  							{
  								internalVertices[i].connectsAsSource.push(internalEdge);
  							}
  						}
  					}
  				}
  				internalVertices[i].temp[0] = 0;
  			}
  		};
  		mxGraphHierarchyModel.prototype.initialRank = function()
  		{
  			var startNodes = [];
  			if (this.roots != null)
  			{
  				for (var i = 0; i < this.roots.length; i++)
  				{
  					var internalNode = this.vertexMapper.get(this.roots[i]);
  					if (internalNode != null)
  					{
  						startNodes.push(internalNode);
  					}
  				}
  			}
  			var internalNodes = this.vertexMapper.getValues();
  			for (var i=0; i < internalNodes.length; i++)
  			{
  				internalNodes[i].temp[0] = -1;
  			}
  			var startNodesCopy = startNodes.slice();
  			while (startNodes.length > 0)
  			{
  				var internalNode = startNodes[0];
  				var layerDeterminingEdges;
  				var edgesToBeMarked;
  				layerDeterminingEdges = internalNode.connectsAsTarget;
  				edgesToBeMarked = internalNode.connectsAsSource;
  				var allEdgesScanned = true;
  				var minimumLayer = this.SOURCESCANSTARTRANK;
  				for (var i = 0; i < layerDeterminingEdges.length; i++)
  				{
  					var internalEdge = layerDeterminingEdges[i];
  					if (internalEdge.temp[0] == 5270620)
  					{
  						var otherNode = internalEdge.source;
  						minimumLayer = Math.min(minimumLayer, otherNode.temp[0] - 1);
  					}
  					else
  					{
  						allEdgesScanned = false;
  						break;
  					}
  				}
  				if (allEdgesScanned)
  				{
  					internalNode.temp[0] = minimumLayer;
  					this.maxRank = Math.min(this.maxRank, minimumLayer);
  					if (edgesToBeMarked != null)
  					{
  						for (var i = 0; i < edgesToBeMarked.length; i++)
  						{
  							var internalEdge = edgesToBeMarked[i];
  							internalEdge.temp[0] = 5270620;
  							var otherNode = internalEdge.target;
  							if (otherNode.temp[0] == -1)
  							{
  								startNodes.push(otherNode);
  								otherNode.temp[0] = -2;
  							}
  						}
  					}
  					startNodes.shift();
  				}
  				else
  				{
  					var removedCell = startNodes.shift();
  					startNodes.push(internalNode);
  					if (removedCell == internalNode && startNodes.length == 1)
  					{
  						break;
  					}
  				}
  			}
  			for (var i=0; i < internalNodes.length; i++)
  			{
  				internalNodes[i].temp[0] -= this.maxRank;
  			}
  			for ( var i = 0; i < startNodesCopy.length; i++)
  			{
  				var internalNode = startNodesCopy[i];
  				var currentMaxLayer = 0;
  				var layerDeterminingEdges = internalNode.connectsAsSource;
  				for ( var j = 0; j < layerDeterminingEdges.length; j++)
  				{
  					var internalEdge = layerDeterminingEdges[j];
  					var otherNode = internalEdge.target;
  					internalNode.temp[0] = Math.max(currentMaxLayer,
  							otherNode.temp[0] + 1);
  					currentMaxLayer = internalNode.temp[0];
  				}
  			}
  			this.maxRank = this.SOURCESCANSTARTRANK - this.maxRank;
  		};
  		mxGraphHierarchyModel.prototype.fixRanks = function()
  		{
  			var rankList = [];
  			this.ranks = [];
  			for (var i = 0; i < this.maxRank + 1; i++)
  			{
  				rankList[i] = [];
  				this.ranks[i] = rankList[i];
  			}
  			var rootsArray = null;
  			if (this.roots != null)
  			{
  				var oldRootsArray = this.roots;
  				rootsArray = [];
  				for (var i = 0; i < oldRootsArray.length; i++)
  				{
  					var cell = oldRootsArray[i];
  					var internalNode = this.vertexMapper.get(cell);
  					rootsArray[i] = internalNode;
  				}
  			}
  			this.visit(function(parent, node, edge, layer, seen)
  			{
  				if (seen == 0 && node.maxRank < 0 && node.minRank < 0)
  				{
  					rankList[node.temp[0]].push(node);
  					node.maxRank = node.temp[0];
  					node.minRank = node.temp[0];
  					node.temp[0] = rankList[node.maxRank].length - 1;
  				}
  				if (parent != null && edge != null)
  				{
  					var parentToCellRankDifference = parent.maxRank - node.maxRank;
  					if (parentToCellRankDifference > 1)
  					{
  						edge.maxRank = parent.maxRank;
  						edge.minRank = node.maxRank;
  						edge.temp = [];
  						edge.x = [];
  						edge.y = [];
  						for (var i = edge.minRank + 1; i < edge.maxRank; i++)
  						{
  							rankList[i].push(edge);
  							edge.setGeneralPurposeVariable(i, rankList[i]
  									.length - 1);
  						}
  					}
  				}
  			}, rootsArray, false, null);
  		};
  		mxGraphHierarchyModel.prototype.visit = function(visitor, dfsRoots, trackAncestors, seenNodes)
  		{
  			if (dfsRoots != null)
  			{
  				for (var i = 0; i < dfsRoots.length; i++)
  				{
  					var internalNode = dfsRoots[i];
  					if (internalNode != null)
  					{
  						if (seenNodes == null)
  						{
  							seenNodes = new Object();
  						}
  						if (trackAncestors)
  						{
  							internalNode.hashCode = [];
  							internalNode.hashCode[0] = this.dfsCount;
  							internalNode.hashCode[1] = i;
  							this.extendedDfs(null, internalNode, null, visitor, seenNodes,
  									internalNode.hashCode, i, 0);
  						}
  						else
  						{
  							this.dfs(null, internalNode, null, visitor, seenNodes, 0);
  						}
  					}
  				}
  				this.dfsCount++;
  			}
  		};
  		mxGraphHierarchyModel.prototype.dfs = function(parent, root, connectingEdge, visitor, seen, layer)
  		{
  			if (root != null)
  			{
  				var rootId = root.id;
  				if (seen[rootId] == null)
  				{
  					seen[rootId] = root;
  					visitor(parent, root, connectingEdge, layer, 0);
  					var outgoingEdges = root.connectsAsSource.slice();
  					for (var i = 0; i< outgoingEdges.length; i++)
  					{
  						var internalEdge = outgoingEdges[i];
  						var targetNode = internalEdge.target;
  						this.dfs(root, targetNode, internalEdge, visitor, seen,
  								layer + 1);
  					}
  				}
  				else
  				{
  					visitor(parent, root, connectingEdge, layer, 1);
  				}
  			}
  		};
  		mxGraphHierarchyModel.prototype.extendedDfs = function(parent, root, connectingEdge, visitor, seen, ancestors, childHash, layer)
  		{
  			if (root != null)
  			{
  				if (parent != null)
  				{
  					if (root.hashCode == null ||
  						root.hashCode[0] != parent.hashCode[0])
  					{
  						var hashCodeLength = parent.hashCode.length + 1;
  						root.hashCode = parent.hashCode.slice();
  						root.hashCode[hashCodeLength - 1] = childHash;
  					}
  				}
  				var rootId = root.id;
  				if (seen[rootId] == null)
  				{
  					seen[rootId] = root;
  					visitor(parent, root, connectingEdge, layer, 0);
  					var outgoingEdges = root.connectsAsSource.slice();
  					for (var i = 0; i < outgoingEdges.length; i++)
  					{
  						var internalEdge = outgoingEdges[i];
  						var targetNode = internalEdge.target;
  						this.extendedDfs(root, targetNode, internalEdge, visitor, seen,
  								root.hashCode, i, layer + 1);
  					}
  				}
  				else
  				{
  					visitor(parent, root, connectingEdge, layer, 1);
  				}
  			}
  		};
  		__mxOutput.mxGraphHierarchyModel = typeof mxGraphHierarchyModel !== 'undefined' ? mxGraphHierarchyModel : undefined;
  		function mxSwimlaneModel(layout, vertices, roots, parent, tightenToSource)
  		{
  			layout.getGraph();
  			this.tightenToSource = tightenToSource;
  			this.roots = roots;
  			this.parent = parent;
  			this.vertexMapper = new mxDictionary();
  			this.edgeMapper = new mxDictionary();
  			this.maxRank = 0;
  			var internalVertices = [];
  			if (vertices == null)
  			{
  				vertices = this.graph.getChildVertices(parent);
  			}
  			this.maxRank = this.SOURCESCANSTARTRANK;
  			this.createInternalCells(layout, vertices, internalVertices);
  			for (var i = 0; i < vertices.length; i++)
  			{
  				var edges = internalVertices[i].connectsAsSource;
  				for (var j = 0; j < edges.length; j++)
  				{
  					var internalEdge = edges[j];
  					var realEdges = internalEdge.edges;
  					if (realEdges != null && realEdges.length > 0)
  					{
  						var realEdge = realEdges[0];
  						var targetCell = layout.getVisibleTerminal(
  								realEdge, false);
  						var internalTargetCell = this.vertexMapper.get(targetCell);
  						if (internalVertices[i] == internalTargetCell)
  						{
  							targetCell = layout.getVisibleTerminal(
  									realEdge, true);
  							internalTargetCell = this.vertexMapper.get(targetCell);
  						}
  						if (internalTargetCell != null
  								&& internalVertices[i] != internalTargetCell)
  						{
  							internalEdge.target = internalTargetCell;
  							if (internalTargetCell.connectsAsTarget.length == 0)
  							{
  								internalTargetCell.connectsAsTarget = [];
  							}
  							if (mxUtils.indexOf(internalTargetCell.connectsAsTarget, internalEdge) < 0)
  							{
  								internalTargetCell.connectsAsTarget.push(internalEdge);
  							}
  						}
  					}
  				}
  				internalVertices[i].temp[0] = 1;
  			}
  		}		mxSwimlaneModel.prototype.maxRank = null;
  		mxSwimlaneModel.prototype.vertexMapper = null;
  		mxSwimlaneModel.prototype.edgeMapper = null;
  		mxSwimlaneModel.prototype.ranks = null;
  		mxSwimlaneModel.prototype.roots = null;
  		mxSwimlaneModel.prototype.parent = null;
  		mxSwimlaneModel.prototype.dfsCount = 0;
  		mxSwimlaneModel.prototype.SOURCESCANSTARTRANK = 100000000;
  		mxSwimlaneModel.prototype.tightenToSource = false;
  		mxSwimlaneModel.prototype.ranksPerGroup = null;
  		mxSwimlaneModel.prototype.createInternalCells = function(layout, vertices, internalVertices)
  		{
  			var graph = layout.getGraph();
  			var swimlanes = layout.swimlanes;
  			for (var i = 0; i < vertices.length; i++)
  			{
  				internalVertices[i] = new mxGraphHierarchyNode(vertices[i]);
  				this.vertexMapper.put(vertices[i], internalVertices[i]);
  				internalVertices[i].swimlaneIndex = -1;
  				for (var ii = 0; ii < swimlanes.length; ii++)
  				{
  					if (graph.model.getParent(vertices[i]) == swimlanes[ii])
  					{
  						internalVertices[i].swimlaneIndex = ii;
  						break;
  					}
  				}
  				var conns = layout.getEdges(vertices[i]);
  				internalVertices[i].connectsAsSource = [];
  				for (var j = 0; j < conns.length; j++)
  				{
  					var cell = layout.getVisibleTerminal(conns[j], false);
  					if (cell != vertices[i] && layout.graph.model.isVertex(cell) &&
  							!layout.isVertexIgnored(cell))
  					{
  						var undirectedEdges = layout.getEdgesBetween(vertices[i],
  								cell, false);
  						var directedEdges = layout.getEdgesBetween(vertices[i],
  								cell, true);
  						if (undirectedEdges != null &&
  								undirectedEdges.length > 0 &&
  								this.edgeMapper.get(undirectedEdges[0]) == null &&
  								directedEdges.length * 2 >= undirectedEdges.length)
  						{
  							var internalEdge = new mxGraphHierarchyEdge(undirectedEdges);
  							for (var k = 0; k < undirectedEdges.length; k++)
  							{
  								var edge = undirectedEdges[k];
  								this.edgeMapper.put(edge, internalEdge);
  								graph.resetEdge(edge);
  							    if (layout.disableEdgeStyle)
  							    {
  							    	layout.setEdgeStyleEnabled(edge, false);
  							    	layout.setOrthogonalEdge(edge,true);
  							    }
  							}
  							internalEdge.source = internalVertices[i];
  							if (mxUtils.indexOf(internalVertices[i].connectsAsSource, internalEdge) < 0)
  							{
  								internalVertices[i].connectsAsSource.push(internalEdge);
  							}
  						}
  					}
  				}
  				internalVertices[i].temp[0] = 0;
  			}
  		};
  		mxSwimlaneModel.prototype.initialRank = function()
  		{
  			this.ranksPerGroup = [];
  			var startNodes = [];
  			var seen = new Object();
  			if (this.roots != null)
  			{
  				for (var i = 0; i < this.roots.length; i++)
  				{
  					var internalNode = this.vertexMapper.get(this.roots[i]);
  					this.maxChainDfs(null, internalNode, null, seen, 0);
  					if (internalNode != null)
  					{
  						startNodes.push(internalNode);
  					}
  				}
  			}
  			var lowerRank = [];
  			var upperRank = [];
  			for (var i = this.ranksPerGroup.length - 1; i >= 0; i--)
  			{
  				if (i == this.ranksPerGroup.length - 1)
  				{
  					lowerRank[i] = 0;
  				}
  				else
  				{
  					lowerRank[i] = upperRank[i+1] + 1;
  				}
  				upperRank[i] = lowerRank[i] + this.ranksPerGroup[i];
  			}
  			this.maxRank = upperRank[0];
  			var internalNodes = this.vertexMapper.getValues();
  			for (var i=0; i < internalNodes.length; i++)
  			{
  				internalNodes[i].temp[0] = -1;
  			}
  			while (startNodes.length > 0)
  			{
  				var internalNode = startNodes[0];
  				var layerDeterminingEdges;
  				var edgesToBeMarked;
  				layerDeterminingEdges = internalNode.connectsAsTarget;
  				edgesToBeMarked = internalNode.connectsAsSource;
  				var allEdgesScanned = true;
  				var minimumLayer = upperRank[0];
  				for (var i = 0; i < layerDeterminingEdges.length; i++)
  				{
  					var internalEdge = layerDeterminingEdges[i];
  					if (internalEdge.temp[0] == 5270620)
  					{
  						var otherNode = internalEdge.source;
  						minimumLayer = Math.min(minimumLayer, otherNode.temp[0] - 1);
  					}
  					else
  					{
  						allEdgesScanned = false;
  						break;
  					}
  				}
  				if (allEdgesScanned)
  				{
  					if (minimumLayer > upperRank[internalNode.swimlaneIndex])
  					{
  						minimumLayer = upperRank[internalNode.swimlaneIndex];
  					}
  					internalNode.temp[0] = minimumLayer;
  					if (edgesToBeMarked != null)
  					{
  						for (var i = 0; i < edgesToBeMarked.length; i++)
  						{
  							var internalEdge = edgesToBeMarked[i];
  							internalEdge.temp[0] = 5270620;
  							var otherNode = internalEdge.target;
  							if (otherNode.temp[0] == -1)
  							{
  								startNodes.push(otherNode);
  								otherNode.temp[0] = -2;
  							}
  						}
  					}
  					startNodes.shift();
  				}
  				else
  				{
  					var removedCell = startNodes.shift();
  					startNodes.push(internalNode);
  					if (removedCell == internalNode && startNodes.length == 1)
  					{
  						break;
  					}
  				}
  			}
  		};
  		mxSwimlaneModel.prototype.maxChainDfs = function(parent, root, connectingEdge, seen, chainCount)
  		{
  			if (root != null)
  			{
  				var rootId = mxCellPath.create(root.cell);
  				if (seen[rootId] == null)
  				{
  					seen[rootId] = root;
  					var slIndex = root.swimlaneIndex;
  					if (this.ranksPerGroup[slIndex] == null || this.ranksPerGroup[slIndex] < chainCount)
  					{
  						this.ranksPerGroup[slIndex] = chainCount;
  					}
  					var outgoingEdges = root.connectsAsSource.slice();
  					for (var i = 0; i < outgoingEdges.length; i++)
  					{
  						var internalEdge = outgoingEdges[i];
  						var targetNode = internalEdge.target;
  						if (root.swimlaneIndex < targetNode.swimlaneIndex)
  						{
  							this.maxChainDfs(root, targetNode, internalEdge, mxUtils.clone(seen, null , true), 0);
  						}
  						else if (root.swimlaneIndex == targetNode.swimlaneIndex)
  						{
  							this.maxChainDfs(root, targetNode, internalEdge, mxUtils.clone(seen, null , true), chainCount + 1);
  						}
  					}
  				}
  			}
  		};
  		mxSwimlaneModel.prototype.fixRanks = function()
  		{
  			var rankList = [];
  			this.ranks = [];
  			for (var i = 0; i < this.maxRank + 1; i++)
  			{
  				rankList[i] = [];
  				this.ranks[i] = rankList[i];
  			}
  			var rootsArray = null;
  			if (this.roots != null)
  			{
  				var oldRootsArray = this.roots;
  				rootsArray = [];
  				for (var i = 0; i < oldRootsArray.length; i++)
  				{
  					var cell = oldRootsArray[i];
  					var internalNode = this.vertexMapper.get(cell);
  					rootsArray[i] = internalNode;
  				}
  			}
  			this.visit(function(parent, node, edge, layer, seen)
  			{
  				if (seen == 0 && node.maxRank < 0 && node.minRank < 0)
  				{
  					rankList[node.temp[0]].push(node);
  					node.maxRank = node.temp[0];
  					node.minRank = node.temp[0];
  					node.temp[0] = rankList[node.maxRank].length - 1;
  				}
  				if (parent != null && edge != null)
  				{
  					var parentToCellRankDifference = parent.maxRank - node.maxRank;
  					if (parentToCellRankDifference > 1)
  					{
  						edge.maxRank = parent.maxRank;
  						edge.minRank = node.maxRank;
  						edge.temp = [];
  						edge.x = [];
  						edge.y = [];
  						for (var i = edge.minRank + 1; i < edge.maxRank; i++)
  						{
  							rankList[i].push(edge);
  							edge.setGeneralPurposeVariable(i, rankList[i]
  									.length - 1);
  						}
  					}
  				}
  			}, rootsArray, false, null);
  		};
  		mxSwimlaneModel.prototype.visit = function(visitor, dfsRoots, trackAncestors, seenNodes)
  		{
  			if (dfsRoots != null)
  			{
  				for (var i = 0; i < dfsRoots.length; i++)
  				{
  					var internalNode = dfsRoots[i];
  					if (internalNode != null)
  					{
  						if (seenNodes == null)
  						{
  							seenNodes = new Object();
  						}
  						if (trackAncestors)
  						{
  							internalNode.hashCode = [];
  							internalNode.hashCode[0] = this.dfsCount;
  							internalNode.hashCode[1] = i;
  							this.extendedDfs(null, internalNode, null, visitor, seenNodes,
  									internalNode.hashCode, i, 0);
  						}
  						else
  						{
  							this.dfs(null, internalNode, null, visitor, seenNodes, 0);
  						}
  					}
  				}
  				this.dfsCount++;
  			}
  		};
  		mxSwimlaneModel.prototype.dfs = function(parent, root, connectingEdge, visitor, seen, layer)
  		{
  			if (root != null)
  			{
  				var rootId = root.id;
  				if (seen[rootId] == null)
  				{
  					seen[rootId] = root;
  					visitor(parent, root, connectingEdge, layer, 0);
  					var outgoingEdges = root.connectsAsSource.slice();
  					for (var i = 0; i< outgoingEdges.length; i++)
  					{
  						var internalEdge = outgoingEdges[i];
  						var targetNode = internalEdge.target;
  						this.dfs(root, targetNode, internalEdge, visitor, seen,
  								layer + 1);
  					}
  				}
  				else
  				{
  					visitor(parent, root, connectingEdge, layer, 1);
  				}
  			}
  		};
  		mxSwimlaneModel.prototype.extendedDfs = function(parent, root, connectingEdge, visitor, seen, ancestors, childHash, layer)
  		{
  			if (root != null)
  			{
  				if (parent != null)
  				{
  					if (root.hashCode == null ||
  						root.hashCode[0] != parent.hashCode[0])
  					{
  						var hashCodeLength = parent.hashCode.length + 1;
  						root.hashCode = parent.hashCode.slice();
  						root.hashCode[hashCodeLength - 1] = childHash;
  					}
  				}
  				var rootId = root.id;
  				if (seen[rootId] == null)
  				{
  					seen[rootId] = root;
  					visitor(parent, root, connectingEdge, layer, 0);
  					var outgoingEdges = root.connectsAsSource.slice();
  					var incomingEdges = root.connectsAsTarget.slice();
  					for (var i = 0; i < outgoingEdges.length; i++)
  					{
  						var internalEdge = outgoingEdges[i];
  						var targetNode = internalEdge.target;
  						if (root.swimlaneIndex <= targetNode.swimlaneIndex)
  						{
  							this.extendedDfs(root, targetNode, internalEdge, visitor, seen,
  									root.hashCode, i, layer + 1);
  						}
  					}
  					for (var i = 0; i < incomingEdges.length; i++)
  					{
  						var internalEdge = incomingEdges[i];
  						var targetNode = internalEdge.source;
  						if (root.swimlaneIndex < targetNode.swimlaneIndex)
  						{
  							this.extendedDfs(root, targetNode, internalEdge, visitor, seen,
  									root.hashCode, i, layer + 1);
  						}
  					}
  				}
  				else
  				{
  					visitor(parent, root, connectingEdge, layer, 1);
  				}
  			}
  		};
  		__mxOutput.mxSwimlaneModel = typeof mxSwimlaneModel !== 'undefined' ? mxSwimlaneModel : undefined;
  		function mxHierarchicalLayoutStage() { }		mxHierarchicalLayoutStage.prototype.execute = function(parent) { };
  		__mxOutput.mxHierarchicalLayoutStage = typeof mxHierarchicalLayoutStage !== 'undefined' ? mxHierarchicalLayoutStage : undefined;
  		function mxMedianHybridCrossingReduction(layout)
  		{
  			this.layout = layout;
  		}		mxMedianHybridCrossingReduction.prototype = new mxHierarchicalLayoutStage();
  		mxMedianHybridCrossingReduction.prototype.constructor = mxMedianHybridCrossingReduction;
  		mxMedianHybridCrossingReduction.prototype.layout = null;
  		mxMedianHybridCrossingReduction.prototype.maxIterations = 24;
  		mxMedianHybridCrossingReduction.prototype.nestedBestRanks = null;
  		mxMedianHybridCrossingReduction.prototype.currentBestCrossings = 0;
  		mxMedianHybridCrossingReduction.prototype.iterationsWithoutImprovement = 0;
  		mxMedianHybridCrossingReduction.prototype.maxNoImprovementIterations = 2;
  		mxMedianHybridCrossingReduction.prototype.execute = function(parent)
  		{
  			var model = this.layout.getModel();
  			this.nestedBestRanks = [];
  			for (var i = 0; i < model.ranks.length; i++)
  			{
  				this.nestedBestRanks[i] = model.ranks[i].slice();
  			}
  			var iterationsWithoutImprovement = 0;
  			var currentBestCrossings = this.calculateCrossings(model);
  			for (var i = 0; i < this.maxIterations &&
  				iterationsWithoutImprovement < this.maxNoImprovementIterations; i++)
  			{
  				this.weightedMedian(i, model);
  				this.transpose(i, model);
  				var candidateCrossings = this.calculateCrossings(model);
  				if (candidateCrossings < currentBestCrossings)
  				{
  					currentBestCrossings = candidateCrossings;
  					iterationsWithoutImprovement = 0;
  					for (var j = 0; j < this.nestedBestRanks.length; j++)
  					{
  						var rank = model.ranks[j];
  						for (var k = 0; k < rank.length; k++)
  						{
  							var cell = rank[k];
  							this.nestedBestRanks[j][cell.getGeneralPurposeVariable(j)] = cell;
  						}
  					}
  				}
  				else
  				{
  					iterationsWithoutImprovement++;
  					for (var j = 0; j < this.nestedBestRanks.length; j++)
  					{
  						var rank = model.ranks[j];
  						for (var k = 0; k < rank.length; k++)
  						{
  							var cell = rank[k];
  							cell.setGeneralPurposeVariable(j, k);
  						}
  					}
  				}
  				if (currentBestCrossings == 0)
  				{
  					break;
  				}
  			}
  			var ranks = [];
  			var rankList = [];
  			for (var i = 0; i < model.maxRank + 1; i++)
  			{
  				rankList[i] = [];
  				ranks[i] = rankList[i];
  			}
  			for (var i = 0; i < this.nestedBestRanks.length; i++)
  			{
  				for (var j = 0; j < this.nestedBestRanks[i].length; j++)
  				{
  					rankList[i].push(this.nestedBestRanks[i][j]);
  				}
  			}
  			model.ranks = ranks;
  		};
  		mxMedianHybridCrossingReduction.prototype.calculateCrossings = function(model)
  		{
  			var numRanks = model.ranks.length;
  			var totalCrossings = 0;
  			for (var i = 1; i < numRanks; i++)
  			{
  				totalCrossings += this.calculateRankCrossing(i, model);
  			}
  			return totalCrossings;
  		};
  		mxMedianHybridCrossingReduction.prototype.calculateRankCrossing = function(i, model)
  		{
  			var totalCrossings = 0;
  			var rank = model.ranks[i];
  			var previousRank = model.ranks[i - 1];
  			var tmpIndices = [];
  			for (var j = 0; j < rank.length; j++)
  			{
  				var node = rank[j];
  				var rankPosition = node.getGeneralPurposeVariable(i);
  				var connectedCells = node.getPreviousLayerConnectedCells(i);
  				var nodeIndices = [];
  				for (var k = 0; k < connectedCells.length; k++)
  				{
  					var connectedNode = connectedCells[k];
  					var otherCellRankPosition = connectedNode.getGeneralPurposeVariable(i - 1);
  					nodeIndices.push(otherCellRankPosition);
  				}
  				nodeIndices.sort(function(x, y) { return x - y; });
  				tmpIndices[rankPosition] = nodeIndices;
  			}
  			var indices = [];
  			for (var j = 0; j < tmpIndices.length; j++)
  			{
  				indices = indices.concat(tmpIndices[j]);
  			}
  			var firstIndex = 1;
  			while (firstIndex < previousRank.length)
  			{
  				firstIndex <<= 1;
  			}
  			var treeSize = 2 * firstIndex - 1;
  			firstIndex -= 1;
  			var tree = [];
  			for (var j = 0; j < treeSize; ++j)
  			{
  				tree[j] = 0;
  			}
  			for (var j = 0; j < indices.length; j++)
  			{
  				var index = indices[j];
  			    var treeIndex = index + firstIndex;
  			    ++tree[treeIndex];
  			    while (treeIndex > 0)
  			    {
  			    	if (treeIndex % 2)
  			    	{
  			    		totalCrossings += tree[treeIndex + 1];
  			    	}
  			    	treeIndex = (treeIndex - 1) >> 1;
  			    	++tree[treeIndex];
  			    }
  			}
  			return totalCrossings;
  		};
  		mxMedianHybridCrossingReduction.prototype.transpose = function(mainLoopIteration, model)
  		{
  			var improved = true;
  			var count = 0;
  			var maxCount = 10;
  			while (improved && count++ < maxCount)
  			{
  				var nudge = mainLoopIteration % 2 == 1 && count % 2 == 1;
  				improved = false;
  				for (var i = 0; i < model.ranks.length; i++)
  				{
  					var rank = model.ranks[i];
  					var orderedCells = [];
  					for (var j = 0; j < rank.length; j++)
  					{
  						var cell = rank[j];
  						var tempRank = cell.getGeneralPurposeVariable(i);
  						if (tempRank < 0)
  						{
  							tempRank = j;
  						}
  						orderedCells[tempRank] = cell;
  					}
  					var leftCellAboveConnections = null;
  					var leftCellBelowConnections = null;
  					var rightCellAboveConnections = null;
  					var rightCellBelowConnections = null;
  					var leftAbovePositions = null;
  					var leftBelowPositions = null;
  					var rightAbovePositions = null;
  					var rightBelowPositions = null;
  					var leftCell = null;
  					var rightCell = null;
  					for (var j = 0; j < (rank.length - 1); j++)
  					{
  						if (j == 0)
  						{
  							leftCell = orderedCells[j];
  							leftCellAboveConnections = leftCell
  									.getNextLayerConnectedCells(i);
  							leftCellBelowConnections = leftCell
  									.getPreviousLayerConnectedCells(i);
  							leftAbovePositions = [];
  							leftBelowPositions = [];
  							for (var k = 0; k < leftCellAboveConnections.length; k++)
  							{
  								leftAbovePositions[k] = leftCellAboveConnections[k].getGeneralPurposeVariable(i + 1);
  							}
  							for (var k = 0; k < leftCellBelowConnections.length; k++)
  							{
  								leftBelowPositions[k] = leftCellBelowConnections[k].getGeneralPurposeVariable(i - 1);
  							}
  						}
  						else
  						{
  							leftCellAboveConnections = rightCellAboveConnections;
  							leftCellBelowConnections = rightCellBelowConnections;
  							leftAbovePositions = rightAbovePositions;
  							leftBelowPositions = rightBelowPositions;
  							leftCell = rightCell;
  						}
  						rightCell = orderedCells[j + 1];
  						rightCellAboveConnections = rightCell
  								.getNextLayerConnectedCells(i);
  						rightCellBelowConnections = rightCell
  								.getPreviousLayerConnectedCells(i);
  						rightAbovePositions = [];
  						rightBelowPositions = [];
  						for (var k = 0; k < rightCellAboveConnections.length; k++)
  						{
  							rightAbovePositions[k] = rightCellAboveConnections[k].getGeneralPurposeVariable(i + 1);
  						}
  						for (var k = 0; k < rightCellBelowConnections.length; k++)
  						{
  							rightBelowPositions[k] = rightCellBelowConnections[k].getGeneralPurposeVariable(i - 1);
  						}
  						var totalCurrentCrossings = 0;
  						var totalSwitchedCrossings = 0;
  						for (var k = 0; k < leftAbovePositions.length; k++)
  						{
  							for (var ik = 0; ik < rightAbovePositions.length; ik++)
  							{
  								if (leftAbovePositions[k] > rightAbovePositions[ik])
  								{
  									totalCurrentCrossings++;
  								}
  								if (leftAbovePositions[k] < rightAbovePositions[ik])
  								{
  									totalSwitchedCrossings++;
  								}
  							}
  						}
  						for (var k = 0; k < leftBelowPositions.length; k++)
  						{
  							for (var ik = 0; ik < rightBelowPositions.length; ik++)
  							{
  								if (leftBelowPositions[k] > rightBelowPositions[ik])
  								{
  									totalCurrentCrossings++;
  								}
  								if (leftBelowPositions[k] < rightBelowPositions[ik])
  								{
  									totalSwitchedCrossings++;
  								}
  							}
  						}
  						if ((totalSwitchedCrossings < totalCurrentCrossings) ||
  							(totalSwitchedCrossings == totalCurrentCrossings &&
  							nudge))
  						{
  							var temp = leftCell.getGeneralPurposeVariable(i);
  							leftCell.setGeneralPurposeVariable(i, rightCell
  									.getGeneralPurposeVariable(i));
  							rightCell.setGeneralPurposeVariable(i, temp);
  							rightCellAboveConnections = leftCellAboveConnections;
  							rightCellBelowConnections = leftCellBelowConnections;
  							rightAbovePositions = leftAbovePositions;
  							rightBelowPositions = leftBelowPositions;
  							rightCell = leftCell;
  							if (!nudge)
  							{
  								improved = true;
  							}
  						}
  					}
  				}
  			}
  		};
  		mxMedianHybridCrossingReduction.prototype.weightedMedian = function(iteration, model)
  		{
  			var downwardSweep = (iteration % 2 == 0);
  			if (downwardSweep)
  			{
  				for (var j = model.maxRank - 1; j >= 0; j--)
  				{
  					this.medianRank(j, downwardSweep);
  				}
  			}
  			else
  			{
  				for (var j = 1; j < model.maxRank; j++)
  				{
  					this.medianRank(j, downwardSweep);
  				}
  			}
  		};
  		mxMedianHybridCrossingReduction.prototype.medianRank = function(rankValue, downwardSweep)
  		{
  			var numCellsForRank = this.nestedBestRanks[rankValue].length;
  			var medianValues = [];
  			var reservedPositions = [];
  			for (var i = 0; i < numCellsForRank; i++)
  			{
  				var cell = this.nestedBestRanks[rankValue][i];
  				var sorterEntry = new MedianCellSorter();
  				sorterEntry.cell = cell;
  				var nextLevelConnectedCells;
  				if (downwardSweep)
  				{
  					nextLevelConnectedCells = cell
  							.getNextLayerConnectedCells(rankValue);
  				}
  				else
  				{
  					nextLevelConnectedCells = cell
  							.getPreviousLayerConnectedCells(rankValue);
  				}
  				var nextRankValue;
  				if (downwardSweep)
  				{
  					nextRankValue = rankValue + 1;
  				}
  				else
  				{
  					nextRankValue = rankValue - 1;
  				}
  				if (nextLevelConnectedCells != null
  						&& nextLevelConnectedCells.length != 0)
  				{
  					sorterEntry.medianValue = this.medianValue(
  							nextLevelConnectedCells, nextRankValue);
  					medianValues.push(sorterEntry);
  				}
  				else
  				{
  					reservedPositions[cell.getGeneralPurposeVariable(rankValue)] = true;
  				}
  			}
  			medianValues.sort(MedianCellSorter.prototype.compare);
  			for (var i = 0; i < numCellsForRank; i++)
  			{
  				if (reservedPositions[i] == null)
  				{
  					var cell = medianValues.shift().cell;
  					cell.setGeneralPurposeVariable(rankValue, i);
  				}
  			}
  		};
  		mxMedianHybridCrossingReduction.prototype.medianValue = function(connectedCells, rankValue)
  		{
  			var medianValues = [];
  			var arrayCount = 0;
  			for (var i = 0; i < connectedCells.length; i++)
  			{
  				var cell = connectedCells[i];
  				medianValues[arrayCount++] = cell.getGeneralPurposeVariable(rankValue);
  			}
  			medianValues.sort(function(a,b){return a - b;});
  			if (arrayCount % 2 == 1)
  			{
  				return medianValues[Math.floor(arrayCount / 2)];
  			}
  			else if (arrayCount == 2)
  			{
  				return ((medianValues[0] + medianValues[1]) / 2.0);
  			}
  			else
  			{
  				var medianPoint = arrayCount / 2;
  				var leftMedian = medianValues[medianPoint - 1] - medianValues[0];
  				var rightMedian = medianValues[arrayCount - 1]
  						- medianValues[medianPoint];
  				return (medianValues[medianPoint - 1] * rightMedian + medianValues[medianPoint]
  						* leftMedian)
  						/ (leftMedian + rightMedian);
  			}
  		};
  		function MedianCellSorter()
  		{
  		}		MedianCellSorter.prototype.medianValue = 0;
  		MedianCellSorter.prototype.cell = false;
  		MedianCellSorter.prototype.compare = function(a, b)
  		{
  			if (a != null && b != null)
  			{
  				if (b.medianValue > a.medianValue)
  				{
  					return -1;
  				}
  				else if (b.medianValue < a.medianValue)
  				{
  					return 1;
  				}
  				else
  				{
  					return 0;
  				}
  			}
  			else
  			{
  				return 0;
  			}
  		};
  		__mxOutput.mxMedianHybridCrossingReduction = typeof mxMedianHybridCrossingReduction !== 'undefined' ? mxMedianHybridCrossingReduction : undefined;
  		function mxMinimumCycleRemover(layout)
  		{
  			this.layout = layout;
  		}		mxMinimumCycleRemover.prototype = new mxHierarchicalLayoutStage();
  		mxMinimumCycleRemover.prototype.constructor = mxMinimumCycleRemover;
  		mxMinimumCycleRemover.prototype.layout = null;
  		mxMinimumCycleRemover.prototype.execute = function(parent)
  		{
  			var model = this.layout.getModel();
  			var seenNodes = new Object();
  			var unseenNodesArray = model.vertexMapper.getValues();
  			var unseenNodes = new Object();
  			for (var i = 0; i < unseenNodesArray.length; i++)
  			{
  				unseenNodes[unseenNodesArray[i].id] = unseenNodesArray[i];
  			}
  			var rootsArray = null;
  			if (model.roots != null)
  			{
  				var modelRoots = model.roots;
  				rootsArray = [];
  				for (var i = 0; i < modelRoots.length; i++)
  				{
  					rootsArray[i] = model.vertexMapper.get(modelRoots[i]);
  				}
  			}
  			model.visit(function(parent, node, connectingEdge, layer, seen)
  			{
  				if (node.isAncestor(parent))
  				{
  					connectingEdge.invert();
  					mxUtils.remove(connectingEdge, parent.connectsAsSource);
  					parent.connectsAsTarget.push(connectingEdge);
  					mxUtils.remove(connectingEdge, node.connectsAsTarget);
  					node.connectsAsSource.push(connectingEdge);
  				}
  				seenNodes[node.id] = node;
  				delete unseenNodes[node.id];
  			}, rootsArray, true, null);
  			var seenNodesCopy = mxUtils.clone(seenNodes, null, true);
  			model.visit(function(parent, node, connectingEdge, layer, seen)
  			{
  				if (node.isAncestor(parent))
  				{
  					connectingEdge.invert();
  					mxUtils.remove(connectingEdge, parent.connectsAsSource);
  					node.connectsAsSource.push(connectingEdge);
  					parent.connectsAsTarget.push(connectingEdge);
  					mxUtils.remove(connectingEdge, node.connectsAsTarget);
  				}
  				seenNodes[node.id] = node;
  				delete unseenNodes[node.id];
  			}, unseenNodes, true, seenNodesCopy);
  		};
  		__mxOutput.mxMinimumCycleRemover = typeof mxMinimumCycleRemover !== 'undefined' ? mxMinimumCycleRemover : undefined;
  		function mxCoordinateAssignment(layout, intraCellSpacing, interRankCellSpacing,
  			orientation, initialX, parallelEdgeSpacing)
  		{
  			this.layout = layout;
  			this.intraCellSpacing = intraCellSpacing;
  			this.interRankCellSpacing = interRankCellSpacing;
  			this.orientation = orientation;
  			this.initialX = initialX;
  			this.parallelEdgeSpacing = parallelEdgeSpacing;
  		}		mxCoordinateAssignment.prototype = new mxHierarchicalLayoutStage();
  		mxCoordinateAssignment.prototype.constructor = mxCoordinateAssignment;
  		mxCoordinateAssignment.prototype.layout = null;
  		mxCoordinateAssignment.prototype.intraCellSpacing = 30;
  		mxCoordinateAssignment.prototype.interRankCellSpacing = 100;
  		mxCoordinateAssignment.prototype.parallelEdgeSpacing = 10;
  		mxCoordinateAssignment.prototype.maxIterations = 8;
  		mxCoordinateAssignment.prototype.prefHozEdgeSep = 5;
  		mxCoordinateAssignment.prototype.prefVertEdgeOff = 2;
  		mxCoordinateAssignment.prototype.minEdgeJetty = 12;
  		mxCoordinateAssignment.prototype.channelBuffer = 4;
  		mxCoordinateAssignment.prototype.jettyPositions = null;
  		mxCoordinateAssignment.prototype.orientation = mxConstants.DIRECTION_NORTH;
  		mxCoordinateAssignment.prototype.initialX = null;
  		mxCoordinateAssignment.prototype.limitX = null;
  		mxCoordinateAssignment.prototype.currentXDelta = null;
  		mxCoordinateAssignment.prototype.widestRank = null;
  		mxCoordinateAssignment.prototype.rankTopY = null;
  		mxCoordinateAssignment.prototype.rankBottomY = null;
  		mxCoordinateAssignment.prototype.widestRankValue = null;
  		mxCoordinateAssignment.prototype.rankWidths = null;
  		mxCoordinateAssignment.prototype.rankY = null;
  		mxCoordinateAssignment.prototype.fineTuning = true;
  		mxCoordinateAssignment.prototype.nextLayerConnectedCache = null;
  		mxCoordinateAssignment.prototype.previousLayerConnectedCache = null;
  		mxCoordinateAssignment.prototype.groupPadding = 10;
  		mxCoordinateAssignment.prototype.printStatus = function()
  		{
  			var model = this.layout.getModel();
  			mxLog.show();
  			mxLog.writeln('======Coord assignment debug=======');
  			for (var j = 0; j < model.ranks.length; j++)
  			{
  				mxLog.write('Rank ', j, ' : ' );
  				var rank = model.ranks[j];
  				for (var k = 0; k < rank.length; k++)
  				{
  					var cell = rank[k];
  					mxLog.write(cell.getGeneralPurposeVariable(j), '  ');
  				}
  				mxLog.writeln();
  			}
  			mxLog.writeln('====================================');
  		};
  		mxCoordinateAssignment.prototype.execute = function(parent)
  		{
  			this.jettyPositions = Object();
  			var model = this.layout.getModel();
  			this.currentXDelta = 0.0;
  			this.initialCoords(this.layout.getGraph(), model);
  			if (this.fineTuning)
  			{
  				this.minNode(model);
  			}
  			var bestXDelta = 100000000.0;
  			if (this.fineTuning)
  			{
  				for (var i = 0; i < this.maxIterations; i++)
  				{
  					if (i != 0)
  					{
  						this.medianPos(i, model);
  						this.minNode(model);
  					}
  					if (this.currentXDelta < bestXDelta)
  					{
  						for (var j = 0; j < model.ranks.length; j++)
  						{
  							var rank = model.ranks[j];
  							for (var k = 0; k < rank.length; k++)
  							{
  								var cell = rank[k];
  								cell.setX(j, cell.getGeneralPurposeVariable(j));
  							}
  						}
  						bestXDelta = this.currentXDelta;
  					}
  					else
  					{
  						for (var j = 0; j < model.ranks.length; j++)
  						{
  							var rank = model.ranks[j];
  							for (var k = 0; k < rank.length; k++)
  							{
  								var cell = rank[k];
  								cell.setGeneralPurposeVariable(j, cell.getX(j));
  							}
  						}
  					}
  					this.minPath(this.layout.getGraph(), model);
  					this.currentXDelta = 0;
  				}
  			}
  			this.setCellLocations(this.layout.getGraph(), model);
  		};
  		mxCoordinateAssignment.prototype.minNode = function(model)
  		{
  			var nodeList = [];
  			var map = new mxDictionary();
  			var rank = [];
  			for (var i = 0; i <= model.maxRank; i++)
  			{
  				rank[i] = model.ranks[i];
  				for (var j = 0; j < rank[i].length; j++)
  				{
  					var node = rank[i][j];
  					var nodeWrapper = new WeightedCellSorter(node, i);
  					nodeWrapper.rankIndex = j;
  					nodeWrapper.visited = true;
  					nodeList.push(nodeWrapper);
  					map.put(node, nodeWrapper);
  				}
  			}
  			var maxTries = nodeList.length * 10;
  			var count = 0;
  			var tolerance = 1;
  			while (nodeList.length > 0 && count <= maxTries)
  			{
  				var cellWrapper = nodeList.shift();
  				var cell = cellWrapper.cell;
  				var rankValue = cellWrapper.weightedValue;
  				var rankIndex = parseInt(cellWrapper.rankIndex);
  				var nextLayerConnectedCells = cell.getNextLayerConnectedCells(rankValue);
  				var previousLayerConnectedCells = cell.getPreviousLayerConnectedCells(rankValue);
  				var numNextLayerConnected = nextLayerConnectedCells.length;
  				var numPreviousLayerConnected = previousLayerConnectedCells.length;
  				var medianNextLevel = this.medianXValue(nextLayerConnectedCells,
  						rankValue + 1);
  				var medianPreviousLevel = this.medianXValue(previousLayerConnectedCells,
  						rankValue - 1);
  				var numConnectedNeighbours = numNextLayerConnected
  						+ numPreviousLayerConnected;
  				var currentPosition = cell.getGeneralPurposeVariable(rankValue);
  				var cellMedian = currentPosition;
  				if (numConnectedNeighbours > 0)
  				{
  					cellMedian = (medianNextLevel * numNextLayerConnected + medianPreviousLevel
  							* numPreviousLayerConnected)
  							/ numConnectedNeighbours;
  				}
  				var positionChanged = false;
  				if (cellMedian < currentPosition - tolerance)
  				{
  					if (rankIndex == 0)
  					{
  						cell.setGeneralPurposeVariable(rankValue, cellMedian);
  						positionChanged = true;
  					}
  					else
  					{
  						var leftCell = rank[rankValue][rankIndex - 1];
  						var leftLimit = leftCell
  								.getGeneralPurposeVariable(rankValue);
  						leftLimit = leftLimit + leftCell.width / 2
  								+ this.intraCellSpacing + cell.width / 2;
  						if (leftLimit < cellMedian)
  						{
  							cell.setGeneralPurposeVariable(rankValue, cellMedian);
  							positionChanged = true;
  						}
  						else if (leftLimit < cell
  								.getGeneralPurposeVariable(rankValue)
  								- tolerance)
  						{
  							cell.setGeneralPurposeVariable(rankValue, leftLimit);
  							positionChanged = true;
  						}
  					}
  				}
  				else if (cellMedian > currentPosition + tolerance)
  				{
  					var rankSize = rank[rankValue].length;
  					if (rankIndex == rankSize - 1)
  					{
  						cell.setGeneralPurposeVariable(rankValue, cellMedian);
  						positionChanged = true;
  					}
  					else
  					{
  						var rightCell = rank[rankValue][rankIndex + 1];
  						var rightLimit = rightCell
  								.getGeneralPurposeVariable(rankValue);
  						rightLimit = rightLimit - rightCell.width / 2
  								- this.intraCellSpacing - cell.width / 2;
  						if (rightLimit > cellMedian)
  						{
  							cell.setGeneralPurposeVariable(rankValue, cellMedian);
  							positionChanged = true;
  						}
  						else if (rightLimit > cell
  								.getGeneralPurposeVariable(rankValue)
  								+ tolerance)
  						{
  							cell.setGeneralPurposeVariable(rankValue, rightLimit);
  							positionChanged = true;
  						}
  					}
  				}
  				if (positionChanged)
  				{
  					for (var i = 0; i < nextLayerConnectedCells.length; i++)
  					{
  						var connectedCell = nextLayerConnectedCells[i];
  						var connectedCellWrapper = map.get(connectedCell);
  						if (connectedCellWrapper != null)
  						{
  							if (connectedCellWrapper.visited == false)
  							{
  								connectedCellWrapper.visited = true;
  								nodeList.push(connectedCellWrapper);
  							}
  						}
  					}
  					for (var i = 0; i < previousLayerConnectedCells.length; i++)
  					{
  						var connectedCell = previousLayerConnectedCells[i];
  						var connectedCellWrapper = map.get(connectedCell);
  						if (connectedCellWrapper != null)
  						{
  							if (connectedCellWrapper.visited == false)
  							{
  								connectedCellWrapper.visited = true;
  								nodeList.push(connectedCellWrapper);
  							}
  						}
  					}
  				}
  				cellWrapper.visited = false;
  				count++;
  			}
  		};
  		mxCoordinateAssignment.prototype.medianPos = function(i, model)
  		{
  			var downwardSweep = (i % 2 == 0);
  			if (downwardSweep)
  			{
  				for (var j = model.maxRank; j > 0; j--)
  				{
  					this.rankMedianPosition(j - 1, model, j);
  				}
  			}
  			else
  			{
  				for (var j = 0; j < model.maxRank - 1; j++)
  				{
  					this.rankMedianPosition(j + 1, model, j);
  				}
  			}
  		};
  		mxCoordinateAssignment.prototype.rankMedianPosition = function(rankValue, model, nextRankValue)
  		{
  			var rank = model.ranks[rankValue];
  			var weightedValues = [];
  			var cellMap = new Object();
  			for (var i = 0; i < rank.length; i++)
  			{
  				var currentCell = rank[i];
  				weightedValues[i] = new WeightedCellSorter();
  				weightedValues[i].cell = currentCell;
  				weightedValues[i].rankIndex = i;
  				cellMap[currentCell.id] = weightedValues[i];
  				var nextLayerConnectedCells = null;
  				if (nextRankValue < rankValue)
  				{
  					nextLayerConnectedCells = currentCell
  							.getPreviousLayerConnectedCells(rankValue);
  				}
  				else
  				{
  					nextLayerConnectedCells = currentCell
  							.getNextLayerConnectedCells(rankValue);
  				}
  				weightedValues[i].weightedValue = this.calculatedWeightedValue(
  						currentCell, nextLayerConnectedCells);
  			}
  			weightedValues.sort(WeightedCellSorter.prototype.compare);
  			for (var i = 0; i < weightedValues.length; i++)
  			{
  				var numConnectionsNextLevel = 0;
  				var cell = weightedValues[i].cell;
  				var nextLayerConnectedCells = null;
  				var medianNextLevel = 0;
  				if (nextRankValue < rankValue)
  				{
  					nextLayerConnectedCells = cell.getPreviousLayerConnectedCells(
  							rankValue).slice();
  				}
  				else
  				{
  					nextLayerConnectedCells = cell.getNextLayerConnectedCells(
  							rankValue).slice();
  				}
  				if (nextLayerConnectedCells != null)
  				{
  					numConnectionsNextLevel = nextLayerConnectedCells.length;
  					if (numConnectionsNextLevel > 0)
  					{
  						medianNextLevel = this.medianXValue(nextLayerConnectedCells,
  								nextRankValue);
  					}
  					else
  					{
  						medianNextLevel = cell.getGeneralPurposeVariable(rankValue);
  					}
  				}
  				var leftBuffer = 0.0;
  				var leftLimit = -1e8;
  				for (var j = weightedValues[i].rankIndex - 1; j >= 0;)
  				{
  					var weightedValue = cellMap[rank[j].id];
  					if (weightedValue != null)
  					{
  						var leftCell = weightedValue.cell;
  						if (weightedValue.visited)
  						{
  							leftLimit = leftCell
  									.getGeneralPurposeVariable(rankValue)
  									+ leftCell.width
  									/ 2.0
  									+ this.intraCellSpacing
  									+ leftBuffer + cell.width / 2.0;
  							j = -1;
  						}
  						else
  						{
  							leftBuffer += leftCell.width + this.intraCellSpacing;
  							j--;
  						}
  					}
  				}
  				var rightBuffer = 0.0;
  				var rightLimit = 100000000.0;
  				for (var j = weightedValues[i].rankIndex + 1; j < weightedValues.length;)
  				{
  					var weightedValue = cellMap[rank[j].id];
  					if (weightedValue != null)
  					{
  						var rightCell = weightedValue.cell;
  						if (weightedValue.visited)
  						{
  							rightLimit = rightCell
  									.getGeneralPurposeVariable(rankValue)
  									- rightCell.width
  									/ 2.0
  									- this.intraCellSpacing
  									- rightBuffer - cell.width / 2.0;
  							j = weightedValues.length;
  						}
  						else
  						{
  							rightBuffer += rightCell.width + this.intraCellSpacing;
  							j++;
  						}
  					}
  				}
  				if (medianNextLevel >= leftLimit && medianNextLevel <= rightLimit)
  				{
  					cell.setGeneralPurposeVariable(rankValue, medianNextLevel);
  				}
  				else if (medianNextLevel < leftLimit)
  				{
  					cell.setGeneralPurposeVariable(rankValue, leftLimit);
  					this.currentXDelta += leftLimit - medianNextLevel;
  				}
  				else if (medianNextLevel > rightLimit)
  				{
  					cell.setGeneralPurposeVariable(rankValue, rightLimit);
  					this.currentXDelta += medianNextLevel - rightLimit;
  				}
  				weightedValues[i].visited = true;
  			}
  		};
  		mxCoordinateAssignment.prototype.calculatedWeightedValue = function(currentCell, collection)
  		{
  			var totalWeight = 0;
  			for (var i = 0; i < collection.length; i++)
  			{
  				var cell = collection[i];
  				if (currentCell.isVertex() && cell.isVertex())
  				{
  					totalWeight++;
  				}
  				else if (currentCell.isEdge() && cell.isEdge())
  				{
  					totalWeight += 8;
  				}
  				else
  				{
  					totalWeight += 2;
  				}
  			}
  			return totalWeight;
  		};
  		mxCoordinateAssignment.prototype.medianXValue = function(connectedCells, rankValue)
  		{
  			if (connectedCells.length == 0)
  			{
  				return 0;
  			}
  			var medianValues = [];
  			for (var i = 0; i < connectedCells.length; i++)
  			{
  				medianValues[i] = connectedCells[i].getGeneralPurposeVariable(rankValue);
  			}
  			medianValues.sort(function(a,b){return a - b;});
  			if (connectedCells.length % 2 == 1)
  			{
  				return medianValues[Math.floor(connectedCells.length / 2)];
  			}
  			else
  			{
  				var medianPoint = connectedCells.length / 2;
  				var leftMedian = medianValues[medianPoint - 1];
  				var rightMedian = medianValues[medianPoint];
  				return ((leftMedian + rightMedian) / 2);
  			}
  		};
  		mxCoordinateAssignment.prototype.initialCoords = function(facade, model)
  		{
  			this.calculateWidestRank(facade, model);
  			for (var i = this.widestRank; i >= 0; i--)
  			{
  				if (i < model.maxRank)
  				{
  					this.rankCoordinates(i, facade, model);
  				}
  			}
  			for (var i = this.widestRank+1; i <= model.maxRank; i++)
  			{
  				if (i > 0)
  				{
  					this.rankCoordinates(i, facade, model);
  				}
  			}
  		};
  		mxCoordinateAssignment.prototype.rankCoordinates = function(rankValue, graph, model)
  		{
  			var rank = model.ranks[rankValue];
  			var maxY = 0.0;
  			var localX = this.initialX + (this.widestRankValue - this.rankWidths[rankValue])
  					/ 2;
  			var boundsWarning = false;
  			for (var i = 0; i < rank.length; i++)
  			{
  				var node = rank[i];
  				if (node.isVertex())
  				{
  					var bounds = this.layout.getVertexBounds(node.cell);
  					if (bounds != null)
  					{
  						if (this.orientation == mxConstants.DIRECTION_NORTH ||
  							this.orientation == mxConstants.DIRECTION_SOUTH)
  						{
  							node.width = bounds.width;
  							node.height = bounds.height;
  						}
  						else
  						{
  							node.width = bounds.height;
  							node.height = bounds.width;
  						}
  					}
  					else
  					{
  						boundsWarning = true;
  					}
  					maxY = Math.max(maxY, node.height);
  				}
  				else if (node.isEdge())
  				{
  					var numEdges = 1;
  					if (node.edges != null)
  					{
  						numEdges = node.edges.length;
  					}
  					else
  					{
  						mxLog.warn('edge.edges is null');
  					}
  					node.width = (numEdges - 1) * this.parallelEdgeSpacing;
  				}
  				localX += node.width / 2.0;
  				node.setX(rankValue, localX);
  				node.setGeneralPurposeVariable(rankValue, localX);
  				localX += node.width / 2.0;
  				localX += this.intraCellSpacing;
  			}
  			if (boundsWarning == true)
  			{
  				mxLog.warn('At least one cell has no bounds');
  			}
  		};
  		mxCoordinateAssignment.prototype.calculateWidestRank = function(graph, model)
  		{
  			var y = -this.interRankCellSpacing;
  			var lastRankMaxCellHeight = 0.0;
  			this.rankWidths = [];
  			this.rankY = [];
  			for (var rankValue = model.maxRank; rankValue >= 0; rankValue--)
  			{
  				var maxCellHeight = 0.0;
  				var rank = model.ranks[rankValue];
  				var localX = this.initialX;
  				var boundsWarning = false;
  				for (var i = 0; i < rank.length; i++)
  				{
  					var node = rank[i];
  					if (node.isVertex())
  					{
  						var bounds = this.layout.getVertexBounds(node.cell);
  						if (bounds != null)
  						{
  							if (this.orientation == mxConstants.DIRECTION_NORTH ||
  								this.orientation == mxConstants.DIRECTION_SOUTH)
  							{
  								node.width = bounds.width;
  								node.height = bounds.height;
  							}
  							else
  							{
  								node.width = bounds.height;
  								node.height = bounds.width;
  							}
  						}
  						else
  						{
  							boundsWarning = true;
  						}
  						maxCellHeight = Math.max(maxCellHeight, node.height);
  					}
  					else if (node.isEdge())
  					{
  						var numEdges = 1;
  						if (node.edges != null)
  						{
  							numEdges = node.edges.length;
  						}
  						else
  						{
  							mxLog.warn('edge.edges is null');
  						}
  						node.width = (numEdges - 1) * this.parallelEdgeSpacing;
  					}
  					localX += node.width / 2.0;
  					node.setX(rankValue, localX);
  					node.setGeneralPurposeVariable(rankValue, localX);
  					localX += node.width / 2.0;
  					localX += this.intraCellSpacing;
  					if (localX > this.widestRankValue)
  					{
  						this.widestRankValue = localX;
  						this.widestRank = rankValue;
  					}
  					this.rankWidths[rankValue] = localX;
  				}
  				if (boundsWarning == true)
  				{
  					mxLog.warn('At least one cell has no bounds');
  				}
  				this.rankY[rankValue] = y;
  				var distanceToNextRank = maxCellHeight / 2.0
  						+ lastRankMaxCellHeight / 2.0 + this.interRankCellSpacing;
  				lastRankMaxCellHeight = maxCellHeight;
  				if (this.orientation == mxConstants.DIRECTION_NORTH ||
  					this.orientation == mxConstants.DIRECTION_WEST)
  				{
  					y += distanceToNextRank;
  				}
  				else
  				{
  					y -= distanceToNextRank;
  				}
  				for (var i = 0; i < rank.length; i++)
  				{
  					var cell = rank[i];
  					cell.setY(rankValue, y);
  				}
  			}
  		};
  		mxCoordinateAssignment.prototype.minPath = function(graph, model)
  		{
  			var edges = model.edgeMapper.getValues();
  			for (var j = 0; j < edges.length; j++)
  			{
  				var cell = edges[j];
  				if (cell.maxRank - cell.minRank - 1 < 1)
  				{
  					continue;
  				}
  				var referenceX = cell
  						.getGeneralPurposeVariable(cell.minRank + 1);
  				var edgeStraight = true;
  				var refSegCount = 0;
  				for (var i = cell.minRank + 2; i < cell.maxRank; i++)
  				{
  					var x = cell.getGeneralPurposeVariable(i);
  					if (referenceX != x)
  					{
  						edgeStraight = false;
  						referenceX = x;
  					}
  					else
  					{
  						refSegCount++;
  					}
  				}
  				if (!edgeStraight)
  				{
  					var upSegCount = 0;
  					var downSegCount = 0;
  					var upXPositions = [];
  					var downXPositions = [];
  					var currentX = cell.getGeneralPurposeVariable(cell.minRank + 1);
  					for (var i = cell.minRank + 1; i < cell.maxRank - 1; i++)
  					{
  						var nextX = cell.getX(i + 1);
  						if (currentX == nextX)
  						{
  							upXPositions[i - cell.minRank - 1] = currentX;
  							upSegCount++;
  						}
  						else if (this.repositionValid(model, cell, i + 1, currentX))
  						{
  							upXPositions[i - cell.minRank - 1] = currentX;
  							upSegCount++;
  						}
  						else
  						{
  							upXPositions[i - cell.minRank - 1] = nextX;
  							currentX = nextX;
  						}
  					}
  					currentX = cell.getX(i);
  					for (var i = cell.maxRank - 1; i > cell.minRank + 1; i--)
  					{
  						var nextX = cell.getX(i - 1);
  						if (currentX == nextX)
  						{
  							downXPositions[i - cell.minRank - 2] = currentX;
  							downSegCount++;
  						}
  						else if (this.repositionValid(model, cell, i - 1, currentX))
  						{
  							downXPositions[i - cell.minRank - 2] = currentX;
  							downSegCount++;
  						}
  						else
  						{
  							downXPositions[i - cell.minRank - 2] = cell.getX(i-1);
  							currentX = nextX;
  						}
  					}
  					if (downSegCount > refSegCount || upSegCount > refSegCount)
  					{
  						if (downSegCount >= upSegCount)
  						{
  							for (var i = cell.maxRank - 2; i > cell.minRank; i--)
  							{
  								cell.setX(i, downXPositions[i - cell.minRank - 1]);
  							}
  						}
  						else if (upSegCount > downSegCount)
  						{
  							for (var i = cell.minRank + 2; i < cell.maxRank; i++)
  							{
  								cell.setX(i, upXPositions[i - cell.minRank - 2]);
  							}
  						}
  						else
  						;
  					}
  				}
  			}
  		};
  		mxCoordinateAssignment.prototype.repositionValid = function(model, cell, rank, position)
  		{
  			var rankArray = model.ranks[rank];
  			var rankIndex = -1;
  			for (var i = 0; i < rankArray.length; i++)
  			{
  				if (cell == rankArray[i])
  				{
  					rankIndex = i;
  					break;
  				}
  			}
  			if (rankIndex < 0)
  			{
  				return false;
  			}
  			var currentX = cell.getGeneralPurposeVariable(rank);
  			if (position < currentX)
  			{
  				if (rankIndex == 0)
  				{
  					return true;
  				}
  				var leftCell = rankArray[rankIndex - 1];
  				var leftLimit = leftCell.getGeneralPurposeVariable(rank);
  				leftLimit = leftLimit + leftCell.width / 2
  						+ this.intraCellSpacing + cell.width / 2;
  				if (leftLimit <= position)
  				{
  					return true;
  				}
  				else
  				{
  					return false;
  				}
  			}
  			else if (position > currentX)
  			{
  				if (rankIndex == rankArray.length - 1)
  				{
  					return true;
  				}
  				var rightCell = rankArray[rankIndex + 1];
  				var rightLimit = rightCell.getGeneralPurposeVariable(rank);
  				rightLimit = rightLimit - rightCell.width / 2
  						- this.intraCellSpacing - cell.width / 2;
  				if (rightLimit >= position)
  				{
  					return true;
  				}
  				else
  				{
  					return false;
  				}
  			}
  			return true;
  		};
  		mxCoordinateAssignment.prototype.setCellLocations = function(graph, model)
  		{
  			this.rankTopY = [];
  			this.rankBottomY = [];
  			for (var i = 0; i < model.ranks.length; i++)
  			{
  				this.rankTopY[i] = Number.MAX_VALUE;
  				this.rankBottomY[i] = -Number.MAX_VALUE;
  			}
  			var vertices = model.vertexMapper.getValues();
  			for (var i = 0; i < vertices.length; i++)
  			{
  				this.setVertexLocation(vertices[i]);
  			}
  			if (this.layout.edgeStyle == mxHierarchicalEdgeStyle.ORTHOGONAL
  					|| this.layout.edgeStyle == mxHierarchicalEdgeStyle.POLYLINE
  					|| this.layout.edgeStyle == mxHierarchicalEdgeStyle.CURVE)
  			{
  				this.localEdgeProcessing(model);
  			}
  			var edges = model.edgeMapper.getValues();
  			for (var i = 0; i < edges.length; i++)
  			{
  				this.setEdgePosition(edges[i]);
  			}
  		};
  		mxCoordinateAssignment.prototype.localEdgeProcessing = function(model)
  		{
  			for (var rankIndex = 0; rankIndex < model.ranks.length; rankIndex++)
  			{
  				var rank = model.ranks[rankIndex];
  				for (var cellIndex = 0; cellIndex < rank.length; cellIndex++)
  				{
  					var cell = rank[cellIndex];
  					if (cell.isVertex())
  					{
  						var currentCells = cell.getPreviousLayerConnectedCells(rankIndex);
  						var currentRank = rankIndex - 1;
  						for (var k = 0; k < 2; k++)
  						{
  							if (currentRank > -1
  									&& currentRank < model.ranks.length
  									&& currentCells != null
  									&& currentCells.length > 0)
  							{
  								var sortedCells = [];
  								for (var j = 0; j < currentCells.length; j++)
  								{
  									var sorter = new WeightedCellSorter(
  											currentCells[j], currentCells[j].getX(currentRank));
  									sortedCells.push(sorter);
  								}
  								sortedCells.sort(WeightedCellSorter.prototype.compare);
  								var leftLimit = cell.x[0] - cell.width / 2;
  								var rightLimit = leftLimit + cell.width;
  								var connectedEdgeCount = 0;
  								var connectedEdges = [];
  								for (var j = 0; j < sortedCells.length; j++)
  								{
  									var innerCell = sortedCells[j].cell;
  									var connections;
  									if (innerCell.isVertex())
  									{
  										if (k == 0)
  										{
  											connections = cell.connectsAsSource;
  										}
  										else
  										{
  											connections = cell.connectsAsTarget;
  										}
  										for (var connIndex = 0; connIndex < connections.length; connIndex++)
  										{
  											if (connections[connIndex].source == innerCell
  													|| connections[connIndex].target == innerCell)
  											{
  												connectedEdgeCount += connections[connIndex].edges
  														.length;
  												connectedEdges.push(connections[connIndex]);
  											}
  										}
  									}
  									else
  									{
  										connectedEdgeCount += innerCell.edges.length;
  										connectedEdges.push(innerCell);
  									}
  								}
  								var requiredWidth = (connectedEdgeCount + 1)
  										* this.prefHozEdgeSep;
  								if (cell.width > requiredWidth
  										+ (2 * this.prefHozEdgeSep))
  								{
  									leftLimit += this.prefHozEdgeSep;
  									rightLimit -= this.prefHozEdgeSep;
  								}
  								var availableWidth = rightLimit - leftLimit;
  								var edgeSpacing = availableWidth / connectedEdgeCount;
  								var currentX = leftLimit + edgeSpacing / 2.0;
  								var currentYOffset = this.minEdgeJetty - this.prefVertEdgeOff;
  								for (var j = 0; j < connectedEdges.length; j++)
  								{
  									var numActualEdges = connectedEdges[j].edges
  											.length;
  									var pos = this.jettyPositions[connectedEdges[j].ids[0]];
  									if (pos == null)
  									{
  										pos = [];
  										this.jettyPositions[connectedEdges[j].ids[0]] = pos;
  									}
  									if (j < connectedEdgeCount / 2)
  									{
  										currentYOffset += this.prefVertEdgeOff;
  									}
  									else if (j > connectedEdgeCount / 2)
  									{
  										currentYOffset -= this.prefVertEdgeOff;
  									}
  									for (var m = 0; m < numActualEdges; m++)
  									{
  										pos[m * 4 + k * 2] = currentX;
  										currentX += edgeSpacing;
  										pos[m * 4 + k * 2 + 1] = currentYOffset;
  									}
  								}
  							}
  							currentCells = cell.getNextLayerConnectedCells(rankIndex);
  							currentRank = rankIndex + 1;
  						}
  					}
  				}
  			}
  		};
  		mxCoordinateAssignment.prototype.setEdgePosition = function(cell)
  		{
  			var offsetX = 0;
  			if (cell.temp[0] != 101207)
  			{
  				var maxRank = cell.maxRank;
  				var minRank = cell.minRank;
  				if (maxRank == minRank)
  				{
  					maxRank = cell.source.maxRank;
  					minRank = cell.target.minRank;
  				}
  				var parallelEdgeCount = 0;
  				var jettys = this.jettyPositions[cell.ids[0]];
  				var source = cell.isReversed ? cell.target.cell : cell.source.cell;
  				var graph = this.layout.graph;
  				var layoutReversed = this.orientation == mxConstants.DIRECTION_EAST
  						|| this.orientation == mxConstants.DIRECTION_SOUTH;
  				for (var i = 0; i < cell.edges.length; i++)
  				{
  					var realEdge = cell.edges[i];
  					var realSource = this.layout.getVisibleTerminal(realEdge, true);
  					var newPoints = [];
  					var reversed = cell.isReversed;
  					if (realSource != source)
  					{
  						reversed = !reversed;
  					}
  					if (jettys != null)
  					{
  						var arrayOffset = reversed ? 2 : 0;
  						var y = reversed ?
  								(layoutReversed ? this.rankBottomY[minRank] : this.rankTopY[minRank]) :
  									(layoutReversed ? this.rankTopY[maxRank] : this.rankBottomY[maxRank]);
  						var jetty = jettys[parallelEdgeCount * 4 + 1 + arrayOffset];
  						if (reversed != layoutReversed)
  						{
  							jetty = -jetty;
  						}
  						y += jetty;
  						var x = jettys[parallelEdgeCount * 4 + arrayOffset];
  						var modelSource = graph.model.getTerminal(realEdge, true);
  						if (this.layout.isPort(modelSource) && graph.model.getParent(modelSource) == realSource)
  						{
  							var state = graph.view.getState(modelSource);
  							if (state != null)
  							{
  								x = state.x;
  							}
  							else
  							{
  								x = realSource.geometry.x + cell.source.width * modelSource.geometry.x;
  							}
  						}
  						if (this.orientation == mxConstants.DIRECTION_NORTH
  								|| this.orientation == mxConstants.DIRECTION_SOUTH)
  						{
  							newPoints.push(new mxPoint(x, y));
  							if (this.layout.edgeStyle == mxHierarchicalEdgeStyle.CURVE)
  							{
  								newPoints.push(new mxPoint(x, y + jetty));
  							}
  						}
  						else
  						{
  							newPoints.push(new mxPoint(y, x));
  							if (this.layout.edgeStyle == mxHierarchicalEdgeStyle.CURVE)
  							{
  								newPoints.push(new mxPoint(y + jetty, x));
  							}
  						}
  					}
  					var loopStart = cell.x.length - 1;
  					var loopLimit = -1;
  					var loopDelta = -1;
  					var currentRank = cell.maxRank - 1;
  					if (reversed)
  					{
  						loopStart = 0;
  						loopLimit = cell.x.length;
  						loopDelta = 1;
  						currentRank = cell.minRank + 1;
  					}
  					for (var j = loopStart; (cell.maxRank != cell.minRank) && j != loopLimit; j += loopDelta)
  					{
  						var positionX = cell.x[j] + offsetX;
  						var topChannelY = (this.rankTopY[currentRank] + this.rankBottomY[currentRank + 1]) / 2.0;
  						var bottomChannelY = (this.rankTopY[currentRank - 1] + this.rankBottomY[currentRank]) / 2.0;
  						if (reversed)
  						{
  							var tmp = topChannelY;
  							topChannelY = bottomChannelY;
  							bottomChannelY = tmp;
  						}
  						if (this.orientation == mxConstants.DIRECTION_NORTH ||
  							this.orientation == mxConstants.DIRECTION_SOUTH)
  						{
  							newPoints.push(new mxPoint(positionX, topChannelY));
  							newPoints.push(new mxPoint(positionX, bottomChannelY));
  						}
  						else
  						{
  							newPoints.push(new mxPoint(topChannelY, positionX));
  							newPoints.push(new mxPoint(bottomChannelY, positionX));
  						}
  						this.limitX = Math.max(this.limitX, positionX);
  						currentRank += loopDelta;
  					}
  					if (jettys != null)
  					{
  						var arrayOffset = reversed ? 2 : 0;
  						var rankY = reversed ?
  								(layoutReversed ? this.rankTopY[maxRank] : this.rankBottomY[maxRank]) :
  									(layoutReversed ? this.rankBottomY[minRank] : this.rankTopY[minRank]);
  						var jetty = jettys[parallelEdgeCount * 4 + 3 - arrayOffset];
  						if (reversed != layoutReversed)
  						{
  							jetty = -jetty;
  						}
  						var y = rankY - jetty;
  						var x = jettys[parallelEdgeCount * 4 + 2 - arrayOffset];
  						var modelTarget = graph.model.getTerminal(realEdge, false);
  						var realTarget = this.layout.getVisibleTerminal(realEdge, false);
  						if (this.layout.isPort(modelTarget) && graph.model.getParent(modelTarget) == realTarget)
  						{
  							var state = graph.view.getState(modelTarget);
  							if (state != null)
  							{
  								x = state.x;
  							}
  							else
  							{
  								x = realTarget.geometry.x + cell.target.width * modelTarget.geometry.x;
  							}
  						}
  						if (this.orientation == mxConstants.DIRECTION_NORTH ||
  								this.orientation == mxConstants.DIRECTION_SOUTH)
  						{
  							if (this.layout.edgeStyle == mxHierarchicalEdgeStyle.CURVE)
  							{
  								newPoints.push(new mxPoint(x, y - jetty));
  							}
  							newPoints.push(new mxPoint(x, y));
  						}
  						else
  						{
  							if (this.layout.edgeStyle == mxHierarchicalEdgeStyle.CURVE)
  							{
  								newPoints.push(new mxPoint(y - jetty, x));
  							}
  							newPoints.push(new mxPoint(y, x));
  						}
  					}
  					if (cell.isReversed)
  					{
  						this.processReversedEdge(cell, realEdge);
  					}
  					this.layout.setEdgePoints(realEdge, newPoints);
  					if (offsetX == 0.0)
  					{
  						offsetX = this.parallelEdgeSpacing;
  					}
  					else if (offsetX > 0)
  					{
  						offsetX = -offsetX;
  					}
  					else
  					{
  						offsetX = -offsetX + this.parallelEdgeSpacing;
  					}
  					parallelEdgeCount++;
  				}
  				cell.temp[0] = 101207;
  			}
  		};
  		mxCoordinateAssignment.prototype.setVertexLocation = function(cell)
  		{
  			var realCell = cell.cell;
  			var positionX = cell.x[0] - cell.width / 2;
  			var positionY = cell.y[0] - cell.height / 2;
  			this.rankTopY[cell.minRank] = Math.min(this.rankTopY[cell.minRank], positionY);
  			this.rankBottomY[cell.minRank] = Math.max(this.rankBottomY[cell.minRank],
  					positionY + cell.height);
  			if (this.orientation == mxConstants.DIRECTION_NORTH ||
  				this.orientation == mxConstants.DIRECTION_SOUTH)
  			{
  				this.layout.setVertexLocation(realCell, positionX, positionY);
  			}
  			else
  			{
  				this.layout.setVertexLocation(realCell, positionY, positionX);
  			}
  			this.limitX = Math.max(this.limitX, positionX + cell.width);
  		};
  		mxCoordinateAssignment.prototype.processReversedEdge = function(graph, model)
  		{
  		};
  		__mxOutput.mxCoordinateAssignment = typeof mxCoordinateAssignment !== 'undefined' ? mxCoordinateAssignment : undefined;
  		function mxSwimlaneOrdering(layout)
  		{
  			this.layout = layout;
  		}		mxSwimlaneOrdering.prototype = new mxHierarchicalLayoutStage();
  		mxSwimlaneOrdering.prototype.constructor = mxSwimlaneOrdering;
  		mxSwimlaneOrdering.prototype.layout = null;
  		mxSwimlaneOrdering.prototype.execute = function(parent)
  		{
  			var model = this.layout.getModel();
  			var seenNodes = new Object();
  			var unseenNodes = mxUtils.clone(model.vertexMapper, null, true);
  			var rootsArray = null;
  			if (model.roots != null)
  			{
  				var modelRoots = model.roots;
  				rootsArray = [];
  				for (var i = 0; i < modelRoots.length; i++)
  				{
  					rootsArray[i] = model.vertexMapper.get(modelRoots[i]);
  				}
  			}
  			model.visit(function(parent, node, connectingEdge, layer, seen)
  			{
  				var isAncestor = parent != null && parent.swimlaneIndex == node.swimlaneIndex && node.isAncestor(parent);
  				var reversedOverSwimlane = parent != null && connectingEdge != null &&
  								parent.swimlaneIndex < node.swimlaneIndex && connectingEdge.source == node;
  				if (isAncestor)
  				{
  					connectingEdge.invert();
  					mxUtils.remove(connectingEdge, parent.connectsAsSource);
  					node.connectsAsSource.push(connectingEdge);
  					parent.connectsAsTarget.push(connectingEdge);
  					mxUtils.remove(connectingEdge, node.connectsAsTarget);
  				}
  				else if (reversedOverSwimlane)
  				{
  					connectingEdge.invert();
  					mxUtils.remove(connectingEdge, parent.connectsAsTarget);
  					node.connectsAsTarget.push(connectingEdge);
  					parent.connectsAsSource.push(connectingEdge);
  					mxUtils.remove(connectingEdge, node.connectsAsSource);
  				}
  				var cellId = mxCellPath.create(node.cell);
  				seenNodes[cellId] = node;
  				delete unseenNodes[cellId];
  			}, rootsArray, true, null);
  		};
  		__mxOutput.mxSwimlaneOrdering = typeof mxSwimlaneOrdering !== 'undefined' ? mxSwimlaneOrdering : undefined;
  		function mxHierarchicalLayout(graph, orientation, deterministic)
  		{
  			mxGraphLayout.call(this, graph);
  			this.orientation = (orientation != null) ? orientation : mxConstants.DIRECTION_NORTH;
  			this.deterministic = (deterministic != null) ? deterministic : true;
  		}		var mxHierarchicalEdgeStyle =
  		{
  			ORTHOGONAL: 1,
  			POLYLINE: 2,
  			CURVE: 4
  		};
  		mxHierarchicalLayout.prototype = new mxGraphLayout();
  		mxHierarchicalLayout.prototype.constructor = mxHierarchicalLayout;
  		mxHierarchicalLayout.prototype.roots = null;
  		mxHierarchicalLayout.prototype.resizeParent = false;
  		mxHierarchicalLayout.prototype.maintainParentLocation = false;
  		mxHierarchicalLayout.prototype.moveParent = false;
  		mxHierarchicalLayout.prototype.parentBorder = 0;
  		mxHierarchicalLayout.prototype.intraCellSpacing = 30;
  		mxHierarchicalLayout.prototype.interRankCellSpacing = 100;
  		mxHierarchicalLayout.prototype.interHierarchySpacing = 60;
  		mxHierarchicalLayout.prototype.parallelEdgeSpacing = 10;
  		mxHierarchicalLayout.prototype.orientation = mxConstants.DIRECTION_NORTH;
  		mxHierarchicalLayout.prototype.fineTuning = true;
  		mxHierarchicalLayout.prototype.tightenToSource = true;
  		mxHierarchicalLayout.prototype.disableEdgeStyle = true;
  		mxHierarchicalLayout.prototype.traverseAncestors = true;
  		mxHierarchicalLayout.prototype.model = null;
  		mxHierarchicalLayout.prototype.edgesCache = null;
  		mxHierarchicalLayout.prototype.edgeSourceTermCache = null;
  		mxHierarchicalLayout.prototype.edgesTargetTermCache = null;
  		mxHierarchicalLayout.prototype.edgeStyle = mxHierarchicalEdgeStyle.POLYLINE;
  		mxHierarchicalLayout.prototype.getModel = function()
  		{
  			return this.model;
  		};
  		mxHierarchicalLayout.prototype.execute = function(parent, roots)
  		{
  			this.parent = parent;
  			var model = this.graph.model;
  			this.edgesCache = new mxDictionary();
  			this.edgeSourceTermCache = new mxDictionary();
  			this.edgesTargetTermCache = new mxDictionary();
  			if (roots != null && !(roots instanceof Array))
  			{
  				roots = [roots];
  			}
  			if (roots == null && parent == null)
  			{
  				return;
  			}
  			this.parentX = null;
  			this.parentY = null;
  			if (parent != this.root && model.isVertex(parent) != null && this.maintainParentLocation)
  			{
  				var geo = this.graph.getCellGeometry(parent);
  				if (geo != null)
  				{
  					this.parentX = geo.x;
  					this.parentY = geo.y;
  				}
  			}
  			if (roots != null)
  			{
  				var rootsCopy = [];
  				for (var i = 0; i < roots.length; i++)
  				{
  					var ancestor = parent != null ? model.isAncestor(parent, roots[i]) : true;
  					if (ancestor && model.isVertex(roots[i]))
  					{
  						rootsCopy.push(roots[i]);
  					}
  				}
  				this.roots = rootsCopy;
  			}
  			model.beginUpdate();
  			try
  			{
  				this.run(parent);
  				if (this.resizeParent && !this.graph.isCellCollapsed(parent))
  				{
  					this.graph.updateGroupBounds([parent], this.parentBorder, this.moveParent);
  				}
  				if (this.parentX != null && this.parentY != null)
  				{
  					var geo = this.graph.getCellGeometry(parent);
  					if (geo != null)
  					{
  						geo = geo.clone();
  						geo.x = this.parentX;
  						geo.y = this.parentY;
  						model.setGeometry(parent, geo);
  					}
  				}
  			}
  			finally
  			{
  				model.endUpdate();
  			}
  		};
  		mxHierarchicalLayout.prototype.findRoots = function(parent, vertices)
  		{
  			var roots = [];
  			if (parent != null && vertices != null)
  			{
  				var model = this.graph.model;
  				var best = null;
  				var maxDiff = -1e5;
  				for (var i in vertices)
  				{
  					var cell = vertices[i];
  					if (model.isVertex(cell) && this.graph.isCellVisible(cell))
  					{
  						var conns = this.getEdges(cell);
  						var fanOut = 0;
  						var fanIn = 0;
  						for (var k = 0; k < conns.length; k++)
  						{
  							var src = this.getVisibleTerminal(conns[k], true);
  							if (src == cell)
  							{
  								fanOut++;
  							}
  							else
  							{
  								fanIn++;
  							}
  						}
  						if (fanIn == 0 && fanOut > 0)
  						{
  							roots.push(cell);
  						}
  						var diff = fanOut - fanIn;
  						if (diff > maxDiff)
  						{
  							maxDiff = diff;
  							best = cell;
  						}
  					}
  				}
  				if (roots.length == 0 && best != null)
  				{
  					roots.push(best);
  				}
  			}
  			return roots;
  		};
  		mxHierarchicalLayout.prototype.getEdges = function(cell)
  		{
  			var cachedEdges = this.edgesCache.get(cell);
  			if (cachedEdges != null)
  			{
  				return cachedEdges;
  			}
  			var model = this.graph.model;
  			var edges = [];
  			var isCollapsed = this.graph.isCellCollapsed(cell);
  			var childCount = model.getChildCount(cell);
  			for (var i = 0; i < childCount; i++)
  			{
  				var child = model.getChildAt(cell, i);
  				if (this.isPort(child))
  				{
  					edges = edges.concat(model.getEdges(child, true, true));
  				}
  				else if (isCollapsed || !this.graph.isCellVisible(child))
  				{
  					edges = edges.concat(model.getEdges(child, true, true));
  				}
  			}
  			edges = edges.concat(model.getEdges(cell, true, true));
  			var result = [];
  			for (var i = 0; i < edges.length; i++)
  			{
  				var source = this.getVisibleTerminal(edges[i], true);
  				var target = this.getVisibleTerminal(edges[i], false);
  				if ((source == target) ||
  						((source != target) &&
  								((target == cell && (this.parent == null || this.isAncestor(this.parent, source, this.traverseAncestors))) ||
  								 	(source == cell && (this.parent == null || this.isAncestor(this.parent, target, this.traverseAncestors))))))
  				{
  					result.push(edges[i]);
  				}
  			}
  			this.edgesCache.put(cell, result);
  			return result;
  		};
  		mxHierarchicalLayout.prototype.getVisibleTerminal = function(edge, source)
  		{
  			var terminalCache = this.edgesTargetTermCache;
  			if (source)
  			{
  				terminalCache = this.edgeSourceTermCache;
  			}
  			var term = terminalCache.get(edge);
  			if (term != null)
  			{
  				return term;
  			}
  			var state = this.graph.view.getState(edge);
  			var terminal = (state != null) ? state.getVisibleTerminal(source) : this.graph.view.getVisibleTerminal(edge, source);
  			if (terminal == null)
  			{
  				terminal = (state != null) ? state.getVisibleTerminal(source) : this.graph.view.getVisibleTerminal(edge, source);
  			}
  			if (terminal != null)
  			{
  				if (this.isPort(terminal))
  				{
  					terminal = this.graph.model.getParent(terminal);
  				}
  				terminalCache.put(edge, terminal);
  			}
  			return terminal;
  		};
  		mxHierarchicalLayout.prototype.run = function(parent)
  		{
  			var hierarchyVertices = [];
  			var allVertexSet = [];
  			if (this.roots == null && parent != null)
  			{
  				var filledVertexSet = Object();
  				this.filterDescendants(parent, filledVertexSet);
  				this.roots = [];
  				var filledVertexSetEmpty = true;
  				for (var key in filledVertexSet)
  				{
  					if (filledVertexSet[key] != null)
  					{
  						filledVertexSetEmpty = false;
  						break;
  					}
  				}
  				while (!filledVertexSetEmpty)
  				{
  					var candidateRoots = this.findRoots(parent, filledVertexSet);
  					for (var i = 0; i < candidateRoots.length; i++)
  					{
  						var vertexSet = Object();
  						hierarchyVertices.push(vertexSet);
  						this.traverse(candidateRoots[i], true, null, allVertexSet, vertexSet,
  								hierarchyVertices, filledVertexSet);
  					}
  					for (var i = 0; i < candidateRoots.length; i++)
  					{
  						this.roots.push(candidateRoots[i]);
  					}
  					filledVertexSetEmpty = true;
  					for (var key in filledVertexSet)
  					{
  						if (filledVertexSet[key] != null)
  						{
  							filledVertexSetEmpty = false;
  							break;
  						}
  					}
  				}
  			}
  			else
  			{
  				for (var i = 0; i < this.roots.length; i++)
  				{
  					var vertexSet = Object();
  					hierarchyVertices.push(vertexSet);
  					this.traverse(this.roots[i], true, null, allVertexSet, vertexSet,
  							hierarchyVertices, null);
  				}
  			}
  			var initialX = 0;
  			for (var i = 0; i < hierarchyVertices.length; i++)
  			{
  				var vertexSet = hierarchyVertices[i];
  				var tmp = [];
  				for (var key in vertexSet)
  				{
  					tmp.push(vertexSet[key]);
  				}
  				this.model = new mxGraphHierarchyModel(this, tmp, this.roots,
  					parent, this.tightenToSource);
  				this.cycleStage(parent);
  				this.layeringStage();
  				this.crossingStage(parent);
  				initialX = this.placementStage(initialX, parent);
  			}
  		};
  		mxHierarchicalLayout.prototype.filterDescendants = function(cell, result)
  		{
  			var model = this.graph.model;
  			if (model.isVertex(cell) && cell != this.parent && this.graph.isCellVisible(cell))
  			{
  				result[mxObjectIdentity.get(cell)] = cell;
  			}
  			if (this.traverseAncestors || cell == this.parent
  					&& this.graph.isCellVisible(cell))
  			{
  				var childCount = model.getChildCount(cell);
  				for (var i = 0; i < childCount; i++)
  				{
  					var child = model.getChildAt(cell, i);
  					if (!this.isPort(child))
  					{
  						this.filterDescendants(child, result);
  					}
  				}
  			}
  		};
  		mxHierarchicalLayout.prototype.isPort = function(cell)
  		{
  			if (cell != null && cell.geometry != null)
  			{
  				return cell.geometry.relative;
  			}
  			else
  			{
  				return false;
  			}
  		};
  		mxHierarchicalLayout.prototype.getEdgesBetween = function(source, target, directed)
  		{
  			directed = (directed != null) ? directed : false;
  			var edges = this.getEdges(source);
  			var result = [];
  			for (var i = 0; i < edges.length; i++)
  			{
  				var src = this.getVisibleTerminal(edges[i], true);
  				var trg = this.getVisibleTerminal(edges[i], false);
  				if ((src == source && trg == target) || (!directed && src == target && trg == source))
  				{
  					result.push(edges[i]);
  				}
  			}
  			return result;
  		};
  		mxHierarchicalLayout.prototype.traverse = function(vertex, directed, edge, allVertices, currentComp,
  													hierarchyVertices, filledVertexSet)
  		{
  			if (vertex != null && allVertices != null)
  			{
  				var vertexID = mxObjectIdentity.get(vertex);
  				if ((allVertices[vertexID] == null)
  						&& (filledVertexSet == null ? true : filledVertexSet[vertexID] != null))
  				{
  					if (currentComp[vertexID] == null)
  					{
  						currentComp[vertexID] = vertex;
  					}
  					if (allVertices[vertexID] == null)
  					{
  						allVertices[vertexID] = vertex;
  					}
  					if (filledVertexSet !== null)
  					{
  						delete filledVertexSet[vertexID];
  					}
  					var edges = this.getEdges(vertex);
  					var edgeIsSource = [];
  					for (var i = 0; i < edges.length; i++)
  					{
  						edgeIsSource[i] = (this.getVisibleTerminal(edges[i], true) == vertex);
  					}
  					for (var i = 0; i < edges.length; i++)
  					{
  						if (!directed || edgeIsSource[i])
  						{
  							var next = this.getVisibleTerminal(edges[i], !edgeIsSource[i]);
  							var netCount = 1;
  							for (var j = 0; j < edges.length; j++)
  							{
  								if (j == i)
  								{
  									continue;
  								}
  								else
  								{
  									var isSource2 = edgeIsSource[j];
  									var otherTerm = this.getVisibleTerminal(edges[j], !isSource2);
  									if (otherTerm == next)
  									{
  										if (isSource2)
  										{
  											netCount++;
  										}
  										else
  										{
  											netCount--;
  										}
  									}
  								}
  							}
  							if (netCount >= 0)
  							{
  								currentComp = this.traverse(next, directed, edges[i], allVertices,
  									currentComp, hierarchyVertices,
  									filledVertexSet);
  							}
  						}
  					}
  				}
  				else
  				{
  					if (currentComp[vertexID] == null)
  					{
  						for (var i = 0; i < hierarchyVertices.length; i++)
  						{
  							var comp = hierarchyVertices[i];
  							if (comp[vertexID] != null)
  							{
  								for (var key in comp)
  								{
  									currentComp[key] = comp[key];
  								}
  								hierarchyVertices.splice(i, 1);
  								return currentComp;
  							}
  						}
  					}
  				}
  			}
  			return currentComp;
  		};
  		mxHierarchicalLayout.prototype.cycleStage = function(parent)
  		{
  			var cycleStage = new mxMinimumCycleRemover(this);
  			cycleStage.execute(parent);
  		};
  		mxHierarchicalLayout.prototype.layeringStage = function()
  		{
  			this.model.initialRank();
  			this.model.fixRanks();
  		};
  		mxHierarchicalLayout.prototype.crossingStage = function(parent)
  		{
  			var crossingStage = new mxMedianHybridCrossingReduction(this);
  			crossingStage.execute(parent);
  		};
  		mxHierarchicalLayout.prototype.placementStage = function(initialX, parent)
  		{
  			var placementStage = new mxCoordinateAssignment(this, this.intraCellSpacing,
  					this.interRankCellSpacing, this.orientation, initialX,
  					this.parallelEdgeSpacing);
  			placementStage.fineTuning = this.fineTuning;
  			placementStage.execute(parent);
  			return placementStage.limitX + this.interHierarchySpacing;
  		};
  		__mxOutput.mxHierarchicalLayout = typeof mxHierarchicalLayout !== 'undefined' ? mxHierarchicalLayout : undefined;
  		function mxSwimlaneLayout(graph, orientation, deterministic)
  		{
  			mxGraphLayout.call(this, graph);
  			this.orientation = (orientation != null) ? orientation : mxConstants.DIRECTION_NORTH;
  			this.deterministic = (deterministic != null) ? deterministic : true;
  		}		mxSwimlaneLayout.prototype = new mxGraphLayout();
  		mxSwimlaneLayout.prototype.constructor = mxSwimlaneLayout;
  		mxSwimlaneLayout.prototype.roots = null;
  		mxSwimlaneLayout.prototype.swimlanes = null;
  		mxSwimlaneLayout.prototype.dummyVertexWidth = 50;
  		mxSwimlaneLayout.prototype.resizeParent = false;
  		mxSwimlaneLayout.prototype.maintainParentLocation = false;
  		mxSwimlaneLayout.prototype.moveParent = false;
  		mxSwimlaneLayout.prototype.parentBorder = 30;
  		mxSwimlaneLayout.prototype.intraCellSpacing = 30;
  		mxSwimlaneLayout.prototype.interRankCellSpacing = 100;
  		mxSwimlaneLayout.prototype.interHierarchySpacing = 60;
  		mxSwimlaneLayout.prototype.parallelEdgeSpacing = 10;
  		mxSwimlaneLayout.prototype.orientation = mxConstants.DIRECTION_NORTH;
  		mxSwimlaneLayout.prototype.fineTuning = true;
  		mxSwimlaneLayout.prototype.tightenToSource = true;
  		mxSwimlaneLayout.prototype.disableEdgeStyle = true;
  		mxSwimlaneLayout.prototype.traverseAncestors = true;
  		mxSwimlaneLayout.prototype.model = null;
  		mxSwimlaneLayout.prototype.edgesCache = null;
  		mxHierarchicalLayout.prototype.edgeSourceTermCache = null;
  		mxHierarchicalLayout.prototype.edgesTargetTermCache = null;
  		mxHierarchicalLayout.prototype.edgeStyle = mxHierarchicalEdgeStyle.POLYLINE;
  		mxSwimlaneLayout.prototype.getModel = function()
  		{
  			return this.model;
  		};
  		mxSwimlaneLayout.prototype.execute = function(parent, swimlanes)
  		{
  			this.parent = parent;
  			var model = this.graph.model;
  			this.edgesCache = new mxDictionary();
  			this.edgeSourceTermCache = new mxDictionary();
  			this.edgesTargetTermCache = new mxDictionary();
  			if (swimlanes == null || swimlanes.length < 1)
  			{
  				return;
  			}
  			if (parent == null)
  			{
  				parent = model.getParent(swimlanes[0]);
  			}
  			this.parentX = null;
  			this.parentY = null;
  			if (parent != this.root && model.isVertex(parent) != null && this.maintainParentLocation)
  			{
  				var geo = this.graph.getCellGeometry(parent);
  				if (geo != null)
  				{
  					this.parentX = geo.x;
  					this.parentY = geo.y;
  				}
  			}
  			this.swimlanes = swimlanes;
  			var dummyVertices = [];
  			for (var i = 0; i < swimlanes.length; i++)
  			{
  				var children = this.graph.getChildCells(swimlanes[i]);
  				if (children == null || children.length == 0)
  				{
  					var vertex = this.graph.insertVertex(swimlanes[i], null, null, 0, 0, this.dummyVertexWidth, 0);
  					dummyVertices.push(vertex);
  				}
  			}
  			model.beginUpdate();
  			try
  			{
  				this.run(parent);
  				if (this.resizeParent && !this.graph.isCellCollapsed(parent))
  				{
  					this.graph.updateGroupBounds([parent], this.parentBorder, this.moveParent);
  				}
  				if (this.parentX != null && this.parentY != null)
  				{
  					var geo = this.graph.getCellGeometry(parent);
  					if (geo != null)
  					{
  						geo = geo.clone();
  						geo.x = this.parentX;
  						geo.y = this.parentY;
  						model.setGeometry(parent, geo);
  					}
  				}
  				this.graph.removeCells(dummyVertices);
  			}
  			finally
  			{
  				model.endUpdate();
  			}
  		};
  		mxSwimlaneLayout.prototype.updateGroupBounds = function()
  		{
  			var cells = [];
  			var model = this.model;
  			for (var key in model.edgeMapper)
  			{
  				var edge = model.edgeMapper[key];
  				for (var i = 0; i < edge.edges.length; i++)
  				{
  					cells.push(edge.edges[i]);
  				}
  			}
  			var layoutBounds = this.graph.getBoundingBoxFromGeometry(cells, true);
  			var childBounds = [];
  			for (var i = 0; i < this.swimlanes.length; i++)
  			{
  				var lane = this.swimlanes[i];
  				var geo = this.graph.getCellGeometry(lane);
  				if (geo != null)
  				{
  					var children = this.graph.getChildCells(lane);
  					var size = (this.graph.isSwimlane(lane)) ?
  							this.graph.getStartSize(lane) : new mxRectangle();
  					var bounds = this.graph.getBoundingBoxFromGeometry(children);
  					childBounds[i] = bounds;
  					var childrenY = bounds.y + geo.y - size.height - this.parentBorder;
  					var maxChildrenY = bounds.y + geo.y + bounds.height;
  					if (layoutBounds == null)
  					{
  						layoutBounds = new mxRectangle(0, childrenY, 0, maxChildrenY - childrenY);
  					}
  					else
  					{
  						layoutBounds.y = Math.min(layoutBounds.y, childrenY);
  						var maxY = Math.max(layoutBounds.y + layoutBounds.height, maxChildrenY);
  						layoutBounds.height = maxY - layoutBounds.y;
  					}
  				}
  			}
  			for (var i = 0; i < this.swimlanes.length; i++)
  			{
  				var lane = this.swimlanes[i];
  				var geo = this.graph.getCellGeometry(lane);
  				if (geo != null)
  				{
  					var children = this.graph.getChildCells(lane);
  					var size = (this.graph.isSwimlane(lane)) ?
  							this.graph.getStartSize(lane) : new mxRectangle();
  					var newGeo = geo.clone();
  					var leftGroupBorder = (i == 0) ? this.parentBorder : this.interRankCellSpacing/2;
  					var w = size.width + leftGroupBorder;
  					var x = childBounds[i].x - w;
  					var y = layoutBounds.y - this.parentBorder;
  					newGeo.x += x;
  					newGeo.y = y;
  					newGeo.width = childBounds[i].width + w + this.interRankCellSpacing/2;
  					newGeo.height = layoutBounds.height + size.height + 2 * this.parentBorder;
  					this.graph.model.setGeometry(lane, newGeo);
  					this.graph.moveCells(children, -x, geo.y - y);
  				}
  			}
  		};
  		mxSwimlaneLayout.prototype.findRoots = function(parent, vertices)
  		{
  			var roots = [];
  			if (parent != null && vertices != null)
  			{
  				var model = this.graph.model;
  				var best = null;
  				var maxDiff = -1e5;
  				for (var i in vertices)
  				{
  					var cell = vertices[i];
  					if (cell != null && model.isVertex(cell) && this.graph.isCellVisible(cell) && model.isAncestor(parent, cell))
  					{
  						var conns = this.getEdges(cell);
  						var fanOut = 0;
  						var fanIn = 0;
  						for (var k = 0; k < conns.length; k++)
  						{
  							var src = this.getVisibleTerminal(conns[k], true);
  							if (src == cell)
  							{
  								var other = this.getVisibleTerminal(conns[k], false);
  								if (model.isAncestor(parent, other))
  								{
  									fanOut++;
  								}
  							}
  							else if (model.isAncestor(parent, src))
  							{
  								fanIn++;
  							}
  						}
  						if (fanIn == 0 && fanOut > 0)
  						{
  							roots.push(cell);
  						}
  						var diff = fanOut - fanIn;
  						if (diff > maxDiff)
  						{
  							maxDiff = diff;
  							best = cell;
  						}
  					}
  				}
  				if (roots.length == 0 && best != null)
  				{
  					roots.push(best);
  				}
  			}
  			return roots;
  		};
  		mxSwimlaneLayout.prototype.getEdges = function(cell)
  		{
  			var cachedEdges = this.edgesCache.get(cell);
  			if (cachedEdges != null)
  			{
  				return cachedEdges;
  			}
  			var model = this.graph.model;
  			var edges = [];
  			var isCollapsed = this.graph.isCellCollapsed(cell);
  			var childCount = model.getChildCount(cell);
  			for (var i = 0; i < childCount; i++)
  			{
  				var child = model.getChildAt(cell, i);
  				if (this.isPort(child))
  				{
  					edges = edges.concat(model.getEdges(child, true, true));
  				}
  				else if (isCollapsed || !this.graph.isCellVisible(child))
  				{
  					edges = edges.concat(model.getEdges(child, true, true));
  				}
  			}
  			edges = edges.concat(model.getEdges(cell, true, true));
  			var result = [];
  			for (var i = 0; i < edges.length; i++)
  			{
  				var source = this.getVisibleTerminal(edges[i], true);
  				var target = this.getVisibleTerminal(edges[i], false);
  				if ((source == target) || ((source != target) && ((target == cell && (this.parent == null || this.graph.isValidAncestor(source, this.parent, this.traverseAncestors))) ||
  					(source == cell && (this.parent == null ||
  							this.graph.isValidAncestor(target, this.parent, this.traverseAncestors))))))
  				{
  					result.push(edges[i]);
  				}
  			}
  			this.edgesCache.put(cell, result);
  			return result;
  		};
  		mxSwimlaneLayout.prototype.getVisibleTerminal = function(edge, source)
  		{
  			var terminalCache = this.edgesTargetTermCache;
  			if (source)
  			{
  				terminalCache = this.edgeSourceTermCache;
  			}
  			var term = terminalCache.get(edge);
  			if (term != null)
  			{
  				return term;
  			}
  			var state = this.graph.view.getState(edge);
  			var terminal = (state != null) ? state.getVisibleTerminal(source) : this.graph.view.getVisibleTerminal(edge, source);
  			if (terminal == null)
  			{
  				terminal = (state != null) ? state.getVisibleTerminal(source) : this.graph.view.getVisibleTerminal(edge, source);
  			}
  			if (terminal != null)
  			{
  				if (this.isPort(terminal))
  				{
  					terminal = this.graph.model.getParent(terminal);
  				}
  				terminalCache.put(edge, terminal);
  			}
  			return terminal;
  		};
  		mxSwimlaneLayout.prototype.run = function(parent)
  		{
  			var hierarchyVertices = [];
  			var allVertexSet = Object();
  			if (this.swimlanes != null && this.swimlanes.length > 0 && parent != null)
  			{
  				var filledVertexSet = Object();
  				for (var i = 0; i < this.swimlanes.length; i++)
  				{
  					this.filterDescendants(this.swimlanes[i], filledVertexSet);
  				}
  				this.roots = [];
  				var filledVertexSetEmpty = true;
  				for (var key in filledVertexSet)
  				{
  					if (filledVertexSet[key] != null)
  					{
  						filledVertexSetEmpty = false;
  						break;
  					}
  				}
  				var laneCounter = 0;
  				while (!filledVertexSetEmpty && laneCounter < this.swimlanes.length)
  				{
  					var candidateRoots = this.findRoots(this.swimlanes[laneCounter], filledVertexSet);
  					if (candidateRoots.length == 0)
  					{
  						laneCounter++;
  						continue;
  					}
  					for (var i = 0; i < candidateRoots.length; i++)
  					{
  						var vertexSet = Object();
  						hierarchyVertices.push(vertexSet);
  						this.traverse(candidateRoots[i], true, null, allVertexSet, vertexSet,
  								hierarchyVertices, filledVertexSet, laneCounter);
  					}
  					for (var i = 0; i < candidateRoots.length; i++)
  					{
  						this.roots.push(candidateRoots[i]);
  					}
  					filledVertexSetEmpty = true;
  					for (var key in filledVertexSet)
  					{
  						if (filledVertexSet[key] != null)
  						{
  							filledVertexSetEmpty = false;
  							break;
  						}
  					}
  				}
  			}
  			else
  			{
  				for (var i = 0; i < this.roots.length; i++)
  				{
  					var vertexSet = Object();
  					hierarchyVertices.push(vertexSet);
  					this.traverse(this.roots[i], true, null, allVertexSet, vertexSet,
  							hierarchyVertices, null);
  				}
  			}
  			var tmp = [];
  			for (var key in allVertexSet)
  			{
  				tmp.push(allVertexSet[key]);
  			}
  			this.model = new mxSwimlaneModel(this, tmp, this.roots,
  				parent, this.tightenToSource);
  			this.cycleStage(parent);
  			this.layeringStage();
  			this.crossingStage(parent);
  			this.placementStage(0, parent);
  		};
  		mxSwimlaneLayout.prototype.filterDescendants = function(cell, result)
  		{
  			var model = this.graph.model;
  			if (model.isVertex(cell) && cell != this.parent && model.getParent(cell) != this.parent && this.graph.isCellVisible(cell))
  			{
  				result[mxObjectIdentity.get(cell)] = cell;
  			}
  			if (this.traverseAncestors || cell == this.parent
  					&& this.graph.isCellVisible(cell))
  			{
  				var childCount = model.getChildCount(cell);
  				for (var i = 0; i < childCount; i++)
  				{
  					var child = model.getChildAt(cell, i);
  					if (!this.isPort(child))
  					{
  						this.filterDescendants(child, result);
  					}
  				}
  			}
  		};
  		mxSwimlaneLayout.prototype.isPort = function(cell)
  		{
  			if (cell.geometry.relative)
  			{
  				return true;
  			}
  			return false;
  		};
  		mxSwimlaneLayout.prototype.getEdgesBetween = function(source, target, directed)
  		{
  			directed = (directed != null) ? directed : false;
  			var edges = this.getEdges(source);
  			var result = [];
  			for (var i = 0; i < edges.length; i++)
  			{
  				var src = this.getVisibleTerminal(edges[i], true);
  				var trg = this.getVisibleTerminal(edges[i], false);
  				if ((src == source && trg == target) || (!directed && src == target && trg == source))
  				{
  					result.push(edges[i]);
  				}
  			}
  			return result;
  		};
  		mxSwimlaneLayout.prototype.traverse = function(vertex, directed, edge, allVertices, currentComp,
  													hierarchyVertices, filledVertexSet, swimlaneIndex)
  		{
  			if (vertex != null && allVertices != null)
  			{
  				var vertexID = mxObjectIdentity.get(vertex);
  				if ((allVertices[vertexID] == null)
  						&& (filledVertexSet == null ? true : filledVertexSet[vertexID] != null))
  				{
  					if (currentComp[vertexID] == null)
  					{
  						currentComp[vertexID] = vertex;
  					}
  					if (allVertices[vertexID] == null)
  					{
  						allVertices[vertexID] = vertex;
  					}
  					if (filledVertexSet !== null)
  					{
  						delete filledVertexSet[vertexID];
  					}
  					var edges = this.getEdges(vertex);
  					var model = this.graph.model;
  					for (var i = 0; i < edges.length; i++)
  					{
  						var otherVertex = this.getVisibleTerminal(edges[i], true);
  						var isSource = otherVertex == vertex;
  						if (isSource)
  						{
  							otherVertex = this.getVisibleTerminal(edges[i], false);
  						}
  						var otherIndex = 0;
  						for (otherIndex = 0; otherIndex < this.swimlanes.length; otherIndex++)
  						{
  							if (model.isAncestor(this.swimlanes[otherIndex], otherVertex))
  							{
  								break;
  							}
  						}
  						if (otherIndex >= this.swimlanes.length)
  						{
  							continue;
  						}
  						if ((otherIndex > swimlaneIndex) ||
  								((!directed || isSource) && otherIndex == swimlaneIndex))
  						{
  							currentComp = this.traverse(otherVertex, directed, edges[i], allVertices,
  									currentComp, hierarchyVertices,
  									filledVertexSet, otherIndex);
  						}
  					}
  				}
  				else
  				{
  					if (currentComp[vertexID] == null)
  					{
  						for (var i = 0; i < hierarchyVertices.length; i++)
  						{
  							var comp = hierarchyVertices[i];
  							if (comp[vertexID] != null)
  							{
  								for (var key in comp)
  								{
  									currentComp[key] = comp[key];
  								}
  								hierarchyVertices.splice(i, 1);
  								return currentComp;
  							}
  						}
  					}
  				}
  			}
  			return currentComp;
  		};
  		mxSwimlaneLayout.prototype.cycleStage = function(parent)
  		{
  			var cycleStage = new mxSwimlaneOrdering(this);
  			cycleStage.execute(parent);
  		};
  		mxSwimlaneLayout.prototype.layeringStage = function()
  		{
  			this.model.initialRank();
  			this.model.fixRanks();
  		};
  		mxSwimlaneLayout.prototype.crossingStage = function(parent)
  		{
  			var crossingStage = new mxMedianHybridCrossingReduction(this);
  			crossingStage.execute(parent);
  		};
  		mxSwimlaneLayout.prototype.placementStage = function(initialX, parent)
  		{
  			var placementStage = new mxCoordinateAssignment(this, this.intraCellSpacing,
  					this.interRankCellSpacing, this.orientation, initialX,
  					this.parallelEdgeSpacing);
  			placementStage.fineTuning = this.fineTuning;
  			placementStage.execute(parent);
  			return placementStage.limitX + this.interHierarchySpacing;
  		};
  		__mxOutput.mxSwimlaneLayout = typeof mxSwimlaneLayout !== 'undefined' ? mxSwimlaneLayout : undefined;
  		function mxGraphModel(root)
  		{
  			this.currentEdit = this.createUndoableEdit();
  			if (root != null)
  			{
  				this.setRoot(root);
  			}
  			else
  			{
  				this.clear();
  			}
  		}		mxGraphModel.prototype = new mxEventSource();
  		mxGraphModel.prototype.constructor = mxGraphModel;
  		mxGraphModel.prototype.root = null;
  		mxGraphModel.prototype.cells = null;
  		mxGraphModel.prototype.maintainEdgeParent = true;
  		mxGraphModel.prototype.ignoreRelativeEdgeParent = true;
  		mxGraphModel.prototype.createIds = true;
  		mxGraphModel.prototype.prefix = '';
  		mxGraphModel.prototype.postfix = '';
  		mxGraphModel.prototype.nextId = 0;
  		mxGraphModel.prototype.currentEdit = null;
  		mxGraphModel.prototype.updateLevel = 0;
  		mxGraphModel.prototype.endingUpdate = false;
  		mxGraphModel.prototype.clear = function()
  		{
  			this.setRoot(this.createRoot());
  		};
  		mxGraphModel.prototype.isCreateIds = function()
  		{
  			return this.createIds;
  		};
  		mxGraphModel.prototype.setCreateIds = function(value)
  		{
  			this.createIds = value;
  		};
  		mxGraphModel.prototype.createRoot = function()
  		{
  			var cell = new mxCell();
  			cell.insert(new mxCell());
  			return cell;
  		};
  		mxGraphModel.prototype.getCell = function(id)
  		{
  			return (this.cells != null) ? this.cells[id] : null;
  		};
  		mxGraphModel.prototype.filterCells = function(cells, filter)
  		{
  			var result = null;
  			if (cells != null)
  			{
  				result = [];
  				for (var i = 0; i < cells.length; i++)
  				{
  					if (filter(cells[i]))
  					{
  						result.push(cells[i]);
  					}
  				}
  			}
  			return result;
  		};
  		mxGraphModel.prototype.getDescendants = function(parent)
  		{
  			return this.filterDescendants(null, parent);
  		};
  		mxGraphModel.prototype.filterDescendants = function(filter, parent)
  		{
  			var result = [];
  			parent = parent || this.getRoot();
  			if (filter == null || filter(parent))
  			{
  				result.push(parent);
  			}
  			var childCount = this.getChildCount(parent);
  			for (var i = 0; i < childCount; i++)
  			{
  				var child = this.getChildAt(parent, i);
  				result = result.concat(this.filterDescendants(filter, child));
  			}
  			return result;
  		};
  		mxGraphModel.prototype.getRoot = function(cell)
  		{
  			var root = cell || this.root;
  			if (cell != null)
  			{
  				while (cell != null)
  				{
  					root = cell;
  					cell = this.getParent(cell);
  				}
  			}
  			return root;
  		};
  		mxGraphModel.prototype.setRoot = function(root)
  		{
  			this.execute(new mxRootChange(this, root));
  			return root;
  		};
  		mxGraphModel.prototype.rootChanged = function(root)
  		{
  			var oldRoot = this.root;
  			this.root = root;
  			this.nextId = 0;
  			this.cells = null;
  			this.cellAdded(root);
  			return oldRoot;
  		};
  		mxGraphModel.prototype.isRoot = function(cell)
  		{
  			return cell != null && this.root == cell;
  		};
  		mxGraphModel.prototype.isLayer = function(cell)
  		{
  			return this.isRoot(this.getParent(cell));
  		};
  		mxGraphModel.prototype.isAncestor = function(parent, child)
  		{
  			while (child != null && child != parent)
  			{
  				child = this.getParent(child);
  			}
  			return child == parent;
  		};
  		mxGraphModel.prototype.contains = function(cell)
  		{
  			return this.isAncestor(this.root, cell);
  		};
  		mxGraphModel.prototype.getParent = function(cell)
  		{
  			return (cell != null) ? cell.getParent() : null;
  		};
  		mxGraphModel.prototype.add = function(parent, child, index)
  		{
  			if (child != parent && parent != null && child != null)
  			{
  				if (index == null)
  				{
  					index = this.getChildCount(parent);
  				}
  				var parentChanged = parent != this.getParent(child);
  				this.execute(new mxChildChange(this, parent, child, index));
  				if (this.maintainEdgeParent && parentChanged)
  				{
  					this.updateEdgeParents(child);
  				}
  			}
  			return child;
  		};
  		mxGraphModel.prototype.cellAdded = function(cell)
  		{
  			if (cell != null)
  			{
  				if (cell.getId() == null && this.createIds)
  				{
  					cell.setId(this.createId(cell));
  				}
  				if (cell.getId() != null)
  				{
  					var collision = this.getCell(cell.getId());
  					if (collision != cell)
  					{
  						while (collision != null)
  						{
  							cell.setId(this.createId(cell));
  							collision = this.getCell(cell.getId());
  						}
  						if (this.cells == null)
  						{
  							this.cells = new Object();
  						}
  						this.cells[cell.getId()] = cell;
  					}
  				}
  				if (mxUtils.isNumeric(cell.getId()))
  				{
  					this.nextId = Math.max(this.nextId, cell.getId());
  				}
  				var childCount = this.getChildCount(cell);
  				for (var i=0; i<childCount; i++)
  				{
  					this.cellAdded(this.getChildAt(cell, i));
  				}
  			}
  		};
  		mxGraphModel.prototype.createId = function(cell)
  		{
  			var id = this.nextId;
  			this.nextId++;
  			return this.prefix + id + this.postfix;
  		};
  		mxGraphModel.prototype.updateEdgeParents = function(cell, root)
  		{
  			root = root || this.getRoot(cell);
  			var childCount = this.getChildCount(cell);
  			for (var i = 0; i < childCount; i++)
  			{
  				var child = this.getChildAt(cell, i);
  				this.updateEdgeParents(child, root);
  			}
  			var edgeCount = this.getEdgeCount(cell);
  			var edges = [];
  			for (var i = 0; i < edgeCount; i++)
  			{
  				edges.push(this.getEdgeAt(cell, i));
  			}
  			for (var i = 0; i < edges.length; i++)
  			{
  				var edge = edges[i];
  				if (this.isAncestor(root, edge))
  				{
  					this.updateEdgeParent(edge, root);
  				}
  			}
  		};
  		mxGraphModel.prototype.updateEdgeParent = function(edge, root)
  		{
  			var source = this.getTerminal(edge, true);
  			var target = this.getTerminal(edge, false);
  			var cell = null;
  			while (source != null && !this.isEdge(source) &&
  				source.geometry != null && source.geometry.relative)
  			{
  				source = this.getParent(source);
  			}
  			while (target != null && this.ignoreRelativeEdgeParent &&
  				!this.isEdge(target) && target.geometry != null &&
  				target.geometry.relative)
  			{
  				target = this.getParent(target);
  			}
  			if (this.isAncestor(root, source) && this.isAncestor(root, target))
  			{
  				if (source == target)
  				{
  					cell = this.getParent(source);
  				}
  				else
  				{
  					cell = this.getNearestCommonAncestor(source, target);
  				}
  				if (cell != null && (this.getParent(cell) != this.root ||
  					this.isAncestor(cell, edge)) && this.getParent(edge) != cell)
  				{
  					var geo = this.getGeometry(edge);
  					if (geo != null)
  					{
  						var origin1 = this.getOrigin(this.getParent(edge));
  						var origin2 = this.getOrigin(cell);
  						var dx = origin2.x - origin1.x;
  						var dy = origin2.y - origin1.y;
  						geo = geo.clone();
  						geo.translate(-dx, -dy);
  						this.setGeometry(edge, geo);
  					}
  					this.add(cell, edge, this.getChildCount(cell));
  				}
  			}
  		};
  		mxGraphModel.prototype.getOrigin = function(cell)
  		{
  			var result = null;
  			if (cell != null)
  			{
  				result = this.getOrigin(this.getParent(cell));
  				if (!this.isEdge(cell))
  				{
  					var geo = this.getGeometry(cell);
  					if (geo != null)
  					{
  						result.x += geo.x;
  						result.y += geo.y;
  					}
  				}
  			}
  			else
  			{
  				result = new mxPoint();
  			}
  			return result;
  		};
  		mxGraphModel.prototype.getNearestCommonAncestor = function(cell1, cell2)
  		{
  			if (cell1 != null && cell2 != null)
  			{
  				var path = mxCellPath.create(cell2);
  				if (path != null && path.length > 0)
  				{
  					var cell = cell1;
  					var current = mxCellPath.create(cell);
  					if (path.length < current.length)
  					{
  						cell = cell2;
  						var tmp = current;
  						current = path;
  						path = tmp;
  					}
  					while (cell != null)
  					{
  						var parent = this.getParent(cell);
  						if (path.indexOf(current + mxCellPath.PATH_SEPARATOR) == 0 && parent != null)
  						{
  							return cell;
  						}
  						current = mxCellPath.getParentPath(current);
  						cell = parent;
  					}
  				}
  			}
  			return null;
  		};
  		mxGraphModel.prototype.remove = function(cell)
  		{
  			if (cell == this.root)
  			{
  				this.setRoot(null);
  			}
  			else if (this.getParent(cell) != null)
  			{
  				this.execute(new mxChildChange(this, null, cell));
  			}
  			return cell;
  		};
  		mxGraphModel.prototype.cellRemoved = function(cell)
  		{
  			if (cell != null && this.cells != null)
  			{
  				var childCount = this.getChildCount(cell);
  				for (var i = childCount - 1; i >= 0; i--)
  				{
  					this.cellRemoved(this.getChildAt(cell, i));
  				}
  				if (this.cells != null && cell.getId() != null)
  				{
  					delete this.cells[cell.getId()];
  				}
  			}
  		};
  		mxGraphModel.prototype.parentForCellChanged = function(cell, parent, index)
  		{
  			var previous = this.getParent(cell);
  			if (parent != null)
  			{
  				if (parent != previous || previous.getIndex(cell) != index)
  				{
  					parent.insert(cell, index);
  				}
  			}
  			else if (previous != null)
  			{
  				var oldIndex = previous.getIndex(cell);
  				previous.remove(oldIndex);
  			}
  			var par = this.contains(parent);
  			var pre = this.contains(previous);
  			if (par && !pre)
  			{
  				this.cellAdded(cell);
  			}
  			else if (pre && !par)
  			{
  				this.cellRemoved(cell);
  			}
  			return previous;
  		};
  		mxGraphModel.prototype.getChildCount = function(cell)
  		{
  			return (cell != null) ? cell.getChildCount() : 0;
  		};
  		mxGraphModel.prototype.getChildAt = function(cell, index)
  		{
  			return (cell != null) ? cell.getChildAt(index) : null;
  		};
  		mxGraphModel.prototype.getChildren = function(cell)
  		{
  			return (cell != null) ? cell.children : null;
  		};
  		mxGraphModel.prototype.getChildVertices = function(parent)
  		{
  			return this.getChildCells(parent, true, false);
  		};
  		mxGraphModel.prototype.getChildEdges = function(parent)
  		{
  			return this.getChildCells(parent, false, true);
  		};
  		mxGraphModel.prototype.getChildCells = function(parent, vertices, edges)
  		{
  			vertices = (vertices != null) ? vertices : false;
  			edges = (edges != null) ? edges : false;
  			var childCount = this.getChildCount(parent);
  			var result = [];
  			for (var i = 0; i < childCount; i++)
  			{
  				var child = this.getChildAt(parent, i);
  				if ((!edges && !vertices) || (edges && this.isEdge(child)) ||
  					(vertices && this.isVertex(child)))
  				{
  					result.push(child);
  				}
  			}
  			return result;
  		};
  		mxGraphModel.prototype.getTerminal = function(edge, isSource)
  		{
  			return (edge != null) ? edge.getTerminal(isSource) : null;
  		};
  		mxGraphModel.prototype.setTerminal = function(edge, terminal, isSource)
  		{
  			var terminalChanged = terminal != this.getTerminal(edge, isSource);
  			this.execute(new mxTerminalChange(this, edge, terminal, isSource));
  			if (this.maintainEdgeParent && terminalChanged)
  			{
  				this.updateEdgeParent(edge, this.getRoot());
  			}
  			return terminal;
  		};
  		mxGraphModel.prototype.setTerminals = function(edge, source, target)
  		{
  			this.beginUpdate();
  			try
  			{
  				this.setTerminal(edge, source, true);
  				this.setTerminal(edge, target, false);
  			}
  			finally
  			{
  				this.endUpdate();
  			}
  		};
  		mxGraphModel.prototype.terminalForCellChanged = function(edge, terminal, isSource)
  		{
  			var previous = this.getTerminal(edge, isSource);
  			if (terminal != null)
  			{
  				terminal.insertEdge(edge, isSource);
  			}
  			else if (previous != null)
  			{
  				previous.removeEdge(edge, isSource);
  			}
  			return previous;
  		};
  		mxGraphModel.prototype.getEdgeCount = function(cell)
  		{
  			return (cell != null) ? cell.getEdgeCount() : 0;
  		};
  		mxGraphModel.prototype.getEdgeAt = function(cell, index)
  		{
  			return (cell != null) ? cell.getEdgeAt(index) : null;
  		};
  		mxGraphModel.prototype.getDirectedEdgeCount = function(cell, outgoing, ignoredEdge)
  		{
  			var count = 0;
  			var edgeCount = this.getEdgeCount(cell);
  			for (var i = 0; i < edgeCount; i++)
  			{
  				var edge = this.getEdgeAt(cell, i);
  				if (edge != ignoredEdge && this.getTerminal(edge, outgoing) == cell)
  				{
  					count++;
  				}
  			}
  			return count;
  		};
  		mxGraphModel.prototype.getConnections = function(cell)
  		{
  			return this.getEdges(cell, true, true, false);
  		};
  		mxGraphModel.prototype.getIncomingEdges = function(cell)
  		{
  			return this.getEdges(cell, true, false, false);
  		};
  		mxGraphModel.prototype.getOutgoingEdges = function(cell)
  		{
  			return this.getEdges(cell, false, true, false);
  		};
  		mxGraphModel.prototype.getEdges = function(cell, incoming, outgoing, includeLoops)
  		{
  			incoming = (incoming != null) ? incoming : true;
  			outgoing = (outgoing != null) ? outgoing : true;
  			includeLoops = (includeLoops != null) ? includeLoops : true;
  			var edgeCount = this.getEdgeCount(cell);
  			var result = [];
  			for (var i = 0; i < edgeCount; i++)
  			{
  				var edge = this.getEdgeAt(cell, i);
  				var source = this.getTerminal(edge, true);
  				var target = this.getTerminal(edge, false);
  				if ((includeLoops && source == target) || ((source != target) && ((incoming && target == cell) ||
  					(outgoing && source == cell))))
  				{
  					result.push(edge);
  				}
  			}
  			return result;
  		};
  		mxGraphModel.prototype.getEdgesBetween = function(source, target, directed)
  		{
  			directed = (directed != null) ? directed : false;
  			var tmp1 = this.getEdgeCount(source);
  			var tmp2 = this.getEdgeCount(target);
  			var terminal = source;
  			var edgeCount = tmp1;
  			if (tmp2 < tmp1)
  			{
  				edgeCount = tmp2;
  				terminal = target;
  			}
  			var result = [];
  			for (var i = 0; i < edgeCount; i++)
  			{
  				var edge = this.getEdgeAt(terminal, i);
  				var src = this.getTerminal(edge, true);
  				var trg = this.getTerminal(edge, false);
  				var directedMatch = (src == source) && (trg == target);
  				var oppositeMatch = (trg == source) && (src == target);
  				if (directedMatch || (!directed && oppositeMatch))
  				{
  					result.push(edge);
  				}
  			}
  			return result;
  		};
  		mxGraphModel.prototype.getOpposites = function(edges, terminal, sources, targets)
  		{
  			sources = (sources != null) ? sources : true;
  			targets = (targets != null) ? targets : true;
  			var terminals = [];
  			if (edges != null)
  			{
  				for (var i = 0; i < edges.length; i++)
  				{
  					var source = this.getTerminal(edges[i], true);
  					var target = this.getTerminal(edges[i], false);
  					if (source == terminal && target != null && target != terminal && targets)
  					{
  						terminals.push(target);
  					}
  					else if (target == terminal && source != null && source != terminal && sources)
  					{
  						terminals.push(source);
  					}
  				}
  			}
  			return terminals;
  		};
  		mxGraphModel.prototype.getTopmostCells = function(cells)
  		{
  			var dict = new mxDictionary();
  			var tmp = [];
  			for (var i = 0; i < cells.length; i++)
  			{
  				dict.put(cells[i], true);
  			}
  			for (var i = 0; i < cells.length; i++)
  			{
  				var cell = cells[i];
  				var topmost = true;
  				var parent = this.getParent(cell);
  				while (parent != null)
  				{
  					if (dict.get(parent))
  					{
  						topmost = false;
  						break;
  					}
  					parent = this.getParent(parent);
  				}
  				if (topmost)
  				{
  					tmp.push(cell);
  				}
  			}
  			return tmp;
  		};
  		mxGraphModel.prototype.isVertex = function(cell)
  		{
  			return (cell != null) ? cell.isVertex() : false;
  		};
  		mxGraphModel.prototype.isEdge = function(cell)
  		{
  			return (cell != null) ? cell.isEdge() : false;
  		};
  		mxGraphModel.prototype.isConnectable = function(cell)
  		{
  			return (cell != null) ? cell.isConnectable() : false;
  		};
  		mxGraphModel.prototype.getValue = function(cell)
  		{
  			return (cell != null) ? cell.getValue() : null;
  		};
  		mxGraphModel.prototype.setValue = function(cell, value)
  		{
  			this.execute(new mxValueChange(this, cell, value));
  			return value;
  		};
  		mxGraphModel.prototype.valueForCellChanged = function(cell, value)
  		{
  			return cell.valueChanged(value);
  		};
  		mxGraphModel.prototype.getGeometry = function(cell)
  		{
  			return (cell != null) ? cell.getGeometry() : null;
  		};
  		mxGraphModel.prototype.setGeometry = function(cell, geometry)
  		{
  			if (geometry != this.getGeometry(cell))
  			{
  				this.execute(new mxGeometryChange(this, cell, geometry));
  			}
  			return geometry;
  		};
  		mxGraphModel.prototype.geometryForCellChanged = function(cell, geometry)
  		{
  			var previous = this.getGeometry(cell);
  			cell.setGeometry(geometry);
  			return previous;
  		};
  		mxGraphModel.prototype.getStyle = function(cell)
  		{
  			return (cell != null) ? cell.getStyle() : null;
  		};
  		mxGraphModel.prototype.setStyle = function(cell, style)
  		{
  			if (style != this.getStyle(cell))
  			{
  				this.execute(new mxStyleChange(this, cell, style));
  			}
  			return style;
  		};
  		mxGraphModel.prototype.styleForCellChanged = function(cell, style)
  		{
  			var previous = this.getStyle(cell);
  			cell.setStyle(style);
  			return previous;
  		};
  		mxGraphModel.prototype.isCollapsed = function(cell)
  		{
  			return (cell != null) ? cell.isCollapsed() : false;
  		};
  		mxGraphModel.prototype.setCollapsed = function(cell, collapsed)
  		{
  			if (collapsed != this.isCollapsed(cell))
  			{
  				this.execute(new mxCollapseChange(this, cell, collapsed));
  			}
  			return collapsed;
  		};
  		mxGraphModel.prototype.collapsedStateForCellChanged = function(cell, collapsed)
  		{
  			var previous = this.isCollapsed(cell);
  			cell.setCollapsed(collapsed);
  			return previous;
  		};
  		mxGraphModel.prototype.isVisible = function(cell)
  		{
  			return (cell != null) ? cell.isVisible() : false;
  		};
  		mxGraphModel.prototype.setVisible = function(cell, visible)
  		{
  			if (visible != this.isVisible(cell))
  			{
  				this.execute(new mxVisibleChange(this, cell, visible));
  			}
  			return visible;
  		};
  		mxGraphModel.prototype.visibleStateForCellChanged = function(cell, visible)
  		{
  			var previous = this.isVisible(cell);
  			cell.setVisible(visible);
  			return previous;
  		};
  		mxGraphModel.prototype.execute = function(change)
  		{
  			change.execute();
  			this.beginUpdate();
  			this.currentEdit.add(change);
  			this.fireEvent(new mxEventObject(mxEvent.EXECUTE, 'change', change));
  			this.fireEvent(new mxEventObject(mxEvent.EXECUTED, 'change', change));
  			this.endUpdate();
  		};
  		mxGraphModel.prototype.beginUpdate = function()
  		{
  			this.updateLevel++;
  			this.fireEvent(new mxEventObject(mxEvent.BEGIN_UPDATE));
  			if (this.updateLevel == 1)
  			{
  				this.fireEvent(new mxEventObject(mxEvent.START_EDIT));
  			}
  		};
  		mxGraphModel.prototype.endUpdate = function()
  		{
  			this.updateLevel--;
  			if (this.updateLevel == 0)
  			{
  				this.fireEvent(new mxEventObject(mxEvent.END_EDIT));
  			}
  			if (!this.endingUpdate)
  			{
  				this.endingUpdate = this.updateLevel == 0;
  				this.fireEvent(new mxEventObject(mxEvent.END_UPDATE, 'edit', this.currentEdit));
  				try
  				{
  					if (this.endingUpdate && !this.currentEdit.isEmpty())
  					{
  						this.fireEvent(new mxEventObject(mxEvent.BEFORE_UNDO, 'edit', this.currentEdit));
  						var tmp = this.currentEdit;
  						this.currentEdit = this.createUndoableEdit();
  						tmp.notify();
  						this.fireEvent(new mxEventObject(mxEvent.UNDO, 'edit', tmp));
  					}
  				}
  				finally
  				{
  					this.endingUpdate = false;
  				}
  			}
  		};
  		mxGraphModel.prototype.createUndoableEdit = function(significant)
  		{
  			var edit = new mxUndoableEdit(this, (significant != null) ? significant : true);
  			edit.notify = function()
  			{
  				edit.source.fireEvent(new mxEventObject(mxEvent.CHANGE,
  					'edit', edit, 'changes', edit.changes));
  				edit.source.fireEvent(new mxEventObject(mxEvent.NOTIFY,
  					'edit', edit, 'changes', edit.changes));
  			};
  			return edit;
  		};
  		mxGraphModel.prototype.mergeChildren = function(from, to, cloneAllEdges)
  		{
  			cloneAllEdges = (cloneAllEdges != null) ? cloneAllEdges : true;
  			this.beginUpdate();
  			try
  			{
  				var mapping = new Object();
  				this.mergeChildrenImpl(from, to, cloneAllEdges, mapping);
  				for (var key in mapping)
  				{
  					var cell = mapping[key];
  					var terminal = this.getTerminal(cell, true);
  					if (terminal != null)
  					{
  						terminal = mapping[mxCellPath.create(terminal)];
  						this.setTerminal(cell, terminal, true);
  					}
  					terminal = this.getTerminal(cell, false);
  					if (terminal != null)
  					{
  						terminal = mapping[mxCellPath.create(terminal)];
  						this.setTerminal(cell, terminal, false);
  					}
  				}
  			}
  			finally
  			{
  				this.endUpdate();
  			}
  		};
  		mxGraphModel.prototype.mergeChildrenImpl = function(from, to, cloneAllEdges, mapping)
  		{
  			this.beginUpdate();
  			try
  			{
  				var childCount = from.getChildCount();
  				for (var i = 0; i < childCount; i++)
  				{
  					var cell = from.getChildAt(i);
  					if (typeof(cell.getId) == 'function')
  					{
  						var id = cell.getId();
  						var target = (id != null && (!this.isEdge(cell) || !cloneAllEdges)) ?
  								this.getCell(id) : null;
  						if (target == null)
  						{
  							var clone = cell.clone();
  							clone.setId(id);
  							clone.setTerminal(cell.getTerminal(true), true);
  							clone.setTerminal(cell.getTerminal(false), false);
  							target = to.insert(clone);
  							this.cellAdded(target);
  						}
  						mapping[mxCellPath.create(cell)] = target;
  						this.mergeChildrenImpl(cell, target, cloneAllEdges, mapping);
  					}
  				}
  			}
  			finally
  			{
  				this.endUpdate();
  			}
  		};
  		mxGraphModel.prototype.getParents = function(cells)
  		{
  			var parents = [];
  			if (cells != null)
  			{
  				var dict = new mxDictionary();
  				for (var i = 0; i < cells.length; i++)
  				{
  					var parent = this.getParent(cells[i]);
  					if (parent != null && !dict.get(parent))
  					{
  						dict.put(parent, true);
  						parents.push(parent);
  					}
  				}
  			}
  			return parents;
  		};
  		mxGraphModel.prototype.cloneCell = function(cell, includeChildren)
  		{
  			if (cell != null)
  			{
  				return this.cloneCells([cell], includeChildren)[0];
  			}
  			return null;
  		};
  		mxGraphModel.prototype.cloneCells = function(cells, includeChildren, mapping)
  		{
  			includeChildren = (includeChildren != null) ? includeChildren : true;
  			mapping = (mapping != null) ? mapping : new Object();
  			var clones = [];
  			for (var i = 0; i < cells.length; i++)
  			{
  				if (cells[i] != null)
  				{
  					clones.push(this.cloneCellImpl(cells[i], mapping, includeChildren));
  				}
  				else
  				{
  					clones.push(null);
  				}
  			}
  			for (var i = 0; i < clones.length; i++)
  			{
  				if (clones[i] != null)
  				{
  					this.restoreClone(clones[i], cells[i], mapping);
  				}
  			}
  			return clones;
  		};
  		mxGraphModel.prototype.cloneCellImpl = function(cell, mapping, includeChildren)
  		{
  			var ident = mxObjectIdentity.get(cell);
  			var clone = mapping[ident];
  			if (clone == null)
  			{
  				clone = this.cellCloned(cell);
  				mapping[ident] = clone;
  				if (includeChildren)
  				{
  					var childCount = this.getChildCount(cell);
  					for (var i = 0; i < childCount; i++)
  					{
  						var cloneChild = this.cloneCellImpl(
  							this.getChildAt(cell, i), mapping, true);
  						clone.insert(cloneChild);
  					}
  				}
  			}
  			return clone;
  		};
  		mxGraphModel.prototype.cellCloned = function(cell)
  		{
  			return cell.clone();
  		};
  		mxGraphModel.prototype.restoreClone = function(clone, cell, mapping)
  		{
  			var source = this.getTerminal(cell, true);
  			if (source != null)
  			{
  				var tmp = mapping[mxObjectIdentity.get(source)];
  				if (tmp != null)
  				{
  					tmp.insertEdge(clone, true);
  				}
  			}
  			var target = this.getTerminal(cell, false);
  			if (target != null)
  			{
  				var tmp = mapping[mxObjectIdentity.get(target)];
  				if (tmp != null)
  				{
  					tmp.insertEdge(clone, false);
  				}
  			}
  			var childCount = this.getChildCount(clone);
  			for (var i = 0; i < childCount; i++)
  			{
  				this.restoreClone(this.getChildAt(clone, i),
  					this.getChildAt(cell, i), mapping);
  			}
  		};
  		function mxRootChange(model, root)
  		{
  			this.model = model;
  			this.root = root;
  			this.previous = root;
  		}		mxRootChange.prototype.execute = function()
  		{
  			this.root = this.previous;
  			this.previous = this.model.rootChanged(this.previous);
  		};
  		function mxChildChange(model, parent, child, index)
  		{
  			this.model = model;
  			this.parent = parent;
  			this.previous = parent;
  			this.child = child;
  			this.index = index;
  			this.previousIndex = index;
  		}		mxChildChange.prototype.execute = function()
  		{
  			if (this.child != null)
  			{
  				var tmp = this.model.getParent(this.child);
  				var tmp2 = (tmp != null) ? tmp.getIndex(this.child) : 0;
  				if (this.previous == null)
  				{
  					this.connect(this.child, false);
  				}
  				tmp = this.model.parentForCellChanged(
  					this.child, this.previous, this.previousIndex);
  				if (this.previous != null)
  				{
  					this.connect(this.child, true);
  				}
  				this.parent = this.previous;
  				this.previous = tmp;
  				this.index = this.previousIndex;
  				this.previousIndex = tmp2;
  			}
  		};
  		mxChildChange.prototype.connect = function(cell, isConnect)
  		{
  			isConnect = (isConnect != null) ? isConnect : true;
  			var source = cell.getTerminal(true);
  			var target = cell.getTerminal(false);
  			if (source != null)
  			{
  				if (isConnect)
  				{
  					this.model.terminalForCellChanged(cell, source, true);
  				}
  				else
  				{
  					this.model.terminalForCellChanged(cell, null, true);
  				}
  			}
  			if (target != null)
  			{
  				if (isConnect)
  				{
  					this.model.terminalForCellChanged(cell, target, false);
  				}
  				else
  				{
  					this.model.terminalForCellChanged(cell, null, false);
  				}
  			}
  			cell.setTerminal(source, true);
  			cell.setTerminal(target, false);
  			var childCount = this.model.getChildCount(cell);
  			for (var i=0; i<childCount; i++)
  			{
  				this.connect(this.model.getChildAt(cell, i), isConnect);
  			}
  		};
  		function mxTerminalChange(model, cell, terminal, source)
  		{
  			this.model = model;
  			this.cell = cell;
  			this.terminal = terminal;
  			this.previous = terminal;
  			this.source = source;
  		}		mxTerminalChange.prototype.execute = function()
  		{
  			if (this.cell != null)
  			{
  				this.terminal = this.previous;
  				this.previous = this.model.terminalForCellChanged(
  					this.cell, this.previous, this.source);
  			}
  		};
  		function mxValueChange(model, cell, value)
  		{
  			this.model = model;
  			this.cell = cell;
  			this.value = value;
  			this.previous = value;
  		}		mxValueChange.prototype.execute = function()
  		{
  			if (this.cell != null)
  			{
  				this.value = this.previous;
  				this.previous = this.model.valueForCellChanged(
  					this.cell, this.previous);
  			}
  		};
  		function mxStyleChange(model, cell, style)
  		{
  			this.model = model;
  			this.cell = cell;
  			this.style = style;
  			this.previous = style;
  		}		mxStyleChange.prototype.execute = function()
  		{
  			if (this.cell != null)
  			{
  				this.style = this.previous;
  				this.previous = this.model.styleForCellChanged(
  					this.cell, this.previous);
  			}
  		};
  		function mxGeometryChange(model, cell, geometry)
  		{
  			this.model = model;
  			this.cell = cell;
  			this.geometry = geometry;
  			this.previous = geometry;
  		}		mxGeometryChange.prototype.execute = function()
  		{
  			if (this.cell != null)
  			{
  				this.geometry = this.previous;
  				this.previous = this.model.geometryForCellChanged(
  					this.cell, this.previous);
  			}
  		};
  		function mxCollapseChange(model, cell, collapsed)
  		{
  			this.model = model;
  			this.cell = cell;
  			this.collapsed = collapsed;
  			this.previous = collapsed;
  		}		mxCollapseChange.prototype.execute = function()
  		{
  			if (this.cell != null)
  			{
  				this.collapsed = this.previous;
  				this.previous = this.model.collapsedStateForCellChanged(
  					this.cell, this.previous);
  			}
  		};
  		function mxVisibleChange(model, cell, visible)
  		{
  			this.model = model;
  			this.cell = cell;
  			this.visible = visible;
  			this.previous = visible;
  		}		mxVisibleChange.prototype.execute = function()
  		{
  			if (this.cell != null)
  			{
  				this.visible = this.previous;
  				this.previous = this.model.visibleStateForCellChanged(
  					this.cell, this.previous);
  			}
  		};
  		function mxCellAttributeChange(cell, attribute, value)
  		{
  			this.cell = cell;
  			this.attribute = attribute;
  			this.value = value;
  			this.previous = value;
  		}		mxCellAttributeChange.prototype.execute = function()
  		{
  			if (this.cell != null)
  			{
  				var tmp = this.cell.getAttribute(this.attribute);
  				if (this.previous == null)
  				{
  					this.cell.value.removeAttribute(this.attribute);
  				}
  				else
  				{
  					this.cell.setAttribute(this.attribute, this.previous);
  				}
  				this.previous = tmp;
  			}
  		};
  		__mxOutput.mxGraphModel = typeof mxGraphModel !== 'undefined' ? mxGraphModel : undefined;
  		function mxCell(value, geometry, style)
  		{
  			this.value = value;
  			this.setGeometry(geometry);
  			this.setStyle(style);
  			if (this.onInit != null)
  			{
  				this.onInit();
  			}
  		}		mxCell.prototype.id = null;
  		mxCell.prototype.value = null;
  		mxCell.prototype.geometry = null;
  		mxCell.prototype.style = null;
  		mxCell.prototype.vertex = false;
  		mxCell.prototype.edge = false;
  		mxCell.prototype.connectable = true;
  		mxCell.prototype.visible = true;
  		mxCell.prototype.collapsed = false;
  		mxCell.prototype.parent = null;
  		mxCell.prototype.source = null;
  		mxCell.prototype.target = null;
  		mxCell.prototype.children = null;
  		mxCell.prototype.edges = null;
  		mxCell.prototype.mxTransient = ['id', 'value', 'parent', 'source',
  		                                'target', 'children', 'edges'];
  		mxCell.prototype.getId = function()
  		{
  			return this.id;
  		};
  		mxCell.prototype.setId = function(id)
  		{
  			this.id = id;
  		};
  		mxCell.prototype.getValue = function()
  		{
  			return this.value;
  		};
  		mxCell.prototype.setValue = function(value)
  		{
  			this.value = value;
  		};
  		mxCell.prototype.valueChanged = function(newValue)
  		{
  			var previous = this.getValue();
  			this.setValue(newValue);
  			return previous;
  		};
  		mxCell.prototype.getGeometry = function()
  		{
  			return this.geometry;
  		};
  		mxCell.prototype.setGeometry = function(geometry)
  		{
  			this.geometry = geometry;
  		};
  		mxCell.prototype.getStyle = function()
  		{
  			return this.style;
  		};
  		mxCell.prototype.setStyle = function(style)
  		{
  			this.style = style;
  		};
  		mxCell.prototype.isVertex = function()
  		{
  			return this.vertex != 0;
  		};
  		mxCell.prototype.setVertex = function(vertex)
  		{
  			this.vertex = vertex;
  		};
  		mxCell.prototype.isEdge = function()
  		{
  			return this.edge != 0;
  		};
  		mxCell.prototype.setEdge = function(edge)
  		{
  			this.edge = edge;
  		};
  		mxCell.prototype.isConnectable = function()
  		{
  			return this.connectable != 0;
  		};
  		mxCell.prototype.setConnectable = function(connectable)
  		{
  			this.connectable = connectable;
  		};
  		mxCell.prototype.isVisible = function()
  		{
  			return this.visible != 0;
  		};
  		mxCell.prototype.setVisible = function(visible)
  		{
  			this.visible = visible;
  		};
  		mxCell.prototype.isCollapsed = function()
  		{
  			return this.collapsed != 0;
  		};
  		mxCell.prototype.setCollapsed = function(collapsed)
  		{
  			this.collapsed = collapsed;
  		};
  		mxCell.prototype.getParent = function()
  		{
  			return this.parent;
  		};
  		mxCell.prototype.setParent = function(parent)
  		{
  			this.parent = parent;
  		};
  		mxCell.prototype.getTerminal = function(source)
  		{
  			return (source) ? this.source : this.target;
  		};
  		mxCell.prototype.setTerminal = function(terminal, isSource)
  		{
  			if (isSource)
  			{
  				this.source = terminal;
  			}
  			else
  			{
  				this.target = terminal;
  			}
  			return terminal;
  		};
  		mxCell.prototype.getChildCount = function()
  		{
  			return (this.children == null) ? 0 : this.children.length;
  		};
  		mxCell.prototype.getIndex = function(child)
  		{
  			return mxUtils.indexOf(this.children, child);
  		};
  		mxCell.prototype.getChildAt = function(index)
  		{
  			return (this.children == null) ? null : this.children[index];
  		};
  		mxCell.prototype.insert = function(child, index)
  		{
  			if (child != null)
  			{
  				if (index == null)
  				{
  					index = this.getChildCount();
  					if (child.getParent() == this)
  					{
  						index--;
  					}
  				}
  				child.removeFromParent();
  				child.setParent(this);
  				if (this.children == null)
  				{
  					this.children = [];
  					this.children.push(child);
  				}
  				else
  				{
  					this.children.splice(index, 0, child);
  				}
  			}
  			return child;
  		};
  		mxCell.prototype.remove = function(index)
  		{
  			var child = null;
  			if (this.children != null && index >= 0)
  			{
  				child = this.getChildAt(index);
  				if (child != null)
  				{
  					this.children.splice(index, 1);
  					child.setParent(null);
  				}
  			}
  			return child;
  		};
  		mxCell.prototype.removeFromParent = function()
  		{
  			if (this.parent != null)
  			{
  				var index = this.parent.getIndex(this);
  				this.parent.remove(index);
  			}
  		};
  		mxCell.prototype.getEdgeCount = function()
  		{
  			return (this.edges == null) ? 0 : this.edges.length;
  		};
  		mxCell.prototype.getEdgeIndex = function(edge)
  		{
  			return mxUtils.indexOf(this.edges, edge);
  		};
  		mxCell.prototype.getEdgeAt = function(index)
  		{
  			return (this.edges == null) ? null : this.edges[index];
  		};
  		mxCell.prototype.insertEdge = function(edge, isOutgoing)
  		{
  			if (edge != null)
  			{
  				edge.removeFromTerminal(isOutgoing);
  				edge.setTerminal(this, isOutgoing);
  				if (this.edges == null ||
  					edge.getTerminal(!isOutgoing) != this ||
  					mxUtils.indexOf(this.edges, edge) < 0)
  				{
  					if (this.edges == null)
  					{
  						this.edges = [];
  					}
  					this.edges.push(edge);
  				}
  			}
  			return edge;
  		};
  		mxCell.prototype.removeEdge = function(edge, isOutgoing)
  		{
  			if (edge != null)
  			{
  				if (edge.getTerminal(!isOutgoing) != this &&
  					this.edges != null)
  				{
  					var index = this.getEdgeIndex(edge);
  					if (index >= 0)
  					{
  						this.edges.splice(index, 1);
  					}
  				}
  				edge.setTerminal(null, isOutgoing);
  			}
  			return edge;
  		};
  		mxCell.prototype.removeFromTerminal = function(isSource)
  		{
  			var terminal = this.getTerminal(isSource);
  			if (terminal != null)
  			{
  				terminal.removeEdge(this, isSource);
  			}
  		};
  		mxCell.prototype.hasAttribute = function(name)
  		{
  			var userObject = this.getValue();
  			return (userObject != null &&
  				userObject.nodeType == mxConstants.NODETYPE_ELEMENT && userObject.hasAttribute) ?
  				userObject.hasAttribute(name) : userObject.getAttribute(name) != null;
  		};
  		mxCell.prototype.getAttribute = function(name, defaultValue)
  		{
  			var userObject = this.getValue();
  			var val = (userObject != null &&
  				userObject.nodeType == mxConstants.NODETYPE_ELEMENT) ?
  				userObject.getAttribute(name) : null;
  			return (val != null) ? val : defaultValue;
  		};
  		mxCell.prototype.setAttribute = function(name, value)
  		{
  			var userObject = this.getValue();
  			if (userObject != null &&
  				userObject.nodeType == mxConstants.NODETYPE_ELEMENT)
  			{
  				userObject.setAttribute(name, value);
  			}
  		};
  		mxCell.prototype.clone = function()
  		{
  			var clone = mxUtils.clone(this, this.mxTransient);
  			clone.setValue(this.cloneValue());
  			return clone;
  		};
  		mxCell.prototype.cloneValue = function()
  		{
  			var value = this.getValue();
  			if (value != null)
  			{
  				if (typeof(value.clone) == 'function')
  				{
  					value = value.clone();
  				}
  				else if (!isNaN(value.nodeType))
  				{
  					value = value.cloneNode(true);
  				}
  			}
  			return value;
  		};
  		__mxOutput.mxCell = typeof mxCell !== 'undefined' ? mxCell : undefined;
  		function mxGeometry(x, y, width, height)
  		{
  			mxRectangle.call(this, x, y, width, height);
  		}		mxGeometry.prototype = new mxRectangle();
  		mxGeometry.prototype.constructor = mxGeometry;
  		mxGeometry.prototype.TRANSLATE_CONTROL_POINTS = true;
  		mxGeometry.prototype.alternateBounds = null;
  		mxGeometry.prototype.sourcePoint = null;
  		mxGeometry.prototype.targetPoint = null;
  		mxGeometry.prototype.points = null;
  		mxGeometry.prototype.offset = null;
  		mxGeometry.prototype.relative = false;
  		mxGeometry.prototype.swap = function()
  		{
  			if (this.alternateBounds != null)
  			{
  				var old = new mxRectangle(
  					this.x, this.y, this.width, this.height);
  				this.x = this.alternateBounds.x;
  				this.y = this.alternateBounds.y;
  				this.width = this.alternateBounds.width;
  				this.height = this.alternateBounds.height;
  				this.alternateBounds = old;
  			}
  		};
  		mxGeometry.prototype.getTerminalPoint = function(isSource)
  		{
  			return (isSource) ? this.sourcePoint : this.targetPoint;
  		};
  		mxGeometry.prototype.setTerminalPoint = function(point, isSource)
  		{
  			if (isSource)
  			{
  				this.sourcePoint = point;
  			}
  			else
  			{
  				this.targetPoint = point;
  			}
  			return point;
  		};
  		mxGeometry.prototype.rotate = function(angle, cx)
  		{
  			var rad = mxUtils.toRadians(angle);
  			var cos = Math.cos(rad);
  			var sin = Math.sin(rad);
  			if (!this.relative)
  			{
  				var ct = new mxPoint(this.getCenterX(), this.getCenterY());
  				var pt = mxUtils.getRotatedPoint(ct, cos, sin, cx);
  				this.x = Math.round(pt.x - this.width / 2);
  				this.y = Math.round(pt.y - this.height / 2);
  			}
  			if (this.sourcePoint != null)
  			{
  				var pt = mxUtils.getRotatedPoint(this.sourcePoint, cos, sin, cx);
  				this.sourcePoint.x = Math.round(pt.x);
  				this.sourcePoint.y = Math.round(pt.y);
  			}
  			if (this.targetPoint != null)
  			{
  				var pt = mxUtils.getRotatedPoint(this.targetPoint, cos, sin, cx);
  				this.targetPoint.x = Math.round(pt.x);
  				this.targetPoint.y = Math.round(pt.y);
  			}
  			if (this.points != null)
  			{
  				for (var i = 0; i < this.points.length; i++)
  				{
  					if (this.points[i] != null)
  					{
  						var pt = mxUtils.getRotatedPoint(this.points[i], cos, sin, cx);
  						this.points[i].x = Math.round(pt.x);
  						this.points[i].y = Math.round(pt.y);
  					}
  				}
  			}
  		};
  		mxGeometry.prototype.translate = function(dx, dy)
  		{
  			dx = parseFloat(dx);
  			dy = parseFloat(dy);
  			if (!this.relative)
  			{
  				this.x = parseFloat(this.x) + dx;
  				this.y = parseFloat(this.y) + dy;
  			}
  			if (this.sourcePoint != null)
  			{
  				this.sourcePoint.x = parseFloat(this.sourcePoint.x) + dx;
  				this.sourcePoint.y = parseFloat(this.sourcePoint.y) + dy;
  			}
  			if (this.targetPoint != null)
  			{
  				this.targetPoint.x = parseFloat(this.targetPoint.x) + dx;
  				this.targetPoint.y = parseFloat(this.targetPoint.y) + dy;
  			}
  			if (this.TRANSLATE_CONTROL_POINTS && this.points != null)
  			{
  				for (var i = 0; i < this.points.length; i++)
  				{
  					if (this.points[i] != null)
  					{
  						this.points[i].x = parseFloat(this.points[i].x) + dx;
  						this.points[i].y = parseFloat(this.points[i].y) + dy;
  					}
  				}
  			}
  		};
  		mxGeometry.prototype.scale = function(sx, sy, fixedAspect)
  		{
  			sx = parseFloat(sx);
  			sy = parseFloat(sy);
  			if (this.sourcePoint != null)
  			{
  				this.sourcePoint.x = parseFloat(this.sourcePoint.x) * sx;
  				this.sourcePoint.y = parseFloat(this.sourcePoint.y) * sy;
  			}
  			if (this.targetPoint != null)
  			{
  				this.targetPoint.x = parseFloat(this.targetPoint.x) * sx;
  				this.targetPoint.y = parseFloat(this.targetPoint.y) * sy;
  			}
  			if (this.points != null)
  			{
  				for (var i = 0; i < this.points.length; i++)
  				{
  					if (this.points[i] != null)
  					{
  						this.points[i].x = parseFloat(this.points[i].x) * sx;
  						this.points[i].y = parseFloat(this.points[i].y) * sy;
  					}
  				}
  			}
  			if (!this.relative)
  			{
  				this.x = parseFloat(this.x) * sx;
  				this.y = parseFloat(this.y) * sy;
  				if (fixedAspect)
  				{
  					sy = sx = Math.min(sx, sy);
  				}
  				this.width = parseFloat(this.width) * sx;
  				this.height = parseFloat(this.height) * sy;
  			}
  		};
  		mxGeometry.prototype.equals = function(obj)
  		{
  			return mxRectangle.prototype.equals.apply(this, arguments) &&
  				this.relative == obj.relative &&
  				((this.sourcePoint == null && obj.sourcePoint == null) || (this.sourcePoint != null && this.sourcePoint.equals(obj.sourcePoint))) &&
  				((this.targetPoint == null && obj.targetPoint == null) || (this.targetPoint != null && this.targetPoint.equals(obj.targetPoint))) &&
  				((this.points == null && obj.points == null) || (this.points != null && mxUtils.equalPoints(this.points, obj.points))) &&
  				((this.alternateBounds == null && obj.alternateBounds == null) || (this.alternateBounds != null && this.alternateBounds.equals(obj.alternateBounds))) &&
  				((this.offset == null && obj.offset == null) || (this.offset != null && this.offset.equals(obj.offset)));
  		};
  		__mxOutput.mxGeometry = typeof mxGeometry !== 'undefined' ? mxGeometry : undefined;
  		var mxCellPath =
  		{
  			PATH_SEPARATOR: '.',
  			create: function(cell)
  			{
  				var result = '';
  				if (cell != null)
  				{
  					var parent = cell.getParent();
  					while (parent != null)
  					{
  						var index = parent.getIndex(cell);
  						result = index + mxCellPath.PATH_SEPARATOR + result;
  						cell = parent;
  						parent = cell.getParent();
  					}
  				}
  				var n = result.length;
  				if (n > 1)
  				{
  					result = result.substring(0, n - 1);
  				}
  				return result;
  			},
  			getParentPath: function(path)
  			{
  				if (path != null)
  				{
  					var index = path.lastIndexOf(mxCellPath.PATH_SEPARATOR);
  					if (index >= 0)
  					{
  						return path.substring(0, index);
  					}
  					else if (path.length > 0)
  					{
  						return '';
  					}
  				}
  				return null;
  			},
  			resolve: function(root, path)
  			{
  				var parent = root;
  				if (path != null)
  				{
  					var tokens = path.split(mxCellPath.PATH_SEPARATOR);
  					for (var i=0; i<tokens.length; i++)
  					{
  						parent = parent.getChildAt(parseInt(tokens[i]));
  					}
  				}
  				return parent;
  			},
  			compare: function(p1, p2)
  			{
  				var min = Math.min(p1.length, p2.length);
  				var comp = 0;
  				for (var i = 0; i < min; i++)
  				{
  					if (p1[i] != p2[i])
  					{
  						if (p1[i].length == 0 ||
  							p2[i].length == 0)
  						{
  							comp = (p1[i] == p2[i]) ? 0 : ((p1[i] > p2[i]) ? 1 : -1);
  						}
  						else
  						{
  							var t1 = parseInt(p1[i]);
  							var t2 = parseInt(p2[i]);
  							comp = (t1 == t2) ? 0 : ((t1 > t2) ? 1 : -1);
  						}
  						break;
  					}
  				}
  				if (comp == 0)
  				{
  					var t1 = p1.length;
  					var t2 = p2.length;
  					if (t1 != t2)
  					{
  						comp = (t1 > t2) ? 1 : -1;
  					}
  				}
  				return comp;
  			}
  		};
  		__mxOutput.mxCellPath = typeof mxCellPath !== 'undefined' ? mxCellPath : undefined;
  		var mxPerimeter =
  		{
  			RectanglePerimeter: function (bounds, vertex, next, orthogonal)
  			{
  				var cx = bounds.getCenterX();
  				var cy = bounds.getCenterY();
  				var dx = next.x - cx;
  				var dy = next.y - cy;
  				var alpha = Math.atan2(dy, dx);
  				var p = new mxPoint(0, 0);
  				var pi = Math.PI;
  				var pi2 = Math.PI/2;
  				var beta = pi2 - alpha;
  				var t = Math.atan2(bounds.height, bounds.width);
  				if (alpha < -pi + t || alpha > pi - t)
  				{
  					p.x = bounds.x;
  					p.y = cy - bounds.width * Math.tan(alpha) / 2;
  				}
  				else if (alpha < -t)
  				{
  					p.y = bounds.y;
  					p.x = cx - bounds.height * Math.tan(beta) / 2;
  				}
  				else if (alpha < t)
  				{
  					p.x = bounds.x + bounds.width;
  					p.y = cy + bounds.width * Math.tan(alpha) / 2;
  				}
  				else
  				{
  					p.y = bounds.y + bounds.height;
  					p.x = cx + bounds.height * Math.tan(beta) / 2;
  				}
  				if (orthogonal)
  				{
  					if (next.x >= bounds.x &&
  						next.x <= bounds.x + bounds.width)
  					{
  						p.x = next.x;
  					}
  					else if (next.y >= bounds.y &&
  							   next.y <= bounds.y + bounds.height)
  					{
  						p.y = next.y;
  					}
  					if (next.x < bounds.x)
  					{
  						p.x = bounds.x;
  					}
  					else if (next.x > bounds.x + bounds.width)
  					{
  						p.x = bounds.x + bounds.width;
  					}
  					if (next.y < bounds.y)
  					{
  						p.y = bounds.y;
  					}
  					else if (next.y > bounds.y + bounds.height)
  					{
  						p.y = bounds.y + bounds.height;
  					}
  				}
  				return p;
  			},
  			EllipsePerimeter: function (bounds, vertex, next, orthogonal)
  			{
  				var x = bounds.x;
  				var y = bounds.y;
  				var a = bounds.width / 2;
  				var b = bounds.height / 2;
  				var cx = x + a;
  				var cy = y + b;
  				var px = next.x;
  				var py = next.y;
  				var dx = parseInt(px - cx);
  				var dy = parseInt(py - cy);
  				if (dx == 0 && dy != 0)
  				{
  					return new mxPoint(cx, cy + b * dy / Math.abs(dy));
  				}
  				else if (dx == 0 && dy == 0)
  				{
  					return new mxPoint(px, py);
  				}
  				if (orthogonal)
  				{
  					if (py >= y && py <= y + bounds.height)
  					{
  						var ty = py - cy;
  						var tx = Math.sqrt(a*a*(1-(ty*ty)/(b*b))) || 0;
  						if (px <= x)
  						{
  							tx = -tx;
  						}
  						return new mxPoint(cx+tx, py);
  					}
  					if (px >= x && px <= x + bounds.width)
  					{
  						var tx = px - cx;
  						var ty = Math.sqrt(b*b*(1-(tx*tx)/(a*a))) || 0;
  						if (py <= y)
  						{
  							ty = -ty;
  						}
  						return new mxPoint(px, cy+ty);
  					}
  				}
  				var d = dy / dx;
  				var h = cy - d * cx;
  				var e = a * a * d * d + b * b;
  				var f = -2 * cx * e;
  				var g = a * a * d * d * cx * cx +
  						b * b * cx * cx -
  						a * a * b * b;
  				var det = Math.sqrt(f * f - 4 * e * g);
  				var xout1 = (-f + det) / (2 * e);
  				var xout2 = (-f - det) / (2 * e);
  				var yout1 = d * xout1 + h;
  				var yout2 = d * xout2 + h;
  				var dist1 = Math.sqrt(Math.pow((xout1 - px), 2)
  							+ Math.pow((yout1 - py), 2));
  				var dist2 = Math.sqrt(Math.pow((xout2 - px), 2)
  							+ Math.pow((yout2 - py), 2));
  				var xout = 0;
  				var yout = 0;
  				if (dist1 < dist2)
  				{
  					xout = xout1;
  					yout = yout1;
  				}
  				else
  				{
  					xout = xout2;
  					yout = yout2;
  				}
  				return new mxPoint(xout, yout);
  			},
  			RhombusPerimeter: function (bounds, vertex, next, orthogonal)
  			{
  				var x = bounds.x;
  				var y = bounds.y;
  				var w = bounds.width;
  				var h = bounds.height;
  				var cx = x + w / 2;
  				var cy = y + h / 2;
  				var px = next.x;
  				var py = next.y;
  				if (cx == px)
  				{
  					if (cy > py)
  					{
  						return new mxPoint(cx, y);
  					}
  					else
  					{
  						return new mxPoint(cx, y + h);
  					}
  				}
  				else if (cy == py)
  				{
  					if (cx > px)
  					{
  						return new mxPoint(x, cy);
  					}
  					else
  					{
  						return new mxPoint(x + w, cy);
  					}
  				}
  				var tx = cx;
  				var ty = cy;
  				if (orthogonal)
  				{
  					if (px >= x && px <= x + w)
  					{
  						tx = px;
  					}
  					else if (py >= y && py <= y + h)
  					{
  						ty = py;
  					}
  				}
  				if (px < cx)
  				{
  					if (py < cy)
  					{
  						return mxUtils.intersection(px, py, tx, ty, cx, y, x, cy);
  					}
  					else
  					{
  						return mxUtils.intersection(px, py, tx, ty, cx, y + h, x, cy);
  					}
  				}
  				else if (py < cy)
  				{
  					return mxUtils.intersection(px, py, tx, ty, cx, y, x + w, cy);
  				}
  				else
  				{
  					return mxUtils.intersection(px, py, tx, ty, cx, y + h, x + w, cy);
  				}
  			},
  			TrianglePerimeter: function (bounds, vertex, next, orthogonal)
  			{
  				var direction = (vertex != null) ?
  					vertex.style[mxConstants.STYLE_DIRECTION] : null;
  				var vertical = direction == mxConstants.DIRECTION_NORTH ||
  					direction == mxConstants.DIRECTION_SOUTH;
  				var x = bounds.x;
  				var y = bounds.y;
  				var w = bounds.width;
  				var h = bounds.height;
  				var cx = x + w / 2;
  				var cy = y + h / 2;
  				var start = new mxPoint(x, y);
  				var corner = new mxPoint(x + w, cy);
  				var end = new mxPoint(x, y + h);
  				if (direction == mxConstants.DIRECTION_NORTH)
  				{
  					start = end;
  					corner = new mxPoint(cx, y);
  					end = new mxPoint(x + w, y + h);
  				}
  				else if (direction == mxConstants.DIRECTION_SOUTH)
  				{
  					corner = new mxPoint(cx, y + h);
  					end = new mxPoint(x + w, y);
  				}
  				else if (direction == mxConstants.DIRECTION_WEST)
  				{
  					start = new mxPoint(x + w, y);
  					corner = new mxPoint(x, cy);
  					end = new mxPoint(x + w, y + h);
  				}
  				var dx = next.x - cx;
  				var dy = next.y - cy;
  				var alpha = (vertical) ? Math.atan2(dx, dy) : Math.atan2(dy, dx);
  				var t = (vertical) ? Math.atan2(w, h) : Math.atan2(h, w);
  				var base = false;
  				if (direction == mxConstants.DIRECTION_NORTH ||
  					direction == mxConstants.DIRECTION_WEST)
  				{
  					base = alpha > -t && alpha < t;
  				}
  				else
  				{
  					base = alpha < -Math.PI + t || alpha > Math.PI - t;
  				}
  				var result = null;
  				if (base)
  				{
  					if (orthogonal && ((vertical && next.x >= start.x && next.x <= end.x) ||
  						(!vertical && next.y >= start.y && next.y <= end.y)))
  					{
  						if (vertical)
  						{
  							result = new mxPoint(next.x, start.y);
  						}
  						else
  						{
  							result = new mxPoint(start.x, next.y);
  						}
  					}
  					else
  					{
  						if (direction == mxConstants.DIRECTION_NORTH)
  						{
  							result = new mxPoint(x + w / 2 + h * Math.tan(alpha) / 2,
  								y + h);
  						}
  						else if (direction == mxConstants.DIRECTION_SOUTH)
  						{
  							result = new mxPoint(x + w / 2 - h * Math.tan(alpha) / 2,
  								y);
  						}
  						else if (direction == mxConstants.DIRECTION_WEST)
  						{
  							result = new mxPoint(x + w, y + h / 2 +
  								w * Math.tan(alpha) / 2);
  						}
  						else
  						{
  							result = new mxPoint(x, y + h / 2 -
  								w * Math.tan(alpha) / 2);
  						}
  					}
  				}
  				else
  				{
  					if (orthogonal)
  					{
  						var pt = new mxPoint(cx, cy);
  						if (next.y >= y && next.y <= y + h)
  						{
  							pt.x = (vertical) ? cx : (
  								(direction == mxConstants.DIRECTION_WEST) ?
  									x + w : x);
  							pt.y = next.y;
  						}
  						else if (next.x >= x && next.x <= x + w)
  						{
  							pt.x = next.x;
  							pt.y = (!vertical) ? cy : (
  								(direction == mxConstants.DIRECTION_NORTH) ?
  									y + h : y);
  						}
  						dx = next.x - pt.x;
  						dy = next.y - pt.y;
  						cx = pt.x;
  						cy = pt.y;
  					}
  					if ((vertical && next.x <= x + w / 2) ||
  						(!vertical && next.y <= y + h / 2))
  					{
  						result = mxUtils.intersection(next.x, next.y, cx, cy,
  							start.x, start.y, corner.x, corner.y);
  					}
  					else
  					{
  						result = mxUtils.intersection(next.x, next.y, cx, cy,
  							corner.x, corner.y, end.x, end.y);
  					}
  				}
  				if (result == null)
  				{
  					result = new mxPoint(cx, cy);
  				}
  				return result;
  			},
  			HexagonPerimeter: function (bounds, vertex, next, orthogonal)
  			{
  				var x = bounds.x;
  				var y = bounds.y;
  				var w = bounds.width;
  				var h = bounds.height;
  				var cx = bounds.getCenterX();
  				var cy = bounds.getCenterY();
  				var px = next.x;
  				var py = next.y;
  				var dx = px - cx;
  				var dy = py - cy;
  				var alpha = -Math.atan2(dy, dx);
  				var pi = Math.PI;
  				var pi2 = Math.PI / 2;
  				var result = new mxPoint(cx, cy);
  				var direction = (vertex != null) ? mxUtils.getValue(
  						vertex.style, mxConstants.STYLE_DIRECTION,
  						mxConstants.DIRECTION_EAST) : mxConstants.DIRECTION_EAST;
  				var vertical = direction == mxConstants.DIRECTION_NORTH
  						|| direction == mxConstants.DIRECTION_SOUTH;
  				var a = new mxPoint();
  				var b = new mxPoint();
  				if ((px < x) && (py < y) || (px < x) && (py > y + h)
  						|| (px > x + w) && (py < y) || (px > x + w) && (py > y + h))
  				{
  					orthogonal = false;
  				}
  				if (orthogonal)
  				{
  					if (vertical)
  					{
  						if (px == cx)
  						{
  							if (py <= y)
  							{
  								return new mxPoint(cx, y);
  							}
  							else if (py >= y + h)
  							{
  								return new mxPoint(cx, y + h);
  							}
  						}
  						else if (px < x)
  						{
  							if (py == y + h / 4)
  							{
  								return new mxPoint(x, y + h / 4);
  							}
  							else if (py == y + 3 * h / 4)
  							{
  								return new mxPoint(x, y + 3 * h / 4);
  							}
  						}
  						else if (px > x + w)
  						{
  							if (py == y + h / 4)
  							{
  								return new mxPoint(x + w, y + h / 4);
  							}
  							else if (py == y + 3 * h / 4)
  							{
  								return new mxPoint(x + w, y + 3 * h / 4);
  							}
  						}
  						else if (px == x)
  						{
  							if (py < cy)
  							{
  								return new mxPoint(x, y + h / 4);
  							}
  							else if (py > cy)
  							{
  								return new mxPoint(x, y + 3 * h / 4);
  							}
  						}
  						else if (px == x + w)
  						{
  							if (py < cy)
  							{
  								return new mxPoint(x + w, y + h / 4);
  							}
  							else if (py > cy)
  							{
  								return new mxPoint(x + w, y + 3 * h / 4);
  							}
  						}
  						if (py == y)
  						{
  							return new mxPoint(cx, y);
  						}
  						else if (py == y + h)
  						{
  							return new mxPoint(cx, y + h);
  						}
  						if (px < cx)
  						{
  							if ((py > y + h / 4) && (py < y + 3 * h / 4))
  							{
  								a = new mxPoint(x, y);
  								b = new mxPoint(x, y + h);
  							}
  							else if (py < y + h / 4)
  							{
  								a = new mxPoint(x - Math.floor(0.5 * w), y
  										+ Math.floor(0.5 * h));
  								b = new mxPoint(x + w, y - Math.floor(0.25 * h));
  							}
  							else if (py > y + 3 * h / 4)
  							{
  								a = new mxPoint(x - Math.floor(0.5 * w), y
  										+ Math.floor(0.5 * h));
  								b = new mxPoint(x + w, y + Math.floor(1.25 * h));
  							}
  						}
  						else if (px > cx)
  						{
  							if ((py > y + h / 4) && (py < y + 3 * h / 4))
  							{
  								a = new mxPoint(x + w, y);
  								b = new mxPoint(x + w, y + h);
  							}
  							else if (py < y + h / 4)
  							{
  								a = new mxPoint(x, y - Math.floor(0.25 * h));
  								b = new mxPoint(x + Math.floor(1.5 * w), y
  										+ Math.floor(0.5 * h));
  							}
  							else if (py > y + 3 * h / 4)
  							{
  								a = new mxPoint(x + Math.floor(1.5 * w), y
  										+ Math.floor(0.5 * h));
  								b = new mxPoint(x, y + Math.floor(1.25 * h));
  							}
  						}
  					}
  					else
  					{
  						if (py == cy)
  						{
  							if (px <= x)
  							{
  								return new mxPoint(x, y + h / 2);
  							}
  							else if (px >= x + w)
  							{
  								return new mxPoint(x + w, y + h / 2);
  							}
  						}
  						else if (py < y)
  						{
  							if (px == x + w / 4)
  							{
  								return new mxPoint(x + w / 4, y);
  							}
  							else if (px == x + 3 * w / 4)
  							{
  								return new mxPoint(x + 3 * w / 4, y);
  							}
  						}
  						else if (py > y + h)
  						{
  							if (px == x + w / 4)
  							{
  								return new mxPoint(x + w / 4, y + h);
  							}
  							else if (px == x + 3 * w / 4)
  							{
  								return new mxPoint(x + 3 * w / 4, y + h);
  							}
  						}
  						else if (py == y)
  						{
  							if (px < cx)
  							{
  								return new mxPoint(x + w / 4, y);
  							}
  							else if (px > cx)
  							{
  								return new mxPoint(x + 3 * w / 4, y);
  							}
  						}
  						else if (py == y + h)
  						{
  							if (px < cx)
  							{
  								return new mxPoint(x + w / 4, y + h);
  							}
  							else if (py > cy)
  							{
  								return new mxPoint(x + 3 * w / 4, y + h);
  							}
  						}
  						if (px == x)
  						{
  							return new mxPoint(x, cy);
  						}
  						else if (px == x + w)
  						{
  							return new mxPoint(x + w, cy);
  						}
  						if (py < cy)
  						{
  							if ((px > x + w / 4) && (px < x + 3 * w / 4))
  							{
  								a = new mxPoint(x, y);
  								b = new mxPoint(x + w, y);
  							}
  							else if (px < x + w / 4)
  							{
  								a = new mxPoint(x - Math.floor(0.25 * w), y + h);
  								b = new mxPoint(x + Math.floor(0.5 * w), y
  										- Math.floor(0.5 * h));
  							}
  							else if (px > x + 3 * w / 4)
  							{
  								a = new mxPoint(x + Math.floor(0.5 * w), y
  										- Math.floor(0.5 * h));
  								b = new mxPoint(x + Math.floor(1.25 * w), y + h);
  							}
  						}
  						else if (py > cy)
  						{
  							if ((px > x + w / 4) && (px < x + 3 * w / 4))
  							{
  								a = new mxPoint(x, y + h);
  								b = new mxPoint(x + w, y + h);
  							}
  							else if (px < x + w / 4)
  							{
  								a = new mxPoint(x - Math.floor(0.25 * w), y);
  								b = new mxPoint(x + Math.floor(0.5 * w), y
  										+ Math.floor(1.5 * h));
  							}
  							else if (px > x + 3 * w / 4)
  							{
  								a = new mxPoint(x + Math.floor(0.5 * w), y
  										+ Math.floor(1.5 * h));
  								b = new mxPoint(x + Math.floor(1.25 * w), y);
  							}
  						}
  					}
  					var tx = cx;
  					var ty = cy;
  					if (px >= x && px <= x + w)
  					{
  						tx = px;
  						if (py < cy)
  						{
  							ty = y + h;
  						}
  						else
  						{
  							ty = y;
  						}
  					}
  					else if (py >= y && py <= y + h)
  					{
  						ty = py;
  						if (px < cx)
  						{
  							tx = x + w;
  						}
  						else
  						{
  							tx = x;
  						}
  					}
  					result = mxUtils.intersection(tx, ty, next.x, next.y, a.x, a.y, b.x, b.y);
  				}
  				else
  				{
  					if (vertical)
  					{
  						var beta = Math.atan2(h / 4, w / 2);
  						if (alpha == beta)
  						{
  							return new mxPoint(x + w, y + Math.floor(0.25 * h));
  						}
  						else if (alpha == pi2)
  						{
  							return new mxPoint(x + Math.floor(0.5 * w), y);
  						}
  						else if (alpha == (pi - beta))
  						{
  							return new mxPoint(x, y + Math.floor(0.25 * h));
  						}
  						else if (alpha == -beta)
  						{
  							return new mxPoint(x + w, y + Math.floor(0.75 * h));
  						}
  						else if (alpha == (-pi2))
  						{
  							return new mxPoint(x + Math.floor(0.5 * w), y + h);
  						}
  						else if (alpha == (-pi + beta))
  						{
  							return new mxPoint(x, y + Math.floor(0.75 * h));
  						}
  						if ((alpha < beta) && (alpha > -beta))
  						{
  							a = new mxPoint(x + w, y);
  							b = new mxPoint(x + w, y + h);
  						}
  						else if ((alpha > beta) && (alpha < pi2))
  						{
  							a = new mxPoint(x, y - Math.floor(0.25 * h));
  							b = new mxPoint(x + Math.floor(1.5 * w), y
  									+ Math.floor(0.5 * h));
  						}
  						else if ((alpha > pi2) && (alpha < (pi - beta)))
  						{
  							a = new mxPoint(x - Math.floor(0.5 * w), y
  									+ Math.floor(0.5 * h));
  							b = new mxPoint(x + w, y - Math.floor(0.25 * h));
  						}
  						else if (((alpha > (pi - beta)) && (alpha <= pi))
  								|| ((alpha < (-pi + beta)) && (alpha >= -pi)))
  						{
  							a = new mxPoint(x, y);
  							b = new mxPoint(x, y + h);
  						}
  						else if ((alpha < -beta) && (alpha > -pi2))
  						{
  							a = new mxPoint(x + Math.floor(1.5 * w), y
  									+ Math.floor(0.5 * h));
  							b = new mxPoint(x, y + Math.floor(1.25 * h));
  						}
  						else if ((alpha < -pi2) && (alpha > (-pi + beta)))
  						{
  							a = new mxPoint(x - Math.floor(0.5 * w), y
  									+ Math.floor(0.5 * h));
  							b = new mxPoint(x + w, y + Math.floor(1.25 * h));
  						}
  					}
  					else
  					{
  						var beta = Math.atan2(h / 2, w / 4);
  						if (alpha == beta)
  						{
  							return new mxPoint(x + Math.floor(0.75 * w), y);
  						}
  						else if (alpha == (pi - beta))
  						{
  							return new mxPoint(x + Math.floor(0.25 * w), y);
  						}
  						else if ((alpha == pi) || (alpha == -pi))
  						{
  							return new mxPoint(x, y + Math.floor(0.5 * h));
  						}
  						else if (alpha == 0)
  						{
  							return new mxPoint(x + w, y + Math.floor(0.5 * h));
  						}
  						else if (alpha == -beta)
  						{
  							return new mxPoint(x + Math.floor(0.75 * w), y + h);
  						}
  						else if (alpha == (-pi + beta))
  						{
  							return new mxPoint(x + Math.floor(0.25 * w), y + h);
  						}
  						if ((alpha > 0) && (alpha < beta))
  						{
  							a = new mxPoint(x + Math.floor(0.5 * w), y
  									- Math.floor(0.5 * h));
  							b = new mxPoint(x + Math.floor(1.25 * w), y + h);
  						}
  						else if ((alpha > beta) && (alpha < (pi - beta)))
  						{
  							a = new mxPoint(x, y);
  							b = new mxPoint(x + w, y);
  						}
  						else if ((alpha > (pi - beta)) && (alpha < pi))
  						{
  							a = new mxPoint(x - Math.floor(0.25 * w), y + h);
  							b = new mxPoint(x + Math.floor(0.5 * w), y
  									- Math.floor(0.5 * h));
  						}
  						else if ((alpha < 0) && (alpha > -beta))
  						{
  							a = new mxPoint(x + Math.floor(0.5 * w), y
  									+ Math.floor(1.5 * h));
  							b = new mxPoint(x + Math.floor(1.25 * w), y);
  						}
  						else if ((alpha < -beta) && (alpha > (-pi + beta)))
  						{
  							a = new mxPoint(x, y + h);
  							b = new mxPoint(x + w, y + h);
  						}
  						else if ((alpha < (-pi + beta)) && (alpha > -pi))
  						{
  							a = new mxPoint(x - Math.floor(0.25 * w), y);
  							b = new mxPoint(x + Math.floor(0.5 * w), y
  									+ Math.floor(1.5 * h));
  						}
  					}
  					result = mxUtils.intersection(cx, cy, next.x, next.y, a.x, a.y, b.x, b.y);
  				}
  				if (result == null)
  				{
  					return new mxPoint(cx, cy);
  				}
  				return result;
  			}
  		};
  		__mxOutput.mxPerimeter = typeof mxPerimeter !== 'undefined' ? mxPerimeter : undefined;
  		function mxPrintPreview(graph, scale, pageFormat, border, x0, y0, borderColor, title, pageSelector)
  		{
  			this.graph = graph;
  			this.scale = (scale != null) ? scale : 1 / graph.pageScale;
  			this.border = (border != null) ? border : 0;
  			this.pageFormat = mxRectangle.fromRectangle((pageFormat != null) ? pageFormat : graph.pageFormat);
  			this.title = (title != null) ? title : 'Printer-friendly version';
  			this.x0 = (x0 != null) ? x0 : 0;
  			this.y0 = (y0 != null) ? y0 : 0;
  			this.borderColor = borderColor;
  			this.pageSelector = (pageSelector != null) ? pageSelector : true;
  		}		mxPrintPreview.prototype.graph = null;
  		mxPrintPreview.prototype.pageFormat = null;
  		mxPrintPreview.prototype.scale = null;
  		mxPrintPreview.prototype.border = 0;
  		mxPrintPreview.prototype.marginTop = 0;
  		mxPrintPreview.prototype.marginBottom = 0;
  		mxPrintPreview.prototype.x0 = 0;
  		mxPrintPreview.prototype.y0 = 0;
  		mxPrintPreview.prototype.autoOrigin = true;
  		mxPrintPreview.prototype.printOverlays = false;
  		mxPrintPreview.prototype.printControls = false;
  		mxPrintPreview.prototype.printBackgroundImage = false;
  		mxPrintPreview.prototype.backgroundColor = '#ffffff';
  		mxPrintPreview.prototype.borderColor = null;
  		mxPrintPreview.prototype.title = null;
  		mxPrintPreview.prototype.pageSelector = null;
  		mxPrintPreview.prototype.wnd = null;
  		mxPrintPreview.prototype.targetWindow = null;
  		mxPrintPreview.prototype.pageCount = 0;
  		mxPrintPreview.prototype.clipping = true;
  		mxPrintPreview.prototype.getWindow = function()
  		{
  			return this.wnd;
  		};
  		mxPrintPreview.prototype.getDoctype = function()
  		{
  			var dt = '';
  			if (document.documentMode == 5)
  			{
  				dt = '<meta http-equiv="X-UA-Compatible" content="IE=5">';
  			}
  			else if (document.documentMode == 8)
  			{
  				dt = '<meta http-equiv="X-UA-Compatible" content="IE=8">';
  			}
  			else if (document.documentMode > 8)
  			{
  				dt = '<!--[if IE]><meta http-equiv="X-UA-Compatible" content="IE=edge"><![endif]-->';
  			}
  			return dt;
  		};
  		mxPrintPreview.prototype.appendGraph = function(graph, scale, x0, y0, forcePageBreaks, keepOpen)
  		{
  			this.graph = graph;
  			this.scale = (scale != null) ? scale : 1 / graph.pageScale;
  			this.x0 = x0;
  			this.y0 = y0;
  			this.open(null, null, forcePageBreaks, keepOpen);
  		};
  		mxPrintPreview.prototype.open = function(css, targetWindow, forcePageBreaks, keepOpen)
  		{
  			var previousInitializeOverlay = this.graph.cellRenderer.initializeOverlay;
  			var div = null;
  			try
  			{
  				if (this.printOverlays)
  				{
  					this.graph.cellRenderer.initializeOverlay = function(state, overlay)
  					{
  						overlay.init(state.view.getDrawPane());
  					};
  				}
  				if (this.printControls)
  				{
  					this.graph.cellRenderer.initControl = function(state, control, handleEvents, clickHandler)
  					{
  						control.dialect = state.view.graph.dialect;
  						control.init(state.view.getDrawPane());
  					};
  				}
  				this.wnd = (targetWindow != null) ? targetWindow : this.wnd;
  				var isNewWindow = false;
  				if (this.wnd == null)
  				{
  					isNewWindow = true;
  					this.wnd = window.open();
  				}
  				var doc = this.wnd.document;
  				if (isNewWindow)
  				{
  					var dt = this.getDoctype();
  					if (dt != null && dt.length > 0)
  					{
  						doc.writeln(dt);
  					}
  					if (mxClient.IS_VML)
  					{
  						doc.writeln('<html xmlns:v="urn:schemas-microsoft-com:vml" xmlns:o="urn:schemas-microsoft-com:office:office">');
  					}
  					else
  					{
  						if (document.compatMode === 'CSS1Compat')
  						{
  							doc.writeln('<!DOCTYPE html>');
  						}
  						doc.writeln('<html>');
  					}
  					doc.writeln('<head>');
  					this.writeHead(doc, css);
  					doc.writeln('</head>');
  					doc.writeln('<body class="mxPage">');
  				}
  				var bounds = this.graph.getGraphBounds().clone();
  				var currentScale = this.graph.getView().getScale();
  				var sc = currentScale / this.scale;
  				var tr = this.graph.getView().getTranslate();
  				if (!this.autoOrigin)
  				{
  					this.x0 -= tr.x * this.scale;
  					this.y0 -= tr.y * this.scale;
  					bounds.width += bounds.x;
  					bounds.height += bounds.y;
  					bounds.x = 0;
  					bounds.y = 0;
  					this.border = 0;
  				}
  				var availableWidth = this.pageFormat.width - (this.border * 2);
  				var availableHeight = this.pageFormat.height - (this.border * 2);
  				this.pageFormat.height += this.marginTop + this.marginBottom;
  				bounds.width /= sc;
  				bounds.height /= sc;
  				var hpages = Math.max(1, Math.ceil((bounds.width + this.x0) / availableWidth));
  				var vpages = Math.max(1, Math.ceil((bounds.height + this.y0) / availableHeight));
  				this.pageCount = hpages * vpages;
  				var writePageSelector = mxUtils.bind(this, function()
  				{
  					if (this.pageSelector && (vpages > 1 || hpages > 1))
  					{
  						var table = this.createPageSelector(vpages, hpages);
  						doc.body.appendChild(table);
  						if (mxClient.IS_IE && doc.documentMode == null || doc.documentMode == 5 || doc.documentMode == 8 || doc.documentMode == 7)
  						{
  							table.style.position = 'absolute';
  							var update = function()
  							{
  								table.style.top = ((doc.body.scrollTop || doc.documentElement.scrollTop) + 10) + 'px';
  							};
  							mxEvent.addListener(this.wnd, 'scroll', function(evt)
  							{
  								update();
  							});
  							mxEvent.addListener(this.wnd, 'resize', function(evt)
  							{
  								update();
  							});
  						}
  					}
  				});
  				var addPage = mxUtils.bind(this, function(div, addBreak)
  				{
  					if (this.borderColor != null)
  					{
  						div.style.borderColor = this.borderColor;
  						div.style.borderStyle = 'solid';
  						div.style.borderWidth = '1px';
  					}
  					div.style.background = this.backgroundColor;
  					if (forcePageBreaks || addBreak)
  					{
  						div.style.pageBreakAfter = 'always';
  					}
  					if (isNewWindow && (mxClient.IS_IE || document.documentMode >= 11 || mxClient.IS_EDGE))
  					{
  						doc.writeln(div.outerHTML);
  						div.parentNode.removeChild(div);
  					}
  					else if (mxClient.IS_IE || document.documentMode >= 11 || mxClient.IS_EDGE)
  					{
  						var clone = doc.createElement('div');
  						clone.innerHTML = div.outerHTML;
  						clone = clone.getElementsByTagName('div')[0];
  						doc.body.appendChild(clone);
  						div.parentNode.removeChild(div);
  					}
  					else
  					{
  						div.parentNode.removeChild(div);
  						doc.body.appendChild(div);
  					}
  					if (forcePageBreaks || addBreak)
  					{
  						this.addPageBreak(doc);
  					}
  				});
  				var cov = this.getCoverPages(this.pageFormat.width, this.pageFormat.height);
  				if (cov != null)
  				{
  					for (var i = 0; i < cov.length; i++)
  					{
  						addPage(cov[i], true);
  					}
  				}
  				var apx = this.getAppendices(this.pageFormat.width, this.pageFormat.height);
  				for (var i = 0; i < vpages; i++)
  				{
  					var dy = i * availableHeight / this.scale - this.y0 / this.scale +
  							(bounds.y - tr.y * currentScale) / currentScale;
  					for (var j = 0; j < hpages; j++)
  					{
  						if (this.wnd == null)
  						{
  							return null;
  						}
  						var dx = j * availableWidth / this.scale - this.x0 / this.scale +
  								(bounds.x - tr.x * currentScale) / currentScale;
  						var pageNum = i * hpages + j + 1;
  						var clip = new mxRectangle(dx, dy, availableWidth, availableHeight);
  						div = this.renderPage(this.pageFormat.width, this.pageFormat.height, 0, 0, mxUtils.bind(this, function(div)
  						{
  							this.addGraphFragment(-dx, -dy, this.scale, pageNum, div, clip);
  							if (this.printBackgroundImage)
  							{
  								this.insertBackgroundImage(div, -dx, -dy);
  							}
  						}), pageNum);
  						div.setAttribute('id', 'mxPage-'+pageNum);
  						addPage(div, apx != null || i < vpages - 1 || j < hpages - 1);
  					}
  				}
  				if (apx != null)
  				{
  					for (var i = 0; i < apx.length; i++)
  					{
  						addPage(apx[i], i < apx.length - 1);
  					}
  				}
  				if (isNewWindow && !keepOpen)
  				{
  					this.closeDocument();
  					writePageSelector();
  				}
  				this.wnd.focus();
  			}
  			catch (e)
  			{
  				if (div != null && div.parentNode != null)
  				{
  					div.parentNode.removeChild(div);
  				}
  			}
  			finally
  			{
  				this.graph.cellRenderer.initializeOverlay = previousInitializeOverlay;
  			}
  			return this.wnd;
  		};
  		mxPrintPreview.prototype.addPageBreak = function(doc)
  		{
  			var hr = doc.createElement('hr');
  			hr.className = 'mxPageBreak';
  			doc.body.appendChild(hr);
  		};
  		mxPrintPreview.prototype.closeDocument = function()
  		{
  			try
  			{
  				if (this.wnd != null && this.wnd.document != null)
  				{
  					var doc = this.wnd.document;
  					this.writePostfix(doc);
  					doc.writeln('</body>');
  					doc.writeln('</html>');
  					doc.close();
  					mxEvent.release(doc.body);
  				}
  			}
  			catch (e)
  			{
  			}
  		};
  		mxPrintPreview.prototype.writeHead = function(doc, css)
  		{
  			if (this.title != null)
  			{
  				doc.writeln('<title>' + this.title + '</title>');
  			}
  			if (mxClient.IS_VML)
  			{
  				doc.writeln('<style type="text/css">v\\:*{behavior:url(#default#VML)}o\\:*{behavior:url(#default#VML)}</style>');
  			}
  			mxClient.link('stylesheet', mxClient.basePath + '/css/common.css', doc);
  			doc.writeln('<style type="text/css">');
  			doc.writeln('@media print {');
  			doc.writeln('  * { -webkit-print-color-adjust: exact; }');
  			doc.writeln('  table.mxPageSelector { display: none; }');
  			doc.writeln('  hr.mxPageBreak { display: none; }');
  			doc.writeln('}');
  			doc.writeln('@media screen {');
  			doc.writeln('  table.mxPageSelector { position: fixed; right: 10px; top: 10px;' +
  					'font-family: Arial; font-size:10pt; border: solid 1px darkgray;' +
  					'background: white; border-collapse:collapse; }');
  			doc.writeln('  table.mxPageSelector td { border: solid 1px gray; padding:4px; }');
  			doc.writeln('  body.mxPage { background: gray; }');
  			doc.writeln('}');
  			if (css != null)
  			{
  				doc.writeln(css);
  			}
  			doc.writeln('</style>');
  		};
  		mxPrintPreview.prototype.writePostfix = function(doc)
  		{
  		};
  		mxPrintPreview.prototype.createPageSelector = function(vpages, hpages)
  		{
  			var doc = this.wnd.document;
  			var table = doc.createElement('table');
  			table.className = 'mxPageSelector';
  			table.setAttribute('border', '0');
  			var tbody = doc.createElement('tbody');
  			for (var i = 0; i < vpages; i++)
  			{
  				var row = doc.createElement('tr');
  				for (var j = 0; j < hpages; j++)
  				{
  					var pageNum = i * hpages + j + 1;
  					var cell = doc.createElement('td');
  					var a = doc.createElement('a');
  					a.setAttribute('href', '#mxPage-' + pageNum);
  					if (mxClient.IS_NS && !mxClient.IS_SF && !mxClient.IS_GC)
  					{
  						var js = 'var page = document.getElementById(\'mxPage-' + pageNum + '\');page.scrollIntoView(true);event.preventDefault();';
  						a.setAttribute('onclick', js);
  					}
  					mxUtils.write(a, pageNum, doc);
  					cell.appendChild(a);
  					row.appendChild(cell);
  				}
  				tbody.appendChild(row);
  			}
  			table.appendChild(tbody);
  			return table;
  		};
  		mxPrintPreview.prototype.renderPage = function(w, h, dx, dy, content, pageNumber)
  		{
  			var doc = this.wnd.document;
  			var div = document.createElement('div');
  			var arg = null;
  			try
  			{
  				if (dx != 0 || dy != 0)
  				{
  					div.style.position = 'relative';
  					div.style.width = w + 'px';
  					div.style.height = h + 'px';
  					div.style.pageBreakInside = 'avoid';
  					var innerDiv = document.createElement('div');
  					innerDiv.style.position = 'relative';
  					innerDiv.style.top = this.border + 'px';
  					innerDiv.style.left = this.border + 'px';
  					innerDiv.style.width = (w - 2 * this.border) + 'px';
  					innerDiv.style.height = (h - 2 * this.border) + 'px';
  					innerDiv.style.overflow = 'hidden';
  					var viewport = document.createElement('div');
  					viewport.style.position = 'relative';
  					viewport.style.marginLeft = dx + 'px';
  					viewport.style.marginTop = dy + 'px';
  					if (doc.documentMode == 8)
  					{
  						innerDiv.style.position = 'absolute';
  						viewport.style.position = 'absolute';
  					}
  					if (doc.documentMode == 10)
  					{
  						viewport.style.width = '100%';
  						viewport.style.height = '100%';
  					}
  					innerDiv.appendChild(viewport);
  					div.appendChild(innerDiv);
  					document.body.appendChild(div);
  					arg = viewport;
  				}
  				else
  				{
  					div.style.width = w + 'px';
  					div.style.height = h + 'px';
  					div.style.overflow = 'hidden';
  					div.style.pageBreakInside = 'avoid';
  					if (doc.documentMode == 8)
  					{
  						div.style.position = 'relative';
  					}
  					var innerDiv = document.createElement('div');
  					innerDiv.style.width = (w - 2 * this.border) + 'px';
  					innerDiv.style.height = (h - 2 * this.border) + 'px';
  					innerDiv.style.overflow = 'hidden';
  					if (mxClient.IS_IE && (doc.documentMode == null || doc.documentMode == 5 ||
  						doc.documentMode == 8 || doc.documentMode == 7))
  					{
  						innerDiv.style.marginTop = this.border + 'px';
  						innerDiv.style.marginLeft = this.border + 'px';
  					}
  					else
  					{
  						innerDiv.style.top = this.border + 'px';
  						innerDiv.style.left = this.border + 'px';
  					}
  					if (this.graph.dialect == mxConstants.DIALECT_VML)
  					{
  						innerDiv.style.position = 'absolute';
  					}
  					div.appendChild(innerDiv);
  					document.body.appendChild(div);
  					arg = innerDiv;
  				}
  			}
  			catch (e)
  			{
  				div.parentNode.removeChild(div);
  				div = null;
  				throw e;
  			}
  			content(arg);
  			return div;
  		};
  		mxPrintPreview.prototype.getRoot = function()
  		{
  			var root = this.graph.view.currentRoot;
  			if (root == null)
  			{
  				root = this.graph.getModel().getRoot();
  			}
  			return root;
  		};
  		mxPrintPreview.prototype.useCssTransforms = function()
  		{
  			return !mxClient.NO_FO && !mxClient.IS_SF;
  		};
  		mxPrintPreview.prototype.addGraphFragment = function(dx, dy, scale, pageNumber, div, clip)
  		{
  			var view = this.graph.getView();
  			var previousContainer = this.graph.container;
  			this.graph.container = div;
  			var canvas = view.getCanvas();
  			var backgroundPane = view.getBackgroundPane();
  			var drawPane = view.getDrawPane();
  			var overlayPane = view.getOverlayPane();
  			var realScale = scale;
  			if (this.graph.dialect == mxConstants.DIALECT_SVG)
  			{
  				view.createSvg();
  				if (this.useCssTransforms())
  				{
  					var g = view.getDrawPane().parentNode;
  					g.getAttribute('transform');
  					g.setAttribute('transformOrigin', '0 0');
  					g.setAttribute('transform', 'scale(' + scale + ',' + scale + ')' +
  						'translate(' + dx + ',' + dy + ')');
  					scale = 1;
  					dx = 0;
  					dy = 0;
  				}
  			}
  			else if (this.graph.dialect == mxConstants.DIALECT_VML)
  			{
  				view.createVml();
  			}
  			else
  			{
  				view.createHtml();
  			}
  			var eventsEnabled = view.isEventsEnabled();
  			view.setEventsEnabled(false);
  			var graphEnabled = this.graph.isEnabled();
  			this.graph.setEnabled(false);
  			var translate = view.getTranslate();
  			view.translate = new mxPoint(dx, dy);
  			var redraw = this.graph.cellRenderer.redraw;
  			var states = view.states;
  			var s = view.scale;
  			if (this.clipping)
  			{
  				var tempClip = new mxRectangle((clip.x + translate.x) * s, (clip.y + translate.y) * s,
  						clip.width * s / realScale, clip.height * s / realScale);
  				this.graph.cellRenderer.redraw = function(state, force, rendering)
  				{
  					if (state != null)
  					{
  						var orig = states.get(state.cell);
  						if (orig != null)
  						{
  							var bbox = view.getBoundingBox(orig, false);
  							if (bbox != null && bbox.width > 0 && bbox.height > 0 &&
  								!mxUtils.intersects(tempClip, bbox))
  							{
  								return;
  							}
  						}
  					}
  					redraw.apply(this, arguments);
  				};
  			}
  			var temp = null;
  			try
  			{
  				var cells = [this.getRoot()];
  				temp = new mxTemporaryCellStates(view, scale, cells, null, mxUtils.bind(this, function(state)
  				{
  					return this.getLinkForCellState(state);
  				}));
  			}
  			finally
  			{
  				if (mxClient.IS_IE)
  				{
  					view.overlayPane.innerHTML = '';
  					view.canvas.style.overflow = 'hidden';
  					view.canvas.style.position = 'relative';
  					view.canvas.style.top = this.marginTop + 'px';
  					view.canvas.style.width = clip.width + 'px';
  					view.canvas.style.height = clip.height + 'px';
  				}
  				else
  				{
  					var tmp = div.firstChild;
  					while (tmp != null)
  					{
  						var next = tmp.nextSibling;
  						var name = tmp.nodeName.toLowerCase();
  						if (name == 'svg')
  						{
  							tmp.style.overflow = 'hidden';
  							tmp.style.position = 'relative';
  							tmp.style.top = this.marginTop + 'px';
  							tmp.setAttribute('width', clip.width);
  							tmp.setAttribute('height', clip.height);
  							tmp.style.width = '';
  							tmp.style.height = '';
  						}
  						else if (tmp.style.cursor != 'default' && name != 'div')
  						{
  							tmp.parentNode.removeChild(tmp);
  						}
  						tmp = next;
  					}
  				}
  				if (this.printBackgroundImage)
  				{
  					var svgs = div.getElementsByTagName('svg');
  					if (svgs.length > 0)
  					{
  						svgs[0].style.position = 'absolute';
  					}
  				}
  				view.overlayPane.parentNode.removeChild(view.overlayPane);
  				this.graph.setEnabled(graphEnabled);
  				this.graph.container = previousContainer;
  				this.graph.cellRenderer.redraw = redraw;
  				view.canvas = canvas;
  				view.backgroundPane = backgroundPane;
  				view.drawPane = drawPane;
  				view.overlayPane = overlayPane;
  				view.translate = translate;
  				temp.destroy();
  				view.setEventsEnabled(eventsEnabled);
  			}
  		};
  		mxPrintPreview.prototype.getLinkForCellState = function(state)
  		{
  			return this.graph.getLinkForCell(state.cell);
  		};
  		mxPrintPreview.prototype.insertBackgroundImage = function(div, dx, dy)
  		{
  			var bg = this.graph.backgroundImage;
  			if (bg != null)
  			{
  				var img = document.createElement('img');
  				img.style.position = 'absolute';
  				img.style.marginLeft = Math.round(dx * this.scale) + 'px';
  				img.style.marginTop = Math.round(dy * this.scale) + 'px';
  				img.setAttribute('width', Math.round(this.scale * bg.width));
  				img.setAttribute('height', Math.round(this.scale * bg.height));
  				img.src = bg.src;
  				div.insertBefore(img, div.firstChild);
  			}
  		};
  		mxPrintPreview.prototype.getCoverPages = function()
  		{
  			return null;
  		};
  		mxPrintPreview.prototype.getAppendices = function()
  		{
  			return null;
  		};
  		mxPrintPreview.prototype.print = function(css)
  		{
  			var wnd = this.open(css);
  			if (wnd != null)
  			{
  				wnd.print();
  			}
  		};
  		mxPrintPreview.prototype.close = function()
  		{
  			if (this.wnd != null)
  			{
  				this.wnd.close();
  				this.wnd = null;
  			}
  		};
  		__mxOutput.mxPrintPreview = typeof mxPrintPreview !== 'undefined' ? mxPrintPreview : undefined;
  		function mxStylesheet()
  		{
  			this.styles = new Object();
  			this.putDefaultVertexStyle(this.createDefaultVertexStyle());
  			this.putDefaultEdgeStyle(this.createDefaultEdgeStyle());
  		}		mxStylesheet.prototype.styles;
  		mxStylesheet.prototype.createDefaultVertexStyle = function()
  		{
  			var style = new Object();
  			style[mxConstants.STYLE_SHAPE] = mxConstants.SHAPE_RECTANGLE;
  			style[mxConstants.STYLE_PERIMETER] = mxPerimeter.RectanglePerimeter;
  			style[mxConstants.STYLE_VERTICAL_ALIGN] = mxConstants.ALIGN_MIDDLE;
  			style[mxConstants.STYLE_ALIGN] = mxConstants.ALIGN_CENTER;
  			style[mxConstants.STYLE_FILLCOLOR] = '#C3D9FF';
  			style[mxConstants.STYLE_STROKECOLOR] = '#6482B9';
  			style[mxConstants.STYLE_FONTCOLOR] = '#774400';
  			return style;
  		};
  		mxStylesheet.prototype.createDefaultEdgeStyle = function()
  		{
  			var style = new Object();
  			style[mxConstants.STYLE_SHAPE] = mxConstants.SHAPE_CONNECTOR;
  			style[mxConstants.STYLE_ENDARROW] = mxConstants.ARROW_CLASSIC;
  			style[mxConstants.STYLE_VERTICAL_ALIGN] = mxConstants.ALIGN_MIDDLE;
  			style[mxConstants.STYLE_ALIGN] = mxConstants.ALIGN_CENTER;
  			style[mxConstants.STYLE_STROKECOLOR] = '#6482B9';
  			style[mxConstants.STYLE_FONTCOLOR] = '#446299';
  			return style;
  		};
  		mxStylesheet.prototype.putDefaultVertexStyle = function(style)
  		{
  			this.putCellStyle('defaultVertex', style);
  		};
  		mxStylesheet.prototype.putDefaultEdgeStyle = function(style)
  		{
  			this.putCellStyle('defaultEdge', style);
  		};
  		mxStylesheet.prototype.getDefaultVertexStyle = function()
  		{
  			return this.styles['defaultVertex'];
  		};
  		mxStylesheet.prototype.getDefaultEdgeStyle = function()
  		{
  			return this.styles['defaultEdge'];
  		};
  		mxStylesheet.prototype.putCellStyle = function(name, style)
  		{
  			this.styles[name] = style;
  		};
  		mxStylesheet.prototype.getCellStyle = function(name, defaultStyle)
  		{
  			var style = defaultStyle;
  			if (name != null && name.length > 0)
  			{
  				var pairs = name.split(';');
  				if (style != null &&
  					name.charAt(0) != ';')
  				{
  					style = mxUtils.clone(style);
  				}
  				else
  				{
  					style = new Object();
  				}
  			 	for (var i = 0; i < pairs.length; i++)
  			 	{
  			 		var tmp = pairs[i];
  			 		var pos = tmp.indexOf('=');
  			 		if (pos >= 0)
  			 		{
  				 		var key = tmp.substring(0, pos);
  				 		var value = tmp.substring(pos + 1);
  				 		if (value == mxConstants.NONE)
  				 		{
  				 			delete style[key];
  				 		}
  				 		else if (mxUtils.isNumeric(value))
  				 		{
  				 			style[key] = parseFloat(value);
  				 		}
  				 		else
  				 		{
  					 		style[key] = value;
  				 		}
  					}
  			 		else
  			 		{
  						var tmpStyle = this.styles[tmp];
  						if (tmpStyle != null)
  						{
  							for (var key in tmpStyle)
  							{
  								style[key] = tmpStyle[key];
  							}
  						}
  			 		}
  				}
  			}
  			return style;
  		};
  		__mxOutput.mxStylesheet = typeof mxStylesheet !== 'undefined' ? mxStylesheet : undefined;
  		function mxCellState(view, cell, style)
  		{
  			this.view = view;
  			this.cell = cell;
  			this.style = (style != null) ? style : {};
  			this.origin = new mxPoint();
  			this.absoluteOffset = new mxPoint();
  		}		mxCellState.prototype = new mxRectangle();
  		mxCellState.prototype.constructor = mxCellState;
  		mxCellState.prototype.view = null;
  		mxCellState.prototype.cell = null;
  		mxCellState.prototype.style = null;
  		mxCellState.prototype.invalidStyle = false;
  		mxCellState.prototype.invalid = true;
  		mxCellState.prototype.origin = null;
  		mxCellState.prototype.absolutePoints = null;
  		mxCellState.prototype.absoluteOffset = null;
  		mxCellState.prototype.visibleSourceState = null;
  		mxCellState.prototype.visibleTargetState = null;
  		mxCellState.prototype.terminalDistance = 0;
  		mxCellState.prototype.length = 0;
  		mxCellState.prototype.segments = null;
  		mxCellState.prototype.shape = null;
  		mxCellState.prototype.text = null;
  		mxCellState.prototype.unscaledWidth = null;
  		mxCellState.prototype.unscaledHeight = null;
  		mxCellState.prototype.getPerimeterBounds = function(border, bounds)
  		{
  			border = border || 0;
  			bounds = (bounds != null) ? bounds : new mxRectangle(this.x, this.y, this.width, this.height);
  			if (this.shape != null && this.shape.stencil != null && this.shape.stencil.aspect == 'fixed')
  			{
  				var aspect = this.shape.stencil.computeAspect(this.style, bounds.x, bounds.y, bounds.width, bounds.height);
  				bounds.x = aspect.x;
  				bounds.y = aspect.y;
  				bounds.width = this.shape.stencil.w0 * aspect.width;
  				bounds.height = this.shape.stencil.h0 * aspect.height;
  			}
  			if (border != 0)
  			{
  				bounds.grow(border);
  			}
  			return bounds;
  		};
  		mxCellState.prototype.setAbsoluteTerminalPoint = function(point, isSource)
  		{
  			if (isSource)
  			{
  				if (this.absolutePoints == null)
  				{
  					this.absolutePoints = [];
  				}
  				if (this.absolutePoints.length == 0)
  				{
  					this.absolutePoints.push(point);
  				}
  				else
  				{
  					this.absolutePoints[0] = point;
  				}
  			}
  			else
  			{
  				if (this.absolutePoints == null)
  				{
  					this.absolutePoints = [];
  					this.absolutePoints.push(null);
  					this.absolutePoints.push(point);
  				}
  				else if (this.absolutePoints.length == 1)
  				{
  					this.absolutePoints.push(point);
  				}
  				else
  				{
  					this.absolutePoints[this.absolutePoints.length - 1] = point;
  				}
  			}
  		};
  		mxCellState.prototype.setCursor = function(cursor)
  		{
  			if (this.shape != null)
  			{
  				this.shape.setCursor(cursor);
  			}
  			if (this.text != null)
  			{
  				this.text.setCursor(cursor);
  			}
  		};
  		mxCellState.prototype.getVisibleTerminal = function(source)
  		{
  			var tmp = this.getVisibleTerminalState(source);
  			return (tmp != null) ? tmp.cell : null;
  		};
  		mxCellState.prototype.getVisibleTerminalState = function(source)
  		{
  			return (source) ? this.visibleSourceState : this.visibleTargetState;
  		};
  		mxCellState.prototype.setVisibleTerminalState = function(terminalState, source)
  		{
  			if (source)
  			{
  				this.visibleSourceState = terminalState;
  			}
  			else
  			{
  				this.visibleTargetState = terminalState;
  			}
  		};
  		mxCellState.prototype.getCellBounds = function()
  		{
  			return this.cellBounds;
  		};
  		mxCellState.prototype.getPaintBounds = function()
  		{
  			return this.paintBounds;
  		};
  		mxCellState.prototype.updateCachedBounds = function()
  		{
  			var tr = this.view.translate;
  			var s = this.view.scale;
  			this.cellBounds = new mxRectangle(this.x / s - tr.x, this.y / s - tr.y, this.width / s, this.height / s);
  			this.paintBounds = mxRectangle.fromRectangle(this.cellBounds);
  			if (this.shape != null && this.shape.isPaintBoundsInverted())
  			{
  				this.paintBounds.rotate90();
  			}
  		};
  		mxCellState.prototype.setState = function(state)
  		{
  			this.view = state.view;
  			this.cell = state.cell;
  			this.style = state.style;
  			this.absolutePoints = state.absolutePoints;
  			this.origin = state.origin;
  			this.absoluteOffset = state.absoluteOffset;
  			this.boundingBox = state.boundingBox;
  			this.terminalDistance = state.terminalDistance;
  			this.segments = state.segments;
  			this.length = state.length;
  			this.x = state.x;
  			this.y = state.y;
  			this.width = state.width;
  			this.height = state.height;
  			this.unscaledWidth = state.unscaledWidth;
  			this.unscaledHeight = state.unscaledHeight;
  		};
  		mxCellState.prototype.clone = function()
  		{
  		 	var clone = new mxCellState(this.view, this.cell, this.style);
  			if (this.absolutePoints != null)
  			{
  				clone.absolutePoints = [];
  				for (var i = 0; i < this.absolutePoints.length; i++)
  				{
  					clone.absolutePoints[i] = this.absolutePoints[i].clone();
  				}
  			}
  			if (this.origin != null)
  			{
  				clone.origin = this.origin.clone();
  			}
  			if (this.absoluteOffset != null)
  			{
  				clone.absoluteOffset = this.absoluteOffset.clone();
  			}
  			if (this.boundingBox != null)
  			{
  				clone.boundingBox = this.boundingBox.clone();
  			}
  			clone.terminalDistance = this.terminalDistance;
  			clone.segments = this.segments;
  			clone.length = this.length;
  			clone.x = this.x;
  			clone.y = this.y;
  			clone.width = this.width;
  			clone.height = this.height;
  			clone.unscaledWidth = this.unscaledWidth;
  			clone.unscaledHeight = this.unscaledHeight;
  			return clone;
  		};
  		mxCellState.prototype.destroy = function()
  		{
  			this.view.graph.cellRenderer.destroy(this);
  		};
  		__mxOutput.mxCellState = typeof mxCellState !== 'undefined' ? mxCellState : undefined;
  		function mxGraphSelectionModel(graph)
  		{
  			this.graph = graph;
  			this.cells = [];
  		}		mxGraphSelectionModel.prototype = new mxEventSource();
  		mxGraphSelectionModel.prototype.constructor = mxGraphSelectionModel;
  		mxGraphSelectionModel.prototype.doneResource = (mxClient.language != 'none') ? 'done' : '';
  		mxGraphSelectionModel.prototype.updatingSelectionResource = (mxClient.language != 'none') ? 'updatingSelection' : '';
  		mxGraphSelectionModel.prototype.graph = null;
  		mxGraphSelectionModel.prototype.singleSelection = false;
  		mxGraphSelectionModel.prototype.isSingleSelection = function()
  		{
  			return this.singleSelection;
  		};
  		mxGraphSelectionModel.prototype.setSingleSelection = function(singleSelection)
  		{
  			this.singleSelection = singleSelection;
  		};
  		mxGraphSelectionModel.prototype.isSelected = function(cell)
  		{
  			if (cell != null)
  			{
  				return mxUtils.indexOf(this.cells, cell) >= 0;
  			}
  			return false;
  		};
  		mxGraphSelectionModel.prototype.isEmpty = function()
  		{
  			return this.cells.length == 0;
  		};
  		mxGraphSelectionModel.prototype.clear = function()
  		{
  			this.changeSelection(null, this.cells);
  		};
  		mxGraphSelectionModel.prototype.setCell = function(cell)
  		{
  			if (cell != null)
  			{
  				this.setCells([cell]);
  			}
  		};
  		mxGraphSelectionModel.prototype.setCells = function(cells)
  		{
  			if (cells != null)
  			{
  				if (this.singleSelection)
  				{
  					cells = [this.getFirstSelectableCell(cells)];
  				}
  				var tmp = [];
  				for (var i = 0; i < cells.length; i++)
  				{
  					if (this.graph.isCellSelectable(cells[i]))
  					{
  						tmp.push(cells[i]);
  					}
  				}
  				this.changeSelection(tmp, this.cells);
  			}
  		};
  		mxGraphSelectionModel.prototype.getFirstSelectableCell = function(cells)
  		{
  			if (cells != null)
  			{
  				for (var i = 0; i < cells.length; i++)
  				{
  					if (this.graph.isCellSelectable(cells[i]))
  					{
  						return cells[i];
  					}
  				}
  			}
  			return null;
  		};
  		mxGraphSelectionModel.prototype.addCell = function(cell)
  		{
  			if (cell != null)
  			{
  				this.addCells([cell]);
  			}
  		};
  		mxGraphSelectionModel.prototype.addCells = function(cells)
  		{
  			if (cells != null)
  			{
  				var remove = null;
  				if (this.singleSelection)
  				{
  					remove = this.cells;
  					cells = [this.getFirstSelectableCell(cells)];
  				}
  				var tmp = [];
  				for (var i = 0; i < cells.length; i++)
  				{
  					if (!this.isSelected(cells[i]) &&
  						this.graph.isCellSelectable(cells[i]))
  					{
  						tmp.push(cells[i]);
  					}
  				}
  				this.changeSelection(tmp, remove);
  			}
  		};
  		mxGraphSelectionModel.prototype.removeCell = function(cell)
  		{
  			if (cell != null)
  			{
  				this.removeCells([cell]);
  			}
  		};
  		mxGraphSelectionModel.prototype.removeCells = function(cells)
  		{
  			if (cells != null)
  			{
  				var tmp = [];
  				for (var i = 0; i < cells.length; i++)
  				{
  					if (this.isSelected(cells[i]))
  					{
  						tmp.push(cells[i]);
  					}
  				}
  				this.changeSelection(null, tmp);
  			}
  		};
  		mxGraphSelectionModel.prototype.changeSelection = function(added, removed)
  		{
  			if ((added != null &&
  				added.length > 0 &&
  				added[0] != null) ||
  				(removed != null &&
  				removed.length > 0 &&
  				removed[0] != null))
  			{
  				var change = new mxSelectionChange(this, added, removed);
  				change.execute();
  				var edit = new mxUndoableEdit(this, false);
  				edit.add(change);
  				this.fireEvent(new mxEventObject(mxEvent.UNDO, 'edit', edit));
  			}
  		};
  		mxGraphSelectionModel.prototype.cellAdded = function(cell)
  		{
  			if (cell != null &&
  				!this.isSelected(cell))
  			{
  				this.cells.push(cell);
  			}
  		};
  		mxGraphSelectionModel.prototype.cellRemoved = function(cell)
  		{
  			if (cell != null)
  			{
  				var index = mxUtils.indexOf(this.cells, cell);
  				if (index >= 0)
  				{
  					this.cells.splice(index, 1);
  				}
  			}
  		};
  		function mxSelectionChange(selectionModel, added, removed)
  		{
  			this.selectionModel = selectionModel;
  			this.added = (added != null) ? added.slice() : null;
  			this.removed = (removed != null) ? removed.slice() : null;
  		}		mxSelectionChange.prototype.execute = function()
  		{
  			var t0 = mxLog.enter('mxSelectionChange.execute');
  			window.status = mxResources.get(
  				this.selectionModel.updatingSelectionResource) ||
  				this.selectionModel.updatingSelectionResource;
  			if (this.removed != null)
  			{
  				for (var i = 0; i < this.removed.length; i++)
  				{
  					this.selectionModel.cellRemoved(this.removed[i]);
  				}
  			}
  			if (this.added != null)
  			{
  				for (var i = 0; i < this.added.length; i++)
  				{
  					this.selectionModel.cellAdded(this.added[i]);
  				}
  			}
  			var tmp = this.added;
  			this.added = this.removed;
  			this.removed = tmp;
  			window.status = mxResources.get(this.selectionModel.doneResource) ||
  				this.selectionModel.doneResource;
  			mxLog.leave('mxSelectionChange.execute', t0);
  			this.selectionModel.fireEvent(new mxEventObject(mxEvent.CHANGE,
  					'added', this.added, 'removed', this.removed));
  		};
  		__mxOutput.mxGraphSelectionModel = typeof mxGraphSelectionModel !== 'undefined' ? mxGraphSelectionModel : undefined;
  		function mxCellEditor(graph)
  		{
  			this.graph = graph;
  			this.zoomHandler = mxUtils.bind(this, function()
  			{
  				if (this.graph.isEditing())
  				{
  					this.resize();
  				}
  			});
  			this.graph.view.addListener(mxEvent.SCALE, this.zoomHandler);
  			this.graph.view.addListener(mxEvent.SCALE_AND_TRANSLATE, this.zoomHandler);
  			this.changeHandler = mxUtils.bind(this, function(sender)
  			{
  				if (this.editingCell != null && this.graph.getView().getState(this.editingCell) == null)
  				{
  					this.stopEditing(true);
  				}
  			});
  			this.graph.getModel().addListener(mxEvent.CHANGE, this.changeHandler);
  		}		mxCellEditor.prototype.graph = null;
  		mxCellEditor.prototype.textarea = null;
  		mxCellEditor.prototype.editingCell = null;
  		mxCellEditor.prototype.trigger = null;
  		mxCellEditor.prototype.modified = false;
  		mxCellEditor.prototype.autoSize = true;
  		mxCellEditor.prototype.selectText = true;
  		mxCellEditor.prototype.emptyLabelText = (mxClient.IS_FF) ? '<br>' : '';
  		mxCellEditor.prototype.escapeCancelsEditing = true;
  		mxCellEditor.prototype.textNode = '';
  		mxCellEditor.prototype.zIndex = 5;
  		mxCellEditor.prototype.minResize = new mxRectangle(0, 20);
  		mxCellEditor.prototype.wordWrapPadding = (mxClient.IS_QUIRKS) ? 2 : (!mxClient.IS_IE11) ? 1 : 0;
  		mxCellEditor.prototype.blurEnabled = false;
  		mxCellEditor.prototype.initialValue = null;
  		mxCellEditor.prototype.align = null;
  		mxCellEditor.prototype.init = function ()
  		{
  			this.textarea = document.createElement('div');
  			this.textarea.className = 'mxCellEditor mxPlainTextEditor';
  			this.textarea.contentEditable = true;
  			if (mxClient.IS_GC)
  			{
  				this.textarea.style.minHeight = '1em';
  			}
  			this.textarea.style.position = ((this.isLegacyEditor())) ? 'absolute' : 'relative';
  			this.installListeners(this.textarea);
  		};
  		mxCellEditor.prototype.applyValue = function(state, value)
  		{
  			this.graph.labelChanged(state.cell, value, this.trigger);
  		};
  		mxCellEditor.prototype.setAlign = function (align)
  		{
  			if (this.textarea != null)
  			{
  				this.textarea.style.textAlign = align;
  			}
  			this.align = align;
  			this.resize();
  		};
  		mxCellEditor.prototype.getInitialValue = function(state, trigger)
  		{
  			var result = mxUtils.htmlEntities(this.graph.getEditingValue(state.cell, trigger), false);
  			if (!mxClient.IS_QUIRKS && document.documentMode != 8 && document.documentMode != 9 &&
  				document.documentMode != 10)
  			{
  				result = mxUtils.replaceTrailingNewlines(result, '<div><br></div>');
  			}
  		    return result.replace(/\n/g, '<br>');
  		};
  		mxCellEditor.prototype.getCurrentValue = function(state)
  		{
  			return mxUtils.extractTextWithWhitespace(this.textarea.childNodes);
  		};
  		mxCellEditor.prototype.isCancelEditingKeyEvent = function(evt)
  		{
  			return this.escapeCancelsEditing || mxEvent.isShiftDown(evt) || mxEvent.isControlDown(evt) || mxEvent.isMetaDown(evt);
  		};
  		mxCellEditor.prototype.installListeners = function(elt)
  		{
  			mxEvent.addListener(elt, 'dragstart', mxUtils.bind(this, function(evt)
  			{
  				this.graph.stopEditing(false);
  				mxEvent.consume(evt);
  			}));
  			mxEvent.addListener(elt, 'blur', mxUtils.bind(this, function(evt)
  			{
  				if (this.blurEnabled)
  				{
  					this.focusLost(evt);
  				}
  			}));
  			mxEvent.addListener(elt, 'keydown', mxUtils.bind(this, function(evt)
  			{
  				if (!mxEvent.isConsumed(evt))
  				{
  					if (this.isStopEditingEvent(evt))
  					{
  						this.graph.stopEditing(false);
  						mxEvent.consume(evt);
  					}
  					else if (evt.keyCode == 27 )
  					{
  						this.graph.stopEditing(this.isCancelEditingKeyEvent(evt));
  						mxEvent.consume(evt);
  					}
  				}
  			}));
  			var keypressHandler = mxUtils.bind(this, function(evt)
  			{
  				if (this.editingCell != null)
  				{
  					if (this.clearOnChange && elt.innerHTML == this.getEmptyLabelText() &&
  						(!mxClient.IS_FF || (evt.keyCode != 8  && evt.keyCode != 46 )))
  					{
  						this.clearOnChange = false;
  						elt.innerHTML = '';
  					}
  				}
  			});
  			mxEvent.addListener(elt, 'keypress', keypressHandler);
  			mxEvent.addListener(elt, 'paste', keypressHandler);
  			var keyupHandler = mxUtils.bind(this, function(evt)
  			{
  				if (this.editingCell != null)
  				{
  					if (this.textarea.innerHTML.length == 0 || this.textarea.innerHTML == '<br>')
  					{
  						this.textarea.innerHTML = this.getEmptyLabelText();
  						this.clearOnChange = this.textarea.innerHTML.length > 0;
  					}
  					else
  					{
  						this.clearOnChange = false;
  					}
  				}
  			});
  			mxEvent.addListener(elt, (!mxClient.IS_IE11 && !mxClient.IS_IE) ? 'input' : 'keyup', keyupHandler);
  			mxEvent.addListener(elt, 'cut', keyupHandler);
  			mxEvent.addListener(elt, 'paste', keyupHandler);
  			var evtName = (!mxClient.IS_IE11 && !mxClient.IS_IE) ? 'input' : 'keydown';
  			var resizeHandler = mxUtils.bind(this, function(evt)
  			{
  				if (this.editingCell != null && this.autoSize && !mxEvent.isConsumed(evt))
  				{
  					if (this.resizeThread != null)
  					{
  						window.clearTimeout(this.resizeThread);
  					}
  					this.resizeThread = window.setTimeout(mxUtils.bind(this, function()
  					{
  						this.resizeThread = null;
  						this.resize();
  					}), 0);
  				}
  			});
  			mxEvent.addListener(elt, evtName, resizeHandler);
  			mxEvent.addListener(window, 'resize', resizeHandler);
  			if (document.documentMode >= 9)
  			{
  				mxEvent.addListener(elt, 'DOMNodeRemoved', resizeHandler);
  				mxEvent.addListener(elt, 'DOMNodeInserted', resizeHandler);
  			}
  			else
  			{
  				mxEvent.addListener(elt, 'cut', resizeHandler);
  				mxEvent.addListener(elt, 'paste', resizeHandler);
  			}
  		};
  		mxCellEditor.prototype.isStopEditingEvent = function(evt)
  		{
  			return evt.keyCode == 113  || (this.graph.isEnterStopsCellEditing() &&
  				evt.keyCode == 13  && !mxEvent.isControlDown(evt) &&
  				!mxEvent.isShiftDown(evt));
  		};
  		mxCellEditor.prototype.isEventSource = function(evt)
  		{
  			return mxEvent.getSource(evt) == this.textarea;
  		};
  		mxCellEditor.prototype.resize = function()
  		{
  			var state = this.graph.getView().getState(this.editingCell);
  			if (state == null)
  			{
  				this.stopEditing(true);
  			}
  			else if (this.textarea != null)
  			{
  				var isEdge = this.graph.getModel().isEdge(state.cell);
  		 		var scale = this.graph.getView().scale;
  		 		var m = null;
  				if (!this.autoSize || (state.style[mxConstants.STYLE_OVERFLOW] == 'fill'))
  				{
  					this.bounds = this.getEditorBounds(state);
  					this.textarea.style.width = Math.round(this.bounds.width / scale) + 'px';
  					this.textarea.style.height = Math.round(this.bounds.height / scale) + 'px';
  					if (document.documentMode == 8 || mxClient.IS_QUIRKS)
  					{
  						this.textarea.style.left = Math.round(this.bounds.x) + 'px';
  						this.textarea.style.top = Math.round(this.bounds.y) + 'px';
  					}
  					else
  					{
  						this.textarea.style.left = Math.max(0, Math.round(this.bounds.x + 1)) + 'px';
  						this.textarea.style.top = Math.max(0, Math.round(this.bounds.y + 1)) + 'px';
  					}
  					if (this.graph.isWrapping(state.cell) && (this.bounds.width >= 2 || this.bounds.height >= 2) &&
  						this.textarea.innerHTML != this.getEmptyLabelText())
  					{
  						this.textarea.style.wordWrap = mxConstants.WORD_WRAP;
  						this.textarea.style.whiteSpace = 'normal';
  						if (state.style[mxConstants.STYLE_OVERFLOW] != 'fill')
  						{
  							this.textarea.style.width = Math.round(this.bounds.width / scale) + this.wordWrapPadding + 'px';
  						}
  					}
  					else
  					{
  						this.textarea.style.whiteSpace = 'nowrap';
  						if (state.style[mxConstants.STYLE_OVERFLOW] != 'fill')
  						{
  							this.textarea.style.width = '';
  						}
  					}
  				}
  				else
  			 	{
  			 		var lw = mxUtils.getValue(state.style, mxConstants.STYLE_LABEL_WIDTH, null);
  					m = (state.text != null && this.align == null) ? state.text.margin : null;
  					if (m == null)
  					{
  						m = mxUtils.getAlignmentAsPoint(this.align || mxUtils.getValue(state.style, mxConstants.STYLE_ALIGN, mxConstants.ALIGN_CENTER),
  								mxUtils.getValue(state.style, mxConstants.STYLE_VERTICAL_ALIGN, mxConstants.ALIGN_MIDDLE));
  					}
  			 		if (isEdge)
  					{
  						this.bounds = new mxRectangle(state.absoluteOffset.x, state.absoluteOffset.y, 0, 0);
  						if (lw != null)
  					 	{
  							var tmp = (parseFloat(lw) + 2) * scale;
  							this.bounds.width = tmp;
  							this.bounds.x += m.x * tmp;
  					 	}
  					}
  					else
  					{
  						var bds = mxRectangle.fromRectangle(state);
  						var hpos = mxUtils.getValue(state.style, mxConstants.STYLE_LABEL_POSITION, mxConstants.ALIGN_CENTER);
  						var vpos = mxUtils.getValue(state.style, mxConstants.STYLE_VERTICAL_LABEL_POSITION, mxConstants.ALIGN_MIDDLE);
  						bds = (state.shape != null && hpos == mxConstants.ALIGN_CENTER && vpos == mxConstants.ALIGN_MIDDLE) ? state.shape.getLabelBounds(bds) : bds;
  					 	if (lw != null)
  					 	{
  					 		bds.width = parseFloat(lw) * scale;
  					 	}
  					 	if (!state.view.graph.cellRenderer.legacySpacing || state.style[mxConstants.STYLE_OVERFLOW] != 'width')
  					 	{
  							var spacing = parseInt(state.style[mxConstants.STYLE_SPACING] || 2) * scale;
  							var spacingTop = (parseInt(state.style[mxConstants.STYLE_SPACING_TOP] || 0) + mxText.prototype.baseSpacingTop) * scale + spacing;
  							var spacingRight = (parseInt(state.style[mxConstants.STYLE_SPACING_RIGHT] || 0) + mxText.prototype.baseSpacingRight) * scale + spacing;
  							var spacingBottom = (parseInt(state.style[mxConstants.STYLE_SPACING_BOTTOM] || 0) + mxText.prototype.baseSpacingBottom) * scale + spacing;
  							var spacingLeft = (parseInt(state.style[mxConstants.STYLE_SPACING_LEFT] || 0) + mxText.prototype.baseSpacingLeft) * scale + spacing;
  							var hpos = mxUtils.getValue(state.style, mxConstants.STYLE_LABEL_POSITION, mxConstants.ALIGN_CENTER);
  							var vpos = mxUtils.getValue(state.style, mxConstants.STYLE_VERTICAL_LABEL_POSITION, mxConstants.ALIGN_MIDDLE);
  							bds = new mxRectangle(bds.x + spacingLeft, bds.y + spacingTop,
  								bds.width - ((hpos == mxConstants.ALIGN_CENTER && lw == null) ? (spacingLeft + spacingRight) : 0),
  								bds.height - ((vpos == mxConstants.ALIGN_MIDDLE) ? (spacingTop + spacingBottom) : 0));
  					 	}
  						this.bounds = new mxRectangle(bds.x + state.absoluteOffset.x, bds.y + state.absoluteOffset.y, bds.width, bds.height);
  					}
  					if (this.graph.isWrapping(state.cell) && (this.bounds.width >= 2 || this.bounds.height >= 2) &&
  						this.textarea.innerHTML != this.getEmptyLabelText())
  					{
  						this.textarea.style.wordWrap = mxConstants.WORD_WRAP;
  						this.textarea.style.whiteSpace = 'normal';
  						var tmp = Math.round(this.bounds.width / ((document.documentMode == 8) ? scale : scale)) + this.wordWrapPadding;
  						if (this.textarea.style.position != 'relative')
  						{
  							this.textarea.style.width = tmp + 'px';
  							if (this.textarea.scrollWidth > tmp)
  							{
  								this.textarea.style.width = this.textarea.scrollWidth + 'px';
  							}
  						}
  						else
  						{
  							this.textarea.style.maxWidth = tmp + 'px';
  						}
  					}
  					else
  					{
  						this.textarea.style.whiteSpace = 'nowrap';
  						this.textarea.style.width = '';
  					}
  					if (document.documentMode == 8)
  					{
  						this.textarea.style.zoom = '1';
  						this.textarea.style.height = 'auto';
  					}
  					var ow = this.textarea.scrollWidth;
  					var oh = this.textarea.scrollHeight;
  					if (document.documentMode == 8)
  					{
  						this.textarea.style.left = Math.max(0, Math.ceil((this.bounds.x - m.x * (this.bounds.width - (ow + 1) * scale) + ow * (scale - 1) * 0 + (m.x + 0.5) * 2) / scale)) + 'px';
  						this.textarea.style.top = Math.max(0, Math.ceil((this.bounds.y - m.y * (this.bounds.height - (oh + 0.5) * scale) + oh * (scale - 1) * 0 + Math.abs(m.y + 0.5) * 1) / scale)) + 'px';
  						this.textarea.style.width = Math.round(ow * scale) + 'px';
  						this.textarea.style.height = Math.round(oh * scale) + 'px';
  					}
  					else if (mxClient.IS_QUIRKS)
  					{
  						this.textarea.style.left = Math.max(0, Math.ceil(this.bounds.x - m.x * (this.bounds.width - (ow + 1) * scale) + ow * (scale - 1) * 0 + (m.x + 0.5) * 2)) + 'px';
  						this.textarea.style.top = Math.max(0, Math.ceil(this.bounds.y - m.y * (this.bounds.height - (oh + 0.5) * scale) + oh * (scale - 1) * 0 + Math.abs(m.y + 0.5) * 1)) + 'px';
  					}
  					else
  					{
  						this.textarea.style.left = Math.max(0, Math.round(this.bounds.x - m.x * (this.bounds.width - 2)) + 1) + 'px';
  						this.textarea.style.top = Math.max(0, Math.round(this.bounds.y - m.y * (this.bounds.height - 4) + ((m.y == -1) ? 3 : 0)) + 1) + 'px';
  					}
  			 	}
  				if (mxClient.IS_VML)
  				{
  					this.textarea.style.zoom = scale;
  				}
  				else
  				{
  					mxUtils.setPrefixedStyle(this.textarea.style, 'transformOrigin', '0px 0px');
  					mxUtils.setPrefixedStyle(this.textarea.style, 'transform',
  						'scale(' + scale + ',' + scale + ')' + ((m == null) ? '' :
  						' translate(' + (m.x * 100) + '%,' + (m.y * 100) + '%)'));
  				}
  			}
  		};
  		mxCellEditor.prototype.focusLost = function()
  		{
  			this.stopEditing(!this.graph.isInvokesStopCellEditing());
  		};
  		mxCellEditor.prototype.getBackgroundColor = function(state)
  		{
  			return null;
  		};
  		mxCellEditor.prototype.isLegacyEditor = function()
  		{
  			if (mxClient.IS_VML)
  			{
  				return true;
  			}
  			else
  			{
  				var absoluteRoot = false;
  				if (mxClient.IS_SVG)
  				{
  					var root = this.graph.view.getDrawPane().ownerSVGElement;
  					if (root != null)
  					{
  						var css = mxUtils.getCurrentStyle(root);
  						if (css != null)
  						{
  							absoluteRoot = css.position == 'absolute';
  						}
  					}
  				}
  				return !absoluteRoot;
  			}
  		};
  		mxCellEditor.prototype.startEditing = function(cell, trigger)
  		{
  			this.stopEditing(true);
  			this.align = null;
  			if (this.textarea == null)
  			{
  				this.init();
  			}
  			if (this.graph.tooltipHandler != null)
  			{
  				this.graph.tooltipHandler.hideTooltip();
  			}
  			var state = this.graph.getView().getState(cell);
  			if (state != null)
  			{
  				this.graph.getView().scale;
  				var size = mxUtils.getValue(state.style, mxConstants.STYLE_FONTSIZE, mxConstants.DEFAULT_FONTSIZE);
  				var family = mxUtils.getValue(state.style, mxConstants.STYLE_FONTFAMILY, mxConstants.DEFAULT_FONTFAMILY);
  				var color = mxUtils.getValue(state.style, mxConstants.STYLE_FONTCOLOR, 'black');
  				var align = mxUtils.getValue(state.style, mxConstants.STYLE_ALIGN, mxConstants.ALIGN_LEFT);
  				var bold = (mxUtils.getValue(state.style, mxConstants.STYLE_FONTSTYLE, 0) &
  						mxConstants.FONT_BOLD) == mxConstants.FONT_BOLD;
  				var italic = (mxUtils.getValue(state.style, mxConstants.STYLE_FONTSTYLE, 0) &
  						mxConstants.FONT_ITALIC) == mxConstants.FONT_ITALIC;
  				var txtDecor = [];
  				if ((mxUtils.getValue(state.style, mxConstants.STYLE_FONTSTYLE, 0) &
  						mxConstants.FONT_UNDERLINE) == mxConstants.FONT_UNDERLINE)
  				{
  					txtDecor.push('underline');
  				}
  				if ((mxUtils.getValue(state.style, mxConstants.STYLE_FONTSTYLE, 0) &
  						mxConstants.FONT_STRIKETHROUGH) == mxConstants.FONT_STRIKETHROUGH)
  				{
  					txtDecor.push('line-through');
  				}
  				this.textarea.style.lineHeight = (mxConstants.ABSOLUTE_LINE_HEIGHT) ? Math.round(size * mxConstants.LINE_HEIGHT) + 'px' : mxConstants.LINE_HEIGHT;
  				this.textarea.style.backgroundColor = this.getBackgroundColor(state);
  				this.textarea.style.textDecoration = txtDecor.join(' ');
  				this.textarea.style.fontWeight = (bold) ? 'bold' : 'normal';
  				this.textarea.style.fontStyle = (italic) ? 'italic' : '';
  				this.textarea.style.fontSize = Math.round(size) + 'px';
  				this.textarea.style.zIndex = this.zIndex;
  				this.textarea.style.fontFamily = family;
  				this.textarea.style.textAlign = align;
  				this.textarea.style.outline = 'none';
  				this.textarea.style.color = color;
  				var dir = this.textDirection = mxUtils.getValue(state.style, mxConstants.STYLE_TEXT_DIRECTION, mxConstants.DEFAULT_TEXT_DIRECTION);
  				if (dir == mxConstants.TEXT_DIRECTION_AUTO)
  				{
  					if (state != null && state.text != null && state.text.dialect != mxConstants.DIALECT_STRICTHTML &&
  						!mxUtils.isNode(state.text.value))
  					{
  						dir = state.text.getAutoDirection();
  					}
  				}
  				if (dir == mxConstants.TEXT_DIRECTION_LTR || dir == mxConstants.TEXT_DIRECTION_RTL)
  				{
  					this.textarea.setAttribute('dir', dir);
  				}
  				else
  				{
  					this.textarea.removeAttribute('dir');
  				}
  				this.textarea.innerHTML = this.getInitialValue(state, trigger) || '';
  				this.initialValue = this.textarea.innerHTML;
  				if (this.textarea.innerHTML.length == 0 || this.textarea.innerHTML == '<br>')
  				{
  					this.textarea.innerHTML = this.getEmptyLabelText();
  					this.clearOnChange = true;
  				}
  				else
  				{
  					this.clearOnChange = this.textarea.innerHTML == this.getEmptyLabelText();
  				}
  				this.graph.container.appendChild(this.textarea);
  				this.editingCell = cell;
  				this.trigger = trigger;
  				this.textNode = null;
  				if (state.text != null && this.isHideLabel(state))
  				{
  					this.textNode = state.text.node;
  					this.textNode.style.visibility = 'hidden';
  				}
  				if (this.autoSize && (this.graph.model.isEdge(state.cell) || state.style[mxConstants.STYLE_OVERFLOW] != 'fill'))
  				{
  					window.setTimeout(mxUtils.bind(this, function()
  					{
  						this.resize();
  					}), 0);
  				}
  				this.resize();
  				try
  				{
  					this.textarea.focus();
  					if (this.isSelectText() && this.textarea.innerHTML.length > 0 &&
  						(this.textarea.innerHTML != this.getEmptyLabelText() || !this.clearOnChange))
  					{
  						document.execCommand('selectAll', false, null);
  					}
  				}
  				catch (e)
  				{
  				}
  			}
  		};
  		mxCellEditor.prototype.isSelectText = function()
  		{
  			return this.selectText;
  		};
  		mxCellEditor.prototype.clearSelection = function()
  		{
  			var selection = null;
  			if (window.getSelection)
  			{
  				selection = window.getSelection();
  			}
  			else if (document.selection)
  			{
  				selection = document.selection;
  			}
  			if (selection != null)
  			{
  				if (selection.empty)
  				{
  					selection.empty();
  				}
  				else if (selection.removeAllRanges)
  				{
  					selection.removeAllRanges();
  				}
  			}
  		};
  		mxCellEditor.prototype.stopEditing = function(cancel)
  		{
  			cancel = cancel || false;
  			if (this.editingCell != null)
  			{
  				if (this.textNode != null)
  				{
  					this.textNode.style.visibility = 'visible';
  					this.textNode = null;
  				}
  				var state = (!cancel) ? this.graph.view.getState(this.editingCell) : null;
  				var initial = this.initialValue;
  				this.initialValue = null;
  				this.editingCell = null;
  				this.trigger = null;
  				this.bounds = null;
  				this.textarea.blur();
  				this.clearSelection();
  				if (this.textarea.parentNode != null)
  				{
  					this.textarea.parentNode.removeChild(this.textarea);
  				}
  				if (this.clearOnChange && this.textarea.innerHTML == this.getEmptyLabelText())
  				{
  					this.textarea.innerHTML = '';
  					this.clearOnChange = false;
  				}
  				if (state != null && (this.textarea.innerHTML != initial || this.align != null))
  				{
  					this.prepareTextarea();
  					var value = this.getCurrentValue(state);
  					this.graph.getModel().beginUpdate();
  					try
  					{
  						if (value != null)
  						{
  							this.applyValue(state, value);
  						}
  						if (this.align != null)
  						{
  							this.graph.setCellStyles(mxConstants.STYLE_ALIGN, this.align, [state.cell]);
  						}
  					}
  					finally
  					{
  						this.graph.getModel().endUpdate();
  					}
  				}
  				mxEvent.release(this.textarea);
  				this.textarea = null;
  				this.align = null;
  			}
  		};
  		mxCellEditor.prototype.prepareTextarea = function()
  		{
  			if (this.textarea.lastChild != null &&
  				this.textarea.lastChild.nodeName == 'BR')
  			{
  				this.textarea.removeChild(this.textarea.lastChild);
  			}
  		};
  		mxCellEditor.prototype.isHideLabel = function(state)
  		{
  			return true;
  		};
  		mxCellEditor.prototype.getMinimumSize = function(state)
  		{
  			var scale = this.graph.getView().scale;
  			return new mxRectangle(0, 0, (state.text == null) ? 30 : state.text.size * scale + 20,
  					(this.textarea.style.textAlign == 'left') ? 120 : 40);
  		};
  		mxCellEditor.prototype.getEditorBounds = function(state)
  		{
  			var isEdge = this.graph.getModel().isEdge(state.cell);
  			var scale = this.graph.getView().scale;
  			var minSize = this.getMinimumSize(state);
  			var minWidth = minSize.width;
  		 	var minHeight = minSize.height;
  		 	var result = null;
  		 	if (!isEdge && state.view.graph.cellRenderer.legacySpacing && state.style[mxConstants.STYLE_OVERFLOW] == 'fill')
  		 	{
  		 		result = state.shape.getLabelBounds(mxRectangle.fromRectangle(state));
  		 	}
  		 	else
  		 	{
  				var spacing = parseInt(state.style[mxConstants.STYLE_SPACING] || 0) * scale;
  				var spacingTop = (parseInt(state.style[mxConstants.STYLE_SPACING_TOP] || 0) + mxText.prototype.baseSpacingTop) * scale + spacing;
  				var spacingRight = (parseInt(state.style[mxConstants.STYLE_SPACING_RIGHT] || 0) + mxText.prototype.baseSpacingRight) * scale + spacing;
  				var spacingBottom = (parseInt(state.style[mxConstants.STYLE_SPACING_BOTTOM] || 0) + mxText.prototype.baseSpacingBottom) * scale + spacing;
  				var spacingLeft = (parseInt(state.style[mxConstants.STYLE_SPACING_LEFT] || 0) + mxText.prototype.baseSpacingLeft) * scale + spacing;
  			 	result = new mxRectangle(state.x, state.y,
  			 		 Math.max(minWidth, state.width - spacingLeft - spacingRight),
  			 		 Math.max(minHeight, state.height - spacingTop - spacingBottom));
  				var hpos = mxUtils.getValue(state.style, mxConstants.STYLE_LABEL_POSITION, mxConstants.ALIGN_CENTER);
  				var vpos = mxUtils.getValue(state.style, mxConstants.STYLE_VERTICAL_LABEL_POSITION, mxConstants.ALIGN_MIDDLE);
  				result = (state.shape != null && hpos == mxConstants.ALIGN_CENTER && vpos == mxConstants.ALIGN_MIDDLE) ? state.shape.getLabelBounds(result) : result;
  				if (isEdge)
  				{
  					result.x = state.absoluteOffset.x;
  					result.y = state.absoluteOffset.y;
  					if (state.text != null && state.text.boundingBox != null)
  					{
  						if (state.text.boundingBox.x > 0)
  						{
  							result.x = state.text.boundingBox.x;
  						}
  						if (state.text.boundingBox.y > 0)
  						{
  							result.y = state.text.boundingBox.y;
  						}
  					}
  				}
  				else if (state.text != null && state.text.boundingBox != null)
  				{
  					result.x = Math.min(result.x, state.text.boundingBox.x);
  					result.y = Math.min(result.y, state.text.boundingBox.y);
  				}
  				result.x += spacingLeft;
  				result.y += spacingTop;
  				if (state.text != null && state.text.boundingBox != null)
  				{
  					if (!isEdge)
  					{
  						result.width = Math.max(result.width, state.text.boundingBox.width);
  						result.height = Math.max(result.height, state.text.boundingBox.height);
  					}
  					else
  					{
  						result.width = Math.max(minWidth, state.text.boundingBox.width);
  						result.height = Math.max(minHeight, state.text.boundingBox.height);
  					}
  				}
  				if (this.graph.getModel().isVertex(state.cell))
  				{
  					var horizontal = mxUtils.getValue(state.style, mxConstants.STYLE_LABEL_POSITION, mxConstants.ALIGN_CENTER);
  					if (horizontal == mxConstants.ALIGN_LEFT)
  					{
  						result.x -= state.width;
  					}
  					else if (horizontal == mxConstants.ALIGN_RIGHT)
  					{
  						result.x += state.width;
  					}
  					var vertical = mxUtils.getValue(state.style, mxConstants.STYLE_VERTICAL_LABEL_POSITION, mxConstants.ALIGN_MIDDLE);
  					if (vertical == mxConstants.ALIGN_TOP)
  					{
  						result.y -= state.height;
  					}
  					else if (vertical == mxConstants.ALIGN_BOTTOM)
  					{
  						result.y += state.height;
  					}
  				}
  		 	}
  		 	return new mxRectangle(Math.round(result.x), Math.round(result.y), Math.round(result.width), Math.round(result.height));
  		};
  		mxCellEditor.prototype.getEmptyLabelText = function (cell)
  		{
  			return this.emptyLabelText;
  		};
  		mxCellEditor.prototype.getEditingCell = function ()
  		{
  			return this.editingCell;
  		};
  		mxCellEditor.prototype.destroy = function ()
  		{
  			if (this.textarea != null)
  			{
  				mxEvent.release(this.textarea);
  				if (this.textarea.parentNode != null)
  				{
  					this.textarea.parentNode.removeChild(this.textarea);
  				}
  				this.textarea = null;
  			}
  			if (this.changeHandler != null)
  			{
  				this.graph.getModel().removeListener(this.changeHandler);
  				this.changeHandler = null;
  			}
  			if (this.zoomHandler)
  			{
  				this.graph.view.removeListener(this.zoomHandler);
  				this.zoomHandler = null;
  			}
  		};
  		__mxOutput.mxCellEditor = typeof mxCellEditor !== 'undefined' ? mxCellEditor : undefined;
  		function mxCellRenderer() { }		mxCellRenderer.defaultShapes = new Object();
  		mxCellRenderer.prototype.defaultEdgeShape = mxConnector;
  		mxCellRenderer.prototype.defaultVertexShape = mxRectangleShape;
  		mxCellRenderer.prototype.defaultTextShape = mxText;
  		mxCellRenderer.prototype.legacyControlPosition = true;
  		mxCellRenderer.prototype.legacySpacing = true;
  		mxCellRenderer.prototype.antiAlias = true;
  		mxCellRenderer.prototype.minSvgStrokeWidth = 1;
  		mxCellRenderer.prototype.forceControlClickHandler = false;
  		mxCellRenderer.registerShape = function(key, shape)
  		{
  			mxCellRenderer.defaultShapes[key] = shape;
  		};
  		mxCellRenderer.registerShape(mxConstants.SHAPE_RECTANGLE, mxRectangleShape);
  		mxCellRenderer.registerShape(mxConstants.SHAPE_ELLIPSE, mxEllipse);
  		mxCellRenderer.registerShape(mxConstants.SHAPE_RHOMBUS, mxRhombus);
  		mxCellRenderer.registerShape(mxConstants.SHAPE_CYLINDER, mxCylinder);
  		mxCellRenderer.registerShape(mxConstants.SHAPE_CONNECTOR, mxConnector);
  		mxCellRenderer.registerShape(mxConstants.SHAPE_ACTOR, mxActor);
  		mxCellRenderer.registerShape(mxConstants.SHAPE_TRIANGLE, mxTriangle);
  		mxCellRenderer.registerShape(mxConstants.SHAPE_HEXAGON, mxHexagon);
  		mxCellRenderer.registerShape(mxConstants.SHAPE_CLOUD, mxCloud);
  		mxCellRenderer.registerShape(mxConstants.SHAPE_LINE, mxLine);
  		mxCellRenderer.registerShape(mxConstants.SHAPE_ARROW, mxArrow);
  		mxCellRenderer.registerShape(mxConstants.SHAPE_ARROW_CONNECTOR, mxArrowConnector);
  		mxCellRenderer.registerShape(mxConstants.SHAPE_DOUBLE_ELLIPSE, mxDoubleEllipse);
  		mxCellRenderer.registerShape(mxConstants.SHAPE_SWIMLANE, mxSwimlane);
  		mxCellRenderer.registerShape(mxConstants.SHAPE_IMAGE, mxImageShape);
  		mxCellRenderer.registerShape(mxConstants.SHAPE_LABEL, mxLabel);
  		mxCellRenderer.prototype.initializeShape = function(state)
  		{
  			state.shape.dialect = state.view.graph.dialect;
  			this.configureShape(state);
  			state.shape.init(state.view.getDrawPane());
  		};
  		mxCellRenderer.prototype.createShape = function(state)
  		{
  			var shape = null;
  			if (state.style != null)
  			{
  				var stencil = mxStencilRegistry.getStencil(state.style[mxConstants.STYLE_SHAPE]);
  				if (stencil != null)
  				{
  					shape = new mxShape(stencil);
  				}
  				else
  				{
  					var ctor = this.getShapeConstructor(state);
  					shape = new ctor();
  				}
  			}
  			return shape;
  		};
  		mxCellRenderer.prototype.createIndicatorShape = function(state)
  		{
  			state.shape.indicatorShape = this.getShape(state.view.graph.getIndicatorShape(state));
  		};
  		mxCellRenderer.prototype.getShape = function(name)
  		{
  			return (name != null) ? mxCellRenderer.defaultShapes[name] : null;
  		};
  		mxCellRenderer.prototype.getShapeConstructor = function(state)
  		{
  			var ctor = this.getShape(state.style[mxConstants.STYLE_SHAPE]);
  			if (ctor == null)
  			{
  				ctor = (state.view.graph.getModel().isEdge(state.cell)) ?
  					this.defaultEdgeShape : this.defaultVertexShape;
  			}
  			return ctor;
  		};
  		mxCellRenderer.prototype.configureShape = function(state)
  		{
  			state.shape.apply(state);
  			state.shape.image = state.view.graph.getImage(state);
  			state.shape.indicatorColor = state.view.graph.getIndicatorColor(state);
  			state.shape.indicatorStrokeColor = state.style[mxConstants.STYLE_INDICATOR_STROKECOLOR];
  			state.shape.indicatorGradientColor = state.view.graph.getIndicatorGradientColor(state);
  			state.shape.indicatorDirection = state.style[mxConstants.STYLE_INDICATOR_DIRECTION];
  			state.shape.indicatorImage = state.view.graph.getIndicatorImage(state);
  			this.postConfigureShape(state);
  		};
  		mxCellRenderer.prototype.postConfigureShape = function(state)
  		{
  			if (state.shape != null)
  			{
  				this.resolveColor(state, 'indicatorGradientColor', mxConstants.STYLE_GRADIENTCOLOR);
  				this.resolveColor(state, 'indicatorColor', mxConstants.STYLE_FILLCOLOR);
  				this.resolveColor(state, 'gradient', mxConstants.STYLE_GRADIENTCOLOR);
  				this.resolveColor(state, 'stroke', mxConstants.STYLE_STROKECOLOR);
  				this.resolveColor(state, 'fill', mxConstants.STYLE_FILLCOLOR);
  			}
  		};
  		mxCellRenderer.prototype.checkPlaceholderStyles = function(state)
  		{
  			if (state.style != null)
  			{
  				var values = ['inherit', 'swimlane', 'indicated'];
  				var styles = [mxConstants.STYLE_FILLCOLOR, mxConstants.STYLE_STROKECOLOR,
  					mxConstants.STYLE_GRADIENTCOLOR, mxConstants.STYLE_FONTCOLOR];
  				for (var i = 0; i < styles.length; i++)
  				{
  					if (mxUtils.indexOf(values, state.style[styles[i]]) >= 0)
  					{
  						return true;
  					}
  				}
  			}
  			return false;
  		};
  		mxCellRenderer.prototype.resolveColor = function(state, field, key)
  		{
  			var shape = (key == mxConstants.STYLE_FONTCOLOR) ?
  				state.text : state.shape;
  			if (shape != null)
  			{
  				var graph = state.view.graph;
  				var value = shape[field];
  				var referenced = null;
  				if (value == 'inherit')
  				{
  					referenced = graph.model.getParent(state.cell);
  				}
  				else if (value == 'swimlane')
  				{
  					shape[field] = (key == mxConstants.STYLE_STROKECOLOR ||
  						key == mxConstants.STYLE_FONTCOLOR) ?
  						'#000000' : '#ffffff';
  					if (graph.model.getTerminal(state.cell, false) != null)
  					{
  						referenced = graph.model.getTerminal(state.cell, false);
  					}
  					else
  					{
  						referenced = state.cell;
  					}
  					referenced = graph.getSwimlane(referenced);
  					key = graph.swimlaneIndicatorColorAttribute;
  				}
  				else if (value == 'indicated' && state.shape != null)
  				{
  					shape[field] = state.shape.indicatorColor;
  				}
  				else if (key != mxConstants.STYLE_FILLCOLOR &&
  					value == mxConstants.STYLE_FILLCOLOR &&
  					state.shape != null)
  				{
  					shape[field] = state.style[mxConstants.STYLE_FILLCOLOR];
  				}
  				else if (key != mxConstants.STYLE_STROKECOLOR &&
  					value == mxConstants.STYLE_STROKECOLOR &&
  					state.shape != null)
  				{
  					shape[field] = state.style[mxConstants.STYLE_STROKECOLOR];
  				}
  				if (referenced != null)
  				{
  					var rstate = graph.getView().getState(referenced);
  					shape[field] = null;
  					if (rstate != null)
  					{
  						var rshape = (key == mxConstants.STYLE_FONTCOLOR) ? rstate.text : rstate.shape;
  						if (rshape != null && field != 'indicatorColor')
  						{
  							shape[field] = rshape[field];
  						}
  						else
  						{
  							shape[field] = rstate.style[key];
  						}
  					}
  				}
  			}
  		};
  		mxCellRenderer.prototype.getLabelValue = function(state)
  		{
  			return state.view.graph.getLabel(state.cell);
  		};
  		mxCellRenderer.prototype.createLabel = function(state, value)
  		{
  			var graph = state.view.graph;
  			graph.getModel().isEdge(state.cell);
  			if (state.style[mxConstants.STYLE_FONTSIZE] > 0 || state.style[mxConstants.STYLE_FONTSIZE] == null)
  			{
  				var isForceHtml = (graph.isHtmlLabel(state.cell) || (value != null && mxUtils.isNode(value)));
  				state.text = new this.defaultTextShape(value, new mxRectangle(),
  						(state.style[mxConstants.STYLE_ALIGN] || mxConstants.ALIGN_CENTER),
  						graph.getVerticalAlign(state),
  						state.style[mxConstants.STYLE_FONTCOLOR],
  						state.style[mxConstants.STYLE_FONTFAMILY],
  						state.style[mxConstants.STYLE_FONTSIZE],
  						state.style[mxConstants.STYLE_FONTSTYLE],
  						state.style[mxConstants.STYLE_SPACING],
  						state.style[mxConstants.STYLE_SPACING_TOP],
  						state.style[mxConstants.STYLE_SPACING_RIGHT],
  						state.style[mxConstants.STYLE_SPACING_BOTTOM],
  						state.style[mxConstants.STYLE_SPACING_LEFT],
  						state.style[mxConstants.STYLE_HORIZONTAL],
  						state.style[mxConstants.STYLE_LABEL_BACKGROUNDCOLOR],
  						state.style[mxConstants.STYLE_LABEL_BORDERCOLOR],
  						graph.isWrapping(state.cell) && graph.isHtmlLabel(state.cell),
  						graph.isLabelClipped(state.cell),
  						state.style[mxConstants.STYLE_OVERFLOW],
  						state.style[mxConstants.STYLE_LABEL_PADDING],
  						mxUtils.getValue(state.style, mxConstants.STYLE_TEXT_DIRECTION, mxConstants.DEFAULT_TEXT_DIRECTION));
  				state.text.opacity = mxUtils.getValue(state.style, mxConstants.STYLE_TEXT_OPACITY, 100);
  				state.text.dialect = (isForceHtml) ? mxConstants.DIALECT_STRICTHTML : state.view.graph.dialect;
  				state.text.style = state.style;
  				state.text.state = state;
  				this.initializeLabel(state, state.text);
  				var forceGetCell = false;
  				var getState = function(evt)
  				{
  					var result = state;
  					if (mxClient.IS_TOUCH || forceGetCell)
  					{
  						var x = mxEvent.getClientX(evt);
  						var y = mxEvent.getClientY(evt);
  						var pt = mxUtils.convertPoint(graph.container, x, y);
  						result = graph.view.getState(graph.getCellAt(pt.x, pt.y));
  					}
  					return result;
  				};
  				mxEvent.addGestureListeners(state.text.node,
  					mxUtils.bind(this, function(evt)
  					{
  						if (this.isLabelEvent(state, evt))
  						{
  							graph.fireMouseEvent(mxEvent.MOUSE_DOWN, new mxMouseEvent(evt, state));
  							forceGetCell = graph.dialect != mxConstants.DIALECT_SVG &&
  								mxEvent.getSource(evt).nodeName == 'IMG';
  						}
  					}),
  					mxUtils.bind(this, function(evt)
  					{
  						if (this.isLabelEvent(state, evt))
  						{
  							graph.fireMouseEvent(mxEvent.MOUSE_MOVE, new mxMouseEvent(evt, getState(evt)));
  						}
  					}),
  					mxUtils.bind(this, function(evt)
  					{
  						if (this.isLabelEvent(state, evt))
  						{
  							graph.fireMouseEvent(mxEvent.MOUSE_UP, new mxMouseEvent(evt, getState(evt)));
  							forceGetCell = false;
  						}
  					})
  				);
  				if (graph.nativeDblClickEnabled)
  				{
  					mxEvent.addListener(state.text.node, 'dblclick',
  						mxUtils.bind(this, function(evt)
  						{
  							if (this.isLabelEvent(state, evt))
  							{
  								graph.dblClick(evt, state.cell);
  								mxEvent.consume(evt);
  							}
  						})
  					);
  				}
  			}
  		};
  		mxCellRenderer.prototype.initializeLabel = function(state, shape)
  		{
  			if (mxClient.IS_SVG && mxClient.NO_FO && shape.dialect != mxConstants.DIALECT_SVG)
  			{
  				shape.init(state.view.graph.container);
  			}
  			else
  			{
  				shape.init(state.view.getDrawPane());
  			}
  		};
  		mxCellRenderer.prototype.createCellOverlays = function(state)
  		{
  			var graph = state.view.graph;
  			var overlays = graph.getCellOverlays(state.cell);
  			var dict = null;
  			if (overlays != null)
  			{
  				dict = new mxDictionary();
  				for (var i = 0; i < overlays.length; i++)
  				{
  					var shape = (state.overlays != null) ? state.overlays.remove(overlays[i]) : null;
  					if (shape == null)
  					{
  						var tmp = new mxImageShape(new mxRectangle(), overlays[i].image.src);
  						tmp.dialect = state.view.graph.dialect;
  						tmp.preserveImageAspect = false;
  						tmp.overlay = overlays[i];
  						this.initializeOverlay(state, tmp);
  						this.installCellOverlayListeners(state, overlays[i], tmp);
  						if (overlays[i].cursor != null)
  						{
  							tmp.node.style.cursor = overlays[i].cursor;
  						}
  						dict.put(overlays[i], tmp);
  					}
  					else
  					{
  						dict.put(overlays[i], shape);
  					}
  				}
  			}
  			if (state.overlays != null)
  			{
  				state.overlays.visit(function(id, shape)
  				{
  					shape.destroy();
  				});
  			}
  			state.overlays = dict;
  		};
  		mxCellRenderer.prototype.initializeOverlay = function(state, overlay)
  		{
  			overlay.init(state.view.getOverlayPane());
  		};
  		mxCellRenderer.prototype.installCellOverlayListeners = function(state, overlay, shape)
  		{
  			var graph  = state.view.graph;
  			mxEvent.addListener(shape.node, 'click', function (evt)
  			{
  				if (graph.isEditing())
  				{
  					graph.stopEditing(!graph.isInvokesStopCellEditing());
  				}
  				overlay.fireEvent(new mxEventObject(mxEvent.CLICK,
  						'event', evt, 'cell', state.cell));
  			});
  			mxEvent.addGestureListeners(shape.node,
  				function (evt)
  				{
  					mxEvent.consume(evt);
  				},
  				function (evt)
  				{
  					graph.fireMouseEvent(mxEvent.MOUSE_MOVE,
  						new mxMouseEvent(evt, state));
  				});
  			if (mxClient.IS_TOUCH)
  			{
  				mxEvent.addListener(shape.node, 'touchend', function (evt)
  				{
  					overlay.fireEvent(new mxEventObject(mxEvent.CLICK,
  							'event', evt, 'cell', state.cell));
  				});
  			}
  		};
  		mxCellRenderer.prototype.createControl = function(state)
  		{
  			var graph = state.view.graph;
  			var image = graph.getFoldingImage(state);
  			if (graph.foldingEnabled && image != null)
  			{
  				if (state.control == null)
  				{
  					var b = new mxRectangle(0, 0, image.width, image.height);
  					state.control = new mxImageShape(b, image.src);
  					state.control.preserveImageAspect = false;
  					state.control.dialect = graph.dialect;
  					this.initControl(state, state.control, true, this.createControlClickHandler(state));
  				}
  			}
  			else if (state.control != null)
  			{
  				state.control.destroy();
  				state.control = null;
  			}
  		};
  		mxCellRenderer.prototype.createControlClickHandler = function(state)
  		{
  			var graph = state.view.graph;
  			return mxUtils.bind(this, function (evt)
  			{
  				if (this.forceControlClickHandler || graph.isEnabled())
  				{
  					var collapse = !graph.isCellCollapsed(state.cell);
  					graph.foldCells(collapse, false, [state.cell], null, evt);
  					mxEvent.consume(evt);
  				}
  			});
  		};
  		mxCellRenderer.prototype.initControl = function(state, control, handleEvents, clickHandler)
  		{
  			var graph = state.view.graph;
  			var isForceHtml = graph.isHtmlLabel(state.cell) && mxClient.NO_FO &&
  				graph.dialect == mxConstants.DIALECT_SVG;
  			if (isForceHtml)
  			{
  				control.dialect = mxConstants.DIALECT_PREFERHTML;
  				control.init(graph.container);
  				control.node.style.zIndex = 1;
  			}
  			else
  			{
  				control.init(state.view.getOverlayPane());
  			}
  			var node = control.innerNode || control.node;
  			if (clickHandler != null && !mxClient.IS_IOS)
  			{
  				if (graph.isEnabled())
  				{
  					node.style.cursor = 'pointer';
  				}
  				mxEvent.addListener(node, 'click', clickHandler);
  			}
  			if (handleEvents)
  			{
  				var first = null;
  				mxEvent.addGestureListeners(node,
  					function (evt)
  					{
  						first = new mxPoint(mxEvent.getClientX(evt), mxEvent.getClientY(evt));
  						graph.fireMouseEvent(mxEvent.MOUSE_DOWN, new mxMouseEvent(evt, state));
  						mxEvent.consume(evt);
  					},
  					function (evt)
  					{
  						graph.fireMouseEvent(mxEvent.MOUSE_MOVE, new mxMouseEvent(evt, state));
  					},
  					function (evt)
  					{
  						graph.fireMouseEvent(mxEvent.MOUSE_UP, new mxMouseEvent(evt, state));
  						mxEvent.consume(evt);
  					});
  				if (clickHandler != null && mxClient.IS_IOS)
  				{
  					node.addEventListener('touchend', function(evt)
  					{
  						if (first != null)
  						{
  							var tol = graph.tolerance;
  							if (Math.abs(first.x - mxEvent.getClientX(evt)) < tol &&
  								Math.abs(first.y - mxEvent.getClientY(evt)) < tol)
  							{
  								clickHandler.call(clickHandler, evt);
  								mxEvent.consume(evt);
  							}
  						}
  					}, true);
  				}
  			}
  			return node;
  		};
  		mxCellRenderer.prototype.isShapeEvent = function(state, evt)
  		{
  			return true;
  		};
  		mxCellRenderer.prototype.isLabelEvent = function(state, evt)
  		{
  			return true;
  		};
  		mxCellRenderer.prototype.installListeners = function(state)
  		{
  			var graph = state.view.graph;
  			var getState = function(evt)
  			{
  				var result = state;
  				if ((graph.dialect != mxConstants.DIALECT_SVG && mxEvent.getSource(evt).nodeName == 'IMG') || mxClient.IS_TOUCH)
  				{
  					var x = mxEvent.getClientX(evt);
  					var y = mxEvent.getClientY(evt);
  					var pt = mxUtils.convertPoint(graph.container, x, y);
  					result = graph.view.getState(graph.getCellAt(pt.x, pt.y));
  				}
  				return result;
  			};
  			mxEvent.addGestureListeners(state.shape.node,
  				mxUtils.bind(this, function(evt)
  				{
  					if (this.isShapeEvent(state, evt))
  					{
  						graph.fireMouseEvent(mxEvent.MOUSE_DOWN, new mxMouseEvent(evt, state));
  					}
  				}),
  				mxUtils.bind(this, function(evt)
  				{
  					if (this.isShapeEvent(state, evt))
  					{
  						graph.fireMouseEvent(mxEvent.MOUSE_MOVE, new mxMouseEvent(evt, getState(evt)));
  					}
  				}),
  				mxUtils.bind(this, function(evt)
  				{
  					if (this.isShapeEvent(state, evt))
  					{
  						graph.fireMouseEvent(mxEvent.MOUSE_UP, new mxMouseEvent(evt, getState(evt)));
  					}
  				})
  			);
  			if (graph.nativeDblClickEnabled)
  			{
  				mxEvent.addListener(state.shape.node, 'dblclick',
  					mxUtils.bind(this, function(evt)
  					{
  						if (this.isShapeEvent(state, evt))
  						{
  							graph.dblClick(evt, state.cell);
  							mxEvent.consume(evt);
  						}
  					})
  				);
  			}
  		};
  		mxCellRenderer.prototype.redrawLabel = function(state, forced)
  		{
  			var graph = state.view.graph;
  			var value = this.getLabelValue(state);
  			var wrapping = graph.isWrapping(state.cell);
  			var clipping = graph.isLabelClipped(state.cell);
  			var isForceHtml = (state.view.graph.isHtmlLabel(state.cell) || (value != null && mxUtils.isNode(value)));
  			var dialect = (isForceHtml) ? mxConstants.DIALECT_STRICTHTML : state.view.graph.dialect;
  			var overflow = state.style[mxConstants.STYLE_OVERFLOW] || 'visible';
  			if (state.text != null && (state.text.wrap != wrapping || state.text.clipped != clipping ||
  				state.text.overflow != overflow || state.text.dialect != dialect))
  			{
  				state.text.destroy();
  				state.text = null;
  			}
  			if (state.text == null && value != null && (mxUtils.isNode(value) || value.length > 0))
  			{
  				this.createLabel(state, value);
  			}
  			else if (state.text != null && (value == null || value.length == 0))
  			{
  				state.text.destroy();
  				state.text = null;
  			}
  			if (state.text != null)
  			{
  				if (forced)
  				{
  					if (state.text.lastValue != null && this.isTextShapeInvalid(state, state.text))
  					{
  						state.text.lastValue = null;
  					}
  					state.text.resetStyles();
  					state.text.apply(state);
  					state.text.valign = graph.getVerticalAlign(state);
  				}
  				var bounds = this.getLabelBounds(state);
  				var nextScale = this.getTextScale(state);
  				this.resolveColor(state, 'color', mxConstants.STYLE_FONTCOLOR);
  				if (forced || state.text.value != value || state.text.isWrapping != wrapping ||
  					state.text.overflow != overflow || state.text.isClipping != clipping ||
  					state.text.scale != nextScale || state.text.dialect != dialect ||
  					state.text.bounds == null || !state.text.bounds.equals(bounds))
  				{
  					state.text.dialect = dialect;
  					state.text.value = value;
  					state.text.bounds = bounds;
  					state.text.scale = nextScale;
  					state.text.wrap = wrapping;
  					state.text.clipped = clipping;
  					state.text.overflow = overflow;
  					var vis = state.text.node.style.visibility;
  					this.redrawLabelShape(state.text);
  					state.text.node.style.visibility = vis;
  				}
  			}
  		};
  		mxCellRenderer.prototype.isTextShapeInvalid = function(state, shape)
  		{
  			function check(property, stylename, defaultValue)
  			{
  				var result = false;
  				if (stylename == 'spacingTop' || stylename == 'spacingRight' ||
  					stylename == 'spacingBottom' || stylename == 'spacingLeft')
  				{
  					result = parseFloat(shape[property]) - parseFloat(shape.spacing) !=
  						(state.style[stylename] || defaultValue);
  				}
  				else
  				{
  					result = shape[property] != (state.style[stylename] || defaultValue);
  				}
  				return result;
  			}			return check('fontStyle', mxConstants.STYLE_FONTSTYLE, mxConstants.DEFAULT_FONTSTYLE) ||
  				check('family', mxConstants.STYLE_FONTFAMILY, mxConstants.DEFAULT_FONTFAMILY) ||
  				check('size', mxConstants.STYLE_FONTSIZE, mxConstants.DEFAULT_FONTSIZE) ||
  				check('color', mxConstants.STYLE_FONTCOLOR, 'black') ||
  				check('align', mxConstants.STYLE_ALIGN, '') ||
  				check('valign', mxConstants.STYLE_VERTICAL_ALIGN, '') ||
  				check('spacing', mxConstants.STYLE_SPACING, 2) ||
  				check('spacingTop', mxConstants.STYLE_SPACING_TOP, 0) ||
  				check('spacingRight', mxConstants.STYLE_SPACING_RIGHT, 0) ||
  				check('spacingBottom', mxConstants.STYLE_SPACING_BOTTOM, 0) ||
  				check('spacingLeft', mxConstants.STYLE_SPACING_LEFT, 0) ||
  				check('horizontal', mxConstants.STYLE_HORIZONTAL, true) ||
  				check('background', mxConstants.STYLE_LABEL_BACKGROUNDCOLOR) ||
  				check('border', mxConstants.STYLE_LABEL_BORDERCOLOR) ||
  				check('opacity', mxConstants.STYLE_TEXT_OPACITY, 100) ||
  				check('textDirection', mxConstants.STYLE_TEXT_DIRECTION, mxConstants.DEFAULT_TEXT_DIRECTION);
  		};
  		mxCellRenderer.prototype.redrawLabelShape = function(shape)
  		{
  			shape.redraw();
  		};
  		mxCellRenderer.prototype.getTextScale = function(state)
  		{
  			return state.view.scale;
  		};
  		mxCellRenderer.prototype.getLabelBounds = function(state)
  		{
  			var graph = state.view.graph;
  			var scale = state.view.scale;
  			var isEdge = graph.getModel().isEdge(state.cell);
  			var bounds = new mxRectangle(state.absoluteOffset.x, state.absoluteOffset.y);
  			if (isEdge)
  			{
  				var spacing = state.text.getSpacing();
  				bounds.x += spacing.x * scale;
  				bounds.y += spacing.y * scale;
  				var geo = graph.getCellGeometry(state.cell);
  				if (geo != null)
  				{
  					bounds.width = Math.max(0, geo.width * scale);
  					bounds.height = Math.max(0, geo.height * scale);
  				}
  			}
  			else
  			{
  				if (state.text.isPaintBoundsInverted())
  				{
  					var tmp = bounds.x;
  					bounds.x = bounds.y;
  					bounds.y = tmp;
  				}
  				bounds.x += state.x;
  				bounds.y += state.y;
  				bounds.width = Math.max(1, state.width);
  				bounds.height = Math.max(1, state.height);
  			}
  			if (state.text.isPaintBoundsInverted())
  			{
  				var t = (state.width - state.height) / 2;
  				bounds.x += t;
  				bounds.y -= t;
  				var tmp = bounds.width;
  				bounds.width = bounds.height;
  				bounds.height = tmp;
  			}
  			if (state.shape != null)
  			{
  				var hpos = mxUtils.getValue(state.style, mxConstants.STYLE_LABEL_POSITION, mxConstants.ALIGN_CENTER);
  				var vpos = mxUtils.getValue(state.style, mxConstants.STYLE_VERTICAL_LABEL_POSITION, mxConstants.ALIGN_MIDDLE);
  				if (hpos == mxConstants.ALIGN_CENTER && vpos == mxConstants.ALIGN_MIDDLE)
  				{
  					bounds = state.shape.getLabelBounds(bounds);
  				}
  			}
  			var lw = mxUtils.getValue(state.style, mxConstants.STYLE_LABEL_WIDTH, null);
  			if (lw != null)
  			{
  				bounds.width = parseFloat(lw) * scale;
  			}
  			if (!isEdge)
  			{
  				this.rotateLabelBounds(state, bounds);
  			}
  			return bounds;
  		};
  		mxCellRenderer.prototype.rotateLabelBounds = function(state, bounds)
  		{
  			bounds.y -= state.text.margin.y * bounds.height;
  			bounds.x -= state.text.margin.x * bounds.width;
  			if (!this.legacySpacing || (state.style[mxConstants.STYLE_OVERFLOW] != 'fill' && state.style[mxConstants.STYLE_OVERFLOW] != 'width'))
  			{
  				var s = state.view.scale;
  				var spacing = state.text.getSpacing();
  				bounds.x += spacing.x * s;
  				bounds.y += spacing.y * s;
  				var hpos = mxUtils.getValue(state.style, mxConstants.STYLE_LABEL_POSITION, mxConstants.ALIGN_CENTER);
  				var vpos = mxUtils.getValue(state.style, mxConstants.STYLE_VERTICAL_LABEL_POSITION, mxConstants.ALIGN_MIDDLE);
  				var lw = mxUtils.getValue(state.style, mxConstants.STYLE_LABEL_WIDTH, null);
  				bounds.width = Math.max(0, bounds.width - ((hpos == mxConstants.ALIGN_CENTER && lw == null) ? (state.text.spacingLeft * s + state.text.spacingRight * s) : 0));
  				bounds.height = Math.max(0, bounds.height - ((vpos == mxConstants.ALIGN_MIDDLE) ? (state.text.spacingTop * s + state.text.spacingBottom * s) : 0));
  			}
  			var theta = state.text.getTextRotation();
  			if (theta != 0 && state != null && state.view.graph.model.isVertex(state.cell))
  			{
  				var cx = state.getCenterX();
  				var cy = state.getCenterY();
  				if (bounds.x != cx || bounds.y != cy)
  				{
  					var rad = theta * (Math.PI / 180);
  					var pt = mxUtils.getRotatedPoint(new mxPoint(bounds.x, bounds.y),
  							Math.cos(rad), Math.sin(rad), new mxPoint(cx, cy));
  					bounds.x = pt.x;
  					bounds.y = pt.y;
  				}
  			}
  		};
  		mxCellRenderer.prototype.redrawCellOverlays = function(state, forced)
  		{
  			this.createCellOverlays(state);
  			if (state.overlays != null)
  			{
  				var rot = mxUtils.mod(mxUtils.getValue(state.style, mxConstants.STYLE_ROTATION, 0), 90);
  		        var rad = mxUtils.toRadians(rot);
  		        var cos = Math.cos(rad);
  		        var sin = Math.sin(rad);
  				state.overlays.visit(function(id, shape)
  				{
  					var bounds = shape.overlay.getBounds(state);
  					if (!state.view.graph.getModel().isEdge(state.cell))
  					{
  						if (state.shape != null && rot != 0)
  						{
  							var cx = bounds.getCenterX();
  							var cy = bounds.getCenterY();
  							var point = mxUtils.getRotatedPoint(new mxPoint(cx, cy), cos, sin,
  					        		new mxPoint(state.getCenterX(), state.getCenterY()));
  					        cx = point.x;
  					        cy = point.y;
  					        bounds.x = Math.round(cx - bounds.width / 2);
  					        bounds.y = Math.round(cy - bounds.height / 2);
  						}
  					}
  					if (forced || shape.bounds == null || shape.scale != state.view.scale ||
  						!shape.bounds.equals(bounds))
  					{
  						shape.bounds = bounds;
  						shape.scale = state.view.scale;
  						shape.redraw();
  					}
  				});
  			}
  		};
  		mxCellRenderer.prototype.redrawControl = function(state, forced)
  		{
  			var image = state.view.graph.getFoldingImage(state);
  			if (state.control != null && image != null)
  			{
  				var bounds = this.getControlBounds(state, image.width, image.height);
  				var r = (this.legacyControlPosition) ?
  						mxUtils.getValue(state.style, mxConstants.STYLE_ROTATION, 0) :
  						state.shape.getTextRotation();
  				var s = state.view.scale;
  				if (forced || state.control.scale != s || !state.control.bounds.equals(bounds) ||
  					state.control.rotation != r)
  				{
  					state.control.rotation = r;
  					state.control.bounds = bounds;
  					state.control.scale = s;
  					state.control.redraw();
  				}
  			}
  		};
  		mxCellRenderer.prototype.getControlBounds = function(state, w, h)
  		{
  			if (state.control != null)
  			{
  				var s = state.view.scale;
  				var cx = state.getCenterX();
  				var cy = state.getCenterY();
  				if (!state.view.graph.getModel().isEdge(state.cell))
  				{
  					cx = state.x + w * s;
  					cy = state.y + h * s;
  					if (state.shape != null)
  					{
  						var rot = state.shape.getShapeRotation();
  						if (this.legacyControlPosition)
  						{
  							rot = mxUtils.getValue(state.style, mxConstants.STYLE_ROTATION, 0);
  						}
  						else
  						{
  							if (state.shape.isPaintBoundsInverted())
  							{
  								var t = (state.width - state.height) / 2;
  								cx += t;
  								cy -= t;
  							}
  						}
  						if (rot != 0)
  						{
  					        var rad = mxUtils.toRadians(rot);
  					        var cos = Math.cos(rad);
  					        var sin = Math.sin(rad);
  					        var point = mxUtils.getRotatedPoint(new mxPoint(cx, cy), cos, sin,
  					        		new mxPoint(state.getCenterX(), state.getCenterY()));
  					        cx = point.x;
  					        cy = point.y;
  						}
  					}
  				}
  				return (state.view.graph.getModel().isEdge(state.cell)) ?
  					new mxRectangle(Math.round(cx - w / 2 * s), Math.round(cy - h / 2 * s), Math.round(w * s), Math.round(h * s))
  					: new mxRectangle(Math.round(cx - w / 2 * s), Math.round(cy - h / 2 * s), Math.round(w * s), Math.round(h * s));
  			}
  			return null;
  		};
  		mxCellRenderer.prototype.insertStateAfter = function(state, node, htmlNode)
  		{
  			var shapes = this.getShapesForState(state);
  			for (var i = 0; i < shapes.length; i++)
  			{
  				if (shapes[i] != null && shapes[i].node != null)
  				{
  					var html = shapes[i].node.parentNode != state.view.getDrawPane() &&
  						shapes[i].node.parentNode != state.view.getOverlayPane();
  					var temp = (html) ? htmlNode : node;
  					if (temp != null && temp.nextSibling != shapes[i].node)
  					{
  						if (temp.nextSibling == null)
  						{
  							temp.parentNode.appendChild(shapes[i].node);
  						}
  						else
  						{
  							temp.parentNode.insertBefore(shapes[i].node, temp.nextSibling);
  						}
  					}
  					else if (temp == null)
  					{
  						if (shapes[i].node.parentNode == state.view.graph.container)
  						{
  							var canvas = state.view.canvas;
  							while (canvas != null && canvas.parentNode != state.view.graph.container)
  							{
  								canvas = canvas.parentNode;
  							}
  							if (canvas != null && canvas.nextSibling != null)
  							{
  								if (canvas.nextSibling != shapes[i].node)
  								{
  									shapes[i].node.parentNode.insertBefore(shapes[i].node, canvas.nextSibling);
  								}
  							}
  							else
  							{
  								shapes[i].node.parentNode.appendChild(shapes[i].node);
  							}
  						}
  						else if (shapes[i].node.parentNode != null &&
  							shapes[i].node.parentNode.firstChild != null &&
  							shapes[i].node.parentNode.firstChild != shapes[i].node)
  						{
  							shapes[i].node.parentNode.insertBefore(shapes[i].node, shapes[i].node.parentNode.firstChild);
  						}
  					}
  					if (html)
  					{
  						htmlNode = shapes[i].node;
  					}
  					else
  					{
  						node = shapes[i].node;
  					}
  				}
  			}
  			return [node, htmlNode];
  		};
  		mxCellRenderer.prototype.getShapesForState = function(state)
  		{
  			return [state.shape, state.text, state.control];
  		};
  		mxCellRenderer.prototype.redraw = function(state, force, rendering)
  		{
  			var shapeChanged = this.redrawShape(state, force, rendering);
  			if (state.shape != null && (rendering == null || rendering))
  			{
  				this.redrawLabel(state, shapeChanged);
  				this.redrawCellOverlays(state, shapeChanged);
  				this.redrawControl(state, shapeChanged);
  			}
  		};
  		mxCellRenderer.prototype.redrawShape = function(state, force, rendering)
  		{
  			var model = state.view.graph.model;
  			var shapeChanged = false;
  			if (state.shape != null && state.shape.style != null && state.style != null &&
  				state.shape.style[mxConstants.STYLE_SHAPE] != state.style[mxConstants.STYLE_SHAPE])
  			{
  				state.shape.destroy();
  				state.shape = null;
  			}
  			if (state.shape == null && state.view.graph.container != null &&
  				state.cell != state.view.currentRoot &&
  				(model.isVertex(state.cell) || model.isEdge(state.cell)))
  			{
  				state.shape = this.createShape(state);
  				if (state.shape != null)
  				{
  					state.shape.minSvgStrokeWidth = this.minSvgStrokeWidth;
  					state.shape.antiAlias = this.antiAlias;
  					this.createIndicatorShape(state);
  					this.initializeShape(state);
  					this.createCellOverlays(state);
  					this.installListeners(state);
  					state.view.graph.selectionCellsHandler.updateHandler(state);
  				}
  			}
  			else if (!force && state.shape != null && (!mxUtils.equalEntries(state.shape.style,
  				state.style) || this.checkPlaceholderStyles(state)))
  			{
  				state.shape.resetStyles();
  				this.configureShape(state);
  				state.view.graph.selectionCellsHandler.updateHandler(state);
  				force = true;
  			}
  			if (state.shape != null && state.shape.indicatorShape !=
  				this.getShape(state.view.graph.getIndicatorShape(state)))
  			{
  				if (state.shape.indicator != null)
  				{
  					state.shape.indicator.destroy();
  					state.shape.indicator = null;
  				}
  				this.createIndicatorShape(state);
  				if (state.shape.indicatorShape != null)
  				{
  					state.shape.indicator = new state.shape.indicatorShape();
  					state.shape.indicator.dialect = state.shape.dialect;
  					state.shape.indicator.init(state.node);
  					force = true;
  				}
  			}
  			if (state.shape != null)
  			{
  				this.createControl(state);
  				if (force || this.isShapeInvalid(state, state.shape))
  				{
  					if (state.absolutePoints != null)
  					{
  						state.shape.points = state.absolutePoints.slice();
  						state.shape.bounds = null;
  					}
  					else
  					{
  						state.shape.points = null;
  						state.shape.bounds = new mxRectangle(state.x, state.y, state.width, state.height);
  					}
  					state.shape.scale = state.view.scale;
  					if (rendering == null || rendering)
  					{
  						this.doRedrawShape(state);
  					}
  					else
  					{
  						state.shape.updateBoundingBox();
  					}
  					shapeChanged = true;
  				}
  			}
  			return shapeChanged;
  		};
  		mxCellRenderer.prototype.doRedrawShape = function(state)
  		{
  			state.shape.redraw();
  		};
  		mxCellRenderer.prototype.isShapeInvalid = function(state, shape)
  		{
  			return shape.bounds == null || shape.scale != state.view.scale ||
  				(state.absolutePoints == null && !shape.bounds.equals(state)) ||
  				(state.absolutePoints != null && !mxUtils.equalPoints(shape.points, state.absolutePoints))
  		};
  		mxCellRenderer.prototype.destroy = function(state)
  		{
  			if (state.shape != null)
  			{
  				if (state.text != null)
  				{
  					state.text.destroy();
  					state.text = null;
  				}
  				if (state.overlays != null)
  				{
  					state.overlays.visit(function(id, shape)
  					{
  						shape.destroy();
  					});
  					state.overlays = null;
  				}
  				if (state.control != null)
  				{
  					state.control.destroy();
  					state.control = null;
  				}
  				state.shape.destroy();
  				state.shape = null;
  			}
  		};
  		__mxOutput.mxCellRenderer = typeof mxCellRenderer !== 'undefined' ? mxCellRenderer : undefined;
  		var mxEdgeStyle =
  		{
  			 EntityRelation: function(state, source, target, points, result)
  			 {
  				var view = state.view;
  			 	var graph = view.graph;
  			 	var segment = mxUtils.getValue(state.style,
  			 			mxConstants.STYLE_SEGMENT,
  			 			mxConstants.ENTITY_SEGMENT) * view.scale;
  				var pts = state.absolutePoints;
  				var p0 = pts[0];
  				var pe = pts[pts.length-1];
  			 	var isSourceLeft = false;
  			 	if (source != null)
  			 	{
  		 			var sourceGeometry = graph.getCellGeometry(source.cell);
  				 	if (sourceGeometry.relative)
  				 	{
  				 		isSourceLeft = sourceGeometry.x <= 0.5;
  				 	}
  				 	else if (target != null)
  				 	{
  				 		isSourceLeft = ((pe != null) ? pe.x : target.x + target.width) < ((p0 != null) ? p0.x : source.x);
  				 	}
  			 	}
  				if (p0 != null)
  				{
  					source = new mxCellState();
  					source.x = p0.x;
  					source.y = p0.y;
  				}
  				else if (source != null)
  				{
  					var constraint = mxUtils.getPortConstraints(source, state, true, mxConstants.DIRECTION_MASK_NONE);
  					if (constraint != mxConstants.DIRECTION_MASK_NONE && constraint != mxConstants.DIRECTION_MASK_WEST +
  						mxConstants.DIRECTION_MASK_EAST)
  					{
  						isSourceLeft = constraint == mxConstants.DIRECTION_MASK_WEST;
  					}
  				}
  				else
  				{
  					return;
  				}
  			 	var isTargetLeft = true;
  			 	if (target != null)
  			 	{
  				 	var targetGeometry = graph.getCellGeometry(target.cell);
  				 	if (targetGeometry.relative)
  				 	{
  				 		isTargetLeft = targetGeometry.x <= 0.5;
  				 	}
  				 	else if (source != null)
  				 	{
  				 		isTargetLeft = ((p0 != null) ? p0.x : source.x + source.width) < ((pe != null) ? pe.x : target.x);
  				 	}
  			 	}
  				if (pe != null)
  				{
  					target = new mxCellState();
  					target.x = pe.x;
  					target.y = pe.y;
  				}
  				else if (target != null)
  			 	{
  					var constraint = mxUtils.getPortConstraints(target, state, false, mxConstants.DIRECTION_MASK_NONE);
  					if (constraint != mxConstants.DIRECTION_MASK_NONE && constraint != mxConstants.DIRECTION_MASK_WEST +
  						mxConstants.DIRECTION_MASK_EAST)
  					{
  						isTargetLeft = constraint == mxConstants.DIRECTION_MASK_WEST;
  					}
  			 	}
  				if (source != null && target != null)
  				{
  					var x0 = (isSourceLeft) ? source.x : source.x + source.width;
  					var y0 = view.getRoutingCenterY(source);
  					var xe = (isTargetLeft) ? target.x : target.x + target.width;
  					var ye = view.getRoutingCenterY(target);
  					var seg = segment;
  					var dx = (isSourceLeft) ? -seg : seg;
  					var dep = new mxPoint(x0 + dx, y0);
  					dx = (isTargetLeft) ? -seg : seg;
  					var arr = new mxPoint(xe + dx, ye);
  					if (isSourceLeft == isTargetLeft)
  					{
  						var x = (isSourceLeft) ?
  							Math.min(x0, xe)-segment :
  							Math.max(x0, xe)+segment;
  						result.push(new mxPoint(x, y0));
  						result.push(new mxPoint(x, ye));
  					}
  					else if ((dep.x < arr.x) == isSourceLeft)
  					{
  						var midY = y0 + (ye - y0) / 2;
  						result.push(dep);
  						result.push(new mxPoint(dep.x, midY));
  						result.push(new mxPoint(arr.x, midY));
  						result.push(arr);
  					}
  					else
  					{
  						result.push(dep);
  						result.push(arr);
  					}
  				}
  			 },
  			Loop: function(state, source, target, points, result)
  			{
  				var pts = state.absolutePoints;
  				var p0 = pts[0];
  				var pe = pts[pts.length-1];
  				if (p0 != null && pe != null)
  				{
  					if (points != null && points.length > 0)
  					{
  						for (var i = 0; i < points.length; i++)
  						{
  							var pt = points[i];
  							pt = state.view.transformControlPoint(state, pt);
  							result.push(new mxPoint(pt.x, pt.y));
  						}
  					}
  					return;
  				}
  				if (source != null)
  				{
  					var view = state.view;
  					var graph = view.graph;
  					var pt = (points != null && points.length > 0) ? points[0] : null;
  					if (pt != null)
  					{
  						pt = view.transformControlPoint(state, pt);
  						if (mxUtils.contains(source, pt.x, pt.y))
  						{
  							pt = null;
  						}
  					}
  					var x = 0;
  					var dx = 0;
  					var y = 0;
  					var dy = 0;
  				 	var seg = mxUtils.getValue(state.style, mxConstants.STYLE_SEGMENT,
  				 		graph.gridSize) * view.scale;
  					var dir = mxUtils.getValue(state.style, mxConstants.STYLE_DIRECTION,
  						mxConstants.DIRECTION_WEST);
  					if (dir == mxConstants.DIRECTION_NORTH ||
  						dir == mxConstants.DIRECTION_SOUTH)
  					{
  						x = view.getRoutingCenterX(source);
  						dx = seg;
  					}
  					else
  					{
  						y = view.getRoutingCenterY(source);
  						dy = seg;
  					}
  					if (pt == null ||
  						pt.x < source.x ||
  						pt.x > source.x + source.width)
  					{
  						if (pt != null)
  						{
  							x = pt.x;
  							dy = Math.max(Math.abs(y - pt.y), dy);
  						}
  						else
  						{
  							if (dir == mxConstants.DIRECTION_NORTH)
  							{
  								y = source.y - 2 * dx;
  							}
  							else if (dir == mxConstants.DIRECTION_SOUTH)
  							{
  								y = source.y + source.height + 2 * dx;
  							}
  							else if (dir == mxConstants.DIRECTION_EAST)
  							{
  								x = source.x - 2 * dy;
  							}
  							else
  							{
  								x = source.x + source.width + 2 * dy;
  							}
  						}
  					}
  					else if (pt != null)
  					{
  						x = view.getRoutingCenterX(source);
  						dx = Math.max(Math.abs(x - pt.x), dy);
  						y = pt.y;
  						dy = 0;
  					}
  					result.push(new mxPoint(x - dx, y - dy));
  					result.push(new mxPoint(x + dx, y + dy));
  				}
  			},
  			ElbowConnector: function(state, source, target, points, result)
  			{
  				var pt = (points != null && points.length > 0) ? points[0] : null;
  				var vertical = false;
  				var horizontal = false;
  				if (source != null && target != null)
  				{
  					if (pt != null)
  					{
  						var left = Math.min(source.x, target.x);
  						var right = Math.max(source.x + source.width,
  							target.x + target.width);
  						var top = Math.min(source.y, target.y);
  						var bottom = Math.max(source.y + source.height,
  							target.y + target.height);
  						pt = state.view.transformControlPoint(state, pt);
  						vertical = pt.y < top || pt.y > bottom;
  						horizontal = pt.x < left || pt.x > right;
  					}
  					else
  					{
  						var left = Math.max(source.x, target.x);
  						var right = Math.min(source.x + source.width,
  							target.x + target.width);
  						vertical = left == right;
  						if (!vertical)
  						{
  							var top = Math.max(source.y, target.y);
  							var bottom = Math.min(source.y + source.height,
  								target.y + target.height);
  							horizontal = top == bottom;
  						}
  					}
  				}
  				if (!horizontal && (vertical ||
  					state.style[mxConstants.STYLE_ELBOW] == mxConstants.ELBOW_VERTICAL))
  				{
  					mxEdgeStyle.TopToBottom(state, source, target, points, result);
  				}
  				else
  				{
  					mxEdgeStyle.SideToSide(state, source, target, points, result);
  				}
  			},
  			SideToSide: function(state, source, target, points, result)
  			{
  				var view = state.view;
  				var pt = (points != null && points.length > 0) ? points[0] : null;
  				var pts = state.absolutePoints;
  				var p0 = pts[0];
  				var pe = pts[pts.length-1];
  				if (pt != null)
  				{
  					pt = view.transformControlPoint(state, pt);
  				}
  				if (p0 != null)
  				{
  					source = new mxCellState();
  					source.x = p0.x;
  					source.y = p0.y;
  				}
  				if (pe != null)
  				{
  					target = new mxCellState();
  					target.x = pe.x;
  					target.y = pe.y;
  				}
  				if (source != null && target != null)
  				{
  					var l = Math.max(source.x, target.x);
  					var r = Math.min(source.x + source.width,
  									 target.x + target.width);
  					var x = (pt != null) ? pt.x : Math.round(r + (l - r) / 2);
  					var y1 = view.getRoutingCenterY(source);
  					var y2 = view.getRoutingCenterY(target);
  					if (pt != null)
  					{
  						if (pt.y >= source.y && pt.y <= source.y + source.height)
  						{
  							y1 = pt.y;
  						}
  						if (pt.y >= target.y && pt.y <= target.y + target.height)
  						{
  							y2 = pt.y;
  						}
  					}
  					if (!mxUtils.contains(target, x, y1) &&
  						!mxUtils.contains(source, x, y1))
  					{
  						result.push(new mxPoint(x,  y1));
  					}
  					if (!mxUtils.contains(target, x, y2) &&
  						!mxUtils.contains(source, x, y2))
  					{
  						result.push(new mxPoint(x, y2));
  					}
  					if (result.length == 1)
  					{
  						if (pt != null)
  						{
  							if (!mxUtils.contains(target, x, pt.y) &&
  								!mxUtils.contains(source, x, pt.y))
  							{
  								result.push(new mxPoint(x, pt.y));
  							}
  						}
  						else
  						{
  							var t = Math.max(source.y, target.y);
  							var b = Math.min(source.y + source.height,
  									 target.y + target.height);
  							result.push(new mxPoint(x, t + (b - t) / 2));
  						}
  					}
  				}
  			},
  			TopToBottom: function(state, source, target, points, result)
  			{
  				var view = state.view;
  				var pt = (points != null && points.length > 0) ? points[0] : null;
  				var pts = state.absolutePoints;
  				var p0 = pts[0];
  				var pe = pts[pts.length-1];
  				if (pt != null)
  				{
  					pt = view.transformControlPoint(state, pt);
  				}
  				if (p0 != null)
  				{
  					source = new mxCellState();
  					source.x = p0.x;
  					source.y = p0.y;
  				}
  				if (pe != null)
  				{
  					target = new mxCellState();
  					target.x = pe.x;
  					target.y = pe.y;
  				}
  				if (source != null && target != null)
  				{
  					var t = Math.max(source.y, target.y);
  					var b = Math.min(source.y + source.height,
  									 target.y + target.height);
  					var x = view.getRoutingCenterX(source);
  					if (pt != null &&
  						pt.x >= source.x &&
  						pt.x <= source.x + source.width)
  					{
  						x = pt.x;
  					}
  					var y = (pt != null) ? pt.y : Math.round(b + (t - b) / 2);
  					if (!mxUtils.contains(target, x, y) &&
  						!mxUtils.contains(source, x, y))
  					{
  						result.push(new mxPoint(x, y));
  					}
  					if (pt != null &&
  						pt.x >= target.x &&
  						pt.x <= target.x + target.width)
  					{
  						x = pt.x;
  					}
  					else
  					{
  						x = view.getRoutingCenterX(target);
  					}
  					if (!mxUtils.contains(target, x, y) &&
  						!mxUtils.contains(source, x, y))
  					{
  						result.push(new mxPoint(x, y));
  					}
  					if (result.length == 1)
  					{
  						if (pt != null && result.length == 1)
  						{
  							if (!mxUtils.contains(target, pt.x, y) &&
  								!mxUtils.contains(source, pt.x, y))
  							{
  								result.push(new mxPoint(pt.x, y));
  							}
  						}
  						else
  						{
  							var l = Math.max(source.x, target.x);
  							var r = Math.min(source.x + source.width,
  									 target.x + target.width);
  							result.push(new mxPoint(l + (r - l) / 2, y));
  						}
  					}
  				}
  			},
  			SegmentConnector: function(state, sourceScaled, targetScaled, controlHints, result)
  			{
  				var pts = mxEdgeStyle.scalePointArray(state.absolutePoints, state.view.scale);
  				var source = mxEdgeStyle.scaleCellState(sourceScaled, state.view.scale);
  				var target = mxEdgeStyle.scaleCellState(targetScaled, state.view.scale);
  				var tol = 1;
  				var lastPushed = (result.length > 0) ? result[0] : null;
  				var horizontal = true;
  				var hint = null;
  				function pushPoint(pt)
  				{
  					pt.x = Math.round(pt.x * state.view.scale * 10) / 10;
  					pt.y = Math.round(pt.y * state.view.scale * 10) / 10;
  					if (lastPushed == null || Math.abs(lastPushed.x - pt.x) >= tol || Math.abs(lastPushed.y - pt.y) >= Math.max(1, state.view.scale))
  					{
  						result.push(pt);
  						lastPushed = pt;
  					}
  					return lastPushed;
  				}				var pt = pts[0];
  				if (pt == null && source != null)
  				{
  					pt = new mxPoint(state.view.getRoutingCenterX(source), state.view.getRoutingCenterY(source));
  				}
  				else if (pt != null)
  				{
  					pt = pt.clone();
  				}
  				var lastInx = pts.length - 1;
  				if (controlHints != null && controlHints.length > 0)
  				{
  					var hints = [];
  					for (var i = 0; i < controlHints.length; i++)
  					{
  						var tmp = state.view.transformControlPoint(state, controlHints[i], true);
  						if (tmp != null)
  						{
  							hints.push(tmp);
  						}
  					}
  					if (hints.length == 0)
  					{
  						return;
  					}
  					if (pt != null && hints[0] != null)
  					{
  						if (Math.abs(hints[0].x - pt.x) < tol)
  						{
  							hints[0].x = pt.x;
  						}
  						if (Math.abs(hints[0].y - pt.y) < tol)
  						{
  							hints[0].y = pt.y;
  						}
  					}
  					var pe = pts[lastInx];
  					if (pe != null && hints[hints.length - 1] != null)
  					{
  						if (Math.abs(hints[hints.length - 1].x - pe.x) < tol)
  						{
  							hints[hints.length - 1].x = pe.x;
  						}
  						if (Math.abs(hints[hints.length - 1].y - pe.y) < tol)
  						{
  							hints[hints.length - 1].y = pe.y;
  						}
  					}
  					hint = hints[0];
  					var currentTerm = source;
  					var currentPt = pts[0];
  					var hozChan = false;
  					var vertChan = false;
  					var currentHint = hint;
  					if (currentPt != null)
  					{
  						currentTerm = null;
  					}
  					for (var i = 0; i < 2; i++)
  					{
  						var fixedVertAlign = currentPt != null && currentPt.x == currentHint.x;
  						var fixedHozAlign = currentPt != null && currentPt.y == currentHint.y;
  						var inHozChan = currentTerm != null && (currentHint.y >= currentTerm.y &&
  								currentHint.y <= currentTerm.y + currentTerm.height);
  						var inVertChan = currentTerm != null && (currentHint.x >= currentTerm.x &&
  								currentHint.x <= currentTerm.x + currentTerm.width);
  						hozChan = fixedHozAlign || (currentPt == null && inHozChan);
  						vertChan = fixedVertAlign || (currentPt == null && inVertChan);
  						if (i==0 && ((hozChan && vertChan) || (fixedVertAlign && fixedHozAlign)))
  						;
  						else
  						{
  							if (currentPt != null && (!fixedHozAlign && !fixedVertAlign) && (inHozChan || inVertChan))
  							{
  								horizontal = inHozChan ? false : true;
  								break;
  							}
  							if (vertChan || hozChan)
  							{
  								horizontal = hozChan;
  								if (i == 1)
  								{
  									horizontal = hints.length % 2 == 0 ? hozChan : vertChan;
  								}
  								break;
  							}
  						}
  						currentTerm = target;
  						currentPt = pts[lastInx];
  						if (currentPt != null)
  						{
  							currentTerm = null;
  						}
  						currentHint = hints[hints.length - 1];
  						if (fixedVertAlign && fixedHozAlign)
  						{
  							hints = hints.slice(1);
  						}
  					}
  					if (horizontal && ((pts[0] != null && pts[0].y != hint.y) ||
  						(pts[0] == null && source != null &&
  						(hint.y < source.y || hint.y > source.y + source.height))))
  					{
  						pushPoint(new mxPoint(pt.x, hint.y));
  					}
  					else if (!horizontal && ((pts[0] != null && pts[0].x != hint.x) ||
  							(pts[0] == null && source != null &&
  							(hint.x < source.x || hint.x > source.x + source.width))))
  					{
  						pushPoint(new mxPoint(hint.x, pt.y));
  					}
  					if (horizontal)
  					{
  						pt.y = hint.y;
  					}
  					else
  					{
  						pt.x = hint.x;
  					}
  					for (var i = 0; i < hints.length; i++)
  					{
  						horizontal = !horizontal;
  						hint = hints[i];
  						if (horizontal)
  						{
  							pt.y = hint.y;
  						}
  						else
  						{
  							pt.x = hint.x;
  						}
  						pushPoint(pt.clone());
  					}
  				}
  				else
  				{
  					hint = pt;
  					horizontal = true;
  				}
  				pt = pts[lastInx];
  				if (pt == null && target != null)
  				{
  					pt = new mxPoint(state.view.getRoutingCenterX(target), state.view.getRoutingCenterY(target));
  				}
  				if (pt != null)
  				{
  					if (hint != null)
  					{
  						if (horizontal && ((pts[lastInx] != null && pts[lastInx].y != hint.y) ||
  							(pts[lastInx] == null && target != null &&
  							(hint.y < target.y || hint.y > target.y + target.height))))
  						{
  							pushPoint(new mxPoint(pt.x, hint.y));
  						}
  						else if (!horizontal && ((pts[lastInx] != null && pts[lastInx].x != hint.x) ||
  								(pts[lastInx] == null && target != null &&
  								(hint.x < target.x || hint.x > target.x + target.width))))
  						{
  							pushPoint(new mxPoint(hint.x, pt.y));
  						}
  					}
  				}
  				if (pts[0] == null && source != null)
  				{
  					while (result.length > 1 && result[1] != null &&
  						mxUtils.contains(source, result[1].x, result[1].y))
  					{
  						result.splice(1, 1);
  					}
  				}
  				if (pts[lastInx] == null && target != null)
  				{
  					while (result.length > 1 && result[result.length - 1] != null &&
  						mxUtils.contains(target, result[result.length - 1].x, result[result.length - 1].y))
  					{
  						result.splice(result.length - 1, 1);
  					}
  				}
  				if (pe != null && result[result.length - 1] != null &&
  					Math.abs(pe.x - result[result.length - 1].x) <= tol &&
  					Math.abs(pe.y - result[result.length - 1].y) <= tol)
  				{
  					result.splice(result.length - 1, 1);
  					if (result[result.length - 1] != null)
  					{
  						if (Math.abs(result[result.length - 1].x - pe.x) < tol)
  						{
  							result[result.length - 1].x = pe.x;
  						}
  						if (Math.abs(result[result.length - 1].y - pe.y) < tol)
  						{
  							result[result.length - 1].y = pe.y;
  						}
  					}
  				}
  			},
  			orthBuffer: 10,
  			orthPointsFallback: true,
  			dirVectors: [ [ -1, 0 ],
  					[ 0, -1 ], [ 1, 0 ], [ 0, 1 ], [ -1, 0 ], [ 0, -1 ], [ 1, 0 ] ],
  			wayPoints1: [ [ 0, 0], [ 0, 0],  [ 0, 0], [ 0, 0], [ 0, 0],  [ 0, 0],
  			              [ 0, 0],  [ 0, 0], [ 0, 0],  [ 0, 0], [ 0, 0],  [ 0, 0] ],
  			routePatterns: [
  				[ [ 513, 2308, 2081, 2562 ], [ 513, 1090, 514, 2184, 2114, 2561 ],
  					[ 513, 1090, 514, 2564, 2184, 2562 ],
  					[ 513, 2308, 2561, 1090, 514, 2568, 2308 ] ],
  			[ [ 514, 1057, 513, 2308, 2081, 2562 ], [ 514, 2184, 2114, 2561 ],
  					[ 514, 2184, 2562, 1057, 513, 2564, 2184 ],
  					[ 514, 1057, 513, 2568, 2308, 2561 ] ],
  			[ [ 1090, 514, 1057, 513, 2308, 2081, 2562 ], [ 2114, 2561 ],
  					[ 1090, 2562, 1057, 513, 2564, 2184 ],
  					[ 1090, 514, 1057, 513, 2308, 2561, 2568 ] ],
  			[ [ 2081, 2562 ], [ 1057, 513, 1090, 514, 2184, 2114, 2561 ],
  					[ 1057, 513, 1090, 514, 2184, 2562, 2564 ],
  					[ 1057, 2561, 1090, 514, 2568, 2308 ] ] ],
  			inlineRoutePatterns: [
  					[ null, [ 2114, 2568 ], null, null ],
  					[ null, [ 514, 2081, 2114, 2568 ] , null, null ],
  					[ null, [ 2114, 2561 ], null, null ],
  					[ [ 2081, 2562 ], [ 1057, 2114, 2568 ],
  							[ 2184, 2562 ],
  							null ] ],
  			vertexSeperations: [],
  			limits: [
  			       [ 0, 0, 0, 0, 0, 0, 0, 0, 0 ],
  			       [ 0, 0, 0, 0, 0, 0, 0, 0, 0 ] ],
  			LEFT_MASK: 32,
  			TOP_MASK: 64,
  			RIGHT_MASK: 128,
  			BOTTOM_MASK: 256,
  			LEFT: 1,
  			TOP: 2,
  			RIGHT: 4,
  			BOTTOM: 8,
  			SIDE_MASK: 480,
  			CENTER_MASK: 512,
  			SOURCE_MASK: 1024,
  			TARGET_MASK: 2048,
  			VERTEX_MASK: 3072,
  			getJettySize: function(state, isSource)
  			{
  				var value = mxUtils.getValue(state.style, (isSource) ? mxConstants.STYLE_SOURCE_JETTY_SIZE :
  					mxConstants.STYLE_TARGET_JETTY_SIZE, mxUtils.getValue(state.style,
  							mxConstants.STYLE_JETTY_SIZE, mxEdgeStyle.orthBuffer));
  				if (value == 'auto')
  				{
  					var type = mxUtils.getValue(state.style, (isSource) ? mxConstants.STYLE_STARTARROW : mxConstants.STYLE_ENDARROW, mxConstants.NONE);
  					if (type != mxConstants.NONE)
  					{
  						var size = mxUtils.getNumber(state.style, (isSource) ? mxConstants.STYLE_STARTSIZE : mxConstants.STYLE_ENDSIZE, mxConstants.DEFAULT_MARKERSIZE);
  						value = Math.max(2, Math.ceil((size + mxEdgeStyle.orthBuffer) / mxEdgeStyle.orthBuffer)) * mxEdgeStyle.orthBuffer;
  					}
  					else
  					{
  						value = 2 * mxEdgeStyle.orthBuffer;
  					}
  				}
  				return value;
  			},
  			scalePointArray: function(points, scale)
  			{
  				var result = [];
  				if (points != null)
  				{
  					for (var i = 0; i < points.length; i++)
  					{
  						if (points[i] != null)
  						{
  							var pt = new mxPoint(Math.round(points[i].x / scale * 10) / 10,
  												Math.round(points[i].y / scale * 10) / 10);
  							result[i] = pt;
  						}
  						else
  						{
  							result[i] = null;
  						}
  					}
  				}
  				else
  				{
  					result = null;
  				}
  				return result;
  			},
  			scaleCellState: function(state, scale)
  			{
  				var result = null;
  				if (state != null)
  				{
  					result = state.clone();
  					result.setRect(Math.round(state.x / scale * 10) / 10,
  									Math.round(state.y / scale * 10) / 10,
  									Math.round(state.width / scale * 10) / 10,
  									Math.round(state.height / scale * 10) / 10);
  				}
  				else
  				{
  					result = null;
  				}
  				return result;
  			},
  			OrthConnector: function(state, sourceScaled, targetScaled, controlHints, result)
  			{
  				var graph = state.view.graph;
  				var sourceEdge = source == null ? false : graph.getModel().isEdge(source.cell);
  				var targetEdge = target == null ? false : graph.getModel().isEdge(target.cell);
  				var pts = mxEdgeStyle.scalePointArray(state.absolutePoints, state.view.scale);
  				var source = mxEdgeStyle.scaleCellState(sourceScaled, state.view.scale);
  				var target = mxEdgeStyle.scaleCellState(targetScaled, state.view.scale);
  				var p0 = pts[0];
  				var pe = pts[pts.length-1];
  				var sourceX = source != null ? source.x : p0.x;
  				var sourceY = source != null ? source.y : p0.y;
  				var sourceWidth = source != null ? source.width : 0;
  				var sourceHeight = source != null ? source.height : 0;
  				var targetX = target != null ? target.x : pe.x;
  				var targetY = target != null ? target.y : pe.y;
  				var targetWidth = target != null ? target.width : 0;
  				var targetHeight = target != null ? target.height : 0;
  				var sourceBuffer = mxEdgeStyle.getJettySize(state, true);
  				var targetBuffer = mxEdgeStyle.getJettySize(state, false);
  				if (source != null && target == source)
  				{
  					targetBuffer = Math.max(sourceBuffer, targetBuffer);
  					sourceBuffer = targetBuffer;
  				}
  				var totalBuffer = targetBuffer + sourceBuffer;
  				var tooShort = false;
  				if (p0 != null && pe != null)
  				{
  					var dx = pe.x - p0.x;
  					var dy = pe.y - p0.y;
  					tooShort = dx * dx + dy * dy < totalBuffer * totalBuffer;
  				}
  				if (tooShort || (mxEdgeStyle.orthPointsFallback && (controlHints != null &&
  						controlHints.length > 0)) || sourceEdge || targetEdge)
  				{
  					mxEdgeStyle.SegmentConnector(state, sourceScaled, targetScaled, controlHints, result);
  					return;
  				}
  				var portConstraint = [mxConstants.DIRECTION_MASK_ALL, mxConstants.DIRECTION_MASK_ALL];
  				var rotation = 0;
  				if (source != null)
  				{
  					portConstraint[0] = mxUtils.getPortConstraints(source, state, true,
  							mxConstants.DIRECTION_MASK_ALL);
  					rotation = mxUtils.getValue(source.style, mxConstants.STYLE_ROTATION, 0);
  					if (rotation != 0)
  					{
  						var newRect = mxUtils.getBoundingBox(new mxRectangle(sourceX, sourceY, sourceWidth, sourceHeight), rotation);
  						sourceX = newRect.x;
  						sourceY = newRect.y;
  						sourceWidth = newRect.width;
  						sourceHeight = newRect.height;
  					}
  				}
  				if (target != null)
  				{
  					portConstraint[1] = mxUtils.getPortConstraints(target, state, false,
  						mxConstants.DIRECTION_MASK_ALL);
  					rotation = mxUtils.getValue(target.style, mxConstants.STYLE_ROTATION, 0);
  					if (rotation != 0)
  					{
  						var newRect = mxUtils.getBoundingBox(new mxRectangle(targetX, targetY, targetWidth, targetHeight), rotation);
  						targetX = newRect.x;
  						targetY = newRect.y;
  						targetWidth = newRect.width;
  						targetHeight = newRect.height;
  					}
  				}
  				var dir = [0, 0];
  				var geo = [ [sourceX, sourceY, sourceWidth, sourceHeight] ,
  				            [targetX, targetY, targetWidth, targetHeight] ];
  				var buffer = [sourceBuffer, targetBuffer];
  				for (var i = 0; i < 2; i++)
  				{
  					mxEdgeStyle.limits[i][1] = geo[i][0] - buffer[i];
  					mxEdgeStyle.limits[i][2] = geo[i][1] - buffer[i];
  					mxEdgeStyle.limits[i][4] = geo[i][0] + geo[i][2] + buffer[i];
  					mxEdgeStyle.limits[i][8] = geo[i][1] + geo[i][3] + buffer[i];
  				}
  				var sourceCenX = geo[0][0] + geo[0][2] / 2.0;
  				var sourceCenY = geo[0][1] + geo[0][3] / 2.0;
  				var targetCenX = geo[1][0] + geo[1][2] / 2.0;
  				var targetCenY = geo[1][1] + geo[1][3] / 2.0;
  				var dx = sourceCenX - targetCenX;
  				var dy = sourceCenY - targetCenY;
  				var quad = 0;
  				if (dx < 0)
  				{
  					if (dy < 0)
  					{
  						quad = 2;
  					}
  					else
  					{
  						quad = 1;
  					}
  				}
  				else
  				{
  					if (dy <= 0)
  					{
  						quad = 3;
  						if (dx == 0)
  						{
  							quad = 2;
  						}
  					}
  				}
  				var currentTerm = null;
  				if (source != null)
  				{
  					currentTerm = p0;
  				}
  				var constraint = [ [0.5, 0.5] , [0.5, 0.5] ];
  				for (var i = 0; i < 2; i++)
  				{
  					if (currentTerm != null)
  					{
  						constraint[i][0] = (currentTerm.x - geo[i][0]) / geo[i][2];
  						if (Math.abs(currentTerm.x - geo[i][0]) <= 1)
  						{
  							dir[i] = mxConstants.DIRECTION_MASK_WEST;
  						}
  						else if (Math.abs(currentTerm.x - geo[i][0] - geo[i][2]) <= 1)
  						{
  							dir[i] = mxConstants.DIRECTION_MASK_EAST;
  						}
  						constraint[i][1] = (currentTerm.y - geo[i][1]) / geo[i][3];
  						if (Math.abs(currentTerm.y - geo[i][1]) <= 1)
  						{
  							dir[i] = mxConstants.DIRECTION_MASK_NORTH;
  						}
  						else if (Math.abs(currentTerm.y - geo[i][1] - geo[i][3]) <= 1)
  						{
  							dir[i] = mxConstants.DIRECTION_MASK_SOUTH;
  						}
  					}
  					currentTerm = null;
  					if (target != null)
  					{
  						currentTerm = pe;
  					}
  				}
  				var sourceTopDist = geo[0][1] - (geo[1][1] + geo[1][3]);
  				var sourceLeftDist = geo[0][0] - (geo[1][0] + geo[1][2]);
  				var sourceBottomDist = geo[1][1] - (geo[0][1] + geo[0][3]);
  				var sourceRightDist = geo[1][0] - (geo[0][0] + geo[0][2]);
  				mxEdgeStyle.vertexSeperations[1] = Math.max(sourceLeftDist - totalBuffer, 0);
  				mxEdgeStyle.vertexSeperations[2] = Math.max(sourceTopDist - totalBuffer, 0);
  				mxEdgeStyle.vertexSeperations[4] = Math.max(sourceBottomDist - totalBuffer, 0);
  				mxEdgeStyle.vertexSeperations[3] = Math.max(sourceRightDist - totalBuffer, 0);
  				var dirPref = [];
  				var horPref = [];
  				var vertPref = [];
  				horPref[0] = (sourceLeftDist >= sourceRightDist) ? mxConstants.DIRECTION_MASK_WEST
  						: mxConstants.DIRECTION_MASK_EAST;
  				vertPref[0] = (sourceTopDist >= sourceBottomDist) ? mxConstants.DIRECTION_MASK_NORTH
  						: mxConstants.DIRECTION_MASK_SOUTH;
  				horPref[1] = mxUtils.reversePortConstraints(horPref[0]);
  				vertPref[1] = mxUtils.reversePortConstraints(vertPref[0]);
  				var preferredHorizDist = sourceLeftDist >= sourceRightDist ? sourceLeftDist
  						: sourceRightDist;
  				var preferredVertDist = sourceTopDist >= sourceBottomDist ? sourceTopDist
  						: sourceBottomDist;
  				var prefOrdering = [ [0, 0] , [0, 0] ];
  				var preferredOrderSet = false;
  				for (var i = 0; i < 2; i++)
  				{
  					if (dir[i] != 0x0)
  					{
  						continue;
  					}
  					if ((horPref[i] & portConstraint[i]) == 0)
  					{
  						horPref[i] = mxUtils.reversePortConstraints(horPref[i]);
  					}
  					if ((vertPref[i] & portConstraint[i]) == 0)
  					{
  						vertPref[i] = mxUtils
  								.reversePortConstraints(vertPref[i]);
  					}
  					prefOrdering[i][0] = vertPref[i];
  					prefOrdering[i][1] = horPref[i];
  				}
  				if (preferredVertDist > 0
  						&& preferredHorizDist > 0)
  				{
  					if (((horPref[0] & portConstraint[0]) > 0)
  							&& ((vertPref[1] & portConstraint[1]) > 0))
  					{
  						prefOrdering[0][0] = horPref[0];
  						prefOrdering[0][1] = vertPref[0];
  						prefOrdering[1][0] = vertPref[1];
  						prefOrdering[1][1] = horPref[1];
  						preferredOrderSet = true;
  					}
  					else if (((vertPref[0] & portConstraint[0]) > 0)
  							&& ((horPref[1] & portConstraint[1]) > 0))
  					{
  						prefOrdering[0][0] = vertPref[0];
  						prefOrdering[0][1] = horPref[0];
  						prefOrdering[1][0] = horPref[1];
  						prefOrdering[1][1] = vertPref[1];
  						preferredOrderSet = true;
  					}
  				}
  				if (preferredVertDist > 0 && !preferredOrderSet)
  				{
  					prefOrdering[0][0] = vertPref[0];
  					prefOrdering[0][1] = horPref[0];
  					prefOrdering[1][0] = vertPref[1];
  					prefOrdering[1][1] = horPref[1];
  					preferredOrderSet = true;
  				}
  				if (preferredHorizDist > 0 && !preferredOrderSet)
  				{
  					prefOrdering[0][0] = horPref[0];
  					prefOrdering[0][1] = vertPref[0];
  					prefOrdering[1][0] = horPref[1];
  					prefOrdering[1][1] = vertPref[1];
  					preferredOrderSet = true;
  				}
  				for (var i = 0; i < 2; i++)
  				{
  					if (dir[i] != 0x0)
  					{
  						continue;
  					}
  					if ((prefOrdering[i][0] & portConstraint[i]) == 0)
  					{
  						prefOrdering[i][0] = prefOrdering[i][1];
  					}
  					dirPref[i] = prefOrdering[i][0] & portConstraint[i];
  					dirPref[i] |= (prefOrdering[i][1] & portConstraint[i]) << 8;
  					dirPref[i] |= (prefOrdering[1 - i][i] & portConstraint[i]) << 16;
  					dirPref[i] |= (prefOrdering[1 - i][1 - i] & portConstraint[i]) << 24;
  					if ((dirPref[i] & 0xF) == 0)
  					{
  						dirPref[i] = dirPref[i] << 8;
  					}
  					if ((dirPref[i] & 0xF00) == 0)
  					{
  						dirPref[i] = (dirPref[i] & 0xF) | dirPref[i] >> 8;
  					}
  					if ((dirPref[i] & 0xF0000) == 0)
  					{
  						dirPref[i] = (dirPref[i] & 0xFFFF)
  								| ((dirPref[i] & 0xF000000) >> 8);
  					}
  					dir[i] = dirPref[i] & 0xF;
  					if (portConstraint[i] == mxConstants.DIRECTION_MASK_WEST
  							|| portConstraint[i] == mxConstants.DIRECTION_MASK_NORTH
  							|| portConstraint[i] == mxConstants.DIRECTION_MASK_EAST
  							|| portConstraint[i] == mxConstants.DIRECTION_MASK_SOUTH)
  					{
  						dir[i] = portConstraint[i];
  					}
  				}
  				var sourceIndex = dir[0] == mxConstants.DIRECTION_MASK_EAST ? 3
  						: dir[0];
  				var targetIndex = dir[1] == mxConstants.DIRECTION_MASK_EAST ? 3
  						: dir[1];
  				sourceIndex -= quad;
  				targetIndex -= quad;
  				if (sourceIndex < 1)
  				{
  					sourceIndex += 4;
  				}
  				if (targetIndex < 1)
  				{
  					targetIndex += 4;
  				}
  				var routePattern = mxEdgeStyle.routePatterns[sourceIndex - 1][targetIndex - 1];
  				mxEdgeStyle.wayPoints1[0][0] = geo[0][0];
  				mxEdgeStyle.wayPoints1[0][1] = geo[0][1];
  				switch (dir[0])
  				{
  					case mxConstants.DIRECTION_MASK_WEST:
  						mxEdgeStyle.wayPoints1[0][0] -= sourceBuffer;
  						mxEdgeStyle.wayPoints1[0][1] += constraint[0][1] * geo[0][3];
  						break;
  					case mxConstants.DIRECTION_MASK_SOUTH:
  						mxEdgeStyle.wayPoints1[0][0] += constraint[0][0] * geo[0][2];
  						mxEdgeStyle.wayPoints1[0][1] += geo[0][3] + sourceBuffer;
  						break;
  					case mxConstants.DIRECTION_MASK_EAST:
  						mxEdgeStyle.wayPoints1[0][0] += geo[0][2] + sourceBuffer;
  						mxEdgeStyle.wayPoints1[0][1] += constraint[0][1] * geo[0][3];
  						break;
  					case mxConstants.DIRECTION_MASK_NORTH:
  						mxEdgeStyle.wayPoints1[0][0] += constraint[0][0] * geo[0][2];
  						mxEdgeStyle.wayPoints1[0][1] -= sourceBuffer;
  						break;
  				}
  				var currentIndex = 0;
  				var lastOrientation = (dir[0] & (mxConstants.DIRECTION_MASK_EAST | mxConstants.DIRECTION_MASK_WEST)) > 0 ? 0
  						: 1;
  				var initialOrientation = lastOrientation;
  				var currentOrientation = 0;
  				for (var i = 0; i < routePattern.length; i++)
  				{
  					var nextDirection = routePattern[i] & 0xF;
  					var directionIndex = nextDirection == mxConstants.DIRECTION_MASK_EAST ? 3
  							: nextDirection;
  					directionIndex += quad;
  					if (directionIndex > 4)
  					{
  						directionIndex -= 4;
  					}
  					var direction = mxEdgeStyle.dirVectors[directionIndex - 1];
  					currentOrientation = (directionIndex % 2 > 0) ? 0 : 1;
  					if (currentOrientation != lastOrientation)
  					{
  						currentIndex++;
  						mxEdgeStyle.wayPoints1[currentIndex][0] = mxEdgeStyle.wayPoints1[currentIndex - 1][0];
  						mxEdgeStyle.wayPoints1[currentIndex][1] = mxEdgeStyle.wayPoints1[currentIndex - 1][1];
  					}
  					var tar = (routePattern[i] & mxEdgeStyle.TARGET_MASK) > 0;
  					var sou = (routePattern[i] & mxEdgeStyle.SOURCE_MASK) > 0;
  					var side = (routePattern[i] & mxEdgeStyle.SIDE_MASK) >> 5;
  					side = side << quad;
  					if (side > 0xF)
  					{
  						side = side >> 4;
  					}
  					var center = (routePattern[i] & mxEdgeStyle.CENTER_MASK) > 0;
  					if ((sou || tar) && side < 9)
  					{
  						var limit = 0;
  						var souTar = sou ? 0 : 1;
  						if (center && currentOrientation == 0)
  						{
  							limit = geo[souTar][0] + constraint[souTar][0] * geo[souTar][2];
  						}
  						else if (center)
  						{
  							limit = geo[souTar][1] + constraint[souTar][1] * geo[souTar][3];
  						}
  						else
  						{
  							limit = mxEdgeStyle.limits[souTar][side];
  						}
  						if (currentOrientation == 0)
  						{
  							var lastX = mxEdgeStyle.wayPoints1[currentIndex][0];
  							var deltaX = (limit - lastX) * direction[0];
  							if (deltaX > 0)
  							{
  								mxEdgeStyle.wayPoints1[currentIndex][0] += direction[0]
  										* deltaX;
  							}
  						}
  						else
  						{
  							var lastY = mxEdgeStyle.wayPoints1[currentIndex][1];
  							var deltaY = (limit - lastY) * direction[1];
  							if (deltaY > 0)
  							{
  								mxEdgeStyle.wayPoints1[currentIndex][1] += direction[1]
  										* deltaY;
  							}
  						}
  					}
  					else if (center)
  					{
  						mxEdgeStyle.wayPoints1[currentIndex][0] += direction[0]
  								* Math.abs(mxEdgeStyle.vertexSeperations[directionIndex] / 2);
  						mxEdgeStyle.wayPoints1[currentIndex][1] += direction[1]
  								* Math.abs(mxEdgeStyle.vertexSeperations[directionIndex] / 2);
  					}
  					if (currentIndex > 0
  							&& mxEdgeStyle.wayPoints1[currentIndex][currentOrientation] == mxEdgeStyle.wayPoints1[currentIndex - 1][currentOrientation])
  					{
  						currentIndex--;
  					}
  					else
  					{
  						lastOrientation = currentOrientation;
  					}
  				}
  				for (var i = 0; i <= currentIndex; i++)
  				{
  					if (i == currentIndex)
  					{
  						var targetOrientation = (dir[1] & (mxConstants.DIRECTION_MASK_EAST | mxConstants.DIRECTION_MASK_WEST)) > 0 ? 0
  								: 1;
  						var sameOrient = targetOrientation == initialOrientation ? 0 : 1;
  						if (sameOrient != (currentIndex + 1) % 2)
  						{
  							break;
  						}
  					}
  					result.push(new mxPoint(Math.round(mxEdgeStyle.wayPoints1[i][0] * state.view.scale * 10) / 10,
  											Math.round(mxEdgeStyle.wayPoints1[i][1] * state.view.scale * 10) / 10));
  				}
  				var index = 1;
  				while (index < result.length)
  				{
  					if (result[index - 1] == null || result[index] == null ||
  						result[index - 1].x != result[index].x ||
  						result[index - 1].y != result[index].y)
  					{
  						index++;
  					}
  					else
  					{
  						result.splice(index, 1);
  					}
  				}
  			},
  			getRoutePattern: function(dir, quad, dx, dy)
  			{
  				var sourceIndex = dir[0] == mxConstants.DIRECTION_MASK_EAST ? 3
  						: dir[0];
  				var targetIndex = dir[1] == mxConstants.DIRECTION_MASK_EAST ? 3
  						: dir[1];
  				sourceIndex -= quad;
  				targetIndex -= quad;
  				if (sourceIndex < 1)
  				{
  					sourceIndex += 4;
  				}
  				if (targetIndex < 1)
  				{
  					targetIndex += 4;
  				}
  				var result = routePatterns[sourceIndex - 1][targetIndex - 1];
  				if (dx == 0 || dy == 0)
  				{
  					if (inlineRoutePatterns[sourceIndex - 1][targetIndex - 1] != null)
  					{
  						result = inlineRoutePatterns[sourceIndex - 1][targetIndex - 1];
  					}
  				}
  				return result;
  			}
  		};
  		__mxOutput.mxEdgeStyle = typeof mxEdgeStyle !== 'undefined' ? mxEdgeStyle : undefined;
  		var mxStyleRegistry =
  		{
  			values: [],
  			putValue: function(name, obj)
  			{
  				mxStyleRegistry.values[name] = obj;
  			},
  			getValue: function(name)
  			{
  				return mxStyleRegistry.values[name];
  			},
  			getName: function(value)
  			{
  				for (var key in mxStyleRegistry.values)
  				{
  					if (mxStyleRegistry.values[key] == value)
  					{
  						return key;
  					}
  				}
  				return null;
  			}
  		};
  		mxStyleRegistry.putValue(mxConstants.EDGESTYLE_ELBOW, mxEdgeStyle.ElbowConnector);
  		mxStyleRegistry.putValue(mxConstants.EDGESTYLE_ENTITY_RELATION, mxEdgeStyle.EntityRelation);
  		mxStyleRegistry.putValue(mxConstants.EDGESTYLE_LOOP, mxEdgeStyle.Loop);
  		mxStyleRegistry.putValue(mxConstants.EDGESTYLE_SIDETOSIDE, mxEdgeStyle.SideToSide);
  		mxStyleRegistry.putValue(mxConstants.EDGESTYLE_TOPTOBOTTOM, mxEdgeStyle.TopToBottom);
  		mxStyleRegistry.putValue(mxConstants.EDGESTYLE_ORTHOGONAL, mxEdgeStyle.OrthConnector);
  		mxStyleRegistry.putValue(mxConstants.EDGESTYLE_SEGMENT, mxEdgeStyle.SegmentConnector);
  		mxStyleRegistry.putValue(mxConstants.PERIMETER_ELLIPSE, mxPerimeter.EllipsePerimeter);
  		mxStyleRegistry.putValue(mxConstants.PERIMETER_RECTANGLE, mxPerimeter.RectanglePerimeter);
  		mxStyleRegistry.putValue(mxConstants.PERIMETER_RHOMBUS, mxPerimeter.RhombusPerimeter);
  		mxStyleRegistry.putValue(mxConstants.PERIMETER_TRIANGLE, mxPerimeter.TrianglePerimeter);
  		mxStyleRegistry.putValue(mxConstants.PERIMETER_HEXAGON, mxPerimeter.HexagonPerimeter);
  		__mxOutput.mxStyleRegistry = typeof mxStyleRegistry !== 'undefined' ? mxStyleRegistry : undefined;
  		function mxGraphView(graph)
  		{
  			this.graph = graph;
  			this.translate = new mxPoint();
  			this.graphBounds = new mxRectangle();
  			this.states = new mxDictionary();
  		}		mxGraphView.prototype = new mxEventSource();
  		mxGraphView.prototype.constructor = mxGraphView;
  		mxGraphView.prototype.EMPTY_POINT = new mxPoint();
  		mxGraphView.prototype.doneResource = (mxClient.language != 'none') ? 'done' : '';
  		mxGraphView.prototype.updatingDocumentResource = (mxClient.language != 'none') ? 'updatingDocument' : '';
  		mxGraphView.prototype.allowEval = false;
  		mxGraphView.prototype.captureDocumentGesture = true;
  		mxGraphView.prototype.optimizeVmlReflows = true;
  		mxGraphView.prototype.rendering = true;
  		mxGraphView.prototype.graph = null;
  		mxGraphView.prototype.currentRoot = null;
  		mxGraphView.prototype.graphBounds = null;
  		mxGraphView.prototype.scale = 1;
  		mxGraphView.prototype.translate = null;
  		mxGraphView.prototype.states = null;
  		mxGraphView.prototype.updateStyle = false;
  		mxGraphView.prototype.lastNode = null;
  		mxGraphView.prototype.lastHtmlNode = null;
  		mxGraphView.prototype.lastForegroundNode = null;
  		mxGraphView.prototype.lastForegroundHtmlNode = null;
  		mxGraphView.prototype.getGraphBounds = function()
  		{
  			return this.graphBounds;
  		};
  		mxGraphView.prototype.setGraphBounds = function(value)
  		{
  			this.graphBounds = value;
  		};
  		mxGraphView.prototype.getBounds = function(cells)
  		{
  			var result = null;
  			if (cells != null && cells.length > 0)
  			{
  				var model = this.graph.getModel();
  				for (var i = 0; i < cells.length; i++)
  				{
  					if (model.isVertex(cells[i]) || model.isEdge(cells[i]))
  					{
  						var state = this.getState(cells[i]);
  						if (state != null)
  						{
  							if (result == null)
  							{
  								result = mxRectangle.fromRectangle(state);
  							}
  							else
  							{
  								result.add(state);
  							}
  						}
  					}
  				}
  			}
  			return result;
  		};
  		mxGraphView.prototype.setCurrentRoot = function(root)
  		{
  			if (this.currentRoot != root)
  			{
  				var change = new mxCurrentRootChange(this, root);
  				change.execute();
  				var edit = new mxUndoableEdit(this, true);
  				edit.add(change);
  				this.fireEvent(new mxEventObject(mxEvent.UNDO, 'edit', edit));
  				this.graph.sizeDidChange();
  			}
  			return root;
  		};
  		mxGraphView.prototype.scaleAndTranslate = function(scale, dx, dy)
  		{
  			var previousScale = this.scale;
  			var previousTranslate = new mxPoint(this.translate.x, this.translate.y);
  			if (this.scale != scale || this.translate.x != dx || this.translate.y != dy)
  			{
  				this.scale = scale;
  				this.translate.x = dx;
  				this.translate.y = dy;
  				if (this.isEventsEnabled())
  				{
  					this.viewStateChanged();
  				}
  			}
  			this.fireEvent(new mxEventObject(mxEvent.SCALE_AND_TRANSLATE,
  				'scale', scale, 'previousScale', previousScale,
  				'translate', this.translate, 'previousTranslate', previousTranslate));
  		};
  		mxGraphView.prototype.getScale = function()
  		{
  			return this.scale;
  		};
  		mxGraphView.prototype.setScale = function(value)
  		{
  			var previousScale = this.scale;
  			if (this.scale != value)
  			{
  				this.scale = value;
  				if (this.isEventsEnabled())
  				{
  					this.viewStateChanged();
  				}
  			}
  			this.fireEvent(new mxEventObject(mxEvent.SCALE,
  				'scale', value, 'previousScale', previousScale));
  		};
  		mxGraphView.prototype.getTranslate = function()
  		{
  			return this.translate;
  		};
  		mxGraphView.prototype.setTranslate = function(dx, dy)
  		{
  			var previousTranslate = new mxPoint(this.translate.x, this.translate.y);
  			if (this.translate.x != dx || this.translate.y != dy)
  			{
  				this.translate.x = dx;
  				this.translate.y = dy;
  				if (this.isEventsEnabled())
  				{
  					this.viewStateChanged();
  				}
  			}
  			this.fireEvent(new mxEventObject(mxEvent.TRANSLATE,
  				'translate', this.translate, 'previousTranslate', previousTranslate));
  		};
  		mxGraphView.prototype.viewStateChanged = function()
  		{
  			this.revalidate();
  			this.graph.sizeDidChange();
  		};
  		mxGraphView.prototype.refresh = function()
  		{
  			if (this.currentRoot != null)
  			{
  				this.clear();
  			}
  			this.revalidate();
  		};
  		mxGraphView.prototype.revalidate = function()
  		{
  			this.invalidate();
  			this.validate();
  		};
  		mxGraphView.prototype.clear = function(cell, force, recurse)
  		{
  			var model = this.graph.getModel();
  			cell = cell || model.getRoot();
  			force = (force != null) ? force : false;
  			recurse = (recurse != null) ? recurse : true;
  			this.removeState(cell);
  			if (recurse && (force || cell != this.currentRoot))
  			{
  				var childCount = model.getChildCount(cell);
  				for (var i = 0; i < childCount; i++)
  				{
  					this.clear(model.getChildAt(cell, i), force);
  				}
  			}
  			else
  			{
  				this.invalidate(cell);
  			}
  		};
  		mxGraphView.prototype.invalidate = function(cell, recurse, includeEdges)
  		{
  			var model = this.graph.getModel();
  			cell = cell || model.getRoot();
  			recurse = (recurse != null) ? recurse : true;
  			includeEdges = (includeEdges != null) ? includeEdges : true;
  			var state = this.getState(cell);
  			if (state != null)
  			{
  				state.invalid = true;
  			}
  			if (!cell.invalidating)
  			{
  				cell.invalidating = true;
  				if (recurse)
  				{
  					var childCount = model.getChildCount(cell);
  					for (var i = 0; i < childCount; i++)
  					{
  						var child = model.getChildAt(cell, i);
  						this.invalidate(child, recurse, includeEdges);
  					}
  				}
  				if (includeEdges)
  				{
  					var edgeCount = model.getEdgeCount(cell);
  					for (var i = 0; i < edgeCount; i++)
  					{
  						this.invalidate(model.getEdgeAt(cell, i), recurse, includeEdges);
  					}
  				}
  				delete cell.invalidating;
  			}
  		};
  		mxGraphView.prototype.validate = function(cell)
  		{
  			var t0 = mxLog.enter('mxGraphView.validate');
  			window.status = mxResources.get(this.updatingDocumentResource) ||
  				this.updatingDocumentResource;
  			this.resetValidationState();
  			var prevDisplay = null;
  			if (this.optimizeVmlReflows && this.canvas != null && this.textDiv == null &&
  				((document.documentMode == 8 && !mxClient.IS_EM) || mxClient.IS_QUIRKS))
  			{
  				this.placeholder = document.createElement('div');
  				this.placeholder.style.position = 'absolute';
  				this.placeholder.style.width = this.canvas.clientWidth + 'px';
  				this.placeholder.style.height = this.canvas.clientHeight + 'px';
  				this.canvas.parentNode.appendChild(this.placeholder);
  				prevDisplay = this.drawPane.style.display;
  				this.canvas.style.display = 'none';
  				this.textDiv = document.createElement('div');
  				this.textDiv.style.position = 'absolute';
  				this.textDiv.style.whiteSpace = 'nowrap';
  				this.textDiv.style.visibility = 'hidden';
  				this.textDiv.style.display = (mxClient.IS_QUIRKS) ? 'inline' : 'inline-block';
  				this.textDiv.style.zoom = '1';
  				document.body.appendChild(this.textDiv);
  			}
  			var graphBounds = this.getBoundingBox(this.validateCellState(
  				this.validateCell(cell || ((this.currentRoot != null) ?
  					this.currentRoot : this.graph.getModel().getRoot()))));
  			this.setGraphBounds((graphBounds != null) ? graphBounds : this.getEmptyBounds());
  			this.validateBackground();
  			if (prevDisplay != null)
  			{
  				this.canvas.style.display = prevDisplay;
  				this.textDiv.parentNode.removeChild(this.textDiv);
  				if (this.placeholder != null)
  				{
  					this.placeholder.parentNode.removeChild(this.placeholder);
  				}
  				this.textDiv = null;
  			}
  			this.resetValidationState();
  			window.status = mxResources.get(this.doneResource) ||
  				this.doneResource;
  			mxLog.leave('mxGraphView.validate', t0);
  		};
  		mxGraphView.prototype.getEmptyBounds = function()
  		{
  			return new mxRectangle(this.translate.x * this.scale, this.translate.y * this.scale);
  		};
  		mxGraphView.prototype.getBoundingBox = function(state, recurse)
  		{
  			recurse = (recurse != null) ? recurse : true;
  			var bbox = null;
  			if (state != null)
  			{
  				if (state.shape != null && state.shape.boundingBox != null)
  				{
  					bbox = state.shape.boundingBox.clone();
  				}
  				if (state.text != null && state.text.boundingBox != null)
  				{
  					if (bbox != null)
  					{
  						bbox.add(state.text.boundingBox);
  					}
  					else
  					{
  						bbox = state.text.boundingBox.clone();
  					}
  				}
  				if (recurse)
  				{
  					var model = this.graph.getModel();
  					var childCount = model.getChildCount(state.cell);
  					for (var i = 0; i < childCount; i++)
  					{
  						var bounds = this.getBoundingBox(this.getState(model.getChildAt(state.cell, i)));
  						if (bounds != null)
  						{
  							if (bbox == null)
  							{
  								bbox = bounds;
  							}
  							else
  							{
  								bbox.add(bounds);
  							}
  						}
  					}
  				}
  			}
  			return bbox;
  		};
  		mxGraphView.prototype.createBackgroundPageShape = function(bounds)
  		{
  			return new mxRectangleShape(bounds, 'white', 'black');
  		};
  		mxGraphView.prototype.validateBackground = function()
  		{
  			this.validateBackgroundImage();
  			this.validateBackgroundPage();
  		};
  		mxGraphView.prototype.validateBackgroundImage = function()
  		{
  			var bg = this.graph.getBackgroundImage();
  			if (bg != null)
  			{
  				if (this.backgroundImage == null || this.backgroundImage.image != bg.src)
  				{
  					if (this.backgroundImage != null)
  					{
  						this.backgroundImage.destroy();
  					}
  					var bounds = new mxRectangle(0, 0, 1, 1);
  					this.backgroundImage = new mxImageShape(bounds, bg.src);
  					this.backgroundImage.dialect = this.graph.dialect;
  					this.backgroundImage.init(this.backgroundPane);
  					this.backgroundImage.redraw();
  					if (document.documentMode == 8 && !mxClient.IS_EM)
  					{
  						mxEvent.addGestureListeners(this.backgroundImage.node,
  							mxUtils.bind(this, function(evt)
  							{
  								this.graph.fireMouseEvent(mxEvent.MOUSE_DOWN, new mxMouseEvent(evt));
  							}),
  							mxUtils.bind(this, function(evt)
  							{
  								this.graph.fireMouseEvent(mxEvent.MOUSE_MOVE, new mxMouseEvent(evt));
  							}),
  							mxUtils.bind(this, function(evt)
  							{
  								this.graph.fireMouseEvent(mxEvent.MOUSE_UP, new mxMouseEvent(evt));
  							})
  						);
  					}
  				}
  				this.redrawBackgroundImage(this.backgroundImage, bg);
  			}
  			else if (this.backgroundImage != null)
  			{
  				this.backgroundImage.destroy();
  				this.backgroundImage = null;
  			}
  		};
  		mxGraphView.prototype.validateBackgroundPage = function()
  		{
  			if (this.graph.pageVisible)
  			{
  				var bounds = this.getBackgroundPageBounds();
  				if (this.backgroundPageShape == null)
  				{
  					this.backgroundPageShape = this.createBackgroundPageShape(bounds);
  					this.backgroundPageShape.scale = this.scale;
  					this.backgroundPageShape.isShadow = true;
  					this.backgroundPageShape.dialect = this.graph.dialect;
  					this.backgroundPageShape.init(this.backgroundPane);
  					this.backgroundPageShape.redraw();
  					if (this.graph.nativeDblClickEnabled)
  					{
  						mxEvent.addListener(this.backgroundPageShape.node, 'dblclick', mxUtils.bind(this, function(evt)
  						{
  							this.graph.dblClick(evt);
  						}));
  					}
  					mxEvent.addGestureListeners(this.backgroundPageShape.node,
  						mxUtils.bind(this, function(evt)
  						{
  							this.graph.fireMouseEvent(mxEvent.MOUSE_DOWN, new mxMouseEvent(evt));
  						}),
  						mxUtils.bind(this, function(evt)
  						{
  							if (this.graph.tooltipHandler != null && this.graph.tooltipHandler.isHideOnHover())
  							{
  								this.graph.tooltipHandler.hide();
  							}
  							if (this.graph.isMouseDown && !mxEvent.isConsumed(evt))
  							{
  								this.graph.fireMouseEvent(mxEvent.MOUSE_MOVE, new mxMouseEvent(evt));
  							}
  						}),
  						mxUtils.bind(this, function(evt)
  						{
  							this.graph.fireMouseEvent(mxEvent.MOUSE_UP, new mxMouseEvent(evt));
  						})
  					);
  				}
  				else
  				{
  					this.backgroundPageShape.scale = this.scale;
  					this.backgroundPageShape.bounds = bounds;
  					this.backgroundPageShape.redraw();
  				}
  			}
  			else if (this.backgroundPageShape != null)
  			{
  				this.backgroundPageShape.destroy();
  				this.backgroundPageShape = null;
  			}
  		};
  		mxGraphView.prototype.getBackgroundPageBounds = function()
  		{
  			var fmt = this.graph.pageFormat;
  			var ps = this.scale * this.graph.pageScale;
  			var bounds = new mxRectangle(this.scale * this.translate.x, this.scale * this.translate.y,
  					fmt.width * ps, fmt.height * ps);
  			return bounds;
  		};
  		mxGraphView.prototype.redrawBackgroundImage = function(backgroundImage, bg)
  		{
  			backgroundImage.scale = this.scale;
  			backgroundImage.bounds.x = this.scale * this.translate.x;
  			backgroundImage.bounds.y = this.scale * this.translate.y;
  			backgroundImage.bounds.width = this.scale * bg.width;
  			backgroundImage.bounds.height = this.scale * bg.height;
  			backgroundImage.redraw();
  		};
  		mxGraphView.prototype.validateCell = function(cell, visible)
  		{
  			visible = (visible != null) ? visible : true;
  			if (cell != null)
  			{
  				visible = visible && this.graph.isCellVisible(cell);
  				var state = this.getState(cell, visible);
  				if (state != null && !visible)
  				{
  					this.removeState(cell);
  				}
  				else
  				{
  					var model = this.graph.getModel();
  					var childCount = model.getChildCount(cell);
  					for (var i = 0; i < childCount; i++)
  					{
  						this.validateCell(model.getChildAt(cell, i), visible &&
  							(!this.isCellCollapsed(cell) || cell == this.currentRoot));
  					}
  				}
  			}
  			return cell;
  		};
  		mxGraphView.prototype.validateCellState = function(cell, recurse)
  		{
  			recurse = (recurse != null) ? recurse : true;
  			var state = null;
  			if (cell != null)
  			{
  				state = this.getState(cell);
  				if (state != null)
  				{
  					var model = this.graph.getModel();
  					if (state.invalid)
  					{
  						state.invalid = false;
  						if (state.style == null || state.invalidStyle)
  						{
  							state.style = this.graph.getCellStyle(state.cell);
  							state.invalidStyle = false;
  						}
  						if (cell != this.currentRoot)
  						{
  							this.validateCellState(model.getParent(cell), false);
  						}
  						state.setVisibleTerminalState(this.validateCellState(this.getVisibleTerminal(cell, true), false), true);
  						state.setVisibleTerminalState(this.validateCellState(this.getVisibleTerminal(cell, false), false), false);
  						this.updateCellState(state);
  						if (cell != this.currentRoot && !state.invalid)
  						{
  							this.graph.cellRenderer.redraw(state, false, this.isRendering());
  							state.updateCachedBounds();
  						}
  					}
  					if (recurse && !state.invalid)
  					{
  						if (state.shape != null)
  						{
  							this.stateValidated(state);
  						}
  						var childCount = model.getChildCount(cell);
  						for (var i = 0; i < childCount; i++)
  						{
  							this.validateCellState(model.getChildAt(cell, i));
  						}
  					}
  				}
  			}
  			return state;
  		};
  		mxGraphView.prototype.updateCellState = function(state)
  		{
  			state.absoluteOffset.x = 0;
  			state.absoluteOffset.y = 0;
  			state.origin.x = 0;
  			state.origin.y = 0;
  			state.length = 0;
  			if (state.cell != this.currentRoot)
  			{
  				var model = this.graph.getModel();
  				var pState = this.getState(model.getParent(state.cell));
  				if (pState != null && pState.cell != this.currentRoot)
  				{
  					state.origin.x += pState.origin.x;
  					state.origin.y += pState.origin.y;
  				}
  				var offset = this.graph.getChildOffsetForCell(state.cell);
  				if (offset != null)
  				{
  					state.origin.x += offset.x;
  					state.origin.y += offset.y;
  				}
  				var geo = this.graph.getCellGeometry(state.cell);
  				if (geo != null)
  				{
  					if (!model.isEdge(state.cell))
  					{
  						offset = (geo.offset != null) ? geo.offset : this.EMPTY_POINT;
  						if (geo.relative && pState != null)
  						{
  							if (model.isEdge(pState.cell))
  							{
  								var origin = this.getPoint(pState, geo);
  								if (origin != null)
  								{
  									state.origin.x += (origin.x / this.scale) - pState.origin.x - this.translate.x;
  									state.origin.y += (origin.y / this.scale) - pState.origin.y - this.translate.y;
  								}
  							}
  							else
  							{
  								state.origin.x += geo.x * pState.unscaledWidth + offset.x;
  								state.origin.y += geo.y * pState.unscaledHeight + offset.y;
  							}
  						}
  						else
  						{
  							state.absoluteOffset.x = this.scale * offset.x;
  							state.absoluteOffset.y = this.scale * offset.y;
  							state.origin.x += geo.x;
  							state.origin.y += geo.y;
  						}
  					}
  					state.x = this.scale * (this.translate.x + state.origin.x);
  					state.y = this.scale * (this.translate.y + state.origin.y);
  					state.width = this.scale * geo.width;
  					state.unscaledWidth = geo.width;
  					state.height = this.scale * geo.height;
  					state.unscaledHeight = geo.height;
  					if (model.isVertex(state.cell))
  					{
  						this.updateVertexState(state, geo);
  					}
  					if (model.isEdge(state.cell))
  					{
  						this.updateEdgeState(state, geo);
  					}
  				}
  			}
  			state.updateCachedBounds();
  		};
  		mxGraphView.prototype.isCellCollapsed = function(cell)
  		{
  			return this.graph.isCellCollapsed(cell);
  		};
  		mxGraphView.prototype.updateVertexState = function(state, geo)
  		{
  			var model = this.graph.getModel();
  			var pState = this.getState(model.getParent(state.cell));
  			if (geo.relative && pState != null && !model.isEdge(pState.cell))
  			{
  				var alpha = mxUtils.toRadians(pState.style[mxConstants.STYLE_ROTATION] || '0');
  				if (alpha != 0)
  				{
  					var cos = Math.cos(alpha);
  					var sin = Math.sin(alpha);
  					var ct = new mxPoint(state.getCenterX(), state.getCenterY());
  					var cx = new mxPoint(pState.getCenterX(), pState.getCenterY());
  					var pt = mxUtils.getRotatedPoint(ct, cos, sin, cx);
  					state.x = pt.x - state.width / 2;
  					state.y = pt.y - state.height / 2;
  				}
  			}
  			this.updateVertexLabelOffset(state);
  		};
  		mxGraphView.prototype.updateEdgeState = function(state, geo)
  		{
  			var source = state.getVisibleTerminalState(true);
  			var target = state.getVisibleTerminalState(false);
  			if ((this.graph.model.getTerminal(state.cell, true) != null && source == null) ||
  				(source == null && geo.getTerminalPoint(true) == null) ||
  				(this.graph.model.getTerminal(state.cell, false) != null && target == null) ||
  				(target == null && geo.getTerminalPoint(false) == null))
  			{
  				this.clear(state.cell, true);
  			}
  			else
  			{
  				this.updateFixedTerminalPoints(state, source, target);
  				this.updatePoints(state, geo.points, source, target);
  				this.updateFloatingTerminalPoints(state, source, target);
  				var pts = state.absolutePoints;
  				if (state.cell != this.currentRoot && (pts == null || pts.length < 2 ||
  					pts[0] == null || pts[pts.length - 1] == null))
  				{
  					this.clear(state.cell, true);
  				}
  				else
  				{
  					this.updateEdgeBounds(state);
  					this.updateEdgeLabelOffset(state);
  				}
  			}
  		};
  		mxGraphView.prototype.updateVertexLabelOffset = function(state)
  		{
  			var h = mxUtils.getValue(state.style, mxConstants.STYLE_LABEL_POSITION, mxConstants.ALIGN_CENTER);
  			if (h == mxConstants.ALIGN_LEFT)
  			{
  				var lw = mxUtils.getValue(state.style, mxConstants.STYLE_LABEL_WIDTH, null);
  				if (lw != null)
  				{
  					lw *= this.scale;
  				}
  				else
  				{
  					lw = state.width;
  				}
  				state.absoluteOffset.x -= lw;
  			}
  			else if (h == mxConstants.ALIGN_RIGHT)
  			{
  				state.absoluteOffset.x += state.width;
  			}
  			else if (h == mxConstants.ALIGN_CENTER)
  			{
  				var lw = mxUtils.getValue(state.style, mxConstants.STYLE_LABEL_WIDTH, null);
  				if (lw != null)
  				{
  					var align = mxUtils.getValue(state.style, mxConstants.STYLE_ALIGN, mxConstants.ALIGN_CENTER);
  					var dx = 0;
  					if (align == mxConstants.ALIGN_CENTER)
  					{
  						dx = 0.5;
  					}
  					else if (align == mxConstants.ALIGN_RIGHT)
  					{
  						dx = 1;
  					}
  					if (dx != 0)
  					{
  						state.absoluteOffset.x -= (lw * this.scale - state.width) * dx;
  					}
  				}
  			}
  			var v = mxUtils.getValue(state.style, mxConstants.STYLE_VERTICAL_LABEL_POSITION, mxConstants.ALIGN_MIDDLE);
  			if (v == mxConstants.ALIGN_TOP)
  			{
  				state.absoluteOffset.y -= state.height;
  			}
  			else if (v == mxConstants.ALIGN_BOTTOM)
  			{
  				state.absoluteOffset.y += state.height;
  			}
  		};
  		mxGraphView.prototype.resetValidationState = function()
  		{
  			this.lastNode = null;
  			this.lastHtmlNode = null;
  			this.lastForegroundNode = null;
  			this.lastForegroundHtmlNode = null;
  		};
  		mxGraphView.prototype.stateValidated = function(state)
  		{
  			var fg = (this.graph.getModel().isEdge(state.cell) && this.graph.keepEdgesInForeground) ||
  				(this.graph.getModel().isVertex(state.cell) && this.graph.keepEdgesInBackground);
  			var htmlNode = (fg) ? this.lastForegroundHtmlNode || this.lastHtmlNode : this.lastHtmlNode;
  			var node = (fg) ? this.lastForegroundNode || this.lastNode : this.lastNode;
  			var result = this.graph.cellRenderer.insertStateAfter(state, node, htmlNode);
  			if (fg)
  			{
  				this.lastForegroundHtmlNode = result[1];
  				this.lastForegroundNode = result[0];
  			}
  			else
  			{
  				this.lastHtmlNode = result[1];
  				this.lastNode = result[0];
  			}
  		};
  		mxGraphView.prototype.updateFixedTerminalPoints = function(edge, source, target)
  		{
  			this.updateFixedTerminalPoint(edge, source, true,
  				this.graph.getConnectionConstraint(edge, source, true));
  			this.updateFixedTerminalPoint(edge, target, false,
  				this.graph.getConnectionConstraint(edge, target, false));
  		};
  		mxGraphView.prototype.updateFixedTerminalPoint = function(edge, terminal, source, constraint)
  		{
  			edge.setAbsoluteTerminalPoint(this.getFixedTerminalPoint(edge, terminal, source, constraint), source);
  		};
  		mxGraphView.prototype.getFixedTerminalPoint = function(edge, terminal, source, constraint)
  		{
  			var pt = null;
  			if (constraint != null)
  			{
  				pt = this.graph.getConnectionPoint(terminal, constraint, false);
  			}
  			if (pt == null && terminal == null)
  			{
  				var s = this.scale;
  				var tr = this.translate;
  				var orig = edge.origin;
  				var geo = this.graph.getCellGeometry(edge.cell);
  				pt = geo.getTerminalPoint(source);
  				if (pt != null)
  				{
  					pt = new mxPoint(s * (tr.x + pt.x + orig.x),
  									 s * (tr.y + pt.y + orig.y));
  				}
  			}
  			return pt;
  		};
  		mxGraphView.prototype.updateBoundsFromStencil = function(state)
  		{
  			var previous = null;
  			if (state != null && state.shape != null && state.shape.stencil != null && state.shape.stencil.aspect == 'fixed')
  			{
  				previous = mxRectangle.fromRectangle(state);
  				var asp = state.shape.stencil.computeAspect(state.style, state.x, state.y, state.width, state.height);
  				state.setRect(asp.x, asp.y, state.shape.stencil.w0 * asp.width, state.shape.stencil.h0 * asp.height);
  			}
  			return previous;
  		};
  		mxGraphView.prototype.updatePoints = function(edge, points, source, target)
  		{
  			if (edge != null)
  			{
  				var pts = [];
  				pts.push(edge.absolutePoints[0]);
  				var edgeStyle = this.getEdgeStyle(edge, points, source, target);
  				if (edgeStyle != null)
  				{
  					var src = this.getTerminalPort(edge, source, true);
  					var trg = this.getTerminalPort(edge, target, false);
  					var srcBounds = this.updateBoundsFromStencil(src);
  					var trgBounds = this.updateBoundsFromStencil(trg);
  					edgeStyle(edge, src, trg, points, pts);
  					if (srcBounds != null)
  					{
  						src.setRect(srcBounds.x, srcBounds.y, srcBounds.width, srcBounds.height);
  					}
  					if (trgBounds != null)
  					{
  						trg.setRect(trgBounds.x, trgBounds.y, trgBounds.width, trgBounds.height);
  					}
  				}
  				else if (points != null)
  				{
  					for (var i = 0; i < points.length; i++)
  					{
  						if (points[i] != null)
  						{
  							var pt = mxUtils.clone(points[i]);
  							pts.push(this.transformControlPoint(edge, pt));
  						}
  					}
  				}
  				var tmp = edge.absolutePoints;
  				pts.push(tmp[tmp.length-1]);
  				edge.absolutePoints = pts;
  			}
  		};
  		mxGraphView.prototype.transformControlPoint = function(state, pt, ignoreScale)
  		{
  			if (state != null && pt != null)
  			{
  				var orig = state.origin;
  				var scale = ignoreScale ? 1 : this.scale;
  			    return new mxPoint(scale * (pt.x + this.translate.x + orig.x),
  			    		scale * (pt.y + this.translate.y + orig.y));
  			}
  			return null;
  		};
  		mxGraphView.prototype.isLoopStyleEnabled = function(edge, points, source, target)
  		{
  			var sc = this.graph.getConnectionConstraint(edge, source, true);
  			var tc = this.graph.getConnectionConstraint(edge, target, false);
  			if ((points == null || points.length < 2) &&
  				(!mxUtils.getValue(edge.style, mxConstants.STYLE_ORTHOGONAL_LOOP, false) ||
  				((sc == null || sc.point == null) && (tc == null || tc.point == null))))
  			{
  				return source != null && source == target;
  			}
  			return false;
  		};
  		mxGraphView.prototype.getEdgeStyle = function(edge, points, source, target)
  		{
  			var edgeStyle = this.isLoopStyleEnabled(edge, points, source, target) ?
  				mxUtils.getValue(edge.style, mxConstants.STYLE_LOOP, this.graph.defaultLoopStyle) :
  				(!mxUtils.getValue(edge.style, mxConstants.STYLE_NOEDGESTYLE, false) ?
  				edge.style[mxConstants.STYLE_EDGE] : null);
  			if (typeof(edgeStyle) == "string")
  			{
  				var tmp = mxStyleRegistry.getValue(edgeStyle);
  				if (tmp == null && this.isAllowEval())
  				{
  		 			tmp = mxUtils.eval(edgeStyle);
  				}
  				edgeStyle = tmp;
  			}
  			if (typeof(edgeStyle) == "function")
  			{
  				return edgeStyle;
  			}
  			return null;
  		};
  		mxGraphView.prototype.updateFloatingTerminalPoints = function(state, source, target)
  		{
  			var pts = state.absolutePoints;
  			var p0 = pts[0];
  			var pe = pts[pts.length - 1];
  			if (pe == null && target != null)
  			{
  				this.updateFloatingTerminalPoint(state, target, source, false);
  			}
  			if (p0 == null && source != null)
  			{
  				this.updateFloatingTerminalPoint(state, source, target, true);
  			}
  		};
  		mxGraphView.prototype.updateFloatingTerminalPoint = function(edge, start, end, source)
  		{
  			edge.setAbsoluteTerminalPoint(this.getFloatingTerminalPoint(edge, start, end, source), source);
  		};
  		mxGraphView.prototype.getFloatingTerminalPoint = function(edge, start, end, source)
  		{
  			start = this.getTerminalPort(edge, start, source);
  			var next = this.getNextPoint(edge, end, source);
  			var orth = this.graph.isOrthogonal(edge);
  			var alpha = mxUtils.toRadians(Number(start.style[mxConstants.STYLE_ROTATION] || '0'));
  			var center = new mxPoint(start.getCenterX(), start.getCenterY());
  			if (alpha != 0)
  			{
  				var cos = Math.cos(-alpha);
  				var sin = Math.sin(-alpha);
  				next = mxUtils.getRotatedPoint(next, cos, sin, center);
  			}
  			var border = parseFloat(edge.style[mxConstants.STYLE_PERIMETER_SPACING] || 0);
  			border += parseFloat(edge.style[(source) ?
  				mxConstants.STYLE_SOURCE_PERIMETER_SPACING :
  				mxConstants.STYLE_TARGET_PERIMETER_SPACING] || 0);
  			var pt = this.getPerimeterPoint(start, next, alpha == 0 && orth, border);
  			if (alpha != 0)
  			{
  				var cos = Math.cos(alpha);
  				var sin = Math.sin(alpha);
  				pt = mxUtils.getRotatedPoint(pt, cos, sin, center);
  			}
  			return pt;
  		};
  		mxGraphView.prototype.getTerminalPort = function(state, terminal, source)
  		{
  			var key = (source) ? mxConstants.STYLE_SOURCE_PORT :
  				mxConstants.STYLE_TARGET_PORT;
  			var id = mxUtils.getValue(state.style, key);
  			if (id != null)
  			{
  				var tmp = this.getState(this.graph.getModel().getCell(id));
  				if (tmp != null)
  				{
  					terminal = tmp;
  				}
  			}
  			return terminal;
  		};
  		mxGraphView.prototype.getPerimeterPoint = function(terminal, next, orthogonal, border)
  		{
  			var point = null;
  			if (terminal != null)
  			{
  				var perimeter = this.getPerimeterFunction(terminal);
  				if (perimeter != null && next != null)
  				{
  					var bounds = this.getPerimeterBounds(terminal, border);
  					if (bounds.width > 0 || bounds.height > 0)
  					{
  						point = new mxPoint(next.x, next.y);
  						var flipH = false;
  						var flipV = false;
  						if (this.graph.model.isVertex(terminal.cell))
  						{
  							flipH = mxUtils.getValue(terminal.style, mxConstants.STYLE_FLIPH, 0) == 1;
  							flipV = mxUtils.getValue(terminal.style, mxConstants.STYLE_FLIPV, 0) == 1;
  							if (terminal.shape != null && terminal.shape.stencil != null)
  							{
  								flipH = (mxUtils.getValue(terminal.style, 'stencilFlipH', 0) == 1) || flipH;
  								flipV = (mxUtils.getValue(terminal.style, 'stencilFlipV', 0) == 1) || flipV;
  							}
  							if (flipH)
  							{
  								point.x = 2 * bounds.getCenterX() - point.x;
  							}
  							if (flipV)
  							{
  								point.y = 2 * bounds.getCenterY() - point.y;
  							}
  						}
  						point = perimeter(bounds, terminal, point, orthogonal);
  						if (point != null)
  						{
  							if (flipH)
  							{
  								point.x = 2 * bounds.getCenterX() - point.x;
  							}
  							if (flipV)
  							{
  								point.y = 2 * bounds.getCenterY() - point.y;
  							}
  						}
  					}
  				}
  				if (point == null)
  				{
  					point = this.getPoint(terminal);
  				}
  			}
  			return point;
  		};
  		mxGraphView.prototype.getRoutingCenterX = function (state)
  		{
  			var f = (state.style != null) ? parseFloat(state.style
  				[mxConstants.STYLE_ROUTING_CENTER_X]) || 0 : 0;
  			return state.getCenterX() + f * state.width;
  		};
  		mxGraphView.prototype.getRoutingCenterY = function (state)
  		{
  			var f = (state.style != null) ? parseFloat(state.style
  				[mxConstants.STYLE_ROUTING_CENTER_Y]) || 0 : 0;
  			return state.getCenterY() + f * state.height;
  		};
  		mxGraphView.prototype.getPerimeterBounds = function(terminal, border)
  		{
  			border = (border != null) ? border : 0;
  			if (terminal != null)
  			{
  				border += parseFloat(terminal.style[mxConstants.STYLE_PERIMETER_SPACING] || 0);
  			}
  			return terminal.getPerimeterBounds(border * this.scale);
  		};
  		mxGraphView.prototype.getPerimeterFunction = function(state)
  		{
  			var perimeter = state.style[mxConstants.STYLE_PERIMETER];
  			if (typeof(perimeter) == "string")
  			{
  				var tmp = mxStyleRegistry.getValue(perimeter);
  				if (tmp == null && this.isAllowEval())
  				{
  		 			tmp = mxUtils.eval(perimeter);
  				}
  				perimeter = tmp;
  			}
  			if (typeof(perimeter) == "function")
  			{
  				return perimeter;
  			}
  			return null;
  		};
  		mxGraphView.prototype.getNextPoint = function(edge, opposite, source)
  		{
  			var pts = edge.absolutePoints;
  			var point = null;
  			if (pts != null && pts.length >= 2)
  			{
  				var count = pts.length;
  				point = pts[(source) ? Math.min(1, count - 1) : Math.max(0, count - 2)];
  			}
  			if (point == null && opposite != null)
  			{
  				point = new mxPoint(opposite.getCenterX(), opposite.getCenterY());
  			}
  			return point;
  		};
  		mxGraphView.prototype.getVisibleTerminal = function(edge, source)
  		{
  			var model = this.graph.getModel();
  			var result = model.getTerminal(edge, source);
  			var best = result;
  			while (result != null && result != this.currentRoot)
  			{
  				if (!this.graph.isCellVisible(best) || this.isCellCollapsed(result))
  				{
  					best = result;
  				}
  				result = model.getParent(result);
  			}
  			if (best != null && (!model.contains(best) ||
  				model.getParent(best) == model.getRoot() ||
  				best == this.currentRoot))
  			{
  				best = null;
  			}
  			return best;
  		};
  		mxGraphView.prototype.updateEdgeBounds = function(state)
  		{
  			var points = state.absolutePoints;
  			var p0 = points[0];
  			var pe = points[points.length - 1];
  			if (p0.x != pe.x || p0.y != pe.y)
  			{
  				var dx = pe.x - p0.x;
  				var dy = pe.y - p0.y;
  				state.terminalDistance = Math.sqrt(dx * dx + dy * dy);
  			}
  			else
  			{
  				state.terminalDistance = 0;
  			}
  			var length = 0;
  			var segments = [];
  			var pt = p0;
  			if (pt != null)
  			{
  				var minX = pt.x;
  				var minY = pt.y;
  				var maxX = minX;
  				var maxY = minY;
  				for (var i = 1; i < points.length; i++)
  				{
  					var tmp = points[i];
  					if (tmp != null)
  					{
  						var dx = pt.x - tmp.x;
  						var dy = pt.y - tmp.y;
  						var segment = Math.sqrt(dx * dx + dy * dy);
  						segments.push(segment);
  						length += segment;
  						pt = tmp;
  						minX = Math.min(pt.x, minX);
  						minY = Math.min(pt.y, minY);
  						maxX = Math.max(pt.x, maxX);
  						maxY = Math.max(pt.y, maxY);
  					}
  				}
  				state.length = length;
  				state.segments = segments;
  				var markerSize = 1;
  				state.x = minX;
  				state.y = minY;
  				state.width = Math.max(markerSize, maxX - minX);
  				state.height = Math.max(markerSize, maxY - minY);
  			}
  		};
  		mxGraphView.prototype.getPoint = function(state, geometry)
  		{
  			var x = state.getCenterX();
  			var y = state.getCenterY();
  			if (state.segments != null && (geometry == null || geometry.relative))
  			{
  				var gx = (geometry != null) ? geometry.x / 2 : 0;
  				var pointCount = state.absolutePoints.length;
  				var dist = Math.round((gx + 0.5) * state.length);
  				var segment = state.segments[0];
  				var length = 0;
  				var index = 1;
  				while (dist >= Math.round(length + segment) && index < pointCount - 1)
  				{
  					length += segment;
  					segment = state.segments[index++];
  				}
  				var factor = (segment == 0) ? 0 : (dist - length) / segment;
  				var p0 = state.absolutePoints[index-1];
  				var pe = state.absolutePoints[index];
  				if (p0 != null && pe != null)
  				{
  					var gy = 0;
  					var offsetX = 0;
  					var offsetY = 0;
  					if (geometry != null)
  					{
  						gy = geometry.y;
  						var offset = geometry.offset;
  						if (offset != null)
  						{
  							offsetX = offset.x;
  							offsetY = offset.y;
  						}
  					}
  					var dx = pe.x - p0.x;
  					var dy = pe.y - p0.y;
  					var nx = (segment == 0) ? 0 : dy / segment;
  					var ny = (segment == 0) ? 0 : dx / segment;
  					x = p0.x + dx * factor + (nx * gy + offsetX) * this.scale;
  					y = p0.y + dy * factor - (ny * gy - offsetY) * this.scale;
  				}
  			}
  			else if (geometry != null)
  			{
  				var offset = geometry.offset;
  				if (offset != null)
  				{
  					x += offset.x;
  					y += offset.y;
  				}
  			}
  			return new mxPoint(x, y);
  		};
  		mxGraphView.prototype.getRelativePoint = function(edgeState, x, y)
  		{
  			var model = this.graph.getModel();
  			var geometry = model.getGeometry(edgeState.cell);
  			if (geometry != null)
  			{
  				var pointCount = edgeState.absolutePoints.length;
  				if (geometry.relative && pointCount > 1)
  				{
  					var totalLength = edgeState.length;
  					var segments = edgeState.segments;
  					var p0 = edgeState.absolutePoints[0];
  					var pe = edgeState.absolutePoints[1];
  					var minDist = mxUtils.ptSegDistSq(p0.x, p0.y, pe.x, pe.y, x, y);
  					var index = 0;
  					var tmp = 0;
  					var length = 0;
  					for (var i = 2; i < pointCount; i++)
  					{
  						tmp += segments[i - 2];
  						pe = edgeState.absolutePoints[i];
  						var dist = mxUtils.ptSegDistSq(p0.x, p0.y, pe.x, pe.y, x, y);
  						if (dist <= minDist)
  						{
  							minDist = dist;
  							index = i - 1;
  							length = tmp;
  						}
  						p0 = pe;
  					}
  					var seg = segments[index];
  					p0 = edgeState.absolutePoints[index];
  					pe = edgeState.absolutePoints[index + 1];
  					var x2 = p0.x;
  					var y2 = p0.y;
  					var x1 = pe.x;
  					var y1 = pe.y;
  					var px = x;
  					var py = y;
  					var xSegment = x2 - x1;
  					var ySegment = y2 - y1;
  					px -= x1;
  					py -= y1;
  					var projlenSq = 0;
  					px = xSegment - px;
  					py = ySegment - py;
  					var dotprod = px * xSegment + py * ySegment;
  					if (dotprod <= 0.0)
  					{
  						projlenSq = 0;
  					}
  					else
  					{
  						projlenSq = dotprod * dotprod
  								/ (xSegment * xSegment + ySegment * ySegment);
  					}
  					var projlen = Math.sqrt(projlenSq);
  					if (projlen > seg)
  					{
  						projlen = seg;
  					}
  					var yDistance = Math.sqrt(mxUtils.ptSegDistSq(p0.x, p0.y, pe
  							.x, pe.y, x, y));
  					var direction = mxUtils.relativeCcw(p0.x, p0.y, pe.x, pe.y, x, y);
  					if (direction == -1)
  					{
  						yDistance = -yDistance;
  					}
  					return new mxPoint(((totalLength / 2 - length - projlen) / totalLength) * -2,
  								yDistance / this.scale);
  				}
  			}
  			return new mxPoint();
  		};
  		mxGraphView.prototype.updateEdgeLabelOffset = function(state)
  		{
  			var points = state.absolutePoints;
  			state.absoluteOffset.x = state.getCenterX();
  			state.absoluteOffset.y = state.getCenterY();
  			if (points != null && points.length > 0 && state.segments != null)
  			{
  				var geometry = this.graph.getCellGeometry(state.cell);
  				if (geometry.relative)
  				{
  					var offset = this.getPoint(state, geometry);
  					if (offset != null)
  					{
  						state.absoluteOffset = offset;
  					}
  				}
  				else
  				{
  					var p0 = points[0];
  					var pe = points[points.length - 1];
  					if (p0 != null && pe != null)
  					{
  						var dx = pe.x - p0.x;
  						var dy = pe.y - p0.y;
  						var x0 = 0;
  						var y0 = 0;
  						var off = geometry.offset;
  						if (off != null)
  						{
  							x0 = off.x;
  							y0 = off.y;
  						}
  						var x = p0.x + dx / 2 + x0 * this.scale;
  						var y = p0.y + dy / 2 + y0 * this.scale;
  						state.absoluteOffset.x = x;
  						state.absoluteOffset.y = y;
  					}
  				}
  			}
  		};
  		mxGraphView.prototype.getState = function(cell, create)
  		{
  			create = create || false;
  			var state = null;
  			if (cell != null)
  			{
  				state = this.states.get(cell);
  				if (create && (state == null || this.updateStyle) && this.graph.isCellVisible(cell))
  				{
  					if (state == null)
  					{
  						state = this.createState(cell);
  						this.states.put(cell, state);
  					}
  					else
  					{
  						state.style = this.graph.getCellStyle(cell);
  					}
  				}
  			}
  			return state;
  		};
  		mxGraphView.prototype.isRendering = function()
  		{
  			return this.rendering;
  		};
  		mxGraphView.prototype.setRendering = function(value)
  		{
  			this.rendering = value;
  		};
  		mxGraphView.prototype.isAllowEval = function()
  		{
  			return this.allowEval;
  		};
  		mxGraphView.prototype.setAllowEval = function(value)
  		{
  			this.allowEval = value;
  		};
  		mxGraphView.prototype.getStates = function()
  		{
  			return this.states;
  		};
  		mxGraphView.prototype.setStates = function(value)
  		{
  			this.states = value;
  		};
  		mxGraphView.prototype.getCellStates = function(cells)
  		{
  			if (cells == null)
  			{
  				return this.states;
  			}
  			else
  			{
  				var result = [];
  				for (var i = 0; i < cells.length; i++)
  				{
  					var state = this.getState(cells[i]);
  					if (state != null)
  					{
  						result.push(state);
  					}
  				}
  				return result;
  			}
  		};
  		mxGraphView.prototype.removeState = function(cell)
  		{
  			var state = null;
  			if (cell != null)
  			{
  				state = this.states.remove(cell);
  				if (state != null)
  				{
  					this.graph.cellRenderer.destroy(state);
  					state.invalid = true;
  					state.destroy();
  				}
  			}
  			return state;
  		};
  		mxGraphView.prototype.createState = function(cell)
  		{
  			return new mxCellState(this, cell, this.graph.getCellStyle(cell));
  		};
  		mxGraphView.prototype.getCanvas = function()
  		{
  			return this.canvas;
  		};
  		mxGraphView.prototype.getBackgroundPane = function()
  		{
  			return this.backgroundPane;
  		};
  		mxGraphView.prototype.getDrawPane = function()
  		{
  			return this.drawPane;
  		};
  		mxGraphView.prototype.getOverlayPane = function()
  		{
  			return this.overlayPane;
  		};
  		mxGraphView.prototype.getDecoratorPane = function()
  		{
  			return this.decoratorPane;
  		};
  		mxGraphView.prototype.isContainerEvent = function(evt)
  		{
  			var source = mxEvent.getSource(evt);
  			return (source == this.graph.container ||
  				source.parentNode == this.backgroundPane ||
  				(source.parentNode != null &&
  				source.parentNode.parentNode == this.backgroundPane) ||
  				source == this.canvas.parentNode ||
  				source == this.canvas ||
  				source == this.backgroundPane ||
  				source == this.drawPane ||
  				source == this.overlayPane ||
  				source == this.decoratorPane);
  		};
  		 mxGraphView.prototype.isScrollEvent = function(evt)
  		{
  			var offset = mxUtils.getOffset(this.graph.container);
  			var pt = new mxPoint(evt.clientX - offset.x, evt.clientY - offset.y);
  			var outWidth = this.graph.container.offsetWidth;
  			var inWidth = this.graph.container.clientWidth;
  			if (outWidth > inWidth && pt.x > inWidth + 2 && pt.x <= outWidth)
  			{
  				return true;
  			}
  			var outHeight = this.graph.container.offsetHeight;
  			var inHeight = this.graph.container.clientHeight;
  			if (outHeight > inHeight && pt.y > inHeight + 2 && pt.y <= outHeight)
  			{
  				return true;
  			}
  			return false;
  		};
  		mxGraphView.prototype.init = function()
  		{
  			this.installListeners();
  			var graph = this.graph;
  			if (graph.dialect == mxConstants.DIALECT_SVG)
  			{
  				this.createSvg();
  			}
  			else if (graph.dialect == mxConstants.DIALECT_VML)
  			{
  				this.createVml();
  			}
  			else
  			{
  				this.createHtml();
  			}
  		};
  		mxGraphView.prototype.installListeners = function()
  		{
  			var graph = this.graph;
  			var container = graph.container;
  			if (container != null)
  			{
  				if (mxClient.IS_TOUCH)
  				{
  					mxEvent.addListener(container, 'gesturestart', mxUtils.bind(this, function(evt)
  					{
  						graph.fireGestureEvent(evt);
  						mxEvent.consume(evt);
  					}));
  					mxEvent.addListener(container, 'gesturechange', mxUtils.bind(this, function(evt)
  					{
  						graph.fireGestureEvent(evt);
  						mxEvent.consume(evt);
  					}));
  					mxEvent.addListener(container, 'gestureend', mxUtils.bind(this, function(evt)
  					{
  						graph.fireGestureEvent(evt);
  						mxEvent.consume(evt);
  					}));
  				}
  				var pointerId = null;
  				mxEvent.addGestureListeners(container, mxUtils.bind(this, function(evt)
  				{
  					if (this.isContainerEvent(evt) && ((!mxClient.IS_IE && !mxClient.IS_IE11 && !mxClient.IS_GC &&
  						!mxClient.IS_OP && !mxClient.IS_SF) || !this.isScrollEvent(evt)))
  					{
  						graph.fireMouseEvent(mxEvent.MOUSE_DOWN, new mxMouseEvent(evt));
  						pointerId = evt.pointerId;
  					}
  				}),
  				mxUtils.bind(this, function(evt)
  				{
  					if (this.isContainerEvent(evt) && (pointerId == null || evt.pointerId == pointerId))
  					{
  						graph.fireMouseEvent(mxEvent.MOUSE_MOVE, new mxMouseEvent(evt));
  					}
  				}),
  				mxUtils.bind(this, function(evt)
  				{
  					if (this.isContainerEvent(evt))
  					{
  						graph.fireMouseEvent(mxEvent.MOUSE_UP, new mxMouseEvent(evt));
  					}
  					pointerId = null;
  				}));
  				mxEvent.addListener(container, 'dblclick', mxUtils.bind(this, function(evt)
  				{
  					if (this.isContainerEvent(evt))
  					{
  						graph.dblClick(evt);
  					}
  				}));
  				var getState = function(evt)
  				{
  					var state = null;
  					if (mxClient.IS_TOUCH)
  					{
  						var x = mxEvent.getClientX(evt);
  						var y = mxEvent.getClientY(evt);
  						var pt = mxUtils.convertPoint(container, x, y);
  						state = graph.view.getState(graph.getCellAt(pt.x, pt.y));
  					}
  					return state;
  				};
  				graph.addMouseListener(
  				{
  					mouseDown: function(sender, me)
  					{
  						graph.popupMenuHandler.hideMenu();
  					},
  					mouseMove: function() { },
  					mouseUp: function() { }
  				});
  				this.moveHandler = mxUtils.bind(this, function(evt)
  				{
  					if (graph.tooltipHandler != null && graph.tooltipHandler.isHideOnHover())
  					{
  						graph.tooltipHandler.hide();
  					}
  					if (this.captureDocumentGesture && graph.isMouseDown && graph.container != null &&
  						!this.isContainerEvent(evt) && graph.container.style.display != 'none' &&
  						graph.container.style.visibility != 'hidden' && !mxEvent.isConsumed(evt))
  					{
  						graph.fireMouseEvent(mxEvent.MOUSE_MOVE, new mxMouseEvent(evt, getState(evt)));
  					}
  				});
  				this.endHandler = mxUtils.bind(this, function(evt)
  				{
  					if (this.captureDocumentGesture && graph.isMouseDown && graph.container != null &&
  						!this.isContainerEvent(evt) && graph.container.style.display != 'none' &&
  						graph.container.style.visibility != 'hidden')
  					{
  						graph.fireMouseEvent(mxEvent.MOUSE_UP, new mxMouseEvent(evt));
  					}
  				});
  				mxEvent.addGestureListeners(document, null, this.moveHandler, this.endHandler);
  			}
  		};
  		mxGraphView.prototype.createHtml = function()
  		{
  			var container = this.graph.container;
  			if (container != null)
  			{
  				this.canvas = this.createHtmlPane('100%', '100%');
  				this.canvas.style.overflow = 'hidden';
  				this.backgroundPane = this.createHtmlPane('1px', '1px');
  				this.drawPane = this.createHtmlPane('1px', '1px');
  				this.overlayPane = this.createHtmlPane('1px', '1px');
  				this.decoratorPane = this.createHtmlPane('1px', '1px');
  				this.canvas.appendChild(this.backgroundPane);
  				this.canvas.appendChild(this.drawPane);
  				this.canvas.appendChild(this.overlayPane);
  				this.canvas.appendChild(this.decoratorPane);
  				container.appendChild(this.canvas);
  				this.updateContainerStyle(container);
  				if (mxClient.IS_QUIRKS)
  				{
  					var onResize = mxUtils.bind(this, function(evt)
  					{
  						var bounds = this.getGraphBounds();
  						var width = bounds.x + bounds.width + this.graph.border;
  						var height = bounds.y + bounds.height + this.graph.border;
  						this.updateHtmlCanvasSize(width, height);
  					});
  					mxEvent.addListener(window, 'resize', onResize);
  				}
  			}
  		};
  		mxGraphView.prototype.updateHtmlCanvasSize = function(width, height)
  		{
  			if (this.graph.container != null)
  			{
  				var ow = this.graph.container.offsetWidth;
  				var oh = this.graph.container.offsetHeight;
  				if (ow < width)
  				{
  					this.canvas.style.width = width + 'px';
  				}
  				else
  				{
  					this.canvas.style.width = '100%';
  				}
  				if (oh < height)
  				{
  					this.canvas.style.height = height + 'px';
  				}
  				else
  				{
  					this.canvas.style.height = '100%';
  				}
  			}
  		};
  		mxGraphView.prototype.createHtmlPane = function(width, height)
  		{
  			var pane = document.createElement('DIV');
  			if (width != null && height != null)
  			{
  				pane.style.position = 'absolute';
  				pane.style.left = '0px';
  				pane.style.top = '0px';
  				pane.style.width = width;
  				pane.style.height = height;
  			}
  			else
  			{
  				pane.style.position = 'relative';
  			}
  			return pane;
  		};
  		mxGraphView.prototype.createVml = function()
  		{
  			var container = this.graph.container;
  			if (container != null)
  			{
  				var width = container.offsetWidth;
  				var height = container.offsetHeight;
  				this.canvas = this.createVmlPane(width, height);
  				this.canvas.style.overflow = 'hidden';
  				this.backgroundPane = this.createVmlPane(width, height);
  				this.drawPane = this.createVmlPane(width, height);
  				this.overlayPane = this.createVmlPane(width, height);
  				this.decoratorPane = this.createVmlPane(width, height);
  				this.canvas.appendChild(this.backgroundPane);
  				this.canvas.appendChild(this.drawPane);
  				this.canvas.appendChild(this.overlayPane);
  				this.canvas.appendChild(this.decoratorPane);
  				container.appendChild(this.canvas);
  			}
  		};
  		mxGraphView.prototype.createVmlPane = function(width, height)
  		{
  			var pane = document.createElement(mxClient.VML_PREFIX + ':group');
  			pane.style.position = 'absolute';
  			pane.style.left = '0px';
  			pane.style.top = '0px';
  			pane.style.width = width + 'px';
  			pane.style.height = height + 'px';
  			pane.setAttribute('coordsize', width + ',' + height);
  			pane.setAttribute('coordorigin', '0,0');
  			return pane;
  		};
  		mxGraphView.prototype.createSvg = function()
  		{
  			var container = this.graph.container;
  			this.canvas = document.createElementNS(mxConstants.NS_SVG, 'g');
  			this.backgroundPane = document.createElementNS(mxConstants.NS_SVG, 'g');
  			this.canvas.appendChild(this.backgroundPane);
  			this.drawPane = document.createElementNS(mxConstants.NS_SVG, 'g');
  			this.canvas.appendChild(this.drawPane);
  			this.overlayPane = document.createElementNS(mxConstants.NS_SVG, 'g');
  			this.canvas.appendChild(this.overlayPane);
  			this.decoratorPane = document.createElementNS(mxConstants.NS_SVG, 'g');
  			this.canvas.appendChild(this.decoratorPane);
  			var root = document.createElementNS(mxConstants.NS_SVG, 'svg');
  			root.style.left = '0px';
  			root.style.top = '0px';
  			root.style.width = '100%';
  			root.style.height = '100%';
  			root.style.display = 'block';
  			root.appendChild(this.canvas);
  			if (mxClient.IS_IE || mxClient.IS_IE11)
  			{
  				root.style.overflow = 'hidden';
  			}
  			if (container != null)
  			{
  				container.appendChild(root);
  				this.updateContainerStyle(container);
  			}
  		};
  		mxGraphView.prototype.updateContainerStyle = function(container)
  		{
  			var style = mxUtils.getCurrentStyle(container);
  			if (style != null && style.position == 'static')
  			{
  				container.style.position = 'relative';
  			}
  			if (mxClient.IS_POINTER)
  			{
  				container.style.touchAction = 'none';
  			}
  		};
  		mxGraphView.prototype.destroy = function()
  		{
  			var root = (this.canvas != null) ? this.canvas.ownerSVGElement : null;
  			if (root == null)
  			{
  				root = this.canvas;
  			}
  			if (root != null && root.parentNode != null)
  			{
  				this.clear(this.currentRoot, true);
  				mxEvent.removeGestureListeners(document, null, this.moveHandler, this.endHandler);
  				mxEvent.release(this.graph.container);
  				root.parentNode.removeChild(root);
  				this.moveHandler = null;
  				this.endHandler = null;
  				this.canvas = null;
  				this.backgroundPane = null;
  				this.drawPane = null;
  				this.overlayPane = null;
  				this.decoratorPane = null;
  			}
  		};
  		function mxCurrentRootChange(view, root)
  		{
  			this.view = view;
  			this.root = root;
  			this.previous = root;
  			this.isUp = root == null;
  			if (!this.isUp)
  			{
  				var tmp = this.view.currentRoot;
  				var model = this.view.graph.getModel();
  				while (tmp != null)
  				{
  					if (tmp == root)
  					{
  						this.isUp = true;
  						break;
  					}
  					tmp = model.getParent(tmp);
  				}
  			}
  		}		mxCurrentRootChange.prototype.execute = function()
  		{
  			var tmp = this.view.currentRoot;
  			this.view.currentRoot = this.previous;
  			this.previous = tmp;
  			var translate = this.view.graph.getTranslateForRoot(this.view.currentRoot);
  			if (translate != null)
  			{
  				this.view.translate = new mxPoint(-translate.x, -translate.y);
  			}
  			if (this.isUp)
  			{
  				this.view.clear(this.view.currentRoot, true);
  				this.view.validate();
  			}
  			else
  			{
  				this.view.refresh();
  			}
  			var name = (this.isUp) ? mxEvent.UP : mxEvent.DOWN;
  			this.view.fireEvent(new mxEventObject(name,
  				'root', this.view.currentRoot, 'previous', this.previous));
  			this.isUp = !this.isUp;
  		};
  		__mxOutput.mxGraphView = typeof mxGraphView !== 'undefined' ? mxGraphView : undefined;
  		function mxGraph(container, model, renderHint, stylesheet)
  		{
  			this.mouseListeners = null;
  			this.renderHint = renderHint;
  			if (mxClient.IS_SVG)
  			{
  				this.dialect = mxConstants.DIALECT_SVG;
  			}
  			else if (renderHint == mxConstants.RENDERING_HINT_EXACT && mxClient.IS_VML)
  			{
  				this.dialect = mxConstants.DIALECT_VML;
  			}
  			else if (renderHint == mxConstants.RENDERING_HINT_FASTEST)
  			{
  				this.dialect = mxConstants.DIALECT_STRICTHTML;
  			}
  			else if (renderHint == mxConstants.RENDERING_HINT_FASTER)
  			{
  				this.dialect = mxConstants.DIALECT_PREFERHTML;
  			}
  			else
  			{
  				this.dialect = mxConstants.DIALECT_MIXEDHTML;
  			}
  			this.model = (model != null) ? model : new mxGraphModel();
  			this.multiplicities = [];
  			this.imageBundles = [];
  			this.cellRenderer = this.createCellRenderer();
  			this.setSelectionModel(this.createSelectionModel());
  			this.setStylesheet((stylesheet != null) ? stylesheet : this.createStylesheet());
  			this.view = this.createGraphView();
  			this.graphModelChangeListener = mxUtils.bind(this, function(sender, evt)
  			{
  				this.graphModelChanged(evt.getProperty('edit').changes);
  			});
  			this.model.addListener(mxEvent.CHANGE, this.graphModelChangeListener);
  			this.createHandlers();
  			if (container != null)
  			{
  				this.init(container);
  			}
  			this.view.revalidate();
  		}		if (mxLoadResources)
  		{
  			mxResources.add(mxClient.basePath + '/resources/graph');
  		}
  		else
  		{
  			mxClient.defaultBundles.push(mxClient.basePath + '/resources/graph');
  		}
  		mxGraph.prototype = new mxEventSource();
  		mxGraph.prototype.constructor = mxGraph;
  		mxGraph.prototype.mouseListeners = null;
  		mxGraph.prototype.isMouseDown = false;
  		mxGraph.prototype.model = null;
  		mxGraph.prototype.view = null;
  		mxGraph.prototype.stylesheet = null;
  		mxGraph.prototype.selectionModel = null;
  		mxGraph.prototype.cellEditor = null;
  		mxGraph.prototype.cellRenderer = null;
  		mxGraph.prototype.multiplicities = null;
  		mxGraph.prototype.renderHint = null;
  		mxGraph.prototype.dialect = null;
  		mxGraph.prototype.gridSize = 10;
  		mxGraph.prototype.gridEnabled = true;
  		mxGraph.prototype.portsEnabled = true;
  		mxGraph.prototype.nativeDblClickEnabled = true;
  		mxGraph.prototype.doubleTapEnabled = true;
  		mxGraph.prototype.doubleTapTimeout = 500;
  		mxGraph.prototype.doubleTapTolerance = 25;
  		mxGraph.prototype.lastTouchY = 0;
  		mxGraph.prototype.lastTouchY = 0;
  		mxGraph.prototype.lastTouchTime = 0;
  		mxGraph.prototype.tapAndHoldEnabled = true;
  		mxGraph.prototype.tapAndHoldDelay = 500;
  		mxGraph.prototype.tapAndHoldInProgress = false;
  		mxGraph.prototype.tapAndHoldValid = false;
  		mxGraph.prototype.initialTouchX = 0;
  		mxGraph.prototype.initialTouchY = 0;
  		mxGraph.prototype.tolerance = 4;
  		mxGraph.prototype.defaultOverlap = 0.5;
  		mxGraph.prototype.defaultParent = null;
  		mxGraph.prototype.alternateEdgeStyle = null;
  		mxGraph.prototype.backgroundImage = null;
  		mxGraph.prototype.pageVisible = false;
  		mxGraph.prototype.pageBreaksVisible = false;
  		mxGraph.prototype.pageBreakColor = 'gray';
  		mxGraph.prototype.pageBreakDashed = true;
  		mxGraph.prototype.minPageBreakDist = 20;
  		mxGraph.prototype.preferPageSize = false;
  		mxGraph.prototype.pageFormat = mxConstants.PAGE_FORMAT_A4_PORTRAIT;
  		mxGraph.prototype.pageScale = 1.5;
  		mxGraph.prototype.enabled = true;
  		mxGraph.prototype.escapeEnabled = true;
  		mxGraph.prototype.invokesStopCellEditing = true;
  		mxGraph.prototype.enterStopsCellEditing = false;
  		mxGraph.prototype.useScrollbarsForPanning = true;
  		mxGraph.prototype.exportEnabled = true;
  		mxGraph.prototype.importEnabled = true;
  		mxGraph.prototype.cellsLocked = false;
  		mxGraph.prototype.cellsCloneable = true;
  		mxGraph.prototype.foldingEnabled = true;
  		mxGraph.prototype.cellsEditable = true;
  		mxGraph.prototype.cellsDeletable = true;
  		mxGraph.prototype.cellsMovable = true;
  		mxGraph.prototype.edgeLabelsMovable = true;
  		mxGraph.prototype.vertexLabelsMovable = false;
  		mxGraph.prototype.dropEnabled = false;
  		mxGraph.prototype.splitEnabled = true;
  		mxGraph.prototype.cellsResizable = true;
  		mxGraph.prototype.cellsBendable = true;
  		mxGraph.prototype.cellsSelectable = true;
  		mxGraph.prototype.cellsDisconnectable = true;
  		mxGraph.prototype.autoSizeCells = false;
  		mxGraph.prototype.autoSizeCellsOnAdd = false;
  		mxGraph.prototype.autoScroll = true;
  		mxGraph.prototype.ignoreScrollbars = false;
  		mxGraph.prototype.translateToScrollPosition = false;
  		mxGraph.prototype.timerAutoScroll = false;
  		mxGraph.prototype.allowAutoPanning = false;
  		mxGraph.prototype.autoExtend = true;
  		mxGraph.prototype.maximumGraphBounds = null;
  		mxGraph.prototype.minimumGraphSize = null;
  		mxGraph.prototype.minimumContainerSize = null;
  		mxGraph.prototype.maximumContainerSize = null;
  		mxGraph.prototype.resizeContainer = false;
  		mxGraph.prototype.border = 0;
  		mxGraph.prototype.keepEdgesInForeground = false;
  		mxGraph.prototype.keepEdgesInBackground = false;
  		mxGraph.prototype.allowNegativeCoordinates = true;
  		mxGraph.prototype.constrainChildren = true;
  		mxGraph.prototype.constrainRelativeChildren = false;
  		mxGraph.prototype.extendParents = true;
  		mxGraph.prototype.extendParentsOnAdd = true;
  		mxGraph.prototype.extendParentsOnMove = false;
  		mxGraph.prototype.recursiveResize = false;
  		mxGraph.prototype.collapseToPreferredSize = true;
  		mxGraph.prototype.zoomFactor = 1.2;
  		mxGraph.prototype.keepSelectionVisibleOnZoom = false;
  		mxGraph.prototype.centerZoom = true;
  		mxGraph.prototype.resetViewOnRootChange = true;
  		mxGraph.prototype.resetEdgesOnResize = false;
  		mxGraph.prototype.resetEdgesOnMove = false;
  		mxGraph.prototype.resetEdgesOnConnect = true;
  		mxGraph.prototype.allowLoops = false;
  		mxGraph.prototype.defaultLoopStyle = mxEdgeStyle.Loop;
  		mxGraph.prototype.multigraph = true;
  		mxGraph.prototype.connectableEdges = false;
  		mxGraph.prototype.allowDanglingEdges = true;
  		mxGraph.prototype.cloneInvalidEdges = false;
  		mxGraph.prototype.disconnectOnMove = true;
  		mxGraph.prototype.labelsVisible = true;
  		mxGraph.prototype.htmlLabels = false;
  		mxGraph.prototype.swimlaneSelectionEnabled = true;
  		mxGraph.prototype.swimlaneNesting = true;
  		mxGraph.prototype.swimlaneIndicatorColorAttribute = mxConstants.STYLE_FILLCOLOR;
  		mxGraph.prototype.imageBundles = null;
  		mxGraph.prototype.minFitScale = 0.1;
  		mxGraph.prototype.maxFitScale = 8;
  		mxGraph.prototype.panDx = 0;
  		mxGraph.prototype.panDy = 0;
  		mxGraph.prototype.collapsedImage = new mxImage(mxClient.imageBasePath + '/collapsed.gif', 9, 9);
  		mxGraph.prototype.expandedImage = new mxImage(mxClient.imageBasePath + '/expanded.gif', 9, 9);
  		mxGraph.prototype.warningImage = new mxImage(mxClient.imageBasePath + '/warning'+
  			((mxClient.IS_MAC) ? '.png' : '.gif'), 16, 16);
  		mxGraph.prototype.alreadyConnectedResource = (mxClient.language != 'none') ? 'alreadyConnected' : '';
  		mxGraph.prototype.containsValidationErrorsResource = (mxClient.language != 'none') ? 'containsValidationErrors' : '';
  		mxGraph.prototype.collapseExpandResource = (mxClient.language != 'none') ? 'collapse-expand' : '';
  		mxGraph.prototype.init = function(container)
  		{
  			this.container = container;
  			this.cellEditor = this.createCellEditor();
  			this.view.init();
  			this.sizeDidChange();
  			mxEvent.addListener(container, 'mouseleave', mxUtils.bind(this, function(evt)
  			{
  				if (this.tooltipHandler != null && this.tooltipHandler.div != null &&
  					this.tooltipHandler.div != evt.relatedTarget)
  				{
  					this.tooltipHandler.hide();
  				}
  			}));
  			if (mxClient.IS_IE)
  			{
  				mxEvent.addListener(window, 'unload', mxUtils.bind(this, function()
  				{
  					this.destroy();
  				}));
  				mxEvent.addListener(container, 'selectstart',
  					mxUtils.bind(this, function(evt)
  					{
  						return this.isEditing() || (!this.isMouseDown && !mxEvent.isShiftDown(evt));
  					})
  				);
  			}
  			if (document.documentMode == 8)
  			{
  				container.insertAdjacentHTML('beforeend', '<' + mxClient.VML_PREFIX + ':group' +
  					' style="DISPLAY: none;"></' + mxClient.VML_PREFIX + ':group>');
  			}
  		};
  		mxGraph.prototype.createHandlers = function()
  		{
  			this.tooltipHandler = this.createTooltipHandler();
  			this.tooltipHandler.setEnabled(false);
  			this.selectionCellsHandler = this.createSelectionCellsHandler();
  			this.connectionHandler = this.createConnectionHandler();
  			this.connectionHandler.setEnabled(false);
  			this.graphHandler = this.createGraphHandler();
  			this.panningHandler = this.createPanningHandler();
  			this.panningHandler.panningEnabled = false;
  			this.popupMenuHandler = this.createPopupMenuHandler();
  		};
  		mxGraph.prototype.createTooltipHandler = function()
  		{
  			return new mxTooltipHandler(this);
  		};
  		mxGraph.prototype.createSelectionCellsHandler = function()
  		{
  			return new mxSelectionCellsHandler(this);
  		};
  		mxGraph.prototype.createConnectionHandler = function()
  		{
  			return new mxConnectionHandler(this);
  		};
  		mxGraph.prototype.createGraphHandler = function()
  		{
  			return new mxGraphHandler(this);
  		};
  		mxGraph.prototype.createPanningHandler = function()
  		{
  			return new mxPanningHandler(this);
  		};
  		mxGraph.prototype.createPopupMenuHandler = function()
  		{
  			return new mxPopupMenuHandler(this);
  		};
  		mxGraph.prototype.createSelectionModel = function()
  		{
  			return new mxGraphSelectionModel(this);
  		};
  		mxGraph.prototype.createStylesheet = function()
  		{
  			return new mxStylesheet();
  		};
  		mxGraph.prototype.createGraphView = function()
  		{
  			return new mxGraphView(this);
  		};
  		mxGraph.prototype.createCellRenderer = function()
  		{
  			return new mxCellRenderer();
  		};
  		mxGraph.prototype.createCellEditor = function()
  		{
  			return new mxCellEditor(this);
  		};
  		mxGraph.prototype.getModel = function()
  		{
  			return this.model;
  		};
  		mxGraph.prototype.getView = function()
  		{
  			return this.view;
  		};
  		mxGraph.prototype.getStylesheet = function()
  		{
  			return this.stylesheet;
  		};
  		mxGraph.prototype.setStylesheet = function(stylesheet)
  		{
  			this.stylesheet = stylesheet;
  		};
  		mxGraph.prototype.getSelectionModel = function()
  		{
  			return this.selectionModel;
  		};
  		mxGraph.prototype.setSelectionModel = function(selectionModel)
  		{
  			this.selectionModel = selectionModel;
  		};
  		mxGraph.prototype.getSelectionCellsForChanges = function(changes, ignoreFn)
  		{
  			var dict = new mxDictionary();
  			var cells = [];
  			var addCell = mxUtils.bind(this, function(cell)
  			{
  				if (!dict.get(cell) && this.model.contains(cell))
  				{
  					if (this.model.isEdge(cell) || this.model.isVertex(cell))
  					{
  						dict.put(cell, true);
  						cells.push(cell);
  					}
  					else
  					{
  						var childCount = this.model.getChildCount(cell);
  						for (var i = 0; i < childCount; i++)
  						{
  							addCell(this.model.getChildAt(cell, i));
  						}
  					}
  				}
  			});
  			for (var i = 0; i < changes.length; i++)
  			{
  				var change = changes[i];
  				if (change.constructor != mxRootChange &&
  					(ignoreFn == null || !ignoreFn(change)))
  				{
  					var cell = null;
  					if (change instanceof mxChildChange)
  					{
  						cell = change.child;
  					}
  					else if (change.cell != null &&
  						change.cell instanceof mxCell)
  					{
  						cell = change.cell;
  					}
  					if (cell != null)
  					{
  						addCell(cell);
  					}
  				}
  			}
  			return cells;
  		};
  		mxGraph.prototype.graphModelChanged = function(changes)
  		{
  			for (var i = 0; i < changes.length; i++)
  			{
  				this.processChange(changes[i]);
  			}
  			this.updateSelection();
  			this.view.validate();
  			this.sizeDidChange();
  		};
  		mxGraph.prototype.updateSelection = function()
  		{
  			var cells = this.getSelectionCells();
  			var removed = [];
  			for (var i = 0; i < cells.length; i++)
  			{
  				if (!this.model.contains(cells[i]) || !this.isCellVisible(cells[i]))
  				{
  					removed.push(cells[i]);
  				}
  				else
  				{
  					var par = this.model.getParent(cells[i]);
  					while (par != null && par != this.view.currentRoot)
  					{
  						if (this.isCellCollapsed(par) || !this.isCellVisible(par))
  						{
  							removed.push(cells[i]);
  							break;
  						}
  						par = this.model.getParent(par);
  					}
  				}
  			}
  			this.removeSelectionCells(removed);
  		};
  		mxGraph.prototype.processChange = function(change)
  		{
  			if (change instanceof mxRootChange)
  			{
  				this.clearSelection();
  				this.setDefaultParent(null);
  				this.removeStateForCell(change.previous);
  				if (this.resetViewOnRootChange)
  				{
  					this.view.scale = 1;
  					this.view.translate.x = 0;
  					this.view.translate.y = 0;
  				}
  				this.fireEvent(new mxEventObject(mxEvent.ROOT));
  			}
  			else if (change instanceof mxChildChange)
  			{
  				var newParent = this.model.getParent(change.child);
  				this.view.invalidate(change.child, true, true);
  				if (!this.model.contains(newParent) || this.isCellCollapsed(newParent))
  				{
  					this.view.invalidate(change.child, true, true);
  					this.removeStateForCell(change.child);
  					if (this.view.currentRoot == change.child)
  					{
  						this.home();
  					}
  				}
  				if (newParent != change.previous)
  				{
  					if (newParent != null)
  					{
  						this.view.invalidate(newParent, false, false);
  					}
  					if (change.previous != null)
  					{
  						this.view.invalidate(change.previous, false, false);
  					}
  				}
  			}
  			else if (change instanceof mxTerminalChange || change instanceof mxGeometryChange)
  			{
  				if (change instanceof mxTerminalChange || ((change.previous == null && change.geometry != null) ||
  					(change.previous != null && !change.previous.equals(change.geometry))))
  				{
  					this.view.invalidate(change.cell);
  				}
  			}
  			else if (change instanceof mxValueChange)
  			{
  				this.view.invalidate(change.cell, false, false);
  			}
  			else if (change instanceof mxStyleChange)
  			{
  				this.view.invalidate(change.cell, true, true);
  				var state = this.view.getState(change.cell);
  				if (state != null)
  				{
  					state.invalidStyle = true;
  				}
  			}
  			else if (change.cell != null && change.cell instanceof mxCell)
  			{
  				this.removeStateForCell(change.cell);
  			}
  		};
  		mxGraph.prototype.removeStateForCell = function(cell)
  		{
  			var childCount = this.model.getChildCount(cell);
  			for (var i = 0; i < childCount; i++)
  			{
  				this.removeStateForCell(this.model.getChildAt(cell, i));
  			}
  			this.view.invalidate(cell, false, true);
  			this.view.removeState(cell);
  		};
  		mxGraph.prototype.addCellOverlay = function(cell, overlay)
  		{
  			if (cell.overlays == null)
  			{
  				cell.overlays = [];
  			}
  			cell.overlays.push(overlay);
  			var state = this.view.getState(cell);
  			if (state != null)
  			{
  				this.cellRenderer.redraw(state);
  			}
  			this.fireEvent(new mxEventObject(mxEvent.ADD_OVERLAY,
  					'cell', cell, 'overlay', overlay));
  			return overlay;
  		};
  		mxGraph.prototype.getCellOverlays = function(cell)
  		{
  			return cell.overlays;
  		};
  		mxGraph.prototype.removeCellOverlay = function(cell, overlay)
  		{
  			if (overlay == null)
  			{
  				this.removeCellOverlays(cell);
  			}
  			else
  			{
  				var index = mxUtils.indexOf(cell.overlays, overlay);
  				if (index >= 0)
  				{
  					cell.overlays.splice(index, 1);
  					if (cell.overlays.length == 0)
  					{
  						cell.overlays = null;
  					}
  					var state = this.view.getState(cell);
  					if (state != null)
  					{
  						this.cellRenderer.redraw(state);
  					}
  					this.fireEvent(new mxEventObject(mxEvent.REMOVE_OVERLAY,
  							'cell', cell, 'overlay', overlay));
  				}
  				else
  				{
  					overlay = null;
  				}
  			}
  			return overlay;
  		};
  		mxGraph.prototype.removeCellOverlays = function(cell)
  		{
  			var overlays = cell.overlays;
  			if (overlays != null)
  			{
  				cell.overlays = null;
  				var state = this.view.getState(cell);
  				if (state != null)
  				{
  					this.cellRenderer.redraw(state);
  				}
  				for (var i = 0; i < overlays.length; i++)
  				{
  					this.fireEvent(new mxEventObject(mxEvent.REMOVE_OVERLAY,
  							'cell', cell, 'overlay', overlays[i]));
  				}
  			}
  			return overlays;
  		};
  		mxGraph.prototype.clearCellOverlays = function(cell)
  		{
  			cell = (cell != null) ? cell : this.model.getRoot();
  			this.removeCellOverlays(cell);
  			var childCount = this.model.getChildCount(cell);
  			for (var i = 0; i < childCount; i++)
  			{
  				var child = this.model.getChildAt(cell, i);
  				this.clearCellOverlays(child);
  			}
  		};
  		mxGraph.prototype.setCellWarning = function(cell, warning, img, isSelect)
  		{
  			if (warning != null && warning.length > 0)
  			{
  				img = (img != null) ? img : this.warningImage;
  				var overlay = new mxCellOverlay(img,
  					'<font color=red>'+warning+'</font>');
  				if (isSelect)
  				{
  					overlay.addListener(mxEvent.CLICK,
  						mxUtils.bind(this, function(sender, evt)
  						{
  							if (this.isEnabled())
  							{
  								this.setSelectionCell(cell);
  							}
  						})
  					);
  				}
  				return this.addCellOverlay(cell, overlay);
  			}
  			else
  			{
  				this.removeCellOverlays(cell);
  			}
  			return null;
  		};
  		mxGraph.prototype.startEditing = function(evt)
  		{
  			this.startEditingAtCell(null, evt);
  		};
  		mxGraph.prototype.startEditingAtCell = function(cell, evt)
  		{
  			if (evt == null || !mxEvent.isMultiTouchEvent(evt))
  			{
  				if (cell == null)
  				{
  					cell = this.getSelectionCell();
  					if (cell != null && !this.isCellEditable(cell))
  					{
  						cell = null;
  					}
  				}
  				if (cell != null)
  				{
  					this.fireEvent(new mxEventObject(mxEvent.START_EDITING,
  							'cell', cell, 'event', evt));
  					this.cellEditor.startEditing(cell, evt);
  					this.fireEvent(new mxEventObject(mxEvent.EDITING_STARTED,
  							'cell', cell, 'event', evt));
  				}
  			}
  		};
  		mxGraph.prototype.getEditingValue = function(cell, evt)
  		{
  			return this.convertValueToString(cell);
  		};
  		mxGraph.prototype.stopEditing = function(cancel)
  		{
  			this.cellEditor.stopEditing(cancel);
  			this.fireEvent(new mxEventObject(mxEvent.EDITING_STOPPED, 'cancel', cancel));
  		};
  		mxGraph.prototype.labelChanged = function(cell, value, evt)
  		{
  			this.model.beginUpdate();
  			try
  			{
  				var old = cell.value;
  				this.cellLabelChanged(cell, value, this.isAutoSizeCell(cell));
  				this.fireEvent(new mxEventObject(mxEvent.LABEL_CHANGED,
  					'cell', cell, 'value', value, 'old', old, 'event', evt));
  			}
  			finally
  			{
  				this.model.endUpdate();
  			}
  			return cell;
  		};
  		mxGraph.prototype.cellLabelChanged = function(cell, value, autoSize)
  		{
  			this.model.beginUpdate();
  			try
  			{
  				this.model.setValue(cell, value);
  				if (autoSize)
  				{
  					this.cellSizeUpdated(cell, false);
  				}
  			}
  			finally
  			{
  				this.model.endUpdate();
  			}
  		};
  		mxGraph.prototype.escape = function(evt)
  		{
  			this.fireEvent(new mxEventObject(mxEvent.ESCAPE, 'event', evt));
  		};
  		mxGraph.prototype.click = function(me)
  		{
  			var evt = me.getEvent();
  			var cell = me.getCell();
  			var mxe = new mxEventObject(mxEvent.CLICK, 'event', evt, 'cell', cell);
  			if (me.isConsumed())
  			{
  				mxe.consume();
  			}
  			this.fireEvent(mxe);
  			if (this.isEnabled() && !mxEvent.isConsumed(evt) && !mxe.isConsumed())
  			{
  				if (cell != null)
  				{
  					if (this.isTransparentClickEvent(evt))
  					{
  						var active = false;
  						var tmp = this.getCellAt(me.graphX, me.graphY, null, null, null,
  							mxUtils.bind(this, function(state)
  						{
  							var selected = this.isCellSelected(state.cell);
  							active = active || selected;
  							return !active || selected || (state.cell != cell &&
  								this.model.isAncestor(state.cell, cell));
  						}));
  						if (tmp != null)
  						{
  							cell = tmp;
  						}
  					}
  				}
  				else if (this.isSwimlaneSelectionEnabled())
  				{
  					cell = this.getSwimlaneAt(me.getGraphX(), me.getGraphY());
  					if (cell != null && (!this.isToggleEvent(evt) ||
  						!mxEvent.isAltDown(evt)))
  					{
  						var temp = cell;
  						var swimlanes = [];
  						while (temp != null)
  						{
  							temp = this.model.getParent(temp);
  							var state = this.view.getState(temp);
  							if (this.isSwimlane(temp) && state != null)
  							{
  								swimlanes.push(temp);
  							}
  						}
  						if (swimlanes.length > 0)
  						{
  							swimlanes = swimlanes.reverse();
  							swimlanes.splice(0, 0, cell);
  							swimlanes.push(cell);
  							for (var i = 0; i < swimlanes.length - 1; i++)
  							{
  								if (this.isCellSelected(swimlanes[i]))
  								{
  									cell = swimlanes[(this.isToggleEvent(evt)) ?
  										i : i + 1];
  								}
  							}
  						}
  					}
  				}
  				if (cell != null)
  				{
  					this.selectCellForEvent(cell, evt);
  				}
  				else if (!this.isToggleEvent(evt))
  				{
  					this.clearSelection();
  				}
  			}
  		};
  		mxGraph.prototype.isSiblingSelected = function(cell)
  		{
  			var model = this.model;
  			var parent = model.getParent(cell);
  			var childCount = model.getChildCount(parent);
  			for (var i = 0; i < childCount; i++)
  			{
  				var child = model.getChildAt(parent, i);
  				if (cell != child && this.isCellSelected(child))
  				{
  					return true;
  				}
  			}
  			return false;
  		};
  		mxGraph.prototype.dblClick = function(evt, cell)
  		{
  			var mxe = new mxEventObject(mxEvent.DOUBLE_CLICK, 'event', evt, 'cell', cell);
  			this.fireEvent(mxe);
  			if (this.isEnabled() && !mxEvent.isConsumed(evt) && !mxe.isConsumed() &&
  				cell != null && this.isCellEditable(cell) && !this.isEditing(cell))
  			{
  				this.startEditingAtCell(cell, evt);
  				mxEvent.consume(evt);
  			}
  		};
  		mxGraph.prototype.tapAndHold = function(me)
  		{
  			var evt = me.getEvent();
  			var mxe = new mxEventObject(mxEvent.TAP_AND_HOLD, 'event', evt, 'cell', me.getCell());
  			this.fireEvent(mxe);
  			if (mxe.isConsumed())
  			{
  				this.panningHandler.panningTrigger = false;
  			}
  			if (this.isEnabled() && !mxEvent.isConsumed(evt) && !mxe.isConsumed() && this.connectionHandler.isEnabled())
  			{
  				var state = this.view.getState(this.connectionHandler.marker.getCell(me));
  				if (state != null)
  				{
  					this.connectionHandler.marker.currentColor = this.connectionHandler.marker.validColor;
  					this.connectionHandler.marker.markedState = state;
  					this.connectionHandler.marker.mark();
  					this.connectionHandler.first = new mxPoint(me.getGraphX(), me.getGraphY());
  					this.connectionHandler.edgeState = this.connectionHandler.createEdgeState(me);
  					this.connectionHandler.previous = state;
  					this.connectionHandler.fireEvent(new mxEventObject(mxEvent.START, 'state', this.connectionHandler.previous));
  				}
  			}
  		};
  		mxGraph.prototype.scrollPointToVisible = function(x, y, extend, border)
  		{
  			if (!this.timerAutoScroll && (this.ignoreScrollbars || mxUtils.hasScrollbars(this.container)))
  			{
  				var c = this.container;
  				border = (border != null) ? border : 20;
  				if (x >= c.scrollLeft && y >= c.scrollTop && x <= c.scrollLeft + c.clientWidth &&
  					y <= c.scrollTop + c.clientHeight)
  				{
  					var dx = c.scrollLeft + c.clientWidth - x;
  					if (dx < border)
  					{
  						var old = c.scrollLeft;
  						c.scrollLeft += border - dx;
  						if (extend && old == c.scrollLeft)
  						{
  							if (this.dialect == mxConstants.DIALECT_SVG)
  							{
  								var root = this.view.getDrawPane().ownerSVGElement;
  								var width = this.container.scrollWidth + border - dx;
  								root.style.width = width + 'px';
  							}
  							else
  							{
  								var width = Math.max(c.clientWidth, c.scrollWidth) + border - dx;
  								var canvas = this.view.getCanvas();
  								canvas.style.width = width + 'px';
  							}
  							c.scrollLeft += border - dx;
  						}
  					}
  					else
  					{
  						dx = x - c.scrollLeft;
  						if (dx < border)
  						{
  							c.scrollLeft -= border - dx;
  						}
  					}
  					var dy = c.scrollTop + c.clientHeight - y;
  					if (dy < border)
  					{
  						var old = c.scrollTop;
  						c.scrollTop += border - dy;
  						if (old == c.scrollTop && extend)
  						{
  							if (this.dialect == mxConstants.DIALECT_SVG)
  							{
  								var root = this.view.getDrawPane().ownerSVGElement;
  								var height = this.container.scrollHeight + border - dy;
  								root.style.height = height + 'px';
  							}
  							else
  							{
  								var height = Math.max(c.clientHeight, c.scrollHeight) + border - dy;
  								var canvas = this.view.getCanvas();
  								canvas.style.height = height + 'px';
  							}
  							c.scrollTop += border - dy;
  						}
  					}
  					else
  					{
  						dy = y - c.scrollTop;
  						if (dy < border)
  						{
  							c.scrollTop -= border - dy;
  						}
  					}
  				}
  			}
  			else if (this.allowAutoPanning && !this.panningHandler.isActive())
  			{
  				if (this.panningManager == null)
  				{
  					this.panningManager = this.createPanningManager();
  				}
  				this.panningManager.panTo(x + this.panDx, y + this.panDy);
  			}
  		};
  		mxGraph.prototype.createPanningManager = function()
  		{
  			return new mxPanningManager(this);
  		};
  		mxGraph.prototype.getBorderSizes = function()
  		{
  			var css = mxUtils.getCurrentStyle(this.container);
  			return new mxRectangle(mxUtils.parseCssNumber(css.paddingLeft) +
  					((css.borderLeftStyle != 'none') ? mxUtils.parseCssNumber(css.borderLeftWidth) : 0),
  				mxUtils.parseCssNumber(css.paddingTop) +
  					((css.borderTopStyle != 'none') ? mxUtils.parseCssNumber(css.borderTopWidth) : 0),
  				mxUtils.parseCssNumber(css.paddingRight) +
  					((css.borderRightStyle != 'none') ? mxUtils.parseCssNumber(css.borderRightWidth) : 0),
  				mxUtils.parseCssNumber(css.paddingBottom) +
  					((css.borderBottomStyle != 'none') ? mxUtils.parseCssNumber(css.borderBottomWidth) : 0));
  		};
  		mxGraph.prototype.getPreferredPageSize = function(bounds, width, height)
  		{
  			this.view.scale;
  			var tr = this.view.translate;
  			var fmt = this.pageFormat;
  			var ps = this.pageScale;
  			var page = new mxRectangle(0, 0, Math.ceil(fmt.width * ps), Math.ceil(fmt.height * ps));
  			var hCount = (this.pageBreaksVisible) ? Math.ceil(width / page.width) : 1;
  			var vCount = (this.pageBreaksVisible) ? Math.ceil(height / page.height) : 1;
  			return new mxRectangle(0, 0, hCount * page.width + 2 + tr.x, vCount * page.height + 2 + tr.y);
  		};
  		mxGraph.prototype.fit = function(border, keepOrigin, margin, enabled, ignoreWidth, ignoreHeight, maxHeight)
  		{
  			if (this.container != null)
  			{
  				border = (border != null) ? border : this.getBorder();
  				keepOrigin = (keepOrigin != null) ? keepOrigin : false;
  				margin = (margin != null) ? margin : 0;
  				enabled = (enabled != null) ? enabled : true;
  				ignoreWidth = (ignoreWidth != null) ? ignoreWidth : false;
  				ignoreHeight = (ignoreHeight != null) ? ignoreHeight : false;
  				var cssBorder = this.getBorderSizes();
  				var w1 = this.container.offsetWidth - cssBorder.x - cssBorder.width - 1;
  				var h1 = (maxHeight != null) ? maxHeight : this.container.offsetHeight - cssBorder.y - cssBorder.height - 1;
  				var bounds = this.view.getGraphBounds();
  				if (bounds.width > 0 && bounds.height > 0)
  				{
  					if (keepOrigin && bounds.x != null && bounds.y != null)
  					{
  						bounds = bounds.clone();
  						bounds.width += bounds.x;
  						bounds.height += bounds.y;
  						bounds.x = 0;
  						bounds.y = 0;
  					}
  					var s = this.view.scale;
  					var w2 = bounds.width / s;
  					var h2 = bounds.height / s;
  					if (this.backgroundImage != null)
  					{
  						w2 = Math.max(w2, this.backgroundImage.width - bounds.x / s);
  						h2 = Math.max(h2, this.backgroundImage.height - bounds.y / s);
  					}
  					var b = ((keepOrigin) ? border : 2 * border) + margin + 1;
  					w1 -= b;
  					h1 -= b;
  					var s2 = (((ignoreWidth) ? h1 / h2 : (ignoreHeight) ? w1 / w2 :
  						Math.min(w1 / w2, h1 / h2)));
  					if (this.minFitScale != null)
  					{
  						s2 = Math.max(s2, this.minFitScale);
  					}
  					if (this.maxFitScale != null)
  					{
  						s2 = Math.min(s2, this.maxFitScale);
  					}
  					if (enabled)
  					{
  						if (!keepOrigin)
  						{
  							if (!mxUtils.hasScrollbars(this.container))
  							{
  								var x0 = (bounds.x != null) ? Math.floor(this.view.translate.x - bounds.x / s + border / s2 + margin / 2) : border;
  								var y0 = (bounds.y != null) ? Math.floor(this.view.translate.y - bounds.y / s + border / s2 + margin / 2) : border;
  								this.view.scaleAndTranslate(s2, x0, y0);
  							}
  							else
  							{
  								this.view.setScale(s2);
  								var b2 = this.getGraphBounds();
  								if (b2.x != null)
  								{
  									this.container.scrollLeft = b2.x;
  								}
  								if (b2.y != null)
  								{
  									this.container.scrollTop = b2.y;
  								}
  							}
  						}
  						else if (this.view.scale != s2)
  						{
  							this.view.setScale(s2);
  						}
  					}
  					else
  					{
  						return s2;
  					}
  				}
  			}
  			return this.view.scale;
  		};
  		mxGraph.prototype.sizeDidChange = function()
  		{
  			var bounds = this.getGraphBounds();
  			if (this.container != null)
  			{
  				var border = this.getBorder();
  				var width = Math.max(0, bounds.x) + bounds.width + 2 * border;
  				var height = Math.max(0, bounds.y) + bounds.height + 2 * border;
  				if (this.minimumContainerSize != null)
  				{
  					width = Math.max(width, this.minimumContainerSize.width);
  					height = Math.max(height, this.minimumContainerSize.height);
  				}
  				if (this.resizeContainer)
  				{
  					this.doResizeContainer(width, height);
  				}
  				if (this.preferPageSize || (!mxClient.IS_IE && this.pageVisible))
  				{
  					var size = this.getPreferredPageSize(bounds, Math.max(1, width), Math.max(1, height));
  					if (size != null)
  					{
  						width = size.width * this.view.scale;
  						height = size.height * this.view.scale;
  					}
  				}
  				if (this.minimumGraphSize != null)
  				{
  					width = Math.max(width, this.minimumGraphSize.width * this.view.scale);
  					height = Math.max(height, this.minimumGraphSize.height * this.view.scale);
  				}
  				width = Math.ceil(width);
  				height = Math.ceil(height);
  				if (this.dialect == mxConstants.DIALECT_SVG)
  				{
  					var root = this.view.getDrawPane().ownerSVGElement;
  					if (root != null)
  					{
  						root.style.minWidth = Math.max(1, width) + 'px';
  						root.style.minHeight = Math.max(1, height) + 'px';
  						root.style.width = '100%';
  						root.style.height = '100%';
  					}
  				}
  				else
  				{
  					if (mxClient.IS_QUIRKS)
  					{
  						this.view.updateHtmlCanvasSize(Math.max(1, width), Math.max(1, height));
  					}
  					else
  					{
  						this.view.canvas.style.minWidth = Math.max(1, width) + 'px';
  						this.view.canvas.style.minHeight = Math.max(1, height) + 'px';
  					}
  				}
  				this.updatePageBreaks(this.pageBreaksVisible, width, height);
  			}
  			this.fireEvent(new mxEventObject(mxEvent.SIZE, 'bounds', bounds));
  		};
  		mxGraph.prototype.doResizeContainer = function(width, height)
  		{
  			if (this.maximumContainerSize != null)
  			{
  				width = Math.min(this.maximumContainerSize.width, width);
  				height = Math.min(this.maximumContainerSize.height, height);
  			}
  			this.container.style.width = Math.ceil(width) + 'px';
  			this.container.style.height = Math.ceil(height) + 'px';
  		};
  		mxGraph.prototype.updatePageBreaks = function(visible, width, height)
  		{
  			var scale = this.view.scale;
  			var tr = this.view.translate;
  			var fmt = this.pageFormat;
  			var ps = scale * this.pageScale;
  			var bounds = new mxRectangle(0, 0, fmt.width * ps, fmt.height * ps);
  			var gb = mxRectangle.fromRectangle(this.getGraphBounds());
  			gb.width = Math.max(1, gb.width);
  			gb.height = Math.max(1, gb.height);
  			bounds.x = Math.floor((gb.x - tr.x * scale) / bounds.width) * bounds.width + tr.x * scale;
  			bounds.y = Math.floor((gb.y - tr.y * scale) / bounds.height) * bounds.height + tr.y * scale;
  			gb.width = Math.ceil((gb.width + (gb.x - bounds.x)) / bounds.width) * bounds.width;
  			gb.height = Math.ceil((gb.height + (gb.y - bounds.y)) / bounds.height) * bounds.height;
  			visible = visible && Math.min(bounds.width, bounds.height) > this.minPageBreakDist;
  			var horizontalCount = (visible) ? Math.ceil(gb.height / bounds.height) + 1 : 0;
  			var verticalCount = (visible) ? Math.ceil(gb.width / bounds.width) + 1 : 0;
  			var right = (verticalCount - 1) * bounds.width;
  			var bottom = (horizontalCount - 1) * bounds.height;
  			if (this.horizontalPageBreaks == null && horizontalCount > 0)
  			{
  				this.horizontalPageBreaks = [];
  			}
  			if (this.verticalPageBreaks == null && verticalCount > 0)
  			{
  				this.verticalPageBreaks = [];
  			}
  			var drawPageBreaks = mxUtils.bind(this, function(breaks)
  			{
  				if (breaks != null)
  				{
  					var count = (breaks == this.horizontalPageBreaks) ? horizontalCount : verticalCount;
  					for (var i = 0; i <= count; i++)
  					{
  						var pts = (breaks == this.horizontalPageBreaks) ?
  							[new mxPoint(Math.round(bounds.x), Math.round(bounds.y + i * bounds.height)),
  					         new mxPoint(Math.round(bounds.x + right), Math.round(bounds.y + i * bounds.height))] :
  					        [new mxPoint(Math.round(bounds.x + i * bounds.width), Math.round(bounds.y)),
  					         new mxPoint(Math.round(bounds.x + i * bounds.width), Math.round(bounds.y + bottom))];
  						if (breaks[i] != null)
  						{
  							breaks[i].points = pts;
  							breaks[i].redraw();
  						}
  						else
  						{
  							var pageBreak = new mxPolyline(pts, this.pageBreakColor);
  							pageBreak.dialect = this.dialect;
  							pageBreak.pointerEvents = false;
  							pageBreak.isDashed = this.pageBreakDashed;
  							pageBreak.init(this.view.backgroundPane);
  							pageBreak.redraw();
  							breaks[i] = pageBreak;
  						}
  					}
  					for (var i = count; i < breaks.length; i++)
  					{
  						breaks[i].destroy();
  					}
  					breaks.splice(count, breaks.length - count);
  				}
  			});
  			drawPageBreaks(this.horizontalPageBreaks);
  			drawPageBreaks(this.verticalPageBreaks);
  		};
  		mxGraph.prototype.getCurrentCellStyle = function(cell, ignoreState)
  		{
  			var state = (ignoreState) ? null : this.view.getState(cell);
  			return (state != null) ? state.style : this.getCellStyle(cell);
  		};
  		mxGraph.prototype.getCellStyle = function(cell)
  		{
  			var stylename = this.model.getStyle(cell);
  			var style = null;
  			if (this.model.isEdge(cell))
  			{
  				style = this.stylesheet.getDefaultEdgeStyle();
  			}
  			else
  			{
  				style = this.stylesheet.getDefaultVertexStyle();
  			}
  			if (stylename != null)
  			{
  				style = this.postProcessCellStyle(this.stylesheet.getCellStyle(stylename, style));
  			}
  			if (style == null)
  			{
  				style = new Object();
  			}
  			return style;
  		};
  		mxGraph.prototype.postProcessCellStyle = function(style)
  		{
  			if (style != null)
  			{
  				var key = style[mxConstants.STYLE_IMAGE];
  				var image = this.getImageFromBundles(key);
  				if (image != null)
  				{
  					style[mxConstants.STYLE_IMAGE] = image;
  				}
  				else
  				{
  					image = key;
  				}
  				if (image != null && image.substring(0, 11) == 'data:image/')
  				{
  					if (image.substring(0, 20) == 'data:image/svg+xml,<')
  					{
  						image = image.substring(0, 19) + encodeURIComponent(image.substring(19));
  					}
  					else if (image.substring(0, 22) != 'data:image/svg+xml,%3C')
  					{
  						var comma = image.indexOf(',');
  						if (comma > 0 && image.substring(comma - 7, comma + 1) != ';base64,')
  						{
  							image = image.substring(0, comma) + ';base64,'
  								+ image.substring(comma + 1);
  						}
  					}
  					style[mxConstants.STYLE_IMAGE] = image;
  				}
  			}
  			return style;
  		};
  		mxGraph.prototype.setCellStyle = function(style, cells)
  		{
  			cells = cells || this.getSelectionCells();
  			if (cells != null)
  			{
  				this.model.beginUpdate();
  				try
  				{
  					for (var i = 0; i < cells.length; i++)
  					{
  						this.model.setStyle(cells[i], style);
  					}
  				}
  				finally
  				{
  					this.model.endUpdate();
  				}
  			}
  		};
  		mxGraph.prototype.toggleCellStyle = function(key, defaultValue, cell)
  		{
  			cell = cell || this.getSelectionCell();
  			return this.toggleCellStyles(key, defaultValue, [cell]);
  		};
  		mxGraph.prototype.toggleCellStyles = function(key, defaultValue, cells)
  		{
  			defaultValue = (defaultValue != null) ? defaultValue : false;
  			cells = cells || this.getSelectionCells();
  			var value = null;
  			if (cells != null && cells.length > 0)
  			{
  				var style = this.getCurrentCellStyle(cells[0]);
  				value = (mxUtils.getValue(style, key, defaultValue)) ? 0 : 1;
  				this.setCellStyles(key, value, cells);
  			}
  			return value;
  		};
  		mxGraph.prototype.setCellStyles = function(key, value, cells)
  		{
  			cells = cells || this.getSelectionCells();
  			mxUtils.setCellStyles(this.model, cells, key, value);
  		};
  		mxGraph.prototype.toggleCellStyleFlags = function(key, flag, cells)
  		{
  			this.setCellStyleFlags(key, flag, null, cells);
  		};
  		mxGraph.prototype.setCellStyleFlags = function(key, flag, value, cells)
  		{
  			cells = cells || this.getSelectionCells();
  			if (cells != null && cells.length > 0)
  			{
  				if (value == null)
  				{
  					var style = this.getCurrentCellStyle(cells[0]);
  					var current = parseInt(style[key] || 0);
  					value = !((current & flag) == flag);
  				}
  				mxUtils.setCellStyleFlags(this.model, cells, key, flag, value);
  			}
  		};
  		mxGraph.prototype.alignCells = function(align, cells, param)
  		{
  			if (cells == null)
  			{
  				cells = this.getSelectionCells();
  			}
  			if (cells != null && cells.length > 1)
  			{
  				if (param == null)
  				{
  					for (var i = 0; i < cells.length; i++)
  					{
  						var state = this.view.getState(cells[i]);
  						if (state != null && !this.model.isEdge(cells[i]))
  						{
  							if (param == null)
  							{
  								if (align == mxConstants.ALIGN_CENTER)
  								{
  									param = state.x + state.width / 2;
  									break;
  								}
  								else if (align == mxConstants.ALIGN_RIGHT)
  								{
  									param = state.x + state.width;
  								}
  								else if (align == mxConstants.ALIGN_TOP)
  								{
  									param = state.y;
  								}
  								else if (align == mxConstants.ALIGN_MIDDLE)
  								{
  									param = state.y + state.height / 2;
  									break;
  								}
  								else if (align == mxConstants.ALIGN_BOTTOM)
  								{
  									param = state.y + state.height;
  								}
  								else
  								{
  									param = state.x;
  								}
  							}
  							else
  							{
  								if (align == mxConstants.ALIGN_RIGHT)
  								{
  									param = Math.max(param, state.x + state.width);
  								}
  								else if (align == mxConstants.ALIGN_TOP)
  								{
  									param = Math.min(param, state.y);
  								}
  								else if (align == mxConstants.ALIGN_BOTTOM)
  								{
  									param = Math.max(param, state.y + state.height);
  								}
  								else
  								{
  									param = Math.min(param, state.x);
  								}
  							}
  						}
  					}
  				}
  				if (param != null)
  				{
  					var s = this.view.scale;
  					this.model.beginUpdate();
  					try
  					{
  						for (var i = 0; i < cells.length; i++)
  						{
  							var state = this.view.getState(cells[i]);
  							if (state != null)
  							{
  								var geo = this.getCellGeometry(cells[i]);
  								if (geo != null && !this.model.isEdge(cells[i]))
  								{
  									geo = geo.clone();
  									if (align == mxConstants.ALIGN_CENTER)
  									{
  										geo.x += (param - state.x - state.width / 2) / s;
  									}
  									else if (align == mxConstants.ALIGN_RIGHT)
  									{
  										geo.x += (param - state.x - state.width) / s;
  									}
  									else if (align == mxConstants.ALIGN_TOP)
  									{
  										geo.y += (param - state.y) / s;
  									}
  									else if (align == mxConstants.ALIGN_MIDDLE)
  									{
  										geo.y += (param - state.y - state.height / 2) / s;
  									}
  									else if (align == mxConstants.ALIGN_BOTTOM)
  									{
  										geo.y += (param - state.y - state.height) / s;
  									}
  									else
  									{
  										geo.x += (param - state.x) / s;
  									}
  									this.resizeCell(cells[i], geo);
  								}
  							}
  						}
  						this.fireEvent(new mxEventObject(mxEvent.ALIGN_CELLS,
  								'align', align, 'cells', cells));
  					}
  					finally
  					{
  						this.model.endUpdate();
  					}
  				}
  			}
  			return cells;
  		};
  		mxGraph.prototype.flipEdge = function(edge)
  		{
  			if (edge != null &&
  				this.alternateEdgeStyle != null)
  			{
  				this.model.beginUpdate();
  				try
  				{
  					var style = this.model.getStyle(edge);
  					if (style == null || style.length == 0)
  					{
  						this.model.setStyle(edge, this.alternateEdgeStyle);
  					}
  					else
  					{
  						this.model.setStyle(edge, null);
  					}
  					this.resetEdge(edge);
  					this.fireEvent(new mxEventObject(mxEvent.FLIP_EDGE, 'edge', edge));
  				}
  				finally
  				{
  					this.model.endUpdate();
  				}
  			}
  			return edge;
  		};
  		mxGraph.prototype.addImageBundle = function(bundle)
  		{
  			this.imageBundles.push(bundle);
  		};
  		mxGraph.prototype.removeImageBundle = function(bundle)
  		{
  			var tmp = [];
  			for (var i = 0; i < this.imageBundles.length; i++)
  			{
  				if (this.imageBundles[i] != bundle)
  				{
  					tmp.push(this.imageBundles[i]);
  				}
  			}
  			this.imageBundles = tmp;
  		};
  		mxGraph.prototype.getImageFromBundles = function(key)
  		{
  			if (key != null)
  			{
  				for (var i = 0; i < this.imageBundles.length; i++)
  				{
  					var image = this.imageBundles[i].getImage(key);
  					if (image != null)
  					{
  						return image;
  					}
  				}
  			}
  			return null;
  		};
  		mxGraph.prototype.orderCells = function(back, cells)
  		{
  			if (cells == null)
  			{
  				cells = mxUtils.sortCells(this.getSelectionCells(), true);
  			}
  			this.model.beginUpdate();
  			try
  			{
  				this.cellsOrdered(cells, back);
  				this.fireEvent(new mxEventObject(mxEvent.ORDER_CELLS,
  						'back', back, 'cells', cells));
  			}
  			finally
  			{
  				this.model.endUpdate();
  			}
  			return cells;
  		};
  		mxGraph.prototype.cellsOrdered = function(cells, back)
  		{
  			if (cells != null)
  			{
  				this.model.beginUpdate();
  				try
  				{
  					for (var i = 0; i < cells.length; i++)
  					{
  						var parent = this.model.getParent(cells[i]);
  						if (back)
  						{
  							this.model.add(parent, cells[i], i);
  						}
  						else
  						{
  							this.model.add(parent, cells[i],
  									this.model.getChildCount(parent) - 1);
  						}
  					}
  					this.fireEvent(new mxEventObject(mxEvent.CELLS_ORDERED,
  							'back', back, 'cells', cells));
  				}
  				finally
  				{
  					this.model.endUpdate();
  				}
  			}
  		};
  		mxGraph.prototype.groupCells = function(group, border, cells)
  		{
  			if (cells == null)
  			{
  				cells = mxUtils.sortCells(this.getSelectionCells(), true);
  			}
  			cells = this.getCellsForGroup(cells);
  			if (group == null)
  			{
  				group = this.createGroupCell(cells);
  			}
  			var bounds = this.getBoundsForGroup(group, cells, border);
  			if (cells.length > 1 && bounds != null)
  			{
  				var parent = this.model.getParent(group);
  				if (parent == null)
  				{
  					parent = this.model.getParent(cells[0]);
  				}
  				this.model.beginUpdate();
  				try
  				{
  					if (this.getCellGeometry(group) == null)
  					{
  						this.model.setGeometry(group, new mxGeometry());
  					}
  					var index = this.model.getChildCount(parent);
  					this.cellsAdded([group], parent, index, null, null, false, false, false);
  					index = this.model.getChildCount(group);
  					this.cellsAdded(cells, group, index, null, null, false, false, false);
  					this.cellsMoved(cells, -bounds.x, -bounds.y, false, false, false);
  					this.cellsResized([group], [bounds], false);
  					this.fireEvent(new mxEventObject(mxEvent.GROUP_CELLS,
  							'group', group, 'border', border, 'cells', cells));
  				}
  				finally
  				{
  					this.model.endUpdate();
  				}
  			}
  			return group;
  		};
  		mxGraph.prototype.getCellsForGroup = function(cells)
  		{
  			var result = [];
  			if (cells != null && cells.length > 0)
  			{
  				var parent = this.model.getParent(cells[0]);
  				result.push(cells[0]);
  				for (var i = 1; i < cells.length; i++)
  				{
  					if (this.model.getParent(cells[i]) == parent)
  					{
  						result.push(cells[i]);
  					}
  				}
  			}
  			return result;
  		};
  		mxGraph.prototype.getBoundsForGroup = function(group, children, border)
  		{
  			var result = this.getBoundingBoxFromGeometry(children, true);
  			if (result != null)
  			{
  				if (this.isSwimlane(group))
  				{
  					var size = this.getStartSize(group);
  					result.x -= size.width;
  					result.y -= size.height;
  					result.width += size.width;
  					result.height += size.height;
  				}
  				if (border != null)
  				{
  					result.x -= border;
  					result.y -= border;
  					result.width += 2 * border;
  					result.height += 2 * border;
  				}
  			}
  			return result;
  		};
  		mxGraph.prototype.createGroupCell = function(cells)
  		{
  			var group = new mxCell('');
  			group.setVertex(true);
  			group.setConnectable(false);
  			return group;
  		};
  		mxGraph.prototype.ungroupCells = function(cells)
  		{
  			var result = [];
  			if (cells == null)
  			{
  				cells = this.getCellsForUngroup();
  			}
  			if (cells != null && cells.length > 0)
  			{
  				this.model.beginUpdate();
  				try
  				{
  					for (var i = 0; i < cells.length; i++)
  					{
  						var children = this.model.getChildren(cells[i]);
  						if (children != null && children.length > 0)
  						{
  							children = children.slice();
  							var parent = this.model.getParent(cells[i]);
  							var index = this.model.getChildCount(parent);
  							this.cellsAdded(children, parent, index, null, null, true);
  							result = result.concat(children);
  							for (var j = 0; j < children.length; j++)
  							{
  								var state = this.view.getState(children[j]);
  								var geo = this.getCellGeometry(children[j]);
  								if (state != null && geo != null && geo.relative)
  								{
  									geo = geo.clone();
  									geo.x = state.origin.x;
  									geo.y = state.origin.y;
  									geo.relative = false;
  									this.model.setGeometry(children[j], geo);
  								}
  							}
  						}
  					}
  					this.removeCellsAfterUngroup(cells);
  					this.fireEvent(new mxEventObject(mxEvent.UNGROUP_CELLS, 'cells', cells));
  				}
  				finally
  				{
  					this.model.endUpdate();
  				}
  			}
  			return result;
  		};
  		mxGraph.prototype.getCellsForUngroup = function()
  		{
  			var cells = this.getSelectionCells();
  			var tmp = [];
  			for (var i = 0; i < cells.length; i++)
  			{
  				if (this.model.isVertex(cells[i]) &&
  					this.model.getChildCount(cells[i]) > 0)
  				{
  					tmp.push(cells[i]);
  				}
  			}
  			return tmp;
  		};
  		mxGraph.prototype.removeCellsAfterUngroup = function(cells)
  		{
  			this.cellsRemoved(this.addAllEdges(cells));
  		};
  		mxGraph.prototype.removeCellsFromParent = function(cells)
  		{
  			if (cells == null)
  			{
  				cells = this.getSelectionCells();
  			}
  			this.model.beginUpdate();
  			try
  			{
  				var parent = this.getDefaultParent();
  				var index = this.model.getChildCount(parent);
  				this.cellsAdded(cells, parent, index, null, null, true);
  				this.fireEvent(new mxEventObject(mxEvent.REMOVE_CELLS_FROM_PARENT, 'cells', cells));
  			}
  			finally
  			{
  				this.model.endUpdate();
  			}
  			return cells;
  		};
  		mxGraph.prototype.updateGroupBounds = function(cells, border, moveGroup, topBorder, rightBorder, bottomBorder, leftBorder)
  		{
  			if (cells == null)
  			{
  				cells = this.getSelectionCells();
  			}
  			border = (border != null) ? border : 0;
  			moveGroup = (moveGroup != null) ? moveGroup : false;
  			topBorder = (topBorder != null) ? topBorder : 0;
  			rightBorder = (rightBorder != null) ? rightBorder : 0;
  			bottomBorder = (bottomBorder != null) ? bottomBorder : 0;
  			leftBorder = (leftBorder != null) ? leftBorder : 0;
  			this.model.beginUpdate();
  			try
  			{
  				for (var i = cells.length - 1; i >= 0; i--)
  				{
  					var geo = this.getCellGeometry(cells[i]);
  					if (geo != null)
  					{
  						var children = this.getChildCells(cells[i]);
  						if (children != null && children.length > 0)
  						{
  							var bounds = this.getBoundingBoxFromGeometry(children, true);
  							if (bounds != null && bounds.width > 0 && bounds.height > 0)
  							{
  								var size = (this.isSwimlane(cells[i])) ?
  									this.getActualStartSize(cells[i], true) : new mxRectangle();
  								geo = geo.clone();
  								if (moveGroup)
  								{
  									geo.x = Math.round(geo.x + bounds.x - border - size.x - leftBorder);
  									geo.y = Math.round(geo.y + bounds.y - border - size.y - topBorder);
  								}
  								geo.width = Math.round(bounds.width + 2 * border + size.x + leftBorder + rightBorder + size.width);
  								geo.height = Math.round(bounds.height + 2 * border + size.y + topBorder + bottomBorder + size.height);
  								this.model.setGeometry(cells[i], geo);
  								this.moveCells(children, border + size.x - bounds.x + leftBorder,
  										border + size.y - bounds.y + topBorder);
  							}
  						}
  					}
  				}
  			}
  			finally
  			{
  				this.model.endUpdate();
  			}
  			return cells;
  		};
  		mxGraph.prototype.getBoundingBox = function(cells)
  		{
  			var result = null;
  			if (cells != null && cells.length > 0)
  			{
  				for (var i = 0; i < cells.length; i++)
  				{
  					if (this.model.isVertex(cells[i]) || this.model.isEdge(cells[i]))
  					{
  						var bbox = this.view.getBoundingBox(this.view.getState(cells[i]), true);
  						if (bbox != null)
  						{
  							if (result == null)
  							{
  								result = mxRectangle.fromRectangle(bbox);
  							}
  							else
  							{
  								result.add(bbox);
  							}
  						}
  					}
  				}
  			}
  			return result;
  		};
  		mxGraph.prototype.cloneCell = function(cell, allowInvalidEdges, mapping, keepPosition)
  		{
  			return this.cloneCells([cell], allowInvalidEdges, mapping, keepPosition)[0];
  		};
  		mxGraph.prototype.cloneCells = function(cells, allowInvalidEdges, mapping, keepPosition)
  		{
  			allowInvalidEdges = (allowInvalidEdges != null) ? allowInvalidEdges : true;
  			var clones = null;
  			if (cells != null)
  			{
  				var dict = new mxDictionary();
  				var tmp = [];
  				for (var i = 0; i < cells.length; i++)
  				{
  					dict.put(cells[i], true);
  					tmp.push(cells[i]);
  				}
  				if (tmp.length > 0)
  				{
  					var scale = this.view.scale;
  					var trans = this.view.translate;
  					clones = this.model.cloneCells(cells, true, mapping);
  					for (var i = 0; i < cells.length; i++)
  					{
  						if (!allowInvalidEdges && this.model.isEdge(clones[i]) &&
  							this.getEdgeValidationError(clones[i],
  								this.model.getTerminal(clones[i], true),
  								this.model.getTerminal(clones[i], false)) != null)
  						{
  							clones[i] = null;
  						}
  						else
  						{
  							var g = this.model.getGeometry(clones[i]);
  							if (g != null)
  							{
  								var state = this.view.getState(cells[i]);
  								var pstate = this.view.getState(this.model.getParent(cells[i]));
  								if (state != null && pstate != null)
  								{
  									var dx = (keepPosition) ? 0 : pstate.origin.x;
  									var dy = (keepPosition) ? 0 : pstate.origin.y;
  									if (this.model.isEdge(clones[i]))
  									{
  										var pts = state.absolutePoints;
  										if (pts != null)
  										{
  											var src = this.model.getTerminal(cells[i], true);
  											while (src != null && !dict.get(src))
  											{
  												src = this.model.getParent(src);
  											}
  											if (src == null && pts[0] != null)
  											{
  												g.setTerminalPoint(
  													new mxPoint(pts[0].x / scale - trans.x,
  														pts[0].y / scale - trans.y), true);
  											}
  											var trg = this.model.getTerminal(cells[i], false);
  											while (trg != null && !dict.get(trg))
  											{
  												trg = this.model.getParent(trg);
  											}
  											var n = pts.length - 1;
  											if (trg == null && pts[n] != null)
  											{
  												g.setTerminalPoint(
  													new mxPoint(pts[n].x / scale - trans.x,
  														pts[n].y / scale - trans.y), false);
  											}
  											var points = g.points;
  											if (points != null)
  											{
  												for (var j = 0; j < points.length; j++)
  												{
  													points[j].x += dx;
  													points[j].y += dy;
  												}
  											}
  										}
  									}
  									else
  									{
  										g.translate(dx, dy);
  									}
  								}
  							}
  						}
  					}
  				}
  				else
  				{
  					clones = [];
  				}
  			}
  			return clones;
  		};
  		mxGraph.prototype.insertVertex = function(parent, id, value,
  			x, y, width, height, style, relative)
  		{
  			var vertex = this.createVertex(parent, id, value, x, y, width, height, style, relative);
  			return this.addCell(vertex, parent);
  		};
  		mxGraph.prototype.createVertex = function(parent, id, value,
  				x, y, width, height, style, relative)
  		{
  			var geometry = new mxGeometry(x, y, width, height);
  			geometry.relative = (relative != null) ? relative : false;
  			var vertex = new mxCell(value, geometry, style);
  			vertex.setId(id);
  			vertex.setVertex(true);
  			vertex.setConnectable(true);
  			return vertex;
  		};
  		mxGraph.prototype.insertEdge = function(parent, id, value, source, target, style)
  		{
  			var edge = this.createEdge(parent, id, value, source, target, style);
  			return this.addEdge(edge, parent, source, target);
  		};
  		mxGraph.prototype.createEdge = function(parent, id, value, source, target, style)
  		{
  			var edge = new mxCell(value, new mxGeometry(), style);
  			edge.setId(id);
  			edge.setEdge(true);
  			edge.geometry.relative = true;
  			return edge;
  		};
  		mxGraph.prototype.addEdge = function(edge, parent, source, target, index)
  		{
  			return this.addCell(edge, parent, index, source, target);
  		};
  		mxGraph.prototype.addCell = function(cell, parent, index, source, target)
  		{
  			return this.addCells([cell], parent, index, source, target)[0];
  		};
  		mxGraph.prototype.addCells = function(cells, parent, index, source, target, absolute)
  		{
  			if (parent == null)
  			{
  				parent = this.getDefaultParent();
  			}
  			if (index == null)
  			{
  				index = this.model.getChildCount(parent);
  			}
  			this.model.beginUpdate();
  			try
  			{
  				this.cellsAdded(cells, parent, index, source, target, (absolute != null) ? absolute : false, true);
  				this.fireEvent(new mxEventObject(mxEvent.ADD_CELLS, 'cells', cells,
  						'parent', parent, 'index', index, 'source', source, 'target', target));
  			}
  			finally
  			{
  				this.model.endUpdate();
  			}
  			return cells;
  		};
  		mxGraph.prototype.cellsAdded = function(cells, parent, index, source, target, absolute, constrain, extend)
  		{
  			if (cells != null && parent != null && index != null)
  			{
  				this.model.beginUpdate();
  				try
  				{
  					var parentState = (absolute) ? this.view.getState(parent) : null;
  					var o1 = (parentState != null) ? parentState.origin : null;
  					var zero = new mxPoint(0, 0);
  					for (var i = 0; i < cells.length; i++)
  					{
  						if (cells[i] == null)
  						{
  							index--;
  						}
  						else
  						{
  							var previous = this.model.getParent(cells[i]);
  							if (o1 != null && cells[i] != parent && parent != previous)
  							{
  								var oldState = this.view.getState(previous);
  								var o2 = (oldState != null) ? oldState.origin : zero;
  								var geo = this.model.getGeometry(cells[i]);
  								if (geo != null)
  								{
  									var dx = o2.x - o1.x;
  									var dy = o2.y - o1.y;
  									geo = geo.clone();
  									geo.translate(dx, dy);
  									if (!geo.relative && this.model.isVertex(cells[i]) &&
  										!this.isAllowNegativeCoordinates())
  									{
  										geo.x = Math.max(0, geo.x);
  										geo.y = Math.max(0, geo.y);
  									}
  									this.model.setGeometry(cells[i], geo);
  								}
  							}
  							if (parent == previous && index + i > this.model.getChildCount(parent))
  							{
  								index--;
  							}
  							this.model.add(parent, cells[i], index + i);
  							if (this.autoSizeCellsOnAdd)
  							{
  								this.autoSizeCell(cells[i], true);
  							}
  							if ((extend == null || extend) &&
  								this.isExtendParentsOnAdd(cells[i]) && this.isExtendParent(cells[i]))
  							{
  								this.extendParent(cells[i]);
  							}
  							if (constrain == null || constrain)
  							{
  								this.constrainChild(cells[i]);
  							}
  							if (source != null)
  							{
  								this.cellConnected(cells[i], source, true);
  							}
  							if (target != null)
  							{
  								this.cellConnected(cells[i], target, false);
  							}
  						}
  					}
  					this.fireEvent(new mxEventObject(mxEvent.CELLS_ADDED, 'cells', cells,
  						'parent', parent, 'index', index, 'source', source, 'target', target,
  						'absolute', absolute));
  				}
  				finally
  				{
  					this.model.endUpdate();
  				}
  			}
  		};
  		mxGraph.prototype.autoSizeCell = function(cell, recurse)
  		{
  			recurse = (recurse != null) ? recurse : true;
  			if (recurse)
  			{
  				var childCount = this.model.getChildCount(cell);
  				for (var i = 0; i < childCount; i++)
  				{
  					this.autoSizeCell(this.model.getChildAt(cell, i));
  				}
  			}
  			if (this.getModel().isVertex(cell) && this.isAutoSizeCell(cell))
  			{
  				this.updateCellSize(cell);
  			}
  		};
  		mxGraph.prototype.removeCells = function(cells, includeEdges)
  		{
  			includeEdges = (includeEdges != null) ? includeEdges : true;
  			if (cells == null)
  			{
  				cells = this.getDeletableCells(this.getSelectionCells());
  			}
  			if (includeEdges)
  			{
  				cells = this.getDeletableCells(this.addAllEdges(cells));
  			}
  			else
  			{
  				cells = cells.slice();
  				var edges = this.getDeletableCells(this.getAllEdges(cells));
  				var dict = new mxDictionary();
  				for (var i = 0; i < cells.length; i++)
  				{
  					dict.put(cells[i], true);
  				}
  				for (var i = 0; i < edges.length; i++)
  				{
  					if (this.view.getState(edges[i]) == null &&
  						!dict.get(edges[i]))
  					{
  						dict.put(edges[i], true);
  						cells.push(edges[i]);
  					}
  				}
  			}
  			this.model.beginUpdate();
  			try
  			{
  				this.cellsRemoved(cells);
  				this.fireEvent(new mxEventObject(mxEvent.REMOVE_CELLS,
  						'cells', cells, 'includeEdges', includeEdges));
  			}
  			finally
  			{
  				this.model.endUpdate();
  			}
  			return cells;
  		};
  		mxGraph.prototype.cellsRemoved = function(cells)
  		{
  			if (cells != null && cells.length > 0)
  			{
  				var scale = this.view.scale;
  				var tr = this.view.translate;
  				this.model.beginUpdate();
  				try
  				{
  					var dict = new mxDictionary();
  					for (var i = 0; i < cells.length; i++)
  					{
  						dict.put(cells[i], true);
  					}
  					for (var i = 0; i < cells.length; i++)
  					{
  						var edges = this.getAllEdges([cells[i]]);
  						var disconnectTerminal = mxUtils.bind(this, function(edge, source)
  						{
  							var geo = this.model.getGeometry(edge);
  							if (geo != null)
  							{
  								var terminal = this.model.getTerminal(edge, source);
  								var connected = false;
  								var tmp = terminal;
  								while (tmp != null)
  								{
  									if (cells[i] == tmp)
  									{
  										connected = true;
  										break;
  									}
  									tmp = this.model.getParent(tmp);
  								}
  								if (connected)
  								{
  									geo = geo.clone();
  									var state = this.view.getState(edge);
  									if (state != null && state.absolutePoints != null)
  									{
  										var pts = state.absolutePoints;
  										var n = (source) ? 0 : pts.length - 1;
  										geo.setTerminalPoint(new mxPoint(
  											pts[n].x / scale - tr.x - state.origin.x,
  											pts[n].y / scale - tr.y - state.origin.y), source);
  									}
  									else
  									{
  										var tstate = this.view.getState(terminal);
  										if (tstate != null)
  										{
  											geo.setTerminalPoint(new mxPoint(
  												tstate.getCenterX() / scale - tr.x,
  												tstate.getCenterY() / scale - tr.y), source);
  										}
  									}
  									this.model.setGeometry(edge, geo);
  									this.model.setTerminal(edge, null, source);
  								}
  							}
  						});
  						for (var j = 0; j < edges.length; j++)
  						{
  							if (!dict.get(edges[j]))
  							{
  								dict.put(edges[j], true);
  								disconnectTerminal(edges[j], true);
  								disconnectTerminal(edges[j], false);
  							}
  						}
  						this.model.remove(cells[i]);
  					}
  					this.fireEvent(new mxEventObject(mxEvent.CELLS_REMOVED, 'cells', cells));
  				}
  				finally
  				{
  					this.model.endUpdate();
  				}
  			}
  		};
  		mxGraph.prototype.splitEdge = function(edge, cells, newEdge, dx, dy, x, y, parent)
  		{
  			dx = dx || 0;
  			dy = dy || 0;
  			parent = (parent != null) ? parent : this.model.getParent(edge);
  			var source = this.model.getTerminal(edge, true);
  			this.model.beginUpdate();
  			try
  			{
  				if (newEdge == null)
  				{
  					newEdge = this.cloneCell(edge);
  					var state = this.view.getState(edge);
  					var geo = this.getCellGeometry(newEdge);
  					if (geo != null && geo.points != null && state != null)
  					{
  						var t = this.view.translate;
  						var s = this.view.scale;
  						var idx = mxUtils.findNearestSegment(state, (dx + t.x) * s, (dy + t.y) * s);
  						geo.points = geo.points.slice(0, idx);
  						geo = this.getCellGeometry(edge);
  						if (geo != null && geo.points != null)
  						{
  							geo = geo.clone();
  							geo.points = geo.points.slice(idx);
  							this.model.setGeometry(edge, geo);
  						}
  					}
  				}
  				this.cellsMoved(cells, dx, dy, false, false);
  				this.cellsAdded(cells, parent, this.model.getChildCount(parent), null, null,
  						true);
  				this.cellsAdded([newEdge], parent, this.model.getChildCount(parent),
  						source, cells[0], false);
  				this.cellConnected(edge, cells[0], true);
  				this.fireEvent(new mxEventObject(mxEvent.SPLIT_EDGE, 'edge', edge,
  						'cells', cells, 'newEdge', newEdge, 'dx', dx, 'dy', dy));
  			}
  			finally
  			{
  				this.model.endUpdate();
  			}
  			return newEdge;
  		};
  		mxGraph.prototype.toggleCells = function(show, cells, includeEdges)
  		{
  			if (cells == null)
  			{
  				cells = this.getSelectionCells();
  			}
  			if (includeEdges)
  			{
  				cells = this.addAllEdges(cells);
  			}
  			this.model.beginUpdate();
  			try
  			{
  				this.cellsToggled(cells, show);
  				this.fireEvent(new mxEventObject(mxEvent.TOGGLE_CELLS,
  					'show', show, 'cells', cells, 'includeEdges', includeEdges));
  			}
  			finally
  			{
  				this.model.endUpdate();
  			}
  			return cells;
  		};
  		mxGraph.prototype.cellsToggled = function(cells, show)
  		{
  			if (cells != null && cells.length > 0)
  			{
  				this.model.beginUpdate();
  				try
  				{
  					for (var i = 0; i < cells.length; i++)
  					{
  						this.model.setVisible(cells[i], show);
  					}
  				}
  				finally
  				{
  					this.model.endUpdate();
  				}
  			}
  		};
  		mxGraph.prototype.foldCells = function(collapse, recurse, cells, checkFoldable, evt)
  		{
  			recurse = (recurse != null) ? recurse : false;
  			if (cells == null)
  			{
  				cells = this.getFoldableCells(this.getSelectionCells(), collapse);
  			}
  			this.stopEditing(false);
  			this.model.beginUpdate();
  			try
  			{
  				this.cellsFolded(cells, collapse, recurse, checkFoldable);
  				this.fireEvent(new mxEventObject(mxEvent.FOLD_CELLS,
  					'collapse', collapse, 'recurse', recurse, 'cells', cells));
  			}
  			finally
  			{
  				this.model.endUpdate();
  			}
  			return cells;
  		};
  		mxGraph.prototype.cellsFolded = function(cells, collapse, recurse, checkFoldable)
  		{
  			if (cells != null && cells.length > 0)
  			{
  				this.model.beginUpdate();
  				try
  				{
  					for (var i = 0; i < cells.length; i++)
  					{
  						if ((!checkFoldable || this.isCellFoldable(cells[i], collapse)) &&
  							collapse != this.isCellCollapsed(cells[i]))
  						{
  							this.model.setCollapsed(cells[i], collapse);
  							this.swapBounds(cells[i], collapse);
  							if (this.isExtendParent(cells[i]))
  							{
  								this.extendParent(cells[i]);
  							}
  							if (recurse)
  							{
  								var children = this.model.getChildren(cells[i]);
  								this.cellsFolded(children, collapse, recurse);
  							}
  							this.constrainChild(cells[i]);
  						}
  					}
  					this.fireEvent(new mxEventObject(mxEvent.CELLS_FOLDED,
  						'cells', cells, 'collapse', collapse, 'recurse', recurse));
  				}
  				finally
  				{
  					this.model.endUpdate();
  				}
  			}
  		};
  		mxGraph.prototype.swapBounds = function(cell, willCollapse)
  		{
  			if (cell != null)
  			{
  				var geo = this.model.getGeometry(cell);
  				if (geo != null)
  				{
  					geo = geo.clone();
  					this.updateAlternateBounds(cell, geo, willCollapse);
  					geo.swap();
  					this.model.setGeometry(cell, geo);
  				}
  			}
  		};
  		mxGraph.prototype.updateAlternateBounds = function(cell, geo, willCollapse)
  		{
  			if (cell != null && geo != null)
  			{
  				var style = this.getCurrentCellStyle(cell);
  				if (geo.alternateBounds == null)
  				{
  					var bounds = geo;
  					if (this.collapseToPreferredSize)
  					{
  						var tmp = this.getPreferredSizeForCell(cell);
  						if (tmp != null)
  						{
  							bounds = tmp;
  							var startSize = mxUtils.getValue(style, mxConstants.STYLE_STARTSIZE);
  							if (startSize > 0)
  							{
  								bounds.height = Math.max(bounds.height, startSize);
  							}
  						}
  					}
  					geo.alternateBounds = new mxRectangle(0, 0, bounds.width, bounds.height);
  				}
  				if (geo.alternateBounds != null)
  				{
  					geo.alternateBounds.x = geo.x;
  					geo.alternateBounds.y = geo.y;
  					var alpha = mxUtils.toRadians(style[mxConstants.STYLE_ROTATION] || 0);
  					if (alpha != 0)
  					{
  						var dx = geo.alternateBounds.getCenterX() - geo.getCenterX();
  						var dy = geo.alternateBounds.getCenterY() - geo.getCenterY();
  						var cos = Math.cos(alpha);
  						var sin = Math.sin(alpha);
  						var dx2 = cos * dx - sin * dy;
  						var dy2 = sin * dx + cos * dy;
  						geo.alternateBounds.x += dx2 - dx;
  						geo.alternateBounds.y += dy2 - dy;
  					}
  				}
  			}
  		};
  		mxGraph.prototype.addAllEdges = function(cells)
  		{
  			var allCells = cells.slice();
  			return mxUtils.removeDuplicates(allCells.concat(this.getAllEdges(cells)));
  		};
  		mxGraph.prototype.getAllEdges = function(cells)
  		{
  			var edges = [];
  			if (cells != null)
  			{
  				for (var i = 0; i < cells.length; i++)
  				{
  					var edgeCount = this.model.getEdgeCount(cells[i]);
  					for (var j = 0; j < edgeCount; j++)
  					{
  						edges.push(this.model.getEdgeAt(cells[i], j));
  					}
  					var children = this.model.getChildren(cells[i]);
  					edges = edges.concat(this.getAllEdges(children));
  				}
  			}
  			return edges;
  		};
  		mxGraph.prototype.updateCellSize = function(cell, ignoreChildren)
  		{
  			ignoreChildren = (ignoreChildren != null) ? ignoreChildren : false;
  			this.model.beginUpdate();
  			try
  			{
  				this.cellSizeUpdated(cell, ignoreChildren);
  				this.fireEvent(new mxEventObject(mxEvent.UPDATE_CELL_SIZE,
  						'cell', cell, 'ignoreChildren', ignoreChildren));
  			}
  			finally
  			{
  				this.model.endUpdate();
  			}
  			return cell;
  		};
  		mxGraph.prototype.cellSizeUpdated = function(cell, ignoreChildren)
  		{
  			if (cell != null)
  			{
  				this.model.beginUpdate();
  				try
  				{
  					var size = this.getPreferredSizeForCell(cell);
  					var geo = this.model.getGeometry(cell);
  					if (size != null && geo != null)
  					{
  						var collapsed = this.isCellCollapsed(cell);
  						geo = geo.clone();
  						if (this.isSwimlane(cell))
  						{
  							var style = this.getCellStyle(cell);
  							var cellStyle = this.model.getStyle(cell);
  							if (cellStyle == null)
  							{
  								cellStyle = '';
  							}
  							if (mxUtils.getValue(style, mxConstants.STYLE_HORIZONTAL, true))
  							{
  								cellStyle = mxUtils.setStyle(cellStyle,
  										mxConstants.STYLE_STARTSIZE, size.height + 8);
  								if (collapsed)
  								{
  									geo.height = size.height + 8;
  								}
  								geo.width = size.width;
  							}
  							else
  							{
  								cellStyle = mxUtils.setStyle(cellStyle,
  										mxConstants.STYLE_STARTSIZE, size.width + 8);
  								if (collapsed)
  								{
  									geo.width = size.width + 8;
  								}
  								geo.height = size.height;
  							}
  							this.model.setStyle(cell, cellStyle);
  						}
  						else
  						{
  							var state = this.view.createState(cell);
  							var align = (state.style[mxConstants.STYLE_ALIGN] || mxConstants.ALIGN_CENTER);
  							if (align == mxConstants.ALIGN_RIGHT)
  							{
  								geo.x += geo.width - size.width;
  							}
  							else if (align == mxConstants.ALIGN_CENTER)
  							{
  								geo.x += Math.round((geo.width - size.width) / 2);
  							}
  							var valign = this.getVerticalAlign(state);
  							if (valign == mxConstants.ALIGN_BOTTOM)
  							{
  								geo.y += geo.height - size.height;
  							}
  							else if (valign == mxConstants.ALIGN_MIDDLE)
  							{
  								geo.y += Math.round((geo.height - size.height) / 2);
  							}
  							geo.width = size.width;
  							geo.height = size.height;
  						}
  						if (!ignoreChildren && !collapsed)
  						{
  							var bounds = this.view.getBounds(this.model.getChildren(cell));
  							if (bounds != null)
  							{
  								var tr = this.view.translate;
  								var scale = this.view.scale;
  								var width = (bounds.x + bounds.width) / scale - geo.x - tr.x;
  								var height = (bounds.y + bounds.height) / scale - geo.y - tr.y;
  								geo.width = Math.max(geo.width, width);
  								geo.height = Math.max(geo.height, height);
  							}
  						}
  						this.cellsResized([cell], [geo], false);
  					}
  				}
  				finally
  				{
  					this.model.endUpdate();
  				}
  			}
  		};
  		mxGraph.prototype.getPreferredSizeForCell = function(cell, textWidth)
  		{
  			var result = null;
  			if (cell != null)
  			{
  				var state = this.view.createState(cell);
  				var style = state.style;
  				if (!this.model.isEdge(cell))
  				{
  					var fontSize = style[mxConstants.STYLE_FONTSIZE] || mxConstants.DEFAULT_FONTSIZE;
  					var dx = 0;
  					var dy = 0;
  					if (this.getImage(state) != null || style[mxConstants.STYLE_IMAGE] != null)
  					{
  						if (style[mxConstants.STYLE_SHAPE] == mxConstants.SHAPE_LABEL)
  						{
  							if (style[mxConstants.STYLE_VERTICAL_ALIGN] == mxConstants.ALIGN_MIDDLE)
  							{
  								dx += parseFloat(style[mxConstants.STYLE_IMAGE_WIDTH]) || mxLabel.prototype.imageSize;
  							}
  							if (style[mxConstants.STYLE_ALIGN] != mxConstants.ALIGN_CENTER)
  							{
  								dy += parseFloat(style[mxConstants.STYLE_IMAGE_HEIGHT]) || mxLabel.prototype.imageSize;
  							}
  						}
  					}
  					dx += 2 * (style[mxConstants.STYLE_SPACING] || 0);
  					dx += style[mxConstants.STYLE_SPACING_LEFT] || 0;
  					dx += style[mxConstants.STYLE_SPACING_RIGHT] || 0;
  					dy += 2 * (style[mxConstants.STYLE_SPACING] || 0);
  					dy += style[mxConstants.STYLE_SPACING_TOP] || 0;
  					dy += style[mxConstants.STYLE_SPACING_BOTTOM] || 0;
  					var image = this.getFoldingImage(state);
  					if (image != null)
  					{
  						dx += image.width + 8;
  					}
  					var value = this.cellRenderer.getLabelValue(state);
  					if (value != null && value.length > 0)
  					{
  						if (!this.isHtmlLabel(state.cell))
  						{
  							value = mxUtils.htmlEntities(value, false);
  						}
  						value = value.replace(/\n/g, '<br>');
  						var size = mxUtils.getSizeForString(value, fontSize,
  							style[mxConstants.STYLE_FONTFAMILY], textWidth,
  							style[mxConstants.STYLE_FONTSTYLE]);
  						var width = size.width + dx;
  						var height = size.height + dy;
  						if (!mxUtils.getValue(style, mxConstants.STYLE_HORIZONTAL, true))
  						{
  							var tmp = height;
  							height = width;
  							width = tmp;
  						}
  						if (this.gridEnabled)
  						{
  							width = this.snap(width + this.gridSize / 2);
  							height = this.snap(height + this.gridSize / 2);
  						}
  						result = new mxRectangle(0, 0, width, height);
  					}
  					else
  					{
  						var gs2 = 4 * this.gridSize;
  						result = new mxRectangle(0, 0, gs2, gs2);
  					}
  				}
  			}
  			return result;
  		};
  		mxGraph.prototype.resizeCell = function(cell, bounds, recurse)
  		{
  			return this.resizeCells([cell], [bounds], recurse)[0];
  		};
  		mxGraph.prototype.resizeCells = function(cells, bounds, recurse)
  		{
  			recurse = (recurse != null) ? recurse : this.isRecursiveResize();
  			this.model.beginUpdate();
  			try
  			{
  				var prev = this.cellsResized(cells, bounds, recurse);
  				this.fireEvent(new mxEventObject(mxEvent.RESIZE_CELLS,
  					'cells', cells, 'bounds', bounds, 'previous', prev));
  			}
  			finally
  			{
  				this.model.endUpdate();
  			}
  			return cells;
  		};
  		mxGraph.prototype.cellsResized = function(cells, bounds, recurse)
  		{
  			recurse = (recurse != null) ? recurse : false;
  			var prev = [];
  			if (cells != null && bounds != null && cells.length == bounds.length)
  			{
  				this.model.beginUpdate();
  				try
  				{
  					for (var i = 0; i < cells.length; i++)
  					{
  						prev.push(this.cellResized(cells[i], bounds[i], false, recurse));
  						if (this.isExtendParent(cells[i]))
  						{
  							this.extendParent(cells[i]);
  						}
  						this.constrainChild(cells[i]);
  					}
  					if (this.resetEdgesOnResize)
  					{
  						this.resetEdges(cells);
  					}
  					this.fireEvent(new mxEventObject(mxEvent.CELLS_RESIZED,
  						'cells', cells, 'bounds', bounds, 'previous', prev));
  				}
  				finally
  				{
  					this.model.endUpdate();
  				}
  			}
  			return prev;
  		};
  		mxGraph.prototype.cellResized = function(cell, bounds, ignoreRelative, recurse)
  		{
  			var prev = this.model.getGeometry(cell);
  			if (prev != null && (prev.x != bounds.x || prev.y != bounds.y ||
  				prev.width != bounds.width || prev.height != bounds.height))
  			{
  				var geo = prev.clone();
  				if (!ignoreRelative && geo.relative)
  				{
  					var offset = geo.offset;
  					if (offset != null)
  					{
  						offset.x += bounds.x - geo.x;
  						offset.y += bounds.y - geo.y;
  					}
  				}
  				else
  				{
  					geo.x = bounds.x;
  					geo.y = bounds.y;
  				}
  				geo.width = bounds.width;
  				geo.height = bounds.height;
  				if (!geo.relative && this.model.isVertex(cell) && !this.isAllowNegativeCoordinates())
  				{
  					geo.x = Math.max(0, geo.x);
  					geo.y = Math.max(0, geo.y);
  				}
  				this.model.beginUpdate();
  				try
  				{
  					if (recurse)
  					{
  						this.resizeChildCells(cell, geo);
  					}
  					this.model.setGeometry(cell, geo);
  					this.constrainChildCells(cell);
  				}
  				finally
  				{
  					this.model.endUpdate();
  				}
  			}
  			return prev;
  		};
  		mxGraph.prototype.resizeChildCells = function(cell, newGeo)
  		{
  			var geo = this.model.getGeometry(cell);
  			var dx = (geo.width != 0) ? newGeo.width / geo.width : 1;
  			var dy = (geo.height != 0) ? newGeo.height / geo.height : 1;
  			var childCount = this.model.getChildCount(cell);
  			for (var i = 0; i < childCount; i++)
  			{
  				this.scaleCell(this.model.getChildAt(cell, i), dx, dy, true);
  			}
  		};
  		mxGraph.prototype.constrainChildCells = function(cell)
  		{
  			var childCount = this.model.getChildCount(cell);
  			for (var i = 0; i < childCount; i++)
  			{
  				this.constrainChild(this.model.getChildAt(cell, i));
  			}
  		};
  		mxGraph.prototype.scaleCell = function(cell, dx, dy, recurse)
  		{
  			var geo = this.model.getGeometry(cell);
  			if (geo != null)
  			{
  				var style = this.getCurrentCellStyle(cell);
  				geo = geo.clone();
  				var x = geo.x;
  				var y = geo.y;
  				var w = geo.width;
  				var h = geo.height;
  				geo.scale(dx, dy, style[mxConstants.STYLE_ASPECT] == 'fixed');
  				if (style[mxConstants.STYLE_RESIZE_WIDTH] == '1')
  				{
  					geo.width = w * dx;
  				}
  				else if (style[mxConstants.STYLE_RESIZE_WIDTH] == '0')
  				{
  					geo.width = w;
  				}
  				if (style[mxConstants.STYLE_RESIZE_HEIGHT] == '1')
  				{
  					geo.height = h * dy;
  				}
  				else if (style[mxConstants.STYLE_RESIZE_HEIGHT] == '0')
  				{
  					geo.height = h;
  				}
  				if (!this.isCellMovable(cell))
  				{
  					geo.x = x;
  					geo.y = y;
  				}
  				if (!this.isCellResizable(cell))
  				{
  					geo.width = w;
  					geo.height = h;
  				}
  				if (this.model.isVertex(cell))
  				{
  					this.cellResized(cell, geo, true, recurse);
  				}
  				else
  				{
  					this.model.setGeometry(cell, geo);
  				}
  			}
  		};
  		mxGraph.prototype.extendParent = function(cell)
  		{
  			if (cell != null)
  			{
  				var parent = this.model.getParent(cell);
  				var p = this.getCellGeometry(parent);
  				if (parent != null && p != null && !this.isCellCollapsed(parent))
  				{
  					var geo = this.getCellGeometry(cell);
  					if (geo != null && !geo.relative &&
  						(p.width < geo.x + geo.width ||
  						p.height < geo.y + geo.height))
  					{
  						p = p.clone();
  						p.width = Math.max(p.width, geo.x + geo.width);
  						p.height = Math.max(p.height, geo.y + geo.height);
  						this.cellsResized([parent], [p], false);
  					}
  				}
  			}
  		};
  		mxGraph.prototype.importCells = function(cells, dx, dy, target, evt, mapping)
  		{
  			return this.moveCells(cells, dx, dy, true, target, evt, mapping);
  		};
  		mxGraph.prototype.moveCells = function(cells, dx, dy, clone, target, evt, mapping)
  		{
  			dx = (dx != null) ? dx : 0;
  			dy = (dy != null) ? dy : 0;
  			clone = (clone != null) ? clone : false;
  			if (cells != null && (dx != 0 || dy != 0 || clone || target != null))
  			{
  				cells = this.model.getTopmostCells(cells);
  				var origCells = cells;
  				this.model.beginUpdate();
  				try
  				{
  					var dict = new mxDictionary();
  					for (var i = 0; i < cells.length; i++)
  					{
  						dict.put(cells[i], true);
  					}
  					var isSelected = mxUtils.bind(this, function(cell)
  					{
  						while (cell != null)
  						{
  							if (dict.get(cell))
  							{
  								return true;
  							}
  							cell = this.model.getParent(cell);
  						}
  						return false;
  					});
  					var checked = [];
  					for (var i = 0; i < cells.length; i++)
  					{
  						var geo = this.getCellGeometry(cells[i]);
  						var parent = this.model.getParent(cells[i]);
  						if ((geo == null || !geo.relative) || !this.model.isEdge(parent) ||
  							(!isSelected(this.model.getTerminal(parent, true)) &&
  							!isSelected(this.model.getTerminal(parent, false))))
  						{
  							checked.push(cells[i]);
  						}
  					}
  					cells = checked;
  					if (clone)
  					{
  						cells = this.cloneCells(cells, this.isCloneInvalidEdges(), mapping);
  						if (target == null)
  						{
  							target = this.getDefaultParent();
  						}
  					}
  					var previous = this.isAllowNegativeCoordinates();
  					if (target != null)
  					{
  						this.setAllowNegativeCoordinates(true);
  					}
  					this.cellsMoved(cells, dx, dy, !clone && this.isDisconnectOnMove()
  							&& this.isAllowDanglingEdges(), target == null,
  							this.isExtendParentsOnMove() && target == null);
  					this.setAllowNegativeCoordinates(previous);
  					if (target != null)
  					{
  						var index = this.model.getChildCount(target);
  						this.cellsAdded(cells, target, index, null, null, true);
  						if (clone)
  						{
  							for (var i = 0; i < cells.length; i++)
  							{
  								var geo = this.getCellGeometry(cells[i]);
  								var parent = this.model.getParent(origCells[i]);
  								if (geo != null && geo.relative &&
  									this.model.isEdge(parent) &&
  									this.model.contains(parent))
  								{
  									this.model.add(parent, cells[i]);
  								}
  							}
  						}
  					}
  					this.fireEvent(new mxEventObject(mxEvent.MOVE_CELLS, 'cells', cells,
  						'dx', dx, 'dy', dy, 'clone', clone, 'target', target, 'event', evt));
  				}
  				finally
  				{
  					this.model.endUpdate();
  				}
  			}
  			return cells;
  		};
  		mxGraph.prototype.cellsMoved = function(cells, dx, dy, disconnect, constrain, extend)
  		{
  			if (cells != null && (dx != 0 || dy != 0))
  			{
  				extend = (extend != null) ? extend : false;
  				this.model.beginUpdate();
  				try
  				{
  					if (disconnect)
  					{
  						this.disconnectGraph(cells);
  					}
  					for (var i = 0; i < cells.length; i++)
  					{
  						this.translateCell(cells[i], dx, dy);
  						if (extend && this.isExtendParent(cells[i]))
  						{
  							this.extendParent(cells[i]);
  						}
  						else if (constrain)
  						{
  							this.constrainChild(cells[i]);
  						}
  					}
  					if (this.resetEdgesOnMove)
  					{
  						this.resetEdges(cells);
  					}
  					this.fireEvent(new mxEventObject(mxEvent.CELLS_MOVED,
  						'cells', cells, 'dx', dx, 'dy', dy, 'disconnect', disconnect));
  				}
  				finally
  				{
  					this.model.endUpdate();
  				}
  			}
  		};
  		mxGraph.prototype.translateCell = function(cell, dx, dy)
  		{
  			var geo = this.model.getGeometry(cell);
  			if (geo != null)
  			{
  				dx = parseFloat(dx);
  				dy = parseFloat(dy);
  				geo = geo.clone();
  				geo.translate(dx, dy);
  				if (!geo.relative && this.model.isVertex(cell) && !this.isAllowNegativeCoordinates())
  				{
  					geo.x = Math.max(0, parseFloat(geo.x));
  					geo.y = Math.max(0, parseFloat(geo.y));
  				}
  				if (geo.relative && !this.model.isEdge(cell))
  				{
  					var parent = this.model.getParent(cell);
  					var angle = 0;
  					if (this.model.isVertex(parent))
  					{
  						var style = this.getCurrentCellStyle(parent);
  						angle = mxUtils.getValue(style, mxConstants.STYLE_ROTATION, 0);
  					}
  					if (angle != 0)
  					{
  						var rad = mxUtils.toRadians(-angle);
  						var cos = Math.cos(rad);
  						var sin = Math.sin(rad);
  						var pt = mxUtils.getRotatedPoint(new mxPoint(dx, dy), cos, sin, new mxPoint(0, 0));
  						dx = pt.x;
  						dy = pt.y;
  					}
  					if (geo.offset == null)
  					{
  						geo.offset = new mxPoint(dx, dy);
  					}
  					else
  					{
  						geo.offset.x = parseFloat(geo.offset.x) + dx;
  						geo.offset.y = parseFloat(geo.offset.y) + dy;
  					}
  				}
  				this.model.setGeometry(cell, geo);
  			}
  		};
  		mxGraph.prototype.getCellContainmentArea = function(cell)
  		{
  			if (cell != null && !this.model.isEdge(cell))
  			{
  				var parent = this.model.getParent(cell);
  				if (parent != null && parent != this.getDefaultParent())
  				{
  					var g = this.model.getGeometry(parent);
  					if (g != null)
  					{
  						var x = 0;
  						var y = 0;
  						var w = g.width;
  						var h = g.height;
  						if (this.isSwimlane(parent))
  						{
  							var size = this.getStartSize(parent);
  							var style = this.getCurrentCellStyle(parent);
  							var dir = mxUtils.getValue(style, mxConstants.STYLE_DIRECTION, mxConstants.DIRECTION_EAST);
  							var flipH = mxUtils.getValue(style, mxConstants.STYLE_FLIPH, 0) == 1;
  							var flipV = mxUtils.getValue(style, mxConstants.STYLE_FLIPV, 0) == 1;
  							if (dir == mxConstants.DIRECTION_SOUTH || dir == mxConstants.DIRECTION_NORTH)
  							{
  								var tmp = size.width;
  								size.width = size.height;
  								size.height = tmp;
  							}
  							if ((dir == mxConstants.DIRECTION_EAST && !flipV) || (dir == mxConstants.DIRECTION_NORTH && !flipH) ||
  								(dir == mxConstants.DIRECTION_WEST && flipV) || (dir == mxConstants.DIRECTION_SOUTH && flipH))
  							{
  								x = size.width;
  								y = size.height;
  							}
  							w -= size.width;
  							h -= size.height;
  						}
  						return new mxRectangle(x, y, w, h);
  					}
  				}
  			}
  			return null;
  		};
  		mxGraph.prototype.getMaximumGraphBounds = function()
  		{
  			return this.maximumGraphBounds;
  		};
  		mxGraph.prototype.constrainChild = function(cell, sizeFirst)
  		{
  			if (cell != null)
  			{
  				var geo = this.getCellGeometry(cell);
  				if (geo != null && (this.isConstrainRelativeChildren() || !geo.relative))
  				{
  					var parent = this.model.getParent(cell);
  					this.getCellGeometry(parent);
  					var max = this.getMaximumGraphBounds();
  					if (max != null)
  					{
  						var off = this.getBoundingBoxFromGeometry([parent], false);
  						if (off != null)
  						{
  							max = mxRectangle.fromRectangle(max);
  							max.x -= off.x;
  							max.y -= off.y;
  						}
  					}
  					if (this.isConstrainChild(cell))
  					{
  						var tmp = this.getCellContainmentArea(cell);
  						if (tmp != null)
  						{
  							var overlap = this.getOverlap(cell);
  							if (overlap > 0)
  							{
  								tmp = mxRectangle.fromRectangle(tmp);
  								tmp.x -= tmp.width * overlap;
  								tmp.y -= tmp.height * overlap;
  								tmp.width += 2 * tmp.width * overlap;
  								tmp.height += 2 * tmp.height * overlap;
  							}
  							if (max == null)
  							{
  								max = tmp;
  							}
  							else
  							{
  								max = mxRectangle.fromRectangle(max);
  								max.intersect(tmp);
  							}
  						}
  					}
  					if (max != null)
  					{
  						var cells = [cell];
  						if (!this.isCellCollapsed(cell))
  						{
  							var desc = this.model.getDescendants(cell);
  							for (var i = 0; i < desc.length; i++)
  							{
  								if (this.isCellVisible(desc[i]))
  								{
  									cells.push(desc[i]);
  								}
  							}
  						}
  						var bbox = this.getBoundingBoxFromGeometry(cells, false);
  						if (bbox != null)
  						{
  							geo = geo.clone();
  							var dx = 0;
  							if (geo.width > max.width)
  							{
  								dx = geo.width - max.width;
  								geo.width -= dx;
  							}
  							if (bbox.x + bbox.width > max.x + max.width)
  							{
  								dx -= bbox.x + bbox.width - max.x - max.width - dx;
  							}
  							var dy = 0;
  							if (geo.height > max.height)
  							{
  								dy = geo.height - max.height;
  								geo.height -= dy;
  							}
  							if (bbox.y + bbox.height > max.y + max.height)
  							{
  								dy -= bbox.y + bbox.height - max.y - max.height - dy;
  							}
  							if (bbox.x < max.x)
  							{
  								dx -= bbox.x - max.x;
  							}
  							if (bbox.y < max.y)
  							{
  								dy -= bbox.y - max.y;
  							}
  							if (dx != 0 || dy != 0)
  							{
  								if (geo.relative)
  								{
  									if (geo.offset == null)
  									{
  										geo.offset = new mxPoint();
  									}
  									geo.offset.x += dx;
  									geo.offset.y += dy;
  								}
  								else
  								{
  									geo.x += dx;
  									geo.y += dy;
  								}
  							}
  							this.model.setGeometry(cell, geo);
  						}
  					}
  				}
  			}
  		};
  		mxGraph.prototype.resetEdges = function(cells)
  		{
  			if (cells != null)
  			{
  				var dict = new mxDictionary();
  				for (var i = 0; i < cells.length; i++)
  				{
  					dict.put(cells[i], true);
  				}
  				this.model.beginUpdate();
  				try
  				{
  					for (var i = 0; i < cells.length; i++)
  					{
  						var edges = this.model.getEdges(cells[i]);
  						if (edges != null)
  						{
  							for (var j = 0; j < edges.length; j++)
  							{
  								var state = this.view.getState(edges[j]);
  								var source = (state != null) ? state.getVisibleTerminal(true) : this.view.getVisibleTerminal(edges[j], true);
  								var target = (state != null) ? state.getVisibleTerminal(false) : this.view.getVisibleTerminal(edges[j], false);
  								if (!dict.get(source) || !dict.get(target))
  								{
  									this.resetEdge(edges[j]);
  								}
  							}
  						}
  						this.resetEdges(this.model.getChildren(cells[i]));
  					}
  				}
  				finally
  				{
  					this.model.endUpdate();
  				}
  			}
  		};
  		mxGraph.prototype.resetEdge = function(edge)
  		{
  			var geo = this.model.getGeometry(edge);
  			if (geo != null && geo.points != null && geo.points.length > 0)
  			{
  				geo = geo.clone();
  				geo.points = [];
  				this.model.setGeometry(edge, geo);
  			}
  			return edge;
  		};
  		mxGraph.prototype.getOutlineConstraint = function(point, terminalState, me)
  		{
  			if (terminalState.shape != null)
  			{
  				var bounds = this.view.getPerimeterBounds(terminalState);
  				var direction = terminalState.style[mxConstants.STYLE_DIRECTION];
  				if (direction == mxConstants.DIRECTION_NORTH || direction == mxConstants.DIRECTION_SOUTH)
  				{
  					bounds.x += bounds.width / 2 - bounds.height / 2;
  					bounds.y += bounds.height / 2 - bounds.width / 2;
  					var tmp = bounds.width;
  					bounds.width = bounds.height;
  					bounds.height = tmp;
  				}
  				var alpha = mxUtils.toRadians(terminalState.shape.getShapeRotation());
  				if (alpha != 0)
  				{
  					var cos = Math.cos(-alpha);
  					var sin = Math.sin(-alpha);
  					var ct = new mxPoint(bounds.getCenterX(), bounds.getCenterY());
  					point = mxUtils.getRotatedPoint(point, cos, sin, ct);
  				}
  				var sx = 1;
  				var sy = 1;
  				var dx = 0;
  				var dy = 0;
  				if (this.getModel().isVertex(terminalState.cell))
  				{
  					var flipH = terminalState.style[mxConstants.STYLE_FLIPH];
  					var flipV = terminalState.style[mxConstants.STYLE_FLIPV];
  					if (terminalState.shape != null && terminalState.shape.stencil != null)
  					{
  						flipH = mxUtils.getValue(terminalState.style, 'stencilFlipH', 0) == 1 || flipH;
  						flipV = mxUtils.getValue(terminalState.style, 'stencilFlipV', 0) == 1 || flipV;
  					}
  					if (direction == mxConstants.DIRECTION_NORTH || direction == mxConstants.DIRECTION_SOUTH)
  					{
  						var tmp = flipH;
  						flipH = flipV;
  						flipV = tmp;
  					}
  					if (flipH)
  					{
  						sx = -1;
  						dx = -bounds.width;
  					}
  					if (flipV)
  					{
  						sy = -1;
  						dy = -bounds.height ;
  					}
  				}
  				point = new mxPoint((point.x - bounds.x) * sx - dx + bounds.x, (point.y - bounds.y) * sy - dy + bounds.y);
  				var x = (bounds.width == 0) ? 0 : Math.round((point.x - bounds.x) * 1000 / bounds.width) / 1000;
  				var y = (bounds.height == 0) ? 0 : Math.round((point.y - bounds.y) * 1000 / bounds.height) / 1000;
  				return new mxConnectionConstraint(new mxPoint(x, y), false);
  			}
  			return null;
  		};
  		mxGraph.prototype.getAllConnectionConstraints = function(terminal, source)
  		{
  			if (terminal != null && terminal.shape != null && terminal.shape.stencil != null)
  			{
  				return terminal.shape.stencil.constraints;
  			}
  			return null;
  		};
  		mxGraph.prototype.getConnectionConstraint = function(edge, terminal, source)
  		{
  			var point = null;
  			var x = edge.style[(source) ? mxConstants.STYLE_EXIT_X : mxConstants.STYLE_ENTRY_X];
  			if (x != null)
  			{
  				var y = edge.style[(source) ? mxConstants.STYLE_EXIT_Y : mxConstants.STYLE_ENTRY_Y];
  				if (y != null)
  				{
  					point = new mxPoint(parseFloat(x), parseFloat(y));
  				}
  			}
  			var perimeter = false;
  			var dx = 0, dy = 0;
  			if (point != null)
  			{
  				perimeter = mxUtils.getValue(edge.style, (source) ? mxConstants.STYLE_EXIT_PERIMETER :
  					mxConstants.STYLE_ENTRY_PERIMETER, true);
  				dx = parseFloat(edge.style[(source) ? mxConstants.STYLE_EXIT_DX : mxConstants.STYLE_ENTRY_DX]);
  				dy = parseFloat(edge.style[(source) ? mxConstants.STYLE_EXIT_DY : mxConstants.STYLE_ENTRY_DY]);
  				dx = isFinite(dx)? dx : 0;
  				dy = isFinite(dy)? dy : 0;
  			}
  			return new mxConnectionConstraint(point, perimeter, null, dx, dy);
  		};
  		mxGraph.prototype.setConnectionConstraint = function(edge, terminal, source, constraint)
  		{
  			if (constraint != null)
  			{
  				this.model.beginUpdate();
  				try
  				{
  					if (constraint == null || constraint.point == null)
  					{
  						this.setCellStyles((source) ? mxConstants.STYLE_EXIT_X :
  							mxConstants.STYLE_ENTRY_X, null, [edge]);
  						this.setCellStyles((source) ? mxConstants.STYLE_EXIT_Y :
  							mxConstants.STYLE_ENTRY_Y, null, [edge]);
  						this.setCellStyles((source) ? mxConstants.STYLE_EXIT_DX :
  							mxConstants.STYLE_ENTRY_DX, null, [edge]);
  						this.setCellStyles((source) ? mxConstants.STYLE_EXIT_DY :
  							mxConstants.STYLE_ENTRY_DY, null, [edge]);
  						this.setCellStyles((source) ? mxConstants.STYLE_EXIT_PERIMETER :
  							mxConstants.STYLE_ENTRY_PERIMETER, null, [edge]);
  					}
  					else if (constraint.point != null)
  					{
  						this.setCellStyles((source) ? mxConstants.STYLE_EXIT_X :
  							mxConstants.STYLE_ENTRY_X, constraint.point.x, [edge]);
  						this.setCellStyles((source) ? mxConstants.STYLE_EXIT_Y :
  							mxConstants.STYLE_ENTRY_Y, constraint.point.y, [edge]);
  						this.setCellStyles((source) ? mxConstants.STYLE_EXIT_DX :
  							mxConstants.STYLE_ENTRY_DX, constraint.dx, [edge]);
  						this.setCellStyles((source) ? mxConstants.STYLE_EXIT_DY :
  							mxConstants.STYLE_ENTRY_DY, constraint.dy, [edge]);
  						if (!constraint.perimeter)
  						{
  							this.setCellStyles((source) ? mxConstants.STYLE_EXIT_PERIMETER :
  								mxConstants.STYLE_ENTRY_PERIMETER, '0', [edge]);
  						}
  						else
  						{
  							this.setCellStyles((source) ? mxConstants.STYLE_EXIT_PERIMETER :
  								mxConstants.STYLE_ENTRY_PERIMETER, null, [edge]);
  						}
  					}
  				}
  				finally
  				{
  					this.model.endUpdate();
  				}
  			}
  		};
  		mxGraph.prototype.getConnectionPoint = function(vertex, constraint, round)
  		{
  			round = (round != null) ? round : true;
  			var point = null;
  			if (vertex != null && constraint.point != null)
  			{
  				var bounds = this.view.getPerimeterBounds(vertex);
  		        var cx = new mxPoint(bounds.getCenterX(), bounds.getCenterY());
  				var direction = vertex.style[mxConstants.STYLE_DIRECTION];
  				var r1 = 0;
  				if (direction != null && mxUtils.getValue(vertex.style,
  					mxConstants.STYLE_ANCHOR_POINT_DIRECTION, 1) == 1)
  				{
  					if (direction == mxConstants.DIRECTION_NORTH)
  					{
  						r1 += 270;
  					}
  					else if (direction == mxConstants.DIRECTION_WEST)
  					{
  						r1 += 180;
  					}
  					else if (direction == mxConstants.DIRECTION_SOUTH)
  					{
  						r1 += 90;
  					}
  					if (direction == mxConstants.DIRECTION_NORTH ||
  						direction == mxConstants.DIRECTION_SOUTH)
  					{
  						bounds.rotate90();
  					}
  				}
  				var scale = this.view.scale;
  				point = new mxPoint(bounds.x + constraint.point.x * bounds.width + constraint.dx * scale,
  						bounds.y + constraint.point.y * bounds.height + constraint.dy * scale);
  				var r2 = vertex.style[mxConstants.STYLE_ROTATION] || 0;
  				if (constraint.perimeter)
  				{
  					if (r1 != 0)
  					{
  						var cos = 0;
  						var sin = 0;
  						if (r1 == 90)
  						{
  							sin = 1;
  						}
  						else if (r1 == 180)
  						{
  							cos = -1;
  						}
  						else if (r1 == 270)
  						{
  							sin = -1;
  						}
  				        point = mxUtils.getRotatedPoint(point, cos, sin, cx);
  					}
  					point = this.view.getPerimeterPoint(vertex, point, false);
  				}
  				else
  				{
  					r2 += r1;
  					if (this.getModel().isVertex(vertex.cell))
  					{
  						var flipH = vertex.style[mxConstants.STYLE_FLIPH] == 1;
  						var flipV = vertex.style[mxConstants.STYLE_FLIPV] == 1;
  						if (vertex.shape != null && vertex.shape.stencil != null)
  						{
  							flipH = (mxUtils.getValue(vertex.style, 'stencilFlipH', 0) == 1) || flipH;
  							flipV = (mxUtils.getValue(vertex.style, 'stencilFlipV', 0) == 1) || flipV;
  						}
  						if (direction == mxConstants.DIRECTION_NORTH ||
  							direction == mxConstants.DIRECTION_SOUTH)
  						{
  							var temp = flipH;
  							flipH = flipV;
  							flipV = temp;
  						}
  						if (flipH)
  						{
  							point.x = 2 * bounds.getCenterX() - point.x;
  						}
  						if (flipV)
  						{
  							point.y = 2 * bounds.getCenterY() - point.y;
  						}
  					}
  				}
  				if (r2 != 0 && point != null)
  				{
  			        var rad = mxUtils.toRadians(r2);
  			        var cos = Math.cos(rad);
  			        var sin = Math.sin(rad);
  			        point = mxUtils.getRotatedPoint(point, cos, sin, cx);
  				}
  			}
  			if (round && point != null)
  			{
  				point.x = Math.round(point.x);
  				point.y = Math.round(point.y);
  			}
  			return point;
  		};
  		mxGraph.prototype.connectCell = function(edge, terminal, source, constraint)
  		{
  			this.model.beginUpdate();
  			try
  			{
  				var previous = this.model.getTerminal(edge, source);
  				this.cellConnected(edge, terminal, source, constraint);
  				this.fireEvent(new mxEventObject(mxEvent.CONNECT_CELL,
  					'edge', edge, 'terminal', terminal, 'source', source,
  					'previous', previous));
  			}
  			finally
  			{
  				this.model.endUpdate();
  			}
  			return edge;
  		};
  		mxGraph.prototype.cellConnected = function(edge, terminal, source, constraint)
  		{
  			if (edge != null)
  			{
  				this.model.beginUpdate();
  				try
  				{
  					var previous = this.model.getTerminal(edge, source);
  					this.setConnectionConstraint(edge, terminal, source, constraint);
  					if (this.isPortsEnabled())
  					{
  						var id = null;
  						if (this.isPort(terminal))
  						{
  							id = terminal.getId();
  							terminal = this.getTerminalForPort(terminal, source);
  						}
  						var key = (source) ? mxConstants.STYLE_SOURCE_PORT :
  							mxConstants.STYLE_TARGET_PORT;
  						this.setCellStyles(key, id, [edge]);
  					}
  					this.model.setTerminal(edge, terminal, source);
  					if (this.resetEdgesOnConnect)
  					{
  						this.resetEdge(edge);
  					}
  					this.fireEvent(new mxEventObject(mxEvent.CELL_CONNECTED,
  						'edge', edge, 'terminal', terminal, 'source', source,
  						'previous', previous));
  				}
  				finally
  				{
  					this.model.endUpdate();
  				}
  			}
  		};
  		mxGraph.prototype.disconnectGraph = function(cells)
  		{
  			if (cells != null)
  			{
  				this.model.beginUpdate();
  				try
  				{
  					var scale = this.view.scale;
  					var tr = this.view.translate;
  					var dict = new mxDictionary();
  					for (var i = 0; i < cells.length; i++)
  					{
  						dict.put(cells[i], true);
  					}
  					for (var i = 0; i < cells.length; i++)
  					{
  						if (this.model.isEdge(cells[i]))
  						{
  							var geo = this.model.getGeometry(cells[i]);
  							if (geo != null)
  							{
  								var state = this.view.getState(cells[i]);
  								var pstate = this.view.getState(
  									this.model.getParent(cells[i]));
  								if (state != null &&
  									pstate != null)
  								{
  									geo = geo.clone();
  									var dx = -pstate.origin.x;
  									var dy = -pstate.origin.y;
  									var pts = state.absolutePoints;
  									var src = this.model.getTerminal(cells[i], true);
  									if (src != null && this.isCellDisconnectable(cells[i], src, true))
  									{
  										while (src != null && !dict.get(src))
  										{
  											src = this.model.getParent(src);
  										}
  										if (src == null)
  										{
  											geo.setTerminalPoint(
  												new mxPoint(pts[0].x / scale - tr.x + dx,
  													pts[0].y / scale - tr.y + dy), true);
  											this.model.setTerminal(cells[i], null, true);
  										}
  									}
  									var trg = this.model.getTerminal(cells[i], false);
  									if (trg != null && this.isCellDisconnectable(cells[i], trg, false))
  									{
  										while (trg != null && !dict.get(trg))
  										{
  											trg = this.model.getParent(trg);
  										}
  										if (trg == null)
  										{
  											var n = pts.length - 1;
  											geo.setTerminalPoint(
  												new mxPoint(pts[n].x / scale - tr.x + dx,
  													pts[n].y / scale - tr.y + dy), false);
  											this.model.setTerminal(cells[i], null, false);
  										}
  									}
  									this.model.setGeometry(cells[i], geo);
  								}
  							}
  						}
  					}
  				}
  				finally
  				{
  					this.model.endUpdate();
  				}
  			}
  		};
  		mxGraph.prototype.getCurrentRoot = function()
  		{
  			return this.view.currentRoot;
  		};
  		mxGraph.prototype.getTranslateForRoot = function(cell)
  		{
  			return null;
  		};
  		mxGraph.prototype.isPort = function(cell)
  		{
  			return false;
  		};
  		mxGraph.prototype.getTerminalForPort = function(cell, source)
  		{
  			return this.model.getParent(cell);
  		};
  		mxGraph.prototype.getChildOffsetForCell = function(cell)
  		{
  			return null;
  		};
  		mxGraph.prototype.enterGroup = function(cell)
  		{
  			cell = cell || this.getSelectionCell();
  			if (cell != null && this.isValidRoot(cell))
  			{
  				this.view.setCurrentRoot(cell);
  				this.clearSelection();
  			}
  		};
  		mxGraph.prototype.exitGroup = function()
  		{
  			var root = this.model.getRoot();
  			var current = this.getCurrentRoot();
  			if (current != null)
  			{
  				var next = this.model.getParent(current);
  				while (next != root && !this.isValidRoot(next) &&
  						this.model.getParent(next) != root)
  				{
  					next = this.model.getParent(next);
  				}
  				if (next == root || this.model.getParent(next) == root)
  				{
  					this.view.setCurrentRoot(null);
  				}
  				else
  				{
  					this.view.setCurrentRoot(next);
  				}
  				var state = this.view.getState(current);
  				if (state != null)
  				{
  					this.setSelectionCell(current);
  				}
  			}
  		};
  		mxGraph.prototype.home = function()
  		{
  			var current = this.getCurrentRoot();
  			if (current != null)
  			{
  				this.view.setCurrentRoot(null);
  				var state = this.view.getState(current);
  				if (state != null)
  				{
  					this.setSelectionCell(current);
  				}
  			}
  		};
  		mxGraph.prototype.isValidRoot = function(cell)
  		{
  			return (cell != null);
  		};
  		 mxGraph.prototype.getGraphBounds = function()
  		 {
  		 	return this.view.getGraphBounds();
  		 };
  		mxGraph.prototype.getCellBounds = function(cell, includeEdges, includeDescendants)
  		{
  			var cells = [cell];
  			if (includeEdges)
  			{
  				cells = cells.concat(this.model.getEdges(cell));
  			}
  			var result = this.view.getBounds(cells);
  			if (includeDescendants)
  			{
  				var childCount = this.model.getChildCount(cell);
  				for (var i = 0; i < childCount; i++)
  				{
  					var tmp = this.getCellBounds(this.model.getChildAt(cell, i),
  						includeEdges, true);
  					if (result != null)
  					{
  						result.add(tmp);
  					}
  					else
  					{
  						result = tmp;
  					}
  				}
  			}
  			return result;
  		};
  		mxGraph.prototype.getBoundingBoxFromGeometry = function(cells, includeEdges)
  		{
  			includeEdges = (includeEdges != null) ? includeEdges : false;
  			var result = null;
  			if (cells != null)
  			{
  				for (var i = 0; i < cells.length; i++)
  				{
  					if (includeEdges || this.model.isVertex(cells[i]))
  					{
  						var geo = this.getCellGeometry(cells[i]);
  						if (geo != null)
  						{
  							var bbox = null;
  							if (this.model.isEdge(cells[i]))
  							{
  								var addPoint = function(pt)
  								{
  									if (pt != null)
  									{
  										if (tmp == null)
  										{
  											tmp = new mxRectangle(pt.x, pt.y, 0, 0);
  										}
  										else
  										{
  											tmp.add(new mxRectangle(pt.x, pt.y, 0, 0));
  										}
  									}
  								};
  								if (this.model.getTerminal(cells[i], true) == null)
  								{
  									addPoint(geo.getTerminalPoint(true));
  								}
  								if (this.model.getTerminal(cells[i], false) == null)
  								{
  									addPoint(geo.getTerminalPoint(false));
  								}
  								var pts = geo.points;
  								if (pts != null && pts.length > 0)
  								{
  									var tmp = new mxRectangle(pts[0].x, pts[0].y, 0, 0);
  									for (var j = 1; j < pts.length; j++)
  									{
  										addPoint(pts[j]);
  									}
  								}
  								bbox = tmp;
  							}
  							else
  							{
  								var parent = this.model.getParent(cells[i]);
  								if (geo.relative)
  								{
  									if (this.model.isVertex(parent) && parent != this.view.currentRoot)
  									{
  										var tmp = this.getBoundingBoxFromGeometry([parent], false);
  										if (tmp != null)
  										{
  											bbox = new mxRectangle(geo.x * tmp.width, geo.y * tmp.height, geo.width, geo.height);
  											if (mxUtils.indexOf(cells, parent) >= 0)
  											{
  												bbox.x += tmp.x;
  												bbox.y += tmp.y;
  											}
  										}
  									}
  								}
  								else
  								{
  									bbox = mxRectangle.fromRectangle(geo);
  									if (this.model.isVertex(parent) && mxUtils.indexOf(cells, parent) >= 0)
  									{
  										var tmp = this.getBoundingBoxFromGeometry([parent], false);
  										if (tmp != null)
  										{
  											bbox.x += tmp.x;
  											bbox.y += tmp.y;
  										}
  									}
  								}
  								if (bbox != null && geo.offset != null)
  								{
  									bbox.x += geo.offset.x;
  									bbox.y += geo.offset.y;
  								}
  								var style = this.getCurrentCellStyle(cells[i]);
  								if (bbox != null)
  								{
  									var angle = mxUtils.getValue(style, mxConstants.STYLE_ROTATION, 0);
  									if (angle != 0)
  									{
  										bbox = mxUtils.getBoundingBox(bbox, angle);
  									}
  								}
  							}
  							if (bbox != null)
  							{
  								if (result == null)
  								{
  									result = mxRectangle.fromRectangle(bbox);
  								}
  								else
  								{
  									result.add(bbox);
  								}
  							}
  						}
  					}
  				}
  			}
  			return result;
  		};
  		mxGraph.prototype.refresh = function(cell)
  		{
  			this.view.clear(cell, cell == null);
  			this.view.validate();
  			this.sizeDidChange();
  			this.fireEvent(new mxEventObject(mxEvent.REFRESH));
  		};
  		mxGraph.prototype.snap = function(value)
  		{
  			if (this.gridEnabled)
  			{
  				value = Math.round(value / this.gridSize ) * this.gridSize;
  			}
  			return value;
  		};
  		mxGraph.prototype.snapDelta = function(delta, bounds, ignoreGrid, ignoreHorizontal, ignoreVertical)
  		{
  			var t = this.view.translate;
  			var s = this.view.scale;
  			if (!ignoreGrid && this.gridEnabled)
  			{
  				var tol = this.gridSize * s * 0.5;
  				if (!ignoreHorizontal)
  				{
  					var tx = bounds.x - (this.snap(bounds.x / s - t.x) + t.x) * s;
  					if (Math.abs(delta.x- tx) < tol)
  					{
  						delta.x = 0;
  					}
  					else
  					{
  						delta.x = this.snap(delta.x / s) * s - tx;
  					}
  				}
  				if (!ignoreVertical)
  				{
  					var ty = bounds.y - (this.snap(bounds.y / s - t.y) + t.y) * s;
  					if (Math.abs(delta.y - ty) < tol)
  					{
  						delta.y = 0;
  					}
  					else
  					{
  						delta.y = this.snap(delta.y / s) * s - ty;
  					}
  				}
  			}
  			else
  			{
  				var tol = 0.5 * s;
  				if (!ignoreHorizontal)
  				{
  					var tx = bounds.x - (Math.round(bounds.x / s - t.x) + t.x) * s;
  					if (Math.abs(delta.x - tx) < tol)
  					{
  						delta.x = 0;
  					}
  					else
  					{
  						delta.x = Math.round(delta.x / s) * s - tx;
  					}
  				}
  				if (!ignoreVertical)
  				{
  					var ty = bounds.y - (Math.round(bounds.y / s - t.y) + t.y) * s;
  					if (Math.abs(delta.y - ty) < tol)
  					{
  						delta.y = 0;
  					}
  					else
  					{
  						delta.y = Math.round(delta.y / s) * s - ty;
  					}
  				}
  			}
  			return delta;
  		};
  		mxGraph.prototype.panGraph = function(dx, dy)
  		{
  			if (this.useScrollbarsForPanning && mxUtils.hasScrollbars(this.container))
  			{
  				this.container.scrollLeft = -dx;
  				this.container.scrollTop = -dy;
  			}
  			else
  			{
  				var canvas = this.view.getCanvas();
  				if (this.dialect == mxConstants.DIALECT_SVG)
  				{
  					if (dx == 0 && dy == 0)
  					{
  						if (mxClient.IS_IE)
  						{
  							canvas.setAttribute('transform', 'translate(' + dx + ',' + dy + ')');
  						}
  						else
  						{
  							canvas.removeAttribute('transform');
  						}
  						if (this.shiftPreview1 != null)
  						{
  							var child = this.shiftPreview1.firstChild;
  							while (child != null)
  							{
  								var next = child.nextSibling;
  								this.container.appendChild(child);
  								child = next;
  							}
  							if (this.shiftPreview1.parentNode != null)
  							{
  								this.shiftPreview1.parentNode.removeChild(this.shiftPreview1);
  							}
  							this.shiftPreview1 = null;
  							this.container.appendChild(canvas.parentNode);
  							child = this.shiftPreview2.firstChild;
  							while (child != null)
  							{
  								var next = child.nextSibling;
  								this.container.appendChild(child);
  								child = next;
  							}
  							if (this.shiftPreview2.parentNode != null)
  							{
  								this.shiftPreview2.parentNode.removeChild(this.shiftPreview2);
  							}
  							this.shiftPreview2 = null;
  						}
  					}
  					else
  					{
  						canvas.setAttribute('transform', 'translate(' + dx + ',' + dy + ')');
  						if (this.shiftPreview1 == null)
  						{
  							this.shiftPreview1 = document.createElement('div');
  							this.shiftPreview1.style.position = 'absolute';
  							this.shiftPreview1.style.overflow = 'visible';
  							this.shiftPreview2 = document.createElement('div');
  							this.shiftPreview2.style.position = 'absolute';
  							this.shiftPreview2.style.overflow = 'visible';
  							var current = this.shiftPreview1;
  							var child = this.container.firstChild;
  							while (child != null)
  							{
  								var next = child.nextSibling;
  								if (child != canvas.parentNode)
  								{
  									current.appendChild(child);
  								}
  								else
  								{
  									current = this.shiftPreview2;
  								}
  								child = next;
  							}
  							if (this.shiftPreview1.firstChild != null)
  							{
  								this.container.insertBefore(this.shiftPreview1, canvas.parentNode);
  							}
  							if (this.shiftPreview2.firstChild != null)
  							{
  								this.container.appendChild(this.shiftPreview2);
  							}
  						}
  						this.shiftPreview1.style.left = dx + 'px';
  						this.shiftPreview1.style.top = dy + 'px';
  						this.shiftPreview2.style.left = dx + 'px';
  						this.shiftPreview2.style.top = dy + 'px';
  					}
  				}
  				else
  				{
  					canvas.style.left = dx + 'px';
  					canvas.style.top = dy + 'px';
  				}
  				this.panDx = dx;
  				this.panDy = dy;
  				this.fireEvent(new mxEventObject(mxEvent.PAN));
  			}
  		};
  		mxGraph.prototype.zoomIn = function()
  		{
  			this.zoom(this.zoomFactor);
  		};
  		mxGraph.prototype.zoomOut = function()
  		{
  			this.zoom(1 / this.zoomFactor);
  		};
  		mxGraph.prototype.zoomActual = function()
  		{
  			if (this.view.scale == 1)
  			{
  				this.view.setTranslate(0, 0);
  			}
  			else
  			{
  				this.view.translate.x = 0;
  				this.view.translate.y = 0;
  				this.view.setScale(1);
  			}
  		};
  		mxGraph.prototype.zoomTo = function(scale, center)
  		{
  			this.zoom(scale / this.view.scale, center);
  		};
  		mxGraph.prototype.center = function(horizontal, vertical, cx, cy)
  		{
  			horizontal = (horizontal != null) ? horizontal : true;
  			vertical = (vertical != null) ? vertical : true;
  			cx = (cx != null) ? cx : 0.5;
  			cy = (cy != null) ? cy : 0.5;
  			var hasScrollbars = mxUtils.hasScrollbars(this.container);
  			var padding = 2 * this.getBorder();
  			var cw = this.container.clientWidth - padding;
  			var ch = this.container.clientHeight - padding;
  			var bounds = this.getGraphBounds();
  			var t = this.view.translate;
  			var s = this.view.scale;
  			var dx = (horizontal) ? cw - bounds.width : 0;
  			var dy = (vertical) ? ch - bounds.height : 0;
  			if (!hasScrollbars)
  			{
  				this.view.setTranslate((horizontal) ? Math.floor(t.x - bounds.x * s + dx * cx / s) : t.x,
  					(vertical) ? Math.floor(t.y - bounds.y * s + dy * cy / s) : t.y);
  			}
  			else
  			{
  				bounds.x -= t.x;
  				bounds.y -= t.y;
  				var sw = this.container.scrollWidth;
  				var sh = this.container.scrollHeight;
  				if (sw > cw)
  				{
  					dx = 0;
  				}
  				if (sh > ch)
  				{
  					dy = 0;
  				}
  				this.view.setTranslate(Math.floor(dx / 2 - bounds.x), Math.floor(dy / 2 - bounds.y));
  				this.container.scrollLeft = (sw - cw) / 2;
  				this.container.scrollTop = (sh - ch) / 2;
  			}
  		};
  		mxGraph.prototype.zoom = function(factor, center)
  		{
  			center = (center != null) ? center : this.centerZoom;
  			var scale = Math.round(this.view.scale * factor * 100) / 100;
  			var state = this.view.getState(this.getSelectionCell());
  			factor = scale / this.view.scale;
  			if (this.keepSelectionVisibleOnZoom && state != null)
  			{
  				var rect = new mxRectangle(state.x * factor, state.y * factor,
  					state.width * factor, state.height * factor);
  				this.view.scale = scale;
  				if (!this.scrollRectToVisible(rect))
  				{
  					this.view.revalidate();
  					this.view.setScale(scale);
  				}
  			}
  			else
  			{
  				var hasScrollbars = mxUtils.hasScrollbars(this.container);
  				if (center && !hasScrollbars)
  				{
  					var dx = this.container.offsetWidth;
  					var dy = this.container.offsetHeight;
  					if (factor > 1)
  					{
  						var f = (factor - 1) / (scale * 2);
  						dx *= -f;
  						dy *= -f;
  					}
  					else
  					{
  						var f = (1 / factor - 1) / (this.view.scale * 2);
  						dx *= f;
  						dy *= f;
  					}
  					this.view.scaleAndTranslate(scale,
  						this.view.translate.x + dx,
  						this.view.translate.y + dy);
  				}
  				else
  				{
  					var tx = this.view.translate.x;
  					var ty = this.view.translate.y;
  					var sl = this.container.scrollLeft;
  					var st = this.container.scrollTop;
  					this.view.setScale(scale);
  					if (hasScrollbars)
  					{
  						var dx = 0;
  						var dy = 0;
  						if (center)
  						{
  							dx = this.container.offsetWidth * (factor - 1) / 2;
  							dy = this.container.offsetHeight * (factor - 1) / 2;
  						}
  						this.container.scrollLeft = (this.view.translate.x - tx) * this.view.scale + Math.round(sl * factor + dx);
  						this.container.scrollTop = (this.view.translate.y - ty) * this.view.scale + Math.round(st * factor + dy);
  					}
  				}
  			}
  		};
  		mxGraph.prototype.zoomToRect = function(rect)
  		{
  			var scaleX = this.container.clientWidth / rect.width;
  			var scaleY = this.container.clientHeight / rect.height;
  			var aspectFactor = scaleX / scaleY;
  			rect.x = Math.max(0, rect.x);
  			rect.y = Math.max(0, rect.y);
  			var rectRight = Math.min(this.container.scrollWidth, rect.x + rect.width);
  			var rectBottom = Math.min(this.container.scrollHeight, rect.y + rect.height);
  			rect.width = rectRight - rect.x;
  			rect.height = rectBottom - rect.y;
  			if (aspectFactor < 1.0)
  			{
  				var newHeight = rect.height / aspectFactor;
  				var deltaHeightBuffer = (newHeight - rect.height) / 2.0;
  				rect.height = newHeight;
  				var upperBuffer = Math.min(rect.y , deltaHeightBuffer);
  				rect.y = rect.y - upperBuffer;
  				rectBottom = Math.min(this.container.scrollHeight, rect.y + rect.height);
  				rect.height = rectBottom - rect.y;
  			}
  			else
  			{
  				var newWidth = rect.width * aspectFactor;
  				var deltaWidthBuffer = (newWidth - rect.width) / 2.0;
  				rect.width = newWidth;
  				var leftBuffer = Math.min(rect.x , deltaWidthBuffer);
  				rect.x = rect.x - leftBuffer;
  				rectRight = Math.min(this.container.scrollWidth, rect.x + rect.width);
  				rect.width = rectRight - rect.x;
  			}
  			var scale = this.container.clientWidth / rect.width;
  			var newScale = this.view.scale * scale;
  			if (!mxUtils.hasScrollbars(this.container))
  			{
  				this.view.scaleAndTranslate(newScale, (this.view.translate.x - rect.x / this.view.scale), (this.view.translate.y - rect.y / this.view.scale));
  			}
  			else
  			{
  				this.view.setScale(newScale);
  				this.container.scrollLeft = Math.round(rect.x * scale);
  				this.container.scrollTop = Math.round(rect.y * scale);
  			}
  		};
  		mxGraph.prototype.scrollCellToVisible = function(cell, center)
  		{
  			var x = -this.view.translate.x;
  			var y = -this.view.translate.y;
  			var state = this.view.getState(cell);
  			if (state != null)
  			{
  				var bounds = new mxRectangle(x + state.x, y + state.y, state.width,
  					state.height);
  				if (center && this.container != null)
  				{
  					var w = this.container.clientWidth;
  					var h = this.container.clientHeight;
  					bounds.x = bounds.getCenterX() - w / 2;
  					bounds.width = w;
  					bounds.y = bounds.getCenterY() - h / 2;
  					bounds.height = h;
  				}
  				var tr = new mxPoint(this.view.translate.x, this.view.translate.y);
  				if (this.scrollRectToVisible(bounds))
  				{
  					var tr2 = new mxPoint(this.view.translate.x, this.view.translate.y);
  					this.view.translate.x = tr.x;
  					this.view.translate.y = tr.y;
  					this.view.setTranslate(tr2.x, tr2.y);
  				}
  			}
  		};
  		mxGraph.prototype.scrollRectToVisible = function(rect)
  		{
  			var isChanged = false;
  			if (rect != null)
  			{
  				var w = this.container.offsetWidth;
  				var h = this.container.offsetHeight;
  		        var widthLimit = Math.min(w, rect.width);
  		        var heightLimit = Math.min(h, rect.height);
  				if (mxUtils.hasScrollbars(this.container))
  				{
  					var c = this.container;
  					rect.x += this.view.translate.x;
  					rect.y += this.view.translate.y;
  					var dx = c.scrollLeft - rect.x;
  					var ddx = Math.max(dx - c.scrollLeft, 0);
  					if (dx > 0)
  					{
  						c.scrollLeft -= dx + 2;
  					}
  					else
  					{
  						dx = rect.x + widthLimit - c.scrollLeft - c.clientWidth;
  						if (dx > 0)
  						{
  							c.scrollLeft += dx + 2;
  						}
  					}
  					var dy = c.scrollTop - rect.y;
  					var ddy = Math.max(0, dy - c.scrollTop);
  					if (dy > 0)
  					{
  						c.scrollTop -= dy + 2;
  					}
  					else
  					{
  						dy = rect.y + heightLimit - c.scrollTop - c.clientHeight;
  						if (dy > 0)
  						{
  							c.scrollTop += dy + 2;
  						}
  					}
  					if (!this.useScrollbarsForPanning && (ddx != 0 || ddy != 0))
  					{
  						this.view.setTranslate(ddx, ddy);
  					}
  				}
  				else
  				{
  					var x = -this.view.translate.x;
  					var y = -this.view.translate.y;
  					var s = this.view.scale;
  					if (rect.x + widthLimit > x + w)
  					{
  						this.view.translate.x -= (rect.x + widthLimit - w - x) / s;
  						isChanged = true;
  					}
  					if (rect.y + heightLimit > y + h)
  					{
  						this.view.translate.y -= (rect.y + heightLimit - h - y) / s;
  						isChanged = true;
  					}
  					if (rect.x < x)
  					{
  						this.view.translate.x += (x - rect.x) / s;
  						isChanged = true;
  					}
  					if (rect.y  < y)
  					{
  						this.view.translate.y += (y - rect.y) / s;
  						isChanged = true;
  					}
  					if (isChanged)
  					{
  						this.view.refresh();
  						if (this.selectionCellsHandler != null)
  						{
  							this.selectionCellsHandler.refresh();
  						}
  					}
  				}
  			}
  			return isChanged;
  		};
  		mxGraph.prototype.getCellGeometry = function(cell)
  		{
  			return this.model.getGeometry(cell);
  		};
  		mxGraph.prototype.isCellVisible = function(cell)
  		{
  			return this.model.isVisible(cell);
  		};
  		mxGraph.prototype.isCellCollapsed = function(cell)
  		{
  			return this.model.isCollapsed(cell);
  		};
  		mxGraph.prototype.isCellConnectable = function(cell)
  		{
  			return this.model.isConnectable(cell);
  		};
  		mxGraph.prototype.isOrthogonal = function(edge)
  		{
  			var orthogonal = edge.style[mxConstants.STYLE_ORTHOGONAL];
  			if (orthogonal != null)
  			{
  				return orthogonal;
  			}
  			var tmp = this.view.getEdgeStyle(edge);
  			return tmp == mxEdgeStyle.SegmentConnector ||
  				tmp == mxEdgeStyle.ElbowConnector ||
  				tmp == mxEdgeStyle.SideToSide ||
  				tmp == mxEdgeStyle.TopToBottom ||
  				tmp == mxEdgeStyle.EntityRelation ||
  				tmp == mxEdgeStyle.OrthConnector;
  		};
  		mxGraph.prototype.isLoop = function(state)
  		{
  			var src = state.getVisibleTerminalState(true);
  			var trg = state.getVisibleTerminalState(false);
  			return (src != null && src == trg);
  		};
  		mxGraph.prototype.isCloneEvent = function(evt)
  		{
  			return mxEvent.isControlDown(evt);
  		};
  		mxGraph.prototype.isTransparentClickEvent = function(evt)
  		{
  			return false;
  		};
  		mxGraph.prototype.isToggleEvent = function(evt)
  		{
  			return (mxClient.IS_MAC) ? mxEvent.isMetaDown(evt) : mxEvent.isControlDown(evt);
  		};
  		mxGraph.prototype.isGridEnabledEvent = function(evt)
  		{
  			return evt != null && !mxEvent.isAltDown(evt);
  		};
  		mxGraph.prototype.isConstrainedEvent = function(evt)
  		{
  			return mxEvent.isShiftDown(evt);
  		};
  		mxGraph.prototype.isIgnoreTerminalEvent = function(evt)
  		{
  			return false;
  		};
  		mxGraph.prototype.validationAlert = function(message)
  		{
  			mxUtils.alert(message);
  		};
  		mxGraph.prototype.isEdgeValid = function(edge, source, target)
  		{
  			return this.getEdgeValidationError(edge, source, target) == null;
  		};
  		mxGraph.prototype.getEdgeValidationError = function(edge, source, target)
  		{
  			if (edge != null && !this.isAllowDanglingEdges() && (source == null || target == null))
  			{
  				return '';
  			}
  			if (edge != null && this.model.getTerminal(edge, true) == null &&
  				this.model.getTerminal(edge, false) == null)
  			{
  				return null;
  			}
  			if (!this.allowLoops && source == target && source != null)
  			{
  				return '';
  			}
  			if (!this.isValidConnection(source, target))
  			{
  				return '';
  			}
  			if (source != null && target != null)
  			{
  				var error = '';
  				if (!this.multigraph)
  				{
  					var tmp = this.model.getEdgesBetween(source, target, true);
  					if (tmp.length > 1 || (tmp.length == 1 && tmp[0] != edge))
  					{
  						error += (mxResources.get(this.alreadyConnectedResource) ||
  							this.alreadyConnectedResource)+'\n';
  					}
  				}
  				var sourceOut = this.model.getDirectedEdgeCount(source, true, edge);
  				var targetIn = this.model.getDirectedEdgeCount(target, false, edge);
  				if (this.multiplicities != null)
  				{
  					for (var i = 0; i < this.multiplicities.length; i++)
  					{
  						var err = this.multiplicities[i].check(this, edge, source,
  							target, sourceOut, targetIn);
  						if (err != null)
  						{
  							error += err;
  						}
  					}
  				}
  				var err = this.validateEdge(edge, source, target);
  				if (err != null)
  				{
  					error += err;
  				}
  				return (error.length > 0) ? error : null;
  			}
  			return (this.allowDanglingEdges) ? null : '';
  		};
  		mxGraph.prototype.validateEdge = function(edge, source, target)
  		{
  			return null;
  		};
  		mxGraph.prototype.validateGraph = function(cell, context)
  		{
  			cell = (cell != null) ? cell : this.model.getRoot();
  			context = (context != null) ? context : new Object();
  			var isValid = true;
  			var childCount = this.model.getChildCount(cell);
  			for (var i = 0; i < childCount; i++)
  			{
  				var tmp = this.model.getChildAt(cell, i);
  				var ctx = context;
  				if (this.isValidRoot(tmp))
  				{
  					ctx = new Object();
  				}
  				var warn = this.validateGraph(tmp, ctx);
  				if (warn != null)
  				{
  					this.setCellWarning(tmp, warn.replace(/\n/g, '<br>'));
  				}
  				else
  				{
  					this.setCellWarning(tmp, null);
  				}
  				isValid = isValid && warn == null;
  			}
  			var warning = '';
  			if (this.isCellCollapsed(cell) && !isValid)
  			{
  				warning += (mxResources.get(this.containsValidationErrorsResource) ||
  					this.containsValidationErrorsResource) + '\n';
  			}
  			if (this.model.isEdge(cell))
  			{
  				warning += this.getEdgeValidationError(cell,
  				this.model.getTerminal(cell, true),
  				this.model.getTerminal(cell, false)) || '';
  			}
  			else
  			{
  				warning += this.getCellValidationError(cell) || '';
  			}
  			var err = this.validateCell(cell, context);
  			if (err != null)
  			{
  				warning += err;
  			}
  			if (this.model.getParent(cell) == null)
  			{
  				this.view.validate();
  			}
  			return (warning.length > 0 || !isValid) ? warning : null;
  		};
  		mxGraph.prototype.getCellValidationError = function(cell)
  		{
  			var outCount = this.model.getDirectedEdgeCount(cell, true);
  			var inCount = this.model.getDirectedEdgeCount(cell, false);
  			var value = this.model.getValue(cell);
  			var error = '';
  			if (this.multiplicities != null)
  			{
  				for (var i = 0; i < this.multiplicities.length; i++)
  				{
  					var rule = this.multiplicities[i];
  					if (rule.source && mxUtils.isNode(value, rule.type,
  						rule.attr, rule.value) && (outCount > rule.max ||
  						outCount < rule.min))
  					{
  						error += rule.countError + '\n';
  					}
  					else if (!rule.source && mxUtils.isNode(value, rule.type,
  							rule.attr, rule.value) && (inCount > rule.max ||
  							inCount < rule.min))
  					{
  						error += rule.countError + '\n';
  					}
  				}
  			}
  			return (error.length > 0) ? error : null;
  		};
  		mxGraph.prototype.validateCell = function(cell, context)
  		{
  			return null;
  		};
  		mxGraph.prototype.getBackgroundImage = function()
  		{
  			return this.backgroundImage;
  		};
  		mxGraph.prototype.setBackgroundImage = function(image)
  		{
  			this.backgroundImage = image;
  		};
  		mxGraph.prototype.getFoldingImage = function(state)
  		{
  			if (state != null && this.foldingEnabled && !this.getModel().isEdge(state.cell))
  			{
  				var tmp = this.isCellCollapsed(state.cell);
  				if (this.isCellFoldable(state.cell, !tmp))
  				{
  					return (tmp) ? this.collapsedImage : this.expandedImage;
  				}
  			}
  			return null;
  		};
  		mxGraph.prototype.convertValueToString = function(cell)
  		{
  			var value = this.model.getValue(cell);
  			if (value != null)
  			{
  				if (mxUtils.isNode(value))
  				{
  					return value.nodeName;
  				}
  				else if (typeof(value.toString) == 'function')
  				{
  					return value.toString();
  				}
  			}
  			return '';
  		};
  		mxGraph.prototype.getLabel = function(cell)
  		{
  			var result = '';
  			if (this.labelsVisible && cell != null)
  			{
  				var style = this.getCurrentCellStyle(cell);
  				if (!mxUtils.getValue(style, mxConstants.STYLE_NOLABEL, false))
  				{
  					result = this.convertValueToString(cell);
  				}
  			}
  			return result;
  		};
  		mxGraph.prototype.isHtmlLabel = function(cell)
  		{
  			return this.isHtmlLabels();
  		};
  		mxGraph.prototype.isHtmlLabels = function()
  		{
  			return this.htmlLabels;
  		};
  		mxGraph.prototype.setHtmlLabels = function(value)
  		{
  			this.htmlLabels = value;
  		};
  		mxGraph.prototype.isWrapping = function(cell)
  		{
  			return this.getCurrentCellStyle(cell)[mxConstants.STYLE_WHITE_SPACE] == 'wrap';
  		};
  		mxGraph.prototype.isLabelClipped = function(cell)
  		{
  			return this.getCurrentCellStyle(cell)[mxConstants.STYLE_OVERFLOW] == 'hidden';
  		};
  		mxGraph.prototype.getTooltip = function(state, node, x, y)
  		{
  			var tip = null;
  			if (state != null)
  			{
  				if (state.control != null && (node == state.control.node ||
  					node.parentNode == state.control.node))
  				{
  					tip = this.collapseExpandResource;
  					tip = mxUtils.htmlEntities(mxResources.get(tip) || tip).replace(/\\n/g, '<br>');
  				}
  				if (tip == null && state.overlays != null)
  				{
  					state.overlays.visit(function(id, shape)
  					{
  						if (tip == null && (node == shape.node || node.parentNode == shape.node))
  						{
  							tip = shape.overlay.toString();
  						}
  					});
  				}
  				if (tip == null)
  				{
  					var handler = this.selectionCellsHandler.getHandler(state.cell);
  					if (handler != null && typeof(handler.getTooltipForNode) == 'function')
  					{
  						tip = handler.getTooltipForNode(node);
  					}
  				}
  				if (tip == null)
  				{
  					tip = this.getTooltipForCell(state.cell);
  				}
  			}
  			return tip;
  		};
  		mxGraph.prototype.getTooltipForCell = function(cell)
  		{
  			var tip = null;
  			if (cell != null && cell.getTooltip != null)
  			{
  				tip = cell.getTooltip();
  			}
  			else
  			{
  				tip = this.convertValueToString(cell);
  			}
  			return tip;
  		};
  		mxGraph.prototype.getLinkForCell = function(cell)
  		{
  			return null;
  		};
  		mxGraph.prototype.getCursorForMouseEvent = function(me)
  		{
  			return this.getCursorForCell(me.getCell());
  		};
  		mxGraph.prototype.getCursorForCell = function(cell)
  		{
  			return null;
  		};
  		mxGraph.prototype.getStartSize = function(swimlane, ignoreState)
  		{
  			var result = new mxRectangle();
  			var style = this.getCurrentCellStyle(swimlane, ignoreState);
  			var size = parseInt(mxUtils.getValue(style,
  				mxConstants.STYLE_STARTSIZE, mxConstants.DEFAULT_STARTSIZE));
  			if (mxUtils.getValue(style, mxConstants.STYLE_HORIZONTAL, true))
  			{
  				result.height = size;
  			}
  			else
  			{
  				result.width = size;
  			}
  			return result;
  		};
  		mxGraph.prototype.getSwimlaneDirection = function(style)
  		{
  			var dir = mxUtils.getValue(style, mxConstants.STYLE_DIRECTION, mxConstants.DIRECTION_EAST);
  			var flipH = mxUtils.getValue(style, mxConstants.STYLE_FLIPH, 0) == 1;
  			var flipV = mxUtils.getValue(style, mxConstants.STYLE_FLIPV, 0) == 1;
  			var h = mxUtils.getValue(style, mxConstants.STYLE_HORIZONTAL, true);
  			var n = (h) ? 0 : 3;
  			if (dir == mxConstants.DIRECTION_NORTH)
  			{
  				n--;
  			}
  			else if (dir == mxConstants.DIRECTION_WEST)
  			{
  				n += 2;
  			}
  			else if (dir == mxConstants.DIRECTION_SOUTH)
  			{
  				n += 1;
  			}
  			var mod = mxUtils.mod(n, 2);
  			if (flipH && mod == 1)
  			{
  				n += 2;
  			}
  			if (flipV && mod == 0)
  			{
  				n += 2;
  			}
  			return [mxConstants.DIRECTION_NORTH, mxConstants.DIRECTION_EAST,
  				mxConstants.DIRECTION_SOUTH, mxConstants.DIRECTION_WEST]
  				[mxUtils.mod(n, 4)];
  		};
  		mxGraph.prototype.getActualStartSize = function(swimlane, ignoreState)
  		{
  			var result = new mxRectangle();
  			if (this.isSwimlane(swimlane, ignoreState))
  			{
  				var style = this.getCurrentCellStyle(swimlane, ignoreState);
  				var size = parseInt(mxUtils.getValue(style, mxConstants.STYLE_STARTSIZE,
  					mxConstants.DEFAULT_STARTSIZE));
  				var dir = this.getSwimlaneDirection(style);
  				if (dir == mxConstants.DIRECTION_NORTH)
  				{
  					result.y = size;
  				}
  				else if (dir == mxConstants.DIRECTION_WEST)
  				{
  					result.x = size;
  				}
  				else if (dir == mxConstants.DIRECTION_SOUTH)
  				{
  					result.height = size;
  				}
  				else
  				{
  					result.width = size;
  				}
  			}
  			return result;
  		};
  		mxGraph.prototype.getImage = function(state)
  		{
  			return (state != null && state.style != null) ? state.style[mxConstants.STYLE_IMAGE] : null;
  		};
  		mxGraph.prototype.isTransparentState = function(state)
  		{
  			var result = false;
  			if (state != null)
  			{
  				var stroke = mxUtils.getValue(state.style, mxConstants.STYLE_STROKECOLOR, mxConstants.NONE);
  				var fill = mxUtils.getValue(state.style, mxConstants.STYLE_FILLCOLOR, mxConstants.NONE);
  				result = stroke == mxConstants.NONE && fill == mxConstants.NONE && this.getImage(state) == null;
  			}
  			return result;
  		};
  		mxGraph.prototype.getVerticalAlign = function(state)
  		{
  			return (state != null && state.style != null) ?
  				(state.style[mxConstants.STYLE_VERTICAL_ALIGN] ||
  				mxConstants.ALIGN_MIDDLE) : null;
  		};
  		mxGraph.prototype.getIndicatorColor = function(state)
  		{
  			return (state != null && state.style != null) ? state.style[mxConstants.STYLE_INDICATOR_COLOR] : null;
  		};
  		mxGraph.prototype.getIndicatorGradientColor = function(state)
  		{
  			return (state != null && state.style != null) ? state.style[mxConstants.STYLE_INDICATOR_GRADIENTCOLOR] : null;
  		};
  		mxGraph.prototype.getIndicatorShape = function(state)
  		{
  			return (state != null && state.style != null) ? state.style[mxConstants.STYLE_INDICATOR_SHAPE] : null;
  		};
  		mxGraph.prototype.getIndicatorImage = function(state)
  		{
  			return (state != null && state.style != null) ? state.style[mxConstants.STYLE_INDICATOR_IMAGE] : null;
  		};
  		mxGraph.prototype.getBorder = function()
  		{
  			return this.border;
  		};
  		mxGraph.prototype.setBorder = function(value)
  		{
  			this.border = value;
  		};
  		mxGraph.prototype.isSwimlane = function(cell, ignoreState)
  		{
  			if (cell != null && this.model.getParent(cell) != this.model.getRoot() &&
  				!this.model.isEdge(cell))
  			{
  				return this.getCurrentCellStyle(cell, ignoreState)
  					[mxConstants.STYLE_SHAPE] == mxConstants.SHAPE_SWIMLANE;
  			}
  			return false;
  		};
  		mxGraph.prototype.isResizeContainer = function()
  		{
  			return this.resizeContainer;
  		};
  		mxGraph.prototype.setResizeContainer = function(value)
  		{
  			this.resizeContainer = value;
  		};
  		mxGraph.prototype.isEnabled = function()
  		{
  			return this.enabled;
  		};
  		mxGraph.prototype.setEnabled = function(value)
  		{
  			this.enabled = value;
  		};
  		mxGraph.prototype.isEscapeEnabled = function()
  		{
  			return this.escapeEnabled;
  		};
  		mxGraph.prototype.setEscapeEnabled = function(value)
  		{
  			this.escapeEnabled = value;
  		};
  		mxGraph.prototype.isInvokesStopCellEditing = function()
  		{
  			return this.invokesStopCellEditing;
  		};
  		mxGraph.prototype.setInvokesStopCellEditing = function(value)
  		{
  			this.invokesStopCellEditing = value;
  		};
  		mxGraph.prototype.isEnterStopsCellEditing = function()
  		{
  			return this.enterStopsCellEditing;
  		};
  		mxGraph.prototype.setEnterStopsCellEditing = function(value)
  		{
  			this.enterStopsCellEditing = value;
  		};
  		mxGraph.prototype.isCellLocked = function(cell)
  		{
  			var geometry = this.model.getGeometry(cell);
  			return this.isCellsLocked() || (geometry != null && this.model.isVertex(cell) && geometry.relative);
  		};
  		mxGraph.prototype.isCellsLocked = function()
  		{
  			return this.cellsLocked;
  		};
  		mxGraph.prototype.setCellsLocked = function(value)
  		{
  			this.cellsLocked = value;
  		};
  		mxGraph.prototype.getCloneableCells = function(cells)
  		{
  			return this.model.filterCells(cells, mxUtils.bind(this, function(cell)
  			{
  				return this.isCellCloneable(cell);
  			}));
  		};
  		mxGraph.prototype.isCellCloneable = function(cell)
  		{
  			var style = this.getCurrentCellStyle(cell);
  			return this.isCellsCloneable() && style[mxConstants.STYLE_CLONEABLE] != 0;
  		};
  		mxGraph.prototype.isCellsCloneable = function()
  		{
  			return this.cellsCloneable;
  		};
  		mxGraph.prototype.setCellsCloneable = function(value)
  		{
  			this.cellsCloneable = value;
  		};
  		mxGraph.prototype.getExportableCells = function(cells)
  		{
  			return this.model.filterCells(cells, mxUtils.bind(this, function(cell)
  			{
  				return this.canExportCell(cell);
  			}));
  		};
  		mxGraph.prototype.canExportCell = function(cell)
  		{
  			return this.exportEnabled;
  		};
  		mxGraph.prototype.getImportableCells = function(cells)
  		{
  			return this.model.filterCells(cells, mxUtils.bind(this, function(cell)
  			{
  				return this.canImportCell(cell);
  			}));
  		};
  		mxGraph.prototype.canImportCell = function(cell)
  		{
  			return this.importEnabled;
  		};
  		mxGraph.prototype.isCellSelectable = function(cell)
  		{
  			return this.isCellsSelectable();
  		};
  		mxGraph.prototype.isCellsSelectable = function()
  		{
  			return this.cellsSelectable;
  		};
  		mxGraph.prototype.setCellsSelectable = function(value)
  		{
  			this.cellsSelectable = value;
  		};
  		mxGraph.prototype.getDeletableCells = function(cells)
  		{
  			return this.model.filterCells(cells, mxUtils.bind(this, function(cell)
  			{
  				return this.isCellDeletable(cell);
  			}));
  		};
  		mxGraph.prototype.isCellDeletable = function(cell)
  		{
  			var style = this.getCurrentCellStyle(cell);
  			return this.isCellsDeletable() && style[mxConstants.STYLE_DELETABLE] != 0;
  		};
  		mxGraph.prototype.isCellsDeletable = function()
  		{
  			return this.cellsDeletable;
  		};
  		mxGraph.prototype.setCellsDeletable = function(value)
  		{
  			this.cellsDeletable = value;
  		};
  		mxGraph.prototype.isLabelMovable = function(cell)
  		{
  			return !this.isCellLocked(cell) &&
  				((this.model.isEdge(cell) && this.edgeLabelsMovable) ||
  				(this.model.isVertex(cell) && this.vertexLabelsMovable));
  		};
  		mxGraph.prototype.isCellRotatable = function(cell)
  		{
  			var style = this.getCurrentCellStyle(cell);
  			return style[mxConstants.STYLE_ROTATABLE] != 0;
  		};
  		mxGraph.prototype.getMovableCells = function(cells)
  		{
  			return this.model.filterCells(cells, mxUtils.bind(this, function(cell)
  			{
  				return this.isCellMovable(cell);
  			}));
  		};
  		mxGraph.prototype.isCellMovable = function(cell)
  		{
  			var style = this.getCurrentCellStyle(cell);
  			return this.isCellsMovable() && !this.isCellLocked(cell) && style[mxConstants.STYLE_MOVABLE] != 0;
  		};
  		mxGraph.prototype.isCellsMovable = function()
  		{
  			return this.cellsMovable;
  		};
  		mxGraph.prototype.setCellsMovable = function(value)
  		{
  			this.cellsMovable = value;
  		};
  		mxGraph.prototype.isGridEnabled = function()
  		{
  			return this.gridEnabled;
  		};
  		mxGraph.prototype.setGridEnabled = function(value)
  		{
  			this.gridEnabled = value;
  		};
  		mxGraph.prototype.isPortsEnabled = function()
  		{
  			return this.portsEnabled;
  		};
  		mxGraph.prototype.setPortsEnabled = function(value)
  		{
  			this.portsEnabled = value;
  		};
  		mxGraph.prototype.getGridSize = function()
  		{
  			return this.gridSize;
  		};
  		mxGraph.prototype.setGridSize = function(value)
  		{
  			this.gridSize = value;
  		};
  		mxGraph.prototype.getTolerance = function()
  		{
  			return this.tolerance;
  		};
  		mxGraph.prototype.setTolerance = function(value)
  		{
  			this.tolerance = value;
  		};
  		mxGraph.prototype.isVertexLabelsMovable = function()
  		{
  			return this.vertexLabelsMovable;
  		};
  		mxGraph.prototype.setVertexLabelsMovable = function(value)
  		{
  			this.vertexLabelsMovable = value;
  		};
  		mxGraph.prototype.isEdgeLabelsMovable = function()
  		{
  			return this.edgeLabelsMovable;
  		};
  		mxGraph.prototype.setEdgeLabelsMovable = function(value)
  		{
  			this.edgeLabelsMovable = value;
  		};
  		mxGraph.prototype.isSwimlaneNesting = function()
  		{
  			return this.swimlaneNesting;
  		};
  		mxGraph.prototype.setSwimlaneNesting = function(value)
  		{
  			this.swimlaneNesting = value;
  		};
  		mxGraph.prototype.isSwimlaneSelectionEnabled = function()
  		{
  			return this.swimlaneSelectionEnabled;
  		};
  		mxGraph.prototype.setSwimlaneSelectionEnabled = function(value)
  		{
  			this.swimlaneSelectionEnabled = value;
  		};
  		mxGraph.prototype.isMultigraph = function()
  		{
  			return this.multigraph;
  		};
  		mxGraph.prototype.setMultigraph = function(value)
  		{
  			this.multigraph = value;
  		};
  		mxGraph.prototype.isAllowLoops = function()
  		{
  			return this.allowLoops;
  		};
  		mxGraph.prototype.setAllowDanglingEdges = function(value)
  		{
  			this.allowDanglingEdges = value;
  		};
  		mxGraph.prototype.isAllowDanglingEdges = function()
  		{
  			return this.allowDanglingEdges;
  		};
  		mxGraph.prototype.setConnectableEdges = function(value)
  		{
  			this.connectableEdges = value;
  		};
  		mxGraph.prototype.isConnectableEdges = function()
  		{
  			return this.connectableEdges;
  		};
  		mxGraph.prototype.setCloneInvalidEdges = function(value)
  		{
  			this.cloneInvalidEdges = value;
  		};
  		mxGraph.prototype.isCloneInvalidEdges = function()
  		{
  			return this.cloneInvalidEdges;
  		};
  		mxGraph.prototype.setAllowLoops = function(value)
  		{
  			this.allowLoops = value;
  		};
  		mxGraph.prototype.isDisconnectOnMove = function()
  		{
  			return this.disconnectOnMove;
  		};
  		mxGraph.prototype.setDisconnectOnMove = function(value)
  		{
  			this.disconnectOnMove = value;
  		};
  		mxGraph.prototype.isDropEnabled = function()
  		{
  			return this.dropEnabled;
  		};
  		mxGraph.prototype.setDropEnabled = function(value)
  		{
  			this.dropEnabled = value;
  		};
  		mxGraph.prototype.isSplitEnabled = function()
  		{
  			return this.splitEnabled;
  		};
  		mxGraph.prototype.setSplitEnabled = function(value)
  		{
  			this.splitEnabled = value;
  		};
  		mxGraph.prototype.isCellResizable = function(cell)
  		{
  			var style = this.getCurrentCellStyle(cell);
  			return this.isCellsResizable() && !this.isCellLocked(cell) &&
  				mxUtils.getValue(style, mxConstants.STYLE_RESIZABLE, '1') != '0';
  		};
  		mxGraph.prototype.isCellsResizable = function()
  		{
  			return this.cellsResizable;
  		};
  		mxGraph.prototype.setCellsResizable = function(value)
  		{
  			this.cellsResizable = value;
  		};
  		mxGraph.prototype.isTerminalPointMovable = function(cell, source)
  		{
  			return true;
  		};
  		mxGraph.prototype.isCellBendable = function(cell)
  		{
  			var style = this.getCurrentCellStyle(cell);
  			return this.isCellsBendable() && !this.isCellLocked(cell) && style[mxConstants.STYLE_BENDABLE] != 0;
  		};
  		mxGraph.prototype.isCellsBendable = function()
  		{
  			return this.cellsBendable;
  		};
  		mxGraph.prototype.setCellsBendable = function(value)
  		{
  			this.cellsBendable = value;
  		};
  		mxGraph.prototype.isCellEditable = function(cell)
  		{
  			var style = this.getCurrentCellStyle(cell);
  			return this.isCellsEditable() && !this.isCellLocked(cell) && style[mxConstants.STYLE_EDITABLE] != 0;
  		};
  		mxGraph.prototype.isCellsEditable = function()
  		{
  			return this.cellsEditable;
  		};
  		mxGraph.prototype.setCellsEditable = function(value)
  		{
  			this.cellsEditable = value;
  		};
  		mxGraph.prototype.isCellDisconnectable = function(cell, terminal, source)
  		{
  			return this.isCellsDisconnectable() && !this.isCellLocked(cell);
  		};
  		mxGraph.prototype.isCellsDisconnectable = function()
  		{
  			return this.cellsDisconnectable;
  		};
  		mxGraph.prototype.setCellsDisconnectable = function(value)
  		{
  			this.cellsDisconnectable = value;
  		};
  		mxGraph.prototype.isValidSource = function(cell)
  		{
  			return (cell == null && this.allowDanglingEdges) ||
  				(cell != null && (!this.model.isEdge(cell) ||
  				this.connectableEdges) && this.isCellConnectable(cell));
  		};
  		mxGraph.prototype.isValidTarget = function(cell)
  		{
  			return this.isValidSource(cell);
  		};
  		mxGraph.prototype.isValidConnection = function(source, target)
  		{
  			return this.isValidSource(source) && this.isValidTarget(target);
  		};
  		mxGraph.prototype.setConnectable = function(connectable)
  		{
  			this.connectionHandler.setEnabled(connectable);
  		};
  		mxGraph.prototype.isConnectable = function()
  		{
  			return this.connectionHandler.isEnabled();
  		};
  		mxGraph.prototype.setTooltips = function (enabled)
  		{
  			this.tooltipHandler.setEnabled(enabled);
  		};
  		mxGraph.prototype.setPanning = function(enabled)
  		{
  			this.panningHandler.panningEnabled = enabled;
  		};
  		mxGraph.prototype.isEditing = function(cell)
  		{
  			if (this.cellEditor != null)
  			{
  				var editingCell = this.cellEditor.getEditingCell();
  				return (cell == null) ? editingCell != null : cell == editingCell;
  			}
  			return false;
  		};
  		mxGraph.prototype.isAutoSizeCell = function(cell)
  		{
  			var style = this.getCurrentCellStyle(cell);
  			return this.isAutoSizeCells() || style[mxConstants.STYLE_AUTOSIZE] == 1;
  		};
  		mxGraph.prototype.isAutoSizeCells = function()
  		{
  			return this.autoSizeCells;
  		};
  		mxGraph.prototype.setAutoSizeCells = function(value)
  		{
  			this.autoSizeCells = value;
  		};
  		mxGraph.prototype.isExtendParent = function(cell)
  		{
  			return !this.getModel().isEdge(cell) && this.isExtendParents();
  		};
  		mxGraph.prototype.isExtendParents = function()
  		{
  			return this.extendParents;
  		};
  		mxGraph.prototype.setExtendParents = function(value)
  		{
  			this.extendParents = value;
  		};
  		mxGraph.prototype.isExtendParentsOnAdd = function(cell)
  		{
  			return this.extendParentsOnAdd;
  		};
  		mxGraph.prototype.setExtendParentsOnAdd = function(value)
  		{
  			this.extendParentsOnAdd = value;
  		};
  		mxGraph.prototype.isExtendParentsOnMove = function()
  		{
  			return this.extendParentsOnMove;
  		};
  		mxGraph.prototype.setExtendParentsOnMove = function(value)
  		{
  			this.extendParentsOnMove = value;
  		};
  		mxGraph.prototype.isRecursiveResize = function(state)
  		{
  			return this.recursiveResize;
  		};
  		mxGraph.prototype.setRecursiveResize = function(value)
  		{
  			this.recursiveResize = value;
  		};
  		mxGraph.prototype.isConstrainChild = function(cell)
  		{
  			return this.isConstrainChildren() && !this.getModel().isEdge(this.getModel().getParent(cell));
  		};
  		mxGraph.prototype.isConstrainChildren = function()
  		{
  			return this.constrainChildren;
  		};
  		mxGraph.prototype.setConstrainChildren = function(value)
  		{
  			this.constrainChildren = value;
  		};
  		mxGraph.prototype.isConstrainRelativeChildren = function()
  		{
  			return this.constrainRelativeChildren;
  		};
  		mxGraph.prototype.setConstrainRelativeChildren = function(value)
  		{
  			this.constrainRelativeChildren = value;
  		};
  		mxGraph.prototype.isAllowNegativeCoordinates = function()
  		{
  			return this.allowNegativeCoordinates;
  		};
  		mxGraph.prototype.setAllowNegativeCoordinates = function(value)
  		{
  			this.allowNegativeCoordinates = value;
  		};
  		mxGraph.prototype.getOverlap = function(cell)
  		{
  			return (this.isAllowOverlapParent(cell)) ? this.defaultOverlap : 0;
  		};
  		mxGraph.prototype.isAllowOverlapParent = function(cell)
  		{
  			return false;
  		};
  		mxGraph.prototype.getFoldableCells = function(cells, collapse)
  		{
  			return this.model.filterCells(cells, mxUtils.bind(this, function(cell)
  			{
  				return this.isCellFoldable(cell, collapse);
  			}));
  		};
  		mxGraph.prototype.isCellFoldable = function(cell, collapse)
  		{
  			var style = this.getCurrentCellStyle(cell);
  			return this.model.getChildCount(cell) > 0 && style[mxConstants.STYLE_FOLDABLE] != 0;
  		};
  		mxGraph.prototype.isValidDropTarget = function(cell, cells, evt)
  		{
  			return cell != null && ((this.isSplitEnabled() &&
  				this.isSplitTarget(cell, cells, evt)) || (!this.model.isEdge(cell) &&
  				(this.isSwimlane(cell) || (this.model.getChildCount(cell) > 0 &&
  				!this.isCellCollapsed(cell)))));
  		};
  		mxGraph.prototype.isSplitTarget = function(target, cells, evt)
  		{
  			if (this.model.isEdge(target) && cells != null && cells.length == 1 &&
  				this.isCellConnectable(cells[0]) && this.getEdgeValidationError(target,
  					this.model.getTerminal(target, true), cells[0]) == null)
  			{
  				var src = this.model.getTerminal(target, true);
  				var trg = this.model.getTerminal(target, false);
  				return (!this.model.isAncestor(cells[0], src) &&
  						!this.model.isAncestor(cells[0], trg));
  			}
  			return false;
  		};
  		mxGraph.prototype.getDropTarget = function(cells, evt, cell, clone)
  		{
  			if (!this.isSwimlaneNesting())
  			{
  				for (var i = 0; i < cells.length; i++)
  				{
  					if (this.isSwimlane(cells[i]))
  					{
  						return null;
  					}
  				}
  			}
  			var pt = mxUtils.convertPoint(this.container,
  				mxEvent.getClientX(evt), mxEvent.getClientY(evt));
  			pt.x -= this.panDx;
  			pt.y -= this.panDy;
  			var swimlane = this.getSwimlaneAt(pt.x, pt.y);
  			if (cell == null)
  			{
  				cell = swimlane;
  			}
  			else if (swimlane != null)
  			{
  				var tmp = this.model.getParent(swimlane);
  				while (tmp != null && this.isSwimlane(tmp) && tmp != cell)
  				{
  					tmp = this.model.getParent(tmp);
  				}
  				if (tmp == cell)
  				{
  					cell = swimlane;
  				}
  			}
  			while (cell != null && !this.isValidDropTarget(cell, cells, evt) &&
  				!this.model.isLayer(cell))
  			{
  				cell = this.model.getParent(cell);
  			}
  			if (clone == null || !clone)
  			{
  				var parent = cell;
  				while (parent != null && mxUtils.indexOf(cells, parent) < 0)
  				{
  					parent = this.model.getParent(parent);
  				}
  			}
  			return (!this.model.isLayer(cell) && parent == null) ? cell : null;
  		};
  		mxGraph.prototype.getDefaultParent = function()
  		{
  			var parent = this.getCurrentRoot();
  			if (parent == null)
  			{
  				parent = this.defaultParent;
  				if (parent == null)
  				{
  					var root = this.model.getRoot();
  					parent = this.model.getChildAt(root, 0);
  				}
  			}
  			return parent;
  		};
  		mxGraph.prototype.setDefaultParent = function(cell)
  		{
  			this.defaultParent = cell;
  		};
  		mxGraph.prototype.getSwimlane = function(cell)
  		{
  			while (cell != null && !this.isSwimlane(cell))
  			{
  				cell = this.model.getParent(cell);
  			}
  			return cell;
  		};
  		mxGraph.prototype.getSwimlaneAt = function (x, y, parent)
  		{
  			if (parent == null)
  			{
  				parent = this.getCurrentRoot();
  				if (parent == null)
  				{
  					parent = this.model.getRoot();
  				}
  			}
  			if (parent != null)
  			{
  				var childCount = this.model.getChildCount(parent);
  				for (var i = 0; i < childCount; i++)
  				{
  					var child = this.model.getChildAt(parent, i);
  					if (child != null)
  					{
  						var result = this.getSwimlaneAt(x, y, child);
  						if (result != null)
  						{
  							return result;
  						}
  						else if (this.isCellVisible(child) && this.isSwimlane(child))
  						{
  							var state = this.view.getState(child);
  							if (this.intersects(state, x, y))
  							{
  								return child;
  							}
  						}
  					}
  				}
  			}
  			return null;
  		};
  		mxGraph.prototype.getCellAt = function(x, y, parent, vertices, edges, ignoreFn)
  		{
  			vertices = (vertices != null) ? vertices : true;
  			edges = (edges != null) ? edges : true;
  			if (parent == null)
  			{
  				parent = this.getCurrentRoot();
  				if (parent == null)
  				{
  					parent = this.getModel().getRoot();
  				}
  			}
  			if (parent != null)
  			{
  				var childCount = this.model.getChildCount(parent);
  				for (var i = childCount - 1; i >= 0; i--)
  				{
  					var cell = this.model.getChildAt(parent, i);
  					var result = this.getCellAt(x, y, cell, vertices, edges, ignoreFn);
  					if (result != null)
  					{
  						return result;
  					}
  					else if (this.isCellVisible(cell) && (edges && this.model.isEdge(cell) ||
  						vertices && this.model.isVertex(cell)))
  					{
  						var state = this.view.getState(cell);
  						if (state != null && (ignoreFn == null || !ignoreFn(state, x, y)) &&
  							this.intersects(state, x, y))
  						{
  							return cell;
  						}
  					}
  				}
  			}
  			return null;
  		};
  		mxGraph.prototype.intersects = function(state, x, y)
  		{
  			if (state != null)
  			{
  				var pts = state.absolutePoints;
  				if (pts != null)
  				{
  					var t2 = this.tolerance * this.tolerance;
  					var pt = pts[0];
  					for (var i = 1; i < pts.length; i++)
  					{
  						var next = pts[i];
  						var dist = mxUtils.ptSegDistSq(pt.x, pt.y, next.x, next.y, x, y);
  						if (dist <= t2)
  						{
  							return true;
  						}
  						pt = next;
  					}
  				}
  				else
  				{
  					var alpha = mxUtils.toRadians(mxUtils.getValue(state.style, mxConstants.STYLE_ROTATION) || 0);
  					if (alpha != 0)
  					{
  						var cos = Math.cos(-alpha);
  						var sin = Math.sin(-alpha);
  						var cx = new mxPoint(state.getCenterX(), state.getCenterY());
  						var pt = mxUtils.getRotatedPoint(new mxPoint(x, y), cos, sin, cx);
  						x = pt.x;
  						y = pt.y;
  					}
  					if (mxUtils.contains(state, x, y))
  					{
  						return true;
  					}
  				}
  			}
  			return false;
  		};
  		mxGraph.prototype.hitsSwimlaneContent = function(swimlane, x, y)
  		{
  			var state = this.getView().getState(swimlane);
  			var size = this.getStartSize(swimlane);
  			if (state != null)
  			{
  				var scale = this.getView().getScale();
  				x -= state.x;
  				y -= state.y;
  				if (size.width > 0 && x > 0 && x > size.width * scale)
  				{
  					return true;
  				}
  				else if (size.height > 0 && y > 0 && y > size.height * scale)
  				{
  					return true;
  				}
  			}
  			return false;
  		};
  		mxGraph.prototype.getChildVertices = function(parent)
  		{
  			return this.getChildCells(parent, true, false);
  		};
  		mxGraph.prototype.getChildEdges = function(parent)
  		{
  			return this.getChildCells(parent, false, true);
  		};
  		mxGraph.prototype.getChildCells = function(parent, vertices, edges)
  		{
  			parent = (parent != null) ? parent : this.getDefaultParent();
  			vertices = (vertices != null) ? vertices : false;
  			edges = (edges != null) ? edges : false;
  			var cells = this.model.getChildCells(parent, vertices, edges);
  			var result = [];
  			for (var i = 0; i < cells.length; i++)
  			{
  				if (this.isCellVisible(cells[i]))
  				{
  					result.push(cells[i]);
  				}
  			}
  			return result;
  		};
  		mxGraph.prototype.getConnections = function(cell, parent)
  		{
  			return this.getEdges(cell, parent, true, true, false);
  		};
  		mxGraph.prototype.getIncomingEdges = function(cell, parent)
  		{
  			return this.getEdges(cell, parent, true, false, false);
  		};
  		mxGraph.prototype.getOutgoingEdges = function(cell, parent)
  		{
  			return this.getEdges(cell, parent, false, true, false);
  		};
  		mxGraph.prototype.getEdges = function(cell, parent, incoming, outgoing, includeLoops, recurse)
  		{
  			incoming = (incoming != null) ? incoming : true;
  			outgoing = (outgoing != null) ? outgoing : true;
  			includeLoops = (includeLoops != null) ? includeLoops : true;
  			recurse = (recurse != null) ? recurse : false;
  			var edges = [];
  			var isCollapsed = this.isCellCollapsed(cell);
  			var childCount = this.model.getChildCount(cell);
  			for (var i = 0; i < childCount; i++)
  			{
  				var child = this.model.getChildAt(cell, i);
  				if (isCollapsed || !this.isCellVisible(child))
  				{
  					edges = edges.concat(this.model.getEdges(child, incoming, outgoing));
  				}
  			}
  			edges = edges.concat(this.model.getEdges(cell, incoming, outgoing));
  			var result = [];
  			for (var i = 0; i < edges.length; i++)
  			{
  				var state = this.view.getState(edges[i]);
  				var source = (state != null) ? state.getVisibleTerminal(true) : this.view.getVisibleTerminal(edges[i], true);
  				var target = (state != null) ? state.getVisibleTerminal(false) : this.view.getVisibleTerminal(edges[i], false);
  				if ((includeLoops && source == target) || ((source != target) && ((incoming &&
  					target == cell && (parent == null || this.isValidAncestor(source, parent, recurse))) ||
  					(outgoing && source == cell && (parent == null ||
  							this.isValidAncestor(target, parent, recurse))))))
  				{
  					result.push(edges[i]);
  				}
  			}
  			return result;
  		};
  		mxGraph.prototype.isValidAncestor = function(cell, parent, recurse)
  		{
  			return (recurse ? this.model.isAncestor(parent, cell) : this.model
  					.getParent(cell) == parent);
  		};
  		mxGraph.prototype.getOpposites = function(edges, terminal, sources, targets)
  		{
  			sources = (sources != null) ? sources : true;
  			targets = (targets != null) ? targets : true;
  			var terminals = [];
  			var dict = new mxDictionary();
  			if (edges != null)
  			{
  				for (var i = 0; i < edges.length; i++)
  				{
  					var state = this.view.getState(edges[i]);
  					var source = (state != null) ? state.getVisibleTerminal(true) : this.view.getVisibleTerminal(edges[i], true);
  					var target = (state != null) ? state.getVisibleTerminal(false) : this.view.getVisibleTerminal(edges[i], false);
  					if (source == terminal && target != null && target != terminal && targets)
  					{
  						if (!dict.get(target))
  						{
  							dict.put(target, true);
  							terminals.push(target);
  						}
  					}
  					else if (target == terminal && source != null && source != terminal && sources)
  					{
  						if (!dict.get(source))
  						{
  							dict.put(source, true);
  							terminals.push(source);
  						}
  					}
  				}
  			}
  			return terminals;
  		};
  		mxGraph.prototype.getEdgesBetween = function(source, target, directed)
  		{
  			directed = (directed != null) ? directed : false;
  			var edges = this.getEdges(source);
  			var result = [];
  			for (var i = 0; i < edges.length; i++)
  			{
  				var state = this.view.getState(edges[i]);
  				var src = (state != null) ? state.getVisibleTerminal(true) : this.view.getVisibleTerminal(edges[i], true);
  				var trg = (state != null) ? state.getVisibleTerminal(false) : this.view.getVisibleTerminal(edges[i], false);
  				if ((src == source && trg == target) || (!directed && src == target && trg == source))
  				{
  					result.push(edges[i]);
  				}
  			}
  			return result;
  		};
  		 mxGraph.prototype.getPointForEvent = function(evt, addOffset)
  		 {
  			var p = mxUtils.convertPoint(this.container,
  				mxEvent.getClientX(evt), mxEvent.getClientY(evt));
  			var s = this.view.scale;
  			var tr = this.view.translate;
  			var off = (addOffset != false) ? this.gridSize / 2 : 0;
  			p.x = this.snap(p.x / s - tr.x - off);
  			p.y = this.snap(p.y / s - tr.y - off);
  			return p;
  		};
  		mxGraph.prototype.getCells = function(x, y, width, height, parent, result, intersection, ignoreFn, includeDescendants)
  		{
  			result = (result != null) ? result : [];
  			if (width > 0 || height > 0 || intersection != null)
  			{
  				var model = this.getModel();
  				var right = x + width;
  				var bottom = y + height;
  				if (parent == null)
  				{
  					parent = this.getCurrentRoot();
  					if (parent == null)
  					{
  						parent = model.getRoot();
  					}
  				}
  				if (parent != null)
  				{
  					var childCount = model.getChildCount(parent);
  					for (var i = 0; i < childCount; i++)
  					{
  						var cell = model.getChildAt(parent, i);
  						var state = this.view.getState(cell);
  						if (state != null && this.isCellVisible(cell) &&
  							(ignoreFn == null || !ignoreFn(state)))
  						{
  							var deg = mxUtils.getValue(state.style, mxConstants.STYLE_ROTATION) || 0;
  							var box = state;
  							if (deg != 0)
  							{
  								box = mxUtils.getBoundingBox(box, deg);
  							}
  							var hit = (intersection != null && model.isVertex(cell) && mxUtils.intersects(intersection, box)) ||
  								(intersection == null && (model.isEdge(cell) || model.isVertex(cell)) &&
  								box.x >= x && box.y + box.height <= bottom &&
  								box.y >= y && box.x + box.width <= right);
  							if (hit)
  							{
  								result.push(cell);
  							}
  							if (!hit || includeDescendants)
  							{
  								this.getCells(x, y, width, height, cell, result, intersection, ignoreFn, includeDescendants);
  							}
  						}
  					}
  				}
  			}
  			return result;
  		};
  		mxGraph.prototype.getCellsBeyond = function(x0, y0, parent, rightHalfpane, bottomHalfpane)
  		{
  			var result = [];
  			if (rightHalfpane || bottomHalfpane)
  			{
  				if (parent == null)
  				{
  					parent = this.getDefaultParent();
  				}
  				if (parent != null)
  				{
  					var childCount = this.model.getChildCount(parent);
  					for (var i = 0; i < childCount; i++)
  					{
  						var child = this.model.getChildAt(parent, i);
  						var state = this.view.getState(child);
  						if (this.isCellVisible(child) && state != null)
  						{
  							if ((!rightHalfpane || state.x >= x0) &&
  								(!bottomHalfpane || state.y >= y0))
  							{
  								result.push(child);
  							}
  						}
  					}
  				}
  			}
  			return result;
  		};
  		mxGraph.prototype.findTreeRoots = function(parent, isolate, invert)
  		{
  			isolate = (isolate != null) ? isolate : false;
  			invert = (invert != null) ? invert : false;
  			var roots = [];
  			if (parent != null)
  			{
  				var model = this.getModel();
  				var childCount = model.getChildCount(parent);
  				var best = null;
  				var maxDiff = 0;
  				for (var i=0; i<childCount; i++)
  				{
  					var cell = model.getChildAt(parent, i);
  					if (this.model.isVertex(cell) && this.isCellVisible(cell))
  					{
  						var conns = this.getConnections(cell, (isolate) ? parent : null);
  						var fanOut = 0;
  						var fanIn = 0;
  						for (var j = 0; j < conns.length; j++)
  						{
  							var src = this.view.getVisibleTerminal(conns[j], true);
  		                    if (src == cell)
  		                    {
  		                        fanOut++;
  		                    }
  		                    else
  		                    {
  		                        fanIn++;
  		                    }
  						}
  						if ((invert && fanOut == 0 && fanIn > 0) ||
  							(!invert && fanIn == 0 && fanOut > 0))
  						{
  							roots.push(cell);
  						}
  						var diff = (invert) ? fanIn - fanOut : fanOut - fanIn;
  						if (diff > maxDiff)
  						{
  							maxDiff = diff;
  							best = cell;
  						}
  					}
  				}
  				if (roots.length == 0 && best != null)
  				{
  					roots.push(best);
  				}
  			}
  			return roots;
  		};
  		mxGraph.prototype.traverse = function(vertex, directed, func, edge, visited, inverse)
  		{
  			if (func != null && vertex != null)
  			{
  				directed = (directed != null) ? directed : true;
  				inverse = (inverse != null) ? inverse : false;
  				visited = visited || new mxDictionary();
  				if (!visited.get(vertex))
  				{
  					visited.put(vertex, true);
  					var result = func(vertex, edge);
  					if (result == null || result)
  					{
  						var edgeCount = this.model.getEdgeCount(vertex);
  						if (edgeCount > 0)
  						{
  							for (var i = 0; i < edgeCount; i++)
  							{
  								var e = this.model.getEdgeAt(vertex, i);
  								var isSource = this.model.getTerminal(e, true) == vertex;
  								if (!directed || (!inverse == isSource))
  								{
  									var next = this.model.getTerminal(e, !isSource);
  									this.traverse(next, directed, func, e, visited, inverse);
  								}
  							}
  						}
  					}
  				}
  			}
  		};
  		mxGraph.prototype.isCellSelected = function(cell)
  		{
  			return this.getSelectionModel().isSelected(cell);
  		};
  		mxGraph.prototype.isSelectionEmpty = function()
  		{
  			return this.getSelectionModel().isEmpty();
  		};
  		mxGraph.prototype.clearSelection = function()
  		{
  			return this.getSelectionModel().clear();
  		};
  		mxGraph.prototype.getSelectionCount = function()
  		{
  			return this.getSelectionModel().cells.length;
  		};
  		mxGraph.prototype.getSelectionCell = function()
  		{
  			return this.getSelectionModel().cells[0];
  		};
  		mxGraph.prototype.getSelectionCells = function()
  		{
  			return this.getSelectionModel().cells.slice();
  		};
  		mxGraph.prototype.setSelectionCell = function(cell)
  		{
  			this.getSelectionModel().setCell(cell);
  		};
  		mxGraph.prototype.setSelectionCells = function(cells)
  		{
  			this.getSelectionModel().setCells(cells);
  		};
  		mxGraph.prototype.addSelectionCell = function(cell)
  		{
  			this.getSelectionModel().addCell(cell);
  		};
  		mxGraph.prototype.addSelectionCells = function(cells)
  		{
  			this.getSelectionModel().addCells(cells);
  		};
  		mxGraph.prototype.removeSelectionCell = function(cell)
  		{
  			this.getSelectionModel().removeCell(cell);
  		};
  		mxGraph.prototype.removeSelectionCells = function(cells)
  		{
  			this.getSelectionModel().removeCells(cells);
  		};
  		mxGraph.prototype.selectRegion = function(rect, evt)
  		{
  			var cells = this.getCells(rect.x, rect.y, rect.width, rect.height);
  			this.selectCellsForEvent(cells, evt);
  			return cells;
  		};
  		mxGraph.prototype.selectNextCell = function()
  		{
  			this.selectCell(true);
  		};
  		mxGraph.prototype.selectPreviousCell = function()
  		{
  			this.selectCell();
  		};
  		mxGraph.prototype.selectParentCell = function()
  		{
  			this.selectCell(false, true);
  		};
  		mxGraph.prototype.selectChildCell = function()
  		{
  			this.selectCell(false, false, true);
  		};
  		mxGraph.prototype.selectCell = function(isNext, isParent, isChild)
  		{
  			var sel = this.selectionModel;
  			var cell = (sel.cells.length > 0) ? sel.cells[0] : null;
  			if (sel.cells.length > 1)
  			{
  				sel.clear();
  			}
  			var parent = (cell != null) ?
  				this.model.getParent(cell) :
  				this.getDefaultParent();
  			var childCount = this.model.getChildCount(parent);
  			if (cell == null && childCount > 0)
  			{
  				var child = this.model.getChildAt(parent, 0);
  				this.setSelectionCell(child);
  			}
  			else if ((cell == null || isParent) &&
  				this.view.getState(parent) != null &&
  				this.model.getGeometry(parent) != null)
  			{
  				if (this.getCurrentRoot() != parent)
  				{
  					this.setSelectionCell(parent);
  				}
  			}
  			else if (cell != null && isChild)
  			{
  				var tmp = this.model.getChildCount(cell);
  				if (tmp > 0)
  				{
  					var child = this.model.getChildAt(cell, 0);
  					this.setSelectionCell(child);
  				}
  			}
  			else if (childCount > 0)
  			{
  				var i = parent.getIndex(cell);
  				if (isNext)
  				{
  					i++;
  					var child = this.model.getChildAt(parent, i % childCount);
  					this.setSelectionCell(child);
  				}
  				else
  				{
  					i--;
  					var index =  (i < 0) ? childCount - 1 : i;
  					var child = this.model.getChildAt(parent, index);
  					this.setSelectionCell(child);
  				}
  			}
  		};
  		mxGraph.prototype.selectAll = function(parent, descendants)
  		{
  			parent = parent || this.getDefaultParent();
  			var cells = (descendants) ? this.model.filterDescendants(mxUtils.bind(this, function(cell)
  			{
  				return cell != parent && this.view.getState(cell) != null;
  			}), parent) : this.model.getChildren(parent);
  			if (cells != null)
  			{
  				this.setSelectionCells(cells);
  			}
  		};
  		mxGraph.prototype.selectVertices = function(parent, selectGroups)
  		{
  			this.selectCells(true, false, parent, selectGroups);
  		};
  		mxGraph.prototype.selectEdges = function(parent)
  		{
  			this.selectCells(false, true, parent);
  		};
  		mxGraph.prototype.selectCells = function(vertices, edges, parent, selectGroups)
  		{
  			parent = parent || this.getDefaultParent();
  			var filter = mxUtils.bind(this, function(cell)
  			{
  				return this.view.getState(cell) != null &&
  					(((selectGroups || this.model.getChildCount(cell) == 0) &&
  					this.model.isVertex(cell) && vertices
  					&& !this.model.isEdge(this.model.getParent(cell))) ||
  					(this.model.isEdge(cell) && edges));
  			});
  			var cells = this.model.filterDescendants(filter, parent);
  			if (cells != null)
  			{
  				this.setSelectionCells(cells);
  			}
  		};
  		mxGraph.prototype.selectCellForEvent = function(cell, evt)
  		{
  			var isSelected = this.isCellSelected(cell);
  			if (this.isToggleEvent(evt))
  			{
  				if (isSelected)
  				{
  					this.removeSelectionCell(cell);
  				}
  				else
  				{
  					this.addSelectionCell(cell);
  				}
  			}
  			else if (!isSelected || this.getSelectionCount() != 1)
  			{
  				this.setSelectionCell(cell);
  			}
  		};
  		mxGraph.prototype.selectCellsForEvent = function(cells, evt)
  		{
  			if (this.isToggleEvent(evt))
  			{
  				this.addSelectionCells(cells);
  			}
  			else
  			{
  				this.setSelectionCells(cells);
  			}
  		};
  		mxGraph.prototype.createHandler = function(state)
  		{
  			var result = null;
  			if (state != null)
  			{
  				if (this.model.isEdge(state.cell))
  				{
  					var source = state.getVisibleTerminalState(true);
  					var target = state.getVisibleTerminalState(false);
  					var geo = this.getCellGeometry(state.cell);
  					var edgeStyle = this.view.getEdgeStyle(state, (geo != null) ? geo.points : null, source, target);
  					result = this.createEdgeHandler(state, edgeStyle);
  				}
  				else
  				{
  					result = this.createVertexHandler(state);
  				}
  			}
  			return result;
  		};
  		mxGraph.prototype.createVertexHandler = function(state)
  		{
  			return new mxVertexHandler(state);
  		};
  		mxGraph.prototype.createEdgeHandler = function(state, edgeStyle)
  		{
  			var result = null;
  			if (edgeStyle == mxEdgeStyle.Loop ||
  				edgeStyle == mxEdgeStyle.ElbowConnector ||
  				edgeStyle == mxEdgeStyle.SideToSide ||
  				edgeStyle == mxEdgeStyle.TopToBottom)
  			{
  				result = this.createElbowEdgeHandler(state);
  			}
  			else if (edgeStyle == mxEdgeStyle.SegmentConnector ||
  					edgeStyle == mxEdgeStyle.OrthConnector)
  			{
  				result = this.createEdgeSegmentHandler(state);
  			}
  			else
  			{
  				result = new mxEdgeHandler(state);
  			}
  			return result;
  		};
  		mxGraph.prototype.createEdgeSegmentHandler = function(state)
  		{
  			return new mxEdgeSegmentHandler(state);
  		};
  		mxGraph.prototype.createElbowEdgeHandler = function(state)
  		{
  			return new mxElbowEdgeHandler(state);
  		};
  		mxGraph.prototype.addMouseListener = function(listener)
  		{
  			if (this.mouseListeners == null)
  			{
  				this.mouseListeners = [];
  			}
  			this.mouseListeners.push(listener);
  		};
  		mxGraph.prototype.removeMouseListener = function(listener)
  		{
  			if (this.mouseListeners != null)
  			{
  				for (var i = 0; i < this.mouseListeners.length; i++)
  				{
  					if (this.mouseListeners[i] == listener)
  					{
  						this.mouseListeners.splice(i, 1);
  						break;
  					}
  				}
  			}
  		};
  		mxGraph.prototype.updateMouseEvent = function(me, evtName)
  		{
  			if (me.graphX == null || me.graphY == null)
  			{
  				var pt = mxUtils.convertPoint(this.container, me.getX(), me.getY());
  				me.graphX = pt.x - this.panDx;
  				me.graphY = pt.y - this.panDy;
  				if (me.getCell() == null && this.isMouseDown && evtName == mxEvent.MOUSE_MOVE)
  				{
  					me.state = this.view.getState(this.getCellAt(pt.x, pt.y, null, null, null, function(state)
  					{
  						return state.shape == null || state.shape.paintBackground != mxRectangleShape.prototype.paintBackground ||
  							mxUtils.getValue(state.style, mxConstants.STYLE_POINTER_EVENTS, '1') == '1' ||
  							(state.shape.fill != null && state.shape.fill != mxConstants.NONE);
  					}));
  				}
  			}
  			return me;
  		};
  		mxGraph.prototype.getStateForTouchEvent = function(evt)
  		{
  			var x = mxEvent.getClientX(evt);
  			var y = mxEvent.getClientY(evt);
  			var pt = mxUtils.convertPoint(this.container, x, y);
  			return this.view.getState(this.getCellAt(pt.x, pt.y));
  		};
  		mxGraph.prototype.isEventIgnored = function(evtName, me, sender)
  		{
  			var mouseEvent = mxEvent.isMouseEvent(me.getEvent());
  			var result = false;
  			if (me.getEvent() == this.lastEvent)
  			{
  				result = true;
  			}
  			else
  			{
  				this.lastEvent = me.getEvent();
  			}
  			if (this.eventSource != null && evtName != mxEvent.MOUSE_MOVE)
  			{
  				mxEvent.removeGestureListeners(this.eventSource, null, this.mouseMoveRedirect, this.mouseUpRedirect);
  				this.mouseMoveRedirect = null;
  				this.mouseUpRedirect = null;
  				this.eventSource = null;
  			}
  			else if (!mxClient.IS_GC && this.eventSource != null && me.getSource() != this.eventSource)
  			{
  				result = true;
  			}
  			else if (mxClient.IS_TOUCH && evtName == mxEvent.MOUSE_DOWN &&
  					!mouseEvent && !mxEvent.isPenEvent(me.getEvent()))
  			{
  				this.eventSource = me.getSource();
  				this.mouseMoveRedirect = mxUtils.bind(this, function(evt)
  				{
  					this.fireMouseEvent(mxEvent.MOUSE_MOVE, new mxMouseEvent(evt, this.getStateForTouchEvent(evt)));
  				});
  				this.mouseUpRedirect = mxUtils.bind(this, function(evt)
  				{
  					this.fireMouseEvent(mxEvent.MOUSE_UP, new mxMouseEvent(evt, this.getStateForTouchEvent(evt)));
  				});
  				mxEvent.addGestureListeners(this.eventSource, null, this.mouseMoveRedirect, this.mouseUpRedirect);
  			}
  			if (this.isSyntheticEventIgnored(evtName, me, sender))
  			{
  				result = true;
  			}
  			if (!mxEvent.isPopupTrigger(this.lastEvent) && evtName != mxEvent.MOUSE_MOVE && this.lastEvent.detail == 2)
  			{
  				return true;
  			}
  			if (evtName == mxEvent.MOUSE_UP && this.isMouseDown)
  			{
  				this.isMouseDown = false;
  			}
  			else if (evtName == mxEvent.MOUSE_DOWN && !this.isMouseDown)
  			{
  				this.isMouseDown = true;
  				this.isMouseTrigger = mouseEvent;
  			}
  			else if (!result && (((!mxClient.IS_FF || evtName != mxEvent.MOUSE_MOVE) &&
  				this.isMouseDown && this.isMouseTrigger != mouseEvent) ||
  				(evtName == mxEvent.MOUSE_DOWN && this.isMouseDown) ||
  				(evtName == mxEvent.MOUSE_UP && !this.isMouseDown)))
  			{
  				result = true;
  			}
  			if (!result && evtName == mxEvent.MOUSE_DOWN)
  			{
  				this.lastMouseX = me.getX();
  				this.lastMouseY = me.getY();
  			}
  			return result;
  		};
  		mxGraph.prototype.isSyntheticEventIgnored = function(evtName, me, sender)
  		{
  			var result = false;
  			var mouseEvent = mxEvent.isMouseEvent(me.getEvent());
  			if (this.ignoreMouseEvents && mouseEvent && evtName != mxEvent.MOUSE_MOVE)
  			{
  				this.ignoreMouseEvents = evtName != mxEvent.MOUSE_UP;
  				result = true;
  			}
  			else if (mxClient.IS_FF && !mouseEvent && evtName == mxEvent.MOUSE_UP)
  			{
  				this.ignoreMouseEvents = true;
  			}
  			return result;
  		};
  		mxGraph.prototype.isEventSourceIgnored = function(evtName, me)
  		{
  			var source = me.getSource();
  			var name = (source.nodeName != null) ? source.nodeName.toLowerCase() : '';
  			var candidate = !mxEvent.isMouseEvent(me.getEvent()) || mxEvent.isLeftMouseButton(me.getEvent());
  			return evtName == mxEvent.MOUSE_DOWN && candidate && (name == 'select' || name == 'option' ||
  				(name == 'input' && source.type != 'checkbox' && source.type != 'radio' &&
  				source.type != 'button' && source.type != 'submit' && source.type != 'file'));
  		};
  		mxGraph.prototype.getEventState = function(state)
  		{
  			return state;
  		};
  		mxGraph.prototype.fireMouseEvent = function(evtName, me, sender)
  		{
  			if (this.isEventSourceIgnored(evtName, me))
  			{
  				if (this.tooltipHandler != null)
  				{
  					this.tooltipHandler.hide();
  				}
  				return;
  			}
  			if (sender == null)
  			{
  				sender = this;
  			}
  			me = this.updateMouseEvent(me, evtName);
  			if ((!this.nativeDblClickEnabled && !mxEvent.isPopupTrigger(me.getEvent())) || (this.doubleTapEnabled &&
  				mxClient.IS_TOUCH && (mxEvent.isTouchEvent(me.getEvent()) || mxEvent.isPenEvent(me.getEvent()))))
  			{
  				var currentTime = new Date().getTime();
  				if ((!mxClient.IS_QUIRKS && evtName == mxEvent.MOUSE_DOWN) || (mxClient.IS_QUIRKS && evtName == mxEvent.MOUSE_UP && !this.fireDoubleClick))
  				{
  					if (this.lastTouchEvent != null && this.lastTouchEvent != me.getEvent() &&
  						currentTime - this.lastTouchTime < this.doubleTapTimeout &&
  						Math.abs(this.lastTouchX - me.getX()) < this.doubleTapTolerance &&
  						Math.abs(this.lastTouchY - me.getY()) < this.doubleTapTolerance &&
  						this.doubleClickCounter < 2)
  					{
  						this.doubleClickCounter++;
  						var doubleClickFired = false;
  						if (evtName == mxEvent.MOUSE_UP)
  						{
  							if (me.getCell() == this.lastTouchCell && this.lastTouchCell != null)
  							{
  								this.lastTouchTime = 0;
  								var cell = this.lastTouchCell;
  								this.lastTouchCell = null;
  								if (mxClient.IS_QUIRKS)
  								{
  									me.getSource().fireEvent('ondblclick');
  								}
  								this.dblClick(me.getEvent(), cell);
  								doubleClickFired = true;
  							}
  						}
  						else
  						{
  							this.fireDoubleClick = true;
  							this.lastTouchTime = 0;
  						}
  						if (!mxClient.IS_QUIRKS || doubleClickFired)
  						{
  							mxEvent.consume(me.getEvent());
  							return;
  						}
  					}
  					else if (this.lastTouchEvent == null || this.lastTouchEvent != me.getEvent())
  					{
  						this.lastTouchCell = me.getCell();
  						this.lastTouchX = me.getX();
  						this.lastTouchY = me.getY();
  						this.lastTouchTime = currentTime;
  						this.lastTouchEvent = me.getEvent();
  						this.doubleClickCounter = 0;
  					}
  				}
  				else if ((this.isMouseDown || evtName == mxEvent.MOUSE_UP) && this.fireDoubleClick)
  				{
  					this.fireDoubleClick = false;
  					var cell = this.lastTouchCell;
  					this.lastTouchCell = null;
  					this.isMouseDown = false;
  					var valid = (cell != null) || ((mxEvent.isTouchEvent(me.getEvent()) || mxEvent.isPenEvent(me.getEvent())) &&
  						(mxClient.IS_GC || mxClient.IS_SF));
  					if (valid && Math.abs(this.lastTouchX - me.getX()) < this.doubleTapTolerance &&
  						Math.abs(this.lastTouchY - me.getY()) < this.doubleTapTolerance)
  					{
  						this.dblClick(me.getEvent(), cell);
  					}
  					else
  					{
  						mxEvent.consume(me.getEvent());
  					}
  					return;
  				}
  			}
  			if (!this.isEventIgnored(evtName, me, sender))
  			{
  				me.state = this.getEventState(me.getState());
  				this.fireEvent(new mxEventObject(mxEvent.FIRE_MOUSE_EVENT, 'eventName', evtName, 'event', me));
  				if ((mxClient.IS_OP || mxClient.IS_SF || mxClient.IS_GC || mxClient.IS_IE11 ||
  					(mxClient.IS_IE && mxClient.IS_SVG) || me.getEvent().target != this.container))
  				{
  					if (evtName == mxEvent.MOUSE_MOVE && this.isMouseDown && this.autoScroll && !mxEvent.isMultiTouchEvent(me.getEvent))
  					{
  						this.scrollPointToVisible(me.getGraphX(), me.getGraphY(), this.autoExtend);
  					}
  					else if (evtName == mxEvent.MOUSE_UP && this.ignoreScrollbars && this.translateToScrollPosition &&
  							(this.container.scrollLeft != 0 || this.container.scrollTop != 0))
  					{
  						var s = this.view.scale;
  						var tr = this.view.translate;
  						this.view.setTranslate(tr.x - this.container.scrollLeft / s, tr.y - this.container.scrollTop / s);
  						this.container.scrollLeft = 0;
  						this.container.scrollTop = 0;
  					}
  					if (this.mouseListeners != null)
  					{
  						var args = [sender, me];
  						if (!me.getEvent().preventDefault)
  						{
  							me.getEvent().returnValue = true;
  						}
  						for (var i = 0; i < this.mouseListeners.length; i++)
  						{
  							var l = this.mouseListeners[i];
  							if (evtName == mxEvent.MOUSE_DOWN)
  							{
  								l.mouseDown.apply(l, args);
  							}
  							else if (evtName == mxEvent.MOUSE_MOVE)
  							{
  								l.mouseMove.apply(l, args);
  							}
  							else if (evtName == mxEvent.MOUSE_UP)
  							{
  								l.mouseUp.apply(l, args);
  							}
  						}
  					}
  					if (evtName == mxEvent.MOUSE_UP)
  					{
  						this.click(me);
  					}
  				}
  				if ((mxEvent.isTouchEvent(me.getEvent()) || mxEvent.isPenEvent(me.getEvent())) &&
  					evtName == mxEvent.MOUSE_DOWN && this.tapAndHoldEnabled && !this.tapAndHoldInProgress)
  				{
  					this.tapAndHoldInProgress = true;
  					this.initialTouchX = me.getGraphX();
  					this.initialTouchY = me.getGraphY();
  					var handler = function()
  					{
  						if (this.tapAndHoldValid)
  						{
  							this.tapAndHold(me);
  						}
  						this.tapAndHoldInProgress = false;
  						this.tapAndHoldValid = false;
  					};
  					if (this.tapAndHoldThread)
  					{
  						window.clearTimeout(this.tapAndHoldThread);
  					}
  					this.tapAndHoldThread = window.setTimeout(mxUtils.bind(this, handler), this.tapAndHoldDelay);
  					this.tapAndHoldValid = true;
  				}
  				else if (evtName == mxEvent.MOUSE_UP)
  				{
  					this.tapAndHoldInProgress = false;
  					this.tapAndHoldValid = false;
  				}
  				else if (this.tapAndHoldValid)
  				{
  					this.tapAndHoldValid =
  						Math.abs(this.initialTouchX - me.getGraphX()) < this.tolerance &&
  						Math.abs(this.initialTouchY - me.getGraphY()) < this.tolerance;
  				}
  				if (evtName == mxEvent.MOUSE_DOWN && this.isEditing() && !this.cellEditor.isEventSource(me.getEvent()))
  				{
  					this.stopEditing(!this.isInvokesStopCellEditing());
  				}
  				this.consumeMouseEvent(evtName, me, sender);
  			}
  		};
  		mxGraph.prototype.consumeMouseEvent = function(evtName, me, sender)
  		{
  			if (evtName == mxEvent.MOUSE_DOWN && mxEvent.isTouchEvent(me.getEvent()))
  			{
  				me.consume(false);
  			}
  		};
  		mxGraph.prototype.fireGestureEvent = function(evt, cell)
  		{
  			this.lastTouchTime = 0;
  			this.fireEvent(new mxEventObject(mxEvent.GESTURE, 'event', evt, 'cell', cell));
  		};
  		mxGraph.prototype.destroy = function()
  		{
  			if (!this.destroyed)
  			{
  				this.destroyed = true;
  				if (this.tooltipHandler != null)
  				{
  					this.tooltipHandler.destroy();
  				}
  				if (this.selectionCellsHandler != null)
  				{
  					this.selectionCellsHandler.destroy();
  				}
  				if (this.panningHandler != null)
  				{
  					this.panningHandler.destroy();
  				}
  				if (this.popupMenuHandler != null)
  				{
  					this.popupMenuHandler.destroy();
  				}
  				if (this.connectionHandler != null)
  				{
  					this.connectionHandler.destroy();
  				}
  				if (this.graphHandler != null)
  				{
  					this.graphHandler.destroy();
  				}
  				if (this.cellEditor != null)
  				{
  					this.cellEditor.destroy();
  				}
  				if (this.view != null)
  				{
  					this.view.destroy();
  				}
  				if (this.model != null && this.graphModelChangeListener != null)
  				{
  					this.model.removeListener(this.graphModelChangeListener);
  					this.graphModelChangeListener = null;
  				}
  				this.container = null;
  			}
  		};
  		__mxOutput.mxGraph = typeof mxGraph !== 'undefined' ? mxGraph : undefined;
  		function mxCellOverlay(image, tooltip, align, verticalAlign, offset, cursor)
  		{
  			this.image = image;
  			this.tooltip = tooltip;
  			this.align = (align != null) ? align : this.align;
  			this.verticalAlign = (verticalAlign != null) ? verticalAlign : this.verticalAlign;
  			this.offset = (offset != null) ? offset : new mxPoint();
  			this.cursor = (cursor != null) ? cursor : 'help';
  		}		mxCellOverlay.prototype = new mxEventSource();
  		mxCellOverlay.prototype.constructor = mxCellOverlay;
  		mxCellOverlay.prototype.image = null;
  		mxCellOverlay.prototype.tooltip = null;
  		mxCellOverlay.prototype.align = mxConstants.ALIGN_RIGHT;
  		mxCellOverlay.prototype.verticalAlign = mxConstants.ALIGN_BOTTOM;
  		mxCellOverlay.prototype.offset = null;
  		mxCellOverlay.prototype.cursor = null;
  		mxCellOverlay.prototype.defaultOverlap = 0.5;
  		mxCellOverlay.prototype.getBounds = function(state)
  		{
  			var isEdge = state.view.graph.getModel().isEdge(state.cell);
  			var s = state.view.scale;
  			var pt = null;
  			var w = this.image.width;
  			var h = this.image.height;
  			if (isEdge)
  			{
  				var pts = state.absolutePoints;
  				if (pts.length % 2 == 1)
  				{
  					pt = pts[Math.floor(pts.length / 2)];
  				}
  				else
  				{
  					var idx = pts.length / 2;
  					var p0 = pts[idx-1];
  					var p1 = pts[idx];
  					pt = new mxPoint(p0.x + (p1.x - p0.x) / 2,
  						p0.y + (p1.y - p0.y) / 2);
  				}
  			}
  			else
  			{
  				pt = new mxPoint();
  				if (this.align == mxConstants.ALIGN_LEFT)
  				{
  					pt.x = state.x;
  				}
  				else if (this.align == mxConstants.ALIGN_CENTER)
  				{
  					pt.x = state.x + state.width / 2;
  				}
  				else
  				{
  					pt.x = state.x + state.width;
  				}
  				if (this.verticalAlign == mxConstants.ALIGN_TOP)
  				{
  					pt.y = state.y;
  				}
  				else if (this.verticalAlign == mxConstants.ALIGN_MIDDLE)
  				{
  					pt.y = state.y + state.height / 2;
  				}
  				else
  				{
  					pt.y = state.y + state.height;
  				}
  			}
  			return new mxRectangle(Math.round(pt.x - (w * this.defaultOverlap - this.offset.x) * s),
  				Math.round(pt.y - (h * this.defaultOverlap - this.offset.y) * s), w * s, h * s);
  		};
  		mxCellOverlay.prototype.toString = function()
  		{
  			return this.tooltip;
  		};
  		__mxOutput.mxCellOverlay = typeof mxCellOverlay !== 'undefined' ? mxCellOverlay : undefined;
  		function mxOutline(source, container)
  		{
  			this.source = source;
  			if (container != null)
  			{
  				this.init(container);
  			}
  		}		mxOutline.prototype.source = null;
  		mxOutline.prototype.outline = null;
  		mxOutline.prototype.graphRenderHint = mxConstants.RENDERING_HINT_FASTER;
  		mxOutline.prototype.enabled = true;
  		mxOutline.prototype.showViewport = true;
  		mxOutline.prototype.border = 10;
  		mxOutline.prototype.sizerSize = 8;
  		mxOutline.prototype.labelsVisible = false;
  		mxOutline.prototype.updateOnPan = false;
  		mxOutline.prototype.sizerImage = null;
  		mxOutline.prototype.minScale = 0.0001;
  		mxOutline.prototype.suspended = false;
  		mxOutline.prototype.forceVmlHandles = document.documentMode == 8;
  		mxOutline.prototype.createGraph = function(container)
  		{
  			var graph = new mxGraph(container, this.source.getModel(), this.graphRenderHint, this.source.getStylesheet());
  			graph.foldingEnabled = false;
  			graph.autoScroll = false;
  			return graph;
  		};
  		mxOutline.prototype.init = function(container)
  		{
  			this.outline = this.createGraph(container);
  			var outlineGraphModelChanged = this.outline.graphModelChanged;
  			this.outline.graphModelChanged = mxUtils.bind(this, function(changes)
  			{
  				if (!this.suspended && this.outline != null)
  				{
  					outlineGraphModelChanged.apply(this.outline, arguments);
  				}
  			});
  			if (mxClient.IS_SVG)
  			{
  				var node = this.outline.getView().getCanvas().parentNode;
  				node.setAttribute('shape-rendering', 'optimizeSpeed');
  				node.setAttribute('image-rendering', 'optimizeSpeed');
  			}
  			this.outline.labelsVisible = this.labelsVisible;
  			this.outline.setEnabled(false);
  			this.updateHandler = mxUtils.bind(this, function(sender, evt)
  			{
  				if (!this.suspended && !this.active)
  				{
  					this.update();
  				}
  			});
  			this.source.getModel().addListener(mxEvent.CHANGE, this.updateHandler);
  			this.outline.addMouseListener(this);
  			var view = this.source.getView();
  			view.addListener(mxEvent.SCALE, this.updateHandler);
  			view.addListener(mxEvent.TRANSLATE, this.updateHandler);
  			view.addListener(mxEvent.SCALE_AND_TRANSLATE, this.updateHandler);
  			view.addListener(mxEvent.DOWN, this.updateHandler);
  			view.addListener(mxEvent.UP, this.updateHandler);
  			mxEvent.addListener(this.source.container, 'scroll', this.updateHandler);
  			this.panHandler = mxUtils.bind(this, function(sender)
  			{
  				if (this.updateOnPan)
  				{
  					this.updateHandler.apply(this, arguments);
  				}
  			});
  			this.source.addListener(mxEvent.PAN, this.panHandler);
  			this.refreshHandler = mxUtils.bind(this, function(sender)
  			{
  				this.outline.setStylesheet(this.source.getStylesheet());
  				this.outline.refresh();
  			});
  			this.source.addListener(mxEvent.REFRESH, this.refreshHandler);
  			this.bounds = new mxRectangle(0, 0, 0, 0);
  			this.selectionBorder = new mxRectangleShape(this.bounds, null,
  				mxConstants.OUTLINE_COLOR, mxConstants.OUTLINE_STROKEWIDTH);
  			this.selectionBorder.dialect = this.outline.dialect;
  			if (this.forceVmlHandles)
  			{
  				this.selectionBorder.isHtmlAllowed = function()
  				{
  					return false;
  				};
  			}
  			this.selectionBorder.init(this.outline.getView().getOverlayPane());
  			var handler = mxUtils.bind(this, function(evt)
  			{
  				var t = mxEvent.getSource(evt);
  				var redirect = mxUtils.bind(this, function(evt)
  				{
  					this.outline.fireMouseEvent(mxEvent.MOUSE_MOVE, new mxMouseEvent(evt));
  				});
  				var redirect2 = mxUtils.bind(this, function(evt)
  				{
  					mxEvent.removeGestureListeners(t, null, redirect, redirect2);
  					this.outline.fireMouseEvent(mxEvent.MOUSE_UP, new mxMouseEvent(evt));
  				});
  				mxEvent.addGestureListeners(t, null, redirect, redirect2);
  				this.outline.fireMouseEvent(mxEvent.MOUSE_DOWN, new mxMouseEvent(evt));
  			});
  			mxEvent.addGestureListeners(this.selectionBorder.node, handler);
  			this.sizer = this.createSizer();
  			if (this.forceVmlHandles)
  			{
  				this.sizer.isHtmlAllowed = function()
  				{
  					return false;
  				};
  			}
  			this.sizer.init(this.outline.getView().getOverlayPane());
  			if (this.enabled)
  			{
  				this.sizer.node.style.cursor = 'nwse-resize';
  			}
  			mxEvent.addGestureListeners(this.sizer.node, handler);
  			this.selectionBorder.node.style.display = (this.showViewport) ? '' : 'none';
  			this.sizer.node.style.display = this.selectionBorder.node.style.display;
  			this.selectionBorder.node.style.cursor = 'move';
  			this.update(false);
  		};
  		mxOutline.prototype.isEnabled = function()
  		{
  			return this.enabled;
  		};
  		mxOutline.prototype.setEnabled = function(value)
  		{
  			this.enabled = value;
  		};
  		mxOutline.prototype.setZoomEnabled = function(value)
  		{
  			this.sizer.node.style.visibility = (value) ? 'visible' : 'hidden';
  		};
  		mxOutline.prototype.refresh = function()
  		{
  			this.update(true);
  		};
  		mxOutline.prototype.createSizer = function()
  		{
  			if (this.sizerImage != null)
  			{
  				var sizer = new mxImageShape(new mxRectangle(0, 0, this.sizerImage.width, this.sizerImage.height), this.sizerImage.src);
  				sizer.dialect = this.outline.dialect;
  				return sizer;
  			}
  			else
  			{
  				var sizer = new mxRectangleShape(new mxRectangle(0, 0, this.sizerSize, this.sizerSize),
  					mxConstants.OUTLINE_HANDLE_FILLCOLOR, mxConstants.OUTLINE_HANDLE_STROKECOLOR);
  				sizer.dialect = this.outline.dialect;
  				return sizer;
  			}
  		};
  		mxOutline.prototype.getSourceContainerSize = function()
  		{
  			return new mxRectangle(0, 0, this.source.container.scrollWidth, this.source.container.scrollHeight);
  		};
  		mxOutline.prototype.getOutlineOffset = function(scale)
  		{
  			return null;
  		};
  		mxOutline.prototype.getSourceGraphBounds = function()
  		{
  			return this.source.getGraphBounds();
  		};
  		mxOutline.prototype.update = function(revalidate)
  		{
  			if (this.source != null && this.source.container != null &&
  				this.outline != null && this.outline.container != null)
  			{
  				var sourceScale = this.source.view.scale;
  				var scaledGraphBounds = this.getSourceGraphBounds();
  				var unscaledGraphBounds = new mxRectangle(scaledGraphBounds.x / sourceScale + this.source.panDx,
  						scaledGraphBounds.y / sourceScale + this.source.panDy, scaledGraphBounds.width / sourceScale,
  						scaledGraphBounds.height / sourceScale);
  				var unscaledFinderBounds = new mxRectangle(0, 0,
  					this.source.container.clientWidth / sourceScale,
  					this.source.container.clientHeight / sourceScale);
  				var union = unscaledGraphBounds.clone();
  				union.add(unscaledFinderBounds);
  				var size = this.getSourceContainerSize();
  				var completeWidth = Math.max(size.width / sourceScale, union.width);
  				var completeHeight = Math.max(size.height / sourceScale, union.height);
  				var availableWidth = Math.max(0, this.outline.container.clientWidth - this.border);
  				var availableHeight = Math.max(0, this.outline.container.clientHeight - this.border);
  				var outlineScale = Math.min(availableWidth / completeWidth, availableHeight / completeHeight);
  				var scale = (isNaN(outlineScale)) ? this.minScale : Math.max(this.minScale, outlineScale);
  				if (scale > 0)
  				{
  					if (this.outline.getView().scale != scale)
  					{
  						this.outline.getView().scale = scale;
  						revalidate = true;
  					}
  					var navView = this.outline.getView();
  					if (navView.currentRoot != this.source.getView().currentRoot)
  					{
  						navView.setCurrentRoot(this.source.getView().currentRoot);
  					}
  					var t = this.source.view.translate;
  					var tx = t.x + this.source.panDx;
  					var ty = t.y + this.source.panDy;
  					var off = this.getOutlineOffset(scale);
  					if (off != null)
  					{
  						tx += off.x;
  						ty += off.y;
  					}
  					if (unscaledGraphBounds.x < 0)
  					{
  						tx = tx - unscaledGraphBounds.x;
  					}
  					if (unscaledGraphBounds.y < 0)
  					{
  						ty = ty - unscaledGraphBounds.y;
  					}
  					if (navView.translate.x != tx || navView.translate.y != ty)
  					{
  						navView.translate.x = tx;
  						navView.translate.y = ty;
  						revalidate = true;
  					}
  					var t2 = navView.translate;
  					scale = this.source.getView().scale;
  					var scale2 = scale / navView.scale;
  					var scale3 = 1.0 / navView.scale;
  					var container = this.source.container;
  					this.bounds = new mxRectangle(
  						(t2.x - t.x - this.source.panDx) / scale3,
  						(t2.y - t.y - this.source.panDy) / scale3,
  						(container.clientWidth / scale2),
  						(container.clientHeight / scale2));
  					this.bounds.x += this.source.container.scrollLeft * navView.scale / scale;
  					this.bounds.y += this.source.container.scrollTop * navView.scale / scale;
  					var b = this.selectionBorder.bounds;
  					if (b.x != this.bounds.x || b.y != this.bounds.y || b.width != this.bounds.width || b.height != this.bounds.height)
  					{
  						this.selectionBorder.bounds = this.bounds;
  						this.selectionBorder.redraw();
  					}
  					var b = this.sizer.bounds;
  					var b2 = new mxRectangle(this.bounds.x + this.bounds.width - b.width / 2,
  							this.bounds.y + this.bounds.height - b.height / 2, b.width, b.height);
  					if (b.x != b2.x || b.y != b2.y || b.width != b2.width || b.height != b2.height)
  					{
  						this.sizer.bounds = b2;
  						if (this.sizer.node.style.visibility != 'hidden')
  						{
  							this.sizer.redraw();
  						}
  					}
  					if (revalidate)
  					{
  						this.outline.view.revalidate();
  					}
  				}
  			}
  		};
  		mxOutline.prototype.mouseDown = function(sender, me)
  		{
  			if (this.enabled && this.showViewport)
  			{
  				var tol = (!mxEvent.isMouseEvent(me.getEvent())) ? this.source.tolerance : 0;
  				var hit = (this.source.allowHandleBoundsCheck && (mxClient.IS_IE || tol > 0)) ?
  						new mxRectangle(me.getGraphX() - tol, me.getGraphY() - tol, 2 * tol, 2 * tol) : null;
  				this.zoom = me.isSource(this.sizer) || (hit != null && mxUtils.intersects(shape.bounds, hit));
  				this.startX = me.getX();
  				this.startY = me.getY();
  				this.active = true;
  				if (this.source.useScrollbarsForPanning && mxUtils.hasScrollbars(this.source.container))
  				{
  					this.dx0 = this.source.container.scrollLeft;
  					this.dy0 = this.source.container.scrollTop;
  				}
  				else
  				{
  					this.dx0 = 0;
  					this.dy0 = 0;
  				}
  			}
  			me.consume();
  		};
  		mxOutline.prototype.mouseMove = function(sender, me)
  		{
  			if (this.active)
  			{
  				this.selectionBorder.node.style.display = (this.showViewport) ? '' : 'none';
  				this.sizer.node.style.display = this.selectionBorder.node.style.display;
  				var delta = this.getTranslateForEvent(me);
  				var dx = delta.x;
  				var dy = delta.y;
  				var bounds = null;
  				if (!this.zoom)
  				{
  					var scale = this.outline.getView().scale;
  					bounds = new mxRectangle(this.bounds.x + dx,
  						this.bounds.y + dy, this.bounds.width, this.bounds.height);
  					this.selectionBorder.bounds = bounds;
  					this.selectionBorder.redraw();
  					dx /= scale;
  					dx *= this.source.getView().scale;
  					dy /= scale;
  					dy *= this.source.getView().scale;
  					this.source.panGraph(-dx - this.dx0, -dy - this.dy0);
  				}
  				else
  				{
  					var container = this.source.container;
  					var viewRatio = container.clientWidth / container.clientHeight;
  					dy = dx / viewRatio;
  					bounds = new mxRectangle(this.bounds.x,
  						this.bounds.y,
  						Math.max(1, this.bounds.width + dx),
  						Math.max(1, this.bounds.height + dy));
  					this.selectionBorder.bounds = bounds;
  					this.selectionBorder.redraw();
  				}
  				var b = this.sizer.bounds;
  				this.sizer.bounds = new mxRectangle(
  					bounds.x + bounds.width - b.width / 2,
  					bounds.y + bounds.height - b.height / 2,
  					b.width, b.height);
  				if (this.sizer.node.style.visibility != 'hidden')
  				{
  					this.sizer.redraw();
  				}
  				me.consume();
  			}
  		};
  		mxOutline.prototype.getTranslateForEvent = function(me)
  		{
  			return new mxPoint(me.getX() - this.startX, me.getY() - this.startY);
  		};
  		mxOutline.prototype.mouseUp = function(sender, me)
  		{
  			if (this.active)
  			{
  				var delta = this.getTranslateForEvent(me);
  				var dx = delta.x;
  				var dy = delta.y;
  				if (Math.abs(dx) > 0 || Math.abs(dy) > 0)
  				{
  					if (!this.zoom)
  					{
  						if (!this.source.useScrollbarsForPanning ||
  							!mxUtils.hasScrollbars(this.source.container))
  						{
  							this.source.panGraph(0, 0);
  							dx /= this.outline.getView().scale;
  							dy /= this.outline.getView().scale;
  							var t = this.source.getView().translate;
  							this.source.getView().setTranslate(t.x - dx, t.y - dy);
  						}
  					}
  					else
  					{
  						var w = this.selectionBorder.bounds.width;
  						var scale = this.source.getView().scale;
  						this.source.zoomTo(Math.max(this.minScale, scale - (dx * scale) / w), false);
  					}
  					this.update();
  					me.consume();
  				}
  				this.index = null;
  				this.active = false;
  			}
  		};
  		mxOutline.prototype.destroy = function()
  		{
  			if (this.source != null)
  			{
  				this.source.removeListener(this.panHandler);
  				this.source.removeListener(this.refreshHandler);
  				this.source.getModel().removeListener(this.updateHandler);
  				this.source.getView().removeListener(this.updateHandler);
  				mxEvent.removeListener(this.source.container, 'scroll', this.updateHandler);
  				this.source = null;
  			}
  			if (this.outline != null)
  			{
  				this.outline.removeMouseListener(this);
  				this.outline.destroy();
  				this.outline = null;
  			}
  			if (this.selectionBorder != null)
  			{
  				this.selectionBorder.destroy();
  				this.selectionBorder = null;
  			}
  			if (this.sizer != null)
  			{
  				this.sizer.destroy();
  				this.sizer = null;
  			}
  		};
  		__mxOutput.mxOutline = typeof mxOutline !== 'undefined' ? mxOutline : undefined;
  		function mxMultiplicity(source, type, attr, value, min, max,
  			validNeighbors, countError, typeError, validNeighborsAllowed)
  		{
  			this.source = source;
  			this.type = type;
  			this.attr = attr;
  			this.value = value;
  			this.min = (min != null) ? min : 0;
  			this.max = (max != null) ? max : 'n';
  			this.validNeighbors = validNeighbors;
  			this.countError = mxResources.get(countError) || countError;
  			this.typeError = mxResources.get(typeError) || typeError;
  			this.validNeighborsAllowed = (validNeighborsAllowed != null) ?
  				validNeighborsAllowed : true;
  		}		mxMultiplicity.prototype.type = null;
  		mxMultiplicity.prototype.attr = null;
  		mxMultiplicity.prototype.value = null;
  		mxMultiplicity.prototype.source = null;
  		mxMultiplicity.prototype.min = null;
  		mxMultiplicity.prototype.max = null;
  		mxMultiplicity.prototype.validNeighbors = null;
  		mxMultiplicity.prototype.validNeighborsAllowed = true;
  		mxMultiplicity.prototype.countError = null;
  		mxMultiplicity.prototype.typeError = null;
  		mxMultiplicity.prototype.check = function(graph, edge, source, target, sourceOut, targetIn)
  		{
  			var error = '';
  			if ((this.source && this.checkTerminal(graph, source, edge)) ||
  				(!this.source && this.checkTerminal(graph, target, edge)))
  			{
  				if (this.countError != null &&
  					((this.source && (this.max == 0 || (sourceOut >= this.max))) ||
  					(!this.source && (this.max == 0 || (targetIn >= this.max)))))
  				{
  					error += this.countError + '\n';
  				}
  				if (this.validNeighbors != null && this.typeError != null && this.validNeighbors.length > 0)
  				{
  					var isValid = this.checkNeighbors(graph, edge, source, target);
  					if (!isValid)
  					{
  						error += this.typeError + '\n';
  					}
  				}
  			}
  			return (error.length > 0) ? error : null;
  		};
  		mxMultiplicity.prototype.checkNeighbors = function(graph, edge, source, target)
  		{
  			var sourceValue = graph.model.getValue(source);
  			var targetValue = graph.model.getValue(target);
  			var isValid = !this.validNeighborsAllowed;
  			var valid = this.validNeighbors;
  			for (var j = 0; j < valid.length; j++)
  			{
  				if (this.source &&
  					this.checkType(graph, targetValue, valid[j]))
  				{
  					isValid = this.validNeighborsAllowed;
  					break;
  				}
  				else if (!this.source &&
  					this.checkType(graph, sourceValue, valid[j]))
  				{
  					isValid = this.validNeighborsAllowed;
  					break;
  				}
  			}
  			return isValid;
  		};
  		mxMultiplicity.prototype.checkTerminal = function(graph, terminal, edge)
  		{
  			var value = graph.model.getValue(terminal);
  			return this.checkType(graph, value, this.type, this.attr, this.value);
  		};
  		mxMultiplicity.prototype.checkType = function(graph, value, type, attr, attrValue)
  		{
  			if (value != null)
  			{
  				if (!isNaN(value.nodeType))
  				{
  					return mxUtils.isNode(value, type, attr, attrValue);
  				}
  				else
  				{
  					return value == type;
  				}
  			}
  			return false;
  		};
  		__mxOutput.mxMultiplicity = typeof mxMultiplicity !== 'undefined' ? mxMultiplicity : undefined;
  		function mxLayoutManager(graph)
  		{
  			this.undoHandler = mxUtils.bind(this, function(sender, evt)
  			{
  				if (this.isEnabled())
  				{
  					this.beforeUndo(evt.getProperty('edit'));
  				}
  			});
  			this.moveHandler = mxUtils.bind(this, function(sender, evt)
  			{
  				if (this.isEnabled())
  				{
  					this.cellsMoved(evt.getProperty('cells'), evt.getProperty('event'));
  				}
  			});
  			this.resizeHandler = mxUtils.bind(this, function(sender, evt)
  			{
  				if (this.isEnabled())
  				{
  					this.cellsResized(evt.getProperty('cells'), evt.getProperty('bounds'),
  						evt.getProperty('previous'));
  				}
  			});
  			this.setGraph(graph);
  		}		mxLayoutManager.prototype = new mxEventSource();
  		mxLayoutManager.prototype.constructor = mxLayoutManager;
  		mxLayoutManager.prototype.graph = null;
  		mxLayoutManager.prototype.bubbling = true;
  		mxLayoutManager.prototype.enabled = true;
  		mxLayoutManager.prototype.undoHandler = null;
  		mxLayoutManager.prototype.moveHandler = null;
  		mxLayoutManager.prototype.resizeHandler = null;
  		mxLayoutManager.prototype.isEnabled = function()
  		{
  			return this.enabled;
  		};
  		mxLayoutManager.prototype.setEnabled = function(enabled)
  		{
  			this.enabled = enabled;
  		};
  		mxLayoutManager.prototype.isBubbling = function()
  		{
  			return this.bubbling;
  		};
  		mxLayoutManager.prototype.setBubbling = function(value)
  		{
  			this.bubbling = value;
  		};
  		mxLayoutManager.prototype.getGraph = function()
  		{
  			return this.graph;
  		};
  		mxLayoutManager.prototype.setGraph = function(graph)
  		{
  			if (this.graph != null)
  			{
  				var model = this.graph.getModel();
  				model.removeListener(this.undoHandler);
  				this.graph.removeListener(this.moveHandler);
  				this.graph.removeListener(this.resizeHandler);
  			}
  			this.graph = graph;
  			if (this.graph != null)
  			{
  				var model = this.graph.getModel();
  				model.addListener(mxEvent.BEFORE_UNDO, this.undoHandler);
  				this.graph.addListener(mxEvent.MOVE_CELLS, this.moveHandler);
  				this.graph.addListener(mxEvent.RESIZE_CELLS, this.resizeHandler);
  			}
  		};
  		mxLayoutManager.prototype.hasLayout = function(cell)
  		{
  			return this.getLayout(cell, mxEvent.LAYOUT_CELLS);
  		};
  		mxLayoutManager.prototype.getLayout = function(cell, eventName)
  		{
  			return null;
  		};
  		mxLayoutManager.prototype.beforeUndo = function(undoableEdit)
  		{
  			this.executeLayoutForCells(this.getCellsForChanges(undoableEdit.changes));
  		};
  		mxLayoutManager.prototype.cellsMoved = function(cells, evt)
  		{
  			if (cells != null && evt != null)
  			{
  				var point = mxUtils.convertPoint(this.getGraph().container,
  					mxEvent.getClientX(evt), mxEvent.getClientY(evt));
  				var model = this.getGraph().getModel();
  				for (var i = 0; i < cells.length; i++)
  				{
  					var layout = this.getLayout(model.getParent(cells[i]), mxEvent.MOVE_CELLS);
  					if (layout != null)
  					{
  						layout.moveCell(cells[i], point.x, point.y);
  					}
  				}
  			}
  		};
  		mxLayoutManager.prototype.cellsResized = function(cells, bounds, prev)
  		{
  			if (cells != null && bounds != null)
  			{
  				var model = this.getGraph().getModel();
  				for (var i = 0; i < cells.length; i++)
  				{
  					var layout = this.getLayout(model.getParent(cells[i]), mxEvent.RESIZE_CELLS);
  					if (layout != null)
  					{
  						layout.resizeCell(cells[i], bounds[i], prev[i]);
  					}
  				}
  			}
  		};
  		mxLayoutManager.prototype.getCellsForChanges = function(changes)
  		{
  			var result = [];
  			for (var i = 0; i < changes.length; i++)
  			{
  				var change = changes[i];
  				if (change instanceof mxRootChange)
  				{
  					return [];
  				}
  				else
  				{
  					result = result.concat(this.getCellsForChange(change));
  				}
  			}
  			return result;
  		};
  		mxLayoutManager.prototype.getCellsForChange = function(change)
  		{
  			if (change instanceof mxChildChange)
  			{
  				return this.addCellsWithLayout(change.child,
  					this.addCellsWithLayout(change.previous));
  			}
  			else if (change instanceof mxTerminalChange ||
  				change instanceof mxGeometryChange)
  			{
  				return this.addCellsWithLayout(change.cell);
  			}
  			else if (change instanceof mxVisibleChange ||
  				change instanceof mxStyleChange)
  			{
  				return this.addCellsWithLayout(change.cell);
  			}
  			return [];
  		};
  		mxLayoutManager.prototype.addCellsWithLayout = function(cell, result)
  		{
  			return this.addDescendantsWithLayout(cell,
  				this.addAncestorsWithLayout(cell, result));
  		};
  		mxLayoutManager.prototype.addAncestorsWithLayout = function(cell, result)
  		{
  			result = (result != null) ? result : [];
  			if (cell != null)
  			{
  				var layout = this.hasLayout(cell);
  				if (layout != null)
  				{
  					result.push(cell);
  				}
  				if (this.isBubbling())
  				{
  					var model = this.getGraph().getModel();
  					this.addAncestorsWithLayout(
  						model.getParent(cell), result);
  				}
  			}
  			return result;
  		};
  		mxLayoutManager.prototype.addDescendantsWithLayout = function(cell, result)
  		{
  			result = (result != null) ? result : [];
  			if (cell != null && this.hasLayout(cell))
  			{
  				var model = this.getGraph().getModel();
  				for (var i = 0; i < model.getChildCount(cell); i++)
  				{
  					var child = model.getChildAt(cell, i);
  					if (this.hasLayout(child))
  					{
  						result.push(child);
  						this.addDescendantsWithLayout(child, result);
  					}
  				}
  			}
  			return result;
  		};
  		mxLayoutManager.prototype.executeLayoutForCells = function(cells)
  		{
  			var sorted = mxUtils.sortCells(cells, false);
  			this.layoutCells(sorted, true);
  			this.layoutCells(sorted.reverse(), false);
  		};
  		mxLayoutManager.prototype.layoutCells = function(cells, bubble)
  		{
  			if (cells.length > 0)
  			{
  				var model = this.getGraph().getModel();
  				model.beginUpdate();
  				try
  				{
  					var last = null;
  					for (var i = 0; i < cells.length; i++)
  					{
  						if (cells[i] != model.getRoot() && cells[i] != last)
  						{
  							this.executeLayout(cells[i], bubble);
  							last = cells[i];
  						}
  					}
  					this.fireEvent(new mxEventObject(mxEvent.LAYOUT_CELLS, 'cells', cells));
  				}
  				finally
  				{
  					model.endUpdate();
  				}
  			}
  		};
  		mxLayoutManager.prototype.executeLayout = function(cell, bubble)
  		{
  			var layout = this.getLayout(cell, (bubble) ?
  				mxEvent.BEGIN_UPDATE : mxEvent.END_UPDATE);
  			if (layout != null)
  			{
  				layout.execute(cell);
  			}
  		};
  		mxLayoutManager.prototype.destroy = function()
  		{
  			this.setGraph(null);
  		};
  		__mxOutput.mxLayoutManager = typeof mxLayoutManager !== 'undefined' ? mxLayoutManager : undefined;
  		function mxSwimlaneManager(graph, horizontal, addEnabled, resizeEnabled)
  		{
  			this.horizontal = (horizontal != null) ? horizontal : true;
  			this.addEnabled = (addEnabled != null) ? addEnabled : true;
  			this.resizeEnabled = (resizeEnabled != null) ? resizeEnabled : true;
  			this.addHandler = mxUtils.bind(this, function(sender, evt)
  			{
  				if (this.isEnabled() && this.isAddEnabled())
  				{
  					this.cellsAdded(evt.getProperty('cells'));
  				}
  			});
  			this.resizeHandler = mxUtils.bind(this, function(sender, evt)
  			{
  				if (this.isEnabled() && this.isResizeEnabled())
  				{
  					this.cellsResized(evt.getProperty('cells'));
  				}
  			});
  			this.setGraph(graph);
  		}		mxSwimlaneManager.prototype = new mxEventSource();
  		mxSwimlaneManager.prototype.constructor = mxSwimlaneManager;
  		mxSwimlaneManager.prototype.graph = null;
  		mxSwimlaneManager.prototype.enabled = true;
  		mxSwimlaneManager.prototype.horizontal = true;
  		mxSwimlaneManager.prototype.addEnabled = true;
  		mxSwimlaneManager.prototype.resizeEnabled = true;
  		mxSwimlaneManager.prototype.addHandler = null;
  		mxSwimlaneManager.prototype.resizeHandler = null;
  		mxSwimlaneManager.prototype.isEnabled = function()
  		{
  			return this.enabled;
  		};
  		mxSwimlaneManager.prototype.setEnabled = function(value)
  		{
  			this.enabled = value;
  		};
  		mxSwimlaneManager.prototype.isHorizontal = function()
  		{
  			return this.horizontal;
  		};
  		mxSwimlaneManager.prototype.setHorizontal = function(value)
  		{
  			this.horizontal = value;
  		};
  		mxSwimlaneManager.prototype.isAddEnabled = function()
  		{
  			return this.addEnabled;
  		};
  		mxSwimlaneManager.prototype.setAddEnabled = function(value)
  		{
  			this.addEnabled = value;
  		};
  		mxSwimlaneManager.prototype.isResizeEnabled = function()
  		{
  			return this.resizeEnabled;
  		};
  		mxSwimlaneManager.prototype.setResizeEnabled = function(value)
  		{
  			this.resizeEnabled = value;
  		};
  		mxSwimlaneManager.prototype.getGraph = function()
  		{
  			return this.graph;
  		};
  		mxSwimlaneManager.prototype.setGraph = function(graph)
  		{
  			if (this.graph != null)
  			{
  				this.graph.removeListener(this.addHandler);
  				this.graph.removeListener(this.resizeHandler);
  			}
  			this.graph = graph;
  			if (this.graph != null)
  			{
  				this.graph.addListener(mxEvent.ADD_CELLS, this.addHandler);
  				this.graph.addListener(mxEvent.CELLS_RESIZED, this.resizeHandler);
  			}
  		};
  		mxSwimlaneManager.prototype.isSwimlaneIgnored = function(swimlane)
  		{
  			return !this.getGraph().isSwimlane(swimlane);
  		};
  		mxSwimlaneManager.prototype.isCellHorizontal = function(cell)
  		{
  			if (this.graph.isSwimlane(cell))
  			{
  				var style = this.graph.getCellStyle(cell);
  				return mxUtils.getValue(style, mxConstants.STYLE_HORIZONTAL, 1) == 1;
  			}
  			return !this.isHorizontal();
  		};
  		mxSwimlaneManager.prototype.cellsAdded = function(cells)
  		{
  			if (cells != null)
  			{
  				var model = this.getGraph().getModel();
  				model.beginUpdate();
  				try
  				{
  					for (var i = 0; i < cells.length; i++)
  					{
  						if (!this.isSwimlaneIgnored(cells[i]))
  						{
  							this.swimlaneAdded(cells[i]);
  						}
  					}
  				}
  				finally
  				{
  					model.endUpdate();
  				}
  			}
  		};
  		mxSwimlaneManager.prototype.swimlaneAdded = function(swimlane)
  		{
  			var model = this.getGraph().getModel();
  			var parent = model.getParent(swimlane);
  			var childCount = model.getChildCount(parent);
  			var geo = null;
  			for (var i = 0; i < childCount; i++)
  			{
  				var child = model.getChildAt(parent, i);
  				if (child != swimlane && !this.isSwimlaneIgnored(child))
  				{
  					geo = model.getGeometry(child);
  					if (geo != null)
  					{
  						break;
  					}
  				}
  			}
  			if (geo != null)
  			{
  				var parentHorizontal = (parent != null) ? this.isCellHorizontal(parent) : this.horizontal;
  				this.resizeSwimlane(swimlane, geo.width, geo.height, parentHorizontal);
  			}
  		};
  		mxSwimlaneManager.prototype.cellsResized = function(cells)
  		{
  			if (cells != null)
  			{
  				var model = this.getGraph().getModel();
  				model.beginUpdate();
  				try
  				{
  					for (var i = 0; i < cells.length; i++)
  					{
  						if (!this.isSwimlaneIgnored(cells[i]))
  						{
  							var geo = model.getGeometry(cells[i]);
  							if (geo != null)
  							{
  								var size = new mxRectangle(0, 0, geo.width, geo.height);
  								var top = cells[i];
  								var current = top;
  								while (current != null)
  								{
  									top = current;
  									current = model.getParent(current);
  									var tmp = (this.graph.isSwimlane(current)) ?
  											this.graph.getStartSize(current) :
  											new mxRectangle();
  									size.width += tmp.width;
  									size.height += tmp.height;
  								}
  								var parentHorizontal = (current != null) ? this.isCellHorizontal(current) : this.horizontal;
  								this.resizeSwimlane(top, size.width, size.height, parentHorizontal);
  							}
  						}
  					}
  				}
  				finally
  				{
  					model.endUpdate();
  				}
  			}
  		};
  		mxSwimlaneManager.prototype.resizeSwimlane = function(swimlane, w, h, parentHorizontal)
  		{
  			var model = this.getGraph().getModel();
  			model.beginUpdate();
  			try
  			{
  				var horizontal = this.isCellHorizontal(swimlane);
  				if (!this.isSwimlaneIgnored(swimlane))
  				{
  					var geo = model.getGeometry(swimlane);
  					if (geo != null)
  					{
  						if ((parentHorizontal && geo.height != h) || (!parentHorizontal && geo.width != w))
  						{
  							geo = geo.clone();
  							if (parentHorizontal)
  							{
  								geo.height = h;
  							}
  							else
  							{
  								geo.width = w;
  							}
  							model.setGeometry(swimlane, geo);
  						}
  					}
  				}
  				var tmp = (this.graph.isSwimlane(swimlane)) ?
  						this.graph.getStartSize(swimlane) :
  						new mxRectangle();
  				w -= tmp.width;
  				h -= tmp.height;
  				var childCount = model.getChildCount(swimlane);
  				for (var i = 0; i < childCount; i++)
  				{
  					var child = model.getChildAt(swimlane, i);
  					this.resizeSwimlane(child, w, h, horizontal);
  				}
  			}
  			finally
  			{
  				model.endUpdate();
  			}
  		};
  		mxSwimlaneManager.prototype.destroy = function()
  		{
  			this.setGraph(null);
  		};
  		__mxOutput.mxSwimlaneManager = typeof mxSwimlaneManager !== 'undefined' ? mxSwimlaneManager : undefined;
  		function mxTemporaryCellStates(view, scale, cells, isCellVisibleFn, getLinkForCellState)
  		{
  			scale = (scale != null) ? scale : 1;
  			this.view = view;
  			this.oldValidateCellState = view.validateCellState;
  			this.oldBounds = view.getGraphBounds();
  			this.oldStates = view.getStates();
  			this.oldScale = view.getScale();
  			this.oldDoRedrawShape = view.graph.cellRenderer.doRedrawShape;
  			var self = this;
  			if (getLinkForCellState != null)
  			{
  				view.graph.cellRenderer.doRedrawShape = function(state)
  				{
  					var oldPaint = state.shape.paint;
  					state.shape.paint = function(c)
  					{
  						var link = getLinkForCellState(state);
  						if (link != null)
  						{
  							c.setLink(link);
  						}
  						oldPaint.apply(this, arguments);
  						if (link != null)
  						{
  							c.setLink(null);
  						}
  					};
  					self.oldDoRedrawShape.apply(view.graph.cellRenderer, arguments);
  					state.shape.paint = oldPaint;
  				};
  			}
  			view.validateCellState = function(cell, resurse)
  			{
  				if (cell == null || isCellVisibleFn == null || isCellVisibleFn(cell))
  				{
  					return self.oldValidateCellState.apply(view, arguments);
  				}
  				return null;
  			};
  			view.setStates(new mxDictionary());
  			view.setScale(scale);
  			if (cells != null)
  			{
  				view.resetValidationState();
  				var bbox = null;
  				for (var i = 0; i < cells.length; i++)
  				{
  					var bounds = view.getBoundingBox(view.validateCellState(view.validateCell(cells[i])));
  					if (bbox == null)
  					{
  						bbox = bounds;
  					}
  					else
  					{
  						bbox.add(bounds);
  					}
  				}
  				view.setGraphBounds(bbox || new mxRectangle());
  			}
  		}		mxTemporaryCellStates.prototype.view = null;
  		mxTemporaryCellStates.prototype.oldStates = null;
  		mxTemporaryCellStates.prototype.oldBounds = null;
  		mxTemporaryCellStates.prototype.oldScale = null;
  		mxTemporaryCellStates.prototype.destroy = function()
  		{
  			this.view.setScale(this.oldScale);
  			this.view.setStates(this.oldStates);
  			this.view.setGraphBounds(this.oldBounds);
  			this.view.validateCellState = this.oldValidateCellState;
  			this.view.graph.cellRenderer.doRedrawShape = this.oldDoRedrawShape;
  		};
  		__mxOutput.mxTemporaryCellStates = typeof mxTemporaryCellStates !== 'undefined' ? mxTemporaryCellStates : undefined;
  		function mxCellStatePreview(graph)
  		{
  			this.deltas = new mxDictionary();
  			this.graph = graph;
  		}		mxCellStatePreview.prototype.graph = null;
  		mxCellStatePreview.prototype.deltas = null;
  		mxCellStatePreview.prototype.count = 0;
  		mxCellStatePreview.prototype.isEmpty = function()
  		{
  			return this.count == 0;
  		};
  		mxCellStatePreview.prototype.moveState = function(state, dx, dy, add, includeEdges)
  		{
  			add = (add != null) ? add : true;
  			includeEdges = (includeEdges != null) ? includeEdges : true;
  			var delta = this.deltas.get(state.cell);
  			if (delta == null)
  			{
  				delta = {point: new mxPoint(dx, dy), state: state};
  				this.deltas.put(state.cell, delta);
  				this.count++;
  			}
  			else if (add)
  			{
  				delta.point.x += dx;
  				delta.point.y += dy;
  			}
  			else
  			{
  				delta.point.x = dx;
  				delta.point.y = dy;
  			}
  			if (includeEdges)
  			{
  				this.addEdges(state);
  			}
  			return delta.point;
  		};
  		mxCellStatePreview.prototype.show = function(visitor)
  		{
  			this.deltas.visit(mxUtils.bind(this, function(key, delta)
  			{
  				this.translateState(delta.state, delta.point.x, delta.point.y);
  			}));
  			this.deltas.visit(mxUtils.bind(this, function(key, delta)
  			{
  				this.revalidateState(delta.state, delta.point.x, delta.point.y, visitor);
  			}));
  		};
  		mxCellStatePreview.prototype.translateState = function(state, dx, dy)
  		{
  			if (state != null)
  			{
  				var model = this.graph.getModel();
  				if (model.isVertex(state.cell))
  				{
  					state.view.updateCellState(state);
  					var geo = model.getGeometry(state.cell);
  					if ((dx != 0 || dy != 0) && geo != null && (!geo.relative || this.deltas.get(state.cell) != null))
  					{
  						state.x += dx;
  						state.y += dy;
  					}
  				}
  			    var childCount = model.getChildCount(state.cell);
  			    for (var i = 0; i < childCount; i++)
  			    {
  			    	this.translateState(state.view.getState(model.getChildAt(state.cell, i)), dx, dy);
  			    }
  			}
  		};
  		mxCellStatePreview.prototype.revalidateState = function(state, dx, dy, visitor)
  		{
  			if (state != null)
  			{
  				var model = this.graph.getModel();
  				if (model.isEdge(state.cell))
  				{
  					state.view.updateCellState(state);
  				}
  				var geo = this.graph.getCellGeometry(state.cell);
  				var pState = state.view.getState(model.getParent(state.cell));
  				if ((dx != 0 || dy != 0) && geo != null && geo.relative &&
  					model.isVertex(state.cell) && (pState == null ||
  					model.isVertex(pState.cell) || this.deltas.get(state.cell) != null))
  				{
  					state.x += dx;
  					state.y += dy;
  				}
  				this.graph.cellRenderer.redraw(state);
  				if (visitor != null)
  				{
  					visitor(state);
  				}
  			    var childCount = model.getChildCount(state.cell);
  			    for (var i = 0; i < childCount; i++)
  			    {
  			    	this.revalidateState(this.graph.view.getState(model.getChildAt(state.cell, i)), dx, dy, visitor);
  			    }
  			}
  		};
  		mxCellStatePreview.prototype.addEdges = function(state)
  		{
  			var model = this.graph.getModel();
  			var edgeCount = model.getEdgeCount(state.cell);
  			for (var i = 0; i < edgeCount; i++)
  			{
  				var s = state.view.getState(model.getEdgeAt(state.cell, i));
  				if (s != null)
  				{
  					this.moveState(s, 0, 0);
  				}
  			}
  		};
  		__mxOutput.mxCellStatePreview = typeof mxCellStatePreview !== 'undefined' ? mxCellStatePreview : undefined;
  		function mxConnectionConstraint(point, perimeter, name, dx, dy)
  		{
  			this.point = point;
  			this.perimeter = (perimeter != null) ? perimeter : true;
  			this.name = name;
  			this.dx = dx? dx : 0;
  			this.dy = dy? dy : 0;
  		}		mxConnectionConstraint.prototype.point = null;
  		mxConnectionConstraint.prototype.perimeter = null;
  		mxConnectionConstraint.prototype.name = null;
  		mxConnectionConstraint.prototype.dx = null;
  		mxConnectionConstraint.prototype.dy = null;
  		__mxOutput.mxConnectionConstraint = typeof mxConnectionConstraint !== 'undefined' ? mxConnectionConstraint : undefined;
  		function mxGraphHandler(graph)
  		{
  			this.graph = graph;
  			this.graph.addMouseListener(this);
  			this.panHandler = mxUtils.bind(this, function()
  			{
  				if (!this.suspended)
  				{
  					this.updatePreview();
  					this.updateHint();
  				}
  			});
  			this.graph.addListener(mxEvent.PAN, this.panHandler);
  			this.escapeHandler = mxUtils.bind(this, function(sender, evt)
  			{
  				this.reset();
  			});
  			this.graph.addListener(mxEvent.ESCAPE, this.escapeHandler);
  			this.refreshHandler = mxUtils.bind(this, function(sender, evt)
  			{
  				if (this.refreshThread)
  				{
  					window.clearTimeout(this.refreshThread);
  				}
  				this.refreshThread = window.setTimeout(mxUtils.bind(this, function()
  				{
  					this.refreshThread = null;
  					if (this.first != null && !this.suspended)
  					{
  						var dx = this.currentDx;
  						var dy = this.currentDy;
  						this.currentDx = 0;
  						this.currentDy = 0;
  						this.updatePreview();
  						this.bounds = this.graph.getView().getBounds(this.cells);
  						this.pBounds = this.getPreviewBounds(this.cells);
  						if (this.pBounds == null && !this.livePreviewUsed)
  						{
  							this.reset();
  						}
  						else
  						{
  							this.currentDx = dx;
  							this.currentDy = dy;
  							this.updatePreview();
  							this.updateHint();
  							if (this.livePreviewUsed)
  							{
  								this.setHandlesVisibleForCells(
  									this.graph.selectionCellsHandler.
  									getHandledSelectionCells(), false, true);
  								this.updatePreview();
  							}
  						}
  					}
  				}), 0);
  			});
  			this.graph.getModel().addListener(mxEvent.CHANGE, this.refreshHandler);
  			this.graph.addListener(mxEvent.REFRESH, this.refreshHandler);
  			this.keyHandler = mxUtils.bind(this, function(e)
  			{
  				if (this.graph.container != null && this.graph.container.style.visibility != 'hidden' &&
  					this.first != null && !this.suspended)
  				{
  					var clone = this.graph.isCloneEvent(e) &&
  						this.graph.isCellsCloneable() &&
  						this.isCloneEnabled();
  					if (clone != this.cloning)
  					{
  						this.cloning = clone;
  						this.checkPreview();
  						this.updatePreview();
  					}
  				}
  			});
  			mxEvent.addListener(document, 'keydown', this.keyHandler);
  			mxEvent.addListener(document, 'keyup', this.keyHandler);
  		}		mxGraphHandler.prototype.graph = null;
  		mxGraphHandler.prototype.maxCells = (mxClient.IS_IE) ? 20 : 50;
  		mxGraphHandler.prototype.enabled = true;
  		mxGraphHandler.prototype.highlightEnabled = true;
  		mxGraphHandler.prototype.cloneEnabled = true;
  		mxGraphHandler.prototype.moveEnabled = true;
  		mxGraphHandler.prototype.guidesEnabled = false;
  		mxGraphHandler.prototype.handlesVisible = true;
  		mxGraphHandler.prototype.guide = null;
  		mxGraphHandler.prototype.currentDx = null;
  		mxGraphHandler.prototype.currentDy = null;
  		mxGraphHandler.prototype.updateCursor = true;
  		mxGraphHandler.prototype.selectEnabled = true;
  		mxGraphHandler.prototype.removeCellsFromParent = true;
  		mxGraphHandler.prototype.removeEmptyParents = false;
  		mxGraphHandler.prototype.connectOnDrop = false;
  		mxGraphHandler.prototype.scrollOnMove = true;
  		mxGraphHandler.prototype.minimumSize = 6;
  		mxGraphHandler.prototype.previewColor = 'black';
  		mxGraphHandler.prototype.htmlPreview = false;
  		mxGraphHandler.prototype.shape = null;
  		mxGraphHandler.prototype.scaleGrid = false;
  		mxGraphHandler.prototype.rotationEnabled = true;
  		mxGraphHandler.prototype.maxLivePreview = 0;
  		mxGraphHandler.prototype.allowLivePreview = mxClient.IS_SVG;
  		mxGraphHandler.prototype.isEnabled = function()
  		{
  			return this.enabled;
  		};
  		mxGraphHandler.prototype.setEnabled = function(value)
  		{
  			this.enabled = value;
  		};
  		mxGraphHandler.prototype.isCloneEnabled = function()
  		{
  			return this.cloneEnabled;
  		};
  		mxGraphHandler.prototype.setCloneEnabled = function(value)
  		{
  			this.cloneEnabled = value;
  		};
  		mxGraphHandler.prototype.isMoveEnabled = function()
  		{
  			return this.moveEnabled;
  		};
  		mxGraphHandler.prototype.setMoveEnabled = function(value)
  		{
  			this.moveEnabled = value;
  		};
  		mxGraphHandler.prototype.isSelectEnabled = function()
  		{
  			return this.selectEnabled;
  		};
  		mxGraphHandler.prototype.setSelectEnabled = function(value)
  		{
  			this.selectEnabled = value;
  		};
  		mxGraphHandler.prototype.isRemoveCellsFromParent = function()
  		{
  			return this.removeCellsFromParent;
  		};
  		mxGraphHandler.prototype.setRemoveCellsFromParent = function(value)
  		{
  			this.removeCellsFromParent = value;
  		};
  		mxGraphHandler.prototype.isPropagateSelectionCell = function(cell, immediate, me)
  		{
  			var parent = this.graph.model.getParent(cell);
  			if (immediate)
  			{
  				var geo = (this.graph.model.isEdge(cell)) ? null :
  					this.graph.getCellGeometry(cell);
  				return !this.graph.isSiblingSelected(cell) &&
  					((geo != null && geo.relative) ||
  					!this.graph.isSwimlane(parent));
  			}
  			else
  			{
  				return (!this.graph.isToggleEvent(me.getEvent()) ||
  					(!this.graph.isSiblingSelected(cell) &&
  					!this.graph.isCellSelected(cell) &&
  					(!this.graph.isSwimlane(parent)) ||
  					this.graph.isCellSelected(parent))) &&
  					(this.graph.isToggleEvent(me.getEvent()) ||
  					!this.graph.isCellSelected(parent));
  			}
  		};
  		mxGraphHandler.prototype.getInitialCellForEvent = function(me)
  		{
  			var state = me.getState();
  			if ((!this.graph.isToggleEvent(me.getEvent()) || !mxEvent.isAltDown(me.getEvent())) &&
  				state != null && !this.graph.isCellSelected(state.cell))
  			{
  				var model = this.graph.model;
  				var next = this.graph.view.getState(model.getParent(state.cell));
  				while (next != null && !this.graph.isCellSelected(next.cell) &&
  					(model.isVertex(next.cell) || model.isEdge(next.cell)) &&
  					this.isPropagateSelectionCell(state.cell, true, me))
  				{
  					state = next;
  					next = this.graph.view.getState(this.graph.getModel().getParent(state.cell));
  				}
  			}
  			return (state != null) ? state.cell : null;
  		};
  		mxGraphHandler.prototype.isDelayedSelection = function(cell, me)
  		{
  			if (!this.graph.isToggleEvent(me.getEvent()) || !mxEvent.isAltDown(me.getEvent()))
  			{
  				while (cell != null)
  				{
  					if (this.graph.selectionCellsHandler.isHandled(cell))
  					{
  						return this.graph.cellEditor.getEditingCell() != cell;
  					}
  					cell = this.graph.model.getParent(cell);
  				}
  			}
  			return this.graph.isToggleEvent(me.getEvent()) && !mxEvent.isAltDown(me.getEvent());
  		};
  		mxGraphHandler.prototype.selectDelayed = function(me)
  		{
  			if (!this.graph.popupMenuHandler.isPopupTrigger(me))
  			{
  				var cell = me.getCell();
  				if (cell == null)
  				{
  					cell = this.cell;
  				}
  				this.selectCellForEvent(cell, me);
  			}
  		};
  		mxGraphHandler.prototype.selectCellForEvent = function(cell, me)
  		{
  			var state = this.graph.view.getState(cell);
  			if (state != null)
  			{
  				if (me.isSource(state.control))
  				{
  					this.graph.selectCellForEvent(cell, me.getEvent());
  				}
  				else
  				{
  					if (!this.graph.isToggleEvent(me.getEvent()) ||
  						!mxEvent.isAltDown(me.getEvent()))
  					{
  						var model = this.graph.getModel();
  						var parent = model.getParent(cell);
  						while (this.graph.view.getState(parent) != null &&
  							(model.isVertex(parent) || model.isEdge(parent)) &&
  							this.isPropagateSelectionCell(cell, false, me))
  						{
  							cell = parent;
  							parent = model.getParent(cell);
  						}
  					}
  					this.graph.selectCellForEvent(cell, me.getEvent());
  				}
  			}
  			return cell;
  		};
  		mxGraphHandler.prototype.consumeMouseEvent = function(evtName, me)
  		{
  			me.consume();
  		};
  		mxGraphHandler.prototype.mouseDown = function(sender, me)
  		{
  			if (!me.isConsumed() && this.isEnabled() && this.graph.isEnabled() &&
  				me.getState() != null && !mxEvent.isMultiTouchEvent(me.getEvent()))
  			{
  				var cell = this.getInitialCellForEvent(me);
  				this.delayedSelection = this.isDelayedSelection(cell, me);
  				this.cell = null;
  				if (this.isSelectEnabled() && !this.delayedSelection)
  				{
  					this.graph.selectCellForEvent(cell, me.getEvent());
  				}
  				if (this.isMoveEnabled())
  				{
  					var model = this.graph.model;
  					var geo = model.getGeometry(cell);
  					if (this.graph.isCellMovable(cell) && ((!model.isEdge(cell) || this.graph.getSelectionCount() > 1 ||
  						(geo.points != null && geo.points.length > 0) || model.getTerminal(cell, true) == null ||
  						model.getTerminal(cell, false) == null) || this.graph.allowDanglingEdges ||
  						(this.graph.isCloneEvent(me.getEvent()) && this.graph.isCellsCloneable())))
  					{
  						this.start(cell, me.getX(), me.getY());
  					}
  					else if (this.delayedSelection)
  					{
  						this.cell = cell;
  					}
  					this.cellWasClicked = true;
  					this.consumeMouseEvent(mxEvent.MOUSE_DOWN, me);
  				}
  			}
  		};
  		mxGraphHandler.prototype.getGuideStates = function()
  		{
  			var parent = this.graph.getDefaultParent();
  			var model = this.graph.getModel();
  			var filter = mxUtils.bind(this, function(cell)
  			{
  				return this.graph.view.getState(cell) != null &&
  					model.isVertex(cell) &&
  					model.getGeometry(cell) != null &&
  					!model.getGeometry(cell).relative;
  			});
  			return this.graph.view.getCellStates(model.filterDescendants(filter, parent));
  		};
  		mxGraphHandler.prototype.getCells = function(initialCell)
  		{
  			if (!this.delayedSelection && this.graph.isCellMovable(initialCell))
  			{
  				return [initialCell];
  			}
  			else
  			{
  				return this.graph.getMovableCells(this.graph.getSelectionCells());
  			}
  		};
  		mxGraphHandler.prototype.getPreviewBounds = function(cells)
  		{
  			var bounds = this.getBoundingBox(cells);
  			if (bounds != null)
  			{
  				bounds.width = Math.max(0, bounds.width - 1);
  				bounds.height = Math.max(0, bounds.height - 1);
  				if (bounds.width < this.minimumSize)
  				{
  					var dx = this.minimumSize - bounds.width;
  					bounds.x -= dx / 2;
  					bounds.width = this.minimumSize;
  				}
  				else
  				{
  					bounds.x = Math.round(bounds.x);
  					bounds.width = Math.ceil(bounds.width);
  				}
  				this.graph.view.translate;
  				this.graph.view.scale;
  				if (bounds.height < this.minimumSize)
  				{
  					var dy = this.minimumSize - bounds.height;
  					bounds.y -= dy / 2;
  					bounds.height = this.minimumSize;
  				}
  				else
  				{
  					bounds.y = Math.round(bounds.y);
  					bounds.height = Math.ceil(bounds.height);
  				}
  			}
  			return bounds;
  		};
  		mxGraphHandler.prototype.getBoundingBox = function(cells)
  		{
  			var result = null;
  			if (cells != null && cells.length > 0)
  			{
  				var model = this.graph.getModel();
  				for (var i = 0; i < cells.length; i++)
  				{
  					if (model.isVertex(cells[i]) || model.isEdge(cells[i]))
  					{
  						var state = this.graph.view.getState(cells[i]);
  						if (state != null)
  						{
  							var bbox = state;
  							if (model.isVertex(cells[i]) && state.shape != null && state.shape.boundingBox != null)
  							{
  								bbox = state.shape.boundingBox;
  							}
  							if (result == null)
  							{
  								result = mxRectangle.fromRectangle(bbox);
  							}
  							else
  							{
  								result.add(bbox);
  							}
  						}
  					}
  				}
  			}
  			return result;
  		};
  		mxGraphHandler.prototype.createPreviewShape = function(bounds)
  		{
  			var shape = new mxRectangleShape(bounds, null, this.previewColor);
  			shape.isDashed = true;
  			if (this.htmlPreview)
  			{
  				shape.dialect = mxConstants.DIALECT_STRICTHTML;
  				shape.init(this.graph.container);
  			}
  			else
  			{
  				shape.dialect = (this.graph.dialect != mxConstants.DIALECT_SVG) ?
  					mxConstants.DIALECT_VML : mxConstants.DIALECT_SVG;
  				shape.init(this.graph.getView().getOverlayPane());
  				shape.pointerEvents = false;
  				if (mxClient.IS_IOS)
  				{
  					shape.getSvgScreenOffset = function()
  					{
  						return 0;
  					};
  				}
  			}
  			return shape;
  		};
  		mxGraphHandler.prototype.start = function(cell, x, y, cells)
  		{
  			this.cell = cell;
  			this.first = mxUtils.convertPoint(this.graph.container, x, y);
  			this.cells = (cells != null) ? cells : this.getCells(this.cell);
  			this.bounds = this.graph.getView().getBounds(this.cells);
  			this.pBounds = this.getPreviewBounds(this.cells);
  			this.allCells = new mxDictionary();
  			this.cloning = false;
  			this.cellCount = 0;
  			for (var i = 0; i < this.cells.length; i++)
  			{
  				this.cellCount += this.addStates(this.cells[i], this.allCells);
  			}
  			if (this.guidesEnabled)
  			{
  				this.guide = new mxGuide(this.graph, this.getGuideStates());
  				var parent = this.graph.model.getParent(cell);
  				var ignore = this.graph.model.getChildCount(parent) < 2;
  				var connected = new mxDictionary();
  				var opps = this.graph.getOpposites(this.graph.getEdges(this.cell), this.cell);
  				for (var i = 0; i < opps.length; i++)
  				{
  					var state = this.graph.view.getState(opps[i]);
  					if (state != null && !connected.get(state))
  					{
  						connected.put(state, true);
  					}
  				}
  				this.guide.isStateIgnored = mxUtils.bind(this, function(state)
  				{
  					var p = this.graph.model.getParent(state.cell);
  					return state.cell != null && ((!this.cloning &&
  						this.isCellMoving(state.cell)) ||
  						(state.cell != (this.target || parent) && !ignore &&
  						!connected.get(state) &&
  						(this.target == null || this.graph.model.getChildCount(
  						this.target) >= 2) && p != (this.target || parent)));
  				});
  			}
  		};
  		mxGraphHandler.prototype.addStates = function(cell, dict)
  		{
  			var state = this.graph.view.getState(cell);
  			var count = 0;
  			if (state != null && dict.get(cell) == null)
  			{
  				dict.put(cell, state);
  				count++;
  				var childCount = this.graph.model.getChildCount(cell);
  				for (var i = 0; i < childCount; i++)
  				{
  					count += this.addStates(this.graph.model.getChildAt(cell, i), dict);
  				}
  			}
  			return count;
  		};
  		mxGraphHandler.prototype.isCellMoving = function(cell)
  		{
  			return this.allCells.get(cell) != null;
  		};
  		mxGraphHandler.prototype.useGuidesForEvent = function(me)
  		{
  			return (this.guide != null) ? this.guide.isEnabledForEvent(me.getEvent()) &&
  				!this.graph.isConstrainedEvent(me.getEvent()) : true;
  		};
  		mxGraphHandler.prototype.snap = function(vector)
  		{
  			var scale = (this.scaleGrid) ? this.graph.view.scale : 1;
  			vector.x = this.graph.snap(vector.x / scale) * scale;
  			vector.y = this.graph.snap(vector.y / scale) * scale;
  			return vector;
  		};
  		mxGraphHandler.prototype.getDelta = function(me)
  		{
  			var point = mxUtils.convertPoint(this.graph.container, me.getX(), me.getY());
  			return new mxPoint(point.x - this.first.x - this.graph.panDx,
  				point.y - this.first.y - this.graph.panDy);
  		};
  		mxGraphHandler.prototype.updateHint = function(me) { };
  		mxGraphHandler.prototype.removeHint = function() { };
  		mxGraphHandler.prototype.roundLength = function(length)
  		{
  			return Math.round(length * 100) / 100;
  		};
  		mxGraphHandler.prototype.isValidDropTarget = function(target, me)
  		{
  			return this.graph.model.getParent(this.cell) != target;
  		};
  		mxGraphHandler.prototype.checkPreview = function()
  		{
  			if (this.livePreviewActive && this.cloning)
  			{
  				this.resetLivePreview();
  				this.livePreviewActive = false;
  			}
  			else if (this.maxLivePreview >= this.cellCount && !this.livePreviewActive && this.allowLivePreview)
  			{
  				if (!this.cloning || !this.livePreviewActive)
  				{
  					this.livePreviewActive = true;
  					this.livePreviewUsed = true;
  				}
  			}
  			else if (!this.livePreviewUsed && this.shape == null)
  			{
  				this.shape = this.createPreviewShape(this.bounds);
  			}
  		};
  		mxGraphHandler.prototype.mouseMove = function(sender, me)
  		{
  			var graph = this.graph;
  			if (!me.isConsumed() && graph.isMouseDown && this.cell != null &&
  				this.first != null && this.bounds != null && !this.suspended)
  			{
  				if (mxEvent.isMultiTouchEvent(me.getEvent()))
  				{
  					this.reset();
  					return;
  				}
  				var delta = this.getDelta(me);
  				var tol = graph.tolerance;
  				if (this.shape != null || this.livePreviewActive || Math.abs(delta.x) > tol || Math.abs(delta.y) > tol)
  				{
  					if (this.highlight == null)
  					{
  						this.highlight = new mxCellHighlight(this.graph,
  							mxConstants.DROP_TARGET_COLOR, 3);
  					}
  					var clone = graph.isCloneEvent(me.getEvent()) && graph.isCellsCloneable() && this.isCloneEnabled();
  					var gridEnabled = graph.isGridEnabledEvent(me.getEvent());
  					var cell = me.getCell();
  					var hideGuide = true;
  					var target = null;
  					this.cloning = clone;
  					if (graph.isDropEnabled() && this.highlightEnabled)
  					{
  						target = graph.getDropTarget(this.cells, me.getEvent(), cell, clone);
  					}
  					var state = graph.getView().getState(target);
  					var highlight = false;
  					if (state != null && (clone || this.isValidDropTarget(target, me)))
  					{
  					    if (this.target != target)
  					    {
  						    this.target = target;
  						    this.setHighlightColor(mxConstants.DROP_TARGET_COLOR);
  						}
  					    highlight = true;
  					}
  					else
  					{
  						this.target = null;
  						if (this.connectOnDrop && cell != null && this.cells.length == 1 &&
  							graph.getModel().isVertex(cell) && graph.isCellConnectable(cell))
  						{
  							state = graph.getView().getState(cell);
  							if (state != null)
  							{
  								var error = graph.getEdgeValidationError(null, this.cell, cell);
  								var color = (error == null) ?
  									mxConstants.VALID_COLOR :
  									mxConstants.INVALID_CONNECT_TARGET_COLOR;
  								this.setHighlightColor(color);
  								highlight = true;
  							}
  						}
  					}
  					if (state != null && highlight)
  					{
  						this.highlight.highlight(state);
  					}
  					else
  					{
  						this.highlight.hide();
  					}
  					if (this.guide != null && this.useGuidesForEvent(me))
  					{
  						delta = this.guide.move(this.bounds, delta, gridEnabled, clone);
  						hideGuide = false;
  					}
  					else
  					{
  						delta = this.graph.snapDelta(delta, this.bounds, !gridEnabled, false, false);
  					}
  					if (this.guide != null && hideGuide)
  					{
  						this.guide.hide();
  					}
  					if (graph.isConstrainedEvent(me.getEvent()))
  					{
  						if (Math.abs(delta.x) > Math.abs(delta.y))
  						{
  							delta.y = 0;
  						}
  						else
  						{
  							delta.x = 0;
  						}
  					}
  					this.checkPreview();
  					if (this.currentDx != delta.x || this.currentDy != delta.y)
  					{
  						this.currentDx = delta.x;
  						this.currentDy = delta.y;
  						this.updatePreview();
  					}
  				}
  				this.updateHint(me);
  				this.consumeMouseEvent(mxEvent.MOUSE_MOVE, me);
  				mxEvent.consume(me.getEvent());
  			}
  			else if ((this.isMoveEnabled() || this.isCloneEnabled()) && this.updateCursor && !me.isConsumed() &&
  					(me.getState() != null || me.sourceState != null) && !graph.isMouseDown)
  			{
  				var cursor = graph.getCursorForMouseEvent(me);
  				if (cursor == null && graph.isEnabled() && graph.isCellMovable(me.getCell()))
  				{
  					if (graph.getModel().isEdge(me.getCell()))
  					{
  						cursor = mxConstants.CURSOR_MOVABLE_EDGE;
  					}
  					else
  					{
  						cursor = mxConstants.CURSOR_MOVABLE_VERTEX;
  					}
  				}
  				if (cursor != null && me.sourceState != null)
  				{
  					me.sourceState.setCursor(cursor);
  				}
  			}
  		};
  		mxGraphHandler.prototype.updatePreview = function(remote)
  		{
  			if (this.livePreviewUsed && !remote)
  			{
  				if (this.cells != null)
  				{
  					this.setHandlesVisibleForCells(
  						this.graph.selectionCellsHandler.
  						getHandledSelectionCells(), false);
  					this.updateLivePreview(this.currentDx, this.currentDy);
  				}
  			}
  			else
  			{
  				this.updatePreviewShape();
  			}
  		};
  		mxGraphHandler.prototype.updatePreviewShape = function()
  		{
  			if (this.shape != null && this.pBounds != null)
  			{
  				this.shape.bounds = new mxRectangle(Math.round(this.pBounds.x + this.currentDx),
  						Math.round(this.pBounds.y + this.currentDy), this.pBounds.width, this.pBounds.height);
  				this.shape.redraw();
  			}
  		};
  		mxGraphHandler.prototype.updateLivePreview = function(dx, dy)
  		{
  			if (!this.suspended)
  			{
  				var states = [];
  				if (this.allCells != null)
  				{
  					this.allCells.visit(mxUtils.bind(this, function(key, state)
  					{
  						var realState = this.graph.view.getState(state.cell);
  						if (realState != state)
  						{
  							state.destroy();
  							if (realState != null)
  							{
  								this.allCells.put(state.cell, realState);
  							}
  							else
  							{
  								this.allCells.remove(state.cell);
  							}
  							state = realState;
  						}
  						if (state != null)
  						{
  							var tempState = state.clone();
  							states.push([state, tempState]);
  							if (state.shape != null)
  							{
  								if (state.shape.originalPointerEvents == null)
  								{
  									state.shape.originalPointerEvents = state.shape.pointerEvents;
  								}
  								state.shape.pointerEvents = false;
  								if (state.text != null)
  								{
  									if (state.text.originalPointerEvents == null)
  									{
  										state.text.originalPointerEvents = state.text.pointerEvents;
  									}
  									state.text.pointerEvents = false;
  								}
  							}
  							if (this.graph.model.isVertex(state.cell))
  							{
  								state.x += dx;
  								state.y += dy;
  								if (!this.cloning)
  								{
  									state.view.graph.cellRenderer.redraw(state, true);
  									state.view.invalidate(state.cell);
  									state.invalid = false;
  									if (state.control != null && state.control.node != null)
  									{
  										state.control.node.style.visibility = 'hidden';
  									}
  								}
  								else if (state.text != null)
  								{
  									state.text.updateBoundingBox();
  									if (state.text.boundingBox != null)
  									{
  										state.text.boundingBox.x += dx;
  										state.text.boundingBox.y += dy;
  									}
  									if (state.text.unrotatedBoundingBox != null)
  									{
  										state.text.unrotatedBoundingBox.x += dx;
  										state.text.unrotatedBoundingBox.y += dy;
  									}
  								}
  							}
  						}
  					}));
  				}
  				if (states.length == 0)
  				{
  					this.reset();
  				}
  				else
  				{
  					var s = this.graph.view.scale;
  					for (var i = 0; i < states.length; i++)
  					{
  						var state = states[i][0];
  						if (this.graph.model.isEdge(state.cell))
  						{
  							var geometry = this.graph.getCellGeometry(state.cell);
  							var points = [];
  							if (geometry != null && geometry.points != null)
  							{
  								for (var j = 0; j < geometry.points.length; j++)
  								{
  									if (geometry.points[j] != null)
  									{
  										points.push(new mxPoint(
  											geometry.points[j].x + dx / s,
  											geometry.points[j].y + dy / s));
  									}
  								}
  							}
  							var source = state.visibleSourceState;
  							var target = state.visibleTargetState;
  							var pts = states[i][1].absolutePoints;
  							if (source == null || !this.isCellMoving(source.cell))
  							{
  								var pt0 = pts[0];
  								state.setAbsoluteTerminalPoint(new mxPoint(pt0.x + dx, pt0.y + dy), true);
  								source = null;
  							}
  							else
  							{
  								state.view.updateFixedTerminalPoint(state, source, true,
  									this.graph.getConnectionConstraint(state, source, true));
  							}
  							if (target == null || !this.isCellMoving(target.cell))
  							{
  								var ptn = pts[pts.length - 1];
  								state.setAbsoluteTerminalPoint(new mxPoint(ptn.x + dx, ptn.y + dy), false);
  								target = null;
  							}
  							else
  							{
  								state.view.updateFixedTerminalPoint(state, target, false,
  									this.graph.getConnectionConstraint(state, target, false));
  							}
  							state.view.updatePoints(state, points, source, target);
  							state.view.updateFloatingTerminalPoints(state, source, target);
  							state.view.updateEdgeLabelOffset(state);
  							state.invalid = false;
  							if (!this.cloning)
  							{
  								state.view.graph.cellRenderer.redraw(state, true);
  							}
  						}
  					}
  					this.graph.view.validate();
  					this.redrawHandles(states);
  					this.resetPreviewStates(states);
  				}
  			}
  		};
  		mxGraphHandler.prototype.redrawHandles = function(states)
  		{
  			for (var i = 0; i < states.length; i++)
  			{
  				var handler = this.graph.selectionCellsHandler.getHandler(states[i][0].cell);
  				if (handler != null)
  				{
  					handler.redraw(true);
  				}
  			}
  		};
  		mxGraphHandler.prototype.resetPreviewStates = function(states)
  		{
  			for (var i = 0; i < states.length; i++)
  			{
  				states[i][0].setState(states[i][1]);
  			}
  		};
  		mxGraphHandler.prototype.suspend = function()
  		{
  			if (!this.suspended)
  			{
  				if (this.livePreviewUsed)
  				{
  					this.updateLivePreview(0, 0);
  				}
  				if (this.shape != null)
  				{
  					this.shape.node.style.visibility = 'hidden';
  				}
  				if (this.guide != null)
  				{
  					this.guide.setVisible(false);
  				}
  				this.suspended = true;
  			}
  		};
  		mxGraphHandler.prototype.resume = function()
  		{
  			if (this.suspended)
  			{
  				this.suspended = null;
  				if (this.livePreviewUsed)
  				{
  					this.livePreviewActive = true;
  				}
  				if (this.shape != null)
  				{
  					this.shape.node.style.visibility = 'visible';
  				}
  				if (this.guide != null)
  				{
  					this.guide.setVisible(true);
  				}
  			}
  		};
  		mxGraphHandler.prototype.resetLivePreview = function()
  		{
  			if (this.allCells != null)
  			{
  				this.allCells.visit(mxUtils.bind(this, function(key, state)
  				{
  					if (state.shape != null && state.shape.originalPointerEvents != null)
  					{
  						state.shape.pointerEvents = state.shape.originalPointerEvents;
  						state.shape.originalPointerEvents = null;
  						state.shape.bounds = null;
  						if (state.text != null)
  						{
  							state.text.pointerEvents = state.text.originalPointerEvents;
  							state.text.originalPointerEvents = null;
  						}
  					}
  					if (state.control != null && state.control.node != null &&
  						state.control.node.style.visibility == 'hidden')
  					{
  						state.control.node.style.visibility = '';
  					}
  					if (!this.cloning)
  					{
  						if (state.text != null)
  						{
  							state.text.updateBoundingBox();
  						}
  					}
  					state.view.invalidate(state.cell);
  				}));
  				this.graph.view.validate();
  			}
  		};
  		mxGraphHandler.prototype.setHandlesVisibleForCells = function(cells, visible, force)
  		{
  			if (force || this.handlesVisible != visible)
  			{
  				this.handlesVisible = visible;
  				for (var i = 0; i < cells.length; i++)
  				{
  					var handler = this.graph.selectionCellsHandler.getHandler(cells[i]);
  					if (handler != null)
  					{
  						handler.setHandlesVisible(visible);
  						if (visible)
  						{
  							handler.redraw();
  						}
  					}
  				}
  			}
  		};
  		mxGraphHandler.prototype.setHighlightColor = function(color)
  		{
  			if (this.highlight != null)
  			{
  				this.highlight.setHighlightColor(color);
  			}
  		};
  		mxGraphHandler.prototype.mouseUp = function(sender, me)
  		{
  			if (!me.isConsumed())
  			{
  				if (this.livePreviewUsed)
  				{
  					this.resetLivePreview();
  				}
  				if (this.cell != null && this.first != null && (this.shape != null || this.livePreviewUsed) &&
  					this.currentDx != null && this.currentDy != null)
  				{
  					var graph = this.graph;
  					var cell = me.getCell();
  					if (this.connectOnDrop && this.target == null && cell != null && graph.getModel().isVertex(cell) &&
  						graph.isCellConnectable(cell) && graph.isEdgeValid(null, this.cell, cell))
  					{
  						graph.connectionHandler.connect(this.cell, cell, me.getEvent());
  					}
  					else
  					{
  						var clone = graph.isCloneEvent(me.getEvent()) && graph.isCellsCloneable() && this.isCloneEnabled();
  						var scale = graph.getView().scale;
  						var dx = this.roundLength(this.currentDx / scale);
  						var dy = this.roundLength(this.currentDy / scale);
  						var target = this.target;
  						if (graph.isSplitEnabled() && graph.isSplitTarget(target, this.cells, me.getEvent()))
  						{
  							graph.splitEdge(target, this.cells, null, dx, dy,
  								me.getGraphX(), me.getGraphY());
  						}
  						else
  						{
  							this.moveCells(this.cells, dx, dy, clone, this.target, me.getEvent());
  						}
  					}
  				}
  				else if (this.isSelectEnabled() && this.delayedSelection && this.cell != null)
  				{
  					this.selectDelayed(me);
  				}
  			}
  			if (this.cellWasClicked)
  			{
  				this.consumeMouseEvent(mxEvent.MOUSE_UP, me);
  			}
  			this.reset();
  		};
  		mxGraphHandler.prototype.reset = function()
  		{
  			if (this.livePreviewUsed)
  			{
  				this.resetLivePreview();
  				this.setHandlesVisibleForCells(
  					this.graph.selectionCellsHandler.
  					getHandledSelectionCells(), true);
  			}
  			this.destroyShapes();
  			this.removeHint();
  			this.delayedSelection = false;
  			this.livePreviewActive = null;
  			this.livePreviewUsed = null;
  			this.cellWasClicked = false;
  			this.suspended = null;
  			this.currentDx = null;
  			this.currentDy = null;
  			this.cellCount = null;
  			this.cloning = false;
  			this.allCells = null;
  			this.pBounds = null;
  			this.guides = null;
  			this.target = null;
  			this.first = null;
  			this.cells = null;
  			this.cell = null;
  		};
  		mxGraphHandler.prototype.shouldRemoveCellsFromParent = function(parent, cells, evt)
  		{
  			if (this.graph.getModel().isVertex(parent))
  			{
  				var pState = this.graph.getView().getState(parent);
  				if (pState != null)
  				{
  					var pt = mxUtils.convertPoint(this.graph.container,
  						mxEvent.getClientX(evt), mxEvent.getClientY(evt));
  					var alpha = mxUtils.toRadians(mxUtils.getValue(pState.style, mxConstants.STYLE_ROTATION) || 0);
  					if (alpha != 0)
  					{
  						var cos = Math.cos(-alpha);
  						var sin = Math.sin(-alpha);
  						var cx = new mxPoint(pState.getCenterX(), pState.getCenterY());
  						pt = mxUtils.getRotatedPoint(pt, cos, sin, cx);
  					}
  					return !mxUtils.contains(pState, pt.x, pt.y);
  				}
  			}
  			return false;
  		};
  		mxGraphHandler.prototype.moveCells = function(cells, dx, dy, clone, target, evt)
  		{
  			if (clone)
  			{
  				cells = this.graph.getCloneableCells(cells);
  			}
  			var parent = this.graph.getModel().getParent(this.cell);
  			if (target == null && this.isRemoveCellsFromParent() &&
  				this.shouldRemoveCellsFromParent(parent, cells, evt))
  			{
  				target = this.graph.getDefaultParent();
  			}
  			clone = clone && !this.graph.isCellLocked(target || this.graph.getDefaultParent());
  			this.graph.getModel().beginUpdate();
  			try
  			{
  				var parents = [];
  				if (!clone && target != null && this.removeEmptyParents)
  				{
  					var dict = new mxDictionary();
  					for (var i = 0; i < cells.length; i++)
  					{
  						dict.put(cells[i], true);
  					}
  					for (var i = 0; i < cells.length; i++)
  					{
  						var par = this.graph.model.getParent(cells[i]);
  						if (par != null && !dict.get(par))
  						{
  							dict.put(par, true);
  							parents.push(par);
  						}
  					}
  				}
  				cells = this.graph.moveCells(cells, dx, dy, clone, target, evt);
  				var temp = [];
  				for (var i = 0; i < parents.length; i++)
  				{
  					if (this.shouldRemoveParent(parents[i]))
  					{
  						temp.push(parents[i]);
  					}
  				}
  				this.graph.removeCells(temp, false);
  			}
  			finally
  			{
  				this.graph.getModel().endUpdate();
  			}
  			if (clone)
  			{
  				this.graph.setSelectionCells(cells);
  			}
  			if (this.isSelectEnabled() && this.scrollOnMove)
  			{
  				this.graph.scrollCellToVisible(cells[0]);
  			}
  		};
  		mxGraphHandler.prototype.shouldRemoveParent = function(parent)
  		{
  			var state = this.graph.view.getState(parent);
  			return state != null && (this.graph.model.isEdge(state.cell) || this.graph.model.isVertex(state.cell)) &&
  				this.graph.isCellDeletable(state.cell) && this.graph.model.getChildCount(state.cell) == 0 &&
  				this.graph.isTransparentState(state);
  		};
  		mxGraphHandler.prototype.destroyShapes = function()
  		{
  			if (this.shape != null)
  			{
  				this.shape.destroy();
  				this.shape = null;
  			}
  			if (this.guide != null)
  			{
  				this.guide.destroy();
  				this.guide = null;
  			}
  			if (this.highlight != null)
  			{
  				this.highlight.destroy();
  				this.highlight = null;
  			}
  		};
  		mxGraphHandler.prototype.destroy = function()
  		{
  			this.graph.removeMouseListener(this);
  			this.graph.removeListener(this.panHandler);
  			if (this.escapeHandler != null)
  			{
  				this.graph.removeListener(this.escapeHandler);
  				this.escapeHandler = null;
  			}
  			if (this.refreshHandler != null)
  			{
  				this.graph.getModel().removeListener(this.refreshHandler);
  				this.graph.removeListener(this.refreshHandler);
  				this.refreshHandler = null;
  			}
  			mxEvent.removeListener(document, 'keydown', this.keyHandler);
  			mxEvent.removeListener(document, 'keyup', this.keyHandler);
  			this.destroyShapes();
  			this.removeHint();
  		};
  		__mxOutput.mxGraphHandler = typeof mxGraphHandler !== 'undefined' ? mxGraphHandler : undefined;
  		function mxPanningHandler(graph)
  		{
  			if (graph != null)
  			{
  				this.graph = graph;
  				this.graph.addMouseListener(this);
  				this.forcePanningHandler = mxUtils.bind(this, function(sender, evt)
  				{
  					var evtName = evt.getProperty('eventName');
  					var me = evt.getProperty('event');
  					if (evtName == mxEvent.MOUSE_DOWN && this.isForcePanningEvent(me))
  					{
  						this.start(me);
  						this.active = true;
  						this.fireEvent(new mxEventObject(mxEvent.PAN_START, 'event', me));
  						me.consume();
  					}
  				});
  				this.graph.addListener(mxEvent.FIRE_MOUSE_EVENT, this.forcePanningHandler);
  				this.gestureHandler = mxUtils.bind(this, function(sender, eo)
  				{
  					if (this.isPinchEnabled())
  					{
  						var evt = eo.getProperty('event');
  						if (!mxEvent.isConsumed(evt) && evt.type == 'gesturestart')
  						{
  							this.initialScale = this.graph.view.scale;
  							if (!this.active && this.mouseDownEvent != null)
  							{
  								this.start(this.mouseDownEvent);
  								this.mouseDownEvent = null;
  							}
  						}
  						else if (evt.type == 'gestureend' && this.initialScale != null)
  						{
  							this.initialScale = null;
  						}
  						if (this.initialScale != null)
  						{
  							this.zoomGraph(evt);
  						}
  					}
  				});
  				this.graph.addListener(mxEvent.GESTURE, this.gestureHandler);
  				this.mouseUpListener = mxUtils.bind(this, function()
  				{
  			    	if (this.active)
  			    	{
  			    		this.reset();
  			    	}
  				});
  				mxEvent.addListener(document, 'mouseup', this.mouseUpListener);
  			}
  		}		mxPanningHandler.prototype = new mxEventSource();
  		mxPanningHandler.prototype.constructor = mxPanningHandler;
  		mxPanningHandler.prototype.graph = null;
  		mxPanningHandler.prototype.useLeftButtonForPanning = false;
  		mxPanningHandler.prototype.usePopupTrigger = true;
  		mxPanningHandler.prototype.ignoreCell = false;
  		mxPanningHandler.prototype.previewEnabled = true;
  		mxPanningHandler.prototype.useGrid = false;
  		mxPanningHandler.prototype.panningEnabled = true;
  		mxPanningHandler.prototype.pinchEnabled = true;
  		mxPanningHandler.prototype.maxScale = 8;
  		mxPanningHandler.prototype.minScale = 0.01;
  		mxPanningHandler.prototype.dx = null;
  		mxPanningHandler.prototype.dy = null;
  		mxPanningHandler.prototype.startX = 0;
  		mxPanningHandler.prototype.startY = 0;
  		mxPanningHandler.prototype.isActive = function()
  		{
  			return this.active || this.initialScale != null;
  		};
  		mxPanningHandler.prototype.isPanningEnabled = function()
  		{
  			return this.panningEnabled;
  		};
  		mxPanningHandler.prototype.setPanningEnabled = function(value)
  		{
  			this.panningEnabled = value;
  		};
  		mxPanningHandler.prototype.isPinchEnabled = function()
  		{
  			return this.pinchEnabled;
  		};
  		mxPanningHandler.prototype.setPinchEnabled = function(value)
  		{
  			this.pinchEnabled = value;
  		};
  		mxPanningHandler.prototype.isPanningTrigger = function(me)
  		{
  			var evt = me.getEvent();
  			return (this.useLeftButtonForPanning && me.getState() == null &&
  					mxEvent.isLeftMouseButton(evt)) || (mxEvent.isControlDown(evt) &&
  					mxEvent.isShiftDown(evt)) || (this.usePopupTrigger && mxEvent.isPopupTrigger(evt));
  		};
  		mxPanningHandler.prototype.isForcePanningEvent = function(me)
  		{
  			return this.ignoreCell || mxEvent.isMultiTouchEvent(me.getEvent());
  		};
  		mxPanningHandler.prototype.mouseDown = function(sender, me)
  		{
  			this.mouseDownEvent = me;
  			if (!me.isConsumed() && this.isPanningEnabled() && !this.active && this.isPanningTrigger(me))
  			{
  				this.start(me);
  				this.consumePanningTrigger(me);
  			}
  		};
  		mxPanningHandler.prototype.start = function(me)
  		{
  			this.dx0 = -this.graph.container.scrollLeft;
  			this.dy0 = -this.graph.container.scrollTop;
  			this.startX = me.getX();
  			this.startY = me.getY();
  			this.dx = null;
  			this.dy = null;
  			this.panningTrigger = true;
  		};
  		mxPanningHandler.prototype.consumePanningTrigger = function(me)
  		{
  			me.consume();
  		};
  		mxPanningHandler.prototype.mouseMove = function(sender, me)
  		{
  			this.dx = me.getX() - this.startX;
  			this.dy = me.getY() - this.startY;
  			if (this.active)
  			{
  				if (this.previewEnabled)
  				{
  					if (this.useGrid)
  					{
  						this.dx = this.graph.snap(this.dx);
  						this.dy = this.graph.snap(this.dy);
  					}
  					this.graph.panGraph(this.dx + this.dx0, this.dy + this.dy0);
  				}
  				this.fireEvent(new mxEventObject(mxEvent.PAN, 'event', me));
  			}
  			else if (this.panningTrigger)
  			{
  				var tmp = this.active;
  				this.active = Math.abs(this.dx) > this.graph.tolerance || Math.abs(this.dy) > this.graph.tolerance;
  				if (!tmp && this.active)
  				{
  					this.fireEvent(new mxEventObject(mxEvent.PAN_START, 'event', me));
  				}
  			}
  			if (this.active || this.panningTrigger)
  			{
  				me.consume();
  			}
  		};
  		mxPanningHandler.prototype.mouseUp = function(sender, me)
  		{
  			if (this.active)
  			{
  				if (this.dx != null && this.dy != null)
  				{
  					if (!this.graph.useScrollbarsForPanning || !mxUtils.hasScrollbars(this.graph.container))
  					{
  						var scale = this.graph.getView().scale;
  						var t = this.graph.getView().translate;
  						this.graph.panGraph(0, 0);
  						this.panGraph(t.x + this.dx / scale, t.y + this.dy / scale);
  					}
  					me.consume();
  				}
  				this.fireEvent(new mxEventObject(mxEvent.PAN_END, 'event', me));
  			}
  			this.reset();
  		};
  		mxPanningHandler.prototype.zoomGraph = function(evt)
  		{
  			var value = Math.round(this.initialScale * evt.scale * 100) / 100;
  			if (this.minScale != null)
  			{
  				value = Math.max(this.minScale, value);
  			}
  			if (this.maxScale != null)
  			{
  				value = Math.min(this.maxScale, value);
  			}
  			if (this.graph.view.scale != value)
  			{
  				this.graph.zoomTo(value);
  				mxEvent.consume(evt);
  			}
  		};
  		mxPanningHandler.prototype.reset = function()
  		{
  			this.panningTrigger = false;
  			this.mouseDownEvent = null;
  			this.active = false;
  			this.dx = null;
  			this.dy = null;
  		};
  		mxPanningHandler.prototype.panGraph = function(dx, dy)
  		{
  			this.graph.getView().setTranslate(dx, dy);
  		};
  		mxPanningHandler.prototype.destroy = function()
  		{
  			this.graph.removeMouseListener(this);
  			this.graph.removeListener(this.forcePanningHandler);
  			this.graph.removeListener(this.gestureHandler);
  			mxEvent.removeListener(document, 'mouseup', this.mouseUpListener);
  		};
  		__mxOutput.mxPanningHandler = typeof mxPanningHandler !== 'undefined' ? mxPanningHandler : undefined;
  		function mxPopupMenuHandler(graph, factoryMethod)
  		{
  			if (graph != null)
  			{
  				this.graph = graph;
  				this.factoryMethod = factoryMethod;
  				this.graph.addMouseListener(this);
  				this.gestureHandler = mxUtils.bind(this, function(sender, eo)
  				{
  					this.inTolerance = false;
  				});
  				this.graph.addListener(mxEvent.GESTURE, this.gestureHandler);
  				this.init();
  			}
  		}		mxPopupMenuHandler.prototype = new mxPopupMenu();
  		mxPopupMenuHandler.prototype.constructor = mxPopupMenuHandler;
  		mxPopupMenuHandler.prototype.graph = null;
  		mxPopupMenuHandler.prototype.selectOnPopup = true;
  		mxPopupMenuHandler.prototype.clearSelectionOnBackground = true;
  		mxPopupMenuHandler.prototype.triggerX = null;
  		mxPopupMenuHandler.prototype.triggerY = null;
  		mxPopupMenuHandler.prototype.screenX = null;
  		mxPopupMenuHandler.prototype.screenY = null;
  		mxPopupMenuHandler.prototype.init = function()
  		{
  			mxPopupMenu.prototype.init.apply(this);
  			mxEvent.addGestureListeners(this.div, mxUtils.bind(this, function(evt)
  			{
  				this.graph.tooltipHandler.hide();
  			}));
  		};
  		mxPopupMenuHandler.prototype.isSelectOnPopup = function(me)
  		{
  			return this.selectOnPopup;
  		};
  		mxPopupMenuHandler.prototype.mouseDown = function(sender, me)
  		{
  			if (this.isEnabled() && !mxEvent.isMultiTouchEvent(me.getEvent()))
  			{
  				this.hideMenu();
  				this.triggerX = me.getGraphX();
  				this.triggerY = me.getGraphY();
  				this.screenX = mxEvent.getMainEvent(me.getEvent()).screenX;
  				this.screenY = mxEvent.getMainEvent(me.getEvent()).screenY;
  				this.popupTrigger = this.isPopupTrigger(me);
  				this.inTolerance = true;
  			}
  		};
  		mxPopupMenuHandler.prototype.mouseMove = function(sender, me)
  		{
  			if (this.inTolerance && this.screenX != null && this.screenY != null)
  			{
  				if (Math.abs(mxEvent.getMainEvent(me.getEvent()).screenX - this.screenX) > this.graph.tolerance ||
  					Math.abs(mxEvent.getMainEvent(me.getEvent()).screenY - this.screenY) > this.graph.tolerance)
  				{
  					this.inTolerance = false;
  				}
  			}
  		};
  		mxPopupMenuHandler.prototype.mouseUp = function(sender, me)
  		{
  			if (this.popupTrigger && this.inTolerance && this.triggerX != null && this.triggerY != null)
  			{
  				var cell = this.getCellForPopupEvent(me);
  				if (this.graph.isEnabled() && this.isSelectOnPopup(me) &&
  					cell != null && !this.graph.isCellSelected(cell))
  				{
  					this.graph.setSelectionCell(cell);
  				}
  				else if (this.clearSelectionOnBackground && cell == null)
  				{
  					this.graph.clearSelection();
  				}
  				this.graph.tooltipHandler.hide();
  				var origin = mxUtils.getScrollOrigin();
  				this.popup(me.getX() + origin.x + 1, me.getY() + origin.y + 1, cell, me.getEvent());
  				me.consume();
  			}
  			this.popupTrigger = false;
  			this.inTolerance = false;
  		};
  		mxPopupMenuHandler.prototype.getCellForPopupEvent = function(me)
  		{
  			return me.getCell();
  		};
  		mxPopupMenuHandler.prototype.destroy = function()
  		{
  			this.graph.removeMouseListener(this);
  			this.graph.removeListener(this.gestureHandler);
  			mxPopupMenu.prototype.destroy.apply(this);
  		};
  		__mxOutput.mxPopupMenuHandler = typeof mxPopupMenuHandler !== 'undefined' ? mxPopupMenuHandler : undefined;
  		function mxCellMarker(graph, validColor, invalidColor, hotspot)
  		{
  			mxEventSource.call(this);
  			if (graph != null)
  			{
  				this.graph = graph;
  				this.validColor = (validColor != null) ? validColor : mxConstants.DEFAULT_VALID_COLOR;
  				this.invalidColor = (invalidColor != null) ? invalidColor : mxConstants.DEFAULT_INVALID_COLOR;
  				this.hotspot = (hotspot != null) ? hotspot : mxConstants.DEFAULT_HOTSPOT;
  				this.highlight = new mxCellHighlight(graph);
  			}
  		}		mxUtils.extend(mxCellMarker, mxEventSource);
  		mxCellMarker.prototype.graph = null;
  		mxCellMarker.prototype.enabled = true;
  		mxCellMarker.prototype.hotspot = mxConstants.DEFAULT_HOTSPOT;
  		mxCellMarker.prototype.hotspotEnabled = false;
  		mxCellMarker.prototype.validColor = null;
  		mxCellMarker.prototype.invalidColor = null;
  		mxCellMarker.prototype.currentColor = null;
  		mxCellMarker.prototype.validState = null;
  		mxCellMarker.prototype.markedState = null;
  		mxCellMarker.prototype.setEnabled = function(enabled)
  		{
  			this.enabled = enabled;
  		};
  		mxCellMarker.prototype.isEnabled = function()
  		{
  			return this.enabled;
  		};
  		mxCellMarker.prototype.setHotspot = function(hotspot)
  		{
  			this.hotspot = hotspot;
  		};
  		mxCellMarker.prototype.getHotspot = function()
  		{
  			return this.hotspot;
  		};
  		mxCellMarker.prototype.setHotspotEnabled = function(enabled)
  		{
  			this.hotspotEnabled = enabled;
  		};
  		mxCellMarker.prototype.isHotspotEnabled = function()
  		{
  			return this.hotspotEnabled;
  		};
  		mxCellMarker.prototype.hasValidState = function()
  		{
  			return this.validState != null;
  		};
  		mxCellMarker.prototype.getValidState = function()
  		{
  			return this.validState;
  		};
  		mxCellMarker.prototype.getMarkedState = function()
  		{
  			return this.markedState;
  		};
  		mxCellMarker.prototype.reset = function()
  		{
  			this.validState = null;
  			if (this.markedState != null)
  			{
  				this.markedState = null;
  				this.unmark();
  			}
  		};
  		mxCellMarker.prototype.process = function(me)
  		{
  			var state = null;
  			if (this.isEnabled())
  			{
  				state = this.getState(me);
  				this.setCurrentState(state, me);
  			}
  			return state;
  		};
  		mxCellMarker.prototype.setCurrentState = function(state, me, color)
  		{
  			var isValid = (state != null) ? this.isValidState(state) : false;
  			color = (color != null) ? color : this.getMarkerColor(me.getEvent(), state, isValid);
  			if (isValid)
  			{
  				this.validState = state;
  			}
  			else
  			{
  				this.validState = null;
  			}
  			if (state != this.markedState || color != this.currentColor)
  			{
  				this.currentColor = color;
  				if (state != null && this.currentColor != null)
  				{
  					this.markedState = state;
  					this.mark();
  				}
  				else if (this.markedState != null)
  				{
  					this.markedState = null;
  					this.unmark();
  				}
  			}
  		};
  		mxCellMarker.prototype.markCell = function(cell, color)
  		{
  			var state = this.graph.getView().getState(cell);
  			if (state != null)
  			{
  				this.currentColor = (color != null) ? color : this.validColor;
  				this.markedState = state;
  				this.mark();
  			}
  		};
  		mxCellMarker.prototype.mark = function()
  		{
  			this.highlight.setHighlightColor(this.currentColor);
  			this.highlight.highlight(this.markedState);
  			this.fireEvent(new mxEventObject(mxEvent.MARK, 'state', this.markedState));
  		};
  		mxCellMarker.prototype.unmark = function()
  		{
  			this.mark();
  		};
  		mxCellMarker.prototype.isValidState = function(state)
  		{
  			return true;
  		};
  		mxCellMarker.prototype.getMarkerColor = function(evt, state, isValid)
  		{
  			return (isValid) ? this.validColor : this.invalidColor;
  		};
  		mxCellMarker.prototype.getState = function(me)
  		{
  			var view = this.graph.getView();
  			var cell = this.getCell(me);
  			var state = this.getStateToMark(view.getState(cell));
  			return (state != null && this.intersects(state, me)) ? state : null;
  		};
  		mxCellMarker.prototype.getCell = function(me)
  		{
  			return me.getCell();
  		};
  		mxCellMarker.prototype.getStateToMark = function(state)
  		{
  			return state;
  		};
  		mxCellMarker.prototype.intersects = function(state, me)
  		{
  			if (this.hotspotEnabled)
  			{
  				return mxUtils.intersectsHotspot(state, me.getGraphX(), me.getGraphY(),
  					this.hotspot, mxConstants.MIN_HOTSPOT_SIZE,
  					mxConstants.MAX_HOTSPOT_SIZE);
  			}
  			return true;
  		};
  		mxCellMarker.prototype.destroy = function()
  		{
  			this.graph.getView().removeListener(this.resetHandler);
  			this.graph.getModel().removeListener(this.resetHandler);
  			this.highlight.destroy();
  		};
  		__mxOutput.mxCellMarker = typeof mxCellMarker !== 'undefined' ? mxCellMarker : undefined;
  		function mxSelectionCellsHandler(graph)
  		{
  			mxEventSource.call(this);
  			this.graph = graph;
  			this.handlers = new mxDictionary();
  			this.graph.addMouseListener(this);
  			this.refreshHandler = mxUtils.bind(this, function(sender, evt)
  			{
  				if (this.isEnabled())
  				{
  					this.refresh();
  				}
  			});
  			this.graph.getSelectionModel().addListener(mxEvent.CHANGE, this.refreshHandler);
  			this.graph.getModel().addListener(mxEvent.CHANGE, this.refreshHandler);
  			this.graph.getView().addListener(mxEvent.SCALE, this.refreshHandler);
  			this.graph.getView().addListener(mxEvent.TRANSLATE, this.refreshHandler);
  			this.graph.getView().addListener(mxEvent.SCALE_AND_TRANSLATE, this.refreshHandler);
  			this.graph.getView().addListener(mxEvent.DOWN, this.refreshHandler);
  			this.graph.getView().addListener(mxEvent.UP, this.refreshHandler);
  		}		mxUtils.extend(mxSelectionCellsHandler, mxEventSource);
  		mxSelectionCellsHandler.prototype.graph = null;
  		mxSelectionCellsHandler.prototype.enabled = true;
  		mxSelectionCellsHandler.prototype.refreshHandler = null;
  		mxSelectionCellsHandler.prototype.maxHandlers = 100;
  		mxSelectionCellsHandler.prototype.handlers = null;
  		mxSelectionCellsHandler.prototype.isEnabled = function()
  		{
  			return this.enabled;
  		};
  		mxSelectionCellsHandler.prototype.setEnabled = function(value)
  		{
  			this.enabled = value;
  		};
  		mxSelectionCellsHandler.prototype.getHandler = function(cell)
  		{
  			return this.handlers.get(cell);
  		};
  		mxSelectionCellsHandler.prototype.isHandled = function(cell)
  		{
  			return this.getHandler(cell) != null;
  		};
  		mxSelectionCellsHandler.prototype.reset = function()
  		{
  			this.handlers.visit(function(key, handler)
  			{
  				handler.reset.apply(handler);
  			});
  		};
  		mxSelectionCellsHandler.prototype.getHandledSelectionCells = function()
  		{
  			return this.graph.getSelectionCells();
  		};
  		mxSelectionCellsHandler.prototype.refresh = function()
  		{
  			var oldHandlers = this.handlers;
  			this.handlers = new mxDictionary();
  			var tmp = mxUtils.sortCells(this.getHandledSelectionCells(), false);
  			for (var i = 0; i < tmp.length; i++)
  			{
  				var state = this.graph.view.getState(tmp[i]);
  				if (state != null)
  				{
  					var handler = oldHandlers.remove(tmp[i]);
  					if (handler != null)
  					{
  						if (handler.state != state)
  						{
  							handler.destroy();
  							handler = null;
  						}
  						else if (!this.isHandlerActive(handler))
  						{
  							if (handler.refresh != null)
  							{
  								handler.refresh();
  							}
  							handler.redraw();
  						}
  					}
  					if (handler != null)
  					{
  						this.handlers.put(tmp[i], handler);
  					}
  				}
  			}
  			oldHandlers.visit(mxUtils.bind(this, function(key, handler)
  			{
  				this.fireEvent(new mxEventObject(mxEvent.REMOVE, 'state', handler.state));
  				handler.destroy();
  			}));
  			for (var i = 0; i < tmp.length; i++)
  			{
  				var state = this.graph.view.getState(tmp[i]);
  				if (state != null)
  				{
  					var handler = this.handlers.get(tmp[i]);
  					if (handler == null)
  					{
  						handler = this.graph.createHandler(state);
  						this.fireEvent(new mxEventObject(mxEvent.ADD, 'state', state));
  						this.handlers.put(tmp[i], handler);
  					}
  					else
  					{
  						handler.updateParentHighlight();
  					}
  				}
  			}
  		};
  		mxSelectionCellsHandler.prototype.isHandlerActive = function(handler)
  		{
  			return handler.index != null;
  		};
  		mxSelectionCellsHandler.prototype.updateHandler = function(state)
  		{
  			var handler = this.handlers.remove(state.cell);
  			if (handler != null)
  			{
  				var index = handler.index;
  				var x = handler.startX;
  				var y = handler.startY;
  				handler.destroy();
  				handler = this.graph.createHandler(state);
  				if (handler != null)
  				{
  					this.handlers.put(state.cell, handler);
  					if (index != null && x != null && y != null)
  					{
  						handler.start(x, y, index);
  					}
  				}
  			}
  		};
  		mxSelectionCellsHandler.prototype.mouseDown = function(sender, me)
  		{
  			if (this.graph.isEnabled() && this.isEnabled())
  			{
  				var args = [sender, me];
  				this.handlers.visit(function(key, handler)
  				{
  					handler.mouseDown.apply(handler, args);
  				});
  			}
  		};
  		mxSelectionCellsHandler.prototype.mouseMove = function(sender, me)
  		{
  			if (this.graph.isEnabled() && this.isEnabled())
  			{
  				var args = [sender, me];
  				this.handlers.visit(function(key, handler)
  				{
  					handler.mouseMove.apply(handler, args);
  				});
  			}
  		};
  		mxSelectionCellsHandler.prototype.mouseUp = function(sender, me)
  		{
  			if (this.graph.isEnabled() && this.isEnabled())
  			{
  				var args = [sender, me];
  				this.handlers.visit(function(key, handler)
  				{
  					handler.mouseUp.apply(handler, args);
  				});
  			}
  		};
  		mxSelectionCellsHandler.prototype.destroy = function()
  		{
  			this.graph.removeMouseListener(this);
  			if (this.refreshHandler != null)
  			{
  				this.graph.getSelectionModel().removeListener(this.refreshHandler);
  				this.graph.getModel().removeListener(this.refreshHandler);
  				this.graph.getView().removeListener(this.refreshHandler);
  				this.refreshHandler = null;
  			}
  		};
  		__mxOutput.mxSelectionCellsHandler = typeof mxSelectionCellsHandler !== 'undefined' ? mxSelectionCellsHandler : undefined;
  		function mxConnectionHandler(graph, factoryMethod)
  		{
  			mxEventSource.call(this);
  			if (graph != null)
  			{
  				this.graph = graph;
  				this.factoryMethod = factoryMethod;
  				this.init();
  				this.escapeHandler = mxUtils.bind(this, function(sender, evt)
  				{
  					this.reset();
  				});
  				this.graph.addListener(mxEvent.ESCAPE, this.escapeHandler);
  			}
  		}		mxUtils.extend(mxConnectionHandler, mxEventSource);
  		mxConnectionHandler.prototype.graph = null;
  		mxConnectionHandler.prototype.factoryMethod = true;
  		mxConnectionHandler.prototype.moveIconFront = false;
  		mxConnectionHandler.prototype.moveIconBack = false;
  		mxConnectionHandler.prototype.connectImage = null;
  		mxConnectionHandler.prototype.targetConnectImage = false;
  		mxConnectionHandler.prototype.enabled = true;
  		mxConnectionHandler.prototype.select = true;
  		mxConnectionHandler.prototype.createTarget = false;
  		mxConnectionHandler.prototype.marker = null;
  		mxConnectionHandler.prototype.constraintHandler = null;
  		mxConnectionHandler.prototype.error = null;
  		mxConnectionHandler.prototype.waypointsEnabled = false;
  		mxConnectionHandler.prototype.ignoreMouseDown = false;
  		mxConnectionHandler.prototype.first = null;
  		mxConnectionHandler.prototype.connectIconOffset = new mxPoint(0, mxConstants.TOOLTIP_VERTICAL_OFFSET);
  		mxConnectionHandler.prototype.edgeState = null;
  		mxConnectionHandler.prototype.changeHandler = null;
  		mxConnectionHandler.prototype.drillHandler = null;
  		mxConnectionHandler.prototype.mouseDownCounter = 0;
  		mxConnectionHandler.prototype.movePreviewAway = mxClient.IS_VML;
  		mxConnectionHandler.prototype.outlineConnect = false;
  		mxConnectionHandler.prototype.livePreview = false;
  		mxConnectionHandler.prototype.cursor = null;
  		mxConnectionHandler.prototype.insertBeforeSource = false;
  		mxConnectionHandler.prototype.isEnabled = function()
  		{
  			return this.enabled;
  		};
  		mxConnectionHandler.prototype.setEnabled = function(enabled)
  		{
  			this.enabled = enabled;
  		};
  		mxConnectionHandler.prototype.isInsertBefore = function(edge, source, target, evt, dropTarget)
  		{
  			return this.insertBeforeSource && source != target;
  		};
  		mxConnectionHandler.prototype.isCreateTarget = function(evt)
  		{
  			return this.createTarget;
  		};
  		mxConnectionHandler.prototype.setCreateTarget = function(value)
  		{
  			this.createTarget = value;
  		};
  		mxConnectionHandler.prototype.createShape = function()
  		{
  			var shape = (this.livePreview && this.edgeState != null) ?
  				this.graph.cellRenderer.createShape(this.edgeState) :
  				new mxPolyline([], mxConstants.INVALID_COLOR);
  			shape.dialect = (this.graph.dialect != mxConstants.DIALECT_SVG) ?
  				mxConstants.DIALECT_VML : mxConstants.DIALECT_SVG;
  			shape.scale = this.graph.view.scale;
  			shape.pointerEvents = false;
  			shape.isDashed = true;
  			shape.init(this.graph.getView().getOverlayPane());
  			mxEvent.redirectMouseEvents(shape.node, this.graph, null);
  			return shape;
  		};
  		mxConnectionHandler.prototype.init = function()
  		{
  			this.graph.addMouseListener(this);
  			this.marker = this.createMarker();
  			this.constraintHandler = new mxConstraintHandler(this.graph);
  			this.changeHandler = mxUtils.bind(this, function(sender)
  			{
  				if (this.iconState != null)
  				{
  					this.iconState = this.graph.getView().getState(this.iconState.cell);
  				}
  				if (this.iconState != null)
  				{
  					this.redrawIcons(this.icons, this.iconState);
  					this.constraintHandler.reset();
  				}
  				else if (this.previous != null && this.graph.view.getState(this.previous.cell) == null)
  				{
  					this.reset();
  				}
  			});
  			this.graph.getModel().addListener(mxEvent.CHANGE, this.changeHandler);
  			this.graph.getView().addListener(mxEvent.SCALE, this.changeHandler);
  			this.graph.getView().addListener(mxEvent.TRANSLATE, this.changeHandler);
  			this.graph.getView().addListener(mxEvent.SCALE_AND_TRANSLATE, this.changeHandler);
  			this.drillHandler = mxUtils.bind(this, function(sender)
  			{
  				this.reset();
  			});
  			this.graph.addListener(mxEvent.START_EDITING, this.drillHandler);
  			this.graph.getView().addListener(mxEvent.DOWN, this.drillHandler);
  			this.graph.getView().addListener(mxEvent.UP, this.drillHandler);
  		};
  		mxConnectionHandler.prototype.isConnectableCell = function(cell)
  		{
  			return true;
  		};
  		mxConnectionHandler.prototype.createMarker = function()
  		{
  			var marker = new mxCellMarker(this.graph);
  			marker.hotspotEnabled = true;
  			marker.getCell = mxUtils.bind(this, function(me)
  			{
  				var cell = mxCellMarker.prototype.getCell.apply(marker, arguments);
  				this.error = null;
  				if (cell == null && this.currentPoint != null)
  				{
  					cell = this.graph.getCellAt(this.currentPoint.x, this.currentPoint.y);
  				}
  				if (cell != null && !this.graph.isCellConnectable(cell))
  				{
  					var parent = this.graph.getModel().getParent(cell);
  					if (this.graph.getModel().isVertex(parent) && this.graph.isCellConnectable(parent))
  					{
  						cell = parent;
  					}
  				}
  				if ((this.graph.isSwimlane(cell) && this.currentPoint != null &&
  					this.graph.hitsSwimlaneContent(cell, this.currentPoint.x, this.currentPoint.y)) ||
  					!this.isConnectableCell(cell))
  				{
  					cell = null;
  				}
  				if (cell != null)
  				{
  					if (this.isConnecting())
  					{
  						if (this.previous != null)
  						{
  							this.error = this.validateConnection(this.previous.cell, cell);
  							if (this.error != null && this.error.length == 0)
  							{
  								cell = null;
  								if (this.isCreateTarget(me.getEvent()))
  								{
  									this.error = null;
  								}
  							}
  						}
  					}
  					else if (!this.isValidSource(cell, me))
  					{
  						cell = null;
  					}
  				}
  				else if (this.isConnecting() && !this.isCreateTarget(me.getEvent()) &&
  						!this.graph.allowDanglingEdges)
  				{
  					this.error = '';
  				}
  				return cell;
  			});
  			marker.isValidState = mxUtils.bind(this, function(state)
  			{
  				if (this.isConnecting())
  				{
  					return this.error == null;
  				}
  				else
  				{
  					return mxCellMarker.prototype.isValidState.apply(marker, arguments);
  				}
  			});
  			marker.getMarkerColor = mxUtils.bind(this, function(evt, state, isValid)
  			{
  				return (this.connectImage == null || this.isConnecting()) ?
  					mxCellMarker.prototype.getMarkerColor.apply(marker, arguments) :
  					null;
  			});
  			marker.intersects = mxUtils.bind(this, function(state, evt)
  			{
  				if (this.connectImage != null || this.isConnecting())
  				{
  					return true;
  				}
  				return mxCellMarker.prototype.intersects.apply(marker, arguments);
  			});
  			return marker;
  		};
  		mxConnectionHandler.prototype.start = function(state, x, y, edgeState)
  		{
  			this.previous = state;
  			this.first = new mxPoint(x, y);
  			this.edgeState = (edgeState != null) ? edgeState : this.createEdgeState(null);
  			this.marker.currentColor = this.marker.validColor;
  			this.marker.markedState = state;
  			this.marker.mark();
  			this.fireEvent(new mxEventObject(mxEvent.START, 'state', this.previous));
  		};
  		mxConnectionHandler.prototype.isConnecting = function()
  		{
  			return this.first != null && this.shape != null;
  		};
  		mxConnectionHandler.prototype.isValidSource = function(cell, me)
  		{
  			return this.graph.isValidSource(cell);
  		};
  		mxConnectionHandler.prototype.isValidTarget = function(cell)
  		{
  			return true;
  		};
  		mxConnectionHandler.prototype.validateConnection = function(source, target)
  		{
  			if (!this.isValidTarget(target))
  			{
  				return '';
  			}
  			return this.graph.getEdgeValidationError(null, source, target);
  		};
  		mxConnectionHandler.prototype.getConnectImage = function(state)
  		{
  			return this.connectImage;
  		};
  		mxConnectionHandler.prototype.isMoveIconToFrontForState = function(state)
  		{
  			if (state.text != null && state.text.node.parentNode == this.graph.container)
  			{
  				return true;
  			}
  			return this.moveIconFront;
  		};
  		mxConnectionHandler.prototype.createIcons = function(state)
  		{
  			var image = this.getConnectImage(state);
  			if (image != null && state != null)
  			{
  				this.iconState = state;
  				var icons = [];
  				var bounds = new mxRectangle(0, 0, image.width, image.height);
  				var icon = new mxImageShape(bounds, image.src, null, null, 0);
  				icon.preserveImageAspect = false;
  				if (this.isMoveIconToFrontForState(state))
  				{
  					icon.dialect = mxConstants.DIALECT_STRICTHTML;
  					icon.init(this.graph.container);
  				}
  				else
  				{
  					icon.dialect = (this.graph.dialect == mxConstants.DIALECT_SVG) ?
  						mxConstants.DIALECT_SVG : mxConstants.DIALECT_VML;
  					icon.init(this.graph.getView().getOverlayPane());
  					if (this.moveIconBack && icon.node.previousSibling != null)
  					{
  						icon.node.parentNode.insertBefore(icon.node, icon.node.parentNode.firstChild);
  					}
  				}
  				icon.node.style.cursor = mxConstants.CURSOR_CONNECT;
  				var getState = mxUtils.bind(this, function()
  				{
  					return (this.currentState != null) ? this.currentState : state;
  				});
  				var mouseDown = mxUtils.bind(this, function(evt)
  				{
  					if (!mxEvent.isConsumed(evt))
  					{
  						this.icon = icon;
  						this.graph.fireMouseEvent(mxEvent.MOUSE_DOWN,
  							new mxMouseEvent(evt, getState()));
  					}
  				});
  				mxEvent.redirectMouseEvents(icon.node, this.graph, getState, mouseDown);
  				icons.push(icon);
  				this.redrawIcons(icons, this.iconState);
  				return icons;
  			}
  			return null;
  		};
  		mxConnectionHandler.prototype.redrawIcons = function(icons, state)
  		{
  			if (icons != null && icons[0] != null && state != null)
  			{
  				var pos = this.getIconPosition(icons[0], state);
  				icons[0].bounds.x = pos.x;
  				icons[0].bounds.y = pos.y;
  				icons[0].redraw();
  			}
  		};
  		mxConnectionHandler.prototype.getIconPosition = function(icon, state)
  		{
  			var scale = this.graph.getView().scale;
  			var cx = state.getCenterX();
  			var cy = state.getCenterY();
  			if (this.graph.isSwimlane(state.cell))
  			{
  				var size = this.graph.getStartSize(state.cell);
  				cx = (size.width != 0) ? state.x + size.width * scale / 2 : cx;
  				cy = (size.height != 0) ? state.y + size.height * scale / 2 : cy;
  				var alpha = mxUtils.toRadians(mxUtils.getValue(state.style, mxConstants.STYLE_ROTATION) || 0);
  				if (alpha != 0)
  				{
  					var cos = Math.cos(alpha);
  					var sin = Math.sin(alpha);
  					var ct = new mxPoint(state.getCenterX(), state.getCenterY());
  					var pt = mxUtils.getRotatedPoint(new mxPoint(cx, cy), cos, sin, ct);
  					cx = pt.x;
  					cy = pt.y;
  				}
  			}
  			return new mxPoint(cx - icon.bounds.width / 2,
  					cy - icon.bounds.height / 2);
  		};
  		mxConnectionHandler.prototype.destroyIcons = function()
  		{
  			if (this.icons != null)
  			{
  				for (var i = 0; i < this.icons.length; i++)
  				{
  					this.icons[i].destroy();
  				}
  				this.icons = null;
  				this.icon = null;
  				this.selectedIcon = null;
  				this.iconState = null;
  			}
  		};
  		mxConnectionHandler.prototype.isStartEvent = function(me)
  		{
  			return ((this.constraintHandler.currentFocus != null && this.constraintHandler.currentConstraint != null) ||
  				(this.previous != null && this.error == null && (this.icons == null || (this.icons != null &&
  				this.icon != null))));
  		};
  		mxConnectionHandler.prototype.mouseDown = function(sender, me)
  		{
  			this.mouseDownCounter++;
  			if (this.isEnabled() && this.graph.isEnabled() && !me.isConsumed() &&
  				!this.isConnecting() && this.isStartEvent(me))
  			{
  				if (this.constraintHandler.currentConstraint != null &&
  					this.constraintHandler.currentFocus != null &&
  					this.constraintHandler.currentPoint != null)
  				{
  					this.sourceConstraint = this.constraintHandler.currentConstraint;
  					this.previous = this.constraintHandler.currentFocus;
  					this.first = this.constraintHandler.currentPoint.clone();
  				}
  				else
  				{
  					this.first = new mxPoint(me.getGraphX(), me.getGraphY());
  				}
  				this.edgeState = this.createEdgeState(me);
  				this.mouseDownCounter = 1;
  				if (this.waypointsEnabled && this.shape == null)
  				{
  					this.waypoints = null;
  					this.shape = this.createShape();
  					if (this.edgeState != null)
  					{
  						this.shape.apply(this.edgeState);
  					}
  				}
  				if (this.previous == null && this.edgeState != null)
  				{
  					var pt = this.graph.getPointForEvent(me.getEvent());
  					this.edgeState.cell.geometry.setTerminalPoint(pt, true);
  				}
  				this.fireEvent(new mxEventObject(mxEvent.START, 'state', this.previous));
  				me.consume();
  			}
  			this.selectedIcon = this.icon;
  			this.icon = null;
  		};
  		mxConnectionHandler.prototype.isImmediateConnectSource = function(state)
  		{
  			return !this.graph.isCellMovable(state.cell);
  		};
  		mxConnectionHandler.prototype.createEdgeState = function(me)
  		{
  			return null;
  		};
  		mxConnectionHandler.prototype.isOutlineConnectEvent = function(me)
  		{
  			var offset = mxUtils.getOffset(this.graph.container);
  			var evt = me.getEvent();
  			var clientX = mxEvent.getClientX(evt);
  			var clientY = mxEvent.getClientY(evt);
  			var doc = document.documentElement;
  			var left = (window.pageXOffset || doc.scrollLeft) - (doc.clientLeft || 0);
  			var top = (window.pageYOffset || doc.scrollTop)  - (doc.clientTop || 0);
  			var gridX = this.currentPoint.x - this.graph.container.scrollLeft + offset.x - left;
  			var gridY = this.currentPoint.y - this.graph.container.scrollTop + offset.y - top;
  			return this.outlineConnect && !mxEvent.isShiftDown(me.getEvent()) &&
  				(me.isSource(this.marker.highlight.shape) ||
  				(mxEvent.isAltDown(me.getEvent()) && me.getState() != null) ||
  				this.marker.highlight.isHighlightAt(clientX, clientY) ||
  				((gridX != clientX || gridY != clientY) && me.getState() == null &&
  				this.marker.highlight.isHighlightAt(gridX, gridY)));
  		};
  		mxConnectionHandler.prototype.updateCurrentState = function(me, point)
  		{
  			this.constraintHandler.update(me, this.first == null, false, (this.first == null ||
  				me.isSource(this.marker.highlight.shape)) ? null : point);
  			if (this.constraintHandler.currentFocus != null && this.constraintHandler.currentConstraint != null)
  			{
  				if (this.marker.highlight != null && this.marker.highlight.state != null &&
  					this.marker.highlight.state.cell == this.constraintHandler.currentFocus.cell)
  				{
  					if (this.marker.highlight.shape.stroke != 'transparent')
  					{
  						this.marker.highlight.shape.stroke = 'transparent';
  						this.marker.highlight.repaint();
  					}
  				}
  				else
  				{
  					this.marker.markCell(this.constraintHandler.currentFocus.cell, 'transparent');
  				}
  				if (this.previous != null)
  				{
  					this.error = this.validateConnection(this.previous.cell, this.constraintHandler.currentFocus.cell);
  					if (this.error == null)
  					{
  						this.currentState = this.constraintHandler.currentFocus;
  					}
  					if (this.error != null || (this.currentState != null &&
  						!this.isCellEnabled(this.currentState.cell)))
  					{
  						this.constraintHandler.reset();
  					}
  				}
  			}
  			else
  			{
  				if (this.graph.isIgnoreTerminalEvent(me.getEvent()))
  				{
  					this.marker.reset();
  					this.currentState = null;
  				}
  				else
  				{
  					this.marker.process(me);
  					this.currentState = this.marker.getValidState();
  				}
  				if (this.currentState != null && !this.isCellEnabled(this.currentState.cell))
  				{
  					this.constraintHandler.reset();
  					this.marker.reset();
  					this.currentState = null;
  				}
  				var outline = this.isOutlineConnectEvent(me);
  				if (this.currentState != null && outline)
  				{
  					if (me.isSource(this.marker.highlight.shape))
  					{
  						point = new mxPoint(me.getGraphX(), me.getGraphY());
  					}
  					var constraint = this.graph.getOutlineConstraint(point, this.currentState, me);
  					this.constraintHandler.setFocus(me, this.currentState, false);
  					this.constraintHandler.currentConstraint = constraint;
  					this.constraintHandler.currentPoint = point;
  				}
  				if (this.outlineConnect)
  				{
  					if (this.marker.highlight != null && this.marker.highlight.shape != null)
  					{
  						var s = this.graph.view.scale;
  						if (this.constraintHandler.currentConstraint != null &&
  							this.constraintHandler.currentFocus != null)
  						{
  							this.marker.highlight.shape.stroke = mxConstants.OUTLINE_HIGHLIGHT_COLOR;
  							this.marker.highlight.shape.strokewidth = mxConstants.OUTLINE_HIGHLIGHT_STROKEWIDTH / s / s;
  							this.marker.highlight.repaint();
  						}
  						else if (this.marker.hasValidState())
  						{
  							if (this.graph.isCellConnectable(me.getCell()) &&
  								this.marker.getValidState() != me.getState())
  							{
  								this.marker.highlight.shape.stroke = 'transparent';
  								this.currentState = null;
  							}
  							else
  							{
  								this.marker.highlight.shape.stroke = mxConstants.DEFAULT_VALID_COLOR;
  							}
  							this.marker.highlight.shape.strokewidth = mxConstants.HIGHLIGHT_STROKEWIDTH / s / s;
  							this.marker.highlight.repaint();
  						}
  					}
  				}
  			}
  		};
  		mxConnectionHandler.prototype.isCellEnabled = function(cell)
  		{
  			return true;
  		};
  		mxConnectionHandler.prototype.convertWaypoint = function(point)
  		{
  			var scale = this.graph.getView().getScale();
  			var tr = this.graph.getView().getTranslate();
  			point.x = point.x / scale - tr.x;
  			point.y = point.y / scale - tr.y;
  		};
  		mxConnectionHandler.prototype.snapToPreview = function(me, point)
  		{
  			if (!mxEvent.isAltDown(me.getEvent()) && this.previous != null)
  			{
  				var tol = this.graph.gridSize * this.graph.view.scale / 2;
  				var tmp = (this.sourceConstraint != null) ? this.first :
  					new mxPoint(this.previous.getCenterX(), this.previous.getCenterY());
  				if (Math.abs(tmp.x - me.getGraphX()) < tol)
  				{
  					point.x = tmp.x;
  				}
  				if (Math.abs(tmp.y - me.getGraphY()) < tol)
  				{
  					point.y = tmp.y;
  				}
  			}
  		};
  		mxConnectionHandler.prototype.mouseMove = function(sender, me)
  		{
  			if (!me.isConsumed() && (this.ignoreMouseDown || this.first != null || !this.graph.isMouseDown))
  			{
  				if (!this.isEnabled() && this.currentState != null)
  				{
  					this.destroyIcons();
  					this.currentState = null;
  				}
  				var view = this.graph.getView();
  				var scale = view.scale;
  				var tr = view.translate;
  				var point = new mxPoint(me.getGraphX(), me.getGraphY());
  				this.error = null;
  				if (this.graph.isGridEnabledEvent(me.getEvent()))
  				{
  					point = new mxPoint((this.graph.snap(point.x / scale - tr.x) + tr.x) * scale,
  						(this.graph.snap(point.y / scale - tr.y) + tr.y) * scale);
  				}
  				this.snapToPreview(me, point);
  				this.currentPoint = point;
  				if ((this.first != null || (this.isEnabled() && this.graph.isEnabled())) &&
  					(this.shape != null || this.first == null ||
  					Math.abs(me.getGraphX() - this.first.x) > this.graph.tolerance ||
  					Math.abs(me.getGraphY() - this.first.y) > this.graph.tolerance))
  				{
  					this.updateCurrentState(me, point);
  				}
  				if (this.first != null)
  				{
  					var constraint = null;
  					var current = point;
  					if (this.constraintHandler.currentConstraint != null &&
  						this.constraintHandler.currentFocus != null &&
  						this.constraintHandler.currentPoint != null)
  					{
  						constraint = this.constraintHandler.currentConstraint;
  						current = this.constraintHandler.currentPoint.clone();
  					}
  					else if (this.previous != null && !this.graph.isIgnoreTerminalEvent(me.getEvent()) &&
  						mxEvent.isShiftDown(me.getEvent()))
  					{
  						if (Math.abs(this.previous.getCenterX() - point.x) <
  							Math.abs(this.previous.getCenterY() - point.y))
  						{
  							point.x = this.previous.getCenterX();
  						}
  						else
  						{
  							point.y = this.previous.getCenterY();
  						}
  					}
  					var pt2 = this.first;
  					if (this.selectedIcon != null)
  					{
  						var w = this.selectedIcon.bounds.width;
  						var h = this.selectedIcon.bounds.height;
  						if (this.currentState != null && this.targetConnectImage)
  						{
  							var pos = this.getIconPosition(this.selectedIcon, this.currentState);
  							this.selectedIcon.bounds.x = pos.x;
  							this.selectedIcon.bounds.y = pos.y;
  						}
  						else
  						{
  							var bounds = new mxRectangle(me.getGraphX() + this.connectIconOffset.x,
  								me.getGraphY() + this.connectIconOffset.y, w, h);
  							this.selectedIcon.bounds = bounds;
  						}
  						this.selectedIcon.redraw();
  					}
  					if (this.edgeState != null)
  					{
  						this.updateEdgeState(current, constraint);
  						current = this.edgeState.absolutePoints[this.edgeState.absolutePoints.length - 1];
  						pt2 = this.edgeState.absolutePoints[0];
  					}
  					else
  					{
  						if (this.currentState != null)
  						{
  							if (this.constraintHandler.currentConstraint == null)
  							{
  								var tmp = this.getTargetPerimeterPoint(this.currentState, me);
  								if (tmp != null)
  								{
  									current = tmp;
  								}
  							}
  						}
  						if (this.sourceConstraint == null && this.previous != null)
  						{
  							var next = (this.waypoints != null && this.waypoints.length > 0) ?
  									this.waypoints[0] : current;
  							var tmp = this.getSourcePerimeterPoint(this.previous, next, me);
  							if (tmp != null)
  							{
  								pt2 = tmp;
  							}
  						}
  					}
  					if (this.currentState == null && this.movePreviewAway)
  					{
  						var tmp = pt2;
  						if (this.edgeState != null && this.edgeState.absolutePoints.length >= 2)
  						{
  							var tmp2 = this.edgeState.absolutePoints[this.edgeState.absolutePoints.length - 2];
  							if (tmp2 != null)
  							{
  								tmp = tmp2;
  							}
  						}
  						var dx = current.x - tmp.x;
  						var dy = current.y - tmp.y;
  						var len = Math.sqrt(dx * dx + dy * dy);
  						if (len == 0)
  						{
  							return;
  						}
  						this.originalPoint = current.clone();
  						current.x -= dx * 4 / len;
  						current.y -= dy * 4 / len;
  					}
  					else
  					{
  						this.originalPoint = null;
  					}
  					if (this.shape == null)
  					{
  						var dx = Math.abs(me.getGraphX() - this.first.x);
  						var dy = Math.abs(me.getGraphY() - this.first.y);
  						if (dx > this.graph.tolerance || dy > this.graph.tolerance)
  						{
  							this.shape = this.createShape();
  							if (this.edgeState != null)
  							{
  								this.shape.apply(this.edgeState);
  							}
  							this.updateCurrentState(me, point);
  						}
  					}
  					if (this.shape != null)
  					{
  						if (this.edgeState != null)
  						{
  							this.shape.points = this.edgeState.absolutePoints;
  						}
  						else
  						{
  							var pts = [pt2];
  							if (this.waypoints != null)
  							{
  								pts = pts.concat(this.waypoints);
  							}
  							pts.push(current);
  							this.shape.points = pts;
  						}
  						this.drawPreview();
  					}
  					if (this.cursor != null)
  					{
  						this.graph.container.style.cursor = this.cursor;
  					}
  					mxEvent.consume(me.getEvent());
  					me.consume();
  				}
  				else if (!this.isEnabled() || !this.graph.isEnabled())
  				{
  					this.constraintHandler.reset();
  				}
  				else if (this.previous != this.currentState && this.edgeState == null)
  				{
  					this.destroyIcons();
  					if (this.currentState != null && this.error == null && this.constraintHandler.currentConstraint == null)
  					{
  						this.icons = this.createIcons(this.currentState);
  						if (this.icons == null)
  						{
  							this.currentState.setCursor(mxConstants.CURSOR_CONNECT);
  							me.consume();
  						}
  					}
  					this.previous = this.currentState;
  				}
  				else if (this.previous == this.currentState && this.currentState != null && this.icons == null &&
  					!this.graph.isMouseDown)
  				{
  					me.consume();
  				}
  				if (!this.graph.isMouseDown && this.currentState != null && this.icons != null)
  				{
  					var hitsIcon = false;
  					var target = me.getSource();
  					for (var i = 0; i < this.icons.length && !hitsIcon; i++)
  					{
  						hitsIcon = target == this.icons[i].node || target.parentNode == this.icons[i].node;
  					}
  					if (!hitsIcon)
  					{
  						this.updateIcons(this.currentState, this.icons, me);
  					}
  				}
  			}
  			else
  			{
  				this.constraintHandler.reset();
  			}
  		};
  		mxConnectionHandler.prototype.updateEdgeState = function(current, constraint)
  		{
  			if (this.sourceConstraint != null && this.sourceConstraint.point != null)
  			{
  				this.edgeState.style[mxConstants.STYLE_EXIT_X] = this.sourceConstraint.point.x;
  				this.edgeState.style[mxConstants.STYLE_EXIT_Y] = this.sourceConstraint.point.y;
  			}
  			if (constraint != null && constraint.point != null)
  			{
  				this.edgeState.style[mxConstants.STYLE_ENTRY_X] = constraint.point.x;
  				this.edgeState.style[mxConstants.STYLE_ENTRY_Y] = constraint.point.y;
  			}
  			else
  			{
  				delete this.edgeState.style[mxConstants.STYLE_ENTRY_X];
  				delete this.edgeState.style[mxConstants.STYLE_ENTRY_Y];
  			}
  			this.edgeState.absolutePoints = [null, (this.currentState != null) ? null : current];
  			this.graph.view.updateFixedTerminalPoint(this.edgeState, this.previous, true, this.sourceConstraint);
  			if (this.currentState != null)
  			{
  				if (constraint == null)
  				{
  					constraint = this.graph.getConnectionConstraint(this.edgeState, this.previous, false);
  				}
  				this.edgeState.setAbsoluteTerminalPoint(null, false);
  				this.graph.view.updateFixedTerminalPoint(this.edgeState, this.currentState, false, constraint);
  			}
  			var realPoints = null;
  			if (this.waypoints != null)
  			{
  				realPoints = [];
  				for (var i = 0; i < this.waypoints.length; i++)
  				{
  					var pt = this.waypoints[i].clone();
  					this.convertWaypoint(pt);
  					realPoints[i] = pt;
  				}
  			}
  			this.graph.view.updatePoints(this.edgeState, realPoints, this.previous, this.currentState);
  			this.graph.view.updateFloatingTerminalPoints(this.edgeState, this.previous, this.currentState);
  		};
  		mxConnectionHandler.prototype.getTargetPerimeterPoint = function(state, me)
  		{
  			var result = null;
  			var view = state.view;
  			var targetPerimeter = view.getPerimeterFunction(state);
  			if (targetPerimeter != null)
  			{
  				var next = (this.waypoints != null && this.waypoints.length > 0) ?
  						this.waypoints[this.waypoints.length - 1] :
  						new mxPoint(this.previous.getCenterX(), this.previous.getCenterY());
  				var tmp = targetPerimeter(view.getPerimeterBounds(state),
  					this.edgeState, next, false);
  				if (tmp != null)
  				{
  					result = tmp;
  				}
  			}
  			else
  			{
  				result = new mxPoint(state.getCenterX(), state.getCenterY());
  			}
  			return result;
  		};
  		mxConnectionHandler.prototype.getSourcePerimeterPoint = function(state, next, me)
  		{
  			var result = null;
  			var view = state.view;
  			var sourcePerimeter = view.getPerimeterFunction(state);
  			var c = new mxPoint(state.getCenterX(), state.getCenterY());
  			if (sourcePerimeter != null)
  			{
  				var theta = mxUtils.getValue(state.style, mxConstants.STYLE_ROTATION, 0);
  				var rad = -theta * (Math.PI / 180);
  				if (theta != 0)
  				{
  					next = mxUtils.getRotatedPoint(new mxPoint(next.x, next.y), Math.cos(rad), Math.sin(rad), c);
  				}
  				var tmp = sourcePerimeter(view.getPerimeterBounds(state), state, next, false);
  				if (tmp != null)
  				{
  					if (theta != 0)
  					{
  						tmp = mxUtils.getRotatedPoint(new mxPoint(tmp.x, tmp.y), Math.cos(-rad), Math.sin(-rad), c);
  					}
  					result = tmp;
  				}
  			}
  			else
  			{
  				result = c;
  			}
  			return result;
  		};
  		mxConnectionHandler.prototype.updateIcons = function(state, icons, me)
  		{
  		};
  		mxConnectionHandler.prototype.isStopEvent = function(me)
  		{
  			return me.getState() != null;
  		};
  		mxConnectionHandler.prototype.addWaypointForEvent = function(me)
  		{
  			var point = mxUtils.convertPoint(this.graph.container, me.getX(), me.getY());
  			var dx = Math.abs(point.x - this.first.x);
  			var dy = Math.abs(point.y - this.first.y);
  			var addPoint = this.waypoints != null || (this.mouseDownCounter > 1 &&
  					(dx > this.graph.tolerance || dy > this.graph.tolerance));
  			if (addPoint)
  			{
  				if (this.waypoints == null)
  				{
  					this.waypoints = [];
  				}
  				var scale = this.graph.view.scale;
  				var point = new mxPoint(this.graph.snap(me.getGraphX() / scale) * scale,
  						this.graph.snap(me.getGraphY() / scale) * scale);
  				this.waypoints.push(point);
  			}
  		};
  		mxConnectionHandler.prototype.checkConstraints = function(c1, c2)
  		{
  			return (c1 == null || c2 == null || c1.point == null || c2.point == null ||
  				!c1.point.equals(c2.point) || c1.dx != c2.dx || c1.dy != c2.dy ||
  				c1.perimeter != c2.perimeter);
  		};
  		mxConnectionHandler.prototype.mouseUp = function(sender, me)
  		{
  			if (!me.isConsumed() && this.isConnecting())
  			{
  				if (this.waypointsEnabled && !this.isStopEvent(me))
  				{
  					this.addWaypointForEvent(me);
  					me.consume();
  					return;
  				}
  				var c1 = this.sourceConstraint;
  				var c2 = this.constraintHandler.currentConstraint;
  				var source = (this.previous != null) ? this.previous.cell : null;
  				var target = null;
  				if (this.constraintHandler.currentConstraint != null &&
  					this.constraintHandler.currentFocus != null)
  				{
  					target = this.constraintHandler.currentFocus.cell;
  				}
  				if (target == null && this.currentState != null)
  				{
  					target = this.currentState.cell;
  				}
  				if (this.error == null && (source == null || target == null ||
  					source != target || this.checkConstraints(c1, c2)))
  				{
  					this.connect(source, target, me.getEvent(), me.getCell());
  				}
  				else
  				{
  					if (this.previous != null && this.marker.validState != null &&
  						this.previous.cell == this.marker.validState.cell)
  					{
  						this.graph.selectCellForEvent(this.marker.source, me.getEvent());
  					}
  					if (this.error != null && this.error.length > 0)
  					{
  						this.graph.validationAlert(this.error);
  					}
  				}
  				this.destroyIcons();
  				me.consume();
  			}
  			if (this.first != null)
  			{
  				this.reset();
  			}
  		};
  		mxConnectionHandler.prototype.reset = function()
  		{
  			if (this.shape != null)
  			{
  				this.shape.destroy();
  				this.shape = null;
  			}
  			if (this.cursor != null && this.graph.container != null)
  			{
  				this.graph.container.style.cursor = '';
  			}
  			this.destroyIcons();
  			this.marker.reset();
  			this.constraintHandler.reset();
  			this.originalPoint = null;
  			this.currentPoint = null;
  			this.edgeState = null;
  			this.previous = null;
  			this.error = null;
  			this.sourceConstraint = null;
  			this.mouseDownCounter = 0;
  			this.first = null;
  			this.fireEvent(new mxEventObject(mxEvent.RESET));
  		};
  		mxConnectionHandler.prototype.drawPreview = function()
  		{
  			this.updatePreview(this.error == null);
  			this.shape.redraw();
  		};
  		mxConnectionHandler.prototype.updatePreview = function(valid)
  		{
  			this.shape.strokewidth = this.getEdgeWidth(valid);
  			this.shape.stroke = this.getEdgeColor(valid);
  		};
  		mxConnectionHandler.prototype.getEdgeColor = function(valid)
  		{
  			return (valid) ? mxConstants.VALID_COLOR : mxConstants.INVALID_COLOR;
  		};
  		mxConnectionHandler.prototype.getEdgeWidth = function(valid)
  		{
  			return (valid) ? 3 : 1;
  		};
  		mxConnectionHandler.prototype.connect = function(source, target, evt, dropTarget)
  		{
  			if (target != null || this.isCreateTarget(evt) || this.graph.allowDanglingEdges)
  			{
  				var model = this.graph.getModel();
  				var terminalInserted = false;
  				var edge = null;
  				model.beginUpdate();
  				try
  				{
  					if (source != null && target == null && !this.graph.isIgnoreTerminalEvent(evt) && this.isCreateTarget(evt))
  					{
  						target = this.createTargetVertex(evt, source);
  						if (target != null)
  						{
  							dropTarget = this.graph.getDropTarget([target], evt, dropTarget);
  							terminalInserted = true;
  							if (dropTarget == null || !this.graph.getModel().isEdge(dropTarget))
  							{
  								var pstate = this.graph.getView().getState(dropTarget);
  								if (pstate != null)
  								{
  									var tmp = model.getGeometry(target);
  									tmp.x -= pstate.origin.x;
  									tmp.y -= pstate.origin.y;
  								}
  							}
  							else
  							{
  								dropTarget = this.graph.getDefaultParent();
  							}
  							this.graph.addCell(target, dropTarget);
  						}
  					}
  					var parent = this.graph.getDefaultParent();
  					if (source != null && target != null &&
  						model.getParent(source) == model.getParent(target) &&
  						model.getParent(model.getParent(source)) != model.getRoot())
  					{
  						parent = model.getParent(source);
  						if ((source.geometry != null && source.geometry.relative) &&
  							(target.geometry != null && target.geometry.relative))
  						{
  							parent = model.getParent(parent);
  						}
  					}
  					var value = null;
  					var style = null;
  					if (this.edgeState != null)
  					{
  						value = this.edgeState.cell.value;
  						style = this.edgeState.cell.style;
  					}
  					edge = this.insertEdge(parent, null, value, source, target, style);
  					if (edge != null)
  					{
  						this.graph.setConnectionConstraint(edge, source, true, this.sourceConstraint);
  						this.graph.setConnectionConstraint(edge, target, false, this.constraintHandler.currentConstraint);
  						if (this.edgeState != null)
  						{
  							model.setGeometry(edge, this.edgeState.cell.geometry);
  						}
  						var parent = model.getParent(source);
  						if (this.isInsertBefore(edge, source, target, evt, dropTarget))
  						{
  							var index = null;
  							var tmp = source;
  							while (tmp.parent != null && tmp.geometry != null &&
  								tmp.geometry.relative && tmp.parent != edge.parent)
  							{
  								tmp = this.graph.model.getParent(tmp);
  							}
  							if (tmp != null && tmp.parent != null && tmp.parent == edge.parent)
  							{
  								model.add(parent, edge, tmp.parent.getIndex(tmp));
  							}
  						}
  						var geo = model.getGeometry(edge);
  						if (geo == null)
  						{
  							geo = new mxGeometry();
  							geo.relative = true;
  							model.setGeometry(edge, geo);
  						}
  						if (this.waypoints != null && this.waypoints.length > 0)
  						{
  							var s = this.graph.view.scale;
  							var tr = this.graph.view.translate;
  							geo.points = [];
  							for (var i = 0; i < this.waypoints.length; i++)
  							{
  								var pt = this.waypoints[i];
  								geo.points.push(new mxPoint(pt.x / s - tr.x, pt.y / s - tr.y));
  							}
  						}
  						if (target == null)
  						{
  							var t = this.graph.view.translate;
  							var s = this.graph.view.scale;
  							var pt = (this.originalPoint != null) ?
  									new mxPoint(this.originalPoint.x / s - t.x, this.originalPoint.y / s - t.y) :
  								new mxPoint(this.currentPoint.x / s - t.x, this.currentPoint.y / s - t.y);
  							pt.x -= this.graph.panDx / this.graph.view.scale;
  							pt.y -= this.graph.panDy / this.graph.view.scale;
  							geo.setTerminalPoint(pt, false);
  						}
  						this.fireEvent(new mxEventObject(mxEvent.CONNECT, 'cell', edge, 'terminal', target,
  							'event', evt, 'target', dropTarget, 'terminalInserted', terminalInserted));
  					}
  				}
  				catch (e)
  				{
  					mxLog.show();
  					mxLog.debug(e.message);
  				}
  				finally
  				{
  					model.endUpdate();
  				}
  				if (this.select)
  				{
  					this.selectCells(edge, (terminalInserted) ? target : null);
  				}
  			}
  		};
  		mxConnectionHandler.prototype.selectCells = function(edge, target)
  		{
  			this.graph.setSelectionCell(edge);
  		};
  		mxConnectionHandler.prototype.insertEdge = function(parent, id, value, source, target, style)
  		{
  			if (this.factoryMethod == null)
  			{
  				return this.graph.insertEdge(parent, id, value, source, target, style);
  			}
  			else
  			{
  				var edge = this.createEdge(value, source, target, style);
  				edge = this.graph.addEdge(edge, parent, source, target);
  				return edge;
  			}
  		};
  		mxConnectionHandler.prototype.createTargetVertex = function(evt, source)
  		{
  			var geo = this.graph.getCellGeometry(source);
  			while (geo != null && geo.relative)
  			{
  				source = this.graph.getModel().getParent(source);
  				geo = this.graph.getCellGeometry(source);
  			}
  			var clone = this.graph.cloneCell(source);
  			var geo = this.graph.getModel().getGeometry(clone);
  			if (geo != null)
  			{
  				var t = this.graph.view.translate;
  				var s = this.graph.view.scale;
  				var point = new mxPoint(this.currentPoint.x / s - t.x, this.currentPoint.y / s - t.y);
  				geo.x = Math.round(point.x - geo.width / 2 - this.graph.panDx / s);
  				geo.y = Math.round(point.y - geo.height / 2 - this.graph.panDy / s);
  				var tol = this.getAlignmentTolerance();
  				if (tol > 0)
  				{
  					var sourceState = this.graph.view.getState(source);
  					if (sourceState != null)
  					{
  						var x = sourceState.x / s - t.x;
  						var y = sourceState.y / s - t.y;
  						if (Math.abs(x - geo.x) <= tol)
  						{
  							geo.x = Math.round(x);
  						}
  						if (Math.abs(y - geo.y) <= tol)
  						{
  							geo.y = Math.round(y);
  						}
  					}
  				}
  			}
  			return clone;
  		};
  		mxConnectionHandler.prototype.getAlignmentTolerance = function(evt)
  		{
  			return (this.graph.isGridEnabled()) ? this.graph.gridSize / 2 : this.graph.tolerance;
  		};
  		mxConnectionHandler.prototype.createEdge = function(value, source, target, style)
  		{
  			var edge = null;
  			if (this.factoryMethod != null)
  			{
  				edge = this.factoryMethod(source, target, style);
  			}
  			if (edge == null)
  			{
  				edge = new mxCell(value || '');
  				edge.setEdge(true);
  				edge.setStyle(style);
  				var geo = new mxGeometry();
  				geo.relative = true;
  				edge.setGeometry(geo);
  			}
  			return edge;
  		};
  		mxConnectionHandler.prototype.destroy = function()
  		{
  			this.graph.removeMouseListener(this);
  			if (this.shape != null)
  			{
  				this.shape.destroy();
  				this.shape = null;
  			}
  			if (this.marker != null)
  			{
  				this.marker.destroy();
  				this.marker = null;
  			}
  			if (this.constraintHandler != null)
  			{
  				this.constraintHandler.destroy();
  				this.constraintHandler = null;
  			}
  			if (this.changeHandler != null)
  			{
  				this.graph.getModel().removeListener(this.changeHandler);
  				this.graph.getView().removeListener(this.changeHandler);
  				this.changeHandler = null;
  			}
  			if (this.drillHandler != null)
  			{
  				this.graph.removeListener(this.drillHandler);
  				this.graph.getView().removeListener(this.drillHandler);
  				this.drillHandler = null;
  			}
  			if (this.escapeHandler != null)
  			{
  				this.graph.removeListener(this.escapeHandler);
  				this.escapeHandler = null;
  			}
  		};
  		__mxOutput.mxConnectionHandler = typeof mxConnectionHandler !== 'undefined' ? mxConnectionHandler : undefined;
  		function mxConstraintHandler(graph)
  		{
  			this.graph = graph;
  			this.resetHandler = mxUtils.bind(this, function(sender, evt)
  			{
  				if (this.currentFocus != null && this.graph.view.getState(this.currentFocus.cell) == null)
  				{
  					this.reset();
  				}
  				else
  				{
  					this.redraw();
  				}
  			});
  			this.graph.model.addListener(mxEvent.CHANGE, this.resetHandler);
  			this.graph.view.addListener(mxEvent.SCALE_AND_TRANSLATE, this.resetHandler);
  			this.graph.view.addListener(mxEvent.TRANSLATE, this.resetHandler);
  			this.graph.view.addListener(mxEvent.SCALE, this.resetHandler);
  			this.graph.addListener(mxEvent.ROOT, this.resetHandler);
  		}		mxConstraintHandler.prototype.pointImage = new mxImage(mxClient.imageBasePath + '/point.gif', 5, 5);
  		mxConstraintHandler.prototype.graph = null;
  		mxConstraintHandler.prototype.enabled = true;
  		mxConstraintHandler.prototype.highlightColor = mxConstants.DEFAULT_VALID_COLOR;
  		mxConstraintHandler.prototype.isEnabled = function()
  		{
  			return this.enabled;
  		};
  		mxConstraintHandler.prototype.setEnabled = function(enabled)
  		{
  			this.enabled = enabled;
  		};
  		mxConstraintHandler.prototype.reset = function()
  		{
  			if (this.focusIcons != null)
  			{
  				for (var i = 0; i < this.focusIcons.length; i++)
  				{
  					this.focusIcons[i].destroy();
  				}
  				this.focusIcons = null;
  			}
  			if (this.focusHighlight != null)
  			{
  				this.focusHighlight.destroy();
  				this.focusHighlight = null;
  			}
  			this.currentConstraint = null;
  			this.currentFocusArea = null;
  			this.currentPoint = null;
  			this.currentFocus = null;
  			this.focusPoints = null;
  		};
  		mxConstraintHandler.prototype.getTolerance = function(me)
  		{
  			return this.graph.getTolerance();
  		};
  		mxConstraintHandler.prototype.getImageForConstraint = function(state, constraint, point)
  		{
  			return this.pointImage;
  		};
  		mxConstraintHandler.prototype.isEventIgnored = function(me, source)
  		{
  			return false;
  		};
  		mxConstraintHandler.prototype.isStateIgnored = function(state, source)
  		{
  			return false;
  		};
  		mxConstraintHandler.prototype.destroyIcons = function()
  		{
  			if (this.focusIcons != null)
  			{
  				for (var i = 0; i < this.focusIcons.length; i++)
  				{
  					this.focusIcons[i].destroy();
  				}
  				this.focusIcons = null;
  				this.focusPoints = null;
  			}
  		};
  		mxConstraintHandler.prototype.destroyFocusHighlight = function()
  		{
  			if (this.focusHighlight != null)
  			{
  				this.focusHighlight.destroy();
  				this.focusHighlight = null;
  			}
  		};
  		mxConstraintHandler.prototype.isKeepFocusEvent = function(me)
  		{
  			return mxEvent.isShiftDown(me.getEvent());
  		};
  		mxConstraintHandler.prototype.getCellForEvent = function(me, point)
  		{
  			var cell = me.getCell();
  			if (cell == null && point != null && (me.getGraphX() != point.x || me.getGraphY() != point.y))
  			{
  				cell = this.graph.getCellAt(point.x, point.y);
  			}
  			if (cell != null && !this.graph.isCellConnectable(cell))
  			{
  				var parent = this.graph.getModel().getParent(cell);
  				if (this.graph.getModel().isVertex(parent) && this.graph.isCellConnectable(parent))
  				{
  					cell = parent;
  				}
  			}
  			return (this.graph.isCellLocked(cell)) ? null : cell;
  		};
  		mxConstraintHandler.prototype.update = function(me, source, existingEdge, point)
  		{
  			if (this.isEnabled() && !this.isEventIgnored(me))
  			{
  				if (this.mouseleaveHandler == null && this.graph.container != null)
  				{
  					this.mouseleaveHandler = mxUtils.bind(this, function()
  					{
  						this.reset();
  					});
  					mxEvent.addListener(this.graph.container, 'mouseleave', this.resetHandler);
  				}
  				var tol = this.getTolerance(me);
  				var x = (point != null) ? point.x : me.getGraphX();
  				var y = (point != null) ? point.y : me.getGraphY();
  				var grid = new mxRectangle(x - tol, y - tol, 2 * tol, 2 * tol);
  				var mouse = new mxRectangle(me.getGraphX() - tol, me.getGraphY() - tol, 2 * tol, 2 * tol);
  				var state = this.graph.view.getState(this.getCellForEvent(me, point));
  				if (!this.isKeepFocusEvent(me) && (this.currentFocusArea == null || this.currentFocus == null ||
  					(state != null) || !this.graph.getModel().isVertex(this.currentFocus.cell) ||
  					!mxUtils.intersects(this.currentFocusArea, mouse)) && (state != this.currentFocus))
  				{
  					this.currentFocusArea = null;
  					this.currentFocus = null;
  					this.setFocus(me, state, source);
  				}
  				this.currentConstraint = null;
  				this.currentPoint = null;
  				var minDistSq = null;
  				if (this.focusIcons != null && this.constraints != null &&
  					(state == null || this.currentFocus == state))
  				{
  					var cx = mouse.getCenterX();
  					var cy = mouse.getCenterY();
  					for (var i = 0; i < this.focusIcons.length; i++)
  					{
  						var dx = cx - this.focusIcons[i].bounds.getCenterX();
  						var dy = cy - this.focusIcons[i].bounds.getCenterY();
  						var tmp = dx * dx + dy * dy;
  						if ((this.intersects(this.focusIcons[i], mouse, source, existingEdge) || (point != null &&
  							this.intersects(this.focusIcons[i], grid, source, existingEdge))) &&
  							(minDistSq == null || tmp < minDistSq))
  						{
  							this.currentConstraint = this.constraints[i];
  							this.currentPoint = this.focusPoints[i];
  							minDistSq = tmp;
  							var tmp = this.focusIcons[i].bounds.clone();
  							tmp.grow(mxConstants.HIGHLIGHT_SIZE + 1);
  							tmp.width -= 1;
  							tmp.height -= 1;
  							if (this.focusHighlight == null)
  							{
  								var hl = this.createHighlightShape();
  								hl.dialect = (this.graph.dialect == mxConstants.DIALECT_SVG) ?
  										mxConstants.DIALECT_SVG : mxConstants.DIALECT_VML;
  								hl.pointerEvents = false;
  								hl.init(this.graph.getView().getOverlayPane());
  								this.focusHighlight = hl;
  								var getState = mxUtils.bind(this, function()
  								{
  									return (this.currentFocus != null) ? this.currentFocus : state;
  								});
  								mxEvent.redirectMouseEvents(hl.node, this.graph, getState);
  							}
  							this.focusHighlight.bounds = tmp;
  							this.focusHighlight.redraw();
  						}
  					}
  				}
  				if (this.currentConstraint == null)
  				{
  					this.destroyFocusHighlight();
  				}
  			}
  			else
  			{
  				this.currentConstraint = null;
  				this.currentFocus = null;
  				this.currentPoint = null;
  			}
  		};
  		mxConstraintHandler.prototype.redraw = function()
  		{
  			if (this.currentFocus != null && this.constraints != null && this.focusIcons != null)
  			{
  				var state = this.graph.view.getState(this.currentFocus.cell);
  				this.currentFocus = state;
  				this.currentFocusArea = new mxRectangle(state.x, state.y, state.width, state.height);
  				for (var i = 0; i < this.constraints.length; i++)
  				{
  					var cp = this.graph.getConnectionPoint(state, this.constraints[i]);
  					var img = this.getImageForConstraint(state, this.constraints[i], cp);
  					var bounds = new mxRectangle(Math.round(cp.x - img.width / 2),
  						Math.round(cp.y - img.height / 2), img.width, img.height);
  					this.focusIcons[i].bounds = bounds;
  					this.focusIcons[i].redraw();
  					this.currentFocusArea.add(this.focusIcons[i].bounds);
  					this.focusPoints[i] = cp;
  				}
  			}
  		};
  		mxConstraintHandler.prototype.setFocus = function(me, state, source)
  		{
  			this.constraints = (state != null && !this.isStateIgnored(state, source) &&
  				this.graph.isCellConnectable(state.cell)) ? ((this.isEnabled()) ?
  				(this.graph.getAllConnectionConstraints(state, source) || []) : []) : null;
  			if (this.constraints != null)
  			{
  				this.currentFocus = state;
  				this.currentFocusArea = new mxRectangle(state.x, state.y, state.width, state.height);
  				if (this.focusIcons != null)
  				{
  					for (var i = 0; i < this.focusIcons.length; i++)
  					{
  						this.focusIcons[i].destroy();
  					}
  					this.focusIcons = null;
  					this.focusPoints = null;
  				}
  				this.focusPoints = [];
  				this.focusIcons = [];
  				for (var i = 0; i < this.constraints.length; i++)
  				{
  					var cp = this.graph.getConnectionPoint(state, this.constraints[i]);
  					var img = this.getImageForConstraint(state, this.constraints[i], cp);
  					var src = img.src;
  					var bounds = new mxRectangle(Math.round(cp.x - img.width / 2),
  						Math.round(cp.y - img.height / 2), img.width, img.height);
  					var icon = new mxImageShape(bounds, src);
  					icon.dialect = (this.graph.dialect != mxConstants.DIALECT_SVG) ?
  							mxConstants.DIALECT_MIXEDHTML : mxConstants.DIALECT_SVG;
  					icon.preserveImageAspect = false;
  					icon.init(this.graph.getView().getDecoratorPane());
  					if (mxClient.IS_QUIRKS || document.documentMode == 8)
  					{
  						mxEvent.addListener(icon.node, 'dragstart', function(evt)
  						{
  							mxEvent.consume(evt);
  							return false;
  						});
  					}
  					if (icon.node.previousSibling != null)
  					{
  						icon.node.parentNode.insertBefore(icon.node, icon.node.parentNode.firstChild);
  					}
  					var getState = mxUtils.bind(this, function()
  					{
  						return (this.currentFocus != null) ? this.currentFocus : state;
  					});
  					icon.redraw();
  					mxEvent.redirectMouseEvents(icon.node, this.graph, getState);
  					this.currentFocusArea.add(icon.bounds);
  					this.focusIcons.push(icon);
  					this.focusPoints.push(cp);
  				}
  				this.currentFocusArea.grow(this.getTolerance(me));
  			}
  			else
  			{
  				this.destroyIcons();
  				this.destroyFocusHighlight();
  			}
  		};
  		mxConstraintHandler.prototype.createHighlightShape = function()
  		{
  			var hl = new mxRectangleShape(null, this.highlightColor, this.highlightColor, mxConstants.HIGHLIGHT_STROKEWIDTH);
  			hl.opacity = mxConstants.HIGHLIGHT_OPACITY;
  			return hl;
  		};
  		mxConstraintHandler.prototype.intersects = function(icon, mouse, source, existingEdge)
  		{
  			return mxUtils.intersects(icon.bounds, mouse);
  		};
  		mxConstraintHandler.prototype.destroy = function()
  		{
  			this.reset();
  			if (this.resetHandler != null)
  			{
  				this.graph.model.removeListener(this.resetHandler);
  				this.graph.view.removeListener(this.resetHandler);
  				this.graph.removeListener(this.resetHandler);
  				this.resetHandler = null;
  			}
  			if (this.mouseleaveHandler != null && this.graph.container != null)
  			{
  				mxEvent.removeListener(this.graph.container, 'mouseleave', this.mouseleaveHandler);
  				this.mouseleaveHandler = null;
  			}
  		};
  		__mxOutput.mxConstraintHandler = typeof mxConstraintHandler !== 'undefined' ? mxConstraintHandler : undefined;
  		function mxRubberband(graph)
  		{
  			if (graph != null)
  			{
  				this.graph = graph;
  				this.graph.addMouseListener(this);
  				this.forceRubberbandHandler = mxUtils.bind(this, function(sender, evt)
  				{
  					var evtName = evt.getProperty('eventName');
  					var me = evt.getProperty('event');
  					if (evtName == mxEvent.MOUSE_DOWN && this.isForceRubberbandEvent(me))
  					{
  						var offset = mxUtils.getOffset(this.graph.container);
  						var origin = mxUtils.getScrollOrigin(this.graph.container);
  						origin.x -= offset.x;
  						origin.y -= offset.y;
  						this.start(me.getX() + origin.x, me.getY() + origin.y);
  						me.consume(false);
  					}
  				});
  				this.graph.addListener(mxEvent.FIRE_MOUSE_EVENT, this.forceRubberbandHandler);
  				this.panHandler = mxUtils.bind(this, function()
  				{
  					this.repaint();
  				});
  				this.graph.addListener(mxEvent.PAN, this.panHandler);
  				this.gestureHandler = mxUtils.bind(this, function(sender, eo)
  				{
  					if (this.first != null)
  					{
  						this.reset();
  					}
  				});
  				this.graph.addListener(mxEvent.GESTURE, this.gestureHandler);
  				if (mxClient.IS_IE)
  				{
  					mxEvent.addListener(window, 'unload',
  						mxUtils.bind(this, function()
  						{
  							this.destroy();
  						})
  					);
  				}
  			}
  		}		mxRubberband.prototype.defaultOpacity = 20;
  		mxRubberband.prototype.enabled = true;
  		mxRubberband.prototype.div = null;
  		mxRubberband.prototype.sharedDiv = null;
  		mxRubberband.prototype.currentX = 0;
  		mxRubberband.prototype.currentY = 0;
  		mxRubberband.prototype.fadeOut = false;
  		mxRubberband.prototype.isEnabled = function()
  		{
  			return this.enabled;
  		};
  		mxRubberband.prototype.setEnabled = function(enabled)
  		{
  			this.enabled = enabled;
  		};
  		mxRubberband.prototype.isForceRubberbandEvent = function(me)
  		{
  			return mxEvent.isAltDown(me.getEvent());
  		};
  		mxRubberband.prototype.mouseDown = function(sender, me)
  		{
  			if (!me.isConsumed() && this.isEnabled() && this.graph.isEnabled() &&
  				me.getState() == null && !mxEvent.isMultiTouchEvent(me.getEvent()))
  			{
  				var offset = mxUtils.getOffset(this.graph.container);
  				var origin = mxUtils.getScrollOrigin(this.graph.container);
  				origin.x -= offset.x;
  				origin.y -= offset.y;
  				this.start(me.getX() + origin.x, me.getY() + origin.y);
  				me.consume(false);
  			}
  		};
  		mxRubberband.prototype.start = function(x, y)
  		{
  			this.first = new mxPoint(x, y);
  			var container = this.graph.container;
  			function createMouseEvent(evt)
  			{
  				var me = new mxMouseEvent(evt);
  				var pt = mxUtils.convertPoint(container, me.getX(), me.getY());
  				me.graphX = pt.x;
  				me.graphY = pt.y;
  				return me;
  			}			this.dragHandler = mxUtils.bind(this, function(evt)
  			{
  				this.mouseMove(this.graph, createMouseEvent(evt));
  			});
  			this.dropHandler = mxUtils.bind(this, function(evt)
  			{
  				this.mouseUp(this.graph, createMouseEvent(evt));
  			});
  			if (mxClient.IS_FF)
  			{
  				mxEvent.addGestureListeners(document, null, this.dragHandler, this.dropHandler);
  			}
  		};
  		mxRubberband.prototype.mouseMove = function(sender, me)
  		{
  			if (!me.isConsumed() && this.first != null)
  			{
  				var origin = mxUtils.getScrollOrigin(this.graph.container);
  				var offset = mxUtils.getOffset(this.graph.container);
  				origin.x -= offset.x;
  				origin.y -= offset.y;
  				var x = me.getX() + origin.x;
  				var y = me.getY() + origin.y;
  				var dx = this.first.x - x;
  				var dy = this.first.y - y;
  				var tol = this.graph.tolerance;
  				if (this.div != null || Math.abs(dx) > tol ||  Math.abs(dy) > tol)
  				{
  					if (this.div == null)
  					{
  						this.div = this.createShape();
  					}
  					mxUtils.clearSelection();
  					this.update(x, y);
  					me.consume();
  				}
  			}
  		};
  		mxRubberband.prototype.createShape = function()
  		{
  			if (this.sharedDiv == null)
  			{
  				this.sharedDiv = document.createElement('div');
  				this.sharedDiv.className = 'mxRubberband';
  				mxUtils.setOpacity(this.sharedDiv, this.defaultOpacity);
  			}
  			this.graph.container.appendChild(this.sharedDiv);
  			var result = this.sharedDiv;
  			if (mxClient.IS_SVG && (!mxClient.IS_IE || document.documentMode >= 10) && this.fadeOut)
  			{
  				this.sharedDiv = null;
  			}
  			return result;
  		};
  		mxRubberband.prototype.isActive = function(sender, me)
  		{
  			return this.div != null && this.div.style.display != 'none';
  		};
  		mxRubberband.prototype.mouseUp = function(sender, me)
  		{
  			var active = this.isActive();
  			this.reset();
  			if (active)
  			{
  				this.execute(me.getEvent());
  				me.consume();
  			}
  		};
  		mxRubberband.prototype.execute = function(evt)
  		{
  			var rect = new mxRectangle(this.x, this.y, this.width, this.height);
  			this.graph.selectRegion(rect, evt);
  		};
  		mxRubberband.prototype.reset = function()
  		{
  			if (this.div != null)
  			{
  				if (mxClient.IS_SVG && (!mxClient.IS_IE || document.documentMode >= 10) && this.fadeOut)
  				{
  					var temp = this.div;
  					mxUtils.setPrefixedStyle(temp.style, 'transition', 'all 0.2s linear');
  					temp.style.pointerEvents = 'none';
  					temp.style.opacity = 0;
  				    window.setTimeout(function()
  				    	{
  				    		temp.parentNode.removeChild(temp);
  				    	}, 200);
  				}
  				else
  				{
  					this.div.parentNode.removeChild(this.div);
  				}
  			}
  			mxEvent.removeGestureListeners(document, null, this.dragHandler, this.dropHandler);
  			this.dragHandler = null;
  			this.dropHandler = null;
  			this.currentX = 0;
  			this.currentY = 0;
  			this.first = null;
  			this.div = null;
  		};
  		mxRubberband.prototype.update = function(x, y)
  		{
  			this.currentX = x;
  			this.currentY = y;
  			this.repaint();
  		};
  		mxRubberband.prototype.repaint = function()
  		{
  			if (this.div != null)
  			{
  				var x = this.currentX - this.graph.panDx;
  				var y = this.currentY - this.graph.panDy;
  				this.x = Math.min(this.first.x, x);
  				this.y = Math.min(this.first.y, y);
  				this.width = Math.max(this.first.x, x) - this.x;
  				this.height =  Math.max(this.first.y, y) - this.y;
  				var dx = (mxClient.IS_VML) ? this.graph.panDx : 0;
  				var dy = (mxClient.IS_VML) ? this.graph.panDy : 0;
  				this.div.style.left = (this.x + dx) + 'px';
  				this.div.style.top = (this.y + dy) + 'px';
  				this.div.style.width = Math.max(1, this.width) + 'px';
  				this.div.style.height = Math.max(1, this.height) + 'px';
  			}
  		};
  		mxRubberband.prototype.destroy = function()
  		{
  			if (!this.destroyed)
  			{
  				this.destroyed = true;
  				this.graph.removeMouseListener(this);
  				this.graph.removeListener(this.forceRubberbandHandler);
  				this.graph.removeListener(this.panHandler);
  				this.reset();
  				if (this.sharedDiv != null)
  				{
  					this.sharedDiv = null;
  				}
  			}
  		};
  		__mxOutput.mxRubberband = typeof mxRubberband !== 'undefined' ? mxRubberband : undefined;
  		function mxHandle(state, cursor, image, shape)
  		{
  			this.graph = state.view.graph;
  			this.state = state;
  			this.cursor = (cursor != null) ? cursor : this.cursor;
  			this.image = (image != null) ? image : this.image;
  			this.shape = (shape != null) ? shape : null;
  			this.init();
  		}		mxHandle.prototype.cursor = 'default';
  		mxHandle.prototype.image = null;
  		mxHandle.prototype.ignoreGrid = false;
  		mxHandle.prototype.getPosition = function(bounds) { };
  		mxHandle.prototype.setPosition = function(bounds, pt, me) { };
  		mxHandle.prototype.execute = function(me) { };
  		mxHandle.prototype.copyStyle = function(key)
  		{
  			this.graph.setCellStyles(key, this.state.style[key], [this.state.cell]);
  		};
  		mxHandle.prototype.processEvent = function(me)
  		{
  			var scale = this.graph.view.scale;
  			var tr = this.graph.view.translate;
  			var pt = new mxPoint(me.getGraphX() / scale - tr.x, me.getGraphY() / scale - tr.y);
  			if (this.shape != null && this.shape.bounds != null)
  			{
  				pt.x -= this.shape.bounds.width / scale / 4;
  				pt.y -= this.shape.bounds.height / scale / 4;
  			}
  			var alpha1 = -mxUtils.toRadians(this.getRotation());
  			var alpha2 = -mxUtils.toRadians(this.getTotalRotation()) - alpha1;
  			pt = this.flipPoint(this.rotatePoint(this.snapPoint(this.rotatePoint(pt, alpha1),
  					this.ignoreGrid || !this.graph.isGridEnabledEvent(me.getEvent())), alpha2));
  			this.setPosition(this.state.getPaintBounds(), pt, me);
  			this.redraw();
  		};
  		mxHandle.prototype.positionChanged = function()
  		{
  			if (this.state.text != null)
  			{
  				this.state.text.apply(this.state);
  			}
  			if (this.state.shape != null)
  			{
  				this.state.shape.apply(this.state);
  			}
  			this.graph.cellRenderer.redraw(this.state, true);
  		};
  		mxHandle.prototype.getRotation = function()
  		{
  			if (this.state.shape != null)
  			{
  				return this.state.shape.getRotation();
  			}
  			return 0;
  		};
  		mxHandle.prototype.getTotalRotation = function()
  		{
  			if (this.state.shape != null)
  			{
  				return this.state.shape.getShapeRotation();
  			}
  			return 0;
  		};
  		mxHandle.prototype.init = function()
  		{
  			var html = this.isHtmlRequired();
  			if (this.image != null)
  			{
  				this.shape = new mxImageShape(new mxRectangle(0, 0, this.image.width, this.image.height), this.image.src);
  				this.shape.preserveImageAspect = false;
  			}
  			else if (this.shape == null)
  			{
  				this.shape = this.createShape(html);
  			}
  			this.initShape(html);
  		};
  		mxHandle.prototype.createShape = function(html)
  		{
  			var bounds = new mxRectangle(0, 0, mxConstants.HANDLE_SIZE, mxConstants.HANDLE_SIZE);
  			return new mxRectangleShape(bounds, mxConstants.HANDLE_FILLCOLOR, mxConstants.HANDLE_STROKECOLOR);
  		};
  		mxHandle.prototype.initShape = function(html)
  		{
  			if (html && this.shape.isHtmlAllowed())
  			{
  				this.shape.dialect = mxConstants.DIALECT_STRICTHTML;
  				this.shape.init(this.graph.container);
  			}
  			else
  			{
  				this.shape.dialect = (this.graph.dialect != mxConstants.DIALECT_SVG) ?
  					mxConstants.DIALECT_MIXEDHTML : mxConstants.DIALECT_SVG;
  				if (this.cursor != null)
  				{
  					this.shape.init(this.graph.getView().getOverlayPane());
  				}
  			}
  			mxEvent.redirectMouseEvents(this.shape.node, this.graph, this.state);
  			this.shape.node.style.cursor = this.cursor;
  		};
  		mxHandle.prototype.redraw = function()
  		{
  			if (this.shape != null && this.state.shape != null)
  			{
  				var pt = this.getPosition(this.state.getPaintBounds());
  				if (pt != null)
  				{
  					var alpha = mxUtils.toRadians(this.getTotalRotation());
  					pt = this.rotatePoint(this.flipPoint(pt), alpha);
  					var scale = this.graph.view.scale;
  					var tr = this.graph.view.translate;
  					this.shape.bounds.x = Math.floor((pt.x + tr.x) * scale - this.shape.bounds.width / 2);
  					this.shape.bounds.y = Math.floor((pt.y + tr.y) * scale - this.shape.bounds.height / 2);
  					this.shape.redraw();
  				}
  			}
  		};
  		mxHandle.prototype.isHtmlRequired = function()
  		{
  			return this.state.text != null && this.state.text.node.parentNode == this.graph.container;
  		};
  		mxHandle.prototype.rotatePoint = function(pt, alpha)
  		{
  			var bounds = this.state.getCellBounds();
  			var cx = new mxPoint(bounds.getCenterX(), bounds.getCenterY());
  			var cos = Math.cos(alpha);
  			var sin = Math.sin(alpha);
  			return mxUtils.getRotatedPoint(pt, cos, sin, cx);
  		};
  		mxHandle.prototype.flipPoint = function(pt)
  		{
  			if (this.state.shape != null)
  			{
  				var bounds = this.state.getCellBounds();
  				if (this.state.shape.flipH)
  				{
  					pt.x = 2 * bounds.x + bounds.width - pt.x;
  				}
  				if (this.state.shape.flipV)
  				{
  					pt.y = 2 * bounds.y + bounds.height - pt.y;
  				}
  			}
  			return pt;
  		};
  		mxHandle.prototype.snapPoint = function(pt, ignore)
  		{
  			if (!ignore)
  			{
  				pt.x = this.graph.snap(pt.x);
  				pt.y = this.graph.snap(pt.y);
  			}
  			return pt;
  		};
  		mxHandle.prototype.setVisible = function(visible)
  		{
  			if (this.shape != null && this.shape.node != null)
  			{
  				this.shape.node.style.display = (visible) ? '' : 'none';
  			}
  		};
  		mxHandle.prototype.reset = function()
  		{
  			this.setVisible(true);
  			this.state.style = this.graph.getCellStyle(this.state.cell);
  			this.positionChanged();
  		};
  		mxHandle.prototype.destroy = function()
  		{
  			if (this.shape != null)
  			{
  				this.shape.destroy();
  				this.shape = null;
  			}
  		};
  		__mxOutput.mxHandle = typeof mxHandle !== 'undefined' ? mxHandle : undefined;
  		function mxVertexHandler(state)
  		{
  			if (state != null)
  			{
  				this.state = state;
  				this.init();
  				this.escapeHandler = mxUtils.bind(this, function(sender, evt)
  				{
  					if (this.livePreview && this.index != null)
  					{
  						this.state.view.graph.cellRenderer.redraw(this.state, true);
  						this.state.view.invalidate(this.state.cell);
  						this.state.invalid = false;
  						this.state.view.validate();
  					}
  					this.reset();
  				});
  				this.state.view.graph.addListener(mxEvent.ESCAPE, this.escapeHandler);
  			}
  		}		mxVertexHandler.prototype.graph = null;
  		mxVertexHandler.prototype.state = null;
  		mxVertexHandler.prototype.singleSizer = false;
  		mxVertexHandler.prototype.index = null;
  		mxVertexHandler.prototype.allowHandleBoundsCheck = true;
  		mxVertexHandler.prototype.handleImage = null;
  		mxVertexHandler.prototype.handlesVisible = true;
  		mxVertexHandler.prototype.tolerance = 0;
  		mxVertexHandler.prototype.rotationEnabled = false;
  		mxVertexHandler.prototype.parentHighlightEnabled = false;
  		mxVertexHandler.prototype.rotationRaster = true;
  		mxVertexHandler.prototype.rotationCursor = 'crosshair';
  		mxVertexHandler.prototype.livePreview = false;
  		mxVertexHandler.prototype.movePreviewToFront = false;
  		mxVertexHandler.prototype.manageSizers = false;
  		mxVertexHandler.prototype.constrainGroupByChildren = false;
  		mxVertexHandler.prototype.rotationHandleVSpacing = -16;
  		mxVertexHandler.prototype.horizontalOffset = 0;
  		mxVertexHandler.prototype.verticalOffset = 0;
  		mxVertexHandler.prototype.init = function()
  		{
  			this.graph = this.state.view.graph;
  			this.selectionBounds = this.getSelectionBounds(this.state);
  			this.bounds = new mxRectangle(this.selectionBounds.x, this.selectionBounds.y, this.selectionBounds.width, this.selectionBounds.height);
  			this.selectionBorder = this.createSelectionShape(this.bounds);
  			this.selectionBorder.dialect = (this.graph.dialect != mxConstants.DIALECT_SVG) ? mxConstants.DIALECT_VML : mxConstants.DIALECT_SVG;
  			this.selectionBorder.pointerEvents = false;
  			this.selectionBorder.rotation = Number(this.state.style[mxConstants.STYLE_ROTATION] || '0');
  			this.selectionBorder.init(this.graph.getView().getOverlayPane());
  			mxEvent.redirectMouseEvents(this.selectionBorder.node, this.graph, this.state);
  			if (this.graph.isCellMovable(this.state.cell))
  			{
  				this.selectionBorder.setCursor(mxConstants.CURSOR_MOVABLE_VERTEX);
  			}
  			if (mxGraphHandler.prototype.maxCells <= 0 || this.graph.getSelectionCount() < mxGraphHandler.prototype.maxCells)
  			{
  				var resizable = this.graph.isCellResizable(this.state.cell);
  				this.sizers = [];
  				if (resizable || (this.graph.isLabelMovable(this.state.cell) &&
  					this.state.width >= 2 && this.state.height >= 2))
  				{
  					var i = 0;
  					if (resizable)
  					{
  						if (!this.singleSizer)
  						{
  							this.sizers.push(this.createSizer('nw-resize', i++));
  							this.sizers.push(this.createSizer('n-resize', i++));
  							this.sizers.push(this.createSizer('ne-resize', i++));
  							this.sizers.push(this.createSizer('w-resize', i++));
  							this.sizers.push(this.createSizer('e-resize', i++));
  							this.sizers.push(this.createSizer('sw-resize', i++));
  							this.sizers.push(this.createSizer('s-resize', i++));
  						}
  						this.sizers.push(this.createSizer('se-resize', i++));
  					}
  					var geo = this.graph.model.getGeometry(this.state.cell);
  					if (geo != null && !geo.relative && !this.graph.isSwimlane(this.state.cell) &&
  						this.graph.isLabelMovable(this.state.cell))
  					{
  						this.labelShape = this.createSizer(mxConstants.CURSOR_LABEL_HANDLE, mxEvent.LABEL_HANDLE,
  							mxConstants.LABEL_HANDLE_SIZE, mxConstants.LABEL_HANDLE_FILLCOLOR);
  						this.sizers.push(this.labelShape);
  					}
  				}
  				else if (this.graph.isCellMovable(this.state.cell) && !this.graph.isCellResizable(this.state.cell) &&
  					this.state.width < 2 && this.state.height < 2)
  				{
  					this.labelShape = this.createSizer(mxConstants.CURSOR_MOVABLE_VERTEX,
  						mxEvent.LABEL_HANDLE, null, mxConstants.LABEL_HANDLE_FILLCOLOR);
  					this.sizers.push(this.labelShape);
  				}
  			}
  			if (this.isRotationHandleVisible())
  			{
  				this.rotationShape = this.createSizer(this.rotationCursor, mxEvent.ROTATION_HANDLE,
  					mxConstants.HANDLE_SIZE + 3, mxConstants.HANDLE_FILLCOLOR);
  				this.sizers.push(this.rotationShape);
  			}
  			this.customHandles = this.createCustomHandles();
  			this.redraw();
  			if (this.constrainGroupByChildren)
  			{
  				this.updateMinBounds();
  			}
  		};
  		mxVertexHandler.prototype.isRotationHandleVisible = function()
  		{
  			return this.graph.isEnabled() && this.rotationEnabled && this.graph.isCellRotatable(this.state.cell) &&
  				(mxGraphHandler.prototype.maxCells <= 0 || this.graph.getSelectionCount() < mxGraphHandler.prototype.maxCells);
  		};
  		mxVertexHandler.prototype.isConstrainedEvent = function(me)
  		{
  			return mxEvent.isShiftDown(me.getEvent()) || this.state.style[mxConstants.STYLE_ASPECT] == 'fixed';
  		};
  		mxVertexHandler.prototype.isCenteredEvent = function(state, me)
  		{
  			return false;
  		};
  		mxVertexHandler.prototype.createCustomHandles = function()
  		{
  			return null;
  		};
  		mxVertexHandler.prototype.updateMinBounds = function()
  		{
  			var children = this.graph.getChildCells(this.state.cell);
  			if (children.length > 0)
  			{
  				this.minBounds = this.graph.view.getBounds(children);
  				if (this.minBounds != null)
  				{
  					var s = this.state.view.scale;
  					var t = this.state.view.translate;
  					this.minBounds.x -= this.state.x;
  					this.minBounds.y -= this.state.y;
  					this.minBounds.x /= s;
  					this.minBounds.y /= s;
  					this.minBounds.width /= s;
  					this.minBounds.height /= s;
  					this.x0 = this.state.x / s - t.x;
  					this.y0 = this.state.y / s - t.y;
  				}
  			}
  		};
  		mxVertexHandler.prototype.getSelectionBounds = function(state)
  		{
  			return new mxRectangle(Math.round(state.x), Math.round(state.y), Math.round(state.width), Math.round(state.height));
  		};
  		mxVertexHandler.prototype.createParentHighlightShape = function(bounds)
  		{
  			return this.createSelectionShape(bounds);
  		};
  		mxVertexHandler.prototype.createSelectionShape = function(bounds)
  		{
  			var shape = new mxRectangleShape(
  				mxRectangle.fromRectangle(bounds),
  				null, this.getSelectionColor());
  			shape.strokewidth = this.getSelectionStrokeWidth();
  			shape.isDashed = this.isSelectionDashed();
  			return shape;
  		};
  		mxVertexHandler.prototype.getSelectionColor = function()
  		{
  			return mxConstants.VERTEX_SELECTION_COLOR;
  		};
  		mxVertexHandler.prototype.getSelectionStrokeWidth = function()
  		{
  			return mxConstants.VERTEX_SELECTION_STROKEWIDTH;
  		};
  		mxVertexHandler.prototype.isSelectionDashed = function()
  		{
  			return mxConstants.VERTEX_SELECTION_DASHED;
  		};
  		mxVertexHandler.prototype.createSizer = function(cursor, index, size, fillColor)
  		{
  			size = size || mxConstants.HANDLE_SIZE;
  			var bounds = new mxRectangle(0, 0, size, size);
  			var sizer = this.createSizerShape(bounds, index, fillColor);
  			if (sizer.isHtmlAllowed() && this.state.text != null && this.state.text.node.parentNode == this.graph.container)
  			{
  				sizer.bounds.height -= 1;
  				sizer.bounds.width -= 1;
  				sizer.dialect = mxConstants.DIALECT_STRICTHTML;
  				sizer.init(this.graph.container);
  			}
  			else
  			{
  				sizer.dialect = (this.graph.dialect != mxConstants.DIALECT_SVG) ?
  						mxConstants.DIALECT_MIXEDHTML : mxConstants.DIALECT_SVG;
  				sizer.init(this.graph.getView().getOverlayPane());
  			}
  			mxEvent.redirectMouseEvents(sizer.node, this.graph, this.state);
  			if (this.graph.isEnabled())
  			{
  				sizer.setCursor(cursor);
  			}
  			if (!this.isSizerVisible(index))
  			{
  				sizer.visible = false;
  			}
  			return sizer;
  		};
  		mxVertexHandler.prototype.isSizerVisible = function(index)
  		{
  			return true;
  		};
  		mxVertexHandler.prototype.createSizerShape = function(bounds, index, fillColor)
  		{
  			if (this.handleImage != null)
  			{
  				bounds = new mxRectangle(bounds.x, bounds.y, this.handleImage.width, this.handleImage.height);
  				var shape = new mxImageShape(bounds, this.handleImage.src);
  				shape.preserveImageAspect = false;
  				return shape;
  			}
  			else if (index == mxEvent.ROTATION_HANDLE)
  			{
  				return new mxEllipse(bounds, fillColor || mxConstants.HANDLE_FILLCOLOR, mxConstants.HANDLE_STROKECOLOR);
  			}
  			else
  			{
  				return new mxRectangleShape(bounds, fillColor || mxConstants.HANDLE_FILLCOLOR, mxConstants.HANDLE_STROKECOLOR);
  			}
  		};
  		mxVertexHandler.prototype.moveSizerTo = function(shape, x, y)
  		{
  			if (shape != null)
  			{
  				shape.bounds.x = Math.floor(x - shape.bounds.width / 2);
  				shape.bounds.y = Math.floor(y - shape.bounds.height / 2);
  				if (shape.node != null && shape.node.style.display != 'none')
  				{
  					shape.redraw();
  				}
  			}
  		};
  		mxVertexHandler.prototype.getHandleForEvent = function(me)
  		{
  			var tol = (!mxEvent.isMouseEvent(me.getEvent())) ? this.tolerance : 1;
  			var hit = (this.allowHandleBoundsCheck && (mxClient.IS_IE || tol > 0)) ?
  				new mxRectangle(me.getGraphX() - tol, me.getGraphY() - tol, 2 * tol, 2 * tol) : null;
  			var checkShape = mxUtils.bind(this, function(shape)
  			{
  				var st = (shape != null && shape.constructor != mxImageShape &&
  					this.allowHandleBoundsCheck) ? shape.strokewidth + shape.svgStrokeTolerance : null;
  				var real = (st != null) ? new mxRectangle(me.getGraphX() - Math.floor(st / 2),
  					me.getGraphY() - Math.floor(st / 2), st, st) : hit;
  				return shape != null && (me.isSource(shape) || (real != null && mxUtils.intersects(shape.bounds, real) &&
  					shape.node.style.display != 'none' && shape.node.style.visibility != 'hidden'));
  			});
  			if (checkShape(this.rotationShape))
  			{
  				return mxEvent.ROTATION_HANDLE;
  			}
  			else if (checkShape(this.labelShape))
  			{
  				return mxEvent.LABEL_HANDLE;
  			}
  			if (this.sizers != null)
  			{
  				for (var i = 0; i < this.sizers.length; i++)
  				{
  					if (checkShape(this.sizers[i]))
  					{
  						return i;
  					}
  				}
  			}
  			if (this.customHandles != null && this.isCustomHandleEvent(me))
  			{
  				for (var i = this.customHandles.length - 1; i >= 0; i--)
  				{
  					if (checkShape(this.customHandles[i].shape))
  					{
  						return mxEvent.CUSTOM_HANDLE - i;
  					}
  				}
  			}
  			return null;
  		};
  		mxVertexHandler.prototype.isCustomHandleEvent = function(me)
  		{
  			return true;
  		};
  		mxVertexHandler.prototype.mouseDown = function(sender, me)
  		{
  			if (!me.isConsumed() && this.graph.isEnabled())
  			{
  				var handle = this.getHandleForEvent(me);
  				if (handle != null)
  				{
  					this.start(me.getGraphX(), me.getGraphY(), handle);
  					me.consume();
  				}
  			}
  		};
  		mxVertexHandler.prototype.isLivePreviewBorder = function()
  		{
  			return this.state.shape != null && this.state.shape.fill == null && this.state.shape.stroke == null;
  		};
  		mxVertexHandler.prototype.start = function(x, y, index)
  		{
  			if (this.selectionBorder != null)
  			{
  				this.livePreviewActive = this.livePreview && this.graph.model.getChildCount(this.state.cell) == 0;
  				this.inTolerance = true;
  				this.childOffsetX = 0;
  				this.childOffsetY = 0;
  				this.index = index;
  				this.startX = x;
  				this.startY = y;
  				if (this.index <= mxEvent.CUSTOM_HANDLE && this.isGhostPreview())
  				{
  					this.ghostPreview = this.createGhostPreview();
  				}
  				else
  				{
  					var model = this.state.view.graph.model;
  					var parent = model.getParent(this.state.cell);
  					if (this.state.view.currentRoot != parent && (model.isVertex(parent) || model.isEdge(parent)))
  					{
  						this.parentState = this.state.view.graph.view.getState(parent);
  					}
  					this.selectionBorder.node.style.display = (index == mxEvent.ROTATION_HANDLE) ? 'inline' : 'none';
  					if (!this.livePreviewActive || this.isLivePreviewBorder())
  					{
  						this.preview = this.createSelectionShape(this.bounds);
  						if (!(mxClient.IS_SVG && Number(this.state.style[mxConstants.STYLE_ROTATION] || '0') != 0) &&
  							this.state.text != null && this.state.text.node.parentNode == this.graph.container)
  						{
  							this.preview.dialect = mxConstants.DIALECT_STRICTHTML;
  							this.preview.init(this.graph.container);
  						}
  						else
  						{
  							this.preview.dialect = (this.graph.dialect != mxConstants.DIALECT_SVG) ?
  									mxConstants.DIALECT_VML : mxConstants.DIALECT_SVG;
  							this.preview.init(this.graph.view.getOverlayPane());
  						}
  					}
  					if (index == mxEvent.ROTATION_HANDLE)
  					{
  						var pos = this.getRotationHandlePosition();
  						var dx = pos.x - this.state.getCenterX();
  						var dy = pos.y - this.state.getCenterY();
  						this.startAngle = (dx != 0) ? Math.atan(dy / dx) * 180 / Math.PI + 90 : 0;
  						this.startDist = Math.sqrt(dx * dx + dy * dy);
  					}
  					if (this.livePreviewActive)
  					{
  						this.hideSizers();
  						if (index == mxEvent.ROTATION_HANDLE)
  						{
  							this.rotationShape.node.style.display = '';
  						}
  						else if (index == mxEvent.LABEL_HANDLE)
  						{
  							this.labelShape.node.style.display = '';
  						}
  						else if (this.sizers != null && this.sizers[index] != null)
  						{
  							this.sizers[index].node.style.display = '';
  						}
  						else if (index <= mxEvent.CUSTOM_HANDLE && this.customHandles != null)
  						{
  							this.customHandles[mxEvent.CUSTOM_HANDLE - index].setVisible(true);
  						}
  						var edges = this.graph.getEdges(this.state.cell);
  						this.edgeHandlers = [];
  						for (var i = 0; i < edges.length; i++)
  						{
  							var handler = this.graph.selectionCellsHandler.getHandler(edges[i]);
  							if (handler != null)
  							{
  								this.edgeHandlers.push(handler);
  							}
  						}
  					}
  				}
  			}
  		};
  		mxVertexHandler.prototype.createGhostPreview = function()
  		{
  			var shape = this.graph.cellRenderer.createShape(this.state);
  			shape.init(this.graph.view.getOverlayPane());
  			shape.scale = this.state.view.scale;
  			shape.bounds = this.bounds;
  			shape.outline = true;
  			return shape;
  		};
  		mxVertexHandler.prototype.setHandlesVisible = function(visible)
  		{
  			this.handlesVisible = visible;
  			if (this.sizers != null)
  			{
  				for (var i = 0; i < this.sizers.length; i++)
  				{
  					this.sizers[i].node.style.display = (visible) ? '' : 'none';
  				}
  			}
  			if (this.customHandles != null)
  			{
  				for (var i = 0; i < this.customHandles.length; i++)
  				{
  					this.customHandles[i].setVisible(visible);
  				}
  			}
  		};
  		mxVertexHandler.prototype.hideSizers = function()
  		{
  			this.setHandlesVisible(false);
  		};
  		mxVertexHandler.prototype.checkTolerance = function(me)
  		{
  			if (this.inTolerance && this.startX != null && this.startY != null)
  			{
  				if (mxEvent.isMouseEvent(me.getEvent()) ||
  					Math.abs(me.getGraphX() - this.startX) > this.graph.tolerance ||
  					Math.abs(me.getGraphY() - this.startY) > this.graph.tolerance)
  				{
  					this.inTolerance = false;
  				}
  			}
  		};
  		mxVertexHandler.prototype.updateHint = function(me) { };
  		mxVertexHandler.prototype.removeHint = function() { };
  		mxVertexHandler.prototype.roundAngle = function(angle)
  		{
  			return Math.round(angle * 10) / 10;
  		};
  		mxVertexHandler.prototype.roundLength = function(length)
  		{
  			return Math.round(length * 100) / 100;
  		};
  		mxVertexHandler.prototype.mouseMove = function(sender, me)
  		{
  			if (!me.isConsumed() && this.index != null)
  			{
  				this.checkTolerance(me);
  				if (!this.inTolerance)
  				{
  					if (this.index <= mxEvent.CUSTOM_HANDLE)
  					{
  						if (this.customHandles != null)
  						{
  							this.customHandles[mxEvent.CUSTOM_HANDLE - this.index].processEvent(me);
  							this.customHandles[mxEvent.CUSTOM_HANDLE - this.index].active = true;
  							if (this.ghostPreview != null)
  							{
  								this.ghostPreview.apply(this.state);
  								this.ghostPreview.strokewidth = this.getSelectionStrokeWidth() /
  									this.ghostPreview.scale / this.ghostPreview.scale;
  								this.ghostPreview.isDashed = this.isSelectionDashed();
  								this.ghostPreview.stroke = this.getSelectionColor();
  								this.ghostPreview.redraw();
  								if (this.selectionBounds != null)
  								{
  									this.selectionBorder.node.style.display = 'none';
  								}
  							}
  							else
  							{
  								if (this.movePreviewToFront)
  								{
  									this.moveToFront();
  								}
  								this.customHandles[mxEvent.CUSTOM_HANDLE - this.index].positionChanged();
  							}
  						}
  					}
  					else if (this.index == mxEvent.LABEL_HANDLE)
  					{
  						this.moveLabel(me);
  					}
  					else
  					{
  						if (this.index == mxEvent.ROTATION_HANDLE)
  						{
  							this.rotateVertex(me);
  						}
  						else
  						{
  							this.resizeVertex(me);
  						}
  						this.updateHint(me);
  					}
  				}
  				me.consume();
  			}
  			else if (!this.graph.isMouseDown && this.getHandleForEvent(me) != null)
  			{
  				me.consume(false);
  			}
  		};
  		mxVertexHandler.prototype.isGhostPreview = function()
  		{
  			return this.state.view.graph.model.getChildCount(this.state.cell) > 0;
  		};
  		mxVertexHandler.prototype.moveLabel = function(me)
  		{
  			var point = new mxPoint(me.getGraphX(), me.getGraphY());
  			var tr = this.graph.view.translate;
  			var scale = this.graph.view.scale;
  			if (this.graph.isGridEnabledEvent(me.getEvent()))
  			{
  				point.x = (this.graph.snap(point.x / scale - tr.x) + tr.x) * scale;
  				point.y = (this.graph.snap(point.y / scale - tr.y) + tr.y) * scale;
  			}
  			var index = (this.rotationShape != null) ? this.sizers.length - 2 : this.sizers.length - 1;
  			this.moveSizerTo(this.sizers[index], point.x, point.y);
  		};
  		mxVertexHandler.prototype.rotateVertex = function(me)
  		{
  			var point = new mxPoint(me.getGraphX(), me.getGraphY());
  			var dx = this.state.x + this.state.width / 2 - point.x;
  			var dy = this.state.y + this.state.height / 2 - point.y;
  			this.currentAlpha = (dx != 0) ? Math.atan(dy / dx) * 180 / Math.PI + 90 : ((dy < 0) ? 180 : 0);
  			if (dx > 0)
  			{
  				this.currentAlpha -= 180;
  			}
  			this.currentAlpha -= this.startAngle;
  			if (this.rotationRaster && this.graph.isGridEnabledEvent(me.getEvent()))
  			{
  				var dx = point.x - this.state.getCenterX();
  				var dy = point.y - this.state.getCenterY();
  				var dist = Math.sqrt(dx * dx + dy * dy);
  				if (dist - this.startDist < 2)
  				{
  					raster = 15;
  				}
  				else if (dist - this.startDist < 25)
  				{
  					raster = 5;
  				}
  				else
  				{
  					raster = 1;
  				}
  				this.currentAlpha = Math.round(this.currentAlpha / raster) * raster;
  			}
  			else
  			{
  				this.currentAlpha = this.roundAngle(this.currentAlpha);
  			}
  			this.selectionBorder.rotation = this.currentAlpha;
  			this.selectionBorder.redraw();
  			if (this.livePreviewActive)
  			{
  				this.redrawHandles();
  			}
  		};
  		mxVertexHandler.prototype.resizeVertex = function(me)
  		{
  			var ct = new mxPoint(this.state.getCenterX(), this.state.getCenterY());
  			var alpha = mxUtils.toRadians(this.state.style[mxConstants.STYLE_ROTATION] || '0');
  			var point = new mxPoint(me.getGraphX(), me.getGraphY());
  			var tr = this.graph.view.translate;
  			var scale = this.graph.view.scale;
  			var cos = Math.cos(-alpha);
  			var sin = Math.sin(-alpha);
  			var dx = point.x - this.startX;
  			var dy = point.y - this.startY;
  			var tx = cos * dx - sin * dy;
  			var ty = sin * dx + cos * dy;
  			dx = tx;
  			dy = ty;
  			var geo = this.graph.getCellGeometry(this.state.cell);
  			this.unscaledBounds = this.union(geo, dx / scale, dy / scale, this.index,
  				this.graph.isGridEnabledEvent(me.getEvent()), 1,
  				new mxPoint(0, 0), this.isConstrainedEvent(me),
  				this.isCenteredEvent(this.state, me));
  			if (!geo.relative)
  			{
  				var max = this.graph.getMaximumGraphBounds();
  				if (max != null && this.parentState != null)
  				{
  					max = mxRectangle.fromRectangle(max);
  					max.x -= (this.parentState.x - tr.x * scale) / scale;
  					max.y -= (this.parentState.y - tr.y * scale) / scale;
  				}
  				if (this.graph.isConstrainChild(this.state.cell))
  				{
  					var tmp = this.graph.getCellContainmentArea(this.state.cell);
  					if (tmp != null)
  					{
  						var overlap = this.graph.getOverlap(this.state.cell);
  						if (overlap > 0)
  						{
  							tmp = mxRectangle.fromRectangle(tmp);
  							tmp.x -= tmp.width * overlap;
  							tmp.y -= tmp.height * overlap;
  							tmp.width += 2 * tmp.width * overlap;
  							tmp.height += 2 * tmp.height * overlap;
  						}
  						if (max == null)
  						{
  							max = tmp;
  						}
  						else
  						{
  							max = mxRectangle.fromRectangle(max);
  							max.intersect(tmp);
  						}
  					}
  				}
  				if (max != null)
  				{
  					if (this.unscaledBounds.x < max.x)
  					{
  						this.unscaledBounds.width -= max.x - this.unscaledBounds.x;
  						this.unscaledBounds.x = max.x;
  					}
  					if (this.unscaledBounds.y < max.y)
  					{
  						this.unscaledBounds.height -= max.y - this.unscaledBounds.y;
  						this.unscaledBounds.y = max.y;
  					}
  					if (this.unscaledBounds.x + this.unscaledBounds.width > max.x + max.width)
  					{
  						this.unscaledBounds.width -= this.unscaledBounds.x +
  							this.unscaledBounds.width - max.x - max.width;
  					}
  					if (this.unscaledBounds.y + this.unscaledBounds.height > max.y + max.height)
  					{
  						this.unscaledBounds.height -= this.unscaledBounds.y +
  							this.unscaledBounds.height - max.y - max.height;
  					}
  				}
  			}
  			var old = this.bounds;
  			this.bounds = new mxRectangle(((this.parentState != null) ? this.parentState.x : tr.x * scale) +
  				(this.unscaledBounds.x) * scale, ((this.parentState != null) ? this.parentState.y : tr.y * scale) +
  				(this.unscaledBounds.y) * scale, this.unscaledBounds.width * scale, this.unscaledBounds.height * scale);
  			if (geo.relative && this.parentState != null)
  			{
  				this.bounds.x += this.state.x - this.parentState.x;
  				this.bounds.y += this.state.y - this.parentState.y;
  			}
  			cos = Math.cos(alpha);
  			sin = Math.sin(alpha);
  			var c2 = new mxPoint(this.bounds.getCenterX(), this.bounds.getCenterY());
  			var dx = c2.x - ct.x;
  			var dy = c2.y - ct.y;
  			var dx2 = cos * dx - sin * dy;
  			var dy2 = sin * dx + cos * dy;
  			var dx3 = dx2 - dx;
  			var dy3 = dy2 - dy;
  			var dx4 = this.bounds.x - this.state.x;
  			var dy4 = this.bounds.y - this.state.y;
  			var dx5 = cos * dx4 - sin * dy4;
  			var dy5 = sin * dx4 + cos * dy4;
  			this.bounds.x += dx3;
  			this.bounds.y += dy3;
  			this.unscaledBounds.x = this.roundLength(this.unscaledBounds.x + dx3 / scale);
  			this.unscaledBounds.y = this.roundLength(this.unscaledBounds.y + dy3 / scale);
  			this.unscaledBounds.width = this.roundLength(this.unscaledBounds.width);
  			this.unscaledBounds.height = this.roundLength(this.unscaledBounds.height);
  			if (!this.graph.isCellCollapsed(this.state.cell) && (dx3 != 0 || dy3 != 0))
  			{
  				this.childOffsetX = this.state.x - this.bounds.x + dx5;
  				this.childOffsetY = this.state.y - this.bounds.y + dy5;
  			}
  			else
  			{
  				this.childOffsetX = 0;
  				this.childOffsetY = 0;
  			}
  			if (!old.equals(this.bounds))
  			{
  				if (this.livePreviewActive)
  				{
  					this.updateLivePreview(me);
  				}
  				if (this.preview != null)
  				{
  					this.drawPreview();
  				}
  				else
  				{
  					this.updateParentHighlight();
  				}
  			}
  		};
  		mxVertexHandler.prototype.updateLivePreview = function(me)
  		{
  			var scale = this.graph.view.scale;
  			var tr = this.graph.view.translate;
  			var tempState = this.state.clone();
  			this.state.x = this.bounds.x;
  			this.state.y = this.bounds.y;
  			this.state.origin = new mxPoint(this.state.x / scale - tr.x, this.state.y / scale - tr.y);
  			this.state.width = this.bounds.width;
  			this.state.height = this.bounds.height;
  			var off = this.state.absoluteOffset;
  			off = new mxPoint(off.x, off.y);
  			this.state.absoluteOffset.x = 0;
  			this.state.absoluteOffset.y = 0;
  			var geo = this.graph.getCellGeometry(this.state.cell);
  			if (geo != null)
  			{
  				var offset = geo.offset || this.EMPTY_POINT;
  				if (offset != null && !geo.relative)
  				{
  					this.state.absoluteOffset.x = this.state.view.scale * offset.x;
  					this.state.absoluteOffset.y = this.state.view.scale * offset.y;
  				}
  				this.state.view.updateVertexLabelOffset(this.state);
  			}
  			this.state.view.graph.cellRenderer.redraw(this.state, true);
  			this.state.view.invalidate(this.state.cell);
  			this.state.invalid = false;
  			this.state.view.validate();
  			this.redrawHandles();
  			if (this.movePreviewToFront)
  			{
  				this.moveToFront();
  			}
  			if (this.state.control != null && this.state.control.node != null)
  			{
  				this.state.control.node.style.visibility = 'hidden';
  			}
  			this.state.setState(tempState);
  		};
  		mxVertexHandler.prototype.moveToFront = function()
  		{
  			if ((this.state.text != null && this.state.text.node != null &&
  				this.state.text.node.nextSibling != null) ||
  				(this.state.shape != null && this.state.shape.node != null &&
  				this.state.shape.node.nextSibling != null && (this.state.text == null ||
  				this.state.shape.node.nextSibling != this.state.text.node)))
  			{
  				if (this.state.shape != null && this.state.shape.node != null)
  				{
  					this.state.shape.node.parentNode.appendChild(this.state.shape.node);
  				}
  				if (this.state.text != null && this.state.text.node != null)
  				{
  					this.state.text.node.parentNode.appendChild(this.state.text.node);
  				}
  			}
  		};
  		mxVertexHandler.prototype.mouseUp = function(sender, me)
  		{
  			if (this.index != null && this.state != null)
  			{
  				var point = new mxPoint(me.getGraphX(), me.getGraphY());
  				var index = this.index;
  				this.index = null;
  				if (this.ghostPreview == null)
  				{
  					this.state.view.invalidate(this.state.cell, false, false);
  					this.state.view.validate();
  				}
  				this.graph.getModel().beginUpdate();
  				try
  				{
  					if (index <= mxEvent.CUSTOM_HANDLE)
  					{
  						if (this.customHandles != null)
  						{
  							var style = this.state.view.graph.getCellStyle(this.state.cell);
  							this.customHandles[mxEvent.CUSTOM_HANDLE - index].active = false;
  							this.customHandles[mxEvent.CUSTOM_HANDLE - index].execute(me);
  							if (this.customHandles != null &&
  								this.customHandles[mxEvent.CUSTOM_HANDLE - index] != null)
  							{
  								this.state.style = style;
  								this.customHandles[mxEvent.CUSTOM_HANDLE - index].positionChanged();
  							}
  						}
  					}
  					else if (index == mxEvent.ROTATION_HANDLE)
  					{
  						if (this.currentAlpha != null)
  						{
  							var delta = this.currentAlpha - (this.state.style[mxConstants.STYLE_ROTATION] || 0);
  							if (delta != 0)
  							{
  								this.rotateCell(this.state.cell, delta);
  							}
  						}
  						else
  						{
  							this.rotateClick();
  						}
  					}
  					else
  					{
  						var gridEnabled = this.graph.isGridEnabledEvent(me.getEvent());
  						var alpha = mxUtils.toRadians(this.state.style[mxConstants.STYLE_ROTATION] || '0');
  						var cos = Math.cos(-alpha);
  						var sin = Math.sin(-alpha);
  						var dx = point.x - this.startX;
  						var dy = point.y - this.startY;
  						var tx = cos * dx - sin * dy;
  						var ty = sin * dx + cos * dy;
  						dx = tx;
  						dy = ty;
  						var s = this.graph.view.scale;
  						var recurse = this.isRecursiveResize(this.state, me);
  						this.resizeCell(this.state.cell, this.roundLength(dx / s), this.roundLength(dy / s),
  							index, gridEnabled, this.isConstrainedEvent(me), recurse);
  					}
  				}
  				finally
  				{
  					this.graph.getModel().endUpdate();
  				}
  				me.consume();
  				this.reset();
  				this.redrawHandles();
  			}
  		};
  		mxVertexHandler.prototype.isRecursiveResize = function(state, me)
  		{
  			return this.graph.isRecursiveResize(this.state);
  		};
  		mxVertexHandler.prototype.rotateClick = function() { };
  		mxVertexHandler.prototype.rotateCell = function(cell, angle, parent)
  		{
  			if (angle != 0)
  			{
  				var model = this.graph.getModel();
  				if (model.isVertex(cell) || model.isEdge(cell))
  				{
  					if (!model.isEdge(cell))
  					{
  						var style = this.graph.getCurrentCellStyle(cell);
  						var total = (style[mxConstants.STYLE_ROTATION] || 0) + angle;
  						this.graph.setCellStyles(mxConstants.STYLE_ROTATION, total, [cell]);
  					}
  					var geo = this.graph.getCellGeometry(cell);
  					if (geo != null)
  					{
  						var pgeo = this.graph.getCellGeometry(parent);
  						if (pgeo != null && !model.isEdge(parent))
  						{
  							geo = geo.clone();
  							geo.rotate(angle, new mxPoint(pgeo.width / 2, pgeo.height / 2));
  							model.setGeometry(cell, geo);
  						}
  						if ((model.isVertex(cell) && !geo.relative) || model.isEdge(cell))
  						{
  							var childCount = model.getChildCount(cell);
  							for (var i = 0; i < childCount; i++)
  							{
  								this.rotateCell(model.getChildAt(cell, i), angle, cell);
  							}
  						}
  					}
  				}
  			}
  		};
  		mxVertexHandler.prototype.reset = function()
  		{
  			if (this.sizers != null && this.index != null && this.sizers[this.index] != null &&
  				this.sizers[this.index].node.style.display == 'none')
  			{
  				this.sizers[this.index].node.style.display = '';
  			}
  			this.currentAlpha = null;
  			this.inTolerance = null;
  			this.index = null;
  			if (this.preview != null)
  			{
  				this.preview.destroy();
  				this.preview = null;
  			}
  			if (this.ghostPreview != null)
  			{
  				this.ghostPreview.destroy();
  				this.ghostPreview = null;
  			}
  			if (this.livePreviewActive && this.sizers != null)
  			{
  				for (var i = 0; i < this.sizers.length; i++)
  				{
  					if (this.sizers[i] != null)
  					{
  						this.sizers[i].node.style.display = '';
  					}
  				}
  				if (this.state.control != null && this.state.control.node != null)
  				{
  					this.state.control.node.style.visibility = '';
  				}
  			}
  			if (this.customHandles != null)
  			{
  				for (var i = 0; i < this.customHandles.length; i++)
  				{
  					if (this.customHandles[i].active)
  					{
  						this.customHandles[i].active = false;
  						this.customHandles[i].reset();
  					}
  					else
  					{
  						this.customHandles[i].setVisible(true);
  					}
  				}
  			}
  			if (this.selectionBorder != null)
  			{
  				this.selectionBorder.node.style.display = 'inline';
  				this.selectionBounds = this.getSelectionBounds(this.state);
  				this.bounds = new mxRectangle(this.selectionBounds.x, this.selectionBounds.y,
  					this.selectionBounds.width, this.selectionBounds.height);
  				this.drawPreview();
  			}
  			this.removeHint();
  			this.redrawHandles();
  			this.edgeHandlers = null;
  			this.handlesVisible = true;
  			this.unscaledBounds = null;
  			this.livePreviewActive = null;
  		};
  		mxVertexHandler.prototype.resizeCell = function(cell, dx, dy, index, gridEnabled, constrained, recurse)
  		{
  			var geo = this.graph.model.getGeometry(cell);
  			if (geo != null)
  			{
  				if (index == mxEvent.LABEL_HANDLE)
  				{
  					var alpha = -mxUtils.toRadians(this.state.style[mxConstants.STYLE_ROTATION] || '0');
  					var cos = Math.cos(alpha);
  					var sin = Math.sin(alpha);
  					var scale = this.graph.view.scale;
  					var pt = mxUtils.getRotatedPoint(new mxPoint(
  						Math.round((this.labelShape.bounds.getCenterX() - this.startX) / scale),
  						Math.round((this.labelShape.bounds.getCenterY() - this.startY) / scale)),
  						cos, sin);
  					geo = geo.clone();
  					if (geo.offset == null)
  					{
  						geo.offset = pt;
  					}
  					else
  					{
  						geo.offset.x += pt.x;
  						geo.offset.y += pt.y;
  					}
  					this.graph.model.setGeometry(cell, geo);
  				}
  				else if (this.unscaledBounds != null)
  				{
  					var scale = this.graph.view.scale;
  					if (this.childOffsetX != 0 || this.childOffsetY != 0)
  					{
  						this.moveChildren(cell, Math.round(this.childOffsetX / scale), Math.round(this.childOffsetY / scale));
  					}
  					this.graph.resizeCell(cell, this.unscaledBounds, recurse);
  				}
  			}
  		};
  		mxVertexHandler.prototype.moveChildren = function(cell, dx, dy)
  		{
  			var model = this.graph.getModel();
  			var childCount = model.getChildCount(cell);
  			for (var i = 0; i < childCount; i++)
  			{
  				var child = model.getChildAt(cell, i);
  				var geo = this.graph.getCellGeometry(child);
  				if (geo != null)
  				{
  					geo = geo.clone();
  					geo.translate(dx, dy);
  					model.setGeometry(child, geo);
  				}
  			}
  		};
  		mxVertexHandler.prototype.union = function(bounds, dx, dy, index, gridEnabled, scale, tr, constrained, centered)
  		{
  			gridEnabled = (gridEnabled != null) ? gridEnabled && this.graph.gridEnabled : this.graph.gridEnabled;
  			if (this.singleSizer)
  			{
  				var x = bounds.x + bounds.width + dx;
  				var y = bounds.y + bounds.height + dy;
  				if (gridEnabled)
  				{
  					x = this.graph.snap(x / scale) * scale;
  					y = this.graph.snap(y / scale) * scale;
  				}
  				var rect = new mxRectangle(bounds.x, bounds.y, 0, 0);
  				rect.add(new mxRectangle(x, y, 0, 0));
  				return rect;
  			}
  			else
  			{
  				var w0 = bounds.width;
  				var h0 = bounds.height;
  				var left = bounds.x - tr.x * scale;
  				var right = left + w0;
  				var top = bounds.y - tr.y * scale;
  				var bottom = top + h0;
  				var cx = left + w0 / 2;
  				var cy = top + h0 / 2;
  				if (index > 4 )
  				{
  					bottom = bottom + dy;
  					if (gridEnabled)
  					{
  						bottom = this.graph.snap(bottom / scale) * scale;
  					}
  					else
  					{
  						bottom = Math.round(bottom / scale) * scale;
  					}
  				}
  				else if (index < 3 )
  				{
  					top = top + dy;
  					if (gridEnabled)
  					{
  						top = this.graph.snap(top / scale) * scale;
  					}
  					else
  					{
  						top = Math.round(top / scale) * scale;
  					}
  				}
  				if (index == 0 || index == 3 || index == 5 )
  				{
  					left += dx;
  					if (gridEnabled)
  					{
  						left = this.graph.snap(left / scale) * scale;
  					}
  					else
  					{
  						left = Math.round(left / scale) * scale;
  					}
  				}
  				else if (index == 2 || index == 4 || index == 7 )
  				{
  					right += dx;
  					if (gridEnabled)
  					{
  						right = this.graph.snap(right / scale) * scale;
  					}
  					else
  					{
  						right = Math.round(right / scale) * scale;
  					}
  				}
  				var width = right - left;
  				var height = bottom - top;
  				if (constrained)
  				{
  					var geo = this.graph.getCellGeometry(this.state.cell);
  					if (geo != null)
  					{
  						var aspect = geo.width / geo.height;
  						if (index== 1 || index== 2 || index == 7 || index == 6)
  						{
  							width = height * aspect;
  						}
  						else
  						{
  							height = width / aspect;
  						}
  						if (index == 0)
  						{
  							left = right - width;
  							top = bottom - height;
  						}
  					}
  				}
  				if (centered)
  				{
  					width += (width - w0);
  					height += (height - h0);
  					var cdx = cx - (left + width / 2);
  					var cdy = cy - (top + height / 2);
  					left += cdx;
  					top += cdy;
  					right += cdx;
  					bottom += cdy;
  				}
  				if (width < 0)
  				{
  					left += width;
  					width = Math.abs(width);
  				}
  				if (height < 0)
  				{
  					top += height;
  					height = Math.abs(height);
  				}
  				var result = new mxRectangle(left + tr.x * scale, top + tr.y * scale, width, height);
  				if (this.minBounds != null)
  				{
  					result.width = Math.max(result.width, this.minBounds.x * scale + this.minBounds.width * scale +
  						Math.max(0, this.x0 * scale - result.x));
  					result.height = Math.max(result.height, this.minBounds.y * scale + this.minBounds.height * scale +
  						Math.max(0, this.y0 * scale - result.y));
  				}
  				return result;
  			}
  		};
  		mxVertexHandler.prototype.redraw = function(ignoreHandles)
  		{
  			this.selectionBounds = this.getSelectionBounds(this.state);
  			this.bounds = new mxRectangle(this.selectionBounds.x, this.selectionBounds.y,
  				this.selectionBounds.width, this.selectionBounds.height);
  			this.drawPreview();
  			if (!ignoreHandles)
  			{
  				this.redrawHandles();
  			}
  		};
  		mxVertexHandler.prototype.getHandlePadding = function()
  		{
  			var result = new mxPoint(0, 0);
  			var tol = this.tolerance;
  			if (this.sizers != null && this.sizers.length > 0 && this.sizers[0] != null &&
  				(this.bounds.width < 2 * this.sizers[0].bounds.width + 2 * tol ||
  				this.bounds.height < 2 * this.sizers[0].bounds.height + 2 * tol))
  			{
  				tol /= 2;
  				result.x = this.sizers[0].bounds.width + tol;
  				result.y = this.sizers[0].bounds.height + tol;
  			}
  			return result;
  		};
  		mxVertexHandler.prototype.getSizerBounds = function()
  		{
  			return this.bounds;
  		};
  		mxVertexHandler.prototype.redrawHandles = function()
  		{
  			var s = this.getSizerBounds();
  			var tol = this.tolerance;
  			this.horizontalOffset = 0;
  			this.verticalOffset = 0;
  			if (this.customHandles != null)
  			{
  				for (var i = 0; i < this.customHandles.length; i++)
  				{
  					var temp = this.customHandles[i].shape.node.style.display;
  					this.customHandles[i].redraw();
  					this.customHandles[i].shape.node.style.display = temp;
  					this.customHandles[i].shape.node.style.visibility =
  						(this.handlesVisible && this.isCustomHandleVisible(
  							this.customHandles[i])) ? '' : 'hidden';
  				}
  			}
  			if (this.sizers != null && this.sizers.length > 0 && this.sizers[0] != null)
  			{
  				if (this.index == null && this.manageSizers && this.sizers.length >= 8)
  				{
  					var padding = this.getHandlePadding();
  					this.horizontalOffset = padding.x;
  					this.verticalOffset = padding.y;
  					if (this.horizontalOffset != 0 || this.verticalOffset != 0)
  					{
  						s = new mxRectangle(s.x, s.y, s.width, s.height);
  						s.x -= this.horizontalOffset / 2;
  						s.width += this.horizontalOffset;
  						s.y -= this.verticalOffset / 2;
  						s.height += this.verticalOffset;
  					}
  					if (this.sizers.length >= 8)
  					{
  						if ((s.width < 2 * this.sizers[0].bounds.width + 2 * tol) ||
  							(s.height < 2 * this.sizers[0].bounds.height + 2 * tol))
  						{
  							this.sizers[0].node.style.display = 'none';
  							this.sizers[2].node.style.display = 'none';
  							this.sizers[5].node.style.display = 'none';
  							this.sizers[7].node.style.display = 'none';
  						}
  						else if (this.handlesVisible)
  						{
  							this.sizers[0].node.style.display = '';
  							this.sizers[2].node.style.display = '';
  							this.sizers[5].node.style.display = '';
  							this.sizers[7].node.style.display = '';
  						}
  					}
  				}
  				var r = s.x + s.width;
  				var b = s.y + s.height;
  				if (this.singleSizer)
  				{
  					this.moveSizerTo(this.sizers[0], r, b);
  				}
  				else
  				{
  					var cx = s.x + s.width / 2;
  					var cy = s.y + s.height / 2;
  					if (this.sizers.length >= 8)
  					{
  						var crs = ['nw-resize', 'n-resize', 'ne-resize', 'e-resize', 'se-resize', 's-resize', 'sw-resize', 'w-resize'];
  						var alpha = mxUtils.toRadians(this.state.style[mxConstants.STYLE_ROTATION] || '0');
  						var cos = Math.cos(alpha);
  						var sin = Math.sin(alpha);
  						var da = Math.round(alpha * 4 / Math.PI);
  						var ct = new mxPoint(s.getCenterX(), s.getCenterY());
  						var pt = mxUtils.getRotatedPoint(new mxPoint(s.x, s.y), cos, sin, ct);
  						this.moveSizerTo(this.sizers[0], pt.x, pt.y);
  						this.sizers[0].setCursor(crs[mxUtils.mod(0 + da, crs.length)]);
  						pt.x = cx;
  						pt.y = s.y;
  						pt = mxUtils.getRotatedPoint(pt, cos, sin, ct);
  						this.moveSizerTo(this.sizers[1], pt.x, pt.y);
  						this.sizers[1].setCursor(crs[mxUtils.mod(1 + da, crs.length)]);
  						pt.x = r;
  						pt.y = s.y;
  						pt = mxUtils.getRotatedPoint(pt, cos, sin, ct);
  						this.moveSizerTo(this.sizers[2], pt.x, pt.y);
  						this.sizers[2].setCursor(crs[mxUtils.mod(2 + da, crs.length)]);
  						pt.x = s.x;
  						pt.y = cy;
  						pt = mxUtils.getRotatedPoint(pt, cos, sin, ct);
  						this.moveSizerTo(this.sizers[3], pt.x, pt.y);
  						this.sizers[3].setCursor(crs[mxUtils.mod(7 + da, crs.length)]);
  						pt.x = r;
  						pt.y = cy;
  						pt = mxUtils.getRotatedPoint(pt, cos, sin, ct);
  						this.moveSizerTo(this.sizers[4], pt.x, pt.y);
  						this.sizers[4].setCursor(crs[mxUtils.mod(3 + da, crs.length)]);
  						pt.x = s.x;
  						pt.y = b;
  						pt = mxUtils.getRotatedPoint(pt, cos, sin, ct);
  						this.moveSizerTo(this.sizers[5], pt.x, pt.y);
  						this.sizers[5].setCursor(crs[mxUtils.mod(6 + da, crs.length)]);
  						pt.x = cx;
  						pt.y = b;
  						pt = mxUtils.getRotatedPoint(pt, cos, sin, ct);
  						this.moveSizerTo(this.sizers[6], pt.x, pt.y);
  						this.sizers[6].setCursor(crs[mxUtils.mod(5 + da, crs.length)]);
  						pt.x = r;
  						pt.y = b;
  						pt = mxUtils.getRotatedPoint(pt, cos, sin, ct);
  						this.moveSizerTo(this.sizers[7], pt.x, pt.y);
  						this.sizers[7].setCursor(crs[mxUtils.mod(4 + da, crs.length)]);
  						pt.x = cx + this.state.absoluteOffset.x;
  						pt.y = cy + this.state.absoluteOffset.y;
  						pt = mxUtils.getRotatedPoint(pt, cos, sin, ct);
  						this.moveSizerTo(this.sizers[8], pt.x, pt.y);
  					}
  					else if (this.state.width >= 2 && this.state.height >= 2)
  					{
  						this.moveSizerTo(this.sizers[0], cx + this.state.absoluteOffset.x, cy + this.state.absoluteOffset.y);
  					}
  					else
  					{
  						this.moveSizerTo(this.sizers[0], this.state.x, this.state.y);
  					}
  				}
  			}
  			if (this.rotationShape != null)
  			{
  				var alpha = mxUtils.toRadians((this.currentAlpha != null) ? this.currentAlpha : this.state.style[mxConstants.STYLE_ROTATION] || '0');
  				var cos = Math.cos(alpha);
  				var sin = Math.sin(alpha);
  				var ct = new mxPoint(this.state.getCenterX(), this.state.getCenterY());
  				var pt = mxUtils.getRotatedPoint(this.getRotationHandlePosition(), cos, sin, ct);
  				if (this.rotationShape.node != null)
  				{
  					this.moveSizerTo(this.rotationShape, pt.x, pt.y);
  					this.rotationShape.node.style.visibility = (this.state.view.graph.isEditing() ||
  						!this.handlesVisible) ? 'hidden' : '';
  				}
  			}
  			if (this.selectionBorder != null)
  			{
  				this.selectionBorder.rotation = Number(this.state.style[mxConstants.STYLE_ROTATION] || '0');
  			}
  			if (this.edgeHandlers != null)
  			{
  				for (var i = 0; i < this.edgeHandlers.length; i++)
  				{
  					this.edgeHandlers[i].redraw();
  				}
  			}
  		};
  		mxVertexHandler.prototype.isCustomHandleVisible = function(handle)
  		{
  			return !this.graph.isEditing() && this.state.view.graph.getSelectionCount() == 1;
  		};
  		mxVertexHandler.prototype.getRotationHandlePosition = function()
  		{
  			return new mxPoint(this.bounds.x + this.bounds.width / 2, this.bounds.y + this.rotationHandleVSpacing)
  		};
  		mxVertexHandler.prototype.isParentHighlightVisible = function()
  		{
  			return !this.graph.isCellSelected(this.graph.model.getParent(this.state.cell));
  		};
  		mxVertexHandler.prototype.updateParentHighlight = function()
  		{
  			if (!this.isDestroyed())
  			{
  				var visible = this.isParentHighlightVisible();
  				var parent = this.graph.model.getParent(this.state.cell);
  				var pstate = this.graph.view.getState(parent);
  				if (this.parentHighlight != null)
  				{
  					if (this.graph.model.isVertex(parent) && visible)
  					{
  						var b = this.parentHighlight.bounds;
  						if (pstate != null && (b.x != pstate.x || b.y != pstate.y ||
  							b.width != pstate.width || b.height != pstate.height))
  						{
  							this.parentHighlight.bounds = mxRectangle.fromRectangle(pstate);
  							this.parentHighlight.redraw();
  						}
  					}
  					else
  					{
  						if (pstate != null && pstate.parentHighlight == this.parentHighlight)
  						{
  							pstate.parentHighlight = null;
  						}
  						this.parentHighlight.destroy();
  						this.parentHighlight = null;
  					}
  				}
  				else if (this.parentHighlightEnabled && visible)
  				{
  					if (this.graph.model.isVertex(parent) && pstate != null &&
  						pstate.parentHighlight == null)
  					{
  						this.parentHighlight = this.createParentHighlightShape(pstate);
  						this.parentHighlight.dialect = (this.graph.dialect != mxConstants.DIALECT_SVG) ? mxConstants.DIALECT_VML : mxConstants.DIALECT_SVG;
  						this.parentHighlight.pointerEvents = false;
  						this.parentHighlight.rotation = Number(pstate.style[mxConstants.STYLE_ROTATION] || '0');
  						this.parentHighlight.init(this.graph.getView().getOverlayPane());
  						this.parentHighlight.redraw();
  						pstate.parentHighlight = this.parentHighlight;
  					}
  				}
  			}
  		};
  		mxVertexHandler.prototype.drawPreview = function()
  		{
  			if (this.preview != null)
  			{
  				this.preview.bounds = this.bounds;
  				if (this.preview.node.parentNode == this.graph.container)
  				{
  					this.preview.bounds.width = Math.max(0, this.preview.bounds.width - 1);
  					this.preview.bounds.height = Math.max(0, this.preview.bounds.height - 1);
  				}
  				this.preview.rotation = Number(this.state.style[mxConstants.STYLE_ROTATION] || '0');
  				this.preview.redraw();
  			}
  			this.selectionBorder.bounds = this.getSelectionBorderBounds();
  			this.selectionBorder.redraw();
  			this.updateParentHighlight();
  		};
  		mxVertexHandler.prototype.getSelectionBorderBounds = function()
  		{
  			return this.bounds;
  		};
  		mxVertexHandler.prototype.isDestroyed = function()
  		{
  			return this.selectionBorder == null;
  		};
  		mxVertexHandler.prototype.destroy = function()
  		{
  			if (this.escapeHandler != null)
  			{
  				this.state.view.graph.removeListener(this.escapeHandler);
  				this.escapeHandler = null;
  			}
  			if (this.preview != null)
  			{
  				this.preview.destroy();
  				this.preview = null;
  			}
  			if (this.parentHighlight != null)
  			{
  				var parent = this.graph.model.getParent(this.state.cell);
  				var pstate = this.graph.view.getState(parent);
  				if (pstate != null && pstate.parentHighlight == this.parentHighlight)
  				{
  					pstate.parentHighlight = null;
  				}
  				this.parentHighlight.destroy();
  				this.parentHighlight = null;
  			}
  			if (this.ghostPreview != null)
  			{
  				this.ghostPreview.destroy();
  				this.ghostPreview = null;
  			}
  			if (this.selectionBorder != null)
  			{
  				this.selectionBorder.destroy();
  				this.selectionBorder = null;
  			}
  			this.labelShape = null;
  			this.removeHint();
  			if (this.sizers != null)
  			{
  				for (var i = 0; i < this.sizers.length; i++)
  				{
  					this.sizers[i].destroy();
  				}
  				this.sizers = null;
  			}
  			if (this.customHandles != null)
  			{
  				for (var i = 0; i < this.customHandles.length; i++)
  				{
  					this.customHandles[i].destroy();
  				}
  				this.customHandles = null;
  			}
  		};
  		__mxOutput.mxVertexHandler = typeof mxVertexHandler !== 'undefined' ? mxVertexHandler : undefined;
  		function mxEdgeHandler(state)
  		{
  			if (state != null && state.shape != null)
  			{
  				this.state = state;
  				this.init();
  				this.escapeHandler = mxUtils.bind(this, function(sender, evt)
  				{
  					var dirty = this.index != null;
  					this.reset();
  					if (dirty)
  					{
  						this.graph.cellRenderer.redraw(this.state, false, state.view.isRendering());
  					}
  				});
  				this.state.view.graph.addListener(mxEvent.ESCAPE, this.escapeHandler);
  			}
  		}		mxEdgeHandler.prototype.graph = null;
  		mxEdgeHandler.prototype.state = null;
  		mxEdgeHandler.prototype.marker = null;
  		mxEdgeHandler.prototype.constraintHandler = null;
  		mxEdgeHandler.prototype.error = null;
  		mxEdgeHandler.prototype.shape = null;
  		mxEdgeHandler.prototype.bends = null;
  		mxEdgeHandler.prototype.labelShape = null;
  		mxEdgeHandler.prototype.cloneEnabled = true;
  		mxEdgeHandler.prototype.addEnabled = false;
  		mxEdgeHandler.prototype.removeEnabled = false;
  		mxEdgeHandler.prototype.dblClickRemoveEnabled = false;
  		mxEdgeHandler.prototype.mergeRemoveEnabled = false;
  		mxEdgeHandler.prototype.straightRemoveEnabled = false;
  		mxEdgeHandler.prototype.virtualBendsEnabled = false;
  		mxEdgeHandler.prototype.virtualBendOpacity = 20;
  		mxEdgeHandler.prototype.parentHighlightEnabled = false;
  		mxEdgeHandler.prototype.preferHtml = false;
  		mxEdgeHandler.prototype.allowHandleBoundsCheck = true;
  		mxEdgeHandler.prototype.snapToTerminals = false;
  		mxEdgeHandler.prototype.handleImage = null;
  		mxEdgeHandler.prototype.tolerance = 0;
  		mxEdgeHandler.prototype.outlineConnect = false;
  		mxEdgeHandler.prototype.manageLabelHandle = false;
  		mxEdgeHandler.prototype.init = function()
  		{
  			this.graph = this.state.view.graph;
  			this.marker = this.createMarker();
  			this.constraintHandler = new mxConstraintHandler(this.graph);
  			this.points = [];
  			this.abspoints = this.getSelectionPoints(this.state);
  			this.shape = this.createSelectionShape(this.abspoints);
  			this.shape.dialect = (this.graph.dialect != mxConstants.DIALECT_SVG) ?
  				mxConstants.DIALECT_MIXEDHTML : mxConstants.DIALECT_SVG;
  			this.shape.init(this.graph.getView().getOverlayPane());
  			this.shape.pointerEvents = false;
  			this.shape.setCursor(mxConstants.CURSOR_MOVABLE_EDGE);
  			mxEvent.redirectMouseEvents(this.shape.node, this.graph, this.state);
  			this.preferHtml = this.state.text != null &&
  				this.state.text.node.parentNode == this.graph.container;
  			if (!this.preferHtml)
  			{
  				var sourceState = this.state.getVisibleTerminalState(true);
  				if (sourceState != null)
  				{
  					this.preferHtml = sourceState.text != null &&
  						sourceState.text.node.parentNode == this.graph.container;
  				}
  				if (!this.preferHtml)
  				{
  					var targetState = this.state.getVisibleTerminalState(false);
  					if (targetState != null)
  					{
  						this.preferHtml = targetState.text != null &&
  						targetState.text.node.parentNode == this.graph.container;
  					}
  				}
  			}
  			if (this.graph.getSelectionCount() < mxGraphHandler.prototype.maxCells ||
  				mxGraphHandler.prototype.maxCells <= 0)
  			{
  				this.bends = this.createBends();
  				if (this.isVirtualBendsEnabled())
  				{
  					this.virtualBends = this.createVirtualBends();
  				}
  			}
  			this.label = new mxPoint(this.state.absoluteOffset.x, this.state.absoluteOffset.y);
  			this.labelShape = this.createLabelHandleShape();
  			this.initBend(this.labelShape);
  			this.labelShape.setCursor(mxConstants.CURSOR_LABEL_HANDLE);
  			this.customHandles = this.createCustomHandles();
  			this.updateParentHighlight();
  			this.redraw();
  		};
  		mxEdgeHandler.prototype.isParentHighlightVisible = mxVertexHandler.prototype.isParentHighlightVisible;
  		mxEdgeHandler.prototype.updateParentHighlight = mxVertexHandler.prototype.updateParentHighlight;
  		mxEdgeHandler.prototype.createCustomHandles = function()
  		{
  			return null;
  		};
  		mxEdgeHandler.prototype.isVirtualBendsEnabled = function(evt)
  		{
  			return this.virtualBendsEnabled && (this.state.style[mxConstants.STYLE_EDGE] == null ||
  					this.state.style[mxConstants.STYLE_EDGE] == mxConstants.NONE ||
  					this.state.style[mxConstants.STYLE_NOEDGESTYLE] == 1)  &&
  					mxUtils.getValue(this.state.style, mxConstants.STYLE_SHAPE, null) != 'arrow';
  		};
  		mxEdgeHandler.prototype.isCellEnabled = function(cell)
  		{
  			return true;
  		};
  		mxEdgeHandler.prototype.isAddPointEvent = function(evt)
  		{
  			return mxEvent.isShiftDown(evt);
  		};
  		mxEdgeHandler.prototype.isRemovePointEvent = function(evt)
  		{
  			return mxEvent.isShiftDown(evt);
  		};
  		mxEdgeHandler.prototype.getSelectionPoints = function(state)
  		{
  			return state.absolutePoints;
  		};
  		mxEdgeHandler.prototype.createParentHighlightShape = function(bounds)
  		{
  			var shape = new mxRectangleShape(mxRectangle.fromRectangle(bounds),
  				null, this.getSelectionColor());
  			shape.strokewidth = this.getSelectionStrokeWidth();
  			shape.isDashed = this.isSelectionDashed();
  			return shape;
  		};
  		mxEdgeHandler.prototype.createSelectionShape = function(points)
  		{
  			var shape = new this.state.shape.constructor();
  			shape.outline = true;
  			shape.apply(this.state);
  			shape.isDashed = this.isSelectionDashed();
  			shape.stroke = this.getSelectionColor();
  			shape.isShadow = false;
  			return shape;
  		};
  		mxEdgeHandler.prototype.getSelectionColor = function()
  		{
  			return mxConstants.EDGE_SELECTION_COLOR;
  		};
  		mxEdgeHandler.prototype.getSelectionStrokeWidth = function()
  		{
  			return mxConstants.EDGE_SELECTION_STROKEWIDTH;
  		};
  		mxEdgeHandler.prototype.isSelectionDashed = function()
  		{
  			return mxConstants.EDGE_SELECTION_DASHED;
  		};
  		mxEdgeHandler.prototype.isConnectableCell = function(cell)
  		{
  			return true;
  		};
  		mxEdgeHandler.prototype.getCellAt = function(x, y)
  		{
  			return (!this.outlineConnect) ? this.graph.getCellAt(x, y) : null;
  		};
  		mxEdgeHandler.prototype.createMarker = function()
  		{
  			var marker = new mxCellMarker(this.graph);
  			var self = this;
  			marker.getCell = function(me)
  			{
  				var cell = mxCellMarker.prototype.getCell.apply(this, arguments);
  				if ((cell == self.state.cell || cell == null) && self.currentPoint != null)
  				{
  					cell = self.graph.getCellAt(self.currentPoint.x, self.currentPoint.y);
  				}
  				if (cell != null && !this.graph.isCellConnectable(cell))
  				{
  					var parent = this.graph.getModel().getParent(cell);
  					if (this.graph.getModel().isVertex(parent) && this.graph.isCellConnectable(parent))
  					{
  						cell = parent;
  					}
  				}
  				var model = self.graph.getModel();
  				if ((this.graph.isSwimlane(cell) && self.currentPoint != null &&
  					this.graph.hitsSwimlaneContent(cell, self.currentPoint.x, self.currentPoint.y)) ||
  					(!self.isConnectableCell(cell)) || (cell == self.state.cell ||
  					(cell != null && !self.graph.connectableEdges && model.isEdge(cell))) ||
  					model.isAncestor(self.state.cell, cell))
  				{
  					cell = null;
  				}
  				if (!this.graph.isCellConnectable(cell))
  				{
  					cell = null;
  				}
  				return cell;
  			};
  			marker.isValidState = function(state)
  			{
  				var model = self.graph.getModel();
  				var other = self.graph.view.getTerminalPort(state,
  					self.graph.view.getState(model.getTerminal(self.state.cell,
  					!self.isSource)), !self.isSource);
  				var otherCell = (other != null) ? other.cell : null;
  				var source = (self.isSource) ? state.cell : otherCell;
  				var target = (self.isSource) ? otherCell : state.cell;
  				self.error = self.validateConnection(source, target);
  				return self.error == null;
  			};
  			return marker;
  		};
  		mxEdgeHandler.prototype.validateConnection = function(source, target)
  		{
  			return this.graph.getEdgeValidationError(this.state.cell, source, target);
  		};
  		 mxEdgeHandler.prototype.createBends = function()
  		 {
  			var cell = this.state.cell;
  			var bends = [];
  			for (var i = 0; i < this.abspoints.length; i++)
  			{
  				if (this.isHandleVisible(i))
  				{
  					var source = i == 0;
  					var target = i == this.abspoints.length - 1;
  					var terminal = source || target;
  					if (terminal || this.graph.isCellBendable(cell))
  					{
  						(mxUtils.bind(this, function(index)
  						{
  							var bend = this.createHandleShape(index);
  							this.initBend(bend, mxUtils.bind(this, mxUtils.bind(this, function()
  							{
  								if (this.dblClickRemoveEnabled)
  								{
  									this.removePoint(this.state, index);
  								}
  							})));
  							if (this.isHandleEnabled(i))
  							{
  								bend.setCursor((terminal) ? mxConstants.CURSOR_TERMINAL_HANDLE : mxConstants.CURSOR_BEND_HANDLE);
  							}
  							bends.push(bend);
  							if (!terminal)
  							{
  								this.points.push(new mxPoint(0,0));
  								bend.node.style.visibility = 'hidden';
  							}
  						}))(i);
  					}
  				}
  			}
  			return bends;
  		};
  		 mxEdgeHandler.prototype.createVirtualBends = function()
  		 {
  			var cell = this.state.cell;
  			this.abspoints[0];
  			var bends = [];
  			if (this.graph.isCellBendable(cell))
  			{
  				for (var i = 1; i < this.abspoints.length; i++)
  				{
  					(mxUtils.bind(this, function(bend)
  					{
  						this.initBend(bend);
  						bend.setCursor(mxConstants.CURSOR_VIRTUAL_BEND_HANDLE);
  						bends.push(bend);
  					}))(this.createHandleShape());
  				}
  			}
  			return bends;
  		};
  		mxEdgeHandler.prototype.isHandleEnabled = function(index)
  		{
  			return true;
  		};
  		mxEdgeHandler.prototype.isHandleVisible = function(index)
  		{
  			var source = this.state.getVisibleTerminalState(true);
  			var target = this.state.getVisibleTerminalState(false);
  			var geo = this.graph.getCellGeometry(this.state.cell);
  			var edgeStyle = (geo != null) ? this.graph.view.getEdgeStyle(this.state, geo.points, source, target) : null;
  			return edgeStyle != mxEdgeStyle.EntityRelation || index == 0 || index == this.abspoints.length - 1;
  		};
  		mxEdgeHandler.prototype.createHandleShape = function(index)
  		{
  			if (this.handleImage != null)
  			{
  				var shape = new mxImageShape(new mxRectangle(0, 0, this.handleImage.width, this.handleImage.height), this.handleImage.src);
  				shape.preserveImageAspect = false;
  				return shape;
  			}
  			else
  			{
  				var s = mxConstants.HANDLE_SIZE;
  				if (this.preferHtml)
  				{
  					s -= 1;
  				}
  				return new mxRectangleShape(new mxRectangle(0, 0, s, s), mxConstants.HANDLE_FILLCOLOR, mxConstants.HANDLE_STROKECOLOR);
  			}
  		};
  		mxEdgeHandler.prototype.createLabelHandleShape = function()
  		{
  			if (this.labelHandleImage != null)
  			{
  				var shape = new mxImageShape(new mxRectangle(0, 0, this.labelHandleImage.width, this.labelHandleImage.height), this.labelHandleImage.src);
  				shape.preserveImageAspect = false;
  				return shape;
  			}
  			else
  			{
  				var s = mxConstants.LABEL_HANDLE_SIZE;
  				return new mxRectangleShape(new mxRectangle(0, 0, s, s), mxConstants.LABEL_HANDLE_FILLCOLOR, mxConstants.HANDLE_STROKECOLOR);
  			}
  		};
  		mxEdgeHandler.prototype.initBend = function(bend, dblClick)
  		{
  			if (this.preferHtml)
  			{
  				bend.dialect = mxConstants.DIALECT_STRICTHTML;
  				bend.init(this.graph.container);
  			}
  			else
  			{
  				bend.dialect = (this.graph.dialect != mxConstants.DIALECT_SVG) ?
  					mxConstants.DIALECT_MIXEDHTML : mxConstants.DIALECT_SVG;
  				bend.init(this.graph.getView().getOverlayPane());
  			}
  			mxEvent.redirectMouseEvents(bend.node, this.graph, this.state,
  					null, null, null, dblClick);
  			if (mxClient.IS_QUIRKS || document.documentMode == 8)
  			{
  				mxEvent.addListener(bend.node, 'dragstart', function(evt)
  				{
  					mxEvent.consume(evt);
  					return false;
  				});
  			}
  			if (mxClient.IS_TOUCH)
  			{
  				bend.node.setAttribute('pointer-events', 'none');
  			}
  		};
  		mxEdgeHandler.prototype.getHandleForEvent = function(me)
  		{
  			var result = null;
  			if (this.state != null)
  			{
  				var tol = (!mxEvent.isMouseEvent(me.getEvent())) ? this.tolerance : 1;
  				var hit = (this.allowHandleBoundsCheck && (mxClient.IS_IE || tol > 0)) ?
  					new mxRectangle(me.getGraphX() - tol, me.getGraphY() - tol, 2 * tol, 2 * tol) : null;
  				var minDistSq = null;
  				function checkShape(shape)
  				{
  					if (shape != null && shape.node != null && shape.node.style.display != 'none' &&
  						shape.node.style.visibility != 'hidden' &&
  						(me.isSource(shape) || (hit != null && mxUtils.intersects(shape.bounds, hit))))
  					{
  						var dx = me.getGraphX() - shape.bounds.getCenterX();
  						var dy = me.getGraphY() - shape.bounds.getCenterY();
  						var tmp = dx * dx + dy * dy;
  						if (minDistSq == null || tmp <= minDistSq)
  						{
  							minDistSq = tmp;
  							return true;
  						}
  					}
  					return false;
  				}
  				if (this.customHandles != null && this.isCustomHandleEvent(me))
  				{
  					for (var i = this.customHandles.length - 1; i >= 0; i--)
  					{
  						if (checkShape(this.customHandles[i].shape))
  						{
  							return mxEvent.CUSTOM_HANDLE - i;
  						}
  					}
  				}
  				if (me.isSource(this.state.text) || checkShape(this.labelShape))
  				{
  					result = mxEvent.LABEL_HANDLE;
  				}
  				if (this.bends != null)
  				{
  					for (var i = 0; i < this.bends.length; i++)
  					{
  						if (checkShape(this.bends[i]))
  						{
  							result = i;
  						}
  					}
  				}
  				if (this.virtualBends != null && this.isAddVirtualBendEvent(me))
  				{
  					for (var i = 0; i < this.virtualBends.length; i++)
  					{
  						if (checkShape(this.virtualBends[i]))
  						{
  							result = mxEvent.VIRTUAL_HANDLE - i;
  						}
  					}
  				}
  			}
  			return result;
  		};
  		mxEdgeHandler.prototype.isAddVirtualBendEvent = function(me)
  		{
  			return true;
  		};
  		mxEdgeHandler.prototype.isCustomHandleEvent = function(me)
  		{
  			return true;
  		};
  		mxEdgeHandler.prototype.mouseDown = function(sender, me)
  		{
  			var handle = this.getHandleForEvent(me);
  			if (this.bends != null && this.bends[handle] != null)
  			{
  				var b = this.bends[handle].bounds;
  				this.snapPoint = new mxPoint(b.getCenterX(), b.getCenterY());
  			}
  			if (this.addEnabled && handle == null && this.isAddPointEvent(me.getEvent()))
  			{
  				this.addPoint(this.state, me.getEvent());
  				me.consume();
  			}
  			else if (handle != null && !me.isConsumed() && this.graph.isEnabled())
  			{
  				if (this.removeEnabled && this.isRemovePointEvent(me.getEvent()))
  				{
  					this.removePoint(this.state, handle);
  				}
  				else if (handle != mxEvent.LABEL_HANDLE || this.graph.isLabelMovable(me.getCell()))
  				{
  					if (handle <= mxEvent.VIRTUAL_HANDLE)
  					{
  						mxUtils.setOpacity(this.virtualBends[mxEvent.VIRTUAL_HANDLE - handle].node, 100);
  					}
  					this.start(me.getX(), me.getY(), handle);
  				}
  				me.consume();
  			}
  		};
  		mxEdgeHandler.prototype.start = function(x, y, index)
  		{
  			this.startX = x;
  			this.startY = y;
  			this.isSource = (this.bends == null) ? false : index == 0;
  			this.isTarget = (this.bends == null) ? false : index == this.bends.length - 1;
  			this.isLabel = index == mxEvent.LABEL_HANDLE;
  			if (this.isSource || this.isTarget)
  			{
  				var cell = this.state.cell;
  				var terminal = this.graph.model.getTerminal(cell, this.isSource);
  				if ((terminal == null && this.graph.isTerminalPointMovable(cell, this.isSource)) ||
  					(terminal != null && this.graph.isCellDisconnectable(cell, terminal, this.isSource)))
  				{
  					this.index = index;
  				}
  			}
  			else
  			{
  				this.index = index;
  			}
  			if (this.index <= mxEvent.CUSTOM_HANDLE && this.index > mxEvent.VIRTUAL_HANDLE)
  			{
  				if (this.customHandles != null)
  				{
  					for (var i = 0; i < this.customHandles.length; i++)
  					{
  						if (i != mxEvent.CUSTOM_HANDLE - this.index)
  						{
  							this.customHandles[i].setVisible(false);
  						}
  					}
  				}
  			}
  		};
  		mxEdgeHandler.prototype.clonePreviewState = function(point, terminal)
  		{
  			return this.state.clone();
  		};
  		mxEdgeHandler.prototype.getSnapToTerminalTolerance = function()
  		{
  			return this.graph.gridSize * this.graph.view.scale / 2;
  		};
  		mxEdgeHandler.prototype.updateHint = function(me, point) { };
  		mxEdgeHandler.prototype.removeHint = function() { };
  		mxEdgeHandler.prototype.roundLength = function(length)
  		{
  			return Math.round(length);
  		};
  		mxEdgeHandler.prototype.isSnapToTerminalsEvent = function(me)
  		{
  			return this.snapToTerminals && !mxEvent.isAltDown(me.getEvent());
  		};
  		mxEdgeHandler.prototype.getPointForEvent = function(me)
  		{
  			var view = this.graph.getView();
  			var scale = view.scale;
  			var point = new mxPoint(this.roundLength(me.getGraphX() / scale) * scale,
  				this.roundLength(me.getGraphY() / scale) * scale);
  			var tt = this.getSnapToTerminalTolerance();
  			var overrideX = false;
  			var overrideY = false;
  			if (tt > 0 && this.isSnapToTerminalsEvent(me))
  			{
  				function snapToPoint(pt)
  				{
  					if (pt != null)
  					{
  						var x = pt.x;
  						if (Math.abs(point.x - x) < tt)
  						{
  							point.x = x;
  							overrideX = true;
  						}
  						var y = pt.y;
  						if (Math.abs(point.y - y) < tt)
  						{
  							point.y = y;
  							overrideY = true;
  						}
  					}
  				}
  				function snapToTerminal(terminal)
  				{
  					if (terminal != null)
  					{
  						snapToPoint.call(this, new mxPoint(view.getRoutingCenterX(terminal),
  								view.getRoutingCenterY(terminal)));
  					}
  				}				snapToTerminal.call(this, this.state.getVisibleTerminalState(true));
  				snapToTerminal.call(this, this.state.getVisibleTerminalState(false));
  				if (this.state.absolutePoints != null)
  				{
  					for (var i = 0; i < this.state.absolutePoints.length; i++)
  					{
  						snapToPoint.call(this, this.state.absolutePoints[i]);
  					}
  				}
  			}
  			if (this.graph.isGridEnabledEvent(me.getEvent()))
  			{
  				var tr = view.translate;
  				if (!overrideX)
  				{
  					point.x = (this.graph.snap(point.x / scale - tr.x) + tr.x) * scale;
  				}
  				if (!overrideY)
  				{
  					point.y = (this.graph.snap(point.y / scale - tr.y) + tr.y) * scale;
  				}
  			}
  			return point;
  		};
  		mxEdgeHandler.prototype.getPreviewTerminalState = function(me)
  		{
  			this.constraintHandler.update(me, this.isSource, true, me.isSource(this.marker.highlight.shape) ? null : this.currentPoint);
  			if (this.constraintHandler.currentFocus != null && this.constraintHandler.currentConstraint != null)
  			{
  				if (this.marker.highlight != null && this.marker.highlight.state != null &&
  					this.marker.highlight.state.cell == this.constraintHandler.currentFocus.cell)
  				{
  					if (this.marker.highlight.shape.stroke != 'transparent')
  					{
  						this.marker.highlight.shape.stroke = 'transparent';
  						this.marker.highlight.repaint();
  					}
  				}
  				else
  				{
  					this.marker.markCell(this.constraintHandler.currentFocus.cell, 'transparent');
  				}
  				var model = this.graph.getModel();
  				var other = this.graph.view.getTerminalPort(this.state,
  						this.graph.view.getState(model.getTerminal(this.state.cell,
  					!this.isSource)), !this.isSource);
  				var otherCell = (other != null) ? other.cell : null;
  				var source = (this.isSource) ? this.constraintHandler.currentFocus.cell : otherCell;
  				var target = (this.isSource) ? otherCell : this.constraintHandler.currentFocus.cell;
  				this.error = this.validateConnection(source, target);
  				var result = null;
  				if (this.error == null)
  				{
  					result = this.constraintHandler.currentFocus;
  				}
  				if (this.error != null || (result != null &&
  					!this.isCellEnabled(result.cell)))
  				{
  					this.constraintHandler.reset();
  				}
  				return result;
  			}
  			else if (!this.graph.isIgnoreTerminalEvent(me.getEvent()))
  			{
  				this.marker.process(me);
  				var state = this.marker.getValidState();
  				if (state != null && !this.isCellEnabled(state.cell))
  				{
  					this.constraintHandler.reset();
  					this.marker.reset();
  				}
  				return this.marker.getValidState();
  			}
  			else
  			{
  				this.marker.reset();
  				return null;
  			}
  		};
  		mxEdgeHandler.prototype.getPreviewPoints = function(pt, me)
  		{
  			var geometry = this.graph.getCellGeometry(this.state.cell);
  			var points = (geometry.points != null) ? geometry.points.slice() : null;
  			var point = new mxPoint(pt.x, pt.y);
  			var result = null;
  			if (!this.isSource && !this.isTarget)
  			{
  				this.convertPoint(point, false);
  				if (points == null)
  				{
  					points = [point];
  				}
  				else
  				{
  					if (this.index <= mxEvent.VIRTUAL_HANDLE)
  					{
  						points.splice(mxEvent.VIRTUAL_HANDLE - this.index, 0, point);
  					}
  					if (!this.isSource && !this.isTarget)
  					{
  						for (var i = 0; i < this.bends.length; i++)
  						{
  							if (i != this.index)
  							{
  								var bend = this.bends[i];
  								if (bend != null && mxUtils.contains(bend.bounds, pt.x, pt.y))
  								{
  									if (this.index <= mxEvent.VIRTUAL_HANDLE)
  									{
  										points.splice(mxEvent.VIRTUAL_HANDLE - this.index, 1);
  									}
  									else
  									{
  										points.splice(this.index - 1, 1);
  									}
  									result = points;
  								}
  							}
  						}
  						if (result == null && this.straightRemoveEnabled && (me == null || !mxEvent.isAltDown(me.getEvent())))
  						{
  							var tol = this.graph.tolerance * this.graph.tolerance;
  							var abs = this.state.absolutePoints.slice();
  							abs[this.index] = pt;
  							var src = this.state.getVisibleTerminalState(true);
  							if (src != null)
  							{
  								var c = this.graph.getConnectionConstraint(this.state, src, true);
  								if (c == null || this.graph.getConnectionPoint(src, c) == null)
  								{
  									abs[0] = new mxPoint(src.view.getRoutingCenterX(src), src.view.getRoutingCenterY(src));
  								}
  							}
  							var trg = this.state.getVisibleTerminalState(false);
  							if (trg != null)
  							{
  								var c = this.graph.getConnectionConstraint(this.state, trg, false);
  								if (c == null || this.graph.getConnectionPoint(trg, c) == null)
  								{
  									abs[abs.length - 1] = new mxPoint(trg.view.getRoutingCenterX(trg), trg.view.getRoutingCenterY(trg));
  								}
  							}
  							function checkRemove(idx, tmp)
  							{
  								if (idx > 0 && idx < abs.length - 1 &&
  									mxUtils.ptSegDistSq(abs[idx - 1].x, abs[idx - 1].y,
  										abs[idx + 1].x, abs[idx + 1].y, tmp.x, tmp.y) < tol)
  								{
  									points.splice(idx - 1, 1);
  									result = points;
  								}
  							}							checkRemove(this.index, pt);
  						}
  					}
  					if (result == null && this.index > mxEvent.VIRTUAL_HANDLE)
  					{
  						points[this.index - 1] = point;
  					}
  				}
  			}
  			else if (this.graph.resetEdgesOnConnect)
  			{
  				points = null;
  			}
  			return (result != null) ? result : points;
  		};
  		mxEdgeHandler.prototype.isOutlineConnectEvent = function(me)
  		{
  			var offset = mxUtils.getOffset(this.graph.container);
  			var evt = me.getEvent();
  			var clientX = mxEvent.getClientX(evt);
  			var clientY = mxEvent.getClientY(evt);
  			var doc = document.documentElement;
  			var left = (window.pageXOffset || doc.scrollLeft) - (doc.clientLeft || 0);
  			var top = (window.pageYOffset || doc.scrollTop)  - (doc.clientTop || 0);
  			var gridX = this.currentPoint.x - this.graph.container.scrollLeft + offset.x - left;
  			var gridY = this.currentPoint.y - this.graph.container.scrollTop + offset.y - top;
  			return this.outlineConnect && !mxEvent.isShiftDown(me.getEvent()) &&
  				(me.isSource(this.marker.highlight.shape) ||
  				(mxEvent.isAltDown(me.getEvent()) && me.getState() != null) ||
  				this.marker.highlight.isHighlightAt(clientX, clientY) ||
  				((gridX != clientX || gridY != clientY) && me.getState() == null &&
  				this.marker.highlight.isHighlightAt(gridX, gridY)));
  		};
  		mxEdgeHandler.prototype.updatePreviewState = function(edge, point, terminalState, me, outline)
  		{
  			var sourceState = (this.isSource) ? terminalState : this.state.getVisibleTerminalState(true);
  			var targetState = (this.isTarget) ? terminalState : this.state.getVisibleTerminalState(false);
  			var sourceConstraint = this.graph.getConnectionConstraint(edge, sourceState, true);
  			var targetConstraint = this.graph.getConnectionConstraint(edge, targetState, false);
  			var constraint = this.constraintHandler.currentConstraint;
  			if (constraint == null && outline)
  			{
  				if (terminalState != null)
  				{
  					if (me.isSource(this.marker.highlight.shape))
  					{
  						point = new mxPoint(me.getGraphX(), me.getGraphY());
  					}
  					constraint = this.graph.getOutlineConstraint(point, terminalState, me);
  					this.constraintHandler.setFocus(me, terminalState, this.isSource);
  					this.constraintHandler.currentConstraint = constraint;
  					this.constraintHandler.currentPoint = point;
  				}
  				else
  				{
  					constraint = new mxConnectionConstraint();
  				}
  			}
  			if (this.outlineConnect && this.marker.highlight != null && this.marker.highlight.shape != null)
  			{
  				var s = this.graph.view.scale;
  				if (this.constraintHandler.currentConstraint != null &&
  					this.constraintHandler.currentFocus != null)
  				{
  					this.marker.highlight.shape.stroke = (outline) ? mxConstants.OUTLINE_HIGHLIGHT_COLOR : 'transparent';
  					this.marker.highlight.shape.strokewidth = mxConstants.OUTLINE_HIGHLIGHT_STROKEWIDTH / s / s;
  					this.marker.highlight.repaint();
  				}
  				else if (this.marker.hasValidState())
  				{
  					this.marker.highlight.shape.stroke = (this.graph.isCellConnectable(me.getCell()) &&
  						this.marker.getValidState() != me.getState()) ?
  						'transparent' : mxConstants.DEFAULT_VALID_COLOR;
  					this.marker.highlight.shape.strokewidth = mxConstants.HIGHLIGHT_STROKEWIDTH / s / s;
  					this.marker.highlight.repaint();
  				}
  			}
  			if (this.isSource)
  			{
  				sourceConstraint = constraint;
  			}
  			else if (this.isTarget)
  			{
  				targetConstraint = constraint;
  			}
  			if (this.isSource || this.isTarget)
  			{
  				if (constraint != null && constraint.point != null)
  				{
  					edge.style[(this.isSource) ? mxConstants.STYLE_EXIT_X : mxConstants.STYLE_ENTRY_X] = constraint.point.x;
  					edge.style[(this.isSource) ? mxConstants.STYLE_EXIT_Y : mxConstants.STYLE_ENTRY_Y] = constraint.point.y;
  				}
  				else
  				{
  					delete edge.style[(this.isSource) ? mxConstants.STYLE_EXIT_X : mxConstants.STYLE_ENTRY_X];
  					delete edge.style[(this.isSource) ? mxConstants.STYLE_EXIT_Y : mxConstants.STYLE_ENTRY_Y];
  				}
  			}
  			edge.setVisibleTerminalState(sourceState, true);
  			edge.setVisibleTerminalState(targetState, false);
  			if (!this.isSource || sourceState != null)
  			{
  				edge.view.updateFixedTerminalPoint(edge, sourceState, true, sourceConstraint);
  			}
  			if (!this.isTarget || targetState != null)
  			{
  				edge.view.updateFixedTerminalPoint(edge, targetState, false, targetConstraint);
  			}
  			if ((this.isSource || this.isTarget) && terminalState == null)
  			{
  				edge.setAbsoluteTerminalPoint(point, this.isSource);
  				if (this.marker.getMarkedState() == null)
  				{
  					this.error = (this.graph.allowDanglingEdges) ? null : '';
  				}
  			}
  			edge.view.updatePoints(edge, this.points, sourceState, targetState);
  			edge.view.updateFloatingTerminalPoints(edge, sourceState, targetState);
  		};
  		mxEdgeHandler.prototype.mouseMove = function(sender, me)
  		{
  			if (this.index != null && this.marker != null)
  			{
  				this.currentPoint = this.getPointForEvent(me);
  				this.error = null;
  				if (!this.graph.isIgnoreTerminalEvent(me.getEvent()) && mxEvent.isShiftDown(me.getEvent()) && this.snapPoint != null)
  				{
  					if (Math.abs(this.snapPoint.x - this.currentPoint.x) < Math.abs(this.snapPoint.y - this.currentPoint.y))
  					{
  						this.currentPoint.x = this.snapPoint.x;
  					}
  					else
  					{
  						this.currentPoint.y = this.snapPoint.y;
  					}
  				}
  				if (this.index <= mxEvent.CUSTOM_HANDLE && this.index > mxEvent.VIRTUAL_HANDLE)
  				{
  					if (this.customHandles != null)
  					{
  						this.customHandles[mxEvent.CUSTOM_HANDLE - this.index].processEvent(me);
  						this.customHandles[mxEvent.CUSTOM_HANDLE - this.index].positionChanged();
  						if (this.shape != null && this.shape.node != null)
  						{
  							this.shape.node.style.display = 'none';
  						}
  					}
  				}
  				else if (this.isLabel)
  				{
  					this.label.x = this.currentPoint.x;
  					this.label.y = this.currentPoint.y;
  				}
  				else
  				{
  					this.points = this.getPreviewPoints(this.currentPoint, me);
  					var terminalState = (this.isSource || this.isTarget) ? this.getPreviewTerminalState(me) : null;
  					if (this.constraintHandler.currentConstraint != null &&
  						this.constraintHandler.currentFocus != null &&
  						this.constraintHandler.currentPoint != null)
  					{
  						this.currentPoint = this.constraintHandler.currentPoint.clone();
  					}
  					else if (this.outlineConnect)
  					{
  						var outline = (this.isSource || this.isTarget) ? this.isOutlineConnectEvent(me) : false;
  						if (outline)
  						{
  							terminalState = this.marker.highlight.state;
  						}
  						else if (terminalState != null && terminalState != me.getState() &&
  							this.graph.isCellConnectable(me.getCell()) &&
  							this.marker.highlight.shape != null)
  						{
  							this.marker.highlight.shape.stroke = 'transparent';
  							this.marker.highlight.repaint();
  							terminalState = null;
  						}
  					}
  					if (terminalState != null && !this.isCellEnabled(terminalState.cell))
  					{
  						terminalState = null;
  						this.marker.reset();
  					}
  					var clone = this.clonePreviewState(this.currentPoint, (terminalState != null) ? terminalState.cell : null);
  					this.updatePreviewState(clone, this.currentPoint, terminalState, me, outline);
  					var color = (this.error == null) ? this.marker.validColor : this.marker.invalidColor;
  					this.setPreviewColor(color);
  					this.abspoints = clone.absolutePoints;
  					this.active = true;
  					this.updateHint(me, this.currentPoint);
  				}
  				this.drawPreview();
  				mxEvent.consume(me.getEvent());
  				me.consume();
  			}
  			else if (mxClient.IS_IE && this.getHandleForEvent(me) != null)
  			{
  				me.consume(false);
  			}
  		};
  		mxEdgeHandler.prototype.mouseUp = function(sender, me)
  		{
  			if (this.index != null && this.marker != null)
  			{
  				if (this.shape != null && this.shape.node != null)
  				{
  					this.shape.node.style.display = '';
  				}
  				var edge = this.state.cell;
  				var index = this.index;
  				this.index = null;
  				if (me.getX() != this.startX || me.getY() != this.startY)
  				{
  					var clone = !this.graph.isIgnoreTerminalEvent(me.getEvent()) && this.graph.isCloneEvent(me.getEvent()) &&
  						this.cloneEnabled && this.graph.isCellsCloneable();
  					if (this.error != null)
  					{
  						if (this.error.length > 0)
  						{
  							this.graph.validationAlert(this.error);
  						}
  					}
  					else if (index <= mxEvent.CUSTOM_HANDLE && index > mxEvent.VIRTUAL_HANDLE)
  					{
  						if (this.customHandles != null)
  						{
  							var model = this.graph.getModel();
  							model.beginUpdate();
  							try
  							{
  								this.customHandles[mxEvent.CUSTOM_HANDLE - index].execute(me);
  								if (this.shape != null && this.shape.node != null)
  								{
  									this.shape.apply(this.state);
  									this.shape.redraw();
  								}
  							}
  							finally
  							{
  								model.endUpdate();
  							}
  						}
  					}
  					else if (this.isLabel)
  					{
  						this.moveLabel(this.state, this.label.x, this.label.y);
  					}
  					else if (this.isSource || this.isTarget)
  					{
  						var terminal = null;
  						if (this.constraintHandler.currentConstraint != null &&
  							this.constraintHandler.currentFocus != null)
  						{
  							terminal = this.constraintHandler.currentFocus.cell;
  						}
  						if (terminal == null && this.marker.hasValidState() && this.marker.highlight != null &&
  							this.marker.highlight.shape != null &&
  							this.marker.highlight.shape.stroke != 'transparent' &&
  							this.marker.highlight.shape.stroke != 'white')
  						{
  							terminal = this.marker.validState.cell;
  						}
  						if (terminal != null)
  						{
  							var model = this.graph.getModel();
  							var parent = model.getParent(edge);
  							model.beginUpdate();
  							try
  							{
  								if (clone)
  								{
  									var geo = model.getGeometry(edge);
  									var clone = this.graph.cloneCell(edge);
  									model.add(parent, clone, model.getChildCount(parent));
  									if (geo != null)
  									{
  										geo = geo.clone();
  										model.setGeometry(clone, geo);
  									}
  									var other = model.getTerminal(edge, !this.isSource);
  									this.graph.connectCell(clone, other, !this.isSource);
  									edge = clone;
  								}
  								edge = this.connect(edge, terminal, this.isSource, clone, me);
  							}
  							finally
  							{
  								model.endUpdate();
  							}
  						}
  						else if (this.graph.isAllowDanglingEdges())
  						{
  							var pt = this.abspoints[(this.isSource) ? 0 : this.abspoints.length - 1];
  							pt.x = this.roundLength(pt.x / this.graph.view.scale - this.graph.view.translate.x);
  							pt.y = this.roundLength(pt.y / this.graph.view.scale - this.graph.view.translate.y);
  							var pstate = this.graph.getView().getState(
  									this.graph.getModel().getParent(edge));
  							if (pstate != null)
  							{
  								pt.x -= pstate.origin.x;
  								pt.y -= pstate.origin.y;
  							}
  							pt.x -= this.graph.panDx / this.graph.view.scale;
  							pt.y -= this.graph.panDy / this.graph.view.scale;
  							edge = this.changeTerminalPoint(edge, pt, this.isSource, clone);
  						}
  					}
  					else if (this.active)
  					{
  						edge = this.changePoints(edge, this.points, clone);
  					}
  					else
  					{
  						this.graph.getView().invalidate(this.state.cell);
  						this.graph.getView().validate(this.state.cell);
  					}
  				}
  				else if (this.graph.isToggleEvent(me.getEvent()))
  				{
  					this.graph.selectCellForEvent(this.state.cell, me.getEvent());
  				}
  				if (this.marker != null)
  				{
  					this.reset();
  					if (edge != this.state.cell)
  					{
  						this.graph.setSelectionCell(edge);
  					}
  				}
  				me.consume();
  			}
  		};
  		mxEdgeHandler.prototype.reset = function()
  		{
  			if (this.active)
  			{
  				this.refresh();
  			}
  			this.error = null;
  			this.index = null;
  			this.label = null;
  			this.points = null;
  			this.snapPoint = null;
  			this.isLabel = false;
  			this.isSource = false;
  			this.isTarget = false;
  			this.active = false;
  			if (this.livePreview && this.sizers != null)
  			{
  				for (var i = 0; i < this.sizers.length; i++)
  				{
  					if (this.sizers[i] != null)
  					{
  						this.sizers[i].node.style.display = '';
  					}
  				}
  			}
  			if (this.marker != null)
  			{
  				this.marker.reset();
  			}
  			if (this.constraintHandler != null)
  			{
  				this.constraintHandler.reset();
  			}
  			if (this.customHandles != null)
  			{
  				for (var i = 0; i < this.customHandles.length; i++)
  				{
  					this.customHandles[i].reset();
  				}
  			}
  			this.setPreviewColor(mxConstants.EDGE_SELECTION_COLOR);
  			this.removeHint();
  			this.redraw();
  		};
  		mxEdgeHandler.prototype.setPreviewColor = function(color)
  		{
  			if (this.shape != null)
  			{
  				this.shape.stroke = color;
  			}
  		};
  		mxEdgeHandler.prototype.convertPoint = function(point, gridEnabled)
  		{
  			var scale = this.graph.getView().getScale();
  			var tr = this.graph.getView().getTranslate();
  			if (gridEnabled)
  			{
  				point.x = this.graph.snap(point.x);
  				point.y = this.graph.snap(point.y);
  			}
  			point.x = Math.round(point.x / scale - tr.x);
  			point.y = Math.round(point.y / scale - tr.y);
  			var pstate = this.graph.getView().getState(
  				this.graph.getModel().getParent(this.state.cell));
  			if (pstate != null)
  			{
  				point.x -= pstate.origin.x;
  				point.y -= pstate.origin.y;
  			}
  			return point;
  		};
  		mxEdgeHandler.prototype.moveLabel = function(edgeState, x, y)
  		{
  			var model = this.graph.getModel();
  			var geometry = model.getGeometry(edgeState.cell);
  			if (geometry != null)
  			{
  				var scale = this.graph.getView().scale;
  				geometry = geometry.clone();
  				if (geometry.relative)
  				{
  					var pt = this.graph.getView().getRelativePoint(edgeState, x, y);
  					geometry.x = Math.round(pt.x * 10000) / 10000;
  					geometry.y = Math.round(pt.y);
  					geometry.offset = new mxPoint(0, 0);
  					var pt = this.graph.view.getPoint(edgeState, geometry);
  					geometry.offset = new mxPoint(Math.round((x - pt.x) / scale), Math.round((y - pt.y) / scale));
  				}
  				else
  				{
  					var points = edgeState.absolutePoints;
  					var p0 = points[0];
  					var pe = points[points.length - 1];
  					if (p0 != null && pe != null)
  					{
  						var cx = p0.x + (pe.x - p0.x) / 2;
  						var cy = p0.y + (pe.y - p0.y) / 2;
  						geometry.offset = new mxPoint(Math.round((x - cx) / scale), Math.round((y - cy) / scale));
  						geometry.x = 0;
  						geometry.y = 0;
  					}
  				}
  				model.setGeometry(edgeState.cell, geometry);
  			}
  		};
  		mxEdgeHandler.prototype.connect = function(edge, terminal, isSource, isClone, me)
  		{
  			var model = this.graph.getModel();
  			model.getParent(edge);
  			model.beginUpdate();
  			try
  			{
  				var constraint = this.constraintHandler.currentConstraint;
  				if (constraint == null)
  				{
  					constraint = new mxConnectionConstraint();
  				}
  				this.graph.connectCell(edge, terminal, isSource, constraint);
  			}
  			finally
  			{
  				model.endUpdate();
  			}
  			return edge;
  		};
  		mxEdgeHandler.prototype.changeTerminalPoint = function(edge, point, isSource, clone)
  		{
  			var model = this.graph.getModel();
  			model.beginUpdate();
  			try
  			{
  				if (clone)
  				{
  					var parent = model.getParent(edge);
  					var terminal = model.getTerminal(edge, !isSource);
  					edge = this.graph.cloneCell(edge);
  					model.add(parent, edge, model.getChildCount(parent));
  					model.setTerminal(edge, terminal, !isSource);
  				}
  				var geo = model.getGeometry(edge);
  				if (geo != null)
  				{
  					geo = geo.clone();
  					geo.setTerminalPoint(point, isSource);
  					model.setGeometry(edge, geo);
  					this.graph.connectCell(edge, null, isSource, new mxConnectionConstraint());
  				}
  			}
  			finally
  			{
  				model.endUpdate();
  			}
  			return edge;
  		};
  		mxEdgeHandler.prototype.changePoints = function(edge, points, clone)
  		{
  			var model = this.graph.getModel();
  			model.beginUpdate();
  			try
  			{
  				if (clone)
  				{
  					var parent = model.getParent(edge);
  					var source = model.getTerminal(edge, true);
  					var target = model.getTerminal(edge, false);
  					edge = this.graph.cloneCell(edge);
  					model.add(parent, edge, model.getChildCount(parent));
  					model.setTerminal(edge, source, true);
  					model.setTerminal(edge, target, false);
  				}
  				var geo = model.getGeometry(edge);
  				if (geo != null)
  				{
  					geo = geo.clone();
  					geo.points = points;
  					model.setGeometry(edge, geo);
  				}
  			}
  			finally
  			{
  				model.endUpdate();
  			}
  			return edge;
  		};
  		mxEdgeHandler.prototype.addPoint = function(state, evt)
  		{
  			var pt = mxUtils.convertPoint(this.graph.container, mxEvent.getClientX(evt),
  					mxEvent.getClientY(evt));
  			var gridEnabled = this.graph.isGridEnabledEvent(evt);
  			this.convertPoint(pt, gridEnabled);
  			this.addPointAt(state, pt.x, pt.y);
  			mxEvent.consume(evt);
  		};
  		mxEdgeHandler.prototype.addPointAt = function(state, x, y)
  		{
  			var geo = this.graph.getCellGeometry(state.cell);
  			var pt = new mxPoint(x, y);
  			if (geo != null)
  			{
  				geo = geo.clone();
  				var t = this.graph.view.translate;
  				var s = this.graph.view.scale;
  				var offset = new mxPoint(t.x * s, t.y * s);
  				var parent = this.graph.model.getParent(this.state.cell);
  				if (this.graph.model.isVertex(parent))
  				{
  					var pState = this.graph.view.getState(parent);
  					offset = new mxPoint(pState.x, pState.y);
  				}
  				var index = mxUtils.findNearestSegment(state, pt.x * s + offset.x, pt.y * s + offset.y);
  				if (geo.points == null)
  				{
  					geo.points = [pt];
  				}
  				else
  				{
  					geo.points.splice(index, 0, pt);
  				}
  				this.graph.getModel().setGeometry(state.cell, geo);
  				this.refresh();
  				this.redraw();
  			}
  		};
  		mxEdgeHandler.prototype.removePoint = function(state, index)
  		{
  			if (index > 0 && index < this.abspoints.length - 1)
  			{
  				var geo = this.graph.getCellGeometry(this.state.cell);
  				if (geo != null && geo.points != null)
  				{
  					geo = geo.clone();
  					geo.points.splice(index - 1, 1);
  					this.graph.getModel().setGeometry(state.cell, geo);
  					this.refresh();
  					this.redraw();
  				}
  			}
  		};
  		mxEdgeHandler.prototype.getHandleFillColor = function(index)
  		{
  			var isSource = index == 0;
  			var cell = this.state.cell;
  			var terminal = this.graph.getModel().getTerminal(cell, isSource);
  			var color = mxConstants.HANDLE_FILLCOLOR;
  			if ((terminal != null && !this.graph.isCellDisconnectable(cell, terminal, isSource)) ||
  				(terminal == null && !this.graph.isTerminalPointMovable(cell, isSource)))
  			{
  				color = mxConstants.LOCKED_HANDLE_FILLCOLOR;
  			}
  			else if (terminal != null && this.graph.isCellDisconnectable(cell, terminal, isSource))
  			{
  				color = mxConstants.CONNECT_HANDLE_FILLCOLOR;
  			}
  			return color;
  		};
  		mxEdgeHandler.prototype.redraw = function(ignoreHandles)
  		{
  			if (this.state != null)
  			{
  				this.abspoints = this.state.absolutePoints.slice();
  				var g = this.graph.getModel().getGeometry(this.state.cell);
  				if (g != null)
  				{
  					var pts = g.points;
  					if (this.bends != null && this.bends.length > 0)
  					{
  						if (pts != null)
  						{
  							if (this.points == null)
  							{
  								this.points = [];
  							}
  							for (var i = 1; i < this.bends.length - 1; i++)
  							{
  								if (this.bends[i] != null && this.abspoints[i] != null)
  								{
  									this.points[i - 1] = pts[i - 1];
  								}
  							}
  						}
  					}
  				}
  				this.drawPreview();
  				if (!ignoreHandles)
  				{
  					this.redrawHandles();
  				}
  			}
  		};
  		mxEdgeHandler.prototype.redrawHandles = function()
  		{
  			var cell = this.state.cell;
  			var b = this.labelShape.bounds;
  			this.label = new mxPoint(this.state.absoluteOffset.x, this.state.absoluteOffset.y);
  			this.labelShape.bounds = new mxRectangle(Math.round(this.label.x - b.width / 2),
  				Math.round(this.label.y - b.height / 2), b.width, b.height);
  			var lab = this.graph.getLabel(cell);
  			this.labelShape.visible = (lab != null && lab.length > 0 && this.graph.isLabelMovable(cell));
  			if (this.bends != null && this.bends.length > 0)
  			{
  				var n = this.abspoints.length - 1;
  				var p0 = this.abspoints[0];
  				var x0 = p0.x;
  				var y0 = p0.y;
  				b = this.bends[0].bounds;
  				this.bends[0].bounds = new mxRectangle(Math.floor(x0 - b.width / 2),
  						Math.floor(y0 - b.height / 2), b.width, b.height);
  				this.bends[0].fill = this.getHandleFillColor(0);
  				this.bends[0].redraw();
  				if (this.manageLabelHandle)
  				{
  					this.checkLabelHandle(this.bends[0].bounds);
  				}
  				var pe = this.abspoints[n];
  				var xn = pe.x;
  				var yn = pe.y;
  				var bn = this.bends.length - 1;
  				b = this.bends[bn].bounds;
  				this.bends[bn].bounds = new mxRectangle(Math.floor(xn - b.width / 2),
  						Math.floor(yn - b.height / 2), b.width, b.height);
  				this.bends[bn].fill = this.getHandleFillColor(bn);
  				this.bends[bn].redraw();
  				if (this.manageLabelHandle)
  				{
  					this.checkLabelHandle(this.bends[bn].bounds);
  				}
  				this.redrawInnerBends(p0, pe);
  			}
  			if (this.abspoints != null && this.virtualBends != null && this.virtualBends.length > 0)
  			{
  				var last = this.abspoints[0];
  				for (var i = 0; i < this.virtualBends.length; i++)
  				{
  					if (this.virtualBends[i] != null && this.abspoints[i + 1] != null)
  					{
  						var pt = this.abspoints[i + 1];
  						var b = this.virtualBends[i];
  						var x = last.x + (pt.x - last.x) / 2;
  						var y = last.y + (pt.y - last.y) / 2;
  						b.bounds = new mxRectangle(Math.floor(x - b.bounds.width / 2),
  								Math.floor(y - b.bounds.height / 2), b.bounds.width, b.bounds.height);
  						b.redraw();
  						mxUtils.setOpacity(b.node, this.virtualBendOpacity);
  						last = pt;
  						if (this.manageLabelHandle)
  						{
  							this.checkLabelHandle(b.bounds);
  						}
  					}
  				}
  			}
  			if (this.labelShape != null)
  			{
  				this.labelShape.redraw();
  			}
  			if (this.customHandles != null)
  			{
  				for (var i = 0; i < this.customHandles.length; i++)
  				{
  					var temp = this.customHandles[i].shape.node.style.display;
  					this.customHandles[i].redraw();
  					this.customHandles[i].shape.node.style.display = temp;
  					this.customHandles[i].shape.node.style.visibility =
  						(this.isCustomHandleVisible(this.customHandles[i])) ?
  						'' : 'hidden';
  				}
  			}
  		};
  		mxEdgeHandler.prototype.isCustomHandleVisible = function(handle)
  		{
  			return !this.graph.isEditing() && this.state.view.graph.getSelectionCount() == 1;
  		};
  		mxEdgeHandler.prototype.setHandlesVisible = function(visible)
  		{
  			if (this.bends != null)
  			{
  				for (var i = 0; i < this.bends.length; i++)
  				{
  					this.bends[i].node.style.display = (visible) ? '' : 'none';
  				}
  			}
  			if (this.virtualBends != null)
  			{
  				for (var i = 0; i < this.virtualBends.length; i++)
  				{
  					this.virtualBends[i].node.style.display = (visible) ? '' : 'none';
  				}
  			}
  			if (this.labelShape != null)
  			{
  				this.labelShape.node.style.display = (visible) ? '' : 'none';
  			}
  			if (this.customHandles != null)
  			{
  				for (var i = 0; i < this.customHandles.length; i++)
  				{
  					this.customHandles[i].setVisible(visible);
  				}
  			}
  		};
  		mxEdgeHandler.prototype.redrawInnerBends = function(p0, pe)
  		{
  			for (var i = 1; i < this.bends.length - 1; i++)
  			{
  				if (this.bends[i] != null)
  				{
  					if (this.abspoints[i] != null)
  					{
  						var x = this.abspoints[i].x;
  						var y = this.abspoints[i].y;
  						var b = this.bends[i].bounds;
  						this.bends[i].node.style.visibility = 'visible';
  						this.bends[i].bounds = new mxRectangle(Math.round(x - b.width / 2),
  								Math.round(y - b.height / 2), b.width, b.height);
  						if (this.manageLabelHandle)
  						{
  							this.checkLabelHandle(this.bends[i].bounds);
  						}
  						else if (this.handleImage == null && this.labelShape.visible && mxUtils.intersects(this.bends[i].bounds, this.labelShape.bounds))
  						{
  							w = mxConstants.HANDLE_SIZE + 3;
  							h = mxConstants.HANDLE_SIZE + 3;
  							this.bends[i].bounds = new mxRectangle(Math.round(x - w / 2), Math.round(y - h / 2), w, h);
  						}
  						this.bends[i].redraw();
  					}
  					else
  					{
  						this.bends[i].destroy();
  						this.bends[i] = null;
  					}
  				}
  			}
  		};
  		mxEdgeHandler.prototype.checkLabelHandle = function(b)
  		{
  			if (this.labelShape != null)
  			{
  				var b2 = this.labelShape.bounds;
  				if (mxUtils.intersects(b, b2))
  				{
  					if (b.getCenterY() < b2.getCenterY())
  					{
  						b2.y = b.y + b.height;
  					}
  					else
  					{
  						b2.y = b.y - b2.height;
  					}
  				}
  			}
  		};
  		mxEdgeHandler.prototype.drawPreview = function()
  		{
  			try
  			{
  				if (this.isLabel)
  				{
  					var b = this.labelShape.bounds;
  					var bounds = new mxRectangle(Math.round(this.label.x - b.width / 2),
  						Math.round(this.label.y - b.height / 2), b.width, b.height);
  					if (!this.labelShape.bounds.equals(bounds))
  					{
  						this.labelShape.bounds = bounds;
  						this.labelShape.redraw();
  					}
  				}
  				if (this.shape != null && !mxUtils.equalPoints(this.shape.points, this.abspoints))
  				{
  					this.shape.apply(this.state);
  					this.shape.points = this.abspoints.slice();
  					this.shape.scale = this.state.view.scale;
  					this.shape.isDashed = this.isSelectionDashed();
  					this.shape.stroke = this.getSelectionColor();
  					this.shape.strokewidth = this.getSelectionStrokeWidth() / this.shape.scale / this.shape.scale;
  					this.shape.isShadow = false;
  					this.shape.redraw();
  				}
  				this.updateParentHighlight();
  			}
  			catch (e)
  			{
  			}
  		};
  		mxEdgeHandler.prototype.refresh = function()
  		{
  			if (this.state != null)
  			{
  				this.abspoints = this.getSelectionPoints(this.state);
  				this.points = [];
  				if (this.bends != null)
  				{
  					this.destroyBends(this.bends);
  					this.bends = this.createBends();
  				}
  				if (this.virtualBends != null)
  				{
  					this.destroyBends(this.virtualBends);
  					this.virtualBends = this.createVirtualBends();
  				}
  				if (this.customHandles != null)
  				{
  					this.destroyBends(this.customHandles);
  					this.customHandles = this.createCustomHandles();
  				}
  				if (this.labelShape != null && this.labelShape.node != null && this.labelShape.node.parentNode != null)
  				{
  					this.labelShape.node.parentNode.appendChild(this.labelShape.node);
  				}
  			}
  		};
  		mxEdgeHandler.prototype.isDestroyed = function()
  		{
  			return this.shape == null;
  		};
  		mxEdgeHandler.prototype.destroyBends = function(bends)
  		{
  			if (bends != null)
  			{
  				for (var i = 0; i < bends.length; i++)
  				{
  					if (bends[i] != null)
  					{
  						bends[i].destroy();
  					}
  				}
  			}
  		};
  		mxEdgeHandler.prototype.destroy = function()
  		{
  			if (this.escapeHandler != null)
  			{
  				this.state.view.graph.removeListener(this.escapeHandler);
  				this.escapeHandler = null;
  			}
  			if (this.marker != null)
  			{
  				this.marker.destroy();
  				this.marker = null;
  			}
  			if (this.shape != null)
  			{
  				this.shape.destroy();
  				this.shape = null;
  			}
  			if (this.parentHighlight != null)
  			{
  				var parent = this.graph.model.getParent(this.state.cell);
  				var pstate = this.graph.view.getState(parent);
  				if (pstate != null && pstate.parentHighlight == this.parentHighlight)
  				{
  					pstate.parentHighlight = null;
  				}
  				this.parentHighlight.destroy();
  				this.parentHighlight = null;
  			}
  			if (this.labelShape != null)
  			{
  				this.labelShape.destroy();
  				this.labelShape = null;
  			}
  			if (this.constraintHandler != null)
  			{
  				this.constraintHandler.destroy();
  				this.constraintHandler = null;
  			}
  			this.destroyBends(this.virtualBends);
  			this.virtualBends = null;
  			this.destroyBends(this.customHandles);
  			this.customHandles = null;
  			this.destroyBends(this.bends);
  			this.bends = null;
  			this.removeHint();
  		};
  		__mxOutput.mxEdgeHandler = typeof mxEdgeHandler !== 'undefined' ? mxEdgeHandler : undefined;
  		function mxElbowEdgeHandler(state)
  		{
  			mxEdgeHandler.call(this, state);
  		}		mxUtils.extend(mxElbowEdgeHandler, mxEdgeHandler);
  		mxElbowEdgeHandler.prototype.flipEnabled = true;
  		mxElbowEdgeHandler.prototype.doubleClickOrientationResource =
  			(mxClient.language != 'none') ? 'doubleClickOrientation' : '';
  		 mxElbowEdgeHandler.prototype.createBends = function()
  		 {
  			var bends = [];
  			var bend = this.createHandleShape(0);
  			this.initBend(bend);
  			bend.setCursor(mxConstants.CURSOR_TERMINAL_HANDLE);
  			bends.push(bend);
  			bends.push(this.createVirtualBend(mxUtils.bind(this, function(evt)
  			{
  				if (!mxEvent.isConsumed(evt) && this.flipEnabled)
  				{
  					this.graph.flipEdge(this.state.cell, evt);
  					mxEvent.consume(evt);
  				}
  			})));
  			this.points.push(new mxPoint(0,0));
  			bend = this.createHandleShape(2);
  			this.initBend(bend);
  			bend.setCursor(mxConstants.CURSOR_TERMINAL_HANDLE);
  			bends.push(bend);
  			return bends;
  		 };
  		mxElbowEdgeHandler.prototype.createVirtualBend = function(dblClickHandler)
  		{
  			var bend = this.createHandleShape();
  			this.initBend(bend, dblClickHandler);
  			bend.setCursor(this.getCursorForBend());
  			if (!this.graph.isCellBendable(this.state.cell))
  			{
  				bend.node.style.display = 'none';
  			}
  			return bend;
  		};
  		mxElbowEdgeHandler.prototype.getCursorForBend = function()
  		{
  			return (this.state.style[mxConstants.STYLE_EDGE] == mxEdgeStyle.TopToBottom ||
  				this.state.style[mxConstants.STYLE_EDGE] == mxConstants.EDGESTYLE_TOPTOBOTTOM ||
  				((this.state.style[mxConstants.STYLE_EDGE] == mxEdgeStyle.ElbowConnector ||
  				this.state.style[mxConstants.STYLE_EDGE] == mxConstants.EDGESTYLE_ELBOW)&&
  				this.state.style[mxConstants.STYLE_ELBOW] == mxConstants.ELBOW_VERTICAL)) ?
  				'row-resize' : 'col-resize';
  		};
  		mxElbowEdgeHandler.prototype.getTooltipForNode = function(node)
  		{
  			var tip = null;
  			if (this.bends != null && this.bends[1] != null && (node == this.bends[1].node ||
  				node.parentNode == this.bends[1].node))
  			{
  				tip = this.doubleClickOrientationResource;
  				tip = mxResources.get(tip) || tip;
  			}
  			return tip;
  		};
  		mxElbowEdgeHandler.prototype.convertPoint = function(point, gridEnabled)
  		{
  			var scale = this.graph.getView().getScale();
  			var tr = this.graph.getView().getTranslate();
  			var origin = this.state.origin;
  			if (gridEnabled)
  			{
  				point.x = this.graph.snap(point.x);
  				point.y = this.graph.snap(point.y);
  			}
  			point.x = Math.round(point.x / scale - tr.x - origin.x);
  			point.y = Math.round(point.y / scale - tr.y - origin.y);
  			return point;
  		};
  		mxElbowEdgeHandler.prototype.redrawInnerBends = function(p0, pe)
  		{
  			var g = this.graph.getModel().getGeometry(this.state.cell);
  			var pts = this.state.absolutePoints;
  			var pt = null;
  			if (pts.length > 1)
  			{
  				p0 = pts[1];
  				pe = pts[pts.length - 2];
  			}
  			else if (g.points != null && g.points.length > 0)
  			{
  				pt = pts[0];
  			}
  			if (pt == null)
  			{
  				pt = new mxPoint(p0.x + (pe.x - p0.x) / 2, p0.y + (pe.y - p0.y) / 2);
  			}
  			else
  			{
  				pt = new mxPoint(this.graph.getView().scale * (pt.x + this.graph.getView().translate.x + this.state.origin.x),
  						this.graph.getView().scale * (pt.y + this.graph.getView().translate.y + this.state.origin.y));
  			}
  			var b = this.bends[1].bounds;
  			var w = b.width;
  			var h = b.height;
  			var bounds = new mxRectangle(Math.round(pt.x - w / 2), Math.round(pt.y - h / 2), w, h);
  			if (this.manageLabelHandle)
  			{
  				this.checkLabelHandle(bounds);
  			}
  			else if (this.handleImage == null && this.labelShape.visible && mxUtils.intersects(bounds, this.labelShape.bounds))
  			{
  				w = mxConstants.HANDLE_SIZE + 3;
  				h = mxConstants.HANDLE_SIZE + 3;
  				bounds = new mxRectangle(Math.floor(pt.x - w / 2), Math.floor(pt.y - h / 2), w, h);
  			}
  			this.bends[1].bounds = bounds;
  			this.bends[1].redraw();
  			if (this.manageLabelHandle)
  			{
  				this.checkLabelHandle(this.bends[1].bounds);
  			}
  		};
  		__mxOutput.mxElbowEdgeHandler = typeof mxElbowEdgeHandler !== 'undefined' ? mxElbowEdgeHandler : undefined;
  		function mxEdgeSegmentHandler(state)
  		{
  			mxEdgeHandler.call(this, state);
  		}		mxUtils.extend(mxEdgeSegmentHandler, mxElbowEdgeHandler);
  		mxEdgeSegmentHandler.prototype.getCurrentPoints = function()
  		{
  			var pts = this.state.absolutePoints;
  			if (pts != null)
  			{
  				var tol = Math.max(1, this.graph.view.scale);
  				if (pts.length == 2 || (pts.length == 3 &&
  					(Math.abs(pts[0].x - pts[1].x) < tol && Math.abs(pts[1].x - pts[2].x) < tol ||
  					Math.abs(pts[0].y - pts[1].y) < tol && Math.abs(pts[1].y - pts[2].y) < tol)))
  				{
  					var cx = pts[0].x + (pts[pts.length - 1].x - pts[0].x) / 2;
  					var cy = pts[0].y + (pts[pts.length - 1].y - pts[0].y) / 2;
  					pts = [pts[0], new mxPoint(cx, cy), new mxPoint(cx, cy), pts[pts.length - 1]];
  				}
  			}
  			return pts;
  		};
  		mxEdgeSegmentHandler.prototype.getPreviewPoints = function(point)
  		{
  			if (this.isSource || this.isTarget)
  			{
  				return mxElbowEdgeHandler.prototype.getPreviewPoints.apply(this, arguments);
  			}
  			else
  			{
  				var pts = this.getCurrentPoints();
  				var last = this.convertPoint(pts[0].clone(), false);
  				point = this.convertPoint(point.clone(), false);
  				var result = [];
  				for (var i = 1; i < pts.length; i++)
  				{
  					var pt = this.convertPoint(pts[i].clone(), false);
  					if (i == this.index)
  					{
  						if (Math.round(last.x - pt.x) == 0)
  				 		{
  							last.x = point.x;
  							pt.x = point.x;
  				 		}
  						if (Math.round(last.y - pt.y) == 0)
  				 		{
  				 			last.y = point.y;
  				 			pt.y = point.y;
  				 		}
  					}
  					if (i < pts.length - 1)
  					{
  						result.push(pt);
  					}
  					last = pt;
  				}
  				if (result.length == 1)
  				{
  					var source = this.state.getVisibleTerminalState(true);
  					var target = this.state.getVisibleTerminalState(false);
  					var scale = this.state.view.getScale();
  					var tr = this.state.view.getTranslate();
  					var x = result[0].x * scale + tr.x;
  					var y = result[0].y * scale + tr.y;
  					if ((source != null && mxUtils.contains(source, x, y)) ||
  						(target != null && mxUtils.contains(target, x, y)))
  					{
  						result = [point, point];
  					}
  				}
  				return result;
  			}
  		};
  		mxEdgeSegmentHandler.prototype.updatePreviewState = function(edge, point, terminalState, me)
  		{
  			mxEdgeHandler.prototype.updatePreviewState.apply(this, arguments);
  			if (!this.isSource && !this.isTarget)
  			{
  				point = this.convertPoint(point.clone(), false);
  				var pts = edge.absolutePoints;
  				var pt0 = pts[0];
  				var pt1 = pts[1];
  				var result = [];
  				for (var i = 2; i < pts.length; i++)
  				{
  					var pt2 = pts[i];
  					if ((Math.round(pt0.x - pt1.x) != 0 || Math.round(pt1.x - pt2.x) != 0) &&
  						(Math.round(pt0.y - pt1.y) != 0 || Math.round(pt1.y - pt2.y) != 0))
  					{
  						result.push(this.convertPoint(pt1.clone(), false));
  					}
  					pt0 = pt1;
  					pt1 = pt2;
  				}
  				var source = this.state.getVisibleTerminalState(true);
  				var target = this.state.getVisibleTerminalState(false);
  				var rpts = this.state.absolutePoints;
  				if (result.length == 0 && (Math.round(pts[0].x - pts[pts.length - 1].x) == 0 ||
  					Math.round(pts[0].y - pts[pts.length - 1].y) == 0))
  				{
  					result = [point, point];
  				}
  				else if (pts.length == 5 && result.length == 2 && source != null && target != null &&
  						rpts != null && Math.round(rpts[0].x - rpts[rpts.length - 1].x) == 0)
  				{
  					var view = this.graph.getView();
  					var scale = view.getScale();
  					var tr = view.getTranslate();
  					var y0 = view.getRoutingCenterY(source) / scale - tr.y;
  					var sc = this.graph.getConnectionConstraint(edge, source, true);
  					if (sc != null)
  					{
  						var pt = this.graph.getConnectionPoint(source, sc);
  						if (pt != null)
  						{
  							this.convertPoint(pt, false);
  							y0 = pt.y;
  						}
  					}
  					var ye = view.getRoutingCenterY(target) / scale - tr.y;
  					var tc = this.graph.getConnectionConstraint(edge, target, false);
  					if (tc)
  					{
  						var pt = this.graph.getConnectionPoint(target, tc);
  						if (pt != null)
  						{
  							this.convertPoint(pt, false);
  							ye = pt.y;
  						}
  					}
  					result = [new mxPoint(point.x, y0), new mxPoint(point.x, ye)];
  				}
  				this.points = result;
  				edge.view.updateFixedTerminalPoints(edge, source, target);
  				edge.view.updatePoints(edge, this.points, source, target);
  				edge.view.updateFloatingTerminalPoints(edge, source, target);
  			}
  		};
  		mxEdgeSegmentHandler.prototype.connect = function(edge, terminal, isSource, isClone, me)
  		{
  			var model = this.graph.getModel();
  			var geo = model.getGeometry(edge);
  			var result = null;
  			if (geo != null && geo.points != null && geo.points.length > 0)
  			{
  				var pts = this.abspoints;
  				var pt0 = pts[0];
  				var pt1 = pts[1];
  				result = [];
  				for (var i = 2; i < pts.length; i++)
  				{
  					var pt2 = pts[i];
  					if ((Math.round(pt0.x - pt1.x) != 0 || Math.round(pt1.x - pt2.x) != 0) &&
  						(Math.round(pt0.y - pt1.y) != 0 || Math.round(pt1.y - pt2.y) != 0))
  					{
  						result.push(this.convertPoint(pt1.clone(), false));
  					}
  					pt0 = pt1;
  					pt1 = pt2;
  				}
  			}
  			model.beginUpdate();
  			try
  			{
  				if (result != null)
  				{
  					var geo = model.getGeometry(edge);
  					if (geo != null)
  					{
  						geo = geo.clone();
  						geo.points = result;
  						model.setGeometry(edge, geo);
  					}
  				}
  				edge = mxEdgeHandler.prototype.connect.apply(this, arguments);
  			}
  			finally
  			{
  				model.endUpdate();
  			}
  			return edge;
  		};
  		mxEdgeSegmentHandler.prototype.getTooltipForNode = function(node)
  		{
  			return null;
  		};
  		mxEdgeSegmentHandler.prototype.start = function(x, y, index)
  		{
  			mxEdgeHandler.prototype.start.apply(this, arguments);
  			if (this.bends != null && this.bends[index] != null &&
  				!this.isSource && !this.isTarget)
  			{
  				mxUtils.setOpacity(this.bends[index].node, 100);
  			}
  		};
  		mxEdgeSegmentHandler.prototype.createBends = function()
  		{
  			var bends = [];
  			var bend = this.createHandleShape(0);
  			this.initBend(bend);
  			bend.setCursor(mxConstants.CURSOR_TERMINAL_HANDLE);
  			bends.push(bend);
  			var pts = this.getCurrentPoints();
  			if (this.graph.isCellBendable(this.state.cell))
  			{
  				if (this.points == null)
  				{
  					this.points = [];
  				}
  				for (var i = 0; i < pts.length - 1; i++)
  				{
  					bend = this.createVirtualBend();
  					bends.push(bend);
  					var horizontal = Math.round(pts[i].x - pts[i + 1].x) == 0;
  					if (Math.round(pts[i].y - pts[i + 1].y) == 0 && i < pts.length - 2)
  					{
  						horizontal = Math.round(pts[i].x - pts[i + 2].x) == 0;
  					}
  					bend.setCursor((horizontal) ? 'col-resize' : 'row-resize');
  					this.points.push(new mxPoint(0,0));
  				}
  			}
  			var bend = this.createHandleShape(pts.length);
  			this.initBend(bend);
  			bend.setCursor(mxConstants.CURSOR_TERMINAL_HANDLE);
  			bends.push(bend);
  			return bends;
  		};
  		mxEdgeSegmentHandler.prototype.redraw = function()
  		{
  			this.refresh();
  			mxEdgeHandler.prototype.redraw.apply(this, arguments);
  		};
  		mxEdgeSegmentHandler.prototype.redrawInnerBends = function(p0, pe)
  		{
  			if (this.graph.isCellBendable(this.state.cell))
  			{
  				var pts = this.getCurrentPoints();
  				if (pts != null && pts.length > 1)
  				{
  					var straight = false;
  					if (pts.length == 4 && Math.round(pts[1].x - pts[2].x) == 0 && Math.round(pts[1].y - pts[2].y) == 0)
  					{
  						straight = true;
  						if (Math.round(pts[0].y - pts[pts.length - 1].y) == 0)
  						{
  							var cx = pts[0].x + (pts[pts.length - 1].x - pts[0].x) / 2;
  							pts[1] = new mxPoint(cx, pts[1].y);
  							pts[2] = new mxPoint(cx, pts[2].y);
  						}
  						else
  						{
  							var cy = pts[0].y + (pts[pts.length - 1].y - pts[0].y) / 2;
  							pts[1] = new mxPoint(pts[1].x, cy);
  							pts[2] = new mxPoint(pts[2].x, cy);
  						}
  					}
  					for (var i = 0; i < pts.length - 1; i++)
  					{
  						if (this.bends[i + 1] != null)
  						{
  				 			var p0 = pts[i];
  			 				var pe = pts[i + 1];
  					 		var pt = new mxPoint(p0.x + (pe.x - p0.x) / 2, p0.y + (pe.y - p0.y) / 2);
  					 		var b = this.bends[i + 1].bounds;
  					 		this.bends[i + 1].bounds = new mxRectangle(Math.floor(pt.x - b.width / 2),
  					 				Math.floor(pt.y - b.height / 2), b.width, b.height);
  						 	this.bends[i + 1].redraw();
  						 	if (this.manageLabelHandle)
  							{
  								this.checkLabelHandle(this.bends[i + 1].bounds);
  							}
  						}
  					}
  					if (straight)
  					{
  						mxUtils.setOpacity(this.bends[1].node, this.virtualBendOpacity);
  						mxUtils.setOpacity(this.bends[3].node, this.virtualBendOpacity);
  					}
  				}
  			}
  		};
  		__mxOutput.mxEdgeSegmentHandler = typeof mxEdgeSegmentHandler !== 'undefined' ? mxEdgeSegmentHandler : undefined;
  		function mxKeyHandler(graph, target)
  		{
  			if (graph != null)
  			{
  				this.graph = graph;
  				this.target = target || document.documentElement;
  				this.normalKeys = [];
  				this.shiftKeys = [];
  				this.controlKeys = [];
  				this.controlShiftKeys = [];
  				this.keydownHandler = mxUtils.bind(this, function(evt)
  				{
  					this.keyDown(evt);
  				});
  				mxEvent.addListener(this.target, 'keydown', this.keydownHandler);
  				if (mxClient.IS_IE)
  				{
  					mxEvent.addListener(window, 'unload',
  						mxUtils.bind(this, function()
  						{
  							this.destroy();
  						})
  					);
  				}
  			}
  		}		mxKeyHandler.prototype.graph = null;
  		mxKeyHandler.prototype.target = null;
  		mxKeyHandler.prototype.normalKeys = null;
  		mxKeyHandler.prototype.shiftKeys = null;
  		mxKeyHandler.prototype.controlKeys = null;
  		mxKeyHandler.prototype.controlShiftKeys = null;
  		mxKeyHandler.prototype.enabled = true;
  		mxKeyHandler.prototype.isEnabled = function()
  		{
  			return this.enabled;
  		};
  		mxKeyHandler.prototype.setEnabled = function(enabled)
  		{
  			this.enabled = enabled;
  		};
  		mxKeyHandler.prototype.bindKey = function(code, funct)
  		{
  			this.normalKeys[code] = funct;
  		};
  		mxKeyHandler.prototype.bindShiftKey = function(code, funct)
  		{
  			this.shiftKeys[code] = funct;
  		};
  		mxKeyHandler.prototype.bindControlKey = function(code, funct)
  		{
  			this.controlKeys[code] = funct;
  		};
  		mxKeyHandler.prototype.bindControlShiftKey = function(code, funct)
  		{
  			this.controlShiftKeys[code] = funct;
  		};
  		mxKeyHandler.prototype.isControlDown = function(evt)
  		{
  			return mxEvent.isControlDown(evt);
  		};
  		mxKeyHandler.prototype.getFunction = function(evt)
  		{
  			if (evt != null && !mxEvent.isAltDown(evt))
  			{
  				if (this.isControlDown(evt))
  				{
  					if (mxEvent.isShiftDown(evt))
  					{
  						return this.controlShiftKeys[evt.keyCode];
  					}
  					else
  					{
  						return this.controlKeys[evt.keyCode];
  					}
  				}
  				else
  				{
  					if (mxEvent.isShiftDown(evt))
  					{
  						return this.shiftKeys[evt.keyCode];
  					}
  					else
  					{
  						return this.normalKeys[evt.keyCode];
  					}
  				}
  			}
  			return null;
  		};
  		mxKeyHandler.prototype.isGraphEvent = function(evt)
  		{
  			var source = mxEvent.getSource(evt);
  			if ((source == this.target || source.parentNode == this.target) ||
  				(this.graph.cellEditor != null && this.graph.cellEditor.isEventSource(evt)))
  			{
  				return true;
  			}
  			return mxUtils.isAncestorNode(this.graph.container, source);
  		};
  		mxKeyHandler.prototype.keyDown = function(evt)
  		{
  			if (this.isEnabledForEvent(evt))
  			{
  				if (evt.keyCode == 27 )
  				{
  					this.escape(evt);
  				}
  				else if (!this.isEventIgnored(evt))
  				{
  					var boundFunction = this.getFunction(evt);
  					if (boundFunction != null)
  					{
  						boundFunction(evt);
  						mxEvent.consume(evt);
  					}
  				}
  			}
  		};
  		mxKeyHandler.prototype.isEnabledForEvent = function(evt)
  		{
  			return (this.graph.isEnabled() && !mxEvent.isConsumed(evt) &&
  				this.isGraphEvent(evt) && this.isEnabled());
  		};
  		mxKeyHandler.prototype.isEventIgnored = function(evt)
  		{
  			return this.graph.isEditing();
  		};
  		mxKeyHandler.prototype.escape = function(evt)
  		{
  			if (this.graph.isEscapeEnabled())
  			{
  				this.graph.escape(evt);
  			}
  		};
  		mxKeyHandler.prototype.destroy = function()
  		{
  			if (this.target != null && this.keydownHandler != null)
  			{
  				mxEvent.removeListener(this.target, 'keydown', this.keydownHandler);
  				this.keydownHandler = null;
  			}
  			this.target = null;
  		};
  		__mxOutput.mxKeyHandler = typeof mxKeyHandler !== 'undefined' ? mxKeyHandler : undefined;
  		function mxTooltipHandler(graph, delay)
  		{
  			if (graph != null)
  			{
  				this.graph = graph;
  				this.delay = delay || 500;
  				this.graph.addMouseListener(this);
  			}
  		}		mxTooltipHandler.prototype.zIndex = 10005;
  		mxTooltipHandler.prototype.graph = null;
  		mxTooltipHandler.prototype.delay = null;
  		mxTooltipHandler.prototype.ignoreTouchEvents = true;
  		mxTooltipHandler.prototype.hideOnHover = false;
  		mxTooltipHandler.prototype.destroyed = false;
  		mxTooltipHandler.prototype.enabled = true;
  		mxTooltipHandler.prototype.isEnabled = function()
  		{
  			return this.enabled;
  		};
  		mxTooltipHandler.prototype.setEnabled = function(enabled)
  		{
  			this.enabled = enabled;
  		};
  		mxTooltipHandler.prototype.isHideOnHover = function()
  		{
  			return this.hideOnHover;
  		};
  		mxTooltipHandler.prototype.setHideOnHover = function(value)
  		{
  			this.hideOnHover = value;
  		};
  		mxTooltipHandler.prototype.init = function()
  		{
  			if (document.body != null)
  			{
  				this.div = document.createElement('div');
  				this.div.className = 'mxTooltip';
  				this.div.style.visibility = 'hidden';
  				document.body.appendChild(this.div);
  				mxEvent.addGestureListeners(this.div, mxUtils.bind(this, function(evt)
  				{
  					var source = mxEvent.getSource(evt);
  					if (source.nodeName != 'A')
  					{
  						this.hideTooltip();
  					}
  				}));
  			}
  		};
  		mxTooltipHandler.prototype.getStateForEvent = function(me)
  		{
  			return me.getState();
  		};
  		mxTooltipHandler.prototype.mouseDown = function(sender, me)
  		{
  			this.reset(me, false);
  			this.hideTooltip();
  		};
  		mxTooltipHandler.prototype.mouseMove = function(sender, me)
  		{
  			if (me.getX() != this.lastX || me.getY() != this.lastY)
  			{
  				this.reset(me, true);
  				var state = this.getStateForEvent(me);
  				if (this.isHideOnHover() || state != this.state || (me.getSource() != this.node &&
  					(!this.stateSource || (state != null && this.stateSource ==
  					(me.isSource(state.shape) || !me.isSource(state.text))))))
  				{
  					this.hideTooltip();
  				}
  			}
  			this.lastX = me.getX();
  			this.lastY = me.getY();
  		};
  		mxTooltipHandler.prototype.mouseUp = function(sender, me)
  		{
  			this.reset(me, true);
  			this.hideTooltip();
  		};
  		mxTooltipHandler.prototype.resetTimer = function()
  		{
  			if (this.thread != null)
  			{
  				window.clearTimeout(this.thread);
  				this.thread = null;
  			}
  		};
  		mxTooltipHandler.prototype.reset = function(me, restart, state)
  		{
  			if (!this.ignoreTouchEvents || mxEvent.isMouseEvent(me.getEvent()))
  			{
  				this.resetTimer();
  				state = (state != null) ? state : this.getStateForEvent(me);
  				if (restart && this.isEnabled() && state != null && (this.div == null ||
  					this.div.style.visibility == 'hidden'))
  				{
  					var node = me.getSource();
  					var x = me.getX();
  					var y = me.getY();
  					var stateSource = me.isSource(state.shape) || me.isSource(state.text);
  					this.thread = window.setTimeout(mxUtils.bind(this, function()
  					{
  						if (!this.graph.isEditing() && !this.graph.popupMenuHandler.isMenuShowing() && !this.graph.isMouseDown)
  						{
  							var tip = this.graph.getTooltip(state, node, x, y);
  							this.show(tip, x, y);
  							this.state = state;
  							this.node = node;
  							this.stateSource = stateSource;
  						}
  					}), this.delay);
  				}
  			}
  		};
  		mxTooltipHandler.prototype.hide = function()
  		{
  			this.resetTimer();
  			this.hideTooltip();
  		};
  		mxTooltipHandler.prototype.hideTooltip = function()
  		{
  			if (this.div != null)
  			{
  				this.div.style.visibility = 'hidden';
  				this.div.innerHTML = '';
  			}
  		};
  		mxTooltipHandler.prototype.show = function(tip, x, y)
  		{
  			if (!this.destroyed && tip != null && tip.length > 0)
  			{
  				if (this.div == null)
  				{
  					this.init();
  				}
  				var origin = mxUtils.getScrollOrigin();
  				this.div.style.zIndex = this.zIndex;
  				this.div.style.left = (x + origin.x) + 'px';
  				this.div.style.top = (y + mxConstants.TOOLTIP_VERTICAL_OFFSET +
  					origin.y) + 'px';
  				if (!mxUtils.isNode(tip))
  				{
  					this.div.innerHTML = tip.replace(/\n/g, '<br>');
  				}
  				else
  				{
  					this.div.innerHTML = '';
  					this.div.appendChild(tip);
  				}
  				this.div.style.visibility = '';
  				mxUtils.fit(this.div);
  			}
  		};
  		mxTooltipHandler.prototype.destroy = function()
  		{
  			if (!this.destroyed)
  			{
  				this.graph.removeMouseListener(this);
  				mxEvent.release(this.div);
  				if (this.div != null && this.div.parentNode != null)
  				{
  					this.div.parentNode.removeChild(this.div);
  				}
  				this.destroyed = true;
  				this.div = null;
  			}
  		};
  		__mxOutput.mxTooltipHandler = typeof mxTooltipHandler !== 'undefined' ? mxTooltipHandler : undefined;
  		function mxCellTracker(graph, color, funct)
  		{
  			mxCellMarker.call(this, graph, color);
  			this.graph.addMouseListener(this);
  			if (funct != null)
  			{
  				this.getCell = funct;
  			}
  			if (mxClient.IS_IE)
  			{
  				mxEvent.addListener(window, 'unload', mxUtils.bind(this, function()
  				{
  					this.destroy();
  				}));
  			}
  		}		mxUtils.extend(mxCellTracker, mxCellMarker);
  		mxCellTracker.prototype.mouseDown = function(sender, me) { };
  		mxCellTracker.prototype.mouseMove = function(sender, me)
  		{
  			if (this.isEnabled())
  			{
  				this.process(me);
  			}
  		};
  		mxCellTracker.prototype.mouseUp = function(sender, me) { };
  		mxCellTracker.prototype.destroy = function()
  		{
  			if (!this.destroyed)
  			{
  				this.destroyed = true;
  				this.graph.removeMouseListener(this);
  				mxCellMarker.prototype.destroy.apply(this);
  			}
  		};
  		__mxOutput.mxCellTracker = typeof mxCellTracker !== 'undefined' ? mxCellTracker : undefined;
  		function mxCellHighlight(graph, highlightColor, strokeWidth, dashed)
  		{
  			if (graph != null)
  			{
  				this.graph = graph;
  				this.highlightColor = (highlightColor != null) ? highlightColor : mxConstants.DEFAULT_VALID_COLOR;
  				this.strokeWidth = (strokeWidth != null) ? strokeWidth : mxConstants.HIGHLIGHT_STROKEWIDTH;
  				this.dashed = (dashed != null) ? dashed : false;
  				this.opacity = mxConstants.HIGHLIGHT_OPACITY;
  				this.repaintHandler = mxUtils.bind(this, function()
  				{
  					if (this.state != null)
  					{
  						var tmp = this.graph.view.getState(this.state.cell);
  						if (tmp == null)
  						{
  							this.hide();
  						}
  						else
  						{
  							this.state = tmp;
  							this.repaint();
  						}
  					}
  				});
  				this.graph.getView().addListener(mxEvent.SCALE, this.repaintHandler);
  				this.graph.getView().addListener(mxEvent.TRANSLATE, this.repaintHandler);
  				this.graph.getView().addListener(mxEvent.SCALE_AND_TRANSLATE, this.repaintHandler);
  				this.graph.getModel().addListener(mxEvent.CHANGE, this.repaintHandler);
  				this.resetHandler = mxUtils.bind(this, function()
  				{
  					this.hide();
  				});
  				this.graph.getView().addListener(mxEvent.DOWN, this.resetHandler);
  				this.graph.getView().addListener(mxEvent.UP, this.resetHandler);
  			}
  		}		mxCellHighlight.prototype.keepOnTop = false;
  		mxCellHighlight.prototype.graph = null;
  		mxCellHighlight.prototype.state = null;
  		mxCellHighlight.prototype.spacing = 2;
  		mxCellHighlight.prototype.resetHandler = null;
  		mxCellHighlight.prototype.setHighlightColor = function(color)
  		{
  			this.highlightColor = color;
  			if (this.shape != null)
  			{
  				this.shape.stroke = color;
  			}
  		};
  		mxCellHighlight.prototype.drawHighlight = function()
  		{
  			this.shape = this.createShape();
  			this.repaint();
  			if (!this.keepOnTop && this.shape.node.parentNode.firstChild != this.shape.node)
  			{
  				this.shape.node.parentNode.insertBefore(this.shape.node, this.shape.node.parentNode.firstChild);
  			}
  		};
  		mxCellHighlight.prototype.createShape = function()
  		{
  			var shape = this.graph.cellRenderer.createShape(this.state);
  			shape.svgStrokeTolerance = this.graph.tolerance;
  			shape.points = this.state.absolutePoints;
  			shape.apply(this.state);
  			shape.stroke = this.highlightColor;
  			shape.opacity = this.opacity;
  			shape.isDashed = this.dashed;
  			shape.isShadow = false;
  			shape.dialect = (this.graph.dialect != mxConstants.DIALECT_SVG) ? mxConstants.DIALECT_VML : mxConstants.DIALECT_SVG;
  			shape.init(this.graph.getView().getOverlayPane());
  			mxEvent.redirectMouseEvents(shape.node, this.graph, this.state);
  			if (this.graph.dialect != mxConstants.DIALECT_SVG)
  			{
  				shape.pointerEvents = false;
  			}
  			else
  			{
  				shape.svgPointerEvents = 'stroke';
  			}
  			return shape;
  		};
  		mxCellHighlight.prototype.getStrokeWidth = function(state)
  		{
  			return this.strokeWidth;
  		};
  		mxCellHighlight.prototype.repaint = function()
  		{
  			if (this.state != null && this.shape != null)
  			{
  				this.shape.scale = this.state.view.scale;
  				if (this.graph.model.isEdge(this.state.cell))
  				{
  					this.shape.strokewidth = this.getStrokeWidth();
  					this.shape.points = this.state.absolutePoints;
  					this.shape.outline = false;
  				}
  				else
  				{
  					this.shape.bounds = new mxRectangle(this.state.x - this.spacing, this.state.y - this.spacing,
  							this.state.width + 2 * this.spacing, this.state.height + 2 * this.spacing);
  					this.shape.rotation = Number(this.state.style[mxConstants.STYLE_ROTATION] || '0');
  					this.shape.strokewidth = this.getStrokeWidth() / this.state.view.scale;
  					this.shape.outline = true;
  				}
  				if (this.state.shape != null)
  				{
  					this.shape.setCursor(this.state.shape.getCursor());
  				}
  				if (mxClient.IS_QUIRKS || document.documentMode == 8)
  				{
  					if (this.shape.stroke == 'transparent')
  					{
  						this.shape.stroke = 'white';
  						this.shape.opacity = 1;
  					}
  					else
  					{
  						this.shape.opacity = this.opacity;
  					}
  				}
  				this.shape.redraw();
  			}
  		};
  		mxCellHighlight.prototype.hide = function()
  		{
  			this.highlight(null);
  		};
  		mxCellHighlight.prototype.highlight = function(state)
  		{
  			if (this.state != state)
  			{
  				if (this.shape != null)
  				{
  					this.shape.destroy();
  					this.shape = null;
  				}
  				this.state = state;
  				if (this.state != null)
  				{
  					this.drawHighlight();
  				}
  			}
  		};
  		mxCellHighlight.prototype.isHighlightAt = function(x, y)
  		{
  			var hit = false;
  			if (this.shape != null && document.elementFromPoint != null && !mxClient.IS_QUIRKS)
  			{
  				var elt = document.elementFromPoint(x, y);
  				while (elt != null)
  				{
  					if (elt == this.shape.node)
  					{
  						hit = true;
  						break;
  					}
  					elt = elt.parentNode;
  				}
  			}
  			return hit;
  		};
  		mxCellHighlight.prototype.destroy = function()
  		{
  			this.graph.getView().removeListener(this.resetHandler);
  			this.graph.getView().removeListener(this.repaintHandler);
  			this.graph.getModel().removeListener(this.repaintHandler);
  			if (this.shape != null)
  			{
  				this.shape.destroy();
  				this.shape = null;
  			}
  		};
  		__mxOutput.mxCellHighlight = typeof mxCellHighlight !== 'undefined' ? mxCellHighlight : undefined;
  		function mxDefaultKeyHandler(editor)
  		{
  			if (editor != null)
  			{
  				this.editor = editor;
  				this.handler = new mxKeyHandler(editor.graph);
  				var old = this.handler.escape;
  				this.handler.escape = function(evt)
  				{
  					old.apply(this, arguments);
  					editor.hideProperties();
  					editor.fireEvent(new mxEventObject(mxEvent.ESCAPE, 'event', evt));
  				};
  			}
  		}		mxDefaultKeyHandler.prototype.editor = null;
  		mxDefaultKeyHandler.prototype.handler = null;
  		mxDefaultKeyHandler.prototype.bindAction = function (code, action, control)
  		{
  			var keyHandler = mxUtils.bind(this, function()
  			{
  				this.editor.execute(action);
  			});
  			if (control)
  			{
  				this.handler.bindControlKey(code, keyHandler);
  			}
  			else
  			{
  				this.handler.bindKey(code, keyHandler);
  			}
  		};
  		mxDefaultKeyHandler.prototype.destroy = function ()
  		{
  			this.handler.destroy();
  			this.handler = null;
  		};
  		__mxOutput.mxDefaultKeyHandler = typeof mxDefaultKeyHandler !== 'undefined' ? mxDefaultKeyHandler : undefined;
  		function mxDefaultPopupMenu(config)
  		{
  			this.config = config;
  		}		mxDefaultPopupMenu.prototype.imageBasePath = null;
  		mxDefaultPopupMenu.prototype.config = null;
  		mxDefaultPopupMenu.prototype.createMenu = function(editor, menu, cell, evt)
  		{
  			if (this.config != null)
  			{
  				var conditions = this.createConditions(editor, cell, evt);
  				var item = this.config.firstChild;
  				this.addItems(editor, menu, cell, evt, conditions, item, null);
  			}
  		};
  		mxDefaultPopupMenu.prototype.addItems = function(editor, menu, cell, evt, conditions, item, parent)
  		{
  			var addSeparator = false;
  			while (item != null)
  			{
  				if (item.nodeName == 'add')
  				{
  					var condition = item.getAttribute('if');
  					if (condition == null || conditions[condition])
  					{
  						var as = item.getAttribute('as');
  						as = mxResources.get(as) || as;
  						var funct = mxUtils.eval(mxUtils.getTextContent(item));
  						var action = item.getAttribute('action');
  						var icon = item.getAttribute('icon');
  						var iconCls = item.getAttribute('iconCls');
  						var enabledCond = item.getAttribute('enabled-if');
  						var enabled = enabledCond == null || conditions[enabledCond];
  						if (addSeparator)
  						{
  							menu.addSeparator(parent);
  							addSeparator = false;
  						}
  						if (icon != null && this.imageBasePath)
  						{
  							icon = this.imageBasePath + icon;
  						}
  						var row = this.addAction(menu, editor, as, icon, funct, action, cell, parent, iconCls, enabled);
  						this.addItems(editor, menu, cell, evt, conditions, item.firstChild, row);
  					}
  				}
  				else if (item.nodeName == 'separator')
  				{
  					addSeparator = true;
  				}
  				item = item.nextSibling;
  			}
  		};
  		mxDefaultPopupMenu.prototype.addAction = function(menu, editor, lab, icon, funct, action, cell, parent, iconCls, enabled)
  		{
  			var clickHandler = function(evt)
  			{
  				if (typeof(funct) == 'function')
  				{
  					funct.call(editor, editor, cell, evt);
  				}
  				if (action != null)
  				{
  					editor.execute(action, cell, evt);
  				}
  			};
  			return menu.addItem(lab, icon, clickHandler, parent, iconCls, enabled);
  		};
  		mxDefaultPopupMenu.prototype.createConditions = function(editor, cell, evt)
  		{
  			var model = editor.graph.getModel();
  			var childCount = model.getChildCount(cell);
  			var conditions = [];
  			conditions['nocell'] = cell == null;
  			conditions['ncells'] = editor.graph.getSelectionCount() > 1;
  			conditions['notRoot'] = model.getRoot() !=
  				model.getParent(editor.graph.getDefaultParent());
  			conditions['cell'] = cell != null;
  			var isCell = cell != null && editor.graph.getSelectionCount() == 1;
  			conditions['nonEmpty'] = isCell && childCount > 0;
  			conditions['expandable'] = isCell && editor.graph.isCellFoldable(cell, false);
  			conditions['collapsable'] = isCell && editor.graph.isCellFoldable(cell, true);
  			conditions['validRoot'] = isCell && editor.graph.isValidRoot(cell);
  			conditions['emptyValidRoot'] = conditions['validRoot'] && childCount == 0;
  			conditions['swimlane'] = isCell && editor.graph.isSwimlane(cell);
  			var condNodes = this.config.getElementsByTagName('condition');
  			for (var i=0; i<condNodes.length; i++)
  			{
  				var funct = mxUtils.eval(mxUtils.getTextContent(condNodes[i]));
  				var name = condNodes[i].getAttribute('name');
  				if (name != null && typeof(funct) == 'function')
  				{
  					conditions[name] = funct(editor, cell, evt);
  				}
  			}
  			return conditions;
  		};
  		__mxOutput.mxDefaultPopupMenu = typeof mxDefaultPopupMenu !== 'undefined' ? mxDefaultPopupMenu : undefined;
  		function mxDefaultToolbar(container, editor)
  		{
  			this.editor = editor;
  			if (container != null && editor != null)
  			{
  				this.init(container);
  			}
  		}		mxDefaultToolbar.prototype.editor = null;
  		mxDefaultToolbar.prototype.toolbar = null;
  		mxDefaultToolbar.prototype.resetHandler = null;
  		mxDefaultToolbar.prototype.spacing = 4;
  		mxDefaultToolbar.prototype.connectOnDrop = false;
  		mxDefaultToolbar.prototype.init = function(container)
  		{
  			if (container != null)
  			{
  				this.toolbar = new mxToolbar(container);
  				this.toolbar.addListener(mxEvent.SELECT, mxUtils.bind(this, function(sender, evt)
  				{
  					var funct = evt.getProperty('function');
  					if (funct != null)
  					{
  						this.editor.insertFunction = mxUtils.bind(this, function()
  						{
  							funct.apply(this, arguments);
  							this.toolbar.resetMode();
  						});
  					}
  					else
  					{
  						this.editor.insertFunction = null;
  					}
  				}));
  				this.resetHandler = mxUtils.bind(this, function()
  				{
  					if (this.toolbar != null)
  					{
  						this.toolbar.resetMode(true);
  					}
  				});
  				this.editor.graph.addListener(mxEvent.DOUBLE_CLICK, this.resetHandler);
  				this.editor.addListener(mxEvent.ESCAPE, this.resetHandler);
  			}
  		};
  		mxDefaultToolbar.prototype.addItem = function(title, icon, action, pressed)
  		{
  			var clickHandler = mxUtils.bind(this, function()
  			{
  				if (action != null && action.length > 0)
  				{
  					this.editor.execute(action);
  				}
  			});
  			return this.toolbar.addItem(title, icon, clickHandler, pressed);
  		};
  		mxDefaultToolbar.prototype.addSeparator = function(icon)
  		{
  			icon = icon || mxClient.imageBasePath + '/separator.gif';
  			this.toolbar.addSeparator(icon);
  		};
  		mxDefaultToolbar.prototype.addCombo = function()
  		{
  			return this.toolbar.addCombo();
  		};
  		mxDefaultToolbar.prototype.addActionCombo = function(title)
  		{
  			return this.toolbar.addActionCombo(title);
  		};
  		mxDefaultToolbar.prototype.addActionOption = function(combo, title, action)
  		{
  			var clickHandler = mxUtils.bind(this, function()
  			{
  				this.editor.execute(action);
  			});
  			this.addOption(combo, title, clickHandler);
  		};
  		mxDefaultToolbar.prototype.addOption = function(combo, title, value)
  		{
  			return this.toolbar.addOption(combo, title, value);
  		};
  		mxDefaultToolbar.prototype.addMode = function(title, icon, mode, pressed, funct)
  		{
  			var clickHandler = mxUtils.bind(this, function()
  			{
  				this.editor.setMode(mode);
  				if (funct != null)
  				{
  					funct(this.editor);
  				}
  			});
  			return this.toolbar.addSwitchMode(title, icon, clickHandler, pressed);
  		};
  		mxDefaultToolbar.prototype.addPrototype = function(title, icon, ptype, pressed, insert, toggle)
  		{
  			var factory = mxUtils.bind(this, function()
  			{
  				if (typeof(ptype) == 'function')
  				{
  					return ptype();
  				}
  				else if (ptype != null)
  				{
  					return this.editor.graph.cloneCell(ptype);
  				}
  				return null;
  			});
  			var clickHandler = mxUtils.bind(this, function(evt, cell)
  			{
  				if (typeof(insert) == 'function')
  				{
  					insert(this.editor, factory(), evt, cell);
  				}
  				else
  				{
  					this.drop(factory(), evt, cell);
  				}
  				this.toolbar.resetMode();
  				mxEvent.consume(evt);
  			});
  			var img = this.toolbar.addMode(title, icon, clickHandler, pressed, null, toggle);
  			var dropHandler = function(graph, evt, cell)
  			{
  				clickHandler(evt, cell);
  			};
  			this.installDropHandler(img, dropHandler);
  			return img;
  		};
  		mxDefaultToolbar.prototype.drop = function(vertex, evt, target)
  		{
  			var graph = this.editor.graph;
  			var model = graph.getModel();
  			if (target == null ||
  				model.isEdge(target) ||
  				!this.connectOnDrop ||
  				!graph.isCellConnectable(target))
  			{
  				while (target != null &&
  					!graph.isValidDropTarget(target, [vertex], evt))
  				{
  					target = model.getParent(target);
  				}
  				this.insert(vertex, evt, target);
  			}
  			else
  			{
  				this.connect(vertex, evt, target);
  			}
  		};
  		mxDefaultToolbar.prototype.insert = function(vertex, evt, target)
  		{
  			var graph = this.editor.graph;
  			if (graph.canImportCell(vertex))
  			{
  				var x = mxEvent.getClientX(evt);
  				var y = mxEvent.getClientY(evt);
  				var pt = mxUtils.convertPoint(graph.container, x, y);
  				if (graph.isSplitEnabled() &&
  					graph.isSplitTarget(target, [vertex], evt))
  				{
  					return graph.splitEdge(target, [vertex], null, pt.x, pt.y);
  				}
  				else
  				{
  					return this.editor.addVertex(target, vertex, pt.x, pt.y);
  				}
  			}
  			return null;
  		};
  		mxDefaultToolbar.prototype.connect = function(vertex, evt, source)
  		{
  			var graph = this.editor.graph;
  			var model = graph.getModel();
  			if (source != null &&
  				graph.isCellConnectable(vertex) &&
  				graph.isEdgeValid(null, source, vertex))
  			{
  				var edge = null;
  				model.beginUpdate();
  				try
  				{
  					var geo = model.getGeometry(source);
  					var g = model.getGeometry(vertex).clone();
  					g.x = geo.x + (geo.width - g.width) / 2;
  					g.y = geo.y + (geo.height - g.height) / 2;
  					var step = this.spacing * graph.gridSize;
  					var dist = model.getDirectedEdgeCount(source, true) * 20;
  					if (this.editor.horizontalFlow)
  					{
  						g.x += (g.width + geo.width) / 2 + step + dist;
  					}
  					else
  					{
  						g.y += (g.height + geo.height) / 2 + step + dist;
  					}
  					vertex.setGeometry(g);
  					var parent = model.getParent(source);
  					graph.addCell(vertex, parent);
  					graph.constrainChild(vertex);
  					edge = this.editor.createEdge(source, vertex);
  					if (model.getGeometry(edge) == null)
  					{
  						var edgeGeometry = new mxGeometry();
  						edgeGeometry.relative = true;
  						model.setGeometry(edge, edgeGeometry);
  					}
  					graph.addEdge(edge, parent, source, vertex);
  				}
  				finally
  				{
  					model.endUpdate();
  				}
  				graph.setSelectionCells([vertex, edge]);
  				graph.scrollCellToVisible(vertex);
  			}
  		};
  		mxDefaultToolbar.prototype.installDropHandler = function (img, dropHandler)
  		{
  			var sprite = document.createElement('img');
  			sprite.setAttribute('src', img.getAttribute('src'));
  			var loader = mxUtils.bind(this, function(evt)
  			{
  				sprite.style.width = (2 * img.offsetWidth) + 'px';
  				sprite.style.height = (2 * img.offsetHeight) + 'px';
  				mxUtils.makeDraggable(img, this.editor.graph, dropHandler,
  					sprite);
  				mxEvent.removeListener(sprite, 'load', loader);
  			});
  			if (mxClient.IS_IE)
  			{
  				loader();
  			}
  			else
  			{
  				mxEvent.addListener(sprite, 'load', loader);
  			}
  		};
  		mxDefaultToolbar.prototype.destroy = function ()
  		{
  			if (this.resetHandler != null)
  			{
  				this.editor.graph.removeListener('dblclick', this.resetHandler);
  				this.editor.removeListener('escape', this.resetHandler);
  				this.resetHandler = null;
  			}
  			if (this.toolbar != null)
  			{
  				this.toolbar.destroy();
  				this.toolbar = null;
  			}
  		};
  		__mxOutput.mxDefaultToolbar = typeof mxDefaultToolbar !== 'undefined' ? mxDefaultToolbar : undefined;
  		function mxEditor(config)
  		{
  			this.actions = [];
  			this.addActions();
  			if (document.body != null)
  			{
  				this.cycleAttributeValues = [];
  				this.popupHandler = new mxDefaultPopupMenu();
  				this.undoManager = new mxUndoManager();
  				this.graph = this.createGraph();
  				this.toolbar = this.createToolbar();
  				this.keyHandler = new mxDefaultKeyHandler(this);
  				this.configure(config);
  				this.graph.swimlaneIndicatorColorAttribute = this.cycleAttributeName;
  				if (this.onInit != null)
  				{
  					this.onInit();
  				}
  				if (mxClient.IS_IE)
  				{
  					mxEvent.addListener(window, 'unload', mxUtils.bind(this, function()
  					{
  						this.destroy();
  					}));
  				}
  			}
  		}		if (mxLoadResources)
  		{
  			mxResources.add(mxClient.basePath + '/resources/editor');
  		}
  		else
  		{
  			mxClient.defaultBundles.push(mxClient.basePath + '/resources/editor');
  		}
  		mxEditor.prototype = new mxEventSource();
  		mxEditor.prototype.constructor = mxEditor;
  		mxEditor.prototype.askZoomResource = (mxClient.language != 'none') ? 'askZoom' : '';
  		mxEditor.prototype.lastSavedResource = (mxClient.language != 'none') ? 'lastSaved' : '';
  		mxEditor.prototype.currentFileResource = (mxClient.language != 'none') ? 'currentFile' : '';
  		mxEditor.prototype.propertiesResource = (mxClient.language != 'none') ? 'properties' : '';
  		mxEditor.prototype.tasksResource = (mxClient.language != 'none') ? 'tasks' : '';
  		mxEditor.prototype.helpResource = (mxClient.language != 'none') ? 'help' : '';
  		mxEditor.prototype.outlineResource = (mxClient.language != 'none') ? 'outline' : '';
  		mxEditor.prototype.outline = null;
  		mxEditor.prototype.graph = null;
  		mxEditor.prototype.graphRenderHint = null;
  		mxEditor.prototype.toolbar = null;
  		mxEditor.prototype.status = null;
  		mxEditor.prototype.popupHandler = null;
  		mxEditor.prototype.undoManager = null;
  		mxEditor.prototype.keyHandler = null;
  		mxEditor.prototype.actions = null;
  		mxEditor.prototype.dblClickAction = 'edit';
  		mxEditor.prototype.swimlaneRequired = false;
  		mxEditor.prototype.disableContextMenu = true;
  		mxEditor.prototype.insertFunction = null;
  		mxEditor.prototype.forcedInserting = false;
  		mxEditor.prototype.templates = null;
  		mxEditor.prototype.defaultEdge = null;
  		mxEditor.prototype.defaultEdgeStyle = null;
  		mxEditor.prototype.defaultGroup = null;
  		mxEditor.prototype.groupBorderSize = null;
  		mxEditor.prototype.filename = null;
  		mxEditor.prototype.linefeed = '&#xa;';
  		mxEditor.prototype.postParameterName = 'xml';
  		mxEditor.prototype.escapePostData = true;
  		mxEditor.prototype.urlPost = null;
  		mxEditor.prototype.urlImage = null;
  		mxEditor.prototype.horizontalFlow = false;
  		mxEditor.prototype.layoutDiagram = false;
  		mxEditor.prototype.swimlaneSpacing = 0;
  		mxEditor.prototype.maintainSwimlanes = false;
  		mxEditor.prototype.layoutSwimlanes = false;
  		mxEditor.prototype.cycleAttributeValues = null;
  		mxEditor.prototype.cycleAttributeIndex = 0;
  		mxEditor.prototype.cycleAttributeName = 'fillColor';
  		mxEditor.prototype.tasks = null;
  		mxEditor.prototype.tasksWindowImage = null;
  		mxEditor.prototype.tasksTop = 20;
  		mxEditor.prototype.help = null;
  		mxEditor.prototype.helpWindowImage = null;
  		mxEditor.prototype.urlHelp = null;
  		mxEditor.prototype.helpWidth = 300;
  		mxEditor.prototype.helpHeight = 260;
  		mxEditor.prototype.propertiesWidth = 240;
  		mxEditor.prototype.propertiesHeight = null;
  		mxEditor.prototype.movePropertiesDialog = false;
  		mxEditor.prototype.validating = false;
  		mxEditor.prototype.modified = false;
  		mxEditor.prototype.isModified = function ()
  		{
  			return this.modified;
  		};
  		mxEditor.prototype.setModified = function (value)
  		{
  			this.modified = value;
  		};
  		mxEditor.prototype.addActions = function ()
  		{
  			this.addAction('save', function(editor)
  			{
  				editor.save();
  			});
  			this.addAction('print', function(editor)
  			{
  				var preview = new mxPrintPreview(editor.graph, 1);
  				preview.open();
  			});
  			this.addAction('show', function(editor)
  			{
  				mxUtils.show(editor.graph, null, 10, 10);
  			});
  			this.addAction('exportImage', function(editor)
  			{
  				var url = editor.getUrlImage();
  				if (url == null || mxClient.IS_LOCAL)
  				{
  					editor.execute('show');
  				}
  				else
  				{
  					var node = mxUtils.getViewXml(editor.graph, 1);
  					var xml = mxUtils.getXml(node, '\n');
  					mxUtils.submit(url, editor.postParameterName + '=' +
  						encodeURIComponent(xml), document, '_blank');
  				}
  			});
  			this.addAction('refresh', function(editor)
  			{
  				editor.graph.refresh();
  			});
  			this.addAction('cut', function(editor)
  			{
  				if (editor.graph.isEnabled())
  				{
  					mxClipboard.cut(editor.graph);
  				}
  			});
  			this.addAction('copy', function(editor)
  			{
  				if (editor.graph.isEnabled())
  				{
  					mxClipboard.copy(editor.graph);
  				}
  			});
  			this.addAction('paste', function(editor)
  			{
  				if (editor.graph.isEnabled())
  				{
  					mxClipboard.paste(editor.graph);
  				}
  			});
  			this.addAction('delete', function(editor)
  			{
  				if (editor.graph.isEnabled())
  				{
  					editor.graph.removeCells();
  				}
  			});
  			this.addAction('group', function(editor)
  			{
  				if (editor.graph.isEnabled())
  				{
  					editor.graph.setSelectionCell(editor.groupCells());
  				}
  			});
  			this.addAction('ungroup', function(editor)
  			{
  				if (editor.graph.isEnabled())
  				{
  					editor.graph.setSelectionCells(editor.graph.ungroupCells());
  				}
  			});
  			this.addAction('removeFromParent', function(editor)
  			{
  				if (editor.graph.isEnabled())
  				{
  					editor.graph.removeCellsFromParent();
  				}
  			});
  			this.addAction('undo', function(editor)
  			{
  				if (editor.graph.isEnabled())
  				{
  					editor.undo();
  				}
  			});
  			this.addAction('redo', function(editor)
  			{
  				if (editor.graph.isEnabled())
  				{
  					editor.redo();
  				}
  			});
  			this.addAction('zoomIn', function(editor)
  			{
  				editor.graph.zoomIn();
  			});
  			this.addAction('zoomOut', function(editor)
  			{
  				editor.graph.zoomOut();
  			});
  			this.addAction('actualSize', function(editor)
  			{
  				editor.graph.zoomActual();
  			});
  			this.addAction('fit', function(editor)
  			{
  				editor.graph.fit();
  			});
  			this.addAction('showProperties', function(editor, cell)
  			{
  				editor.showProperties(cell);
  			});
  			this.addAction('selectAll', function(editor)
  			{
  				if (editor.graph.isEnabled())
  				{
  					editor.graph.selectAll();
  				}
  			});
  			this.addAction('selectNone', function(editor)
  			{
  				if (editor.graph.isEnabled())
  				{
  					editor.graph.clearSelection();
  				}
  			});
  			this.addAction('selectVertices', function(editor)
  			{
  				if (editor.graph.isEnabled())
  				{
  					editor.graph.selectVertices();
  				}
  			});
  			this.addAction('selectEdges', function(editor)
  			{
  				if (editor.graph.isEnabled())
  				{
  					editor.graph.selectEdges();
  				}
  			});
  			this.addAction('edit', function(editor, cell)
  			{
  				if (editor.graph.isEnabled() &&
  					editor.graph.isCellEditable(cell))
  				{
  					editor.graph.startEditingAtCell(cell);
  				}
  			});
  			this.addAction('toBack', function(editor, cell)
  			{
  				if (editor.graph.isEnabled())
  				{
  					editor.graph.orderCells(true);
  				}
  			});
  			this.addAction('toFront', function(editor, cell)
  			{
  				if (editor.graph.isEnabled())
  				{
  					editor.graph.orderCells(false);
  				}
  			});
  			this.addAction('enterGroup', function(editor, cell)
  			{
  				editor.graph.enterGroup(cell);
  			});
  			this.addAction('exitGroup', function(editor)
  			{
  				editor.graph.exitGroup();
  			});
  			this.addAction('home', function(editor)
  			{
  				editor.graph.home();
  			});
  			this.addAction('selectPrevious', function(editor)
  			{
  				if (editor.graph.isEnabled())
  				{
  					editor.graph.selectPreviousCell();
  				}
  			});
  			this.addAction('selectNext', function(editor)
  			{
  				if (editor.graph.isEnabled())
  				{
  					editor.graph.selectNextCell();
  				}
  			});
  			this.addAction('selectParent', function(editor)
  			{
  				if (editor.graph.isEnabled())
  				{
  					editor.graph.selectParentCell();
  				}
  			});
  			this.addAction('selectChild', function(editor)
  			{
  				if (editor.graph.isEnabled())
  				{
  					editor.graph.selectChildCell();
  				}
  			});
  			this.addAction('collapse', function(editor)
  			{
  				if (editor.graph.isEnabled())
  				{
  					editor.graph.foldCells(true);
  				}
  			});
  			this.addAction('collapseAll', function(editor)
  			{
  				if (editor.graph.isEnabled())
  				{
  					var cells = editor.graph.getChildVertices();
  					editor.graph.foldCells(true, false, cells);
  				}
  			});
  			this.addAction('expand', function(editor)
  			{
  				if (editor.graph.isEnabled())
  				{
  					editor.graph.foldCells(false);
  				}
  			});
  			this.addAction('expandAll', function(editor)
  			{
  				if (editor.graph.isEnabled())
  				{
  					var cells = editor.graph.getChildVertices();
  					editor.graph.foldCells(false, false, cells);
  				}
  			});
  			this.addAction('bold', function(editor)
  			{
  				if (editor.graph.isEnabled())
  				{
  					editor.graph.toggleCellStyleFlags(
  						mxConstants.STYLE_FONTSTYLE,
  						mxConstants.FONT_BOLD);
  				}
  			});
  			this.addAction('italic', function(editor)
  			{
  				if (editor.graph.isEnabled())
  				{
  					editor.graph.toggleCellStyleFlags(
  						mxConstants.STYLE_FONTSTYLE,
  						mxConstants.FONT_ITALIC);
  				}
  			});
  			this.addAction('underline', function(editor)
  			{
  				if (editor.graph.isEnabled())
  				{
  					editor.graph.toggleCellStyleFlags(
  						mxConstants.STYLE_FONTSTYLE,
  						mxConstants.FONT_UNDERLINE);
  				}
  			});
  			this.addAction('alignCellsLeft', function(editor)
  			{
  				if (editor.graph.isEnabled())
  				{
  					editor.graph.alignCells(mxConstants.ALIGN_LEFT);
  				}
  			});
  			this.addAction('alignCellsCenter', function(editor)
  			{
  				if (editor.graph.isEnabled())
  				{
  					editor.graph.alignCells(mxConstants.ALIGN_CENTER);
  				}
  			});
  			this.addAction('alignCellsRight', function(editor)
  			{
  				if (editor.graph.isEnabled())
  				{
  					editor.graph.alignCells(mxConstants.ALIGN_RIGHT);
  				}
  			});
  			this.addAction('alignCellsTop', function(editor)
  			{
  				if (editor.graph.isEnabled())
  				{
  					editor.graph.alignCells(mxConstants.ALIGN_TOP);
  				}
  			});
  			this.addAction('alignCellsMiddle', function(editor)
  			{
  				if (editor.graph.isEnabled())
  				{
  					editor.graph.alignCells(mxConstants.ALIGN_MIDDLE);
  				}
  			});
  			this.addAction('alignCellsBottom', function(editor)
  			{
  				if (editor.graph.isEnabled())
  				{
  					editor.graph.alignCells(mxConstants.ALIGN_BOTTOM);
  				}
  			});
  			this.addAction('alignFontLeft', function(editor)
  			{
  				editor.graph.setCellStyles(
  					mxConstants.STYLE_ALIGN,
  					mxConstants.ALIGN_LEFT);
  			});
  			this.addAction('alignFontCenter', function(editor)
  			{
  				if (editor.graph.isEnabled())
  				{
  					editor.graph.setCellStyles(
  						mxConstants.STYLE_ALIGN,
  						mxConstants.ALIGN_CENTER);
  				}
  			});
  			this.addAction('alignFontRight', function(editor)
  			{
  				if (editor.graph.isEnabled())
  				{
  					editor.graph.setCellStyles(
  						mxConstants.STYLE_ALIGN,
  						mxConstants.ALIGN_RIGHT);
  				}
  			});
  			this.addAction('alignFontTop', function(editor)
  			{
  				if (editor.graph.isEnabled())
  				{
  					editor.graph.setCellStyles(
  						mxConstants.STYLE_VERTICAL_ALIGN,
  						mxConstants.ALIGN_TOP);
  				}
  			});
  			this.addAction('alignFontMiddle', function(editor)
  			{
  				if (editor.graph.isEnabled())
  				{
  					editor.graph.setCellStyles(
  						mxConstants.STYLE_VERTICAL_ALIGN,
  						mxConstants.ALIGN_MIDDLE);
  				}
  			});
  			this.addAction('alignFontBottom', function(editor)
  			{
  				if (editor.graph.isEnabled())
  				{
  					editor.graph.setCellStyles(
  						mxConstants.STYLE_VERTICAL_ALIGN,
  						mxConstants.ALIGN_BOTTOM);
  				}
  			});
  			this.addAction('zoom', function(editor)
  			{
  				var current = editor.graph.getView().scale*100;
  				var scale = parseFloat(mxUtils.prompt(
  					mxResources.get(editor.askZoomResource) ||
  					editor.askZoomResource,
  					current))/100;
  				if (!isNaN(scale))
  				{
  					editor.graph.getView().setScale(scale);
  				}
  			});
  			this.addAction('toggleTasks', function(editor)
  			{
  				if (editor.tasks != null)
  				{
  					editor.tasks.setVisible(!editor.tasks.isVisible());
  				}
  				else
  				{
  					editor.showTasks();
  				}
  			});
  			this.addAction('toggleHelp', function(editor)
  			{
  				if (editor.help != null)
  				{
  					editor.help.setVisible(!editor.help.isVisible());
  				}
  				else
  				{
  					editor.showHelp();
  				}
  			});
  			this.addAction('toggleOutline', function(editor)
  			{
  				if (editor.outline == null)
  				{
  					editor.showOutline();
  				}
  				else
  				{
  					editor.outline.setVisible(!editor.outline.isVisible());
  				}
  			});
  			this.addAction('toggleConsole', function(editor)
  			{
  				mxLog.setVisible(!mxLog.isVisible());
  			});
  		};
  		mxEditor.prototype.configure = function (node)
  		{
  			if (node != null)
  			{
  				var dec = new mxCodec(node.ownerDocument);
  				dec.decode(node, this);
  				this.resetHistory();
  			}
  		};
  		mxEditor.prototype.resetFirstTime = function ()
  		{
  			document.cookie =
  				'mxgraph=seen; expires=Fri, 27 Jul 2001 02:47:11 UTC; path=/';
  		};
  		mxEditor.prototype.resetHistory = function ()
  		{
  			this.lastSnapshot = new Date().getTime();
  			this.undoManager.clear();
  			this.ignoredChanges = 0;
  			this.setModified(false);
  		};
  		mxEditor.prototype.addAction = function (actionname, funct)
  		{
  			this.actions[actionname] = funct;
  		};
  		mxEditor.prototype.execute = function (actionname, cell, evt)
  		{
  			var action = this.actions[actionname];
  			if (action != null)
  			{
  				try
  				{
  					var args = arguments;
  					args[0] = this;
  					action.apply(this, args);
  				}
  				catch (e)
  				{
  					mxUtils.error('Cannot execute ' + actionname +
  						': ' + e.message, 280, true);
  					throw e;
  				}
  			}
  			else
  			{
  				mxUtils.error('Cannot find action '+actionname, 280, true);
  			}
  		};
  		mxEditor.prototype.addTemplate = function (name, template)
  		{
  			this.templates[name] = template;
  		};
  		mxEditor.prototype.getTemplate = function (name)
  		{
  			return this.templates[name];
  		};
  		mxEditor.prototype.createGraph = function ()
  		{
  			var graph = new mxGraph(null, null, this.graphRenderHint);
  			graph.setTooltips(true);
  			graph.setPanning(true);
  			this.installDblClickHandler(graph);
  			this.installUndoHandler(graph);
  			this.installDrillHandler(graph);
  			this.installChangeHandler(graph);
  			this.installInsertHandler(graph);
  			graph.popupMenuHandler.factoryMethod =
  				mxUtils.bind(this, function(menu, cell, evt)
  				{
  					return this.createPopupMenu(menu, cell, evt);
  				});
  			graph.connectionHandler.factoryMethod =
  				mxUtils.bind(this, function(source, target)
  				{
  					return this.createEdge(source, target);
  				});
  			this.createSwimlaneManager(graph);
  			this.createLayoutManager(graph);
  			return graph;
  		};
  		mxEditor.prototype.createSwimlaneManager = function (graph)
  		{
  			var swimlaneMgr = new mxSwimlaneManager(graph, false);
  			swimlaneMgr.isHorizontal = mxUtils.bind(this, function()
  			{
  				return this.horizontalFlow;
  			});
  			swimlaneMgr.isEnabled = mxUtils.bind(this, function()
  			{
  				return this.maintainSwimlanes;
  			});
  			return swimlaneMgr;
  		};
  		mxEditor.prototype.createLayoutManager = function (graph)
  		{
  			var layoutMgr = new mxLayoutManager(graph);
  			var self = this;
  			layoutMgr.getLayout = function(cell)
  			{
  				var layout = null;
  				var model = self.graph.getModel();
  				if (model.getParent(cell) != null)
  				{
  					if (self.layoutSwimlanes &&
  						graph.isSwimlane(cell))
  					{
  						if (self.swimlaneLayout == null)
  						{
  							self.swimlaneLayout = self.createSwimlaneLayout();
  						}
  						layout = self.swimlaneLayout;
  					}
  					else if (self.layoutDiagram &&
  						(graph.isValidRoot(cell) ||
  						model.getParent(model.getParent(cell)) == null))
  					{
  						if (self.diagramLayout == null)
  						{
  							self.diagramLayout = self.createDiagramLayout();
  						}
  						layout = self.diagramLayout;
  					}
  				}
  				return layout;
  			};
  			return layoutMgr;
  		};
  		mxEditor.prototype.setGraphContainer = function (container)
  		{
  			if (this.graph.container == null)
  			{
  				this.graph.init(container);
  				this.rubberband = new mxRubberband(this.graph);
  				if (this.disableContextMenu)
  				{
  					mxEvent.disableContextMenu(container);
  				}
  				if (mxClient.IS_QUIRKS)
  				{
  					new mxDivResizer(container);
  				}
  			}
  		};
  		mxEditor.prototype.installDblClickHandler = function (graph)
  		{
  			graph.addListener(mxEvent.DOUBLE_CLICK,
  				mxUtils.bind(this, function(sender, evt)
  				{
  					var cell = evt.getProperty('cell');
  					if (cell != null &&
  						graph.isEnabled() &&
  						this.dblClickAction != null)
  					{
  						this.execute(this.dblClickAction, cell);
  						evt.consume();
  					}
  				})
  			);
  		};
  		mxEditor.prototype.installUndoHandler = function (graph)
  		{
  			var listener = mxUtils.bind(this, function(sender, evt)
  			{
  				var edit = evt.getProperty('edit');
  				this.undoManager.undoableEditHappened(edit);
  			});
  			graph.getModel().addListener(mxEvent.UNDO, listener);
  			graph.getView().addListener(mxEvent.UNDO, listener);
  			var undoHandler = function(sender, evt)
  			{
  				var changes = evt.getProperty('edit').changes;
  				graph.setSelectionCells(graph.getSelectionCellsForChanges(changes));
  			};
  			this.undoManager.addListener(mxEvent.UNDO, undoHandler);
  			this.undoManager.addListener(mxEvent.REDO, undoHandler);
  		};
  		mxEditor.prototype.installDrillHandler = function (graph)
  		{
  			var listener = mxUtils.bind(this, function(sender)
  			{
  				this.fireEvent(new mxEventObject(mxEvent.ROOT));
  			});
  			graph.getView().addListener(mxEvent.DOWN, listener);
  			graph.getView().addListener(mxEvent.UP, listener);
  		};
  		mxEditor.prototype.installChangeHandler = function (graph)
  		{
  			var listener = mxUtils.bind(this, function(sender, evt)
  			{
  				this.setModified(true);
  				if (this.validating == true)
  				{
  					graph.validateGraph();
  				}
  				var changes = evt.getProperty('edit').changes;
  				for (var i = 0; i < changes.length; i++)
  				{
  					var change = changes[i];
  					if (change instanceof mxRootChange ||
  						(change instanceof mxValueChange &&
  						change.cell == this.graph.model.root) ||
  						(change instanceof mxCellAttributeChange &&
  						change.cell == this.graph.model.root))
  					{
  						this.fireEvent(new mxEventObject(mxEvent.ROOT));
  						break;
  					}
  				}
  			});
  			graph.getModel().addListener(mxEvent.CHANGE, listener);
  		};
  		mxEditor.prototype.installInsertHandler = function (graph)
  		{
  			var self = this;
  			var insertHandler =
  			{
  				mouseDown: function(sender, me)
  				{
  					if (self.insertFunction != null &&
  						!me.isPopupTrigger() &&
  						(self.forcedInserting ||
  						me.getState() == null))
  					{
  						self.graph.clearSelection();
  						self.insertFunction(me.getEvent(), me.getCell());
  						this.isActive = true;
  						me.consume();
  					}
  				},
  				mouseMove: function(sender, me)
  				{
  					if (this.isActive)
  					{
  						me.consume();
  					}
  				},
  				mouseUp: function(sender, me)
  				{
  					if (this.isActive)
  					{
  						this.isActive = false;
  						me.consume();
  					}
  				}
  			};
  			graph.addMouseListener(insertHandler);
  		};
  		mxEditor.prototype.createDiagramLayout = function ()
  		{
  			var gs = this.graph.gridSize;
  			var layout = new mxStackLayout(this.graph, !this.horizontalFlow,
  				 this.swimlaneSpacing, 2*gs, 2*gs);
  			layout.isVertexIgnored = function(cell)
  			{
  				return !layout.graph.isSwimlane(cell);
  			};
  			return layout;
  		};
  		mxEditor.prototype.createSwimlaneLayout = function ()
  		{
  			return new mxCompactTreeLayout(this.graph, this.horizontalFlow);
  		};
  		mxEditor.prototype.createToolbar = function ()
  		{
  			return new mxDefaultToolbar(null, this);
  		};
  		mxEditor.prototype.setToolbarContainer = function (container)
  		{
  			this.toolbar.init(container);
  			if (mxClient.IS_QUIRKS)
  			{
  				new mxDivResizer(container);
  			}
  		};
  		mxEditor.prototype.setStatusContainer = function (container)
  		{
  			if (this.status == null)
  			{
  				this.status = container;
  				this.addListener(mxEvent.SAVE, mxUtils.bind(this, function()
  				{
  					var tstamp = new Date().toLocaleString();
  					this.setStatus((mxResources.get(this.lastSavedResource) ||
  						this.lastSavedResource)+': '+tstamp);
  				}));
  				this.addListener(mxEvent.OPEN, mxUtils.bind(this, function()
  				{
  					this.setStatus((mxResources.get(this.currentFileResource) ||
  						this.currentFileResource)+': '+this.filename);
  				}));
  				if (mxClient.IS_QUIRKS)
  				{
  					new mxDivResizer(container);
  				}
  			}
  		};
  		mxEditor.prototype.setStatus = function (message)
  		{
  			if (this.status != null && message != null)
  			{
  				this.status.innerHTML = message;
  			}
  		};
  		mxEditor.prototype.setTitleContainer = function (container)
  		{
  			this.addListener(mxEvent.ROOT, mxUtils.bind(this, function(sender)
  			{
  				container.innerHTML = this.getTitle();
  			}));
  			if (mxClient.IS_QUIRKS)
  			{
  				new mxDivResizer(container);
  			}
  		};
  		mxEditor.prototype.treeLayout = function (cell, horizontal)
  		{
  			if (cell != null)
  			{
  				var layout = new mxCompactTreeLayout(this.graph, horizontal);
  				layout.execute(cell);
  			}
  		};
  		mxEditor.prototype.getTitle = function ()
  		{
  			var title = '';
  			var graph = this.graph;
  			var cell = graph.getCurrentRoot();
  			while (cell != null &&
  				   graph.getModel().getParent(
  						graph.getModel().getParent(cell)) != null)
  			{
  				if (graph.isValidRoot(cell))
  				{
  					title = ' > ' +
  					graph.convertValueToString(cell) + title;
  				}
  				cell = graph.getModel().getParent(cell);
  			}
  			var prefix = this.getRootTitle();
  			return prefix + title;
  		};
  		mxEditor.prototype.getRootTitle = function ()
  		{
  			var root = this.graph.getModel().getRoot();
  			return this.graph.convertValueToString(root);
  		};
  		mxEditor.prototype.undo = function ()
  		{
  			this.undoManager.undo();
  		};
  		mxEditor.prototype.redo = function ()
  		{
  			this.undoManager.redo();
  		};
  		mxEditor.prototype.groupCells = function ()
  		{
  			var border = (this.groupBorderSize != null) ?
  				this.groupBorderSize :
  				this.graph.gridSize;
  			return this.graph.groupCells(this.createGroup(), border);
  		};
  		mxEditor.prototype.createGroup = function ()
  		{
  			var model = this.graph.getModel();
  			return model.cloneCell(this.defaultGroup);
  		};
  		mxEditor.prototype.open = function (filename)
  		{
  			if (filename != null)
  			{
  				var xml = mxUtils.load(filename).getXml();
  				this.readGraphModel(xml.documentElement);
  				this.filename = filename;
  				this.fireEvent(new mxEventObject(mxEvent.OPEN, 'filename', filename));
  			}
  		};
  		mxEditor.prototype.readGraphModel = function (node)
  		{
  			var dec = new mxCodec(node.ownerDocument);
  			dec.decode(node, this.graph.getModel());
  			this.resetHistory();
  		};
  		mxEditor.prototype.save = function (url, linefeed)
  		{
  			url = url || this.getUrlPost();
  			if (url != null && url.length > 0)
  			{
  				var data = this.writeGraphModel(linefeed);
  				this.postDiagram(url, data);
  				this.setModified(false);
  			}
  			this.fireEvent(new mxEventObject(mxEvent.SAVE, 'url', url));
  		};
  		mxEditor.prototype.postDiagram = function (url, data)
  		{
  			if (this.escapePostData)
  			{
  				data = encodeURIComponent(data);
  			}
  			mxUtils.post(url, this.postParameterName+'='+data,
  				mxUtils.bind(this, function(req)
  				{
  					this.fireEvent(new mxEventObject(mxEvent.POST,
  						'request', req, 'url', url, 'data', data));
  				})
  			);
  		};
  		mxEditor.prototype.writeGraphModel = function (linefeed)
  		{
  			linefeed = (linefeed != null) ? linefeed : this.linefeed;
  			var enc = new mxCodec();
  			var node = enc.encode(this.graph.getModel());
  			return mxUtils.getXml(node, linefeed);
  		};
  		mxEditor.prototype.getUrlPost = function ()
  		{
  			return this.urlPost;
  		};
  		mxEditor.prototype.getUrlImage = function ()
  		{
  			return this.urlImage;
  		};
  		mxEditor.prototype.swapStyles = function (first, second)
  		{
  			var style = this.graph.getStylesheet().styles[second];
  			this.graph.getView().getStylesheet().putCellStyle(
  				second, this.graph.getStylesheet().styles[first]);
  			this.graph.getStylesheet().putCellStyle(first, style);
  			this.graph.refresh();
  		};
  		mxEditor.prototype.showProperties = function (cell)
  		{
  			cell = cell || this.graph.getSelectionCell();
  			if (cell == null)
  			{
  				cell = this.graph.getCurrentRoot();
  				if (cell == null)
  				{
  					cell = this.graph.getModel().getRoot();
  				}
  			}
  			if (cell != null)
  			{
  				this.graph.stopEditing(true);
  				var offset = mxUtils.getOffset(this.graph.container);
  				var x = offset.x+10;
  				var y = offset.y;
  				if (this.properties != null && !this.movePropertiesDialog)
  				{
  					x = this.properties.getX();
  					y = this.properties.getY();
  				}
  				else
  				{
  					var bounds = this.graph.getCellBounds(cell);
  					if (bounds != null)
  					{
  						x += bounds.x+Math.min(200, bounds.width);
  						y += bounds.y;
  					}
  				}
  				this.hideProperties();
  				var node = this.createProperties(cell);
  				if (node != null)
  				{
  					this.properties = new mxWindow(mxResources.get(this.propertiesResource) ||
  						this.propertiesResource, node, x, y, this.propertiesWidth, this.propertiesHeight, false);
  					this.properties.setVisible(true);
  				}
  			}
  		};
  		mxEditor.prototype.isPropertiesVisible = function ()
  		{
  			return this.properties != null;
  		};
  		mxEditor.prototype.createProperties = function (cell)
  		{
  			var model = this.graph.getModel();
  			var value = model.getValue(cell);
  			if (mxUtils.isNode(value))
  			{
  				var form = new mxForm('properties');
  				var id = form.addText('ID', cell.getId());
  				id.setAttribute('readonly', 'true');
  				var geo = null;
  				var yField = null;
  				var xField = null;
  				var widthField = null;
  				var heightField = null;
  				if (model.isVertex(cell))
  				{
  					geo = model.getGeometry(cell);
  					if (geo != null)
  					{
  						yField = form.addText('top', geo.y);
  						xField = form.addText('left', geo.x);
  						widthField = form.addText('width', geo.width);
  						heightField = form.addText('height', geo.height);
  					}
  				}
  				var tmp = model.getStyle(cell);
  				var style = form.addText('Style', tmp || '');
  				var attrs = value.attributes;
  				var texts = [];
  				for (var i = 0; i < attrs.length; i++)
  				{
  					var val = attrs[i].value;
  					texts[i] = form.addTextarea(attrs[i].nodeName, val,
  						(attrs[i].nodeName == 'label') ? 4 : 2);
  				}
  				var okFunction = mxUtils.bind(this, function()
  				{
  					this.hideProperties();
  					model.beginUpdate();
  					try
  					{
  						if (geo != null)
  						{
  							geo = geo.clone();
  							geo.x = parseFloat(xField.value);
  							geo.y = parseFloat(yField.value);
  							geo.width = parseFloat(widthField.value);
  							geo.height = parseFloat(heightField.value);
  							model.setGeometry(cell, geo);
  						}
  						if (style.value.length > 0)
  						{
  							model.setStyle(cell, style.value);
  						}
  						else
  						{
  							model.setStyle(cell, null);
  						}
  						for (var i=0; i<attrs.length; i++)
  						{
  							var edit = new mxCellAttributeChange(
  								cell, attrs[i].nodeName,
  								texts[i].value);
  							model.execute(edit);
  						}
  						if (this.graph.isAutoSizeCell(cell))
  						{
  							this.graph.updateCellSize(cell);
  						}
  					}
  					finally
  					{
  						model.endUpdate();
  					}
  				});
  				var cancelFunction = mxUtils.bind(this, function()
  				{
  					this.hideProperties();
  				});
  				form.addButtons(okFunction, cancelFunction);
  				return form.table;
  			}
  			return null;
  		};
  		mxEditor.prototype.hideProperties = function ()
  		{
  			if (this.properties != null)
  			{
  				this.properties.destroy();
  				this.properties = null;
  			}
  		};
  		mxEditor.prototype.showTasks = function ()
  		{
  			if (this.tasks == null)
  			{
  				var div = document.createElement('div');
  				div.style.padding = '4px';
  				div.style.paddingLeft = '20px';
  				var w = document.body.clientWidth;
  				var wnd = new mxWindow(
  					mxResources.get(this.tasksResource) ||
  					this.tasksResource,
  					div, w - 220, this.tasksTop, 200);
  				wnd.setClosable(true);
  				wnd.destroyOnClose = false;
  				var funct = mxUtils.bind(this, function(sender)
  				{
  					mxEvent.release(div);
  					div.innerHTML = '';
  					this.createTasks(div);
  				});
  				this.graph.getModel().addListener(mxEvent.CHANGE, funct);
  				this.graph.getSelectionModel().addListener(mxEvent.CHANGE, funct);
  				this.graph.addListener(mxEvent.ROOT, funct);
  				if (this.tasksWindowImage != null)
  				{
  					wnd.setImage(this.tasksWindowImage);
  				}
  				this.tasks = wnd;
  				this.createTasks(div);
  			}
  			this.tasks.setVisible(true);
  		};
  		mxEditor.prototype.refreshTasks = function (div)
  		{
  			if (this.tasks != null)
  			{
  				var div = this.tasks.content;
  				mxEvent.release(div);
  				div.innerHTML = '';
  				this.createTasks(div);
  			}
  		};
  		mxEditor.prototype.createTasks = function (div)
  		{
  		};
  		mxEditor.prototype.showHelp = function (tasks)
  		{
  			if (this.help == null)
  			{
  				var frame = document.createElement('iframe');
  				frame.setAttribute('src', mxResources.get('urlHelp') || this.urlHelp);
  				frame.setAttribute('height', '100%');
  				frame.setAttribute('width', '100%');
  				frame.setAttribute('frameBorder', '0');
  				frame.style.backgroundColor = 'white';
  				var w = document.body.clientWidth;
  				var h = (document.body.clientHeight || document.documentElement.clientHeight);
  				var wnd = new mxWindow(mxResources.get(this.helpResource) || this.helpResource,
  					frame, (w-this.helpWidth)/2, (h-this.helpHeight)/3, this.helpWidth, this.helpHeight);
  				wnd.setMaximizable(true);
  				wnd.setClosable(true);
  				wnd.destroyOnClose = false;
  				wnd.setResizable(true);
  				if (this.helpWindowImage != null)
  				{
  					wnd.setImage(this.helpWindowImage);
  				}
  				if (mxClient.IS_NS)
  				{
  					var handler = function(sender)
  					{
  						var h = wnd.div.offsetHeight;
  						frame.setAttribute('height', (h-26)+'px');
  					};
  					wnd.addListener(mxEvent.RESIZE_END, handler);
  					wnd.addListener(mxEvent.MAXIMIZE, handler);
  					wnd.addListener(mxEvent.NORMALIZE, handler);
  					wnd.addListener(mxEvent.SHOW, handler);
  				}
  				this.help = wnd;
  			}
  			this.help.setVisible(true);
  		};
  		mxEditor.prototype.showOutline = function ()
  		{
  			var create = this.outline == null;
  			if (create)
  			{
  				var div = document.createElement('div');
  				div.style.overflow = 'hidden';
  				div.style.position = 'relative';
  				div.style.width = '100%';
  				div.style.height = '100%';
  				div.style.background = 'white';
  				div.style.cursor = 'move';
  				if (document.documentMode == 8)
  				{
  					div.style.filter = 'progid:DXImageTransform.Microsoft.alpha(opacity=100)';
  				}
  				var wnd = new mxWindow(
  					mxResources.get(this.outlineResource) ||
  					this.outlineResource,
  					div, 600, 480, 200, 200, false);
  				var outline = new mxOutline(this.graph, div);
  				wnd.setClosable(true);
  				wnd.setResizable(true);
  				wnd.destroyOnClose = false;
  				wnd.addListener(mxEvent.RESIZE_END, function()
  				{
  					outline.update();
  				});
  				this.outline = wnd;
  				this.outline.outline = outline;
  			}
  			this.outline.setVisible(true);
  			this.outline.outline.update(true);
  		};
  		mxEditor.prototype.setMode = function(modename)
  		{
  			if (modename == 'select')
  			{
  				this.graph.panningHandler.useLeftButtonForPanning = false;
  				this.graph.setConnectable(false);
  			}
  			else if (modename == 'connect')
  			{
  				this.graph.panningHandler.useLeftButtonForPanning = false;
  				this.graph.setConnectable(true);
  			}
  			else if (modename == 'pan')
  			{
  				this.graph.panningHandler.useLeftButtonForPanning = true;
  				this.graph.setConnectable(false);
  			}
  		};
  		mxEditor.prototype.createPopupMenu = function (menu, cell, evt)
  		{
  			this.popupHandler.createMenu(this, menu, cell, evt);
  		};
  		mxEditor.prototype.createEdge = function (source, target)
  		{
  			var e = null;
  			if (this.defaultEdge != null)
  			{
  				var model = this.graph.getModel();
  				e = model.cloneCell(this.defaultEdge);
  			}
  			else
  			{
  				e = new mxCell('');
  				e.setEdge(true);
  				var geo = new mxGeometry();
  				geo.relative = true;
  				e.setGeometry(geo);
  			}
  			var style = this.getEdgeStyle();
  			if (style != null)
  			{
  				e.setStyle(style);
  			}
  			return e;
  		};
  		mxEditor.prototype.getEdgeStyle = function ()
  		{
  			return this.defaultEdgeStyle;
  		};
  		mxEditor.prototype.consumeCycleAttribute = function (cell)
  		{
  			return (this.cycleAttributeValues != null &&
  				this.cycleAttributeValues.length > 0 &&
  				this.graph.isSwimlane(cell)) ?
  				this.cycleAttributeValues[this.cycleAttributeIndex++ %
  					this.cycleAttributeValues.length] : null;
  		};
  		mxEditor.prototype.cycleAttribute = function (cell)
  		{
  			if (this.cycleAttributeName != null)
  			{
  				var value = this.consumeCycleAttribute(cell);
  				if (value != null)
  				{
  					cell.setStyle(cell.getStyle()+';'+
  						this.cycleAttributeName+'='+value);
  				}
  			}
  		};
  		mxEditor.prototype.addVertex = function (parent, vertex, x, y)
  		{
  			var model = this.graph.getModel();
  			while (parent != null && !this.graph.isValidDropTarget(parent))
  			{
  				parent = model.getParent(parent);
  			}
  			parent = (parent != null) ? parent : this.graph.getSwimlaneAt(x, y);
  			var scale = this.graph.getView().scale;
  			var geo = model.getGeometry(vertex);
  			var pgeo = model.getGeometry(parent);
  			if (this.graph.isSwimlane(vertex) &&
  				!this.graph.swimlaneNesting)
  			{
  				parent = null;
  			}
  			else if (parent == null && this.swimlaneRequired)
  			{
  				return null;
  			}
  			else if (parent != null && pgeo != null)
  			{
  				var state = this.graph.getView().getState(parent);
  				if (state != null)
  				{
  					x -= state.origin.x * scale;
  					y -= state.origin.y * scale;
  					if (this.graph.isConstrainedMoving)
  					{
  						var width = geo.width;
  						var height = geo.height;
  						var tmp = state.x+state.width;
  						if (x+width > tmp)
  						{
  							x -= x+width - tmp;
  						}
  						tmp = state.y+state.height;
  						if (y+height > tmp)
  						{
  							y -= y+height - tmp;
  						}
  					}
  				}
  				else if (pgeo != null)
  				{
  					x -= pgeo.x*scale;
  					y -= pgeo.y*scale;
  				}
  			}
  			geo = geo.clone();
  			geo.x = this.graph.snap(x / scale -
  				this.graph.getView().translate.x -
  				this.graph.gridSize/2);
  			geo.y = this.graph.snap(y / scale -
  				this.graph.getView().translate.y -
  				this.graph.gridSize/2);
  			vertex.setGeometry(geo);
  			if (parent == null)
  			{
  				parent = this.graph.getDefaultParent();
  			}
  			this.cycleAttribute(vertex);
  			this.fireEvent(new mxEventObject(mxEvent.BEFORE_ADD_VERTEX,
  					'vertex', vertex, 'parent', parent));
  			model.beginUpdate();
  			try
  			{
  				vertex = this.graph.addCell(vertex, parent);
  				if (vertex != null)
  				{
  					this.graph.constrainChild(vertex);
  					this.fireEvent(new mxEventObject(mxEvent.ADD_VERTEX, 'vertex', vertex));
  				}
  			}
  			finally
  			{
  				model.endUpdate();
  			}
  			if (vertex != null)
  			{
  				this.graph.setSelectionCell(vertex);
  				this.graph.scrollCellToVisible(vertex);
  				this.fireEvent(new mxEventObject(mxEvent.AFTER_ADD_VERTEX, 'vertex', vertex));
  			}
  			return vertex;
  		};
  		mxEditor.prototype.destroy = function ()
  		{
  			if (!this.destroyed)
  			{
  				this.destroyed = true;
  				if (this.tasks != null)
  				{
  					this.tasks.destroy();
  				}
  				if (this.outline != null)
  				{
  					this.outline.destroy();
  				}
  				if (this.properties != null)
  				{
  					this.properties.destroy();
  				}
  				if (this.keyHandler != null)
  				{
  					this.keyHandler.destroy();
  				}
  				if (this.rubberband != null)
  				{
  					this.rubberband.destroy();
  				}
  				if (this.toolbar != null)
  				{
  					this.toolbar.destroy();
  				}
  				if (this.graph != null)
  				{
  					this.graph.destroy();
  				}
  				this.status = null;
  				this.templates = null;
  			}
  		};
  		__mxOutput.mxEditor = typeof mxEditor !== 'undefined' ? mxEditor : undefined;
  		var mxCodecRegistry =
  		{
  			codecs: [],
  			aliases: [],
  			register: function(codec)
  			{
  				if (codec != null)
  				{
  					var name = codec.getName();
  					mxCodecRegistry.codecs[name] = codec;
  					var classname = mxUtils.getFunctionName(codec.template.constructor);
  					if (classname != name)
  					{
  						mxCodecRegistry.addAlias(classname, name);
  					}
  				}
  				return codec;
  			},
  			addAlias: function(classname, codecname)
  			{
  				mxCodecRegistry.aliases[classname] = codecname;
  			},
  			getCodec: function(ctor)
  			{
  				var codec = null;
  				if (ctor != null)
  				{
  					var name = mxUtils.getFunctionName(ctor);
  					var tmp = mxCodecRegistry.aliases[name];
  					if (tmp != null)
  					{
  						name = tmp;
  					}
  					codec = mxCodecRegistry.codecs[name];
  					if (codec == null)
  					{
  						try
  						{
  							codec = new mxObjectCodec(new ctor());
  							mxCodecRegistry.register(codec);
  						}
  						catch (e)
  						{
  						}
  					}
  				}
  				return codec;
  			}
  		};
  		__mxOutput.mxCodecRegistry = typeof mxCodecRegistry !== 'undefined' ? mxCodecRegistry : undefined;
  		function mxCodec(document)
  		{
  			this.document = document || mxUtils.createXmlDocument();
  			this.objects = [];
  		}		mxCodec.prototype.document = null;
  		mxCodec.prototype.objects = null;
  		mxCodec.prototype.elements = null;
  		mxCodec.prototype.encodeDefaults = false;
  		mxCodec.prototype.putObject = function(id, obj)
  		{
  			this.objects[id] = obj;
  			return obj;
  		};
  		mxCodec.prototype.getObject = function(id)
  		{
  			var obj = null;
  			if (id != null)
  			{
  				obj = this.objects[id];
  				if (obj == null)
  				{
  					obj = this.lookup(id);
  					if (obj == null)
  					{
  						var node = this.getElementById(id);
  						if (node != null)
  						{
  							obj = this.decode(node);
  						}
  					}
  				}
  			}
  			return obj;
  		};
  		mxCodec.prototype.lookup = function(id)
  		{
  			return null;
  		};
  		mxCodec.prototype.getElementById = function(id)
  		{
  			this.updateElements();
  			return this.elements[id];
  		};
  		mxCodec.prototype.updateElements = function()
  		{
  			if (this.elements == null)
  			{
  				this.elements = new Object();
  				if (this.document.documentElement != null)
  				{
  					this.addElement(this.document.documentElement);
  				}
  			}
  		};
  		mxCodec.prototype.addElement = function(node)
  		{
  			if (node.nodeType == mxConstants.NODETYPE_ELEMENT)
  			{
  				var id = node.getAttribute('id');
  				if (id != null)
  				{
  					if (this.elements[id] == null)
  					{
  						this.elements[id] = node;
  					}
  					else if (this.elements[id] != node)
  					{
  						throw new Error(id + ': Duplicate ID');
  					}
  				}
  			}
  			node = node.firstChild;
  			while (node != null)
  			{
  				this.addElement(node);
  				node = node.nextSibling;
  			}
  		};
  		mxCodec.prototype.getId = function(obj)
  		{
  			var id = null;
  			if (obj != null)
  			{
  				id = this.reference(obj);
  				if (id == null && obj instanceof mxCell)
  				{
  					id = obj.getId();
  					if (id == null)
  					{
  						id = mxCellPath.create(obj);
  						if (id.length == 0)
  						{
  							id = 'root';
  						}
  					}
  				}
  			}
  			return id;
  		};
  		mxCodec.prototype.reference = function(obj)
  		{
  			return null;
  		};
  		mxCodec.prototype.encode = function(obj)
  		{
  			var node = null;
  			if (obj != null && obj.constructor != null)
  			{
  				var enc = mxCodecRegistry.getCodec(obj.constructor);
  				if (enc != null)
  				{
  					node = enc.encode(this, obj);
  				}
  				else
  				{
  					if (mxUtils.isNode(obj))
  					{
  						node = mxUtils.importNode(this.document, obj, true);
  					}
  					else
  					{
  			    		mxLog.warn('mxCodec.encode: No codec for ' + mxUtils.getFunctionName(obj.constructor));
  					}
  				}
  			}
  			return node;
  		};
  		mxCodec.prototype.decode = function(node, into)
  		{
  			this.updateElements();
  			var obj = null;
  			if (node != null && node.nodeType == mxConstants.NODETYPE_ELEMENT)
  			{
  				var ctor = null;
  				try
  				{
  					ctor = window[node.nodeName];
  				}
  				catch (err)
  				{
  				}
  				var dec = mxCodecRegistry.getCodec(ctor);
  				if (dec != null)
  				{
  					obj = dec.decode(this, node, into);
  				}
  				else
  				{
  					obj = node.cloneNode(true);
  					obj.removeAttribute('as');
  				}
  			}
  			return obj;
  		};
  		mxCodec.prototype.encodeCell = function(cell, node, includeChildren)
  		{
  			node.appendChild(this.encode(cell));
  			if (includeChildren == null || includeChildren)
  			{
  				var childCount = cell.getChildCount();
  				for (var i = 0; i < childCount; i++)
  				{
  					this.encodeCell(cell.getChildAt(i), node);
  				}
  			}
  		};
  		mxCodec.prototype.isCellCodec = function(codec)
  		{
  			if (codec != null && typeof(codec.isCellCodec) == 'function')
  			{
  				return codec.isCellCodec();
  			}
  			return false;
  		};
  		mxCodec.prototype.decodeCell = function(node, restoreStructures)
  		{
  			restoreStructures = (restoreStructures != null) ? restoreStructures : true;
  			var cell = null;
  			if (node != null && node.nodeType == mxConstants.NODETYPE_ELEMENT)
  			{
  				var decoder = mxCodecRegistry.getCodec(node.nodeName);
  				if (!this.isCellCodec(decoder))
  				{
  					var child = node.firstChild;
  					while (child != null && !this.isCellCodec(decoder))
  					{
  						decoder = mxCodecRegistry.getCodec(child.nodeName);
  						child = child.nextSibling;
  					}
  				}
  				if (!this.isCellCodec(decoder))
  				{
  					decoder = mxCodecRegistry.getCodec(mxCell);
  				}
  				cell = decoder.decode(this, node);
  				if (restoreStructures)
  				{
  					this.insertIntoGraph(cell);
  				}
  			}
  			return cell;
  		};
  		mxCodec.prototype.insertIntoGraph = function(cell)
  		{
  			var parent = cell.parent;
  			var source = cell.getTerminal(true);
  			var target = cell.getTerminal(false);
  			cell.setTerminal(null, false);
  			cell.setTerminal(null, true);
  			cell.parent = null;
  			if (parent != null)
  			{
  				if (parent == cell)
  				{
  					throw new Error(parent.id + ': Self Reference');
  				}
  				else
  				{
  					parent.insert(cell);
  				}
  			}
  			if (source != null)
  			{
  				source.insertEdge(cell, true);
  			}
  			if (target != null)
  			{
  				target.insertEdge(cell, false);
  			}
  		};
  		mxCodec.prototype.setAttribute = function(node, attribute, value)
  		{
  			if (attribute != null && value != null)
  			{
  				node.setAttribute(attribute, value);
  			}
  		};
  		__mxOutput.mxCodec = typeof mxCodec !== 'undefined' ? mxCodec : undefined;
  		function mxObjectCodec(template, exclude, idrefs, mapping)
  		{
  			this.template = template;
  			this.exclude = (exclude != null) ? exclude : [];
  			this.idrefs = (idrefs != null) ? idrefs : [];
  			this.mapping = (mapping != null) ? mapping : [];
  			this.reverse = new Object();
  			for (var i in this.mapping)
  			{
  				this.reverse[this.mapping[i]] = i;
  			}
  		}		mxObjectCodec.allowEval = false;
  		mxObjectCodec.prototype.template = null;
  		mxObjectCodec.prototype.exclude = null;
  		mxObjectCodec.prototype.idrefs = null;
  		mxObjectCodec.prototype.mapping = null;
  		mxObjectCodec.prototype.reverse = null;
  		mxObjectCodec.prototype.getName = function()
  		{
  			return mxUtils.getFunctionName(this.template.constructor);
  		};
  		mxObjectCodec.prototype.cloneTemplate = function()
  		{
  			return new this.template.constructor();
  		};
  		mxObjectCodec.prototype.getFieldName = function(attributename)
  		{
  			if (attributename != null)
  			{
  				var mapped = this.reverse[attributename];
  				if (mapped != null)
  				{
  					attributename = mapped;
  				}
  			}
  			return attributename;
  		};
  		mxObjectCodec.prototype.getAttributeName = function(fieldname)
  		{
  			if (fieldname != null)
  			{
  				var mapped = this.mapping[fieldname];
  				if (mapped != null)
  				{
  					fieldname = mapped;
  				}
  			}
  			return fieldname;
  		};
  		mxObjectCodec.prototype.isExcluded = function(obj, attr, value, write)
  		{
  			return attr == mxObjectIdentity.FIELD_NAME ||
  				mxUtils.indexOf(this.exclude, attr) >= 0;
  		};
  		mxObjectCodec.prototype.isReference = function(obj, attr, value, write)
  		{
  			return mxUtils.indexOf(this.idrefs, attr) >= 0;
  		};
  		mxObjectCodec.prototype.encode = function(enc, obj)
  		{
  			var node = enc.document.createElement(this.getName());
  			obj = this.beforeEncode(enc, obj, node);
  			this.encodeObject(enc, obj, node);
  			return this.afterEncode(enc, obj, node);
  		};
  		mxObjectCodec.prototype.encodeObject = function(enc, obj, node)
  		{
  			enc.setAttribute(node, 'id', enc.getId(obj));
  		    for (var i in obj)
  		    {
  				var name = i;
  				var value = obj[name];
  		    	if (value != null && !this.isExcluded(obj, name, value, true))
  		    	{
  		    		if (mxUtils.isInteger(name))
  		    		{
  		    			name = null;
  		    		}
  		    		this.encodeValue(enc, obj, name, value, node);
  		    	}
  		    }
  		};
  		mxObjectCodec.prototype.encodeValue = function(enc, obj, name, value, node)
  		{
  			if (value != null)
  			{
  				if (this.isReference(obj, name, value, true))
  				{
  					var tmp = enc.getId(value);
  					if (tmp == null)
  					{
  				    	mxLog.warn('mxObjectCodec.encode: No ID for ' +
  				    		this.getName() + '.' + name + '=' + value);
  				    	return;
  				    }
  				    value = tmp;
  				}
  				var defaultValue = this.template[name];
  				if (name == null || enc.encodeDefaults || defaultValue != value)
  				{
  					name = this.getAttributeName(name);
  					this.writeAttribute(enc, obj, name, value, node);
  				}
  			}
  		};
  		mxObjectCodec.prototype.writeAttribute = function(enc, obj, name, value, node)
  		{
  			if (typeof(value) != 'object' )
  			{
  				this.writePrimitiveAttribute(enc, obj, name, value, node);
  			}
  			else
  			{
  				this.writeComplexAttribute(enc, obj, name, value, node);
  			}
  		};
  		mxObjectCodec.prototype.writePrimitiveAttribute = function(enc, obj, name, value, node)
  		{
  			value = this.convertAttributeToXml(enc, obj, name, value, node);
  			if (name == null)
  			{
  				var child = enc.document.createElement('add');
  				if (typeof(value) == 'function')
  				{
  		    		child.appendChild(enc.document.createTextNode(value));
  		    	}
  		    	else
  		    	{
  		    		enc.setAttribute(child, 'value', value);
  		    	}
  				node.appendChild(child);
  			}
  			else if (typeof(value) != 'function')
  			{
  		    	enc.setAttribute(node, name, value);
  			}
  		};
  		mxObjectCodec.prototype.writeComplexAttribute = function(enc, obj, name, value, node)
  		{
  			var child = enc.encode(value);
  			if (child != null)
  			{
  				if (name != null)
  				{
  		    		child.setAttribute('as', name);
  		    	}
  		    	node.appendChild(child);
  			}
  			else
  			{
  				mxLog.warn('mxObjectCodec.encode: No node for ' + this.getName() + '.' + name + ': ' + value);
  			}
  		};
  		mxObjectCodec.prototype.convertAttributeToXml = function(enc, obj, name, value)
  		{
  			if (this.isBooleanAttribute(enc, obj, name, value))
  			{
  				value = (value == true) ? '1' : '0';
  			}
  			return value;
  		};
  		mxObjectCodec.prototype.isBooleanAttribute = function(enc, obj, name, value)
  		{
  			return (typeof(value.length) == 'undefined' && (value == true || value == false));
  		};
  		mxObjectCodec.prototype.convertAttributeFromXml = function(dec, attr, obj)
  		{
  			var value = attr.value;
  			if (this.isNumericAttribute(dec, attr, obj))
  			{
  				value = parseFloat(value);
  				if (isNaN(value) || !isFinite(value))
  				{
  					value = 0;
  				}
  			}
  			return value;
  		};
  		mxObjectCodec.prototype.isNumericAttribute = function(dec, attr, obj)
  		{
  			var result = (obj.constructor == mxGeometry &&
  				(attr.name == 'x' || attr.name == 'y' ||
  				attr.name == 'width' || attr.name == 'height')) ||
  				(obj.constructor == mxPoint &&
  				(attr.name == 'x' || attr.name == 'y')) ||
  				mxUtils.isNumeric(attr.value);
  			return result;
  		};
  		mxObjectCodec.prototype.beforeEncode = function(enc, obj, node)
  		{
  			return obj;
  		};
  		mxObjectCodec.prototype.afterEncode = function(enc, obj, node)
  		{
  			return node;
  		};
  		mxObjectCodec.prototype.decode = function(dec, node, into)
  		{
  			var id = node.getAttribute('id');
  			var obj = dec.objects[id];
  			if (obj == null)
  			{
  				obj = into || this.cloneTemplate();
  				if (id != null)
  				{
  					dec.putObject(id, obj);
  				}
  			}
  			node = this.beforeDecode(dec, node, obj);
  			this.decodeNode(dec, node, obj);
  		    return this.afterDecode(dec, node, obj);
  		};
  		mxObjectCodec.prototype.decodeNode = function(dec, node, obj)
  		{
  			if (node != null)
  			{
  				this.decodeAttributes(dec, node, obj);
  				this.decodeChildren(dec, node, obj);
  			}
  		};
  		mxObjectCodec.prototype.decodeAttributes = function(dec, node, obj)
  		{
  			var attrs = node.attributes;
  			if (attrs != null)
  			{
  				for (var i = 0; i < attrs.length; i++)
  				{
  					this.decodeAttribute(dec, attrs[i], obj);
  				}
  			}
  		};
  		mxObjectCodec.prototype.isIgnoredAttribute = function(dec, attr, obj)
  		{
  			return attr.nodeName == 'as' || attr.nodeName == 'id';
  		};
  		mxObjectCodec.prototype.decodeAttribute = function(dec, attr, obj)
  		{
  			if (!this.isIgnoredAttribute(dec, attr, obj))
  			{
  				var name = attr.nodeName;
  				var value = this.convertAttributeFromXml(dec, attr, obj);
  				var fieldname = this.getFieldName(name);
  				if (this.isReference(obj, fieldname, value, false))
  				{
  					var tmp = dec.getObject(value);
  					if (tmp == null)
  					{
  				    	mxLog.warn('mxObjectCodec.decode: No object for ' +
  				    		this.getName() + '.' + name + '=' + value);
  				    	return;
  				    }
  				    value = tmp;
  				}
  				if (!this.isExcluded(obj, name, value, false))
  				{
  					obj[name] = value;
  				}
  			}
  		};
  		mxObjectCodec.prototype.decodeChildren = function(dec, node, obj)
  		{
  			var child = node.firstChild;
  			while (child != null)
  			{
  				var tmp = child.nextSibling;
  				if (child.nodeType == mxConstants.NODETYPE_ELEMENT &&
  					!this.processInclude(dec, child, obj))
  				{
  					this.decodeChild(dec, child, obj);
  				}
  				child = tmp;
  			}
  		};
  		mxObjectCodec.prototype.decodeChild = function(dec, child, obj)
  		{
  			var fieldname = this.getFieldName(child.getAttribute('as'));
  			if (fieldname == null || !this.isExcluded(obj, fieldname, child, false))
  			{
  				var template = this.getFieldTemplate(obj, fieldname, child);
  				var value = null;
  				if (child.nodeName == 'add')
  				{
  					value = child.getAttribute('value');
  					if (value == null && mxObjectCodec.allowEval)
  					{
  						value = mxUtils.eval(mxUtils.getTextContent(child));
  					}
  				}
  				else
  				{
  					value = dec.decode(child, template);
  				}
  				try
  				{
  					this.addObjectValue(obj, fieldname, value, template);
  				}
  				catch (e)
  				{
  					throw new Error(e.message + ' for ' + child.nodeName);
  				}
  			}
  		};
  		mxObjectCodec.prototype.getFieldTemplate = function(obj, fieldname, child)
  		{
  			var template = obj[fieldname];
  		    if (template instanceof Array && template.length > 0)
  		    {
  		        template = null;
  		    }
  		    return template;
  		};
  		mxObjectCodec.prototype.addObjectValue = function(obj, fieldname, value, template)
  		{
  			if (value != null && value != template)
  			{
  				if (fieldname != null && fieldname.length > 0)
  				{
  					obj[fieldname] = value;
  				}
  				else
  				{
  					obj.push(value);
  				}
  			}
  		};
  		mxObjectCodec.prototype.processInclude = function(dec, node, into)
  		{
  			if (node.nodeName == 'include')
  			{
  				var name = node.getAttribute('name');
  				if (name != null)
  				{
  					try
  					{
  						var xml = mxUtils.load(name).getDocumentElement();
  						if (xml != null)
  						{
  							dec.decode(xml, into);
  						}
  					}
  					catch (e)
  					{
  					}
  				}
  				return true;
  			}
  			return false;
  		};
  		mxObjectCodec.prototype.beforeDecode = function(dec, node, obj)
  		{
  			return node;
  		};
  		mxObjectCodec.prototype.afterDecode = function(dec, node, obj)
  		{
  			return obj;
  		};
  		__mxOutput.mxObjectCodec = typeof mxObjectCodec !== 'undefined' ? mxObjectCodec : undefined;
  		mxCodecRegistry.register(function()
  		{
  			var codec = new mxObjectCodec(new mxCell(),
  				['children', 'edges', 'overlays', 'mxTransient'],
  				['parent', 'source', 'target']);
  			codec.isCellCodec = function()
  			{
  				return true;
  			};
  			codec.isNumericAttribute = function(dec, attr, obj)
  			{
  				return attr.nodeName !== 'value' && mxObjectCodec.prototype.isNumericAttribute.apply(this, arguments);
  			};
  			codec.isExcluded = function(obj, attr, value, isWrite)
  			{
  				return mxObjectCodec.prototype.isExcluded.apply(this, arguments) ||
  					(isWrite && attr == 'value' &&
  					value.nodeType == mxConstants.NODETYPE_ELEMENT);
  			};
  			codec.afterEncode = function(enc, obj, node)
  			{
  				if (obj.value != null && obj.value.nodeType == mxConstants.NODETYPE_ELEMENT)
  				{
  					var tmp = node;
  					node = mxUtils.importNode(enc.document, obj.value, true);
  					node.appendChild(tmp);
  					var id = tmp.getAttribute('id');
  					node.setAttribute('id', id);
  					tmp.removeAttribute('id');
  				}
  				return node;
  			};
  			codec.beforeDecode = function(dec, node, obj)
  			{
  				var inner = node.cloneNode(true);
  				var classname = this.getName();
  				if (node.nodeName != classname)
  				{
  					var tmp = node.getElementsByTagName(classname)[0];
  					if (tmp != null && tmp.parentNode == node)
  					{
  						mxUtils.removeWhitespace(tmp, true);
  						mxUtils.removeWhitespace(tmp, false);
  						tmp.parentNode.removeChild(tmp);
  						inner = tmp;
  					}
  					else
  					{
  						inner = null;
  					}
  					obj.value = node.cloneNode(true);
  					var id = obj.value.getAttribute('id');
  					if (id != null)
  					{
  						obj.setId(id);
  						obj.value.removeAttribute('id');
  					}
  				}
  				else
  				{
  					obj.setId(node.getAttribute('id'));
  				}
  				if (inner != null)
  				{
  					for (var i = 0; i < this.idrefs.length; i++)
  					{
  						var attr = this.idrefs[i];
  						var ref = inner.getAttribute(attr);
  						if (ref != null)
  						{
  							inner.removeAttribute(attr);
  							var object = dec.objects[ref] || dec.lookup(ref);
  							if (object == null)
  							{
  								var element = dec.getElementById(ref);
  								if (element != null)
  								{
  									var decoder = mxCodecRegistry.codecs[element.nodeName] || this;
  									object = decoder.decode(dec, element);
  								}
  							}
  							obj[attr] = object;
  						}
  					}
  				}
  				return inner;
  			};
  			return codec;
  		}());
  		__mxOutput.mxCellCodec = typeof mxCellCodec !== 'undefined' ? mxCellCodec : undefined;
  		mxCodecRegistry.register(function()
  		{
  			var codec = new mxObjectCodec(new mxGraphModel());
  			codec.encodeObject = function(enc, obj, node)
  			{
  				var rootNode = enc.document.createElement('root');
  				enc.encodeCell(obj.getRoot(), rootNode);
  				node.appendChild(rootNode);
  			};
  			codec.decodeChild = function(dec, child, obj)
  			{
  				if (child.nodeName == 'root')
  				{
  					this.decodeRoot(dec, child, obj);
  				}
  				else
  				{
  					mxObjectCodec.prototype.decodeChild.apply(this, arguments);
  				}
  			};
  			codec.decodeRoot = function(dec, root, model)
  			{
  				var rootCell = null;
  				var tmp = root.firstChild;
  				while (tmp != null)
  				{
  					var cell = dec.decodeCell(tmp);
  					if (cell != null && cell.getParent() == null)
  					{
  						rootCell = cell;
  					}
  					tmp = tmp.nextSibling;
  				}
  				if (rootCell != null)
  				{
  					model.setRoot(rootCell);
  				}
  			};
  			return codec;
  		}());
  		__mxOutput.mxModelCodec = typeof mxModelCodec !== 'undefined' ? mxModelCodec : undefined;
  		mxCodecRegistry.register(function()
  		{
  			var codec = new mxObjectCodec(new mxRootChange(),
  				['model', 'previous', 'root']);
  			codec.afterEncode = function(enc, obj, node)
  			{
  				enc.encodeCell(obj.root, node);
  				return node;
  			};
  			codec.beforeDecode = function(dec, node, obj)
  			{
  				if (node.firstChild != null &&
  					node.firstChild.nodeType == mxConstants.NODETYPE_ELEMENT)
  				{
  					node = node.cloneNode(true);
  					var tmp = node.firstChild;
  					obj.root = dec.decodeCell(tmp, false);
  					var tmp2 = tmp.nextSibling;
  					tmp.parentNode.removeChild(tmp);
  					tmp = tmp2;
  					while (tmp != null)
  					{
  						tmp2 = tmp.nextSibling;
  						dec.decodeCell(tmp);
  						tmp.parentNode.removeChild(tmp);
  						tmp = tmp2;
  					}
  				}
  				return node;
  			};
  			codec.afterDecode = function(dec, node, obj)
  			{
  				obj.previous = obj.root;
  				return obj;
  			};
  			return codec;
  		}());
  		__mxOutput.mxRootChangeCodec = typeof mxRootChangeCodec !== 'undefined' ? mxRootChangeCodec : undefined;
  		mxCodecRegistry.register(function()
  		{
  			var codec = new mxObjectCodec(new mxChildChange(),
  				['model', 'child', 'previousIndex'],
  				['parent', 'previous']);
  			codec.isReference = function(obj, attr, value, isWrite)
  			{
  				if (attr == 'child' && (!isWrite || obj.model.contains(obj.previous)))
  				{
  					return true;
  				}
  				return mxUtils.indexOf(this.idrefs, attr) >= 0;
  			};
  		  	codec.isExcluded = function(obj, attr, value, write)
  		  	{
  		  		return mxObjectCodec.prototype.isExcluded.apply(this, arguments) ||
  		  			(write && value != null && (attr == 'previous' ||
  		  			attr == 'parent') && !obj.model.contains(value));
  		  	};
  			codec.afterEncode = function(enc, obj, node)
  			{
  				if (this.isReference(obj, 'child', obj.child, true))
  				{
  					node.setAttribute('child', enc.getId(obj.child));
  				}
  				else
  				{
  					enc.encodeCell(obj.child, node);
  				}
  				return node;
  			};
  			codec.beforeDecode = function(dec, node, obj)
  			{
  				if (node.firstChild != null &&
  					node.firstChild.nodeType == mxConstants.NODETYPE_ELEMENT)
  				{
  					node = node.cloneNode(true);
  					var tmp = node.firstChild;
  					obj.child = dec.decodeCell(tmp, false);
  					var tmp2 = tmp.nextSibling;
  					tmp.parentNode.removeChild(tmp);
  					tmp = tmp2;
  					while (tmp != null)
  					{
  						tmp2 = tmp.nextSibling;
  						if (tmp.nodeType == mxConstants.NODETYPE_ELEMENT)
  						{
  							var id = tmp.getAttribute('id');
  							if (dec.lookup(id) == null)
  							{
  								dec.decodeCell(tmp);
  							}
  						}
  						tmp.parentNode.removeChild(tmp);
  						tmp = tmp2;
  					}
  				}
  				else
  				{
  					var childRef = node.getAttribute('child');
  					obj.child = dec.getObject(childRef);
  				}
  				return node;
  			};
  			codec.afterDecode = function(dec, node, obj)
  			{
  		        if (obj.child != null)
  		        {
  		            if (obj.child.parent != null && obj.previous != null &&
  		                obj.child.parent != obj.previous)
  		            {
  		                obj.previous = obj.child.parent;
  		            }
  		            obj.child.parent = obj.previous;
  		            obj.previous = obj.parent;
  		            obj.previousIndex = obj.index;
  		        }
  				return obj;
  			};
  			return codec;
  		}());
  		__mxOutput.mxChildChangeCodec = typeof mxChildChangeCodec !== 'undefined' ? mxChildChangeCodec : undefined;
  		mxCodecRegistry.register(function()
  		{
  			var codec = new mxObjectCodec(new mxTerminalChange(),
  				['model', 'previous'], ['cell', 'terminal']);
  			codec.afterDecode = function(dec, node, obj)
  			{
  				obj.previous = obj.terminal;
  				return obj;
  			};
  			return codec;
  		}());
  		__mxOutput.mxTerminalChangeCodec = typeof mxTerminalChangeCodec !== 'undefined' ? mxTerminalChangeCodec : undefined;
  		var mxGenericChangeCodec = function(obj, variable)
  		{
  			var codec = new mxObjectCodec(obj,  ['model', 'previous'], ['cell']);
  			codec.afterDecode = function(dec, node, obj)
  			{
  				if (mxUtils.isNode(obj.cell))
  				{
  					obj.cell = dec.decodeCell(obj.cell, false);
  				}
  				obj.previous = obj[variable];
  				return obj;
  			};
  			return codec;
  		};
  		mxCodecRegistry.register(mxGenericChangeCodec(new mxValueChange(), 'value'));
  		mxCodecRegistry.register(mxGenericChangeCodec(new mxStyleChange(), 'style'));
  		mxCodecRegistry.register(mxGenericChangeCodec(new mxGeometryChange(), 'geometry'));
  		mxCodecRegistry.register(mxGenericChangeCodec(new mxCollapseChange(), 'collapsed'));
  		mxCodecRegistry.register(mxGenericChangeCodec(new mxVisibleChange(), 'visible'));
  		mxCodecRegistry.register(mxGenericChangeCodec(new mxCellAttributeChange(), 'value'));
  		__mxOutput.mxGenericChangeCodec = typeof mxGenericChangeCodec !== 'undefined' ? mxGenericChangeCodec : undefined;
  		mxCodecRegistry.register(function()
  		{
  			return new mxObjectCodec(new mxGraph(),
  				['graphListeners', 'eventListeners', 'view', 'container',
  				'cellRenderer', 'editor', 'selection']);
  		}());
  		__mxOutput.mxGraphCodec = typeof mxGraphCodec !== 'undefined' ? mxGraphCodec : undefined;
  		mxCodecRegistry.register(function()
  		{
  			var codec = new mxObjectCodec(new mxGraphView());
  			codec.encode = function(enc, view)
  			{
  				return this.encodeCell(enc, view,
  					view.graph.getModel().getRoot());
  			};
  			codec.encodeCell = function(enc, view, cell)
  			{
  				var model = view.graph.getModel();
  				var state = view.getState(cell);
  				var parent = model.getParent(cell);
  				if (parent == null || state != null)
  				{
  					var childCount = model.getChildCount(cell);
  					var geo = view.graph.getCellGeometry(cell);
  					var name = null;
  					if (parent == model.getRoot())
  					{
  						name = 'layer';
  					}
  					else if (parent == null)
  					{
  						name = 'graph';
  					}
  					else if (model.isEdge(cell))
  					{
  						name = 'edge';
  					}
  					else if (childCount > 0 && geo != null)
  					{
  						name = 'group';
  					}
  					else if (model.isVertex(cell))
  					{
  						name = 'vertex';
  					}
  					if (name != null)
  					{
  						var node = enc.document.createElement(name);
  						var lab = view.graph.getLabel(cell);
  						if (lab != null)
  						{
  							node.setAttribute('label', view.graph.getLabel(cell));
  							if (view.graph.isHtmlLabel(cell))
  							{
  								node.setAttribute('html', true);
  							}
  						}
  						if (parent == null)
  						{
  							var bounds = view.getGraphBounds();
  							if (bounds != null)
  							{
  								node.setAttribute('x', Math.round(bounds.x));
  								node.setAttribute('y', Math.round(bounds.y));
  								node.setAttribute('width', Math.round(bounds.width));
  								node.setAttribute('height', Math.round(bounds.height));
  							}
  							node.setAttribute('scale', view.scale);
  						}
  						else if (state != null && geo != null)
  						{
  						    for (var i in state.style)
  						    {
  						    	var value = state.style[i];
  							    if (typeof(value) == 'function' &&
  									typeof(value) == 'object')
  								{
  							    	value = mxStyleRegistry.getName(value);
  						        }
  						    	if (value != null &&
  						    		typeof(value) != 'function' &&
  									typeof(value) != 'object')
  								{
  									node.setAttribute(i, value);
  						        }
  						    }
  							var abs = state.absolutePoints;
  							if (abs != null && abs.length > 0)
  							{
  								var pts = Math.round(abs[0].x) + ',' + Math.round(abs[0].y);
  								for (var i=1; i<abs.length; i++)
  								{
  									pts += ' ' + Math.round(abs[i].x) + ',' +
  										Math.round(abs[i].y);
  								}
  								node.setAttribute('points', pts);
  							}
  							else
  							{
  								node.setAttribute('x', Math.round(state.x));
  								node.setAttribute('y', Math.round(state.y));
  								node.setAttribute('width', Math.round(state.width));
  								node.setAttribute('height', Math.round(state.height));
  							}
  							var offset = state.absoluteOffset;
  							if (offset != null)
  							{
  								if (offset.x != 0)
  								{
  									node.setAttribute('dx', Math.round(offset.x));
  								}
  								if (offset.y != 0)
  								{
  									node.setAttribute('dy', Math.round(offset.y));
  								}
  							}
  						}
  						for (var i=0; i<childCount; i++)
  						{
  							var childNode = this.encodeCell(enc,
  									view, model.getChildAt(cell, i));
  							if (childNode != null)
  							{
  								node.appendChild(childNode);
  							}
  						}
  					}
  				}
  				return node;
  			};
  			return codec;
  		}());
  		__mxOutput.mxGraphViewCodec = typeof mxGraphViewCodec !== 'undefined' ? mxGraphViewCodec : undefined;
  		var mxStylesheetCodec = mxCodecRegistry.register(function()
  		{
  			var codec = new mxObjectCodec(new mxStylesheet());
  			codec.encode = function(enc, obj)
  			{
  				var node = enc.document.createElement(this.getName());
  				for (var i in obj.styles)
  				{
  					var style = obj.styles[i];
  					var styleNode = enc.document.createElement('add');
  					if (i != null)
  					{
  						styleNode.setAttribute('as', i);
  						for (var j in style)
  						{
  							var value = this.getStringValue(j, style[j]);
  							if (value != null)
  							{
  								var entry = enc.document.createElement('add');
  								entry.setAttribute('value', value);
  								entry.setAttribute('as', j);
  								styleNode.appendChild(entry);
  							}
  						}
  						if (styleNode.childNodes.length > 0)
  						{
  							node.appendChild(styleNode);
  						}
  					}
  				}
  			    return node;
  			};
  			codec.getStringValue = function(key, value)
  			{
  				var type = typeof(value);
  				if (type == 'function')
  				{
  					value = mxStyleRegistry.getName(value);
  				}
  				else if (type == 'object')
  				{
  					value = null;
  				}
  				return value;
  			};
  			codec.decode = function(dec, node, into)
  			{
  				var obj = into || new this.template.constructor();
  				var id = node.getAttribute('id');
  				if (id != null)
  				{
  					dec.objects[id] = obj;
  				}
  				node = node.firstChild;
  				while (node != null)
  				{
  					if (!this.processInclude(dec, node, obj) && node.nodeName == 'add')
  					{
  						var as = node.getAttribute('as');
  						if (as != null)
  						{
  							var extend = node.getAttribute('extend');
  							var style = (extend != null) ? mxUtils.clone(obj.styles[extend]) : null;
  							if (style == null)
  							{
  								if (extend != null)
  								{
  									mxLog.warn('mxStylesheetCodec.decode: stylesheet ' +
  										extend + ' not found to extend');
  								}
  								style = new Object();
  							}
  							var entry = node.firstChild;
  							while (entry != null)
  							{
  								if (entry.nodeType == mxConstants.NODETYPE_ELEMENT)
  								{
  								 	var key = entry.getAttribute('as');
  								 	if (entry.nodeName == 'add')
  								 	{
  									 	var text = mxUtils.getTextContent(entry);
  									 	var value = null;
  									 	if (text != null && text.length > 0 && mxStylesheetCodec.allowEval)
  									 	{
  									 		value = mxUtils.eval(text);
  									 	}
  									 	else
  									 	{
  									 		value = entry.getAttribute('value');
  									 		if (mxUtils.isNumeric(value))
  									 		{
  												value = parseFloat(value);
  											}
  									 	}
  									 	if (value != null)
  									 	{
  									 		style[key] = value;
  									 	}
  								 	}
  								 	else if (entry.nodeName == 'remove')
  								 	{
  								 		delete style[key];
  								 	}
  								}
  								entry = entry.nextSibling;
  							}
  							obj.putCellStyle(as, style);
  						}
  					}
  					node = node.nextSibling;
  				}
  				return obj;
  			};
  			return codec;
  		}());
  		mxStylesheetCodec.allowEval = true;
  		__mxOutput.mxStylesheetCodec = typeof mxStylesheetCodec !== 'undefined' ? mxStylesheetCodec : undefined;
  		mxCodecRegistry.register(function()
  		{
  			var codec = new mxObjectCodec(new mxDefaultKeyHandler());
  			codec.encode = function(enc, obj)
  			{
  				return null;
  			};
  			codec.decode = function(dec, node, into)
  			{
  				if (into != null)
  				{
  					into.editor;
  					node = node.firstChild;
  					while (node != null)
  					{
  						if (!this.processInclude(dec, node, into) &&
  							node.nodeName == 'add')
  						{
  							var as = node.getAttribute('as');
  							var action = node.getAttribute('action');
  							var control = node.getAttribute('control');
  							into.bindAction(as, action, control);
  						}
  						node = node.nextSibling;
  					}
  				}
  				return into;
  			};
  			return codec;
  		}());
  		__mxOutput.mxDefaultKeyHandlerCodec = typeof mxDefaultKeyHandlerCodec !== 'undefined' ? mxDefaultKeyHandlerCodec : undefined;
  		var mxDefaultToolbarCodec = mxCodecRegistry.register(function()
  		{
  			var codec = new mxObjectCodec(new mxDefaultToolbar());
  			codec.encode = function(enc, obj)
  			{
  				return null;
  			};
  			codec.decode = function(dec, node, into)
  			{
  				if (into != null)
  				{
  					var editor = into.editor;
  					node = node.firstChild;
  					while (node != null)
  					{
  						if (node.nodeType == mxConstants.NODETYPE_ELEMENT)
  						{
  							if (!this.processInclude(dec, node, into))
  							{
  								if (node.nodeName == 'separator')
  								{
  									into.addSeparator();
  								}
  								else if (node.nodeName == 'br')
  								{
  									into.toolbar.addBreak();
  								}
  								else if (node.nodeName == 'hr')
  								{
  									into.toolbar.addLine();
  								}
  								else if (node.nodeName == 'add')
  								{
  									var as = node.getAttribute('as');
  									as = mxResources.get(as) || as;
  									var icon = node.getAttribute('icon');
  									var pressedIcon = node.getAttribute('pressedIcon');
  									var action = node.getAttribute('action');
  									var mode = node.getAttribute('mode');
  									var template = node.getAttribute('template');
  									var toggle = node.getAttribute('toggle') != '0';
  									var text = mxUtils.getTextContent(node);
  									var elt = null;
  									if (action != null)
  									{
  										elt = into.addItem(as, icon, action, pressedIcon);
  									}
  									else if (mode != null)
  									{
  										var funct = (mxDefaultToolbarCodec.allowEval) ? mxUtils.eval(text) : null;
  										elt = into.addMode(as, icon, mode, pressedIcon, funct);
  									}
  									else if (template != null || (text != null && text.length > 0))
  									{
  										var cell = editor.templates[template];
  										var style = node.getAttribute('style');
  										if (cell != null && style != null)
  										{
  											cell = editor.graph.cloneCell(cell);
  											cell.setStyle(style);
  										}
  										var insertFunction = null;
  										if (text != null && text.length > 0 && mxDefaultToolbarCodec.allowEval)
  										{
  											insertFunction = mxUtils.eval(text);
  										}
  										elt = into.addPrototype(as, icon, cell, pressedIcon, insertFunction, toggle);
  									}
  									else
  									{
  										var children = mxUtils.getChildNodes(node);
  										if (children.length > 0)
  										{
  											if (icon == null)
  											{
  												var combo = into.addActionCombo(as);
  												for (var i=0; i<children.length; i++)
  												{
  													var child = children[i];
  													if (child.nodeName == 'separator')
  													{
  														into.addOption(combo, '---');
  													}
  													else if (child.nodeName == 'add')
  													{
  														var lab = child.getAttribute('as');
  														var act = child.getAttribute('action');
  														into.addActionOption(combo, lab, act);
  													}
  												}
  											}
  											else
  											{
  												var select = null;
  												var create = function()
  												{
  													var template = editor.templates[select.value];
  													if (template != null)
  													{
  														var clone = template.clone();
  														var style = select.options[select.selectedIndex].cellStyle;
  														if (style != null)
  														{
  															clone.setStyle(style);
  														}
  														return clone;
  													}
  													else
  													{
  														mxLog.warn('Template '+template+' not found');
  													}
  													return null;
  												};
  												var img = into.addPrototype(as, icon, create, null, null, toggle);
  												select = into.addCombo();
  												mxEvent.addListener(select, 'change', function()
  												{
  													into.toolbar.selectMode(img, function(evt)
  													{
  														var pt = mxUtils.convertPoint(editor.graph.container,
  															mxEvent.getClientX(evt), mxEvent.getClientY(evt));
  														return editor.addVertex(null, funct(), pt.x, pt.y);
  													});
  													into.toolbar.noReset = false;
  												});
  												for (var i=0; i<children.length; i++)
  												{
  													var child = children[i];
  													if (child.nodeName == 'separator')
  													{
  														into.addOption(select, '---');
  													}
  													else if (child.nodeName == 'add')
  													{
  														var lab = child.getAttribute('as');
  														var tmp = child.getAttribute('template');
  														var option = into.addOption(select, lab, tmp || template);
  														option.cellStyle = child.getAttribute('style');
  													}
  												}
  											}
  										}
  									}
  									if (elt != null)
  									{
  										var id = node.getAttribute('id');
  										if (id != null && id.length > 0)
  										{
  											elt.setAttribute('id', id);
  										}
  									}
  								}
  							}
  						}
  						node = node.nextSibling;
  					}
  				}
  				return into;
  			};
  			return codec;
  		}());
  		mxDefaultToolbarCodec.allowEval = true;
  		__mxOutput.mxDefaultToolbarCodec = typeof mxDefaultToolbarCodec !== 'undefined' ? mxDefaultToolbarCodec : undefined;
  		mxCodecRegistry.register(function()
  		{
  			var codec = new mxObjectCodec(new mxDefaultPopupMenu());
  			codec.encode = function(enc, obj)
  			{
  				return null;
  			};
  			codec.decode = function(dec, node, into)
  			{
  				var inc = node.getElementsByTagName('include')[0];
  				if (inc != null)
  				{
  					this.processInclude(dec, inc, into);
  				}
  				else if (into != null)
  				{
  					into.config = node;
  				}
  				return into;
  			};
  			return codec;
  		}());
  		__mxOutput.mxDefaultPopupMenuCodec = typeof mxDefaultPopupMenuCodec !== 'undefined' ? mxDefaultPopupMenuCodec : undefined;
  		mxCodecRegistry.register(function()
  		{
  			var codec = new mxObjectCodec(new mxEditor(),
  				['modified', 'lastSnapshot', 'ignoredChanges',
  				'undoManager', 'graphContainer', 'toolbarContainer']);
  			codec.afterDecode = function(dec, node, obj)
  			{
  				var defaultEdge = node.getAttribute('defaultEdge');
  				if (defaultEdge != null)
  				{
  					node.removeAttribute('defaultEdge');
  					obj.defaultEdge = obj.templates[defaultEdge];
  				}
  				var defaultGroup = node.getAttribute('defaultGroup');
  				if (defaultGroup != null)
  				{
  					node.removeAttribute('defaultGroup');
  					obj.defaultGroup = obj.templates[defaultGroup];
  				}
  				return obj;
  			};
  			codec.decodeChild = function(dec, child, obj)
  			{
  				if (child.nodeName == 'Array')
  				{
  					var role = child.getAttribute('as');
  					if (role == 'templates')
  					{
  						this.decodeTemplates(dec, child, obj);
  						return;
  					}
  				}
  				else if (child.nodeName == 'ui')
  				{
  					this.decodeUi(dec, child, obj);
  					return;
  				}
  				mxObjectCodec.prototype.decodeChild.apply(this, arguments);
  			};
  			codec.decodeUi = function(dec, node, editor)
  			{
  				var tmp = node.firstChild;
  				while (tmp != null)
  				{
  					if (tmp.nodeName == 'add')
  					{
  						var as = tmp.getAttribute('as');
  						var elt = tmp.getAttribute('element');
  						var style = tmp.getAttribute('style');
  						var element = null;
  						if (elt != null)
  						{
  							element = document.getElementById(elt);
  							if (element != null && style != null)
  							{
  								element.style.cssText += ';' + style;
  							}
  						}
  						else
  						{
  							var x = parseInt(tmp.getAttribute('x'));
  							var y = parseInt(tmp.getAttribute('y'));
  							var width = tmp.getAttribute('width');
  							var height = tmp.getAttribute('height');
  							element = document.createElement('div');
  							element.style.cssText = style;
  							var wnd = new mxWindow(mxResources.get(as) || as,
  								element, x, y, width, height, false, true);
  							wnd.setVisible(true);
  						}
  						if (as == 'graph')
  						{
  							editor.setGraphContainer(element);
  						}
  						else if (as == 'toolbar')
  						{
  							editor.setToolbarContainer(element);
  						}
  						else if (as == 'title')
  						{
  							editor.setTitleContainer(element);
  						}
  						else if (as == 'status')
  						{
  							editor.setStatusContainer(element);
  						}
  						else if (as == 'map')
  						{
  							editor.setMapContainer(element);
  						}
  					}
  					else if (tmp.nodeName == 'resource')
  					{
  						mxResources.add(tmp.getAttribute('basename'));
  					}
  					else if (tmp.nodeName == 'stylesheet')
  					{
  						mxClient.link('stylesheet', tmp.getAttribute('name'));
  					}
  					tmp = tmp.nextSibling;
  				}
  			};
  			codec.decodeTemplates = function(dec, node, editor)
  			{
  				if (editor.templates == null)
  				{
  					editor.templates = [];
  				}
  				var children = mxUtils.getChildNodes(node);
  				for (var j=0; j<children.length; j++)
  				{
  					var name = children[j].getAttribute('as');
  					var child = children[j].firstChild;
  					while (child != null && child.nodeType != 1)
  					{
  						child = child.nextSibling;
  					}
  					if (child != null)
  					{
  						editor.templates[name] = dec.decodeCell(child);
  					}
  				}
  			};
  			return codec;
  		}());
  		__mxOutput.mxEditorCodec = typeof mxEditorCodec !== 'undefined' ? mxEditorCodec : undefined;
  		return __mxOutput;
  		};
  		}));
  	} (build$1));
  	return build$1.exports;
  }

  var buildExports = requireBuild();
  var factory = /*@__PURE__*/getDefaultExportFromCjs(buildExports);

  const mxgraph = initialize();
  const mxCellRenderer = mxgraph.mxCellRenderer;
  const mxClient = mxgraph.mxClient;
  const mxConstants = mxgraph.mxConstants;
  const mxEvent = mxgraph.mxEvent;
  const mxPerimeter = mxgraph.mxPerimeter;
  const mxPoint = mxgraph.mxPoint;
  const mxRectangle = mxgraph.mxRectangle;
  const mxRectangleShape = mxgraph.mxRectangleShape;
  const mxSvgCanvas2D = mxgraph.mxSvgCanvas2D;
  const mxUtils = mxgraph.mxUtils;
  function initialize() {
      window.mxForceIncludes = false;
      window.mxLoadResources = false;
      window.mxLoadStylesheets = false;
      window.mxResourceExtension = '.txt';
      return factory({});
  }

  class CoordinatesTranslator {
      constructor(graph) {
          Object.defineProperty(this, "graph", {
              enumerable: true,
              configurable: true,
              writable: true,
              value: graph
          });
      }
      computeRelativeCoordinates(parent, absoluteCoordinate) {
          const translateForRoot = this.getTranslateForRoot(parent);
          const relativeX = absoluteCoordinate.x + translateForRoot.x;
          const relativeY = absoluteCoordinate.y + translateForRoot.y;
          return new mxPoint(relativeX, relativeY);
      }
      getTranslateForRoot(cell) {
          const model = this.graph.getModel();
          const offset = new mxPoint(0, 0);
          while (cell != null) {
              const geo = model.getGeometry(cell);
              if (geo != null) {
                  offset.x -= geo.x;
                  offset.y -= geo.y;
              }
              cell = model.getParent(cell);
          }
          return offset;
      }
      computeEdgeCenter(edge) {
          const points = edge.geometry.points;
          const p0 = points[0];
          const pe = points.at(-1);
          const dx = pe.x - p0.x;
          const dy = pe.y - p0.y;
          return new mxPoint(p0.x + dx / 2, p0.y + dy / 2);
      }
  }

  class Shape {
      constructor(id, bpmnElement, bounds, label, isHorizontal) {
          Object.defineProperty(this, "id", {
              enumerable: true,
              configurable: true,
              writable: true,
              value: id
          });
          Object.defineProperty(this, "bpmnElement", {
              enumerable: true,
              configurable: true,
              writable: true,
              value: bpmnElement
          });
          Object.defineProperty(this, "bounds", {
              enumerable: true,
              configurable: true,
              writable: true,
              value: bounds
          });
          Object.defineProperty(this, "label", {
              enumerable: true,
              configurable: true,
              writable: true,
              value: label
          });
          Object.defineProperty(this, "isHorizontal", {
              enumerable: true,
              configurable: true,
              writable: true,
              value: isHorizontal
          });
          Object.defineProperty(this, "extensions", {
              enumerable: true,
              configurable: true,
              writable: true,
              value: {}
          });
      }
  }

  class ShapeBpmnElement {
      constructor(id, name, kind, parentId, instantiate = false) {
          Object.defineProperty(this, "id", {
              enumerable: true,
              configurable: true,
              writable: true,
              value: id
          });
          Object.defineProperty(this, "name", {
              enumerable: true,
              configurable: true,
              writable: true,
              value: name
          });
          Object.defineProperty(this, "kind", {
              enumerable: true,
              configurable: true,
              writable: true,
              value: kind
          });
          Object.defineProperty(this, "parentId", {
              enumerable: true,
              configurable: true,
              writable: true,
              value: parentId
          });
          Object.defineProperty(this, "instantiate", {
              enumerable: true,
              configurable: true,
              writable: true,
              value: instantiate
          });
          Object.defineProperty(this, "incomingIds", {
              enumerable: true,
              configurable: true,
              writable: true,
              value: []
          });
          Object.defineProperty(this, "outgoingIds", {
              enumerable: true,
              configurable: true,
              writable: true,
              value: []
          });
      }
  }
  class ShapeBpmnActivity extends ShapeBpmnElement {
      constructor(id, name, kind, parentId, instantiate, markers = []) {
          super(id, name, kind, parentId, instantiate);
          Object.defineProperty(this, "markers", {
              enumerable: true,
              configurable: true,
              writable: true,
              value: markers
          });
      }
  }
  class ShapeBpmnCallActivity extends ShapeBpmnActivity {
      constructor(id, name, callActivityKind, parentId, markers, globalTaskKind) {
          super(id, name, exports.ShapeBpmnElementKind.CALL_ACTIVITY, parentId, undefined, markers);
          Object.defineProperty(this, "callActivityKind", {
              enumerable: true,
              configurable: true,
              writable: true,
              value: callActivityKind
          });
          Object.defineProperty(this, "globalTaskKind", {
              enumerable: true,
              configurable: true,
              writable: true,
              value: globalTaskKind
          });
      }
  }
  class ShapeBpmnSubProcess extends ShapeBpmnActivity {
      constructor(id, name, subProcessKind, parentId, markers) {
          subProcessKind == exports.ShapeBpmnSubProcessKind.AD_HOC && !markers.includes(exports.ShapeBpmnMarkerKind.ADHOC) && markers.push(exports.ShapeBpmnMarkerKind.ADHOC);
          super(id, name, exports.ShapeBpmnElementKind.SUB_PROCESS, parentId, undefined, markers);
          Object.defineProperty(this, "subProcessKind", {
              enumerable: true,
              configurable: true,
              writable: true,
              value: subProcessKind
          });
      }
  }
  class ShapeBpmnEvent extends ShapeBpmnElement {
      constructor(id, name, elementKind, eventDefinitionKind, parentId) {
          super(id, name, elementKind, parentId);
          Object.defineProperty(this, "eventDefinitionKind", {
              enumerable: true,
              configurable: true,
              writable: true,
              value: eventDefinitionKind
          });
      }
  }
  class ShapeBpmnIntermediateCatchEvent extends ShapeBpmnEvent {
      constructor(id, name, eventDefinitionKind, parentId) {
          super(id, name, exports.ShapeBpmnElementKind.EVENT_INTERMEDIATE_CATCH, eventDefinitionKind, parentId);
          Object.defineProperty(this, "sourceIds", {
              enumerable: true,
              configurable: true,
              writable: true,
              value: []
          });
      }
  }
  class ShapeBpmnIntermediateThrowEvent extends ShapeBpmnEvent {
      constructor(id, name, eventDefinitionKind, parentId) {
          super(id, name, exports.ShapeBpmnElementKind.EVENT_INTERMEDIATE_THROW, eventDefinitionKind, parentId);
          Object.defineProperty(this, "targetId", {
              enumerable: true,
              configurable: true,
              writable: true,
              value: void 0
          });
      }
  }
  class ShapeBpmnStartEvent extends ShapeBpmnEvent {
      constructor(id, name, eventDefinitionKind, parentId, isInterrupting) {
          super(id, name, exports.ShapeBpmnElementKind.EVENT_START, eventDefinitionKind, parentId);
          Object.defineProperty(this, "isInterrupting", {
              enumerable: true,
              configurable: true,
              writable: true,
              value: isInterrupting
          });
      }
  }
  class ShapeBpmnBoundaryEvent extends ShapeBpmnEvent {
      constructor(id, name, eventDefinitionKind, parentId, isInterrupting = true) {
          super(id, name, exports.ShapeBpmnElementKind.EVENT_BOUNDARY, eventDefinitionKind, parentId);
          Object.defineProperty(this, "isInterrupting", {
              enumerable: true,
              configurable: true,
              writable: true,
              value: isInterrupting
          });
      }
  }
  class ShapeBpmnEventBasedGateway extends ShapeBpmnElement {
      constructor(id, name, parentId, instantiate, gatewayKind = exports.ShapeBpmnEventBasedGatewayKind.None) {
          super(id, name, exports.ShapeBpmnElementKind.GATEWAY_EVENT_BASED, parentId, instantiate);
          Object.defineProperty(this, "gatewayKind", {
              enumerable: true,
              configurable: true,
              writable: true,
              value: gatewayKind
          });
      }
  }

  function ensureInRange(value, min, max, defaultValue) {
      const inRangeValue = value !== null && value !== void 0 ? value : defaultValue;
      return Math.min(Math.max(inRangeValue, min), max);
  }
  function ensurePositiveValue(input) {
      return Math.max(input !== null && input !== void 0 ? input : 0, 0);
  }
  function ensureValidZoomConfiguration(config) {
      const validatedConfig = config !== null && config !== void 0 ? config : {};
      validatedConfig.debounceDelay = ensureInRange(validatedConfig.debounceDelay, 0, 100, 50);
      validatedConfig.throttleDelay = ensureInRange(validatedConfig.throttleDelay, 0, 100, 50);
      return validatedConfig;
  }
  function ensureOpacityValue(opacity) {
      return opacity == 'default' ? undefined : ensureInRange(opacity, 0, 100, 100);
  }
  function ensureStrokeWidthValue(strokeWidth) {
      return strokeWidth == 'default' ? undefined : ensureInRange(strokeWidth, 1, 50, 1);
  }

  const BpmnStyleIdentifier = {
      EDGE: 'bpmn.edge',
      EDGE_START_FILL_COLOR: 'bpmn.edge.startFillColor',
      EDGE_END_FILL_COLOR: 'bpmn.edge.endFillColor',
      EVENT_BASED_GATEWAY_KIND: 'bpmn.gatewayKind',
      EVENT_DEFINITION_KIND: 'bpmn.eventDefinitionKind',
      GLOBAL_TASK_KIND: 'bpmn.globalTaskKind',
      SUB_PROCESS_KIND: 'bpmn.subProcessKind',
      IS_INITIATING: 'bpmn.isInitiating',
      IS_INSTANTIATING: 'bpmn.isInstantiating',
      IS_INTERRUPTING: 'bpmn.isInterrupting',
      EXTRA_CSS_CLASSES: 'bpmn.extra.css.classes',
      MARKERS: 'bpmn.markers',
      MESSAGE_FLOW_ICON: 'bpmn.messageFlowIcon',
  };
  const MarkerIdentifier = {
      ARROW_DASH: 'bpmn.dash',
  };

  const StyleDefault = {
      STROKE_WIDTH_THIN: 2,
      STROKE_WIDTH_THICK: 5,
      SHAPE_ACTIVITY_BOTTOM_MARGIN: 7,
      SHAPE_ACTIVITY_TOP_MARGIN: 7,
      SHAPE_ACTIVITY_LEFT_MARGIN: 7,
      SHAPE_ACTIVITY_MARKER_ICON_MARGIN: 5,
      SHAPE_ACTIVITY_MARKER_ICON_SIZE: 20,
      POOL_LABEL_SIZE: 30,
      POOL_LABEL_FILL_COLOR: 'none',
      LANE_LABEL_SIZE: 30,
      LANE_LABEL_FILL_COLOR: 'none',
      SUB_PROCESS_TRANSACTION_INNER_RECT_OFFSET: 4,
      SUB_PROCESS_TRANSACTION_INNER_RECT_ARC_SIZE: 6,
      TEXT_ANNOTATION_BORDER_LENGTH: 10,
      TEXT_ANNOTATION_FILL_COLOR: 'none',
      GROUP_FILL_COLOR: 'none',
      DEFAULT_FILL_COLOR: 'White',
      DEFAULT_STROKE_COLOR: 'Black',
      DEFAULT_FONT_FAMILY: 'Arial, Helvetica, sans-serif',
      DEFAULT_FONT_SIZE: 11,
      DEFAULT_FONT_COLOR: 'Black',
      DEFAULT_MARGIN: 0,
      SHAPE_ARC_SIZE: 20,
      DEFAULT_OVERLAY_FILL_COLOR: 'White',
      DEFAULT_OVERLAY_FILL_OPACITY: 100,
      DEFAULT_OVERLAY_STROKE_COLOR: 'Black',
      DEFAULT_OVERLAY_STROKE_WIDTH: 1,
      DEFAULT_OVERLAY_FONT_SIZE: 11,
      DEFAULT_OVERLAY_FONT_COLOR: 'Black',
      SEQUENCE_FLOW_CONDITIONAL_FROM_ACTIVITY_MARKER_FILL_COLOR: 'White',
      MESSAGE_FLOW_MARKER_START_FILL_COLOR: 'White',
      MESSAGE_FLOW_MARKER_END_FILL_COLOR: 'White',
  };
  const getBpmnIsInstantiating = (style) => mxUtils.getValue(style, BpmnStyleIdentifier.IS_INSTANTIATING, 'false') == 'true';
  const convertDefaultValue = (value) => (value == 'default' ? undefined : value);
  const updateStroke = (cellStyle, stroke) => {
      if (stroke) {
          cellStyle = setStyle(cellStyle, mxConstants.STYLE_STROKECOLOR, stroke.color, convertDefaultValue);
          cellStyle = setStyle(cellStyle, mxConstants.STYLE_STROKE_OPACITY, stroke.opacity, ensureOpacityValue);
          cellStyle = setStyle(cellStyle, mxConstants.STYLE_STROKEWIDTH, stroke.width, ensureStrokeWidthValue);
      }
      return cellStyle;
  };
  const setStyle = (cellStyle, key, value, converter = (value) => value) => {
      return value == undefined ? cellStyle : mxUtils.setStyle(cellStyle, key, converter(value));
  };
  const setStyleFlag = (cellStyle, key, flag, value) => value == undefined ? cellStyle : mxUtils.setStyleFlag(cellStyle, key, flag, value);
  const updateFont = (cellStyle, font) => {
      if (font) {
          cellStyle = setStyle(cellStyle, mxConstants.STYLE_FONTCOLOR, font.color, convertDefaultValue);
          cellStyle = setStyle(cellStyle, mxConstants.STYLE_FONTSIZE, font.size);
          cellStyle = setStyle(cellStyle, mxConstants.STYLE_FONTFAMILY, font.family);
          cellStyle = setStyleFlag(cellStyle, mxConstants.STYLE_FONTSTYLE, mxConstants.FONT_BOLD, font.isBold);
          cellStyle = setStyleFlag(cellStyle, mxConstants.STYLE_FONTSTYLE, mxConstants.FONT_ITALIC, font.isItalic);
          cellStyle = setStyleFlag(cellStyle, mxConstants.STYLE_FONTSTYLE, mxConstants.FONT_UNDERLINE, font.isUnderline);
          cellStyle = setStyleFlag(cellStyle, mxConstants.STYLE_FONTSTYLE, mxConstants.FONT_STRIKETHROUGH, font.isStrikeThrough);
          cellStyle = setStyle(cellStyle, mxConstants.STYLE_TEXT_OPACITY, font.opacity, ensureOpacityValue);
      }
      return cellStyle;
  };
  const getStyleValue = (cellStyle, key, defaultValue) => {
      var _a;
      return (_a = cellStyle === null || cellStyle === void 0 ? void 0 : cellStyle.split(';').map(entry => entry.split('=')).filter(([k]) => k === key).map(([, v]) => v)[0]) !== null && _a !== void 0 ? _a : defaultValue;
  };
  const convertDirection = (direction) => {
      switch (direction) {
          case 'right-to-left': {
              return mxConstants.DIRECTION_WEST;
          }
          case 'bottom-to-top': {
              return mxConstants.DIRECTION_NORTH;
          }
          case 'top-to-bottom': {
              return mxConstants.DIRECTION_SOUTH;
          }
          default: {
              return mxConstants.DIRECTION_EAST;
          }
      }
  };
  const updateFill = (cellStyle, fill) => {
      const color = fill.color;
      if (color) {
          const isGradient = isFillColorGradient(color);
          const fillColor = isGradient ? color.startColor : color;
          cellStyle = setStyle(cellStyle, mxConstants.STYLE_FILLCOLOR, fillColor, convertDefaultValue);
          if (isGradient) {
              cellStyle = mxUtils.setStyle(cellStyle, mxConstants.STYLE_GRADIENTCOLOR, color.endColor);
              cellStyle = mxUtils.setStyle(cellStyle, mxConstants.STYLE_GRADIENT_DIRECTION, convertDirection(color.direction));
          }
          else if (color === 'default') {
              cellStyle = mxUtils.setStyle(cellStyle, mxConstants.STYLE_GRADIENTCOLOR, undefined);
              cellStyle = mxUtils.setStyle(cellStyle, mxConstants.STYLE_GRADIENT_DIRECTION, undefined);
          }
          if (cellStyle.includes(exports.ShapeBpmnElementKind.POOL) || cellStyle.includes(exports.ShapeBpmnElementKind.LANE)) {
              cellStyle = setStyle(cellStyle, mxConstants.STYLE_SWIMLANE_FILLCOLOR, fillColor, convertDefaultValue);
          }
      }
      cellStyle = setStyle(cellStyle, mxConstants.STYLE_FILL_OPACITY, fill.opacity, ensureOpacityValue);
      return cellStyle;
  };
  const isShapeStyleUpdate = (style) => {
      return style && typeof style === 'object' && 'fill' in style;
  };
  const isFillColorGradient = (color) => {
      return color && typeof color === 'object';
  };

  class StyleComputer {
      constructor(options) {
          var _a;
          Object.defineProperty(this, "ignoreBpmnColors", {
              enumerable: true,
              configurable: true,
              writable: true,
              value: void 0
          });
          this.ignoreBpmnColors = (_a = options === null || options === void 0 ? void 0 : options.ignoreBpmnColors) !== null && _a !== void 0 ? _a : true;
      }
      computeStyle(bpmnCell, labelBounds) {
          const styles = [bpmnCell.bpmnElement.kind];
          let mainStyleValues;
          if (bpmnCell instanceof Shape) {
              mainStyleValues = this.computeShapeStyleValues(bpmnCell);
          }
          else {
              styles.push(...computeEdgeBaseStyles(bpmnCell));
              mainStyleValues = this.computeEdgeStyleValues(bpmnCell);
          }
          const fontStyleValues = this.computeFontStyleValues(bpmnCell);
          const labelStyleValues = computeLabelStyleValues(bpmnCell, labelBounds);
          styles.push(...toArrayOfMxGraphStyleEntries([...mainStyleValues, ...fontStyleValues, ...labelStyleValues]));
          return styles.join(';');
      }
      computeShapeStyleValues(shape) {
          const styleValues = new Map();
          const bpmnElement = shape.bpmnElement;
          if (bpmnElement instanceof ShapeBpmnEvent) {
              computeEventShapeStyle(bpmnElement, styleValues);
          }
          else if (bpmnElement instanceof ShapeBpmnActivity) {
              computeActivityShapeStyle(bpmnElement, styleValues);
          }
          else if (ShapeUtil.isPoolOrLane(bpmnElement.kind)) {
              styleValues.set(mxConstants.STYLE_HORIZONTAL, shape.isHorizontal ? '0' : '1');
          }
          else if (bpmnElement instanceof ShapeBpmnEventBasedGateway) {
              styleValues.set(BpmnStyleIdentifier.IS_INSTANTIATING, String(bpmnElement.instantiate));
              styleValues.set(BpmnStyleIdentifier.EVENT_BASED_GATEWAY_KIND, String(bpmnElement.gatewayKind));
          }
          if (!this.ignoreBpmnColors) {
              const extensions = shape.extensions;
              const fillColor = extensions.fillColor;
              if (fillColor) {
                  styleValues.set(mxConstants.STYLE_FILLCOLOR, fillColor);
                  if (ShapeUtil.isPoolOrLane(bpmnElement.kind)) {
                      styleValues.set(mxConstants.STYLE_SWIMLANE_FILLCOLOR, fillColor);
                  }
              }
              extensions.strokeColor && styleValues.set(mxConstants.STYLE_STROKECOLOR, extensions.strokeColor);
          }
          return styleValues;
      }
      computeEdgeStyleValues(edge) {
          const styleValues = new Map();
          if (!this.ignoreBpmnColors) {
              const extensions = edge.extensions;
              extensions.strokeColor && styleValues.set(mxConstants.STYLE_STROKECOLOR, extensions.strokeColor);
          }
          return styleValues;
      }
      computeFontStyleValues(bpmnCell) {
          var _a, _b;
          const styleValues = new Map();
          const font = (_a = bpmnCell.label) === null || _a === void 0 ? void 0 : _a.font;
          if (font) {
              styleValues.set(mxConstants.STYLE_FONTFAMILY, font.name);
              styleValues.set(mxConstants.STYLE_FONTSIZE, font.size);
              styleValues.set(mxConstants.STYLE_FONTSTYLE, getFontStyleValue(font));
          }
          if (!this.ignoreBpmnColors) {
              const extensions = (_b = bpmnCell.label) === null || _b === void 0 ? void 0 : _b.extensions;
              (extensions === null || extensions === void 0 ? void 0 : extensions.color) && styleValues.set(mxConstants.STYLE_FONTCOLOR, extensions.color);
          }
          return styleValues;
      }
      computeMessageFlowIconStyle(edge) {
          const styleValues = [];
          styleValues.push(['shape', BpmnStyleIdentifier.MESSAGE_FLOW_ICON], [BpmnStyleIdentifier.IS_INITIATING, String(edge.messageVisibleKind === exports.MessageVisibleKind.INITIATING)]);
          if (!this.ignoreBpmnColors) {
              edge.extensions.strokeColor && styleValues.push([mxConstants.STYLE_STROKECOLOR, edge.extensions.strokeColor]);
          }
          return toArrayOfMxGraphStyleEntries(styleValues).join(';');
      }
  }
  function computeEventShapeStyle(bpmnElement, styleValues) {
      styleValues.set(BpmnStyleIdentifier.EVENT_DEFINITION_KIND, bpmnElement.eventDefinitionKind);
      if (bpmnElement instanceof ShapeBpmnBoundaryEvent || (bpmnElement instanceof ShapeBpmnStartEvent && bpmnElement.isInterrupting !== undefined)) {
          styleValues.set(BpmnStyleIdentifier.IS_INTERRUPTING, String(bpmnElement.isInterrupting));
      }
  }
  function computeActivityShapeStyle(bpmnElement, styleValues) {
      if (bpmnElement instanceof ShapeBpmnSubProcess) {
          styleValues.set(BpmnStyleIdentifier.SUB_PROCESS_KIND, bpmnElement.subProcessKind);
      }
      else if (bpmnElement.kind === exports.ShapeBpmnElementKind.TASK_RECEIVE) {
          styleValues.set(BpmnStyleIdentifier.IS_INSTANTIATING, String(bpmnElement.instantiate));
      }
      else if (bpmnElement instanceof ShapeBpmnCallActivity) {
          styleValues.set(BpmnStyleIdentifier.GLOBAL_TASK_KIND, bpmnElement.globalTaskKind);
      }
      const markers = bpmnElement.markers;
      if (markers.length > 0) {
          styleValues.set(BpmnStyleIdentifier.MARKERS, markers.join(','));
      }
  }
  function computeEdgeBaseStyles(edge) {
      const styles = [];
      const bpmnElement = edge.bpmnElement;
      if (bpmnElement instanceof SequenceFlow) {
          styles.push(bpmnElement.sequenceFlowKind);
      }
      if (bpmnElement instanceof AssociationFlow) {
          styles.push(bpmnElement.associationDirectionKind);
      }
      return styles;
  }
  function computeLabelStyleValues(bpmnCell, labelBounds) {
      const styleValues = new Map();
      const bpmnElement = bpmnCell.bpmnElement;
      if (labelBounds) {
          styleValues.set(mxConstants.STYLE_VERTICAL_ALIGN, mxConstants.ALIGN_TOP);
          if (bpmnCell.bpmnElement.kind != exports.ShapeBpmnElementKind.TEXT_ANNOTATION) {
              styleValues.set(mxConstants.STYLE_ALIGN, mxConstants.ALIGN_CENTER);
          }
          if (bpmnCell instanceof Shape) {
              styleValues.set(mxConstants.STYLE_LABEL_WIDTH, labelBounds.width + 1);
              styleValues.set(mxConstants.STYLE_LABEL_POSITION, 'ignore');
              styleValues.set(mxConstants.STYLE_VERTICAL_LABEL_POSITION, mxConstants.ALIGN_MIDDLE);
          }
      }
      else if (bpmnCell instanceof Shape &&
          (bpmnElement instanceof ShapeBpmnSubProcess || (bpmnElement instanceof ShapeBpmnCallActivity && bpmnElement.callActivityKind === exports.ShapeBpmnCallActivityKind.CALLING_PROCESS)) &&
          !bpmnElement.markers.includes(exports.ShapeBpmnMarkerKind.EXPAND)) {
          styleValues.set(mxConstants.STYLE_VERTICAL_ALIGN, mxConstants.ALIGN_TOP);
      }
      return styleValues;
  }
  function getFontStyleValue(font) {
      let value = 0;
      if (font.isBold) {
          value += mxConstants.FONT_BOLD;
      }
      if (font.isItalic) {
          value += mxConstants.FONT_ITALIC;
      }
      if (font.isStrikeThrough) {
          value += mxConstants.FONT_STRIKETHROUGH;
      }
      if (font.isUnderline) {
          value += mxConstants.FONT_UNDERLINE;
      }
      return value;
  }
  function toArrayOfMxGraphStyleEntries(styleValues) {
      return styleValues.filter(([, v]) => v && v != 'undefined').map(([key, value]) => `${key}=${value}`);
  }

  class BpmnRenderer {
      constructor(graph, coordinatesTranslator, styleComputer) {
          Object.defineProperty(this, "graph", {
              enumerable: true,
              configurable: true,
              writable: true,
              value: graph
          });
          Object.defineProperty(this, "coordinatesTranslator", {
              enumerable: true,
              configurable: true,
              writable: true,
              value: coordinatesTranslator
          });
          Object.defineProperty(this, "styleComputer", {
              enumerable: true,
              configurable: true,
              writable: true,
              value: styleComputer
          });
      }
      render(renderedModel, fitOptions) {
          this.insertShapesAndEdges(renderedModel);
          this.graph.customFit(fitOptions);
      }
      insertShapesAndEdges({ pools, lanes, subprocesses, otherFlowNodes, boundaryEvents, edges }) {
          this.graph.batchUpdate(() => {
              this.graph.getModel().clear();
              this.insertShapes(pools);
              this.insertShapes(lanes);
              this.insertShapes(subprocesses);
              this.insertShapes(otherFlowNodes);
              this.insertShapes(boundaryEvents);
              this.insertEdges(edges);
          });
      }
      insertShapes(shapes) {
          for (const shape of shapes)
              this.insertShape(shape);
      }
      getParent(bpmnElement) {
          const bpmnElementParent = this.getCell(bpmnElement.parentId);
          return bpmnElementParent !== null && bpmnElementParent !== void 0 ? bpmnElementParent : this.graph.getDefaultParent();
      }
      insertShape(shape) {
          var _a;
          const bpmnElement = shape.bpmnElement;
          const parent = this.getParent(bpmnElement);
          const bounds = shape.bounds;
          let labelBounds = (_a = shape.label) === null || _a === void 0 ? void 0 : _a.bounds;
          labelBounds = ShapeUtil.isPoolOrLane(bpmnElement.kind) ? undefined : labelBounds;
          const style = this.styleComputer.computeStyle(shape, labelBounds);
          this.insertVertex(parent, bpmnElement.id, bpmnElement.name, bounds, labelBounds, style);
      }
      insertEdges(edges) {
          var _a;
          for (const internalEdge of edges) {
              const bpmnElement = internalEdge.bpmnElement;
              const parent = this.graph.getDefaultParent();
              const source = this.getCell(bpmnElement.sourceReferenceId);
              const target = this.getCell(bpmnElement.targetReferenceId);
              const labelBounds = (_a = internalEdge.label) === null || _a === void 0 ? void 0 : _a.bounds;
              const style = this.styleComputer.computeStyle(internalEdge, labelBounds);
              const edge = this.graph.insertEdge(parent, bpmnElement.id, bpmnElement.name, source, target, style);
              this.insertWaypoints(internalEdge.waypoints, edge);
              if (labelBounds) {
                  edge.geometry.width = labelBounds.width;
                  edge.geometry.height = labelBounds.height;
                  const edgeCenterCoordinate = this.coordinatesTranslator.computeEdgeCenter(edge);
                  edge.geometry.relative = false;
                  const labelBoundsRelativeCoordinateFromParent = this.coordinatesTranslator.computeRelativeCoordinates(edge.parent, new mxPoint(labelBounds.x, labelBounds.y));
                  const relativeLabelX = labelBoundsRelativeCoordinateFromParent.x + labelBounds.width / 2 - edgeCenterCoordinate.x;
                  const relativeLabelY = labelBoundsRelativeCoordinateFromParent.y - edgeCenterCoordinate.y;
                  edge.geometry.offset = new mxPoint(relativeLabelX, relativeLabelY);
              }
              this.insertMessageFlowIconIfNeeded(internalEdge, edge);
          }
      }
      insertMessageFlowIconIfNeeded(internalEdge, edge) {
          if (internalEdge.bpmnElement instanceof MessageFlow && internalEdge.messageVisibleKind !== exports.MessageVisibleKind.NONE) {
              const cell = this.graph.insertVertex(edge, messageFlowIconId(edge.id), undefined, 0, 0, 20, 14, this.styleComputer.computeMessageFlowIconStyle(internalEdge));
              cell.geometry.relative = true;
              cell.geometry.offset = new mxPoint(-10, -7);
          }
      }
      insertWaypoints(waypoints, edge) {
          if (waypoints) {
              edge.geometry.points = waypoints.map(waypoint => this.coordinatesTranslator.computeRelativeCoordinates(edge.parent, new mxPoint(waypoint.x, waypoint.y)));
          }
      }
      getCell(id) {
          return this.graph.getModel().getCell(id);
      }
      insertVertex(parent, id, value, bounds, labelBounds, style) {
          const vertexCoordinates = this.coordinatesTranslator.computeRelativeCoordinates(parent, new mxPoint(bounds.x, bounds.y));
          const cell = this.graph.insertVertex(parent, id, value, vertexCoordinates.x, vertexCoordinates.y, bounds.width, bounds.height, style);
          if (labelBounds) {
              const relativeLabelX = labelBounds.x - bounds.x;
              const relativeLabelY = labelBounds.y - bounds.y;
              cell.geometry.offset = new mxPoint(relativeLabelX, relativeLabelY);
          }
          return cell;
      }
  }
  function newBpmnRenderer(graph, options) {
      return new BpmnRenderer(graph, new CoordinatesTranslator(graph), new StyleComputer(options));
  }
  function messageFlowIconId(messageFlowId) {
      return `messageFlowIcon_of_${messageFlowId}`;
  }

  function debounce(func, debounceMs, { signal, edges } = {}) {
      let pendingThis = undefined;
      let pendingArgs = null;
      const leading = edges != null && edges.includes('leading');
      const trailing = edges == null || edges.includes('trailing');
      const invoke = () => {
          if (pendingArgs !== null) {
              func.apply(pendingThis, pendingArgs);
              pendingThis = undefined;
              pendingArgs = null;
          }
      };
      const onTimerEnd = () => {
          if (trailing) {
              invoke();
          }
          cancel();
      };
      let timeoutId = null;
      const schedule = () => {
          if (timeoutId != null) {
              clearTimeout(timeoutId);
          }
          timeoutId = setTimeout(() => {
              timeoutId = null;
              onTimerEnd();
          }, debounceMs);
      };
      const cancelTimer = () => {
          if (timeoutId !== null) {
              clearTimeout(timeoutId);
              timeoutId = null;
          }
      };
      const cancel = () => {
          cancelTimer();
          pendingThis = undefined;
          pendingArgs = null;
      };
      const flush = () => {
          cancelTimer();
          invoke();
      };
      const debounced = function (...args) {
          if (signal?.aborted) {
              return;
          }
          pendingThis = this;
          pendingArgs = args;
          const isFirstCall = timeoutId == null;
          schedule();
          if (leading && isFirstCall) {
              invoke();
          }
      };
      debounced.schedule = schedule;
      debounced.cancel = cancel;
      debounced.flush = flush;
      signal?.addEventListener('abort', cancel, { once: true });
      return debounced;
  }

  function throttle(func, throttleMs, { signal, edges = ['leading', 'trailing'] } = {}) {
      let pendingAt = null;
      const debounced = debounce(func, throttleMs, { signal, edges });
      const throttled = function (...args) {
          if (pendingAt == null) {
              pendingAt = Date.now();
          }
          else {
              if (Date.now() - pendingAt >= throttleMs) {
                  pendingAt = Date.now();
                  debounced.cancel();
                  debounced(...args);
              }
          }
          debounced(...args);
      };
      throttled.cancel = debounced.cancel;
      throttled.flush = debounced.flush;
      return throttled;
  }

  class MxGraphCustomOverlay extends mxgraph.mxCellOverlay {
      constructor(label, options) {
          super(null, '', options.position.horizontalAlign, options.position.verticalAlign, null, 'default');
          Object.defineProperty(this, "label", {
              enumerable: true,
              configurable: true,
              writable: true,
              value: label
          });
          Object.defineProperty(this, "style", {
              enumerable: true,
              configurable: true,
              writable: true,
              value: void 0
          });
          this.style = options.style;
      }
      getBounds(state) {
          const isEdge = state.view.graph.getModel().isEdge(state.cell);
          const s = state.view.scale;
          let pt;
          const w = 0;
          const h = 0;
          if (isEdge) {
              pt = this.computeEdgeBounds(state);
          }
          else {
              pt = new mxPoint();
              if (this.align == mxConstants.ALIGN_LEFT) {
                  pt.x = state.x;
              }
              else if (this.align == mxConstants.ALIGN_CENTER) {
                  pt.x = state.x + state.width / 2;
              }
              else {
                  pt.x = state.x + state.width;
              }
              if (this.verticalAlign == mxConstants.ALIGN_TOP) {
                  pt.y = state.y;
              }
              else if (this.verticalAlign == mxConstants.ALIGN_MIDDLE) {
                  pt.y = state.y + state.height / 2;
              }
              else {
                  pt.y = state.y + state.height;
              }
          }
          return new mxRectangle(Math.round(pt.x - (w * this.defaultOverlap - this.offset.x) * s), Math.round(pt.y - (h * this.defaultOverlap - this.offset.y) * s), w * s, h * s);
      }
      computeEdgeBounds(state) {
          const pts = state.absolutePoints;
          if (this.align == mxConstants.ALIGN_LEFT) {
              return pts[0];
          }
          else if (this.align == mxConstants.ALIGN_CENTER) {
              if (pts.length % 2 == 1) {
                  return pts[Math.floor(pts.length / 2)];
              }
              else {
                  const index = pts.length / 2;
                  const p0 = pts[index - 1];
                  const p1 = pts[index];
                  return new mxPoint(p0.x + (p1.x - p0.x) / 2, p0.y + (p1.y - p0.y) / 2);
              }
          }
          else {
              return pts.at(-1);
          }
      }
  }

  class OverlayBadgeShape extends mxgraph.mxText {
      constructor(value, bounds, style) {
          super(value, bounds, undefined, undefined, style.font.color, undefined, style.font.size, undefined, undefined, undefined, undefined, undefined, undefined, undefined, style.fill.color, style.stroke.color);
          this.fillOpacity = style.fill.opacity;
          this.strokewidth = style.stroke.width;
      }
  }

  function isFlowKind(kind) {
      return Object.values(exports.FlowKind)
          .map(value => value)
          .includes(kind);
  }

  function computeAllBpmnClassNamesOfCell(cell, isLabel) {
      return computeAllBpmnClassNames(cell.style, isLabel);
  }
  function computeAllBpmnClassNames(style, isLabel) {
      const classes = [];
      const styleElements = style.split(';');
      const pseudoBpmnElementKind = styleElements[0];
      const bpmnElementKind = pseudoBpmnElementKind.replace(/shape=bpmn./g, '');
      const typeClasses = new Map();
      typeClasses.set('bpmn-type-activity', ShapeUtil.isActivity(bpmnElementKind));
      typeClasses.set('bpmn-type-container', ShapeUtil.isPoolOrLane(bpmnElementKind));
      typeClasses.set('bpmn-type-event', ShapeUtil.isEvent(bpmnElementKind));
      typeClasses.set('bpmn-type-flow', isFlowKind(bpmnElementKind));
      typeClasses.set('bpmn-type-gateway', ShapeUtil.isGateway(bpmnElementKind));
      typeClasses.set('bpmn-type-task', ShapeUtil.isTask(bpmnElementKind));
      for (const [className] of [...typeClasses].filter(([, isType]) => isType))
          classes.push(className);
      classes.push(computeBpmnBaseClassName(bpmnElementKind));
      for (const [key, value] of styleElements.map(entry => {
          const elements = entry.split('=');
          return [elements[0], elements[1]];
      })) {
          switch (key) {
              case BpmnStyleIdentifier.EVENT_DEFINITION_KIND: {
                  classes.push(`bpmn-event-def-${value}`);
                  break;
              }
              case BpmnStyleIdentifier.EVENT_BASED_GATEWAY_KIND: {
                  classes.push(`bpmn-gateway-kind-${value.toLowerCase()}`);
                  break;
              }
              case BpmnStyleIdentifier.IS_INITIATING: {
                  classes.push(value == 'true' ? 'bpmn-icon-initiating' : 'bpmn-icon-non-initiating');
                  break;
              }
              case BpmnStyleIdentifier.SUB_PROCESS_KIND: {
                  classes.push(`bpmn-sub-process-${value.toLowerCase()}`);
                  break;
              }
              case BpmnStyleIdentifier.GLOBAL_TASK_KIND: {
                  classes.push(computeBpmnBaseClassName(value));
                  break;
              }
          }
      }
      if (isLabel) {
          classes.push('bpmn-label');
      }
      return classes;
  }
  function computeBpmnBaseClassName(bpmnElementKind) {
      return bpmnElementKind ? 'bpmn-' + bpmnElementKind.replace(/([A-Z])/g, g => '-' + g[0].toLowerCase()) : '';
  }

  const overrideCreateSvgCanvas = function (shape) {
      const originalShapeCreateSvgCanvas = shape.createSvgCanvas;
      shape.createSvgCanvas = function () {
          var _a;
          const canvas = originalShapeCreateSvgCanvas.bind(this)();
          const originalCanvasGetTextCss = canvas.getTextCss;
          canvas.getTextCss = function () {
              const originalPointerEvents = this.pointerEvents;
              this.pointerEvents = false;
              const textCss = originalCanvasGetTextCss.bind(this)();
              this.pointerEvents = originalPointerEvents;
              return textCss;
          };
          if ((_a = this.state) === null || _a === void 0 ? void 0 : _a.cell) {
              const cell = this.state.cell;
              const allBpmnClassNames = computeAllBpmnClassNamesOfCell(cell, this.dialect === mxConstants.DIALECT_STRICTHTML);
              const extraCssClasses = this.state.style[BpmnStyleIdentifier.EXTRA_CSS_CLASSES];
              if (typeof extraCssClasses == 'string') {
                  allBpmnClassNames.push(...extraCssClasses.split(','));
              }
              this.node.setAttribute('class', allBpmnClassNames.join(' '));
              this.node.dataset.bpmnId = this.state.cell.id;
          }
          return canvas;
      };
  };

  class BpmnCellRenderer extends mxgraph.mxCellRenderer {
      constructor(iconPainter) {
          super();
          Object.defineProperty(this, "iconPainter", {
              enumerable: true,
              configurable: true,
              writable: true,
              value: iconPainter
          });
      }
      createCellOverlays(state) {
          const graph = state.view.graph;
          const overlays = graph.getCellOverlays(state.cell);
          let dict = null;
          if (overlays != null) {
              dict = new mxgraph.mxDictionary();
              for (const currentOverlay of overlays) {
                  const shape = state.overlays == null ? null : state.overlays.remove(currentOverlay);
                  if (shape != null) {
                      dict.put(currentOverlay, shape);
                      continue;
                  }
                  let overlayShape;
                  if (currentOverlay instanceof MxGraphCustomOverlay) {
                      overlayShape = new OverlayBadgeShape(currentOverlay.label, new mxRectangle(0, 0, 0, 0), currentOverlay.style);
                  }
                  else {
                      overlayShape = new mxgraph.mxImageShape(new mxRectangle(0, 0, 0, 0), currentOverlay.image.src);
                      overlayShape.preserveImageAspect = false;
                  }
                  overlayShape.dialect = state.view.graph.dialect;
                  overlayShape.overlay = currentOverlay;
                  this.initializeOverlay(state, overlayShape);
                  this.installCellOverlayListeners(state, currentOverlay, overlayShape);
                  if (currentOverlay.cursor != null) {
                      overlayShape.node.style.cursor = currentOverlay.cursor;
                  }
                  if (overlayShape instanceof OverlayBadgeShape) {
                      overlayShape.node.classList.add('overlay-badge');
                      overlayShape.node.dataset.bpmnId = state.cell.id;
                  }
                  dict.put(currentOverlay, overlayShape);
              }
          }
          if (state.overlays != null) {
              state.overlays.visit(function (_id, shape) {
                  shape.destroy();
              });
          }
          state.overlays = dict;
      }
      createShape(state) {
          const shape = super.createShape(state);
          if ('iconPainter' in shape) {
              shape.iconPainter = this.iconPainter;
          }
          overrideCreateSvgCanvas(shape);
          return shape;
      }
      createLabel(state, value) {
          super.createLabel(state, value);
          overrideCreateSvgCanvas(state.text);
      }
  }

  function computeScaledIconSize(initialIconSize, iconStyleConfiguration, shapeConfiguration, ratioFromShape) {
      let iconWidthProportionalToShape;
      let iconHeightProportionalToShape;
      if (initialIconSize.height < initialIconSize.width || (initialIconSize.height == initialIconSize.width && shapeConfiguration.width <= shapeConfiguration.height)) {
          iconWidthProportionalToShape = shapeConfiguration.width;
          iconHeightProportionalToShape = (shapeConfiguration.width * initialIconSize.height) / initialIconSize.width;
      }
      else {
          iconWidthProportionalToShape = (shapeConfiguration.height * initialIconSize.width) / initialIconSize.height;
          iconHeightProportionalToShape = shapeConfiguration.height;
      }
      const inset = iconStyleConfiguration.strokeWidth ? (iconStyleConfiguration.strokeWidth - 1) * 2 : 0;
      const paintIconWidth = iconWidthProportionalToShape * ratioFromShape - inset;
      const paintIconHeight = iconHeightProportionalToShape * ratioFromShape - inset;
      return { width: paintIconWidth, height: paintIconHeight };
  }
  class BpmnCanvas {
      constructor({ canvas, shapeConfig, iconConfig }) {
          Object.defineProperty(this, "canvas", {
              enumerable: true,
              configurable: true,
              writable: true,
              value: void 0
          });
          Object.defineProperty(this, "iconOriginalSize", {
              enumerable: true,
              configurable: true,
              writable: true,
              value: void 0
          });
          Object.defineProperty(this, "scaleX", {
              enumerable: true,
              configurable: true,
              writable: true,
              value: void 0
          });
          Object.defineProperty(this, "scaleY", {
              enumerable: true,
              configurable: true,
              writable: true,
              value: void 0
          });
          Object.defineProperty(this, "iconPaintingOriginX", {
              enumerable: true,
              configurable: true,
              writable: true,
              value: 0
          });
          Object.defineProperty(this, "iconPaintingOriginY", {
              enumerable: true,
              configurable: true,
              writable: true,
              value: 0
          });
          Object.defineProperty(this, "shapeConfiguration", {
              enumerable: true,
              configurable: true,
              writable: true,
              value: void 0
          });
          this.canvas = canvas;
          this.shapeConfiguration = shapeConfig;
          this.iconOriginalSize = iconConfig.originalSize;
          const ratioFromShape = iconConfig.ratioFromParent;
          if (ratioFromShape) {
              const scaledIconSize = computeScaledIconSize(this.iconOriginalSize, iconConfig.styleConfig, this.shapeConfiguration, ratioFromShape);
              this.scaleX = scaledIconSize.width / this.iconOriginalSize.width;
              this.scaleY = scaledIconSize.height / this.iconOriginalSize.height;
          }
          else {
              this.scaleX = 1;
              this.scaleY = 1;
          }
          this.updateCanvasStyle(iconConfig.styleConfig);
          iconConfig.setIconOriginFunct(this);
      }
      setIconOriginToShapeTopLeftProportionally(shapeDimensionProportion) {
          const shape = this.shapeConfiguration;
          this.iconPaintingOriginX = shape.x + shape.width / shapeDimensionProportion;
          this.iconPaintingOriginY = shape.y + shape.height / shapeDimensionProportion;
      }
      setIconOriginToShapeTopLeft(topMargin = StyleDefault.SHAPE_ACTIVITY_TOP_MARGIN, leftMargin = StyleDefault.SHAPE_ACTIVITY_LEFT_MARGIN) {
          const shape = this.shapeConfiguration;
          this.iconPaintingOriginX = shape.x + leftMargin;
          this.iconPaintingOriginY = shape.y + topMargin;
      }
      setIconOriginForIconCentered() {
          const shape = this.shapeConfiguration;
          this.iconPaintingOriginX = shape.x + (shape.width - this.iconOriginalSize.width * this.scaleX) / 2;
          this.iconPaintingOriginY = shape.y + (shape.height - this.iconOriginalSize.height * this.scaleY) / 2;
      }
      setIconOriginForIconBottomCentered(bottomMargin = StyleDefault.SHAPE_ACTIVITY_BOTTOM_MARGIN) {
          const shape = this.shapeConfiguration;
          this.iconPaintingOriginX = shape.x + (shape.width - this.iconOriginalSize.width * this.scaleX) / 2;
          this.iconPaintingOriginY = shape.y + (shape.height - this.iconOriginalSize.height * this.scaleY - bottomMargin);
      }
      translateIconOrigin(dx, dy) {
          this.iconPaintingOriginX += this.scaleX * dx;
          this.iconPaintingOriginY += this.scaleY * dy;
      }
      computeScaleFromOriginX(x) {
          return this.iconPaintingOriginX + x * this.scaleX;
      }
      computeScaleFromOriginY(y) {
          return this.iconPaintingOriginY + y * this.scaleY;
      }
      updateCanvasStyle({ isFilled, strokeColor, fillColor, strokeWidth }) {
          if (isFilled) {
              this.canvas.setFillColor(strokeColor);
          }
          else {
              this.canvas.setFillColor(fillColor);
          }
          this.canvas.setStrokeWidth(strokeWidth);
      }
      arcTo(rx, ry, angle, largeArcFlag, sweepFlag, x, y) {
          this.canvas.arcTo(rx * this.scaleX, ry * this.scaleY, angle, largeArcFlag, sweepFlag, this.computeScaleFromOriginX(x), this.computeScaleFromOriginY(y));
      }
      begin() {
          this.canvas.begin();
      }
      close() {
          this.canvas.close();
      }
      curveTo(x1, y1, x2, y2, x3, y3) {
          this.canvas.curveTo(this.computeScaleFromOriginX(x1), this.computeScaleFromOriginY(y1), this.computeScaleFromOriginX(x2), this.computeScaleFromOriginY(y2), this.computeScaleFromOriginX(x3), this.computeScaleFromOriginY(y3));
      }
      fill() {
          this.canvas.fill();
      }
      fillAndStroke() {
          this.canvas.fillAndStroke();
      }
      setFillColor(fillColor) {
          this.canvas.setFillColor(fillColor);
      }
      stroke() {
          this.canvas.stroke();
      }
      setStrokeColor(color) {
          this.canvas.setStrokeColor(color);
      }
      setRoundLineJoin() {
          this.canvas.setLineJoin('round');
      }
      lineTo(x, y) {
          this.canvas.lineTo(this.computeScaleFromOriginX(x), this.computeScaleFromOriginY(y));
      }
      moveTo(x, y) {
          this.canvas.moveTo(this.computeScaleFromOriginX(x), this.computeScaleFromOriginY(y));
      }
      rect(x, y, w, h) {
          this.canvas.rect(this.computeScaleFromOriginX(x), this.computeScaleFromOriginY(y), w * this.scaleX, h * this.scaleY);
      }
      roundrect(x, y, w, h, dx, dy) {
          this.canvas.roundrect(this.computeScaleFromOriginX(x), this.computeScaleFromOriginY(y), w * this.scaleX, h * this.scaleY, dx, dy);
      }
      ellipse(x, y, w, h) {
          this.canvas.ellipse(this.computeScaleFromOriginX(x), this.computeScaleFromOriginY(y), w * this.scaleX, h * this.scaleY);
      }
      rotateOnIconCenter(theta) {
          const rotationCenterX = this.iconPaintingOriginX + (this.iconOriginalSize.width / 2) * this.scaleX;
          const rotationCenterY = this.iconPaintingOriginY + (this.iconOriginalSize.height / 2) * this.scaleY;
          this.canvas.rotate(theta, false, false, rotationCenterX, rotationCenterY);
      }
  }

  function buildPaintParameter({ canvas, x, y, width, height, shape, ratioFromParent, isFilled, iconStrokeWidth, }) {
      const shapeStrokeWidth = mxUtils.getValue(shape.style, mxConstants.STYLE_STROKEWIDTH, StyleDefault.STROKE_WIDTH_THIN);
      const fillColor = mxUtils.getValue(shape.style, mxConstants.STYLE_FILLCOLOR, StyleDefault.DEFAULT_FILL_COLOR);
      const strokeColor = mxUtils.getValue(shape.style, mxConstants.STYLE_STROKECOLOR, StyleDefault.DEFAULT_STROKE_COLOR);
      const margin = mxUtils.getValue(shape.style, mxConstants.STYLE_MARGIN, StyleDefault.DEFAULT_MARGIN);
      ratioFromParent !== null && ratioFromParent !== void 0 ? ratioFromParent : (ratioFromParent = 0.25);
      isFilled !== null && isFilled !== void 0 ? isFilled : (isFilled = false);
      iconStrokeWidth !== null && iconStrokeWidth !== void 0 ? iconStrokeWidth : (iconStrokeWidth = 0);
      return {
          canvas,
          ratioFromParent,
          setIconOriginFunct: (internalCanvas) => internalCanvas.setIconOriginForIconCentered(),
          shapeConfig: { x, y, width, height, strokeWidth: shapeStrokeWidth },
          iconStyleConfig: { isFilled, fillColor, strokeColor, strokeWidth: iconStrokeWidth, margin },
      };
  }
  class IconPainter {
      newBpmnCanvas({ canvas, ratioFromParent, setIconOriginFunct, shapeConfig, iconStyleConfig }, originalIconSize) {
          return new BpmnCanvas({
              canvas,
              shapeConfig,
              iconConfig: {
                  originalSize: originalIconSize,
                  styleConfig: iconStyleConfig,
                  ratioFromParent,
                  setIconOriginFunct,
              },
          });
      }
      paintEnvelopeIcon(paintParameter) {
          const originalIconSize = { width: 485.41, height: 321.76 };
          const canvas = this.newBpmnCanvas(paintParameter, originalIconSize);
          const w = originalIconSize.width;
          const h = originalIconSize.height;
          canvas.rect(0, 0, w, h);
          canvas.fillAndStroke();
          const { iconStyleConfig } = paintParameter;
          if (iconStyleConfig.isFilled) {
              canvas.setStrokeColor(iconStyleConfig.fillColor);
          }
          canvas.begin();
          canvas.moveTo(0, 0);
          canvas.lineTo(w * 0.5, h * 0.6);
          canvas.lineTo(w, 0);
          canvas.moveTo(0, h);
          canvas.lineTo(w / 3, h * 0.45);
          canvas.moveTo(w, h);
          canvas.lineTo((w * 2) / 3, h * 0.45);
          canvas.stroke();
      }
      paintCircleIcon(paintParameter) {
          const originalIconSize = { width: paintParameter.shapeConfig.width, height: paintParameter.shapeConfig.height };
          const canvas = this.newBpmnCanvas(paintParameter, originalIconSize);
          const w = originalIconSize.width;
          const h = originalIconSize.height;
          if (w > 0 && h > 0) {
              canvas.ellipse(0, 0, w, h);
          }
          if (paintParameter.iconStyleConfig.isFilled) {
              canvas.fillAndStroke();
          }
          else {
              canvas.stroke();
          }
      }
      paintClockIcon(paintParameter) {
          const canvas = this.newBpmnCanvas(paintParameter, { height: 152, width: 152 });
          canvas.begin();
          canvas.moveTo(184, 60);
          canvas.curveTo(188.4, 60, 192, 56.4, 192, 52);
          canvas.lineTo(192, 48);
          canvas.curveTo(192, 40, 188.4, 40, 184, 40);
          canvas.curveTo(179.6, 40, 176, 43.6, 176, 48);
          canvas.lineTo(176, 52);
          canvas.curveTo(176, 56.4, 179.6, 60, 184, 60);
          canvas.close();
          canvas.moveTo(184, 308);
          canvas.curveTo(179.6, 308, 176, 311.6, 176, 316);
          canvas.lineTo(176, 320);
          canvas.curveTo(176, 324.4, 179.6, 328, 184, 328);
          canvas.curveTo(188.4, 328, 192, 324.4, 192, 320);
          canvas.lineTo(192, 316);
          canvas.curveTo(192, 311.6, 188.4, 308, 184, 308);
          canvas.close();
          canvas.moveTo(52, 176);
          canvas.lineTo(48, 176);
          canvas.curveTo(43.6, 176, 40, 179.6, 40, 184);
          canvas.curveTo(40, 188.4, 43.6, 192, 48, 192);
          canvas.lineTo(52, 192);
          canvas.curveTo(56.4, 192, 69, 188.4, 60, 184);
          canvas.curveTo(60, 179.6, 56.4, 176, 52, 176);
          canvas.close();
          canvas.moveTo(320, 176);
          canvas.lineTo(316, 176);
          canvas.curveTo(311.6, 176, 308, 179.6, 308, 184);
          canvas.curveTo(308, 188.4, 311.6, 192, 316, 192);
          canvas.lineTo(320, 192);
          canvas.curveTo(324.4, 192, 328, 188.4, 328, 184);
          canvas.curveTo(328, 179.6, 324.4, 176, 320, 176);
          canvas.moveTo(93.6, 82.4);
          canvas.curveTo(90.4, 79.2, 85.6, 79.2, 82.4, 82.4);
          canvas.curveTo(79.2, 85.6, 79.2, 90.4, 82.4, 93.6);
          canvas.lineTo(85.2, 96.4);
          canvas.curveTo(86.8, 98, 88.8, 98.8, 90.8, 98.8);
          canvas.curveTo(92.8, 98.8, 94.4, 98, 96.4, 96.4);
          canvas.curveTo(99.6, 93.2, 99.6, 88.4, 96.4, 85.2);
          canvas.lineTo(93.6, 82.4);
          canvas.moveTo(85.2, 271.6);
          canvas.lineTo(82.4, 274.4);
          canvas.curveTo(79.2, 277.6, 79.2, 282.4, 82.4, 285.6);
          canvas.curveTo(84, 287.2, 86, 288, 88, 288);
          canvas.curveTo(90, 288, 92, 287.2, 93.6, 285.6);
          canvas.lineTo(96.4, 282.8);
          canvas.curveTo(99.6, 279.6, 99.6, 274.8, 96.4, 271.6);
          canvas.curveTo(93.2, 268.4, 88.4, 268.4, 85.2, 271.6);
          canvas.moveTo(274.4, 82.4);
          canvas.lineTo(271.6, 85.2);
          canvas.curveTo(268.4, 88.4, 268.4, 93.2, 271.6, 96.4);
          canvas.curveTo(273.298, 98, 275.2, 98.8, 277.2, 98.8);
          canvas.curveTo(279.2, 98.8, 281.2, 98, 282.8, 96.4);
          canvas.lineTo(285.6, 93.6);
          canvas.curveTo(288.8, 90.4, 288.8, 85.6, 285.6, 82.4);
          canvas.curveTo(282.4, 79.2, 277.6, 79.2, 274.4, 82.4);
          canvas.moveTo(192, 180.8);
          canvas.lineTo(192, 108);
          canvas.curveTo(192, 103.6, 188.4, 100, 184, 100);
          canvas.curveTo(179.6, 100, 176, 103.6, 176, 108);
          canvas.lineTo(176, 184);
          canvas.curveTo(176, 186, 176.8, 188, 178.4, 189.6);
          canvas.lineTo(266, 277.2);
          canvas.curveTo(267.6, 278.8, 269.6, 279.6, 271.6, 279.6);
          canvas.curveTo(273.6, 279.6, 275.6, 278.8, 277.2, 277.2);
          canvas.curveTo(280.4, 274, 280.4, 269.2, 277.2, 266);
          canvas.lineTo(192, 180.8);
          canvas.moveTo(184, 0);
          canvas.curveTo(82.4, 0, 0, 82.4, 0, 184);
          canvas.curveTo(0, 285.6, 82.4, 368, 184, 368);
          canvas.curveTo(285.6, 368, 368, 285.6, 368, 184);
          canvas.curveTo(368, 82.4, 285.6, 0, 184, 0);
          canvas.moveTo(184, 352);
          canvas.curveTo(91.2, 352, 16, 276.8, 16, 184);
          canvas.curveTo(16, 91.2, 91.2, 16, 184, 16);
          canvas.curveTo(276.8, 16, 352, 91.2, 352, 184);
          canvas.curveTo(352, 276.8, 276.8, 352, 184, 352);
          canvas.fillAndStroke();
      }
      paintTriangleIcon(paintParameter) {
          const canvas = this.newBpmnCanvas(paintParameter, { height: 735, width: 849 });
          canvas.begin();
          canvas.moveTo(497, 55);
          canvas.lineTo(817, 609);
          canvas.curveTo(849, 665, 808, 735, 744, 735);
          canvas.lineTo(105, 735);
          canvas.curveTo(40, 735, 0, 665, 32, 609);
          canvas.lineTo(352, 55);
          canvas.curveTo(384, 0, 465, 0, 497, 55);
          canvas.close();
          canvas.fillAndStroke();
      }
      paintUpArrowheadIcon(paintParameter) {
          const canvas = this.newBpmnCanvas(paintParameter, { height: 50, width: 40 });
          canvas.begin();
          canvas.moveTo(0, 49.5);
          canvas.lineTo(19.5, 1);
          canvas.curveTo(19.75, 0.25, 20, 0, 20.25, 0.25);
          canvas.lineTo(40, 49.5);
          canvas.curveTo(40, 49.5, 39.75, 50, 39.6, 49.75);
          canvas.lineTo(20, 30);
          canvas.lineTo(0.4, 49.75);
          canvas.curveTo(0.4, 49.75, 0.25, 50, 0, 49.5);
          canvas.close();
          canvas.fillAndStroke();
      }
      paintDoubleLeftArrowheadsIcon(paintParameter) {
          const canvas = this.newBpmnCanvas(paintParameter, { height: 53.5, width: 105 });
          canvas.begin();
          canvas.moveTo(91.4, 0);
          canvas.curveTo(91.4, 0, 91.2, 0, 91, 0.2);
          canvas.lineTo(50, 25);
          canvas.curveTo(47.9, 25.8, 46.7, 26.6, 46.4, 27.3);
          canvas.lineTo(46.4, 0);
          canvas.curveTo(46.4, 0, 46.2, 0, 46, 0.2);
          canvas.lineTo(4.9, 25);
          canvas.curveTo(2, 26.2, 0, 27.3, 4.9, 28.5);
          canvas.lineTo(45.8, 53);
          canvas.curveTo(46, 53.3, 46.2, 53.5, 46.4, 53.5);
          canvas.lineTo(46.4, 27);
          canvas.curveTo(46.6, 27.3, 47.8, 28.1, 49.9, 29.9);
          canvas.lineTo(90.8, 53.3);
          canvas.curveTo(91, 53.3, 91.2, 53.5, 91.4, 53.5);
          canvas.lineTo(91.4, 0);
          canvas.close();
          canvas.fillAndStroke();
      }
      drawCrossIcon(paintParameter) {
          const canvas = this.newBpmnCanvas(paintParameter, { height: 1, width: 1 });
          canvas.begin();
          canvas.moveTo(0.38, 0);
          canvas.lineTo(0.62, 0);
          canvas.lineTo(0.62, 0.38);
          canvas.lineTo(1, 0.38);
          canvas.lineTo(1, 0.62);
          canvas.lineTo(0.62, 0.62);
          canvas.lineTo(0.62, 1);
          canvas.lineTo(0.38, 1);
          canvas.lineTo(0.38, 0.62);
          canvas.lineTo(0, 0.62);
          canvas.lineTo(0, 0.38);
          canvas.lineTo(0.38, 0.38);
          canvas.close();
          return canvas;
      }
      paintListIcon(paintParameter) {
          const canvas = this.newBpmnCanvas(paintParameter, { height: 60, width: 60 });
          canvas.begin();
          canvas.moveTo(0, 0);
          canvas.lineTo(60, 0);
          canvas.lineTo(60, 60);
          canvas.lineTo(0, 60);
          canvas.lineTo(0, 0);
          canvas.close();
          canvas.moveTo(5, 5);
          canvas.lineTo(55, 5);
          canvas.close();
          canvas.moveTo(5, 21.6);
          canvas.lineTo(55, 21.6);
          canvas.close();
          canvas.moveTo(5, 38.3);
          canvas.lineTo(55, 38.3);
          canvas.close();
          canvas.moveTo(5, 55);
          canvas.lineTo(55, 55);
          canvas.close();
          canvas.fillAndStroke();
      }
      paintXCrossIcon(paintParameter) {
          const canvas = this.drawCrossIcon(paintParameter);
          canvas.rotateOnIconCenter(45);
          canvas.fillAndStroke();
      }
      paintPlusCrossIcon(paintParameter) {
          this.drawCrossIcon(paintParameter).fillAndStroke();
      }
      paintAsteriskIcon(paintParameter) {
          const canvas = this.newBpmnCanvas(paintParameter, { height: 1, width: 1 });
          drawVerticalLine(canvas);
          canvas.fillAndStroke();
          drawVerticalLine(canvas);
          canvas.rotateOnIconCenter(60);
          canvas.fillAndStroke();
          drawVerticalLine(canvas);
          canvas.rotateOnIconCenter(240);
          canvas.fillAndStroke();
      }
      paintPersonIcon(paintParameter) {
          const canvas = this.newBpmnCanvas(Object.assign(Object.assign({}, paintParameter), { iconStyleConfig: Object.assign(Object.assign({}, paintParameter.iconStyleConfig), { isFilled: true }) }), { height: 239.68, width: 143.61 });
          canvas.begin();
          canvas.moveTo(124.31, 150.29);
          canvas.lineTo(99.66, 141.03);
          canvas.arcTo(6.43, 6.43, 0, 0, 1, 95.51, 135.03);
          canvas.lineTo(95.51, 130.66);
          canvas.arcTo(47.75, 47.75, 0, 0, 0, 119.51, 89.25);
          canvas.lineTo(119.51, 71.25);
          canvas.arcTo(47.62, 47.62, 0, 0, 0, 101.18, 33.64);
          canvas.arcTo(29.35, 29.35, 0, 0, 0, 101.52, 29.14);
          canvas.arcTo(29.68, 29.68, 0, 0, 0, 42.17, 29.14);
          canvas.arcTo(29.24, 29.24, 0, 0, 0, 42.53, 33.63);
          canvas.arcTo(47.65, 47.65, 0, 0, 0, 24.14, 71.23);
          canvas.lineTo(24.14, 89.23);
          canvas.arcTo(47.7, 47.7, 0, 0, 0, 48.19, 130.63);
          canvas.lineTo(48.19, 135.03);
          canvas.arcTo(6.43, 6.43, 0, 0, 1, 44.03, 141.03);
          canvas.lineTo(19.31, 150.29);
          canvas.arcTo(29.81, 29.81, 0, 0, 0, 0.09, 178.03);
          canvas.lineTo(0.09, 233.51);
          canvas.arcTo(5.63, 5.63, 0, 1, 0, 11.34, 233.51);
          canvas.lineTo(11.34, 178.03);
          canvas.arcTo(18.19, 18.19, 0, 0, 1, 11.57, 175.17);
          canvas.lineTo(20.5, 184.11);
          canvas.arcTo(12.32, 12.32, 0, 0, 1, 24.14, 192.89);
          canvas.lineTo(24.14, 233.51);
          canvas.arcTo(5.63, 5.63, 0, 1, 0, 35.39, 233.51);
          canvas.lineTo(35.39, 192.93);
          canvas.arcTo(23.5, 23.5, 0, 0, 0, 28.46, 176.2);
          canvas.lineTo(17.04, 164.78);
          canvas.arcTo(18.34, 18.34, 0, 0, 1, 23.29, 160.78);
          canvas.lineTo(43.65, 153.15);
          canvas.lineTo(66.22, 175.72);
          canvas.lineTo(66.22, 233.51);
          canvas.arcTo(5.63, 5.63, 0, 1, 0, 77.47, 233.51);
          canvas.lineTo(77.47, 175.76);
          canvas.lineTo(100.04, 153.19);
          canvas.lineTo(120.4, 160.82);
          canvas.arcTo(18.39, 18.39, 0, 0, 1, 126.65, 164.82);
          canvas.lineTo(115.24, 176.24);
          canvas.arcTo(23.5, 23.5, 0, 0, 0, 108.31, 192.93);
          canvas.lineTo(108.31, 233.55);
          canvas.arcTo(5.63, 5.63, 0, 1, 0, 119.56, 233.55);
          canvas.lineTo(119.56, 192.93);
          canvas.arcTo(12.35, 12.35, 0, 0, 1, 123.19, 184.15);
          canvas.lineTo(132.13, 175.22);
          canvas.arcTo(18, 18, 0, 0, 1, 132.36, 178.08);
          canvas.lineTo(132.36, 233.56);
          canvas.arcTo(5.63, 5.63, 0, 0, 0, 143.61, 233.56);
          canvas.lineTo(143.61, 178.03);
          canvas.arcTo(29.81, 29.81, 0, 0, 0, 124.31, 150.29);
          canvas.close();
          canvas.moveTo(71.85, 10.72);
          canvas.arcTo(18.46, 18.46, 0, 0, 1, 90.17, 27.18);
          canvas.arcTo(47.68, 47.68, 0, 0, 0, 53.53, 27.18);
          canvas.arcTo(18.44, 18.44, 0, 0, 1, 71.85, 10.72);
          canvas.close();
          canvas.moveTo(35.39, 71.23);
          canvas.arcTo(36.46, 36.46, 0, 0, 1, 108.31, 71.23);
          canvas.lineTo(108.31, 77.4);
          canvas.curveTo(82.12, 75.4, 56.97, 60.55, 56.71, 60.4);
          canvas.arcTo(5.62, 5.62, 0, 0, 0, 48.78, 62.71);
          canvas.curveTo(46.24, 67.79, 40.45, 71.89, 35.39, 74.62);
          canvas.close();
          canvas.moveTo(35.39, 89.23);
          canvas.lineTo(35.39, 87.08);
          canvas.curveTo(40.55, 84.85, 49.73, 80.08, 55.67, 72.66);
          canvas.curveTo(64.83, 77.46, 85.92, 87.21, 108.31, 88.66);
          canvas.lineTo(108.31, 89.24);
          canvas.arcTo(36.46, 36.46, 0, 1, 1, 35.39, 89.24);
          canvas.close();
          canvas.moveTo(71.85, 165.45);
          canvas.lineTo(54.06, 147.69);
          canvas.arcTo(17.7, 17.7, 0, 0, 0, 59.43, 135.32);
          canvas.arcTo(47.57, 47.57, 0, 0, 0, 84.27, 135.32);
          canvas.arcTo(17.7, 17.7, 0, 0, 0, 89.64, 147.69);
          canvas.close();
          canvas.fill();
      }
      paintGearIcon(paintParameter) {
          const canvas = this.newBpmnCanvas(paintParameter, { height: 100, width: 100 });
          paintGearIconBackground(canvas);
          canvas.translateIconOrigin(14, 14);
          paintGearIconForeground(canvas);
      }
      paintExpandIcon(paintParameter) {
          const originalIconSize = { width: 16, height: 16 };
          const canvas = this.newBpmnCanvas(paintParameter, originalIconSize);
          const w = originalIconSize.width;
          const h = originalIconSize.height;
          canvas.roundrect(0, 0, w, h, 2, 2);
          canvas.stroke();
          canvas.begin();
          canvas.moveTo(w / 2, h / 4);
          canvas.lineTo(w / 2, (h * 3) / 4);
          canvas.close();
          canvas.moveTo(w / 4, h / 2);
          canvas.lineTo((w * 3) / 4, h / 2);
          canvas.close();
          canvas.fillAndStroke();
      }
      paintLoopIcon(paintParameter) {
          const { iconStyleConfig } = paintParameter;
          iconStyleConfig.fillColor = iconStyleConfig.strokeColor;
          const canvas = this.newBpmnCanvas(paintParameter, { width: 22.49, height: 21.62 });
          canvas.begin();
          canvas.moveTo(5.5, 19.08);
          canvas.arcTo(8, 8, 0, 1, 1, 10.5, 21.08);
          canvas.stroke();
          canvas.begin();
          canvas.moveTo(7.5, 14.08);
          canvas.lineTo(5.75, 19.08);
          canvas.lineTo(0, 17.08);
          canvas.close();
          canvas.fillAndStroke();
      }
      paintSequentialMultiInstanceIcon(paintParameter) {
          const originalIconSize = { width: 16, height: 16 };
          const bpmnCanvas = this.newBpmnCanvas(paintParameter, originalIconSize);
          const { canvas, iconStyleConfig } = paintParameter;
          canvas.setFillColor(iconStyleConfig.strokeColor);
          const barWidth = originalIconSize.width;
          const barHeight = originalIconSize.height / 5;
          bpmnCanvas.rect(0, 0, barWidth, barHeight);
          bpmnCanvas.fill();
          bpmnCanvas.rect(0, 2 * barHeight, barWidth, barHeight);
          bpmnCanvas.fill();
          bpmnCanvas.rect(0, 4 * barHeight, barWidth, barHeight);
          bpmnCanvas.fill();
      }
      paintParallelMultiInstanceIcon(paintParameter) {
          const originalIconSize = { width: 16, height: 16 };
          const bpmnCanvas = this.newBpmnCanvas(paintParameter, originalIconSize);
          const { canvas, iconStyleConfig } = paintParameter;
          canvas.setFillColor(iconStyleConfig.strokeColor);
          const barWidth = originalIconSize.width / 5;
          const barHeight = originalIconSize.height;
          bpmnCanvas.begin();
          bpmnCanvas.rect(0, 0, barWidth, barHeight);
          bpmnCanvas.fill();
          bpmnCanvas.rect(2 * barWidth, 0, barWidth, barHeight);
          bpmnCanvas.fill();
          bpmnCanvas.rect(4 * barWidth, 0, barWidth, barHeight);
          bpmnCanvas.fill();
      }
      paintRightArrowIcon(paintParameter) {
          const canvas = this.newBpmnCanvas(paintParameter, { width: 512, height: 415.23 });
          canvas.setRoundLineJoin();
          canvas.begin();
          canvas.moveTo(512, 207.61);
          canvas.lineTo(304.38, 0);
          canvas.lineTo(304.38, 135.39);
          canvas.lineTo(0, 135.39);
          canvas.lineTo(0, 279.84);
          canvas.lineTo(304.38, 279.84);
          canvas.lineTo(304.38, 415.23);
          canvas.lineTo(512, 207.61);
          canvas.close();
          canvas.fillAndStroke();
      }
      paintErrorIcon(paintParameter) {
          const canvas = this.newBpmnCanvas(paintParameter, { width: 72.44, height: 71.82 });
          canvas.begin();
          canvas.moveTo(0, 53.32);
          canvas.lineTo(19.48, 0);
          canvas.lineTo(19.48, 0);
          canvas.lineTo(50.85, 40.07);
          canvas.lineTo(72.44, 18.21);
          canvas.lineTo(53.12, 71.82);
          canvas.lineTo(22.5, 31.37);
          canvas.close();
          canvas.fillAndStroke();
      }
      paintHandIcon(paintParameter) {
          const canvas = this.newBpmnCanvas(paintParameter, { width: 343.65, height: 354.12 });
          canvas.begin();
          canvas.moveTo(231.66, 336.39);
          canvas.curveTo(240.84, 316.9, 220.53, 306.92, 220.53, 306.92);
          canvas.curveTo(215.2, 303.67, 188.58, 287.43, 140.67, 258.19);
          canvas.lineTo(146.33, 248.39);
          canvas.curveTo(223.98, 269.38, 267.12, 281.04, 275.75, 283.38);
          canvas.curveTo(275.75, 283.38, 297.25, 288, 301.42, 267.77);
          canvas.curveTo(306.34, 245.29, 288.32, 238.63, 288.32, 238.63);
          canvas.curveTo(279.91, 236.44, 237.86, 225.48, 162.18, 205.75);
          canvas.lineTo(165.2, 194.8);
          canvas.curveTo(255.88, 204.4, 306.27, 209.73, 316.34, 210.8);
          canvas.curveTo(316.34, 210.8, 339.89, 212.16, 341.76, 189.55);
          canvas.curveTo(343.65, 166.93, 320.5, 164.13, 320.5, 164.13);
          canvas.curveTo(310.43, 163.1, 260.04, 157.99, 169.35, 148.77);
          canvas.lineTo(169.35, 138.97);
          canvas.curveTo(253.41, 132.12, 300.11, 128.32, 309.45, 127.56);
          canvas.curveTo(309.45, 127.56, 332.27, 122.38, 332.27, 102.61);
          canvas.curveTo(332.27, 82.85, 305.48, 81.87, 305.48, 81.87);
          canvas.curveTo(293.99, 82.2, 236.54, 83.88, 133.13, 86.9);
          canvas.lineTo(127.61, 81.87);
          canvas.curveTo(145.3, 59.39, 155.12, 46.9, 157.09, 44.41);
          canvas.curveTo(157.09, 44.41, 171.12, 26.8, 156.78, 12.72);
          canvas.curveTo(143.83, 0, 124.08, 14.49, 124.08, 14.49);
          canvas.curveTo(116.45, 19.41, 78.35, 44.06, 9.77, 88.43);
          canvas.lineTo(0, 251.94);
          canvas.curveTo(122.84, 308.79, 191.09, 340.37, 204.74, 346.69);
          canvas.curveTo(204.74, 346.69, 222.91, 354.12, 231.66, 336.39);
          canvas.fillAndStroke();
      }
      paintScriptIcon(paintParameter) {
          paintParameter.iconStyleConfig.fillColor = paintParameter.iconStyleConfig.strokeColor;
          const canvas = this.newBpmnCanvas(paintParameter, { width: 458.75, height: 461.64 });
          canvas.begin();
          canvas.moveTo(67.85, 0.57);
          canvas.curveTo(50.73, 0, 33.26, 8.86, 22.35, 18.84);
          canvas.curveTo(8.11, 32.15, 0, 50.77, 0, 70.26);
          canvas.curveTo(0, 73.15, 0, 87.59, 0, 113.6);
          canvas.curveTo(55.4, 113.6, 86.18, 113.6, 92.33, 113.6);
          canvas.curveTo(94.92, 150.46, 85.64, 180.4, 74.22, 211.27);
          canvas.curveTo(40.16, 298.07, 30.77, 339.83, 55.56, 410.87);
          canvas.curveTo(63.72, 438.26, 87.59, 457.85, 114.91, 461.09);
          canvas.curveTo(216.96, 460.85, 294.9, 461.64, 388.41, 461.2);
          canvas.curveTo(407.2, 461.09, 425.14, 453.55, 438.3, 440.13);
          canvas.curveTo(451.46, 426.71, 458.75, 403.06, 458.46, 384.26);
          canvas.curveTo(458.43, 382.23, 458.18, 365.93, 458.15, 363.89);
          canvas.curveTo(432.12, 364.24, 406.09, 364.04, 380.06, 364.04);
          canvas.curveTo(377.61, 347.52, 377.24, 337.58, 378.28, 324.48);
          canvas.curveTo(380.5, 296.47, 389.08, 273.36, 398.59, 247.1);
          canvas.curveTo(408.11, 220.83, 418.41, 191.47, 420.86, 154.24);
          canvas.curveTo(422.11, 135.34, 421.4, 110.24, 417.77, 86.75);
          canvas.curveTo(417.76, 86.71, 417.73, 86.54, 417.69, 86.22);
          canvas.curveTo(417.64, 85.95, 417.61, 85.79, 417.6, 85.76);
          canvas.curveTo(414.03, 68.13, 410.49, 48.84, 399.79, 31.47);
          canvas.curveTo(389.09, 14.11, 366.95, 0.59, 341.75, 0.59);
          canvas.curveTo(286.97, 0.59, 122.63, 0.57, 67.85, 0.57);
          canvas.close();
          canvas.moveTo(85.04, 72.68);
          canvas.curveTo(80.63, 72.68, 45.33, 72.68, 40.92, 72.68);
          canvas.curveTo(40.46, 58.4, 47.15, 51.87, 50.27, 48.75);
          canvas.curveTo(55.8, 44.28, 59.84, 41, 73.82, 41);
          canvas.curveTo(78.45, 52.13, 82.23, 62.71, 85.04, 72.68);
          canvas.close();
          canvas.moveTo(364.94, 52.9);
          canvas.curveTo(370, 61.11, 373.9, 76.44, 377.38, 93.51);
          canvas.curveTo(380.35, 113.1, 381.01, 136.42, 380.02, 151.57);
          canvas.curveTo(377.97, 182.76, 369.51, 207.12, 360.1, 233.1);
          canvas.curveTo(350.69, 259.09, 340.27, 286.77, 337.53, 321.27);
          canvas.curveTo(336.38, 335.86, 336.72, 346.69, 338.87, 364.01);
          canvas.curveTo(326.35, 364.01, 263.75, 364.01, 151.06, 364.01);
          canvas.curveTo(151.06, 382.2, 151.06, 392.31, 151.06, 394.33);
          canvas.curveTo(147.77, 404.8, 138.9, 418.2, 127.43, 419.94);
          canvas.curveTo(111.49, 422.35, 97.86, 411.8, 94.75, 399.19);
          canvas.curveTo(65.14, 321.99, 94.93, 275.54, 112.57, 225.47);
          canvas.curveTo(130.14, 177.95, 137.92, 117.41, 112.71, 42.09);
          canvas.curveTo(192.88, 41.9, 274.33, 42.21, 342.89, 41.98);
          canvas.curveTo(357.15, 42.03, 359.83, 44.61, 364.94, 52.9);
          canvas.close();
          canvas.moveTo(409.96, 399.48);
          canvas.curveTo(409.96, 408.42, 398.54, 425.67, 392.02, 425.67);
          canvas.curveTo(325.19, 425.79, 252.29, 425.67, 185.23, 425.67);
          canvas.curveTo(189.88, 424.43, 194.66, 405.64, 194.66, 399.48);
          canvas.curveTo(237.72, 399.48, 388.43, 399.48, 409.96, 399.48);
          canvas.close();
          canvas.fill();
          canvas.begin();
          canvas.moveTo(182.1, 131.2);
          canvas.lineTo(182.1, 151.68);
          canvas.lineTo(321.89, 151.68);
          canvas.lineTo(321.89, 131.2);
          canvas.lineTo(182.1, 131.2);
          canvas.close();
          canvas.moveTo(162.25, 251.09);
          canvas.lineTo(162.25, 271.49);
          canvas.lineTo(301.96, 271.49);
          canvas.lineTo(301.96, 251.09);
          canvas.lineTo(162.25, 251.09);
          canvas.close();
          canvas.fill();
      }
      paintTableIcon(paintParameter) {
          const canvas = this.newBpmnCanvas(paintParameter, { width: 640, height: 640 });
          canvas.begin();
          canvas.moveTo(0.19, 0.1);
          canvas.lineTo(298.78, 0.1);
          canvas.lineTo(298.78, 198.88);
          canvas.lineTo(0.19, 198.88);
          canvas.lineTo(0.19, 0.1);
          canvas.close();
          canvas.fillAndStroke();
          canvas.begin();
          canvas.moveTo(0, 0);
          canvas.lineTo(298.78, 0);
          canvas.lineTo(298.78, 48.88);
          canvas.lineTo(0, 48.88);
          canvas.lineTo(0, 0);
          canvas.close();
          canvas.fillAndStroke();
          canvas.begin();
          canvas.moveTo(0, 48.88);
          canvas.lineTo(98.78, 48.88);
          canvas.lineTo(98.78, 198.88);
          canvas.lineTo(0, 198.88);
          canvas.lineTo(0, 48.88);
          canvas.close();
          canvas.fillAndStroke();
          canvas.begin();
          canvas.moveTo(1.09, 122.69);
          canvas.lineTo(298.78, 122.69);
          canvas.close();
          canvas.fillAndStroke();
          canvas.setFillColor(paintParameter.iconStyleConfig.strokeColor);
          canvas.begin();
          canvas.moveTo(0, 0);
          canvas.lineTo(298.78, 0);
          canvas.lineTo(298.78, 48.88);
          canvas.lineTo(0, 48.88);
          canvas.lineTo(0, 0);
          canvas.close();
          canvas.fillAndStroke();
      }
      paintPentagon(paintParameter) {
          const canvas = this.newBpmnCanvas(paintParameter, { width: 16, height: 16 });
          canvas.begin();
          canvas.moveTo(16, 6.5);
          canvas.lineTo(8, 0);
          canvas.lineTo(0, 6.5);
          canvas.lineTo(3, 16);
          canvas.lineTo(13, 16);
          canvas.lineTo(16, 6.5);
          canvas.lineTo(8, 0);
          canvas.stroke();
      }
  }
  function drawVerticalLine(canvas) {
      canvas.begin();
      canvas.moveTo(0.38, 0);
      canvas.lineTo(0.62, 0);
      canvas.lineTo(0.62, 1);
      canvas.lineTo(0.38, 1);
      canvas.close();
  }
  function paintGearIconBackground(canvas) {
      canvas.begin();
      canvas.moveTo(2.06, 24.62);
      canvas.lineTo(10.17, 30.95);
      canvas.lineTo(9.29, 37.73);
      canvas.lineTo(0, 41.42);
      canvas.lineTo(2.95, 54.24);
      canvas.lineTo(13.41, 52.92);
      canvas.lineTo(17.39, 58.52);
      canvas.lineTo(13.56, 67.66);
      canvas.lineTo(24.47, 74.44);
      canvas.lineTo(30.81, 66.33);
      canvas.lineTo(37.88, 67.21);
      canvas.lineTo(41.57, 76.5);
      canvas.lineTo(54.24, 73.55);
      canvas.lineTo(53.06, 62.94);
      canvas.lineTo(58.52, 58.52);
      canvas.lineTo(67.21, 63.09);
      canvas.lineTo(74.58, 51.88);
      canvas.lineTo(66.03, 45.25);
      canvas.lineTo(66.92, 38.62);
      canvas.lineTo(76.5, 34.93);
      canvas.lineTo(73.7, 22.26);
      canvas.lineTo(62.64, 23.44);
      canvas.lineTo(58.81, 18.42);
      canvas.lineTo(62.79, 8.7);
      canvas.lineTo(51.74, 2.21);
      canvas.lineTo(44.81, 10.47);
      canvas.lineTo(38.03, 9.43);
      canvas.lineTo(33.75, 0);
      canvas.lineTo(21.52, 3.24);
      canvas.lineTo(22.7, 13.56);
      canvas.lineTo(18.13, 17.54);
      canvas.lineTo(8.7, 13.56);
      canvas.close();
      const arcStartX = 24.8;
      const arcStartY = 39;
      paintGearInnerCircle(canvas, arcStartX, arcStartY);
  }
  function paintGearIconForeground(canvas) {
      canvas.begin();
      canvas.moveTo(16.46, 41.42);
      canvas.lineTo(24.57, 47.75);
      canvas.lineTo(23.69, 54.53);
      canvas.lineTo(14.4, 58.22);
      canvas.lineTo(17.35, 71.04);
      canvas.lineTo(27.81, 69.72);
      canvas.lineTo(31.79, 75.32);
      canvas.lineTo(27.96, 84.46);
      canvas.lineTo(38.87, 91.24);
      canvas.lineTo(45.21, 83.13);
      canvas.lineTo(52.28, 84.01);
      canvas.lineTo(55.97, 93.3);
      canvas.lineTo(68.64, 90.35);
      canvas.lineTo(67.46, 79.74);
      canvas.lineTo(72.92, 75.32);
      canvas.lineTo(81.61, 79.89);
      canvas.lineTo(88.98, 68.68);
      canvas.lineTo(80.43, 62.05);
      canvas.lineTo(81.32, 55.42);
      canvas.lineTo(90.9, 51.73);
      canvas.lineTo(88.1, 39.06);
      canvas.lineTo(77.04, 40.24);
      canvas.lineTo(73.21, 35.22);
      canvas.lineTo(77.19, 25.5);
      canvas.lineTo(66.14, 19.01);
      canvas.lineTo(59.21, 27.27);
      canvas.lineTo(52.43, 26.23);
      canvas.lineTo(48.15, 16.8);
      canvas.lineTo(35.92, 20.04);
      canvas.lineTo(37.1, 30.36);
      canvas.lineTo(32.53, 34.34);
      canvas.lineTo(23.1, 30.36);
      canvas.close();
      const arcStartX = 39.2;
      const arcStartY = 55.8;
      paintGearInnerCircle(canvas, arcStartX, arcStartY);
      canvas.begin();
      paintGearInnerCircle(canvas, arcStartX, arcStartY);
  }
  function paintGearInnerCircle(canvas, arcStartX, arcStartY) {
      const arcRay = 13.5;
      canvas.moveTo(arcStartX, arcStartY);
      canvas.arcTo(arcRay, arcRay, 0, 1, 1, arcStartX + 2 * arcRay, arcStartY);
      canvas.arcTo(arcRay, arcRay, 0, 0, 1, arcStartX, arcStartY);
      canvas.close();
      canvas.fillAndStroke();
  }
  class IconPainterProvider {
      static get() {
          return this.instance;
      }
      static set(painter) {
          this.instance = painter;
      }
  }
  Object.defineProperty(IconPainterProvider, "instance", {
      enumerable: true,
      configurable: true,
      writable: true,
      value: new IconPainter()
  });

  const zoomFactorIn = 1.25;
  const zoomFactorOut = 1 / zoomFactorIn;
  class BpmnGraph extends mxgraph.mxGraph {
      constructor(container) {
          super(container);
          Object.defineProperty(this, "currentZoomLevel", {
              enumerable: true,
              configurable: true,
              writable: true,
              value: 1
          });
          this.zoomFactor = zoomFactorIn;
          if (this.container) {
              this.container.style.cursor = 'default';
          }
      }
      createGraphView() {
          return new BpmnGraphView(this);
      }
      createCellRenderer() {
          return new BpmnCellRenderer(IconPainterProvider.get());
      }
      batchUpdate(callbackFunction) {
          this.model.beginUpdate();
          try {
              callbackFunction();
          }
          finally {
              this.model.endUpdate();
          }
      }
      fit(border, keepOrigin, margin, enabled, ignoreWidth, ignoreHeight, maxHeight) {
          const scale = super.fit(border, keepOrigin, margin, enabled, ignoreWidth, ignoreHeight, maxHeight);
          this.setCurrentZoomLevel(scale);
          return scale;
      }
      setCurrentZoomLevel(scale) {
          this.currentZoomLevel = scale !== null && scale !== void 0 ? scale : this.view.scale;
      }
      zoomActual() {
          super.zoomActual();
          this.setCurrentZoomLevel();
      }
      zoomIn() {
          super.zoomIn();
          this.setCurrentZoomLevel();
      }
      zoomOut() {
          super.zoomOut();
          this.setCurrentZoomLevel();
      }
      customFit(fitOptions) {
          this.zoomActual();
          const type = fitOptions === null || fitOptions === void 0 ? void 0 : fitOptions.type;
          if (type == undefined || type == exports.FitType.None) {
              return;
          }
          const margin = ensurePositiveValue(fitOptions === null || fitOptions === void 0 ? void 0 : fitOptions.margin);
          if (type == exports.FitType.Center) {
              const maxScale = 3;
              const bounds = this.getGraphBounds();
              const clientWidth = this.container.clientWidth - margin;
              const clientHeight = this.container.clientHeight - margin;
              const width = bounds.width / this.view.scale;
              const height = bounds.height / this.view.scale;
              const scale = Math.min(maxScale, Math.min(clientWidth / width, clientHeight / height));
              this.setCurrentZoomLevel(scale);
              this.view.scaleAndTranslate(scale, (margin + clientWidth - width * scale) / (2 * scale) - bounds.x / this.view.scale, (margin + clientHeight - height * scale) / (2 * scale) - bounds.y / this.view.scale);
          }
          else {
              let ignoreWidth = false;
              let ignoreHeight = false;
              switch (type) {
                  case exports.FitType.Horizontal: {
                      ignoreHeight = true;
                      break;
                  }
                  case exports.FitType.Vertical: {
                      ignoreWidth = true;
                      break;
                  }
              }
              this.fit(this.border, false, margin, true, ignoreWidth, ignoreHeight);
          }
      }
      registerMouseWheelZoomListeners(config) {
          config = ensureValidZoomConfiguration(config);
          mxEvent.addMouseWheelListener(debounce(this.createMouseWheelZoomListener(true), config.debounceDelay), this.container);
          mxEvent.addMouseWheelListener(throttle(this.createMouseWheelZoomListener(false), config.throttleDelay), this.container);
      }
      manageMouseWheelZoomEvent(up, event, performScaling) {
          if (performScaling) {
              const [offsetX, offsetY] = this.getEventRelativeCoordinates(event);
              const [newScale, dx, dy] = this.getScaleAndTranslationDeltas(offsetX, offsetY);
              this.view.scaleAndTranslate(newScale, this.view.translate.x + dx, this.view.translate.y + dy);
              mxEvent.consume(event);
          }
          else {
              this.currentZoomLevel *= up ? zoomFactorIn : zoomFactorOut;
          }
      }
      createMouseWheelZoomListener(performScaling) {
          return (event, up) => {
              if (mxEvent.isConsumed(event) || !(event instanceof MouseEvent)) {
                  return;
              }
              const isZoomWheelEvent = event.ctrlKey && !event.altKey && !event.shiftKey && !event.metaKey;
              if (isZoomWheelEvent) {
                  this.manageMouseWheelZoomEvent(up, event, performScaling);
              }
          };
      }
      getEventRelativeCoordinates(event) {
          const rect = this.container.getBoundingClientRect();
          const x = event.clientX - rect.left;
          const y = event.clientY - rect.top;
          return [x, y];
      }
      getScaleAndTranslationDeltas(offsetX, offsetY) {
          const [factor, scale] = this.calculateFactorAndScale();
          const [dx, dy] = this.calculateTranslationDeltas(factor, scale, offsetX * 2, offsetY * 2);
          return [scale, dx, dy];
      }
      calculateTranslationDeltas(factor, scale, dx, dy) {
          if (factor > 1) {
              const f = (factor - 1) / (scale * 2);
              dx *= -f;
              dy *= -f;
          }
          else {
              const f = (1 / factor - 1) / (this.view.scale * 2);
              dx *= f;
              dy *= f;
          }
          return [dx, dy];
      }
      calculateFactorAndScale() {
          const scale = Math.round(this.currentZoomLevel * 100) / 100;
          const factor = scale / this.view.scale;
          return [factor, scale];
      }
  }
  class BpmnGraphView extends mxgraph.mxGraphView {
      getFloatingTerminalPoint(edge, start, end, source) {
          const edgePoints = edge.absolutePoints.filter(Boolean);
          const needsFloatingTerminalPoint = edgePoints.length < 2;
          if (needsFloatingTerminalPoint) {
              return super.getFloatingTerminalPoint(edge, start, end, source);
          }
          const pts = edge.absolutePoints;
          return source ? pts[1] : pts.at(-2);
      }
  }

  class MarkerConfigurator {
      configureMarkers() {
          this.registerArrowDashMarker();
      }
      registerArrowDashMarker() {
          const createMarker = (c, _shape, _type, pe, unitX, unitY, size, _source, strokewidth) => {
              const nx = unitX * (size + strokewidth + 4);
              const ny = unitY * (size + strokewidth + 4);
              return function () {
                  c.begin();
                  c.moveTo(pe.x - nx / 2 - ny / 2, pe.y - ny / 2 + nx / 2);
                  c.lineTo(pe.x + ny / 2 - (3 * nx) / 2, pe.y - (3 * ny) / 2 - nx / 2);
                  c.stroke();
              };
          };
          mxgraph.mxMarker.addMarker(MarkerIdentifier.ARROW_DASH, createMarker);
      }
  }

  const referenceOrderedMarkers = [
      exports.ShapeBpmnMarkerKind.LOOP,
      exports.ShapeBpmnMarkerKind.MULTI_INSTANCE_PARALLEL,
      exports.ShapeBpmnMarkerKind.MULTI_INSTANCE_SEQUENTIAL,
      exports.ShapeBpmnMarkerKind.COMPENSATION,
      exports.ShapeBpmnMarkerKind.EXPAND,
      exports.ShapeBpmnMarkerKind.ADHOC,
  ];
  function orderActivityMarkers(markers) {
      const orderedMarkers = referenceOrderedMarkers.filter(marker => markers.includes(marker));
      for (const marker of markers.filter(marker => !orderedMarkers.includes(marker)))
          orderedMarkers.push(marker);
      return orderedMarkers;
  }

  function getMarkerIconOriginFunction(numberOfMarkers, markerPosition) {
      return numberOfMarkers === 1
          ? (canvas) => canvas.setIconOriginForIconBottomCentered()
          : (canvas) => {
              canvas.setIconOriginForIconBottomCentered();
              const xTranslation = (Math.pow(-1, markerPosition) * (StyleDefault.SHAPE_ACTIVITY_MARKER_ICON_SIZE + StyleDefault.SHAPE_ACTIVITY_MARKER_ICON_MARGIN)) / 2;
              canvas.translateIconOrigin(xTranslation, 0);
          };
  }
  class BaseActivityShape extends mxRectangleShape {
      constructor() {
          super(undefined, undefined, undefined);
          Object.defineProperty(this, "iconPainter", {
              enumerable: true,
              configurable: true,
              writable: true,
              value: undefined
          });
          Object.defineProperty(this, "markerPainterFunctions", {
              enumerable: true,
              configurable: true,
              writable: true,
              value: new Map([
                  [exports.ShapeBpmnMarkerKind.EXPAND, (paintParameter) => this.iconPainter.paintExpandIcon(paintParameter)],
                  [exports.ShapeBpmnMarkerKind.LOOP, (paintParameter) => this.iconPainter.paintLoopIcon(paintParameter)],
                  [exports.ShapeBpmnMarkerKind.MULTI_INSTANCE_PARALLEL, (paintParameter) => this.iconPainter.paintParallelMultiInstanceIcon(paintParameter)],
                  [exports.ShapeBpmnMarkerKind.MULTI_INSTANCE_SEQUENTIAL, (paintParameter) => this.iconPainter.paintSequentialMultiInstanceIcon(paintParameter)],
              ])
          });
      }
      paintForeground(c, x, y, w, h) {
          super.paintForeground(c, x, y, w, h);
          this.paintMarkerIcons(buildPaintParameter({ canvas: c, x, y, width: w, height: h, shape: this, ratioFromParent: 0, iconStrokeWidth: 1.5 }));
      }
      paintMarkerIcons(paintParameter) {
          var _a;
          const markers = mxUtils.getValue(this.style, BpmnStyleIdentifier.MARKERS, undefined);
          if (markers) {
              const orderedMarkers = orderActivityMarkers(markers.split(','));
              for (const [index, marker] of orderedMarkers.entries()) {
                  paintParameter = Object.assign(Object.assign({}, paintParameter), { setIconOriginFunct: getMarkerIconOriginFunction(orderedMarkers.length, index + 1) });
                  paintParameter.canvas.save();
                  (_a = this.markerPainterFunctions.get(marker)) === null || _a === void 0 ? void 0 : _a(paintParameter);
                  paintParameter.canvas.restore();
              }
          }
      }
      paintEnvelopeIcon(paintParameter, isFilled) {
          this.iconPainter.paintEnvelopeIcon(Object.assign(Object.assign({}, paintParameter), { setIconOriginFunct: (canvas) => canvas.setIconOriginToShapeTopLeft(), ratioFromParent: 0.2, iconStyleConfig: Object.assign(Object.assign({}, paintParameter.iconStyleConfig), { isFilled: isFilled }) }));
      }
  }
  class BaseTaskShape extends BaseActivityShape {
      paintForeground(c, x, y, w, h) {
          super.paintForeground(c, x, y, w, h);
          this.paintTaskIcon(buildPaintParameter({ canvas: c, x, y, width: w, height: h, shape: this }));
      }
  }
  class TaskShape extends BaseTaskShape {
      paintTaskIcon(_paintParameter) {
      }
  }
  class ServiceTaskShape extends BaseTaskShape {
      paintTaskIcon(paintParameter) {
          this.iconPainter.paintGearIcon(Object.assign(Object.assign({}, paintParameter), { setIconOriginFunct: (canvas) => canvas.setIconOriginToShapeTopLeftProportionally(20) }));
      }
  }
  class UserTaskShape extends BaseTaskShape {
      paintTaskIcon(paintParameter) {
          this.iconPainter.paintPersonIcon(Object.assign(Object.assign({}, paintParameter), { setIconOriginFunct: (canvas) => canvas.setIconOriginToShapeTopLeftProportionally(20) }));
      }
  }
  class ReceiveTaskShape extends BaseTaskShape {
      paintTaskIcon(paintParameter) {
          if (!getBpmnIsInstantiating(this.style)) {
              this.paintEnvelopeIcon(paintParameter, false);
              return;
          }
          const leftMargin = 4;
          const topMargin = 4;
          const circleShapeConfig = Object.assign(Object.assign({}, paintParameter.shapeConfig), { width: 20, height: 20 });
          this.iconPainter.paintCircleIcon({
              canvas: paintParameter.canvas,
              shapeConfig: circleShapeConfig,
              iconStyleConfig: Object.assign(Object.assign({}, paintParameter.iconStyleConfig), { isFilled: false }),
              ratioFromParent: undefined,
              setIconOriginFunct: (canvas) => canvas.setIconOriginToShapeTopLeft(topMargin, leftMargin),
          });
          circleShapeConfig.x += leftMargin;
          circleShapeConfig.y += topMargin;
          this.iconPainter.paintEnvelopeIcon(Object.assign(Object.assign({}, paintParameter), { shapeConfig: circleShapeConfig, ratioFromParent: 0.65, setIconOriginFunct: (canvas) => canvas.setIconOriginForIconCentered() }));
      }
  }
  class SendTaskShape extends BaseTaskShape {
      paintTaskIcon(paintParameter) {
          this.paintEnvelopeIcon(paintParameter, true);
      }
  }
  class ManualTaskShape extends BaseTaskShape {
      paintTaskIcon(paintParameter) {
          this.iconPainter.paintHandIcon(Object.assign(Object.assign({}, paintParameter), { ratioFromParent: 0.18, setIconOriginFunct: (canvas) => canvas.setIconOriginToShapeTopLeftProportionally(20) }));
      }
  }
  class ScriptTaskShape extends BaseTaskShape {
      paintTaskIcon(paintParameter) {
          this.iconPainter.paintScriptIcon(Object.assign(Object.assign({}, paintParameter), { ratioFromParent: 0.22, setIconOriginFunct: (canvas) => canvas.setIconOriginToShapeTopLeftProportionally(20) }));
      }
  }
  class CallActivityShape extends BaseActivityShape {
      paintForeground(c, x, y, w, h) {
          super.paintForeground(c, x, y, w, h);
          const paintParameter = buildPaintParameter({ canvas: c, x, y, width: w, height: h, shape: this });
          switch (mxUtils.getValue(this.style, BpmnStyleIdentifier.GLOBAL_TASK_KIND, undefined)) {
              case exports.ShapeBpmnElementKind.GLOBAL_TASK_MANUAL: {
                  this.iconPainter.paintHandIcon(Object.assign(Object.assign({}, paintParameter), { ratioFromParent: 0.18, setIconOriginFunct: (canvas) => canvas.setIconOriginToShapeTopLeftProportionally(20) }));
                  break;
              }
              case exports.ShapeBpmnElementKind.GLOBAL_TASK_SCRIPT: {
                  this.iconPainter.paintScriptIcon(Object.assign(Object.assign({}, paintParameter), { ratioFromParent: 0.22, setIconOriginFunct: (canvas) => canvas.setIconOriginToShapeTopLeftProportionally(20) }));
                  break;
              }
              case exports.ShapeBpmnElementKind.GLOBAL_TASK_USER: {
                  this.iconPainter.paintPersonIcon(Object.assign(Object.assign({}, paintParameter), { setIconOriginFunct: (canvas) => canvas.setIconOriginToShapeTopLeftProportionally(20) }));
                  break;
              }
              case exports.ShapeBpmnElementKind.GLOBAL_TASK_BUSINESS_RULE: {
                  this.iconPainter.paintTableIcon(Object.assign(Object.assign({}, paintParameter), { ratioFromParent: 0.6, setIconOriginFunct: (canvas) => canvas.setIconOriginToShapeTopLeftProportionally(15) }));
                  break;
              }
          }
      }
  }
  class SubProcessShape extends BaseActivityShape {
      paintBackground(c, x, y, w, h) {
          const subProcessKind = mxUtils.getValue(this.style, BpmnStyleIdentifier.SUB_PROCESS_KIND, undefined);
          c.save();
          if (subProcessKind === exports.ShapeBpmnSubProcessKind.EVENT) {
              c.setDashed(true, false);
              c.setDashPattern('1 2');
          }
          super.paintBackground(c, x, y, w, h);
          if (subProcessKind === exports.ShapeBpmnSubProcessKind.TRANSACTION) {
              const innerOffset = StyleDefault.SUB_PROCESS_TRANSACTION_INNER_RECT_OFFSET;
              const innerArcSize = StyleDefault.SUB_PROCESS_TRANSACTION_INNER_RECT_ARC_SIZE;
              c.roundrect(x + innerOffset, y + innerOffset, w - 2 * innerOffset, h - 2 * innerOffset, innerArcSize, innerArcSize);
              c.stroke();
          }
          c.restore();
      }
  }
  class BusinessRuleTaskShape extends BaseTaskShape {
      paintTaskIcon(paintParameter) {
          this.iconPainter.paintTableIcon(Object.assign(Object.assign({}, paintParameter), { ratioFromParent: 0.6, setIconOriginFunct: (canvas) => canvas.setIconOriginToShapeTopLeftProportionally(15) }));
      }
  }

  class BpmnConnector extends mxgraph.mxConnector {
      paintEdgeShape(c, pts) {
          const sourceMarker = this.createMarker(c, pts, true);
          const targetMarker = this.createMarker(c, pts, false);
          this.paintEdgeLine(c, pts);
          c.setShadow(false);
          c.setDashed(false, false);
          if (sourceMarker != null) {
              c.setFillColor(mxUtils.getValue(this.style, BpmnStyleIdentifier.EDGE_START_FILL_COLOR, this.stroke));
              sourceMarker();
          }
          if (targetMarker != null) {
              c.setFillColor(mxUtils.getValue(this.style, BpmnStyleIdentifier.EDGE_END_FILL_COLOR, this.stroke));
              targetMarker();
          }
      }
      paintEdgeLine(c, pts) {
          const previous = getPointerEventsValue(c);
          setPointerEventsValue(c, 'stroke');
          this.paintLine(c, pts, this.isRounded);
          setPointerEventsValue(c, previous);
      }
  }
  function getPointerEventsValue(c) {
      return c instanceof mxSvgCanvas2D ? c.pointerEventsValue : null;
  }
  function setPointerEventsValue(c, value) {
      if (c instanceof mxSvgCanvas2D) {
          c.pointerEventsValue = value;
      }
  }

  class EventShape extends mxgraph.mxEllipse {
      constructor() {
          super(undefined, undefined, undefined);
          Object.defineProperty(this, "iconPainter", {
              enumerable: true,
              configurable: true,
              writable: true,
              value: undefined
          });
          Object.defineProperty(this, "iconPainters", {
              enumerable: true,
              configurable: true,
              writable: true,
              value: new Map([
                  [exports.ShapeBpmnEventDefinitionKind.MESSAGE, (paintParameter) => this.iconPainter.paintEnvelopeIcon(Object.assign(Object.assign({}, paintParameter), { ratioFromParent: 0.5 }))],
                  [exports.ShapeBpmnEventDefinitionKind.TERMINATE, (paintParameter) => this.iconPainter.paintCircleIcon(Object.assign(Object.assign({}, paintParameter), { ratioFromParent: 0.6 }))],
                  [
                      exports.ShapeBpmnEventDefinitionKind.TIMER,
                      (paintParameter) => this.iconPainter.paintClockIcon(Object.assign(Object.assign({}, paintParameter), { setIconOriginFunct: (canvas) => canvas.setIconOriginToShapeTopLeftProportionally(5) })),
                  ],
                  [
                      exports.ShapeBpmnEventDefinitionKind.SIGNAL,
                      (paintParameter) => this.iconPainter.paintTriangleIcon(Object.assign(Object.assign({}, paintParameter), { ratioFromParent: 0.55, iconStyleConfig: Object.assign(Object.assign({}, paintParameter.iconStyleConfig), { strokeWidth: StyleDefault.STROKE_WIDTH_THIN.valueOf() }), setIconOriginFunct: (canvas) => canvas.setIconOriginToShapeTopLeftProportionally(4) })),
                  ],
                  [
                      exports.ShapeBpmnEventDefinitionKind.LINK,
                      (paintParameter) => this.iconPainter.paintRightArrowIcon(Object.assign(Object.assign({}, paintParameter), { ratioFromParent: 0.55, iconStyleConfig: Object.assign(Object.assign({}, paintParameter.iconStyleConfig), { strokeWidth: 1.5 }) })),
                  ],
                  [
                      exports.ShapeBpmnEventDefinitionKind.ERROR,
                      (paintParameter) => this.iconPainter.paintErrorIcon(Object.assign(Object.assign({}, paintParameter), { ratioFromParent: 0.55, iconStyleConfig: Object.assign(Object.assign({}, paintParameter.iconStyleConfig), { strokeWidth: 1.5 }) })),
                  ],
                  [
                      exports.ShapeBpmnEventDefinitionKind.COMPENSATION,
                      (paintParameter) => this.iconPainter.paintDoubleLeftArrowheadsIcon(Object.assign(Object.assign({}, paintParameter), { ratioFromParent: 0.7, iconStyleConfig: Object.assign(Object.assign({}, paintParameter.iconStyleConfig), { strokeWidth: 1.5 }) })),
                  ],
                  [exports.ShapeBpmnEventDefinitionKind.CANCEL, (paintParameter) => this.iconPainter.paintXCrossIcon(Object.assign(Object.assign({}, paintParameter), { ratioFromParent: 0.78 }))],
                  [
                      exports.ShapeBpmnEventDefinitionKind.ESCALATION,
                      (paintParameter) => this.iconPainter.paintUpArrowheadIcon(Object.assign(Object.assign({}, paintParameter), { ratioFromParent: 0.55, iconStyleConfig: Object.assign(Object.assign({}, paintParameter.iconStyleConfig), { strokeWidth: StyleDefault.STROKE_WIDTH_THIN.valueOf() }) })),
                  ],
                  [
                      exports.ShapeBpmnEventDefinitionKind.CONDITIONAL,
                      (paintParameter) => this.iconPainter.paintListIcon(Object.assign(Object.assign({}, paintParameter), { ratioFromParent: 0.6, iconStyleConfig: Object.assign(Object.assign({}, paintParameter.iconStyleConfig), { strokeWidth: 1.5 }) })),
                  ],
              ])
          });
          Object.defineProperty(this, "withFilledIcon", {
              enumerable: true,
              configurable: true,
              writable: true,
              value: false
          });
      }
      paintVertexShape(c, x, y, w, h) {
          const paintParameter = buildPaintParameter({ canvas: c, x, y, width: w, height: h, shape: this, isFilled: this.withFilledIcon });
          setDashedOuterShapePattern(paintParameter, mxUtils.getValue(this.style, BpmnStyleIdentifier.IS_INTERRUPTING, undefined));
          this.paintOuterShape(paintParameter);
          restoreOriginalOuterShapePattern(paintParameter);
          this.paintInnerShape(paintParameter);
      }
      paintOuterShape({ canvas, shapeConfig: { x, y, width, height } }) {
          super.paintVertexShape(canvas, x, y, width, height);
      }
      paintInnerShape(paintParameter) {
          const paintIcon = this.iconPainters.get(mxUtils.getValue(this.style, BpmnStyleIdentifier.EVENT_DEFINITION_KIND, exports.ShapeBpmnEventDefinitionKind.NONE));
          paintIcon === null || paintIcon === void 0 ? void 0 : paintIcon(paintParameter);
      }
  }
  function setDashedOuterShapePattern(paintParameter, isInterrupting) {
      paintParameter.canvas.save();
      if (isInterrupting === 'false') {
          paintParameter.canvas.setDashed(true, false);
          paintParameter.canvas.setDashPattern('3 2');
      }
  }
  function restoreOriginalOuterShapePattern(paintParameter) {
      paintParameter.canvas.restore();
  }
  class EndEventShape extends EventShape {
      constructor() {
          super();
          this.withFilledIcon = true;
      }
  }
  class IntermediateEventShape extends EventShape {
      paintOuterShape({ canvas, shapeConfig: { x, y, width, height, strokeWidth } }) {
          canvas.ellipse(x, y, width, height);
          canvas.fillAndStroke();
          const inset = strokeWidth * 1.5;
          canvas.ellipse(width * 0.02 + inset + x, height * 0.02 + inset + y, width * 0.96 - 2 * inset, height * 0.96 - 2 * inset);
          canvas.stroke();
      }
  }
  class ThrowIntermediateEventShape extends IntermediateEventShape {
      constructor() {
          super();
          this.withFilledIcon = true;
      }
  }

  class MessageFlowIconShape extends mxRectangleShape {
      constructor() {
          super(...arguments);
          Object.defineProperty(this, "iconPainter", {
              enumerable: true,
              configurable: true,
              writable: true,
              value: undefined
          });
      }
      paintVertexShape(c, x, y, w, h) {
          const paintParameter = buildPaintParameter({
              canvas: c,
              x,
              y,
              width: w,
              height: h,
              shape: this,
              ratioFromParent: 1,
              isFilled: mxUtils.getValue(this.style, BpmnStyleIdentifier.IS_INITIATING, 'true') == 'false',
          });
          this.iconPainter.paintEnvelopeIcon(paintParameter);
      }
  }

  class GatewayShape extends mxgraph.mxRhombus {
      constructor() {
          super(...arguments);
          Object.defineProperty(this, "iconPainter", {
              enumerable: true,
              configurable: true,
              writable: true,
              value: undefined
          });
      }
      paintVertexShape(c, x, y, w, h) {
          const paintParameter = buildPaintParameter({ canvas: c, x, y, width: w, height: h, shape: this });
          this.paintOuterShape(paintParameter);
          this.paintInnerShape(paintParameter);
      }
      paintOuterShape({ canvas, shapeConfig: { x, y, width, height } }) {
          super.paintVertexShape(canvas, x, y, width, height);
      }
  }
  class ExclusiveGatewayShape extends GatewayShape {
      paintInnerShape(paintParameter) {
          this.iconPainter.paintXCrossIcon(Object.assign(Object.assign({}, paintParameter), { iconStyleConfig: Object.assign(Object.assign({}, paintParameter.iconStyleConfig), { isFilled: true }), ratioFromParent: 0.5 }));
      }
  }
  class ParallelGatewayShape extends GatewayShape {
      paintInnerShape(paintParameter) {
          this.iconPainter.paintPlusCrossIcon(Object.assign(Object.assign({}, paintParameter), { iconStyleConfig: Object.assign(Object.assign({}, paintParameter.iconStyleConfig), { isFilled: true }), ratioFromParent: 0.5 }));
      }
  }
  class InclusiveGatewayShape extends GatewayShape {
      paintInnerShape(paintParameter) {
          this.iconPainter.paintCircleIcon(Object.assign(Object.assign({}, paintParameter), { ratioFromParent: 0.62, iconStyleConfig: Object.assign(Object.assign({}, paintParameter.iconStyleConfig), { isFilled: false, strokeWidth: StyleDefault.STROKE_WIDTH_THICK.valueOf() }) }));
      }
  }
  class ComplexGatewayShape extends GatewayShape {
      paintInnerShape(paintParameter) {
          this.iconPainter.paintAsteriskIcon(Object.assign(Object.assign({}, paintParameter), { iconStyleConfig: Object.assign(Object.assign({}, paintParameter.iconStyleConfig), { isFilled: true }), ratioFromParent: 0.5 }));
      }
  }
  class EventBasedGatewayShape extends GatewayShape {
      paintInnerShape(paintParameter) {
          paintParameter = Object.assign(Object.assign({}, paintParameter), { iconStyleConfig: Object.assign(Object.assign({}, paintParameter.iconStyleConfig), { strokeWidth: 1 }) });
          this.iconPainter.paintCircleIcon(Object.assign(Object.assign({}, paintParameter), { ratioFromParent: 0.55 }));
          if (!getBpmnIsInstantiating(this.style)) {
              this.iconPainter.paintCircleIcon(Object.assign(Object.assign({}, paintParameter), { ratioFromParent: 0.45 }));
          }
          const innerIconPaintParameter = Object.assign(Object.assign({}, paintParameter), { ratioFromParent: 0.3 });
          if (mxUtils.getValue(this.style, BpmnStyleIdentifier.EVENT_BASED_GATEWAY_KIND, exports.ShapeBpmnEventBasedGatewayKind.Exclusive) == exports.ShapeBpmnEventBasedGatewayKind.Parallel) {
              this.iconPainter.paintPlusCrossIcon(innerIconPaintParameter);
          }
          else {
              this.iconPainter.paintPentagon(innerIconPaintParameter);
          }
      }
  }

  class TextAnnotationShape extends mxRectangleShape {
      paintForeground(c, x, y, _w, h) {
          c.begin();
          c.moveTo(x + StyleDefault.TEXT_ANNOTATION_BORDER_LENGTH, y);
          c.lineTo(x, y);
          c.lineTo(x, y + h);
          c.lineTo(x + StyleDefault.TEXT_ANNOTATION_BORDER_LENGTH, y + h);
          c.stroke();
      }
      paintBackground(c, x, y, w, h) {
          c.save();
          c.setStrokeColor('none');
          super.paintBackground(c, x, y, w, h);
          c.restore();
      }
  }

  const registerShapes = () => {
      const shapesToRegister = [
          [exports.ShapeBpmnElementKind.EVENT_END, EndEventShape],
          [exports.ShapeBpmnElementKind.EVENT_START, EventShape],
          [exports.ShapeBpmnElementKind.EVENT_INTERMEDIATE_THROW, ThrowIntermediateEventShape],
          [exports.ShapeBpmnElementKind.EVENT_INTERMEDIATE_CATCH, IntermediateEventShape],
          [exports.ShapeBpmnElementKind.EVENT_BOUNDARY, IntermediateEventShape],
          [exports.ShapeBpmnElementKind.GATEWAY_COMPLEX, ComplexGatewayShape],
          [exports.ShapeBpmnElementKind.GATEWAY_EVENT_BASED, EventBasedGatewayShape],
          [exports.ShapeBpmnElementKind.GATEWAY_EXCLUSIVE, ExclusiveGatewayShape],
          [exports.ShapeBpmnElementKind.GATEWAY_INCLUSIVE, InclusiveGatewayShape],
          [exports.ShapeBpmnElementKind.GATEWAY_PARALLEL, ParallelGatewayShape],
          [exports.ShapeBpmnElementKind.SUB_PROCESS, SubProcessShape],
          [exports.ShapeBpmnElementKind.CALL_ACTIVITY, CallActivityShape],
          [exports.ShapeBpmnElementKind.TASK, TaskShape],
          [exports.ShapeBpmnElementKind.TASK_SERVICE, ServiceTaskShape],
          [exports.ShapeBpmnElementKind.TASK_USER, UserTaskShape],
          [exports.ShapeBpmnElementKind.TASK_RECEIVE, ReceiveTaskShape],
          [exports.ShapeBpmnElementKind.TASK_SEND, SendTaskShape],
          [exports.ShapeBpmnElementKind.TASK_MANUAL, ManualTaskShape],
          [exports.ShapeBpmnElementKind.TASK_SCRIPT, ScriptTaskShape],
          [exports.ShapeBpmnElementKind.TASK_BUSINESS_RULE, BusinessRuleTaskShape],
          [exports.ShapeBpmnElementKind.TEXT_ANNOTATION, TextAnnotationShape],
          [BpmnStyleIdentifier.EDGE, BpmnConnector],
          [BpmnStyleIdentifier.MESSAGE_FLOW_ICON, MessageFlowIconShape],
      ];
      for (const [shapeName, shapeClass] of shapesToRegister) {
          mxCellRenderer.registerShape(shapeName, shapeClass);
      }
  };
  class ShapeConfigurator {
      configureShapes() {
          registerShapes();
      }
  }

  const arrowDefaultSize = 12;
  class MapWithDefault extends Map {
      get(key) {
          var _a;
          return ((_a = super.get(key)) !== null && _a !== void 0 ? _a : (() => {
          }));
      }
  }
  const specificFlowStyles = new MapWithDefault([
      [
          exports.FlowKind.SEQUENCE_FLOW,
          (style) => {
              style[mxConstants.STYLE_ENDARROW] = mxConstants.ARROW_BLOCK_THIN;
          },
      ],
      [
          exports.FlowKind.MESSAGE_FLOW,
          (style) => {
              style[mxConstants.STYLE_DASHED] = true;
              style[mxConstants.STYLE_DASH_PATTERN] = '8 5';
              style[mxConstants.STYLE_STARTARROW] = mxConstants.ARROW_OVAL;
              style[mxConstants.STYLE_STARTSIZE] = 8;
              style[mxConstants.STYLE_STARTFILL] = true;
              style[BpmnStyleIdentifier.EDGE_START_FILL_COLOR] = StyleDefault.MESSAGE_FLOW_MARKER_START_FILL_COLOR;
              style[mxConstants.STYLE_ENDARROW] = mxConstants.ARROW_BLOCK_THIN;
              style[mxConstants.STYLE_ENDFILL] = true;
              style[BpmnStyleIdentifier.EDGE_END_FILL_COLOR] = StyleDefault.MESSAGE_FLOW_MARKER_END_FILL_COLOR;
          },
      ],
      [
          exports.FlowKind.ASSOCIATION_FLOW,
          (style) => {
              style[mxConstants.STYLE_DASHED] = true;
              style[mxConstants.STYLE_DASH_PATTERN] = '1 2';
              style[mxConstants.STYLE_STARTSIZE] = arrowDefaultSize;
          },
      ],
  ]);
  const specificSequenceFlowStyles = new MapWithDefault([
      [
          exports.SequenceFlowKind.DEFAULT,
          (style) => {
              style[mxConstants.STYLE_STARTARROW] = MarkerIdentifier.ARROW_DASH;
          },
      ],
      [
          exports.SequenceFlowKind.CONDITIONAL_FROM_ACTIVITY,
          (style) => {
              style[mxConstants.STYLE_STARTARROW] = mxConstants.ARROW_DIAMOND_THIN;
              style[mxConstants.STYLE_STARTSIZE] = 18;
              style[mxConstants.STYLE_STARTFILL] = true;
              style[BpmnStyleIdentifier.EDGE_START_FILL_COLOR] = StyleDefault.SEQUENCE_FLOW_CONDITIONAL_FROM_ACTIVITY_MARKER_FILL_COLOR;
          },
      ],
  ]);
  const specificAssociationFlowStyles = new MapWithDefault([
      [
          exports.AssociationDirectionKind.NONE,
          (_style) => {
          },
      ],
      [
          exports.AssociationDirectionKind.ONE,
          (style) => {
              style[mxConstants.STYLE_ENDARROW] = mxConstants.ARROW_OPEN_THIN;
          },
      ],
      [
          exports.AssociationDirectionKind.BOTH,
          (style) => {
              style[mxConstants.STYLE_STARTARROW] = mxConstants.ARROW_OPEN_THIN;
              style[mxConstants.STYLE_ENDARROW] = mxConstants.ARROW_OPEN_THIN;
          },
      ],
  ]);
  class StyleConfigurator {
      constructor(graph) {
          Object.defineProperty(this, "graph", {
              enumerable: true,
              configurable: true,
              writable: true,
              value: graph
          });
      }
      configureStyles() {
          this.configureDefaultVertexStyle();
          this.configurePoolStyle();
          this.configureLaneStyle();
          this.configureTextAnnotationStyle();
          this.configureGroupStyle();
          this.configureActivityStyles();
          this.configureEventStyles();
          this.configureGatewayStyles();
          this.configureDefaultEdgeStyle();
          this.configureFlowStyles();
      }
      getStylesheet() {
          return this.graph.getStylesheet();
      }
      putCellStyle(name, style) {
          this.getStylesheet().putCellStyle(name, style);
      }
      configureDefaultVertexStyle() {
          const style = this.getStylesheet().getDefaultVertexStyle();
          configureCommonDefaultStyle(style);
          style[mxConstants.STYLE_ABSOLUTE_ARCSIZE] = true;
          style[mxConstants.STYLE_ARCSIZE] = StyleDefault.SHAPE_ARC_SIZE;
      }
      configurePoolStyle() {
          const style = {};
          style[mxConstants.STYLE_SHAPE] = mxConstants.SHAPE_SWIMLANE;
          style[mxConstants.STYLE_VERTICAL_ALIGN] = mxConstants.ALIGN_MIDDLE;
          style[mxConstants.STYLE_ALIGN] = mxConstants.ALIGN_CENTER;
          style[mxConstants.STYLE_STARTSIZE] = StyleDefault.POOL_LABEL_SIZE;
          style[mxConstants.STYLE_FILLCOLOR] = StyleDefault.POOL_LABEL_FILL_COLOR;
          this.graph.getStylesheet().putCellStyle(exports.ShapeBpmnElementKind.POOL, style);
      }
      configureLaneStyle() {
          const style = {};
          style[mxConstants.STYLE_SHAPE] = mxConstants.SHAPE_SWIMLANE;
          style[mxConstants.STYLE_VERTICAL_ALIGN] = mxConstants.ALIGN_MIDDLE;
          style[mxConstants.STYLE_ALIGN] = mxConstants.ALIGN_CENTER;
          style[mxConstants.STYLE_SWIMLANE_LINE] = 0;
          style[mxConstants.STYLE_STARTSIZE] = StyleDefault.LANE_LABEL_SIZE;
          style[mxConstants.STYLE_FILLCOLOR] = StyleDefault.LANE_LABEL_FILL_COLOR;
          this.graph.getStylesheet().putCellStyle(exports.ShapeBpmnElementKind.LANE, style);
      }
      configureEventStyles() {
          for (const kind of ShapeUtil.eventKinds()) {
              const style = {};
              style[mxConstants.STYLE_SHAPE] = kind;
              style[mxConstants.STYLE_PERIMETER] = mxPerimeter.EllipsePerimeter;
              style[mxConstants.STYLE_STROKEWIDTH] = kind == exports.ShapeBpmnElementKind.EVENT_END ? StyleDefault.STROKE_WIDTH_THICK : StyleDefault.STROKE_WIDTH_THIN;
              style[mxConstants.STYLE_VERTICAL_LABEL_POSITION] = mxConstants.ALIGN_BOTTOM;
              this.putCellStyle(kind, style);
          }
      }
      configureTextAnnotationStyle() {
          const style = {};
          style[mxConstants.STYLE_SHAPE] = exports.ShapeBpmnElementKind.TEXT_ANNOTATION;
          style[mxConstants.STYLE_VERTICAL_ALIGN] = mxConstants.ALIGN_MIDDLE;
          style[mxConstants.STYLE_ALIGN] = mxConstants.ALIGN_LEFT;
          style[mxConstants.STYLE_SPACING_LEFT] = 5;
          style[mxConstants.STYLE_FILLCOLOR] = StyleDefault.TEXT_ANNOTATION_FILL_COLOR;
          style[mxConstants.STYLE_STROKEWIDTH] = StyleDefault.STROKE_WIDTH_THIN;
          this.putCellStyle(exports.ShapeBpmnElementKind.TEXT_ANNOTATION, style);
      }
      configureGroupStyle() {
          const style = {};
          style[mxConstants.STYLE_ROUNDED] = true;
          style[mxConstants.STYLE_DASHED] = true;
          style[mxConstants.STYLE_DASH_PATTERN] = '7 4 1 4';
          style[mxConstants.STYLE_STROKEWIDTH] = StyleDefault.STROKE_WIDTH_THIN;
          style[mxConstants.STYLE_FILLCOLOR] = StyleDefault.GROUP_FILL_COLOR;
          style[mxConstants.STYLE_ALIGN] = mxConstants.ALIGN_CENTER;
          style[mxConstants.STYLE_VERTICAL_ALIGN] = mxConstants.ALIGN_TOP;
          this.putCellStyle(exports.ShapeBpmnElementKind.GROUP, style);
      }
      configureActivityStyles() {
          for (const kind of ShapeUtil.activityKinds()) {
              const style = {};
              style[mxConstants.STYLE_SHAPE] = kind;
              style[mxConstants.STYLE_ROUNDED] = true;
              style[mxConstants.STYLE_VERTICAL_ALIGN] = mxConstants.ALIGN_MIDDLE;
              style[mxConstants.STYLE_STROKEWIDTH] = kind == exports.ShapeBpmnElementKind.CALL_ACTIVITY ? StyleDefault.STROKE_WIDTH_THICK : StyleDefault.STROKE_WIDTH_THIN;
              this.putCellStyle(kind, style);
          }
      }
      configureGatewayStyles() {
          for (const kind of ShapeUtil.gatewayKinds()) {
              const style = {};
              style[mxConstants.STYLE_SHAPE] = kind;
              style[mxConstants.STYLE_PERIMETER] = mxPerimeter.RhombusPerimeter;
              style[mxConstants.STYLE_STROKEWIDTH] = StyleDefault.STROKE_WIDTH_THIN;
              style[mxConstants.STYLE_VERTICAL_ALIGN] = mxConstants.ALIGN_TOP;
              style[mxConstants.STYLE_LABEL_POSITION] = mxConstants.ALIGN_LEFT;
              style[mxConstants.STYLE_VERTICAL_LABEL_POSITION] = mxConstants.ALIGN_TOP;
              this.putCellStyle(kind, style);
          }
      }
      configureDefaultEdgeStyle() {
          const style = this.getStylesheet().getDefaultEdgeStyle();
          configureCommonDefaultStyle(style);
          style[mxConstants.STYLE_SHAPE] = BpmnStyleIdentifier.EDGE;
          style[mxConstants.STYLE_ENDSIZE] = arrowDefaultSize;
          style[mxConstants.STYLE_STROKEWIDTH] = 1.5;
          style[mxConstants.STYLE_ROUNDED] = true;
          style[mxConstants.STYLE_ARCSIZE] = 5;
          style[mxConstants.STYLE_VERTICAL_ALIGN] = mxConstants.ALIGN_BOTTOM;
          delete style[mxConstants.STYLE_ENDARROW];
      }
      configureEdgeStyles(styleKinds, specificStyles) {
          for (const kind of styleKinds) {
              const style = {};
              specificStyles.get(kind)(style);
              this.graph.getStylesheet().putCellStyle(kind.toString(), style);
          }
      }
      configureFlowStyles() {
          this.configureEdgeStyles(Object.values(exports.FlowKind), specificFlowStyles);
          this.configureEdgeStyles(Object.values(exports.SequenceFlowKind), specificSequenceFlowStyles);
          this.configureEdgeStyles(Object.values(exports.AssociationDirectionKind), specificAssociationFlowStyles);
      }
  }
  function configureCommonDefaultStyle(style) {
      style[mxConstants.STYLE_FONTFAMILY] = StyleDefault.DEFAULT_FONT_FAMILY;
      style[mxConstants.STYLE_FONTSIZE] = StyleDefault.DEFAULT_FONT_SIZE;
      style[mxConstants.STYLE_FONTCOLOR] = StyleDefault.DEFAULT_FONT_COLOR;
      style[mxConstants.STYLE_FILLCOLOR] = StyleDefault.DEFAULT_FILL_COLOR;
      style[mxConstants.STYLE_STROKECOLOR] = StyleDefault.DEFAULT_STROKE_COLOR;
      style[mxConstants.STYLE_LABEL_BACKGROUNDCOLOR] = mxConstants.NONE;
      style[mxConstants.STYLE_WHITE_SPACE] = 'wrap';
  }

  class GraphConfigurator {
      constructor(container) {
          Object.defineProperty(this, "graph", {
              enumerable: true,
              configurable: true,
              writable: true,
              value: void 0
          });
          this.graph = new BpmnGraph(container);
      }
      configure(options) {
          this.configureGraph();
          this.configureNavigationSupport(options);
          new StyleConfigurator(this.graph).configureStyles();
          new ShapeConfigurator().configureShapes();
          new MarkerConfigurator().configureMarkers();
          return this.graph;
      }
      configureGraph() {
          this.graph.setCellsLocked(true);
          this.graph.setCellsSelectable(false);
          this.graph.setEdgeLabelsMovable(false);
          this.graph.setHtmlLabels(true);
          this.graph.setConstrainChildren(false);
          this.graph.setExtendParents(false);
          this.graph.foldingEnabled = false;
      }
      configureNavigationSupport(options) {
          var _a;
          const panningHandler = this.graph.panningHandler;
          if ((_a = options === null || options === void 0 ? void 0 : options.navigation) === null || _a === void 0 ? void 0 : _a.enabled) {
              panningHandler.addListener(mxEvent.PAN_START, setContainerCursor(this.graph, 'grab'));
              panningHandler.addListener(mxEvent.PAN_END, setContainerCursor(this.graph, 'default'));
              panningHandler.usePopupTrigger = false;
              panningHandler.isForcePanningEvent = (me) => mxEvent.isLeftMouseButton(me.getEvent()) || mxEvent.isMultiTouchEvent(me.getEvent());
              this.graph.setPanning(true);
              this.graph.registerMouseWheelZoomListeners(options.navigation.zoom);
          }
          else {
              this.graph.setPanning(false);
              panningHandler.setPinchEnabled(false);
              panningHandler.isForcePanningEvent = (_me) => false;
          }
      }
  }
  function setContainerCursor(graph, cursor) {
      return () => {
          graph.container.style.cursor = cursor;
      };
  }

  class Navigation {
      constructor(graph) {
          Object.defineProperty(this, "graph", {
              enumerable: true,
              configurable: true,
              writable: true,
              value: graph
          });
      }
      fit(options) {
          this.graph.customFit(options);
      }
      zoom(type) {
          type == 'in' ? this.graph.zoomIn() : this.graph.zoomOut();
      }
  }

  class CategoryConverter {
      constructor(convertedElements) {
          Object.defineProperty(this, "convertedElements", {
              enumerable: true,
              configurable: true,
              writable: true,
              value: convertedElements
          });
      }
      deserialize(definitions) {
          const categoryValues = ensureIsArray(definitions.category).flatMap(category => ensureIsArray(category.categoryValue));
          for (const categoryValue of categoryValues) {
              this.convertedElements.registerCategoryValue(categoryValue.id, categoryValue.value);
          }
      }
  }

  class JsonParsingWarning {
  }
  class ParsingMessageCollector {
      constructor(options) {
          Object.defineProperty(this, "options", {
              enumerable: true,
              configurable: true,
              writable: true,
              value: options
          });
      }
      warning(warning) {
          var _a;
          if ((_a = this.options) === null || _a === void 0 ? void 0 : _a.disableConsoleLog) {
              return;
          }
          const message = warning.getMessage();
          console.warn(`[bv-parser] ${message.template}`, ...message.arguments);
      }
  }

  class GroupUnknownCategoryValueWarning extends JsonParsingWarning {
      constructor(groupBpmnElementId, categoryValueReference) {
          super();
          Object.defineProperty(this, "groupBpmnElementId", {
              enumerable: true,
              configurable: true,
              writable: true,
              value: groupBpmnElementId
          });
          Object.defineProperty(this, "categoryValueReference", {
              enumerable: true,
              configurable: true,
              writable: true,
              value: categoryValueReference
          });
      }
      getMessage() {
          return {
              arguments: [this.categoryValueReference, this.groupBpmnElementId],
              template: 'Group json deserialization: unable to find category value ref %s for bpmn element %s',
          };
      }
  }
  class ShapeUnknownBpmnElementWarning extends JsonParsingWarning {
      constructor(bpmnElementId) {
          super();
          Object.defineProperty(this, "bpmnElementId", {
              enumerable: true,
              configurable: true,
              writable: true,
              value: bpmnElementId
          });
      }
      getMessage() {
          return {
              arguments: [this.bpmnElementId],
              template: 'Shape json deserialization: unable to find bpmn element with id %s',
          };
      }
  }
  class EdgeUnknownBpmnElementWarning extends JsonParsingWarning {
      constructor(bpmnElementId) {
          super();
          Object.defineProperty(this, "bpmnElementId", {
              enumerable: true,
              configurable: true,
              writable: true,
              value: bpmnElementId
          });
      }
      getMessage() {
          return {
              arguments: [this.bpmnElementId],
              template: 'Edge json deserialization: unable to find bpmn element with id %s',
          };
      }
  }
  class LabelStyleMissingFontWarning extends JsonParsingWarning {
      constructor(shapeOrEdgeId, labelStyleId) {
          super();
          Object.defineProperty(this, "shapeOrEdgeId", {
              enumerable: true,
              configurable: true,
              writable: true,
              value: shapeOrEdgeId
          });
          Object.defineProperty(this, "labelStyleId", {
              enumerable: true,
              configurable: true,
              writable: true,
              value: labelStyleId
          });
      }
      getMessage() {
          return {
              arguments: [this.labelStyleId, this.shapeOrEdgeId],
              template: 'Unable to assign font from style %s to shape/edge %s',
          };
      }
  }
  class LaneUnknownFlowNodeReferenceWarning extends JsonParsingWarning {
      constructor(laneId, flowNodeReference) {
          super();
          Object.defineProperty(this, "laneId", {
              enumerable: true,
              configurable: true,
              writable: true,
              value: laneId
          });
          Object.defineProperty(this, "flowNodeReference", {
              enumerable: true,
              configurable: true,
              writable: true,
              value: flowNodeReference
          });
      }
      getMessage() {
          return {
              arguments: [this.flowNodeReference, this.laneId],
              template: 'Unable to assign lane %s as parent: flow node %s is not found',
          };
      }
  }
  class BoundaryEventNotAttachedToActivityWarning extends JsonParsingWarning {
      constructor(bpmnElementId, attachedToReference, attachedToKind) {
          super();
          Object.defineProperty(this, "bpmnElementId", {
              enumerable: true,
              configurable: true,
              writable: true,
              value: bpmnElementId
          });
          Object.defineProperty(this, "attachedToReference", {
              enumerable: true,
              configurable: true,
              writable: true,
              value: attachedToReference
          });
          Object.defineProperty(this, "attachedToKind", {
              enumerable: true,
              configurable: true,
              writable: true,
              value: attachedToKind
          });
      }
      getMessage() {
          return {
              arguments: [this.bpmnElementId, this.attachedToReference, this.attachedToKind],
              template: 'The boundary event %s must be attached to an activity, and not to %s of kind %s',
          };
      }
  }

  class ConvertedElements {
      constructor() {
          Object.defineProperty(this, "poolsById", {
              enumerable: true,
              configurable: true,
              writable: true,
              value: new Map()
          });
          Object.defineProperty(this, "poolsByProcessRef", {
              enumerable: true,
              configurable: true,
              writable: true,
              value: new Map()
          });
          Object.defineProperty(this, "messageFlows", {
              enumerable: true,
              configurable: true,
              writable: true,
              value: new Map()
          });
          Object.defineProperty(this, "flowNodes", {
              enumerable: true,
              configurable: true,
              writable: true,
              value: new Map()
          });
          Object.defineProperty(this, "lanes", {
              enumerable: true,
              configurable: true,
              writable: true,
              value: new Map()
          });
          Object.defineProperty(this, "sequenceFlows", {
              enumerable: true,
              configurable: true,
              writable: true,
              value: new Map()
          });
          Object.defineProperty(this, "associationFlows", {
              enumerable: true,
              configurable: true,
              writable: true,
              value: new Map()
          });
          Object.defineProperty(this, "eventDefinitionsOfDefinitions", {
              enumerable: true,
              configurable: true,
              writable: true,
              value: new Map()
          });
          Object.defineProperty(this, "globalTasks", {
              enumerable: true,
              configurable: true,
              writable: true,
              value: new Map()
          });
          Object.defineProperty(this, "categoryValues", {
              enumerable: true,
              configurable: true,
              writable: true,
              value: new Map()
          });
      }
      getFlows() {
          return [...this.messageFlows.values(), ...this.sequenceFlows.values(), ...this.associationFlows.values()];
      }
      findPoolById(id) {
          return this.poolsById.get(id);
      }
      findPoolByProcessRef(processReference) {
          return this.poolsByProcessRef.get(processReference);
      }
      registerPool(pool, processReference) {
          this.poolsById.set(pool.id, pool);
          if (processReference) {
              this.poolsByProcessRef.set(processReference, pool);
          }
      }
      findMessageFlow(id) {
          return this.messageFlows.get(id);
      }
      registerMessageFlow(messageFlow) {
          this.messageFlows.set(messageFlow.id, messageFlow);
      }
      findFlowNode(id) {
          return this.flowNodes.get(id);
      }
      registerFlowNode(flowNode) {
          this.flowNodes.set(flowNode.id, flowNode);
      }
      findLane(id) {
          return this.lanes.get(id);
      }
      registerLane(lane) {
          this.lanes.set(lane.id, lane);
      }
      findSequenceFlow(id) {
          return this.sequenceFlows.get(id);
      }
      registerSequenceFlow(sequenceFlow) {
          this.sequenceFlows.set(sequenceFlow.id, sequenceFlow);
      }
      findAssociationFlow(id) {
          return this.associationFlows.get(id);
      }
      registerAssociationFlow(associationFlow) {
          this.associationFlows.set(associationFlow.id, associationFlow);
      }
      findEventDefinitionOfDefinition(id) {
          return this.eventDefinitionsOfDefinitions.get(id);
      }
      registerEventDefinitionsOfDefinition(id, eventDefinition) {
          this.eventDefinitionsOfDefinitions.set(id, eventDefinition);
      }
      findGlobalTask(id) {
          return this.globalTasks.get(id);
      }
      registerGlobalTask(id, kind) {
          this.globalTasks.set(id, kind);
      }
      findCategoryValue(categoryValue) {
          return this.categoryValues.get(categoryValue);
      }
      registerCategoryValue(id, value) {
          this.categoryValues.set(id, { value });
      }
  }
  const buildShapeBpmnGroup = (convertedElements, parsingMessageCollector, groupBpmnElement, processId) => {
      const categoryValueData = convertedElements.findCategoryValue(groupBpmnElement.categoryValueRef);
      if (categoryValueData) {
          return new ShapeBpmnElement(groupBpmnElement.id, categoryValueData.value, exports.ShapeBpmnElementKind.GROUP, processId);
      }
      parsingMessageCollector.warning(new GroupUnknownCategoryValueWarning(groupBpmnElement.id, groupBpmnElement.categoryValueRef));
      return undefined;
  };
  const convertAndRegisterAssociationFlows = (convertedElements, bpmnElements) => {
      for (const association of ensureIsArray(bpmnElements)) {
          const direction = association.associationDirection;
          convertedElements.registerAssociationFlow(new AssociationFlow(association.id, undefined, association.sourceRef, association.targetRef, direction));
      }
  };

  class CollaborationConverter {
      constructor(convertedElements, parsingMessageCollector) {
          Object.defineProperty(this, "convertedElements", {
              enumerable: true,
              configurable: true,
              writable: true,
              value: convertedElements
          });
          Object.defineProperty(this, "parsingMessageCollector", {
              enumerable: true,
              configurable: true,
              writable: true,
              value: parsingMessageCollector
          });
      }
      deserialize(collaborations) {
          for (const collaboration of ensureIsArray(collaborations))
              this.parseCollaboration(collaboration);
      }
      parseCollaboration(collaboration) {
          this.buildParticipant(collaboration.participant);
          this.buildMessageFlows(collaboration.messageFlow);
          convertAndRegisterAssociationFlows(this.convertedElements, collaboration.association);
          this.buildGroups(collaboration.group);
          this.buildTextAnnotation(collaboration.textAnnotation);
      }
      buildParticipant(bpmnElements) {
          for (const participant of ensureIsArray(bpmnElements))
              this.convertedElements.registerPool(new ShapeBpmnElement(participant.id, participant.name, exports.ShapeBpmnElementKind.POOL), participant.processRef);
      }
      buildMessageFlows(bpmnElements) {
          for (const messageFlow of ensureIsArray(bpmnElements))
              this.convertedElements.registerMessageFlow(new MessageFlow(messageFlow.id, messageFlow.name, messageFlow.sourceRef, messageFlow.targetRef));
      }
      buildGroups(bpmnElements) {
          for (const groupBpmnElement of ensureIsArray(bpmnElements)) {
              const shapeBpmnElement = buildShapeBpmnGroup(this.convertedElements, this.parsingMessageCollector, groupBpmnElement);
              shapeBpmnElement && this.convertedElements.registerFlowNode(shapeBpmnElement);
          }
      }
      buildTextAnnotation(bpmnElements) {
          for (const textAnnotation of ensureIsArray(bpmnElements)) {
              this.convertedElements.registerFlowNode(new ShapeBpmnElement(textAnnotation.id, textAnnotation.text, exports.ShapeBpmnElementKind.TEXT_ANNOTATION));
          }
      }
  }

  class Bounds {
      constructor(x, y, width, height) {
          Object.defineProperty(this, "x", {
              enumerable: true,
              configurable: true,
              writable: true,
              value: x
          });
          Object.defineProperty(this, "y", {
              enumerable: true,
              configurable: true,
              writable: true,
              value: y
          });
          Object.defineProperty(this, "width", {
              enumerable: true,
              configurable: true,
              writable: true,
              value: width
          });
          Object.defineProperty(this, "height", {
              enumerable: true,
              configurable: true,
              writable: true,
              value: height
          });
      }
  }

  class Edge {
      constructor(id, bpmnElement, waypoints, label, messageVisibleKind = exports.MessageVisibleKind.NONE) {
          Object.defineProperty(this, "id", {
              enumerable: true,
              configurable: true,
              writable: true,
              value: id
          });
          Object.defineProperty(this, "bpmnElement", {
              enumerable: true,
              configurable: true,
              writable: true,
              value: bpmnElement
          });
          Object.defineProperty(this, "waypoints", {
              enumerable: true,
              configurable: true,
              writable: true,
              value: waypoints
          });
          Object.defineProperty(this, "label", {
              enumerable: true,
              configurable: true,
              writable: true,
              value: label
          });
          Object.defineProperty(this, "messageVisibleKind", {
              enumerable: true,
              configurable: true,
              writable: true,
              value: messageVisibleKind
          });
          Object.defineProperty(this, "extensions", {
              enumerable: true,
              configurable: true,
              writable: true,
              value: {}
          });
      }
  }
  class Waypoint {
      constructor(x, y) {
          Object.defineProperty(this, "x", {
              enumerable: true,
              configurable: true,
              writable: true,
              value: x
          });
          Object.defineProperty(this, "y", {
              enumerable: true,
              configurable: true,
              writable: true,
              value: y
          });
      }
  }

  class Label {
      constructor(font, bounds) {
          Object.defineProperty(this, "font", {
              enumerable: true,
              configurable: true,
              writable: true,
              value: font
          });
          Object.defineProperty(this, "bounds", {
              enumerable: true,
              configurable: true,
              writable: true,
              value: bounds
          });
          Object.defineProperty(this, "extensions", {
              enumerable: true,
              configurable: true,
              writable: true,
              value: {}
          });
      }
  }
  class Font {
      constructor(name, size, isBold, isItalic, isUnderline, isStrikeThrough) {
          Object.defineProperty(this, "name", {
              enumerable: true,
              configurable: true,
              writable: true,
              value: name
          });
          Object.defineProperty(this, "size", {
              enumerable: true,
              configurable: true,
              writable: true,
              value: size
          });
          Object.defineProperty(this, "isBold", {
              enumerable: true,
              configurable: true,
              writable: true,
              value: isBold
          });
          Object.defineProperty(this, "isItalic", {
              enumerable: true,
              configurable: true,
              writable: true,
              value: isItalic
          });
          Object.defineProperty(this, "isUnderline", {
              enumerable: true,
              configurable: true,
              writable: true,
              value: isUnderline
          });
          Object.defineProperty(this, "isStrikeThrough", {
              enumerable: true,
              configurable: true,
              writable: true,
              value: isStrikeThrough
          });
      }
  }

  class DiagramConverter {
      constructor(convertedElements, parsingMessageCollector) {
          Object.defineProperty(this, "convertedElements", {
              enumerable: true,
              configurable: true,
              writable: true,
              value: convertedElements
          });
          Object.defineProperty(this, "parsingMessageCollector", {
              enumerable: true,
              configurable: true,
              writable: true,
              value: parsingMessageCollector
          });
          Object.defineProperty(this, "convertedFonts", {
              enumerable: true,
              configurable: true,
              writable: true,
              value: new Map()
          });
      }
      deserialize(bpmnDiagrams) {
          const flowNodes = [];
          const lanes = [];
          const pools = [];
          const edges = [];
          const bpmnDiagram = ensureIsArray(bpmnDiagrams)[0];
          if (bpmnDiagram) {
              this.deserializeFonts(bpmnDiagram.BPMNLabelStyle);
              const plane = bpmnDiagram.BPMNPlane;
              const convertedEdges = this.deserializeEdges(plane.BPMNEdge);
              const convertedShapes = this.deserializeShapes(plane.BPMNShape);
              flowNodes.push(...convertedShapes.flowNodes);
              lanes.push(...convertedShapes.lanes);
              pools.push(...convertedShapes.pools);
              edges.push(...convertedEdges);
          }
          return { flowNodes, lanes, pools, edges };
      }
      deserializeFonts(bpmnLabelStyle) {
          for (const labelStyle of ensureIsArray(bpmnLabelStyle))
              for (const font of ensureIsArray(labelStyle.Font))
                  this.convertedFonts.set(labelStyle.id, new Font(font.name, font.size, font.isBold, font.isItalic, font.isUnderline, font.isStrikeThrough));
      }
      deserializeShapes(shapes) {
          const convertedShapes = { flowNodes: [], lanes: [], pools: [] };
          for (const shape of ensureIsArray(shapes)) {
              if (this.deserializeShapeAndStoreIfFound(shape, convertedShapes.flowNodes, (bpmnElementId) => this.convertedElements.findFlowNode(bpmnElementId))) {
                  continue;
              }
              if (this.deserializeShapeAndStoreIfFound(shape, convertedShapes.lanes, (bpmnElementId) => this.convertedElements.findLane(bpmnElementId))) {
                  continue;
              }
              if (this.deserializeShapeAndStoreIfFound(shape, convertedShapes.pools, (bpmnElementId) => this.convertedElements.findPoolById(bpmnElementId))) {
                  continue;
              }
              this.parsingMessageCollector.warning(new ShapeUnknownBpmnElementWarning(shape.bpmnElement));
          }
          return convertedShapes;
      }
      deserializeShapeAndStoreIfFound(shape, storage, findShapeElement) {
          const element = this.deserializeShape(shape, findShapeElement);
          if (element) {
              storage.push(element);
              return true;
          }
          return false;
      }
      deserializeShape(bpmnShape, findShapeElement) {
          var _a;
          const bpmnElement = findShapeElement(bpmnShape.bpmnElement);
          if (bpmnElement) {
              const bounds = deserializeBounds(bpmnShape);
              if ((bpmnElement instanceof ShapeBpmnSubProcess ||
                  (bpmnElement instanceof ShapeBpmnCallActivity && bpmnElement.callActivityKind === exports.ShapeBpmnCallActivityKind.CALLING_PROCESS)) &&
                  !bpmnShape.isExpanded) {
                  bpmnElement.markers.push(exports.ShapeBpmnMarkerKind.EXPAND);
              }
              let isHorizontal;
              if (ShapeUtil.isPoolOrLane(bpmnElement.kind)) {
                  isHorizontal = (_a = bpmnShape.isHorizontal) !== null && _a !== void 0 ? _a : true;
              }
              const bpmnLabel = bpmnShape.BPMNLabel;
              const label = this.deserializeLabel(bpmnLabel, bpmnShape.id);
              const shape = new Shape(bpmnShape.id, bpmnElement, bounds, label, isHorizontal);
              setColorExtensionsOnShape(shape, bpmnShape);
              return shape;
          }
      }
      deserializeEdges(edges) {
          return ensureIsArray(edges)
              .map(bpmnEdge => {
              const flow = this.convertedElements.findSequenceFlow(bpmnEdge.bpmnElement) ||
                  this.convertedElements.findMessageFlow(bpmnEdge.bpmnElement) ||
                  this.convertedElements.findAssociationFlow(bpmnEdge.bpmnElement);
              if (!flow) {
                  this.parsingMessageCollector.warning(new EdgeUnknownBpmnElementWarning(bpmnEdge.bpmnElement));
                  return;
              }
              const waypoints = this.deserializeWaypoints(bpmnEdge.waypoint);
              const label = this.deserializeLabel(bpmnEdge.BPMNLabel, bpmnEdge.id);
              const messageVisibleKind = bpmnEdge.messageVisibleKind ? bpmnEdge.messageVisibleKind : exports.MessageVisibleKind.NONE;
              const edge = new Edge(bpmnEdge.id, flow, waypoints, label, messageVisibleKind);
              setColorExtensionsOnEdge(edge, bpmnEdge);
              return edge;
          })
              .filter(Boolean);
      }
      deserializeWaypoints(waypoints) {
          return ensureIsArray(waypoints).map(waypoint => new Waypoint(waypoint.x, waypoint.y));
      }
      deserializeLabel(bpmnLabel, id) {
          if (bpmnLabel && typeof bpmnLabel === 'object') {
              const font = this.findFont(bpmnLabel.labelStyle, id);
              const bounds = deserializeBounds(bpmnLabel);
              const label = new Label(font, bounds);
              if ('color' in bpmnLabel) {
                  label.extensions.color = bpmnLabel.color;
                  return label;
              }
              if (font || bounds) {
                  return label;
              }
          }
      }
      findFont(labelStyle, id) {
          let font;
          if (labelStyle) {
              font = this.convertedFonts.get(labelStyle);
              if (!font) {
                  this.parsingMessageCollector.warning(new LabelStyleMissingFontWarning(id, labelStyle));
              }
          }
          return font;
      }
  }
  function setColorExtensionsOnShape(shape, bpmnShape) {
      if ('background-color' in bpmnShape) {
          shape.extensions.fillColor = bpmnShape['background-color'];
      }
      else if ('fill' in bpmnShape) {
          shape.extensions.fillColor = bpmnShape.fill;
      }
      if ('border-color' in bpmnShape) {
          shape.extensions.strokeColor = bpmnShape['border-color'];
      }
      else if ('stroke' in bpmnShape) {
          shape.extensions.strokeColor = bpmnShape.stroke;
      }
  }
  function deserializeBounds(boundedElement) {
      const bounds = boundedElement.Bounds;
      if (bounds) {
          return new Bounds(bounds.x, bounds.y, bounds.width, bounds.height);
      }
  }
  function setColorExtensionsOnEdge(edge, bpmnEdge) {
      if ('border-color' in bpmnEdge) {
          edge.extensions.strokeColor = bpmnEdge['border-color'];
      }
      else if ('stroke' in bpmnEdge) {
          edge.extensions.strokeColor = bpmnEdge.stroke;
      }
  }

  const isTLinkEventDefinition = (eventDefinition) => 'source' in eventDefinition || 'target' in eventDefinition;

  class EventDefinitionConverter {
      constructor(convertedElements) {
          Object.defineProperty(this, "convertedElements", {
              enumerable: true,
              configurable: true,
              writable: true,
              value: convertedElements
          });
      }
      deserialize(definitions) {
          for (const eventDefinitionKind of eventDefinitionKinds) {
              const eventDefinitions = definitions[(eventDefinitionKind + 'EventDefinition')];
              for (const eventDefinition of ensureIsArray(eventDefinitions, true)) {
                  this.convertedElements.registerEventDefinitionsOfDefinition(eventDefinition.id, Object.assign({ id: eventDefinition.id, kind: eventDefinitionKind }, (isTLinkEventDefinition(eventDefinition)
                      ? {
                          source: eventDefinition.source,
                          target: eventDefinition.target,
                      }
                      : {})));
              }
          }
      }
  }

  class GlobalTaskConverter {
      constructor(convertedElements) {
          Object.defineProperty(this, "convertedElements", {
              enumerable: true,
              configurable: true,
              writable: true,
              value: convertedElements
          });
      }
      deserialize(definitions) {
          this.parseGlobalTasks(definitions.globalTask, exports.ShapeBpmnElementKind.GLOBAL_TASK);
          this.parseGlobalTasks(definitions.globalBusinessRuleTask, exports.ShapeBpmnElementKind.GLOBAL_TASK_BUSINESS_RULE);
          this.parseGlobalTasks(definitions.globalManualTask, exports.ShapeBpmnElementKind.GLOBAL_TASK_MANUAL);
          this.parseGlobalTasks(definitions.globalScriptTask, exports.ShapeBpmnElementKind.GLOBAL_TASK_SCRIPT);
          this.parseGlobalTasks(definitions.globalUserTask, exports.ShapeBpmnElementKind.GLOBAL_TASK_USER);
      }
      parseGlobalTasks(globalTasks, kind) {
          for (const globalTask of ensureIsArray(globalTasks))
              this.convertedElements.registerGlobalTask(globalTask.id, kind);
      }
  }

  const computeSubProcessKind = (processedSemanticType, bpmnElement) => {
      switch (processedSemanticType) {
          case 'adHocSubProcess': {
              return exports.ShapeBpmnSubProcessKind.AD_HOC;
          }
          case 'transaction': {
              return exports.ShapeBpmnSubProcessKind.TRANSACTION;
          }
          default: {
              return bpmnElement.triggeredByEvent ? exports.ShapeBpmnSubProcessKind.EVENT : exports.ShapeBpmnSubProcessKind.EMBEDDED;
          }
      }
  };
  const orderedFlowNodeBpmnTypes = [
      'adHocSubProcess',
      'transaction',
      ...ShapeUtil.flowNodeKinds().filter(kind => kind !== exports.ShapeBpmnElementKind.EVENT_BOUNDARY),
      exports.ShapeBpmnElementKind.EVENT_BOUNDARY,
  ];
  function getShapeBpmnElementKind(bpmnSemanticType) {
      return ['adHocSubProcess', 'transaction'].includes(bpmnSemanticType) ? exports.ShapeBpmnElementKind.SUB_PROCESS : bpmnSemanticType;
  }
  class ProcessConverter {
      constructor(convertedElements, parsingMessageCollector) {
          Object.defineProperty(this, "convertedElements", {
              enumerable: true,
              configurable: true,
              writable: true,
              value: convertedElements
          });
          Object.defineProperty(this, "parsingMessageCollector", {
              enumerable: true,
              configurable: true,
              writable: true,
              value: parsingMessageCollector
          });
          Object.defineProperty(this, "defaultSequenceFlowIds", {
              enumerable: true,
              configurable: true,
              writable: true,
              value: []
          });
          Object.defineProperty(this, "elementsWithoutParentByProcessId", {
              enumerable: true,
              configurable: true,
              writable: true,
              value: new Map()
          });
          Object.defineProperty(this, "callActivitiesCallingProcess", {
              enumerable: true,
              configurable: true,
              writable: true,
              value: new Map()
          });
          Object.defineProperty(this, "eventsByLinkEventDefinition", {
              enumerable: true,
              configurable: true,
              writable: true,
              value: new Map()
          });
      }
      deserialize(processes) {
          for (const process of ensureIsArray(processes))
              this.parseProcess(process);
          for (const process of ensureIsArray(processes))
              this.assignParentOfProcessElementsCalledByCallActivity(process.id);
          this.assignIncomingAndOutgoingIdsFromFlows();
          this.assignSourceAndTargetIdsToLinkEvents();
      }
      assignParentOfProcessElementsCalledByCallActivity(processId) {
          const callActivity = this.callActivitiesCallingProcess.get(processId);
          if (callActivity) {
              const pool = this.convertedElements.findPoolByProcessRef(processId);
              if (pool) {
                  pool.parentId = callActivity.id;
              }
              for (const element of this.elementsWithoutParentByProcessId.get(processId)) {
                  element.parentId = callActivity.id;
              }
          }
      }
      assignIncomingAndOutgoingIdsFromFlows() {
          const fillShapeBpmnElementAttribute = (shapeBpmnElementId, shapeBpmnElementAttributeName, valueToAdd) => {
              var _a, _b;
              const shapeBpmnElement = (_b = (_a = this.convertedElements.findFlowNode(shapeBpmnElementId)) !== null && _a !== void 0 ? _a : this.convertedElements.findLane(shapeBpmnElementId)) !== null && _b !== void 0 ? _b : this.convertedElements.findPoolById(shapeBpmnElementId);
              if (shapeBpmnElement && !shapeBpmnElement[shapeBpmnElementAttributeName].includes(valueToAdd)) {
                  shapeBpmnElement[shapeBpmnElementAttributeName].push(valueToAdd);
              }
          };
          for (const flow of this.convertedElements.getFlows()) {
              fillShapeBpmnElementAttribute(flow.sourceReferenceId, 'outgoingIds', flow.id);
              fillShapeBpmnElementAttribute(flow.targetReferenceId, 'incomingIds', flow.id);
          }
      }
      assignSourceAndTargetIdsToLinkEvents() {
          var _a;
          const linkEventDefinitions = [...this.eventsByLinkEventDefinition.entries()].filter(([targetEventDefinition]) => targetEventDefinition.id);
          for (const [eventDefinition, bpmnEvent] of this.eventsByLinkEventDefinition) {
              if (bpmnEvent instanceof ShapeBpmnIntermediateThrowEvent) {
                  const target = linkEventDefinitions.find(([targetEventDefinition]) => eventDefinition.target === targetEventDefinition.id);
                  bpmnEvent.targetId = (_a = target === null || target === void 0 ? void 0 : target[1]) === null || _a === void 0 ? void 0 : _a.id;
              }
              else if (bpmnEvent instanceof ShapeBpmnIntermediateCatchEvent) {
                  bpmnEvent.sourceIds = linkEventDefinitions
                      .filter(([sourceEventDefinition]) => Array.isArray(eventDefinition.source) ? eventDefinition.source.includes(sourceEventDefinition.id) : eventDefinition.source === sourceEventDefinition.id)
                      .map(([, sourceEvent]) => sourceEvent.id);
              }
          }
      }
      parseProcess(process) {
          const processReference = process.id;
          const pool = this.convertedElements.findPoolByProcessRef(processReference);
          if (pool && !pool.name) {
              this.convertedElements.registerPool(new ShapeBpmnElement(pool.id, process.name, exports.ShapeBpmnElementKind.POOL), processReference);
          }
          this.buildProcessInnerElements(process, pool === null || pool === void 0 ? void 0 : pool.id);
      }
      buildProcessInnerElements(process, parentId) {
          this.elementsWithoutParentByProcessId.set(process.id, []);
          for (const bpmnType of orderedFlowNodeBpmnTypes)
              this.buildFlowNodeBpmnElements(process[bpmnType], getShapeBpmnElementKind(bpmnType), parentId, process.id, bpmnType);
          this.buildLaneSetBpmnElements(process.laneSet, parentId, process.id);
          this.buildSequenceFlows(process.sequenceFlow);
          convertAndRegisterAssociationFlows(this.convertedElements, process.association);
      }
      buildFlowNodeBpmnElements(bpmnElements, kind, parentId, processId, processedSemanticType) {
          for (const bpmnElement of ensureIsArray(bpmnElements)) {
              const shapeBpmnElement = this.buildFlowNodeBpmnElement(kind, bpmnElement, parentId, processedSemanticType);
              if ('default' in bpmnElement && ShapeUtil.isWithDefaultSequenceFlow(kind)) {
                  this.defaultSequenceFlowIds.push(bpmnElement.default);
              }
              if (shapeBpmnElement) {
                  this.convertedElements.registerFlowNode(shapeBpmnElement);
                  if (!parentId) {
                      this.elementsWithoutParentByProcessId.get(processId).push(shapeBpmnElement);
                  }
              }
          }
      }
      buildFlowNodeBpmnElement(kind, bpmnElement, parentId, processedSemanticType) {
          if (ShapeUtil.isEvent(kind)) {
              return this.buildShapeBpmnEvent(bpmnElement, kind, parentId);
          }
          else if (ShapeUtil.isActivity(kind)) {
              return this.buildShapeBpmnActivity(bpmnElement, kind, parentId, processedSemanticType);
          }
          else if (kind == exports.ShapeBpmnElementKind.GATEWAY_EVENT_BASED) {
              const eventBasedGatewayBpmnElement = bpmnElement;
              return new ShapeBpmnEventBasedGateway(eventBasedGatewayBpmnElement.id, eventBasedGatewayBpmnElement.name, parentId, eventBasedGatewayBpmnElement.instantiate, exports.ShapeBpmnEventBasedGatewayKind[eventBasedGatewayBpmnElement.eventGatewayType]);
          }
          else if (kind == exports.ShapeBpmnElementKind.GROUP) {
              return buildShapeBpmnGroup(this.convertedElements, this.parsingMessageCollector, bpmnElement, parentId);
          }
          else {
              const name = kind === exports.ShapeBpmnElementKind.TEXT_ANNOTATION ? bpmnElement.text : bpmnElement.name;
              return new ShapeBpmnElement(bpmnElement.id, name, kind, parentId, bpmnElement.instantiate);
          }
      }
      buildShapeBpmnActivity(bpmnElement, kind, parentId, processedSemanticType) {
          const markers = buildMarkers(bpmnElement);
          if (ShapeUtil.isSubProcess(kind)) {
              return this.buildShapeBpmnSubProcess(bpmnElement, parentId, computeSubProcessKind(processedSemanticType, bpmnElement), markers);
          }
          if (!ShapeUtil.isCallActivity(kind)) {
              return new ShapeBpmnActivity(bpmnElement.id, bpmnElement.name, kind, parentId, bpmnElement.instantiate, markers);
          }
          return this.buildShapeBpmnCallActivity(bpmnElement, parentId, markers);
      }
      buildShapeBpmnCallActivity(bpmnElement, parentId, markers) {
          const globalTaskKind = this.convertedElements.findGlobalTask(bpmnElement.calledElement);
          if (!globalTaskKind) {
              const shapeBpmnCallActivity = new ShapeBpmnCallActivity(bpmnElement.id, bpmnElement.name, exports.ShapeBpmnCallActivityKind.CALLING_PROCESS, parentId, markers);
              this.callActivitiesCallingProcess.set(bpmnElement.calledElement, shapeBpmnCallActivity);
              return shapeBpmnCallActivity;
          }
          return new ShapeBpmnCallActivity(bpmnElement.id, bpmnElement.name, exports.ShapeBpmnCallActivityKind.CALLING_GLOBAL_TASK, parentId, markers, globalTaskKind);
      }
      buildShapeBpmnEvent(bpmnElement, elementKind, parentId) {
          const eventDefinitionsByKind = this.getEventDefinitions(bpmnElement);
          const numberOfEventDefinitions = [...eventDefinitionsByKind.entries()]
              .map(([, registeredEventDefinitions]) => registeredEventDefinitions.length)
              .reduce((counter, it) => counter + it, 0);
          if (numberOfEventDefinitions == 0 && ShapeUtil.canHaveNoneEvent(elementKind)) {
              return new ShapeBpmnEvent(bpmnElement.id, bpmnElement.name, elementKind, exports.ShapeBpmnEventDefinitionKind.NONE, parentId);
          }
          if (numberOfEventDefinitions == 1) {
              const [eventDefinitionKind, eventDefinitions] = [...eventDefinitionsByKind.entries()][0];
              const bpmnEvent = ShapeUtil.isCatchEvent(elementKind)
                  ? this.buildShapeBpmnCatchEvent(bpmnElement, elementKind, eventDefinitionKind, parentId)
                  : this.buildShapeBpmnThrowEvent(bpmnElement, elementKind, eventDefinitionKind, parentId);
              if (eventDefinitionKind === exports.ShapeBpmnEventDefinitionKind.LINK && (eventDefinitions[0].id || eventDefinitions[0].target || eventDefinitions[0].source)) {
                  this.eventsByLinkEventDefinition.set(eventDefinitions[0], bpmnEvent);
              }
              return bpmnEvent;
          }
      }
      buildShapeBpmnCatchEvent(bpmnElement, elementKind, eventDefinitionKind, parentId) {
          if (ShapeUtil.isBoundaryEvent(elementKind)) {
              return this.buildShapeBpmnBoundaryEvent(bpmnElement, eventDefinitionKind);
          }
          if (ShapeUtil.isStartEvent(elementKind)) {
              return new ShapeBpmnStartEvent(bpmnElement.id, bpmnElement.name, eventDefinitionKind, parentId, bpmnElement.isInterrupting);
          }
          return new ShapeBpmnIntermediateCatchEvent(bpmnElement.id, bpmnElement.name, eventDefinitionKind, parentId);
      }
      buildShapeBpmnThrowEvent(bpmnElement, elementKind, eventDefinitionKind, parentId) {
          if (ShapeUtil.isIntermediateThrowEvent(elementKind)) {
              return new ShapeBpmnIntermediateThrowEvent(bpmnElement.id, bpmnElement.name, eventDefinitionKind, parentId);
          }
          return new ShapeBpmnEvent(bpmnElement.id, bpmnElement.name, elementKind, eventDefinitionKind, parentId);
      }
      buildShapeBpmnBoundaryEvent(bpmnElement, eventDefinitionKind) {
          const parent = this.convertedElements.findFlowNode(bpmnElement.attachedToRef);
          if (ShapeUtil.isActivity(parent === null || parent === void 0 ? void 0 : parent.kind)) {
              return new ShapeBpmnBoundaryEvent(bpmnElement.id, bpmnElement.name, eventDefinitionKind, bpmnElement.attachedToRef, bpmnElement.cancelActivity);
          }
          else {
              this.parsingMessageCollector.warning(new BoundaryEventNotAttachedToActivityWarning(bpmnElement.id, bpmnElement.attachedToRef, parent === null || parent === void 0 ? void 0 : parent.kind));
          }
      }
      getEventDefinitions(bpmnElement) {
          const eventDefinitionsByKind = new Map();
          for (const eventDefinitionKind of eventDefinitionKinds) {
              const eventDefinition = bpmnElement[`${eventDefinitionKind}EventDefinition`];
              eventDefinitionsByKind.set(eventDefinitionKind, ensureIsArray(eventDefinition, true));
          }
          for (const eventDefinitionReference of ensureIsArray(bpmnElement.eventDefinitionRef)) {
              const eventDefinition = this.convertedElements.findEventDefinitionOfDefinition(eventDefinitionReference);
              eventDefinition && eventDefinitionsByKind.get(eventDefinition.kind).push(eventDefinition);
          }
          for (const [kind] of [...eventDefinitionsByKind.entries()].filter(([, registeredEventDefinitions]) => registeredEventDefinitions.length === 0)) {
              eventDefinitionsByKind.delete(kind);
          }
          return eventDefinitionsByKind;
      }
      buildShapeBpmnSubProcess(bpmnElement, parentId, subProcessKind, markers) {
          const convertedSubProcess = new ShapeBpmnSubProcess(bpmnElement.id, bpmnElement.name, subProcessKind, parentId, markers);
          this.buildProcessInnerElements(bpmnElement, bpmnElement.id);
          return convertedSubProcess;
      }
      buildLaneSetBpmnElements(laneSets, parentId, processId) {
          for (const laneSet of ensureIsArray(laneSets))
              this.buildLaneBpmnElements(laneSet.lane, parentId, processId);
      }
      buildLaneBpmnElements(lanes, parentId, processId) {
          var _a;
          for (const lane of ensureIsArray(lanes)) {
              const shapeBpmnElement = new ShapeBpmnElement(lane.id, lane.name, exports.ShapeBpmnElementKind.LANE, parentId);
              this.convertedElements.registerLane(shapeBpmnElement);
              if (!parentId) {
                  this.elementsWithoutParentByProcessId.get(processId).push(shapeBpmnElement);
              }
              this.assignParentOfLaneFlowNodes(lane);
              if ((_a = lane.childLaneSet) === null || _a === void 0 ? void 0 : _a.lane) {
                  this.buildLaneBpmnElements(lane.childLaneSet.lane, lane.id, processId);
              }
          }
      }
      assignParentOfLaneFlowNodes(lane) {
          for (const flowNodeReference of ensureIsArray(lane.flowNodeRef)) {
              const shapeBpmnElement = this.convertedElements.findFlowNode(flowNodeReference);
              const laneId = lane.id;
              if (shapeBpmnElement) {
                  if (!ShapeUtil.isBoundaryEvent(shapeBpmnElement.kind)) {
                      shapeBpmnElement.parentId = laneId;
                  }
              }
              else {
                  this.parsingMessageCollector.warning(new LaneUnknownFlowNodeReferenceWarning(laneId, flowNodeReference));
              }
          }
      }
      buildSequenceFlows(bpmnElements) {
          for (const sequenceFlow of ensureIsArray(bpmnElements)) {
              const kind = this.getSequenceFlowKind(sequenceFlow);
              this.convertedElements.registerSequenceFlow(new SequenceFlow(sequenceFlow.id, sequenceFlow.name, sequenceFlow.sourceRef, sequenceFlow.targetRef, kind));
          }
      }
      getSequenceFlowKind(sequenceFlow) {
          if (this.defaultSequenceFlowIds.includes(sequenceFlow.id)) {
              return exports.SequenceFlowKind.DEFAULT;
          }
          else {
              const sourceShapeBpmnElement = this.convertedElements.findFlowNode(sequenceFlow.sourceRef);
              if (sourceShapeBpmnElement && ShapeUtil.isWithDefaultSequenceFlow(sourceShapeBpmnElement.kind) && sequenceFlow.conditionExpression) {
                  return ShapeUtil.isActivity(sourceShapeBpmnElement.kind) ? exports.SequenceFlowKind.CONDITIONAL_FROM_ACTIVITY : exports.SequenceFlowKind.CONDITIONAL_FROM_GATEWAY;
              }
          }
          return exports.SequenceFlowKind.NORMAL;
      }
  }
  const buildMarkers = (bpmnElement) => {
      const markers = [];
      const standardLoopCharacteristics = bpmnElement.standardLoopCharacteristics;
      const multiInstanceLoopCharacteristics = ensureIsArray(bpmnElement.multiInstanceLoopCharacteristics, true)[0];
      if (standardLoopCharacteristics !== undefined) {
          markers.push(exports.ShapeBpmnMarkerKind.LOOP);
      }
      else if (multiInstanceLoopCharacteristics) {
          markers.push(multiInstanceLoopCharacteristics.isSequential ? exports.ShapeBpmnMarkerKind.MULTI_INSTANCE_SEQUENTIAL : exports.ShapeBpmnMarkerKind.MULTI_INSTANCE_PARALLEL);
      }
      return markers;
  };

  class BpmnJsonParser {
      constructor(categoryConverter, collaborationConverter, eventDefinitionConverter, globalTaskConverter, processConverter, diagramConverter) {
          Object.defineProperty(this, "categoryConverter", {
              enumerable: true,
              configurable: true,
              writable: true,
              value: categoryConverter
          });
          Object.defineProperty(this, "collaborationConverter", {
              enumerable: true,
              configurable: true,
              writable: true,
              value: collaborationConverter
          });
          Object.defineProperty(this, "eventDefinitionConverter", {
              enumerable: true,
              configurable: true,
              writable: true,
              value: eventDefinitionConverter
          });
          Object.defineProperty(this, "globalTaskConverter", {
              enumerable: true,
              configurable: true,
              writable: true,
              value: globalTaskConverter
          });
          Object.defineProperty(this, "processConverter", {
              enumerable: true,
              configurable: true,
              writable: true,
              value: processConverter
          });
          Object.defineProperty(this, "diagramConverter", {
              enumerable: true,
              configurable: true,
              writable: true,
              value: diagramConverter
          });
      }
      parse(json) {
          const definitions = json.definitions;
          this.categoryConverter.deserialize(definitions);
          this.collaborationConverter.deserialize(definitions.collaboration);
          this.eventDefinitionConverter.deserialize(definitions);
          this.globalTaskConverter.deserialize(definitions);
          this.processConverter.deserialize(definitions.process);
          return this.diagramConverter.deserialize(definitions.BPMNDiagram);
      }
  }
  function newBpmnJsonParser(parsingMessageCollector) {
      const convertedElements = new ConvertedElements();
      return new BpmnJsonParser(new CategoryConverter(convertedElements), new CollaborationConverter(convertedElements, parsingMessageCollector), new EventDefinitionConverter(convertedElements), new GlobalTaskConverter(convertedElements), new ProcessConverter(convertedElements, parsingMessageCollector), new DiagramConverter(convertedElements, parsingMessageCollector));
  }

  const nameStartChar = ':A-Za-z_\\u00C0-\\u00D6\\u00D8-\\u00F6\\u00F8-\\u02FF\\u0370-\\u037D\\u037F-\\u1FFF\\u200C-\\u200D\\u2070-\\u218F\\u2C00-\\u2FEF\\u3001-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFFD';
  const nameChar = nameStartChar + '\\-.\\d\\u00B7\\u0300-\\u036F\\u203F-\\u2040';
  const nameRegexp = '[' + nameStartChar + '][' + nameChar + ']*';
  const regexName = new RegExp('^' + nameRegexp + '$');
  function getAllMatches(string, regex) {
    const matches = [];
    let match = regex.exec(string);
    while (match) {
      const allmatches = [];
      allmatches.startIndex = regex.lastIndex - match[0].length;
      const len = match.length;
      for (let index = 0; index < len; index++) {
        allmatches.push(match[index]);
      }
      matches.push(allmatches);
      match = regex.exec(string);
    }
    return matches;
  }
  const isName = function(string) {
    const match = regexName.exec(string);
    return !(match === null || typeof match === 'undefined');
  };
  function isExist(v) {
    return typeof v !== 'undefined';
  }

  const defaultOptions$1 = {
    allowBooleanAttributes: false,
    unpairedTags: []
  };
  function validate(xmlData, options) {
    options = Object.assign({}, defaultOptions$1, options);
    const tags = [];
    let tagFound = false;
    let reachedRoot = false;
    if (xmlData[0] === '\ufeff') {
      xmlData = xmlData.substr(1);
    }
    for (let i = 0; i < xmlData.length; i++) {
      if (xmlData[i] === '<' && xmlData[i+1] === '?') {
        i+=2;
        i = readPI(xmlData,i);
        if (i.err) return i;
      }else if (xmlData[i] === '<') {
        let tagStartPos = i;
        i++;
        if (xmlData[i] === '!') {
          i = readCommentAndCDATA(xmlData, i);
          continue;
        } else {
          let closingTag = false;
          if (xmlData[i] === '/') {
            closingTag = true;
            i++;
          }
          let tagName = '';
          for (; i < xmlData.length &&
            xmlData[i] !== '>' &&
            xmlData[i] !== ' ' &&
            xmlData[i] !== '\t' &&
            xmlData[i] !== '\n' &&
            xmlData[i] !== '\r'; i++
          ) {
            tagName += xmlData[i];
          }
          tagName = tagName.trim();
          if (tagName[tagName.length - 1] === '/') {
            tagName = tagName.substring(0, tagName.length - 1);
            i--;
          }
          if (!validateTagName(tagName)) {
            let msg;
            if (tagName.trim().length === 0) {
              msg = "Invalid space after '<'.";
            } else {
              msg = "Tag '"+tagName+"' is an invalid name.";
            }
            return getErrorObject('InvalidTag', msg, getLineNumberForPosition(xmlData, i));
          }
          const result = readAttributeStr(xmlData, i);
          if (result === false) {
            return getErrorObject('InvalidAttr', "Attributes for '"+tagName+"' have open quote.", getLineNumberForPosition(xmlData, i));
          }
          let attrStr = result.value;
          i = result.index;
          if (attrStr[attrStr.length - 1] === '/') {
            const attrStrStart = i - attrStr.length;
            attrStr = attrStr.substring(0, attrStr.length - 1);
            const isValid = validateAttributeString(attrStr, options);
            if (isValid === true) {
              tagFound = true;
            } else {
              return getErrorObject(isValid.err.code, isValid.err.msg, getLineNumberForPosition(xmlData, attrStrStart + isValid.err.line));
            }
          } else if (closingTag) {
            if (!result.tagClosed) {
              return getErrorObject('InvalidTag', "Closing tag '"+tagName+"' doesn't have proper closing.", getLineNumberForPosition(xmlData, i));
            } else if (attrStr.trim().length > 0) {
              return getErrorObject('InvalidTag', "Closing tag '"+tagName+"' can't have attributes or invalid starting.", getLineNumberForPosition(xmlData, tagStartPos));
            } else if (tags.length === 0) {
              return getErrorObject('InvalidTag', "Closing tag '"+tagName+"' has not been opened.", getLineNumberForPosition(xmlData, tagStartPos));
            } else {
              const otg = tags.pop();
              if (tagName !== otg.tagName) {
                let openPos = getLineNumberForPosition(xmlData, otg.tagStartPos);
                return getErrorObject('InvalidTag',
                  "Expected closing tag '"+otg.tagName+"' (opened in line "+openPos.line+", col "+openPos.col+") instead of closing tag '"+tagName+"'.",
                  getLineNumberForPosition(xmlData, tagStartPos));
              }
              if (tags.length == 0) {
                reachedRoot = true;
              }
            }
          } else {
            const isValid = validateAttributeString(attrStr, options);
            if (isValid !== true) {
              return getErrorObject(isValid.err.code, isValid.err.msg, getLineNumberForPosition(xmlData, i - attrStr.length + isValid.err.line));
            }
            if (reachedRoot === true) {
              return getErrorObject('InvalidXml', 'Multiple possible root nodes found.', getLineNumberForPosition(xmlData, i));
            } else if(options.unpairedTags.indexOf(tagName) !== -1); else {
              tags.push({tagName, tagStartPos});
            }
            tagFound = true;
          }
          for (i++; i < xmlData.length; i++) {
            if (xmlData[i] === '<') {
              if (xmlData[i + 1] === '!') {
                i++;
                i = readCommentAndCDATA(xmlData, i);
                continue;
              } else if (xmlData[i+1] === '?') {
                i = readPI(xmlData, ++i);
                if (i.err) return i;
              } else {
                break;
              }
            } else if (xmlData[i] === '&') {
              const afterAmp = validateAmpersand(xmlData, i);
              if (afterAmp == -1)
                return getErrorObject('InvalidChar', "char '&' is not expected.", getLineNumberForPosition(xmlData, i));
              i = afterAmp;
            }else {
              if (reachedRoot === true && !isWhiteSpace(xmlData[i])) {
                return getErrorObject('InvalidXml', "Extra text at the end", getLineNumberForPosition(xmlData, i));
              }
            }
          }
          if (xmlData[i] === '<') {
            i--;
          }
        }
      } else {
        if ( isWhiteSpace(xmlData[i])) {
          continue;
        }
        return getErrorObject('InvalidChar', "char '"+xmlData[i]+"' is not expected.", getLineNumberForPosition(xmlData, i));
      }
    }
    if (!tagFound) {
      return getErrorObject('InvalidXml', 'Start tag expected.', 1);
    }else if (tags.length == 1) {
        return getErrorObject('InvalidTag', "Unclosed tag '"+tags[0].tagName+"'.", getLineNumberForPosition(xmlData, tags[0].tagStartPos));
    }else if (tags.length > 0) {
        return getErrorObject('InvalidXml', "Invalid '"+
            JSON.stringify(tags.map(t => t.tagName), null, 4).replace(/\r?\n/g, '')+
            "' found.", {line: 1, col: 1});
    }
    return true;
  }function isWhiteSpace(char){
    return char === ' ' || char === '\t' || char === '\n'  || char === '\r';
  }
  function readPI(xmlData, i) {
    const start = i;
    for (; i < xmlData.length; i++) {
      if (xmlData[i] == '?' || xmlData[i] == ' ') {
        const tagname = xmlData.substr(start, i - start);
        if (i > 5 && tagname === 'xml') {
          return getErrorObject('InvalidXml', 'XML declaration allowed only at the start of the document.', getLineNumberForPosition(xmlData, i));
        } else if (xmlData[i] == '?' && xmlData[i + 1] == '>') {
          i++;
          break;
        } else {
          continue;
        }
      }
    }
    return i;
  }
  function readCommentAndCDATA(xmlData, i) {
    if (xmlData.length > i + 5 && xmlData[i + 1] === '-' && xmlData[i + 2] === '-') {
      for (i += 3; i < xmlData.length; i++) {
        if (xmlData[i] === '-' && xmlData[i + 1] === '-' && xmlData[i + 2] === '>') {
          i += 2;
          break;
        }
      }
    } else if (
      xmlData.length > i + 8 &&
      xmlData[i + 1] === 'D' &&
      xmlData[i + 2] === 'O' &&
      xmlData[i + 3] === 'C' &&
      xmlData[i + 4] === 'T' &&
      xmlData[i + 5] === 'Y' &&
      xmlData[i + 6] === 'P' &&
      xmlData[i + 7] === 'E'
    ) {
      let angleBracketsCount = 1;
      for (i += 8; i < xmlData.length; i++) {
        if (xmlData[i] === '<') {
          angleBracketsCount++;
        } else if (xmlData[i] === '>') {
          angleBracketsCount--;
          if (angleBracketsCount === 0) {
            break;
          }
        }
      }
    } else if (
      xmlData.length > i + 9 &&
      xmlData[i + 1] === '[' &&
      xmlData[i + 2] === 'C' &&
      xmlData[i + 3] === 'D' &&
      xmlData[i + 4] === 'A' &&
      xmlData[i + 5] === 'T' &&
      xmlData[i + 6] === 'A' &&
      xmlData[i + 7] === '['
    ) {
      for (i += 8; i < xmlData.length; i++) {
        if (xmlData[i] === ']' && xmlData[i + 1] === ']' && xmlData[i + 2] === '>') {
          i += 2;
          break;
        }
      }
    }
    return i;
  }
  const doubleQuote = '"';
  const singleQuote = "'";
  function readAttributeStr(xmlData, i) {
    let attrStr = '';
    let startChar = '';
    let tagClosed = false;
    for (; i < xmlData.length; i++) {
      if (xmlData[i] === doubleQuote || xmlData[i] === singleQuote) {
        if (startChar === '') {
          startChar = xmlData[i];
        } else if (startChar !== xmlData[i]) ; else {
          startChar = '';
        }
      } else if (xmlData[i] === '>') {
        if (startChar === '') {
          tagClosed = true;
          break;
        }
      }
      attrStr += xmlData[i];
    }
    if (startChar !== '') {
      return false;
    }
    return {
      value: attrStr,
      index: i,
      tagClosed: tagClosed
    };
  }
  const validAttrStrRegxp = new RegExp('(\\s*)([^\\s=]+)(\\s*=)?(\\s*([\'"])(([\\s\\S])*?)\\5)?', 'g');
  function validateAttributeString(attrStr, options) {
    const matches = getAllMatches(attrStr, validAttrStrRegxp);
    const attrNames = {};
    for (let i = 0; i < matches.length; i++) {
      if (matches[i][1].length === 0) {
        return getErrorObject('InvalidAttr', "Attribute '"+matches[i][2]+"' has no space in starting.", getPositionFromMatch(matches[i]))
      } else if (matches[i][3] !== undefined && matches[i][4] === undefined) {
        return getErrorObject('InvalidAttr', "Attribute '"+matches[i][2]+"' is without value.", getPositionFromMatch(matches[i]));
      } else if (matches[i][3] === undefined && !options.allowBooleanAttributes) {
        return getErrorObject('InvalidAttr', "boolean attribute '"+matches[i][2]+"' is not allowed.", getPositionFromMatch(matches[i]));
      }
      const attrName = matches[i][2];
      if (!validateAttrName(attrName)) {
        return getErrorObject('InvalidAttr', "Attribute '"+attrName+"' is an invalid name.", getPositionFromMatch(matches[i]));
      }
      if (!attrNames.hasOwnProperty(attrName)) {
        attrNames[attrName] = 1;
      } else {
        return getErrorObject('InvalidAttr', "Attribute '"+attrName+"' is repeated.", getPositionFromMatch(matches[i]));
      }
    }
    return true;
  }
  function validateNumberAmpersand(xmlData, i) {
    let re = /\d/;
    if (xmlData[i] === 'x') {
      i++;
      re = /[\da-fA-F]/;
    }
    for (; i < xmlData.length; i++) {
      if (xmlData[i] === ';')
        return i;
      if (!xmlData[i].match(re))
        break;
    }
    return -1;
  }
  function validateAmpersand(xmlData, i) {
    i++;
    if (xmlData[i] === ';')
      return -1;
    if (xmlData[i] === '#') {
      i++;
      return validateNumberAmpersand(xmlData, i);
    }
    let count = 0;
    for (; i < xmlData.length; i++, count++) {
      if (xmlData[i].match(/\w/) && count < 20)
        continue;
      if (xmlData[i] === ';')
        break;
      return -1;
    }
    return i;
  }
  function getErrorObject(code, message, lineNumber) {
    return {
      err: {
        code: code,
        msg: message,
        line: lineNumber.line || lineNumber,
        col: lineNumber.col,
      },
    };
  }
  function validateAttrName(attrName) {
    return isName(attrName);
  }
  function validateTagName(tagname) {
    return isName(tagname) ;
  }
  function getLineNumberForPosition(xmlData, index) {
    const lines = xmlData.substring(0, index).split(/\r?\n/);
    return {
      line: lines.length,
      col: lines[lines.length - 1].length + 1
    };
  }
  function getPositionFromMatch(match) {
    return match.startIndex + match[1].length;
  }

  const defaultOptions = {
      preserveOrder: false,
      attributeNamePrefix: '@_',
      attributesGroupName: false,
      textNodeName: '#text',
      ignoreAttributes: true,
      removeNSPrefix: false,
      allowBooleanAttributes: false,
      parseTagValue: true,
      parseAttributeValue: false,
      trimValues: true,
      cdataPropName: false,
      numberParseOptions: {
        hex: true,
        leadingZeros: true,
        eNotation: true
      },
      tagValueProcessor: function(tagName, val) {
        return val;
      },
      attributeValueProcessor: function(attrName, val) {
        return val;
      },
      stopNodes: [],
      alwaysCreateTextNode: false,
      isArray: () => false,
      commentPropName: false,
      unpairedTags: [],
      processEntities: true,
      htmlEntities: false,
      ignoreDeclaration: false,
      ignorePiTags: false,
      transformTagName: false,
      transformAttributeName: false,
      updateTag: function(tagName, jPath, attrs){
        return tagName
      },
  };
  const buildOptions = function(options) {
      return Object.assign({}, defaultOptions, options);
  };

  class XmlNode{
    constructor(tagname) {
      this.tagname = tagname;
      this.child = [];
      this[":@"] = {};
    }
    add(key,val){
      if(key === "__proto__") key = "#__proto__";
      this.child.push( {[key]: val });
    }
    addChild(node) {
      if(node.tagname === "__proto__") node.tagname = "#__proto__";
      if(node[":@"] && Object.keys(node[":@"]).length > 0){
        this.child.push( { [node.tagname]: node.child, [":@"]: node[":@"] });
      }else {
        this.child.push( { [node.tagname]: node.child });
      }
    }
  }

  function readDocType(xmlData, i){
      const entities = {};
      if( xmlData[i + 3] === 'O' &&
           xmlData[i + 4] === 'C' &&
           xmlData[i + 5] === 'T' &&
           xmlData[i + 6] === 'Y' &&
           xmlData[i + 7] === 'P' &&
           xmlData[i + 8] === 'E')
      {
          i = i+9;
          let angleBracketsCount = 1;
          let hasBody = false, comment = false;
          let exp = "";
          for(;i<xmlData.length;i++){
              if (xmlData[i] === '<' && !comment) {
                  if( hasBody && isEntity(xmlData, i)){
                      i += 7;
                      let entityName, val;
                      [entityName, val,i] = readEntityExp(xmlData,i+1);
                      if(val.indexOf("&") === -1)
                          entities[ validateEntityName(entityName) ] = {
                              regx : RegExp( `&${entityName};`,"g"),
                              val: val
                          };
                  }
                  else if( hasBody && isElement(xmlData, i))  i += 8;
                  else if( hasBody && isAttlist(xmlData, i))  i += 8;
                  else if( hasBody && isNotation(xmlData, i)) i += 9;
                  else if( isComment)                         comment = true;
                  else                                        throw new Error("Invalid DOCTYPE");
                  angleBracketsCount++;
                  exp = "";
              } else if (xmlData[i] === '>') {
                  if(comment){
                      if( xmlData[i - 1] === "-" && xmlData[i - 2] === "-"){
                          comment = false;
                          angleBracketsCount--;
                      }
                  }else {
                      angleBracketsCount--;
                  }
                  if (angleBracketsCount === 0) {
                    break;
                  }
              }else if( xmlData[i] === '['){
                  hasBody = true;
              }else {
                  exp += xmlData[i];
              }
          }
          if(angleBracketsCount !== 0){
              throw new Error(`Unclosed DOCTYPE`);
          }
      }else {
          throw new Error(`Invalid Tag instead of DOCTYPE`);
      }
      return {entities, i};
  }
  function readEntityExp(xmlData,i){
      let entityName = "";
      for (; i < xmlData.length && (xmlData[i] !== "'" && xmlData[i] !== '"' ); i++) {
          entityName += xmlData[i];
      }
      entityName = entityName.trim();
      if(entityName.indexOf(" ") !== -1) throw new Error("External entites are not supported");
      const startChar = xmlData[i++];
      let val = "";
      for (; i < xmlData.length && xmlData[i] !== startChar ; i++) {
          val += xmlData[i];
      }
      return [entityName, val, i];
  }
  function isComment(xmlData, i){
      if(xmlData[i+1] === '!' &&
      xmlData[i+2] === '-' &&
      xmlData[i+3] === '-') return true
      return false
  }
  function isEntity(xmlData, i){
      if(xmlData[i+1] === '!' &&
      xmlData[i+2] === 'E' &&
      xmlData[i+3] === 'N' &&
      xmlData[i+4] === 'T' &&
      xmlData[i+5] === 'I' &&
      xmlData[i+6] === 'T' &&
      xmlData[i+7] === 'Y') return true
      return false
  }
  function isElement(xmlData, i){
      if(xmlData[i+1] === '!' &&
      xmlData[i+2] === 'E' &&
      xmlData[i+3] === 'L' &&
      xmlData[i+4] === 'E' &&
      xmlData[i+5] === 'M' &&
      xmlData[i+6] === 'E' &&
      xmlData[i+7] === 'N' &&
      xmlData[i+8] === 'T') return true
      return false
  }
  function isAttlist(xmlData, i){
      if(xmlData[i+1] === '!' &&
      xmlData[i+2] === 'A' &&
      xmlData[i+3] === 'T' &&
      xmlData[i+4] === 'T' &&
      xmlData[i+5] === 'L' &&
      xmlData[i+6] === 'I' &&
      xmlData[i+7] === 'S' &&
      xmlData[i+8] === 'T') return true
      return false
  }
  function isNotation(xmlData, i){
      if(xmlData[i+1] === '!' &&
      xmlData[i+2] === 'N' &&
      xmlData[i+3] === 'O' &&
      xmlData[i+4] === 'T' &&
      xmlData[i+5] === 'A' &&
      xmlData[i+6] === 'T' &&
      xmlData[i+7] === 'I' &&
      xmlData[i+8] === 'O' &&
      xmlData[i+9] === 'N') return true
      return false
  }
  function validateEntityName(name){
      if (isName(name))
  	return name;
      else
          throw new Error(`Invalid entity name ${name}`);
  }

  const hexRegex = /^[-+]?0x[a-fA-F0-9]+$/;
  const numRegex = /^([\-\+])?(0*)([0-9]*(\.[0-9]*)?)$/;
  const consider = {
      hex :  true,
      leadingZeros: true,
      decimalPoint: "\.",
      eNotation: true,
  };
  function toNumber(str, options = {}){
      options = Object.assign({}, consider, options );
      if(!str || typeof str !== "string" ) return str;
      let trimmedStr  = str.trim();
      if(options.skipLike !== undefined && options.skipLike.test(trimmedStr)) return str;
      else if(str==="0") return 0;
      else if (options.hex && hexRegex.test(trimmedStr)) {
          return parse_int(trimmedStr, 16);
      }else if (trimmedStr.search(/[eE]/)!== -1) {
          const notation = trimmedStr.match(/^([-\+])?(0*)([0-9]*(\.[0-9]*)?[eE][-\+]?[0-9]+)$/);
          if(notation){
              if(options.leadingZeros){
                  trimmedStr = (notation[1] || "") + notation[3];
              }else {
                  if(notation[2] === "0" && notation[3][0]=== ".");else {
                      return str;
                  }
              }
              return options.eNotation ? Number(trimmedStr) : str;
          }else {
              return str;
          }
      }else {
          const match = numRegex.exec(trimmedStr);
          if(match){
              const sign = match[1];
              const leadingZeros = match[2];
              let numTrimmedByZeros = trimZeros(match[3]);
              if(!options.leadingZeros && leadingZeros.length > 0 && sign && trimmedStr[2] !== ".") return str;
              else if(!options.leadingZeros && leadingZeros.length > 0 && !sign && trimmedStr[1] !== ".") return str;
              else if(options.leadingZeros && leadingZeros===str) return 0;
              else {
                  const num = Number(trimmedStr);
                  const numStr = "" + num;
                  if(numStr.search(/[eE]/) !== -1){
                      if(options.eNotation) return num;
                      else return str;
                  }else if(trimmedStr.indexOf(".") !== -1){
                      if(numStr === "0" && (numTrimmedByZeros === "") ) return num;
                      else if(numStr === numTrimmedByZeros) return num;
                      else if( sign && numStr === "-"+numTrimmedByZeros) return num;
                      else return str;
                  }
                  if(leadingZeros){
                      return (numTrimmedByZeros === numStr) || (sign+numTrimmedByZeros === numStr) ? num : str
                  }else  {
                      return (trimmedStr === numStr) || (trimmedStr === sign+numStr) ? num : str
                  }
              }
          }else {
              return str;
          }
      }
  }
  function trimZeros(numStr){
      if(numStr && numStr.indexOf(".") !== -1){
          numStr = numStr.replace(/0+$/, "");
          if(numStr === ".")  numStr = "0";
          else if(numStr[0] === ".")  numStr = "0"+numStr;
          else if(numStr[numStr.length-1] === ".")  numStr = numStr.substr(0,numStr.length-1);
          return numStr;
      }
      return numStr;
  }
  function parse_int(numStr, base){
      if(parseInt) return parseInt(numStr, base);
      else if(Number.parseInt) return Number.parseInt(numStr, base);
      else if(window && window.parseInt) return window.parseInt(numStr, base);
      else throw new Error("parseInt, Number.parseInt, window.parseInt are not supported")
  }

  function getIgnoreAttributesFn(ignoreAttributes) {
      if (typeof ignoreAttributes === 'function') {
          return ignoreAttributes
      }
      if (Array.isArray(ignoreAttributes)) {
          return (attrName) => {
              for (const pattern of ignoreAttributes) {
                  if (typeof pattern === 'string' && attrName === pattern) {
                      return true
                  }
                  if (pattern instanceof RegExp && pattern.test(attrName)) {
                      return true
                  }
              }
          }
      }
      return () => false
  }

  class OrderedObjParser{
    constructor(options){
      this.options = options;
      this.currentNode = null;
      this.tagsNodeStack = [];
      this.docTypeEntities = {};
      this.lastEntities = {
        "apos" : { regex: /&(apos|#39|#x27);/g, val : "'"},
        "gt" : { regex: /&(gt|#62|#x3E);/g, val : ">"},
        "lt" : { regex: /&(lt|#60|#x3C);/g, val : "<"},
        "quot" : { regex: /&(quot|#34|#x22);/g, val : "\""},
      };
      this.ampEntity = { regex: /&(amp|#38|#x26);/g, val : "&"};
      this.htmlEntities = {
        "space": { regex: /&(nbsp|#160);/g, val: " " },
        "cent" : { regex: /&(cent|#162);/g, val: "¢" },
        "pound" : { regex: /&(pound|#163);/g, val: "£" },
        "yen" : { regex: /&(yen|#165);/g, val: "¥" },
        "euro" : { regex: /&(euro|#8364);/g, val: "€" },
        "copyright" : { regex: /&(copy|#169);/g, val: "©" },
        "reg" : { regex: /&(reg|#174);/g, val: "®" },
        "inr" : { regex: /&(inr|#8377);/g, val: "₹" },
        "num_dec": { regex: /&#([0-9]{1,7});/g, val : (_, str) => String.fromCharCode(Number.parseInt(str, 10)) },
        "num_hex": { regex: /&#x([0-9a-fA-F]{1,6});/g, val : (_, str) => String.fromCharCode(Number.parseInt(str, 16)) },
      };
      this.addExternalEntities = addExternalEntities;
      this.parseXml = parseXml;
      this.parseTextData = parseTextData;
      this.resolveNameSpace = resolveNameSpace;
      this.buildAttributesMap = buildAttributesMap;
      this.isItStopNode = isItStopNode;
      this.replaceEntitiesValue = replaceEntitiesValue;
      this.readStopNodeData = readStopNodeData;
      this.saveTextToParentTag = saveTextToParentTag;
      this.addChild = addChild;
      this.ignoreAttributesFn = getIgnoreAttributesFn(this.options.ignoreAttributes);
    }
  }
  function addExternalEntities(externalEntities){
    const entKeys = Object.keys(externalEntities);
    for (let i = 0; i < entKeys.length; i++) {
      const ent = entKeys[i];
      this.lastEntities[ent] = {
         regex: new RegExp("&"+ent+";","g"),
         val : externalEntities[ent]
      };
    }
  }
  function parseTextData(val, tagName, jPath, dontTrim, hasAttributes, isLeafNode, escapeEntities) {
    if (val !== undefined) {
      if (this.options.trimValues && !dontTrim) {
        val = val.trim();
      }
      if(val.length > 0){
        if(!escapeEntities) val = this.replaceEntitiesValue(val);
        const newval = this.options.tagValueProcessor(tagName, val, jPath, hasAttributes, isLeafNode);
        if(newval === null || newval === undefined){
          return val;
        }else if(typeof newval !== typeof val || newval !== val){
          return newval;
        }else if(this.options.trimValues){
          return parseValue(val, this.options.parseTagValue, this.options.numberParseOptions);
        }else {
          const trimmedVal = val.trim();
          if(trimmedVal === val){
            return parseValue(val, this.options.parseTagValue, this.options.numberParseOptions);
          }else {
            return val;
          }
        }
      }
    }
  }
  function resolveNameSpace(tagname) {
    if (this.options.removeNSPrefix) {
      const tags = tagname.split(':');
      const prefix = tagname.charAt(0) === '/' ? '/' : '';
      if (tags[0] === 'xmlns') {
        return '';
      }
      if (tags.length === 2) {
        tagname = prefix + tags[1];
      }
    }
    return tagname;
  }
  const attrsRegx = new RegExp('([^\\s=]+)\\s*(=\\s*([\'"])([\\s\\S]*?)\\3)?', 'gm');
  function buildAttributesMap(attrStr, jPath, tagName) {
    if (this.options.ignoreAttributes !== true && typeof attrStr === 'string') {
      const matches = getAllMatches(attrStr, attrsRegx);
      const len = matches.length;
      const attrs = {};
      for (let i = 0; i < len; i++) {
        const attrName = this.resolveNameSpace(matches[i][1]);
        if (this.ignoreAttributesFn(attrName, jPath)) {
          continue
        }
        let oldVal = matches[i][4];
        let aName = this.options.attributeNamePrefix + attrName;
        if (attrName.length) {
          if (this.options.transformAttributeName) {
            aName = this.options.transformAttributeName(aName);
          }
          if(aName === "__proto__") aName  = "#__proto__";
          if (oldVal !== undefined) {
            if (this.options.trimValues) {
              oldVal = oldVal.trim();
            }
            oldVal = this.replaceEntitiesValue(oldVal);
            const newVal = this.options.attributeValueProcessor(attrName, oldVal, jPath);
            if(newVal === null || newVal === undefined){
              attrs[aName] = oldVal;
            }else if(typeof newVal !== typeof oldVal || newVal !== oldVal){
              attrs[aName] = newVal;
            }else {
              attrs[aName] = parseValue(
                oldVal,
                this.options.parseAttributeValue,
                this.options.numberParseOptions
              );
            }
          } else if (this.options.allowBooleanAttributes) {
            attrs[aName] = true;
          }
        }
      }
      if (!Object.keys(attrs).length) {
        return;
      }
      if (this.options.attributesGroupName) {
        const attrCollection = {};
        attrCollection[this.options.attributesGroupName] = attrs;
        return attrCollection;
      }
      return attrs
    }
  }
  const parseXml = function(xmlData) {
    xmlData = xmlData.replace(/\r\n?/g, "\n");
    const xmlObj = new XmlNode('!xml');
    let currentNode = xmlObj;
    let textData = "";
    let jPath = "";
    for(let i=0; i< xmlData.length; i++){
      const ch = xmlData[i];
      if(ch === '<'){
        if( xmlData[i+1] === '/') {
          const closeIndex = findClosingIndex(xmlData, ">", i, "Closing Tag is not closed.");
          let tagName = xmlData.substring(i+2,closeIndex).trim();
          if(this.options.removeNSPrefix){
            const colonIndex = tagName.indexOf(":");
            if(colonIndex !== -1){
              tagName = tagName.substr(colonIndex+1);
            }
          }
          if(this.options.transformTagName) {
            tagName = this.options.transformTagName(tagName);
          }
          if(currentNode){
            textData = this.saveTextToParentTag(textData, currentNode, jPath);
          }
          const lastTagName = jPath.substring(jPath.lastIndexOf(".")+1);
          if(tagName && this.options.unpairedTags.indexOf(tagName) !== -1 ){
            throw new Error(`Unpaired tag can not be used as closing tag: </${tagName}>`);
          }
          let propIndex = 0;
          if(lastTagName && this.options.unpairedTags.indexOf(lastTagName) !== -1 ){
            propIndex = jPath.lastIndexOf('.', jPath.lastIndexOf('.')-1);
            this.tagsNodeStack.pop();
          }else {
            propIndex = jPath.lastIndexOf(".");
          }
          jPath = jPath.substring(0, propIndex);
          currentNode = this.tagsNodeStack.pop();
          textData = "";
          i = closeIndex;
        } else if( xmlData[i+1] === '?') {
          let tagData = readTagExp(xmlData,i, false, "?>");
          if(!tagData) throw new Error("Pi Tag is not closed.");
          textData = this.saveTextToParentTag(textData, currentNode, jPath);
          if( (this.options.ignoreDeclaration && tagData.tagName === "?xml") || this.options.ignorePiTags);else {
            const childNode = new XmlNode(tagData.tagName);
            childNode.add(this.options.textNodeName, "");
            if(tagData.tagName !== tagData.tagExp && tagData.attrExpPresent){
              childNode[":@"] = this.buildAttributesMap(tagData.tagExp, jPath, tagData.tagName);
            }
            this.addChild(currentNode, childNode, jPath);
          }
          i = tagData.closeIndex + 1;
        } else if(xmlData.substr(i + 1, 3) === '!--') {
          const endIndex = findClosingIndex(xmlData, "-->", i+4, "Comment is not closed.");
          if(this.options.commentPropName){
            const comment = xmlData.substring(i + 4, endIndex - 2);
            textData = this.saveTextToParentTag(textData, currentNode, jPath);
            currentNode.add(this.options.commentPropName, [ { [this.options.textNodeName] : comment } ]);
          }
          i = endIndex;
        } else if( xmlData.substr(i + 1, 2) === '!D') {
          const result = readDocType(xmlData, i);
          this.docTypeEntities = result.entities;
          i = result.i;
        }else if(xmlData.substr(i + 1, 2) === '![') {
          const closeIndex = findClosingIndex(xmlData, "]]>", i, "CDATA is not closed.") - 2;
          const tagExp = xmlData.substring(i + 9,closeIndex);
          textData = this.saveTextToParentTag(textData, currentNode, jPath);
          let val = this.parseTextData(tagExp, currentNode.tagname, jPath, true, false, true, true);
          if(val == undefined) val = "";
          if(this.options.cdataPropName){
            currentNode.add(this.options.cdataPropName, [ { [this.options.textNodeName] : tagExp } ]);
          }else {
            currentNode.add(this.options.textNodeName, val);
          }
          i = closeIndex + 2;
        }else {
          let result = readTagExp(xmlData,i, this.options.removeNSPrefix);
          let tagName= result.tagName;
          const rawTagName = result.rawTagName;
          let tagExp = result.tagExp;
          let attrExpPresent = result.attrExpPresent;
          let closeIndex = result.closeIndex;
          if (this.options.transformTagName) {
            tagName = this.options.transformTagName(tagName);
          }
          if (currentNode && textData) {
            if(currentNode.tagname !== '!xml'){
              textData = this.saveTextToParentTag(textData, currentNode, jPath, false);
            }
          }
          const lastTag = currentNode;
          if(lastTag && this.options.unpairedTags.indexOf(lastTag.tagname) !== -1 ){
            currentNode = this.tagsNodeStack.pop();
            jPath = jPath.substring(0, jPath.lastIndexOf("."));
          }
          if(tagName !== xmlObj.tagname){
            jPath += jPath ? "." + tagName : tagName;
          }
          if (this.isItStopNode(this.options.stopNodes, jPath, tagName)) {
            let tagContent = "";
            if(tagExp.length > 0 && tagExp.lastIndexOf("/") === tagExp.length - 1){
              if(tagName[tagName.length - 1] === "/"){
                tagName = tagName.substr(0, tagName.length - 1);
                jPath = jPath.substr(0, jPath.length - 1);
                tagExp = tagName;
              }else {
                tagExp = tagExp.substr(0, tagExp.length - 1);
              }
              i = result.closeIndex;
            }
            else if(this.options.unpairedTags.indexOf(tagName) !== -1){
              i = result.closeIndex;
            }
            else {
              const result = this.readStopNodeData(xmlData, rawTagName, closeIndex + 1);
              if(!result) throw new Error(`Unexpected end of ${rawTagName}`);
              i = result.i;
              tagContent = result.tagContent;
            }
            const childNode = new XmlNode(tagName);
            if(tagName !== tagExp && attrExpPresent){
              childNode[":@"] = this.buildAttributesMap(tagExp, jPath, tagName);
            }
            if(tagContent) {
              tagContent = this.parseTextData(tagContent, tagName, jPath, true, attrExpPresent, true, true);
            }
            jPath = jPath.substr(0, jPath.lastIndexOf("."));
            childNode.add(this.options.textNodeName, tagContent);
            this.addChild(currentNode, childNode, jPath);
          }else {
            if(tagExp.length > 0 && tagExp.lastIndexOf("/") === tagExp.length - 1){
              if(tagName[tagName.length - 1] === "/"){
                tagName = tagName.substr(0, tagName.length - 1);
                jPath = jPath.substr(0, jPath.length - 1);
                tagExp = tagName;
              }else {
                tagExp = tagExp.substr(0, tagExp.length - 1);
              }
              if(this.options.transformTagName) {
                tagName = this.options.transformTagName(tagName);
              }
              const childNode = new XmlNode(tagName);
              if(tagName !== tagExp && attrExpPresent){
                childNode[":@"] = this.buildAttributesMap(tagExp, jPath, tagName);
              }
              this.addChild(currentNode, childNode, jPath);
              jPath = jPath.substr(0, jPath.lastIndexOf("."));
            }
            else {
              const childNode = new XmlNode( tagName);
              this.tagsNodeStack.push(currentNode);
              if(tagName !== tagExp && attrExpPresent){
                childNode[":@"] = this.buildAttributesMap(tagExp, jPath, tagName);
              }
              this.addChild(currentNode, childNode, jPath);
              currentNode = childNode;
            }
            textData = "";
            i = closeIndex;
          }
        }
      }else {
        textData += xmlData[i];
      }
    }
    return xmlObj.child;
  };
  function addChild(currentNode, childNode, jPath){
    const result = this.options.updateTag(childNode.tagname, jPath, childNode[":@"]);
    if(result === false);else if(typeof result === "string"){
      childNode.tagname = result;
      currentNode.addChild(childNode);
    }else {
      currentNode.addChild(childNode);
    }
  }
  const replaceEntitiesValue = function(val){
    if(this.options.processEntities){
      for(let entityName in this.docTypeEntities){
        const entity = this.docTypeEntities[entityName];
        val = val.replace( entity.regx, entity.val);
      }
      for(let entityName in this.lastEntities){
        const entity = this.lastEntities[entityName];
        val = val.replace( entity.regex, entity.val);
      }
      if(this.options.htmlEntities){
        for(let entityName in this.htmlEntities){
          const entity = this.htmlEntities[entityName];
          val = val.replace( entity.regex, entity.val);
        }
      }
      val = val.replace( this.ampEntity.regex, this.ampEntity.val);
    }
    return val;
  };
  function saveTextToParentTag(textData, currentNode, jPath, isLeafNode) {
    if (textData) {
      if(isLeafNode === undefined) isLeafNode = currentNode.child.length === 0;
      textData = this.parseTextData(textData,
        currentNode.tagname,
        jPath,
        false,
        currentNode[":@"] ? Object.keys(currentNode[":@"]).length !== 0 : false,
        isLeafNode);
      if (textData !== undefined && textData !== "")
        currentNode.add(this.options.textNodeName, textData);
      textData = "";
    }
    return textData;
  }
  function isItStopNode(stopNodes, jPath, currentTagName){
    const allNodesExp = "*." + currentTagName;
    for (const stopNodePath in stopNodes) {
      const stopNodeExp = stopNodes[stopNodePath];
      if( allNodesExp === stopNodeExp || jPath === stopNodeExp  ) return true;
    }
    return false;
  }
  function tagExpWithClosingIndex(xmlData, i, closingChar = ">"){
    let attrBoundary;
    let tagExp = "";
    for (let index = i; index < xmlData.length; index++) {
      let ch = xmlData[index];
      if (attrBoundary) {
          if (ch === attrBoundary) attrBoundary = "";
      } else if (ch === '"' || ch === "'") {
          attrBoundary = ch;
      } else if (ch === closingChar[0]) {
        if(closingChar[1]){
          if(xmlData[index + 1] === closingChar[1]){
            return {
              data: tagExp,
              index: index
            }
          }
        }else {
          return {
            data: tagExp,
            index: index
          }
        }
      } else if (ch === '\t') {
        ch = " ";
      }
      tagExp += ch;
    }
  }
  function findClosingIndex(xmlData, str, i, errMsg){
    const closingIndex = xmlData.indexOf(str, i);
    if(closingIndex === -1){
      throw new Error(errMsg)
    }else {
      return closingIndex + str.length - 1;
    }
  }
  function readTagExp(xmlData,i, removeNSPrefix, closingChar = ">"){
    const result = tagExpWithClosingIndex(xmlData, i+1, closingChar);
    if(!result) return;
    let tagExp = result.data;
    const closeIndex = result.index;
    const separatorIndex = tagExp.search(/\s/);
    let tagName = tagExp;
    let attrExpPresent = true;
    if(separatorIndex !== -1){
      tagName = tagExp.substring(0, separatorIndex);
      tagExp = tagExp.substring(separatorIndex + 1).trimStart();
    }
    const rawTagName = tagName;
    if(removeNSPrefix){
      const colonIndex = tagName.indexOf(":");
      if(colonIndex !== -1){
        tagName = tagName.substr(colonIndex+1);
        attrExpPresent = tagName !== result.data.substr(colonIndex + 1);
      }
    }
    return {
      tagName: tagName,
      tagExp: tagExp,
      closeIndex: closeIndex,
      attrExpPresent: attrExpPresent,
      rawTagName: rawTagName,
    }
  }
  function readStopNodeData(xmlData, tagName, i){
    const startIndex = i;
    let openTagCount = 1;
    for (; i < xmlData.length; i++) {
      if( xmlData[i] === "<"){
        if (xmlData[i+1] === "/") {
            const closeIndex = findClosingIndex(xmlData, ">", i, `${tagName} is not closed`);
            let closeTagName = xmlData.substring(i+2,closeIndex).trim();
            if(closeTagName === tagName){
              openTagCount--;
              if (openTagCount === 0) {
                return {
                  tagContent: xmlData.substring(startIndex, i),
                  i : closeIndex
                }
              }
            }
            i=closeIndex;
          } else if(xmlData[i+1] === '?') {
            const closeIndex = findClosingIndex(xmlData, "?>", i+1, "StopNode is not closed.");
            i=closeIndex;
          } else if(xmlData.substr(i + 1, 3) === '!--') {
            const closeIndex = findClosingIndex(xmlData, "-->", i+3, "StopNode is not closed.");
            i=closeIndex;
          } else if(xmlData.substr(i + 1, 2) === '![') {
            const closeIndex = findClosingIndex(xmlData, "]]>", i, "StopNode is not closed.") - 2;
            i=closeIndex;
          } else {
            const tagData = readTagExp(xmlData, i, '>');
            if (tagData) {
              const openTagName = tagData && tagData.tagName;
              if (openTagName === tagName && tagData.tagExp[tagData.tagExp.length-1] !== "/") {
                openTagCount++;
              }
              i=tagData.closeIndex;
            }
          }
        }
    }
  }
  function parseValue(val, shouldParse, options) {
    if (shouldParse && typeof val === 'string') {
      const newval = val.trim();
      if(newval === 'true' ) return true;
      else if(newval === 'false' ) return false;
      else return toNumber(val, options);
    } else {
      if (isExist(val)) {
        return val;
      } else {
        return '';
      }
    }
  }

  function prettify(node, options){
    return compress( node, options);
  }
  function compress(arr, options, jPath){
    let text;
    const compressedObj = {};
    for (let i = 0; i < arr.length; i++) {
      const tagObj = arr[i];
      const property = propName(tagObj);
      let newJpath = "";
      if(jPath === undefined) newJpath = property;
      else newJpath = jPath + "." + property;
      if(property === options.textNodeName){
        if(text === undefined) text = tagObj[property];
        else text += "" + tagObj[property];
      }else if(property === undefined){
        continue;
      }else if(tagObj[property]){
        let val = compress(tagObj[property], options, newJpath);
        const isLeaf = isLeafTag(val, options);
        if(tagObj[":@"]){
          assignAttributes( val, tagObj[":@"], newJpath, options);
        }else if(Object.keys(val).length === 1 && val[options.textNodeName] !== undefined && !options.alwaysCreateTextNode){
          val = val[options.textNodeName];
        }else if(Object.keys(val).length === 0){
          if(options.alwaysCreateTextNode) val[options.textNodeName] = "";
          else val = "";
        }
        if(compressedObj[property] !== undefined && compressedObj.hasOwnProperty(property)) {
          if(!Array.isArray(compressedObj[property])) {
              compressedObj[property] = [ compressedObj[property] ];
          }
          compressedObj[property].push(val);
        }else {
          if (options.isArray(property, newJpath, isLeaf )) {
            compressedObj[property] = [val];
          }else {
            compressedObj[property] = val;
          }
        }
      }
    }
    if(typeof text === "string"){
      if(text.length > 0) compressedObj[options.textNodeName] = text;
    }else if(text !== undefined) compressedObj[options.textNodeName] = text;
    return compressedObj;
  }
  function propName(obj){
    const keys = Object.keys(obj);
    for (let i = 0; i < keys.length; i++) {
      const key = keys[i];
      if(key !== ":@") return key;
    }
  }
  function assignAttributes(obj, attrMap, jpath, options){
    if (attrMap) {
      const keys = Object.keys(attrMap);
      const len = keys.length;
      for (let i = 0; i < len; i++) {
        const atrrName = keys[i];
        if (options.isArray(atrrName, jpath + "." + atrrName, true, true)) {
          obj[atrrName] = [ attrMap[atrrName] ];
        } else {
          obj[atrrName] = attrMap[atrrName];
        }
      }
    }
  }
  function isLeafTag(obj, options){
    const { textNodeName } = options;
    const propCount = Object.keys(obj).length;
    if (propCount === 0) {
      return true;
    }
    if (
      propCount === 1 &&
      (obj[textNodeName] || typeof obj[textNodeName] === "boolean" || obj[textNodeName] === 0)
    ) {
      return true;
    }
    return false;
  }

  class XMLParser{
      constructor(options){
          this.externalEntities = {};
          this.options = buildOptions(options);
      }
      parse(xmlData,validationOption){
          if(typeof xmlData === "string");else if( xmlData.toString){
              xmlData = xmlData.toString();
          }else {
              throw new Error("XML data is accepted in String or Bytes[] form.")
          }
          if( validationOption){
              if(validationOption === true) validationOption = {};
              const result = validate(xmlData, validationOption);
              if (result !== true) {
                throw Error( `${result.err.msg}:${result.err.line}:${result.err.col}` )
              }
            }
          const orderedObjParser = new OrderedObjParser(this.options);
          orderedObjParser.addExternalEntities(this.externalEntities);
          const orderedResult = orderedObjParser.parseXml(xmlData);
          if(this.options.preserveOrder || orderedResult === undefined) return orderedResult;
          else return prettify(orderedResult, this.options);
      }
      addEntity(key, value){
          if(value.indexOf("&") !== -1){
              throw new Error("Entity value can't have '&'")
          }else if(key.indexOf("&") !== -1 || key.indexOf(";") !== -1){
              throw new Error("An entity must be set without '&' and ';'. Eg. use '#xD' for '&#xD;'")
          }else if(value === "&"){
              throw new Error("An entity with value '&' is not permitted");
          }else {
              this.externalEntities[key] = value;
          }
      }
  }

  const entitiesReplacements = [
      { regex: /&(amp|#38|#x26);/g, val: '&' },
      { regex: /&(apos|#39|#x27);/g, val: "'" },
      { regex: /&#(xa|xA|10);/g, val: '\n' },
      { regex: /&(gt|#62|#x3e|#x3E);/g, val: '>' },
      { regex: /&(lt|#60|#x3c|#x3C);/g, val: '<' },
      { regex: /&(quot|#34|#x22);/g, val: '"' },
  ];
  const nodesWithNumericAttributes = new Set(['BPMNShape.Bounds', 'BPMNShape.BPMNLabel.Bounds', 'BPMNEdge.BPMNLabel.Bounds', 'BPMNEdge.waypoint'].map(element => `definitions.BPMNDiagram.BPMNPlane.${element}`));
  const numericAttributes = new Set(['x', 'y', 'width', 'height']);
  const isNumeric = (attributeName, nodePath) => {
      return nodesWithNumericAttributes.has(nodePath) && numericAttributes.has(attributeName);
  };
  class BpmnXmlParser {
      constructor(options) {
          Object.defineProperty(this, "options", {
              enumerable: true,
              configurable: true,
              writable: true,
              value: options
          });
          Object.defineProperty(this, "x2jOptions", {
              enumerable: true,
              configurable: true,
              writable: true,
              value: {
                  attributeNamePrefix: '',
                  removeNSPrefix: true,
                  ignoreAttributes: false,
                  parseAttributeValue: true,
                  processEntities: false,
                  attributeValueProcessor: (name, value, nodePath) => {
                      if (isNumeric(name, nodePath)) {
                          return Number(value);
                      }
                      return this.processAttribute(value);
                  },
              }
          });
          Object.defineProperty(this, "xmlParser", {
              enumerable: true,
              configurable: true,
              writable: true,
              value: new XMLParser(this.x2jOptions)
          });
      }
      parse(xml) {
          let model;
          try {
              model = this.xmlParser.parse(xml);
          }
          catch (_a) {
              throw new Error('XML parsing failed. Invalid BPMN source.');
          }
          if (!model.definitions) {
              throw new Error(`XML parsing failed. Unable to retrieve 'definitions' from the BPMN source.`);
          }
          return model;
      }
      processAttribute(value) {
          var _a;
          for (const replacement of entitiesReplacements) {
              value = value.replace(replacement.regex, replacement.val);
          }
          if ((_a = this.options) === null || _a === void 0 ? void 0 : _a.additionalXmlAttributeProcessor) {
              value = this.options.additionalXmlAttributeProcessor(value);
          }
          return value;
      }
  }

  class BpmnParser {
      constructor(jsonParser, xmlParser) {
          Object.defineProperty(this, "jsonParser", {
              enumerable: true,
              configurable: true,
              writable: true,
              value: jsonParser
          });
          Object.defineProperty(this, "xmlParser", {
              enumerable: true,
              configurable: true,
              writable: true,
              value: xmlParser
          });
      }
      parse(bpmnAsXml) {
          const json = this.xmlParser.parse(bpmnAsXml);
          return this.jsonParser.parse(json);
      }
  }
  function newBpmnParser(options) {
      return new BpmnParser(newBpmnJsonParser(new ParsingMessageCollector(options)), new BpmnXmlParser(options));
  }

  function createNewCssClassesUpdater(graph) {
      return new CssClassesUpdater(graph);
  }
  class CssClassesUpdater {
      constructor(graph) {
          Object.defineProperty(this, "graph", {
              enumerable: true,
              configurable: true,
              writable: true,
              value: graph
          });
      }
      updateAndRefreshCssClassesOfCell(bpmnElementId, cssClasses) {
          this.updateAndRefreshCssClassesOfElement(bpmnElementId, cssClasses);
          this.updateAndRefreshCssClassesOfElement(messageFlowIconId(bpmnElementId), cssClasses);
      }
      updateAndRefreshCssClassesOfElement(elementId, cssClasses) {
          const model = this.graph.getModel();
          const cell = model.getCell(elementId);
          if (!cell) {
              return;
          }
          let cellStyle = cell.getStyle();
          cellStyle = setStyle(cellStyle, BpmnStyleIdentifier.EXTRA_CSS_CLASSES, cssClasses.join(','));
          model.setStyle(cell, cellStyle);
      }
  }

  function createNewCssRegistry(graph) {
      return new CssClassesRegistryImpl(createNewCssClassesUpdater(graph), new CssClassesCache());
  }
  class CssClassesRegistryImpl {
      constructor(cssClassesUpdater, cssClassesCache) {
          Object.defineProperty(this, "cssClassesUpdater", {
              enumerable: true,
              configurable: true,
              writable: true,
              value: cssClassesUpdater
          });
          Object.defineProperty(this, "cssClassesCache", {
              enumerable: true,
              configurable: true,
              writable: true,
              value: cssClassesCache
          });
      }
      clearCache() {
          this.cssClassesCache.clear();
      }
      addCssClasses(bpmnElementIds, classNames) {
          this.updateCssClasses(bpmnElementIds, classNames, this.cssClassesCache.addClassNames);
      }
      removeCssClasses(bpmnElementIds, classNames) {
          this.updateCssClasses(bpmnElementIds, classNames, this.cssClassesCache.removeClassNames);
      }
      removeAllCssClasses(bpmnElementIds) {
          if (bpmnElementIds || bpmnElementIds == '') {
              for (const bpmnElementId of ensureIsArray(bpmnElementIds)) {
                  const isChanged = this.cssClassesCache.removeAllClassNames(bpmnElementId);
                  this.updateCellIfChanged(isChanged, bpmnElementId);
              }
          }
          else {
              const bpmnIds = this.cssClassesCache.getBpmnIds();
              this.cssClassesCache.clear();
              for (const bpmnElementId of bpmnIds)
                  this.updateCellIfChanged(true, bpmnElementId);
          }
      }
      toggleCssClasses(bpmnElementIds, classNames) {
          this.updateCssClasses(bpmnElementIds, classNames, this.cssClassesCache.toggleClassNames);
      }
      updateCssClasses(bpmnElementIds, classNames, updateClassNames) {
          const arrayClassNames = ensureIsArray(classNames);
          for (const bpmnElementId of ensureIsArray(bpmnElementIds))
              this.updateCellIfChanged(updateClassNames(bpmnElementId, arrayClassNames), bpmnElementId);
      }
      updateCellIfChanged(updateCell, bpmnElementId) {
          if (updateCell) {
              const allClassNames = this.cssClassesCache.getClassNames(bpmnElementId);
              this.cssClassesUpdater.updateAndRefreshCssClassesOfCell(bpmnElementId, allClassNames);
          }
      }
  }
  class CssClassesCache {
      constructor() {
          Object.defineProperty(this, "classNamesByBpmnId", {
              enumerable: true,
              configurable: true,
              writable: true,
              value: new Map()
          });
          Object.defineProperty(this, "clear", {
              enumerable: true,
              configurable: true,
              writable: true,
              value: () => {
                  this.classNamesByBpmnId.clear();
              }
          });
          Object.defineProperty(this, "addClassNames", {
              enumerable: true,
              configurable: true,
              writable: true,
              value: (bpmnElementId, classNames) => this.updateClassNames(bpmnElementId, classNames, (currentClassNames, className) => currentClassNames.add(className))
          });
          Object.defineProperty(this, "removeClassNames", {
              enumerable: true,
              configurable: true,
              writable: true,
              value: (bpmnElementId, classNames) => this.updateClassNames(bpmnElementId, classNames, (currentClassNames, className) => currentClassNames.delete(className))
          });
          Object.defineProperty(this, "toggleClassNames", {
              enumerable: true,
              configurable: true,
              writable: true,
              value: (bpmnElementId, classNames) => {
                  this.updateClassNames(bpmnElementId, classNames, (currentClassNames, className) => currentClassNames.has(className) ? currentClassNames.delete(className) : currentClassNames.add(className));
                  return classNames && classNames.length > 0;
              }
          });
      }
      getClassNames(bpmnElementId) {
          return this.classNamesByBpmnId.has(bpmnElementId) ? [...this.classNamesByBpmnId.get(bpmnElementId)] : [];
      }
      getBpmnIds() {
          return [...this.classNamesByBpmnId.keys()];
      }
      removeAllClassNames(bpmnElementId) {
          const currentClassNames = this.getOrInitializeClassNames(bpmnElementId);
          const initialClassNamesNumber = currentClassNames.size;
          currentClassNames.clear();
          return currentClassNames.size < initialClassNamesNumber;
      }
      updateClassNames(bpmnElementId, classNames, manageClassNames) {
          const currentClassNames = this.getOrInitializeClassNames(bpmnElementId);
          const initialClassNamesNumber = currentClassNames.size;
          for (const className of ensureIsArray(classNames))
              manageClassNames(currentClassNames, className);
          return currentClassNames.size != initialClassNamesNumber;
      }
      getOrInitializeClassNames(bpmnElementId) {
          let classNames = this.classNamesByBpmnId.get(bpmnElementId);
          if (classNames == null) {
              classNames = new Set();
              this.classNamesByBpmnId.set(bpmnElementId, classNames);
          }
          return classNames;
      }
  }

  const overlayPositions = new Map([
      ['start', { horizontalAlign: 'left', verticalAlign: 'top' }],
      ['middle', { horizontalAlign: 'center', verticalAlign: 'top' }],
      ['end', { horizontalAlign: 'right', verticalAlign: 'top' }],
      ['top-left', { horizontalAlign: 'left', verticalAlign: 'top' }],
      ['top-right', { horizontalAlign: 'right', verticalAlign: 'top' }],
      ['top-center', { horizontalAlign: 'center', verticalAlign: 'top' }],
      ['bottom-left', { horizontalAlign: 'left', verticalAlign: 'bottom' }],
      ['bottom-right', { horizontalAlign: 'right', verticalAlign: 'bottom' }],
      ['bottom-center', { horizontalAlign: 'center', verticalAlign: 'bottom' }],
      ['middle-left', { horizontalAlign: 'left', verticalAlign: 'middle' }],
      ['middle-right', { horizontalAlign: 'right', verticalAlign: 'middle' }],
  ]);
  const convertPosition = (overlay) => overlayPositions.get(overlay.position);
  const convertFill = (convertedStyle, apiFill) => {
      var _a, _b;
      if (apiFill) {
          convertedStyle.fill.color = (_a = apiFill.color) !== null && _a !== void 0 ? _a : convertedStyle.fill.color;
          convertedStyle.fill.opacity = (_b = apiFill.opacity) !== null && _b !== void 0 ? _b : convertedStyle.fill.opacity;
      }
  };
  const convertStroke = (convertedStyle, apiStroke) => {
      var _a, _b;
      if (apiStroke) {
          convertedStyle.stroke.color = (_a = apiStroke.color) !== null && _a !== void 0 ? _a : convertedStyle.stroke.color;
          convertedStyle.stroke.width = (_b = apiStroke.width) !== null && _b !== void 0 ? _b : convertedStyle.stroke.width;
      }
  };
  const convertFont = (convertedStyle, apiFont) => {
      var _a, _b;
      if (apiFont) {
          convertedStyle.font.color = (_a = apiFont.color) !== null && _a !== void 0 ? _a : convertedStyle.font.color;
          convertedStyle.font.size = (_b = apiFont.size) !== null && _b !== void 0 ? _b : convertedStyle.font.size;
      }
  };
  const convertStyle = (overlay) => {
      const defaultStyle = {
          fill: { color: StyleDefault.DEFAULT_OVERLAY_FILL_COLOR.valueOf(), opacity: StyleDefault.DEFAULT_OVERLAY_FILL_OPACITY.valueOf() },
          stroke: { color: StyleDefault.DEFAULT_OVERLAY_STROKE_COLOR.valueOf(), width: StyleDefault.DEFAULT_OVERLAY_STROKE_WIDTH.valueOf() },
          font: { color: StyleDefault.DEFAULT_OVERLAY_FONT_COLOR.valueOf(), size: StyleDefault.DEFAULT_OVERLAY_FONT_SIZE.valueOf() },
      };
      const style = overlay.style;
      const convertedStyle = Object.assign({}, defaultStyle);
      if (!style) {
          return convertedStyle;
      }
      convertFill(convertedStyle, style.fill);
      convertStroke(convertedStyle, style.stroke);
      convertFont(convertedStyle, style.font);
      return convertedStyle;
  };
  class OverlayConverter {
      convert(overlay) {
          const position = convertPosition(overlay);
          const style = convertStyle(overlay);
          return { position, style };
      }
  }

  function createNewOverlaysUpdater(graph) {
      return new OverlaysUpdater(graph, new OverlayConverter());
  }
  class OverlaysUpdater {
      constructor(graph, overlayConverter) {
          Object.defineProperty(this, "graph", {
              enumerable: true,
              configurable: true,
              writable: true,
              value: graph
          });
          Object.defineProperty(this, "overlayConverter", {
              enumerable: true,
              configurable: true,
              writable: true,
              value: overlayConverter
          });
      }
      addOverlays(bpmnElementId, overlays) {
          const cell = this.graph.getModel().getCell(bpmnElementId);
          if (!cell) {
              return;
          }
          for (const overlay of ensureIsArray(overlays)) {
              const bpmnOverlay = new MxGraphCustomOverlay(overlay.label, this.overlayConverter.convert(overlay));
              this.graph.addCellOverlay(cell, bpmnOverlay);
          }
      }
      removeAllOverlays(bpmnElementId) {
          const cell = this.graph.getModel().getCell(bpmnElementId);
          if (!cell) {
              return;
          }
          this.graph.removeCellOverlays(cell);
      }
  }

  function createNewOverlaysRegistry(graph) {
      return new OverlaysRegistryImpl(createNewOverlaysUpdater(graph));
  }
  class OverlaysRegistryImpl {
      constructor(overlaysUpdater) {
          Object.defineProperty(this, "overlaysUpdater", {
              enumerable: true,
              configurable: true,
              writable: true,
              value: overlaysUpdater
          });
      }
      addOverlays(bpmnElementId, overlays) {
          this.overlaysUpdater.addOverlays(bpmnElementId, overlays);
      }
      removeAllOverlays(bpmnElementId) {
          this.overlaysUpdater.removeAllOverlays(bpmnElementId);
      }
  }

  class BpmnQuerySelectors {
      element(bpmnElementId) {
          return `svg > g > g > g[data-bpmn-id="${bpmnElementId}"]`;
      }
      elementsOfKind(bpmnKindCssClassname) {
          return `svg > g > g > g.${bpmnKindCssClassname}:not(.bpmn-label)`;
      }
  }

  function createNewStyleUpdater(graph) {
      return new StyleUpdater(graph, new StyleManager(graph.getModel()));
  }
  const withCellIdsOfMessageFlowIcons = (bpmnElementIds) => {
      const cellIds = ensureIsArray(bpmnElementIds);
      cellIds.push(...cellIds.map(id => messageFlowIconId(id)));
      return cellIds;
  };
  class StyleUpdater {
      constructor(graph, styleManager) {
          Object.defineProperty(this, "graph", {
              enumerable: true,
              configurable: true,
              writable: true,
              value: graph
          });
          Object.defineProperty(this, "styleManager", {
              enumerable: true,
              configurable: true,
              writable: true,
              value: styleManager
          });
      }
      clear() {
          this.styleManager.clear();
      }
      updateStyle(bpmnElementIds, styleUpdate) {
          if (!styleUpdate) {
              return;
          }
          const model = this.graph.getModel();
          const cells = withCellIdsOfMessageFlowIcons(bpmnElementIds)
              .map(id => model.getCell(id))
              .filter(Boolean);
          if (cells.length === 0) {
              return;
          }
          this.graph.batchUpdate(() => {
              for (const cell of cells) {
                  this.styleManager.ensureStyleIsStored(cell);
                  let cellStyle = cell.getStyle();
                  cellStyle = setStyle(cellStyle, mxConstants.STYLE_OPACITY, styleUpdate.opacity, ensureOpacityValue);
                  cellStyle = updateStroke(cellStyle, styleUpdate.stroke);
                  cellStyle = updateFont(cellStyle, styleUpdate.font);
                  if (isShapeStyleUpdate(styleUpdate)) {
                      cellStyle = updateFill(cellStyle, styleUpdate.fill);
                  }
                  model.setStyle(cell, cellStyle);
              }
          });
      }
      resetStyle(bpmnElementIds) {
          this.graph.batchUpdate(() => {
              if (bpmnElementIds || bpmnElementIds == '') {
                  for (const id of withCellIdsOfMessageFlowIcons(bpmnElementIds)) {
                      this.styleManager.resetStyleIfIsStored(id);
                  }
              }
              else {
                  this.styleManager.resetAllStyles();
              }
          });
      }
  }
  const cssClassesStyleIdentifier = BpmnStyleIdentifier.EXTRA_CSS_CLASSES;
  class StyleManager {
      constructor(model) {
          Object.defineProperty(this, "model", {
              enumerable: true,
              configurable: true,
              writable: true,
              value: model
          });
          Object.defineProperty(this, "stylesCache", {
              enumerable: true,
              configurable: true,
              writable: true,
              value: new Map()
          });
      }
      clear() {
          this.stylesCache.clear();
      }
      resetAllStyles() {
          for (const cellId of this.stylesCache.keys()) {
              this.resetStyle(cellId, this.stylesCache.get(cellId));
          }
      }
      resetStyleIfIsStored(cellId) {
          const style = this.stylesCache.get(cellId);
          if (style) {
              this.resetStyle(cellId, style);
          }
      }
      resetStyle(cellId, initialStyle) {
          const cell = this.model.getCell(cellId);
          const cssClasses = getStyleValue(cell.getStyle(), cssClassesStyleIdentifier, '');
          const styleWithCssClasses = setStyle(initialStyle, cssClassesStyleIdentifier, cssClasses);
          this.model.setStyle(cell, styleWithCssClasses);
          this.stylesCache.delete(cellId);
      }
      ensureStyleIsStored(cell) {
          const cellId = cell.getId();
          if (!this.stylesCache.has(cellId)) {
              this.stylesCache.set(cellId, cell.getStyle());
          }
      }
  }

  function createNewStyleRegistry(graph) {
      return new StyleRegistryImpl(createNewStyleUpdater(graph));
  }
  class StyleRegistryImpl {
      constructor(styleUpdater) {
          Object.defineProperty(this, "styleUpdater", {
              enumerable: true,
              configurable: true,
              writable: true,
              value: styleUpdater
          });
      }
      clearCache() {
          this.styleUpdater.clear();
      }
      updateStyle(bpmnElementIds, styleUpdate) {
          this.styleUpdater.updateStyle(bpmnElementIds, styleUpdate);
      }
      resetStyle(bpmnElementIds) {
          this.styleUpdater.resetStyle(bpmnElementIds);
      }
  }

  function createNewBpmnElementsRegistry(bpmnModelRegistry, graph) {
      return new BpmnElementsRegistry(bpmnModelRegistry, new HtmlElementRegistry(graph.container, new BpmnQuerySelectors()), createNewCssRegistry(graph), createNewOverlaysRegistry(graph), createNewStyleRegistry(graph));
  }
  class BpmnElementsRegistry {
      constructor(bpmnModelRegistry, htmlElementRegistry, cssClassesRegistry, overlaysRegistry, styleRegistry) {
          Object.defineProperty(this, "bpmnModelRegistry", {
              enumerable: true,
              configurable: true,
              writable: true,
              value: bpmnModelRegistry
          });
          Object.defineProperty(this, "htmlElementRegistry", {
              enumerable: true,
              configurable: true,
              writable: true,
              value: htmlElementRegistry
          });
          Object.defineProperty(this, "cssClassesRegistry", {
              enumerable: true,
              configurable: true,
              writable: true,
              value: cssClassesRegistry
          });
          Object.defineProperty(this, "overlaysRegistry", {
              enumerable: true,
              configurable: true,
              writable: true,
              value: overlaysRegistry
          });
          Object.defineProperty(this, "styleRegistry", {
              enumerable: true,
              configurable: true,
              writable: true,
              value: styleRegistry
          });
          this.bpmnModelRegistry.registerOnLoadCallback(() => {
              this.cssClassesRegistry.clearCache();
              this.styleRegistry.clearCache();
          });
      }
      getModelElementsByIds(bpmnElementIds) {
          return filterDuplicates(bpmnElementIds)
              .map(id => this.bpmnModelRegistry.getBpmnSemantic(id))
              .filter(Boolean);
      }
      getElementsByIds(bpmnElementIds) {
          return this.getModelElementsByIds(bpmnElementIds).map(bpmnSemantic => ({
              bpmnSemantic: bpmnSemantic,
              htmlElement: this.htmlElementRegistry.getBpmnHtmlElement(bpmnSemantic.id),
          }));
      }
      getModelElementsByKinds(bpmnKinds) {
          return filterDuplicates(bpmnKinds)
              .flatMap(kind => this.htmlElementRegistry.getBpmnHtmlElements(kind))
              .map(htmlElement => this.getRelatedBpmnSemantic(htmlElement));
      }
      getElementsByKinds(bpmnKinds) {
          return filterDuplicates(bpmnKinds)
              .flatMap(kind => this.htmlElementRegistry.getBpmnHtmlElements(kind))
              .map(htmlElement => ({ htmlElement, bpmnSemantic: this.getRelatedBpmnSemantic(htmlElement) }));
      }
      getRelatedBpmnSemantic(htmlElement) {
          return this.bpmnModelRegistry.getBpmnSemantic(htmlElement.dataset.bpmnId);
      }
      addCssClasses(bpmnElementIds, classNames) {
          this.cssClassesRegistry.addCssClasses(bpmnElementIds, classNames);
      }
      removeCssClasses(bpmnElementIds, classNames) {
          this.cssClassesRegistry.removeCssClasses(bpmnElementIds, classNames);
      }
      removeAllCssClasses(bpmnElementIds) {
          this.cssClassesRegistry.removeAllCssClasses(bpmnElementIds);
      }
      toggleCssClasses(bpmnElementIds, classNames) {
          this.cssClassesRegistry.toggleCssClasses(bpmnElementIds, classNames);
      }
      addOverlays(bpmnElementId, overlays) {
          this.overlaysRegistry.addOverlays(bpmnElementId, overlays);
      }
      removeAllOverlays(bpmnElementId) {
          this.overlaysRegistry.removeAllOverlays(bpmnElementId);
      }
      updateStyle(bpmnElementIds, styleUpdate) {
          this.styleRegistry.updateStyle(bpmnElementIds, styleUpdate);
      }
      resetStyle(bpmnElementIds) {
          this.styleRegistry.resetStyle(bpmnElementIds);
      }
  }
  class HtmlElementRegistry {
      constructor(container, querySelectors) {
          Object.defineProperty(this, "container", {
              enumerable: true,
              configurable: true,
              writable: true,
              value: container
          });
          Object.defineProperty(this, "querySelectors", {
              enumerable: true,
              configurable: true,
              writable: true,
              value: querySelectors
          });
      }
      getBpmnHtmlElement(bpmnElementId) {
          return this.container.querySelector(this.querySelectors.element(bpmnElementId));
      }
      getBpmnHtmlElements(bpmnElementKind) {
          const selectors = this.querySelectors.elementsOfKind(computeBpmnBaseClassName(bpmnElementKind));
          return [...this.container.querySelectorAll(selectors)];
      }
  }
  const filterDuplicates = (ids) => [...new Set(ensureIsArray(ids))];

  class ModelFiltering {
      filter(bpmnModel, modelFilter) {
          const poolIdsFilter = [];
          const poolNamesFilter = [];
          for (const filter of ensureIsArray(modelFilter === null || modelFilter === void 0 ? void 0 : modelFilter.pools).filter(p => p && Object.keys(p).length > 0))
              filter.id ? poolIdsFilter.push(filter.id) : filter.name && poolNamesFilter.push(filter.name);
          if (poolIdsFilter.length === 0 && poolNamesFilter.length === 0) {
              return bpmnModel;
          }
          const { filteredPools, filteredPoolIds } = filterPools(bpmnModel, poolIdsFilter, poolNamesFilter);
          const filteredPoolAndBlackPoolIds = [...poolIdsFilter, ...filteredPoolIds];
          const { filteredLanes, filteredLaneIds, filteredFlowNodes, filteredFlowNodeIds } = filterLanesAndFlowNodes(bpmnModel.lanes, bpmnModel.flowNodes, filteredPoolAndBlackPoolIds);
          const filteredEdges = filterEdges(bpmnModel.edges, [...filteredPoolAndBlackPoolIds, ...filteredLaneIds, ...filteredFlowNodeIds]);
          if (filteredPools.length === 0 && filteredLanes.length === 0 && filteredFlowNodes.length === 0 && filteredEdges.length === 0) {
              let errorMessageSuffix = poolIdsFilter.length > 0 ? ` for ids [${poolIdsFilter}]` : '';
              const messageSeparator = errorMessageSuffix ? ' and' : '';
              errorMessageSuffix += poolNamesFilter.length > 0 ? `${messageSeparator} for names [${poolNamesFilter}]` : '';
              throw new Error('No matching pools' + errorMessageSuffix);
          }
          return { lanes: filteredLanes, flowNodes: filteredFlowNodes, pools: filteredPools, edges: filteredEdges };
      }
  }
  function filterPools(bpmnModel, poolIdsFilter, poolNamesFilter) {
      const filteredPools = bpmnModel.pools.filter(pool => poolIdsFilter.includes(pool.bpmnElement.id) || poolNamesFilter.includes(pool.bpmnElement.name));
      const filteredPoolIds = filteredPools.map(shape => shape.bpmnElement.id);
      return { filteredPools, filteredPoolIds };
  }
  function filterLanesAndFlowNodes(lanes, flowNodes, parentIdsToFilter) {
      const { filteredLanes, filteredLaneIds } = filterLanes(lanes, parentIdsToFilter);
      const { filteredLanes: filteredSubLanes, filteredLaneIds: filteredSubLanesIds, filteredFlowNodes, filteredFlowNodeIds, } = filterFlowNodes(flowNodes, [...parentIdsToFilter, ...filteredLaneIds], lanes);
      filteredLanes.push(...filteredSubLanes);
      filteredLaneIds.push(...filteredSubLanesIds);
      return { filteredLanes, filteredLaneIds, filteredFlowNodes, filteredFlowNodeIds };
  }
  function filterLanes(lanes, parentIdsToFilter) {
      const filteredLanes = lanes.filter(shape => parentIdsToFilter.includes(shape.bpmnElement.parentId));
      const filteredLaneIds = filteredLanes.map(shape => shape.bpmnElement.id);
      if (filteredLanes.length > 0) {
          const { filteredLanes: filteredSubLanes, filteredLaneIds: filteredSubLaneIds } = filterLanes(lanes, filteredLaneIds);
          filteredLanes.push(...filteredSubLanes);
          filteredLaneIds.push(...filteredSubLaneIds);
      }
      return { filteredLanes, filteredLaneIds };
  }
  function filterFlowNodes(flowNodes, parentIdsToFilter, lanes) {
      const filteredFlowNodes = flowNodes.filter(shape => parentIdsToFilter.includes(shape.bpmnElement.parentId));
      if (filteredFlowNodes.length === 0) {
          return { filteredLanes: [], filteredLaneIds: [], filteredFlowNodes: [], filteredFlowNodeIds: [] };
      }
      const filteredFlowNodeIds = filteredFlowNodes.map(shape => shape.bpmnElement.id);
      const { filteredLanes, filteredLaneIds, filteredFlowNodes: filteredChildFlowNodes, filteredFlowNodeIds: filteredChildFlowNodeIds, } = filterLanesAndFlowNodes(lanes, flowNodes, filteredFlowNodeIds);
      filteredFlowNodes.push(...filteredChildFlowNodes);
      filteredFlowNodeIds.push(...filteredChildFlowNodeIds);
      return { filteredLanes, filteredLaneIds, filteredFlowNodes, filteredFlowNodeIds };
  }
  function filterEdges(edges, filteredElementIds) {
      return edges.filter(edge => filteredElementIds.includes(edge.bpmnElement.sourceReferenceId) && filteredElementIds.includes(edge.bpmnElement.targetReferenceId));
  }

  class BpmnModelRegistry {
      constructor() {
          Object.defineProperty(this, "searchableModel", {
              enumerable: true,
              configurable: true,
              writable: true,
              value: void 0
          });
          Object.defineProperty(this, "onLoadCallback", {
              enumerable: true,
              configurable: true,
              writable: true,
              value: void 0
          });
      }
      load(bpmnModel, modelFilter) {
          var _a;
          const filteredModel = new ModelFiltering().filter(bpmnModel, modelFilter);
          this.searchableModel = new SearchableModel(filteredModel);
          (_a = this.onLoadCallback) === null || _a === void 0 ? void 0 : _a.call(this);
          return toRenderedModel(filteredModel);
      }
      registerOnLoadCallback(callback) {
          this.onLoadCallback = callback;
      }
      getBpmnSemantic(bpmnElementId) {
          var _a;
          const element = (_a = this.searchableModel) === null || _a === void 0 ? void 0 : _a.elementById(bpmnElementId);
          if (!element) {
              return undefined;
          }
          const bpmnElement = element.bpmnElement;
          const isShape = bpmnElement instanceof ShapeBpmnElement;
          return Object.assign({ id: bpmnElementId, isShape: isShape, kind: bpmnElement.kind, name: bpmnElement.name }, (bpmnElement instanceof Flow
              ? {
                  sourceRefId: bpmnElement.sourceReferenceId,
                  targetRefId: bpmnElement.targetReferenceId,
              }
              : {
                  callActivityGlobalTaskKind: bpmnElement instanceof ShapeBpmnCallActivity ? bpmnElement.globalTaskKind : undefined,
                  callActivityKind: bpmnElement instanceof ShapeBpmnCallActivity ? bpmnElement.callActivityKind : undefined,
                  eventDefinitionKind: bpmnElement instanceof ShapeBpmnEvent ? bpmnElement.eventDefinitionKind : undefined,
                  linkEventSourceIds: bpmnElement instanceof ShapeBpmnIntermediateCatchEvent && bpmnElement.eventDefinitionKind == exports.ShapeBpmnEventDefinitionKind.LINK ? bpmnElement.sourceIds : undefined,
                  linkEventTargetId: bpmnElement instanceof ShapeBpmnIntermediateThrowEvent ? bpmnElement.targetId : undefined,
                  incomingIds: bpmnElement.incomingIds,
                  outgoingIds: bpmnElement.outgoingIds,
                  parentId: bpmnElement.parentId,
                  subProcessKind: bpmnElement instanceof ShapeBpmnSubProcess ? bpmnElement.subProcessKind : undefined,
              }));
      }
  }
  function toRenderedModel(bpmnModel) {
      const collapsedSubProcessIds = new Set(bpmnModel.flowNodes
          .filter(shape => {
          const bpmnElement = shape.bpmnElement;
          return ShapeUtil.isSubProcess(bpmnElement.kind) && bpmnElement.markers.includes(exports.ShapeBpmnMarkerKind.EXPAND);
      })
          .map(shape => shape.bpmnElement.id));
      const subprocesses = [];
      const boundaryEvents = [];
      const otherFlowNodes = [];
      for (const shape of bpmnModel.flowNodes) {
          const kind = shape.bpmnElement.kind;
          if (ShapeUtil.isSubProcess(kind)) {
              subprocesses.push(shape);
          }
          else if (ShapeUtil.isBoundaryEvent(kind)) {
              boundaryEvents.push(shape);
          }
          else if (!collapsedSubProcessIds.has(shape.bpmnElement.parentId)) {
              otherFlowNodes.push(shape);
          }
      }
      return { boundaryEvents: boundaryEvents, edges: bpmnModel.edges, lanes: bpmnModel.lanes, otherFlowNodes: otherFlowNodes, pools: bpmnModel.pools, subprocesses: subprocesses };
  }
  class SearchableModel {
      constructor(bpmnModel) {
          Object.defineProperty(this, "elements", {
              enumerable: true,
              configurable: true,
              writable: true,
              value: new Map()
          });
          for (const shapeOrEdge of [...bpmnModel.pools, ...bpmnModel.lanes, ...bpmnModel.flowNodes, ...bpmnModel.edges]) {
              this.elements.set(shapeOrEdge.bpmnElement.id, shapeOrEdge);
          }
      }
      elementById(id) {
          return this.elements.get(id);
      }
  }

  class BpmnVisualization {
      constructor(options) {
          Object.defineProperty(this, "graph", {
              enumerable: true,
              configurable: true,
              writable: true,
              value: void 0
          });
          Object.defineProperty(this, "navigation", {
              enumerable: true,
              configurable: true,
              writable: true,
              value: void 0
          });
          Object.defineProperty(this, "bpmnElementsRegistry", {
              enumerable: true,
              configurable: true,
              writable: true,
              value: void 0
          });
          Object.defineProperty(this, "bpmnModelRegistry", {
              enumerable: true,
              configurable: true,
              writable: true,
              value: void 0
          });
          Object.defineProperty(this, "parserOptions", {
              enumerable: true,
              configurable: true,
              writable: true,
              value: void 0
          });
          Object.defineProperty(this, "rendererOptions", {
              enumerable: true,
              configurable: true,
              writable: true,
              value: void 0
          });
          this.rendererOptions = options === null || options === void 0 ? void 0 : options.renderer;
          const configurator = new GraphConfigurator(htmlElement(options === null || options === void 0 ? void 0 : options.container));
          this.graph = configurator.configure(options);
          this.navigation = new Navigation(this.graph);
          this.bpmnModelRegistry = new BpmnModelRegistry();
          this.bpmnElementsRegistry = createNewBpmnElementsRegistry(this.bpmnModelRegistry, this.graph);
          this.parserOptions = options === null || options === void 0 ? void 0 : options.parser;
      }
      load(xml, options) {
          const bpmnModel = newBpmnParser(this.parserOptions).parse(xml);
          const renderedModel = this.bpmnModelRegistry.load(bpmnModel, options === null || options === void 0 ? void 0 : options.modelFilter);
          newBpmnRenderer(this.graph, this.rendererOptions).render(renderedModel, options === null || options === void 0 ? void 0 : options.fit);
      }
  }

  const libraryVersion = '0.46.0';
  const getVersion = () => {
      return { lib: libraryVersion, dependencies: new Map([['mxGraph', mxClient.VERSION]]) };
  };

  exports.BpmnCanvas = BpmnCanvas;
  exports.BpmnElementsRegistry = BpmnElementsRegistry;
  exports.BpmnStyleIdentifier = BpmnStyleIdentifier;
  exports.BpmnVisualization = BpmnVisualization;
  exports.IconPainter = IconPainter;
  exports.IconPainterProvider = IconPainterProvider;
  exports.MarkerIdentifier = MarkerIdentifier;
  exports.ShapeUtil = ShapeUtil;
  exports.StyleConfigurator = StyleConfigurator;
  exports.StyleDefault = StyleDefault;
  exports.getVersion = getVersion;
  exports.mxgraph = mxgraph;

  return exports;

})({});